aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaiyi Li <kaiyili@google.com>2023-08-03 23:03:37 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-08-03 23:03:37 +0000
commit045280734097d17265aaabda1f63b0baacd9cd60 (patch)
treef204b748c5dd920d6176f3d0e10b820dafbb5784
parentfb2b6698695715a10326c143c33dab4c50cab03d (diff)
parent308c941f21a4d9a4bf66f64c811b91237922c2e6 (diff)
downloadvulkano-045280734097d17265aaabda1f63b0baacd9cd60.tar.gz
Upgrade vulkano to 0.33.0 am: cfa3173d1d am: 6fb41c608d am: 570756a047 am: 0f5fd0001f am: 308c941f21
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/vulkano/+/2690275 Change-Id: Icd5245a7a5195111669af1db7933576b1fee8bd0 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--.cargo_vcs_info.json6
-rw-r--r--Android.bp54
-rw-r--r--Cargo.toml112
-rw-r--r--Cargo.toml.orig56
-rw-r--r--METADATA13
-rw-r--r--README.md226
-rw-r--r--autogen/errors.rs84
-rw-r--r--autogen/extensions.rs911
-rw-r--r--autogen/features.rs774
-rw-r--r--autogen/fns.rs161
-rw-r--r--autogen/formats.rs891
-rw-r--r--autogen/mod.rs528
-rw-r--r--autogen/properties.rs450
-rw-r--r--autogen/spirv_grammar.rs78
-rw-r--r--autogen/spirv_parse.rs686
-rw-r--r--autogen/spirv_reqs.rs275
-rw-r--r--autogen/version.rs52
-rw-r--r--build.rs8
-rw-r--r--out/autogen.rs9611
-rw-r--r--out/device_extensions.rs13961
-rw-r--r--out/errors.rs99
-rw-r--r--out/features.rs21154
-rw-r--r--out/fns.rs408
-rw-r--r--out/formats.rs4625
-rw-r--r--out/instance_extensions.rs1903
-rw-r--r--out/properties.rs1812
-rw-r--r--out/spirv_parse.rs11909
-rw-r--r--out/spirv_reqs.rs1683
-rw-r--r--out/version.rs20
-rw-r--r--spirv.core.grammar.json24586
-rw-r--r--src/buffer/allocator.rs474
-rw-r--r--src/buffer/cpu_access.rs659
-rw-r--r--src/buffer/cpu_pool.rs945
-rw-r--r--src/buffer/device_local.rs398
-rw-r--r--src/buffer/immutable.rs728
-rw-r--r--src/buffer/mod.rs1159
-rw-r--r--src/buffer/slice.rs315
-rw-r--r--src/buffer/subbuffer.rs1331
-rw-r--r--src/buffer/sys.rs1084
-rw-r--r--src/buffer/traits.rs243
-rw-r--r--src/buffer/usage.rs360
-rw-r--r--src/buffer/view.rs708
-rw-r--r--src/cache.rs87
-rw-r--r--src/command_buffer/allocator.rs698
-rw-r--r--src/command_buffer/auto.rs3315
-rw-r--r--src/command_buffer/commands/bind_push.rs1536
-rw-r--r--src/command_buffer/commands/clear.rs1207
-rw-r--r--src/command_buffer/commands/copy.rs5404
-rw-r--r--src/command_buffer/commands/debug.rs345
-rw-r--r--src/command_buffer/commands/dynamic_state.rs3006
-rw-r--r--src/command_buffer/commands/mod.rs (renamed from src/sync/semaphore/mod.rs)18
-rw-r--r--src/command_buffer/commands/pipeline.rs2975
-rw-r--r--src/command_buffer/commands/query.rs1024
-rw-r--r--src/command_buffer/commands/render_pass.rs3175
-rw-r--r--src/command_buffer/commands/secondary.rs930
-rw-r--r--src/command_buffer/commands/sync.rs931
-rw-r--r--src/command_buffer/mod.rs677
-rw-r--r--src/command_buffer/pool.rs645
-rw-r--r--src/command_buffer/pool/mod.rs103
-rw-r--r--src/command_buffer/pool/standard.rs313
-rw-r--r--src/command_buffer/pool/sys.rs421
-rw-r--r--src/command_buffer/standard/builder/bind_push.rs936
-rw-r--r--src/command_buffer/standard/builder/clear.rs742
-rw-r--r--src/command_buffer/standard/builder/copy.rs3729
-rw-r--r--src/command_buffer/standard/builder/debug.rs216
-rw-r--r--src/command_buffer/standard/builder/dynamic_state.rs2350
-rw-r--r--src/command_buffer/standard/builder/mod.rs1585
-rw-r--r--src/command_buffer/standard/builder/pipeline.rs2433
-rw-r--r--src/command_buffer/standard/builder/query.rs752
-rw-r--r--src/command_buffer/standard/builder/render_pass.rs2248
-rw-r--r--src/command_buffer/standard/builder/secondary.rs393
-rw-r--r--src/command_buffer/standard/builder/sync.rs4459
-rw-r--r--src/command_buffer/standard/mod.rs175
-rw-r--r--src/command_buffer/state_cacher.rs484
-rw-r--r--src/command_buffer/submit/bind_sparse.rs511
-rw-r--r--src/command_buffer/submit/mod.rs52
-rw-r--r--src/command_buffer/submit/queue_present.rs279
-rw-r--r--src/command_buffer/submit/queue_submit.rs359
-rw-r--r--src/command_buffer/submit/semaphores_wait.rs81
-rw-r--r--src/command_buffer/synced/builder.rs1801
-rw-r--r--src/command_buffer/synced/commands.rs3123
-rw-r--r--src/command_buffer/synced/mod.rs789
-rw-r--r--src/command_buffer/synced/tests.rs52
-rw-r--r--src/command_buffer/sys.rs2045
-rw-r--r--src/command_buffer/traits.rs549
-rw-r--r--src/command_buffer/validity/blit_image.rs302
-rw-r--r--src/command_buffer/validity/clear_color_image.rs81
-rw-r--r--src/command_buffer/validity/copy_buffer.rs103
-rw-r--r--src/command_buffer/validity/copy_image.rs243
-rw-r--r--src/command_buffer/validity/copy_image_buffer.rs266
-rw-r--r--src/command_buffer/validity/debug_marker.rs32
-rw-r--r--src/command_buffer/validity/descriptor_sets.rs109
-rw-r--r--src/command_buffer/validity/dispatch.rs88
-rw-r--r--src/command_buffer/validity/dynamic_state.rs215
-rw-r--r--src/command_buffer/validity/fill_buffer.rs105
-rw-r--r--src/command_buffer/validity/index_buffer.rs148
-rw-r--r--src/command_buffer/validity/indirect_buffer.rs72
-rw-r--r--src/command_buffer/validity/mod.rs50
-rw-r--r--src/command_buffer/validity/push_constants.rs52
-rw-r--r--src/command_buffer/validity/query.rs391
-rw-r--r--src/command_buffer/validity/update_buffer.rs181
-rw-r--r--src/command_buffer/validity/vertex_buffers.rs118
-rw-r--r--src/descriptor_set/allocator.rs576
-rw-r--r--src/descriptor_set/collection.rs13
-rw-r--r--src/descriptor_set/fixed_size_pool.rs604
-rw-r--r--src/descriptor_set/layout.rs951
-rw-r--r--src/descriptor_set/layout/desc.rs889
-rw-r--r--src/descriptor_set/layout/mod.rs29
-rw-r--r--src/descriptor_set/layout/sys.rs202
-rw-r--r--src/descriptor_set/mod.rs511
-rw-r--r--src/descriptor_set/persistent.rs1315
-rw-r--r--src/descriptor_set/pool.rs592
-rw-r--r--src/descriptor_set/pool/mod.rs220
-rw-r--r--src/descriptor_set/pool/standard.rs213
-rw-r--r--src/descriptor_set/pool/sys.rs503
-rw-r--r--src/descriptor_set/sys.rs611
-rw-r--r--src/descriptor_set/update.rs1204
-rw-r--r--src/device/extensions.rs166
-rw-r--r--src/device/features.rs266
-rw-r--r--src/device/mod.rs1326
-rw-r--r--src/device/physical.rs3341
-rw-r--r--src/device/properties.rs202
-rw-r--r--src/device/queue.rs1730
-rw-r--r--src/extensions.rs256
-rw-r--r--src/fns.rs26
-rw-r--r--src/format.rs1406
-rw-r--r--src/image/aspect.rs205
-rw-r--r--src/image/attachment.rs627
-rw-r--r--src/image/immutable.rs830
-rw-r--r--src/image/layout.rs241
-rw-r--r--src/image/mod.rs1011
-rw-r--r--src/image/storage.rs712
-rw-r--r--src/image/swapchain.rs182
-rw-r--r--src/image/sys.rs4232
-rw-r--r--src/image/traits.rs395
-rw-r--r--src/image/usage.rs301
-rw-r--r--src/image/view.rs1665
-rw-r--r--src/instance/debug.rs755
-rw-r--r--src/instance/extensions.rs153
-rw-r--r--src/instance/instance.rs693
-rw-r--r--src/instance/layers.rs194
-rw-r--r--src/instance/loader.rs316
-rw-r--r--src/instance/mod.rs880
-rw-r--r--src/lib.rs543
-rw-r--r--src/library.rs464
-rw-r--r--src/macros.rs947
-rw-r--r--src/memory/alignment.rs249
-rw-r--r--src/memory/allocator/layout.rs352
-rw-r--r--src/memory/allocator/mod.rs1654
-rw-r--r--src/memory/allocator/suballocator.rs3142
-rw-r--r--src/memory/device_memory.rs2276
-rw-r--r--src/memory/external_memory_handle_type.rs168
-rw-r--r--src/memory/mod.rs584
-rw-r--r--src/memory/pool/host_visible.rs252
-rw-r--r--src/memory/pool/mod.rs352
-rw-r--r--src/memory/pool/non_host_visible.rs251
-rw-r--r--src/memory/pool/pool.rs273
-rw-r--r--src/padded.rs338
-rw-r--r--src/pipeline/blend.rs291
-rw-r--r--src/pipeline/cache.rs242
-rw-r--r--src/pipeline/compute.rs541
-rw-r--r--src/pipeline/compute_pipeline.rs523
-rw-r--r--src/pipeline/depth_stencil.rs263
-rw-r--r--src/pipeline/graphics/builder.rs4585
-rw-r--r--src/pipeline/graphics/color_blend.rs717
-rw-r--r--src/pipeline/graphics/creation_error.rs451
-rw-r--r--src/pipeline/graphics/depth_stencil.rs338
-rw-r--r--src/pipeline/graphics/discard_rectangle.rs66
-rw-r--r--src/pipeline/graphics/input_assembly.rs262
-rw-r--r--src/pipeline/graphics/mod.rs302
-rw-r--r--src/pipeline/graphics/multisample.rs80
-rw-r--r--src/pipeline/graphics/rasterization.rs320
-rw-r--r--src/pipeline/graphics/render_pass.rs141
-rw-r--r--src/pipeline/graphics/tessellation.rs56
-rw-r--r--src/pipeline/graphics/tests.rs (renamed from src/pipeline/graphics_pipeline/tests.rs)18
-rw-r--r--src/pipeline/graphics/vertex_input/buffers.rs72
-rw-r--r--src/pipeline/graphics/vertex_input/collection.rs67
-rw-r--r--src/pipeline/graphics/vertex_input/definition.rs226
-rw-r--r--src/pipeline/graphics/vertex_input/impl_vertex.rs200
-rw-r--r--src/pipeline/graphics/vertex_input/mod.rs235
-rw-r--r--src/pipeline/graphics/vertex_input/vertex.rs155
-rw-r--r--src/pipeline/graphics/viewport.rs (renamed from src/pipeline/viewport.rs)167
-rw-r--r--src/pipeline/graphics_pipeline/builder.rs1952
-rw-r--r--src/pipeline/graphics_pipeline/creation_error.rs380
-rw-r--r--src/pipeline/graphics_pipeline/mod.rs448
-rw-r--r--src/pipeline/input_assembly.rs136
-rw-r--r--src/pipeline/layout.rs1468
-rw-r--r--src/pipeline/layout/limits_check.rs513
-rw-r--r--src/pipeline/layout/mod.rs47
-rw-r--r--src/pipeline/layout/sys.rs469
-rw-r--r--src/pipeline/mod.rs526
-rw-r--r--src/pipeline/multisample.rs61
-rw-r--r--src/pipeline/raster.rs166
-rw-r--r--src/pipeline/shader.rs808
-rw-r--r--src/pipeline/vertex/bufferless.rs67
-rw-r--r--src/pipeline/vertex/buffers.rs234
-rw-r--r--src/pipeline/vertex/definition.rs105
-rw-r--r--src/pipeline/vertex/impl_vertex.rs199
-rw-r--r--src/pipeline/vertex/mod.rs244
-rw-r--r--src/pipeline/vertex/vertex.rs76
-rw-r--r--src/query.rs666
-rw-r--r--src/range_map.rs1527
-rw-r--r--src/range_set.rs68
-rw-r--r--src/render_pass/attachments_list.rs82
-rw-r--r--src/render_pass/compat_atch.rs263
-rw-r--r--src/render_pass/create.rs1979
-rw-r--r--src/render_pass/desc.rs434
-rw-r--r--src/render_pass/framebuffer.rs1551
-rw-r--r--src/render_pass/macros.rs169
-rw-r--r--src/render_pass/mod.rs1306
-rw-r--r--src/render_pass/render_pass.rs911
-rw-r--r--src/sampler.rs1051
-rw-r--r--src/sampler/mod.rs1834
-rw-r--r--src/sampler/ycbcr.rs809
-rw-r--r--src/shader/mod.rs1402
-rw-r--r--src/shader/reflect.rs1443
-rw-r--r--src/shader/spirv.rs794
-rw-r--r--src/swapchain/capabilities.rs664
-rw-r--r--src/swapchain/display.rs332
-rw-r--r--src/swapchain/mod.rs379
-rw-r--r--src/swapchain/present_region.rs69
-rw-r--r--src/swapchain/surface.rs2146
-rw-r--r--src/swapchain/swapchain.rs2929
-rw-r--r--src/sync/event.rs311
-rw-r--r--src/sync/fence.rs1851
-rw-r--r--src/sync/future/fence_signal.rs358
-rw-r--r--src/sync/future/join.rs211
-rw-r--r--src/sync/future/mod.rs436
-rw-r--r--src/sync/future/now.rs55
-rw-r--r--src/sync/future/semaphore_signal.rs204
-rw-r--r--src/sync/mod.rs151
-rw-r--r--src/sync/pipeline.rs2840
-rw-r--r--src/sync/semaphore.rs1667
-rw-r--r--src/sync/semaphore/external_semaphore_handle_type.rs101
-rw-r--r--src/sync/semaphore/semaphore.rs355
-rw-r--r--src/tests.rs86
-rw-r--r--src/version.rs80
-rw-r--r--vk.xml9381
238 files changed, 205296 insertions, 61254 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
new file mode 100644
index 0000000..e5aa74d
--- /dev/null
+++ b/.cargo_vcs_info.json
@@ -0,0 +1,6 @@
+{
+ "git": {
+ "sha1": "096d3bc6605316c62f75ea5ad5908dd03b2efa4f"
+ },
+ "path_in_vcs": "vulkano"
+} \ No newline at end of file
diff --git a/Android.bp b/Android.bp
index d08c144..68c54b6 100644
--- a/Android.bp
+++ b/Android.bp
@@ -41,7 +41,18 @@ genrule {
name: "copy_vulkano_build_out",
srcs: ["out/*"],
cmd: "cp $(in) $(genDir)",
- out: ["autogen.rs"],
+ out: [
+ "device_extensions.rs",
+ "errors.rs",
+ "features.rs",
+ "fns.rs",
+ "formats.rs",
+ "instance_extensions.rs",
+ "properties.rs",
+ "spirv_parse.rs",
+ "spirv_reqs.rs",
+ "version.rs",
+ ],
}
rust_library {
@@ -50,21 +61,23 @@ rust_library {
host_supported: true,
crate_name: "vulkano",
cargo_env_compat: true,
- cargo_pkg_version: "0.25.0",
+ cargo_pkg_version: "0.33.0",
srcs: [
"src/lib.rs",
":copy_vulkano_build_out",
],
- edition: "2018",
+ edition: "2021",
rustlibs: [
+ "libahash",
"libash_rust",
+ "libbytemuck",
"libcrossbeam_queue",
- "libfnv",
"libhalf",
- "liblazy_static",
+ "liblibloading",
+ "libonce_cell",
"libparking_lot",
- "libshared_library",
"libsmallvec",
+ "libthread_local",
],
apex_available: [
"//apex_available:platform",
@@ -73,32 +86,3 @@ rust_library {
product_available: true,
vendor_available: true,
}
-
-rust_test {
- name: "vulkano_test_src_lib",
- // has rustc warnings
- host_supported: true,
- crate_name: "vulkano",
- cargo_env_compat: true,
- cargo_pkg_version: "0.25.0",
- srcs: [
- "src/lib.rs",
- ":copy_vulkano_build_out",
- ],
- test_suites: ["general-tests"],
- auto_gen_config: true,
- test_options: {
- unit_test: false,
- },
- edition: "2018",
- rustlibs: [
- "libash_rust",
- "libcrossbeam_queue",
- "libfnv",
- "libhalf",
- "liblazy_static",
- "libparking_lot",
- "libshared_library",
- "libsmallvec",
- ],
-}
diff --git a/Cargo.toml b/Cargo.toml
index d18af58..c68f39a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -3,59 +3,121 @@
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
-# to registry (e.g., crates.io) dependencies
+# to registry (e.g., crates.io) dependencies.
#
-# If you believe there's an error in this file please file an
-# issue against the rust-lang/cargo repository. If you're
-# editing this file be aware that the upstream Cargo.toml
-# will likely look very different (and much more reasonable)
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
[package]
-edition = "2018"
+edition = "2021"
name = "vulkano"
-version = "0.25.0"
-authors = ["Pierre Krieger <pierre.krieger1708@gmail.com>", "The vulkano contributors"]
+version = "0.33.0"
+authors = [
+ "Pierre Krieger <pierre.krieger1708@gmail.com>",
+ "The vulkano contributors",
+]
build = "build.rs"
description = "Safe wrapper for the Vulkan graphics API"
homepage = "https://vulkano.rs"
documentation = "https://docs.rs/vulkano"
-readme = "../README.md"
-keywords = ["vulkan", "bindings", "graphics", "gpu", "rendering"]
+readme = "README.md"
+keywords = [
+ "vulkan",
+ "bindings",
+ "graphics",
+ "gpu",
+ "rendering",
+]
categories = ["rendering::graphics-api"]
license = "MIT/Apache-2.0"
repository = "https://github.com/vulkano-rs/vulkano"
+resolver = "1"
+
+[dependencies.ahash]
+version = "0.8"
+
[dependencies.ash]
-version = "0.33.0"
+version = "^0.37.2"
+
+[dependencies.bytemuck]
+version = "1.9"
[dependencies.crossbeam-queue]
version = "0.3"
-[dependencies.fnv]
-version = "1.0"
-
[dependencies.half]
-version = "1.7"
+version = "2"
+features = ["bytemuck"]
+
+[dependencies.libloading]
+version = "0.7"
-[dependencies.lazy_static]
-version = "1.4"
+[dependencies.once_cell]
+version = "1.17"
[dependencies.parking_lot]
-version = "0.11.1"
+version = "0.12"
features = ["send_guard"]
-[dependencies.shared_library]
-version = "0.1"
+[dependencies.serde]
+version = "1.0"
+optional = true
[dependencies.smallvec]
-version = "1.6"
+version = "1.8"
+
+[dependencies.thread_local]
+version = "1.1"
+
+[dependencies.vulkano-macros]
+version = "0.33.0"
+optional = true
+
+[dev-dependencies.cgmath]
+version = "0.18"
+
+[dev-dependencies.nalgebra]
+version = "0.32"
+
+[build-dependencies.ahash]
+version = "0.8"
+
[build-dependencies.heck]
-version = "0.3"
+version = "0.4"
[build-dependencies.indexmap]
-version = "1.7"
+version = "1.8"
+
+[build-dependencies.once_cell]
+version = "1.16"
+
+[build-dependencies.proc-macro2]
+version = "1.0"
+
+[build-dependencies.quote]
+version = "1.0"
[build-dependencies.regex]
-version = "1.5"
+version = "1.0"
+
+[build-dependencies.serde]
+version = "1.0"
+features = ["derive"]
+
+[build-dependencies.serde_json]
+version = "1.0"
[build-dependencies.vk-parse]
-version = "0.6"
+version = "0.8"
+
+[features]
+default = ["macros"]
+document_unchecked = []
+macros = ["vulkano-macros"]
+
+[target."cfg(target_os = \"ios\")".dependencies.core-graphics-types]
+version = "0.1"
+
+[target."cfg(target_os = \"ios\")".dependencies.objc]
+version = "0.2.5"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 99c9a33..b83bb09 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,8 +1,11 @@
[package]
name = "vulkano"
-version = "0.25.0"
-edition = "2018"
-authors = ["Pierre Krieger <pierre.krieger1708@gmail.com>", "The vulkano contributors"]
+version = "0.33.0"
+edition = "2021"
+authors = [
+ "Pierre Krieger <pierre.krieger1708@gmail.com>",
+ "The vulkano contributors",
+]
repository = "https://github.com/vulkano-rs/vulkano"
description = "Safe wrapper for the Vulkan graphics API"
license = "MIT/Apache-2.0"
@@ -14,19 +17,42 @@ readme = "../README.md"
build = "build.rs"
[dependencies]
+ahash = "0.8"
# When updating Ash, also update vk.xml to the same Vulkan patch version that Ash uses.
-# All versions of vk.xml can be found at https://github.com/KhronosGroup/Vulkan-Headers/commits/master/registry/vk.xml.
-ash = "0.33.0"
+# All versions of vk.xml can be found at https://github.com/KhronosGroup/Vulkan-Headers/commits/main/registry/vk.xml.
+ash = "^0.37.2"
+bytemuck = "1.9"
crossbeam-queue = "0.3"
-fnv = "1.0"
-half = "1.7"
-lazy_static = "1.4"
-parking_lot = { version = "0.11.1", features = ["send_guard"] }
-shared_library = "0.1"
-smallvec = "1.6"
+half = { version = "2", features = ["bytemuck"] }
+libloading = "0.7"
+once_cell = "1.17"
+parking_lot = { version = "0.12", features = ["send_guard"] }
+serde = { version = "1.0", optional = true }
+smallvec = "1.8"
+thread_local = "1.1"
+vulkano-macros = { path = "../vulkano-macros", version = "0.33.0", optional = true }
+
+[target.'cfg(target_os = "ios")'.dependencies]
+objc = "0.2.5"
+core-graphics-types = "0.1"
[build-dependencies]
-heck = "0.3"
-indexmap = "1.7"
-regex = "1.5"
-vk-parse = "0.6"
+ahash = "0.8"
+heck = "0.4"
+indexmap = "1.8"
+once_cell = "1.16"
+proc-macro2 = "1.0"
+quote = "1.0"
+regex = "1.0"
+serde = { version = "1.0", features = ["derive"] }
+serde_json = "1.0"
+vk-parse = "0.8"
+
+[dev-dependencies]
+cgmath = "0.18"
+nalgebra = "0.32"
+
+[features]
+default = ["macros"]
+macros = ["vulkano-macros"]
+document_unchecked = []
diff --git a/METADATA b/METADATA
index fe0bbcc..71c1b99 100644
--- a/METADATA
+++ b/METADATA
@@ -1,3 +1,7 @@
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update rust/crates/vulkano
+# For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md
+
name: "vulkano"
description: "Safe wrapper for the Vulkan graphics API"
third_party {
@@ -7,14 +11,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/vulkano/vulkano-0.25.0.crate"
+ value: "https://static.crates.io/crates/vulkano/vulkano-0.33.0.crate"
}
- version: "0.25.0"
- # Dual-licensed, using the least restrictive per go/thirdpartylicenses#same.
+ version: "0.33.0"
license_type: NOTICE
last_upgrade_date {
- year: 2021
+ year: 2023
month: 8
- day: 30
+ day: 2
}
}
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..3d339ab
--- /dev/null
+++ b/README.md
@@ -0,0 +1,226 @@
+<img align="left" alt="" src="logo.png" height="150" />
+
+# [Vulkano](https://vulkano.rs)
+
+[![Build Status](https://github.com/vulkano-rs/vulkano/workflows/Rust/badge.svg)](https://github.com/vulkano-rs/vulkano/actions?query=workflow%3ARust)
+[![Discord](https://img.shields.io/discord/937149253296476201?label=discord)](https://discord.gg/bncB9W2VDV)
+[![Website/guide](https://img.shields.io/badge/-website/guide-%23555.svg)](https://vulkano.rs/)
+<br/>
+[![vulkano crates.io](https://img.shields.io/crates/v/vulkano?label=vulkano)](https://crates.io/crates/vulkano)
+[![vulkano-shaders crates.io](https://img.shields.io/crates/v/vulkano-shaders?label=shaders)](https://crates.io/crates/vulkano-shaders)
+[![vulkano-util crates.io](https://img.shields.io/crates/v/vulkano-util?label=util)](https://crates.io/crates/vulkano-util)
+[![vulkano-win crates.io](https://img.shields.io/crates/v/vulkano-win?label=win)](https://crates.io/crates/vulkano-win)
+<br/>
+[![vulkano docs](https://img.shields.io/docsrs/vulkano?label=vulkano%20docs)](https://docs.rs/vulkano)
+[![vulkano-shaders docs](https://img.shields.io/docsrs/vulkano-shaders?label=shaders%20docs)](https://docs.rs/vulkano-shaders)
+[![vulkano-util docs](https://img.shields.io/docsrs/vulkano-util?label=util%20docs)](https://docs.rs/vulkano-util)
+[![vulkano-win docs](https://img.shields.io/docsrs/vulkano-win?label=win%20docs)](https://docs.rs/vulkano-win)
+
+Vulkano is a Rust wrapper around [the Vulkan graphics API](https://www.khronos.org/vulkan/).
+It follows the Rust philosophy, which is that as long as you don't use unsafe code you shouldn't
+be able to trigger any undefined behavior. In the case of Vulkan, this means that non-unsafe code
+should always conform to valid API usage.
+
+What does vulkano do?
+
+- Provides a low-levelish API around Vulkan. It doesn't hide what it does but provides some
+ comfort types.
+- Plans to prevent all invalid API usages, even the most obscure ones. The purpose of Vulkano
+ is not to simply let you draw a teapot, but to cover all possible usages of Vulkan and detect all
+ the possible problems in order to write robust programs. Invalid API usage is prevented thanks to
+ both compile-time checks and runtime checks.
+- Can handle synchronization on the GPU side for you (unless you choose to do that yourself), as this
+ aspect of Vulkan is both annoying to handle and error-prone. Dependencies between submissions are
+ automatically detected, and semaphores are managed automatically. The behavior of the library can
+ be customized thanks to unsafe trait implementations.
+- Tries to be convenient to use. Nobody is going to use a library that requires you to browse
+ the documentation for hours for every single operation.
+
+### Comparison
+
+Comparison to other well-known Graphics APIs in Rust ecosystem.
+
+| Name | Open-sourced Since | API Level | Notable Features |
+| ---- | ------------------ | --------- | ------------- |
+| Vulkano | March, 2016 | High-level Rust API wrapping Vulkan APIs. | Type-safe compile-time shaders. Transparent interoperability with glsl and spir-v shader code types in Rust code. Automatically generated types for shader's Layout. |
+| [Wgpu](https://github.com/gfx-rs/wgpu) | May, 2019 | High-level Rust API with multiple backends. | Supports multiple backends: Vulkan, Metal, DirectX, WebGPU, and other. Follows WebGPU specification. With async/await API. |
+| [Miniquad](https://github.com/not-fl3/miniquad) | March, 2020 | High-level minimalistic Rust API with multiple backends. | Relatively minimalistic API well suited for small to medium graphics projects. Supports multiple backends, including browser target. |
+| [Sierra](https://github.com/zakarumych/sierra) | March, 2021 | High-level Rust API for Vulkan/Metal APIs. | Layouts, Descriptors and shader Types construction in Rust code through the macro system. Built on top of [Erupt](https://gitlab.com/Friz64/erupt). Supports Ray Tracing Pipeline. |
+| [Glium](https://github.com/glium/glium) | October, 2014 | High-level Rust API wrapping OpenGL | OpenGL only. |
+| [Ash](https://github.com/MaikKlein/ash) | August, 2016 | Low-level API for Vulkan. | Unsafe Vulkan API bindings. |
+| [Erupt](https://gitlab.com/Friz64/erupt) | April, 2020 | Low-level API for Vulkan. | Unsafe Vulkan API bindings. |
+
+Please note that by the current date none of the known projects in the ecosystem(including Vulkano)
+reached stable release versions and the final design goals, their APIs are changing from time
+to time in a breakable way too, and there could be bugs and unfinished features too.
+
+However, most of the projects mentioned above are already established definitive structures, all
+feature breaking changes will likely be straightforward to fix in user code, and most of them
+are maintained. As such we can recommend using any of them in the 3rd party code.
+The choice depends on the end project's goals and requirements, and we recommend examining
+their actual set of features and API capabilities beforehand.
+
+### Projects using Vulkano
+
+We started collecting this list just recently and it would be appreciated if you help us by
+contributing(opening a PR) into [README.md](https://github.com/vulkano-rs/vulkano/blob/master/README.md).
+
+| Project Name | Description |
+| ------------ | ----------- |
+| [Basalt](https://github.com/AustinJ235/basalt) | GUI framework for Desktop applications |
+| [Ferret](https://github.com/Rua/ferret) | Doom-compatible game engine |
+| [Sandbox](https://github.com/hakolao/sandbox) | 2D Pixel Physics Simulator |
+| [Egui Winit Vulkano](https://github.com/hakolao/egui_winit_vulkano) | Vulkano integration with Egui |
+| [VideowindoW](https://www.videowindow.eu/) | Uses Vulkano under the hood to enable asynchronous video stream compositing |
+| [Korangar](https://github.com/vE5li/korangar) | A Vulkan based Ragnarok Online client |
+
+We would love to help you keep your project in sync with the most recent changes in Vulkano
+if you give us feedback by adding your project to this list.
+
+Thanks in advance!
+
+## Documentation and Resources
+
+To get started you are encouraged to use the following resources:
+
+- The [examples](https://github.com/vulkano-rs/vulkano/tree/master/examples) folder in this repository.
+ - [docs.rs](https://docs.rs/vulkano) - Full Vulkano API documentation
+ - The guide on [vulkano.rs](https://vulkano.rs/guide/introduction) - Starts with trivial compute
+ examples (~50 lines of code) and then works up to rendering triangles and mandelbrots.
+ The guide is currently outdated a little. We are planning to update it in the future, but it's
+ a good place to start understanding the base building blocks of Vulkano API.
+ - Github [Issues](https://github.com/vulkano-rs/vulkano/issues) - Raise a topic, ask a question
+ or report a bug. The new topics there are watched regularly by maintainers and other
+ community users.
+ - Gitter [Chat](https://gitter.im/vulkano-rs/Lobby) - Another place to raise a question. However,
+ the chat is not maintained regularly at this moment. Better use Github Issues for this purpose.
+
+## Contributing
+
+Contributions are very welcome! Feel free to submit pull requests, to open questions and topics
+in the [Issues](https://github.com/vulkano-rs/vulkano/issues) section.
+
+The project was initially developed by Pierre Krieger(Tomaka), who established Vulkano's base
+design goals, and the code structure. In the meantime, development is driven by Vulkano
+community members.
+
+**New Pull Requests are usually scheduled for review by the end of each week.**
+The older PRs that are already in review have priority over the new ones. We are trying to push
+development forward as quick as possible, but the review process sometimes takes time,
+please be patient as the maintainers need time to check everything properly.
+
+If something needs to get promoted urgently, please ping current Vulkano
+maintainer([@Eliah-Lakhin](https://github.com/Eliah-Lakhin/)) in the PR's
+or Issue's comments.
+
+If your change adds, removes or modifies a trait or a function, please
+specify changelog entries **in the Pull Request description**(not in the changelog file directly).
+They will be transferred to the changelog right after the PR merge.
+
+Every PR must pass tests in order to be merged to `master`.
+
+Minor releases are usually happening between 1 to 3 months averagely depending on grow
+of unreleased and breaking changes in `master`
+
+### Repository Structure
+
+This repository contains four libraries:
+
+- `vulkano` is the main one.
+- `vulkano-shaders` provides the `shader!` macro for compiling glsl shaders.
+- `vulkano-util` provides a variety of utility functions to streamline certain common operations such as device and swapchain creation.
+- `vulkano-win` provides a safe link between vulkano and the `winit` library which can create
+ a window to render to.
+
+In order to run tests, run `cargo test --all` at the root of the repository. Make sure your Vulkan
+driver is up to date before doing so.
+
+### Hall of Fame
+
+We would love to mention some members, who put significant contributions to this project:
+- Pierre Krieger. The initial developer. [Patreon page](https://www.patreon.com/tomaka).
+- Lucas Kent. Maintainer. [Patreon page](https://www.patreon.com/rukai).
+- Austin Johnson. Maintainer. [Patreon page](https://www.patreon.com/austinj235).
+- Rua. An active developer, who put a lot of effort to improve Vulkano and constantly keeping it up to date.
+- **You!** Thanks to your help, contributions, improvements, bug reports and user experience
+ to make this project one of the major Rust graphics API library in Rust!
+
+## Setup and Troubleshooting
+
+Vulkano uses [shaderc-rs](https://github.com/google/shaderc-rs) for shader compilation. Refer to shaderc-rs documentation to provide a pre-built libshaderc for faster build times.
+
+Note that in general vulkano does **not** require you to install the official Vulkan SDK. This is
+not something specific to vulkano (you don't need the SDK to write programs that use Vulkan, even
+without vulkano), but many people are unaware of that and install the SDK thinking that it is
+required. However, macOS and iOS platforms do require a little more Vulkan setup since it is not
+natively supported. See below for more details.
+
+Unless you provide libshaderc, in order to build libshaderc with the shaderc-sys crate, the following tools must be installed and available on `PATH`:
+- [CMake](https://cmake.org/)
+- [Ninja](https://ninja-build.org/) Is optional except when building with MSVC. It may speed up build time for libshaderc.
+- [Python](https://www.python.org/) (works with both Python 2.x and 3.x, on windows the executable must be named `python.exe`)
+
+These requirements can be either installed with your favourite package manager or with installers
+from the projects' websites. Below are some examples of ways to set up.
+
+### windows-msvc Specific Setup
+
+1. `rustup default stable-x86_64-pc-windows-msvc`
+2. Install [Build Tools for Visual Studio 2017](https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2017). If you have already been using this toolchain then its probably already installed.
+3. Install [msys2](https://www.msys2.org/), following ALL of the instructions.
+4. Then in the msys2 terminal run: `pacman --noconfirm -Syu mingw-w64-x86_64-cmake mingw-w64-x86_64-python2 mingw-w64-x86_64-ninja`
+5. Add the msys2 mingw64 binary path to the PATH environment variable.
+
+### Windows-gnu Specific Setup
+
+windows-gnu toolchain is not supported but you can instead cross-compile to windows-gnu from windows-msvc
+
+Steps 1 and 2 are to workaround https://github.com/rust-lang/rust/issues/49078 by using the same mingw that rust uses.
+
+1. Download and extract https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z
+2. Add the absolute path to mingw64\bin to your PATH environment variable. (This path needs to be before the msys2 path)
+3. Run the command: `rustup default stable-x86_64-pc-windows-msvc`
+4. Run the command: `rustup target install x86_64-pc-windows-gnu`
+5. Install [Build Tools for Visual Studio 2017](https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2017). If you have already been using this toolchain then it's probably already installed.
+6. Install [msys2](https://www.msys2.org/), following ALL of the instructions.
+7. Then in the msys2 terminal run: `pacman --noconfirm -Syu mingw64/mingw-w64-x86_64-pkg-config mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake mingw-w64-x86_64-make mingw-w64-x86_64-python2 mingw-w64-x86_64-ninja`
+8. Add the msys2 mingw64 binary path to the PATH environment variable.
+9. Any cargo command that builds the project needs to include `--target x86_64-pc-windows-gnu` e.g. to run: `cargo run --target x86_64-pc-windows-gnu`
+
+### Linux Specific Setup
+
+Use your package manager to install the required dev-tools and Vulkan drivers
+
+For example on ubuntu:
+```
+sudo apt-get install build-essential git python cmake libvulkan-dev vulkan-utils
+```
+On arch based system
+```
+sudo pacman -Sy base-devel git python cmake vulkan-devel --noconfirm
+```
+
+### macOS and iOS Specific Setup
+
+Vulkan is not natively supported by macOS and iOS. However, there exists [MoltenVK](https://github.com/KhronosGroup/MoltenVK)
+an open-source Vulkan implementation on top of Apple's Metal API. This allows vulkano to build and run on macOS
+and iOS platforms.
+
+The easiest way to get vulkano up and running with MoltenVK is to install the
+[Vulkan SDK for macOS](https://vulkan.lunarg.com/sdk/home). There are [installation instructions](https://vulkan.lunarg.com/doc/sdk/latest/mac/getting_started.html) on the LunarG website.
+
+On iOS, vulkano links directly to the MoltenVK framework. There is nothing else to do besides
+installing it. Note that the Vulkan SDK for macOS also comes with the iOS framework.
+
+## License
+
+Licensed under either of
+ * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or https://www.apache.org/licenses/LICENSE-2.0)
+ * MIT license ([LICENSE-MIT](LICENSE-MIT) or https://opensource.org/licenses/MIT)
+at your option.
+
+### Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in the work by you shall be dual licensed as above, without any
+additional terms or conditions.
diff --git a/autogen/errors.rs b/autogen/errors.rs
new file mode 100644
index 0000000..920b9b3
--- /dev/null
+++ b/autogen/errors.rs
@@ -0,0 +1,84 @@
+// Copyright (c) 2022 The Vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use super::{write_file, VkRegistryData};
+use heck::ToUpperCamelCase;
+use proc_macro2::{Ident, TokenStream};
+use quote::{format_ident, quote};
+
+pub fn write(vk_data: &VkRegistryData) {
+ write_file(
+ "errors.rs",
+ format!(
+ "vk.xml header version {}.{}.{}",
+ vk_data.header_version.0, vk_data.header_version.1, vk_data.header_version.2
+ ),
+ errors_output(&errors_members(&vk_data.errors)),
+ );
+}
+
+#[derive(Clone, Debug)]
+struct ErrorsMember {
+ name: Ident,
+ ffi_name: Ident,
+}
+
+fn errors_output(members: &[ErrorsMember]) -> TokenStream {
+ let enum_items = members.iter().map(|ErrorsMember { name, .. }| {
+ quote! { #name, }
+ });
+ let try_from_items = members.iter().map(|ErrorsMember { name, ffi_name }| {
+ quote! { ash::vk::Result::#ffi_name => Self::#name, }
+ });
+
+ quote! {
+ /// An enumeration of runtime errors that can be returned by Vulkan.
+ #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+ #[repr(i32)]
+ #[non_exhaustive]
+ pub enum VulkanError {
+ #(#enum_items)*
+ Unnamed(ash::vk::Result),
+ }
+
+ impl From<ash::vk::Result> for VulkanError {
+ fn from(val: ash::vk::Result) -> VulkanError {
+ match val {
+ #(#try_from_items)*
+ x => Self::Unnamed(x),
+ }
+ }
+ }
+ }
+}
+
+fn errors_members(errors: &[&str]) -> Vec<ErrorsMember> {
+ errors
+ .iter()
+ .map(|error| {
+ let ffi_name = error.strip_prefix("VK_").unwrap();
+
+ let mut parts = ffi_name.split('_').collect::<Vec<_>>();
+
+ assert!(parts[0] == "ERROR");
+ parts.remove(0);
+
+ if ["EXT", "KHR", "NV"].contains(parts.last().unwrap()) {
+ parts.pop();
+ }
+
+ let name = parts.join("_").to_upper_camel_case();
+
+ ErrorsMember {
+ name: format_ident!("{}", name),
+ ffi_name: format_ident!("{}", ffi_name),
+ }
+ })
+ .collect()
+}
diff --git a/autogen/extensions.rs b/autogen/extensions.rs
index b303da1..953e568 100644
--- a/autogen/extensions.rs
+++ b/autogen/extensions.rs
@@ -7,13 +7,16 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use heck::SnakeCase;
-use indexmap::IndexMap;
-use std::io::Write;
+use super::{write_file, IndexMap, VkRegistryData};
+use heck::ToSnakeCase;
+use proc_macro2::{Ident, Literal, TokenStream};
+use quote::{format_ident, quote};
+use std::fmt::Write as _;
use vk_parse::Extension;
// This is not included in vk.xml, so it's added here manually
fn required_if_supported(name: &str) -> bool {
+ #[allow(clippy::match_like_matches_macro)]
match name {
"VK_KHR_portability_subset" => true,
_ => false,
@@ -28,29 +31,34 @@ fn conflicts_extensions(name: &str) -> &'static [&'static str] {
}
}
-pub fn write<W: Write>(writer: &mut W, extensions: &IndexMap<&str, &Extension>) {
- write_device_extensions(writer, make_vulkano_extensions("device", &extensions));
- write!(writer, "\n\n").unwrap();
- write_instance_extensions(writer, make_vulkano_extensions("instance", &extensions));
+pub fn write(vk_data: &VkRegistryData) {
+ write_device_extensions(vk_data);
+ write_instance_extensions(vk_data);
}
#[derive(Clone, Debug)]
-struct VulkanoExtension {
- member: String,
+struct ExtensionsMember {
+ name: Ident,
+ doc: String,
raw: String,
- requires_core: (u16, u16),
- requires_device_extensions: Vec<String>,
- requires_instance_extensions: Vec<String>,
required_if_supported: bool,
- conflicts_device_extensions: Vec<String>,
+ requires: Vec<RequiresOneOf>,
+ conflicts_device_extensions: Vec<Ident>,
status: Option<ExtensionStatus>,
}
+#[derive(Clone, Debug, Default, PartialEq, Eq)]
+pub struct RequiresOneOf {
+ pub api_version: Option<(String, String)>,
+ pub device_extensions: Vec<Ident>,
+ pub instance_extensions: Vec<Ident>,
+}
+
#[derive(Clone, Debug)]
enum Replacement {
- Core((u16, u16)),
- DeviceExtension(String),
- InstanceExtension(String),
+ Core((String, String)),
+ DeviceExtension(Ident),
+ InstanceExtension(Ident),
}
#[derive(Clone, Debug)]
@@ -59,284 +67,629 @@ enum ExtensionStatus {
Deprecated(Option<Replacement>),
}
-fn make_vulkano_extensions(
- ty: &str,
- extensions: &IndexMap<&str, &Extension>,
-) -> Vec<VulkanoExtension> {
+fn write_device_extensions(vk_data: &VkRegistryData) {
+ write_file(
+ "device_extensions.rs",
+ format!(
+ "vk.xml header version {}.{}.{}",
+ vk_data.header_version.0, vk_data.header_version.1, vk_data.header_version.2
+ ),
+ device_extensions_output(&extensions_members("device", &vk_data.extensions)),
+ );
+}
+
+fn write_instance_extensions(vk_data: &VkRegistryData) {
+ write_file(
+ "instance_extensions.rs",
+ format!(
+ "vk.xml header version {}.{}.{}",
+ vk_data.header_version.0, vk_data.header_version.1, vk_data.header_version.2
+ ),
+ instance_extensions_output(&extensions_members("instance", &vk_data.extensions)),
+ );
+}
+
+fn device_extensions_output(members: &[ExtensionsMember]) -> TokenStream {
+ let common = extensions_common_output(format_ident!("DeviceExtensions"), members);
+
+ let check_requirements_items = members.iter().map(|ExtensionsMember {
+ name,
+ requires,
+ conflicts_device_extensions,
+ required_if_supported,
+ ..
+ }| {
+ let name_string = name.to_string();
+
+ let requires_items = requires.iter().map(|require| {
+ let require_items = require.api_version.iter().map(|version| {
+ let version = format_ident!("V{}_{}", version.0, version.1);
+ quote! { api_version >= crate::Version::#version }
+ }).chain(require.instance_extensions.iter().map(|ext| {
+ quote! { instance_extensions.#ext }
+ })).chain(require.device_extensions.iter().map(|ext| {
+ quote! { device_extensions.#ext }
+ }));
+
+ let api_version_items = require.api_version.as_ref().map(|version| {
+ let version = format_ident!("V{}_{}", version.0, version.1);
+ quote! { Some(crate::Version::#version) }
+ }).unwrap_or_else(|| quote!{ None });
+ let device_extensions_items = require.device_extensions.iter().map(|ext| ext.to_string());
+ let instance_extensions_items = require.instance_extensions.iter().map(|ext| ext.to_string());
+
+ quote! {
+ if !(#(#require_items)||*) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: #name_string,
+ restriction: crate::device::ExtensionRestriction::Requires(crate::RequiresOneOf {
+ api_version: #api_version_items,
+ device_extensions: &[#(#device_extensions_items),*],
+ instance_extensions: &[#(#instance_extensions_items),*],
+ ..Default::default()
+ }),
+ })
+ }
+ }
+ });
+ let conflicts_device_extensions_items = conflicts_device_extensions.iter().map(|extension| {
+ let string = extension.to_string();
+ quote! {
+ if self.#extension {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: #name_string,
+ restriction: crate::device::ExtensionRestriction::ConflictsDeviceExtension(#string),
+ });
+ }
+ }
+ });
+ let required_if_supported = if *required_if_supported {
+ quote! {
+ if supported.#name {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: #name_string,
+ restriction: crate::device::ExtensionRestriction::RequiredIfSupported,
+ });
+ }
+ }
+ } else {
+ quote! {}
+ };
+
+ quote! {
+ if self.#name {
+ if !supported.#name {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: #name_string,
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+
+ #(#requires_items)*
+ #(#conflicts_device_extensions_items)*
+ } else {
+ #required_if_supported
+ }
+ }
+ });
+
+ quote! {
+ #common
+
+ impl DeviceExtensions {
+ /// Checks enabled extensions against the device version, instance extensions and each other.
+ pub(super) fn check_requirements(
+ &self,
+ supported: &DeviceExtensions,
+ api_version: crate::Version,
+ instance_extensions: &crate::instance::InstanceExtensions,
+ ) -> Result<(), crate::device::ExtensionRestrictionError> {
+ let device_extensions = self;
+ #(#check_requirements_items)*
+ Ok(())
+ }
+ }
+ }
+}
+
+fn instance_extensions_output(members: &[ExtensionsMember]) -> TokenStream {
+ let common = extensions_common_output(format_ident!("InstanceExtensions"), members);
+
+ let check_requirements_items =
+ members
+ .iter()
+ .map(|ExtensionsMember { name, requires, .. }| {
+ let name_string = name.to_string();
+
+ let requires_items = requires.iter().map(|require| {
+ let require_items = require
+ .api_version
+ .iter()
+ .map(|version| {
+ let version = format_ident!("V{}_{}", version.0, version.1);
+ quote! { api_version >= crate::Version::#version }
+ })
+ .chain(require.instance_extensions.iter().map(|ext| {
+ quote! { instance_extensions.#ext }
+ }))
+ .chain(require.device_extensions.iter().map(|ext| {
+ quote! { device_extensions.#ext }
+ }));
+
+ let api_version_items = require
+ .api_version
+ .as_ref()
+ .map(|version| {
+ let version = format_ident!("V{}_{}", version.0, version.1);
+ quote! { Some(crate::Version::#version) }
+ })
+ .unwrap_or_else(|| quote! { None });
+ let device_extensions_items =
+ require.device_extensions.iter().map(|ext| ext.to_string());
+ let instance_extensions_items = require
+ .instance_extensions
+ .iter()
+ .map(|ext| ext.to_string());
+
+ quote! {
+ if !(#(#require_items)||*) {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: #name_string,
+ restriction: crate::instance::ExtensionRestriction::Requires(crate::RequiresOneOf {
+ api_version: #api_version_items,
+ device_extensions: &[#(#device_extensions_items),*],
+ instance_extensions: &[#(#instance_extensions_items),*],
+ ..Default::default()
+ }),
+ })
+ }
+ }
+ });
+
+ quote! {
+ if self.#name {
+ if !supported.#name {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: #name_string,
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+
+ #(#requires_items)*
+ }
+ }
+ });
+
+ quote! {
+ #common
+
+ impl InstanceExtensions {
+ /// Checks enabled extensions against the instance version and each other.
+ pub(super) fn check_requirements(
+ &self,
+ supported: &InstanceExtensions,
+ api_version: crate::Version,
+ ) -> Result<(), crate::instance::ExtensionRestrictionError> {
+ let instance_extensions = self;
+ #(#check_requirements_items)*
+ Ok(())
+ }
+ }
+ }
+}
+
+fn extensions_common_output(struct_name: Ident, members: &[ExtensionsMember]) -> TokenStream {
+ let struct_items = members.iter().map(|ExtensionsMember { name, doc, .. }| {
+ quote! {
+ #[doc = #doc]
+ pub #name: bool,
+ }
+ });
+
+ let empty_items = members.iter().map(|ExtensionsMember { name, .. }| {
+ quote! {
+ #name: false,
+ }
+ });
+
+ let intersects_items = members.iter().map(|ExtensionsMember { name, .. }| {
+ quote! {
+ (self.#name && other.#name)
+ }
+ });
+
+ let contains_items = members.iter().map(|ExtensionsMember { name, .. }| {
+ quote! {
+ (self.#name || !other.#name)
+ }
+ });
+
+ let union_items = members.iter().map(|ExtensionsMember { name, .. }| {
+ quote! {
+ #name: self.#name || other.#name,
+ }
+ });
+
+ let intersection_items = members.iter().map(|ExtensionsMember { name, .. }| {
+ quote! {
+ #name: self.#name && other.#name,
+ }
+ });
+
+ let difference_items = members.iter().map(|ExtensionsMember { name, .. }| {
+ quote! {
+ #name: self.#name && !other.#name,
+ }
+ });
+
+ let symmetric_difference_items = members.iter().map(|ExtensionsMember { name, .. }| {
+ quote! {
+ #name: self.#name ^ other.#name,
+ }
+ });
+
+ let debug_items = members.iter().map(|ExtensionsMember { name, raw, .. }| {
+ quote! {
+ if self.#name {
+ if !first { write!(f, ", ")? }
+ else { first = false; }
+ f.write_str(#raw)?;
+ }
+ }
+ });
+
+ let arr_items = members.iter().map(|ExtensionsMember { name, raw, .. }| {
+ quote! {
+ (#raw, self.#name),
+ }
+ });
+ let arr_len = members.len();
+
+ let from_str_for_extensions_items =
+ members.iter().map(|ExtensionsMember { name, raw, .. }| {
+ let raw = Literal::string(raw);
+ quote! {
+ #raw => { extensions.#name = true; }
+ }
+ });
+
+ let from_extensions_for_vec_cstring_items =
+ members.iter().map(|ExtensionsMember { name, raw, .. }| {
+ quote! {
+ if x.#name { data.push(std::ffi::CString::new(#raw).unwrap()); }
+ }
+ });
+
+ quote! {
+ /// List of extensions that are enabled or available.
+ #[derive(Copy, Clone, PartialEq, Eq)]
+ pub struct #struct_name {
+ #(#struct_items)*
+
+ pub _ne: crate::NonExhaustive,
+ }
+
+ impl Default for #struct_name {
+ #[inline]
+ fn default() -> Self {
+ Self::empty()
+ }
+ }
+
+ impl #struct_name {
+ /// Returns an `Extensions` object with none of the members set.
+ #[inline]
+ pub const fn empty() -> Self {
+ Self {
+ #(#empty_items)*
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+
+ /// Returns an `Extensions` object with none of the members set.
+ #[deprecated(since = "0.31.0", note = "Use `empty` instead.")]
+ #[inline]
+ pub const fn none() -> Self {
+ Self::empty()
+ }
+
+ /// Returns whether any members are set in both `self` and `other`.
+ #[inline]
+ pub const fn intersects(&self, other: &Self) -> bool {
+ #(#intersects_items)||*
+ }
+
+ /// Returns whether all members in `other` are set in `self`.
+ #[inline]
+ pub const fn contains(&self, other: &Self) -> bool {
+ #(#contains_items)&&*
+ }
+
+ /// Returns whether all members in `other` are set in `self`.
+ #[deprecated(since = "0.31.0", note = "Use `contains` instead.")]
+ #[inline]
+ pub const fn is_superset_of(&self, other: &Self) -> bool {
+ self.contains(other)
+ }
+
+ /// Returns the union of `self` and `other`.
+ #[inline]
+ pub const fn union(&self, other: &Self) -> Self {
+ Self {
+ #(#union_items)*
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+
+ /// Returns the intersection of `self` and `other`.
+ #[inline]
+ pub const fn intersection(&self, other: &Self) -> Self {
+ Self {
+ #(#intersection_items)*
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+
+ /// Returns `self` without the members set in `other`.
+ #[inline]
+ pub const fn difference(&self, other: &Self) -> Self {
+ Self {
+ #(#difference_items)*
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+
+ /// Returns the members set in `self` or `other`, but not both.
+ #[inline]
+ pub const fn symmetric_difference(&self, other: &Self) -> Self {
+ Self {
+ #(#symmetric_difference_items)*
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+ }
+
+ impl std::ops::BitAnd for #struct_name {
+ type Output = #struct_name;
+
+ #[inline]
+ fn bitand(self, rhs: Self) -> Self::Output {
+ self.union(&rhs)
+ }
+ }
+
+ impl std::ops::BitAndAssign for #struct_name {
+ #[inline]
+ fn bitand_assign(&mut self, rhs: Self) {
+ *self = self.union(&rhs);
+ }
+ }
+
+ impl std::ops::BitOr for #struct_name {
+ type Output = #struct_name;
+
+ #[inline]
+ fn bitor(self, rhs: Self) -> Self::Output {
+ self.intersection(&rhs)
+ }
+ }
+
+ impl std::ops::BitOrAssign for #struct_name {
+ #[inline]
+ fn bitor_assign(&mut self, rhs: Self) {
+ *self = self.intersection(&rhs);
+ }
+ }
+
+ impl std::ops::BitXor for #struct_name {
+ type Output = #struct_name;
+
+ #[inline]
+ fn bitxor(self, rhs: Self) -> Self::Output {
+ self.symmetric_difference(&rhs)
+ }
+ }
+
+ impl std::ops::BitXorAssign for #struct_name {
+ #[inline]
+ fn bitxor_assign(&mut self, rhs: Self) {
+ *self = self.symmetric_difference(&rhs);
+ }
+ }
+
+ impl std::ops::Sub for #struct_name {
+ type Output = #struct_name;
+
+ #[inline]
+ fn sub(self, rhs: Self) -> Self::Output {
+ self.difference(&rhs)
+ }
+ }
+
+ impl std::ops::SubAssign for #struct_name {
+ #[inline]
+ fn sub_assign(&mut self, rhs: Self) {
+ *self = self.difference(&rhs);
+ }
+ }
+
+ impl std::fmt::Debug for #struct_name {
+ #[allow(unused_assignments)]
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
+ write!(f, "[")?;
+
+ let mut first = true;
+ #(#debug_items)*
+
+ write!(f, "]")
+ }
+ }
+
+ impl<'a> FromIterator<&'a str> for #struct_name {
+ fn from_iter<I>(iter: I) -> Self
+ where I: IntoIterator<Item = &'a str>
+ {
+ let mut extensions = Self::empty();
+ for name in iter {
+ match name {
+ #(#from_str_for_extensions_items)*
+ _ => (),
+ }
+ }
+ extensions
+ }
+ }
+
+ impl<'a> From<&'a #struct_name> for Vec<std::ffi::CString> {
+ fn from(x: &'a #struct_name) -> Self {
+ let mut data = Self::new();
+ #(#from_extensions_for_vec_cstring_items)*
+ data
+ }
+ }
+
+ impl IntoIterator for #struct_name {
+ type Item = (&'static str, bool);
+ type IntoIter = std::array::IntoIter<Self::Item, #arr_len>;
+
+ #[inline]
+ fn into_iter(self) -> Self::IntoIter {
+ [#(#arr_items)*].into_iter()
+ }
+ }
+ }
+}
+
+fn extensions_members(ty: &str, extensions: &IndexMap<&str, &Extension>) -> Vec<ExtensionsMember> {
extensions
.values()
.filter(|ext| ext.ext_type.as_ref().unwrap() == ty)
.map(|ext| {
let raw = ext.name.to_owned();
- let member = raw.strip_prefix("VK_").unwrap().to_snake_case();
- let (major, minor) = ext
- .requires_core
- .as_ref()
- .map(|s| s.as_str())
- .unwrap_or("1.0")
- .split_once('.')
- .unwrap();
- let requires_extensions: Vec<_> = ext
- .requires
- .as_ref()
- .map(|s| s.split(',').collect())
- .unwrap_or_default();
+ let name = raw.strip_prefix("VK_").unwrap().to_snake_case();
+
+ let mut requires = Vec::new();
+
+ if let Some(core) = ext.requires_core.as_ref() {
+ let (major, minor) = core.split_once('.').unwrap();
+ requires.push(RequiresOneOf {
+ api_version: Some((major.to_owned(), minor.to_owned())),
+ ..Default::default()
+ });
+ }
+
+ if let Some(req) = ext.requires.as_ref() {
+ requires.extend(req.split(',').map(|mut vk_name| {
+ let mut dependencies = RequiresOneOf::default();
+
+ loop {
+ if let Some(version) = vk_name.strip_prefix("VK_VERSION_") {
+ let (major, minor) = version.split_once('_').unwrap();
+ dependencies.api_version = Some((major.to_owned(), minor.to_owned()));
+ break;
+ } else {
+ let ident = format_ident!(
+ "{}",
+ vk_name.strip_prefix("VK_").unwrap().to_snake_case()
+ );
+ let extension = extensions[vk_name];
+
+ match extension.ext_type.as_deref() {
+ Some("device") => &mut dependencies.device_extensions,
+ Some("instance") => &mut dependencies.instance_extensions,
+ _ => unreachable!(),
+ }
+ .insert(0, ident);
+
+ if let Some(promotedto) = extension.promotedto.as_ref() {
+ vk_name = promotedto.as_str();
+ } else {
+ break;
+ }
+ }
+ }
+
+ dependencies
+ }));
+ }
+
let conflicts_extensions = conflicts_extensions(&ext.name);
- VulkanoExtension {
- member: member.clone(),
+ let mut member = ExtensionsMember {
+ name: format_ident!("{}", name),
+ doc: String::new(),
raw,
- requires_core: (major.parse().unwrap(), minor.parse().unwrap()),
- requires_device_extensions: requires_extensions
- .iter()
- .filter(|&&vk_name| extensions[vk_name].ext_type.as_ref().unwrap() == "device")
- .map(|vk_name| vk_name.strip_prefix("VK_").unwrap().to_snake_case())
- .collect(),
- requires_instance_extensions: requires_extensions
- .iter()
- .filter(|&&vk_name| {
- extensions[vk_name].ext_type.as_ref().unwrap() == "instance"
- })
- .map(|vk_name| vk_name.strip_prefix("VK_").unwrap().to_snake_case())
- .collect(),
required_if_supported: required_if_supported(ext.name.as_str()),
+ requires,
conflicts_device_extensions: conflicts_extensions
.iter()
.filter(|&&vk_name| extensions[vk_name].ext_type.as_ref().unwrap() == "device")
- .map(|vk_name| vk_name.strip_prefix("VK_").unwrap().to_snake_case())
+ .map(|vk_name| {
+ format_ident!("{}", vk_name.strip_prefix("VK_").unwrap().to_snake_case())
+ })
.collect(),
status: ext
.promotedto
- .as_ref()
- .map(|s| s.as_str())
+ .as_deref()
.and_then(|pr| {
if let Some(version) = pr.strip_prefix("VK_VERSION_") {
let (major, minor) = version.split_once('_').unwrap();
Some(ExtensionStatus::Promoted(Replacement::Core((
- major.parse().unwrap(),
- minor.parse().unwrap(),
+ major.to_owned(),
+ minor.to_owned(),
))))
} else {
let member = pr.strip_prefix("VK_").unwrap().to_snake_case();
match extensions[pr].ext_type.as_ref().unwrap().as_str() {
"device" => Some(ExtensionStatus::Promoted(
- Replacement::DeviceExtension(member),
+ Replacement::DeviceExtension(format_ident!("{}", member)),
)),
"instance" => Some(ExtensionStatus::Promoted(
- Replacement::InstanceExtension(member),
+ Replacement::InstanceExtension(format_ident!("{}", member)),
)),
_ => unreachable!(),
}
}
})
.or_else(|| {
- ext.deprecatedby
- .as_ref()
- .map(|s| s.as_str())
- .and_then(|depr| {
- if depr.is_empty() {
- Some(ExtensionStatus::Deprecated(None))
- } else if let Some(version) = depr.strip_prefix("VK_VERSION_") {
- let (major, minor) = version.split_once('_').unwrap();
- Some(ExtensionStatus::Deprecated(Some(Replacement::Core((
- major.parse().unwrap(),
- minor.parse().unwrap(),
- )))))
- } else {
- let member = depr.strip_prefix("VK_").unwrap().to_snake_case();
- match extensions[depr].ext_type.as_ref().unwrap().as_str() {
- "device" => Some(ExtensionStatus::Deprecated(Some(
- Replacement::DeviceExtension(member),
- ))),
- "instance" => Some(ExtensionStatus::Deprecated(Some(
- Replacement::InstanceExtension(member),
- ))),
- _ => unreachable!(),
- }
+ ext.deprecatedby.as_deref().and_then(|depr| {
+ if depr.is_empty() {
+ Some(ExtensionStatus::Deprecated(None))
+ } else if let Some(version) = depr.strip_prefix("VK_VERSION_") {
+ let (major, minor) = version.split_once('_').unwrap();
+ Some(ExtensionStatus::Deprecated(Some(Replacement::Core((
+ major.parse().unwrap(),
+ minor.parse().unwrap(),
+ )))))
+ } else {
+ let member = depr.strip_prefix("VK_").unwrap().to_snake_case();
+ match extensions[depr].ext_type.as_ref().unwrap().as_str() {
+ "device" => Some(ExtensionStatus::Deprecated(Some(
+ Replacement::DeviceExtension(format_ident!("{}", member)),
+ ))),
+ "instance" => Some(ExtensionStatus::Deprecated(Some(
+ Replacement::InstanceExtension(format_ident!("{}", member)),
+ ))),
+ _ => unreachable!(),
}
- })
+ }
+ })
}),
- }
+ };
+ make_doc(&mut member);
+ member
})
.collect()
}
-fn write_device_extensions<W, I>(writer: &mut W, extensions: I)
-where
- W: Write,
- I: IntoIterator<Item = VulkanoExtension>,
-{
- write!(writer, "crate::device::extensions::device_extensions! {{").unwrap();
- for ext in extensions {
- write!(writer, "\n\t{} => {{", ext.member).unwrap();
- write_doc(writer, &ext);
- write!(writer, "\n\t\traw: b\"{}\",", ext.raw).unwrap();
- write!(
- writer,
- "\n\t\trequires_core: crate::Version::V{}_{},",
- ext.requires_core.0, ext.requires_core.1
- )
- .unwrap();
- write!(
- writer,
- "\n\t\trequires_device_extensions: [{}],",
- ext.requires_device_extensions.join(", ")
- )
- .unwrap();
- write!(
- writer,
- "\n\t\trequires_instance_extensions: [{}],",
- ext.requires_instance_extensions.join(", ")
- )
- .unwrap();
- write!(
- writer,
- "\n\t\trequired_if_supported: {},",
- ext.required_if_supported
- )
- .unwrap();
- write!(
- writer,
- "\n\t\tconflicts_device_extensions: [{}],",
- ext.conflicts_device_extensions.join(", ")
- )
- .unwrap();
-
- /*if let Some(promoted_to_core) = ext.promoted_to_core {
- write!(
- writer,
- "\n\t\tpromoted_to_core: Some(Version::V{}_{}),",
- promoted_to_core.0, promoted_to_core.1
- )
- .unwrap();
- } else {
- write!(writer, "\n\t\tpromoted_to_core: None,",).unwrap();
- }*/
-
- write!(writer, "\n\t}},").unwrap();
- }
- write!(writer, "\n}}").unwrap();
-}
-
-fn write_instance_extensions<W, I>(writer: &mut W, extensions: I)
-where
- W: Write,
- I: IntoIterator<Item = VulkanoExtension>,
-{
- write!(
- writer,
- "crate::instance::extensions::instance_extensions! {{"
- )
- .unwrap();
- for ext in extensions {
- write!(writer, "\n\t{} => {{", ext.member).unwrap();
- write_doc(writer, &ext);
- write!(writer, "\n\t\traw: b\"{}\",", ext.raw).unwrap();
- write!(
- writer,
- "\n\t\trequires_core: crate::Version::V{}_{},",
- ext.requires_core.0, ext.requires_core.1
- )
- .unwrap();
- write!(
- writer,
- "\n\t\trequires_instance_extensions: [{}],",
- ext.requires_instance_extensions.join(", ")
- )
- .unwrap();
-
- /*if let Some(promoted_to_core) = ext.promoted_to_core {
- write!(
- writer,
- "\n\t\tpromoted_to_core: Some(crate::Version::V{}_{}),",
- promoted_to_core.0, promoted_to_core.1
- )
- .unwrap();
- } else {
- write!(writer, "\n\t\tpromoted_to_core: None,",).unwrap();
- }*/
-
- write!(writer, "\n\t}},").unwrap();
- }
- write!(writer, "\n}}").unwrap();
-}
-
-fn write_doc<W>(writer: &mut W, ext: &VulkanoExtension)
-where
- W: Write,
-{
- write!(writer, "\n\t\tdoc: \"\n\t\t\t- [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/{}.html)", ext.raw).unwrap();
-
- if ext.requires_core != (1, 0) {
- write!(
- writer,
- "\n\t\t\t- Requires Vulkan {}.{}",
- ext.requires_core.0, ext.requires_core.1
- )
- .unwrap();
- }
-
- if !ext.requires_device_extensions.is_empty() {
- let links: Vec<_> = ext
- .requires_device_extensions
- .iter()
- .map(|ext| format!("[`{}`](crate::device::DeviceExtensions::{0})", ext))
- .collect();
- write!(
- writer,
- "\n\t\t\t- Requires device extension{}: {}",
- if ext.requires_device_extensions.len() > 1 {
- "s"
- } else {
- ""
- },
- links.join(", ")
- )
- .unwrap();
- }
-
- if !ext.requires_instance_extensions.is_empty() {
- let links: Vec<_> = ext
- .requires_instance_extensions
- .iter()
- .map(|ext| format!("[`{}`](crate::instance::InstanceExtensions::{0})", ext))
- .collect();
- write!(
- writer,
- "\n\t\t\t- Requires instance extension{}: {}",
- if ext.requires_instance_extensions.len() > 1 {
- "s"
- } else {
- ""
- },
- links.join(", ")
- )
- .unwrap();
- }
+fn make_doc(ext: &mut ExtensionsMember) {
+ let writer = &mut ext.doc;
+ write!(writer, "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/{}.html)", ext.raw).unwrap();
if ext.required_if_supported {
write!(
writer,
- "\n\t\t\t- Must be enabled if it is supported by the physical device",
- )
- .unwrap();
- }
-
- if !ext.conflicts_device_extensions.is_empty() {
- let links: Vec<_> = ext
- .conflicts_device_extensions
- .iter()
- .map(|ext| format!("[`{}`](crate::device::DeviceExtensions::{0})", ext))
- .collect();
- write!(
- writer,
- "\n\t\t\t- Conflicts with device extension{}: {}",
- if ext.conflicts_device_extensions.len() > 1 {
- "s"
- } else {
- ""
- },
- links.join(", ")
+ "\n- Must be enabled if it is supported by the physical device",
)
.unwrap();
}
@@ -344,7 +697,7 @@ where
if let Some(status) = ext.status.as_ref() {
match status {
ExtensionStatus::Promoted(replacement) => {
- write!(writer, "\n\t\t\t- Promoted to ",).unwrap();
+ write!(writer, "\n- Promoted to ",).unwrap();
match replacement {
Replacement::Core(version) => {
@@ -365,7 +718,7 @@ where
}
}
ExtensionStatus::Deprecated(replacement) => {
- write!(writer, "\n\t\t\t- Deprecated ",).unwrap();
+ write!(writer, "\n- Deprecated ",).unwrap();
match replacement {
Some(Replacement::Core(version)) => {
@@ -395,5 +748,53 @@ where
}
}
- write!(writer, "\n\t\t\",").unwrap();
+ if !ext.requires.is_empty() {
+ write!(writer, "\n- Requires:").unwrap();
+ }
+
+ for require in &ext.requires {
+ let mut line = Vec::new();
+
+ if let Some((major, minor)) = require.api_version.as_ref() {
+ line.push(format!("Vulkan API version {}.{}", major, minor));
+ }
+
+ line.extend(require.device_extensions.iter().map(|ext| {
+ format!(
+ "device extension [`{}`](crate::device::DeviceExtensions::{0})",
+ ext
+ )
+ }));
+ line.extend(require.instance_extensions.iter().map(|ext| {
+ format!(
+ "instance extension [`{}`](crate::instance::InstanceExtensions::{0})",
+ ext
+ )
+ }));
+
+ if line.len() == 1 {
+ write!(writer, "\n - {}", line[0]).unwrap();
+ } else {
+ write!(writer, "\n - One of: {}", line.join(", ")).unwrap();
+ }
+ }
+
+ if !ext.conflicts_device_extensions.is_empty() {
+ let links: Vec<_> = ext
+ .conflicts_device_extensions
+ .iter()
+ .map(|ext| format!("[`{}`](crate::device::DeviceExtensions::{0})", ext))
+ .collect();
+ write!(
+ writer,
+ "\n- Conflicts with device extension{}: {}",
+ if ext.conflicts_device_extensions.len() > 1 {
+ "s"
+ } else {
+ ""
+ },
+ links.join(", ")
+ )
+ .unwrap();
+ }
}
diff --git a/autogen/features.rs b/autogen/features.rs
index 4c49747..ec8105d 100644
--- a/autogen/features.rs
+++ b/autogen/features.rs
@@ -7,13 +7,13 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use heck::SnakeCase;
-use indexmap::IndexMap;
+use super::{write_file, IndexMap, VkRegistryData};
+use ahash::HashMap;
+use heck::ToSnakeCase;
+use proc_macro2::{Ident, TokenStream};
+use quote::{format_ident, quote};
use regex::Regex;
-use std::{
- collections::{hash_map::Entry, HashMap},
- io::Write,
-};
+use std::{collections::hash_map::Entry, fmt::Write as _};
use vk_parse::{Extension, Type, TypeMember, TypeMemberMarkup, TypeSpec};
// This is not included in vk.xml, so it's added here manually
@@ -22,6 +22,7 @@ fn requires_features(name: &str) -> &'static [&'static str] {
"sparseImageInt64Atomics" => &["shaderImageInt64Atomics"],
"sparseImageFloat32Atomics" => &["shaderImageFloat32Atomics"],
"sparseImageFloat32AtomicAdd" => &["shaderImageFloat32AtomicAdd"],
+ "sparseImageFloat32AtomicMinMax" => &["shaderImageFloat32AtomicMinMax"],
_ => &[],
}
}
@@ -45,143 +46,560 @@ fn conflicts_features(name: &str) -> &'static [&'static str] {
}
}
-fn required_by_extensions(name: &str) -> &'static [&'static str] {
+fn required_by_extensions(name: &str) -> &'static [(&'static str, &'static str)] {
match name {
- "shaderDrawParameters" => &["VK_KHR_shader_draw_parameters"],
- "drawIndirectCount" => &["VK_KHR_draw_indirect_count"],
- "samplerMirrorClampToEdge" => &["VK_KHR_sampler_mirror_clamp_to_edge"],
- "descriptorIndexing" => &["VK_EXT_descriptor_indexing"],
- "samplerFilterMinmax" => &["VK_EXT_sampler_filter_minmax"],
- "shaderOutputViewportIndex" => &["VK_EXT_shader_viewport_index_layer"],
- "shaderOutputLayer" => &["VK_EXT_shader_viewport_index_layer"],
+ "shaderDrawParameters" => &[("V1_2", "VK_KHR_shader_draw_parameters")],
+ "drawIndirectCount" => &[("V1_2", "VK_KHR_draw_indirect_count")],
+ "samplerMirrorClampToEdge" => &[("V1_2", "VK_KHR_sampler_mirror_clamp_to_edge")],
+ "descriptorIndexing" => &[("V1_2", "VK_EXT_descriptor_indexing")],
+ "samplerFilterMinmax" => &[("V1_2", "VK_EXT_sampler_filter_minmax")],
+ "shaderOutputViewportIndex" => &[("V1_2", "VK_EXT_shader_viewport_index_layer")],
+ "shaderOutputLayer" => &[("V1_2", "VK_EXT_shader_viewport_index_layer")],
_ => &[],
}
}
-pub fn write<W: Write>(
- writer: &mut W,
- types: &HashMap<&str, (&Type, Vec<&str>)>,
- extensions: &IndexMap<&str, &Extension>,
-) {
- write!(writer, "crate::device::features::features! {{").unwrap();
-
- for feat in make_vulkano_features(types) {
- write!(writer, "\n\t{} => {{", feat.member).unwrap();
- write_doc(writer, &feat);
- write!(writer, "\n\t\tffi_name: {},", feat.ffi_name).unwrap();
- write!(
- writer,
- "\n\t\tffi_members: [{}],",
- feat.ffi_members.join(", ")
- )
- .unwrap();
- write!(
- writer,
- "\n\t\trequires_features: [{}],",
- feat.requires_features.join(", ")
- )
- .unwrap();
- write!(
- writer,
- "\n\t\tconflicts_features: [{}],",
- feat.conflicts_features.join(", ")
- )
- .unwrap();
- write!(
- writer,
- "\n\t\trequired_by_extensions: [{}],",
- feat.required_by_extensions.join(", ")
- )
- .unwrap();
- write!(writer, "\n\t}},").unwrap();
- }
+pub fn write(vk_data: &VkRegistryData) {
+ let features_output = features_output(&features_members(&vk_data.types));
+ let features_ffi_output =
+ features_ffi_output(&features_ffi_members(&vk_data.types, &vk_data.extensions));
+ write_file(
+ "features.rs",
+ format!(
+ "vk.xml header version {}.{}.{}",
+ vk_data.header_version.0, vk_data.header_version.1, vk_data.header_version.2
+ ),
+ quote! {
+ #features_output
+ #features_ffi_output
+ },
+ );
+}
- write!(
- writer,
- "\n}}\n\ncrate::device::features::features_ffi! {{\n\tapi_version,\n\tdevice_extensions,\n\tinstance_extensions,"
- )
- .unwrap();
+#[derive(Clone, Debug)]
+struct FeaturesMember {
+ name: Ident,
+ doc: String,
+ raw: String,
+ ffi_name: Ident,
+ ffi_members: Vec<(Ident, TokenStream)>,
+ requires_features: Vec<Ident>,
+ conflicts_features: Vec<Ident>,
+ required_by_extensions: Vec<(Ident, Ident)>,
+ optional: bool,
+}
- for ffi in make_vulkano_features_ffi(types, extensions) {
- write!(writer, "\n\t{} => {{", ffi.member).unwrap();
- write!(writer, "\n\t\tty: {},", ffi.ty).unwrap();
- write!(
- writer,
- "\n\t\tprovided_by: [{}],",
- ffi.provided_by.join(", ")
- )
- .unwrap();
- write!(writer, "\n\t\tconflicts: [{}],", ffi.conflicts.join(", ")).unwrap();
- write!(writer, "\n\t}},").unwrap();
- }
+fn features_output(members: &[FeaturesMember]) -> TokenStream {
+ let struct_items = members.iter().map(|FeaturesMember { name, doc, .. }| {
+ quote! {
+ #[doc = #doc]
+ pub #name: bool,
+ }
+ });
- write!(writer, "\n}}").unwrap();
-}
+ let check_requirements_items = members.iter().map(
+ |FeaturesMember {
+ name,
+ requires_features,
+ conflicts_features,
+ required_by_extensions,
+ ..
+ }| {
+ let name_string = name.to_string();
+ let requires_features_items = requires_features.iter().map(|feature| {
+ let string = feature.to_string();
+ quote! {
+ if !self.#feature {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: #name_string,
+ restriction: crate::device::FeatureRestriction::RequiresFeature(#string),
+ });
+ }
+ }
+ });
+ let conflicts_features_items = conflicts_features.iter().map(|feature| {
+ let string = feature.to_string();
+ quote! {
+ if self.#feature {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: #name_string,
+ restriction: crate::device::FeatureRestriction::ConflictsFeature(#string),
+ });
+ }
+ }
+ });
+ let required_by_extensions_items =
+ required_by_extensions.iter().map(|(version, extension)| {
+ let string = extension.to_string();
+ quote! {
+ if extensions.#extension && api_version >= crate::Version::#version {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: #name_string,
+ restriction: crate::device::FeatureRestriction::RequiredByExtension(#string),
+ });
+ }
+ }
+ });
+ quote! {
+ if self.#name {
+ if !supported.#name {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: #name_string,
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
-#[derive(Clone, Debug)]
-struct VulkanoFeature {
- member: String,
- vulkan_doc: String,
- ffi_name: String,
- ffi_members: Vec<String>,
- requires_features: Vec<String>,
- conflicts_features: Vec<String>,
- required_by_extensions: Vec<String>,
+ #(#requires_features_items)*
+ #(#conflicts_features_items)*
+ } else {
+ #(#required_by_extensions_items)*
+ }
+ }
+ },
+ );
+
+ let empty_items = members.iter().map(|FeaturesMember { name, .. }| {
+ quote! {
+ #name: false,
+ }
+ });
+
+ let all_items = members.iter().map(|FeaturesMember { name, .. }| {
+ quote! {
+ #name: true,
+ }
+ });
+
+ let intersects_items = members.iter().map(|FeaturesMember { name, .. }| {
+ quote! {
+ (self.#name && other.#name)
+ }
+ });
+
+ let contains_items = members.iter().map(|FeaturesMember { name, .. }| {
+ quote! {
+ (self.#name || !other.#name)
+ }
+ });
+
+ let union_items = members.iter().map(|FeaturesMember { name, .. }| {
+ quote! {
+ #name: self.#name || other.#name,
+ }
+ });
+
+ let intersection_items = members.iter().map(|FeaturesMember { name, .. }| {
+ quote! {
+ #name: self.#name && other.#name,
+ }
+ });
+
+ let difference_items = members.iter().map(|FeaturesMember { name, .. }| {
+ quote! {
+ #name: self.#name && !other.#name,
+ }
+ });
+
+ let symmetric_difference_items = members.iter().map(|FeaturesMember { name, .. }| {
+ quote! {
+ #name: self.#name ^ other.#name,
+ }
+ });
+
+ let debug_items = members.iter().map(|FeaturesMember { name, raw, .. }| {
+ quote! {
+ if self.#name {
+ if !first { write!(f, ", ")? }
+ else { first = false; }
+ f.write_str(#raw)?;
+ }
+ }
+ });
+
+ let arr_items = members.iter().map(|FeaturesMember { name, raw, .. }| {
+ quote! {
+ (#raw, self.#name),
+ }
+ });
+ let arr_len = members.len();
+
+ let write_items = members.iter().map(
+ |FeaturesMember {
+ name,
+ ffi_name,
+ ffi_members,
+ optional,
+ ..
+ }| {
+ if *optional {
+ let ffi_members = ffi_members.iter().map(|(ffi_member, ffi_member_field)| {
+ quote! { self.#ffi_member.as_mut().map(|s| &mut s #ffi_member_field .#ffi_name) }
+ });
+ quote! {
+ if let Some(f) = [
+ #(#ffi_members),*
+ ].into_iter().flatten().next() {
+ *f = features.#name as ash::vk::Bool32;
+ }
+ }
+ } else {
+ let ffi_members = ffi_members.iter().map(|(ffi_member, ffi_member_field)| {
+ quote! { &mut self.#ffi_member #ffi_member_field .#ffi_name }
+ });
+ quote! {
+ if let Some(f) = [
+ #(#ffi_members),*
+ ].into_iter().next() {
+ *f = features.#name as ash::vk::Bool32;
+ }
+ }
+ }
+ },
+ );
+
+ let from_items = members.iter().map(
+ |FeaturesMember {
+ name,
+ ffi_name,
+ ffi_members,
+ optional,
+ ..
+ }| {
+ if *optional {
+ let ffi_members = ffi_members.iter().map(|(ffi_member, ffi_member_field)| {
+ quote! { features_ffi.#ffi_member.map(|s| s #ffi_member_field .#ffi_name) }
+ });
+ quote! {
+ #name: [
+ #(#ffi_members),*
+ ].into_iter().flatten().next().unwrap_or(0) != 0,
+ }
+ } else {
+ let ffi_members = ffi_members.iter().map(|(ffi_member, ffi_member_field)| {
+ quote! { features_ffi.#ffi_member #ffi_member_field .#ffi_name }
+ });
+ quote! {
+ #name: [
+ #(#ffi_members),*
+ ].into_iter().next().unwrap_or(0) != 0,
+ }
+ }
+ },
+ );
+
+ quote! {
+ /// Represents all the features that are available on a physical device or enabled on
+ /// a logical device.
+ ///
+ /// Note that the `robust_buffer_access` is guaranteed to be supported by all Vulkan
+ /// implementations.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use vulkano::device::Features;
+ /// # let physical_device: vulkano::device::physical::PhysicalDevice = return;
+ /// let minimal_features = Features {
+ /// geometry_shader: true,
+ /// ..Features::empty()
+ /// };
+ ///
+ /// let optimal_features = vulkano::device::Features {
+ /// geometry_shader: true,
+ /// tessellation_shader: true,
+ /// ..Features::empty()
+ /// };
+ ///
+ /// if !physical_device.supported_features().is_superset_of(&minimal_features) {
+ /// panic!("The physical device is not good enough for this application.");
+ /// }
+ ///
+ /// assert!(optimal_features.is_superset_of(&minimal_features));
+ /// let features_to_request = optimal_features.intersection(physical_device.supported_features());
+ /// ```
+ #[derive(Copy, Clone, PartialEq, Eq, Hash)]
+ pub struct Features {
+ #(#struct_items)*
+ pub _ne: crate::NonExhaustive,
+ }
+
+ impl Default for Features {
+ #[inline]
+ fn default() -> Self {
+ Self::empty()
+ }
+ }
+
+ impl Features {
+ /// Checks enabled features against the device version, device extensions and each
+ /// other.
+ pub(super) fn check_requirements(
+ &self,
+ supported: &Features,
+ api_version: crate::Version,
+ extensions: &crate::device::DeviceExtensions,
+ ) -> Result<(), crate::device::FeatureRestrictionError> {
+ #(#check_requirements_items)*
+ Ok(())
+ }
+
+ /// Returns an `Features` object with none of the members set.
+ #[inline]
+ pub const fn empty() -> Self {
+ Self {
+ #(#empty_items)*
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+
+ /// Returns an `Features` object with none of the members set.
+ #[deprecated(since = "0.31.0", note = "Use `empty` instead.")]
+ #[inline]
+ pub const fn none() -> Self {
+ Self::empty()
+ }
+
+ /// Returns a `Features` object with all of the members set.
+ #[cfg(test)]
+ pub(crate) const fn all() -> Features {
+ Features {
+ #(#all_items)*
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+
+ /// Returns whether any members are set in both `self` and `other`.
+ #[inline]
+ pub const fn intersects(&self, other: &Self) -> bool {
+ #(#intersects_items)||*
+ }
+
+ /// Returns whether all members in `other` are set in `self`.
+ #[inline]
+ pub const fn contains(&self, other: &Self) -> bool {
+ #(#contains_items)&&*
+ }
+
+ /// Returns whether all members in `other` are set in `self`.
+ #[deprecated(since = "0.31.0", note = "Use `contains` instead.")]
+ #[inline]
+ pub const fn is_superset_of(&self, other: &Self) -> bool {
+ self.contains(other)
+ }
+
+ /// Returns the union of `self` and `other`.
+ #[inline]
+ pub const fn union(&self, other: &Self) -> Self {
+ Self {
+ #(#union_items)*
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+
+ /// Returns the intersection of `self` and `other`.
+ #[inline]
+ pub const fn intersection(&self, other: &Self) -> Self {
+ Self {
+ #(#intersection_items)*
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+
+ /// Returns `self` without the members set in `other`.
+ #[inline]
+ pub const fn difference(&self, other: &Self) -> Self {
+ Self {
+ #(#difference_items)*
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+
+ /// Returns the members set in `self` or `other`, but not both.
+ #[inline]
+ pub const fn symmetric_difference(&self, other: &Self) -> Self {
+ Self {
+ #(#symmetric_difference_items)*
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+ }
+
+ impl std::ops::BitAnd for Features {
+ type Output = Features;
+
+ #[inline]
+ fn bitand(self, rhs: Self) -> Self::Output {
+ self.intersection(&rhs)
+ }
+ }
+
+ impl std::ops::BitAndAssign for Features {
+ #[inline]
+ fn bitand_assign(&mut self, rhs: Self) {
+ *self = self.intersection(&rhs);
+ }
+ }
+
+ impl std::ops::BitOr for Features {
+ type Output = Features;
+
+ #[inline]
+ fn bitor(self, rhs: Self) -> Self::Output {
+ self.union(&rhs)
+ }
+ }
+
+ impl std::ops::BitOrAssign for Features {
+ #[inline]
+ fn bitor_assign(&mut self, rhs: Self) {
+ *self = self.union(&rhs);
+ }
+ }
+
+ impl std::ops::BitXor for Features {
+ type Output = Features;
+
+ #[inline]
+ fn bitxor(self, rhs: Self) -> Self::Output {
+ self.symmetric_difference(&rhs)
+ }
+ }
+
+ impl std::ops::BitXorAssign for Features {
+ #[inline]
+ fn bitxor_assign(&mut self, rhs: Self) {
+ *self = self.symmetric_difference(&rhs);
+ }
+ }
+
+ impl std::ops::Sub for Features {
+ type Output = Features;
+
+ #[inline]
+ fn sub(self, rhs: Self) -> Self::Output {
+ self.difference(&rhs)
+ }
+ }
+
+ impl std::ops::SubAssign for Features {
+ #[inline]
+ fn sub_assign(&mut self, rhs: Self) {
+ *self = self.difference(&rhs);
+ }
+ }
+
+ impl std::fmt::Debug for Features {
+ #[allow(unused_assignments)]
+ fn fmt(&self, f: &mut std::fmt:: Formatter<'_>) -> Result<(), std::fmt::Error> {
+ write!(f, "[")?;
+
+ let mut first = true;
+ #(#debug_items)*
+
+ write!(f, "]")
+ }
+ }
+
+ impl FeaturesFfi {
+ pub(crate) fn write(&mut self, features: &Features) {
+ #(#write_items)*
+ }
+ }
+
+ impl From<&FeaturesFfi> for Features {
+ fn from(features_ffi: &FeaturesFfi) -> Self {
+ Features {
+ #(#from_items)*
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+ }
+
+ impl IntoIterator for Features {
+ type Item = (&'static str, bool);
+ type IntoIter = std::array::IntoIter<Self::Item, #arr_len>;
+
+ #[inline]
+ fn into_iter(self) -> Self::IntoIter {
+ [#(#arr_items)*].into_iter()
+ }
+ }
+ }
}
-fn make_vulkano_features(types: &HashMap<&str, (&Type, Vec<&str>)>) -> Vec<VulkanoFeature> {
- let mut features = HashMap::new();
+fn features_members(types: &HashMap<&str, (&Type, Vec<&str>)>) -> Vec<FeaturesMember> {
+ let mut features = HashMap::default();
std::iter::once(&types["VkPhysicalDeviceFeatures"])
.chain(sorted_structs(types).into_iter())
.filter(|(ty, _)| {
- ty.name.as_ref().map(|s| s.as_str()) == Some("VkPhysicalDeviceFeatures")
- || ty.structextends.as_ref().map(|s| s.as_str())
+ ty.name.as_deref() == Some("VkPhysicalDeviceFeatures")
+ || ty.structextends.as_deref()
== Some("VkPhysicalDeviceFeatures2,VkDeviceCreateInfo")
})
.for_each(|(ty, _)| {
let vulkan_ty_name = ty.name.as_ref().unwrap();
- let ty_name = if vulkan_ty_name == "VkPhysicalDeviceFeatures" {
- "features_vulkan10.features".to_owned()
+ let (ty_name, optional) = if vulkan_ty_name == "VkPhysicalDeviceFeatures" {
+ (
+ (format_ident!("features_vulkan10"), quote! { .features }),
+ false,
+ )
} else {
- ffi_member(vulkan_ty_name)
+ (
+ (format_ident!("{}", ffi_member(vulkan_ty_name)), quote! {}),
+ true,
+ )
};
- members(ty).into_iter().for_each(|name| {
- let member = name.to_snake_case();
- match features.entry(member.clone()) {
+ members(ty).into_iter().for_each(|vulkan_name| {
+ let name = vulkan_name.to_snake_case();
+ match features.entry(name.clone()) {
Entry::Vacant(entry) => {
- let requires_features = requires_features(name);
- let conflicts_features = conflicts_features(name);
- let required_by_extensions = required_by_extensions(name);
-
- entry.insert(VulkanoFeature {
- member: member.clone(),
- vulkan_doc: format!("{}.html#features-{}", vulkan_ty_name, name),
- ffi_name: member,
- ffi_members: vec![ty_name.to_owned()],
+ let requires_features = requires_features(vulkan_name);
+ let conflicts_features = conflicts_features(vulkan_name);
+ let required_by_extensions = required_by_extensions(vulkan_name);
+
+ let mut member = FeaturesMember {
+ name: format_ident!("{}", name),
+ doc: String::new(),
+ ffi_name: format_ident!("{}", name),
+ raw: vulkan_name.to_owned(),
+ ffi_members: vec![ty_name.clone()],
requires_features: requires_features
- .into_iter()
- .map(|&s| s.to_snake_case())
+ .iter()
+ .map(|&s| format_ident!("{}", s.to_snake_case()))
.collect(),
conflicts_features: conflicts_features
- .into_iter()
- .map(|&s| s.to_snake_case())
+ .iter()
+ .map(|&s| format_ident!("{}", s.to_snake_case()))
.collect(),
required_by_extensions: required_by_extensions
.iter()
- .map(|vk_name| vk_name.strip_prefix("VK_").unwrap().to_snake_case())
+ .map(|(version, vk_name)| {
+ let version = format_ident!("{}", version);
+ let name = format_ident!(
+ "{}",
+ vk_name.strip_prefix("VK_").unwrap().to_snake_case()
+ );
+ (version, name)
+ })
.collect(),
- });
+ optional,
+ };
+ make_doc(&mut member, vulkan_ty_name);
+ entry.insert(member);
}
Entry::Occupied(entry) => {
- entry.into_mut().ffi_members.push(ty_name.to_owned());
+ entry.into_mut().ffi_members.push(ty_name.clone());
}
};
});
});
- let mut names: Vec<_> = features.values().map(|feat| feat.member.clone()).collect();
+ let mut names: Vec<_> = features
+ .values()
+ .map(|feat| feat.name.to_string())
+ .collect();
names.sort_unstable();
names
.into_iter()
@@ -189,11 +607,15 @@ fn make_vulkano_features(types: &HashMap<&str, (&Type, Vec<&str>)>) -> Vec<Vulka
.collect()
}
-fn write_doc<W>(writer: &mut W, feat: &VulkanoFeature)
-where
- W: Write,
-{
- write!(writer, "\n\t\tdoc: \"\n\t\t\t- [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/{})", feat.vulkan_doc).unwrap();
+fn make_doc(feat: &mut FeaturesMember, vulkan_ty_name: &str) {
+ let writer = &mut feat.doc;
+ write!(
+ writer,
+ "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/{}.html#features-{})",
+ vulkan_ty_name,
+ feat.raw
+ )
+ .unwrap();
if !feat.requires_features.is_empty() {
let links: Vec<_> = feat
@@ -203,7 +625,7 @@ where
.collect();
write!(
writer,
- "\n\t\t\t- Requires feature{}: {}",
+ "\n- Requires feature{}: {}",
if feat.requires_features.len() > 1 {
"s"
} else {
@@ -218,11 +640,11 @@ where
let links: Vec<_> = feat
.required_by_extensions
.iter()
- .map(|ext| format!("[`{}`](crate::device::DeviceExtensions::{0})", ext))
+ .map(|(_, ext)| format!("[`{}`](crate::device::DeviceExtensions::{0})", ext))
.collect();
write!(
writer,
- "\n\t\t\t- Required by device extension{}: {}",
+ "\n- Required by device extension{}: {}",
if feat.required_by_extensions.len() > 1 {
"s"
} else {
@@ -241,7 +663,7 @@ where
.collect();
write!(
writer,
- "\n\t\t\t- Conflicts with feature{}: {}",
+ "\n- Conflicts with feature{}: {}",
if feat.conflicts_features.len() > 1 {
"s"
} else {
@@ -251,41 +673,99 @@ where
)
.unwrap();
}
-
- write!(writer, "\n\t\t\",").unwrap();
}
#[derive(Clone, Debug)]
-struct VulkanoFeatureFfi {
- member: String,
- ty: String,
- provided_by: Vec<String>,
- conflicts: Vec<String>,
+struct FeaturesFfiMember {
+ name: Ident,
+ ty: Ident,
+ provided_by: Vec<TokenStream>,
+ conflicts: Vec<Ident>,
+}
+
+fn features_ffi_output(members: &[FeaturesFfiMember]) -> TokenStream {
+ let struct_items = members.iter().map(|FeaturesFfiMember { name, ty, .. }| {
+ quote! { #name: Option<ash::vk::#ty>, }
+ });
+
+ let make_chain_items = members.iter().map(
+ |FeaturesFfiMember {
+ name,
+ provided_by,
+ conflicts,
+ ..
+ }| {
+ quote! {
+ if [#(#provided_by),*].into_iter().any(|x| x) &&
+ [#(self.#conflicts.is_none()),*].into_iter().all(|x| x) {
+ self.#name = Some(Default::default());
+ let member = self.#name.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ }
+ },
+ );
+
+ quote! {
+ #[derive(Default)]
+ pub(crate) struct FeaturesFfi {
+ features_vulkan10: ash::vk::PhysicalDeviceFeatures2KHR,
+ #(#struct_items)*
+ }
+
+ impl FeaturesFfi {
+ pub(crate) fn make_chain(
+ &mut self,
+ api_version: crate::Version,
+ device_extensions: &crate::device::DeviceExtensions,
+ _instance_extensions: &crate::instance::InstanceExtensions,
+ ) {
+ self.features_vulkan10 = Default::default();
+ let head = &mut self.features_vulkan10;
+ #(#make_chain_items)*
+ }
+
+ pub(crate) fn head_as_ref(&self) -> &ash::vk::PhysicalDeviceFeatures2KHR {
+ &self.features_vulkan10
+ }
+
+ pub(crate) fn head_as_mut(&mut self) -> &mut ash::vk::PhysicalDeviceFeatures2KHR {
+ &mut self.features_vulkan10
+ }
+ }
+ }
}
-fn make_vulkano_features_ffi<'a>(
+fn features_ffi_members<'a>(
types: &'a HashMap<&str, (&Type, Vec<&str>)>,
extensions: &IndexMap<&'a str, &Extension>,
-) -> Vec<VulkanoFeatureFfi> {
- let mut feature_included_in: HashMap<&str, Vec<&str>> = HashMap::new();
+) -> Vec<FeaturesFfiMember> {
+ let mut feature_included_in: HashMap<&str, Vec<&str>> = HashMap::default();
sorted_structs(types)
.into_iter()
.map(|(ty, provided_by)| {
- let name = ty.name.as_ref().unwrap();
+ let ty_name = ty.name.as_ref().unwrap();
let provided_by = provided_by
.iter()
.map(|provided_by| {
if let Some(version) = provided_by.strip_prefix("VK_VERSION_") {
- format!("api_version >= crate::Version::V{}", version)
+ let version = format_ident!("V{}", version);
+ quote! { api_version >= crate::Version::#version }
} else {
- format!(
- "{}_extensions.{}",
- extensions[provided_by].ext_type.as_ref().unwrap().as_str(),
+ let member = format_ident!(
+ "{}_extensions",
+ extensions[provided_by].ext_type.as_ref().unwrap().as_str()
+ );
+ let name = format_ident!(
+ "{}",
provided_by
.strip_prefix("VK_")
.unwrap()
- .to_ascii_lowercase()
- )
+ .to_ascii_lowercase(),
+ );
+
+ quote! { #member.#name }
}
})
.collect();
@@ -294,7 +774,7 @@ fn make_vulkano_features_ffi<'a>(
.into_iter()
.for_each(|member| match feature_included_in.entry(member) {
Entry::Vacant(entry) => {
- entry.insert(vec![name]);
+ entry.insert(vec![ty_name]);
}
Entry::Occupied(entry) => {
let conflicters = entry.into_mut();
@@ -304,15 +784,18 @@ fn make_vulkano_features_ffi<'a>(
conflicts.push(conflicter);
}
});
- conflicters.push(name);
+ conflicters.push(ty_name);
}
});
- VulkanoFeatureFfi {
- member: ffi_member(name),
- ty: name.strip_prefix("Vk").unwrap().to_owned(),
+ FeaturesFfiMember {
+ name: format_ident!("{}", ffi_member(ty_name)),
+ ty: format_ident!("{}", ty_name.strip_prefix("Vk").unwrap()),
provided_by,
- conflicts,
+ conflicts: conflicts
+ .into_iter()
+ .map(|s| format_ident!("{}", s))
+ .collect(),
}
})
.collect()
@@ -324,8 +807,7 @@ fn sorted_structs<'a>(
let mut structs: Vec<_> = types
.values()
.filter(|(ty, _)| {
- ty.structextends.as_ref().map(|s| s.as_str())
- == Some("VkPhysicalDeviceFeatures2,VkDeviceCreateInfo")
+ ty.structextends.as_deref() == Some("VkPhysicalDeviceFeatures2,VkDeviceCreateInfo")
})
.collect();
let regex = Regex::new(r"^VkPhysicalDeviceVulkan\d+Features$").unwrap();
@@ -339,17 +821,9 @@ fn sorted_structs<'a>(
{
let (major, minor) = version.split_once('_').unwrap();
major.parse::<i32>().unwrap() << 22 | minor.parse::<i32>().unwrap() << 12
- } else if provided_by
- .iter()
- .find(|s| s.starts_with("VK_KHR_"))
- .is_some()
- {
+ } else if provided_by.iter().any(|s| s.starts_with("VK_KHR_")) {
i32::MAX - 2
- } else if provided_by
- .iter()
- .find(|s| s.starts_with("VK_EXT_"))
- .is_some()
- {
+ } else if provided_by.iter().any(|s| s.starts_with("VK_EXT_")) {
i32::MAX - 1
} else {
i32::MAX
diff --git a/autogen/fns.rs b/autogen/fns.rs
index da25938..0e53935 100644
--- a/autogen/fns.rs
+++ b/autogen/fns.rs
@@ -7,41 +7,100 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use heck::{CamelCase, SnakeCase};
-use indexmap::IndexMap;
-use std::io::Write;
+use super::{write_file, IndexMap, VkRegistryData};
+use heck::{ToSnakeCase, ToUpperCamelCase};
+use proc_macro2::{Ident, TokenStream};
+use quote::{format_ident, quote};
use vk_parse::{Extension, ExtensionChild, InterfaceItem};
-pub fn write<W: Write>(writer: &mut W, extensions: &IndexMap<&str, &Extension>) {
- write_fns(writer, std::iter::empty(), "Entry");
- write!(writer, "\n\n").unwrap();
- write_fns(
- writer,
- make_vulkano_extension_fns("instance", &extensions),
+pub fn write(vk_data: &VkRegistryData) {
+ let entry_fns_output = fns_output(
+ &[],
+ "Entry",
+ "Raw Vulkan global entry point-level functions.\n\nTo use these, you need to include the Ash crate, using the same version Vulkano uses.",
+ );
+ let instance_fns_output = fns_output(
+ &instance_extension_fns_members(&vk_data.extensions),
"Instance",
+ "Raw Vulkan instance-level functions.\n\nTo use these, you need to include the Ash crate, using the same version Vulkano uses.",
);
- write!(writer, "\n\n").unwrap();
- write_fns(
- writer,
- make_vulkano_extension_fns("device", &extensions),
+ let device_fns_output = fns_output(
+ &device_extension_fns_members(&vk_data.extensions),
"Device",
+ "Raw Vulkan device-level functions.\n\nTo use these, you need to include the Ash crate, using the same version Vulkano uses.",
+ );
+ write_file(
+ "fns.rs",
+ format!(
+ "vk.xml header version {}.{}.{}",
+ vk_data.header_version.0, vk_data.header_version.1, vk_data.header_version.2
+ ),
+ quote! {
+ #entry_fns_output
+ #instance_fns_output
+ #device_fns_output
+ },
);
}
#[derive(Clone, Debug)]
-struct VulkanoFns {
- member: String,
- fn_struct: String,
+struct FnsMember {
+ name: Ident,
+ fn_struct: Ident,
+}
+
+fn fns_output(extension_members: &[FnsMember], fns_level: &str, doc: &str) -> TokenStream {
+ let struct_name = format_ident!("{}Functions", fns_level);
+ let members = ["1_0", "1_1", "1_2", "1_3"]
+ .into_iter()
+ .map(|version| FnsMember {
+ name: format_ident!("v{}", version),
+ fn_struct: format_ident!("{}FnV{}", fns_level, version),
+ })
+ .chain(extension_members.iter().cloned())
+ .collect::<Vec<_>>();
+
+ let struct_items = members.iter().map(|FnsMember { name, fn_struct }| {
+ quote! { pub #name: ash::vk::#fn_struct, }
+ });
+
+ let load_items = members.iter().map(|FnsMember { name, fn_struct }| {
+ quote! { #name: ash::vk::#fn_struct::load(&mut load_fn), }
+ });
+
+ quote! {
+ #[doc = #doc]
+ #[allow(missing_docs)]
+ pub struct #struct_name {
+ #(#struct_items)*
+ pub _ne: crate::NonExhaustive,
+ }
+
+ impl #struct_name {
+ pub(crate) fn load<F>(mut load_fn: F) -> #struct_name
+ where F: FnMut(&CStr) -> *const c_void
+ {
+ #struct_name {
+ #(#load_items)*
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+ }
+
+ impl std::fmt::Debug for #struct_name {
+ #[inline]
+ fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
+ Ok(())
+ }
+ }
+ }
}
-fn make_vulkano_extension_fns(
- ty: &str,
- extensions: &IndexMap<&str, &Extension>,
-) -> Vec<VulkanoFns> {
+fn device_extension_fns_members(extensions: &IndexMap<&str, &Extension>) -> Vec<FnsMember> {
extensions
.values()
- .filter(|ext| ext.ext_type.as_ref().unwrap() == ty)
- // Filter only extensions that have functions
+ // Include any device extensions that have functions.
+ .filter(|ext| ext.ext_type.as_ref().unwrap() == "device")
.filter(|ext| {
ext.children.iter().any(|ch| {
if let ExtensionChild::Require { items, .. } = ch {
@@ -54,26 +113,48 @@ fn make_vulkano_extension_fns(
})
})
.map(|ext| {
- let member = ext.name.strip_prefix("VK_").unwrap().to_snake_case();
- let fn_struct = member.to_camel_case() + "Fn";
- VulkanoFns { member, fn_struct }
+ let base = ext.name.strip_prefix("VK_").unwrap().to_snake_case();
+ let name = format_ident!("{}", base);
+ let fn_struct = format_ident!("{}Fn", base.to_upper_camel_case());
+ FnsMember { name, fn_struct }
})
.collect()
}
-fn write_fns<W, I>(writer: &mut W, extension_fns: I, ty: &str)
-where
- W: Write,
- I: IntoIterator<Item = VulkanoFns>,
-{
- write!(writer, "crate::fns::fns!({}Functions, {{", ty).unwrap();
-
- for version in std::array::IntoIter::new(["1_0", "1_1", "1_2"]) {
- write!(writer, "\n\tv{} => {}FnV{0},", version, ty).unwrap();
- }
-
- for ext in extension_fns {
- write!(writer, "\n\t{} => {},", ext.member, ext.fn_struct).unwrap();
- }
- write!(writer, "\n}});").unwrap();
+fn instance_extension_fns_members(extensions: &IndexMap<&str, &Extension>) -> Vec<FnsMember> {
+ extensions
+ .values()
+ .filter(|ext| {
+ match ext.ext_type.as_deref().unwrap() {
+ // Include any instance extensions that have functions.
+ "instance" => ext.children.iter().any(|ch| {
+ if let ExtensionChild::Require { items, .. } = ch {
+ items
+ .iter()
+ .any(|i| matches!(i, InterfaceItem::Command { .. }))
+ } else {
+ false
+ }
+ }),
+ // Include device extensions that have functions containing "PhysicalDevice".
+ // Note: this test might not be sufficient in the long run...
+ "device" => ext.children.iter().any(|ch| {
+ if let ExtensionChild::Require { items, .. } = ch {
+ items
+ .iter()
+ .any(|i| matches!(i, InterfaceItem::Command { name, .. } if name.contains("PhysicalDevice")))
+ } else {
+ false
+ }
+ }),
+ _ => unreachable!(),
+ }
+ })
+ .map(|ext| {
+ let base = ext.name.strip_prefix("VK_").unwrap().to_snake_case();
+ let name = format_ident!("{}", base);
+ let fn_struct = format_ident!("{}Fn", base.to_upper_camel_case());
+ FnsMember { name, fn_struct }
+ })
+ .collect()
}
diff --git a/autogen/formats.rs b/autogen/formats.rs
new file mode 100644
index 0000000..3e1f399
--- /dev/null
+++ b/autogen/formats.rs
@@ -0,0 +1,891 @@
+// Copyright (c) 2021 The Vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use super::{extensions::RequiresOneOf, write_file, IndexMap, VkRegistryData};
+use heck::ToSnakeCase;
+use once_cell::sync::Lazy;
+use proc_macro2::{Ident, Literal, TokenStream};
+use quote::{format_ident, quote};
+use regex::Regex;
+use vk_parse::{
+ Enum, EnumSpec, Extension, ExtensionChild, Feature, Format, FormatChild, InterfaceItem,
+};
+
+pub fn write(vk_data: &VkRegistryData) {
+ write_file(
+ "formats.rs",
+ format!(
+ "vk.xml header version {}.{}.{}",
+ vk_data.header_version.0, vk_data.header_version.1, vk_data.header_version.2
+ ),
+ formats_output(&formats_members(
+ &vk_data.formats,
+ &vk_data.features,
+ &vk_data.extensions,
+ )),
+ );
+}
+
+#[derive(Clone, Debug)]
+struct FormatMember {
+ name: Ident,
+ ffi_name: Ident,
+ requires: Vec<RequiresOneOf>,
+
+ aspect_color: bool,
+ aspect_depth: bool,
+ aspect_stencil: bool,
+ aspect_plane0: bool,
+ aspect_plane1: bool,
+ aspect_plane2: bool,
+
+ block_extent: [u32; 3],
+ block_size: Option<u64>,
+ compatibility: Ident,
+ components: [u8; 4],
+ compression: Option<Ident>,
+ planes: Vec<Ident>,
+ texels_per_block: u8,
+ type_color: Option<Ident>,
+ type_depth: Option<Ident>,
+ type_stencil: Option<Ident>,
+ ycbcr_chroma_sampling: Option<Ident>,
+
+ type_std_array: Option<TokenStream>,
+ type_cgmath: Option<TokenStream>,
+ type_nalgebra: Option<TokenStream>,
+}
+
+fn formats_output(members: &[FormatMember]) -> TokenStream {
+ let enum_items = members.iter().map(|FormatMember { name, ffi_name, .. }| {
+ quote! { #name = ash::vk::Format::#ffi_name.as_raw(), }
+ });
+ let aspects_items = members.iter().map(
+ |FormatMember {
+ name,
+ aspect_color,
+ aspect_depth,
+ aspect_stencil,
+ aspect_plane0,
+ aspect_plane1,
+ aspect_plane2,
+ ..
+ }| {
+ let aspect_items = [
+ aspect_color.then(|| quote! { crate::image::ImageAspects::COLOR }),
+ aspect_depth.then(|| quote! { crate::image::ImageAspects::DEPTH }),
+ aspect_stencil.then(|| quote! { crate::image::ImageAspects::STENCIL }),
+ aspect_plane0.then(|| quote! { crate::image::ImageAspects::PLANE_0 }),
+ aspect_plane1.then(|| quote! { crate::image::ImageAspects::PLANE_1 }),
+ aspect_plane2.then(|| quote! { crate::image::ImageAspects::PLANE_2 }),
+ ]
+ .into_iter()
+ .flatten();
+
+ quote! {
+ Self::#name => #(#aspect_items)|*,
+ }
+ },
+ );
+ let block_extent_items = members.iter().filter_map(
+ |FormatMember {
+ name,
+ block_extent: [x, y, z],
+ ..
+ }| {
+ if *x == 1 && *y == 1 && *z == 1 {
+ None
+ } else {
+ let x = Literal::u32_unsuffixed(*x);
+ let y = Literal::u32_unsuffixed(*y);
+ let z = Literal::u32_unsuffixed(*z);
+ Some(quote! { Self::#name => [#x, #y, #z], })
+ }
+ },
+ );
+ let block_size_items = members.iter().filter_map(
+ |FormatMember {
+ name, block_size, ..
+ }| {
+ block_size.as_ref().map(|size| {
+ let size = Literal::u64_unsuffixed(*size);
+ quote! { Self::#name => Some(#size), }
+ })
+ },
+ );
+ let compatibility_items = members.iter().map(
+ |FormatMember {
+ name,
+ compatibility,
+ ..
+ }| {
+ quote! {
+ Self::#name => &FormatCompatibilityInner::#compatibility,
+ }
+ },
+ );
+ let components_items = members.iter().map(
+ |FormatMember {
+ name, components, ..
+ }| {
+ let components = components.iter().map(|c| Literal::u8_unsuffixed(*c));
+ quote! {
+ Self::#name => [#(#components),*],
+ }
+ },
+ );
+ let compression_items = members.iter().filter_map(
+ |FormatMember {
+ name, compression, ..
+ }| {
+ compression
+ .as_ref()
+ .map(|x| quote! { Self::#name => Some(CompressionType::#x), })
+ },
+ );
+ let planes_items = members
+ .iter()
+ .filter_map(|FormatMember { name, planes, .. }| {
+ if planes.is_empty() {
+ None
+ } else {
+ Some(quote! { Self::#name => &[#(Self::#planes),*], })
+ }
+ });
+ let texels_per_block_items = members.iter().filter_map(
+ |FormatMember {
+ name,
+ texels_per_block,
+ ..
+ }| {
+ (*texels_per_block != 1).then(|| {
+ let texels_per_block = Literal::u8_unsuffixed(*texels_per_block);
+ quote! { Self::#name => #texels_per_block, }
+ })
+ },
+ );
+ let type_color_items = members.iter().filter_map(
+ |FormatMember {
+ name, type_color, ..
+ }| {
+ type_color
+ .as_ref()
+ .map(|ty| quote! { Self::#name => Some(NumericType::#ty), })
+ },
+ );
+ let type_depth_items = members.iter().filter_map(
+ |FormatMember {
+ name, type_depth, ..
+ }| {
+ type_depth
+ .as_ref()
+ .map(|ty| quote! { Self::#name => Some(NumericType::#ty), })
+ },
+ );
+ let type_stencil_items = members.iter().filter_map(
+ |FormatMember {
+ name, type_stencil, ..
+ }| {
+ type_stencil
+ .as_ref()
+ .map(|ty| quote! { Self::#name => Some(NumericType::#ty), })
+ },
+ );
+ let ycbcr_chroma_sampling_items = members.iter().filter_map(
+ |FormatMember {
+ name,
+ ycbcr_chroma_sampling,
+ ..
+ }| {
+ ycbcr_chroma_sampling
+ .as_ref()
+ .map(|ty| quote! { Self::#name => Some(ChromaSampling::#ty), })
+ },
+ );
+ let try_from_items = members.iter().map(|FormatMember { name, ffi_name, .. }| {
+ quote! { ash::vk::Format::#ffi_name => Ok(Self::#name), }
+ });
+
+ let type_for_format_items = members.iter().filter_map(
+ |FormatMember {
+ name,
+ type_std_array,
+ ..
+ }| {
+ type_std_array.as_ref().map(|ty| {
+ quote! { (#name) => { #ty }; }
+ })
+ },
+ );
+ let type_for_format_cgmath_items = members.iter().filter_map(
+ |FormatMember {
+ name,
+ type_std_array,
+ type_cgmath,
+ ..
+ }| {
+ (type_cgmath.as_ref().or(type_std_array.as_ref())).map(|ty| {
+ quote! { (cgmath, #name) => { #ty }; }
+ })
+ },
+ );
+ let type_for_format_nalgebra_items = members.iter().filter_map(
+ |FormatMember {
+ name,
+ type_std_array,
+ type_nalgebra,
+ ..
+ }| {
+ (type_nalgebra.as_ref().or(type_std_array.as_ref())).map(|ty| {
+ quote! { (nalgebra, #name) => { #ty }; }
+ })
+ },
+ );
+
+ let validate_device_items = members.iter().map(|FormatMember { name, requires, .. }| {
+ let requires_items = requires.iter().map(
+ |RequiresOneOf {
+ api_version,
+ device_extensions,
+ instance_extensions,
+ }| {
+ let condition_items = (api_version.iter().map(|(major, minor)| {
+ let version = format_ident!("V{}_{}", major, minor);
+ quote! { device.api_version() >= crate::Version::#version }
+ }))
+ .chain(device_extensions.iter().map(|ext| {
+ quote! { device.enabled_extensions().#ext }
+ }))
+ .chain(instance_extensions.iter().map(|ext| {
+ quote! { device.instance().enabled_extensions().#ext }
+ }));
+ let required_for = format!("`Format::{}`", name);
+ let requires_one_of_items = (api_version.iter().map(|(major, minor)| {
+ let version = format_ident!("V{}_{}", major, minor);
+ quote! { api_version: Some(crate::Version::#version), }
+ }))
+ .chain((!device_extensions.is_empty()).then(|| {
+ let items = device_extensions.iter().map(|ext| ext.to_string());
+ quote! { device_extensions: &[#(#items),*], }
+ }))
+ .chain((!instance_extensions.is_empty()).then(|| {
+ let items = instance_extensions.iter().map(|ext| ext.to_string());
+ quote! { instance_extensions: &[#(#items),*], }
+ }));
+
+ quote! {
+ if !(#(#condition_items)||*) {
+ return Err(crate::RequirementNotMet {
+ required_for: #required_for,
+ requires_one_of: crate::RequiresOneOf {
+ #(#requires_one_of_items)*
+ ..Default::default()
+ },
+ });
+ }
+ }
+ },
+ );
+
+ quote! {
+ Self::#name => {
+ #(#requires_items)*
+ }
+ }
+ });
+ let validate_physical_device_items =
+ members.iter().map(|FormatMember { name, requires, .. }| {
+ let requires_items = requires.iter().map(
+ |RequiresOneOf {
+ api_version,
+ device_extensions,
+ instance_extensions,
+ }| {
+ let condition_items = (api_version.iter().map(|(major, minor)| {
+ let version = format_ident!("V{}_{}", major, minor);
+ quote! { physical_device.api_version() >= crate::Version::#version }
+ }))
+ .chain(device_extensions.iter().map(|ext| {
+ quote! { physical_device.supported_extensions().#ext }
+ }))
+ .chain(instance_extensions.iter().map(|ext| {
+ quote! { physical_device.instance().enabled_extensions().#ext }
+ }));
+ let required_for = format!("`Format::{}`", name);
+ let requires_one_of_items = (api_version.iter().map(|(major, minor)| {
+ let version = format_ident!("V{}_{}", major, minor);
+ quote! { api_version: Some(crate::Version::#version), }
+ }))
+ .chain((!device_extensions.is_empty()).then(|| {
+ let items = device_extensions.iter().map(|ext| ext.to_string());
+ quote! { device_extensions: &[#(#items),*], }
+ }))
+ .chain((!instance_extensions.is_empty()).then(|| {
+ let items = instance_extensions.iter().map(|ext| ext.to_string());
+ quote! { instance_extensions: &[#(#items),*], }
+ }));
+
+ quote! {
+ if !(#(#condition_items)||*) {
+ return Err(crate::RequirementNotMet {
+ required_for: #required_for,
+ requires_one_of: crate::RequiresOneOf {
+ #(#requires_one_of_items)*
+ ..Default::default()
+ },
+ });
+ }
+ }
+ },
+ );
+
+ quote! {
+ Self::#name => {
+ #(#requires_items)*
+ }
+ }
+ });
+
+ quote! {
+ /// An enumeration of all the possible formats.
+ #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+ #[repr(i32)]
+ #[allow(non_camel_case_types)]
+ #[non_exhaustive]
+ pub enum Format {
+ #(#enum_items)*
+ }
+
+ impl Format {
+ /// Returns the aspects that images of this format have.
+ pub fn aspects(self) -> ImageAspects {
+ match self {
+ #(#aspects_items)*
+ }
+ }
+
+ /// Returns the extent in texels (horizontally and vertically) of a single texel
+ /// block of this format. A texel block is a rectangle of pixels that is represented by
+ /// a single element of this format. It is also the minimum granularity of the extent of
+ /// an image; images must always have an extent that's a multiple of the block extent.
+ ///
+ /// For normal formats, the block extent is [1, 1, 1], meaning that each element of the
+ /// format represents one texel. Block-compressed formats encode multiple texels into
+ /// a single element. The 422 and 420 YCbCr formats have a block extent of [2, 1, 1] and
+ /// [2, 2, 1] respectively, as the red and blue components are shared across multiple
+ /// texels.
+ pub fn block_extent(self) -> [u32; 3] {
+ match self {
+ #(#block_extent_items)*
+ _ => [1, 1, 1],
+ }
+ }
+
+ /// Returns the size in bytes of a single texel block of this format. Returns `None`
+ /// if the texel block size is not well-defined for this format.
+ ///
+ /// For regular formats, this is the size of a single texel, but for more specialized
+ /// formats this may be the size of multiple texels.
+ ///
+ /// Depth/stencil formats are considered to have an opaque memory representation, and do
+ /// not have a well-defined size. Multi-planar formats store the color components
+ /// disjointly in memory, and therefore do not have a well-defined size for all
+ /// components as a whole. The individual planes do have a well-defined size.
+ pub fn block_size(self) -> Option<DeviceSize> {
+ match self {
+ #(#block_size_items)*
+ _ => None,
+ }
+ }
+
+ /// Returns the an opaque object representing the compatibility class of the format.
+ /// This can be used to determine whether two formats are compatible for the purposes
+ /// of certain Vulkan operations, such as image copying.
+ pub fn compatibility(self) -> FormatCompatibility {
+ FormatCompatibility(match self {
+ #(#compatibility_items)*
+ })
+ }
+
+ /// Returns the number of bits per texel block that each component (R, G, B, A) is
+ /// represented with. Components that are not present in the format have 0 bits.
+ ///
+ /// For depth/stencil formats, the depth component is the first, stencil the second. For
+ /// multi-planar formats, this is the number of bits across all planes.
+ ///
+ /// For block-compressed formats, the number of bits in individual components is not
+ /// well-defined, and the return value is merely binary: 1 indicates a component
+ /// that is present in the format, 0 indicates one that is absent.
+ pub fn components(self) -> [u8; 4] {
+ match self {
+ #(#components_items)*
+ }
+ }
+
+ /// Returns the block compression scheme used for this format, if any. Returns `None` if
+ /// the format does not use compression.
+ pub fn compression(self) -> Option<CompressionType> {
+ match self {
+ #(#compression_items)*
+ _ => None,
+ }
+ }
+
+ /// For multi-planar formats, returns a slice of length 2 or 3, containing the
+ /// equivalent regular format of each plane.
+ ///
+ /// For non-planar formats, returns the empty slice.
+ pub fn planes(self) -> &'static [Self] {
+ match self {
+ #(#planes_items)*
+ _ => &[],
+ }
+ }
+
+ /// Returns the number of texels for a single texel block. For most formats, this is
+ /// the product of the `block_extent` elements, but for some it differs.
+ pub fn texels_per_block(self) -> u8 {
+ match self {
+ #(#texels_per_block_items)*
+ _ => 1,
+ }
+ }
+
+ /// Returns the numeric data type of the color aspect of this format. Returns `None`
+ /// for depth/stencil formats.
+ pub fn type_color(self) -> Option<NumericType> {
+ match self {
+ #(#type_color_items)*
+ _ => None,
+ }
+ }
+
+ /// Returns the numeric data type of the depth aspect of this format. Returns `None`
+ /// color and stencil-only formats.
+ pub fn type_depth(self) -> Option<NumericType> {
+ match self {
+ #(#type_depth_items)*
+ _ => None,
+ }
+ }
+
+ /// Returns the numeric data type of the stencil aspect of this format. Returns `None`
+ /// for color and depth-only formats.
+ pub fn type_stencil(self) -> Option<NumericType> {
+ match self {
+ #(#type_stencil_items)*
+ _ => None,
+ }
+ }
+
+ /// For YCbCr (YUV) formats, returns the way in which the chroma components are
+ /// represented. Returns `None` for non-YCbCr formats.
+ ///
+ /// If an image view is created for one of the formats for which this function returns
+ /// `Some`, with the `color` aspect selected, then the view and any samplers that sample
+ /// it must be created with an attached sampler YCbCr conversion object.
+ pub fn ycbcr_chroma_sampling(self) -> Option<ChromaSampling> {
+ match self {
+ #(#ycbcr_chroma_sampling_items)*
+ _ => None,
+ }
+ }
+
+ #[allow(dead_code)]
+ pub(crate) fn validate_device(
+ self,
+ #[allow(unused_variables)] device: &crate::device::Device,
+ ) -> Result<(), crate::RequirementNotMet> {
+ match self {
+ #(#validate_device_items)*
+ }
+
+ Ok(())
+ }
+
+ #[allow(dead_code)]
+ pub(crate) fn validate_physical_device(
+ self,
+ #[allow(unused_variables)] physical_device: &crate::device::physical::PhysicalDevice,
+ ) -> Result<(), crate::RequirementNotMet> {
+ match self {
+ #(#validate_physical_device_items)*
+ }
+
+ Ok(())
+ }
+ }
+
+ impl TryFrom<ash::vk::Format> for Format {
+ type Error = ();
+
+ fn try_from(val: ash::vk::Format) -> Result<Format, ()> {
+ match val {
+ #(#try_from_items)*
+ _ => Err(()),
+ }
+ }
+ }
+
+ /// Converts a format enum identifier to a standard Rust type that is suitable for
+ /// representing the format in a buffer or image.
+ ///
+ /// This macro returns one possible suitable representation, but there are usually other
+ /// possibilities for a given format. A compile error occurs for formats that have no
+ /// well-defined size (the `size` method returns `None`).
+ ///
+ /// - For regular unpacked formats with one component, this returns a single floating point,
+ /// signed or unsigned integer with the appropriate number of bits. For formats with
+ /// multiple components, an array is returned.
+ /// - For packed formats, this returns an unsigned integer with the size of the packed
+ /// element. For multi-packed formats (such as `2PACK16`), an array is returned.
+ /// - For compressed formats, this returns `[u8; N]` where N is the size of a block.
+ ///
+ /// Note: for 16-bit floating point values, you need to import the [`half::f16`] type.
+ ///
+ /// # Examples
+ ///
+ /// For arrays:
+ ///
+ /// ```
+ /// # use vulkano::type_for_format;
+ /// let pixel: type_for_format!(R32G32B32A32_SFLOAT);
+ /// pixel = [1.0f32, 0.0, 0.0, 1.0];
+ /// ```
+ ///
+ /// For [`cgmath`]:
+ ///
+ /// ```
+ /// # use vulkano::type_for_format;
+ /// let pixel: type_for_format!(cgmath, R32G32B32A32_SFLOAT);
+ /// pixel = cgmath::Vector4::new(1.0f32, 0.0, 0.0, 1.0);
+ /// ```
+ ///
+ /// For [`nalgebra`]:
+ ///
+ /// ```
+ /// # use vulkano::type_for_format;
+ /// let pixel: type_for_format!(nalgebra, R32G32B32A32_SFLOAT);
+ /// pixel = nalgebra::vector![1.0f32, 0.0, 0.0, 1.0];
+ /// ```
+ ///
+ /// [`cgmath`]: https://crates.io/crates/cgmath
+ /// [`nalgebra`]: https://crates.io/crates/nalgebra
+ #[macro_export]
+ macro_rules! type_for_format {
+ #(#type_for_format_items)*
+ #(#type_for_format_cgmath_items)*
+ #(#type_for_format_nalgebra_items)*
+ }
+ }
+}
+
+fn formats_members(
+ formats: &[&Format],
+ features: &IndexMap<&str, &Feature>,
+ extensions: &IndexMap<&str, &Extension>,
+) -> Vec<FormatMember> {
+ static BLOCK_EXTENT_REGEX: Lazy<Regex> =
+ Lazy::new(|| Regex::new(r"^(\d+),(\d+),(\d+)$").unwrap());
+
+ formats
+ .iter()
+ .map(|format| {
+ let vulkan_name = format.name.strip_prefix("VK_FORMAT_").unwrap();
+ let ffi_name = format_ident!("{}", vulkan_name.to_ascii_uppercase());
+
+ let mut parts = vulkan_name.split('_').collect::<Vec<_>>();
+
+ if ["EXT", "IMG"].contains(parts.last().unwrap()) {
+ parts.pop();
+ }
+
+ let name = format_ident!("{}", parts.join("_"));
+
+ let mut member = FormatMember {
+ name,
+ ffi_name,
+ requires: Vec::new(),
+
+ aspect_color: false,
+ aspect_depth: false,
+ aspect_stencil: false,
+ aspect_plane0: false,
+ aspect_plane1: false,
+ aspect_plane2: false,
+
+ block_extent: [1, 1, 1],
+ block_size: None,
+ compatibility: format_ident!(
+ "Class_{}",
+ format.class.replace('-', "").replace(' ', "_")
+ ),
+ components: [0u8; 4],
+ compression: format
+ .compressed
+ .as_ref()
+ .map(|c| format_ident!("{}", c.replace(' ', "_"))),
+ planes: vec![],
+ texels_per_block: format.texelsPerBlock,
+ type_color: None,
+ type_depth: None,
+ type_stencil: None,
+ ycbcr_chroma_sampling: None,
+
+ type_std_array: None,
+ type_cgmath: None,
+ type_nalgebra: None,
+ };
+
+ for child in &format.children {
+ match child {
+ FormatChild::Component {
+ name,
+ bits,
+ numericFormat,
+ ..
+ } => {
+ let bits = if bits == "compressed" {
+ 1u8
+ } else {
+ bits.parse().unwrap()
+ };
+ let ty = format_ident!("{}", numericFormat);
+
+ match name.as_str() {
+ "R" => {
+ member.aspect_color = true;
+ member.components[0] += bits;
+ member.type_color = Some(ty);
+ }
+ "G" => {
+ member.aspect_color = true;
+ member.components[1] += bits;
+ member.type_color = Some(ty);
+ }
+ "B" => {
+ member.aspect_color = true;
+ member.components[2] += bits;
+ member.type_color = Some(ty);
+ }
+ "A" => {
+ member.aspect_color = true;
+ member.components[3] += bits;
+ member.type_color = Some(ty);
+ }
+ "D" => {
+ member.aspect_depth = true;
+ member.components[0] += bits;
+ member.type_depth = Some(ty);
+ }
+ "S" => {
+ member.aspect_stencil = true;
+ member.components[1] += bits;
+ member.type_stencil = Some(ty);
+ }
+ _ => {
+ panic!("Unknown component type {} on format {}", name, format.name)
+ }
+ }
+ }
+ FormatChild::Plane {
+ index, compatible, ..
+ } => {
+ match *index {
+ 0 => member.aspect_plane0 = true,
+ 1 => member.aspect_plane1 = true,
+ 2 => member.aspect_plane2 = true,
+ _ => (),
+ }
+
+ assert_eq!(*index as usize, member.planes.len());
+ member.planes.push(format_ident!(
+ "{}",
+ compatible.strip_prefix("VK_FORMAT_").unwrap()
+ ));
+ }
+ //FormatChild::SpirvImageFormat { name, .. } => (),
+ _ => (),
+ }
+ }
+
+ if let Some(block_extent) = format.blockExtent.as_ref() {
+ let captures = BLOCK_EXTENT_REGEX.captures(block_extent).unwrap();
+ member.block_extent = [
+ captures.get(1).unwrap().as_str().parse().unwrap(),
+ captures.get(2).unwrap().as_str().parse().unwrap(),
+ captures.get(3).unwrap().as_str().parse().unwrap(),
+ ];
+ } else {
+ match format.chroma.as_deref() {
+ Some("420") => member.block_extent = [2, 2, 1],
+ Some("422") => member.block_extent = [2, 1, 1],
+ _ => (),
+ }
+ };
+
+ // Depth-stencil and multi-planar formats don't have well-defined block sizes.
+ if let (Some(numeric_type), true) = (&member.type_color, member.planes.is_empty()) {
+ member.block_size = Some(format.blockSize as u64);
+
+ if format.compressed.is_some() {
+ member.type_std_array = Some({
+ let block_size = Literal::usize_unsuffixed(format.blockSize as usize);
+ quote! { [u8; #block_size] }
+ });
+ } else if let Some(pack_bits) = format.packed {
+ let pack_elements = format.blockSize * 8 / pack_bits;
+ let element_type = format_ident!("u{}", pack_bits);
+
+ member.type_std_array = Some(if pack_elements > 1 {
+ let elements = Literal::usize_unsuffixed(pack_elements as usize);
+ quote! { [#element_type; #elements] }
+ } else {
+ quote! { #element_type }
+ });
+ } else {
+ let prefix = match numeric_type.to_string().as_str() {
+ "SFLOAT" => "f",
+ "SINT" | "SNORM" | "SSCALED" => "i",
+ "UINT" | "UNORM" | "USCALED" | "SRGB" => "u",
+ _ => unreachable!(),
+ };
+ let bits = member.components[0];
+ let component_type = format_ident!("{}{}", prefix, bits);
+
+ let component_count = if member.components[1] == 2 * bits {
+ // 422 format with repeated G component
+ 4
+ } else {
+ // Normal format
+ member
+ .components
+ .into_iter()
+ .filter(|&c| {
+ if c != 0 {
+ debug_assert!(c == bits);
+ true
+ } else {
+ false
+ }
+ })
+ .count()
+ };
+
+ if component_count > 1 {
+ let elements = Literal::usize_unsuffixed(component_count);
+ member.type_std_array = Some(quote! { [#component_type; #elements] });
+
+ // cgmath only has 1, 2, 3 and 4-component vector types.
+ // Fall back to arrays for anything else.
+ if matches!(component_count, 1 | 2 | 3 | 4) {
+ let ty = format_ident!("{}", format!("Vector{}", component_count));
+ member.type_cgmath = Some(quote! { cgmath::#ty<#component_type> });
+ }
+
+ member.type_nalgebra = Some(quote! {
+ nalgebra::base::SVector<#component_type, #component_count>
+ });
+ } else {
+ member.type_std_array = Some(quote! { #component_type });
+ }
+ }
+ }
+
+ if let Some(chroma) = format.chroma.as_ref() {
+ member.ycbcr_chroma_sampling = Some(format_ident!("Mode{}", chroma));
+ }
+
+ debug_assert!(
+ !member.components.iter().all(|x| *x == 0),
+ "format {} has 0 components",
+ vulkan_name
+ );
+
+ for &feature in features.values() {
+ for child in &feature.children {
+ if let ExtensionChild::Require { items, .. } = child {
+ for item in items {
+ match item {
+ InterfaceItem::Enum(Enum {
+ name,
+ spec: EnumSpec::Offset { extends, .. },
+ ..
+ }) if name == &format.name && extends == "VkFormat" => {
+ if let Some(version) = feature.name.strip_prefix("VK_VERSION_")
+ {
+ let (major, minor) = version.split_once('_').unwrap();
+ member.requires.push(RequiresOneOf {
+ api_version: Some((
+ major.to_string(),
+ minor.to_string(),
+ )),
+ ..Default::default()
+ });
+ }
+ }
+ _ => (),
+ }
+ }
+ }
+ }
+ }
+
+ for &extension in extensions.values() {
+ for child in &extension.children {
+ if let ExtensionChild::Require { items, .. } = child {
+ for item in items {
+ if let InterfaceItem::Enum(en) = item {
+ if matches!(
+ en,
+ Enum {
+ name,
+ spec: EnumSpec::Offset { extends, .. },
+ ..
+ } if name == &format.name && extends == "VkFormat")
+ || matches!(
+ en,
+ Enum {
+ spec: EnumSpec::Alias { alias, extends, .. },
+ ..
+ } if alias == &format.name && extends.as_deref() == Some("VkFormat"))
+ {
+ let extension_name =
+ extension.name.strip_prefix("VK_").unwrap().to_snake_case();
+
+ if member.requires.is_empty() {
+ member.requires.push(Default::default());
+ };
+
+ let requires = member.requires.first_mut().unwrap();
+
+ match extension.ext_type.as_deref() {
+ Some("device") => {
+ requires
+ .device_extensions
+ .push(format_ident!("{}", extension_name));
+ }
+ Some("instance") => {
+ requires
+ .instance_extensions
+ .push(format_ident!("{}", extension_name));
+ }
+ _ => (),
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ member
+ })
+ .collect()
+}
diff --git a/autogen/mod.rs b/autogen/mod.rs
index dde09ea..fbc3bd7 100644
--- a/autogen/mod.rs
+++ b/autogen/mod.rs
@@ -7,47 +7,72 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use indexmap::IndexMap;
-use std::{collections::HashMap, io::Write, path::Path};
+use self::spirv_grammar::SpirvGrammar;
+use ahash::HashMap;
+use once_cell::sync::Lazy;
+use regex::Regex;
+use std::{
+ env,
+ fmt::Display,
+ fs::File,
+ io::{BufWriter, Write},
+ path::Path,
+ process::Command,
+};
use vk_parse::{
- Extension, ExtensionChild, Feature, InterfaceItem, Registry, RegistryChild, Type,
- TypeCodeMarkup, TypeSpec, TypesChild,
+ Enum, EnumSpec, Enums, EnumsChild, Extension, ExtensionChild, Feature, Format, InterfaceItem,
+ Registry, RegistryChild, SpirvExtOrCap, Type, TypeSpec, TypesChild,
};
+mod errors;
mod extensions;
mod features;
mod fns;
+mod formats;
mod properties;
+mod spirv_grammar;
+mod spirv_parse;
+mod spirv_reqs;
+mod version;
+
+pub type IndexMap<K, V> = indexmap::IndexMap<K, V, ahash::RandomState>;
+
+pub fn autogen() {
+ let registry = get_vk_registry("vk.xml");
+ let vk_data = VkRegistryData::new(&registry);
+ let spirv_grammar = get_spirv_grammar("spirv.core.grammar.json");
-pub fn write<W: Write>(writer: &mut W) {
- let registry = get_registry("vk.xml");
- let aliases = get_aliases(&registry);
- let extensions = get_extensions(&registry);
- let features = get_features(&registry);
- let types = get_types(&registry, &aliases, &features, &extensions);
- let header_version = get_header_version(&registry);
+ errors::write(&vk_data);
+ extensions::write(&vk_data);
+ features::write(&vk_data);
+ formats::write(&vk_data);
+ fns::write(&vk_data);
+ properties::write(&vk_data);
+ spirv_parse::write(&spirv_grammar);
+ spirv_reqs::write(&vk_data, &spirv_grammar);
+ version::write(&vk_data);
+}
+
+fn write_file(file: impl AsRef<Path>, source: impl AsRef<str>, content: impl Display) {
+ let path = Path::new(&env::var_os("OUT_DIR").unwrap()).join(file.as_ref());
+ let mut writer = BufWriter::new(File::create(&path).unwrap());
write!(
writer,
"\
- // This file is auto-generated by vulkano-gen from vk.xml header version {}.\n\
- // It should not be edited manually. Changes should be made by editing vulkano-gen.\n\
- \n",
- header_version
+ // This file is auto-generated by vulkano autogen from {}.\n\
+ // It should not be edited manually. Changes should be made by editing autogen.\n\
+ \n\n{}",
+ source.as_ref(),
+ content,
)
.unwrap();
- extensions::write(writer, &extensions);
- write!(writer, "\n\n").unwrap();
- fns::write(writer, &extensions);
- write!(writer, "\n\n").unwrap();
- features::write(writer, &types, &extensions);
- write!(writer, "\n\n").unwrap();
- properties::write(writer, &types, &extensions);
- write!(writer, "\n").unwrap();
+ std::mem::drop(writer); // Ensure that the file is fully written
+ Command::new("rustfmt").arg(&path).status().ok();
}
-fn get_registry<P: AsRef<Path> + ?Sized>(path: &P) -> Registry {
+fn get_vk_registry<P: AsRef<Path> + ?Sized>(path: &P) -> Registry {
let (registry, errors) = vk_parse::parse_file(path.as_ref()).unwrap();
if !errors.is_empty() {
@@ -61,155 +86,358 @@ fn get_registry<P: AsRef<Path> + ?Sized>(path: &P) -> Registry {
registry
}
-fn get_aliases(registry: &Registry) -> HashMap<&str, &str> {
- registry
- .0
- .iter()
- .filter_map(|child| {
- if let RegistryChild::Types(types) = child {
- return Some(types.children.iter().filter_map(|ty| {
- if let TypesChild::Type(ty) = ty {
- if let Some(alias) = ty.alias.as_ref().map(|s| s.as_str()) {
- return Some((ty.name.as_ref().unwrap().as_str(), alias));
- }
- }
- None
- }));
- }
- None
- })
- .flatten()
- .collect()
+pub struct VkRegistryData<'r> {
+ pub header_version: (u16, u16, u16),
+ pub errors: Vec<&'r str>,
+ pub extensions: IndexMap<&'r str, &'r Extension>,
+ pub features: IndexMap<&'r str, &'r Feature>,
+ pub formats: Vec<&'r Format>,
+ pub spirv_capabilities: Vec<&'r SpirvExtOrCap>,
+ pub spirv_extensions: Vec<&'r SpirvExtOrCap>,
+ pub types: HashMap<&'r str, (&'r Type, Vec<&'r str>)>,
}
-fn get_extensions(registry: &Registry) -> IndexMap<&str, &Extension> {
- let iter = registry
- .0
- .iter()
- .filter_map(|child| {
- if let RegistryChild::Extensions(ext) = child {
- return Some(ext.children.iter().filter_map(|ext| {
- if ext.supported.as_ref().map(|s| s.as_str()) == Some("vulkan")
- && ext.obsoletedby.is_none()
- {
- return Some(ext);
- }
- None
- }));
- }
- None
- })
- .flatten();
-
- let extensions: HashMap<&str, &Extension> =
- iter.clone().map(|ext| (ext.name.as_str(), ext)).collect();
- let mut names: Vec<_> = iter.map(|ext| ext.name.as_str()).collect();
- names.sort_unstable_by_key(|name| {
- if name.starts_with("VK_KHR_") {
- (0, name.to_owned())
- } else if name.starts_with("VK_EXT_") {
- (1, name.to_owned())
- } else {
- (2, name.to_owned())
- }
- });
+impl<'r> VkRegistryData<'r> {
+ fn new(registry: &'r Registry) -> Self {
+ let aliases = Self::get_aliases(registry);
+ let extensions = Self::get_extensions(registry);
+ let features = Self::get_features(registry);
+ let formats = Self::get_formats(registry);
+ let spirv_capabilities = Self::get_spirv_capabilities(registry);
+ let spirv_extensions = Self::get_spirv_extensions(registry);
+ let errors = Self::get_errors(registry, &features, &extensions);
+ let types = Self::get_types(registry, &aliases, &features, &extensions);
+ let header_version = Self::get_header_version(registry);
- names.iter().map(|&name| (name, extensions[name])).collect()
-}
+ VkRegistryData {
+ header_version,
+ errors,
+ extensions,
+ features,
+ formats,
+ spirv_capabilities,
+ spirv_extensions,
+ types,
+ }
+ }
-fn get_features(registry: &Registry) -> IndexMap<&str, &Feature> {
- registry
- .0
- .iter()
- .filter_map(|child| {
- if let RegistryChild::Feature(feat) = child {
- return Some((feat.name.as_str(), feat));
- }
+ fn get_header_version(registry: &Registry) -> (u16, u16, u16) {
+ static VK_HEADER_VERSION: Lazy<Regex> =
+ Lazy::new(|| Regex::new(r"#define\s+VK_HEADER_VERSION\s+(\d+)\s*$").unwrap());
+ static VK_HEADER_VERSION_COMPLETE: Lazy<Regex> = Lazy::new(|| {
+ Regex::new(r"#define\s+VK_HEADER_VERSION_COMPLETE\s+VK_MAKE_API_VERSION\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*VK_HEADER_VERSION\s*\)").unwrap()
+ });
- None
- })
- .collect()
-}
+ let mut major = None;
+ let mut minor = None;
+ let mut patch = None;
-fn get_types<'a>(
- registry: &'a Registry,
- aliases: &'a HashMap<&str, &str>,
- features: &'a IndexMap<&str, &Feature>,
- extensions: &'a IndexMap<&str, &Extension>,
-) -> HashMap<&'a str, (&'a Type, Vec<&'a str>)> {
- let mut types: HashMap<&str, (&Type, Vec<&str>)> = registry
- .0
- .iter()
- .filter_map(|child| {
+ for child in registry.0.iter() {
if let RegistryChild::Types(types) = child {
- return Some(types.children.iter().filter_map(|ty| {
+ for ty in types.children.iter() {
if let TypesChild::Type(ty) = ty {
- if ty.alias.is_none() {
- return ty.name.as_ref().map(|name| (name.as_str(), (ty, vec![])));
+ if let TypeSpec::Code(code) = &ty.spec {
+ if let Some(captures) = VK_HEADER_VERSION.captures(&code.code) {
+ patch = Some(captures.get(1).unwrap().as_str().parse().unwrap());
+ } else if let Some(captures) =
+ VK_HEADER_VERSION_COMPLETE.captures(&code.code)
+ {
+ major = Some(captures.get(2).unwrap().as_str().parse().unwrap());
+ minor = Some(captures.get(3).unwrap().as_str().parse().unwrap());
+ }
}
}
- None
- }));
+ }
}
- None
- })
- .flatten()
- .collect();
-
- features
- .iter()
- .map(|(name, feature)| (name, &feature.children))
- .chain(extensions.iter().map(|(name, ext)| (name, &ext.children)))
- .for_each(|(provided_by, children)| {
- children
- .iter()
- .filter_map(|child| {
- if let ExtensionChild::Require { items, .. } = child {
- return Some(items.iter());
+ }
+
+ (major.unwrap(), minor.unwrap(), patch.unwrap())
+ }
+
+ fn get_aliases(registry: &Registry) -> HashMap<&str, &str> {
+ registry
+ .0
+ .iter()
+ .filter_map(|child| {
+ if let RegistryChild::Types(types) = child {
+ return Some(types.children.iter().filter_map(|ty| {
+ if let TypesChild::Type(ty) = ty {
+ if let Some(alias) = ty.alias.as_deref() {
+ return Some((ty.name.as_ref().unwrap().as_str(), alias));
+ }
+ }
+ None
+ }));
+ }
+ None
+ })
+ .flatten()
+ .collect()
+ }
+
+ fn get_errors<'a>(
+ registry: &'a Registry,
+ features: &IndexMap<&'a str, &'a Feature>,
+ extensions: &IndexMap<&'a str, &'a Extension>,
+ ) -> Vec<&'a str> {
+ (registry
+ .0
+ .iter()
+ .filter_map(|child| match child {
+ RegistryChild::Enums(Enums {
+ name: Some(name),
+ children,
+ ..
+ }) if name == "VkResult" => Some(children.iter().filter_map(|en| {
+ if let EnumsChild::Enum(en) = en {
+ if let EnumSpec::Value { value, .. } = &en.spec {
+ if value.starts_with('-') {
+ return Some(en.name.as_str());
+ }
+ }
}
None
- })
+ })),
+ _ => None,
+ })
+ .flatten())
+ .chain(
+ (features.values().map(|feature| feature.children.iter()))
+ .chain(
+ extensions
+ .values()
+ .map(|extension| extension.children.iter()),
+ )
.flatten()
- .filter_map(|item| {
- if let InterfaceItem::Type { name, .. } = item {
- return Some(name.as_str());
+ .filter_map(|child| {
+ if let ExtensionChild::Require { items, .. } = child {
+ return Some(items.iter().filter_map(|item| match item {
+ InterfaceItem::Enum(Enum {
+ name,
+ spec:
+ EnumSpec::Offset {
+ extends,
+ dir: false,
+ ..
+ },
+ ..
+ }) if extends == "VkResult" => Some(name.as_str()),
+ _ => None,
+ }));
}
None
})
- .for_each(|item_name| {
- let item_name = aliases.get(item_name).unwrap_or(&item_name);
- if let Some(ty) = types.get_mut(item_name) {
- if !ty.1.contains(provided_by) {
- ty.1.push(provided_by);
+ .flatten(),
+ )
+ .collect()
+ }
+
+ fn get_extensions(registry: &Registry) -> IndexMap<&str, &Extension> {
+ let iter = registry
+ .0
+ .iter()
+ .filter_map(|child| {
+ if let RegistryChild::Extensions(ext) = child {
+ return Some(ext.children.iter().filter(|ext| {
+ if ext.supported.as_deref() == Some("vulkan") && ext.obsoletedby.is_none() {
+ return true;
}
- }
- });
+ false
+ }));
+ }
+ None
+ })
+ .flatten();
+
+ let extensions: HashMap<&str, &Extension> =
+ iter.clone().map(|ext| (ext.name.as_str(), ext)).collect();
+ let mut names: Vec<_> = iter.map(|ext| ext.name.as_str()).collect();
+ names.sort_unstable_by_key(|name| {
+ if name.starts_with("VK_KHR_") {
+ (0, name.to_owned())
+ } else if name.starts_with("VK_EXT_") {
+ (1, name.to_owned())
+ } else {
+ (2, name.to_owned())
+ }
});
- types
- .into_iter()
- .filter(|(_key, val)| !val.1.is_empty())
- .collect()
-}
+ names.iter().map(|&name| (name, extensions[name])).collect()
+ }
-fn get_header_version(registry: &Registry) -> u16 {
- registry.0.iter()
- .find_map(|child| -> Option<u16> {
- if let RegistryChild::Types(types) = child {
- return types.children.iter().find_map(|ty| -> Option<u16> {
- if let TypesChild::Type(ty) = ty {
- if let TypeSpec::Code(code) = &ty.spec {
- if code.markup.iter().any(|mkup| matches!(mkup, TypeCodeMarkup::Name(name) if name == "VK_HEADER_VERSION")) {
- return Some(code.code.rsplit_once(' ').unwrap().1.parse().unwrap());
+ fn get_features(registry: &Registry) -> IndexMap<&str, &Feature> {
+ registry
+ .0
+ .iter()
+ .filter_map(|child| {
+ if let RegistryChild::Feature(feat) = child {
+ return Some((feat.name.as_str(), feat));
+ }
+
+ None
+ })
+ .collect()
+ }
+
+ fn get_formats(registry: &Registry) -> Vec<&Format> {
+ registry
+ .0
+ .iter()
+ .filter_map(|child| {
+ if let RegistryChild::Formats(formats) = child {
+ return Some(formats.children.iter());
+ }
+ None
+ })
+ .flatten()
+ .collect()
+ }
+
+ fn get_spirv_capabilities(registry: &Registry) -> Vec<&SpirvExtOrCap> {
+ registry
+ .0
+ .iter()
+ .filter_map(|child| {
+ if let RegistryChild::SpirvCapabilities(capabilities) = child {
+ return Some(capabilities.children.iter());
+ }
+ None
+ })
+ .flatten()
+ .collect()
+ }
+
+ fn get_spirv_extensions(registry: &Registry) -> Vec<&SpirvExtOrCap> {
+ registry
+ .0
+ .iter()
+ .filter_map(|child| {
+ if let RegistryChild::SpirvExtensions(extensions) = child {
+ return Some(extensions.children.iter());
+ }
+ None
+ })
+ .flatten()
+ .collect()
+ }
+
+ fn get_types<'a>(
+ registry: &'a Registry,
+ aliases: &HashMap<&'a str, &'a str>,
+ features: &IndexMap<&'a str, &'a Feature>,
+ extensions: &IndexMap<&'a str, &'a Extension>,
+ ) -> HashMap<&'a str, (&'a Type, Vec<&'a str>)> {
+ let mut types: HashMap<&str, (&Type, Vec<&str>)> = registry
+ .0
+ .iter()
+ .filter_map(|child| {
+ if let RegistryChild::Types(types) = child {
+ return Some(types.children.iter().filter_map(|ty| {
+ if let TypesChild::Type(ty) = ty {
+ if ty.alias.is_none() {
+ return ty.name.as_ref().map(|name| (name.as_str(), (ty, vec![])));
}
}
- }
+ None
+ }));
+ }
+ None
+ })
+ .flatten()
+ .collect();
- None
- });
- }
+ features
+ .iter()
+ .map(|(name, feature)| (name, &feature.children))
+ .chain(extensions.iter().map(|(name, ext)| (name, &ext.children)))
+ .for_each(|(provided_by, children)| {
+ children
+ .iter()
+ .filter_map(|child| {
+ if let ExtensionChild::Require { items, .. } = child {
+ return Some(items.iter());
+ }
+ None
+ })
+ .flatten()
+ .filter_map(|item| {
+ if let InterfaceItem::Type { name, .. } = item {
+ return Some(name.as_str());
+ }
+ None
+ })
+ .for_each(|item_name| {
+ let item_name = aliases.get(item_name).unwrap_or(&item_name);
+ if let Some(ty) = types.get_mut(item_name) {
+ if !ty.1.contains(provided_by) {
+ ty.1.push(provided_by);
+ }
+ }
+ });
+ });
+
+ types
+ .into_iter()
+ .filter(|(_key, val)| !val.1.is_empty())
+ .collect()
+ }
+}
- None
- })
- .unwrap()
+pub fn get_spirv_grammar<P: AsRef<Path> + ?Sized>(path: &P) -> SpirvGrammar {
+ let mut grammar = SpirvGrammar::new(path);
+
+ // Remove duplicate opcodes and enum values, preferring "more official" suffixes
+ grammar
+ .instructions
+ .sort_by_key(|instruction| (instruction.opcode, suffix_key(&instruction.opname)));
+ grammar
+ .instructions
+ .dedup_by_key(|instruction| instruction.opcode);
+
+ grammar
+ .operand_kinds
+ .iter_mut()
+ .filter(|operand_kind| operand_kind.category == "BitEnum")
+ .for_each(|operand_kind| {
+ operand_kind.enumerants.sort_by_key(|enumerant| {
+ let value = enumerant
+ .value
+ .as_str()
+ .unwrap()
+ .strip_prefix("0x")
+ .unwrap();
+ (
+ u32::from_str_radix(value, 16).unwrap(),
+ suffix_key(&enumerant.enumerant),
+ )
+ });
+ });
+
+ grammar
+ .operand_kinds
+ .iter_mut()
+ .filter(|operand_kind| operand_kind.category == "ValueEnum")
+ .for_each(|operand_kind| {
+ operand_kind.enumerants.sort_by_key(|enumerant| {
+ (enumerant.value.as_u64(), suffix_key(&enumerant.enumerant))
+ });
+ });
+
+ grammar
+}
+
+fn suffix_key(name: &str) -> u32 {
+ static VENDOR_SUFFIXES: Lazy<Regex> =
+ Lazy::new(|| Regex::new(r"(?:AMD|GOOGLE|INTEL|NV)$").unwrap());
+
+ #[allow(clippy::bool_to_int_with_if)]
+ if VENDOR_SUFFIXES.is_match(name) {
+ 3
+ } else if name.ends_with("EXT") {
+ 2
+ } else if name.ends_with("KHR") {
+ 1
+ } else {
+ 0
+ }
}
diff --git a/autogen/properties.rs b/autogen/properties.rs
index 1dfb695..1212dba 100644
--- a/autogen/properties.rs
+++ b/autogen/properties.rs
@@ -7,99 +7,183 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use heck::SnakeCase;
-use indexmap::IndexMap;
+use super::{write_file, IndexMap, VkRegistryData};
+use ahash::HashMap;
+use heck::ToSnakeCase;
+use proc_macro2::{Ident, TokenStream};
+use quote::{format_ident, quote};
use regex::Regex;
-use std::{
- collections::{hash_map::Entry, HashMap},
- io::Write,
-};
+use std::{collections::hash_map::Entry, fmt::Write as _};
use vk_parse::{Extension, Type, TypeMember, TypeMemberMarkup, TypeSpec};
-pub fn write<W: Write>(
- writer: &mut W,
- types: &HashMap<&str, (&Type, Vec<&str>)>,
- extensions: &IndexMap<&str, &Extension>,
-) {
- write!(writer, "crate::device::properties::properties! {{").unwrap();
-
- for feat in make_vulkano_properties(&types) {
- write!(writer, "\n\t{} => {{", feat.member).unwrap();
- write_doc(writer, &feat);
- write!(writer, "\n\t\tty: {},", feat.ty).unwrap();
- write!(writer, "\n\t\tffi_name: {},", feat.ffi_name).unwrap();
- write!(
- writer,
- "\n\t\tffi_members: [{}],",
- feat.ffi_members.join(", ")
- )
- .unwrap();
- write!(writer, "\n\t\trequired: {},", feat.required).unwrap();
- write!(writer, "\n\t}},").unwrap();
- }
+pub fn write(vk_data: &VkRegistryData) {
+ let properties_output = properties_output(&properties_members(&vk_data.types));
+ let properties_ffi_output =
+ properties_ffi_output(&properties_ffi_members(&vk_data.types, &vk_data.extensions));
+ write_file(
+ "properties.rs",
+ format!(
+ "vk.xml header version {}.{}.{}",
+ vk_data.header_version.0, vk_data.header_version.1, vk_data.header_version.2
+ ),
+ quote! {
+ #properties_output
+ #properties_ffi_output
+ },
+ );
+}
- write!(
- writer,
- "\n}}\n\ncrate::device::properties::properties_ffi! {{\n\tapi_version,\n\tdevice_extensions,\n\tinstance_extensions,"
- )
- .unwrap();
+#[derive(Clone, Debug)]
+struct PropertiesMember {
+ name: Ident,
+ ty: TokenStream,
+ doc: String,
+ raw: String,
+ ffi_name: Ident,
+ ffi_members: Vec<(Ident, TokenStream)>,
+ optional: bool,
+}
- for ffi in make_vulkano_properties_ffi(types, extensions) {
- write!(writer, "\n\t{} => {{", ffi.member).unwrap();
- write!(writer, "\n\t\tty: {},", ffi.ty).unwrap();
- write!(
- writer,
- "\n\t\tprovided_by: [{}],",
- ffi.provided_by.join(", ")
- )
- .unwrap();
- write!(writer, "\n\t\tconflicts: [{}],", ffi.conflicts.join(", ")).unwrap();
- write!(writer, "\n\t}},").unwrap();
- }
+fn properties_output(members: &[PropertiesMember]) -> TokenStream {
+ let struct_items = members.iter().map(
+ |PropertiesMember {
+ name,
+ ty,
+ doc,
+ optional,
+ ..
+ }| {
+ if *optional {
+ quote! {
+ #[doc = #doc]
+ pub #name: Option<#ty>,
+ }
+ } else {
+ quote! {
+ #[doc = #doc]
+ pub #name: #ty,
+ }
+ }
+ },
+ );
- write!(writer, "\n}}").unwrap();
-}
+ let default_items = members.iter().map(|PropertiesMember { name, .. }| {
+ quote! {
+ #name: Default::default(),
+ }
+ });
-#[derive(Clone, Debug)]
-struct VulkanoProperty {
- member: String,
- ty: String,
- vulkan_doc: String,
- ffi_name: String,
- ffi_members: Vec<String>,
- required: bool,
+ let from_items = members.iter().map(
+ |PropertiesMember {
+ name,
+ ty,
+ ffi_name,
+ ffi_members,
+ optional,
+ ..
+ }| {
+ if *optional {
+ let ffi_members = ffi_members.iter().map(|(ffi_member, ffi_member_field)| {
+ quote! { properties_ffi.#ffi_member.map(|s| s #ffi_member_field .#ffi_name) }
+ });
+
+ quote! {
+ #name: [
+ #(#ffi_members),*
+ ].into_iter().flatten().next().and_then(<#ty>::from_vulkan),
+ }
+ } else {
+ let ffi_members = ffi_members.iter().map(|(ffi_member, ffi_member_field)| {
+ quote! { properties_ffi.#ffi_member #ffi_member_field .#ffi_name }
+ });
+
+ quote! {
+ #name: [
+ #(#ffi_members),*
+ ].into_iter().next().and_then(<#ty>::from_vulkan).unwrap(),
+ }
+ }
+ },
+ );
+
+ quote! {
+ /// Represents all the properties of a physical device.
+ ///
+ /// Depending on the highest version of Vulkan supported by the physical device, and the
+ /// available extensions, not every property may be available. For that reason, some
+ /// properties are wrapped in an `Option`.
+ #[derive(Clone, Debug)]
+ pub struct Properties {
+ #(#struct_items)*
+ pub _ne: crate::NonExhaustive,
+ }
+
+ impl Default for Properties {
+ fn default() -> Self {
+ Properties {
+ #(#default_items)*
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+ }
+
+ impl From<&PropertiesFfi> for Properties {
+ fn from(properties_ffi: &PropertiesFfi) -> Self {
+ Properties {
+ #(#from_items)*
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+ }
+ }
}
-fn make_vulkano_properties(types: &HashMap<&str, (&Type, Vec<&str>)>) -> Vec<VulkanoProperty> {
- let mut properties = HashMap::new();
- std::array::IntoIter::new([
+fn properties_members(types: &HashMap<&str, (&Type, Vec<&str>)>) -> Vec<PropertiesMember> {
+ let mut properties = HashMap::default();
+
+ [
&types["VkPhysicalDeviceProperties"],
&types["VkPhysicalDeviceLimits"],
&types["VkPhysicalDeviceSparseProperties"],
- ])
+ ]
+ .into_iter()
.chain(sorted_structs(types).into_iter())
.filter(|(ty, _)| {
- let name = ty.name.as_ref().map(|s| s.as_str());
+ let name = ty.name.as_deref();
name == Some("VkPhysicalDeviceProperties")
|| name == Some("VkPhysicalDeviceLimits")
|| name == Some("VkPhysicalDeviceSparseProperties")
- || ty.structextends.as_ref().map(|s| s.as_str()) == Some("VkPhysicalDeviceProperties2")
+ || ty.structextends.as_deref() == Some("VkPhysicalDeviceProperties2")
})
.for_each(|(ty, _)| {
let vulkan_ty_name = ty.name.as_ref().unwrap();
- let required = vulkan_ty_name == "VkPhysicalDeviceProperties"
- || vulkan_ty_name == "VkPhysicalDeviceLimits"
- || vulkan_ty_name == "VkPhysicalDeviceSparseProperties"
- ;
- let ty_name = if vulkan_ty_name == "VkPhysicalDeviceProperties" {
- "properties_vulkan10.properties".to_owned()
+ let (ty_name, optional) = if vulkan_ty_name == "VkPhysicalDeviceProperties" {
+ (
+ (format_ident!("properties_vulkan10"), quote! { .properties }),
+ false,
+ )
} else if vulkan_ty_name == "VkPhysicalDeviceLimits" {
- "properties_vulkan10.properties.limits".to_owned()
+ (
+ (
+ format_ident!("properties_vulkan10"),
+ quote! { .properties.limits },
+ ),
+ false,
+ )
} else if vulkan_ty_name == "VkPhysicalDeviceSparseProperties" {
- "properties_vulkan10.properties.sparse_properties".to_owned()
+ (
+ (
+ format_ident!("properties_vulkan10"),
+ quote! { .properties.sparse_properties },
+ ),
+ false,
+ )
} else {
- ffi_member(vulkan_ty_name)
+ (
+ (format_ident!("{}", ffi_member(vulkan_ty_name)), quote! {}),
+ true,
+ )
};
members(ty)
@@ -111,22 +195,38 @@ fn make_vulkano_properties(types: &HashMap<&str, (&Type, Vec<&str>)>) -> Vec<Vul
let vulkano_member = name.to_snake_case();
let vulkano_ty = match name {
- "apiVersion" => "crate::Version",
+ "apiVersion" => quote! { Version },
+ "bufferImageGranularity"
+ | "minStorageBufferOffsetAlignment"
+ | "minTexelBufferOffsetAlignment"
+ | "minUniformBufferOffsetAlignment"
+ | "nonCoherentAtomSize"
+ | "optimalBufferCopyOffsetAlignment"
+ | "optimalBufferCopyRowPitchAlignment"
+ | "robustStorageBufferAccessSizeAlignment"
+ | "robustUniformBufferAccessSizeAlignment"
+ | "storageTexelBufferOffsetAlignmentBytes"
+ | "uniformTexelBufferOffsetAlignmentBytes" => {
+ quote! { DeviceAlignment }
+ }
_ => vulkano_type(ty, len),
};
match properties.entry(vulkano_member.clone()) {
Entry::Vacant(entry) => {
- entry.insert(VulkanoProperty {
- member: vulkano_member.clone(),
- ty: vulkano_ty.to_owned(),
- vulkan_doc: format!("{}.html#limits-{}", vulkan_ty_name, name),
- ffi_name: vulkano_member,
- ffi_members: vec![ty_name.to_owned()],
- required: required,
- });
+ let mut member = PropertiesMember {
+ name: format_ident!("{}", vulkano_member),
+ ty: vulkano_ty,
+ doc: String::new(),
+ raw: name.to_owned(),
+ ffi_name: format_ident!("{}", vulkano_member),
+ ffi_members: vec![ty_name.clone()],
+ optional,
+ };
+ make_doc(&mut member, vulkan_ty_name);
+ entry.insert(member);
}
Entry::Occupied(entry) => {
- entry.into_mut().ffi_members.push(ty_name.to_owned());
+ entry.into_mut().ffi_members.push(ty_name.clone());
}
};
});
@@ -134,7 +234,7 @@ fn make_vulkano_properties(types: &HashMap<&str, (&Type, Vec<&str>)>) -> Vec<Vul
let mut names: Vec<_> = properties
.values()
- .map(|feat| feat.member.clone())
+ .map(|prop| prop.name.to_string())
.collect();
names.sort_unstable();
names
@@ -143,27 +243,80 @@ fn make_vulkano_properties(types: &HashMap<&str, (&Type, Vec<&str>)>) -> Vec<Vul
.collect()
}
-fn write_doc<W>(writer: &mut W, feat: &VulkanoProperty)
-where
- W: Write,
-{
- write!(writer, "\n\t\tdoc: \"\n\t\t\t- [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/{})", feat.vulkan_doc).unwrap();
- write!(writer, "\n\t\t\",").unwrap();
+fn make_doc(prop: &mut PropertiesMember, vulkan_ty_name: &str) {
+ let writer = &mut prop.doc;
+ write!(
+ writer,
+ "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/{}.html#limits-{})",
+ vulkan_ty_name,
+ prop.raw
+ )
+ .unwrap();
}
#[derive(Clone, Debug)]
-struct VulkanoPropertyFfi {
- member: String,
- ty: String,
- provided_by: Vec<String>,
- conflicts: Vec<String>,
+struct PropertiesFfiMember {
+ name: Ident,
+ ty: Ident,
+ provided_by: Vec<TokenStream>,
+ conflicts: Vec<Ident>,
+}
+
+fn properties_ffi_output(members: &[PropertiesFfiMember]) -> TokenStream {
+ let struct_items = members.iter().map(|PropertiesFfiMember { name, ty, .. }| {
+ quote! { #name: Option<ash::vk::#ty>, }
+ });
+
+ let make_chain_items = members.iter().map(
+ |PropertiesFfiMember {
+ name,
+ provided_by,
+ conflicts,
+ ..
+ }| {
+ quote! {
+ if [#(#provided_by),*].into_iter().any(|x| x) &&
+ [#(self.#conflicts.is_none()),*].into_iter().all(|x| x) {
+ self.#name = Some(Default::default());
+ let member = self.#name.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ }
+ },
+ );
+
+ quote! {
+ #[derive(Default)]
+ pub(crate) struct PropertiesFfi {
+ properties_vulkan10: ash::vk::PhysicalDeviceProperties2KHR,
+ #(#struct_items)*
+ }
+
+ impl PropertiesFfi {
+ pub(crate) fn make_chain(
+ &mut self,
+ api_version: Version,
+ device_extensions: &DeviceExtensions,
+ instance_extensions: &InstanceExtensions,
+ ) {
+ self.properties_vulkan10 = Default::default();
+ let head = &mut self.properties_vulkan10;
+ #(#make_chain_items)*
+ }
+
+ pub(crate) fn head_as_mut(&mut self) -> &mut ash::vk::PhysicalDeviceProperties2KHR {
+ &mut self.properties_vulkan10
+ }
+ }
+ }
}
-fn make_vulkano_properties_ffi<'a>(
+fn properties_ffi_members<'a>(
types: &'a HashMap<&str, (&Type, Vec<&str>)>,
extensions: &IndexMap<&'a str, &Extension>,
-) -> Vec<VulkanoPropertyFfi> {
- let mut property_included_in: HashMap<&str, Vec<&str>> = HashMap::new();
+) -> Vec<PropertiesFfiMember> {
+ let mut property_included_in: HashMap<&str, Vec<&str>> = HashMap::default();
sorted_structs(types)
.into_iter()
.map(|(ty, provided_by)| {
@@ -172,16 +325,22 @@ fn make_vulkano_properties_ffi<'a>(
.iter()
.map(|provided_by| {
if let Some(version) = provided_by.strip_prefix("VK_VERSION_") {
- format!("api_version >= crate::Version::V{}", version)
+ let version = format_ident!("V{}", version);
+ quote! { api_version >= Version::#version }
} else {
- format!(
- "{}_extensions.{}",
- extensions[provided_by].ext_type.as_ref().unwrap().as_str(),
+ let member = format_ident!(
+ "{}_extensions",
+ extensions[provided_by].ext_type.as_ref().unwrap().as_str()
+ );
+ let name = format_ident!(
+ "{}",
provided_by
.strip_prefix("VK_")
.unwrap()
- .to_ascii_lowercase()
- )
+ .to_ascii_lowercase(),
+ );
+
+ quote! { #member.#name }
}
})
.collect();
@@ -204,11 +363,14 @@ fn make_vulkano_properties_ffi<'a>(
}
});
- VulkanoPropertyFfi {
- member: ffi_member(ty_name),
- ty: ty_name.strip_prefix("Vk").unwrap().to_owned(),
+ PropertiesFfiMember {
+ name: format_ident!("{}", ffi_member(ty_name)),
+ ty: format_ident!("{}", ty_name.strip_prefix("Vk").unwrap()),
provided_by,
- conflicts,
+ conflicts: conflicts
+ .into_iter()
+ .map(|s| format_ident!("{}", s))
+ .collect(),
}
})
.collect()
@@ -219,9 +381,7 @@ fn sorted_structs<'a>(
) -> Vec<&'a (&'a Type, Vec<&'a str>)> {
let mut structs: Vec<_> = types
.values()
- .filter(|(ty, _)| {
- ty.structextends.as_ref().map(|s| s.as_str()) == Some("VkPhysicalDeviceProperties2")
- })
+ .filter(|(ty, _)| ty.structextends.as_deref() == Some("VkPhysicalDeviceProperties2"))
.collect();
let regex = Regex::new(r"^VkPhysicalDeviceVulkan\d+Properties$").unwrap();
structs.sort_unstable_by_key(|&(ty, provided_by)| {
@@ -234,17 +394,9 @@ fn sorted_structs<'a>(
{
let (major, minor) = version.split_once('_').unwrap();
major.parse::<i32>().unwrap() << 22 | minor.parse::<i32>().unwrap() << 12
- } else if provided_by
- .iter()
- .find(|s| s.starts_with("VK_KHR_"))
- .is_some()
- {
+ } else if provided_by.iter().any(|s| s.starts_with("VK_KHR_")) {
i32::MAX - 2
- } else if provided_by
- .iter()
- .find(|s| s.starts_with("VK_EXT_"))
- .is_some()
- {
+ } else if provided_by.iter().any(|s| s.starts_with("VK_EXT_")) {
i32::MAX - 1
} else {
i32::MAX
@@ -315,42 +467,46 @@ fn members(ty: &Type) -> Vec<Member> {
}
}
-fn vulkano_type(ty: &str, len: Option<&str>) -> &'static str {
+fn vulkano_type(ty: &str, len: Option<&str>) -> TokenStream {
if let Some(len) = len {
match ty {
- "char" => "String",
- "uint8_t" if len == "VK_LUID_SIZE" => "[u8; 8]",
- "uint8_t" if len == "VK_UUID_SIZE" => "[u8; 16]",
- "uint32_t" if len == "2" => "[u32; 2]",
- "uint32_t" if len == "3" => "[u32; 3]",
- "float" if len == "2" => "[f32; 2]",
+ "char" => quote! { String },
+ "uint8_t" if len == "VK_LUID_SIZE" => quote! { [u8; 8] },
+ "uint8_t" if len == "VK_UUID_SIZE" => quote! { [u8; 16] },
+ "uint32_t" if len == "2" => quote! { [u32; 2] },
+ "uint32_t" if len == "3" => quote! { [u32; 3] },
+ "float" if len == "2" => quote! { [f32; 2] },
_ => unimplemented!("{}[{}]", ty, len),
}
} else {
match ty {
- "float" => "f32",
- "int32_t" => "i32",
- "int64_t" => "i64",
- "size_t" => "usize",
- "uint8_t" => "u8",
- "uint32_t" => "u32",
- "uint64_t" => "u64",
- "VkBool32" => "bool",
- "VkConformanceVersion" => "crate::device::physical::ConformanceVersion",
- "VkDeviceSize" => "crate::DeviceSize",
- "VkDriverId" => "crate::device::physical::DriverId",
- "VkExtent2D" => "[u32; 2]",
- "VkPhysicalDeviceType" => "crate::device::physical::PhysicalDeviceType",
- "VkPointClippingBehavior" => "crate::device::physical::PointClippingBehavior",
- "VkResolveModeFlags" => "crate::render_pass::ResolveModes",
- "VkSampleCountFlags" => "crate::image::SampleCounts",
- "VkSampleCountFlagBits" => "crate::image::SampleCount",
- "VkShaderCorePropertiesFlagsAMD" => "crate::device::physical::ShaderCoreProperties",
- "VkShaderFloatControlsIndependence" => {
- "crate::device::physical::ShaderFloatControlsIndependence"
- }
- "VkShaderStageFlags" => "crate::pipeline::shader::ShaderStages",
- "VkSubgroupFeatureFlags" => "crate::device::physical::SubgroupFeatures",
+ "float" => quote! { f32 },
+ "int32_t" => quote! { i32 },
+ "int64_t" => quote! { i64 },
+ "size_t" => quote! { usize },
+ "uint8_t" => quote! { u8 },
+ "uint32_t" => quote! { u32 },
+ "uint64_t" => quote! { u64 },
+ "VkBool32" => quote! { bool },
+ "VkConformanceVersion" => quote! { ConformanceVersion },
+ "VkDeviceSize" => quote! { DeviceSize },
+ "VkDriverId" => quote! { DriverId },
+ "VkExtent2D" => quote! { [u32; 2] },
+ "VkMemoryDecompressionMethodFlagsNV" => quote! { MemoryDecompressionMethods },
+ "VkOpticalFlowGridSizeFlagsNV" => quote! { OpticalFlowGridSizes },
+ "VkPhysicalDeviceType" => quote! { PhysicalDeviceType },
+ "VkPipelineRobustnessBufferBehaviorEXT" => quote! { PipelineRobustnessBufferBehavior },
+ "VkPipelineRobustnessImageBehaviorEXT" => quote! { PipelineRobustnessImageBehavior },
+ "VkPointClippingBehavior" => quote! { PointClippingBehavior },
+ "VkQueueFlags" => quote! { QueueFlags },
+ "VkRayTracingInvocationReorderModeNV" => quote! { RayTracingInvocationReorderMode },
+ "VkResolveModeFlags" => quote! { ResolveModes },
+ "VkSampleCountFlags" => quote! { SampleCounts },
+ "VkSampleCountFlagBits" => quote! { SampleCount },
+ "VkShaderCorePropertiesFlagsAMD" => quote! { ShaderCoreProperties },
+ "VkShaderFloatControlsIndependence" => quote! { ShaderFloatControlsIndependence },
+ "VkShaderStageFlags" => quote! { ShaderStages },
+ "VkSubgroupFeatureFlags" => quote! { SubgroupFeatures },
_ => unimplemented!("{}", ty),
}
}
diff --git a/autogen/spirv_grammar.rs b/autogen/spirv_grammar.rs
new file mode 100644
index 0000000..3087672
--- /dev/null
+++ b/autogen/spirv_grammar.rs
@@ -0,0 +1,78 @@
+// Copyright (c) 2021 The Vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use serde::Deserialize;
+use serde_json::Value;
+use std::{
+ fs::File,
+ io::{BufReader, Read},
+ path::Path,
+};
+
+#[derive(Clone, Debug, Deserialize)]
+pub struct SpirvGrammar {
+ pub major_version: u16,
+ pub minor_version: u16,
+ pub revision: u16,
+ pub instructions: Vec<SpirvInstruction>,
+ pub operand_kinds: Vec<SpirvOperandKind>,
+}
+
+impl SpirvGrammar {
+ pub fn new<P: AsRef<Path> + ?Sized>(path: &P) -> Self {
+ let mut reader = BufReader::new(File::open(path).unwrap());
+ let mut json = String::new();
+ reader.read_to_string(&mut json).unwrap();
+ serde_json::from_str(&json).unwrap()
+ }
+}
+
+#[derive(Clone, Debug, Deserialize)]
+pub struct SpirvInstruction {
+ pub opname: String,
+ pub class: String,
+ pub opcode: u16,
+ #[serde(default)]
+ pub operands: Vec<SpirvOperand>,
+ #[serde(default)]
+ pub capabilities: Vec<String>,
+ #[serde(default)]
+ pub extensions: Vec<String>,
+}
+
+#[derive(Clone, Debug, Deserialize)]
+pub struct SpirvOperand {
+ pub kind: String,
+ pub quantifier: Option<char>,
+ pub name: Option<String>,
+}
+
+#[derive(Clone, Debug, Deserialize)]
+pub struct SpirvOperandKind {
+ pub category: String,
+ pub kind: String,
+ #[serde(default)]
+ pub enumerants: Vec<SpirvKindEnumerant>,
+}
+
+#[derive(Clone, Debug, Deserialize)]
+pub struct SpirvKindEnumerant {
+ pub enumerant: String,
+ pub value: Value,
+ #[serde(default)]
+ pub parameters: Vec<SpirvParameter>,
+ #[serde(default)]
+ pub capabilities: Vec<String>,
+}
+
+#[derive(Clone, Debug, Deserialize)]
+pub struct SpirvParameter {
+ pub kind: String,
+ pub name: Option<String>,
+}
diff --git a/autogen/spirv_parse.rs b/autogen/spirv_parse.rs
new file mode 100644
index 0000000..e2d37b4
--- /dev/null
+++ b/autogen/spirv_parse.rs
@@ -0,0 +1,686 @@
+// Copyright (c) 2021 The Vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use super::{write_file, SpirvGrammar};
+use ahash::{HashMap, HashSet};
+use heck::ToSnakeCase;
+use once_cell::sync::Lazy;
+use proc_macro2::{Ident, TokenStream};
+use quote::{format_ident, quote};
+
+static SPEC_CONSTANT_OP: Lazy<HashSet<&'static str>> = Lazy::new(|| {
+ HashSet::from_iter([
+ "SConvert",
+ "FConvert",
+ "SNegate",
+ "Not",
+ "IAdd",
+ "ISub",
+ "IMul",
+ "UDiv",
+ "SDiv",
+ "UMod",
+ "SRem",
+ "SMod",
+ "ShiftRightLogical",
+ "ShiftRightArithmetic",
+ "ShiftLeftLogical",
+ "BitwiseOr",
+ "BitwiseXor",
+ "BitwiseAnd",
+ "VectorShuffle",
+ "CompositeExtract",
+ "CompositeInsert",
+ "LogicalOr",
+ "LogicalAnd",
+ "LogicalNot",
+ "LogicalEqual",
+ "LogicalNotEqual",
+ "Select",
+ "IEqual",
+ "INotEqual",
+ "ULessThan",
+ "SLessThan",
+ "UGreaterThan",
+ "SGreaterThan",
+ "ULessThanEqual",
+ "SLessThanEqual",
+ "UGreaterThanEqual",
+ "SGreaterThanEqual",
+ "QuantizeToF16",
+ "ConvertFToS",
+ "ConvertSToF",
+ "ConvertFToU",
+ "ConvertUToF",
+ "UConvert",
+ "ConvertPtrToU",
+ "ConvertUToPtr",
+ "GenericCastToPtr",
+ "PtrCastToGeneric",
+ "Bitcast",
+ "FNegate",
+ "FAdd",
+ "FSub",
+ "FMul",
+ "FDiv",
+ "FRem",
+ "FMod",
+ "AccessChain",
+ "InBoundsAccessChain",
+ "PtrAccessChain",
+ "InBoundsPtrAccessChain",
+ ])
+});
+
+pub fn write(grammar: &SpirvGrammar) {
+ let mut instr_members = instruction_members(grammar);
+ let instr_output = instruction_output(&instr_members, false);
+
+ instr_members.retain(|member| SPEC_CONSTANT_OP.contains(member.name.to_string().as_str()));
+ instr_members.iter_mut().for_each(|member| {
+ if member.has_result_type_id {
+ member.operands.remove(0);
+ }
+ if member.has_result_id {
+ member.operands.remove(0);
+ }
+ });
+ let spec_constant_instr_output = instruction_output(&instr_members, true);
+
+ let bit_enum_output = bit_enum_output(&bit_enum_members(grammar));
+ let value_enum_output = value_enum_output(&value_enum_members(grammar));
+
+ write_file(
+ "spirv_parse.rs",
+ format!(
+ "SPIR-V grammar version {}.{}.{}",
+ grammar.major_version, grammar.minor_version, grammar.revision
+ ),
+ quote! {
+ #instr_output
+ #spec_constant_instr_output
+ #bit_enum_output
+ #value_enum_output
+ },
+ );
+}
+
+#[derive(Clone, Debug)]
+struct InstructionMember {
+ name: Ident,
+ has_result_id: bool,
+ has_result_type_id: bool,
+ opcode: u16,
+ operands: Vec<OperandMember>,
+}
+
+#[derive(Clone, Debug)]
+struct OperandMember {
+ name: Ident,
+ ty: TokenStream,
+ parse: TokenStream,
+}
+
+fn instruction_output(members: &[InstructionMember], spec_constant: bool) -> TokenStream {
+ let struct_items = members
+ .iter()
+ .map(|InstructionMember { name, operands, .. }| {
+ if operands.is_empty() {
+ quote! { #name, }
+ } else {
+ let operands = operands.iter().map(|OperandMember { name, ty, .. }| {
+ quote! { #name: #ty, }
+ });
+ quote! {
+ #name {
+ #(#operands)*
+ },
+ }
+ }
+ });
+ let parse_items = members.iter().map(
+ |InstructionMember {
+ name,
+ opcode,
+ operands,
+ ..
+ }| {
+ if operands.is_empty() {
+ quote! {
+ #opcode => Self::#name,
+ }
+ } else {
+ let operands_items =
+ operands.iter().map(|OperandMember { name, parse, .. }| {
+ quote! {
+ #name: #parse,
+ }
+ });
+
+ quote! {
+ #opcode => Self::#name {
+ #(#operands_items)*
+ },
+ }
+ }
+ },
+ );
+
+ let doc = if spec_constant {
+ "An instruction that is used as the operand of the `SpecConstantOp` instruction."
+ } else {
+ "A parsed SPIR-V instruction."
+ };
+
+ let enum_name = if spec_constant {
+ format_ident!("SpecConstantInstruction")
+ } else {
+ format_ident!("Instruction")
+ };
+
+ let result_fns = if spec_constant {
+ quote! {}
+ } else {
+ let result_id_items = members.iter().filter_map(
+ |InstructionMember {
+ name,
+ has_result_id,
+ ..
+ }| {
+ if *has_result_id {
+ Some(quote! { Self::#name { result_id, .. } })
+ } else {
+ None
+ }
+ },
+ );
+
+ quote! {
+ /// Returns the `Id` that is assigned by this instruction, if any.
+ pub fn result_id(&self) -> Option<Id> {
+ match self {
+ #(#result_id_items)|* => Some(*result_id),
+ _ => None
+ }
+ }
+ }
+ };
+
+ let opcode_error = if spec_constant {
+ format_ident!("UnknownSpecConstantOpcode")
+ } else {
+ format_ident!("UnknownOpcode")
+ };
+
+ quote! {
+ #[derive(Clone, Debug, PartialEq, Eq)]
+ #[doc=#doc]
+ pub enum #enum_name {
+ #(#struct_items)*
+ }
+
+ impl #enum_name {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<Self, ParseError> {
+ let opcode = (reader.next_u32()? & 0xffff) as u16;
+
+ Ok(match opcode {
+ #(#parse_items)*
+ opcode => return Err(reader.map_err(ParseErrors::#opcode_error(opcode))),
+ })
+ }
+
+ #result_fns
+ }
+ }
+}
+
+fn instruction_members(grammar: &SpirvGrammar) -> Vec<InstructionMember> {
+ let operand_kinds = kinds_to_types(grammar);
+ grammar
+ .instructions
+ .iter()
+ .map(|instruction| {
+ let name = format_ident!("{}", instruction.opname.strip_prefix("Op").unwrap());
+ let mut has_result_id = false;
+ let mut has_result_type_id = false;
+ let mut operand_names = HashMap::default();
+
+ let mut operands = instruction
+ .operands
+ .iter()
+ .map(|operand| {
+ let name = if operand.kind == "IdResult" {
+ has_result_id = true;
+ format_ident!("result_id")
+ } else if operand.kind == "IdResultType" {
+ has_result_type_id = true;
+ format_ident!("result_type_id")
+ } else {
+ to_member_name(&operand.kind, operand.name.as_deref())
+ };
+
+ *operand_names.entry(name.clone()).or_insert(0) += 1;
+
+ let (ty, parse) = &operand_kinds[operand.kind.as_str()];
+ let ty = match operand.quantifier {
+ Some('?') => quote! { Option<#ty> },
+ Some('*') => quote! { Vec<#ty> },
+ _ => ty.clone(),
+ };
+ let parse = match operand.quantifier {
+ Some('?') => quote! {
+ if !reader.is_empty() {
+ Some(#parse)
+ } else {
+ None
+ }
+ },
+ Some('*') => quote! {{
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(#parse);
+ }
+ vec
+ }},
+ _ => parse.clone(),
+ };
+
+ OperandMember { name, ty, parse }
+ })
+ .collect::<Vec<_>>();
+
+ // Add number to operands with identical names
+ for name in operand_names
+ .into_iter()
+ .filter_map(|(n, c)| if c > 1 { Some(n) } else { None })
+ {
+ let mut num = 1;
+
+ for operand in operands.iter_mut().filter(|o| o.name == name) {
+ operand.name = format_ident!("{}{}", name, format!("{}", num));
+ num += 1;
+ }
+ }
+
+ InstructionMember {
+ name,
+ has_result_id,
+ has_result_type_id,
+ opcode: instruction.opcode,
+ operands,
+ }
+ })
+ .collect()
+}
+
+#[derive(Clone, Debug)]
+struct KindEnumMember {
+ name: Ident,
+ value: u32,
+ parameters: Vec<OperandMember>,
+}
+
+fn bit_enum_output(enums: &[(Ident, Vec<KindEnumMember>)]) -> TokenStream {
+ let enum_items = enums.iter().map(|(name, members)| {
+ let members_items = members.iter().map(
+ |KindEnumMember {
+ name, parameters, ..
+ }| {
+ if parameters.is_empty() {
+ quote! {
+ pub #name: bool,
+ }
+ } else if let [OperandMember { ty, .. }] = parameters.as_slice() {
+ quote! {
+ pub #name: Option<#ty>,
+ }
+ } else {
+ let params = parameters.iter().map(|OperandMember { ty, .. }| {
+ quote! { #ty }
+ });
+ quote! {
+ pub #name: Option<(#(#params),*)>,
+ }
+ }
+ },
+ );
+ let parse_items = members.iter().map(
+ |KindEnumMember {
+ name,
+ value,
+ parameters,
+ ..
+ }| {
+ if parameters.is_empty() {
+ quote! {
+ #name: value & #value != 0,
+ }
+ } else {
+ let some = if let [OperandMember { parse, .. }] = parameters.as_slice() {
+ quote! { #parse }
+ } else {
+ let parse = parameters.iter().map(|OperandMember { parse, .. }| parse);
+ quote! { (#(#parse),*) }
+ };
+
+ quote! {
+ #name: if value & #value != 0 {
+ Some(#some)
+ } else {
+ None
+ },
+ }
+ }
+ },
+ );
+
+ quote! {
+ #[derive(Clone, Copy, Debug, PartialEq, Eq)]
+ #[allow(non_camel_case_types)]
+ pub struct #name {
+ #(#members_items)*
+ }
+
+ impl #name {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<#name, ParseError> {
+ let value = reader.next_u32()?;
+
+ Ok(Self {
+ #(#parse_items)*
+ })
+ }
+ }
+ }
+ });
+
+ quote! {
+ #(#enum_items)*
+ }
+}
+
+fn bit_enum_members(grammar: &SpirvGrammar) -> Vec<(Ident, Vec<KindEnumMember>)> {
+ let parameter_kinds = kinds_to_types(grammar);
+
+ grammar
+ .operand_kinds
+ .iter()
+ .filter(|operand_kind| operand_kind.category == "BitEnum")
+ .map(|operand_kind| {
+ let mut previous_value = None;
+
+ let members = operand_kind
+ .enumerants
+ .iter()
+ .filter_map(|enumerant| {
+ // Skip enumerants with the same value as the previous.
+ if previous_value == Some(&enumerant.value) {
+ return None;
+ }
+
+ previous_value = Some(&enumerant.value);
+
+ let value = enumerant
+ .value
+ .as_str()
+ .unwrap()
+ .strip_prefix("0x")
+ .unwrap();
+ let value = u32::from_str_radix(value, 16).unwrap();
+
+ if value == 0 {
+ return None;
+ }
+
+ let name = match enumerant.enumerant.to_snake_case().as_str() {
+ "const" => format_ident!("constant"),
+ "not_na_n" => format_ident!("not_nan"),
+ name => format_ident!("{}", name),
+ };
+
+ let parameters = enumerant
+ .parameters
+ .iter()
+ .map(|param| {
+ let name = to_member_name(&param.kind, param.name.as_deref());
+ let (ty, parse) = parameter_kinds[param.kind.as_str()].clone();
+
+ OperandMember { name, ty, parse }
+ })
+ .collect();
+
+ Some(KindEnumMember {
+ name,
+ value,
+ parameters,
+ })
+ })
+ .collect();
+
+ (format_ident!("{}", operand_kind.kind), members)
+ })
+ .collect()
+}
+
+fn value_enum_output(enums: &[(Ident, Vec<KindEnumMember>)]) -> TokenStream {
+ let enum_items = enums.iter().map(|(name, members)| {
+ let members_items = members.iter().map(
+ |KindEnumMember {
+ name, parameters, ..
+ }| {
+ if parameters.is_empty() {
+ quote! {
+ #name,
+ }
+ } else {
+ let params = parameters.iter().map(|OperandMember { name, ty, .. }| {
+ quote! { #name: #ty, }
+ });
+ quote! {
+ #name {
+ #(#params)*
+ },
+ }
+ }
+ },
+ );
+ let parse_items = members.iter().map(
+ |KindEnumMember {
+ name,
+ value,
+ parameters,
+ ..
+ }| {
+ if parameters.is_empty() {
+ quote! {
+ #value => Self::#name,
+ }
+ } else {
+ let params_items =
+ parameters.iter().map(|OperandMember { name, parse, .. }| {
+ quote! {
+ #name: #parse,
+ }
+ });
+
+ quote! {
+ #value => Self::#name {
+ #(#params_items)*
+ },
+ }
+ }
+ },
+ );
+ let name_string = name.to_string();
+
+ let derives = match name_string.as_str() {
+ "ExecutionModel" => quote! { #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] },
+ "Decoration" => quote! { #[derive(Clone, Debug, PartialEq, Eq)] },
+ _ => quote! { #[derive(Clone, Copy, Debug, PartialEq, Eq)] },
+ };
+
+ quote! {
+ #derives
+ #[allow(non_camel_case_types)]
+ pub enum #name {
+ #(#members_items)*
+ }
+
+ impl #name {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<#name, ParseError> {
+ Ok(match reader.next_u32()? {
+ #(#parse_items)*
+ value => return Err(reader.map_err(ParseErrors::UnknownEnumerant(#name_string, value))),
+ })
+ }
+ }
+ }
+ });
+
+ quote! {
+ #(#enum_items)*
+ }
+}
+
+fn value_enum_members(grammar: &SpirvGrammar) -> Vec<(Ident, Vec<KindEnumMember>)> {
+ let parameter_kinds = kinds_to_types(grammar);
+
+ grammar
+ .operand_kinds
+ .iter()
+ .filter(|operand_kind| operand_kind.category == "ValueEnum")
+ .map(|operand_kind| {
+ let mut previous_value = None;
+
+ let members = operand_kind
+ .enumerants
+ .iter()
+ .filter_map(|enumerant| {
+ // Skip enumerants with the same value as the previous.
+ if previous_value == Some(&enumerant.value) {
+ return None;
+ }
+
+ previous_value = Some(&enumerant.value);
+
+ let name = match enumerant.enumerant.as_str() {
+ "1D" => format_ident!("Dim1D"),
+ "2D" => format_ident!("Dim2D"),
+ "3D" => format_ident!("Dim3D"),
+ name => format_ident!("{}", name),
+ };
+ let parameters = enumerant
+ .parameters
+ .iter()
+ .map(|param| {
+ let name = to_member_name(&param.kind, param.name.as_deref());
+ let (ty, parse) = parameter_kinds[param.kind.as_str()].clone();
+
+ OperandMember { name, ty, parse }
+ })
+ .collect();
+
+ Some(KindEnumMember {
+ name,
+ value: enumerant.value.as_u64().unwrap() as u32,
+ parameters,
+ })
+ })
+ .collect();
+
+ (format_ident!("{}", operand_kind.kind), members)
+ })
+ .collect()
+}
+
+fn to_member_name(kind: &str, name: Option<&str>) -> Ident {
+ if let Some(name) = name {
+ let name = name.to_snake_case();
+
+ // Fix some weird names
+ match name.as_str() {
+ "argument_0_argument_1" => format_ident!("arguments"),
+ "member_0_type_member_1_type" => format_ident!("member_types"),
+ "operand_1_operand_2" => format_ident!("operands"),
+ "parameter_0_type_parameter_1_type" => format_ident!("parameter_types"),
+ "the_name_of_the_opaque_type" => format_ident!("name"),
+ "d_ref" => format_ident!("dref"),
+ "type" => format_ident!("ty"), // type is a keyword
+ _ => format_ident!("{}", name.replace("operand_", "operand")),
+ }
+ } else {
+ format_ident!("{}", kind.to_snake_case())
+ }
+}
+
+fn kinds_to_types(grammar: &SpirvGrammar) -> HashMap<&str, (TokenStream, TokenStream)> {
+ grammar
+ .operand_kinds
+ .iter()
+ .map(|k| {
+ let (ty, parse) = match k.kind.as_str() {
+ "LiteralContextDependentNumber" => {
+ (quote! { Vec<u32> }, quote! { reader.remainder() })
+ }
+ "LiteralExtInstInteger" | "LiteralInteger" | "LiteralInt32" => {
+ (quote! { u32 }, quote! { reader.next_u32()? })
+ }
+ "LiteralInt64" => (quote! { u64 }, quote! { reader.next_u64()? }),
+ "LiteralFloat32" => (
+ quote! { f32 },
+ quote! { f32::from_bits(reader.next_u32()?) },
+ ),
+ "LiteralFloat64" => (
+ quote! { f64 },
+ quote! { f64::from_bits(reader.next_u64()?) },
+ ),
+ "LiteralSpecConstantOpInteger" => (
+ quote! { SpecConstantInstruction },
+ quote! { SpecConstantInstruction::parse(reader)? },
+ ),
+ "LiteralString" => (quote! { String }, quote! { reader.next_string()? }),
+ "PairIdRefIdRef" => (
+ quote! { (Id, Id) },
+ quote! {
+ (
+ Id(reader.next_u32()?),
+ Id(reader.next_u32()?),
+ )
+ },
+ ),
+ "PairIdRefLiteralInteger" => (
+ quote! { (Id, u32) },
+ quote! {
+ (
+ Id(reader.next_u32()?),
+ reader.next_u32()?
+ )
+ },
+ ),
+ "PairLiteralIntegerIdRef" => (
+ quote! { (u32, Id) },
+ quote! {
+ (
+ reader.next_u32()?,
+ Id(reader.next_u32()?)),
+ },
+ ),
+ _ if k.kind.starts_with("Id") => (quote! { Id }, quote! { Id(reader.next_u32()?) }),
+ ident => {
+ let ident = format_ident!("{}", ident);
+ (quote! { #ident }, quote! { #ident::parse(reader)? })
+ }
+ };
+
+ (k.kind.as_str(), (ty, parse))
+ })
+ .collect()
+}
diff --git a/autogen/spirv_reqs.rs b/autogen/spirv_reqs.rs
new file mode 100644
index 0000000..32b674e
--- /dev/null
+++ b/autogen/spirv_reqs.rs
@@ -0,0 +1,275 @@
+// Copyright (c) 2021 The Vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use super::{
+ spirv_grammar::{SpirvGrammar, SpirvKindEnumerant},
+ write_file, IndexMap, VkRegistryData,
+};
+use heck::ToSnakeCase;
+use indexmap::map::Entry;
+use once_cell::sync::Lazy;
+use proc_macro2::{Ident, TokenStream};
+use quote::{format_ident, quote};
+use regex::Regex;
+use vk_parse::SpirvExtOrCap;
+
+pub fn write(vk_data: &VkRegistryData, grammar: &SpirvGrammar) {
+ let grammar_enumerants = grammar
+ .operand_kinds
+ .iter()
+ .find(|operand_kind| operand_kind.kind == "Capability")
+ .unwrap()
+ .enumerants
+ .as_slice();
+ let spirv_capabilities_output = spirv_reqs_output(
+ &spirv_capabilities_members(&vk_data.spirv_capabilities, grammar_enumerants),
+ false,
+ );
+ let spirv_extensions_output =
+ spirv_reqs_output(&spirv_extensions_members(&vk_data.spirv_extensions), true);
+ write_file(
+ "spirv_reqs.rs",
+ format!(
+ "vk.xml header version {}.{}.{}",
+ vk_data.header_version.0, vk_data.header_version.1, vk_data.header_version.2
+ ),
+ quote! {
+ #spirv_capabilities_output
+ #spirv_extensions_output
+ },
+ );
+}
+
+#[derive(Clone, Debug)]
+struct SpirvReqsMember {
+ name: String,
+ enables: Vec<(Enable, String)>,
+}
+
+#[derive(Clone, Debug, PartialEq)]
+enum Enable {
+ Core((String, String)),
+ Extension(Ident),
+ Feature(Ident),
+ Property((Ident, PropertyValue)),
+}
+
+#[derive(Clone, Debug, PartialEq)]
+enum PropertyValue {
+ Bool,
+ BoolMember(Vec<Ident>),
+}
+
+fn spirv_reqs_output(members: &[SpirvReqsMember], extension: bool) -> TokenStream {
+ let items = members.iter().map(|SpirvReqsMember { name, enables }| {
+ let arm = if extension {
+ quote! { #name }
+ } else {
+ let name = format_ident!("{}", name);
+ quote! { Capability::#name }
+ };
+
+ if enables.is_empty() {
+ quote! {
+ #arm => (),
+ }
+ } else {
+ let enables_items = enables.iter().map(|(enable, _description)| match enable {
+ Enable::Core((major, minor)) => {
+ let version = format_ident!("V{}_{}", major, minor);
+ quote! {
+ device.api_version() >= Version::#version
+ }
+ }
+ Enable::Extension(extension) => quote! {
+ device.enabled_extensions().#extension
+ },
+ Enable::Feature(feature) => quote! {
+ device.enabled_features().#feature
+ },
+ Enable::Property((name, value)) => {
+ let access = match value {
+ PropertyValue::Bool => quote! {},
+ PropertyValue::BoolMember(member) => quote! {
+ .map(|x| x.intersects(#(#member)::*))
+ },
+ };
+
+ quote! {
+ device.physical_device().properties().#name #access .unwrap_or(false)
+ }
+ }
+ });
+
+ let description_items = enables.iter().map(|(_enable, description)| description);
+
+ quote! {
+ #arm => {
+ if !(#(#enables_items)||*) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ #(#description_items),*
+ ]));
+ }
+ },
+ }
+ }
+ });
+
+ if extension {
+ quote! {
+ fn check_spirv_extension(device: &Device, extension: &str) -> Result<(), ShaderSupportError> {
+ match extension {
+ #(#items)*
+ _ => return Err(ShaderSupportError::NotSupportedByVulkan),
+ }
+ Ok(())
+ }
+ }
+ } else {
+ quote! {
+ fn check_spirv_capability(device: &Device, capability: Capability) -> Result<(), ShaderSupportError> {
+ match capability {
+ #(#items)*
+ _ => return Err(ShaderSupportError::NotSupportedByVulkan),
+ }
+ Ok(())
+ }
+ }
+ }
+}
+
+fn spirv_capabilities_members(
+ capabilities: &[&SpirvExtOrCap],
+ grammar_enumerants: &[SpirvKindEnumerant],
+) -> Vec<SpirvReqsMember> {
+ let mut members: IndexMap<String, SpirvReqsMember> = IndexMap::default();
+
+ for ext_or_cap in capabilities {
+ let mut enables: Vec<_> = ext_or_cap.enables.iter().filter_map(make_enable).collect();
+ enables.dedup();
+
+ // Find the capability in the list of enumerants, then go backwards through the list to find
+ // the first enumerant with the same value.
+ let enumerant_pos = match grammar_enumerants
+ .iter()
+ .position(|enumerant| enumerant.enumerant == ext_or_cap.name)
+ {
+ Some(pos) => pos,
+ // This can happen if the grammar file is behind on the vk.xml file.
+ None => continue,
+ };
+ let enumerant_value = &grammar_enumerants[enumerant_pos].value;
+
+ let name = if let Some(enumerant) = grammar_enumerants[..enumerant_pos]
+ .iter()
+ .rev()
+ .take_while(|enumerant| &enumerant.value == enumerant_value)
+ .last()
+ {
+ // Another enumerant was found with the same value, so this one is an alias.
+ &enumerant.enumerant
+ } else {
+ // No other enumerant was found, so this is its canonical name.
+ &ext_or_cap.name
+ };
+
+ match members.entry(name.clone()) {
+ Entry::Occupied(entry) => {
+ entry.into_mut().enables.extend(enables);
+ }
+ Entry::Vacant(entry) => {
+ entry.insert(SpirvReqsMember {
+ name: name.clone(),
+ enables,
+ });
+ }
+ }
+ }
+
+ members.into_iter().map(|(_, v)| v).collect()
+}
+
+fn spirv_extensions_members(extensions: &[&SpirvExtOrCap]) -> Vec<SpirvReqsMember> {
+ extensions
+ .iter()
+ .map(|ext_or_cap| {
+ let enables: Vec<_> = ext_or_cap.enables.iter().filter_map(make_enable).collect();
+
+ SpirvReqsMember {
+ name: ext_or_cap.name.clone(),
+ enables,
+ }
+ })
+ .collect()
+}
+
+fn make_enable(enable: &vk_parse::Enable) -> Option<(Enable, String)> {
+ static VK_API_VERSION: Lazy<Regex> =
+ Lazy::new(|| Regex::new(r"^VK_(?:API_)?VERSION_(\d+)_(\d+)$").unwrap());
+ static BIT: Lazy<Regex> = Lazy::new(|| Regex::new(r"_BIT(?:_NV)?$").unwrap());
+
+ if matches!(enable, vk_parse::Enable::Version(version) if version == "VK_VERSION_1_0") {
+ return None;
+ }
+
+ Some(match enable {
+ vk_parse::Enable::Version(version) => {
+ let captures = VK_API_VERSION.captures(version).unwrap();
+ let major = captures.get(1).unwrap().as_str();
+ let minor = captures.get(1).unwrap().as_str();
+
+ (
+ Enable::Core((major.parse().unwrap(), minor.parse().unwrap())),
+ format!("Vulkan API version {}.{}", major, minor),
+ )
+ }
+ vk_parse::Enable::Extension(extension) => {
+ let extension_name = extension.strip_prefix("VK_").unwrap().to_snake_case();
+
+ (
+ Enable::Extension(format_ident!("{}", extension_name)),
+ format!("device extension `{}`", extension_name),
+ )
+ }
+ vk_parse::Enable::Feature(feature) => {
+ let feature_name = feature.feature.to_snake_case();
+
+ (
+ Enable::Feature(format_ident!("{}", feature_name)),
+ format!("feature `{}`", feature_name),
+ )
+ }
+ vk_parse::Enable::Property(property) => {
+ let property_name = property.member.to_snake_case();
+
+ let (value, description) = if property.value == "VK_TRUE" {
+ (PropertyValue::Bool, format!("property `{}`", property_name))
+ } else if let Some(member) = property.value.strip_prefix("VK_SUBGROUP_FEATURE_") {
+ let member = BIT.replace(member, "");
+ (
+ PropertyValue::BoolMember(
+ ["crate", "device", "physical", "SubgroupFeatures", &member]
+ .into_iter()
+ .map(|s| format_ident!("{}", s))
+ .collect(),
+ ),
+ format!("property `{}.{}`", property_name, member),
+ )
+ } else {
+ unimplemented!()
+ };
+
+ (
+ Enable::Property((format_ident!("{}", property_name), value)),
+ description,
+ )
+ }
+ _ => unimplemented!(),
+ })
+}
diff --git a/autogen/version.rs b/autogen/version.rs
new file mode 100644
index 0000000..dfaec8b
--- /dev/null
+++ b/autogen/version.rs
@@ -0,0 +1,52 @@
+// Copyright (c) 2022 The Vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use super::{write_file, VkRegistryData};
+use proc_macro2::{Literal, TokenStream};
+use quote::quote;
+
+pub fn write(vk_data: &VkRegistryData) {
+ let version_output = version_output(vk_data.header_version);
+ write_file(
+ "version.rs",
+ format!(
+ "vk.xml header version {}.{}.{}",
+ vk_data.header_version.0, vk_data.header_version.1, vk_data.header_version.2
+ ),
+ quote! {
+ #version_output
+ },
+ );
+}
+
+fn version_output((major, minor, patch): (u16, u16, u16)) -> TokenStream {
+ let major = Literal::u16_unsuffixed(major);
+ let minor = Literal::u16_unsuffixed(minor);
+ let patch = Literal::u16_unsuffixed(patch);
+
+ quote! {
+ impl Version {
+ /// The highest Vulkan API version currently supported by Vulkano.
+ ///
+ /// It is allowed for applications that use Vulkano to make use of features from higher
+ /// versions than this. However, Vulkano itself will not make use of those features and
+ /// will not expose their APIs, so they must be accessed by other means.
+ ///
+ /// The `max_api_version` of an [`Instance`](crate::instance::Instance) equals
+ /// `HEADER_VERSION` by default, which locks out features from newer versions. In order
+ /// to enable the use of higher versions, the `max_api_version` must be overridden when
+ /// creating an instance.
+ pub const HEADER_VERSION: Version = Version {
+ major: #major,
+ minor: #minor,
+ patch: #patch,
+ };
+ }
+ }
+}
diff --git a/build.rs b/build.rs
index 1f2b2bf..a2e9ce8 100644
--- a/build.rs
+++ b/build.rs
@@ -7,7 +7,7 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use std::{env, fs::File, io::BufWriter, path::Path};
+use std::env;
mod autogen;
@@ -24,9 +24,7 @@ fn main() {
println!("cargo:rustc-link-lib=framework=Foundation");
}
- // Write autogen.rs
+ // Run autogen
println!("cargo:rerun-if-changed=vk.xml");
- let path = Path::new(&env::var_os("OUT_DIR").unwrap()).join("autogen.rs");
- let mut writer = BufWriter::new(File::create(path).unwrap());
- autogen::write(&mut writer);
+ autogen::autogen();
}
diff --git a/out/autogen.rs b/out/autogen.rs
deleted file mode 100644
index 4158e48..0000000
--- a/out/autogen.rs
+++ /dev/null
@@ -1,9611 +0,0 @@
-// This file is auto-generated by vulkano-gen from vk.xml header version 186.
-// It should not be edited manually. Changes should be made by editing vulkano-gen.
-
-crate::device::extensions::device_extensions! {
- khr_16bit_storage => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_16bit_storage.html)
- - Requires device extension: [`khr_storage_buffer_storage_class`](crate::device::DeviceExtensions::khr_storage_buffer_storage_class)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- - Promoted to Vulkan 1.1
- ",
- raw: b"VK_KHR_16bit_storage",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_storage_buffer_storage_class],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_8bit_storage => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_8bit_storage.html)
- - Requires device extension: [`khr_storage_buffer_storage_class`](crate::device::DeviceExtensions::khr_storage_buffer_storage_class)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- - Promoted to Vulkan 1.2
- ",
- raw: b"VK_KHR_8bit_storage",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_storage_buffer_storage_class],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_acceleration_structure => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_acceleration_structure.html)
- - Requires Vulkan 1.1
- - Requires device extensions: [`ext_descriptor_indexing`](crate::device::DeviceExtensions::ext_descriptor_indexing), [`khr_buffer_device_address`](crate::device::DeviceExtensions::khr_buffer_device_address), [`khr_deferred_host_operations`](crate::device::DeviceExtensions::khr_deferred_host_operations)
- ",
- raw: b"VK_KHR_acceleration_structure",
- requires_core: crate::Version::V1_1,
- requires_device_extensions: [ext_descriptor_indexing, khr_buffer_device_address, khr_deferred_host_operations],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_bind_memory2 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_bind_memory2.html)
- - Promoted to Vulkan 1.1
- ",
- raw: b"VK_KHR_bind_memory2",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_buffer_device_address => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_buffer_device_address.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- - Conflicts with device extension: [`ext_buffer_device_address`](crate::device::DeviceExtensions::ext_buffer_device_address)
- - Promoted to Vulkan 1.2
- ",
- raw: b"VK_KHR_buffer_device_address",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [ext_buffer_device_address],
- },
- khr_copy_commands2 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_copy_commands2.html)
- ",
- raw: b"VK_KHR_copy_commands2",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_create_renderpass2 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_create_renderpass2.html)
- - Requires device extensions: [`khr_multiview`](crate::device::DeviceExtensions::khr_multiview), [`khr_maintenance2`](crate::device::DeviceExtensions::khr_maintenance2)
- - Promoted to Vulkan 1.2
- ",
- raw: b"VK_KHR_create_renderpass2",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_multiview, khr_maintenance2],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_dedicated_allocation => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_dedicated_allocation.html)
- - Requires device extension: [`khr_get_memory_requirements2`](crate::device::DeviceExtensions::khr_get_memory_requirements2)
- - Promoted to Vulkan 1.1
- ",
- raw: b"VK_KHR_dedicated_allocation",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_get_memory_requirements2],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_deferred_host_operations => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_deferred_host_operations.html)
- ",
- raw: b"VK_KHR_deferred_host_operations",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_depth_stencil_resolve => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_depth_stencil_resolve.html)
- - Requires device extension: [`khr_create_renderpass2`](crate::device::DeviceExtensions::khr_create_renderpass2)
- - Promoted to Vulkan 1.2
- ",
- raw: b"VK_KHR_depth_stencil_resolve",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_create_renderpass2],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_descriptor_update_template => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_descriptor_update_template.html)
- - Promoted to Vulkan 1.1
- ",
- raw: b"VK_KHR_descriptor_update_template",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_device_group => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_device_group.html)
- - Requires instance extension: [`khr_device_group_creation`](crate::instance::InstanceExtensions::khr_device_group_creation)
- - Promoted to Vulkan 1.1
- ",
- raw: b"VK_KHR_device_group",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_device_group_creation],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_display_swapchain => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_display_swapchain.html)
- - Requires device extension: [`khr_swapchain`](crate::device::DeviceExtensions::khr_swapchain)
- - Requires instance extension: [`khr_display`](crate::instance::InstanceExtensions::khr_display)
- ",
- raw: b"VK_KHR_display_swapchain",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_swapchain],
- requires_instance_extensions: [khr_display],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_draw_indirect_count => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_draw_indirect_count.html)
- - Promoted to Vulkan 1.2
- ",
- raw: b"VK_KHR_draw_indirect_count",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_driver_properties => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_driver_properties.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- - Promoted to Vulkan 1.2
- ",
- raw: b"VK_KHR_driver_properties",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_external_fence => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_external_fence.html)
- - Requires instance extension: [`khr_external_fence_capabilities`](crate::instance::InstanceExtensions::khr_external_fence_capabilities)
- - Promoted to Vulkan 1.1
- ",
- raw: b"VK_KHR_external_fence",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_external_fence_capabilities],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_external_fence_fd => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_external_fence_fd.html)
- - Requires device extension: [`khr_external_fence`](crate::device::DeviceExtensions::khr_external_fence)
- ",
- raw: b"VK_KHR_external_fence_fd",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_external_fence],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_external_fence_win32 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_external_fence_win32.html)
- - Requires device extension: [`khr_external_fence`](crate::device::DeviceExtensions::khr_external_fence)
- ",
- raw: b"VK_KHR_external_fence_win32",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_external_fence],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_external_memory => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_external_memory.html)
- - Requires instance extension: [`khr_external_memory_capabilities`](crate::instance::InstanceExtensions::khr_external_memory_capabilities)
- - Promoted to Vulkan 1.1
- ",
- raw: b"VK_KHR_external_memory",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_external_memory_capabilities],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_external_memory_fd => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_external_memory_fd.html)
- - Requires device extension: [`khr_external_memory`](crate::device::DeviceExtensions::khr_external_memory)
- ",
- raw: b"VK_KHR_external_memory_fd",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_external_memory],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_external_memory_win32 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_external_memory_win32.html)
- - Requires device extension: [`khr_external_memory`](crate::device::DeviceExtensions::khr_external_memory)
- ",
- raw: b"VK_KHR_external_memory_win32",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_external_memory],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_external_semaphore => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_external_semaphore.html)
- - Requires instance extension: [`khr_external_semaphore_capabilities`](crate::instance::InstanceExtensions::khr_external_semaphore_capabilities)
- - Promoted to Vulkan 1.1
- ",
- raw: b"VK_KHR_external_semaphore",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_external_semaphore_capabilities],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_external_semaphore_fd => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_external_semaphore_fd.html)
- - Requires device extension: [`khr_external_semaphore`](crate::device::DeviceExtensions::khr_external_semaphore)
- ",
- raw: b"VK_KHR_external_semaphore_fd",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_external_semaphore],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_external_semaphore_win32 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_external_semaphore_win32.html)
- - Requires device extension: [`khr_external_semaphore`](crate::device::DeviceExtensions::khr_external_semaphore)
- ",
- raw: b"VK_KHR_external_semaphore_win32",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_external_semaphore],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_fragment_shading_rate => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_fragment_shading_rate.html)
- - Requires device extension: [`khr_create_renderpass2`](crate::device::DeviceExtensions::khr_create_renderpass2)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_KHR_fragment_shading_rate",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_create_renderpass2],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_get_memory_requirements2 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_get_memory_requirements2.html)
- - Promoted to Vulkan 1.1
- ",
- raw: b"VK_KHR_get_memory_requirements2",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_image_format_list => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_image_format_list.html)
- - Promoted to Vulkan 1.2
- ",
- raw: b"VK_KHR_image_format_list",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_imageless_framebuffer => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_imageless_framebuffer.html)
- - Requires device extensions: [`khr_maintenance2`](crate::device::DeviceExtensions::khr_maintenance2), [`khr_image_format_list`](crate::device::DeviceExtensions::khr_image_format_list)
- - Promoted to Vulkan 1.2
- ",
- raw: b"VK_KHR_imageless_framebuffer",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_maintenance2, khr_image_format_list],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_incremental_present => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_incremental_present.html)
- - Requires device extension: [`khr_swapchain`](crate::device::DeviceExtensions::khr_swapchain)
- ",
- raw: b"VK_KHR_incremental_present",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_swapchain],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_maintenance1 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_maintenance1.html)
- - Promoted to Vulkan 1.1
- ",
- raw: b"VK_KHR_maintenance1",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_maintenance2 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_maintenance2.html)
- - Promoted to Vulkan 1.1
- ",
- raw: b"VK_KHR_maintenance2",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_maintenance3 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_maintenance3.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- - Promoted to Vulkan 1.1
- ",
- raw: b"VK_KHR_maintenance3",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_multiview => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_multiview.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- - Promoted to Vulkan 1.1
- ",
- raw: b"VK_KHR_multiview",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_performance_query => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_performance_query.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_KHR_performance_query",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_pipeline_executable_properties => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_pipeline_executable_properties.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_KHR_pipeline_executable_properties",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_pipeline_library => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_pipeline_library.html)
- ",
- raw: b"VK_KHR_pipeline_library",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_portability_subset => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_portability_subset.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- - Must be enabled if it is supported by the physical device
- ",
- raw: b"VK_KHR_portability_subset",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: true,
- conflicts_device_extensions: [],
- },
- khr_present_id => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_present_id.html)
- - Requires device extension: [`khr_swapchain`](crate::device::DeviceExtensions::khr_swapchain)
- ",
- raw: b"VK_KHR_present_id",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_swapchain],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_present_wait => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_present_wait.html)
- - Requires device extensions: [`khr_swapchain`](crate::device::DeviceExtensions::khr_swapchain), [`khr_present_id`](crate::device::DeviceExtensions::khr_present_id)
- ",
- raw: b"VK_KHR_present_wait",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_swapchain, khr_present_id],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_push_descriptor => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_push_descriptor.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_KHR_push_descriptor",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_ray_query => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_ray_query.html)
- - Requires Vulkan 1.1
- - Requires device extensions: [`khr_spirv_1_4`](crate::device::DeviceExtensions::khr_spirv_1_4), [`khr_acceleration_structure`](crate::device::DeviceExtensions::khr_acceleration_structure)
- ",
- raw: b"VK_KHR_ray_query",
- requires_core: crate::Version::V1_1,
- requires_device_extensions: [khr_spirv_1_4, khr_acceleration_structure],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_ray_tracing_pipeline => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_ray_tracing_pipeline.html)
- - Requires Vulkan 1.1
- - Requires device extensions: [`khr_spirv_1_4`](crate::device::DeviceExtensions::khr_spirv_1_4), [`khr_acceleration_structure`](crate::device::DeviceExtensions::khr_acceleration_structure)
- ",
- raw: b"VK_KHR_ray_tracing_pipeline",
- requires_core: crate::Version::V1_1,
- requires_device_extensions: [khr_spirv_1_4, khr_acceleration_structure],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_relaxed_block_layout => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_relaxed_block_layout.html)
- - Promoted to Vulkan 1.1
- ",
- raw: b"VK_KHR_relaxed_block_layout",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_sampler_mirror_clamp_to_edge => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_sampler_mirror_clamp_to_edge.html)
- - Promoted to Vulkan 1.2
- ",
- raw: b"VK_KHR_sampler_mirror_clamp_to_edge",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_sampler_ycbcr_conversion => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_sampler_ycbcr_conversion.html)
- - Requires device extensions: [`khr_maintenance1`](crate::device::DeviceExtensions::khr_maintenance1), [`khr_bind_memory2`](crate::device::DeviceExtensions::khr_bind_memory2), [`khr_get_memory_requirements2`](crate::device::DeviceExtensions::khr_get_memory_requirements2)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- - Promoted to Vulkan 1.1
- ",
- raw: b"VK_KHR_sampler_ycbcr_conversion",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_maintenance1, khr_bind_memory2, khr_get_memory_requirements2],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_separate_depth_stencil_layouts => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_separate_depth_stencil_layouts.html)
- - Requires device extension: [`khr_create_renderpass2`](crate::device::DeviceExtensions::khr_create_renderpass2)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- - Promoted to Vulkan 1.2
- ",
- raw: b"VK_KHR_separate_depth_stencil_layouts",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_create_renderpass2],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_shader_atomic_int64 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_shader_atomic_int64.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- - Promoted to Vulkan 1.2
- ",
- raw: b"VK_KHR_shader_atomic_int64",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_shader_clock => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_shader_clock.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_KHR_shader_clock",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_shader_draw_parameters => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_shader_draw_parameters.html)
- - Promoted to Vulkan 1.1
- ",
- raw: b"VK_KHR_shader_draw_parameters",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_shader_float16_int8 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_shader_float16_int8.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- - Promoted to Vulkan 1.2
- ",
- raw: b"VK_KHR_shader_float16_int8",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_shader_float_controls => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_shader_float_controls.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- - Promoted to Vulkan 1.2
- ",
- raw: b"VK_KHR_shader_float_controls",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_shader_non_semantic_info => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_shader_non_semantic_info.html)
- ",
- raw: b"VK_KHR_shader_non_semantic_info",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_shader_subgroup_extended_types => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_shader_subgroup_extended_types.html)
- - Requires Vulkan 1.1
- - Promoted to Vulkan 1.2
- ",
- raw: b"VK_KHR_shader_subgroup_extended_types",
- requires_core: crate::Version::V1_1,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_shader_subgroup_uniform_control_flow => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_shader_subgroup_uniform_control_flow.html)
- - Requires Vulkan 1.1
- ",
- raw: b"VK_KHR_shader_subgroup_uniform_control_flow",
- requires_core: crate::Version::V1_1,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_shader_terminate_invocation => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_shader_terminate_invocation.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_KHR_shader_terminate_invocation",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_shared_presentable_image => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_shared_presentable_image.html)
- - Requires device extension: [`khr_swapchain`](crate::device::DeviceExtensions::khr_swapchain)
- - Requires instance extensions: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2), [`khr_get_surface_capabilities2`](crate::instance::InstanceExtensions::khr_get_surface_capabilities2)
- ",
- raw: b"VK_KHR_shared_presentable_image",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_swapchain],
- requires_instance_extensions: [khr_get_physical_device_properties2, khr_get_surface_capabilities2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_spirv_1_4 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_spirv_1_4.html)
- - Requires Vulkan 1.1
- - Requires device extension: [`khr_shader_float_controls`](crate::device::DeviceExtensions::khr_shader_float_controls)
- - Promoted to Vulkan 1.2
- ",
- raw: b"VK_KHR_spirv_1_4",
- requires_core: crate::Version::V1_1,
- requires_device_extensions: [khr_shader_float_controls],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_storage_buffer_storage_class => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_storage_buffer_storage_class.html)
- - Promoted to Vulkan 1.1
- ",
- raw: b"VK_KHR_storage_buffer_storage_class",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_swapchain => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_swapchain.html)
- - Requires instance extension: [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)
- ",
- raw: b"VK_KHR_swapchain",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_surface],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_swapchain_mutable_format => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_swapchain_mutable_format.html)
- - Requires device extensions: [`khr_swapchain`](crate::device::DeviceExtensions::khr_swapchain), [`khr_maintenance2`](crate::device::DeviceExtensions::khr_maintenance2), [`khr_image_format_list`](crate::device::DeviceExtensions::khr_image_format_list)
- ",
- raw: b"VK_KHR_swapchain_mutable_format",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_swapchain, khr_maintenance2, khr_image_format_list],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_synchronization2 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_synchronization2.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_KHR_synchronization2",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_timeline_semaphore => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_timeline_semaphore.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- - Promoted to Vulkan 1.2
- ",
- raw: b"VK_KHR_timeline_semaphore",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_uniform_buffer_standard_layout => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_uniform_buffer_standard_layout.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- - Promoted to Vulkan 1.2
- ",
- raw: b"VK_KHR_uniform_buffer_standard_layout",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_variable_pointers => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_variable_pointers.html)
- - Requires device extension: [`khr_storage_buffer_storage_class`](crate::device::DeviceExtensions::khr_storage_buffer_storage_class)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- - Promoted to Vulkan 1.1
- ",
- raw: b"VK_KHR_variable_pointers",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_storage_buffer_storage_class],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_video_decode_queue => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_video_decode_queue.html)
- - Requires device extensions: [`khr_video_queue`](crate::device::DeviceExtensions::khr_video_queue), [`khr_synchronization2`](crate::device::DeviceExtensions::khr_synchronization2)
- ",
- raw: b"VK_KHR_video_decode_queue",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_video_queue, khr_synchronization2],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_video_encode_queue => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_video_encode_queue.html)
- - Requires device extensions: [`khr_video_queue`](crate::device::DeviceExtensions::khr_video_queue), [`khr_synchronization2`](crate::device::DeviceExtensions::khr_synchronization2)
- ",
- raw: b"VK_KHR_video_encode_queue",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_video_queue, khr_synchronization2],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_video_queue => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_video_queue.html)
- - Requires device extension: [`khr_sampler_ycbcr_conversion`](crate::device::DeviceExtensions::khr_sampler_ycbcr_conversion)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_KHR_video_queue",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_sampler_ycbcr_conversion],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_vulkan_memory_model => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_vulkan_memory_model.html)
- - Promoted to Vulkan 1.2
- ",
- raw: b"VK_KHR_vulkan_memory_model",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_win32_keyed_mutex => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_win32_keyed_mutex.html)
- - Requires device extension: [`khr_external_memory_win32`](crate::device::DeviceExtensions::khr_external_memory_win32)
- ",
- raw: b"VK_KHR_win32_keyed_mutex",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_external_memory_win32],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_workgroup_memory_explicit_layout => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_workgroup_memory_explicit_layout.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_KHR_workgroup_memory_explicit_layout",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- khr_zero_initialize_workgroup_memory => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_zero_initialize_workgroup_memory.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_KHR_zero_initialize_workgroup_memory",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_4444_formats => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_4444_formats.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_EXT_4444_formats",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_astc_decode_mode => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_astc_decode_mode.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_EXT_astc_decode_mode",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_blend_operation_advanced => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_blend_operation_advanced.html)
- ",
- raw: b"VK_EXT_blend_operation_advanced",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_buffer_device_address => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_buffer_device_address.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- - Conflicts with device extension: [`khr_buffer_device_address`](crate::device::DeviceExtensions::khr_buffer_device_address)
- - Deprecated by [`khr_buffer_device_address`](crate::device::DeviceExtensions::khr_buffer_device_address)
- ",
- raw: b"VK_EXT_buffer_device_address",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [khr_buffer_device_address],
- },
- ext_calibrated_timestamps => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_calibrated_timestamps.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_EXT_calibrated_timestamps",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_color_write_enable => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_color_write_enable.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_EXT_color_write_enable",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_conditional_rendering => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_conditional_rendering.html)
- ",
- raw: b"VK_EXT_conditional_rendering",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_conservative_rasterization => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_conservative_rasterization.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_EXT_conservative_rasterization",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_custom_border_color => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_custom_border_color.html)
- ",
- raw: b"VK_EXT_custom_border_color",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_debug_marker => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_debug_marker.html)
- - Requires instance extension: [`ext_debug_report`](crate::instance::InstanceExtensions::ext_debug_report)
- - Promoted to [`ext_debug_utils`](crate::instance::InstanceExtensions::ext_debug_utils)
- ",
- raw: b"VK_EXT_debug_marker",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [ext_debug_report],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_depth_clip_enable => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_depth_clip_enable.html)
- ",
- raw: b"VK_EXT_depth_clip_enable",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_depth_range_unrestricted => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_depth_range_unrestricted.html)
- ",
- raw: b"VK_EXT_depth_range_unrestricted",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_descriptor_indexing => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_descriptor_indexing.html)
- - Requires device extension: [`khr_maintenance3`](crate::device::DeviceExtensions::khr_maintenance3)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- - Promoted to Vulkan 1.2
- ",
- raw: b"VK_EXT_descriptor_indexing",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_maintenance3],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_device_memory_report => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_device_memory_report.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_EXT_device_memory_report",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_discard_rectangles => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_discard_rectangles.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_EXT_discard_rectangles",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_display_control => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_display_control.html)
- - Requires device extension: [`khr_swapchain`](crate::device::DeviceExtensions::khr_swapchain)
- - Requires instance extension: [`ext_display_surface_counter`](crate::instance::InstanceExtensions::ext_display_surface_counter)
- ",
- raw: b"VK_EXT_display_control",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_swapchain],
- requires_instance_extensions: [ext_display_surface_counter],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_extended_dynamic_state => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_extended_dynamic_state.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_EXT_extended_dynamic_state",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_extended_dynamic_state2 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_extended_dynamic_state2.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_EXT_extended_dynamic_state2",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_external_memory_dma_buf => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_external_memory_dma_buf.html)
- - Requires device extension: [`khr_external_memory_fd`](crate::device::DeviceExtensions::khr_external_memory_fd)
- ",
- raw: b"VK_EXT_external_memory_dma_buf",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_external_memory_fd],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_external_memory_host => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_external_memory_host.html)
- - Requires device extension: [`khr_external_memory`](crate::device::DeviceExtensions::khr_external_memory)
- ",
- raw: b"VK_EXT_external_memory_host",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_external_memory],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_filter_cubic => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_filter_cubic.html)
- ",
- raw: b"VK_EXT_filter_cubic",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_fragment_density_map => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_fragment_density_map.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_EXT_fragment_density_map",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_fragment_density_map2 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_fragment_density_map2.html)
- - Requires device extension: [`ext_fragment_density_map`](crate::device::DeviceExtensions::ext_fragment_density_map)
- ",
- raw: b"VK_EXT_fragment_density_map2",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [ext_fragment_density_map],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_fragment_shader_interlock => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_fragment_shader_interlock.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_EXT_fragment_shader_interlock",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_full_screen_exclusive => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_full_screen_exclusive.html)
- - Requires device extension: [`khr_swapchain`](crate::device::DeviceExtensions::khr_swapchain)
- - Requires instance extensions: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2), [`khr_surface`](crate::instance::InstanceExtensions::khr_surface), [`khr_get_surface_capabilities2`](crate::instance::InstanceExtensions::khr_get_surface_capabilities2)
- ",
- raw: b"VK_EXT_full_screen_exclusive",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_swapchain],
- requires_instance_extensions: [khr_get_physical_device_properties2, khr_surface, khr_get_surface_capabilities2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_global_priority => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_global_priority.html)
- ",
- raw: b"VK_EXT_global_priority",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_global_priority_query => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_global_priority_query.html)
- - Requires device extension: [`ext_global_priority`](crate::device::DeviceExtensions::ext_global_priority)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_EXT_global_priority_query",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [ext_global_priority],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_hdr_metadata => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_hdr_metadata.html)
- - Requires device extension: [`khr_swapchain`](crate::device::DeviceExtensions::khr_swapchain)
- ",
- raw: b"VK_EXT_hdr_metadata",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_swapchain],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_host_query_reset => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_host_query_reset.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- - Promoted to Vulkan 1.2
- ",
- raw: b"VK_EXT_host_query_reset",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_image_drm_format_modifier => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_image_drm_format_modifier.html)
- - Requires device extensions: [`khr_bind_memory2`](crate::device::DeviceExtensions::khr_bind_memory2), [`khr_image_format_list`](crate::device::DeviceExtensions::khr_image_format_list), [`khr_sampler_ycbcr_conversion`](crate::device::DeviceExtensions::khr_sampler_ycbcr_conversion)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_EXT_image_drm_format_modifier",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_bind_memory2, khr_image_format_list, khr_sampler_ycbcr_conversion],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_image_robustness => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_image_robustness.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_EXT_image_robustness",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_index_type_uint8 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_index_type_uint8.html)
- ",
- raw: b"VK_EXT_index_type_uint8",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_inline_uniform_block => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_inline_uniform_block.html)
- - Requires device extension: [`khr_maintenance1`](crate::device::DeviceExtensions::khr_maintenance1)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_EXT_inline_uniform_block",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_maintenance1],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_line_rasterization => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_line_rasterization.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_EXT_line_rasterization",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_memory_budget => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_memory_budget.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_EXT_memory_budget",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_memory_priority => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_memory_priority.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_EXT_memory_priority",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_multi_draw => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_multi_draw.html)
- ",
- raw: b"VK_EXT_multi_draw",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_pci_bus_info => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_pci_bus_info.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_EXT_pci_bus_info",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_physical_device_drm => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_physical_device_drm.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_EXT_physical_device_drm",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_pipeline_creation_cache_control => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_pipeline_creation_cache_control.html)
- ",
- raw: b"VK_EXT_pipeline_creation_cache_control",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_pipeline_creation_feedback => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_pipeline_creation_feedback.html)
- ",
- raw: b"VK_EXT_pipeline_creation_feedback",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_post_depth_coverage => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_post_depth_coverage.html)
- ",
- raw: b"VK_EXT_post_depth_coverage",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_private_data => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_private_data.html)
- ",
- raw: b"VK_EXT_private_data",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_provoking_vertex => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_provoking_vertex.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_EXT_provoking_vertex",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_queue_family_foreign => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_queue_family_foreign.html)
- - Requires device extension: [`khr_external_memory`](crate::device::DeviceExtensions::khr_external_memory)
- ",
- raw: b"VK_EXT_queue_family_foreign",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_external_memory],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_robustness2 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_robustness2.html)
- ",
- raw: b"VK_EXT_robustness2",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_sample_locations => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_sample_locations.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_EXT_sample_locations",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_sampler_filter_minmax => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_sampler_filter_minmax.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- - Promoted to Vulkan 1.2
- ",
- raw: b"VK_EXT_sampler_filter_minmax",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_scalar_block_layout => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_scalar_block_layout.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- - Promoted to Vulkan 1.2
- ",
- raw: b"VK_EXT_scalar_block_layout",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_separate_stencil_usage => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_separate_stencil_usage.html)
- - Promoted to Vulkan 1.2
- ",
- raw: b"VK_EXT_separate_stencil_usage",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_shader_atomic_float => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_shader_atomic_float.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_EXT_shader_atomic_float",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_shader_atomic_float2 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_shader_atomic_float2.html)
- - Requires device extension: [`ext_shader_atomic_float`](crate::device::DeviceExtensions::ext_shader_atomic_float)
- ",
- raw: b"VK_EXT_shader_atomic_float2",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [ext_shader_atomic_float],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_shader_demote_to_helper_invocation => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_shader_demote_to_helper_invocation.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_EXT_shader_demote_to_helper_invocation",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_shader_image_atomic_int64 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_shader_image_atomic_int64.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_EXT_shader_image_atomic_int64",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_shader_stencil_export => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_shader_stencil_export.html)
- ",
- raw: b"VK_EXT_shader_stencil_export",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_shader_subgroup_ballot => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_shader_subgroup_ballot.html)
- - Deprecated by Vulkan 1.2
- ",
- raw: b"VK_EXT_shader_subgroup_ballot",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_shader_subgroup_vote => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_shader_subgroup_vote.html)
- - Deprecated by Vulkan 1.1
- ",
- raw: b"VK_EXT_shader_subgroup_vote",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_shader_viewport_index_layer => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_shader_viewport_index_layer.html)
- - Promoted to Vulkan 1.2
- ",
- raw: b"VK_EXT_shader_viewport_index_layer",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_subgroup_size_control => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_subgroup_size_control.html)
- - Requires Vulkan 1.1
- ",
- raw: b"VK_EXT_subgroup_size_control",
- requires_core: crate::Version::V1_1,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_texel_buffer_alignment => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_texel_buffer_alignment.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_EXT_texel_buffer_alignment",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_texture_compression_astc_hdr => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_texture_compression_astc_hdr.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_EXT_texture_compression_astc_hdr",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_tooling_info => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_tooling_info.html)
- ",
- raw: b"VK_EXT_tooling_info",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_transform_feedback => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_transform_feedback.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_EXT_transform_feedback",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_validation_cache => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_validation_cache.html)
- ",
- raw: b"VK_EXT_validation_cache",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_vertex_attribute_divisor => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_vertex_attribute_divisor.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_EXT_vertex_attribute_divisor",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_vertex_input_dynamic_state => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_vertex_input_dynamic_state.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_EXT_vertex_input_dynamic_state",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_video_decode_h264 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_video_decode_h264.html)
- - Requires device extension: [`khr_video_decode_queue`](crate::device::DeviceExtensions::khr_video_decode_queue)
- ",
- raw: b"VK_EXT_video_decode_h264",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_video_decode_queue],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_video_decode_h265 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_video_decode_h265.html)
- - Requires device extension: [`khr_video_decode_queue`](crate::device::DeviceExtensions::khr_video_decode_queue)
- ",
- raw: b"VK_EXT_video_decode_h265",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_video_decode_queue],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_video_encode_h264 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_video_encode_h264.html)
- - Requires device extension: [`khr_video_encode_queue`](crate::device::DeviceExtensions::khr_video_encode_queue)
- ",
- raw: b"VK_EXT_video_encode_h264",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_video_encode_queue],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_ycbcr_2plane_444_formats => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_ycbcr_2plane_444_formats.html)
- - Requires device extension: [`khr_sampler_ycbcr_conversion`](crate::device::DeviceExtensions::khr_sampler_ycbcr_conversion)
- ",
- raw: b"VK_EXT_ycbcr_2plane_444_formats",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_sampler_ycbcr_conversion],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ext_ycbcr_image_arrays => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_ycbcr_image_arrays.html)
- - Requires device extension: [`khr_sampler_ycbcr_conversion`](crate::device::DeviceExtensions::khr_sampler_ycbcr_conversion)
- ",
- raw: b"VK_EXT_ycbcr_image_arrays",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_sampler_ycbcr_conversion],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- amd_buffer_marker => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_AMD_buffer_marker.html)
- ",
- raw: b"VK_AMD_buffer_marker",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- amd_device_coherent_memory => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_AMD_device_coherent_memory.html)
- ",
- raw: b"VK_AMD_device_coherent_memory",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- amd_display_native_hdr => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_AMD_display_native_hdr.html)
- - Requires device extension: [`khr_swapchain`](crate::device::DeviceExtensions::khr_swapchain)
- - Requires instance extensions: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2), [`khr_get_surface_capabilities2`](crate::instance::InstanceExtensions::khr_get_surface_capabilities2)
- ",
- raw: b"VK_AMD_display_native_hdr",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_swapchain],
- requires_instance_extensions: [khr_get_physical_device_properties2, khr_get_surface_capabilities2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- amd_draw_indirect_count => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_AMD_draw_indirect_count.html)
- - Promoted to [`khr_draw_indirect_count`](crate::device::DeviceExtensions::khr_draw_indirect_count)
- ",
- raw: b"VK_AMD_draw_indirect_count",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- amd_gcn_shader => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_AMD_gcn_shader.html)
- ",
- raw: b"VK_AMD_gcn_shader",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- amd_gpu_shader_half_float => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_AMD_gpu_shader_half_float.html)
- - Deprecated by [`khr_shader_float16_int8`](crate::device::DeviceExtensions::khr_shader_float16_int8)
- ",
- raw: b"VK_AMD_gpu_shader_half_float",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- amd_gpu_shader_int16 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_AMD_gpu_shader_int16.html)
- - Deprecated by [`khr_shader_float16_int8`](crate::device::DeviceExtensions::khr_shader_float16_int8)
- ",
- raw: b"VK_AMD_gpu_shader_int16",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- amd_memory_overallocation_behavior => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_AMD_memory_overallocation_behavior.html)
- ",
- raw: b"VK_AMD_memory_overallocation_behavior",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- amd_mixed_attachment_samples => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_AMD_mixed_attachment_samples.html)
- ",
- raw: b"VK_AMD_mixed_attachment_samples",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- amd_pipeline_compiler_control => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_AMD_pipeline_compiler_control.html)
- ",
- raw: b"VK_AMD_pipeline_compiler_control",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- amd_rasterization_order => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_AMD_rasterization_order.html)
- ",
- raw: b"VK_AMD_rasterization_order",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- amd_shader_ballot => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_AMD_shader_ballot.html)
- ",
- raw: b"VK_AMD_shader_ballot",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- amd_shader_core_properties => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_AMD_shader_core_properties.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_AMD_shader_core_properties",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- amd_shader_core_properties2 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_AMD_shader_core_properties2.html)
- - Requires device extension: [`amd_shader_core_properties`](crate::device::DeviceExtensions::amd_shader_core_properties)
- ",
- raw: b"VK_AMD_shader_core_properties2",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [amd_shader_core_properties],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- amd_shader_explicit_vertex_parameter => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_AMD_shader_explicit_vertex_parameter.html)
- ",
- raw: b"VK_AMD_shader_explicit_vertex_parameter",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- amd_shader_fragment_mask => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_AMD_shader_fragment_mask.html)
- ",
- raw: b"VK_AMD_shader_fragment_mask",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- amd_shader_image_load_store_lod => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_AMD_shader_image_load_store_lod.html)
- ",
- raw: b"VK_AMD_shader_image_load_store_lod",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- amd_shader_info => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_AMD_shader_info.html)
- ",
- raw: b"VK_AMD_shader_info",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- amd_shader_trinary_minmax => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_AMD_shader_trinary_minmax.html)
- ",
- raw: b"VK_AMD_shader_trinary_minmax",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- amd_texture_gather_bias_lod => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_AMD_texture_gather_bias_lod.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_AMD_texture_gather_bias_lod",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- android_external_memory_android_hardware_buffer => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_ANDROID_external_memory_android_hardware_buffer.html)
- - Requires device extensions: [`khr_sampler_ycbcr_conversion`](crate::device::DeviceExtensions::khr_sampler_ycbcr_conversion), [`khr_external_memory`](crate::device::DeviceExtensions::khr_external_memory), [`ext_queue_family_foreign`](crate::device::DeviceExtensions::ext_queue_family_foreign), [`khr_dedicated_allocation`](crate::device::DeviceExtensions::khr_dedicated_allocation)
- ",
- raw: b"VK_ANDROID_external_memory_android_hardware_buffer",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_sampler_ycbcr_conversion, khr_external_memory, ext_queue_family_foreign, khr_dedicated_allocation],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- fuchsia_external_memory => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_FUCHSIA_external_memory.html)
- - Requires device extension: [`khr_external_memory`](crate::device::DeviceExtensions::khr_external_memory)
- - Requires instance extension: [`khr_external_memory_capabilities`](crate::instance::InstanceExtensions::khr_external_memory_capabilities)
- ",
- raw: b"VK_FUCHSIA_external_memory",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_external_memory],
- requires_instance_extensions: [khr_external_memory_capabilities],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- fuchsia_external_semaphore => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_FUCHSIA_external_semaphore.html)
- - Requires device extension: [`khr_external_semaphore`](crate::device::DeviceExtensions::khr_external_semaphore)
- - Requires instance extension: [`khr_external_semaphore_capabilities`](crate::instance::InstanceExtensions::khr_external_semaphore_capabilities)
- ",
- raw: b"VK_FUCHSIA_external_semaphore",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_external_semaphore],
- requires_instance_extensions: [khr_external_semaphore_capabilities],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- ggp_frame_token => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_GGP_frame_token.html)
- - Requires device extension: [`khr_swapchain`](crate::device::DeviceExtensions::khr_swapchain)
- - Requires instance extension: [`ggp_stream_descriptor_surface`](crate::instance::InstanceExtensions::ggp_stream_descriptor_surface)
- ",
- raw: b"VK_GGP_frame_token",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_swapchain],
- requires_instance_extensions: [ggp_stream_descriptor_surface],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- google_decorate_string => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_GOOGLE_decorate_string.html)
- ",
- raw: b"VK_GOOGLE_decorate_string",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- google_display_timing => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_GOOGLE_display_timing.html)
- - Requires device extension: [`khr_swapchain`](crate::device::DeviceExtensions::khr_swapchain)
- ",
- raw: b"VK_GOOGLE_display_timing",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_swapchain],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- google_hlsl_functionality1 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_GOOGLE_hlsl_functionality1.html)
- ",
- raw: b"VK_GOOGLE_hlsl_functionality1",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- google_user_type => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_GOOGLE_user_type.html)
- ",
- raw: b"VK_GOOGLE_user_type",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- huawei_invocation_mask => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_HUAWEI_invocation_mask.html)
- - Requires device extensions: [`khr_ray_tracing_pipeline`](crate::device::DeviceExtensions::khr_ray_tracing_pipeline), [`khr_synchronization2`](crate::device::DeviceExtensions::khr_synchronization2)
- ",
- raw: b"VK_HUAWEI_invocation_mask",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_ray_tracing_pipeline, khr_synchronization2],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- huawei_subpass_shading => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_HUAWEI_subpass_shading.html)
- - Requires device extensions: [`khr_create_renderpass2`](crate::device::DeviceExtensions::khr_create_renderpass2), [`khr_synchronization2`](crate::device::DeviceExtensions::khr_synchronization2)
- ",
- raw: b"VK_HUAWEI_subpass_shading",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_create_renderpass2, khr_synchronization2],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- img_filter_cubic => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_IMG_filter_cubic.html)
- ",
- raw: b"VK_IMG_filter_cubic",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- img_format_pvrtc => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_IMG_format_pvrtc.html)
- ",
- raw: b"VK_IMG_format_pvrtc",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- intel_performance_query => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_INTEL_performance_query.html)
- ",
- raw: b"VK_INTEL_performance_query",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- intel_shader_integer_functions2 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_INTEL_shader_integer_functions2.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_INTEL_shader_integer_functions2",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nvx_binary_import => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NVX_binary_import.html)
- ",
- raw: b"VK_NVX_binary_import",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nvx_image_view_handle => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NVX_image_view_handle.html)
- ",
- raw: b"VK_NVX_image_view_handle",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nvx_multiview_per_view_attributes => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NVX_multiview_per_view_attributes.html)
- - Requires device extension: [`khr_multiview`](crate::device::DeviceExtensions::khr_multiview)
- ",
- raw: b"VK_NVX_multiview_per_view_attributes",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_multiview],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_acquire_winrt_display => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_acquire_winrt_display.html)
- - Requires instance extension: [`ext_direct_mode_display`](crate::instance::InstanceExtensions::ext_direct_mode_display)
- ",
- raw: b"VK_NV_acquire_winrt_display",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [ext_direct_mode_display],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_clip_space_w_scaling => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_clip_space_w_scaling.html)
- ",
- raw: b"VK_NV_clip_space_w_scaling",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_compute_shader_derivatives => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_compute_shader_derivatives.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_NV_compute_shader_derivatives",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_cooperative_matrix => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_cooperative_matrix.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_NV_cooperative_matrix",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_corner_sampled_image => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_corner_sampled_image.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_NV_corner_sampled_image",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_coverage_reduction_mode => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_coverage_reduction_mode.html)
- - Requires device extension: [`nv_framebuffer_mixed_samples`](crate::device::DeviceExtensions::nv_framebuffer_mixed_samples)
- ",
- raw: b"VK_NV_coverage_reduction_mode",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [nv_framebuffer_mixed_samples],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_dedicated_allocation => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_dedicated_allocation.html)
- - Deprecated by [`khr_dedicated_allocation`](crate::device::DeviceExtensions::khr_dedicated_allocation)
- ",
- raw: b"VK_NV_dedicated_allocation",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_dedicated_allocation_image_aliasing => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_dedicated_allocation_image_aliasing.html)
- - Requires device extension: [`khr_dedicated_allocation`](crate::device::DeviceExtensions::khr_dedicated_allocation)
- ",
- raw: b"VK_NV_dedicated_allocation_image_aliasing",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_dedicated_allocation],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_device_diagnostic_checkpoints => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_device_diagnostic_checkpoints.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_NV_device_diagnostic_checkpoints",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_device_diagnostics_config => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_device_diagnostics_config.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_NV_device_diagnostics_config",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_device_generated_commands => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_device_generated_commands.html)
- - Requires Vulkan 1.1
- ",
- raw: b"VK_NV_device_generated_commands",
- requires_core: crate::Version::V1_1,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_external_memory => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_external_memory.html)
- - Requires instance extension: [`nv_external_memory_capabilities`](crate::instance::InstanceExtensions::nv_external_memory_capabilities)
- - Deprecated by [`khr_external_memory`](crate::device::DeviceExtensions::khr_external_memory)
- ",
- raw: b"VK_NV_external_memory",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [nv_external_memory_capabilities],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_external_memory_rdma => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_external_memory_rdma.html)
- - Requires device extension: [`khr_external_memory`](crate::device::DeviceExtensions::khr_external_memory)
- ",
- raw: b"VK_NV_external_memory_rdma",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_external_memory],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_external_memory_win32 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_external_memory_win32.html)
- - Requires device extension: [`nv_external_memory`](crate::device::DeviceExtensions::nv_external_memory)
- - Deprecated by [`khr_external_memory_win32`](crate::device::DeviceExtensions::khr_external_memory_win32)
- ",
- raw: b"VK_NV_external_memory_win32",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [nv_external_memory],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_fill_rectangle => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_fill_rectangle.html)
- ",
- raw: b"VK_NV_fill_rectangle",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_fragment_coverage_to_color => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_fragment_coverage_to_color.html)
- ",
- raw: b"VK_NV_fragment_coverage_to_color",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_fragment_shader_barycentric => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_fragment_shader_barycentric.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_NV_fragment_shader_barycentric",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_fragment_shading_rate_enums => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_fragment_shading_rate_enums.html)
- - Requires device extension: [`khr_fragment_shading_rate`](crate::device::DeviceExtensions::khr_fragment_shading_rate)
- ",
- raw: b"VK_NV_fragment_shading_rate_enums",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_fragment_shading_rate],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_framebuffer_mixed_samples => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_framebuffer_mixed_samples.html)
- ",
- raw: b"VK_NV_framebuffer_mixed_samples",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_geometry_shader_passthrough => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_geometry_shader_passthrough.html)
- ",
- raw: b"VK_NV_geometry_shader_passthrough",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_glsl_shader => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_glsl_shader.html)
- - Deprecated without a replacement
- ",
- raw: b"VK_NV_glsl_shader",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_inherited_viewport_scissor => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_inherited_viewport_scissor.html)
- ",
- raw: b"VK_NV_inherited_viewport_scissor",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_mesh_shader => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_mesh_shader.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_NV_mesh_shader",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_ray_tracing => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_ray_tracing.html)
- - Requires device extension: [`khr_get_memory_requirements2`](crate::device::DeviceExtensions::khr_get_memory_requirements2)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_NV_ray_tracing",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_get_memory_requirements2],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_ray_tracing_motion_blur => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_ray_tracing_motion_blur.html)
- - Requires device extension: [`khr_ray_tracing_pipeline`](crate::device::DeviceExtensions::khr_ray_tracing_pipeline)
- ",
- raw: b"VK_NV_ray_tracing_motion_blur",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_ray_tracing_pipeline],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_representative_fragment_test => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_representative_fragment_test.html)
- ",
- raw: b"VK_NV_representative_fragment_test",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_sample_mask_override_coverage => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_sample_mask_override_coverage.html)
- ",
- raw: b"VK_NV_sample_mask_override_coverage",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_scissor_exclusive => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_scissor_exclusive.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_NV_scissor_exclusive",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_shader_image_footprint => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_shader_image_footprint.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_NV_shader_image_footprint",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_shader_sm_builtins => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_shader_sm_builtins.html)
- - Requires Vulkan 1.1
- ",
- raw: b"VK_NV_shader_sm_builtins",
- requires_core: crate::Version::V1_1,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_shader_subgroup_partitioned => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_shader_subgroup_partitioned.html)
- - Requires Vulkan 1.1
- ",
- raw: b"VK_NV_shader_subgroup_partitioned",
- requires_core: crate::Version::V1_1,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_shading_rate_image => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_shading_rate_image.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- ",
- raw: b"VK_NV_shading_rate_image",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [khr_get_physical_device_properties2],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_viewport_array2 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_viewport_array2.html)
- ",
- raw: b"VK_NV_viewport_array2",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_viewport_swizzle => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_viewport_swizzle.html)
- ",
- raw: b"VK_NV_viewport_swizzle",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- nv_win32_keyed_mutex => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_win32_keyed_mutex.html)
- - Requires device extension: [`nv_external_memory_win32`](crate::device::DeviceExtensions::nv_external_memory_win32)
- - Promoted to [`khr_win32_keyed_mutex`](crate::device::DeviceExtensions::khr_win32_keyed_mutex)
- ",
- raw: b"VK_NV_win32_keyed_mutex",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [nv_external_memory_win32],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- qcom_render_pass_shader_resolve => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_QCOM_render_pass_shader_resolve.html)
- ",
- raw: b"VK_QCOM_render_pass_shader_resolve",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- qcom_render_pass_store_ops => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_QCOM_render_pass_store_ops.html)
- ",
- raw: b"VK_QCOM_render_pass_store_ops",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- qcom_render_pass_transform => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_QCOM_render_pass_transform.html)
- - Requires device extension: [`khr_swapchain`](crate::device::DeviceExtensions::khr_swapchain)
- - Requires instance extension: [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)
- ",
- raw: b"VK_QCOM_render_pass_transform",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_swapchain],
- requires_instance_extensions: [khr_surface],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- qcom_rotated_copy_commands => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_QCOM_rotated_copy_commands.html)
- - Requires device extensions: [`khr_swapchain`](crate::device::DeviceExtensions::khr_swapchain), [`khr_copy_commands2`](crate::device::DeviceExtensions::khr_copy_commands2)
- ",
- raw: b"VK_QCOM_rotated_copy_commands",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_swapchain, khr_copy_commands2],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
- valve_mutable_descriptor_type => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_VALVE_mutable_descriptor_type.html)
- - Requires device extension: [`khr_maintenance3`](crate::device::DeviceExtensions::khr_maintenance3)
- ",
- raw: b"VK_VALVE_mutable_descriptor_type",
- requires_core: crate::Version::V1_0,
- requires_device_extensions: [khr_maintenance3],
- requires_instance_extensions: [],
- required_if_supported: false,
- conflicts_device_extensions: [],
- },
-}
-
-crate::instance::extensions::instance_extensions! {
- khr_android_surface => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_android_surface.html)
- - Requires instance extension: [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)
- ",
- raw: b"VK_KHR_android_surface",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [khr_surface],
- },
- khr_device_group_creation => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_device_group_creation.html)
- - Promoted to Vulkan 1.1
- ",
- raw: b"VK_KHR_device_group_creation",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [],
- },
- khr_display => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_display.html)
- - Requires instance extension: [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)
- ",
- raw: b"VK_KHR_display",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [khr_surface],
- },
- khr_external_fence_capabilities => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_external_fence_capabilities.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- - Promoted to Vulkan 1.1
- ",
- raw: b"VK_KHR_external_fence_capabilities",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [khr_get_physical_device_properties2],
- },
- khr_external_memory_capabilities => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_external_memory_capabilities.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- - Promoted to Vulkan 1.1
- ",
- raw: b"VK_KHR_external_memory_capabilities",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [khr_get_physical_device_properties2],
- },
- khr_external_semaphore_capabilities => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_external_semaphore_capabilities.html)
- - Requires instance extension: [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)
- - Promoted to Vulkan 1.1
- ",
- raw: b"VK_KHR_external_semaphore_capabilities",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [khr_get_physical_device_properties2],
- },
- khr_get_display_properties2 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_get_display_properties2.html)
- - Requires instance extension: [`khr_display`](crate::instance::InstanceExtensions::khr_display)
- ",
- raw: b"VK_KHR_get_display_properties2",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [khr_display],
- },
- khr_get_physical_device_properties2 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_get_physical_device_properties2.html)
- - Promoted to Vulkan 1.1
- ",
- raw: b"VK_KHR_get_physical_device_properties2",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [],
- },
- khr_get_surface_capabilities2 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_get_surface_capabilities2.html)
- - Requires instance extension: [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)
- ",
- raw: b"VK_KHR_get_surface_capabilities2",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [khr_surface],
- },
- khr_surface => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_surface.html)
- ",
- raw: b"VK_KHR_surface",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [],
- },
- khr_surface_protected_capabilities => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_surface_protected_capabilities.html)
- - Requires Vulkan 1.1
- - Requires instance extension: [`khr_get_surface_capabilities2`](crate::instance::InstanceExtensions::khr_get_surface_capabilities2)
- ",
- raw: b"VK_KHR_surface_protected_capabilities",
- requires_core: crate::Version::V1_1,
- requires_instance_extensions: [khr_get_surface_capabilities2],
- },
- khr_wayland_surface => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_wayland_surface.html)
- - Requires instance extension: [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)
- ",
- raw: b"VK_KHR_wayland_surface",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [khr_surface],
- },
- khr_win32_surface => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_win32_surface.html)
- - Requires instance extension: [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)
- ",
- raw: b"VK_KHR_win32_surface",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [khr_surface],
- },
- khr_xcb_surface => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_xcb_surface.html)
- - Requires instance extension: [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)
- ",
- raw: b"VK_KHR_xcb_surface",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [khr_surface],
- },
- khr_xlib_surface => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_xlib_surface.html)
- - Requires instance extension: [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)
- ",
- raw: b"VK_KHR_xlib_surface",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [khr_surface],
- },
- ext_acquire_drm_display => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_acquire_drm_display.html)
- - Requires instance extension: [`ext_direct_mode_display`](crate::instance::InstanceExtensions::ext_direct_mode_display)
- ",
- raw: b"VK_EXT_acquire_drm_display",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [ext_direct_mode_display],
- },
- ext_acquire_xlib_display => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_acquire_xlib_display.html)
- - Requires instance extension: [`ext_direct_mode_display`](crate::instance::InstanceExtensions::ext_direct_mode_display)
- ",
- raw: b"VK_EXT_acquire_xlib_display",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [ext_direct_mode_display],
- },
- ext_debug_report => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_debug_report.html)
- - Deprecated by [`ext_debug_utils`](crate::instance::InstanceExtensions::ext_debug_utils)
- ",
- raw: b"VK_EXT_debug_report",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [],
- },
- ext_debug_utils => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_debug_utils.html)
- ",
- raw: b"VK_EXT_debug_utils",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [],
- },
- ext_direct_mode_display => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_direct_mode_display.html)
- - Requires instance extension: [`khr_display`](crate::instance::InstanceExtensions::khr_display)
- ",
- raw: b"VK_EXT_direct_mode_display",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [khr_display],
- },
- ext_directfb_surface => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_directfb_surface.html)
- - Requires instance extension: [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)
- ",
- raw: b"VK_EXT_directfb_surface",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [khr_surface],
- },
- ext_display_surface_counter => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_display_surface_counter.html)
- - Requires instance extension: [`khr_display`](crate::instance::InstanceExtensions::khr_display)
- ",
- raw: b"VK_EXT_display_surface_counter",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [khr_display],
- },
- ext_headless_surface => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_headless_surface.html)
- - Requires instance extension: [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)
- ",
- raw: b"VK_EXT_headless_surface",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [khr_surface],
- },
- ext_metal_surface => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_metal_surface.html)
- - Requires instance extension: [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)
- ",
- raw: b"VK_EXT_metal_surface",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [khr_surface],
- },
- ext_swapchain_colorspace => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_swapchain_colorspace.html)
- - Requires instance extension: [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)
- ",
- raw: b"VK_EXT_swapchain_colorspace",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [khr_surface],
- },
- ext_validation_features => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_validation_features.html)
- ",
- raw: b"VK_EXT_validation_features",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [],
- },
- ext_validation_flags => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_validation_flags.html)
- - Deprecated by [`ext_validation_features`](crate::instance::InstanceExtensions::ext_validation_features)
- ",
- raw: b"VK_EXT_validation_flags",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [],
- },
- fuchsia_imagepipe_surface => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_FUCHSIA_imagepipe_surface.html)
- - Requires instance extension: [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)
- ",
- raw: b"VK_FUCHSIA_imagepipe_surface",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [khr_surface],
- },
- ggp_stream_descriptor_surface => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_GGP_stream_descriptor_surface.html)
- - Requires instance extension: [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)
- ",
- raw: b"VK_GGP_stream_descriptor_surface",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [khr_surface],
- },
- mvk_ios_surface => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_MVK_ios_surface.html)
- - Requires instance extension: [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)
- - Deprecated by [`ext_metal_surface`](crate::instance::InstanceExtensions::ext_metal_surface)
- ",
- raw: b"VK_MVK_ios_surface",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [khr_surface],
- },
- mvk_macos_surface => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_MVK_macos_surface.html)
- - Requires instance extension: [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)
- - Deprecated by [`ext_metal_surface`](crate::instance::InstanceExtensions::ext_metal_surface)
- ",
- raw: b"VK_MVK_macos_surface",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [khr_surface],
- },
- nn_vi_surface => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NN_vi_surface.html)
- - Requires instance extension: [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)
- ",
- raw: b"VK_NN_vi_surface",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [khr_surface],
- },
- nv_external_memory_capabilities => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_NV_external_memory_capabilities.html)
- - Deprecated by [`khr_external_memory_capabilities`](crate::instance::InstanceExtensions::khr_external_memory_capabilities)
- ",
- raw: b"VK_NV_external_memory_capabilities",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [],
- },
- qnx_screen_surface => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_QNX_screen_surface.html)
- - Requires instance extension: [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)
- ",
- raw: b"VK_QNX_screen_surface",
- requires_core: crate::Version::V1_0,
- requires_instance_extensions: [khr_surface],
- },
-}
-
-crate::fns::fns!(EntryFunctions, {
- v1_0 => EntryFnV1_0,
- v1_1 => EntryFnV1_1,
- v1_2 => EntryFnV1_2,
-});
-
-crate::fns::fns!(InstanceFunctions, {
- v1_0 => InstanceFnV1_0,
- v1_1 => InstanceFnV1_1,
- v1_2 => InstanceFnV1_2,
- khr_android_surface => KhrAndroidSurfaceFn,
- khr_device_group_creation => KhrDeviceGroupCreationFn,
- khr_display => KhrDisplayFn,
- khr_external_fence_capabilities => KhrExternalFenceCapabilitiesFn,
- khr_external_memory_capabilities => KhrExternalMemoryCapabilitiesFn,
- khr_external_semaphore_capabilities => KhrExternalSemaphoreCapabilitiesFn,
- khr_get_display_properties2 => KhrGetDisplayProperties2Fn,
- khr_get_physical_device_properties2 => KhrGetPhysicalDeviceProperties2Fn,
- khr_get_surface_capabilities2 => KhrGetSurfaceCapabilities2Fn,
- khr_surface => KhrSurfaceFn,
- khr_wayland_surface => KhrWaylandSurfaceFn,
- khr_win32_surface => KhrWin32SurfaceFn,
- khr_xcb_surface => KhrXcbSurfaceFn,
- khr_xlib_surface => KhrXlibSurfaceFn,
- ext_acquire_drm_display => ExtAcquireDrmDisplayFn,
- ext_acquire_xlib_display => ExtAcquireXlibDisplayFn,
- ext_debug_report => ExtDebugReportFn,
- ext_debug_utils => ExtDebugUtilsFn,
- ext_direct_mode_display => ExtDirectModeDisplayFn,
- ext_directfb_surface => ExtDirectfbSurfaceFn,
- ext_display_surface_counter => ExtDisplaySurfaceCounterFn,
- ext_headless_surface => ExtHeadlessSurfaceFn,
- ext_metal_surface => ExtMetalSurfaceFn,
- fuchsia_imagepipe_surface => FuchsiaImagepipeSurfaceFn,
- ggp_stream_descriptor_surface => GgpStreamDescriptorSurfaceFn,
- mvk_ios_surface => MvkIosSurfaceFn,
- mvk_macos_surface => MvkMacosSurfaceFn,
- nn_vi_surface => NnViSurfaceFn,
- nv_external_memory_capabilities => NvExternalMemoryCapabilitiesFn,
- qnx_screen_surface => QnxScreenSurfaceFn,
-});
-
-crate::fns::fns!(DeviceFunctions, {
- v1_0 => DeviceFnV1_0,
- v1_1 => DeviceFnV1_1,
- v1_2 => DeviceFnV1_2,
- khr_acceleration_structure => KhrAccelerationStructureFn,
- khr_bind_memory2 => KhrBindMemory2Fn,
- khr_buffer_device_address => KhrBufferDeviceAddressFn,
- khr_copy_commands2 => KhrCopyCommands2Fn,
- khr_create_renderpass2 => KhrCreateRenderpass2Fn,
- khr_deferred_host_operations => KhrDeferredHostOperationsFn,
- khr_descriptor_update_template => KhrDescriptorUpdateTemplateFn,
- khr_device_group => KhrDeviceGroupFn,
- khr_display_swapchain => KhrDisplaySwapchainFn,
- khr_draw_indirect_count => KhrDrawIndirectCountFn,
- khr_external_fence_fd => KhrExternalFenceFdFn,
- khr_external_fence_win32 => KhrExternalFenceWin32Fn,
- khr_external_memory_fd => KhrExternalMemoryFdFn,
- khr_external_memory_win32 => KhrExternalMemoryWin32Fn,
- khr_external_semaphore_fd => KhrExternalSemaphoreFdFn,
- khr_external_semaphore_win32 => KhrExternalSemaphoreWin32Fn,
- khr_fragment_shading_rate => KhrFragmentShadingRateFn,
- khr_get_memory_requirements2 => KhrGetMemoryRequirements2Fn,
- khr_maintenance1 => KhrMaintenance1Fn,
- khr_maintenance3 => KhrMaintenance3Fn,
- khr_performance_query => KhrPerformanceQueryFn,
- khr_pipeline_executable_properties => KhrPipelineExecutablePropertiesFn,
- khr_present_wait => KhrPresentWaitFn,
- khr_push_descriptor => KhrPushDescriptorFn,
- khr_ray_tracing_pipeline => KhrRayTracingPipelineFn,
- khr_sampler_ycbcr_conversion => KhrSamplerYcbcrConversionFn,
- khr_shared_presentable_image => KhrSharedPresentableImageFn,
- khr_swapchain => KhrSwapchainFn,
- khr_synchronization2 => KhrSynchronization2Fn,
- khr_timeline_semaphore => KhrTimelineSemaphoreFn,
- khr_video_decode_queue => KhrVideoDecodeQueueFn,
- khr_video_encode_queue => KhrVideoEncodeQueueFn,
- khr_video_queue => KhrVideoQueueFn,
- ext_buffer_device_address => ExtBufferDeviceAddressFn,
- ext_calibrated_timestamps => ExtCalibratedTimestampsFn,
- ext_color_write_enable => ExtColorWriteEnableFn,
- ext_conditional_rendering => ExtConditionalRenderingFn,
- ext_debug_marker => ExtDebugMarkerFn,
- ext_discard_rectangles => ExtDiscardRectanglesFn,
- ext_display_control => ExtDisplayControlFn,
- ext_extended_dynamic_state => ExtExtendedDynamicStateFn,
- ext_extended_dynamic_state2 => ExtExtendedDynamicState2Fn,
- ext_external_memory_host => ExtExternalMemoryHostFn,
- ext_full_screen_exclusive => ExtFullScreenExclusiveFn,
- ext_hdr_metadata => ExtHdrMetadataFn,
- ext_host_query_reset => ExtHostQueryResetFn,
- ext_image_drm_format_modifier => ExtImageDrmFormatModifierFn,
- ext_line_rasterization => ExtLineRasterizationFn,
- ext_multi_draw => ExtMultiDrawFn,
- ext_private_data => ExtPrivateDataFn,
- ext_sample_locations => ExtSampleLocationsFn,
- ext_tooling_info => ExtToolingInfoFn,
- ext_transform_feedback => ExtTransformFeedbackFn,
- ext_validation_cache => ExtValidationCacheFn,
- ext_vertex_input_dynamic_state => ExtVertexInputDynamicStateFn,
- amd_buffer_marker => AmdBufferMarkerFn,
- amd_display_native_hdr => AmdDisplayNativeHdrFn,
- amd_draw_indirect_count => AmdDrawIndirectCountFn,
- amd_shader_info => AmdShaderInfoFn,
- android_external_memory_android_hardware_buffer => AndroidExternalMemoryAndroidHardwareBufferFn,
- fuchsia_external_memory => FuchsiaExternalMemoryFn,
- fuchsia_external_semaphore => FuchsiaExternalSemaphoreFn,
- google_display_timing => GoogleDisplayTimingFn,
- huawei_invocation_mask => HuaweiInvocationMaskFn,
- huawei_subpass_shading => HuaweiSubpassShadingFn,
- intel_performance_query => IntelPerformanceQueryFn,
- nvx_binary_import => NvxBinaryImportFn,
- nvx_image_view_handle => NvxImageViewHandleFn,
- nv_acquire_winrt_display => NvAcquireWinrtDisplayFn,
- nv_clip_space_w_scaling => NvClipSpaceWScalingFn,
- nv_cooperative_matrix => NvCooperativeMatrixFn,
- nv_coverage_reduction_mode => NvCoverageReductionModeFn,
- nv_device_diagnostic_checkpoints => NvDeviceDiagnosticCheckpointsFn,
- nv_device_generated_commands => NvDeviceGeneratedCommandsFn,
- nv_external_memory_rdma => NvExternalMemoryRdmaFn,
- nv_external_memory_win32 => NvExternalMemoryWin32Fn,
- nv_fragment_shading_rate_enums => NvFragmentShadingRateEnumsFn,
- nv_mesh_shader => NvMeshShaderFn,
- nv_ray_tracing => NvRayTracingFn,
- nv_scissor_exclusive => NvScissorExclusiveFn,
- nv_shading_rate_image => NvShadingRateImageFn,
-});
-
-crate::device::features::features! {
- acceleration_structure => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceAccelerationStructureFeaturesKHR.html#features-accelerationStructure)
- ",
- ffi_name: acceleration_structure,
- ffi_members: [features_acceleration_structure_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- acceleration_structure_capture_replay => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceAccelerationStructureFeaturesKHR.html#features-accelerationStructureCaptureReplay)
- ",
- ffi_name: acceleration_structure_capture_replay,
- ffi_members: [features_acceleration_structure_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- acceleration_structure_host_commands => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceAccelerationStructureFeaturesKHR.html#features-accelerationStructureHostCommands)
- ",
- ffi_name: acceleration_structure_host_commands,
- ffi_members: [features_acceleration_structure_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- acceleration_structure_indirect_build => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceAccelerationStructureFeaturesKHR.html#features-accelerationStructureIndirectBuild)
- ",
- ffi_name: acceleration_structure_indirect_build,
- ffi_members: [features_acceleration_structure_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- advanced_blend_coherent_operations => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT.html#features-advancedBlendCoherentOperations)
- ",
- ffi_name: advanced_blend_coherent_operations,
- ffi_members: [features_blend_operation_advanced_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- alpha_to_one => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-alphaToOne)
- ",
- ffi_name: alpha_to_one,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- attachment_fragment_shading_rate => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentShadingRateFeaturesKHR.html#features-attachmentFragmentShadingRate)
- - Conflicts with features: [`shading_rate_image`](crate::device::Features::shading_rate_image), [`fragment_density_map`](crate::device::Features::fragment_density_map)
- ",
- ffi_name: attachment_fragment_shading_rate,
- ffi_members: [features_fragment_shading_rate_khr],
- requires_features: [],
- conflicts_features: [shading_rate_image, fragment_density_map],
- required_by_extensions: [],
- },
- bresenham_lines => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLineRasterizationFeaturesEXT.html#features-bresenhamLines)
- ",
- ffi_name: bresenham_lines,
- ffi_members: [features_line_rasterization_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- buffer_device_address => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-bufferDeviceAddress)
- ",
- ffi_name: buffer_device_address,
- ffi_members: [features_vulkan12, features_buffer_device_address, features_buffer_device_address_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- buffer_device_address_capture_replay => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-bufferDeviceAddressCaptureReplay)
- ",
- ffi_name: buffer_device_address_capture_replay,
- ffi_members: [features_vulkan12, features_buffer_device_address, features_buffer_device_address_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- buffer_device_address_multi_device => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-bufferDeviceAddressMultiDevice)
- ",
- ffi_name: buffer_device_address_multi_device,
- ffi_members: [features_vulkan12, features_buffer_device_address, features_buffer_device_address_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- color_write_enable => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceColorWriteEnableFeaturesEXT.html#features-colorWriteEnable)
- ",
- ffi_name: color_write_enable,
- ffi_members: [features_color_write_enable_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- compute_derivative_group_linear => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceComputeShaderDerivativesFeaturesNV.html#features-computeDerivativeGroupLinear)
- ",
- ffi_name: compute_derivative_group_linear,
- ffi_members: [features_compute_shader_derivatives_nv],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- compute_derivative_group_quads => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceComputeShaderDerivativesFeaturesNV.html#features-computeDerivativeGroupQuads)
- ",
- ffi_name: compute_derivative_group_quads,
- ffi_members: [features_compute_shader_derivatives_nv],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- compute_full_subgroups => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceSubgroupSizeControlFeaturesEXT.html#features-computeFullSubgroups)
- ",
- ffi_name: compute_full_subgroups,
- ffi_members: [features_subgroup_size_control_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- conditional_rendering => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceConditionalRenderingFeaturesEXT.html#features-conditionalRendering)
- ",
- ffi_name: conditional_rendering,
- ffi_members: [features_conditional_rendering_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- constant_alpha_color_blend_factors => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDevicePortabilitySubsetFeaturesKHR.html#features-constantAlphaColorBlendFactors)
- ",
- ffi_name: constant_alpha_color_blend_factors,
- ffi_members: [features_portability_subset_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- cooperative_matrix => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceCooperativeMatrixFeaturesNV.html#features-cooperativeMatrix)
- ",
- ffi_name: cooperative_matrix,
- ffi_members: [features_cooperative_matrix_nv],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- cooperative_matrix_robust_buffer_access => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceCooperativeMatrixFeaturesNV.html#features-cooperativeMatrixRobustBufferAccess)
- ",
- ffi_name: cooperative_matrix_robust_buffer_access,
- ffi_members: [features_cooperative_matrix_nv],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- corner_sampled_image => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceCornerSampledImageFeaturesNV.html#features-cornerSampledImage)
- ",
- ffi_name: corner_sampled_image,
- ffi_members: [features_corner_sampled_image_nv],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- coverage_reduction_mode => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceCoverageReductionModeFeaturesNV.html#features-coverageReductionMode)
- ",
- ffi_name: coverage_reduction_mode,
- ffi_members: [features_coverage_reduction_mode_nv],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- custom_border_color_without_format => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceCustomBorderColorFeaturesEXT.html#features-customBorderColorWithoutFormat)
- ",
- ffi_name: custom_border_color_without_format,
- ffi_members: [features_custom_border_color_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- custom_border_colors => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceCustomBorderColorFeaturesEXT.html#features-customBorderColors)
- ",
- ffi_name: custom_border_colors,
- ffi_members: [features_custom_border_color_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- decode_mode_shared_exponent => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceASTCDecodeFeaturesEXT.html#features-decodeModeSharedExponent)
- ",
- ffi_name: decode_mode_shared_exponent,
- ffi_members: [features_astc_decode_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- dedicated_allocation_image_aliasing => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV.html#features-dedicatedAllocationImageAliasing)
- ",
- ffi_name: dedicated_allocation_image_aliasing,
- ffi_members: [features_dedicated_allocation_image_aliasing_nv],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- depth_bias_clamp => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-depthBiasClamp)
- ",
- ffi_name: depth_bias_clamp,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- depth_bounds => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-depthBounds)
- ",
- ffi_name: depth_bounds,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- depth_clamp => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-depthClamp)
- ",
- ffi_name: depth_clamp,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- depth_clip_enable => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceDepthClipEnableFeaturesEXT.html#features-depthClipEnable)
- ",
- ffi_name: depth_clip_enable,
- ffi_members: [features_depth_clip_enable_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- descriptor_binding_acceleration_structure_update_after_bind => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceAccelerationStructureFeaturesKHR.html#features-descriptorBindingAccelerationStructureUpdateAfterBind)
- ",
- ffi_name: descriptor_binding_acceleration_structure_update_after_bind,
- ffi_members: [features_acceleration_structure_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- descriptor_binding_inline_uniform_block_update_after_bind => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceInlineUniformBlockFeaturesEXT.html#features-descriptorBindingInlineUniformBlockUpdateAfterBind)
- ",
- ffi_name: descriptor_binding_inline_uniform_block_update_after_bind,
- ffi_members: [features_inline_uniform_block_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- descriptor_binding_partially_bound => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-descriptorBindingPartiallyBound)
- ",
- ffi_name: descriptor_binding_partially_bound,
- ffi_members: [features_vulkan12, features_descriptor_indexing],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- descriptor_binding_sampled_image_update_after_bind => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-descriptorBindingSampledImageUpdateAfterBind)
- ",
- ffi_name: descriptor_binding_sampled_image_update_after_bind,
- ffi_members: [features_vulkan12, features_descriptor_indexing],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- descriptor_binding_storage_buffer_update_after_bind => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-descriptorBindingStorageBufferUpdateAfterBind)
- ",
- ffi_name: descriptor_binding_storage_buffer_update_after_bind,
- ffi_members: [features_vulkan12, features_descriptor_indexing],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- descriptor_binding_storage_image_update_after_bind => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-descriptorBindingStorageImageUpdateAfterBind)
- ",
- ffi_name: descriptor_binding_storage_image_update_after_bind,
- ffi_members: [features_vulkan12, features_descriptor_indexing],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- descriptor_binding_storage_texel_buffer_update_after_bind => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-descriptorBindingStorageTexelBufferUpdateAfterBind)
- ",
- ffi_name: descriptor_binding_storage_texel_buffer_update_after_bind,
- ffi_members: [features_vulkan12, features_descriptor_indexing],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- descriptor_binding_uniform_buffer_update_after_bind => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-descriptorBindingUniformBufferUpdateAfterBind)
- ",
- ffi_name: descriptor_binding_uniform_buffer_update_after_bind,
- ffi_members: [features_vulkan12, features_descriptor_indexing],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- descriptor_binding_uniform_texel_buffer_update_after_bind => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-descriptorBindingUniformTexelBufferUpdateAfterBind)
- ",
- ffi_name: descriptor_binding_uniform_texel_buffer_update_after_bind,
- ffi_members: [features_vulkan12, features_descriptor_indexing],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- descriptor_binding_update_unused_while_pending => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-descriptorBindingUpdateUnusedWhilePending)
- ",
- ffi_name: descriptor_binding_update_unused_while_pending,
- ffi_members: [features_vulkan12, features_descriptor_indexing],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- descriptor_binding_variable_descriptor_count => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-descriptorBindingVariableDescriptorCount)
- ",
- ffi_name: descriptor_binding_variable_descriptor_count,
- ffi_members: [features_vulkan12, features_descriptor_indexing],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- descriptor_indexing => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-descriptorIndexing)
- - Required by device extension: [`ext_descriptor_indexing`](crate::device::DeviceExtensions::ext_descriptor_indexing)
- ",
- ffi_name: descriptor_indexing,
- ffi_members: [features_vulkan12],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [ext_descriptor_indexing],
- },
- device_coherent_memory => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceCoherentMemoryFeaturesAMD.html#features-deviceCoherentMemory)
- ",
- ffi_name: device_coherent_memory,
- ffi_members: [features_coherent_memory_amd],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- device_generated_commands => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV.html#features-deviceGeneratedCommands)
- ",
- ffi_name: device_generated_commands,
- ffi_members: [features_device_generated_commands_nv],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- device_memory_report => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceDeviceMemoryReportFeaturesEXT.html#features-deviceMemoryReport)
- ",
- ffi_name: device_memory_report,
- ffi_members: [features_device_memory_report_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- diagnostics_config => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceDiagnosticsConfigFeaturesNV.html#features-diagnosticsConfig)
- ",
- ffi_name: diagnostics_config,
- ffi_members: [features_diagnostics_config_nv],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- draw_indirect_count => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-drawIndirectCount)
- - Required by device extension: [`khr_draw_indirect_count`](crate::device::DeviceExtensions::khr_draw_indirect_count)
- ",
- ffi_name: draw_indirect_count,
- ffi_members: [features_vulkan12],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [khr_draw_indirect_count],
- },
- draw_indirect_first_instance => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-drawIndirectFirstInstance)
- ",
- ffi_name: draw_indirect_first_instance,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- dual_src_blend => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-dualSrcBlend)
- ",
- ffi_name: dual_src_blend,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- events => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDevicePortabilitySubsetFeaturesKHR.html#features-events)
- ",
- ffi_name: events,
- ffi_members: [features_portability_subset_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- exclusive_scissor => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceExclusiveScissorFeaturesNV.html#features-exclusiveScissor)
- ",
- ffi_name: exclusive_scissor,
- ffi_members: [features_exclusive_scissor_nv],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- extended_dynamic_state => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceExtendedDynamicStateFeaturesEXT.html#features-extendedDynamicState)
- ",
- ffi_name: extended_dynamic_state,
- ffi_members: [features_extended_dynamic_state_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- extended_dynamic_state2 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceExtendedDynamicState2FeaturesEXT.html#features-extendedDynamicState2)
- ",
- ffi_name: extended_dynamic_state2,
- ffi_members: [features_extended_dynamic_state2_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- extended_dynamic_state2_logic_op => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceExtendedDynamicState2FeaturesEXT.html#features-extendedDynamicState2LogicOp)
- ",
- ffi_name: extended_dynamic_state2_logic_op,
- ffi_members: [features_extended_dynamic_state2_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- extended_dynamic_state2_patch_control_points => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceExtendedDynamicState2FeaturesEXT.html#features-extendedDynamicState2PatchControlPoints)
- ",
- ffi_name: extended_dynamic_state2_patch_control_points,
- ffi_members: [features_extended_dynamic_state2_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- external_memory_rdma => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceExternalMemoryRDMAFeaturesNV.html#features-externalMemoryRDMA)
- ",
- ffi_name: external_memory_rdma,
- ffi_members: [features_external_memory_rdma_nv],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- fill_mode_non_solid => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-fillModeNonSolid)
- ",
- ffi_name: fill_mode_non_solid,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- format_a4b4g4r4 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDevice4444FormatsFeaturesEXT.html#features-formatA4B4G4R4)
- ",
- ffi_name: format_a4b4g4r4,
- ffi_members: [features_4444formats_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- format_a4r4g4b4 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDevice4444FormatsFeaturesEXT.html#features-formatA4R4G4B4)
- ",
- ffi_name: format_a4r4g4b4,
- ffi_members: [features_4444formats_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- fragment_density_map => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentDensityMapFeaturesEXT.html#features-fragmentDensityMap)
- - Conflicts with features: [`pipeline_fragment_shading_rate`](crate::device::Features::pipeline_fragment_shading_rate), [`primitive_fragment_shading_rate`](crate::device::Features::primitive_fragment_shading_rate), [`attachment_fragment_shading_rate`](crate::device::Features::attachment_fragment_shading_rate)
- ",
- ffi_name: fragment_density_map,
- ffi_members: [features_fragment_density_map_ext],
- requires_features: [],
- conflicts_features: [pipeline_fragment_shading_rate, primitive_fragment_shading_rate, attachment_fragment_shading_rate],
- required_by_extensions: [],
- },
- fragment_density_map_deferred => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentDensityMap2FeaturesEXT.html#features-fragmentDensityMapDeferred)
- ",
- ffi_name: fragment_density_map_deferred,
- ffi_members: [features_fragment_density_map2_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- fragment_density_map_dynamic => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentDensityMapFeaturesEXT.html#features-fragmentDensityMapDynamic)
- ",
- ffi_name: fragment_density_map_dynamic,
- ffi_members: [features_fragment_density_map_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- fragment_density_map_non_subsampled_images => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentDensityMapFeaturesEXT.html#features-fragmentDensityMapNonSubsampledImages)
- ",
- ffi_name: fragment_density_map_non_subsampled_images,
- ffi_members: [features_fragment_density_map_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- fragment_shader_barycentric => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV.html#features-fragmentShaderBarycentric)
- ",
- ffi_name: fragment_shader_barycentric,
- ffi_members: [features_fragment_shader_barycentric_nv],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- fragment_shader_pixel_interlock => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT.html#features-fragmentShaderPixelInterlock)
- ",
- ffi_name: fragment_shader_pixel_interlock,
- ffi_members: [features_fragment_shader_interlock_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- fragment_shader_sample_interlock => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT.html#features-fragmentShaderSampleInterlock)
- ",
- ffi_name: fragment_shader_sample_interlock,
- ffi_members: [features_fragment_shader_interlock_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- fragment_shader_shading_rate_interlock => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT.html#features-fragmentShaderShadingRateInterlock)
- ",
- ffi_name: fragment_shader_shading_rate_interlock,
- ffi_members: [features_fragment_shader_interlock_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- fragment_shading_rate_enums => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV.html#features-fragmentShadingRateEnums)
- ",
- ffi_name: fragment_shading_rate_enums,
- ffi_members: [features_fragment_shading_rate_enums_nv],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- fragment_stores_and_atomics => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-fragmentStoresAndAtomics)
- ",
- ffi_name: fragment_stores_and_atomics,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- full_draw_index_uint32 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-fullDrawIndexUint32)
- ",
- ffi_name: full_draw_index_uint32,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- geometry_shader => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-geometryShader)
- ",
- ffi_name: geometry_shader,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- geometry_streams => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceTransformFeedbackFeaturesEXT.html#features-geometryStreams)
- ",
- ffi_name: geometry_streams,
- ffi_members: [features_transform_feedback_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- global_priority_query => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceGlobalPriorityQueryFeaturesEXT.html#features-globalPriorityQuery)
- ",
- ffi_name: global_priority_query,
- ffi_members: [features_global_priority_query_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- host_query_reset => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-hostQueryReset)
- ",
- ffi_name: host_query_reset,
- ffi_members: [features_vulkan12, features_host_query_reset],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- image_cube_array => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-imageCubeArray)
- ",
- ffi_name: image_cube_array,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- image_footprint => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderImageFootprintFeaturesNV.html#features-imageFootprint)
- ",
- ffi_name: image_footprint,
- ffi_members: [features_shader_image_footprint_nv],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- image_view2_d_on3_d_image => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDevicePortabilitySubsetFeaturesKHR.html#features-imageView2DOn3DImage)
- ",
- ffi_name: image_view2_d_on3_d_image,
- ffi_members: [features_portability_subset_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- image_view_format_reinterpretation => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDevicePortabilitySubsetFeaturesKHR.html#features-imageViewFormatReinterpretation)
- ",
- ffi_name: image_view_format_reinterpretation,
- ffi_members: [features_portability_subset_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- image_view_format_swizzle => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDevicePortabilitySubsetFeaturesKHR.html#features-imageViewFormatSwizzle)
- ",
- ffi_name: image_view_format_swizzle,
- ffi_members: [features_portability_subset_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- imageless_framebuffer => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-imagelessFramebuffer)
- ",
- ffi_name: imageless_framebuffer,
- ffi_members: [features_vulkan12, features_imageless_framebuffer],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- independent_blend => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-independentBlend)
- ",
- ffi_name: independent_blend,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- index_type_uint8 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceIndexTypeUint8FeaturesEXT.html#features-indexTypeUint8)
- ",
- ffi_name: index_type_uint8,
- ffi_members: [features_index_type_uint8_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- inherited_conditional_rendering => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceConditionalRenderingFeaturesEXT.html#features-inheritedConditionalRendering)
- ",
- ffi_name: inherited_conditional_rendering,
- ffi_members: [features_conditional_rendering_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- inherited_queries => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-inheritedQueries)
- ",
- ffi_name: inherited_queries,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- inherited_viewport_scissor2_d => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceInheritedViewportScissorFeaturesNV.html#features-inheritedViewportScissor2D)
- ",
- ffi_name: inherited_viewport_scissor2_d,
- ffi_members: [features_inherited_viewport_scissor_nv],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- inline_uniform_block => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceInlineUniformBlockFeaturesEXT.html#features-inlineUniformBlock)
- ",
- ffi_name: inline_uniform_block,
- ffi_members: [features_inline_uniform_block_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- invocation_mask => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceInvocationMaskFeaturesHUAWEI.html#features-invocationMask)
- ",
- ffi_name: invocation_mask,
- ffi_members: [features_invocation_mask_huawei],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- large_points => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-largePoints)
- ",
- ffi_name: large_points,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- logic_op => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-logicOp)
- ",
- ffi_name: logic_op,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- memory_priority => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceMemoryPriorityFeaturesEXT.html#features-memoryPriority)
- ",
- ffi_name: memory_priority,
- ffi_members: [features_memory_priority_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- mesh_shader => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceMeshShaderFeaturesNV.html#features-meshShader)
- ",
- ffi_name: mesh_shader,
- ffi_members: [features_mesh_shader_nv],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- multi_draw => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceMultiDrawFeaturesEXT.html#features-multiDraw)
- ",
- ffi_name: multi_draw,
- ffi_members: [features_multi_draw_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- multi_draw_indirect => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-multiDrawIndirect)
- ",
- ffi_name: multi_draw_indirect,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- multi_viewport => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-multiViewport)
- ",
- ffi_name: multi_viewport,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- multisample_array_image => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDevicePortabilitySubsetFeaturesKHR.html#features-multisampleArrayImage)
- ",
- ffi_name: multisample_array_image,
- ffi_members: [features_portability_subset_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- multiview => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan11Features.html#features-multiview)
- ",
- ffi_name: multiview,
- ffi_members: [features_vulkan11, features_multiview],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- multiview_geometry_shader => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan11Features.html#features-multiviewGeometryShader)
- ",
- ffi_name: multiview_geometry_shader,
- ffi_members: [features_vulkan11, features_multiview],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- multiview_tessellation_shader => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan11Features.html#features-multiviewTessellationShader)
- ",
- ffi_name: multiview_tessellation_shader,
- ffi_members: [features_vulkan11, features_multiview],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- mutable_comparison_samplers => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDevicePortabilitySubsetFeaturesKHR.html#features-mutableComparisonSamplers)
- ",
- ffi_name: mutable_comparison_samplers,
- ffi_members: [features_portability_subset_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- mutable_descriptor_type => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceMutableDescriptorTypeFeaturesVALVE.html#features-mutableDescriptorType)
- ",
- ffi_name: mutable_descriptor_type,
- ffi_members: [features_mutable_descriptor_type_valve],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- no_invocation_fragment_shading_rates => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV.html#features-noInvocationFragmentShadingRates)
- ",
- ffi_name: no_invocation_fragment_shading_rates,
- ffi_members: [features_fragment_shading_rate_enums_nv],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- null_descriptor => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceRobustness2FeaturesEXT.html#features-nullDescriptor)
- ",
- ffi_name: null_descriptor,
- ffi_members: [features_robustness2_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- occlusion_query_precise => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-occlusionQueryPrecise)
- ",
- ffi_name: occlusion_query_precise,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- performance_counter_multiple_query_pools => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDevicePerformanceQueryFeaturesKHR.html#features-performanceCounterMultipleQueryPools)
- ",
- ffi_name: performance_counter_multiple_query_pools,
- ffi_members: [features_performance_query_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- performance_counter_query_pools => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDevicePerformanceQueryFeaturesKHR.html#features-performanceCounterQueryPools)
- ",
- ffi_name: performance_counter_query_pools,
- ffi_members: [features_performance_query_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- pipeline_creation_cache_control => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDevicePipelineCreationCacheControlFeaturesEXT.html#features-pipelineCreationCacheControl)
- ",
- ffi_name: pipeline_creation_cache_control,
- ffi_members: [features_pipeline_creation_cache_control_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- pipeline_executable_info => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR.html#features-pipelineExecutableInfo)
- ",
- ffi_name: pipeline_executable_info,
- ffi_members: [features_pipeline_executable_properties_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- pipeline_fragment_shading_rate => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentShadingRateFeaturesKHR.html#features-pipelineFragmentShadingRate)
- - Conflicts with features: [`shading_rate_image`](crate::device::Features::shading_rate_image), [`fragment_density_map`](crate::device::Features::fragment_density_map)
- ",
- ffi_name: pipeline_fragment_shading_rate,
- ffi_members: [features_fragment_shading_rate_khr],
- requires_features: [],
- conflicts_features: [shading_rate_image, fragment_density_map],
- required_by_extensions: [],
- },
- pipeline_statistics_query => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-pipelineStatisticsQuery)
- ",
- ffi_name: pipeline_statistics_query,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- point_polygons => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDevicePortabilitySubsetFeaturesKHR.html#features-pointPolygons)
- ",
- ffi_name: point_polygons,
- ffi_members: [features_portability_subset_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- present_id => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDevicePresentIdFeaturesKHR.html#features-presentId)
- ",
- ffi_name: present_id,
- ffi_members: [features_present_id_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- present_wait => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDevicePresentWaitFeaturesKHR.html#features-presentWait)
- ",
- ffi_name: present_wait,
- ffi_members: [features_present_wait_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- primitive_fragment_shading_rate => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentShadingRateFeaturesKHR.html#features-primitiveFragmentShadingRate)
- - Conflicts with features: [`shading_rate_image`](crate::device::Features::shading_rate_image), [`fragment_density_map`](crate::device::Features::fragment_density_map)
- ",
- ffi_name: primitive_fragment_shading_rate,
- ffi_members: [features_fragment_shading_rate_khr],
- requires_features: [],
- conflicts_features: [shading_rate_image, fragment_density_map],
- required_by_extensions: [],
- },
- private_data => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDevicePrivateDataFeaturesEXT.html#features-privateData)
- ",
- ffi_name: private_data,
- ffi_members: [features_private_data_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- protected_memory => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan11Features.html#features-protectedMemory)
- ",
- ffi_name: protected_memory,
- ffi_members: [features_vulkan11, features_protected_memory],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- provoking_vertex_last => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceProvokingVertexFeaturesEXT.html#features-provokingVertexLast)
- ",
- ffi_name: provoking_vertex_last,
- ffi_members: [features_provoking_vertex_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- ray_query => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceRayQueryFeaturesKHR.html#features-rayQuery)
- ",
- ffi_name: ray_query,
- ffi_members: [features_ray_query_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- ray_tracing_motion_blur => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceRayTracingMotionBlurFeaturesNV.html#features-rayTracingMotionBlur)
- ",
- ffi_name: ray_tracing_motion_blur,
- ffi_members: [features_ray_tracing_motion_blur_nv],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- ray_tracing_motion_blur_pipeline_trace_rays_indirect => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceRayTracingMotionBlurFeaturesNV.html#features-rayTracingMotionBlurPipelineTraceRaysIndirect)
- ",
- ffi_name: ray_tracing_motion_blur_pipeline_trace_rays_indirect,
- ffi_members: [features_ray_tracing_motion_blur_nv],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- ray_tracing_pipeline => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceRayTracingPipelineFeaturesKHR.html#features-rayTracingPipeline)
- ",
- ffi_name: ray_tracing_pipeline,
- ffi_members: [features_ray_tracing_pipeline_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- ray_tracing_pipeline_shader_group_handle_capture_replay => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceRayTracingPipelineFeaturesKHR.html#features-rayTracingPipelineShaderGroupHandleCaptureReplay)
- ",
- ffi_name: ray_tracing_pipeline_shader_group_handle_capture_replay,
- ffi_members: [features_ray_tracing_pipeline_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- ray_tracing_pipeline_shader_group_handle_capture_replay_mixed => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceRayTracingPipelineFeaturesKHR.html#features-rayTracingPipelineShaderGroupHandleCaptureReplayMixed)
- ",
- ffi_name: ray_tracing_pipeline_shader_group_handle_capture_replay_mixed,
- ffi_members: [features_ray_tracing_pipeline_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- ray_tracing_pipeline_trace_rays_indirect => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceRayTracingPipelineFeaturesKHR.html#features-rayTracingPipelineTraceRaysIndirect)
- ",
- ffi_name: ray_tracing_pipeline_trace_rays_indirect,
- ffi_members: [features_ray_tracing_pipeline_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- ray_traversal_primitive_culling => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceRayTracingPipelineFeaturesKHR.html#features-rayTraversalPrimitiveCulling)
- ",
- ffi_name: ray_traversal_primitive_culling,
- ffi_members: [features_ray_tracing_pipeline_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- rectangular_lines => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLineRasterizationFeaturesEXT.html#features-rectangularLines)
- ",
- ffi_name: rectangular_lines,
- ffi_members: [features_line_rasterization_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- representative_fragment_test => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV.html#features-representativeFragmentTest)
- ",
- ffi_name: representative_fragment_test,
- ffi_members: [features_representative_fragment_test_nv],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- robust_buffer_access => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-robustBufferAccess)
- ",
- ffi_name: robust_buffer_access,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- robust_buffer_access2 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceRobustness2FeaturesEXT.html#features-robustBufferAccess2)
- ",
- ffi_name: robust_buffer_access2,
- ffi_members: [features_robustness2_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- robust_image_access => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceImageRobustnessFeaturesEXT.html#features-robustImageAccess)
- ",
- ffi_name: robust_image_access,
- ffi_members: [features_image_robustness_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- robust_image_access2 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceRobustness2FeaturesEXT.html#features-robustImageAccess2)
- ",
- ffi_name: robust_image_access2,
- ffi_members: [features_robustness2_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- runtime_descriptor_array => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-runtimeDescriptorArray)
- ",
- ffi_name: runtime_descriptor_array,
- ffi_members: [features_vulkan12, features_descriptor_indexing],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- sample_rate_shading => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-sampleRateShading)
- ",
- ffi_name: sample_rate_shading,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- sampler_anisotropy => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-samplerAnisotropy)
- ",
- ffi_name: sampler_anisotropy,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- sampler_filter_minmax => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-samplerFilterMinmax)
- - Required by device extension: [`ext_sampler_filter_minmax`](crate::device::DeviceExtensions::ext_sampler_filter_minmax)
- ",
- ffi_name: sampler_filter_minmax,
- ffi_members: [features_vulkan12],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [ext_sampler_filter_minmax],
- },
- sampler_mip_lod_bias => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDevicePortabilitySubsetFeaturesKHR.html#features-samplerMipLodBias)
- ",
- ffi_name: sampler_mip_lod_bias,
- ffi_members: [features_portability_subset_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- sampler_mirror_clamp_to_edge => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-samplerMirrorClampToEdge)
- - Required by device extension: [`khr_sampler_mirror_clamp_to_edge`](crate::device::DeviceExtensions::khr_sampler_mirror_clamp_to_edge)
- ",
- ffi_name: sampler_mirror_clamp_to_edge,
- ffi_members: [features_vulkan12],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [khr_sampler_mirror_clamp_to_edge],
- },
- sampler_ycbcr_conversion => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan11Features.html#features-samplerYcbcrConversion)
- ",
- ffi_name: sampler_ycbcr_conversion,
- ffi_members: [features_vulkan11, features_sampler_ycbcr_conversion],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- scalar_block_layout => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-scalarBlockLayout)
- ",
- ffi_name: scalar_block_layout,
- ffi_members: [features_vulkan12, features_scalar_block_layout],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- separate_depth_stencil_layouts => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-separateDepthStencilLayouts)
- ",
- ffi_name: separate_depth_stencil_layouts,
- ffi_members: [features_vulkan12, features_separate_depth_stencil_layouts],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- separate_stencil_mask_ref => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDevicePortabilitySubsetFeaturesKHR.html#features-separateStencilMaskRef)
- ",
- ffi_name: separate_stencil_mask_ref,
- ffi_members: [features_portability_subset_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_buffer_float16_atomic_add => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT.html#features-shaderBufferFloat16AtomicAdd)
- ",
- ffi_name: shader_buffer_float16_atomic_add,
- ffi_members: [features_shader_atomic_float2_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_buffer_float16_atomic_min_max => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT.html#features-shaderBufferFloat16AtomicMinMax)
- ",
- ffi_name: shader_buffer_float16_atomic_min_max,
- ffi_members: [features_shader_atomic_float2_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_buffer_float16_atomics => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT.html#features-shaderBufferFloat16Atomics)
- ",
- ffi_name: shader_buffer_float16_atomics,
- ffi_members: [features_shader_atomic_float2_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_buffer_float32_atomic_add => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderAtomicFloatFeaturesEXT.html#features-shaderBufferFloat32AtomicAdd)
- ",
- ffi_name: shader_buffer_float32_atomic_add,
- ffi_members: [features_shader_atomic_float_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_buffer_float32_atomic_min_max => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT.html#features-shaderBufferFloat32AtomicMinMax)
- ",
- ffi_name: shader_buffer_float32_atomic_min_max,
- ffi_members: [features_shader_atomic_float2_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_buffer_float32_atomics => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderAtomicFloatFeaturesEXT.html#features-shaderBufferFloat32Atomics)
- ",
- ffi_name: shader_buffer_float32_atomics,
- ffi_members: [features_shader_atomic_float_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_buffer_float64_atomic_add => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderAtomicFloatFeaturesEXT.html#features-shaderBufferFloat64AtomicAdd)
- ",
- ffi_name: shader_buffer_float64_atomic_add,
- ffi_members: [features_shader_atomic_float_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_buffer_float64_atomic_min_max => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT.html#features-shaderBufferFloat64AtomicMinMax)
- ",
- ffi_name: shader_buffer_float64_atomic_min_max,
- ffi_members: [features_shader_atomic_float2_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_buffer_float64_atomics => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderAtomicFloatFeaturesEXT.html#features-shaderBufferFloat64Atomics)
- ",
- ffi_name: shader_buffer_float64_atomics,
- ffi_members: [features_shader_atomic_float_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_buffer_int64_atomics => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderBufferInt64Atomics)
- ",
- ffi_name: shader_buffer_int64_atomics,
- ffi_members: [features_vulkan12, features_shader_atomic_int64],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_clip_distance => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderClipDistance)
- ",
- ffi_name: shader_clip_distance,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_cull_distance => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderCullDistance)
- ",
- ffi_name: shader_cull_distance,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_demote_to_helper_invocation => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT.html#features-shaderDemoteToHelperInvocation)
- ",
- ffi_name: shader_demote_to_helper_invocation,
- ffi_members: [features_shader_demote_to_helper_invocation_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_device_clock => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderClockFeaturesKHR.html#features-shaderDeviceClock)
- ",
- ffi_name: shader_device_clock,
- ffi_members: [features_shader_clock_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_draw_parameters => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan11Features.html#features-shaderDrawParameters)
- - Required by device extension: [`khr_shader_draw_parameters`](crate::device::DeviceExtensions::khr_shader_draw_parameters)
- ",
- ffi_name: shader_draw_parameters,
- ffi_members: [features_vulkan11, features_shader_draw_parameters],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [khr_shader_draw_parameters],
- },
- shader_float16 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderFloat16)
- ",
- ffi_name: shader_float16,
- ffi_members: [features_vulkan12, features_shader_float16_int8],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_float64 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderFloat64)
- ",
- ffi_name: shader_float64,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_image_float32_atomic_add => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderAtomicFloatFeaturesEXT.html#features-shaderImageFloat32AtomicAdd)
- ",
- ffi_name: shader_image_float32_atomic_add,
- ffi_members: [features_shader_atomic_float_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_image_float32_atomic_min_max => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT.html#features-shaderImageFloat32AtomicMinMax)
- ",
- ffi_name: shader_image_float32_atomic_min_max,
- ffi_members: [features_shader_atomic_float2_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_image_float32_atomics => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderAtomicFloatFeaturesEXT.html#features-shaderImageFloat32Atomics)
- ",
- ffi_name: shader_image_float32_atomics,
- ffi_members: [features_shader_atomic_float_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_image_gather_extended => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderImageGatherExtended)
- ",
- ffi_name: shader_image_gather_extended,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_image_int64_atomics => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT.html#features-shaderImageInt64Atomics)
- ",
- ffi_name: shader_image_int64_atomics,
- ffi_members: [features_shader_image_atomic_int64_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_input_attachment_array_dynamic_indexing => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderInputAttachmentArrayDynamicIndexing)
- ",
- ffi_name: shader_input_attachment_array_dynamic_indexing,
- ffi_members: [features_vulkan12, features_descriptor_indexing],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_input_attachment_array_non_uniform_indexing => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderInputAttachmentArrayNonUniformIndexing)
- ",
- ffi_name: shader_input_attachment_array_non_uniform_indexing,
- ffi_members: [features_vulkan12, features_descriptor_indexing],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_int16 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderInt16)
- ",
- ffi_name: shader_int16,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_int64 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderInt64)
- ",
- ffi_name: shader_int64,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_int8 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderInt8)
- ",
- ffi_name: shader_int8,
- ffi_members: [features_vulkan12, features_shader_float16_int8],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_integer_functions2 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL.html#features-shaderIntegerFunctions2)
- ",
- ffi_name: shader_integer_functions2,
- ffi_members: [features_shader_integer_functions2_intel],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_output_layer => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderOutputLayer)
- - Required by device extension: [`ext_shader_viewport_index_layer`](crate::device::DeviceExtensions::ext_shader_viewport_index_layer)
- ",
- ffi_name: shader_output_layer,
- ffi_members: [features_vulkan12],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [ext_shader_viewport_index_layer],
- },
- shader_output_viewport_index => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderOutputViewportIndex)
- - Required by device extension: [`ext_shader_viewport_index_layer`](crate::device::DeviceExtensions::ext_shader_viewport_index_layer)
- ",
- ffi_name: shader_output_viewport_index,
- ffi_members: [features_vulkan12],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [ext_shader_viewport_index_layer],
- },
- shader_resource_min_lod => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderResourceMinLod)
- ",
- ffi_name: shader_resource_min_lod,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_resource_residency => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderResourceResidency)
- ",
- ffi_name: shader_resource_residency,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_sample_rate_interpolation_functions => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDevicePortabilitySubsetFeaturesKHR.html#features-shaderSampleRateInterpolationFunctions)
- ",
- ffi_name: shader_sample_rate_interpolation_functions,
- ffi_members: [features_portability_subset_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_sampled_image_array_dynamic_indexing => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderSampledImageArrayDynamicIndexing)
- ",
- ffi_name: shader_sampled_image_array_dynamic_indexing,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_sampled_image_array_non_uniform_indexing => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderSampledImageArrayNonUniformIndexing)
- ",
- ffi_name: shader_sampled_image_array_non_uniform_indexing,
- ffi_members: [features_vulkan12, features_descriptor_indexing],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_shared_float16_atomic_add => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT.html#features-shaderSharedFloat16AtomicAdd)
- ",
- ffi_name: shader_shared_float16_atomic_add,
- ffi_members: [features_shader_atomic_float2_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_shared_float16_atomic_min_max => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT.html#features-shaderSharedFloat16AtomicMinMax)
- ",
- ffi_name: shader_shared_float16_atomic_min_max,
- ffi_members: [features_shader_atomic_float2_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_shared_float16_atomics => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT.html#features-shaderSharedFloat16Atomics)
- ",
- ffi_name: shader_shared_float16_atomics,
- ffi_members: [features_shader_atomic_float2_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_shared_float32_atomic_add => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderAtomicFloatFeaturesEXT.html#features-shaderSharedFloat32AtomicAdd)
- ",
- ffi_name: shader_shared_float32_atomic_add,
- ffi_members: [features_shader_atomic_float_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_shared_float32_atomic_min_max => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT.html#features-shaderSharedFloat32AtomicMinMax)
- ",
- ffi_name: shader_shared_float32_atomic_min_max,
- ffi_members: [features_shader_atomic_float2_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_shared_float32_atomics => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderAtomicFloatFeaturesEXT.html#features-shaderSharedFloat32Atomics)
- ",
- ffi_name: shader_shared_float32_atomics,
- ffi_members: [features_shader_atomic_float_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_shared_float64_atomic_add => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderAtomicFloatFeaturesEXT.html#features-shaderSharedFloat64AtomicAdd)
- ",
- ffi_name: shader_shared_float64_atomic_add,
- ffi_members: [features_shader_atomic_float_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_shared_float64_atomic_min_max => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT.html#features-shaderSharedFloat64AtomicMinMax)
- ",
- ffi_name: shader_shared_float64_atomic_min_max,
- ffi_members: [features_shader_atomic_float2_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_shared_float64_atomics => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderAtomicFloatFeaturesEXT.html#features-shaderSharedFloat64Atomics)
- ",
- ffi_name: shader_shared_float64_atomics,
- ffi_members: [features_shader_atomic_float_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_shared_int64_atomics => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderSharedInt64Atomics)
- ",
- ffi_name: shader_shared_int64_atomics,
- ffi_members: [features_vulkan12, features_shader_atomic_int64],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_sm_builtins => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderSMBuiltinsFeaturesNV.html#features-shaderSMBuiltins)
- ",
- ffi_name: shader_sm_builtins,
- ffi_members: [features_shader_sm_builtins_nv],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_storage_buffer_array_dynamic_indexing => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderStorageBufferArrayDynamicIndexing)
- ",
- ffi_name: shader_storage_buffer_array_dynamic_indexing,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_storage_buffer_array_non_uniform_indexing => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderStorageBufferArrayNonUniformIndexing)
- ",
- ffi_name: shader_storage_buffer_array_non_uniform_indexing,
- ffi_members: [features_vulkan12, features_descriptor_indexing],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_storage_image_array_dynamic_indexing => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderStorageImageArrayDynamicIndexing)
- ",
- ffi_name: shader_storage_image_array_dynamic_indexing,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_storage_image_array_non_uniform_indexing => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderStorageImageArrayNonUniformIndexing)
- ",
- ffi_name: shader_storage_image_array_non_uniform_indexing,
- ffi_members: [features_vulkan12, features_descriptor_indexing],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_storage_image_extended_formats => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderStorageImageExtendedFormats)
- ",
- ffi_name: shader_storage_image_extended_formats,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_storage_image_multisample => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderStorageImageMultisample)
- ",
- ffi_name: shader_storage_image_multisample,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_storage_image_read_without_format => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderStorageImageReadWithoutFormat)
- ",
- ffi_name: shader_storage_image_read_without_format,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_storage_image_write_without_format => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderStorageImageWriteWithoutFormat)
- ",
- ffi_name: shader_storage_image_write_without_format,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_storage_texel_buffer_array_dynamic_indexing => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderStorageTexelBufferArrayDynamicIndexing)
- ",
- ffi_name: shader_storage_texel_buffer_array_dynamic_indexing,
- ffi_members: [features_vulkan12, features_descriptor_indexing],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_storage_texel_buffer_array_non_uniform_indexing => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderStorageTexelBufferArrayNonUniformIndexing)
- ",
- ffi_name: shader_storage_texel_buffer_array_non_uniform_indexing,
- ffi_members: [features_vulkan12, features_descriptor_indexing],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_subgroup_clock => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderClockFeaturesKHR.html#features-shaderSubgroupClock)
- ",
- ffi_name: shader_subgroup_clock,
- ffi_members: [features_shader_clock_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_subgroup_extended_types => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderSubgroupExtendedTypes)
- ",
- ffi_name: shader_subgroup_extended_types,
- ffi_members: [features_vulkan12, features_shader_subgroup_extended_types],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_subgroup_uniform_control_flow => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR.html#features-shaderSubgroupUniformControlFlow)
- ",
- ffi_name: shader_subgroup_uniform_control_flow,
- ffi_members: [features_shader_subgroup_uniform_control_flow_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_terminate_invocation => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderTerminateInvocationFeaturesKHR.html#features-shaderTerminateInvocation)
- ",
- ffi_name: shader_terminate_invocation,
- ffi_members: [features_shader_terminate_invocation_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_tessellation_and_geometry_point_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderTessellationAndGeometryPointSize)
- ",
- ffi_name: shader_tessellation_and_geometry_point_size,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_uniform_buffer_array_dynamic_indexing => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderUniformBufferArrayDynamicIndexing)
- ",
- ffi_name: shader_uniform_buffer_array_dynamic_indexing,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_uniform_buffer_array_non_uniform_indexing => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderUniformBufferArrayNonUniformIndexing)
- ",
- ffi_name: shader_uniform_buffer_array_non_uniform_indexing,
- ffi_members: [features_vulkan12, features_descriptor_indexing],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_uniform_texel_buffer_array_dynamic_indexing => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderUniformTexelBufferArrayDynamicIndexing)
- ",
- ffi_name: shader_uniform_texel_buffer_array_dynamic_indexing,
- ffi_members: [features_vulkan12, features_descriptor_indexing],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_uniform_texel_buffer_array_non_uniform_indexing => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderUniformTexelBufferArrayNonUniformIndexing)
- ",
- ffi_name: shader_uniform_texel_buffer_array_non_uniform_indexing,
- ffi_members: [features_vulkan12, features_descriptor_indexing],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shader_zero_initialize_workgroup_memory => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeaturesKHR.html#features-shaderZeroInitializeWorkgroupMemory)
- ",
- ffi_name: shader_zero_initialize_workgroup_memory,
- ffi_members: [features_zero_initialize_workgroup_memory_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shading_rate_coarse_sample_order => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShadingRateImageFeaturesNV.html#features-shadingRateCoarseSampleOrder)
- ",
- ffi_name: shading_rate_coarse_sample_order,
- ffi_members: [features_shading_rate_image_nv],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- shading_rate_image => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShadingRateImageFeaturesNV.html#features-shadingRateImage)
- - Conflicts with features: [`pipeline_fragment_shading_rate`](crate::device::Features::pipeline_fragment_shading_rate), [`primitive_fragment_shading_rate`](crate::device::Features::primitive_fragment_shading_rate), [`attachment_fragment_shading_rate`](crate::device::Features::attachment_fragment_shading_rate)
- ",
- ffi_name: shading_rate_image,
- ffi_members: [features_shading_rate_image_nv],
- requires_features: [],
- conflicts_features: [pipeline_fragment_shading_rate, primitive_fragment_shading_rate, attachment_fragment_shading_rate],
- required_by_extensions: [],
- },
- smooth_lines => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLineRasterizationFeaturesEXT.html#features-smoothLines)
- ",
- ffi_name: smooth_lines,
- ffi_members: [features_line_rasterization_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- sparse_binding => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-sparseBinding)
- ",
- ffi_name: sparse_binding,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- sparse_image_float32_atomic_add => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderAtomicFloatFeaturesEXT.html#features-sparseImageFloat32AtomicAdd)
- - Requires feature: [`shader_image_float32_atomic_add`](crate::device::Features::shader_image_float32_atomic_add)
- ",
- ffi_name: sparse_image_float32_atomic_add,
- ffi_members: [features_shader_atomic_float_ext],
- requires_features: [shader_image_float32_atomic_add],
- conflicts_features: [],
- required_by_extensions: [],
- },
- sparse_image_float32_atomic_min_max => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT.html#features-sparseImageFloat32AtomicMinMax)
- ",
- ffi_name: sparse_image_float32_atomic_min_max,
- ffi_members: [features_shader_atomic_float2_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- sparse_image_float32_atomics => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderAtomicFloatFeaturesEXT.html#features-sparseImageFloat32Atomics)
- - Requires feature: [`shader_image_float32_atomics`](crate::device::Features::shader_image_float32_atomics)
- ",
- ffi_name: sparse_image_float32_atomics,
- ffi_members: [features_shader_atomic_float_ext],
- requires_features: [shader_image_float32_atomics],
- conflicts_features: [],
- required_by_extensions: [],
- },
- sparse_image_int64_atomics => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT.html#features-sparseImageInt64Atomics)
- - Requires feature: [`shader_image_int64_atomics`](crate::device::Features::shader_image_int64_atomics)
- ",
- ffi_name: sparse_image_int64_atomics,
- ffi_members: [features_shader_image_atomic_int64_ext],
- requires_features: [shader_image_int64_atomics],
- conflicts_features: [],
- required_by_extensions: [],
- },
- sparse_residency16_samples => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-sparseResidency16Samples)
- ",
- ffi_name: sparse_residency16_samples,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- sparse_residency2_samples => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-sparseResidency2Samples)
- ",
- ffi_name: sparse_residency2_samples,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- sparse_residency4_samples => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-sparseResidency4Samples)
- ",
- ffi_name: sparse_residency4_samples,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- sparse_residency8_samples => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-sparseResidency8Samples)
- ",
- ffi_name: sparse_residency8_samples,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- sparse_residency_aliased => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-sparseResidencyAliased)
- ",
- ffi_name: sparse_residency_aliased,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- sparse_residency_buffer => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-sparseResidencyBuffer)
- ",
- ffi_name: sparse_residency_buffer,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- sparse_residency_image2_d => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-sparseResidencyImage2D)
- ",
- ffi_name: sparse_residency_image2_d,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- sparse_residency_image3_d => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-sparseResidencyImage3D)
- ",
- ffi_name: sparse_residency_image3_d,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- stippled_bresenham_lines => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLineRasterizationFeaturesEXT.html#features-stippledBresenhamLines)
- ",
- ffi_name: stippled_bresenham_lines,
- ffi_members: [features_line_rasterization_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- stippled_rectangular_lines => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLineRasterizationFeaturesEXT.html#features-stippledRectangularLines)
- ",
- ffi_name: stippled_rectangular_lines,
- ffi_members: [features_line_rasterization_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- stippled_smooth_lines => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLineRasterizationFeaturesEXT.html#features-stippledSmoothLines)
- ",
- ffi_name: stippled_smooth_lines,
- ffi_members: [features_line_rasterization_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- storage_buffer16_bit_access => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan11Features.html#features-storageBuffer16BitAccess)
- ",
- ffi_name: storage_buffer16_bit_access,
- ffi_members: [features_vulkan11, features_16bit_storage],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- storage_buffer8_bit_access => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-storageBuffer8BitAccess)
- ",
- ffi_name: storage_buffer8_bit_access,
- ffi_members: [features_vulkan12, features_8bit_storage],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- storage_input_output16 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan11Features.html#features-storageInputOutput16)
- ",
- ffi_name: storage_input_output16,
- ffi_members: [features_vulkan11, features_16bit_storage],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- storage_push_constant16 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan11Features.html#features-storagePushConstant16)
- ",
- ffi_name: storage_push_constant16,
- ffi_members: [features_vulkan11, features_16bit_storage],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- storage_push_constant8 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-storagePushConstant8)
- ",
- ffi_name: storage_push_constant8,
- ffi_members: [features_vulkan12, features_8bit_storage],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- subgroup_broadcast_dynamic_id => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-subgroupBroadcastDynamicId)
- ",
- ffi_name: subgroup_broadcast_dynamic_id,
- ffi_members: [features_vulkan12],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- subgroup_size_control => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceSubgroupSizeControlFeaturesEXT.html#features-subgroupSizeControl)
- ",
- ffi_name: subgroup_size_control,
- ffi_members: [features_subgroup_size_control_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- subpass_shading => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceSubpassShadingFeaturesHUAWEI.html#features-subpassShading)
- ",
- ffi_name: subpass_shading,
- ffi_members: [features_subpass_shading_huawei],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- supersample_fragment_shading_rates => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV.html#features-supersampleFragmentShadingRates)
- ",
- ffi_name: supersample_fragment_shading_rates,
- ffi_members: [features_fragment_shading_rate_enums_nv],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- synchronization2 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceSynchronization2FeaturesKHR.html#features-synchronization2)
- ",
- ffi_name: synchronization2,
- ffi_members: [features_synchronization2_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- task_shader => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceMeshShaderFeaturesNV.html#features-taskShader)
- ",
- ffi_name: task_shader,
- ffi_members: [features_mesh_shader_nv],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- tessellation_isolines => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDevicePortabilitySubsetFeaturesKHR.html#features-tessellationIsolines)
- ",
- ffi_name: tessellation_isolines,
- ffi_members: [features_portability_subset_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- tessellation_point_mode => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDevicePortabilitySubsetFeaturesKHR.html#features-tessellationPointMode)
- ",
- ffi_name: tessellation_point_mode,
- ffi_members: [features_portability_subset_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- tessellation_shader => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-tessellationShader)
- ",
- ffi_name: tessellation_shader,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- texel_buffer_alignment => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT.html#features-texelBufferAlignment)
- ",
- ffi_name: texel_buffer_alignment,
- ffi_members: [features_texel_buffer_alignment_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- texture_compression_astc_hdr => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceTextureCompressionASTCHDRFeaturesEXT.html#features-textureCompressionASTC_HDR)
- ",
- ffi_name: texture_compression_astc_hdr,
- ffi_members: [features_texture_compression_astchdr_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- texture_compression_astc_ldr => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-textureCompressionASTC_LDR)
- ",
- ffi_name: texture_compression_astc_ldr,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- texture_compression_bc => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-textureCompressionBC)
- ",
- ffi_name: texture_compression_bc,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- texture_compression_etc2 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-textureCompressionETC2)
- ",
- ffi_name: texture_compression_etc2,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- timeline_semaphore => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-timelineSemaphore)
- ",
- ffi_name: timeline_semaphore,
- ffi_members: [features_vulkan12, features_timeline_semaphore],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- transform_feedback => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceTransformFeedbackFeaturesEXT.html#features-transformFeedback)
- ",
- ffi_name: transform_feedback,
- ffi_members: [features_transform_feedback_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- transform_feedback_preserves_provoking_vertex => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceProvokingVertexFeaturesEXT.html#features-transformFeedbackPreservesProvokingVertex)
- ",
- ffi_name: transform_feedback_preserves_provoking_vertex,
- ffi_members: [features_provoking_vertex_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- triangle_fans => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDevicePortabilitySubsetFeaturesKHR.html#features-triangleFans)
- ",
- ffi_name: triangle_fans,
- ffi_members: [features_portability_subset_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- uniform_and_storage_buffer16_bit_access => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan11Features.html#features-uniformAndStorageBuffer16BitAccess)
- ",
- ffi_name: uniform_and_storage_buffer16_bit_access,
- ffi_members: [features_vulkan11, features_16bit_storage],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- uniform_and_storage_buffer8_bit_access => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-uniformAndStorageBuffer8BitAccess)
- ",
- ffi_name: uniform_and_storage_buffer8_bit_access,
- ffi_members: [features_vulkan12, features_8bit_storage],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- uniform_buffer_standard_layout => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-uniformBufferStandardLayout)
- ",
- ffi_name: uniform_buffer_standard_layout,
- ffi_members: [features_vulkan12, features_uniform_buffer_standard_layout],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- variable_multisample_rate => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-variableMultisampleRate)
- ",
- ffi_name: variable_multisample_rate,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- variable_pointers => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan11Features.html#features-variablePointers)
- ",
- ffi_name: variable_pointers,
- ffi_members: [features_vulkan11, features_variable_pointers],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- variable_pointers_storage_buffer => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan11Features.html#features-variablePointersStorageBuffer)
- ",
- ffi_name: variable_pointers_storage_buffer,
- ffi_members: [features_vulkan11, features_variable_pointers],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- vertex_attribute_access_beyond_stride => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDevicePortabilitySubsetFeaturesKHR.html#features-vertexAttributeAccessBeyondStride)
- ",
- ffi_name: vertex_attribute_access_beyond_stride,
- ffi_members: [features_portability_subset_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- vertex_attribute_instance_rate_divisor => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT.html#features-vertexAttributeInstanceRateDivisor)
- ",
- ffi_name: vertex_attribute_instance_rate_divisor,
- ffi_members: [features_vertex_attribute_divisor_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- vertex_attribute_instance_rate_zero_divisor => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT.html#features-vertexAttributeInstanceRateZeroDivisor)
- ",
- ffi_name: vertex_attribute_instance_rate_zero_divisor,
- ffi_members: [features_vertex_attribute_divisor_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- vertex_input_dynamic_state => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT.html#features-vertexInputDynamicState)
- ",
- ffi_name: vertex_input_dynamic_state,
- ffi_members: [features_vertex_input_dynamic_state_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- vertex_pipeline_stores_and_atomics => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-vertexPipelineStoresAndAtomics)
- ",
- ffi_name: vertex_pipeline_stores_and_atomics,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- vulkan_memory_model => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-vulkanMemoryModel)
- ",
- ffi_name: vulkan_memory_model,
- ffi_members: [features_vulkan12, features_vulkan_memory_model],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- vulkan_memory_model_availability_visibility_chains => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-vulkanMemoryModelAvailabilityVisibilityChains)
- ",
- ffi_name: vulkan_memory_model_availability_visibility_chains,
- ffi_members: [features_vulkan12, features_vulkan_memory_model],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- vulkan_memory_model_device_scope => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-vulkanMemoryModelDeviceScope)
- ",
- ffi_name: vulkan_memory_model_device_scope,
- ffi_members: [features_vulkan12, features_vulkan_memory_model],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- wide_lines => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFeatures.html#features-wideLines)
- ",
- ffi_name: wide_lines,
- ffi_members: [features_vulkan10.features],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- workgroup_memory_explicit_layout => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR.html#features-workgroupMemoryExplicitLayout)
- ",
- ffi_name: workgroup_memory_explicit_layout,
- ffi_members: [features_workgroup_memory_explicit_layout_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- workgroup_memory_explicit_layout16_bit_access => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR.html#features-workgroupMemoryExplicitLayout16BitAccess)
- ",
- ffi_name: workgroup_memory_explicit_layout16_bit_access,
- ffi_members: [features_workgroup_memory_explicit_layout_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- workgroup_memory_explicit_layout8_bit_access => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR.html#features-workgroupMemoryExplicitLayout8BitAccess)
- ",
- ffi_name: workgroup_memory_explicit_layout8_bit_access,
- ffi_members: [features_workgroup_memory_explicit_layout_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- workgroup_memory_explicit_layout_scalar_block_layout => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR.html#features-workgroupMemoryExplicitLayoutScalarBlockLayout)
- ",
- ffi_name: workgroup_memory_explicit_layout_scalar_block_layout,
- ffi_members: [features_workgroup_memory_explicit_layout_khr],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- ycbcr2plane444_formats => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT.html#features-ycbcr2plane444Formats)
- ",
- ffi_name: ycbcr2plane444_formats,
- ffi_members: [features_ycbcr2_plane444_formats_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
- ycbcr_image_arrays => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceYcbcrImageArraysFeaturesEXT.html#features-ycbcrImageArrays)
- ",
- ffi_name: ycbcr_image_arrays,
- ffi_members: [features_ycbcr_image_arrays_ext],
- requires_features: [],
- conflicts_features: [],
- required_by_extensions: [],
- },
-}
-
-crate::device::features::features_ffi! {
- api_version,
- device_extensions,
- instance_extensions,
- features_vulkan11 => {
- ty: PhysicalDeviceVulkan11Features,
- provided_by: [api_version >= crate::Version::V1_2],
- conflicts: [],
- },
- features_vulkan12 => {
- ty: PhysicalDeviceVulkan12Features,
- provided_by: [api_version >= crate::Version::V1_2],
- conflicts: [],
- },
- features_16bit_storage => {
- ty: PhysicalDevice16BitStorageFeatures,
- provided_by: [api_version >= crate::Version::V1_1, device_extensions.khr_16bit_storage],
- conflicts: [features_vulkan11],
- },
- features_multiview => {
- ty: PhysicalDeviceMultiviewFeatures,
- provided_by: [api_version >= crate::Version::V1_1, device_extensions.khr_multiview],
- conflicts: [features_vulkan11],
- },
- features_protected_memory => {
- ty: PhysicalDeviceProtectedMemoryFeatures,
- provided_by: [api_version >= crate::Version::V1_1],
- conflicts: [features_vulkan11],
- },
- features_sampler_ycbcr_conversion => {
- ty: PhysicalDeviceSamplerYcbcrConversionFeatures,
- provided_by: [api_version >= crate::Version::V1_1, device_extensions.khr_sampler_ycbcr_conversion],
- conflicts: [features_vulkan11],
- },
- features_shader_draw_parameters => {
- ty: PhysicalDeviceShaderDrawParametersFeatures,
- provided_by: [api_version >= crate::Version::V1_1],
- conflicts: [features_vulkan11],
- },
- features_variable_pointers => {
- ty: PhysicalDeviceVariablePointersFeatures,
- provided_by: [api_version >= crate::Version::V1_1, device_extensions.khr_variable_pointers],
- conflicts: [features_vulkan11],
- },
- features_8bit_storage => {
- ty: PhysicalDevice8BitStorageFeatures,
- provided_by: [api_version >= crate::Version::V1_2, device_extensions.khr_8bit_storage],
- conflicts: [features_vulkan12],
- },
- features_buffer_device_address => {
- ty: PhysicalDeviceBufferDeviceAddressFeatures,
- provided_by: [api_version >= crate::Version::V1_2, device_extensions.khr_buffer_device_address],
- conflicts: [features_vulkan12],
- },
- features_descriptor_indexing => {
- ty: PhysicalDeviceDescriptorIndexingFeatures,
- provided_by: [api_version >= crate::Version::V1_2, device_extensions.ext_descriptor_indexing],
- conflicts: [features_vulkan12],
- },
- features_host_query_reset => {
- ty: PhysicalDeviceHostQueryResetFeatures,
- provided_by: [api_version >= crate::Version::V1_2, device_extensions.ext_host_query_reset],
- conflicts: [features_vulkan12],
- },
- features_imageless_framebuffer => {
- ty: PhysicalDeviceImagelessFramebufferFeatures,
- provided_by: [api_version >= crate::Version::V1_2, device_extensions.khr_imageless_framebuffer],
- conflicts: [features_vulkan12],
- },
- features_scalar_block_layout => {
- ty: PhysicalDeviceScalarBlockLayoutFeatures,
- provided_by: [api_version >= crate::Version::V1_2, device_extensions.ext_scalar_block_layout],
- conflicts: [features_vulkan12],
- },
- features_separate_depth_stencil_layouts => {
- ty: PhysicalDeviceSeparateDepthStencilLayoutsFeatures,
- provided_by: [api_version >= crate::Version::V1_2, device_extensions.khr_separate_depth_stencil_layouts],
- conflicts: [features_vulkan12],
- },
- features_shader_atomic_int64 => {
- ty: PhysicalDeviceShaderAtomicInt64Features,
- provided_by: [api_version >= crate::Version::V1_2, device_extensions.khr_shader_atomic_int64],
- conflicts: [features_vulkan12],
- },
- features_shader_float16_int8 => {
- ty: PhysicalDeviceShaderFloat16Int8Features,
- provided_by: [api_version >= crate::Version::V1_2, device_extensions.khr_shader_float16_int8],
- conflicts: [features_vulkan12],
- },
- features_shader_subgroup_extended_types => {
- ty: PhysicalDeviceShaderSubgroupExtendedTypesFeatures,
- provided_by: [api_version >= crate::Version::V1_2, device_extensions.khr_shader_subgroup_extended_types],
- conflicts: [features_vulkan12],
- },
- features_timeline_semaphore => {
- ty: PhysicalDeviceTimelineSemaphoreFeatures,
- provided_by: [api_version >= crate::Version::V1_2, device_extensions.khr_timeline_semaphore],
- conflicts: [features_vulkan12],
- },
- features_uniform_buffer_standard_layout => {
- ty: PhysicalDeviceUniformBufferStandardLayoutFeatures,
- provided_by: [api_version >= crate::Version::V1_2, device_extensions.khr_uniform_buffer_standard_layout],
- conflicts: [features_vulkan12],
- },
- features_vulkan_memory_model => {
- ty: PhysicalDeviceVulkanMemoryModelFeatures,
- provided_by: [api_version >= crate::Version::V1_2, device_extensions.khr_vulkan_memory_model],
- conflicts: [features_vulkan12],
- },
- features_acceleration_structure_khr => {
- ty: PhysicalDeviceAccelerationStructureFeaturesKHR,
- provided_by: [device_extensions.khr_acceleration_structure],
- conflicts: [],
- },
- features_fragment_shading_rate_khr => {
- ty: PhysicalDeviceFragmentShadingRateFeaturesKHR,
- provided_by: [device_extensions.khr_fragment_shading_rate],
- conflicts: [],
- },
- features_performance_query_khr => {
- ty: PhysicalDevicePerformanceQueryFeaturesKHR,
- provided_by: [device_extensions.khr_performance_query],
- conflicts: [],
- },
- features_pipeline_executable_properties_khr => {
- ty: PhysicalDevicePipelineExecutablePropertiesFeaturesKHR,
- provided_by: [device_extensions.khr_pipeline_executable_properties],
- conflicts: [],
- },
- features_portability_subset_khr => {
- ty: PhysicalDevicePortabilitySubsetFeaturesKHR,
- provided_by: [device_extensions.khr_portability_subset],
- conflicts: [],
- },
- features_present_id_khr => {
- ty: PhysicalDevicePresentIdFeaturesKHR,
- provided_by: [device_extensions.khr_present_id],
- conflicts: [],
- },
- features_present_wait_khr => {
- ty: PhysicalDevicePresentWaitFeaturesKHR,
- provided_by: [device_extensions.khr_present_wait],
- conflicts: [],
- },
- features_ray_query_khr => {
- ty: PhysicalDeviceRayQueryFeaturesKHR,
- provided_by: [device_extensions.khr_ray_query],
- conflicts: [],
- },
- features_ray_tracing_pipeline_khr => {
- ty: PhysicalDeviceRayTracingPipelineFeaturesKHR,
- provided_by: [device_extensions.khr_ray_tracing_pipeline],
- conflicts: [],
- },
- features_shader_clock_khr => {
- ty: PhysicalDeviceShaderClockFeaturesKHR,
- provided_by: [device_extensions.khr_shader_clock],
- conflicts: [],
- },
- features_shader_subgroup_uniform_control_flow_khr => {
- ty: PhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR,
- provided_by: [device_extensions.khr_shader_subgroup_uniform_control_flow],
- conflicts: [],
- },
- features_shader_terminate_invocation_khr => {
- ty: PhysicalDeviceShaderTerminateInvocationFeaturesKHR,
- provided_by: [device_extensions.khr_shader_terminate_invocation],
- conflicts: [],
- },
- features_synchronization2_khr => {
- ty: PhysicalDeviceSynchronization2FeaturesKHR,
- provided_by: [device_extensions.khr_synchronization2],
- conflicts: [],
- },
- features_workgroup_memory_explicit_layout_khr => {
- ty: PhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR,
- provided_by: [device_extensions.khr_workgroup_memory_explicit_layout],
- conflicts: [],
- },
- features_zero_initialize_workgroup_memory_khr => {
- ty: PhysicalDeviceZeroInitializeWorkgroupMemoryFeaturesKHR,
- provided_by: [device_extensions.khr_zero_initialize_workgroup_memory],
- conflicts: [],
- },
- features_4444formats_ext => {
- ty: PhysicalDevice4444FormatsFeaturesEXT,
- provided_by: [device_extensions.ext_4444_formats],
- conflicts: [],
- },
- features_astc_decode_ext => {
- ty: PhysicalDeviceASTCDecodeFeaturesEXT,
- provided_by: [device_extensions.ext_astc_decode_mode],
- conflicts: [],
- },
- features_blend_operation_advanced_ext => {
- ty: PhysicalDeviceBlendOperationAdvancedFeaturesEXT,
- provided_by: [device_extensions.ext_blend_operation_advanced],
- conflicts: [],
- },
- features_buffer_device_address_ext => {
- ty: PhysicalDeviceBufferDeviceAddressFeaturesEXT,
- provided_by: [device_extensions.ext_buffer_device_address],
- conflicts: [features_vulkan12, features_buffer_device_address],
- },
- features_color_write_enable_ext => {
- ty: PhysicalDeviceColorWriteEnableFeaturesEXT,
- provided_by: [device_extensions.ext_color_write_enable],
- conflicts: [],
- },
- features_conditional_rendering_ext => {
- ty: PhysicalDeviceConditionalRenderingFeaturesEXT,
- provided_by: [device_extensions.ext_conditional_rendering],
- conflicts: [],
- },
- features_custom_border_color_ext => {
- ty: PhysicalDeviceCustomBorderColorFeaturesEXT,
- provided_by: [device_extensions.ext_custom_border_color],
- conflicts: [],
- },
- features_depth_clip_enable_ext => {
- ty: PhysicalDeviceDepthClipEnableFeaturesEXT,
- provided_by: [device_extensions.ext_depth_clip_enable],
- conflicts: [],
- },
- features_device_memory_report_ext => {
- ty: PhysicalDeviceDeviceMemoryReportFeaturesEXT,
- provided_by: [device_extensions.ext_device_memory_report],
- conflicts: [],
- },
- features_extended_dynamic_state2_ext => {
- ty: PhysicalDeviceExtendedDynamicState2FeaturesEXT,
- provided_by: [device_extensions.ext_extended_dynamic_state2],
- conflicts: [],
- },
- features_extended_dynamic_state_ext => {
- ty: PhysicalDeviceExtendedDynamicStateFeaturesEXT,
- provided_by: [device_extensions.ext_extended_dynamic_state],
- conflicts: [],
- },
- features_fragment_density_map2_ext => {
- ty: PhysicalDeviceFragmentDensityMap2FeaturesEXT,
- provided_by: [device_extensions.ext_fragment_density_map2],
- conflicts: [],
- },
- features_fragment_density_map_ext => {
- ty: PhysicalDeviceFragmentDensityMapFeaturesEXT,
- provided_by: [device_extensions.ext_fragment_density_map],
- conflicts: [],
- },
- features_fragment_shader_interlock_ext => {
- ty: PhysicalDeviceFragmentShaderInterlockFeaturesEXT,
- provided_by: [device_extensions.ext_fragment_shader_interlock],
- conflicts: [],
- },
- features_global_priority_query_ext => {
- ty: PhysicalDeviceGlobalPriorityQueryFeaturesEXT,
- provided_by: [device_extensions.ext_global_priority_query],
- conflicts: [],
- },
- features_image_robustness_ext => {
- ty: PhysicalDeviceImageRobustnessFeaturesEXT,
- provided_by: [device_extensions.ext_image_robustness],
- conflicts: [],
- },
- features_index_type_uint8_ext => {
- ty: PhysicalDeviceIndexTypeUint8FeaturesEXT,
- provided_by: [device_extensions.ext_index_type_uint8],
- conflicts: [],
- },
- features_inline_uniform_block_ext => {
- ty: PhysicalDeviceInlineUniformBlockFeaturesEXT,
- provided_by: [device_extensions.ext_inline_uniform_block],
- conflicts: [],
- },
- features_line_rasterization_ext => {
- ty: PhysicalDeviceLineRasterizationFeaturesEXT,
- provided_by: [device_extensions.ext_line_rasterization],
- conflicts: [],
- },
- features_memory_priority_ext => {
- ty: PhysicalDeviceMemoryPriorityFeaturesEXT,
- provided_by: [device_extensions.ext_memory_priority],
- conflicts: [],
- },
- features_multi_draw_ext => {
- ty: PhysicalDeviceMultiDrawFeaturesEXT,
- provided_by: [device_extensions.ext_multi_draw],
- conflicts: [],
- },
- features_pipeline_creation_cache_control_ext => {
- ty: PhysicalDevicePipelineCreationCacheControlFeaturesEXT,
- provided_by: [device_extensions.ext_pipeline_creation_cache_control],
- conflicts: [],
- },
- features_private_data_ext => {
- ty: PhysicalDevicePrivateDataFeaturesEXT,
- provided_by: [device_extensions.ext_private_data],
- conflicts: [],
- },
- features_provoking_vertex_ext => {
- ty: PhysicalDeviceProvokingVertexFeaturesEXT,
- provided_by: [device_extensions.ext_provoking_vertex],
- conflicts: [],
- },
- features_robustness2_ext => {
- ty: PhysicalDeviceRobustness2FeaturesEXT,
- provided_by: [device_extensions.ext_robustness2],
- conflicts: [],
- },
- features_shader_atomic_float2_ext => {
- ty: PhysicalDeviceShaderAtomicFloat2FeaturesEXT,
- provided_by: [device_extensions.ext_shader_atomic_float2],
- conflicts: [],
- },
- features_shader_atomic_float_ext => {
- ty: PhysicalDeviceShaderAtomicFloatFeaturesEXT,
- provided_by: [device_extensions.ext_shader_atomic_float],
- conflicts: [],
- },
- features_shader_demote_to_helper_invocation_ext => {
- ty: PhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT,
- provided_by: [device_extensions.ext_shader_demote_to_helper_invocation],
- conflicts: [],
- },
- features_shader_image_atomic_int64_ext => {
- ty: PhysicalDeviceShaderImageAtomicInt64FeaturesEXT,
- provided_by: [device_extensions.ext_shader_image_atomic_int64],
- conflicts: [],
- },
- features_subgroup_size_control_ext => {
- ty: PhysicalDeviceSubgroupSizeControlFeaturesEXT,
- provided_by: [device_extensions.ext_subgroup_size_control],
- conflicts: [],
- },
- features_texel_buffer_alignment_ext => {
- ty: PhysicalDeviceTexelBufferAlignmentFeaturesEXT,
- provided_by: [device_extensions.ext_texel_buffer_alignment],
- conflicts: [],
- },
- features_texture_compression_astchdr_ext => {
- ty: PhysicalDeviceTextureCompressionASTCHDRFeaturesEXT,
- provided_by: [device_extensions.ext_texture_compression_astc_hdr],
- conflicts: [],
- },
- features_transform_feedback_ext => {
- ty: PhysicalDeviceTransformFeedbackFeaturesEXT,
- provided_by: [device_extensions.ext_transform_feedback],
- conflicts: [],
- },
- features_vertex_attribute_divisor_ext => {
- ty: PhysicalDeviceVertexAttributeDivisorFeaturesEXT,
- provided_by: [device_extensions.ext_vertex_attribute_divisor],
- conflicts: [],
- },
- features_vertex_input_dynamic_state_ext => {
- ty: PhysicalDeviceVertexInputDynamicStateFeaturesEXT,
- provided_by: [device_extensions.ext_vertex_input_dynamic_state],
- conflicts: [],
- },
- features_ycbcr2_plane444_formats_ext => {
- ty: PhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT,
- provided_by: [device_extensions.ext_ycbcr_2plane_444_formats],
- conflicts: [],
- },
- features_ycbcr_image_arrays_ext => {
- ty: PhysicalDeviceYcbcrImageArraysFeaturesEXT,
- provided_by: [device_extensions.ext_ycbcr_image_arrays],
- conflicts: [],
- },
- features_coherent_memory_amd => {
- ty: PhysicalDeviceCoherentMemoryFeaturesAMD,
- provided_by: [device_extensions.amd_device_coherent_memory],
- conflicts: [],
- },
- features_compute_shader_derivatives_nv => {
- ty: PhysicalDeviceComputeShaderDerivativesFeaturesNV,
- provided_by: [device_extensions.nv_compute_shader_derivatives],
- conflicts: [],
- },
- features_cooperative_matrix_nv => {
- ty: PhysicalDeviceCooperativeMatrixFeaturesNV,
- provided_by: [device_extensions.nv_cooperative_matrix],
- conflicts: [],
- },
- features_corner_sampled_image_nv => {
- ty: PhysicalDeviceCornerSampledImageFeaturesNV,
- provided_by: [device_extensions.nv_corner_sampled_image],
- conflicts: [],
- },
- features_coverage_reduction_mode_nv => {
- ty: PhysicalDeviceCoverageReductionModeFeaturesNV,
- provided_by: [device_extensions.nv_coverage_reduction_mode],
- conflicts: [],
- },
- features_dedicated_allocation_image_aliasing_nv => {
- ty: PhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV,
- provided_by: [device_extensions.nv_dedicated_allocation_image_aliasing],
- conflicts: [],
- },
- features_device_generated_commands_nv => {
- ty: PhysicalDeviceDeviceGeneratedCommandsFeaturesNV,
- provided_by: [device_extensions.nv_device_generated_commands],
- conflicts: [],
- },
- features_diagnostics_config_nv => {
- ty: PhysicalDeviceDiagnosticsConfigFeaturesNV,
- provided_by: [device_extensions.nv_device_diagnostics_config],
- conflicts: [],
- },
- features_exclusive_scissor_nv => {
- ty: PhysicalDeviceExclusiveScissorFeaturesNV,
- provided_by: [device_extensions.nv_scissor_exclusive],
- conflicts: [],
- },
- features_external_memory_rdma_nv => {
- ty: PhysicalDeviceExternalMemoryRDMAFeaturesNV,
- provided_by: [device_extensions.nv_external_memory_rdma],
- conflicts: [],
- },
- features_fragment_shader_barycentric_nv => {
- ty: PhysicalDeviceFragmentShaderBarycentricFeaturesNV,
- provided_by: [device_extensions.nv_fragment_shader_barycentric],
- conflicts: [],
- },
- features_fragment_shading_rate_enums_nv => {
- ty: PhysicalDeviceFragmentShadingRateEnumsFeaturesNV,
- provided_by: [device_extensions.nv_fragment_shading_rate_enums],
- conflicts: [],
- },
- features_inherited_viewport_scissor_nv => {
- ty: PhysicalDeviceInheritedViewportScissorFeaturesNV,
- provided_by: [device_extensions.nv_inherited_viewport_scissor],
- conflicts: [],
- },
- features_invocation_mask_huawei => {
- ty: PhysicalDeviceInvocationMaskFeaturesHUAWEI,
- provided_by: [device_extensions.huawei_invocation_mask],
- conflicts: [],
- },
- features_mesh_shader_nv => {
- ty: PhysicalDeviceMeshShaderFeaturesNV,
- provided_by: [device_extensions.nv_mesh_shader],
- conflicts: [],
- },
- features_mutable_descriptor_type_valve => {
- ty: PhysicalDeviceMutableDescriptorTypeFeaturesVALVE,
- provided_by: [device_extensions.valve_mutable_descriptor_type],
- conflicts: [],
- },
- features_ray_tracing_motion_blur_nv => {
- ty: PhysicalDeviceRayTracingMotionBlurFeaturesNV,
- provided_by: [device_extensions.nv_ray_tracing_motion_blur],
- conflicts: [],
- },
- features_representative_fragment_test_nv => {
- ty: PhysicalDeviceRepresentativeFragmentTestFeaturesNV,
- provided_by: [device_extensions.nv_representative_fragment_test],
- conflicts: [],
- },
- features_shader_image_footprint_nv => {
- ty: PhysicalDeviceShaderImageFootprintFeaturesNV,
- provided_by: [device_extensions.nv_shader_image_footprint],
- conflicts: [],
- },
- features_shader_integer_functions2_intel => {
- ty: PhysicalDeviceShaderIntegerFunctions2FeaturesINTEL,
- provided_by: [device_extensions.intel_shader_integer_functions2],
- conflicts: [],
- },
- features_shader_sm_builtins_nv => {
- ty: PhysicalDeviceShaderSMBuiltinsFeaturesNV,
- provided_by: [device_extensions.nv_shader_sm_builtins],
- conflicts: [],
- },
- features_shading_rate_image_nv => {
- ty: PhysicalDeviceShadingRateImageFeaturesNV,
- provided_by: [device_extensions.nv_shading_rate_image],
- conflicts: [],
- },
- features_subpass_shading_huawei => {
- ty: PhysicalDeviceSubpassShadingFeaturesHUAWEI,
- provided_by: [device_extensions.huawei_subpass_shading],
- conflicts: [],
- },
-}
-
-crate::device::properties::properties! {
- active_compute_unit_count => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderCoreProperties2AMD.html#limits-activeComputeUnitCount)
- ",
- ty: u32,
- ffi_name: active_compute_unit_count,
- ffi_members: [properties_shader_core2_amd],
- required: false,
- },
- advanced_blend_all_operations => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT.html#limits-advancedBlendAllOperations)
- ",
- ty: bool,
- ffi_name: advanced_blend_all_operations,
- ffi_members: [properties_blend_operation_advanced_ext],
- required: false,
- },
- advanced_blend_correlated_overlap => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT.html#limits-advancedBlendCorrelatedOverlap)
- ",
- ty: bool,
- ffi_name: advanced_blend_correlated_overlap,
- ffi_members: [properties_blend_operation_advanced_ext],
- required: false,
- },
- advanced_blend_independent_blend => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT.html#limits-advancedBlendIndependentBlend)
- ",
- ty: bool,
- ffi_name: advanced_blend_independent_blend,
- ffi_members: [properties_blend_operation_advanced_ext],
- required: false,
- },
- advanced_blend_max_color_attachments => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT.html#limits-advancedBlendMaxColorAttachments)
- ",
- ty: u32,
- ffi_name: advanced_blend_max_color_attachments,
- ffi_members: [properties_blend_operation_advanced_ext],
- required: false,
- },
- advanced_blend_non_premultiplied_dst_color => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT.html#limits-advancedBlendNonPremultipliedDstColor)
- ",
- ty: bool,
- ffi_name: advanced_blend_non_premultiplied_dst_color,
- ffi_members: [properties_blend_operation_advanced_ext],
- required: false,
- },
- advanced_blend_non_premultiplied_src_color => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT.html#limits-advancedBlendNonPremultipliedSrcColor)
- ",
- ty: bool,
- ffi_name: advanced_blend_non_premultiplied_src_color,
- ffi_members: [properties_blend_operation_advanced_ext],
- required: false,
- },
- allow_command_buffer_query_copies => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDevicePerformanceQueryPropertiesKHR.html#limits-allowCommandBufferQueryCopies)
- ",
- ty: bool,
- ffi_name: allow_command_buffer_query_copies,
- ffi_members: [properties_performance_query_khr],
- required: false,
- },
- api_version => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceProperties.html#limits-apiVersion)
- ",
- ty: crate::Version,
- ffi_name: api_version,
- ffi_members: [properties_vulkan10.properties],
- required: true,
- },
- buffer_image_granularity => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-bufferImageGranularity)
- ",
- ty: crate::DeviceSize,
- ffi_name: buffer_image_granularity,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- compute_units_per_shader_array => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderCorePropertiesAMD.html#limits-computeUnitsPerShaderArray)
- ",
- ty: u32,
- ffi_name: compute_units_per_shader_array,
- ffi_members: [properties_shader_core_amd],
- required: false,
- },
- conformance_version => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-conformanceVersion)
- ",
- ty: crate::device::physical::ConformanceVersion,
- ffi_name: conformance_version,
- ffi_members: [properties_vulkan12, properties_driver],
- required: false,
- },
- conservative_point_and_line_rasterization => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceConservativeRasterizationPropertiesEXT.html#limits-conservativePointAndLineRasterization)
- ",
- ty: bool,
- ffi_name: conservative_point_and_line_rasterization,
- ffi_members: [properties_conservative_rasterization_ext],
- required: false,
- },
- conservative_rasterization_post_depth_coverage => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceConservativeRasterizationPropertiesEXT.html#limits-conservativeRasterizationPostDepthCoverage)
- ",
- ty: bool,
- ffi_name: conservative_rasterization_post_depth_coverage,
- ffi_members: [properties_conservative_rasterization_ext],
- required: false,
- },
- cooperative_matrix_supported_stages => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceCooperativeMatrixPropertiesNV.html#limits-cooperativeMatrixSupportedStages)
- ",
- ty: crate::pipeline::shader::ShaderStages,
- ffi_name: cooperative_matrix_supported_stages,
- ffi_members: [properties_cooperative_matrix_nv],
- required: false,
- },
- degenerate_lines_rasterized => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceConservativeRasterizationPropertiesEXT.html#limits-degenerateLinesRasterized)
- ",
- ty: bool,
- ffi_name: degenerate_lines_rasterized,
- ffi_members: [properties_conservative_rasterization_ext],
- required: false,
- },
- degenerate_triangles_rasterized => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceConservativeRasterizationPropertiesEXT.html#limits-degenerateTrianglesRasterized)
- ",
- ty: bool,
- ffi_name: degenerate_triangles_rasterized,
- ffi_members: [properties_conservative_rasterization_ext],
- required: false,
- },
- denorm_behavior_independence => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-denormBehaviorIndependence)
- ",
- ty: crate::device::physical::ShaderFloatControlsIndependence,
- ffi_name: denorm_behavior_independence,
- ffi_members: [properties_vulkan12, properties_float_controls],
- required: false,
- },
- device_id => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceProperties.html#limits-deviceID)
- ",
- ty: u32,
- ffi_name: device_id,
- ffi_members: [properties_vulkan10.properties],
- required: true,
- },
- device_luid => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan11Properties.html#limits-deviceLUID)
- ",
- ty: [u8; 8],
- ffi_name: device_luid,
- ffi_members: [properties_vulkan11, properties_id],
- required: false,
- },
- device_luid_valid => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan11Properties.html#limits-deviceLUIDValid)
- ",
- ty: bool,
- ffi_name: device_luid_valid,
- ffi_members: [properties_vulkan11, properties_id],
- required: false,
- },
- device_name => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceProperties.html#limits-deviceName)
- ",
- ty: String,
- ffi_name: device_name,
- ffi_members: [properties_vulkan10.properties],
- required: true,
- },
- device_node_mask => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan11Properties.html#limits-deviceNodeMask)
- ",
- ty: u32,
- ffi_name: device_node_mask,
- ffi_members: [properties_vulkan11, properties_id],
- required: false,
- },
- device_type => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceProperties.html#limits-deviceType)
- ",
- ty: crate::device::physical::PhysicalDeviceType,
- ffi_name: device_type,
- ffi_members: [properties_vulkan10.properties],
- required: true,
- },
- device_uuid => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan11Properties.html#limits-deviceUUID)
- ",
- ty: [u8; 16],
- ffi_name: device_uuid,
- ffi_members: [properties_vulkan11, properties_id],
- required: false,
- },
- discrete_queue_priorities => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-discreteQueuePriorities)
- ",
- ty: u32,
- ffi_name: discrete_queue_priorities,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- driver_id => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-driverID)
- ",
- ty: crate::device::physical::DriverId,
- ffi_name: driver_id,
- ffi_members: [properties_vulkan12, properties_driver],
- required: false,
- },
- driver_info => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-driverInfo)
- ",
- ty: String,
- ffi_name: driver_info,
- ffi_members: [properties_vulkan12, properties_driver],
- required: false,
- },
- driver_name => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-driverName)
- ",
- ty: String,
- ffi_name: driver_name,
- ffi_members: [properties_vulkan12, properties_driver],
- required: false,
- },
- driver_uuid => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan11Properties.html#limits-driverUUID)
- ",
- ty: [u8; 16],
- ffi_name: driver_uuid,
- ffi_members: [properties_vulkan11, properties_id],
- required: false,
- },
- driver_version => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceProperties.html#limits-driverVersion)
- ",
- ty: u32,
- ffi_name: driver_version,
- ffi_members: [properties_vulkan10.properties],
- required: true,
- },
- extra_primitive_overestimation_size_granularity => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceConservativeRasterizationPropertiesEXT.html#limits-extraPrimitiveOverestimationSizeGranularity)
- ",
- ty: f32,
- ffi_name: extra_primitive_overestimation_size_granularity,
- ffi_members: [properties_conservative_rasterization_ext],
- required: false,
- },
- filter_minmax_image_component_mapping => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-filterMinmaxImageComponentMapping)
- ",
- ty: bool,
- ffi_name: filter_minmax_image_component_mapping,
- ffi_members: [properties_vulkan12, properties_sampler_filter_minmax],
- required: false,
- },
- filter_minmax_single_component_formats => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-filterMinmaxSingleComponentFormats)
- ",
- ty: bool,
- ffi_name: filter_minmax_single_component_formats,
- ffi_members: [properties_vulkan12, properties_sampler_filter_minmax],
- required: false,
- },
- fragment_density_invocations => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentDensityMapPropertiesEXT.html#limits-fragmentDensityInvocations)
- ",
- ty: bool,
- ffi_name: fragment_density_invocations,
- ffi_members: [properties_fragment_density_map_ext],
- required: false,
- },
- fragment_shading_rate_non_trivial_combiner_ops => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-fragmentShadingRateNonTrivialCombinerOps)
- ",
- ty: bool,
- ffi_name: fragment_shading_rate_non_trivial_combiner_ops,
- ffi_members: [properties_fragment_shading_rate_khr],
- required: false,
- },
- fragment_shading_rate_strict_multiply_combiner => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-fragmentShadingRateStrictMultiplyCombiner)
- ",
- ty: bool,
- ffi_name: fragment_shading_rate_strict_multiply_combiner,
- ffi_members: [properties_fragment_shading_rate_khr],
- required: false,
- },
- fragment_shading_rate_with_conservative_rasterization => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-fragmentShadingRateWithConservativeRasterization)
- ",
- ty: bool,
- ffi_name: fragment_shading_rate_with_conservative_rasterization,
- ffi_members: [properties_fragment_shading_rate_khr],
- required: false,
- },
- fragment_shading_rate_with_custom_sample_locations => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-fragmentShadingRateWithCustomSampleLocations)
- ",
- ty: bool,
- ffi_name: fragment_shading_rate_with_custom_sample_locations,
- ffi_members: [properties_fragment_shading_rate_khr],
- required: false,
- },
- fragment_shading_rate_with_fragment_shader_interlock => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-fragmentShadingRateWithFragmentShaderInterlock)
- ",
- ty: bool,
- ffi_name: fragment_shading_rate_with_fragment_shader_interlock,
- ffi_members: [properties_fragment_shading_rate_khr],
- required: false,
- },
- fragment_shading_rate_with_sample_mask => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-fragmentShadingRateWithSampleMask)
- ",
- ty: bool,
- ffi_name: fragment_shading_rate_with_sample_mask,
- ffi_members: [properties_fragment_shading_rate_khr],
- required: false,
- },
- fragment_shading_rate_with_shader_depth_stencil_writes => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-fragmentShadingRateWithShaderDepthStencilWrites)
- ",
- ty: bool,
- ffi_name: fragment_shading_rate_with_shader_depth_stencil_writes,
- ffi_members: [properties_fragment_shading_rate_khr],
- required: false,
- },
- fragment_shading_rate_with_shader_sample_mask => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-fragmentShadingRateWithShaderSampleMask)
- ",
- ty: bool,
- ffi_name: fragment_shading_rate_with_shader_sample_mask,
- ffi_members: [properties_fragment_shading_rate_khr],
- required: false,
- },
- framebuffer_color_sample_counts => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-framebufferColorSampleCounts)
- ",
- ty: crate::image::SampleCounts,
- ffi_name: framebuffer_color_sample_counts,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- framebuffer_depth_sample_counts => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-framebufferDepthSampleCounts)
- ",
- ty: crate::image::SampleCounts,
- ffi_name: framebuffer_depth_sample_counts,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- framebuffer_integer_color_sample_counts => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-framebufferIntegerColorSampleCounts)
- ",
- ty: crate::image::SampleCounts,
- ffi_name: framebuffer_integer_color_sample_counts,
- ffi_members: [properties_vulkan12],
- required: false,
- },
- framebuffer_no_attachments_sample_counts => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-framebufferNoAttachmentsSampleCounts)
- ",
- ty: crate::image::SampleCounts,
- ffi_name: framebuffer_no_attachments_sample_counts,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- framebuffer_stencil_sample_counts => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-framebufferStencilSampleCounts)
- ",
- ty: crate::image::SampleCounts,
- ffi_name: framebuffer_stencil_sample_counts,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- fully_covered_fragment_shader_input_variable => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceConservativeRasterizationPropertiesEXT.html#limits-fullyCoveredFragmentShaderInputVariable)
- ",
- ty: bool,
- ffi_name: fully_covered_fragment_shader_input_variable,
- ffi_members: [properties_conservative_rasterization_ext],
- required: false,
- },
- has_primary => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceDrmPropertiesEXT.html#limits-hasPrimary)
- ",
- ty: bool,
- ffi_name: has_primary,
- ffi_members: [properties_drm_ext],
- required: false,
- },
- has_render => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceDrmPropertiesEXT.html#limits-hasRender)
- ",
- ty: bool,
- ffi_name: has_render,
- ffi_members: [properties_drm_ext],
- required: false,
- },
- independent_resolve => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-independentResolve)
- ",
- ty: bool,
- ffi_name: independent_resolve,
- ffi_members: [properties_vulkan12, properties_depth_stencil_resolve],
- required: false,
- },
- independent_resolve_none => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-independentResolveNone)
- ",
- ty: bool,
- ffi_name: independent_resolve_none,
- ffi_members: [properties_vulkan12, properties_depth_stencil_resolve],
- required: false,
- },
- layered_shading_rate_attachments => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-layeredShadingRateAttachments)
- ",
- ty: bool,
- ffi_name: layered_shading_rate_attachments,
- ffi_members: [properties_fragment_shading_rate_khr],
- required: false,
- },
- line_sub_pixel_precision_bits => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLineRasterizationPropertiesEXT.html#limits-lineSubPixelPrecisionBits)
- ",
- ty: u32,
- ffi_name: line_sub_pixel_precision_bits,
- ffi_members: [properties_line_rasterization_ext],
- required: false,
- },
- line_width_granularity => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-lineWidthGranularity)
- ",
- ty: f32,
- ffi_name: line_width_granularity,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- line_width_range => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-lineWidthRange)
- ",
- ty: [f32; 2],
- ffi_name: line_width_range,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_bound_descriptor_sets => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxBoundDescriptorSets)
- ",
- ty: u32,
- ffi_name: max_bound_descriptor_sets,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_clip_distances => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxClipDistances)
- ",
- ty: u32,
- ffi_name: max_clip_distances,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_color_attachments => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxColorAttachments)
- ",
- ty: u32,
- ffi_name: max_color_attachments,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_combined_clip_and_cull_distances => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxCombinedClipAndCullDistances)
- ",
- ty: u32,
- ffi_name: max_combined_clip_and_cull_distances,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_compute_shared_memory_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxComputeSharedMemorySize)
- ",
- ty: u32,
- ffi_name: max_compute_shared_memory_size,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_compute_work_group_count => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxComputeWorkGroupCount)
- ",
- ty: [u32; 3],
- ffi_name: max_compute_work_group_count,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_compute_work_group_invocations => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxComputeWorkGroupInvocations)
- ",
- ty: u32,
- ffi_name: max_compute_work_group_invocations,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_compute_work_group_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxComputeWorkGroupSize)
- ",
- ty: [u32; 3],
- ffi_name: max_compute_work_group_size,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_compute_workgroup_subgroups => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceSubgroupSizeControlPropertiesEXT.html#limits-maxComputeWorkgroupSubgroups)
- ",
- ty: u32,
- ffi_name: max_compute_workgroup_subgroups,
- ffi_members: [properties_subgroup_size_control_ext],
- required: false,
- },
- max_cull_distances => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxCullDistances)
- ",
- ty: u32,
- ffi_name: max_cull_distances,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_custom_border_color_samplers => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceCustomBorderColorPropertiesEXT.html#limits-maxCustomBorderColorSamplers)
- ",
- ty: u32,
- ffi_name: max_custom_border_color_samplers,
- ffi_members: [properties_custom_border_color_ext],
- required: false,
- },
- max_descriptor_set_acceleration_structures => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceAccelerationStructurePropertiesKHR.html#limits-maxDescriptorSetAccelerationStructures)
- ",
- ty: u32,
- ffi_name: max_descriptor_set_acceleration_structures,
- ffi_members: [properties_acceleration_structure_khr, properties_ray_tracing_nv],
- required: false,
- },
- max_descriptor_set_inline_uniform_blocks => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceInlineUniformBlockPropertiesEXT.html#limits-maxDescriptorSetInlineUniformBlocks)
- ",
- ty: u32,
- ffi_name: max_descriptor_set_inline_uniform_blocks,
- ffi_members: [properties_inline_uniform_block_ext],
- required: false,
- },
- max_descriptor_set_input_attachments => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxDescriptorSetInputAttachments)
- ",
- ty: u32,
- ffi_name: max_descriptor_set_input_attachments,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_descriptor_set_sampled_images => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxDescriptorSetSampledImages)
- ",
- ty: u32,
- ffi_name: max_descriptor_set_sampled_images,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_descriptor_set_samplers => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxDescriptorSetSamplers)
- ",
- ty: u32,
- ffi_name: max_descriptor_set_samplers,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_descriptor_set_storage_buffers => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxDescriptorSetStorageBuffers)
- ",
- ty: u32,
- ffi_name: max_descriptor_set_storage_buffers,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_descriptor_set_storage_buffers_dynamic => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxDescriptorSetStorageBuffersDynamic)
- ",
- ty: u32,
- ffi_name: max_descriptor_set_storage_buffers_dynamic,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_descriptor_set_storage_images => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxDescriptorSetStorageImages)
- ",
- ty: u32,
- ffi_name: max_descriptor_set_storage_images,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_descriptor_set_subsampled_samplers => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentDensityMap2PropertiesEXT.html#limits-maxDescriptorSetSubsampledSamplers)
- ",
- ty: u32,
- ffi_name: max_descriptor_set_subsampled_samplers,
- ffi_members: [properties_fragment_density_map2_ext],
- required: false,
- },
- max_descriptor_set_uniform_buffers => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxDescriptorSetUniformBuffers)
- ",
- ty: u32,
- ffi_name: max_descriptor_set_uniform_buffers,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_descriptor_set_uniform_buffers_dynamic => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxDescriptorSetUniformBuffersDynamic)
- ",
- ty: u32,
- ffi_name: max_descriptor_set_uniform_buffers_dynamic,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_descriptor_set_update_after_bind_acceleration_structures => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceAccelerationStructurePropertiesKHR.html#limits-maxDescriptorSetUpdateAfterBindAccelerationStructures)
- ",
- ty: u32,
- ffi_name: max_descriptor_set_update_after_bind_acceleration_structures,
- ffi_members: [properties_acceleration_structure_khr],
- required: false,
- },
- max_descriptor_set_update_after_bind_inline_uniform_blocks => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceInlineUniformBlockPropertiesEXT.html#limits-maxDescriptorSetUpdateAfterBindInlineUniformBlocks)
- ",
- ty: u32,
- ffi_name: max_descriptor_set_update_after_bind_inline_uniform_blocks,
- ffi_members: [properties_inline_uniform_block_ext],
- required: false,
- },
- max_descriptor_set_update_after_bind_input_attachments => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxDescriptorSetUpdateAfterBindInputAttachments)
- ",
- ty: u32,
- ffi_name: max_descriptor_set_update_after_bind_input_attachments,
- ffi_members: [properties_vulkan12, properties_descriptor_indexing],
- required: false,
- },
- max_descriptor_set_update_after_bind_sampled_images => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxDescriptorSetUpdateAfterBindSampledImages)
- ",
- ty: u32,
- ffi_name: max_descriptor_set_update_after_bind_sampled_images,
- ffi_members: [properties_vulkan12, properties_descriptor_indexing],
- required: false,
- },
- max_descriptor_set_update_after_bind_samplers => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxDescriptorSetUpdateAfterBindSamplers)
- ",
- ty: u32,
- ffi_name: max_descriptor_set_update_after_bind_samplers,
- ffi_members: [properties_vulkan12, properties_descriptor_indexing],
- required: false,
- },
- max_descriptor_set_update_after_bind_storage_buffers => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxDescriptorSetUpdateAfterBindStorageBuffers)
- ",
- ty: u32,
- ffi_name: max_descriptor_set_update_after_bind_storage_buffers,
- ffi_members: [properties_vulkan12, properties_descriptor_indexing],
- required: false,
- },
- max_descriptor_set_update_after_bind_storage_buffers_dynamic => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxDescriptorSetUpdateAfterBindStorageBuffersDynamic)
- ",
- ty: u32,
- ffi_name: max_descriptor_set_update_after_bind_storage_buffers_dynamic,
- ffi_members: [properties_vulkan12, properties_descriptor_indexing],
- required: false,
- },
- max_descriptor_set_update_after_bind_storage_images => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxDescriptorSetUpdateAfterBindStorageImages)
- ",
- ty: u32,
- ffi_name: max_descriptor_set_update_after_bind_storage_images,
- ffi_members: [properties_vulkan12, properties_descriptor_indexing],
- required: false,
- },
- max_descriptor_set_update_after_bind_uniform_buffers => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxDescriptorSetUpdateAfterBindUniformBuffers)
- ",
- ty: u32,
- ffi_name: max_descriptor_set_update_after_bind_uniform_buffers,
- ffi_members: [properties_vulkan12, properties_descriptor_indexing],
- required: false,
- },
- max_descriptor_set_update_after_bind_uniform_buffers_dynamic => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxDescriptorSetUpdateAfterBindUniformBuffersDynamic)
- ",
- ty: u32,
- ffi_name: max_descriptor_set_update_after_bind_uniform_buffers_dynamic,
- ffi_members: [properties_vulkan12, properties_descriptor_indexing],
- required: false,
- },
- max_discard_rectangles => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceDiscardRectanglePropertiesEXT.html#limits-maxDiscardRectangles)
- ",
- ty: u32,
- ffi_name: max_discard_rectangles,
- ffi_members: [properties_discard_rectangle_ext],
- required: false,
- },
- max_draw_indexed_index_value => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxDrawIndexedIndexValue)
- ",
- ty: u32,
- ffi_name: max_draw_indexed_index_value,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_draw_indirect_count => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxDrawIndirectCount)
- ",
- ty: u32,
- ffi_name: max_draw_indirect_count,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_draw_mesh_tasks_count => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesNV.html#limits-maxDrawMeshTasksCount)
- ",
- ty: u32,
- ffi_name: max_draw_mesh_tasks_count,
- ffi_members: [properties_mesh_shader_nv],
- required: false,
- },
- max_extra_primitive_overestimation_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceConservativeRasterizationPropertiesEXT.html#limits-maxExtraPrimitiveOverestimationSize)
- ",
- ty: f32,
- ffi_name: max_extra_primitive_overestimation_size,
- ffi_members: [properties_conservative_rasterization_ext],
- required: false,
- },
- max_fragment_combined_output_resources => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxFragmentCombinedOutputResources)
- ",
- ty: u32,
- ffi_name: max_fragment_combined_output_resources,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_fragment_density_texel_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentDensityMapPropertiesEXT.html#limits-maxFragmentDensityTexelSize)
- ",
- ty: [u32; 2],
- ffi_name: max_fragment_density_texel_size,
- ffi_members: [properties_fragment_density_map_ext],
- required: false,
- },
- max_fragment_dual_src_attachments => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxFragmentDualSrcAttachments)
- ",
- ty: u32,
- ffi_name: max_fragment_dual_src_attachments,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_fragment_input_components => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxFragmentInputComponents)
- ",
- ty: u32,
- ffi_name: max_fragment_input_components,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_fragment_output_attachments => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxFragmentOutputAttachments)
- ",
- ty: u32,
- ffi_name: max_fragment_output_attachments,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_fragment_shading_rate_attachment_texel_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-maxFragmentShadingRateAttachmentTexelSize)
- ",
- ty: [u32; 2],
- ffi_name: max_fragment_shading_rate_attachment_texel_size,
- ffi_members: [properties_fragment_shading_rate_khr],
- required: false,
- },
- max_fragment_shading_rate_attachment_texel_size_aspect_ratio => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-maxFragmentShadingRateAttachmentTexelSizeAspectRatio)
- ",
- ty: u32,
- ffi_name: max_fragment_shading_rate_attachment_texel_size_aspect_ratio,
- ffi_members: [properties_fragment_shading_rate_khr],
- required: false,
- },
- max_fragment_shading_rate_coverage_samples => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-maxFragmentShadingRateCoverageSamples)
- ",
- ty: u32,
- ffi_name: max_fragment_shading_rate_coverage_samples,
- ffi_members: [properties_fragment_shading_rate_khr],
- required: false,
- },
- max_fragment_shading_rate_invocation_count => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentShadingRateEnumsPropertiesNV.html#limits-maxFragmentShadingRateInvocationCount)
- ",
- ty: crate::image::SampleCount,
- ffi_name: max_fragment_shading_rate_invocation_count,
- ffi_members: [properties_fragment_shading_rate_enums_nv],
- required: false,
- },
- max_fragment_shading_rate_rasterization_samples => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-maxFragmentShadingRateRasterizationSamples)
- ",
- ty: crate::image::SampleCount,
- ffi_name: max_fragment_shading_rate_rasterization_samples,
- ffi_members: [properties_fragment_shading_rate_khr],
- required: false,
- },
- max_fragment_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-maxFragmentSize)
- ",
- ty: [u32; 2],
- ffi_name: max_fragment_size,
- ffi_members: [properties_fragment_shading_rate_khr],
- required: false,
- },
- max_fragment_size_aspect_ratio => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-maxFragmentSizeAspectRatio)
- ",
- ty: u32,
- ffi_name: max_fragment_size_aspect_ratio,
- ffi_members: [properties_fragment_shading_rate_khr],
- required: false,
- },
- max_framebuffer_height => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxFramebufferHeight)
- ",
- ty: u32,
- ffi_name: max_framebuffer_height,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_framebuffer_layers => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxFramebufferLayers)
- ",
- ty: u32,
- ffi_name: max_framebuffer_layers,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_framebuffer_width => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxFramebufferWidth)
- ",
- ty: u32,
- ffi_name: max_framebuffer_width,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_geometry_count => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceAccelerationStructurePropertiesKHR.html#limits-maxGeometryCount)
- ",
- ty: u64,
- ffi_name: max_geometry_count,
- ffi_members: [properties_acceleration_structure_khr, properties_ray_tracing_nv],
- required: false,
- },
- max_geometry_input_components => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxGeometryInputComponents)
- ",
- ty: u32,
- ffi_name: max_geometry_input_components,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_geometry_output_components => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxGeometryOutputComponents)
- ",
- ty: u32,
- ffi_name: max_geometry_output_components,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_geometry_output_vertices => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxGeometryOutputVertices)
- ",
- ty: u32,
- ffi_name: max_geometry_output_vertices,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_geometry_shader_invocations => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxGeometryShaderInvocations)
- ",
- ty: u32,
- ffi_name: max_geometry_shader_invocations,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_geometry_total_output_components => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxGeometryTotalOutputComponents)
- ",
- ty: u32,
- ffi_name: max_geometry_total_output_components,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_graphics_shader_group_count => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV.html#limits-maxGraphicsShaderGroupCount)
- ",
- ty: u32,
- ffi_name: max_graphics_shader_group_count,
- ffi_members: [properties_device_generated_commands_nv],
- required: false,
- },
- max_image_array_layers => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxImageArrayLayers)
- ",
- ty: u32,
- ffi_name: max_image_array_layers,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_image_dimension1_d => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxImageDimension1D)
- ",
- ty: u32,
- ffi_name: max_image_dimension1_d,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_image_dimension2_d => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxImageDimension2D)
- ",
- ty: u32,
- ffi_name: max_image_dimension2_d,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_image_dimension3_d => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxImageDimension3D)
- ",
- ty: u32,
- ffi_name: max_image_dimension3_d,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_image_dimension_cube => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxImageDimensionCube)
- ",
- ty: u32,
- ffi_name: max_image_dimension_cube,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_indirect_commands_stream_count => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV.html#limits-maxIndirectCommandsStreamCount)
- ",
- ty: u32,
- ffi_name: max_indirect_commands_stream_count,
- ffi_members: [properties_device_generated_commands_nv],
- required: false,
- },
- max_indirect_commands_stream_stride => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV.html#limits-maxIndirectCommandsStreamStride)
- ",
- ty: u32,
- ffi_name: max_indirect_commands_stream_stride,
- ffi_members: [properties_device_generated_commands_nv],
- required: false,
- },
- max_indirect_commands_token_count => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV.html#limits-maxIndirectCommandsTokenCount)
- ",
- ty: u32,
- ffi_name: max_indirect_commands_token_count,
- ffi_members: [properties_device_generated_commands_nv],
- required: false,
- },
- max_indirect_commands_token_offset => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV.html#limits-maxIndirectCommandsTokenOffset)
- ",
- ty: u32,
- ffi_name: max_indirect_commands_token_offset,
- ffi_members: [properties_device_generated_commands_nv],
- required: false,
- },
- max_indirect_sequence_count => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV.html#limits-maxIndirectSequenceCount)
- ",
- ty: u32,
- ffi_name: max_indirect_sequence_count,
- ffi_members: [properties_device_generated_commands_nv],
- required: false,
- },
- max_inline_uniform_block_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceInlineUniformBlockPropertiesEXT.html#limits-maxInlineUniformBlockSize)
- ",
- ty: u32,
- ffi_name: max_inline_uniform_block_size,
- ffi_members: [properties_inline_uniform_block_ext],
- required: false,
- },
- max_instance_count => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceAccelerationStructurePropertiesKHR.html#limits-maxInstanceCount)
- ",
- ty: u64,
- ffi_name: max_instance_count,
- ffi_members: [properties_acceleration_structure_khr, properties_ray_tracing_nv],
- required: false,
- },
- max_interpolation_offset => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxInterpolationOffset)
- ",
- ty: f32,
- ffi_name: max_interpolation_offset,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_memory_allocation_count => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxMemoryAllocationCount)
- ",
- ty: u32,
- ffi_name: max_memory_allocation_count,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_memory_allocation_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan11Properties.html#limits-maxMemoryAllocationSize)
- ",
- ty: crate::DeviceSize,
- ffi_name: max_memory_allocation_size,
- ffi_members: [properties_vulkan11, properties_maintenance3],
- required: false,
- },
- max_mesh_multiview_view_count => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesNV.html#limits-maxMeshMultiviewViewCount)
- ",
- ty: u32,
- ffi_name: max_mesh_multiview_view_count,
- ffi_members: [properties_mesh_shader_nv],
- required: false,
- },
- max_mesh_output_primitives => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesNV.html#limits-maxMeshOutputPrimitives)
- ",
- ty: u32,
- ffi_name: max_mesh_output_primitives,
- ffi_members: [properties_mesh_shader_nv],
- required: false,
- },
- max_mesh_output_vertices => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesNV.html#limits-maxMeshOutputVertices)
- ",
- ty: u32,
- ffi_name: max_mesh_output_vertices,
- ffi_members: [properties_mesh_shader_nv],
- required: false,
- },
- max_mesh_total_memory_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesNV.html#limits-maxMeshTotalMemorySize)
- ",
- ty: u32,
- ffi_name: max_mesh_total_memory_size,
- ffi_members: [properties_mesh_shader_nv],
- required: false,
- },
- max_mesh_work_group_invocations => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesNV.html#limits-maxMeshWorkGroupInvocations)
- ",
- ty: u32,
- ffi_name: max_mesh_work_group_invocations,
- ffi_members: [properties_mesh_shader_nv],
- required: false,
- },
- max_mesh_work_group_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesNV.html#limits-maxMeshWorkGroupSize)
- ",
- ty: [u32; 3],
- ffi_name: max_mesh_work_group_size,
- ffi_members: [properties_mesh_shader_nv],
- required: false,
- },
- max_multi_draw_count => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceMultiDrawPropertiesEXT.html#limits-maxMultiDrawCount)
- ",
- ty: u32,
- ffi_name: max_multi_draw_count,
- ffi_members: [properties_multi_draw_ext],
- required: false,
- },
- max_multiview_instance_index => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan11Properties.html#limits-maxMultiviewInstanceIndex)
- ",
- ty: u32,
- ffi_name: max_multiview_instance_index,
- ffi_members: [properties_vulkan11, properties_multiview],
- required: false,
- },
- max_multiview_view_count => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan11Properties.html#limits-maxMultiviewViewCount)
- ",
- ty: u32,
- ffi_name: max_multiview_view_count,
- ffi_members: [properties_vulkan11, properties_multiview],
- required: false,
- },
- max_per_set_descriptors => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan11Properties.html#limits-maxPerSetDescriptors)
- ",
- ty: u32,
- ffi_name: max_per_set_descriptors,
- ffi_members: [properties_vulkan11, properties_maintenance3],
- required: false,
- },
- max_per_stage_descriptor_acceleration_structures => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceAccelerationStructurePropertiesKHR.html#limits-maxPerStageDescriptorAccelerationStructures)
- ",
- ty: u32,
- ffi_name: max_per_stage_descriptor_acceleration_structures,
- ffi_members: [properties_acceleration_structure_khr],
- required: false,
- },
- max_per_stage_descriptor_inline_uniform_blocks => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceInlineUniformBlockPropertiesEXT.html#limits-maxPerStageDescriptorInlineUniformBlocks)
- ",
- ty: u32,
- ffi_name: max_per_stage_descriptor_inline_uniform_blocks,
- ffi_members: [properties_inline_uniform_block_ext],
- required: false,
- },
- max_per_stage_descriptor_input_attachments => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxPerStageDescriptorInputAttachments)
- ",
- ty: u32,
- ffi_name: max_per_stage_descriptor_input_attachments,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_per_stage_descriptor_sampled_images => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxPerStageDescriptorSampledImages)
- ",
- ty: u32,
- ffi_name: max_per_stage_descriptor_sampled_images,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_per_stage_descriptor_samplers => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxPerStageDescriptorSamplers)
- ",
- ty: u32,
- ffi_name: max_per_stage_descriptor_samplers,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_per_stage_descriptor_storage_buffers => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxPerStageDescriptorStorageBuffers)
- ",
- ty: u32,
- ffi_name: max_per_stage_descriptor_storage_buffers,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_per_stage_descriptor_storage_images => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxPerStageDescriptorStorageImages)
- ",
- ty: u32,
- ffi_name: max_per_stage_descriptor_storage_images,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_per_stage_descriptor_uniform_buffers => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxPerStageDescriptorUniformBuffers)
- ",
- ty: u32,
- ffi_name: max_per_stage_descriptor_uniform_buffers,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_per_stage_descriptor_update_after_bind_acceleration_structures => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceAccelerationStructurePropertiesKHR.html#limits-maxPerStageDescriptorUpdateAfterBindAccelerationStructures)
- ",
- ty: u32,
- ffi_name: max_per_stage_descriptor_update_after_bind_acceleration_structures,
- ffi_members: [properties_acceleration_structure_khr],
- required: false,
- },
- max_per_stage_descriptor_update_after_bind_inline_uniform_blocks => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceInlineUniformBlockPropertiesEXT.html#limits-maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks)
- ",
- ty: u32,
- ffi_name: max_per_stage_descriptor_update_after_bind_inline_uniform_blocks,
- ffi_members: [properties_inline_uniform_block_ext],
- required: false,
- },
- max_per_stage_descriptor_update_after_bind_input_attachments => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxPerStageDescriptorUpdateAfterBindInputAttachments)
- ",
- ty: u32,
- ffi_name: max_per_stage_descriptor_update_after_bind_input_attachments,
- ffi_members: [properties_vulkan12, properties_descriptor_indexing],
- required: false,
- },
- max_per_stage_descriptor_update_after_bind_sampled_images => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxPerStageDescriptorUpdateAfterBindSampledImages)
- ",
- ty: u32,
- ffi_name: max_per_stage_descriptor_update_after_bind_sampled_images,
- ffi_members: [properties_vulkan12, properties_descriptor_indexing],
- required: false,
- },
- max_per_stage_descriptor_update_after_bind_samplers => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxPerStageDescriptorUpdateAfterBindSamplers)
- ",
- ty: u32,
- ffi_name: max_per_stage_descriptor_update_after_bind_samplers,
- ffi_members: [properties_vulkan12, properties_descriptor_indexing],
- required: false,
- },
- max_per_stage_descriptor_update_after_bind_storage_buffers => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxPerStageDescriptorUpdateAfterBindStorageBuffers)
- ",
- ty: u32,
- ffi_name: max_per_stage_descriptor_update_after_bind_storage_buffers,
- ffi_members: [properties_vulkan12, properties_descriptor_indexing],
- required: false,
- },
- max_per_stage_descriptor_update_after_bind_storage_images => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxPerStageDescriptorUpdateAfterBindStorageImages)
- ",
- ty: u32,
- ffi_name: max_per_stage_descriptor_update_after_bind_storage_images,
- ffi_members: [properties_vulkan12, properties_descriptor_indexing],
- required: false,
- },
- max_per_stage_descriptor_update_after_bind_uniform_buffers => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxPerStageDescriptorUpdateAfterBindUniformBuffers)
- ",
- ty: u32,
- ffi_name: max_per_stage_descriptor_update_after_bind_uniform_buffers,
- ffi_members: [properties_vulkan12, properties_descriptor_indexing],
- required: false,
- },
- max_per_stage_resources => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxPerStageResources)
- ",
- ty: u32,
- ffi_name: max_per_stage_resources,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_per_stage_update_after_bind_resources => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxPerStageUpdateAfterBindResources)
- ",
- ty: u32,
- ffi_name: max_per_stage_update_after_bind_resources,
- ffi_members: [properties_vulkan12, properties_descriptor_indexing],
- required: false,
- },
- max_primitive_count => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceAccelerationStructurePropertiesKHR.html#limits-maxPrimitiveCount)
- ",
- ty: u64,
- ffi_name: max_primitive_count,
- ffi_members: [properties_acceleration_structure_khr],
- required: false,
- },
- max_push_constants_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxPushConstantsSize)
- ",
- ty: u32,
- ffi_name: max_push_constants_size,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_push_descriptors => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDevicePushDescriptorPropertiesKHR.html#limits-maxPushDescriptors)
- ",
- ty: u32,
- ffi_name: max_push_descriptors,
- ffi_members: [properties_push_descriptor_khr],
- required: false,
- },
- max_ray_dispatch_invocation_count => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceRayTracingPipelinePropertiesKHR.html#limits-maxRayDispatchInvocationCount)
- ",
- ty: u32,
- ffi_name: max_ray_dispatch_invocation_count,
- ffi_members: [properties_ray_tracing_pipeline_khr],
- required: false,
- },
- max_ray_hit_attribute_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceRayTracingPipelinePropertiesKHR.html#limits-maxRayHitAttributeSize)
- ",
- ty: u32,
- ffi_name: max_ray_hit_attribute_size,
- ffi_members: [properties_ray_tracing_pipeline_khr],
- required: false,
- },
- max_ray_recursion_depth => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceRayTracingPipelinePropertiesKHR.html#limits-maxRayRecursionDepth)
- ",
- ty: u32,
- ffi_name: max_ray_recursion_depth,
- ffi_members: [properties_ray_tracing_pipeline_khr],
- required: false,
- },
- max_recursion_depth => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceRayTracingPropertiesNV.html#limits-maxRecursionDepth)
- ",
- ty: u32,
- ffi_name: max_recursion_depth,
- ffi_members: [properties_ray_tracing_nv],
- required: false,
- },
- max_sample_location_grid_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceSampleLocationsPropertiesEXT.html#limits-maxSampleLocationGridSize)
- ",
- ty: [u32; 2],
- ffi_name: max_sample_location_grid_size,
- ffi_members: [properties_sample_locations_ext],
- required: false,
- },
- max_sample_mask_words => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxSampleMaskWords)
- ",
- ty: u32,
- ffi_name: max_sample_mask_words,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_sampler_allocation_count => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxSamplerAllocationCount)
- ",
- ty: u32,
- ffi_name: max_sampler_allocation_count,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_sampler_anisotropy => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxSamplerAnisotropy)
- ",
- ty: f32,
- ffi_name: max_sampler_anisotropy,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_sampler_lod_bias => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxSamplerLodBias)
- ",
- ty: f32,
- ffi_name: max_sampler_lod_bias,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_sgpr_allocation => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderCorePropertiesAMD.html#limits-maxSgprAllocation)
- ",
- ty: u32,
- ffi_name: max_sgpr_allocation,
- ffi_members: [properties_shader_core_amd],
- required: false,
- },
- max_shader_group_stride => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceRayTracingPipelinePropertiesKHR.html#limits-maxShaderGroupStride)
- ",
- ty: u32,
- ffi_name: max_shader_group_stride,
- ffi_members: [properties_ray_tracing_pipeline_khr, properties_ray_tracing_nv],
- required: false,
- },
- max_storage_buffer_range => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxStorageBufferRange)
- ",
- ty: u32,
- ffi_name: max_storage_buffer_range,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_subgroup_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceSubgroupSizeControlPropertiesEXT.html#limits-maxSubgroupSize)
- ",
- ty: u32,
- ffi_name: max_subgroup_size,
- ffi_members: [properties_subgroup_size_control_ext],
- required: false,
- },
- max_subpass_shading_workgroup_size_aspect_ratio => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceSubpassShadingPropertiesHUAWEI.html#limits-maxSubpassShadingWorkgroupSizeAspectRatio)
- ",
- ty: u32,
- ffi_name: max_subpass_shading_workgroup_size_aspect_ratio,
- ffi_members: [properties_subpass_shading_huawei],
- required: false,
- },
- max_subsampled_array_layers => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentDensityMap2PropertiesEXT.html#limits-maxSubsampledArrayLayers)
- ",
- ty: u32,
- ffi_name: max_subsampled_array_layers,
- ffi_members: [properties_fragment_density_map2_ext],
- required: false,
- },
- max_task_output_count => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesNV.html#limits-maxTaskOutputCount)
- ",
- ty: u32,
- ffi_name: max_task_output_count,
- ffi_members: [properties_mesh_shader_nv],
- required: false,
- },
- max_task_total_memory_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesNV.html#limits-maxTaskTotalMemorySize)
- ",
- ty: u32,
- ffi_name: max_task_total_memory_size,
- ffi_members: [properties_mesh_shader_nv],
- required: false,
- },
- max_task_work_group_invocations => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesNV.html#limits-maxTaskWorkGroupInvocations)
- ",
- ty: u32,
- ffi_name: max_task_work_group_invocations,
- ffi_members: [properties_mesh_shader_nv],
- required: false,
- },
- max_task_work_group_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesNV.html#limits-maxTaskWorkGroupSize)
- ",
- ty: [u32; 3],
- ffi_name: max_task_work_group_size,
- ffi_members: [properties_mesh_shader_nv],
- required: false,
- },
- max_tessellation_control_per_patch_output_components => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxTessellationControlPerPatchOutputComponents)
- ",
- ty: u32,
- ffi_name: max_tessellation_control_per_patch_output_components,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_tessellation_control_per_vertex_input_components => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxTessellationControlPerVertexInputComponents)
- ",
- ty: u32,
- ffi_name: max_tessellation_control_per_vertex_input_components,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_tessellation_control_per_vertex_output_components => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxTessellationControlPerVertexOutputComponents)
- ",
- ty: u32,
- ffi_name: max_tessellation_control_per_vertex_output_components,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_tessellation_control_total_output_components => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxTessellationControlTotalOutputComponents)
- ",
- ty: u32,
- ffi_name: max_tessellation_control_total_output_components,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_tessellation_evaluation_input_components => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxTessellationEvaluationInputComponents)
- ",
- ty: u32,
- ffi_name: max_tessellation_evaluation_input_components,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_tessellation_evaluation_output_components => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxTessellationEvaluationOutputComponents)
- ",
- ty: u32,
- ffi_name: max_tessellation_evaluation_output_components,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_tessellation_generation_level => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxTessellationGenerationLevel)
- ",
- ty: u32,
- ffi_name: max_tessellation_generation_level,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_tessellation_patch_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxTessellationPatchSize)
- ",
- ty: u32,
- ffi_name: max_tessellation_patch_size,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_texel_buffer_elements => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxTexelBufferElements)
- ",
- ty: u32,
- ffi_name: max_texel_buffer_elements,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_texel_gather_offset => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxTexelGatherOffset)
- ",
- ty: u32,
- ffi_name: max_texel_gather_offset,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_texel_offset => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxTexelOffset)
- ",
- ty: u32,
- ffi_name: max_texel_offset,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_timeline_semaphore_value_difference => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxTimelineSemaphoreValueDifference)
- ",
- ty: u64,
- ffi_name: max_timeline_semaphore_value_difference,
- ffi_members: [properties_vulkan12, properties_timeline_semaphore],
- required: false,
- },
- max_transform_feedback_buffer_data_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceTransformFeedbackPropertiesEXT.html#limits-maxTransformFeedbackBufferDataSize)
- ",
- ty: u32,
- ffi_name: max_transform_feedback_buffer_data_size,
- ffi_members: [properties_transform_feedback_ext],
- required: false,
- },
- max_transform_feedback_buffer_data_stride => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceTransformFeedbackPropertiesEXT.html#limits-maxTransformFeedbackBufferDataStride)
- ",
- ty: u32,
- ffi_name: max_transform_feedback_buffer_data_stride,
- ffi_members: [properties_transform_feedback_ext],
- required: false,
- },
- max_transform_feedback_buffer_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceTransformFeedbackPropertiesEXT.html#limits-maxTransformFeedbackBufferSize)
- ",
- ty: crate::DeviceSize,
- ffi_name: max_transform_feedback_buffer_size,
- ffi_members: [properties_transform_feedback_ext],
- required: false,
- },
- max_transform_feedback_buffers => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceTransformFeedbackPropertiesEXT.html#limits-maxTransformFeedbackBuffers)
- ",
- ty: u32,
- ffi_name: max_transform_feedback_buffers,
- ffi_members: [properties_transform_feedback_ext],
- required: false,
- },
- max_transform_feedback_stream_data_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceTransformFeedbackPropertiesEXT.html#limits-maxTransformFeedbackStreamDataSize)
- ",
- ty: u32,
- ffi_name: max_transform_feedback_stream_data_size,
- ffi_members: [properties_transform_feedback_ext],
- required: false,
- },
- max_transform_feedback_streams => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceTransformFeedbackPropertiesEXT.html#limits-maxTransformFeedbackStreams)
- ",
- ty: u32,
- ffi_name: max_transform_feedback_streams,
- ffi_members: [properties_transform_feedback_ext],
- required: false,
- },
- max_triangle_count => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceRayTracingPropertiesNV.html#limits-maxTriangleCount)
- ",
- ty: u64,
- ffi_name: max_triangle_count,
- ffi_members: [properties_ray_tracing_nv],
- required: false,
- },
- max_uniform_buffer_range => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxUniformBufferRange)
- ",
- ty: u32,
- ffi_name: max_uniform_buffer_range,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_update_after_bind_descriptors_in_all_pools => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxUpdateAfterBindDescriptorsInAllPools)
- ",
- ty: u32,
- ffi_name: max_update_after_bind_descriptors_in_all_pools,
- ffi_members: [properties_vulkan12, properties_descriptor_indexing],
- required: false,
- },
- max_vertex_attrib_divisor => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT.html#limits-maxVertexAttribDivisor)
- ",
- ty: u32,
- ffi_name: max_vertex_attrib_divisor,
- ffi_members: [properties_vertex_attribute_divisor_ext],
- required: false,
- },
- max_vertex_input_attribute_offset => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxVertexInputAttributeOffset)
- ",
- ty: u32,
- ffi_name: max_vertex_input_attribute_offset,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_vertex_input_attributes => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxVertexInputAttributes)
- ",
- ty: u32,
- ffi_name: max_vertex_input_attributes,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_vertex_input_binding_stride => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxVertexInputBindingStride)
- ",
- ty: u32,
- ffi_name: max_vertex_input_binding_stride,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_vertex_input_bindings => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxVertexInputBindings)
- ",
- ty: u32,
- ffi_name: max_vertex_input_bindings,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_vertex_output_components => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxVertexOutputComponents)
- ",
- ty: u32,
- ffi_name: max_vertex_output_components,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_vgpr_allocation => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderCorePropertiesAMD.html#limits-maxVgprAllocation)
- ",
- ty: u32,
- ffi_name: max_vgpr_allocation,
- ffi_members: [properties_shader_core_amd],
- required: false,
- },
- max_viewport_dimensions => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxViewportDimensions)
- ",
- ty: [u32; 2],
- ffi_name: max_viewport_dimensions,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- max_viewports => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxViewports)
- ",
- ty: u32,
- ffi_name: max_viewports,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- mesh_output_per_primitive_granularity => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesNV.html#limits-meshOutputPerPrimitiveGranularity)
- ",
- ty: u32,
- ffi_name: mesh_output_per_primitive_granularity,
- ffi_members: [properties_mesh_shader_nv],
- required: false,
- },
- mesh_output_per_vertex_granularity => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesNV.html#limits-meshOutputPerVertexGranularity)
- ",
- ty: u32,
- ffi_name: mesh_output_per_vertex_granularity,
- ffi_members: [properties_mesh_shader_nv],
- required: false,
- },
- min_acceleration_structure_scratch_offset_alignment => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceAccelerationStructurePropertiesKHR.html#limits-minAccelerationStructureScratchOffsetAlignment)
- ",
- ty: u32,
- ffi_name: min_acceleration_structure_scratch_offset_alignment,
- ffi_members: [properties_acceleration_structure_khr],
- required: false,
- },
- min_fragment_density_texel_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentDensityMapPropertiesEXT.html#limits-minFragmentDensityTexelSize)
- ",
- ty: [u32; 2],
- ffi_name: min_fragment_density_texel_size,
- ffi_members: [properties_fragment_density_map_ext],
- required: false,
- },
- min_fragment_shading_rate_attachment_texel_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-minFragmentShadingRateAttachmentTexelSize)
- ",
- ty: [u32; 2],
- ffi_name: min_fragment_shading_rate_attachment_texel_size,
- ffi_members: [properties_fragment_shading_rate_khr],
- required: false,
- },
- min_imported_host_pointer_alignment => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceExternalMemoryHostPropertiesEXT.html#limits-minImportedHostPointerAlignment)
- ",
- ty: crate::DeviceSize,
- ffi_name: min_imported_host_pointer_alignment,
- ffi_members: [properties_external_memory_host_ext],
- required: false,
- },
- min_indirect_commands_buffer_offset_alignment => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV.html#limits-minIndirectCommandsBufferOffsetAlignment)
- ",
- ty: u32,
- ffi_name: min_indirect_commands_buffer_offset_alignment,
- ffi_members: [properties_device_generated_commands_nv],
- required: false,
- },
- min_interpolation_offset => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-minInterpolationOffset)
- ",
- ty: f32,
- ffi_name: min_interpolation_offset,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- min_memory_map_alignment => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-minMemoryMapAlignment)
- ",
- ty: usize,
- ffi_name: min_memory_map_alignment,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- min_sequences_count_buffer_offset_alignment => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV.html#limits-minSequencesCountBufferOffsetAlignment)
- ",
- ty: u32,
- ffi_name: min_sequences_count_buffer_offset_alignment,
- ffi_members: [properties_device_generated_commands_nv],
- required: false,
- },
- min_sequences_index_buffer_offset_alignment => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV.html#limits-minSequencesIndexBufferOffsetAlignment)
- ",
- ty: u32,
- ffi_name: min_sequences_index_buffer_offset_alignment,
- ffi_members: [properties_device_generated_commands_nv],
- required: false,
- },
- min_sgpr_allocation => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderCorePropertiesAMD.html#limits-minSgprAllocation)
- ",
- ty: u32,
- ffi_name: min_sgpr_allocation,
- ffi_members: [properties_shader_core_amd],
- required: false,
- },
- min_storage_buffer_offset_alignment => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-minStorageBufferOffsetAlignment)
- ",
- ty: crate::DeviceSize,
- ffi_name: min_storage_buffer_offset_alignment,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- min_subgroup_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceSubgroupSizeControlPropertiesEXT.html#limits-minSubgroupSize)
- ",
- ty: u32,
- ffi_name: min_subgroup_size,
- ffi_members: [properties_subgroup_size_control_ext],
- required: false,
- },
- min_texel_buffer_offset_alignment => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-minTexelBufferOffsetAlignment)
- ",
- ty: crate::DeviceSize,
- ffi_name: min_texel_buffer_offset_alignment,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- min_texel_gather_offset => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-minTexelGatherOffset)
- ",
- ty: i32,
- ffi_name: min_texel_gather_offset,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- min_texel_offset => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-minTexelOffset)
- ",
- ty: i32,
- ffi_name: min_texel_offset,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- min_uniform_buffer_offset_alignment => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-minUniformBufferOffsetAlignment)
- ",
- ty: crate::DeviceSize,
- ffi_name: min_uniform_buffer_offset_alignment,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- min_vertex_input_binding_stride_alignment => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDevicePortabilitySubsetPropertiesKHR.html#limits-minVertexInputBindingStrideAlignment)
- ",
- ty: u32,
- ffi_name: min_vertex_input_binding_stride_alignment,
- ffi_members: [properties_portability_subset_khr],
- required: false,
- },
- min_vgpr_allocation => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderCorePropertiesAMD.html#limits-minVgprAllocation)
- ",
- ty: u32,
- ffi_name: min_vgpr_allocation,
- ffi_members: [properties_shader_core_amd],
- required: false,
- },
- mipmap_precision_bits => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-mipmapPrecisionBits)
- ",
- ty: u32,
- ffi_name: mipmap_precision_bits,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- non_coherent_atom_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-nonCoherentAtomSize)
- ",
- ty: crate::DeviceSize,
- ffi_name: non_coherent_atom_size,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- optimal_buffer_copy_offset_alignment => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-optimalBufferCopyOffsetAlignment)
- ",
- ty: crate::DeviceSize,
- ffi_name: optimal_buffer_copy_offset_alignment,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- optimal_buffer_copy_row_pitch_alignment => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-optimalBufferCopyRowPitchAlignment)
- ",
- ty: crate::DeviceSize,
- ffi_name: optimal_buffer_copy_row_pitch_alignment,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- pci_bus => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDevicePCIBusInfoPropertiesEXT.html#limits-pciBus)
- ",
- ty: u32,
- ffi_name: pci_bus,
- ffi_members: [properties_pci_bus_info_ext],
- required: false,
- },
- pci_device => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDevicePCIBusInfoPropertiesEXT.html#limits-pciDevice)
- ",
- ty: u32,
- ffi_name: pci_device,
- ffi_members: [properties_pci_bus_info_ext],
- required: false,
- },
- pci_domain => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDevicePCIBusInfoPropertiesEXT.html#limits-pciDomain)
- ",
- ty: u32,
- ffi_name: pci_domain,
- ffi_members: [properties_pci_bus_info_ext],
- required: false,
- },
- pci_function => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDevicePCIBusInfoPropertiesEXT.html#limits-pciFunction)
- ",
- ty: u32,
- ffi_name: pci_function,
- ffi_members: [properties_pci_bus_info_ext],
- required: false,
- },
- per_view_position_all_components => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX.html#limits-perViewPositionAllComponents)
- ",
- ty: bool,
- ffi_name: per_view_position_all_components,
- ffi_members: [properties_multiview_per_view_attributes_nvx],
- required: false,
- },
- pipeline_cache_uuid => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceProperties.html#limits-pipelineCacheUUID)
- ",
- ty: [u8; 16],
- ffi_name: pipeline_cache_uuid,
- ffi_members: [properties_vulkan10.properties],
- required: true,
- },
- point_clipping_behavior => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan11Properties.html#limits-pointClippingBehavior)
- ",
- ty: crate::device::physical::PointClippingBehavior,
- ffi_name: point_clipping_behavior,
- ffi_members: [properties_vulkan11, properties_point_clipping],
- required: false,
- },
- point_size_granularity => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-pointSizeGranularity)
- ",
- ty: f32,
- ffi_name: point_size_granularity,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- point_size_range => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-pointSizeRange)
- ",
- ty: [f32; 2],
- ffi_name: point_size_range,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- primary_major => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceDrmPropertiesEXT.html#limits-primaryMajor)
- ",
- ty: i64,
- ffi_name: primary_major,
- ffi_members: [properties_drm_ext],
- required: false,
- },
- primary_minor => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceDrmPropertiesEXT.html#limits-primaryMinor)
- ",
- ty: i64,
- ffi_name: primary_minor,
- ffi_members: [properties_drm_ext],
- required: false,
- },
- primitive_fragment_shading_rate_with_multiple_viewports => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-primitiveFragmentShadingRateWithMultipleViewports)
- ",
- ty: bool,
- ffi_name: primitive_fragment_shading_rate_with_multiple_viewports,
- ffi_members: [properties_fragment_shading_rate_khr],
- required: false,
- },
- primitive_overestimation_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceConservativeRasterizationPropertiesEXT.html#limits-primitiveOverestimationSize)
- ",
- ty: f32,
- ffi_name: primitive_overestimation_size,
- ffi_members: [properties_conservative_rasterization_ext],
- required: false,
- },
- primitive_underestimation => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceConservativeRasterizationPropertiesEXT.html#limits-primitiveUnderestimation)
- ",
- ty: bool,
- ffi_name: primitive_underestimation,
- ffi_members: [properties_conservative_rasterization_ext],
- required: false,
- },
- protected_no_fault => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan11Properties.html#limits-protectedNoFault)
- ",
- ty: bool,
- ffi_name: protected_no_fault,
- ffi_members: [properties_vulkan11, properties_protected_memory],
- required: false,
- },
- provoking_vertex_mode_per_pipeline => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceProvokingVertexPropertiesEXT.html#limits-provokingVertexModePerPipeline)
- ",
- ty: bool,
- ffi_name: provoking_vertex_mode_per_pipeline,
- ffi_members: [properties_provoking_vertex_ext],
- required: false,
- },
- quad_divergent_implicit_lod => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-quadDivergentImplicitLod)
- ",
- ty: bool,
- ffi_name: quad_divergent_implicit_lod,
- ffi_members: [properties_vulkan12, properties_descriptor_indexing],
- required: false,
- },
- quad_operations_in_all_stages => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceSubgroupProperties.html#limits-quadOperationsInAllStages)
- ",
- ty: bool,
- ffi_name: quad_operations_in_all_stages,
- ffi_members: [properties_subgroup],
- required: false,
- },
- render_major => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceDrmPropertiesEXT.html#limits-renderMajor)
- ",
- ty: i64,
- ffi_name: render_major,
- ffi_members: [properties_drm_ext],
- required: false,
- },
- render_minor => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceDrmPropertiesEXT.html#limits-renderMinor)
- ",
- ty: i64,
- ffi_name: render_minor,
- ffi_members: [properties_drm_ext],
- required: false,
- },
- required_subgroup_size_stages => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceSubgroupSizeControlPropertiesEXT.html#limits-requiredSubgroupSizeStages)
- ",
- ty: crate::pipeline::shader::ShaderStages,
- ffi_name: required_subgroup_size_stages,
- ffi_members: [properties_subgroup_size_control_ext],
- required: false,
- },
- residency_aligned_mip_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceSparseProperties.html#limits-residencyAlignedMipSize)
- ",
- ty: bool,
- ffi_name: residency_aligned_mip_size,
- ffi_members: [properties_vulkan10.properties.sparse_properties],
- required: true,
- },
- residency_non_resident_strict => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceSparseProperties.html#limits-residencyNonResidentStrict)
- ",
- ty: bool,
- ffi_name: residency_non_resident_strict,
- ffi_members: [properties_vulkan10.properties.sparse_properties],
- required: true,
- },
- residency_standard2_d_block_shape => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceSparseProperties.html#limits-residencyStandard2DBlockShape)
- ",
- ty: bool,
- ffi_name: residency_standard2_d_block_shape,
- ffi_members: [properties_vulkan10.properties.sparse_properties],
- required: true,
- },
- residency_standard2_d_multisample_block_shape => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceSparseProperties.html#limits-residencyStandard2DMultisampleBlockShape)
- ",
- ty: bool,
- ffi_name: residency_standard2_d_multisample_block_shape,
- ffi_members: [properties_vulkan10.properties.sparse_properties],
- required: true,
- },
- residency_standard3_d_block_shape => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceSparseProperties.html#limits-residencyStandard3DBlockShape)
- ",
- ty: bool,
- ffi_name: residency_standard3_d_block_shape,
- ffi_members: [properties_vulkan10.properties.sparse_properties],
- required: true,
- },
- robust_buffer_access_update_after_bind => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-robustBufferAccessUpdateAfterBind)
- ",
- ty: bool,
- ffi_name: robust_buffer_access_update_after_bind,
- ffi_members: [properties_vulkan12, properties_descriptor_indexing],
- required: false,
- },
- robust_storage_buffer_access_size_alignment => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceRobustness2PropertiesEXT.html#limits-robustStorageBufferAccessSizeAlignment)
- ",
- ty: crate::DeviceSize,
- ffi_name: robust_storage_buffer_access_size_alignment,
- ffi_members: [properties_robustness2_ext],
- required: false,
- },
- robust_uniform_buffer_access_size_alignment => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceRobustness2PropertiesEXT.html#limits-robustUniformBufferAccessSizeAlignment)
- ",
- ty: crate::DeviceSize,
- ffi_name: robust_uniform_buffer_access_size_alignment,
- ffi_members: [properties_robustness2_ext],
- required: false,
- },
- rounding_mode_independence => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-roundingModeIndependence)
- ",
- ty: crate::device::physical::ShaderFloatControlsIndependence,
- ffi_name: rounding_mode_independence,
- ffi_members: [properties_vulkan12, properties_float_controls],
- required: false,
- },
- sample_location_coordinate_range => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceSampleLocationsPropertiesEXT.html#limits-sampleLocationCoordinateRange)
- ",
- ty: [f32; 2],
- ffi_name: sample_location_coordinate_range,
- ffi_members: [properties_sample_locations_ext],
- required: false,
- },
- sample_location_sample_counts => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceSampleLocationsPropertiesEXT.html#limits-sampleLocationSampleCounts)
- ",
- ty: crate::image::SampleCounts,
- ffi_name: sample_location_sample_counts,
- ffi_members: [properties_sample_locations_ext],
- required: false,
- },
- sample_location_sub_pixel_bits => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceSampleLocationsPropertiesEXT.html#limits-sampleLocationSubPixelBits)
- ",
- ty: u32,
- ffi_name: sample_location_sub_pixel_bits,
- ffi_members: [properties_sample_locations_ext],
- required: false,
- },
- sampled_image_color_sample_counts => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-sampledImageColorSampleCounts)
- ",
- ty: crate::image::SampleCounts,
- ffi_name: sampled_image_color_sample_counts,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- sampled_image_depth_sample_counts => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-sampledImageDepthSampleCounts)
- ",
- ty: crate::image::SampleCounts,
- ffi_name: sampled_image_depth_sample_counts,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- sampled_image_integer_sample_counts => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-sampledImageIntegerSampleCounts)
- ",
- ty: crate::image::SampleCounts,
- ffi_name: sampled_image_integer_sample_counts,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- sampled_image_stencil_sample_counts => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-sampledImageStencilSampleCounts)
- ",
- ty: crate::image::SampleCounts,
- ffi_name: sampled_image_stencil_sample_counts,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- sgpr_allocation_granularity => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderCorePropertiesAMD.html#limits-sgprAllocationGranularity)
- ",
- ty: u32,
- ffi_name: sgpr_allocation_granularity,
- ffi_members: [properties_shader_core_amd],
- required: false,
- },
- sgprs_per_simd => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderCorePropertiesAMD.html#limits-sgprsPerSimd)
- ",
- ty: u32,
- ffi_name: sgprs_per_simd,
- ffi_members: [properties_shader_core_amd],
- required: false,
- },
- shader_arrays_per_engine_count => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderCorePropertiesAMD.html#limits-shaderArraysPerEngineCount)
- ",
- ty: u32,
- ffi_name: shader_arrays_per_engine_count,
- ffi_members: [properties_shader_core_amd],
- required: false,
- },
- shader_core_features => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderCoreProperties2AMD.html#limits-shaderCoreFeatures)
- ",
- ty: crate::device::physical::ShaderCoreProperties,
- ffi_name: shader_core_features,
- ffi_members: [properties_shader_core2_amd],
- required: false,
- },
- shader_denorm_flush_to_zero_float16 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderDenormFlushToZeroFloat16)
- ",
- ty: bool,
- ffi_name: shader_denorm_flush_to_zero_float16,
- ffi_members: [properties_vulkan12, properties_float_controls],
- required: false,
- },
- shader_denorm_flush_to_zero_float32 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderDenormFlushToZeroFloat32)
- ",
- ty: bool,
- ffi_name: shader_denorm_flush_to_zero_float32,
- ffi_members: [properties_vulkan12, properties_float_controls],
- required: false,
- },
- shader_denorm_flush_to_zero_float64 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderDenormFlushToZeroFloat64)
- ",
- ty: bool,
- ffi_name: shader_denorm_flush_to_zero_float64,
- ffi_members: [properties_vulkan12, properties_float_controls],
- required: false,
- },
- shader_denorm_preserve_float16 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderDenormPreserveFloat16)
- ",
- ty: bool,
- ffi_name: shader_denorm_preserve_float16,
- ffi_members: [properties_vulkan12, properties_float_controls],
- required: false,
- },
- shader_denorm_preserve_float32 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderDenormPreserveFloat32)
- ",
- ty: bool,
- ffi_name: shader_denorm_preserve_float32,
- ffi_members: [properties_vulkan12, properties_float_controls],
- required: false,
- },
- shader_denorm_preserve_float64 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderDenormPreserveFloat64)
- ",
- ty: bool,
- ffi_name: shader_denorm_preserve_float64,
- ffi_members: [properties_vulkan12, properties_float_controls],
- required: false,
- },
- shader_engine_count => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderCorePropertiesAMD.html#limits-shaderEngineCount)
- ",
- ty: u32,
- ffi_name: shader_engine_count,
- ffi_members: [properties_shader_core_amd],
- required: false,
- },
- shader_group_base_alignment => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceRayTracingPipelinePropertiesKHR.html#limits-shaderGroupBaseAlignment)
- ",
- ty: u32,
- ffi_name: shader_group_base_alignment,
- ffi_members: [properties_ray_tracing_pipeline_khr, properties_ray_tracing_nv],
- required: false,
- },
- shader_group_handle_alignment => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceRayTracingPipelinePropertiesKHR.html#limits-shaderGroupHandleAlignment)
- ",
- ty: u32,
- ffi_name: shader_group_handle_alignment,
- ffi_members: [properties_ray_tracing_pipeline_khr],
- required: false,
- },
- shader_group_handle_capture_replay_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceRayTracingPipelinePropertiesKHR.html#limits-shaderGroupHandleCaptureReplaySize)
- ",
- ty: u32,
- ffi_name: shader_group_handle_capture_replay_size,
- ffi_members: [properties_ray_tracing_pipeline_khr],
- required: false,
- },
- shader_group_handle_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceRayTracingPipelinePropertiesKHR.html#limits-shaderGroupHandleSize)
- ",
- ty: u32,
- ffi_name: shader_group_handle_size,
- ffi_members: [properties_ray_tracing_pipeline_khr, properties_ray_tracing_nv],
- required: false,
- },
- shader_input_attachment_array_non_uniform_indexing_native => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderInputAttachmentArrayNonUniformIndexingNative)
- ",
- ty: bool,
- ffi_name: shader_input_attachment_array_non_uniform_indexing_native,
- ffi_members: [properties_vulkan12, properties_descriptor_indexing],
- required: false,
- },
- shader_rounding_mode_rte_float16 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderRoundingModeRTEFloat16)
- ",
- ty: bool,
- ffi_name: shader_rounding_mode_rte_float16,
- ffi_members: [properties_vulkan12, properties_float_controls],
- required: false,
- },
- shader_rounding_mode_rte_float32 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderRoundingModeRTEFloat32)
- ",
- ty: bool,
- ffi_name: shader_rounding_mode_rte_float32,
- ffi_members: [properties_vulkan12, properties_float_controls],
- required: false,
- },
- shader_rounding_mode_rte_float64 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderRoundingModeRTEFloat64)
- ",
- ty: bool,
- ffi_name: shader_rounding_mode_rte_float64,
- ffi_members: [properties_vulkan12, properties_float_controls],
- required: false,
- },
- shader_rounding_mode_rtz_float16 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderRoundingModeRTZFloat16)
- ",
- ty: bool,
- ffi_name: shader_rounding_mode_rtz_float16,
- ffi_members: [properties_vulkan12, properties_float_controls],
- required: false,
- },
- shader_rounding_mode_rtz_float32 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderRoundingModeRTZFloat32)
- ",
- ty: bool,
- ffi_name: shader_rounding_mode_rtz_float32,
- ffi_members: [properties_vulkan12, properties_float_controls],
- required: false,
- },
- shader_rounding_mode_rtz_float64 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderRoundingModeRTZFloat64)
- ",
- ty: bool,
- ffi_name: shader_rounding_mode_rtz_float64,
- ffi_members: [properties_vulkan12, properties_float_controls],
- required: false,
- },
- shader_sampled_image_array_non_uniform_indexing_native => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderSampledImageArrayNonUniformIndexingNative)
- ",
- ty: bool,
- ffi_name: shader_sampled_image_array_non_uniform_indexing_native,
- ffi_members: [properties_vulkan12, properties_descriptor_indexing],
- required: false,
- },
- shader_signed_zero_inf_nan_preserve_float16 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderSignedZeroInfNanPreserveFloat16)
- ",
- ty: bool,
- ffi_name: shader_signed_zero_inf_nan_preserve_float16,
- ffi_members: [properties_vulkan12, properties_float_controls],
- required: false,
- },
- shader_signed_zero_inf_nan_preserve_float32 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderSignedZeroInfNanPreserveFloat32)
- ",
- ty: bool,
- ffi_name: shader_signed_zero_inf_nan_preserve_float32,
- ffi_members: [properties_vulkan12, properties_float_controls],
- required: false,
- },
- shader_signed_zero_inf_nan_preserve_float64 => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderSignedZeroInfNanPreserveFloat64)
- ",
- ty: bool,
- ffi_name: shader_signed_zero_inf_nan_preserve_float64,
- ffi_members: [properties_vulkan12, properties_float_controls],
- required: false,
- },
- shader_sm_count => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderSMBuiltinsPropertiesNV.html#limits-shaderSMCount)
- ",
- ty: u32,
- ffi_name: shader_sm_count,
- ffi_members: [properties_shader_sm_builtins_nv],
- required: false,
- },
- shader_storage_buffer_array_non_uniform_indexing_native => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderStorageBufferArrayNonUniformIndexingNative)
- ",
- ty: bool,
- ffi_name: shader_storage_buffer_array_non_uniform_indexing_native,
- ffi_members: [properties_vulkan12, properties_descriptor_indexing],
- required: false,
- },
- shader_storage_image_array_non_uniform_indexing_native => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderStorageImageArrayNonUniformIndexingNative)
- ",
- ty: bool,
- ffi_name: shader_storage_image_array_non_uniform_indexing_native,
- ffi_members: [properties_vulkan12, properties_descriptor_indexing],
- required: false,
- },
- shader_uniform_buffer_array_non_uniform_indexing_native => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderUniformBufferArrayNonUniformIndexingNative)
- ",
- ty: bool,
- ffi_name: shader_uniform_buffer_array_non_uniform_indexing_native,
- ffi_members: [properties_vulkan12, properties_descriptor_indexing],
- required: false,
- },
- shader_warps_per_sm => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderSMBuiltinsPropertiesNV.html#limits-shaderWarpsPerSM)
- ",
- ty: u32,
- ffi_name: shader_warps_per_sm,
- ffi_members: [properties_shader_sm_builtins_nv],
- required: false,
- },
- shading_rate_max_coarse_samples => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShadingRateImagePropertiesNV.html#limits-shadingRateMaxCoarseSamples)
- ",
- ty: u32,
- ffi_name: shading_rate_max_coarse_samples,
- ffi_members: [properties_shading_rate_image_nv],
- required: false,
- },
- shading_rate_palette_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShadingRateImagePropertiesNV.html#limits-shadingRatePaletteSize)
- ",
- ty: u32,
- ffi_name: shading_rate_palette_size,
- ffi_members: [properties_shading_rate_image_nv],
- required: false,
- },
- shading_rate_texel_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShadingRateImagePropertiesNV.html#limits-shadingRateTexelSize)
- ",
- ty: [u32; 2],
- ffi_name: shading_rate_texel_size,
- ffi_members: [properties_shading_rate_image_nv],
- required: false,
- },
- simd_per_compute_unit => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderCorePropertiesAMD.html#limits-simdPerComputeUnit)
- ",
- ty: u32,
- ffi_name: simd_per_compute_unit,
- ffi_members: [properties_shader_core_amd],
- required: false,
- },
- sparse_address_space_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-sparseAddressSpaceSize)
- ",
- ty: crate::DeviceSize,
- ffi_name: sparse_address_space_size,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- standard_sample_locations => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-standardSampleLocations)
- ",
- ty: bool,
- ffi_name: standard_sample_locations,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- storage_image_sample_counts => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-storageImageSampleCounts)
- ",
- ty: crate::image::SampleCounts,
- ffi_name: storage_image_sample_counts,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- storage_texel_buffer_offset_alignment_bytes => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT.html#limits-storageTexelBufferOffsetAlignmentBytes)
- ",
- ty: crate::DeviceSize,
- ffi_name: storage_texel_buffer_offset_alignment_bytes,
- ffi_members: [properties_texel_buffer_alignment_ext],
- required: false,
- },
- storage_texel_buffer_offset_single_texel_alignment => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT.html#limits-storageTexelBufferOffsetSingleTexelAlignment)
- ",
- ty: bool,
- ffi_name: storage_texel_buffer_offset_single_texel_alignment,
- ffi_members: [properties_texel_buffer_alignment_ext],
- required: false,
- },
- strict_lines => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-strictLines)
- ",
- ty: bool,
- ffi_name: strict_lines,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- sub_pixel_interpolation_offset_bits => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-subPixelInterpolationOffsetBits)
- ",
- ty: u32,
- ffi_name: sub_pixel_interpolation_offset_bits,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- sub_pixel_precision_bits => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-subPixelPrecisionBits)
- ",
- ty: u32,
- ffi_name: sub_pixel_precision_bits,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- sub_texel_precision_bits => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-subTexelPrecisionBits)
- ",
- ty: u32,
- ffi_name: sub_texel_precision_bits,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- subgroup_quad_operations_in_all_stages => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan11Properties.html#limits-subgroupQuadOperationsInAllStages)
- ",
- ty: bool,
- ffi_name: subgroup_quad_operations_in_all_stages,
- ffi_members: [properties_vulkan11],
- required: false,
- },
- subgroup_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan11Properties.html#limits-subgroupSize)
- ",
- ty: u32,
- ffi_name: subgroup_size,
- ffi_members: [properties_vulkan11, properties_subgroup],
- required: false,
- },
- subgroup_supported_operations => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan11Properties.html#limits-subgroupSupportedOperations)
- ",
- ty: crate::device::physical::SubgroupFeatures,
- ffi_name: subgroup_supported_operations,
- ffi_members: [properties_vulkan11],
- required: false,
- },
- subgroup_supported_stages => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan11Properties.html#limits-subgroupSupportedStages)
- ",
- ty: crate::pipeline::shader::ShaderStages,
- ffi_name: subgroup_supported_stages,
- ffi_members: [properties_vulkan11],
- required: false,
- },
- subsampled_coarse_reconstruction_early_access => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentDensityMap2PropertiesEXT.html#limits-subsampledCoarseReconstructionEarlyAccess)
- ",
- ty: bool,
- ffi_name: subsampled_coarse_reconstruction_early_access,
- ffi_members: [properties_fragment_density_map2_ext],
- required: false,
- },
- subsampled_loads => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceFragmentDensityMap2PropertiesEXT.html#limits-subsampledLoads)
- ",
- ty: bool,
- ffi_name: subsampled_loads,
- ffi_members: [properties_fragment_density_map2_ext],
- required: false,
- },
- supported_depth_resolve_modes => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-supportedDepthResolveModes)
- ",
- ty: crate::render_pass::ResolveModes,
- ffi_name: supported_depth_resolve_modes,
- ffi_members: [properties_vulkan12, properties_depth_stencil_resolve],
- required: false,
- },
- supported_operations => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceSubgroupProperties.html#limits-supportedOperations)
- ",
- ty: crate::device::physical::SubgroupFeatures,
- ffi_name: supported_operations,
- ffi_members: [properties_subgroup],
- required: false,
- },
- supported_stages => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceSubgroupProperties.html#limits-supportedStages)
- ",
- ty: crate::pipeline::shader::ShaderStages,
- ffi_name: supported_stages,
- ffi_members: [properties_subgroup],
- required: false,
- },
- supported_stencil_resolve_modes => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-supportedStencilResolveModes)
- ",
- ty: crate::render_pass::ResolveModes,
- ffi_name: supported_stencil_resolve_modes,
- ffi_members: [properties_vulkan12, properties_depth_stencil_resolve],
- required: false,
- },
- timestamp_compute_and_graphics => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-timestampComputeAndGraphics)
- ",
- ty: bool,
- ffi_name: timestamp_compute_and_graphics,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- timestamp_period => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-timestampPeriod)
- ",
- ty: f32,
- ffi_name: timestamp_period,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- transform_feedback_draw => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceTransformFeedbackPropertiesEXT.html#limits-transformFeedbackDraw)
- ",
- ty: bool,
- ffi_name: transform_feedback_draw,
- ffi_members: [properties_transform_feedback_ext],
- required: false,
- },
- transform_feedback_preserves_triangle_fan_provoking_vertex => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceProvokingVertexPropertiesEXT.html#limits-transformFeedbackPreservesTriangleFanProvokingVertex)
- ",
- ty: bool,
- ffi_name: transform_feedback_preserves_triangle_fan_provoking_vertex,
- ffi_members: [properties_provoking_vertex_ext],
- required: false,
- },
- transform_feedback_queries => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceTransformFeedbackPropertiesEXT.html#limits-transformFeedbackQueries)
- ",
- ty: bool,
- ffi_name: transform_feedback_queries,
- ffi_members: [properties_transform_feedback_ext],
- required: false,
- },
- transform_feedback_rasterization_stream_select => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceTransformFeedbackPropertiesEXT.html#limits-transformFeedbackRasterizationStreamSelect)
- ",
- ty: bool,
- ffi_name: transform_feedback_rasterization_stream_select,
- ffi_members: [properties_transform_feedback_ext],
- required: false,
- },
- transform_feedback_streams_lines_triangles => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceTransformFeedbackPropertiesEXT.html#limits-transformFeedbackStreamsLinesTriangles)
- ",
- ty: bool,
- ffi_name: transform_feedback_streams_lines_triangles,
- ffi_members: [properties_transform_feedback_ext],
- required: false,
- },
- uniform_texel_buffer_offset_alignment_bytes => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT.html#limits-uniformTexelBufferOffsetAlignmentBytes)
- ",
- ty: crate::DeviceSize,
- ffi_name: uniform_texel_buffer_offset_alignment_bytes,
- ffi_members: [properties_texel_buffer_alignment_ext],
- required: false,
- },
- uniform_texel_buffer_offset_single_texel_alignment => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT.html#limits-uniformTexelBufferOffsetSingleTexelAlignment)
- ",
- ty: bool,
- ffi_name: uniform_texel_buffer_offset_single_texel_alignment,
- ffi_members: [properties_texel_buffer_alignment_ext],
- required: false,
- },
- variable_sample_locations => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceSampleLocationsPropertiesEXT.html#limits-variableSampleLocations)
- ",
- ty: bool,
- ffi_name: variable_sample_locations,
- ffi_members: [properties_sample_locations_ext],
- required: false,
- },
- vendor_id => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceProperties.html#limits-vendorID)
- ",
- ty: u32,
- ffi_name: vendor_id,
- ffi_members: [properties_vulkan10.properties],
- required: true,
- },
- vgpr_allocation_granularity => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderCorePropertiesAMD.html#limits-vgprAllocationGranularity)
- ",
- ty: u32,
- ffi_name: vgpr_allocation_granularity,
- ffi_members: [properties_shader_core_amd],
- required: false,
- },
- vgprs_per_simd => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderCorePropertiesAMD.html#limits-vgprsPerSimd)
- ",
- ty: u32,
- ffi_name: vgprs_per_simd,
- ffi_members: [properties_shader_core_amd],
- required: false,
- },
- viewport_bounds_range => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-viewportBoundsRange)
- ",
- ty: [f32; 2],
- ffi_name: viewport_bounds_range,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- viewport_sub_pixel_bits => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceLimits.html#limits-viewportSubPixelBits)
- ",
- ty: u32,
- ffi_name: viewport_sub_pixel_bits,
- ffi_members: [properties_vulkan10.properties.limits],
- required: true,
- },
- wavefront_size => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderCorePropertiesAMD.html#limits-wavefrontSize)
- ",
- ty: u32,
- ffi_name: wavefront_size,
- ffi_members: [properties_shader_core_amd],
- required: false,
- },
- wavefronts_per_simd => {
- doc: "
- - [Vulkan documentation](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkPhysicalDeviceShaderCorePropertiesAMD.html#limits-wavefrontsPerSimd)
- ",
- ty: u32,
- ffi_name: wavefronts_per_simd,
- ffi_members: [properties_shader_core_amd],
- required: false,
- },
-}
-
-crate::device::properties::properties_ffi! {
- api_version,
- device_extensions,
- instance_extensions,
- properties_vulkan11 => {
- ty: PhysicalDeviceVulkan11Properties,
- provided_by: [api_version >= crate::Version::V1_2],
- conflicts: [],
- },
- properties_vulkan12 => {
- ty: PhysicalDeviceVulkan12Properties,
- provided_by: [api_version >= crate::Version::V1_2],
- conflicts: [],
- },
- properties_id => {
- ty: PhysicalDeviceIDProperties,
- provided_by: [api_version >= crate::Version::V1_1, instance_extensions.khr_external_fence_capabilities, instance_extensions.khr_external_memory_capabilities, instance_extensions.khr_external_semaphore_capabilities],
- conflicts: [properties_vulkan11],
- },
- properties_maintenance3 => {
- ty: PhysicalDeviceMaintenance3Properties,
- provided_by: [api_version >= crate::Version::V1_1, device_extensions.khr_maintenance3],
- conflicts: [properties_vulkan11],
- },
- properties_multiview => {
- ty: PhysicalDeviceMultiviewProperties,
- provided_by: [api_version >= crate::Version::V1_1, device_extensions.khr_multiview],
- conflicts: [properties_vulkan11],
- },
- properties_point_clipping => {
- ty: PhysicalDevicePointClippingProperties,
- provided_by: [api_version >= crate::Version::V1_1, device_extensions.khr_maintenance2],
- conflicts: [properties_vulkan11],
- },
- properties_protected_memory => {
- ty: PhysicalDeviceProtectedMemoryProperties,
- provided_by: [api_version >= crate::Version::V1_1],
- conflicts: [properties_vulkan11],
- },
- properties_subgroup => {
- ty: PhysicalDeviceSubgroupProperties,
- provided_by: [api_version >= crate::Version::V1_1],
- conflicts: [properties_vulkan11],
- },
- properties_depth_stencil_resolve => {
- ty: PhysicalDeviceDepthStencilResolveProperties,
- provided_by: [api_version >= crate::Version::V1_2, device_extensions.khr_depth_stencil_resolve],
- conflicts: [properties_vulkan12],
- },
- properties_descriptor_indexing => {
- ty: PhysicalDeviceDescriptorIndexingProperties,
- provided_by: [api_version >= crate::Version::V1_2, device_extensions.ext_descriptor_indexing],
- conflicts: [properties_vulkan12],
- },
- properties_driver => {
- ty: PhysicalDeviceDriverProperties,
- provided_by: [api_version >= crate::Version::V1_2, device_extensions.khr_driver_properties],
- conflicts: [properties_vulkan12],
- },
- properties_float_controls => {
- ty: PhysicalDeviceFloatControlsProperties,
- provided_by: [api_version >= crate::Version::V1_2, device_extensions.khr_shader_float_controls],
- conflicts: [properties_vulkan12],
- },
- properties_sampler_filter_minmax => {
- ty: PhysicalDeviceSamplerFilterMinmaxProperties,
- provided_by: [api_version >= crate::Version::V1_2, device_extensions.ext_sampler_filter_minmax],
- conflicts: [properties_vulkan12],
- },
- properties_timeline_semaphore => {
- ty: PhysicalDeviceTimelineSemaphoreProperties,
- provided_by: [api_version >= crate::Version::V1_2, device_extensions.khr_timeline_semaphore],
- conflicts: [properties_vulkan12],
- },
- properties_acceleration_structure_khr => {
- ty: PhysicalDeviceAccelerationStructurePropertiesKHR,
- provided_by: [device_extensions.khr_acceleration_structure],
- conflicts: [],
- },
- properties_fragment_shading_rate_khr => {
- ty: PhysicalDeviceFragmentShadingRatePropertiesKHR,
- provided_by: [device_extensions.khr_fragment_shading_rate],
- conflicts: [],
- },
- properties_performance_query_khr => {
- ty: PhysicalDevicePerformanceQueryPropertiesKHR,
- provided_by: [device_extensions.khr_performance_query],
- conflicts: [],
- },
- properties_portability_subset_khr => {
- ty: PhysicalDevicePortabilitySubsetPropertiesKHR,
- provided_by: [device_extensions.khr_portability_subset],
- conflicts: [],
- },
- properties_push_descriptor_khr => {
- ty: PhysicalDevicePushDescriptorPropertiesKHR,
- provided_by: [device_extensions.khr_push_descriptor],
- conflicts: [],
- },
- properties_ray_tracing_pipeline_khr => {
- ty: PhysicalDeviceRayTracingPipelinePropertiesKHR,
- provided_by: [device_extensions.khr_ray_tracing_pipeline],
- conflicts: [],
- },
- properties_blend_operation_advanced_ext => {
- ty: PhysicalDeviceBlendOperationAdvancedPropertiesEXT,
- provided_by: [device_extensions.ext_blend_operation_advanced],
- conflicts: [],
- },
- properties_conservative_rasterization_ext => {
- ty: PhysicalDeviceConservativeRasterizationPropertiesEXT,
- provided_by: [device_extensions.ext_conservative_rasterization],
- conflicts: [],
- },
- properties_custom_border_color_ext => {
- ty: PhysicalDeviceCustomBorderColorPropertiesEXT,
- provided_by: [device_extensions.ext_custom_border_color],
- conflicts: [],
- },
- properties_discard_rectangle_ext => {
- ty: PhysicalDeviceDiscardRectanglePropertiesEXT,
- provided_by: [device_extensions.ext_discard_rectangles],
- conflicts: [],
- },
- properties_drm_ext => {
- ty: PhysicalDeviceDrmPropertiesEXT,
- provided_by: [device_extensions.ext_physical_device_drm],
- conflicts: [],
- },
- properties_external_memory_host_ext => {
- ty: PhysicalDeviceExternalMemoryHostPropertiesEXT,
- provided_by: [device_extensions.ext_external_memory_host],
- conflicts: [],
- },
- properties_fragment_density_map2_ext => {
- ty: PhysicalDeviceFragmentDensityMap2PropertiesEXT,
- provided_by: [device_extensions.ext_fragment_density_map2],
- conflicts: [],
- },
- properties_fragment_density_map_ext => {
- ty: PhysicalDeviceFragmentDensityMapPropertiesEXT,
- provided_by: [device_extensions.ext_fragment_density_map],
- conflicts: [],
- },
- properties_inline_uniform_block_ext => {
- ty: PhysicalDeviceInlineUniformBlockPropertiesEXT,
- provided_by: [device_extensions.ext_inline_uniform_block],
- conflicts: [],
- },
- properties_line_rasterization_ext => {
- ty: PhysicalDeviceLineRasterizationPropertiesEXT,
- provided_by: [device_extensions.ext_line_rasterization],
- conflicts: [],
- },
- properties_multi_draw_ext => {
- ty: PhysicalDeviceMultiDrawPropertiesEXT,
- provided_by: [device_extensions.ext_multi_draw],
- conflicts: [],
- },
- properties_pci_bus_info_ext => {
- ty: PhysicalDevicePCIBusInfoPropertiesEXT,
- provided_by: [device_extensions.ext_pci_bus_info],
- conflicts: [],
- },
- properties_provoking_vertex_ext => {
- ty: PhysicalDeviceProvokingVertexPropertiesEXT,
- provided_by: [device_extensions.ext_provoking_vertex],
- conflicts: [],
- },
- properties_robustness2_ext => {
- ty: PhysicalDeviceRobustness2PropertiesEXT,
- provided_by: [device_extensions.ext_robustness2],
- conflicts: [],
- },
- properties_sample_locations_ext => {
- ty: PhysicalDeviceSampleLocationsPropertiesEXT,
- provided_by: [device_extensions.ext_sample_locations],
- conflicts: [],
- },
- properties_subgroup_size_control_ext => {
- ty: PhysicalDeviceSubgroupSizeControlPropertiesEXT,
- provided_by: [device_extensions.ext_subgroup_size_control],
- conflicts: [],
- },
- properties_texel_buffer_alignment_ext => {
- ty: PhysicalDeviceTexelBufferAlignmentPropertiesEXT,
- provided_by: [device_extensions.ext_texel_buffer_alignment],
- conflicts: [],
- },
- properties_transform_feedback_ext => {
- ty: PhysicalDeviceTransformFeedbackPropertiesEXT,
- provided_by: [device_extensions.ext_transform_feedback],
- conflicts: [],
- },
- properties_vertex_attribute_divisor_ext => {
- ty: PhysicalDeviceVertexAttributeDivisorPropertiesEXT,
- provided_by: [device_extensions.ext_vertex_attribute_divisor],
- conflicts: [],
- },
- properties_cooperative_matrix_nv => {
- ty: PhysicalDeviceCooperativeMatrixPropertiesNV,
- provided_by: [device_extensions.nv_cooperative_matrix],
- conflicts: [],
- },
- properties_device_generated_commands_nv => {
- ty: PhysicalDeviceDeviceGeneratedCommandsPropertiesNV,
- provided_by: [device_extensions.nv_device_generated_commands],
- conflicts: [],
- },
- properties_fragment_shading_rate_enums_nv => {
- ty: PhysicalDeviceFragmentShadingRateEnumsPropertiesNV,
- provided_by: [device_extensions.nv_fragment_shading_rate_enums],
- conflicts: [],
- },
- properties_mesh_shader_nv => {
- ty: PhysicalDeviceMeshShaderPropertiesNV,
- provided_by: [device_extensions.nv_mesh_shader],
- conflicts: [],
- },
- properties_multiview_per_view_attributes_nvx => {
- ty: PhysicalDeviceMultiviewPerViewAttributesPropertiesNVX,
- provided_by: [device_extensions.nvx_multiview_per_view_attributes],
- conflicts: [],
- },
- properties_ray_tracing_nv => {
- ty: PhysicalDeviceRayTracingPropertiesNV,
- provided_by: [device_extensions.nv_ray_tracing],
- conflicts: [properties_ray_tracing_pipeline_khr, properties_acceleration_structure_khr],
- },
- properties_shader_core2_amd => {
- ty: PhysicalDeviceShaderCoreProperties2AMD,
- provided_by: [device_extensions.amd_shader_core_properties2],
- conflicts: [],
- },
- properties_shader_core_amd => {
- ty: PhysicalDeviceShaderCorePropertiesAMD,
- provided_by: [device_extensions.amd_shader_core_properties],
- conflicts: [],
- },
- properties_shader_sm_builtins_nv => {
- ty: PhysicalDeviceShaderSMBuiltinsPropertiesNV,
- provided_by: [device_extensions.nv_shader_sm_builtins],
- conflicts: [],
- },
- properties_shading_rate_image_nv => {
- ty: PhysicalDeviceShadingRateImagePropertiesNV,
- provided_by: [device_extensions.nv_shading_rate_image],
- conflicts: [],
- },
- properties_subpass_shading_huawei => {
- ty: PhysicalDeviceSubpassShadingPropertiesHUAWEI,
- provided_by: [device_extensions.huawei_subpass_shading],
- conflicts: [],
- },
-}
diff --git a/out/device_extensions.rs b/out/device_extensions.rs
new file mode 100644
index 0000000..a24bad4
--- /dev/null
+++ b/out/device_extensions.rs
@@ -0,0 +1,13961 @@
+// This file is auto-generated by vulkano autogen from vk.xml header version 1.3.238.
+// It should not be edited manually. Changes should be made by editing autogen.
+
+#[doc = r" List of extensions that are enabled or available."]
+#[derive(Copy, Clone, PartialEq, Eq)]
+pub struct DeviceExtensions {
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_16bit_storage.html)\n- Promoted to Vulkan 1.1\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)\n - One of: Vulkan API version 1.1, device extension [`khr_storage_buffer_storage_class`](crate::device::DeviceExtensions::khr_storage_buffer_storage_class)"]
+ pub khr_16bit_storage: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_8bit_storage.html)\n- Promoted to Vulkan 1.2\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)\n - One of: Vulkan API version 1.1, device extension [`khr_storage_buffer_storage_class`](crate::device::DeviceExtensions::khr_storage_buffer_storage_class)"]
+ pub khr_8bit_storage: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_acceleration_structure.html)\n- Requires:\n - Vulkan API version 1.1\n - One of: Vulkan API version 1.2, device extension [`ext_descriptor_indexing`](crate::device::DeviceExtensions::ext_descriptor_indexing)\n - One of: Vulkan API version 1.2, device extension [`khr_buffer_device_address`](crate::device::DeviceExtensions::khr_buffer_device_address)\n - device extension [`khr_deferred_host_operations`](crate::device::DeviceExtensions::khr_deferred_host_operations)"]
+ pub khr_acceleration_structure: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_bind_memory2.html)\n- Promoted to Vulkan 1.1"]
+ pub khr_bind_memory2: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_buffer_device_address.html)\n- Promoted to Vulkan 1.2\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)\n- Conflicts with device extension: [`ext_buffer_device_address`](crate::device::DeviceExtensions::ext_buffer_device_address)"]
+ pub khr_buffer_device_address: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_copy_commands2.html)\n- Promoted to Vulkan 1.3"]
+ pub khr_copy_commands2: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_create_renderpass2.html)\n- Promoted to Vulkan 1.2\n- Requires:\n - One of: Vulkan API version 1.1, device extension [`khr_multiview`](crate::device::DeviceExtensions::khr_multiview)\n - One of: Vulkan API version 1.1, device extension [`khr_maintenance2`](crate::device::DeviceExtensions::khr_maintenance2)"]
+ pub khr_create_renderpass2: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_dedicated_allocation.html)\n- Promoted to Vulkan 1.1\n- Requires:\n - One of: Vulkan API version 1.1, device extension [`khr_get_memory_requirements2`](crate::device::DeviceExtensions::khr_get_memory_requirements2)"]
+ pub khr_dedicated_allocation: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_deferred_host_operations.html)"]
+ pub khr_deferred_host_operations: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_depth_stencil_resolve.html)\n- Promoted to Vulkan 1.2\n- Requires:\n - One of: Vulkan API version 1.2, device extension [`khr_create_renderpass2`](crate::device::DeviceExtensions::khr_create_renderpass2)"]
+ pub khr_depth_stencil_resolve: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_descriptor_update_template.html)\n- Promoted to Vulkan 1.1"]
+ pub khr_descriptor_update_template: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_device_group.html)\n- Promoted to Vulkan 1.1\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_device_group_creation`](crate::instance::InstanceExtensions::khr_device_group_creation)"]
+ pub khr_device_group: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_display_swapchain.html)\n- Requires:\n - device extension [`khr_swapchain`](crate::device::DeviceExtensions::khr_swapchain)\n - instance extension [`khr_display`](crate::instance::InstanceExtensions::khr_display)"]
+ pub khr_display_swapchain: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_draw_indirect_count.html)\n- Promoted to Vulkan 1.2"]
+ pub khr_draw_indirect_count: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_driver_properties.html)\n- Promoted to Vulkan 1.2\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub khr_driver_properties: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_dynamic_rendering.html)\n- Promoted to Vulkan 1.3\n- Requires:\n - One of: Vulkan API version 1.2, device extension [`khr_depth_stencil_resolve`](crate::device::DeviceExtensions::khr_depth_stencil_resolve)\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub khr_dynamic_rendering: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_external_fence.html)\n- Promoted to Vulkan 1.1\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_external_fence_capabilities`](crate::instance::InstanceExtensions::khr_external_fence_capabilities)"]
+ pub khr_external_fence: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_external_fence_fd.html)\n- Requires:\n - One of: Vulkan API version 1.1, device extension [`khr_external_fence`](crate::device::DeviceExtensions::khr_external_fence)"]
+ pub khr_external_fence_fd: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_external_fence_win32.html)\n- Requires:\n - One of: Vulkan API version 1.1, device extension [`khr_external_fence`](crate::device::DeviceExtensions::khr_external_fence)"]
+ pub khr_external_fence_win32: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_external_memory.html)\n- Promoted to Vulkan 1.1\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_external_memory_capabilities`](crate::instance::InstanceExtensions::khr_external_memory_capabilities)"]
+ pub khr_external_memory: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_external_memory_fd.html)\n- Requires:\n - One of: Vulkan API version 1.1, device extension [`khr_external_memory`](crate::device::DeviceExtensions::khr_external_memory)"]
+ pub khr_external_memory_fd: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_external_memory_win32.html)\n- Requires:\n - One of: Vulkan API version 1.1, device extension [`khr_external_memory`](crate::device::DeviceExtensions::khr_external_memory)"]
+ pub khr_external_memory_win32: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_external_semaphore.html)\n- Promoted to Vulkan 1.1\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_external_semaphore_capabilities`](crate::instance::InstanceExtensions::khr_external_semaphore_capabilities)"]
+ pub khr_external_semaphore: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_external_semaphore_fd.html)\n- Requires:\n - One of: Vulkan API version 1.1, device extension [`khr_external_semaphore`](crate::device::DeviceExtensions::khr_external_semaphore)"]
+ pub khr_external_semaphore_fd: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_external_semaphore_win32.html)\n- Requires:\n - One of: Vulkan API version 1.1, device extension [`khr_external_semaphore`](crate::device::DeviceExtensions::khr_external_semaphore)"]
+ pub khr_external_semaphore_win32: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_format_feature_flags2.html)\n- Promoted to Vulkan 1.3\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub khr_format_feature_flags2: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_fragment_shader_barycentric.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub khr_fragment_shader_barycentric: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_fragment_shading_rate.html)\n- Requires:\n - One of: Vulkan API version 1.2, device extension [`khr_create_renderpass2`](crate::device::DeviceExtensions::khr_create_renderpass2)\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub khr_fragment_shading_rate: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_get_memory_requirements2.html)\n- Promoted to Vulkan 1.1"]
+ pub khr_get_memory_requirements2: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_global_priority.html)"]
+ pub khr_global_priority: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_image_format_list.html)\n- Promoted to Vulkan 1.2"]
+ pub khr_image_format_list: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_imageless_framebuffer.html)\n- Promoted to Vulkan 1.2\n- Requires:\n - One of: Vulkan API version 1.1, device extension [`khr_maintenance2`](crate::device::DeviceExtensions::khr_maintenance2)\n - One of: Vulkan API version 1.2, device extension [`khr_image_format_list`](crate::device::DeviceExtensions::khr_image_format_list)"]
+ pub khr_imageless_framebuffer: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_incremental_present.html)\n- Requires:\n - device extension [`khr_swapchain`](crate::device::DeviceExtensions::khr_swapchain)"]
+ pub khr_incremental_present: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_maintenance1.html)\n- Promoted to Vulkan 1.1"]
+ pub khr_maintenance1: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_maintenance2.html)\n- Promoted to Vulkan 1.1"]
+ pub khr_maintenance2: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_maintenance3.html)\n- Promoted to Vulkan 1.1\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub khr_maintenance3: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_maintenance4.html)\n- Promoted to Vulkan 1.3\n- Requires:\n - Vulkan API version 1.1"]
+ pub khr_maintenance4: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_multiview.html)\n- Promoted to Vulkan 1.1\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub khr_multiview: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_performance_query.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub khr_performance_query: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_pipeline_executable_properties.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub khr_pipeline_executable_properties: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_pipeline_library.html)"]
+ pub khr_pipeline_library: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_portability_subset.html)\n- Must be enabled if it is supported by the physical device\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub khr_portability_subset: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_present_id.html)\n- Requires:\n - device extension [`khr_swapchain`](crate::device::DeviceExtensions::khr_swapchain)"]
+ pub khr_present_id: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_present_wait.html)\n- Requires:\n - device extension [`khr_swapchain`](crate::device::DeviceExtensions::khr_swapchain)\n - device extension [`khr_present_id`](crate::device::DeviceExtensions::khr_present_id)"]
+ pub khr_present_wait: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_push_descriptor.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub khr_push_descriptor: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_ray_query.html)\n- Requires:\n - Vulkan API version 1.1\n - One of: Vulkan API version 1.2, device extension [`khr_spirv_1_4`](crate::device::DeviceExtensions::khr_spirv_1_4)\n - device extension [`khr_acceleration_structure`](crate::device::DeviceExtensions::khr_acceleration_structure)"]
+ pub khr_ray_query: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_ray_tracing_maintenance1.html)\n- Requires:\n - Vulkan API version 1.1\n - device extension [`khr_acceleration_structure`](crate::device::DeviceExtensions::khr_acceleration_structure)"]
+ pub khr_ray_tracing_maintenance1: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_ray_tracing_pipeline.html)\n- Requires:\n - Vulkan API version 1.1\n - One of: Vulkan API version 1.2, device extension [`khr_spirv_1_4`](crate::device::DeviceExtensions::khr_spirv_1_4)\n - device extension [`khr_acceleration_structure`](crate::device::DeviceExtensions::khr_acceleration_structure)"]
+ pub khr_ray_tracing_pipeline: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_relaxed_block_layout.html)\n- Promoted to Vulkan 1.1"]
+ pub khr_relaxed_block_layout: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_sampler_mirror_clamp_to_edge.html)\n- Promoted to Vulkan 1.2"]
+ pub khr_sampler_mirror_clamp_to_edge: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_sampler_ycbcr_conversion.html)\n- Promoted to Vulkan 1.1\n- Requires:\n - One of: Vulkan API version 1.1, device extension [`khr_maintenance1`](crate::device::DeviceExtensions::khr_maintenance1)\n - One of: Vulkan API version 1.1, device extension [`khr_bind_memory2`](crate::device::DeviceExtensions::khr_bind_memory2)\n - One of: Vulkan API version 1.1, device extension [`khr_get_memory_requirements2`](crate::device::DeviceExtensions::khr_get_memory_requirements2)\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub khr_sampler_ycbcr_conversion: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_separate_depth_stencil_layouts.html)\n- Promoted to Vulkan 1.2\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)\n - One of: Vulkan API version 1.2, device extension [`khr_create_renderpass2`](crate::device::DeviceExtensions::khr_create_renderpass2)"]
+ pub khr_separate_depth_stencil_layouts: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_shader_atomic_int64.html)\n- Promoted to Vulkan 1.2\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub khr_shader_atomic_int64: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_shader_clock.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub khr_shader_clock: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_shader_draw_parameters.html)\n- Promoted to Vulkan 1.1"]
+ pub khr_shader_draw_parameters: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_shader_float16_int8.html)\n- Promoted to Vulkan 1.2\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub khr_shader_float16_int8: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_shader_float_controls.html)\n- Promoted to Vulkan 1.2\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub khr_shader_float_controls: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_shader_integer_dot_product.html)\n- Promoted to Vulkan 1.3\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub khr_shader_integer_dot_product: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_shader_non_semantic_info.html)\n- Promoted to Vulkan 1.3"]
+ pub khr_shader_non_semantic_info: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_shader_subgroup_extended_types.html)\n- Promoted to Vulkan 1.2\n- Requires:\n - Vulkan API version 1.1"]
+ pub khr_shader_subgroup_extended_types: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_shader_subgroup_uniform_control_flow.html)\n- Requires:\n - Vulkan API version 1.1"]
+ pub khr_shader_subgroup_uniform_control_flow: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_shader_terminate_invocation.html)\n- Promoted to Vulkan 1.3\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub khr_shader_terminate_invocation: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_shared_presentable_image.html)\n- Requires:\n - device extension [`khr_swapchain`](crate::device::DeviceExtensions::khr_swapchain)\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)\n - instance extension [`khr_get_surface_capabilities2`](crate::instance::InstanceExtensions::khr_get_surface_capabilities2)"]
+ pub khr_shared_presentable_image: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_spirv_1_4.html)\n- Promoted to Vulkan 1.2\n- Requires:\n - Vulkan API version 1.1\n - One of: Vulkan API version 1.2, device extension [`khr_shader_float_controls`](crate::device::DeviceExtensions::khr_shader_float_controls)"]
+ pub khr_spirv_1_4: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_storage_buffer_storage_class.html)\n- Promoted to Vulkan 1.1"]
+ pub khr_storage_buffer_storage_class: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_swapchain.html)\n- Requires:\n - instance extension [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)"]
+ pub khr_swapchain: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_swapchain_mutable_format.html)\n- Requires:\n - device extension [`khr_swapchain`](crate::device::DeviceExtensions::khr_swapchain)\n - One of: Vulkan API version 1.1, device extension [`khr_maintenance2`](crate::device::DeviceExtensions::khr_maintenance2)\n - One of: Vulkan API version 1.2, device extension [`khr_image_format_list`](crate::device::DeviceExtensions::khr_image_format_list)"]
+ pub khr_swapchain_mutable_format: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_synchronization2.html)\n- Promoted to Vulkan 1.3\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub khr_synchronization2: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_timeline_semaphore.html)\n- Promoted to Vulkan 1.2\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub khr_timeline_semaphore: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_uniform_buffer_standard_layout.html)\n- Promoted to Vulkan 1.2\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub khr_uniform_buffer_standard_layout: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_variable_pointers.html)\n- Promoted to Vulkan 1.1\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)\n - One of: Vulkan API version 1.1, device extension [`khr_storage_buffer_storage_class`](crate::device::DeviceExtensions::khr_storage_buffer_storage_class)"]
+ pub khr_variable_pointers: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_video_decode_h264.html)\n- Requires:\n - device extension [`khr_video_decode_queue`](crate::device::DeviceExtensions::khr_video_decode_queue)"]
+ pub khr_video_decode_h264: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_video_decode_h265.html)\n- Requires:\n - device extension [`khr_video_decode_queue`](crate::device::DeviceExtensions::khr_video_decode_queue)"]
+ pub khr_video_decode_h265: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_video_decode_queue.html)\n- Requires:\n - device extension [`khr_video_queue`](crate::device::DeviceExtensions::khr_video_queue)\n - One of: Vulkan API version 1.3, device extension [`khr_synchronization2`](crate::device::DeviceExtensions::khr_synchronization2)"]
+ pub khr_video_decode_queue: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_video_encode_queue.html)\n- Requires:\n - device extension [`khr_video_queue`](crate::device::DeviceExtensions::khr_video_queue)\n - One of: Vulkan API version 1.3, device extension [`khr_synchronization2`](crate::device::DeviceExtensions::khr_synchronization2)"]
+ pub khr_video_encode_queue: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_video_queue.html)\n- Requires:\n - Vulkan API version 1.1\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)\n - One of: Vulkan API version 1.3, device extension [`khr_synchronization2`](crate::device::DeviceExtensions::khr_synchronization2)"]
+ pub khr_video_queue: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_vulkan_memory_model.html)\n- Promoted to Vulkan 1.2"]
+ pub khr_vulkan_memory_model: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_win32_keyed_mutex.html)\n- Requires:\n - device extension [`khr_external_memory_win32`](crate::device::DeviceExtensions::khr_external_memory_win32)"]
+ pub khr_win32_keyed_mutex: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_workgroup_memory_explicit_layout.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub khr_workgroup_memory_explicit_layout: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_zero_initialize_workgroup_memory.html)\n- Promoted to Vulkan 1.3\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub khr_zero_initialize_workgroup_memory: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_4444_formats.html)\n- Promoted to Vulkan 1.3\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_4444_formats: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_astc_decode_mode.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_astc_decode_mode: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_attachment_feedback_loop_layout.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_attachment_feedback_loop_layout: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_blend_operation_advanced.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_blend_operation_advanced: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_border_color_swizzle.html)\n- Requires:\n - device extension [`ext_custom_border_color`](crate::device::DeviceExtensions::ext_custom_border_color)"]
+ pub ext_border_color_swizzle: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_buffer_device_address.html)\n- Deprecated by [`khr_buffer_device_address`](crate::device::DeviceExtensions::khr_buffer_device_address)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)\n- Conflicts with device extension: [`khr_buffer_device_address`](crate::device::DeviceExtensions::khr_buffer_device_address)"]
+ pub ext_buffer_device_address: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_calibrated_timestamps.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_calibrated_timestamps: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_color_write_enable.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_color_write_enable: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_conditional_rendering.html)"]
+ pub ext_conditional_rendering: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_conservative_rasterization.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_conservative_rasterization: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_custom_border_color.html)"]
+ pub ext_custom_border_color: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_debug_marker.html)\n- Promoted to [`ext_debug_utils`](crate::instance::InstanceExtensions::ext_debug_utils)\n- Requires:\n - instance extension [`ext_debug_report`](crate::instance::InstanceExtensions::ext_debug_report)"]
+ pub ext_debug_marker: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_depth_clamp_zero_one.html)"]
+ pub ext_depth_clamp_zero_one: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_depth_clip_control.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_depth_clip_control: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_depth_clip_enable.html)"]
+ pub ext_depth_clip_enable: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_depth_range_unrestricted.html)"]
+ pub ext_depth_range_unrestricted: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_descriptor_buffer.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)\n - One of: Vulkan API version 1.2, device extension [`khr_buffer_device_address`](crate::device::DeviceExtensions::khr_buffer_device_address)\n - One of: Vulkan API version 1.3, device extension [`khr_synchronization2`](crate::device::DeviceExtensions::khr_synchronization2)\n - One of: Vulkan API version 1.2, device extension [`ext_descriptor_indexing`](crate::device::DeviceExtensions::ext_descriptor_indexing)"]
+ pub ext_descriptor_buffer: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_descriptor_indexing.html)\n- Promoted to Vulkan 1.2\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)\n - One of: Vulkan API version 1.1, device extension [`khr_maintenance3`](crate::device::DeviceExtensions::khr_maintenance3)"]
+ pub ext_descriptor_indexing: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_device_address_binding_report.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)\n - instance extension [`ext_debug_utils`](crate::instance::InstanceExtensions::ext_debug_utils)"]
+ pub ext_device_address_binding_report: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_device_fault.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_device_fault: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_device_memory_report.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_device_memory_report: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_discard_rectangles.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_discard_rectangles: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_display_control.html)\n- Requires:\n - instance extension [`ext_display_surface_counter`](crate::instance::InstanceExtensions::ext_display_surface_counter)\n - device extension [`khr_swapchain`](crate::device::DeviceExtensions::khr_swapchain)"]
+ pub ext_display_control: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_extended_dynamic_state.html)\n- Promoted to Vulkan 1.3\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_extended_dynamic_state: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_extended_dynamic_state2.html)\n- Promoted to Vulkan 1.3\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_extended_dynamic_state2: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_extended_dynamic_state3.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_extended_dynamic_state3: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_external_memory_dma_buf.html)\n- Requires:\n - device extension [`khr_external_memory_fd`](crate::device::DeviceExtensions::khr_external_memory_fd)"]
+ pub ext_external_memory_dma_buf: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_external_memory_host.html)\n- Requires:\n - One of: Vulkan API version 1.1, device extension [`khr_external_memory`](crate::device::DeviceExtensions::khr_external_memory)"]
+ pub ext_external_memory_host: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_filter_cubic.html)"]
+ pub ext_filter_cubic: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_fragment_density_map.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_fragment_density_map: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_fragment_density_map2.html)\n- Requires:\n - device extension [`ext_fragment_density_map`](crate::device::DeviceExtensions::ext_fragment_density_map)"]
+ pub ext_fragment_density_map2: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_fragment_shader_interlock.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_fragment_shader_interlock: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_full_screen_exclusive.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)\n - instance extension [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)\n - instance extension [`khr_get_surface_capabilities2`](crate::instance::InstanceExtensions::khr_get_surface_capabilities2)\n - device extension [`khr_swapchain`](crate::device::DeviceExtensions::khr_swapchain)"]
+ pub ext_full_screen_exclusive: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_global_priority.html)\n- Promoted to [`khr_global_priority`](crate::device::DeviceExtensions::khr_global_priority)"]
+ pub ext_global_priority: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_global_priority_query.html)\n- Promoted to [`khr_global_priority`](crate::device::DeviceExtensions::khr_global_priority)\n- Requires:\n - One of: device extension [`khr_global_priority`](crate::device::DeviceExtensions::khr_global_priority), device extension [`ext_global_priority`](crate::device::DeviceExtensions::ext_global_priority)\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_global_priority_query: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_graphics_pipeline_library.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)\n - device extension [`khr_pipeline_library`](crate::device::DeviceExtensions::khr_pipeline_library)"]
+ pub ext_graphics_pipeline_library: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_hdr_metadata.html)\n- Requires:\n - device extension [`khr_swapchain`](crate::device::DeviceExtensions::khr_swapchain)"]
+ pub ext_hdr_metadata: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_host_query_reset.html)\n- Promoted to Vulkan 1.2\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_host_query_reset: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_image_2d_view_of_3d.html)\n- Requires:\n - One of: Vulkan API version 1.1, device extension [`khr_maintenance1`](crate::device::DeviceExtensions::khr_maintenance1)\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_image_2d_view_of_3d: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_image_compression_control.html)"]
+ pub ext_image_compression_control: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_image_compression_control_swapchain.html)\n- Requires:\n - device extension [`ext_image_compression_control`](crate::device::DeviceExtensions::ext_image_compression_control)"]
+ pub ext_image_compression_control_swapchain: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_image_drm_format_modifier.html)\n- Requires:\n - One of: Vulkan API version 1.1, device extension [`khr_bind_memory2`](crate::device::DeviceExtensions::khr_bind_memory2)\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)\n - One of: Vulkan API version 1.2, device extension [`khr_image_format_list`](crate::device::DeviceExtensions::khr_image_format_list)\n - One of: Vulkan API version 1.1, device extension [`khr_sampler_ycbcr_conversion`](crate::device::DeviceExtensions::khr_sampler_ycbcr_conversion)"]
+ pub ext_image_drm_format_modifier: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_image_robustness.html)\n- Promoted to Vulkan 1.3\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_image_robustness: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_image_view_min_lod.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_image_view_min_lod: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_index_type_uint8.html)"]
+ pub ext_index_type_uint8: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_inline_uniform_block.html)\n- Promoted to Vulkan 1.3\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)\n - One of: Vulkan API version 1.1, device extension [`khr_maintenance1`](crate::device::DeviceExtensions::khr_maintenance1)"]
+ pub ext_inline_uniform_block: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_legacy_dithering.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_legacy_dithering: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_line_rasterization.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_line_rasterization: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_load_store_op_none.html)"]
+ pub ext_load_store_op_none: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_memory_budget.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_memory_budget: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_memory_priority.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_memory_priority: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_mesh_shader.html)\n- Requires:\n - Vulkan API version 1.1\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)\n - One of: Vulkan API version 1.2, device extension [`khr_spirv_1_4`](crate::device::DeviceExtensions::khr_spirv_1_4)"]
+ pub ext_mesh_shader: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_metal_objects.html)"]
+ pub ext_metal_objects: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_multi_draw.html)"]
+ pub ext_multi_draw: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_multisampled_render_to_single_sampled.html)\n- Requires:\n - One of: Vulkan API version 1.2, device extension [`khr_create_renderpass2`](crate::device::DeviceExtensions::khr_create_renderpass2)\n - One of: Vulkan API version 1.2, device extension [`khr_depth_stencil_resolve`](crate::device::DeviceExtensions::khr_depth_stencil_resolve)"]
+ pub ext_multisampled_render_to_single_sampled: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_mutable_descriptor_type.html)\n- Requires:\n - One of: Vulkan API version 1.1, device extension [`khr_maintenance3`](crate::device::DeviceExtensions::khr_maintenance3)"]
+ pub ext_mutable_descriptor_type: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_non_seamless_cube_map.html)"]
+ pub ext_non_seamless_cube_map: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_opacity_micromap.html)\n- Requires:\n - device extension [`khr_acceleration_structure`](crate::device::DeviceExtensions::khr_acceleration_structure)\n - One of: Vulkan API version 1.3, device extension [`khr_synchronization2`](crate::device::DeviceExtensions::khr_synchronization2)"]
+ pub ext_opacity_micromap: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_pageable_device_local_memory.html)\n- Requires:\n - device extension [`ext_memory_priority`](crate::device::DeviceExtensions::ext_memory_priority)"]
+ pub ext_pageable_device_local_memory: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_pci_bus_info.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_pci_bus_info: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_physical_device_drm.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_physical_device_drm: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_pipeline_creation_cache_control.html)\n- Promoted to Vulkan 1.3"]
+ pub ext_pipeline_creation_cache_control: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_pipeline_creation_feedback.html)\n- Promoted to Vulkan 1.3"]
+ pub ext_pipeline_creation_feedback: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_pipeline_properties.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_pipeline_properties: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_pipeline_protected_access.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_pipeline_protected_access: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_pipeline_robustness.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_pipeline_robustness: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_post_depth_coverage.html)"]
+ pub ext_post_depth_coverage: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_primitive_topology_list_restart.html)"]
+ pub ext_primitive_topology_list_restart: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_primitives_generated_query.html)\n- Requires:\n - device extension [`ext_transform_feedback`](crate::device::DeviceExtensions::ext_transform_feedback)"]
+ pub ext_primitives_generated_query: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_private_data.html)\n- Promoted to Vulkan 1.3"]
+ pub ext_private_data: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_provoking_vertex.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_provoking_vertex: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_queue_family_foreign.html)\n- Requires:\n - One of: Vulkan API version 1.1, device extension [`khr_external_memory`](crate::device::DeviceExtensions::khr_external_memory)"]
+ pub ext_queue_family_foreign: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_rasterization_order_attachment_access.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_rasterization_order_attachment_access: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_rgba10x6_formats.html)\n- Requires:\n - One of: Vulkan API version 1.1, device extension [`khr_sampler_ycbcr_conversion`](crate::device::DeviceExtensions::khr_sampler_ycbcr_conversion)"]
+ pub ext_rgba10x6_formats: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_robustness2.html)"]
+ pub ext_robustness2: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_sample_locations.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_sample_locations: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_sampler_filter_minmax.html)\n- Promoted to Vulkan 1.2\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_sampler_filter_minmax: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_scalar_block_layout.html)\n- Promoted to Vulkan 1.2\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_scalar_block_layout: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_separate_stencil_usage.html)\n- Promoted to Vulkan 1.2"]
+ pub ext_separate_stencil_usage: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_shader_atomic_float.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_shader_atomic_float: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_shader_atomic_float2.html)\n- Requires:\n - device extension [`ext_shader_atomic_float`](crate::device::DeviceExtensions::ext_shader_atomic_float)"]
+ pub ext_shader_atomic_float2: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_shader_demote_to_helper_invocation.html)\n- Promoted to Vulkan 1.3\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_shader_demote_to_helper_invocation: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_shader_image_atomic_int64.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_shader_image_atomic_int64: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_shader_module_identifier.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)\n - One of: Vulkan API version 1.3, device extension [`ext_pipeline_creation_cache_control`](crate::device::DeviceExtensions::ext_pipeline_creation_cache_control)"]
+ pub ext_shader_module_identifier: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_shader_stencil_export.html)"]
+ pub ext_shader_stencil_export: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_shader_subgroup_ballot.html)\n- Deprecated by Vulkan 1.2"]
+ pub ext_shader_subgroup_ballot: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_shader_subgroup_vote.html)\n- Deprecated by Vulkan 1.1"]
+ pub ext_shader_subgroup_vote: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_shader_viewport_index_layer.html)\n- Promoted to Vulkan 1.2"]
+ pub ext_shader_viewport_index_layer: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_subgroup_size_control.html)\n- Promoted to Vulkan 1.3\n- Requires:\n - Vulkan API version 1.1"]
+ pub ext_subgroup_size_control: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_subpass_merge_feedback.html)"]
+ pub ext_subpass_merge_feedback: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_swapchain_maintenance1.html)\n- Requires:\n - device extension [`khr_swapchain`](crate::device::DeviceExtensions::khr_swapchain)\n - instance extension [`ext_surface_maintenance1`](crate::instance::InstanceExtensions::ext_surface_maintenance1)\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_swapchain_maintenance1: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_texel_buffer_alignment.html)\n- Promoted to Vulkan 1.3\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_texel_buffer_alignment: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_texture_compression_astc_hdr.html)\n- Promoted to Vulkan 1.3\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_texture_compression_astc_hdr: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_tooling_info.html)\n- Promoted to Vulkan 1.3"]
+ pub ext_tooling_info: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_transform_feedback.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_transform_feedback: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_validation_cache.html)"]
+ pub ext_validation_cache: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_vertex_attribute_divisor.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_vertex_attribute_divisor: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_vertex_input_dynamic_state.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub ext_vertex_input_dynamic_state: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_video_encode_h264.html)\n- Requires:\n - device extension [`khr_video_encode_queue`](crate::device::DeviceExtensions::khr_video_encode_queue)"]
+ pub ext_video_encode_h264: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_video_encode_h265.html)\n- Requires:\n - device extension [`khr_video_encode_queue`](crate::device::DeviceExtensions::khr_video_encode_queue)"]
+ pub ext_video_encode_h265: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_ycbcr_2plane_444_formats.html)\n- Promoted to Vulkan 1.3\n- Requires:\n - One of: Vulkan API version 1.1, device extension [`khr_sampler_ycbcr_conversion`](crate::device::DeviceExtensions::khr_sampler_ycbcr_conversion)"]
+ pub ext_ycbcr_2plane_444_formats: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_ycbcr_image_arrays.html)\n- Requires:\n - One of: Vulkan API version 1.1, device extension [`khr_sampler_ycbcr_conversion`](crate::device::DeviceExtensions::khr_sampler_ycbcr_conversion)"]
+ pub ext_ycbcr_image_arrays: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_AMD_buffer_marker.html)"]
+ pub amd_buffer_marker: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_AMD_device_coherent_memory.html)"]
+ pub amd_device_coherent_memory: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_AMD_display_native_hdr.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)\n - instance extension [`khr_get_surface_capabilities2`](crate::instance::InstanceExtensions::khr_get_surface_capabilities2)\n - device extension [`khr_swapchain`](crate::device::DeviceExtensions::khr_swapchain)"]
+ pub amd_display_native_hdr: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_AMD_draw_indirect_count.html)\n- Promoted to [`khr_draw_indirect_count`](crate::device::DeviceExtensions::khr_draw_indirect_count)"]
+ pub amd_draw_indirect_count: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_AMD_gcn_shader.html)"]
+ pub amd_gcn_shader: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_AMD_gpu_shader_half_float.html)\n- Deprecated by [`khr_shader_float16_int8`](crate::device::DeviceExtensions::khr_shader_float16_int8)"]
+ pub amd_gpu_shader_half_float: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_AMD_gpu_shader_int16.html)\n- Deprecated by [`khr_shader_float16_int8`](crate::device::DeviceExtensions::khr_shader_float16_int8)"]
+ pub amd_gpu_shader_int16: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_AMD_memory_overallocation_behavior.html)"]
+ pub amd_memory_overallocation_behavior: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_AMD_mixed_attachment_samples.html)"]
+ pub amd_mixed_attachment_samples: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_AMD_pipeline_compiler_control.html)"]
+ pub amd_pipeline_compiler_control: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_AMD_rasterization_order.html)"]
+ pub amd_rasterization_order: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_AMD_shader_ballot.html)"]
+ pub amd_shader_ballot: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_AMD_shader_core_properties.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub amd_shader_core_properties: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_AMD_shader_core_properties2.html)\n- Requires:\n - device extension [`amd_shader_core_properties`](crate::device::DeviceExtensions::amd_shader_core_properties)"]
+ pub amd_shader_core_properties2: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_AMD_shader_early_and_late_fragment_tests.html)"]
+ pub amd_shader_early_and_late_fragment_tests: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_AMD_shader_explicit_vertex_parameter.html)"]
+ pub amd_shader_explicit_vertex_parameter: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_AMD_shader_fragment_mask.html)"]
+ pub amd_shader_fragment_mask: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_AMD_shader_image_load_store_lod.html)"]
+ pub amd_shader_image_load_store_lod: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_AMD_shader_info.html)"]
+ pub amd_shader_info: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_AMD_shader_trinary_minmax.html)"]
+ pub amd_shader_trinary_minmax: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_AMD_texture_gather_bias_lod.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub amd_texture_gather_bias_lod: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_ANDROID_external_memory_android_hardware_buffer.html)\n- Requires:\n - One of: Vulkan API version 1.1, device extension [`khr_sampler_ycbcr_conversion`](crate::device::DeviceExtensions::khr_sampler_ycbcr_conversion)\n - One of: Vulkan API version 1.1, device extension [`khr_external_memory`](crate::device::DeviceExtensions::khr_external_memory)\n - device extension [`ext_queue_family_foreign`](crate::device::DeviceExtensions::ext_queue_family_foreign)\n - One of: Vulkan API version 1.1, device extension [`khr_dedicated_allocation`](crate::device::DeviceExtensions::khr_dedicated_allocation)"]
+ pub android_external_memory_android_hardware_buffer: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_ARM_rasterization_order_attachment_access.html)\n- Promoted to [`ext_rasterization_order_attachment_access`](crate::device::DeviceExtensions::ext_rasterization_order_attachment_access)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub arm_rasterization_order_attachment_access: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_ARM_shader_core_builtins.html)"]
+ pub arm_shader_core_builtins: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_FUCHSIA_buffer_collection.html)\n- Requires:\n - device extension [`fuchsia_external_memory`](crate::device::DeviceExtensions::fuchsia_external_memory)\n - One of: Vulkan API version 1.1, device extension [`khr_sampler_ycbcr_conversion`](crate::device::DeviceExtensions::khr_sampler_ycbcr_conversion)"]
+ pub fuchsia_buffer_collection: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_FUCHSIA_external_memory.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_external_memory_capabilities`](crate::instance::InstanceExtensions::khr_external_memory_capabilities)\n - One of: Vulkan API version 1.1, device extension [`khr_external_memory`](crate::device::DeviceExtensions::khr_external_memory)"]
+ pub fuchsia_external_memory: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_FUCHSIA_external_semaphore.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_external_semaphore_capabilities`](crate::instance::InstanceExtensions::khr_external_semaphore_capabilities)\n - One of: Vulkan API version 1.1, device extension [`khr_external_semaphore`](crate::device::DeviceExtensions::khr_external_semaphore)"]
+ pub fuchsia_external_semaphore: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_GGP_frame_token.html)\n- Requires:\n - device extension [`khr_swapchain`](crate::device::DeviceExtensions::khr_swapchain)\n - instance extension [`ggp_stream_descriptor_surface`](crate::instance::InstanceExtensions::ggp_stream_descriptor_surface)"]
+ pub ggp_frame_token: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_GOOGLE_decorate_string.html)"]
+ pub google_decorate_string: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_GOOGLE_display_timing.html)\n- Requires:\n - device extension [`khr_swapchain`](crate::device::DeviceExtensions::khr_swapchain)"]
+ pub google_display_timing: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_GOOGLE_hlsl_functionality1.html)"]
+ pub google_hlsl_functionality1: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_GOOGLE_user_type.html)"]
+ pub google_user_type: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_HUAWEI_invocation_mask.html)\n- Requires:\n - device extension [`khr_ray_tracing_pipeline`](crate::device::DeviceExtensions::khr_ray_tracing_pipeline)\n - One of: Vulkan API version 1.3, device extension [`khr_synchronization2`](crate::device::DeviceExtensions::khr_synchronization2)"]
+ pub huawei_invocation_mask: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_HUAWEI_subpass_shading.html)\n- Requires:\n - One of: Vulkan API version 1.2, device extension [`khr_create_renderpass2`](crate::device::DeviceExtensions::khr_create_renderpass2)\n - One of: Vulkan API version 1.3, device extension [`khr_synchronization2`](crate::device::DeviceExtensions::khr_synchronization2)"]
+ pub huawei_subpass_shading: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_IMG_filter_cubic.html)"]
+ pub img_filter_cubic: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_IMG_format_pvrtc.html)\n- Deprecated without a replacement"]
+ pub img_format_pvrtc: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_INTEL_performance_query.html)"]
+ pub intel_performance_query: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_INTEL_shader_integer_functions2.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub intel_shader_integer_functions2: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NVX_binary_import.html)"]
+ pub nvx_binary_import: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NVX_image_view_handle.html)"]
+ pub nvx_image_view_handle: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NVX_multiview_per_view_attributes.html)\n- Requires:\n - One of: Vulkan API version 1.1, device extension [`khr_multiview`](crate::device::DeviceExtensions::khr_multiview)"]
+ pub nvx_multiview_per_view_attributes: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_acquire_winrt_display.html)\n- Requires:\n - instance extension [`ext_direct_mode_display`](crate::instance::InstanceExtensions::ext_direct_mode_display)"]
+ pub nv_acquire_winrt_display: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_clip_space_w_scaling.html)"]
+ pub nv_clip_space_w_scaling: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_compute_shader_derivatives.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub nv_compute_shader_derivatives: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_cooperative_matrix.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub nv_cooperative_matrix: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_copy_memory_indirect.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)\n - One of: Vulkan API version 1.2, device extension [`khr_buffer_device_address`](crate::device::DeviceExtensions::khr_buffer_device_address)"]
+ pub nv_copy_memory_indirect: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_corner_sampled_image.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub nv_corner_sampled_image: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_coverage_reduction_mode.html)\n- Requires:\n - device extension [`nv_framebuffer_mixed_samples`](crate::device::DeviceExtensions::nv_framebuffer_mixed_samples)"]
+ pub nv_coverage_reduction_mode: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_dedicated_allocation.html)\n- Deprecated by [`khr_dedicated_allocation`](crate::device::DeviceExtensions::khr_dedicated_allocation)"]
+ pub nv_dedicated_allocation: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_dedicated_allocation_image_aliasing.html)\n- Requires:\n - One of: Vulkan API version 1.1, device extension [`khr_dedicated_allocation`](crate::device::DeviceExtensions::khr_dedicated_allocation)"]
+ pub nv_dedicated_allocation_image_aliasing: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_device_diagnostic_checkpoints.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub nv_device_diagnostic_checkpoints: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_device_diagnostics_config.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub nv_device_diagnostics_config: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_device_generated_commands.html)\n- Requires:\n - Vulkan API version 1.1\n - One of: Vulkan API version 1.2, device extension [`khr_buffer_device_address`](crate::device::DeviceExtensions::khr_buffer_device_address)"]
+ pub nv_device_generated_commands: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_external_memory.html)\n- Deprecated by [`khr_external_memory`](crate::device::DeviceExtensions::khr_external_memory)\n- Requires:\n - instance extension [`nv_external_memory_capabilities`](crate::instance::InstanceExtensions::nv_external_memory_capabilities)"]
+ pub nv_external_memory: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_external_memory_rdma.html)\n- Requires:\n - One of: Vulkan API version 1.1, device extension [`khr_external_memory`](crate::device::DeviceExtensions::khr_external_memory)"]
+ pub nv_external_memory_rdma: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_external_memory_win32.html)\n- Deprecated by [`khr_external_memory_win32`](crate::device::DeviceExtensions::khr_external_memory_win32)\n- Requires:\n - device extension [`nv_external_memory`](crate::device::DeviceExtensions::nv_external_memory)"]
+ pub nv_external_memory_win32: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_fill_rectangle.html)"]
+ pub nv_fill_rectangle: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_fragment_coverage_to_color.html)"]
+ pub nv_fragment_coverage_to_color: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_fragment_shader_barycentric.html)\n- Promoted to [`khr_fragment_shader_barycentric`](crate::device::DeviceExtensions::khr_fragment_shader_barycentric)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub nv_fragment_shader_barycentric: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_fragment_shading_rate_enums.html)\n- Requires:\n - device extension [`khr_fragment_shading_rate`](crate::device::DeviceExtensions::khr_fragment_shading_rate)"]
+ pub nv_fragment_shading_rate_enums: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_framebuffer_mixed_samples.html)"]
+ pub nv_framebuffer_mixed_samples: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_geometry_shader_passthrough.html)"]
+ pub nv_geometry_shader_passthrough: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_glsl_shader.html)\n- Deprecated without a replacement"]
+ pub nv_glsl_shader: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_inherited_viewport_scissor.html)"]
+ pub nv_inherited_viewport_scissor: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_linear_color_attachment.html)"]
+ pub nv_linear_color_attachment: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_memory_decompression.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)\n - One of: Vulkan API version 1.2, device extension [`khr_buffer_device_address`](crate::device::DeviceExtensions::khr_buffer_device_address)"]
+ pub nv_memory_decompression: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_mesh_shader.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub nv_mesh_shader: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_optical_flow.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)\n - One of: Vulkan API version 1.3, device extension [`khr_format_feature_flags2`](crate::device::DeviceExtensions::khr_format_feature_flags2)\n - One of: Vulkan API version 1.3, device extension [`khr_synchronization2`](crate::device::DeviceExtensions::khr_synchronization2)"]
+ pub nv_optical_flow: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_present_barrier.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)\n - instance extension [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)\n - instance extension [`khr_get_surface_capabilities2`](crate::instance::InstanceExtensions::khr_get_surface_capabilities2)\n - device extension [`khr_swapchain`](crate::device::DeviceExtensions::khr_swapchain)"]
+ pub nv_present_barrier: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_ray_tracing.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)\n - One of: Vulkan API version 1.1, device extension [`khr_get_memory_requirements2`](crate::device::DeviceExtensions::khr_get_memory_requirements2)"]
+ pub nv_ray_tracing: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_ray_tracing_invocation_reorder.html)\n- Requires:\n - device extension [`khr_ray_tracing_pipeline`](crate::device::DeviceExtensions::khr_ray_tracing_pipeline)"]
+ pub nv_ray_tracing_invocation_reorder: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_ray_tracing_motion_blur.html)\n- Requires:\n - device extension [`khr_ray_tracing_pipeline`](crate::device::DeviceExtensions::khr_ray_tracing_pipeline)"]
+ pub nv_ray_tracing_motion_blur: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_representative_fragment_test.html)"]
+ pub nv_representative_fragment_test: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_sample_mask_override_coverage.html)"]
+ pub nv_sample_mask_override_coverage: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_scissor_exclusive.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub nv_scissor_exclusive: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_shader_image_footprint.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub nv_shader_image_footprint: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_shader_sm_builtins.html)\n- Requires:\n - Vulkan API version 1.1"]
+ pub nv_shader_sm_builtins: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_shader_subgroup_partitioned.html)\n- Requires:\n - Vulkan API version 1.1"]
+ pub nv_shader_subgroup_partitioned: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_shading_rate_image.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub nv_shading_rate_image: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_viewport_array2.html)"]
+ pub nv_viewport_array2: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_viewport_swizzle.html)"]
+ pub nv_viewport_swizzle: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_win32_keyed_mutex.html)\n- Promoted to [`khr_win32_keyed_mutex`](crate::device::DeviceExtensions::khr_win32_keyed_mutex)\n- Requires:\n - device extension [`nv_external_memory_win32`](crate::device::DeviceExtensions::nv_external_memory_win32)"]
+ pub nv_win32_keyed_mutex: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_QCOM_fragment_density_map_offset.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)\n - device extension [`ext_fragment_density_map`](crate::device::DeviceExtensions::ext_fragment_density_map)"]
+ pub qcom_fragment_density_map_offset: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_QCOM_image_processing.html)\n- Requires:\n - One of: Vulkan API version 1.3, device extension [`khr_format_feature_flags2`](crate::device::DeviceExtensions::khr_format_feature_flags2)"]
+ pub qcom_image_processing: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_QCOM_multiview_per_view_viewports.html)"]
+ pub qcom_multiview_per_view_viewports: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_QCOM_render_pass_shader_resolve.html)"]
+ pub qcom_render_pass_shader_resolve: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_QCOM_render_pass_store_ops.html)"]
+ pub qcom_render_pass_store_ops: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_QCOM_render_pass_transform.html)\n- Requires:\n - device extension [`khr_swapchain`](crate::device::DeviceExtensions::khr_swapchain)\n - instance extension [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)"]
+ pub qcom_render_pass_transform: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_QCOM_rotated_copy_commands.html)\n- Requires:\n - device extension [`khr_swapchain`](crate::device::DeviceExtensions::khr_swapchain)\n - One of: Vulkan API version 1.3, device extension [`khr_copy_commands2`](crate::device::DeviceExtensions::khr_copy_commands2)"]
+ pub qcom_rotated_copy_commands: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_QCOM_tile_properties.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub qcom_tile_properties: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_SEC_amigo_profiling.html)\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub sec_amigo_profiling: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_VALVE_descriptor_set_host_mapping.html)"]
+ pub valve_descriptor_set_host_mapping: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_VALVE_mutable_descriptor_type.html)\n- Promoted to [`ext_mutable_descriptor_type`](crate::device::DeviceExtensions::ext_mutable_descriptor_type)\n- Requires:\n - One of: Vulkan API version 1.1, device extension [`khr_maintenance3`](crate::device::DeviceExtensions::khr_maintenance3)"]
+ pub valve_mutable_descriptor_type: bool,
+ pub _ne: crate::NonExhaustive,
+}
+impl Default for DeviceExtensions {
+ #[inline]
+ fn default() -> Self {
+ Self::empty()
+ }
+}
+impl DeviceExtensions {
+ #[doc = r" Returns an `Extensions` object with none of the members set."]
+ #[inline]
+ pub const fn empty() -> Self {
+ Self {
+ khr_16bit_storage: false,
+ khr_8bit_storage: false,
+ khr_acceleration_structure: false,
+ khr_bind_memory2: false,
+ khr_buffer_device_address: false,
+ khr_copy_commands2: false,
+ khr_create_renderpass2: false,
+ khr_dedicated_allocation: false,
+ khr_deferred_host_operations: false,
+ khr_depth_stencil_resolve: false,
+ khr_descriptor_update_template: false,
+ khr_device_group: false,
+ khr_display_swapchain: false,
+ khr_draw_indirect_count: false,
+ khr_driver_properties: false,
+ khr_dynamic_rendering: false,
+ khr_external_fence: false,
+ khr_external_fence_fd: false,
+ khr_external_fence_win32: false,
+ khr_external_memory: false,
+ khr_external_memory_fd: false,
+ khr_external_memory_win32: false,
+ khr_external_semaphore: false,
+ khr_external_semaphore_fd: false,
+ khr_external_semaphore_win32: false,
+ khr_format_feature_flags2: false,
+ khr_fragment_shader_barycentric: false,
+ khr_fragment_shading_rate: false,
+ khr_get_memory_requirements2: false,
+ khr_global_priority: false,
+ khr_image_format_list: false,
+ khr_imageless_framebuffer: false,
+ khr_incremental_present: false,
+ khr_maintenance1: false,
+ khr_maintenance2: false,
+ khr_maintenance3: false,
+ khr_maintenance4: false,
+ khr_multiview: false,
+ khr_performance_query: false,
+ khr_pipeline_executable_properties: false,
+ khr_pipeline_library: false,
+ khr_portability_subset: false,
+ khr_present_id: false,
+ khr_present_wait: false,
+ khr_push_descriptor: false,
+ khr_ray_query: false,
+ khr_ray_tracing_maintenance1: false,
+ khr_ray_tracing_pipeline: false,
+ khr_relaxed_block_layout: false,
+ khr_sampler_mirror_clamp_to_edge: false,
+ khr_sampler_ycbcr_conversion: false,
+ khr_separate_depth_stencil_layouts: false,
+ khr_shader_atomic_int64: false,
+ khr_shader_clock: false,
+ khr_shader_draw_parameters: false,
+ khr_shader_float16_int8: false,
+ khr_shader_float_controls: false,
+ khr_shader_integer_dot_product: false,
+ khr_shader_non_semantic_info: false,
+ khr_shader_subgroup_extended_types: false,
+ khr_shader_subgroup_uniform_control_flow: false,
+ khr_shader_terminate_invocation: false,
+ khr_shared_presentable_image: false,
+ khr_spirv_1_4: false,
+ khr_storage_buffer_storage_class: false,
+ khr_swapchain: false,
+ khr_swapchain_mutable_format: false,
+ khr_synchronization2: false,
+ khr_timeline_semaphore: false,
+ khr_uniform_buffer_standard_layout: false,
+ khr_variable_pointers: false,
+ khr_video_decode_h264: false,
+ khr_video_decode_h265: false,
+ khr_video_decode_queue: false,
+ khr_video_encode_queue: false,
+ khr_video_queue: false,
+ khr_vulkan_memory_model: false,
+ khr_win32_keyed_mutex: false,
+ khr_workgroup_memory_explicit_layout: false,
+ khr_zero_initialize_workgroup_memory: false,
+ ext_4444_formats: false,
+ ext_astc_decode_mode: false,
+ ext_attachment_feedback_loop_layout: false,
+ ext_blend_operation_advanced: false,
+ ext_border_color_swizzle: false,
+ ext_buffer_device_address: false,
+ ext_calibrated_timestamps: false,
+ ext_color_write_enable: false,
+ ext_conditional_rendering: false,
+ ext_conservative_rasterization: false,
+ ext_custom_border_color: false,
+ ext_debug_marker: false,
+ ext_depth_clamp_zero_one: false,
+ ext_depth_clip_control: false,
+ ext_depth_clip_enable: false,
+ ext_depth_range_unrestricted: false,
+ ext_descriptor_buffer: false,
+ ext_descriptor_indexing: false,
+ ext_device_address_binding_report: false,
+ ext_device_fault: false,
+ ext_device_memory_report: false,
+ ext_discard_rectangles: false,
+ ext_display_control: false,
+ ext_extended_dynamic_state: false,
+ ext_extended_dynamic_state2: false,
+ ext_extended_dynamic_state3: false,
+ ext_external_memory_dma_buf: false,
+ ext_external_memory_host: false,
+ ext_filter_cubic: false,
+ ext_fragment_density_map: false,
+ ext_fragment_density_map2: false,
+ ext_fragment_shader_interlock: false,
+ ext_full_screen_exclusive: false,
+ ext_global_priority: false,
+ ext_global_priority_query: false,
+ ext_graphics_pipeline_library: false,
+ ext_hdr_metadata: false,
+ ext_host_query_reset: false,
+ ext_image_2d_view_of_3d: false,
+ ext_image_compression_control: false,
+ ext_image_compression_control_swapchain: false,
+ ext_image_drm_format_modifier: false,
+ ext_image_robustness: false,
+ ext_image_view_min_lod: false,
+ ext_index_type_uint8: false,
+ ext_inline_uniform_block: false,
+ ext_legacy_dithering: false,
+ ext_line_rasterization: false,
+ ext_load_store_op_none: false,
+ ext_memory_budget: false,
+ ext_memory_priority: false,
+ ext_mesh_shader: false,
+ ext_metal_objects: false,
+ ext_multi_draw: false,
+ ext_multisampled_render_to_single_sampled: false,
+ ext_mutable_descriptor_type: false,
+ ext_non_seamless_cube_map: false,
+ ext_opacity_micromap: false,
+ ext_pageable_device_local_memory: false,
+ ext_pci_bus_info: false,
+ ext_physical_device_drm: false,
+ ext_pipeline_creation_cache_control: false,
+ ext_pipeline_creation_feedback: false,
+ ext_pipeline_properties: false,
+ ext_pipeline_protected_access: false,
+ ext_pipeline_robustness: false,
+ ext_post_depth_coverage: false,
+ ext_primitive_topology_list_restart: false,
+ ext_primitives_generated_query: false,
+ ext_private_data: false,
+ ext_provoking_vertex: false,
+ ext_queue_family_foreign: false,
+ ext_rasterization_order_attachment_access: false,
+ ext_rgba10x6_formats: false,
+ ext_robustness2: false,
+ ext_sample_locations: false,
+ ext_sampler_filter_minmax: false,
+ ext_scalar_block_layout: false,
+ ext_separate_stencil_usage: false,
+ ext_shader_atomic_float: false,
+ ext_shader_atomic_float2: false,
+ ext_shader_demote_to_helper_invocation: false,
+ ext_shader_image_atomic_int64: false,
+ ext_shader_module_identifier: false,
+ ext_shader_stencil_export: false,
+ ext_shader_subgroup_ballot: false,
+ ext_shader_subgroup_vote: false,
+ ext_shader_viewport_index_layer: false,
+ ext_subgroup_size_control: false,
+ ext_subpass_merge_feedback: false,
+ ext_swapchain_maintenance1: false,
+ ext_texel_buffer_alignment: false,
+ ext_texture_compression_astc_hdr: false,
+ ext_tooling_info: false,
+ ext_transform_feedback: false,
+ ext_validation_cache: false,
+ ext_vertex_attribute_divisor: false,
+ ext_vertex_input_dynamic_state: false,
+ ext_video_encode_h264: false,
+ ext_video_encode_h265: false,
+ ext_ycbcr_2plane_444_formats: false,
+ ext_ycbcr_image_arrays: false,
+ amd_buffer_marker: false,
+ amd_device_coherent_memory: false,
+ amd_display_native_hdr: false,
+ amd_draw_indirect_count: false,
+ amd_gcn_shader: false,
+ amd_gpu_shader_half_float: false,
+ amd_gpu_shader_int16: false,
+ amd_memory_overallocation_behavior: false,
+ amd_mixed_attachment_samples: false,
+ amd_pipeline_compiler_control: false,
+ amd_rasterization_order: false,
+ amd_shader_ballot: false,
+ amd_shader_core_properties: false,
+ amd_shader_core_properties2: false,
+ amd_shader_early_and_late_fragment_tests: false,
+ amd_shader_explicit_vertex_parameter: false,
+ amd_shader_fragment_mask: false,
+ amd_shader_image_load_store_lod: false,
+ amd_shader_info: false,
+ amd_shader_trinary_minmax: false,
+ amd_texture_gather_bias_lod: false,
+ android_external_memory_android_hardware_buffer: false,
+ arm_rasterization_order_attachment_access: false,
+ arm_shader_core_builtins: false,
+ fuchsia_buffer_collection: false,
+ fuchsia_external_memory: false,
+ fuchsia_external_semaphore: false,
+ ggp_frame_token: false,
+ google_decorate_string: false,
+ google_display_timing: false,
+ google_hlsl_functionality1: false,
+ google_user_type: false,
+ huawei_invocation_mask: false,
+ huawei_subpass_shading: false,
+ img_filter_cubic: false,
+ img_format_pvrtc: false,
+ intel_performance_query: false,
+ intel_shader_integer_functions2: false,
+ nvx_binary_import: false,
+ nvx_image_view_handle: false,
+ nvx_multiview_per_view_attributes: false,
+ nv_acquire_winrt_display: false,
+ nv_clip_space_w_scaling: false,
+ nv_compute_shader_derivatives: false,
+ nv_cooperative_matrix: false,
+ nv_copy_memory_indirect: false,
+ nv_corner_sampled_image: false,
+ nv_coverage_reduction_mode: false,
+ nv_dedicated_allocation: false,
+ nv_dedicated_allocation_image_aliasing: false,
+ nv_device_diagnostic_checkpoints: false,
+ nv_device_diagnostics_config: false,
+ nv_device_generated_commands: false,
+ nv_external_memory: false,
+ nv_external_memory_rdma: false,
+ nv_external_memory_win32: false,
+ nv_fill_rectangle: false,
+ nv_fragment_coverage_to_color: false,
+ nv_fragment_shader_barycentric: false,
+ nv_fragment_shading_rate_enums: false,
+ nv_framebuffer_mixed_samples: false,
+ nv_geometry_shader_passthrough: false,
+ nv_glsl_shader: false,
+ nv_inherited_viewport_scissor: false,
+ nv_linear_color_attachment: false,
+ nv_memory_decompression: false,
+ nv_mesh_shader: false,
+ nv_optical_flow: false,
+ nv_present_barrier: false,
+ nv_ray_tracing: false,
+ nv_ray_tracing_invocation_reorder: false,
+ nv_ray_tracing_motion_blur: false,
+ nv_representative_fragment_test: false,
+ nv_sample_mask_override_coverage: false,
+ nv_scissor_exclusive: false,
+ nv_shader_image_footprint: false,
+ nv_shader_sm_builtins: false,
+ nv_shader_subgroup_partitioned: false,
+ nv_shading_rate_image: false,
+ nv_viewport_array2: false,
+ nv_viewport_swizzle: false,
+ nv_win32_keyed_mutex: false,
+ qcom_fragment_density_map_offset: false,
+ qcom_image_processing: false,
+ qcom_multiview_per_view_viewports: false,
+ qcom_render_pass_shader_resolve: false,
+ qcom_render_pass_store_ops: false,
+ qcom_render_pass_transform: false,
+ qcom_rotated_copy_commands: false,
+ qcom_tile_properties: false,
+ sec_amigo_profiling: false,
+ valve_descriptor_set_host_mapping: false,
+ valve_mutable_descriptor_type: false,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+ #[doc = r" Returns an `Extensions` object with none of the members set."]
+ #[deprecated(since = "0.31.0", note = "Use `empty` instead.")]
+ #[inline]
+ pub const fn none() -> Self {
+ Self::empty()
+ }
+ #[doc = r" Returns whether any members are set in both `self` and `other`."]
+ #[inline]
+ pub const fn intersects(&self, other: &Self) -> bool {
+ (self.khr_16bit_storage && other.khr_16bit_storage)
+ || (self.khr_8bit_storage && other.khr_8bit_storage)
+ || (self.khr_acceleration_structure && other.khr_acceleration_structure)
+ || (self.khr_bind_memory2 && other.khr_bind_memory2)
+ || (self.khr_buffer_device_address && other.khr_buffer_device_address)
+ || (self.khr_copy_commands2 && other.khr_copy_commands2)
+ || (self.khr_create_renderpass2 && other.khr_create_renderpass2)
+ || (self.khr_dedicated_allocation && other.khr_dedicated_allocation)
+ || (self.khr_deferred_host_operations && other.khr_deferred_host_operations)
+ || (self.khr_depth_stencil_resolve && other.khr_depth_stencil_resolve)
+ || (self.khr_descriptor_update_template && other.khr_descriptor_update_template)
+ || (self.khr_device_group && other.khr_device_group)
+ || (self.khr_display_swapchain && other.khr_display_swapchain)
+ || (self.khr_draw_indirect_count && other.khr_draw_indirect_count)
+ || (self.khr_driver_properties && other.khr_driver_properties)
+ || (self.khr_dynamic_rendering && other.khr_dynamic_rendering)
+ || (self.khr_external_fence && other.khr_external_fence)
+ || (self.khr_external_fence_fd && other.khr_external_fence_fd)
+ || (self.khr_external_fence_win32 && other.khr_external_fence_win32)
+ || (self.khr_external_memory && other.khr_external_memory)
+ || (self.khr_external_memory_fd && other.khr_external_memory_fd)
+ || (self.khr_external_memory_win32 && other.khr_external_memory_win32)
+ || (self.khr_external_semaphore && other.khr_external_semaphore)
+ || (self.khr_external_semaphore_fd && other.khr_external_semaphore_fd)
+ || (self.khr_external_semaphore_win32 && other.khr_external_semaphore_win32)
+ || (self.khr_format_feature_flags2 && other.khr_format_feature_flags2)
+ || (self.khr_fragment_shader_barycentric && other.khr_fragment_shader_barycentric)
+ || (self.khr_fragment_shading_rate && other.khr_fragment_shading_rate)
+ || (self.khr_get_memory_requirements2 && other.khr_get_memory_requirements2)
+ || (self.khr_global_priority && other.khr_global_priority)
+ || (self.khr_image_format_list && other.khr_image_format_list)
+ || (self.khr_imageless_framebuffer && other.khr_imageless_framebuffer)
+ || (self.khr_incremental_present && other.khr_incremental_present)
+ || (self.khr_maintenance1 && other.khr_maintenance1)
+ || (self.khr_maintenance2 && other.khr_maintenance2)
+ || (self.khr_maintenance3 && other.khr_maintenance3)
+ || (self.khr_maintenance4 && other.khr_maintenance4)
+ || (self.khr_multiview && other.khr_multiview)
+ || (self.khr_performance_query && other.khr_performance_query)
+ || (self.khr_pipeline_executable_properties && other.khr_pipeline_executable_properties)
+ || (self.khr_pipeline_library && other.khr_pipeline_library)
+ || (self.khr_portability_subset && other.khr_portability_subset)
+ || (self.khr_present_id && other.khr_present_id)
+ || (self.khr_present_wait && other.khr_present_wait)
+ || (self.khr_push_descriptor && other.khr_push_descriptor)
+ || (self.khr_ray_query && other.khr_ray_query)
+ || (self.khr_ray_tracing_maintenance1 && other.khr_ray_tracing_maintenance1)
+ || (self.khr_ray_tracing_pipeline && other.khr_ray_tracing_pipeline)
+ || (self.khr_relaxed_block_layout && other.khr_relaxed_block_layout)
+ || (self.khr_sampler_mirror_clamp_to_edge && other.khr_sampler_mirror_clamp_to_edge)
+ || (self.khr_sampler_ycbcr_conversion && other.khr_sampler_ycbcr_conversion)
+ || (self.khr_separate_depth_stencil_layouts && other.khr_separate_depth_stencil_layouts)
+ || (self.khr_shader_atomic_int64 && other.khr_shader_atomic_int64)
+ || (self.khr_shader_clock && other.khr_shader_clock)
+ || (self.khr_shader_draw_parameters && other.khr_shader_draw_parameters)
+ || (self.khr_shader_float16_int8 && other.khr_shader_float16_int8)
+ || (self.khr_shader_float_controls && other.khr_shader_float_controls)
+ || (self.khr_shader_integer_dot_product && other.khr_shader_integer_dot_product)
+ || (self.khr_shader_non_semantic_info && other.khr_shader_non_semantic_info)
+ || (self.khr_shader_subgroup_extended_types && other.khr_shader_subgroup_extended_types)
+ || (self.khr_shader_subgroup_uniform_control_flow
+ && other.khr_shader_subgroup_uniform_control_flow)
+ || (self.khr_shader_terminate_invocation && other.khr_shader_terminate_invocation)
+ || (self.khr_shared_presentable_image && other.khr_shared_presentable_image)
+ || (self.khr_spirv_1_4 && other.khr_spirv_1_4)
+ || (self.khr_storage_buffer_storage_class && other.khr_storage_buffer_storage_class)
+ || (self.khr_swapchain && other.khr_swapchain)
+ || (self.khr_swapchain_mutable_format && other.khr_swapchain_mutable_format)
+ || (self.khr_synchronization2 && other.khr_synchronization2)
+ || (self.khr_timeline_semaphore && other.khr_timeline_semaphore)
+ || (self.khr_uniform_buffer_standard_layout && other.khr_uniform_buffer_standard_layout)
+ || (self.khr_variable_pointers && other.khr_variable_pointers)
+ || (self.khr_video_decode_h264 && other.khr_video_decode_h264)
+ || (self.khr_video_decode_h265 && other.khr_video_decode_h265)
+ || (self.khr_video_decode_queue && other.khr_video_decode_queue)
+ || (self.khr_video_encode_queue && other.khr_video_encode_queue)
+ || (self.khr_video_queue && other.khr_video_queue)
+ || (self.khr_vulkan_memory_model && other.khr_vulkan_memory_model)
+ || (self.khr_win32_keyed_mutex && other.khr_win32_keyed_mutex)
+ || (self.khr_workgroup_memory_explicit_layout
+ && other.khr_workgroup_memory_explicit_layout)
+ || (self.khr_zero_initialize_workgroup_memory
+ && other.khr_zero_initialize_workgroup_memory)
+ || (self.ext_4444_formats && other.ext_4444_formats)
+ || (self.ext_astc_decode_mode && other.ext_astc_decode_mode)
+ || (self.ext_attachment_feedback_loop_layout
+ && other.ext_attachment_feedback_loop_layout)
+ || (self.ext_blend_operation_advanced && other.ext_blend_operation_advanced)
+ || (self.ext_border_color_swizzle && other.ext_border_color_swizzle)
+ || (self.ext_buffer_device_address && other.ext_buffer_device_address)
+ || (self.ext_calibrated_timestamps && other.ext_calibrated_timestamps)
+ || (self.ext_color_write_enable && other.ext_color_write_enable)
+ || (self.ext_conditional_rendering && other.ext_conditional_rendering)
+ || (self.ext_conservative_rasterization && other.ext_conservative_rasterization)
+ || (self.ext_custom_border_color && other.ext_custom_border_color)
+ || (self.ext_debug_marker && other.ext_debug_marker)
+ || (self.ext_depth_clamp_zero_one && other.ext_depth_clamp_zero_one)
+ || (self.ext_depth_clip_control && other.ext_depth_clip_control)
+ || (self.ext_depth_clip_enable && other.ext_depth_clip_enable)
+ || (self.ext_depth_range_unrestricted && other.ext_depth_range_unrestricted)
+ || (self.ext_descriptor_buffer && other.ext_descriptor_buffer)
+ || (self.ext_descriptor_indexing && other.ext_descriptor_indexing)
+ || (self.ext_device_address_binding_report && other.ext_device_address_binding_report)
+ || (self.ext_device_fault && other.ext_device_fault)
+ || (self.ext_device_memory_report && other.ext_device_memory_report)
+ || (self.ext_discard_rectangles && other.ext_discard_rectangles)
+ || (self.ext_display_control && other.ext_display_control)
+ || (self.ext_extended_dynamic_state && other.ext_extended_dynamic_state)
+ || (self.ext_extended_dynamic_state2 && other.ext_extended_dynamic_state2)
+ || (self.ext_extended_dynamic_state3 && other.ext_extended_dynamic_state3)
+ || (self.ext_external_memory_dma_buf && other.ext_external_memory_dma_buf)
+ || (self.ext_external_memory_host && other.ext_external_memory_host)
+ || (self.ext_filter_cubic && other.ext_filter_cubic)
+ || (self.ext_fragment_density_map && other.ext_fragment_density_map)
+ || (self.ext_fragment_density_map2 && other.ext_fragment_density_map2)
+ || (self.ext_fragment_shader_interlock && other.ext_fragment_shader_interlock)
+ || (self.ext_full_screen_exclusive && other.ext_full_screen_exclusive)
+ || (self.ext_global_priority && other.ext_global_priority)
+ || (self.ext_global_priority_query && other.ext_global_priority_query)
+ || (self.ext_graphics_pipeline_library && other.ext_graphics_pipeline_library)
+ || (self.ext_hdr_metadata && other.ext_hdr_metadata)
+ || (self.ext_host_query_reset && other.ext_host_query_reset)
+ || (self.ext_image_2d_view_of_3d && other.ext_image_2d_view_of_3d)
+ || (self.ext_image_compression_control && other.ext_image_compression_control)
+ || (self.ext_image_compression_control_swapchain
+ && other.ext_image_compression_control_swapchain)
+ || (self.ext_image_drm_format_modifier && other.ext_image_drm_format_modifier)
+ || (self.ext_image_robustness && other.ext_image_robustness)
+ || (self.ext_image_view_min_lod && other.ext_image_view_min_lod)
+ || (self.ext_index_type_uint8 && other.ext_index_type_uint8)
+ || (self.ext_inline_uniform_block && other.ext_inline_uniform_block)
+ || (self.ext_legacy_dithering && other.ext_legacy_dithering)
+ || (self.ext_line_rasterization && other.ext_line_rasterization)
+ || (self.ext_load_store_op_none && other.ext_load_store_op_none)
+ || (self.ext_memory_budget && other.ext_memory_budget)
+ || (self.ext_memory_priority && other.ext_memory_priority)
+ || (self.ext_mesh_shader && other.ext_mesh_shader)
+ || (self.ext_metal_objects && other.ext_metal_objects)
+ || (self.ext_multi_draw && other.ext_multi_draw)
+ || (self.ext_multisampled_render_to_single_sampled
+ && other.ext_multisampled_render_to_single_sampled)
+ || (self.ext_mutable_descriptor_type && other.ext_mutable_descriptor_type)
+ || (self.ext_non_seamless_cube_map && other.ext_non_seamless_cube_map)
+ || (self.ext_opacity_micromap && other.ext_opacity_micromap)
+ || (self.ext_pageable_device_local_memory && other.ext_pageable_device_local_memory)
+ || (self.ext_pci_bus_info && other.ext_pci_bus_info)
+ || (self.ext_physical_device_drm && other.ext_physical_device_drm)
+ || (self.ext_pipeline_creation_cache_control
+ && other.ext_pipeline_creation_cache_control)
+ || (self.ext_pipeline_creation_feedback && other.ext_pipeline_creation_feedback)
+ || (self.ext_pipeline_properties && other.ext_pipeline_properties)
+ || (self.ext_pipeline_protected_access && other.ext_pipeline_protected_access)
+ || (self.ext_pipeline_robustness && other.ext_pipeline_robustness)
+ || (self.ext_post_depth_coverage && other.ext_post_depth_coverage)
+ || (self.ext_primitive_topology_list_restart
+ && other.ext_primitive_topology_list_restart)
+ || (self.ext_primitives_generated_query && other.ext_primitives_generated_query)
+ || (self.ext_private_data && other.ext_private_data)
+ || (self.ext_provoking_vertex && other.ext_provoking_vertex)
+ || (self.ext_queue_family_foreign && other.ext_queue_family_foreign)
+ || (self.ext_rasterization_order_attachment_access
+ && other.ext_rasterization_order_attachment_access)
+ || (self.ext_rgba10x6_formats && other.ext_rgba10x6_formats)
+ || (self.ext_robustness2 && other.ext_robustness2)
+ || (self.ext_sample_locations && other.ext_sample_locations)
+ || (self.ext_sampler_filter_minmax && other.ext_sampler_filter_minmax)
+ || (self.ext_scalar_block_layout && other.ext_scalar_block_layout)
+ || (self.ext_separate_stencil_usage && other.ext_separate_stencil_usage)
+ || (self.ext_shader_atomic_float && other.ext_shader_atomic_float)
+ || (self.ext_shader_atomic_float2 && other.ext_shader_atomic_float2)
+ || (self.ext_shader_demote_to_helper_invocation
+ && other.ext_shader_demote_to_helper_invocation)
+ || (self.ext_shader_image_atomic_int64 && other.ext_shader_image_atomic_int64)
+ || (self.ext_shader_module_identifier && other.ext_shader_module_identifier)
+ || (self.ext_shader_stencil_export && other.ext_shader_stencil_export)
+ || (self.ext_shader_subgroup_ballot && other.ext_shader_subgroup_ballot)
+ || (self.ext_shader_subgroup_vote && other.ext_shader_subgroup_vote)
+ || (self.ext_shader_viewport_index_layer && other.ext_shader_viewport_index_layer)
+ || (self.ext_subgroup_size_control && other.ext_subgroup_size_control)
+ || (self.ext_subpass_merge_feedback && other.ext_subpass_merge_feedback)
+ || (self.ext_swapchain_maintenance1 && other.ext_swapchain_maintenance1)
+ || (self.ext_texel_buffer_alignment && other.ext_texel_buffer_alignment)
+ || (self.ext_texture_compression_astc_hdr && other.ext_texture_compression_astc_hdr)
+ || (self.ext_tooling_info && other.ext_tooling_info)
+ || (self.ext_transform_feedback && other.ext_transform_feedback)
+ || (self.ext_validation_cache && other.ext_validation_cache)
+ || (self.ext_vertex_attribute_divisor && other.ext_vertex_attribute_divisor)
+ || (self.ext_vertex_input_dynamic_state && other.ext_vertex_input_dynamic_state)
+ || (self.ext_video_encode_h264 && other.ext_video_encode_h264)
+ || (self.ext_video_encode_h265 && other.ext_video_encode_h265)
+ || (self.ext_ycbcr_2plane_444_formats && other.ext_ycbcr_2plane_444_formats)
+ || (self.ext_ycbcr_image_arrays && other.ext_ycbcr_image_arrays)
+ || (self.amd_buffer_marker && other.amd_buffer_marker)
+ || (self.amd_device_coherent_memory && other.amd_device_coherent_memory)
+ || (self.amd_display_native_hdr && other.amd_display_native_hdr)
+ || (self.amd_draw_indirect_count && other.amd_draw_indirect_count)
+ || (self.amd_gcn_shader && other.amd_gcn_shader)
+ || (self.amd_gpu_shader_half_float && other.amd_gpu_shader_half_float)
+ || (self.amd_gpu_shader_int16 && other.amd_gpu_shader_int16)
+ || (self.amd_memory_overallocation_behavior && other.amd_memory_overallocation_behavior)
+ || (self.amd_mixed_attachment_samples && other.amd_mixed_attachment_samples)
+ || (self.amd_pipeline_compiler_control && other.amd_pipeline_compiler_control)
+ || (self.amd_rasterization_order && other.amd_rasterization_order)
+ || (self.amd_shader_ballot && other.amd_shader_ballot)
+ || (self.amd_shader_core_properties && other.amd_shader_core_properties)
+ || (self.amd_shader_core_properties2 && other.amd_shader_core_properties2)
+ || (self.amd_shader_early_and_late_fragment_tests
+ && other.amd_shader_early_and_late_fragment_tests)
+ || (self.amd_shader_explicit_vertex_parameter
+ && other.amd_shader_explicit_vertex_parameter)
+ || (self.amd_shader_fragment_mask && other.amd_shader_fragment_mask)
+ || (self.amd_shader_image_load_store_lod && other.amd_shader_image_load_store_lod)
+ || (self.amd_shader_info && other.amd_shader_info)
+ || (self.amd_shader_trinary_minmax && other.amd_shader_trinary_minmax)
+ || (self.amd_texture_gather_bias_lod && other.amd_texture_gather_bias_lod)
+ || (self.android_external_memory_android_hardware_buffer
+ && other.android_external_memory_android_hardware_buffer)
+ || (self.arm_rasterization_order_attachment_access
+ && other.arm_rasterization_order_attachment_access)
+ || (self.arm_shader_core_builtins && other.arm_shader_core_builtins)
+ || (self.fuchsia_buffer_collection && other.fuchsia_buffer_collection)
+ || (self.fuchsia_external_memory && other.fuchsia_external_memory)
+ || (self.fuchsia_external_semaphore && other.fuchsia_external_semaphore)
+ || (self.ggp_frame_token && other.ggp_frame_token)
+ || (self.google_decorate_string && other.google_decorate_string)
+ || (self.google_display_timing && other.google_display_timing)
+ || (self.google_hlsl_functionality1 && other.google_hlsl_functionality1)
+ || (self.google_user_type && other.google_user_type)
+ || (self.huawei_invocation_mask && other.huawei_invocation_mask)
+ || (self.huawei_subpass_shading && other.huawei_subpass_shading)
+ || (self.img_filter_cubic && other.img_filter_cubic)
+ || (self.img_format_pvrtc && other.img_format_pvrtc)
+ || (self.intel_performance_query && other.intel_performance_query)
+ || (self.intel_shader_integer_functions2 && other.intel_shader_integer_functions2)
+ || (self.nvx_binary_import && other.nvx_binary_import)
+ || (self.nvx_image_view_handle && other.nvx_image_view_handle)
+ || (self.nvx_multiview_per_view_attributes && other.nvx_multiview_per_view_attributes)
+ || (self.nv_acquire_winrt_display && other.nv_acquire_winrt_display)
+ || (self.nv_clip_space_w_scaling && other.nv_clip_space_w_scaling)
+ || (self.nv_compute_shader_derivatives && other.nv_compute_shader_derivatives)
+ || (self.nv_cooperative_matrix && other.nv_cooperative_matrix)
+ || (self.nv_copy_memory_indirect && other.nv_copy_memory_indirect)
+ || (self.nv_corner_sampled_image && other.nv_corner_sampled_image)
+ || (self.nv_coverage_reduction_mode && other.nv_coverage_reduction_mode)
+ || (self.nv_dedicated_allocation && other.nv_dedicated_allocation)
+ || (self.nv_dedicated_allocation_image_aliasing
+ && other.nv_dedicated_allocation_image_aliasing)
+ || (self.nv_device_diagnostic_checkpoints && other.nv_device_diagnostic_checkpoints)
+ || (self.nv_device_diagnostics_config && other.nv_device_diagnostics_config)
+ || (self.nv_device_generated_commands && other.nv_device_generated_commands)
+ || (self.nv_external_memory && other.nv_external_memory)
+ || (self.nv_external_memory_rdma && other.nv_external_memory_rdma)
+ || (self.nv_external_memory_win32 && other.nv_external_memory_win32)
+ || (self.nv_fill_rectangle && other.nv_fill_rectangle)
+ || (self.nv_fragment_coverage_to_color && other.nv_fragment_coverage_to_color)
+ || (self.nv_fragment_shader_barycentric && other.nv_fragment_shader_barycentric)
+ || (self.nv_fragment_shading_rate_enums && other.nv_fragment_shading_rate_enums)
+ || (self.nv_framebuffer_mixed_samples && other.nv_framebuffer_mixed_samples)
+ || (self.nv_geometry_shader_passthrough && other.nv_geometry_shader_passthrough)
+ || (self.nv_glsl_shader && other.nv_glsl_shader)
+ || (self.nv_inherited_viewport_scissor && other.nv_inherited_viewport_scissor)
+ || (self.nv_linear_color_attachment && other.nv_linear_color_attachment)
+ || (self.nv_memory_decompression && other.nv_memory_decompression)
+ || (self.nv_mesh_shader && other.nv_mesh_shader)
+ || (self.nv_optical_flow && other.nv_optical_flow)
+ || (self.nv_present_barrier && other.nv_present_barrier)
+ || (self.nv_ray_tracing && other.nv_ray_tracing)
+ || (self.nv_ray_tracing_invocation_reorder && other.nv_ray_tracing_invocation_reorder)
+ || (self.nv_ray_tracing_motion_blur && other.nv_ray_tracing_motion_blur)
+ || (self.nv_representative_fragment_test && other.nv_representative_fragment_test)
+ || (self.nv_sample_mask_override_coverage && other.nv_sample_mask_override_coverage)
+ || (self.nv_scissor_exclusive && other.nv_scissor_exclusive)
+ || (self.nv_shader_image_footprint && other.nv_shader_image_footprint)
+ || (self.nv_shader_sm_builtins && other.nv_shader_sm_builtins)
+ || (self.nv_shader_subgroup_partitioned && other.nv_shader_subgroup_partitioned)
+ || (self.nv_shading_rate_image && other.nv_shading_rate_image)
+ || (self.nv_viewport_array2 && other.nv_viewport_array2)
+ || (self.nv_viewport_swizzle && other.nv_viewport_swizzle)
+ || (self.nv_win32_keyed_mutex && other.nv_win32_keyed_mutex)
+ || (self.qcom_fragment_density_map_offset && other.qcom_fragment_density_map_offset)
+ || (self.qcom_image_processing && other.qcom_image_processing)
+ || (self.qcom_multiview_per_view_viewports && other.qcom_multiview_per_view_viewports)
+ || (self.qcom_render_pass_shader_resolve && other.qcom_render_pass_shader_resolve)
+ || (self.qcom_render_pass_store_ops && other.qcom_render_pass_store_ops)
+ || (self.qcom_render_pass_transform && other.qcom_render_pass_transform)
+ || (self.qcom_rotated_copy_commands && other.qcom_rotated_copy_commands)
+ || (self.qcom_tile_properties && other.qcom_tile_properties)
+ || (self.sec_amigo_profiling && other.sec_amigo_profiling)
+ || (self.valve_descriptor_set_host_mapping && other.valve_descriptor_set_host_mapping)
+ || (self.valve_mutable_descriptor_type && other.valve_mutable_descriptor_type)
+ }
+ #[doc = r" Returns whether all members in `other` are set in `self`."]
+ #[inline]
+ pub const fn contains(&self, other: &Self) -> bool {
+ (self.khr_16bit_storage || !other.khr_16bit_storage)
+ && (self.khr_8bit_storage || !other.khr_8bit_storage)
+ && (self.khr_acceleration_structure || !other.khr_acceleration_structure)
+ && (self.khr_bind_memory2 || !other.khr_bind_memory2)
+ && (self.khr_buffer_device_address || !other.khr_buffer_device_address)
+ && (self.khr_copy_commands2 || !other.khr_copy_commands2)
+ && (self.khr_create_renderpass2 || !other.khr_create_renderpass2)
+ && (self.khr_dedicated_allocation || !other.khr_dedicated_allocation)
+ && (self.khr_deferred_host_operations || !other.khr_deferred_host_operations)
+ && (self.khr_depth_stencil_resolve || !other.khr_depth_stencil_resolve)
+ && (self.khr_descriptor_update_template || !other.khr_descriptor_update_template)
+ && (self.khr_device_group || !other.khr_device_group)
+ && (self.khr_display_swapchain || !other.khr_display_swapchain)
+ && (self.khr_draw_indirect_count || !other.khr_draw_indirect_count)
+ && (self.khr_driver_properties || !other.khr_driver_properties)
+ && (self.khr_dynamic_rendering || !other.khr_dynamic_rendering)
+ && (self.khr_external_fence || !other.khr_external_fence)
+ && (self.khr_external_fence_fd || !other.khr_external_fence_fd)
+ && (self.khr_external_fence_win32 || !other.khr_external_fence_win32)
+ && (self.khr_external_memory || !other.khr_external_memory)
+ && (self.khr_external_memory_fd || !other.khr_external_memory_fd)
+ && (self.khr_external_memory_win32 || !other.khr_external_memory_win32)
+ && (self.khr_external_semaphore || !other.khr_external_semaphore)
+ && (self.khr_external_semaphore_fd || !other.khr_external_semaphore_fd)
+ && (self.khr_external_semaphore_win32 || !other.khr_external_semaphore_win32)
+ && (self.khr_format_feature_flags2 || !other.khr_format_feature_flags2)
+ && (self.khr_fragment_shader_barycentric || !other.khr_fragment_shader_barycentric)
+ && (self.khr_fragment_shading_rate || !other.khr_fragment_shading_rate)
+ && (self.khr_get_memory_requirements2 || !other.khr_get_memory_requirements2)
+ && (self.khr_global_priority || !other.khr_global_priority)
+ && (self.khr_image_format_list || !other.khr_image_format_list)
+ && (self.khr_imageless_framebuffer || !other.khr_imageless_framebuffer)
+ && (self.khr_incremental_present || !other.khr_incremental_present)
+ && (self.khr_maintenance1 || !other.khr_maintenance1)
+ && (self.khr_maintenance2 || !other.khr_maintenance2)
+ && (self.khr_maintenance3 || !other.khr_maintenance3)
+ && (self.khr_maintenance4 || !other.khr_maintenance4)
+ && (self.khr_multiview || !other.khr_multiview)
+ && (self.khr_performance_query || !other.khr_performance_query)
+ && (self.khr_pipeline_executable_properties
+ || !other.khr_pipeline_executable_properties)
+ && (self.khr_pipeline_library || !other.khr_pipeline_library)
+ && (self.khr_portability_subset || !other.khr_portability_subset)
+ && (self.khr_present_id || !other.khr_present_id)
+ && (self.khr_present_wait || !other.khr_present_wait)
+ && (self.khr_push_descriptor || !other.khr_push_descriptor)
+ && (self.khr_ray_query || !other.khr_ray_query)
+ && (self.khr_ray_tracing_maintenance1 || !other.khr_ray_tracing_maintenance1)
+ && (self.khr_ray_tracing_pipeline || !other.khr_ray_tracing_pipeline)
+ && (self.khr_relaxed_block_layout || !other.khr_relaxed_block_layout)
+ && (self.khr_sampler_mirror_clamp_to_edge || !other.khr_sampler_mirror_clamp_to_edge)
+ && (self.khr_sampler_ycbcr_conversion || !other.khr_sampler_ycbcr_conversion)
+ && (self.khr_separate_depth_stencil_layouts
+ || !other.khr_separate_depth_stencil_layouts)
+ && (self.khr_shader_atomic_int64 || !other.khr_shader_atomic_int64)
+ && (self.khr_shader_clock || !other.khr_shader_clock)
+ && (self.khr_shader_draw_parameters || !other.khr_shader_draw_parameters)
+ && (self.khr_shader_float16_int8 || !other.khr_shader_float16_int8)
+ && (self.khr_shader_float_controls || !other.khr_shader_float_controls)
+ && (self.khr_shader_integer_dot_product || !other.khr_shader_integer_dot_product)
+ && (self.khr_shader_non_semantic_info || !other.khr_shader_non_semantic_info)
+ && (self.khr_shader_subgroup_extended_types
+ || !other.khr_shader_subgroup_extended_types)
+ && (self.khr_shader_subgroup_uniform_control_flow
+ || !other.khr_shader_subgroup_uniform_control_flow)
+ && (self.khr_shader_terminate_invocation || !other.khr_shader_terminate_invocation)
+ && (self.khr_shared_presentable_image || !other.khr_shared_presentable_image)
+ && (self.khr_spirv_1_4 || !other.khr_spirv_1_4)
+ && (self.khr_storage_buffer_storage_class || !other.khr_storage_buffer_storage_class)
+ && (self.khr_swapchain || !other.khr_swapchain)
+ && (self.khr_swapchain_mutable_format || !other.khr_swapchain_mutable_format)
+ && (self.khr_synchronization2 || !other.khr_synchronization2)
+ && (self.khr_timeline_semaphore || !other.khr_timeline_semaphore)
+ && (self.khr_uniform_buffer_standard_layout
+ || !other.khr_uniform_buffer_standard_layout)
+ && (self.khr_variable_pointers || !other.khr_variable_pointers)
+ && (self.khr_video_decode_h264 || !other.khr_video_decode_h264)
+ && (self.khr_video_decode_h265 || !other.khr_video_decode_h265)
+ && (self.khr_video_decode_queue || !other.khr_video_decode_queue)
+ && (self.khr_video_encode_queue || !other.khr_video_encode_queue)
+ && (self.khr_video_queue || !other.khr_video_queue)
+ && (self.khr_vulkan_memory_model || !other.khr_vulkan_memory_model)
+ && (self.khr_win32_keyed_mutex || !other.khr_win32_keyed_mutex)
+ && (self.khr_workgroup_memory_explicit_layout
+ || !other.khr_workgroup_memory_explicit_layout)
+ && (self.khr_zero_initialize_workgroup_memory
+ || !other.khr_zero_initialize_workgroup_memory)
+ && (self.ext_4444_formats || !other.ext_4444_formats)
+ && (self.ext_astc_decode_mode || !other.ext_astc_decode_mode)
+ && (self.ext_attachment_feedback_loop_layout
+ || !other.ext_attachment_feedback_loop_layout)
+ && (self.ext_blend_operation_advanced || !other.ext_blend_operation_advanced)
+ && (self.ext_border_color_swizzle || !other.ext_border_color_swizzle)
+ && (self.ext_buffer_device_address || !other.ext_buffer_device_address)
+ && (self.ext_calibrated_timestamps || !other.ext_calibrated_timestamps)
+ && (self.ext_color_write_enable || !other.ext_color_write_enable)
+ && (self.ext_conditional_rendering || !other.ext_conditional_rendering)
+ && (self.ext_conservative_rasterization || !other.ext_conservative_rasterization)
+ && (self.ext_custom_border_color || !other.ext_custom_border_color)
+ && (self.ext_debug_marker || !other.ext_debug_marker)
+ && (self.ext_depth_clamp_zero_one || !other.ext_depth_clamp_zero_one)
+ && (self.ext_depth_clip_control || !other.ext_depth_clip_control)
+ && (self.ext_depth_clip_enable || !other.ext_depth_clip_enable)
+ && (self.ext_depth_range_unrestricted || !other.ext_depth_range_unrestricted)
+ && (self.ext_descriptor_buffer || !other.ext_descriptor_buffer)
+ && (self.ext_descriptor_indexing || !other.ext_descriptor_indexing)
+ && (self.ext_device_address_binding_report || !other.ext_device_address_binding_report)
+ && (self.ext_device_fault || !other.ext_device_fault)
+ && (self.ext_device_memory_report || !other.ext_device_memory_report)
+ && (self.ext_discard_rectangles || !other.ext_discard_rectangles)
+ && (self.ext_display_control || !other.ext_display_control)
+ && (self.ext_extended_dynamic_state || !other.ext_extended_dynamic_state)
+ && (self.ext_extended_dynamic_state2 || !other.ext_extended_dynamic_state2)
+ && (self.ext_extended_dynamic_state3 || !other.ext_extended_dynamic_state3)
+ && (self.ext_external_memory_dma_buf || !other.ext_external_memory_dma_buf)
+ && (self.ext_external_memory_host || !other.ext_external_memory_host)
+ && (self.ext_filter_cubic || !other.ext_filter_cubic)
+ && (self.ext_fragment_density_map || !other.ext_fragment_density_map)
+ && (self.ext_fragment_density_map2 || !other.ext_fragment_density_map2)
+ && (self.ext_fragment_shader_interlock || !other.ext_fragment_shader_interlock)
+ && (self.ext_full_screen_exclusive || !other.ext_full_screen_exclusive)
+ && (self.ext_global_priority || !other.ext_global_priority)
+ && (self.ext_global_priority_query || !other.ext_global_priority_query)
+ && (self.ext_graphics_pipeline_library || !other.ext_graphics_pipeline_library)
+ && (self.ext_hdr_metadata || !other.ext_hdr_metadata)
+ && (self.ext_host_query_reset || !other.ext_host_query_reset)
+ && (self.ext_image_2d_view_of_3d || !other.ext_image_2d_view_of_3d)
+ && (self.ext_image_compression_control || !other.ext_image_compression_control)
+ && (self.ext_image_compression_control_swapchain
+ || !other.ext_image_compression_control_swapchain)
+ && (self.ext_image_drm_format_modifier || !other.ext_image_drm_format_modifier)
+ && (self.ext_image_robustness || !other.ext_image_robustness)
+ && (self.ext_image_view_min_lod || !other.ext_image_view_min_lod)
+ && (self.ext_index_type_uint8 || !other.ext_index_type_uint8)
+ && (self.ext_inline_uniform_block || !other.ext_inline_uniform_block)
+ && (self.ext_legacy_dithering || !other.ext_legacy_dithering)
+ && (self.ext_line_rasterization || !other.ext_line_rasterization)
+ && (self.ext_load_store_op_none || !other.ext_load_store_op_none)
+ && (self.ext_memory_budget || !other.ext_memory_budget)
+ && (self.ext_memory_priority || !other.ext_memory_priority)
+ && (self.ext_mesh_shader || !other.ext_mesh_shader)
+ && (self.ext_metal_objects || !other.ext_metal_objects)
+ && (self.ext_multi_draw || !other.ext_multi_draw)
+ && (self.ext_multisampled_render_to_single_sampled
+ || !other.ext_multisampled_render_to_single_sampled)
+ && (self.ext_mutable_descriptor_type || !other.ext_mutable_descriptor_type)
+ && (self.ext_non_seamless_cube_map || !other.ext_non_seamless_cube_map)
+ && (self.ext_opacity_micromap || !other.ext_opacity_micromap)
+ && (self.ext_pageable_device_local_memory || !other.ext_pageable_device_local_memory)
+ && (self.ext_pci_bus_info || !other.ext_pci_bus_info)
+ && (self.ext_physical_device_drm || !other.ext_physical_device_drm)
+ && (self.ext_pipeline_creation_cache_control
+ || !other.ext_pipeline_creation_cache_control)
+ && (self.ext_pipeline_creation_feedback || !other.ext_pipeline_creation_feedback)
+ && (self.ext_pipeline_properties || !other.ext_pipeline_properties)
+ && (self.ext_pipeline_protected_access || !other.ext_pipeline_protected_access)
+ && (self.ext_pipeline_robustness || !other.ext_pipeline_robustness)
+ && (self.ext_post_depth_coverage || !other.ext_post_depth_coverage)
+ && (self.ext_primitive_topology_list_restart
+ || !other.ext_primitive_topology_list_restart)
+ && (self.ext_primitives_generated_query || !other.ext_primitives_generated_query)
+ && (self.ext_private_data || !other.ext_private_data)
+ && (self.ext_provoking_vertex || !other.ext_provoking_vertex)
+ && (self.ext_queue_family_foreign || !other.ext_queue_family_foreign)
+ && (self.ext_rasterization_order_attachment_access
+ || !other.ext_rasterization_order_attachment_access)
+ && (self.ext_rgba10x6_formats || !other.ext_rgba10x6_formats)
+ && (self.ext_robustness2 || !other.ext_robustness2)
+ && (self.ext_sample_locations || !other.ext_sample_locations)
+ && (self.ext_sampler_filter_minmax || !other.ext_sampler_filter_minmax)
+ && (self.ext_scalar_block_layout || !other.ext_scalar_block_layout)
+ && (self.ext_separate_stencil_usage || !other.ext_separate_stencil_usage)
+ && (self.ext_shader_atomic_float || !other.ext_shader_atomic_float)
+ && (self.ext_shader_atomic_float2 || !other.ext_shader_atomic_float2)
+ && (self.ext_shader_demote_to_helper_invocation
+ || !other.ext_shader_demote_to_helper_invocation)
+ && (self.ext_shader_image_atomic_int64 || !other.ext_shader_image_atomic_int64)
+ && (self.ext_shader_module_identifier || !other.ext_shader_module_identifier)
+ && (self.ext_shader_stencil_export || !other.ext_shader_stencil_export)
+ && (self.ext_shader_subgroup_ballot || !other.ext_shader_subgroup_ballot)
+ && (self.ext_shader_subgroup_vote || !other.ext_shader_subgroup_vote)
+ && (self.ext_shader_viewport_index_layer || !other.ext_shader_viewport_index_layer)
+ && (self.ext_subgroup_size_control || !other.ext_subgroup_size_control)
+ && (self.ext_subpass_merge_feedback || !other.ext_subpass_merge_feedback)
+ && (self.ext_swapchain_maintenance1 || !other.ext_swapchain_maintenance1)
+ && (self.ext_texel_buffer_alignment || !other.ext_texel_buffer_alignment)
+ && (self.ext_texture_compression_astc_hdr || !other.ext_texture_compression_astc_hdr)
+ && (self.ext_tooling_info || !other.ext_tooling_info)
+ && (self.ext_transform_feedback || !other.ext_transform_feedback)
+ && (self.ext_validation_cache || !other.ext_validation_cache)
+ && (self.ext_vertex_attribute_divisor || !other.ext_vertex_attribute_divisor)
+ && (self.ext_vertex_input_dynamic_state || !other.ext_vertex_input_dynamic_state)
+ && (self.ext_video_encode_h264 || !other.ext_video_encode_h264)
+ && (self.ext_video_encode_h265 || !other.ext_video_encode_h265)
+ && (self.ext_ycbcr_2plane_444_formats || !other.ext_ycbcr_2plane_444_formats)
+ && (self.ext_ycbcr_image_arrays || !other.ext_ycbcr_image_arrays)
+ && (self.amd_buffer_marker || !other.amd_buffer_marker)
+ && (self.amd_device_coherent_memory || !other.amd_device_coherent_memory)
+ && (self.amd_display_native_hdr || !other.amd_display_native_hdr)
+ && (self.amd_draw_indirect_count || !other.amd_draw_indirect_count)
+ && (self.amd_gcn_shader || !other.amd_gcn_shader)
+ && (self.amd_gpu_shader_half_float || !other.amd_gpu_shader_half_float)
+ && (self.amd_gpu_shader_int16 || !other.amd_gpu_shader_int16)
+ && (self.amd_memory_overallocation_behavior
+ || !other.amd_memory_overallocation_behavior)
+ && (self.amd_mixed_attachment_samples || !other.amd_mixed_attachment_samples)
+ && (self.amd_pipeline_compiler_control || !other.amd_pipeline_compiler_control)
+ && (self.amd_rasterization_order || !other.amd_rasterization_order)
+ && (self.amd_shader_ballot || !other.amd_shader_ballot)
+ && (self.amd_shader_core_properties || !other.amd_shader_core_properties)
+ && (self.amd_shader_core_properties2 || !other.amd_shader_core_properties2)
+ && (self.amd_shader_early_and_late_fragment_tests
+ || !other.amd_shader_early_and_late_fragment_tests)
+ && (self.amd_shader_explicit_vertex_parameter
+ || !other.amd_shader_explicit_vertex_parameter)
+ && (self.amd_shader_fragment_mask || !other.amd_shader_fragment_mask)
+ && (self.amd_shader_image_load_store_lod || !other.amd_shader_image_load_store_lod)
+ && (self.amd_shader_info || !other.amd_shader_info)
+ && (self.amd_shader_trinary_minmax || !other.amd_shader_trinary_minmax)
+ && (self.amd_texture_gather_bias_lod || !other.amd_texture_gather_bias_lod)
+ && (self.android_external_memory_android_hardware_buffer
+ || !other.android_external_memory_android_hardware_buffer)
+ && (self.arm_rasterization_order_attachment_access
+ || !other.arm_rasterization_order_attachment_access)
+ && (self.arm_shader_core_builtins || !other.arm_shader_core_builtins)
+ && (self.fuchsia_buffer_collection || !other.fuchsia_buffer_collection)
+ && (self.fuchsia_external_memory || !other.fuchsia_external_memory)
+ && (self.fuchsia_external_semaphore || !other.fuchsia_external_semaphore)
+ && (self.ggp_frame_token || !other.ggp_frame_token)
+ && (self.google_decorate_string || !other.google_decorate_string)
+ && (self.google_display_timing || !other.google_display_timing)
+ && (self.google_hlsl_functionality1 || !other.google_hlsl_functionality1)
+ && (self.google_user_type || !other.google_user_type)
+ && (self.huawei_invocation_mask || !other.huawei_invocation_mask)
+ && (self.huawei_subpass_shading || !other.huawei_subpass_shading)
+ && (self.img_filter_cubic || !other.img_filter_cubic)
+ && (self.img_format_pvrtc || !other.img_format_pvrtc)
+ && (self.intel_performance_query || !other.intel_performance_query)
+ && (self.intel_shader_integer_functions2 || !other.intel_shader_integer_functions2)
+ && (self.nvx_binary_import || !other.nvx_binary_import)
+ && (self.nvx_image_view_handle || !other.nvx_image_view_handle)
+ && (self.nvx_multiview_per_view_attributes || !other.nvx_multiview_per_view_attributes)
+ && (self.nv_acquire_winrt_display || !other.nv_acquire_winrt_display)
+ && (self.nv_clip_space_w_scaling || !other.nv_clip_space_w_scaling)
+ && (self.nv_compute_shader_derivatives || !other.nv_compute_shader_derivatives)
+ && (self.nv_cooperative_matrix || !other.nv_cooperative_matrix)
+ && (self.nv_copy_memory_indirect || !other.nv_copy_memory_indirect)
+ && (self.nv_corner_sampled_image || !other.nv_corner_sampled_image)
+ && (self.nv_coverage_reduction_mode || !other.nv_coverage_reduction_mode)
+ && (self.nv_dedicated_allocation || !other.nv_dedicated_allocation)
+ && (self.nv_dedicated_allocation_image_aliasing
+ || !other.nv_dedicated_allocation_image_aliasing)
+ && (self.nv_device_diagnostic_checkpoints || !other.nv_device_diagnostic_checkpoints)
+ && (self.nv_device_diagnostics_config || !other.nv_device_diagnostics_config)
+ && (self.nv_device_generated_commands || !other.nv_device_generated_commands)
+ && (self.nv_external_memory || !other.nv_external_memory)
+ && (self.nv_external_memory_rdma || !other.nv_external_memory_rdma)
+ && (self.nv_external_memory_win32 || !other.nv_external_memory_win32)
+ && (self.nv_fill_rectangle || !other.nv_fill_rectangle)
+ && (self.nv_fragment_coverage_to_color || !other.nv_fragment_coverage_to_color)
+ && (self.nv_fragment_shader_barycentric || !other.nv_fragment_shader_barycentric)
+ && (self.nv_fragment_shading_rate_enums || !other.nv_fragment_shading_rate_enums)
+ && (self.nv_framebuffer_mixed_samples || !other.nv_framebuffer_mixed_samples)
+ && (self.nv_geometry_shader_passthrough || !other.nv_geometry_shader_passthrough)
+ && (self.nv_glsl_shader || !other.nv_glsl_shader)
+ && (self.nv_inherited_viewport_scissor || !other.nv_inherited_viewport_scissor)
+ && (self.nv_linear_color_attachment || !other.nv_linear_color_attachment)
+ && (self.nv_memory_decompression || !other.nv_memory_decompression)
+ && (self.nv_mesh_shader || !other.nv_mesh_shader)
+ && (self.nv_optical_flow || !other.nv_optical_flow)
+ && (self.nv_present_barrier || !other.nv_present_barrier)
+ && (self.nv_ray_tracing || !other.nv_ray_tracing)
+ && (self.nv_ray_tracing_invocation_reorder || !other.nv_ray_tracing_invocation_reorder)
+ && (self.nv_ray_tracing_motion_blur || !other.nv_ray_tracing_motion_blur)
+ && (self.nv_representative_fragment_test || !other.nv_representative_fragment_test)
+ && (self.nv_sample_mask_override_coverage || !other.nv_sample_mask_override_coverage)
+ && (self.nv_scissor_exclusive || !other.nv_scissor_exclusive)
+ && (self.nv_shader_image_footprint || !other.nv_shader_image_footprint)
+ && (self.nv_shader_sm_builtins || !other.nv_shader_sm_builtins)
+ && (self.nv_shader_subgroup_partitioned || !other.nv_shader_subgroup_partitioned)
+ && (self.nv_shading_rate_image || !other.nv_shading_rate_image)
+ && (self.nv_viewport_array2 || !other.nv_viewport_array2)
+ && (self.nv_viewport_swizzle || !other.nv_viewport_swizzle)
+ && (self.nv_win32_keyed_mutex || !other.nv_win32_keyed_mutex)
+ && (self.qcom_fragment_density_map_offset || !other.qcom_fragment_density_map_offset)
+ && (self.qcom_image_processing || !other.qcom_image_processing)
+ && (self.qcom_multiview_per_view_viewports || !other.qcom_multiview_per_view_viewports)
+ && (self.qcom_render_pass_shader_resolve || !other.qcom_render_pass_shader_resolve)
+ && (self.qcom_render_pass_store_ops || !other.qcom_render_pass_store_ops)
+ && (self.qcom_render_pass_transform || !other.qcom_render_pass_transform)
+ && (self.qcom_rotated_copy_commands || !other.qcom_rotated_copy_commands)
+ && (self.qcom_tile_properties || !other.qcom_tile_properties)
+ && (self.sec_amigo_profiling || !other.sec_amigo_profiling)
+ && (self.valve_descriptor_set_host_mapping || !other.valve_descriptor_set_host_mapping)
+ && (self.valve_mutable_descriptor_type || !other.valve_mutable_descriptor_type)
+ }
+ #[doc = r" Returns whether all members in `other` are set in `self`."]
+ #[deprecated(since = "0.31.0", note = "Use `contains` instead.")]
+ #[inline]
+ pub const fn is_superset_of(&self, other: &Self) -> bool {
+ self.contains(other)
+ }
+ #[doc = r" Returns the union of `self` and `other`."]
+ #[inline]
+ pub const fn union(&self, other: &Self) -> Self {
+ Self {
+ khr_16bit_storage: self.khr_16bit_storage || other.khr_16bit_storage,
+ khr_8bit_storage: self.khr_8bit_storage || other.khr_8bit_storage,
+ khr_acceleration_structure: self.khr_acceleration_structure
+ || other.khr_acceleration_structure,
+ khr_bind_memory2: self.khr_bind_memory2 || other.khr_bind_memory2,
+ khr_buffer_device_address: self.khr_buffer_device_address
+ || other.khr_buffer_device_address,
+ khr_copy_commands2: self.khr_copy_commands2 || other.khr_copy_commands2,
+ khr_create_renderpass2: self.khr_create_renderpass2 || other.khr_create_renderpass2,
+ khr_dedicated_allocation: self.khr_dedicated_allocation
+ || other.khr_dedicated_allocation,
+ khr_deferred_host_operations: self.khr_deferred_host_operations
+ || other.khr_deferred_host_operations,
+ khr_depth_stencil_resolve: self.khr_depth_stencil_resolve
+ || other.khr_depth_stencil_resolve,
+ khr_descriptor_update_template: self.khr_descriptor_update_template
+ || other.khr_descriptor_update_template,
+ khr_device_group: self.khr_device_group || other.khr_device_group,
+ khr_display_swapchain: self.khr_display_swapchain || other.khr_display_swapchain,
+ khr_draw_indirect_count: self.khr_draw_indirect_count || other.khr_draw_indirect_count,
+ khr_driver_properties: self.khr_driver_properties || other.khr_driver_properties,
+ khr_dynamic_rendering: self.khr_dynamic_rendering || other.khr_dynamic_rendering,
+ khr_external_fence: self.khr_external_fence || other.khr_external_fence,
+ khr_external_fence_fd: self.khr_external_fence_fd || other.khr_external_fence_fd,
+ khr_external_fence_win32: self.khr_external_fence_win32
+ || other.khr_external_fence_win32,
+ khr_external_memory: self.khr_external_memory || other.khr_external_memory,
+ khr_external_memory_fd: self.khr_external_memory_fd || other.khr_external_memory_fd,
+ khr_external_memory_win32: self.khr_external_memory_win32
+ || other.khr_external_memory_win32,
+ khr_external_semaphore: self.khr_external_semaphore || other.khr_external_semaphore,
+ khr_external_semaphore_fd: self.khr_external_semaphore_fd
+ || other.khr_external_semaphore_fd,
+ khr_external_semaphore_win32: self.khr_external_semaphore_win32
+ || other.khr_external_semaphore_win32,
+ khr_format_feature_flags2: self.khr_format_feature_flags2
+ || other.khr_format_feature_flags2,
+ khr_fragment_shader_barycentric: self.khr_fragment_shader_barycentric
+ || other.khr_fragment_shader_barycentric,
+ khr_fragment_shading_rate: self.khr_fragment_shading_rate
+ || other.khr_fragment_shading_rate,
+ khr_get_memory_requirements2: self.khr_get_memory_requirements2
+ || other.khr_get_memory_requirements2,
+ khr_global_priority: self.khr_global_priority || other.khr_global_priority,
+ khr_image_format_list: self.khr_image_format_list || other.khr_image_format_list,
+ khr_imageless_framebuffer: self.khr_imageless_framebuffer
+ || other.khr_imageless_framebuffer,
+ khr_incremental_present: self.khr_incremental_present || other.khr_incremental_present,
+ khr_maintenance1: self.khr_maintenance1 || other.khr_maintenance1,
+ khr_maintenance2: self.khr_maintenance2 || other.khr_maintenance2,
+ khr_maintenance3: self.khr_maintenance3 || other.khr_maintenance3,
+ khr_maintenance4: self.khr_maintenance4 || other.khr_maintenance4,
+ khr_multiview: self.khr_multiview || other.khr_multiview,
+ khr_performance_query: self.khr_performance_query || other.khr_performance_query,
+ khr_pipeline_executable_properties: self.khr_pipeline_executable_properties
+ || other.khr_pipeline_executable_properties,
+ khr_pipeline_library: self.khr_pipeline_library || other.khr_pipeline_library,
+ khr_portability_subset: self.khr_portability_subset || other.khr_portability_subset,
+ khr_present_id: self.khr_present_id || other.khr_present_id,
+ khr_present_wait: self.khr_present_wait || other.khr_present_wait,
+ khr_push_descriptor: self.khr_push_descriptor || other.khr_push_descriptor,
+ khr_ray_query: self.khr_ray_query || other.khr_ray_query,
+ khr_ray_tracing_maintenance1: self.khr_ray_tracing_maintenance1
+ || other.khr_ray_tracing_maintenance1,
+ khr_ray_tracing_pipeline: self.khr_ray_tracing_pipeline
+ || other.khr_ray_tracing_pipeline,
+ khr_relaxed_block_layout: self.khr_relaxed_block_layout
+ || other.khr_relaxed_block_layout,
+ khr_sampler_mirror_clamp_to_edge: self.khr_sampler_mirror_clamp_to_edge
+ || other.khr_sampler_mirror_clamp_to_edge,
+ khr_sampler_ycbcr_conversion: self.khr_sampler_ycbcr_conversion
+ || other.khr_sampler_ycbcr_conversion,
+ khr_separate_depth_stencil_layouts: self.khr_separate_depth_stencil_layouts
+ || other.khr_separate_depth_stencil_layouts,
+ khr_shader_atomic_int64: self.khr_shader_atomic_int64 || other.khr_shader_atomic_int64,
+ khr_shader_clock: self.khr_shader_clock || other.khr_shader_clock,
+ khr_shader_draw_parameters: self.khr_shader_draw_parameters
+ || other.khr_shader_draw_parameters,
+ khr_shader_float16_int8: self.khr_shader_float16_int8 || other.khr_shader_float16_int8,
+ khr_shader_float_controls: self.khr_shader_float_controls
+ || other.khr_shader_float_controls,
+ khr_shader_integer_dot_product: self.khr_shader_integer_dot_product
+ || other.khr_shader_integer_dot_product,
+ khr_shader_non_semantic_info: self.khr_shader_non_semantic_info
+ || other.khr_shader_non_semantic_info,
+ khr_shader_subgroup_extended_types: self.khr_shader_subgroup_extended_types
+ || other.khr_shader_subgroup_extended_types,
+ khr_shader_subgroup_uniform_control_flow: self.khr_shader_subgroup_uniform_control_flow
+ || other.khr_shader_subgroup_uniform_control_flow,
+ khr_shader_terminate_invocation: self.khr_shader_terminate_invocation
+ || other.khr_shader_terminate_invocation,
+ khr_shared_presentable_image: self.khr_shared_presentable_image
+ || other.khr_shared_presentable_image,
+ khr_spirv_1_4: self.khr_spirv_1_4 || other.khr_spirv_1_4,
+ khr_storage_buffer_storage_class: self.khr_storage_buffer_storage_class
+ || other.khr_storage_buffer_storage_class,
+ khr_swapchain: self.khr_swapchain || other.khr_swapchain,
+ khr_swapchain_mutable_format: self.khr_swapchain_mutable_format
+ || other.khr_swapchain_mutable_format,
+ khr_synchronization2: self.khr_synchronization2 || other.khr_synchronization2,
+ khr_timeline_semaphore: self.khr_timeline_semaphore || other.khr_timeline_semaphore,
+ khr_uniform_buffer_standard_layout: self.khr_uniform_buffer_standard_layout
+ || other.khr_uniform_buffer_standard_layout,
+ khr_variable_pointers: self.khr_variable_pointers || other.khr_variable_pointers,
+ khr_video_decode_h264: self.khr_video_decode_h264 || other.khr_video_decode_h264,
+ khr_video_decode_h265: self.khr_video_decode_h265 || other.khr_video_decode_h265,
+ khr_video_decode_queue: self.khr_video_decode_queue || other.khr_video_decode_queue,
+ khr_video_encode_queue: self.khr_video_encode_queue || other.khr_video_encode_queue,
+ khr_video_queue: self.khr_video_queue || other.khr_video_queue,
+ khr_vulkan_memory_model: self.khr_vulkan_memory_model || other.khr_vulkan_memory_model,
+ khr_win32_keyed_mutex: self.khr_win32_keyed_mutex || other.khr_win32_keyed_mutex,
+ khr_workgroup_memory_explicit_layout: self.khr_workgroup_memory_explicit_layout
+ || other.khr_workgroup_memory_explicit_layout,
+ khr_zero_initialize_workgroup_memory: self.khr_zero_initialize_workgroup_memory
+ || other.khr_zero_initialize_workgroup_memory,
+ ext_4444_formats: self.ext_4444_formats || other.ext_4444_formats,
+ ext_astc_decode_mode: self.ext_astc_decode_mode || other.ext_astc_decode_mode,
+ ext_attachment_feedback_loop_layout: self.ext_attachment_feedback_loop_layout
+ || other.ext_attachment_feedback_loop_layout,
+ ext_blend_operation_advanced: self.ext_blend_operation_advanced
+ || other.ext_blend_operation_advanced,
+ ext_border_color_swizzle: self.ext_border_color_swizzle
+ || other.ext_border_color_swizzle,
+ ext_buffer_device_address: self.ext_buffer_device_address
+ || other.ext_buffer_device_address,
+ ext_calibrated_timestamps: self.ext_calibrated_timestamps
+ || other.ext_calibrated_timestamps,
+ ext_color_write_enable: self.ext_color_write_enable || other.ext_color_write_enable,
+ ext_conditional_rendering: self.ext_conditional_rendering
+ || other.ext_conditional_rendering,
+ ext_conservative_rasterization: self.ext_conservative_rasterization
+ || other.ext_conservative_rasterization,
+ ext_custom_border_color: self.ext_custom_border_color || other.ext_custom_border_color,
+ ext_debug_marker: self.ext_debug_marker || other.ext_debug_marker,
+ ext_depth_clamp_zero_one: self.ext_depth_clamp_zero_one
+ || other.ext_depth_clamp_zero_one,
+ ext_depth_clip_control: self.ext_depth_clip_control || other.ext_depth_clip_control,
+ ext_depth_clip_enable: self.ext_depth_clip_enable || other.ext_depth_clip_enable,
+ ext_depth_range_unrestricted: self.ext_depth_range_unrestricted
+ || other.ext_depth_range_unrestricted,
+ ext_descriptor_buffer: self.ext_descriptor_buffer || other.ext_descriptor_buffer,
+ ext_descriptor_indexing: self.ext_descriptor_indexing || other.ext_descriptor_indexing,
+ ext_device_address_binding_report: self.ext_device_address_binding_report
+ || other.ext_device_address_binding_report,
+ ext_device_fault: self.ext_device_fault || other.ext_device_fault,
+ ext_device_memory_report: self.ext_device_memory_report
+ || other.ext_device_memory_report,
+ ext_discard_rectangles: self.ext_discard_rectangles || other.ext_discard_rectangles,
+ ext_display_control: self.ext_display_control || other.ext_display_control,
+ ext_extended_dynamic_state: self.ext_extended_dynamic_state
+ || other.ext_extended_dynamic_state,
+ ext_extended_dynamic_state2: self.ext_extended_dynamic_state2
+ || other.ext_extended_dynamic_state2,
+ ext_extended_dynamic_state3: self.ext_extended_dynamic_state3
+ || other.ext_extended_dynamic_state3,
+ ext_external_memory_dma_buf: self.ext_external_memory_dma_buf
+ || other.ext_external_memory_dma_buf,
+ ext_external_memory_host: self.ext_external_memory_host
+ || other.ext_external_memory_host,
+ ext_filter_cubic: self.ext_filter_cubic || other.ext_filter_cubic,
+ ext_fragment_density_map: self.ext_fragment_density_map
+ || other.ext_fragment_density_map,
+ ext_fragment_density_map2: self.ext_fragment_density_map2
+ || other.ext_fragment_density_map2,
+ ext_fragment_shader_interlock: self.ext_fragment_shader_interlock
+ || other.ext_fragment_shader_interlock,
+ ext_full_screen_exclusive: self.ext_full_screen_exclusive
+ || other.ext_full_screen_exclusive,
+ ext_global_priority: self.ext_global_priority || other.ext_global_priority,
+ ext_global_priority_query: self.ext_global_priority_query
+ || other.ext_global_priority_query,
+ ext_graphics_pipeline_library: self.ext_graphics_pipeline_library
+ || other.ext_graphics_pipeline_library,
+ ext_hdr_metadata: self.ext_hdr_metadata || other.ext_hdr_metadata,
+ ext_host_query_reset: self.ext_host_query_reset || other.ext_host_query_reset,
+ ext_image_2d_view_of_3d: self.ext_image_2d_view_of_3d || other.ext_image_2d_view_of_3d,
+ ext_image_compression_control: self.ext_image_compression_control
+ || other.ext_image_compression_control,
+ ext_image_compression_control_swapchain: self.ext_image_compression_control_swapchain
+ || other.ext_image_compression_control_swapchain,
+ ext_image_drm_format_modifier: self.ext_image_drm_format_modifier
+ || other.ext_image_drm_format_modifier,
+ ext_image_robustness: self.ext_image_robustness || other.ext_image_robustness,
+ ext_image_view_min_lod: self.ext_image_view_min_lod || other.ext_image_view_min_lod,
+ ext_index_type_uint8: self.ext_index_type_uint8 || other.ext_index_type_uint8,
+ ext_inline_uniform_block: self.ext_inline_uniform_block
+ || other.ext_inline_uniform_block,
+ ext_legacy_dithering: self.ext_legacy_dithering || other.ext_legacy_dithering,
+ ext_line_rasterization: self.ext_line_rasterization || other.ext_line_rasterization,
+ ext_load_store_op_none: self.ext_load_store_op_none || other.ext_load_store_op_none,
+ ext_memory_budget: self.ext_memory_budget || other.ext_memory_budget,
+ ext_memory_priority: self.ext_memory_priority || other.ext_memory_priority,
+ ext_mesh_shader: self.ext_mesh_shader || other.ext_mesh_shader,
+ ext_metal_objects: self.ext_metal_objects || other.ext_metal_objects,
+ ext_multi_draw: self.ext_multi_draw || other.ext_multi_draw,
+ ext_multisampled_render_to_single_sampled: self
+ .ext_multisampled_render_to_single_sampled
+ || other.ext_multisampled_render_to_single_sampled,
+ ext_mutable_descriptor_type: self.ext_mutable_descriptor_type
+ || other.ext_mutable_descriptor_type,
+ ext_non_seamless_cube_map: self.ext_non_seamless_cube_map
+ || other.ext_non_seamless_cube_map,
+ ext_opacity_micromap: self.ext_opacity_micromap || other.ext_opacity_micromap,
+ ext_pageable_device_local_memory: self.ext_pageable_device_local_memory
+ || other.ext_pageable_device_local_memory,
+ ext_pci_bus_info: self.ext_pci_bus_info || other.ext_pci_bus_info,
+ ext_physical_device_drm: self.ext_physical_device_drm || other.ext_physical_device_drm,
+ ext_pipeline_creation_cache_control: self.ext_pipeline_creation_cache_control
+ || other.ext_pipeline_creation_cache_control,
+ ext_pipeline_creation_feedback: self.ext_pipeline_creation_feedback
+ || other.ext_pipeline_creation_feedback,
+ ext_pipeline_properties: self.ext_pipeline_properties || other.ext_pipeline_properties,
+ ext_pipeline_protected_access: self.ext_pipeline_protected_access
+ || other.ext_pipeline_protected_access,
+ ext_pipeline_robustness: self.ext_pipeline_robustness || other.ext_pipeline_robustness,
+ ext_post_depth_coverage: self.ext_post_depth_coverage || other.ext_post_depth_coverage,
+ ext_primitive_topology_list_restart: self.ext_primitive_topology_list_restart
+ || other.ext_primitive_topology_list_restart,
+ ext_primitives_generated_query: self.ext_primitives_generated_query
+ || other.ext_primitives_generated_query,
+ ext_private_data: self.ext_private_data || other.ext_private_data,
+ ext_provoking_vertex: self.ext_provoking_vertex || other.ext_provoking_vertex,
+ ext_queue_family_foreign: self.ext_queue_family_foreign
+ || other.ext_queue_family_foreign,
+ ext_rasterization_order_attachment_access: self
+ .ext_rasterization_order_attachment_access
+ || other.ext_rasterization_order_attachment_access,
+ ext_rgba10x6_formats: self.ext_rgba10x6_formats || other.ext_rgba10x6_formats,
+ ext_robustness2: self.ext_robustness2 || other.ext_robustness2,
+ ext_sample_locations: self.ext_sample_locations || other.ext_sample_locations,
+ ext_sampler_filter_minmax: self.ext_sampler_filter_minmax
+ || other.ext_sampler_filter_minmax,
+ ext_scalar_block_layout: self.ext_scalar_block_layout || other.ext_scalar_block_layout,
+ ext_separate_stencil_usage: self.ext_separate_stencil_usage
+ || other.ext_separate_stencil_usage,
+ ext_shader_atomic_float: self.ext_shader_atomic_float || other.ext_shader_atomic_float,
+ ext_shader_atomic_float2: self.ext_shader_atomic_float2
+ || other.ext_shader_atomic_float2,
+ ext_shader_demote_to_helper_invocation: self.ext_shader_demote_to_helper_invocation
+ || other.ext_shader_demote_to_helper_invocation,
+ ext_shader_image_atomic_int64: self.ext_shader_image_atomic_int64
+ || other.ext_shader_image_atomic_int64,
+ ext_shader_module_identifier: self.ext_shader_module_identifier
+ || other.ext_shader_module_identifier,
+ ext_shader_stencil_export: self.ext_shader_stencil_export
+ || other.ext_shader_stencil_export,
+ ext_shader_subgroup_ballot: self.ext_shader_subgroup_ballot
+ || other.ext_shader_subgroup_ballot,
+ ext_shader_subgroup_vote: self.ext_shader_subgroup_vote
+ || other.ext_shader_subgroup_vote,
+ ext_shader_viewport_index_layer: self.ext_shader_viewport_index_layer
+ || other.ext_shader_viewport_index_layer,
+ ext_subgroup_size_control: self.ext_subgroup_size_control
+ || other.ext_subgroup_size_control,
+ ext_subpass_merge_feedback: self.ext_subpass_merge_feedback
+ || other.ext_subpass_merge_feedback,
+ ext_swapchain_maintenance1: self.ext_swapchain_maintenance1
+ || other.ext_swapchain_maintenance1,
+ ext_texel_buffer_alignment: self.ext_texel_buffer_alignment
+ || other.ext_texel_buffer_alignment,
+ ext_texture_compression_astc_hdr: self.ext_texture_compression_astc_hdr
+ || other.ext_texture_compression_astc_hdr,
+ ext_tooling_info: self.ext_tooling_info || other.ext_tooling_info,
+ ext_transform_feedback: self.ext_transform_feedback || other.ext_transform_feedback,
+ ext_validation_cache: self.ext_validation_cache || other.ext_validation_cache,
+ ext_vertex_attribute_divisor: self.ext_vertex_attribute_divisor
+ || other.ext_vertex_attribute_divisor,
+ ext_vertex_input_dynamic_state: self.ext_vertex_input_dynamic_state
+ || other.ext_vertex_input_dynamic_state,
+ ext_video_encode_h264: self.ext_video_encode_h264 || other.ext_video_encode_h264,
+ ext_video_encode_h265: self.ext_video_encode_h265 || other.ext_video_encode_h265,
+ ext_ycbcr_2plane_444_formats: self.ext_ycbcr_2plane_444_formats
+ || other.ext_ycbcr_2plane_444_formats,
+ ext_ycbcr_image_arrays: self.ext_ycbcr_image_arrays || other.ext_ycbcr_image_arrays,
+ amd_buffer_marker: self.amd_buffer_marker || other.amd_buffer_marker,
+ amd_device_coherent_memory: self.amd_device_coherent_memory
+ || other.amd_device_coherent_memory,
+ amd_display_native_hdr: self.amd_display_native_hdr || other.amd_display_native_hdr,
+ amd_draw_indirect_count: self.amd_draw_indirect_count || other.amd_draw_indirect_count,
+ amd_gcn_shader: self.amd_gcn_shader || other.amd_gcn_shader,
+ amd_gpu_shader_half_float: self.amd_gpu_shader_half_float
+ || other.amd_gpu_shader_half_float,
+ amd_gpu_shader_int16: self.amd_gpu_shader_int16 || other.amd_gpu_shader_int16,
+ amd_memory_overallocation_behavior: self.amd_memory_overallocation_behavior
+ || other.amd_memory_overallocation_behavior,
+ amd_mixed_attachment_samples: self.amd_mixed_attachment_samples
+ || other.amd_mixed_attachment_samples,
+ amd_pipeline_compiler_control: self.amd_pipeline_compiler_control
+ || other.amd_pipeline_compiler_control,
+ amd_rasterization_order: self.amd_rasterization_order || other.amd_rasterization_order,
+ amd_shader_ballot: self.amd_shader_ballot || other.amd_shader_ballot,
+ amd_shader_core_properties: self.amd_shader_core_properties
+ || other.amd_shader_core_properties,
+ amd_shader_core_properties2: self.amd_shader_core_properties2
+ || other.amd_shader_core_properties2,
+ amd_shader_early_and_late_fragment_tests: self.amd_shader_early_and_late_fragment_tests
+ || other.amd_shader_early_and_late_fragment_tests,
+ amd_shader_explicit_vertex_parameter: self.amd_shader_explicit_vertex_parameter
+ || other.amd_shader_explicit_vertex_parameter,
+ amd_shader_fragment_mask: self.amd_shader_fragment_mask
+ || other.amd_shader_fragment_mask,
+ amd_shader_image_load_store_lod: self.amd_shader_image_load_store_lod
+ || other.amd_shader_image_load_store_lod,
+ amd_shader_info: self.amd_shader_info || other.amd_shader_info,
+ amd_shader_trinary_minmax: self.amd_shader_trinary_minmax
+ || other.amd_shader_trinary_minmax,
+ amd_texture_gather_bias_lod: self.amd_texture_gather_bias_lod
+ || other.amd_texture_gather_bias_lod,
+ android_external_memory_android_hardware_buffer: self
+ .android_external_memory_android_hardware_buffer
+ || other.android_external_memory_android_hardware_buffer,
+ arm_rasterization_order_attachment_access: self
+ .arm_rasterization_order_attachment_access
+ || other.arm_rasterization_order_attachment_access,
+ arm_shader_core_builtins: self.arm_shader_core_builtins
+ || other.arm_shader_core_builtins,
+ fuchsia_buffer_collection: self.fuchsia_buffer_collection
+ || other.fuchsia_buffer_collection,
+ fuchsia_external_memory: self.fuchsia_external_memory || other.fuchsia_external_memory,
+ fuchsia_external_semaphore: self.fuchsia_external_semaphore
+ || other.fuchsia_external_semaphore,
+ ggp_frame_token: self.ggp_frame_token || other.ggp_frame_token,
+ google_decorate_string: self.google_decorate_string || other.google_decorate_string,
+ google_display_timing: self.google_display_timing || other.google_display_timing,
+ google_hlsl_functionality1: self.google_hlsl_functionality1
+ || other.google_hlsl_functionality1,
+ google_user_type: self.google_user_type || other.google_user_type,
+ huawei_invocation_mask: self.huawei_invocation_mask || other.huawei_invocation_mask,
+ huawei_subpass_shading: self.huawei_subpass_shading || other.huawei_subpass_shading,
+ img_filter_cubic: self.img_filter_cubic || other.img_filter_cubic,
+ img_format_pvrtc: self.img_format_pvrtc || other.img_format_pvrtc,
+ intel_performance_query: self.intel_performance_query || other.intel_performance_query,
+ intel_shader_integer_functions2: self.intel_shader_integer_functions2
+ || other.intel_shader_integer_functions2,
+ nvx_binary_import: self.nvx_binary_import || other.nvx_binary_import,
+ nvx_image_view_handle: self.nvx_image_view_handle || other.nvx_image_view_handle,
+ nvx_multiview_per_view_attributes: self.nvx_multiview_per_view_attributes
+ || other.nvx_multiview_per_view_attributes,
+ nv_acquire_winrt_display: self.nv_acquire_winrt_display
+ || other.nv_acquire_winrt_display,
+ nv_clip_space_w_scaling: self.nv_clip_space_w_scaling || other.nv_clip_space_w_scaling,
+ nv_compute_shader_derivatives: self.nv_compute_shader_derivatives
+ || other.nv_compute_shader_derivatives,
+ nv_cooperative_matrix: self.nv_cooperative_matrix || other.nv_cooperative_matrix,
+ nv_copy_memory_indirect: self.nv_copy_memory_indirect || other.nv_copy_memory_indirect,
+ nv_corner_sampled_image: self.nv_corner_sampled_image || other.nv_corner_sampled_image,
+ nv_coverage_reduction_mode: self.nv_coverage_reduction_mode
+ || other.nv_coverage_reduction_mode,
+ nv_dedicated_allocation: self.nv_dedicated_allocation || other.nv_dedicated_allocation,
+ nv_dedicated_allocation_image_aliasing: self.nv_dedicated_allocation_image_aliasing
+ || other.nv_dedicated_allocation_image_aliasing,
+ nv_device_diagnostic_checkpoints: self.nv_device_diagnostic_checkpoints
+ || other.nv_device_diagnostic_checkpoints,
+ nv_device_diagnostics_config: self.nv_device_diagnostics_config
+ || other.nv_device_diagnostics_config,
+ nv_device_generated_commands: self.nv_device_generated_commands
+ || other.nv_device_generated_commands,
+ nv_external_memory: self.nv_external_memory || other.nv_external_memory,
+ nv_external_memory_rdma: self.nv_external_memory_rdma || other.nv_external_memory_rdma,
+ nv_external_memory_win32: self.nv_external_memory_win32
+ || other.nv_external_memory_win32,
+ nv_fill_rectangle: self.nv_fill_rectangle || other.nv_fill_rectangle,
+ nv_fragment_coverage_to_color: self.nv_fragment_coverage_to_color
+ || other.nv_fragment_coverage_to_color,
+ nv_fragment_shader_barycentric: self.nv_fragment_shader_barycentric
+ || other.nv_fragment_shader_barycentric,
+ nv_fragment_shading_rate_enums: self.nv_fragment_shading_rate_enums
+ || other.nv_fragment_shading_rate_enums,
+ nv_framebuffer_mixed_samples: self.nv_framebuffer_mixed_samples
+ || other.nv_framebuffer_mixed_samples,
+ nv_geometry_shader_passthrough: self.nv_geometry_shader_passthrough
+ || other.nv_geometry_shader_passthrough,
+ nv_glsl_shader: self.nv_glsl_shader || other.nv_glsl_shader,
+ nv_inherited_viewport_scissor: self.nv_inherited_viewport_scissor
+ || other.nv_inherited_viewport_scissor,
+ nv_linear_color_attachment: self.nv_linear_color_attachment
+ || other.nv_linear_color_attachment,
+ nv_memory_decompression: self.nv_memory_decompression || other.nv_memory_decompression,
+ nv_mesh_shader: self.nv_mesh_shader || other.nv_mesh_shader,
+ nv_optical_flow: self.nv_optical_flow || other.nv_optical_flow,
+ nv_present_barrier: self.nv_present_barrier || other.nv_present_barrier,
+ nv_ray_tracing: self.nv_ray_tracing || other.nv_ray_tracing,
+ nv_ray_tracing_invocation_reorder: self.nv_ray_tracing_invocation_reorder
+ || other.nv_ray_tracing_invocation_reorder,
+ nv_ray_tracing_motion_blur: self.nv_ray_tracing_motion_blur
+ || other.nv_ray_tracing_motion_blur,
+ nv_representative_fragment_test: self.nv_representative_fragment_test
+ || other.nv_representative_fragment_test,
+ nv_sample_mask_override_coverage: self.nv_sample_mask_override_coverage
+ || other.nv_sample_mask_override_coverage,
+ nv_scissor_exclusive: self.nv_scissor_exclusive || other.nv_scissor_exclusive,
+ nv_shader_image_footprint: self.nv_shader_image_footprint
+ || other.nv_shader_image_footprint,
+ nv_shader_sm_builtins: self.nv_shader_sm_builtins || other.nv_shader_sm_builtins,
+ nv_shader_subgroup_partitioned: self.nv_shader_subgroup_partitioned
+ || other.nv_shader_subgroup_partitioned,
+ nv_shading_rate_image: self.nv_shading_rate_image || other.nv_shading_rate_image,
+ nv_viewport_array2: self.nv_viewport_array2 || other.nv_viewport_array2,
+ nv_viewport_swizzle: self.nv_viewport_swizzle || other.nv_viewport_swizzle,
+ nv_win32_keyed_mutex: self.nv_win32_keyed_mutex || other.nv_win32_keyed_mutex,
+ qcom_fragment_density_map_offset: self.qcom_fragment_density_map_offset
+ || other.qcom_fragment_density_map_offset,
+ qcom_image_processing: self.qcom_image_processing || other.qcom_image_processing,
+ qcom_multiview_per_view_viewports: self.qcom_multiview_per_view_viewports
+ || other.qcom_multiview_per_view_viewports,
+ qcom_render_pass_shader_resolve: self.qcom_render_pass_shader_resolve
+ || other.qcom_render_pass_shader_resolve,
+ qcom_render_pass_store_ops: self.qcom_render_pass_store_ops
+ || other.qcom_render_pass_store_ops,
+ qcom_render_pass_transform: self.qcom_render_pass_transform
+ || other.qcom_render_pass_transform,
+ qcom_rotated_copy_commands: self.qcom_rotated_copy_commands
+ || other.qcom_rotated_copy_commands,
+ qcom_tile_properties: self.qcom_tile_properties || other.qcom_tile_properties,
+ sec_amigo_profiling: self.sec_amigo_profiling || other.sec_amigo_profiling,
+ valve_descriptor_set_host_mapping: self.valve_descriptor_set_host_mapping
+ || other.valve_descriptor_set_host_mapping,
+ valve_mutable_descriptor_type: self.valve_mutable_descriptor_type
+ || other.valve_mutable_descriptor_type,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+ #[doc = r" Returns the intersection of `self` and `other`."]
+ #[inline]
+ pub const fn intersection(&self, other: &Self) -> Self {
+ Self {
+ khr_16bit_storage: self.khr_16bit_storage && other.khr_16bit_storage,
+ khr_8bit_storage: self.khr_8bit_storage && other.khr_8bit_storage,
+ khr_acceleration_structure: self.khr_acceleration_structure
+ && other.khr_acceleration_structure,
+ khr_bind_memory2: self.khr_bind_memory2 && other.khr_bind_memory2,
+ khr_buffer_device_address: self.khr_buffer_device_address
+ && other.khr_buffer_device_address,
+ khr_copy_commands2: self.khr_copy_commands2 && other.khr_copy_commands2,
+ khr_create_renderpass2: self.khr_create_renderpass2 && other.khr_create_renderpass2,
+ khr_dedicated_allocation: self.khr_dedicated_allocation
+ && other.khr_dedicated_allocation,
+ khr_deferred_host_operations: self.khr_deferred_host_operations
+ && other.khr_deferred_host_operations,
+ khr_depth_stencil_resolve: self.khr_depth_stencil_resolve
+ && other.khr_depth_stencil_resolve,
+ khr_descriptor_update_template: self.khr_descriptor_update_template
+ && other.khr_descriptor_update_template,
+ khr_device_group: self.khr_device_group && other.khr_device_group,
+ khr_display_swapchain: self.khr_display_swapchain && other.khr_display_swapchain,
+ khr_draw_indirect_count: self.khr_draw_indirect_count && other.khr_draw_indirect_count,
+ khr_driver_properties: self.khr_driver_properties && other.khr_driver_properties,
+ khr_dynamic_rendering: self.khr_dynamic_rendering && other.khr_dynamic_rendering,
+ khr_external_fence: self.khr_external_fence && other.khr_external_fence,
+ khr_external_fence_fd: self.khr_external_fence_fd && other.khr_external_fence_fd,
+ khr_external_fence_win32: self.khr_external_fence_win32
+ && other.khr_external_fence_win32,
+ khr_external_memory: self.khr_external_memory && other.khr_external_memory,
+ khr_external_memory_fd: self.khr_external_memory_fd && other.khr_external_memory_fd,
+ khr_external_memory_win32: self.khr_external_memory_win32
+ && other.khr_external_memory_win32,
+ khr_external_semaphore: self.khr_external_semaphore && other.khr_external_semaphore,
+ khr_external_semaphore_fd: self.khr_external_semaphore_fd
+ && other.khr_external_semaphore_fd,
+ khr_external_semaphore_win32: self.khr_external_semaphore_win32
+ && other.khr_external_semaphore_win32,
+ khr_format_feature_flags2: self.khr_format_feature_flags2
+ && other.khr_format_feature_flags2,
+ khr_fragment_shader_barycentric: self.khr_fragment_shader_barycentric
+ && other.khr_fragment_shader_barycentric,
+ khr_fragment_shading_rate: self.khr_fragment_shading_rate
+ && other.khr_fragment_shading_rate,
+ khr_get_memory_requirements2: self.khr_get_memory_requirements2
+ && other.khr_get_memory_requirements2,
+ khr_global_priority: self.khr_global_priority && other.khr_global_priority,
+ khr_image_format_list: self.khr_image_format_list && other.khr_image_format_list,
+ khr_imageless_framebuffer: self.khr_imageless_framebuffer
+ && other.khr_imageless_framebuffer,
+ khr_incremental_present: self.khr_incremental_present && other.khr_incremental_present,
+ khr_maintenance1: self.khr_maintenance1 && other.khr_maintenance1,
+ khr_maintenance2: self.khr_maintenance2 && other.khr_maintenance2,
+ khr_maintenance3: self.khr_maintenance3 && other.khr_maintenance3,
+ khr_maintenance4: self.khr_maintenance4 && other.khr_maintenance4,
+ khr_multiview: self.khr_multiview && other.khr_multiview,
+ khr_performance_query: self.khr_performance_query && other.khr_performance_query,
+ khr_pipeline_executable_properties: self.khr_pipeline_executable_properties
+ && other.khr_pipeline_executable_properties,
+ khr_pipeline_library: self.khr_pipeline_library && other.khr_pipeline_library,
+ khr_portability_subset: self.khr_portability_subset && other.khr_portability_subset,
+ khr_present_id: self.khr_present_id && other.khr_present_id,
+ khr_present_wait: self.khr_present_wait && other.khr_present_wait,
+ khr_push_descriptor: self.khr_push_descriptor && other.khr_push_descriptor,
+ khr_ray_query: self.khr_ray_query && other.khr_ray_query,
+ khr_ray_tracing_maintenance1: self.khr_ray_tracing_maintenance1
+ && other.khr_ray_tracing_maintenance1,
+ khr_ray_tracing_pipeline: self.khr_ray_tracing_pipeline
+ && other.khr_ray_tracing_pipeline,
+ khr_relaxed_block_layout: self.khr_relaxed_block_layout
+ && other.khr_relaxed_block_layout,
+ khr_sampler_mirror_clamp_to_edge: self.khr_sampler_mirror_clamp_to_edge
+ && other.khr_sampler_mirror_clamp_to_edge,
+ khr_sampler_ycbcr_conversion: self.khr_sampler_ycbcr_conversion
+ && other.khr_sampler_ycbcr_conversion,
+ khr_separate_depth_stencil_layouts: self.khr_separate_depth_stencil_layouts
+ && other.khr_separate_depth_stencil_layouts,
+ khr_shader_atomic_int64: self.khr_shader_atomic_int64 && other.khr_shader_atomic_int64,
+ khr_shader_clock: self.khr_shader_clock && other.khr_shader_clock,
+ khr_shader_draw_parameters: self.khr_shader_draw_parameters
+ && other.khr_shader_draw_parameters,
+ khr_shader_float16_int8: self.khr_shader_float16_int8 && other.khr_shader_float16_int8,
+ khr_shader_float_controls: self.khr_shader_float_controls
+ && other.khr_shader_float_controls,
+ khr_shader_integer_dot_product: self.khr_shader_integer_dot_product
+ && other.khr_shader_integer_dot_product,
+ khr_shader_non_semantic_info: self.khr_shader_non_semantic_info
+ && other.khr_shader_non_semantic_info,
+ khr_shader_subgroup_extended_types: self.khr_shader_subgroup_extended_types
+ && other.khr_shader_subgroup_extended_types,
+ khr_shader_subgroup_uniform_control_flow: self.khr_shader_subgroup_uniform_control_flow
+ && other.khr_shader_subgroup_uniform_control_flow,
+ khr_shader_terminate_invocation: self.khr_shader_terminate_invocation
+ && other.khr_shader_terminate_invocation,
+ khr_shared_presentable_image: self.khr_shared_presentable_image
+ && other.khr_shared_presentable_image,
+ khr_spirv_1_4: self.khr_spirv_1_4 && other.khr_spirv_1_4,
+ khr_storage_buffer_storage_class: self.khr_storage_buffer_storage_class
+ && other.khr_storage_buffer_storage_class,
+ khr_swapchain: self.khr_swapchain && other.khr_swapchain,
+ khr_swapchain_mutable_format: self.khr_swapchain_mutable_format
+ && other.khr_swapchain_mutable_format,
+ khr_synchronization2: self.khr_synchronization2 && other.khr_synchronization2,
+ khr_timeline_semaphore: self.khr_timeline_semaphore && other.khr_timeline_semaphore,
+ khr_uniform_buffer_standard_layout: self.khr_uniform_buffer_standard_layout
+ && other.khr_uniform_buffer_standard_layout,
+ khr_variable_pointers: self.khr_variable_pointers && other.khr_variable_pointers,
+ khr_video_decode_h264: self.khr_video_decode_h264 && other.khr_video_decode_h264,
+ khr_video_decode_h265: self.khr_video_decode_h265 && other.khr_video_decode_h265,
+ khr_video_decode_queue: self.khr_video_decode_queue && other.khr_video_decode_queue,
+ khr_video_encode_queue: self.khr_video_encode_queue && other.khr_video_encode_queue,
+ khr_video_queue: self.khr_video_queue && other.khr_video_queue,
+ khr_vulkan_memory_model: self.khr_vulkan_memory_model && other.khr_vulkan_memory_model,
+ khr_win32_keyed_mutex: self.khr_win32_keyed_mutex && other.khr_win32_keyed_mutex,
+ khr_workgroup_memory_explicit_layout: self.khr_workgroup_memory_explicit_layout
+ && other.khr_workgroup_memory_explicit_layout,
+ khr_zero_initialize_workgroup_memory: self.khr_zero_initialize_workgroup_memory
+ && other.khr_zero_initialize_workgroup_memory,
+ ext_4444_formats: self.ext_4444_formats && other.ext_4444_formats,
+ ext_astc_decode_mode: self.ext_astc_decode_mode && other.ext_astc_decode_mode,
+ ext_attachment_feedback_loop_layout: self.ext_attachment_feedback_loop_layout
+ && other.ext_attachment_feedback_loop_layout,
+ ext_blend_operation_advanced: self.ext_blend_operation_advanced
+ && other.ext_blend_operation_advanced,
+ ext_border_color_swizzle: self.ext_border_color_swizzle
+ && other.ext_border_color_swizzle,
+ ext_buffer_device_address: self.ext_buffer_device_address
+ && other.ext_buffer_device_address,
+ ext_calibrated_timestamps: self.ext_calibrated_timestamps
+ && other.ext_calibrated_timestamps,
+ ext_color_write_enable: self.ext_color_write_enable && other.ext_color_write_enable,
+ ext_conditional_rendering: self.ext_conditional_rendering
+ && other.ext_conditional_rendering,
+ ext_conservative_rasterization: self.ext_conservative_rasterization
+ && other.ext_conservative_rasterization,
+ ext_custom_border_color: self.ext_custom_border_color && other.ext_custom_border_color,
+ ext_debug_marker: self.ext_debug_marker && other.ext_debug_marker,
+ ext_depth_clamp_zero_one: self.ext_depth_clamp_zero_one
+ && other.ext_depth_clamp_zero_one,
+ ext_depth_clip_control: self.ext_depth_clip_control && other.ext_depth_clip_control,
+ ext_depth_clip_enable: self.ext_depth_clip_enable && other.ext_depth_clip_enable,
+ ext_depth_range_unrestricted: self.ext_depth_range_unrestricted
+ && other.ext_depth_range_unrestricted,
+ ext_descriptor_buffer: self.ext_descriptor_buffer && other.ext_descriptor_buffer,
+ ext_descriptor_indexing: self.ext_descriptor_indexing && other.ext_descriptor_indexing,
+ ext_device_address_binding_report: self.ext_device_address_binding_report
+ && other.ext_device_address_binding_report,
+ ext_device_fault: self.ext_device_fault && other.ext_device_fault,
+ ext_device_memory_report: self.ext_device_memory_report
+ && other.ext_device_memory_report,
+ ext_discard_rectangles: self.ext_discard_rectangles && other.ext_discard_rectangles,
+ ext_display_control: self.ext_display_control && other.ext_display_control,
+ ext_extended_dynamic_state: self.ext_extended_dynamic_state
+ && other.ext_extended_dynamic_state,
+ ext_extended_dynamic_state2: self.ext_extended_dynamic_state2
+ && other.ext_extended_dynamic_state2,
+ ext_extended_dynamic_state3: self.ext_extended_dynamic_state3
+ && other.ext_extended_dynamic_state3,
+ ext_external_memory_dma_buf: self.ext_external_memory_dma_buf
+ && other.ext_external_memory_dma_buf,
+ ext_external_memory_host: self.ext_external_memory_host
+ && other.ext_external_memory_host,
+ ext_filter_cubic: self.ext_filter_cubic && other.ext_filter_cubic,
+ ext_fragment_density_map: self.ext_fragment_density_map
+ && other.ext_fragment_density_map,
+ ext_fragment_density_map2: self.ext_fragment_density_map2
+ && other.ext_fragment_density_map2,
+ ext_fragment_shader_interlock: self.ext_fragment_shader_interlock
+ && other.ext_fragment_shader_interlock,
+ ext_full_screen_exclusive: self.ext_full_screen_exclusive
+ && other.ext_full_screen_exclusive,
+ ext_global_priority: self.ext_global_priority && other.ext_global_priority,
+ ext_global_priority_query: self.ext_global_priority_query
+ && other.ext_global_priority_query,
+ ext_graphics_pipeline_library: self.ext_graphics_pipeline_library
+ && other.ext_graphics_pipeline_library,
+ ext_hdr_metadata: self.ext_hdr_metadata && other.ext_hdr_metadata,
+ ext_host_query_reset: self.ext_host_query_reset && other.ext_host_query_reset,
+ ext_image_2d_view_of_3d: self.ext_image_2d_view_of_3d && other.ext_image_2d_view_of_3d,
+ ext_image_compression_control: self.ext_image_compression_control
+ && other.ext_image_compression_control,
+ ext_image_compression_control_swapchain: self.ext_image_compression_control_swapchain
+ && other.ext_image_compression_control_swapchain,
+ ext_image_drm_format_modifier: self.ext_image_drm_format_modifier
+ && other.ext_image_drm_format_modifier,
+ ext_image_robustness: self.ext_image_robustness && other.ext_image_robustness,
+ ext_image_view_min_lod: self.ext_image_view_min_lod && other.ext_image_view_min_lod,
+ ext_index_type_uint8: self.ext_index_type_uint8 && other.ext_index_type_uint8,
+ ext_inline_uniform_block: self.ext_inline_uniform_block
+ && other.ext_inline_uniform_block,
+ ext_legacy_dithering: self.ext_legacy_dithering && other.ext_legacy_dithering,
+ ext_line_rasterization: self.ext_line_rasterization && other.ext_line_rasterization,
+ ext_load_store_op_none: self.ext_load_store_op_none && other.ext_load_store_op_none,
+ ext_memory_budget: self.ext_memory_budget && other.ext_memory_budget,
+ ext_memory_priority: self.ext_memory_priority && other.ext_memory_priority,
+ ext_mesh_shader: self.ext_mesh_shader && other.ext_mesh_shader,
+ ext_metal_objects: self.ext_metal_objects && other.ext_metal_objects,
+ ext_multi_draw: self.ext_multi_draw && other.ext_multi_draw,
+ ext_multisampled_render_to_single_sampled: self
+ .ext_multisampled_render_to_single_sampled
+ && other.ext_multisampled_render_to_single_sampled,
+ ext_mutable_descriptor_type: self.ext_mutable_descriptor_type
+ && other.ext_mutable_descriptor_type,
+ ext_non_seamless_cube_map: self.ext_non_seamless_cube_map
+ && other.ext_non_seamless_cube_map,
+ ext_opacity_micromap: self.ext_opacity_micromap && other.ext_opacity_micromap,
+ ext_pageable_device_local_memory: self.ext_pageable_device_local_memory
+ && other.ext_pageable_device_local_memory,
+ ext_pci_bus_info: self.ext_pci_bus_info && other.ext_pci_bus_info,
+ ext_physical_device_drm: self.ext_physical_device_drm && other.ext_physical_device_drm,
+ ext_pipeline_creation_cache_control: self.ext_pipeline_creation_cache_control
+ && other.ext_pipeline_creation_cache_control,
+ ext_pipeline_creation_feedback: self.ext_pipeline_creation_feedback
+ && other.ext_pipeline_creation_feedback,
+ ext_pipeline_properties: self.ext_pipeline_properties && other.ext_pipeline_properties,
+ ext_pipeline_protected_access: self.ext_pipeline_protected_access
+ && other.ext_pipeline_protected_access,
+ ext_pipeline_robustness: self.ext_pipeline_robustness && other.ext_pipeline_robustness,
+ ext_post_depth_coverage: self.ext_post_depth_coverage && other.ext_post_depth_coverage,
+ ext_primitive_topology_list_restart: self.ext_primitive_topology_list_restart
+ && other.ext_primitive_topology_list_restart,
+ ext_primitives_generated_query: self.ext_primitives_generated_query
+ && other.ext_primitives_generated_query,
+ ext_private_data: self.ext_private_data && other.ext_private_data,
+ ext_provoking_vertex: self.ext_provoking_vertex && other.ext_provoking_vertex,
+ ext_queue_family_foreign: self.ext_queue_family_foreign
+ && other.ext_queue_family_foreign,
+ ext_rasterization_order_attachment_access: self
+ .ext_rasterization_order_attachment_access
+ && other.ext_rasterization_order_attachment_access,
+ ext_rgba10x6_formats: self.ext_rgba10x6_formats && other.ext_rgba10x6_formats,
+ ext_robustness2: self.ext_robustness2 && other.ext_robustness2,
+ ext_sample_locations: self.ext_sample_locations && other.ext_sample_locations,
+ ext_sampler_filter_minmax: self.ext_sampler_filter_minmax
+ && other.ext_sampler_filter_minmax,
+ ext_scalar_block_layout: self.ext_scalar_block_layout && other.ext_scalar_block_layout,
+ ext_separate_stencil_usage: self.ext_separate_stencil_usage
+ && other.ext_separate_stencil_usage,
+ ext_shader_atomic_float: self.ext_shader_atomic_float && other.ext_shader_atomic_float,
+ ext_shader_atomic_float2: self.ext_shader_atomic_float2
+ && other.ext_shader_atomic_float2,
+ ext_shader_demote_to_helper_invocation: self.ext_shader_demote_to_helper_invocation
+ && other.ext_shader_demote_to_helper_invocation,
+ ext_shader_image_atomic_int64: self.ext_shader_image_atomic_int64
+ && other.ext_shader_image_atomic_int64,
+ ext_shader_module_identifier: self.ext_shader_module_identifier
+ && other.ext_shader_module_identifier,
+ ext_shader_stencil_export: self.ext_shader_stencil_export
+ && other.ext_shader_stencil_export,
+ ext_shader_subgroup_ballot: self.ext_shader_subgroup_ballot
+ && other.ext_shader_subgroup_ballot,
+ ext_shader_subgroup_vote: self.ext_shader_subgroup_vote
+ && other.ext_shader_subgroup_vote,
+ ext_shader_viewport_index_layer: self.ext_shader_viewport_index_layer
+ && other.ext_shader_viewport_index_layer,
+ ext_subgroup_size_control: self.ext_subgroup_size_control
+ && other.ext_subgroup_size_control,
+ ext_subpass_merge_feedback: self.ext_subpass_merge_feedback
+ && other.ext_subpass_merge_feedback,
+ ext_swapchain_maintenance1: self.ext_swapchain_maintenance1
+ && other.ext_swapchain_maintenance1,
+ ext_texel_buffer_alignment: self.ext_texel_buffer_alignment
+ && other.ext_texel_buffer_alignment,
+ ext_texture_compression_astc_hdr: self.ext_texture_compression_astc_hdr
+ && other.ext_texture_compression_astc_hdr,
+ ext_tooling_info: self.ext_tooling_info && other.ext_tooling_info,
+ ext_transform_feedback: self.ext_transform_feedback && other.ext_transform_feedback,
+ ext_validation_cache: self.ext_validation_cache && other.ext_validation_cache,
+ ext_vertex_attribute_divisor: self.ext_vertex_attribute_divisor
+ && other.ext_vertex_attribute_divisor,
+ ext_vertex_input_dynamic_state: self.ext_vertex_input_dynamic_state
+ && other.ext_vertex_input_dynamic_state,
+ ext_video_encode_h264: self.ext_video_encode_h264 && other.ext_video_encode_h264,
+ ext_video_encode_h265: self.ext_video_encode_h265 && other.ext_video_encode_h265,
+ ext_ycbcr_2plane_444_formats: self.ext_ycbcr_2plane_444_formats
+ && other.ext_ycbcr_2plane_444_formats,
+ ext_ycbcr_image_arrays: self.ext_ycbcr_image_arrays && other.ext_ycbcr_image_arrays,
+ amd_buffer_marker: self.amd_buffer_marker && other.amd_buffer_marker,
+ amd_device_coherent_memory: self.amd_device_coherent_memory
+ && other.amd_device_coherent_memory,
+ amd_display_native_hdr: self.amd_display_native_hdr && other.amd_display_native_hdr,
+ amd_draw_indirect_count: self.amd_draw_indirect_count && other.amd_draw_indirect_count,
+ amd_gcn_shader: self.amd_gcn_shader && other.amd_gcn_shader,
+ amd_gpu_shader_half_float: self.amd_gpu_shader_half_float
+ && other.amd_gpu_shader_half_float,
+ amd_gpu_shader_int16: self.amd_gpu_shader_int16 && other.amd_gpu_shader_int16,
+ amd_memory_overallocation_behavior: self.amd_memory_overallocation_behavior
+ && other.amd_memory_overallocation_behavior,
+ amd_mixed_attachment_samples: self.amd_mixed_attachment_samples
+ && other.amd_mixed_attachment_samples,
+ amd_pipeline_compiler_control: self.amd_pipeline_compiler_control
+ && other.amd_pipeline_compiler_control,
+ amd_rasterization_order: self.amd_rasterization_order && other.amd_rasterization_order,
+ amd_shader_ballot: self.amd_shader_ballot && other.amd_shader_ballot,
+ amd_shader_core_properties: self.amd_shader_core_properties
+ && other.amd_shader_core_properties,
+ amd_shader_core_properties2: self.amd_shader_core_properties2
+ && other.amd_shader_core_properties2,
+ amd_shader_early_and_late_fragment_tests: self.amd_shader_early_and_late_fragment_tests
+ && other.amd_shader_early_and_late_fragment_tests,
+ amd_shader_explicit_vertex_parameter: self.amd_shader_explicit_vertex_parameter
+ && other.amd_shader_explicit_vertex_parameter,
+ amd_shader_fragment_mask: self.amd_shader_fragment_mask
+ && other.amd_shader_fragment_mask,
+ amd_shader_image_load_store_lod: self.amd_shader_image_load_store_lod
+ && other.amd_shader_image_load_store_lod,
+ amd_shader_info: self.amd_shader_info && other.amd_shader_info,
+ amd_shader_trinary_minmax: self.amd_shader_trinary_minmax
+ && other.amd_shader_trinary_minmax,
+ amd_texture_gather_bias_lod: self.amd_texture_gather_bias_lod
+ && other.amd_texture_gather_bias_lod,
+ android_external_memory_android_hardware_buffer: self
+ .android_external_memory_android_hardware_buffer
+ && other.android_external_memory_android_hardware_buffer,
+ arm_rasterization_order_attachment_access: self
+ .arm_rasterization_order_attachment_access
+ && other.arm_rasterization_order_attachment_access,
+ arm_shader_core_builtins: self.arm_shader_core_builtins
+ && other.arm_shader_core_builtins,
+ fuchsia_buffer_collection: self.fuchsia_buffer_collection
+ && other.fuchsia_buffer_collection,
+ fuchsia_external_memory: self.fuchsia_external_memory && other.fuchsia_external_memory,
+ fuchsia_external_semaphore: self.fuchsia_external_semaphore
+ && other.fuchsia_external_semaphore,
+ ggp_frame_token: self.ggp_frame_token && other.ggp_frame_token,
+ google_decorate_string: self.google_decorate_string && other.google_decorate_string,
+ google_display_timing: self.google_display_timing && other.google_display_timing,
+ google_hlsl_functionality1: self.google_hlsl_functionality1
+ && other.google_hlsl_functionality1,
+ google_user_type: self.google_user_type && other.google_user_type,
+ huawei_invocation_mask: self.huawei_invocation_mask && other.huawei_invocation_mask,
+ huawei_subpass_shading: self.huawei_subpass_shading && other.huawei_subpass_shading,
+ img_filter_cubic: self.img_filter_cubic && other.img_filter_cubic,
+ img_format_pvrtc: self.img_format_pvrtc && other.img_format_pvrtc,
+ intel_performance_query: self.intel_performance_query && other.intel_performance_query,
+ intel_shader_integer_functions2: self.intel_shader_integer_functions2
+ && other.intel_shader_integer_functions2,
+ nvx_binary_import: self.nvx_binary_import && other.nvx_binary_import,
+ nvx_image_view_handle: self.nvx_image_view_handle && other.nvx_image_view_handle,
+ nvx_multiview_per_view_attributes: self.nvx_multiview_per_view_attributes
+ && other.nvx_multiview_per_view_attributes,
+ nv_acquire_winrt_display: self.nv_acquire_winrt_display
+ && other.nv_acquire_winrt_display,
+ nv_clip_space_w_scaling: self.nv_clip_space_w_scaling && other.nv_clip_space_w_scaling,
+ nv_compute_shader_derivatives: self.nv_compute_shader_derivatives
+ && other.nv_compute_shader_derivatives,
+ nv_cooperative_matrix: self.nv_cooperative_matrix && other.nv_cooperative_matrix,
+ nv_copy_memory_indirect: self.nv_copy_memory_indirect && other.nv_copy_memory_indirect,
+ nv_corner_sampled_image: self.nv_corner_sampled_image && other.nv_corner_sampled_image,
+ nv_coverage_reduction_mode: self.nv_coverage_reduction_mode
+ && other.nv_coverage_reduction_mode,
+ nv_dedicated_allocation: self.nv_dedicated_allocation && other.nv_dedicated_allocation,
+ nv_dedicated_allocation_image_aliasing: self.nv_dedicated_allocation_image_aliasing
+ && other.nv_dedicated_allocation_image_aliasing,
+ nv_device_diagnostic_checkpoints: self.nv_device_diagnostic_checkpoints
+ && other.nv_device_diagnostic_checkpoints,
+ nv_device_diagnostics_config: self.nv_device_diagnostics_config
+ && other.nv_device_diagnostics_config,
+ nv_device_generated_commands: self.nv_device_generated_commands
+ && other.nv_device_generated_commands,
+ nv_external_memory: self.nv_external_memory && other.nv_external_memory,
+ nv_external_memory_rdma: self.nv_external_memory_rdma && other.nv_external_memory_rdma,
+ nv_external_memory_win32: self.nv_external_memory_win32
+ && other.nv_external_memory_win32,
+ nv_fill_rectangle: self.nv_fill_rectangle && other.nv_fill_rectangle,
+ nv_fragment_coverage_to_color: self.nv_fragment_coverage_to_color
+ && other.nv_fragment_coverage_to_color,
+ nv_fragment_shader_barycentric: self.nv_fragment_shader_barycentric
+ && other.nv_fragment_shader_barycentric,
+ nv_fragment_shading_rate_enums: self.nv_fragment_shading_rate_enums
+ && other.nv_fragment_shading_rate_enums,
+ nv_framebuffer_mixed_samples: self.nv_framebuffer_mixed_samples
+ && other.nv_framebuffer_mixed_samples,
+ nv_geometry_shader_passthrough: self.nv_geometry_shader_passthrough
+ && other.nv_geometry_shader_passthrough,
+ nv_glsl_shader: self.nv_glsl_shader && other.nv_glsl_shader,
+ nv_inherited_viewport_scissor: self.nv_inherited_viewport_scissor
+ && other.nv_inherited_viewport_scissor,
+ nv_linear_color_attachment: self.nv_linear_color_attachment
+ && other.nv_linear_color_attachment,
+ nv_memory_decompression: self.nv_memory_decompression && other.nv_memory_decompression,
+ nv_mesh_shader: self.nv_mesh_shader && other.nv_mesh_shader,
+ nv_optical_flow: self.nv_optical_flow && other.nv_optical_flow,
+ nv_present_barrier: self.nv_present_barrier && other.nv_present_barrier,
+ nv_ray_tracing: self.nv_ray_tracing && other.nv_ray_tracing,
+ nv_ray_tracing_invocation_reorder: self.nv_ray_tracing_invocation_reorder
+ && other.nv_ray_tracing_invocation_reorder,
+ nv_ray_tracing_motion_blur: self.nv_ray_tracing_motion_blur
+ && other.nv_ray_tracing_motion_blur,
+ nv_representative_fragment_test: self.nv_representative_fragment_test
+ && other.nv_representative_fragment_test,
+ nv_sample_mask_override_coverage: self.nv_sample_mask_override_coverage
+ && other.nv_sample_mask_override_coverage,
+ nv_scissor_exclusive: self.nv_scissor_exclusive && other.nv_scissor_exclusive,
+ nv_shader_image_footprint: self.nv_shader_image_footprint
+ && other.nv_shader_image_footprint,
+ nv_shader_sm_builtins: self.nv_shader_sm_builtins && other.nv_shader_sm_builtins,
+ nv_shader_subgroup_partitioned: self.nv_shader_subgroup_partitioned
+ && other.nv_shader_subgroup_partitioned,
+ nv_shading_rate_image: self.nv_shading_rate_image && other.nv_shading_rate_image,
+ nv_viewport_array2: self.nv_viewport_array2 && other.nv_viewport_array2,
+ nv_viewport_swizzle: self.nv_viewport_swizzle && other.nv_viewport_swizzle,
+ nv_win32_keyed_mutex: self.nv_win32_keyed_mutex && other.nv_win32_keyed_mutex,
+ qcom_fragment_density_map_offset: self.qcom_fragment_density_map_offset
+ && other.qcom_fragment_density_map_offset,
+ qcom_image_processing: self.qcom_image_processing && other.qcom_image_processing,
+ qcom_multiview_per_view_viewports: self.qcom_multiview_per_view_viewports
+ && other.qcom_multiview_per_view_viewports,
+ qcom_render_pass_shader_resolve: self.qcom_render_pass_shader_resolve
+ && other.qcom_render_pass_shader_resolve,
+ qcom_render_pass_store_ops: self.qcom_render_pass_store_ops
+ && other.qcom_render_pass_store_ops,
+ qcom_render_pass_transform: self.qcom_render_pass_transform
+ && other.qcom_render_pass_transform,
+ qcom_rotated_copy_commands: self.qcom_rotated_copy_commands
+ && other.qcom_rotated_copy_commands,
+ qcom_tile_properties: self.qcom_tile_properties && other.qcom_tile_properties,
+ sec_amigo_profiling: self.sec_amigo_profiling && other.sec_amigo_profiling,
+ valve_descriptor_set_host_mapping: self.valve_descriptor_set_host_mapping
+ && other.valve_descriptor_set_host_mapping,
+ valve_mutable_descriptor_type: self.valve_mutable_descriptor_type
+ && other.valve_mutable_descriptor_type,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+ #[doc = r" Returns `self` without the members set in `other`."]
+ #[inline]
+ pub const fn difference(&self, other: &Self) -> Self {
+ Self {
+ khr_16bit_storage: self.khr_16bit_storage && !other.khr_16bit_storage,
+ khr_8bit_storage: self.khr_8bit_storage && !other.khr_8bit_storage,
+ khr_acceleration_structure: self.khr_acceleration_structure
+ && !other.khr_acceleration_structure,
+ khr_bind_memory2: self.khr_bind_memory2 && !other.khr_bind_memory2,
+ khr_buffer_device_address: self.khr_buffer_device_address
+ && !other.khr_buffer_device_address,
+ khr_copy_commands2: self.khr_copy_commands2 && !other.khr_copy_commands2,
+ khr_create_renderpass2: self.khr_create_renderpass2 && !other.khr_create_renderpass2,
+ khr_dedicated_allocation: self.khr_dedicated_allocation
+ && !other.khr_dedicated_allocation,
+ khr_deferred_host_operations: self.khr_deferred_host_operations
+ && !other.khr_deferred_host_operations,
+ khr_depth_stencil_resolve: self.khr_depth_stencil_resolve
+ && !other.khr_depth_stencil_resolve,
+ khr_descriptor_update_template: self.khr_descriptor_update_template
+ && !other.khr_descriptor_update_template,
+ khr_device_group: self.khr_device_group && !other.khr_device_group,
+ khr_display_swapchain: self.khr_display_swapchain && !other.khr_display_swapchain,
+ khr_draw_indirect_count: self.khr_draw_indirect_count && !other.khr_draw_indirect_count,
+ khr_driver_properties: self.khr_driver_properties && !other.khr_driver_properties,
+ khr_dynamic_rendering: self.khr_dynamic_rendering && !other.khr_dynamic_rendering,
+ khr_external_fence: self.khr_external_fence && !other.khr_external_fence,
+ khr_external_fence_fd: self.khr_external_fence_fd && !other.khr_external_fence_fd,
+ khr_external_fence_win32: self.khr_external_fence_win32
+ && !other.khr_external_fence_win32,
+ khr_external_memory: self.khr_external_memory && !other.khr_external_memory,
+ khr_external_memory_fd: self.khr_external_memory_fd && !other.khr_external_memory_fd,
+ khr_external_memory_win32: self.khr_external_memory_win32
+ && !other.khr_external_memory_win32,
+ khr_external_semaphore: self.khr_external_semaphore && !other.khr_external_semaphore,
+ khr_external_semaphore_fd: self.khr_external_semaphore_fd
+ && !other.khr_external_semaphore_fd,
+ khr_external_semaphore_win32: self.khr_external_semaphore_win32
+ && !other.khr_external_semaphore_win32,
+ khr_format_feature_flags2: self.khr_format_feature_flags2
+ && !other.khr_format_feature_flags2,
+ khr_fragment_shader_barycentric: self.khr_fragment_shader_barycentric
+ && !other.khr_fragment_shader_barycentric,
+ khr_fragment_shading_rate: self.khr_fragment_shading_rate
+ && !other.khr_fragment_shading_rate,
+ khr_get_memory_requirements2: self.khr_get_memory_requirements2
+ && !other.khr_get_memory_requirements2,
+ khr_global_priority: self.khr_global_priority && !other.khr_global_priority,
+ khr_image_format_list: self.khr_image_format_list && !other.khr_image_format_list,
+ khr_imageless_framebuffer: self.khr_imageless_framebuffer
+ && !other.khr_imageless_framebuffer,
+ khr_incremental_present: self.khr_incremental_present && !other.khr_incremental_present,
+ khr_maintenance1: self.khr_maintenance1 && !other.khr_maintenance1,
+ khr_maintenance2: self.khr_maintenance2 && !other.khr_maintenance2,
+ khr_maintenance3: self.khr_maintenance3 && !other.khr_maintenance3,
+ khr_maintenance4: self.khr_maintenance4 && !other.khr_maintenance4,
+ khr_multiview: self.khr_multiview && !other.khr_multiview,
+ khr_performance_query: self.khr_performance_query && !other.khr_performance_query,
+ khr_pipeline_executable_properties: self.khr_pipeline_executable_properties
+ && !other.khr_pipeline_executable_properties,
+ khr_pipeline_library: self.khr_pipeline_library && !other.khr_pipeline_library,
+ khr_portability_subset: self.khr_portability_subset && !other.khr_portability_subset,
+ khr_present_id: self.khr_present_id && !other.khr_present_id,
+ khr_present_wait: self.khr_present_wait && !other.khr_present_wait,
+ khr_push_descriptor: self.khr_push_descriptor && !other.khr_push_descriptor,
+ khr_ray_query: self.khr_ray_query && !other.khr_ray_query,
+ khr_ray_tracing_maintenance1: self.khr_ray_tracing_maintenance1
+ && !other.khr_ray_tracing_maintenance1,
+ khr_ray_tracing_pipeline: self.khr_ray_tracing_pipeline
+ && !other.khr_ray_tracing_pipeline,
+ khr_relaxed_block_layout: self.khr_relaxed_block_layout
+ && !other.khr_relaxed_block_layout,
+ khr_sampler_mirror_clamp_to_edge: self.khr_sampler_mirror_clamp_to_edge
+ && !other.khr_sampler_mirror_clamp_to_edge,
+ khr_sampler_ycbcr_conversion: self.khr_sampler_ycbcr_conversion
+ && !other.khr_sampler_ycbcr_conversion,
+ khr_separate_depth_stencil_layouts: self.khr_separate_depth_stencil_layouts
+ && !other.khr_separate_depth_stencil_layouts,
+ khr_shader_atomic_int64: self.khr_shader_atomic_int64 && !other.khr_shader_atomic_int64,
+ khr_shader_clock: self.khr_shader_clock && !other.khr_shader_clock,
+ khr_shader_draw_parameters: self.khr_shader_draw_parameters
+ && !other.khr_shader_draw_parameters,
+ khr_shader_float16_int8: self.khr_shader_float16_int8 && !other.khr_shader_float16_int8,
+ khr_shader_float_controls: self.khr_shader_float_controls
+ && !other.khr_shader_float_controls,
+ khr_shader_integer_dot_product: self.khr_shader_integer_dot_product
+ && !other.khr_shader_integer_dot_product,
+ khr_shader_non_semantic_info: self.khr_shader_non_semantic_info
+ && !other.khr_shader_non_semantic_info,
+ khr_shader_subgroup_extended_types: self.khr_shader_subgroup_extended_types
+ && !other.khr_shader_subgroup_extended_types,
+ khr_shader_subgroup_uniform_control_flow: self.khr_shader_subgroup_uniform_control_flow
+ && !other.khr_shader_subgroup_uniform_control_flow,
+ khr_shader_terminate_invocation: self.khr_shader_terminate_invocation
+ && !other.khr_shader_terminate_invocation,
+ khr_shared_presentable_image: self.khr_shared_presentable_image
+ && !other.khr_shared_presentable_image,
+ khr_spirv_1_4: self.khr_spirv_1_4 && !other.khr_spirv_1_4,
+ khr_storage_buffer_storage_class: self.khr_storage_buffer_storage_class
+ && !other.khr_storage_buffer_storage_class,
+ khr_swapchain: self.khr_swapchain && !other.khr_swapchain,
+ khr_swapchain_mutable_format: self.khr_swapchain_mutable_format
+ && !other.khr_swapchain_mutable_format,
+ khr_synchronization2: self.khr_synchronization2 && !other.khr_synchronization2,
+ khr_timeline_semaphore: self.khr_timeline_semaphore && !other.khr_timeline_semaphore,
+ khr_uniform_buffer_standard_layout: self.khr_uniform_buffer_standard_layout
+ && !other.khr_uniform_buffer_standard_layout,
+ khr_variable_pointers: self.khr_variable_pointers && !other.khr_variable_pointers,
+ khr_video_decode_h264: self.khr_video_decode_h264 && !other.khr_video_decode_h264,
+ khr_video_decode_h265: self.khr_video_decode_h265 && !other.khr_video_decode_h265,
+ khr_video_decode_queue: self.khr_video_decode_queue && !other.khr_video_decode_queue,
+ khr_video_encode_queue: self.khr_video_encode_queue && !other.khr_video_encode_queue,
+ khr_video_queue: self.khr_video_queue && !other.khr_video_queue,
+ khr_vulkan_memory_model: self.khr_vulkan_memory_model && !other.khr_vulkan_memory_model,
+ khr_win32_keyed_mutex: self.khr_win32_keyed_mutex && !other.khr_win32_keyed_mutex,
+ khr_workgroup_memory_explicit_layout: self.khr_workgroup_memory_explicit_layout
+ && !other.khr_workgroup_memory_explicit_layout,
+ khr_zero_initialize_workgroup_memory: self.khr_zero_initialize_workgroup_memory
+ && !other.khr_zero_initialize_workgroup_memory,
+ ext_4444_formats: self.ext_4444_formats && !other.ext_4444_formats,
+ ext_astc_decode_mode: self.ext_astc_decode_mode && !other.ext_astc_decode_mode,
+ ext_attachment_feedback_loop_layout: self.ext_attachment_feedback_loop_layout
+ && !other.ext_attachment_feedback_loop_layout,
+ ext_blend_operation_advanced: self.ext_blend_operation_advanced
+ && !other.ext_blend_operation_advanced,
+ ext_border_color_swizzle: self.ext_border_color_swizzle
+ && !other.ext_border_color_swizzle,
+ ext_buffer_device_address: self.ext_buffer_device_address
+ && !other.ext_buffer_device_address,
+ ext_calibrated_timestamps: self.ext_calibrated_timestamps
+ && !other.ext_calibrated_timestamps,
+ ext_color_write_enable: self.ext_color_write_enable && !other.ext_color_write_enable,
+ ext_conditional_rendering: self.ext_conditional_rendering
+ && !other.ext_conditional_rendering,
+ ext_conservative_rasterization: self.ext_conservative_rasterization
+ && !other.ext_conservative_rasterization,
+ ext_custom_border_color: self.ext_custom_border_color && !other.ext_custom_border_color,
+ ext_debug_marker: self.ext_debug_marker && !other.ext_debug_marker,
+ ext_depth_clamp_zero_one: self.ext_depth_clamp_zero_one
+ && !other.ext_depth_clamp_zero_one,
+ ext_depth_clip_control: self.ext_depth_clip_control && !other.ext_depth_clip_control,
+ ext_depth_clip_enable: self.ext_depth_clip_enable && !other.ext_depth_clip_enable,
+ ext_depth_range_unrestricted: self.ext_depth_range_unrestricted
+ && !other.ext_depth_range_unrestricted,
+ ext_descriptor_buffer: self.ext_descriptor_buffer && !other.ext_descriptor_buffer,
+ ext_descriptor_indexing: self.ext_descriptor_indexing && !other.ext_descriptor_indexing,
+ ext_device_address_binding_report: self.ext_device_address_binding_report
+ && !other.ext_device_address_binding_report,
+ ext_device_fault: self.ext_device_fault && !other.ext_device_fault,
+ ext_device_memory_report: self.ext_device_memory_report
+ && !other.ext_device_memory_report,
+ ext_discard_rectangles: self.ext_discard_rectangles && !other.ext_discard_rectangles,
+ ext_display_control: self.ext_display_control && !other.ext_display_control,
+ ext_extended_dynamic_state: self.ext_extended_dynamic_state
+ && !other.ext_extended_dynamic_state,
+ ext_extended_dynamic_state2: self.ext_extended_dynamic_state2
+ && !other.ext_extended_dynamic_state2,
+ ext_extended_dynamic_state3: self.ext_extended_dynamic_state3
+ && !other.ext_extended_dynamic_state3,
+ ext_external_memory_dma_buf: self.ext_external_memory_dma_buf
+ && !other.ext_external_memory_dma_buf,
+ ext_external_memory_host: self.ext_external_memory_host
+ && !other.ext_external_memory_host,
+ ext_filter_cubic: self.ext_filter_cubic && !other.ext_filter_cubic,
+ ext_fragment_density_map: self.ext_fragment_density_map
+ && !other.ext_fragment_density_map,
+ ext_fragment_density_map2: self.ext_fragment_density_map2
+ && !other.ext_fragment_density_map2,
+ ext_fragment_shader_interlock: self.ext_fragment_shader_interlock
+ && !other.ext_fragment_shader_interlock,
+ ext_full_screen_exclusive: self.ext_full_screen_exclusive
+ && !other.ext_full_screen_exclusive,
+ ext_global_priority: self.ext_global_priority && !other.ext_global_priority,
+ ext_global_priority_query: self.ext_global_priority_query
+ && !other.ext_global_priority_query,
+ ext_graphics_pipeline_library: self.ext_graphics_pipeline_library
+ && !other.ext_graphics_pipeline_library,
+ ext_hdr_metadata: self.ext_hdr_metadata && !other.ext_hdr_metadata,
+ ext_host_query_reset: self.ext_host_query_reset && !other.ext_host_query_reset,
+ ext_image_2d_view_of_3d: self.ext_image_2d_view_of_3d && !other.ext_image_2d_view_of_3d,
+ ext_image_compression_control: self.ext_image_compression_control
+ && !other.ext_image_compression_control,
+ ext_image_compression_control_swapchain: self.ext_image_compression_control_swapchain
+ && !other.ext_image_compression_control_swapchain,
+ ext_image_drm_format_modifier: self.ext_image_drm_format_modifier
+ && !other.ext_image_drm_format_modifier,
+ ext_image_robustness: self.ext_image_robustness && !other.ext_image_robustness,
+ ext_image_view_min_lod: self.ext_image_view_min_lod && !other.ext_image_view_min_lod,
+ ext_index_type_uint8: self.ext_index_type_uint8 && !other.ext_index_type_uint8,
+ ext_inline_uniform_block: self.ext_inline_uniform_block
+ && !other.ext_inline_uniform_block,
+ ext_legacy_dithering: self.ext_legacy_dithering && !other.ext_legacy_dithering,
+ ext_line_rasterization: self.ext_line_rasterization && !other.ext_line_rasterization,
+ ext_load_store_op_none: self.ext_load_store_op_none && !other.ext_load_store_op_none,
+ ext_memory_budget: self.ext_memory_budget && !other.ext_memory_budget,
+ ext_memory_priority: self.ext_memory_priority && !other.ext_memory_priority,
+ ext_mesh_shader: self.ext_mesh_shader && !other.ext_mesh_shader,
+ ext_metal_objects: self.ext_metal_objects && !other.ext_metal_objects,
+ ext_multi_draw: self.ext_multi_draw && !other.ext_multi_draw,
+ ext_multisampled_render_to_single_sampled: self
+ .ext_multisampled_render_to_single_sampled
+ && !other.ext_multisampled_render_to_single_sampled,
+ ext_mutable_descriptor_type: self.ext_mutable_descriptor_type
+ && !other.ext_mutable_descriptor_type,
+ ext_non_seamless_cube_map: self.ext_non_seamless_cube_map
+ && !other.ext_non_seamless_cube_map,
+ ext_opacity_micromap: self.ext_opacity_micromap && !other.ext_opacity_micromap,
+ ext_pageable_device_local_memory: self.ext_pageable_device_local_memory
+ && !other.ext_pageable_device_local_memory,
+ ext_pci_bus_info: self.ext_pci_bus_info && !other.ext_pci_bus_info,
+ ext_physical_device_drm: self.ext_physical_device_drm && !other.ext_physical_device_drm,
+ ext_pipeline_creation_cache_control: self.ext_pipeline_creation_cache_control
+ && !other.ext_pipeline_creation_cache_control,
+ ext_pipeline_creation_feedback: self.ext_pipeline_creation_feedback
+ && !other.ext_pipeline_creation_feedback,
+ ext_pipeline_properties: self.ext_pipeline_properties && !other.ext_pipeline_properties,
+ ext_pipeline_protected_access: self.ext_pipeline_protected_access
+ && !other.ext_pipeline_protected_access,
+ ext_pipeline_robustness: self.ext_pipeline_robustness && !other.ext_pipeline_robustness,
+ ext_post_depth_coverage: self.ext_post_depth_coverage && !other.ext_post_depth_coverage,
+ ext_primitive_topology_list_restart: self.ext_primitive_topology_list_restart
+ && !other.ext_primitive_topology_list_restart,
+ ext_primitives_generated_query: self.ext_primitives_generated_query
+ && !other.ext_primitives_generated_query,
+ ext_private_data: self.ext_private_data && !other.ext_private_data,
+ ext_provoking_vertex: self.ext_provoking_vertex && !other.ext_provoking_vertex,
+ ext_queue_family_foreign: self.ext_queue_family_foreign
+ && !other.ext_queue_family_foreign,
+ ext_rasterization_order_attachment_access: self
+ .ext_rasterization_order_attachment_access
+ && !other.ext_rasterization_order_attachment_access,
+ ext_rgba10x6_formats: self.ext_rgba10x6_formats && !other.ext_rgba10x6_formats,
+ ext_robustness2: self.ext_robustness2 && !other.ext_robustness2,
+ ext_sample_locations: self.ext_sample_locations && !other.ext_sample_locations,
+ ext_sampler_filter_minmax: self.ext_sampler_filter_minmax
+ && !other.ext_sampler_filter_minmax,
+ ext_scalar_block_layout: self.ext_scalar_block_layout && !other.ext_scalar_block_layout,
+ ext_separate_stencil_usage: self.ext_separate_stencil_usage
+ && !other.ext_separate_stencil_usage,
+ ext_shader_atomic_float: self.ext_shader_atomic_float && !other.ext_shader_atomic_float,
+ ext_shader_atomic_float2: self.ext_shader_atomic_float2
+ && !other.ext_shader_atomic_float2,
+ ext_shader_demote_to_helper_invocation: self.ext_shader_demote_to_helper_invocation
+ && !other.ext_shader_demote_to_helper_invocation,
+ ext_shader_image_atomic_int64: self.ext_shader_image_atomic_int64
+ && !other.ext_shader_image_atomic_int64,
+ ext_shader_module_identifier: self.ext_shader_module_identifier
+ && !other.ext_shader_module_identifier,
+ ext_shader_stencil_export: self.ext_shader_stencil_export
+ && !other.ext_shader_stencil_export,
+ ext_shader_subgroup_ballot: self.ext_shader_subgroup_ballot
+ && !other.ext_shader_subgroup_ballot,
+ ext_shader_subgroup_vote: self.ext_shader_subgroup_vote
+ && !other.ext_shader_subgroup_vote,
+ ext_shader_viewport_index_layer: self.ext_shader_viewport_index_layer
+ && !other.ext_shader_viewport_index_layer,
+ ext_subgroup_size_control: self.ext_subgroup_size_control
+ && !other.ext_subgroup_size_control,
+ ext_subpass_merge_feedback: self.ext_subpass_merge_feedback
+ && !other.ext_subpass_merge_feedback,
+ ext_swapchain_maintenance1: self.ext_swapchain_maintenance1
+ && !other.ext_swapchain_maintenance1,
+ ext_texel_buffer_alignment: self.ext_texel_buffer_alignment
+ && !other.ext_texel_buffer_alignment,
+ ext_texture_compression_astc_hdr: self.ext_texture_compression_astc_hdr
+ && !other.ext_texture_compression_astc_hdr,
+ ext_tooling_info: self.ext_tooling_info && !other.ext_tooling_info,
+ ext_transform_feedback: self.ext_transform_feedback && !other.ext_transform_feedback,
+ ext_validation_cache: self.ext_validation_cache && !other.ext_validation_cache,
+ ext_vertex_attribute_divisor: self.ext_vertex_attribute_divisor
+ && !other.ext_vertex_attribute_divisor,
+ ext_vertex_input_dynamic_state: self.ext_vertex_input_dynamic_state
+ && !other.ext_vertex_input_dynamic_state,
+ ext_video_encode_h264: self.ext_video_encode_h264 && !other.ext_video_encode_h264,
+ ext_video_encode_h265: self.ext_video_encode_h265 && !other.ext_video_encode_h265,
+ ext_ycbcr_2plane_444_formats: self.ext_ycbcr_2plane_444_formats
+ && !other.ext_ycbcr_2plane_444_formats,
+ ext_ycbcr_image_arrays: self.ext_ycbcr_image_arrays && !other.ext_ycbcr_image_arrays,
+ amd_buffer_marker: self.amd_buffer_marker && !other.amd_buffer_marker,
+ amd_device_coherent_memory: self.amd_device_coherent_memory
+ && !other.amd_device_coherent_memory,
+ amd_display_native_hdr: self.amd_display_native_hdr && !other.amd_display_native_hdr,
+ amd_draw_indirect_count: self.amd_draw_indirect_count && !other.amd_draw_indirect_count,
+ amd_gcn_shader: self.amd_gcn_shader && !other.amd_gcn_shader,
+ amd_gpu_shader_half_float: self.amd_gpu_shader_half_float
+ && !other.amd_gpu_shader_half_float,
+ amd_gpu_shader_int16: self.amd_gpu_shader_int16 && !other.amd_gpu_shader_int16,
+ amd_memory_overallocation_behavior: self.amd_memory_overallocation_behavior
+ && !other.amd_memory_overallocation_behavior,
+ amd_mixed_attachment_samples: self.amd_mixed_attachment_samples
+ && !other.amd_mixed_attachment_samples,
+ amd_pipeline_compiler_control: self.amd_pipeline_compiler_control
+ && !other.amd_pipeline_compiler_control,
+ amd_rasterization_order: self.amd_rasterization_order && !other.amd_rasterization_order,
+ amd_shader_ballot: self.amd_shader_ballot && !other.amd_shader_ballot,
+ amd_shader_core_properties: self.amd_shader_core_properties
+ && !other.amd_shader_core_properties,
+ amd_shader_core_properties2: self.amd_shader_core_properties2
+ && !other.amd_shader_core_properties2,
+ amd_shader_early_and_late_fragment_tests: self.amd_shader_early_and_late_fragment_tests
+ && !other.amd_shader_early_and_late_fragment_tests,
+ amd_shader_explicit_vertex_parameter: self.amd_shader_explicit_vertex_parameter
+ && !other.amd_shader_explicit_vertex_parameter,
+ amd_shader_fragment_mask: self.amd_shader_fragment_mask
+ && !other.amd_shader_fragment_mask,
+ amd_shader_image_load_store_lod: self.amd_shader_image_load_store_lod
+ && !other.amd_shader_image_load_store_lod,
+ amd_shader_info: self.amd_shader_info && !other.amd_shader_info,
+ amd_shader_trinary_minmax: self.amd_shader_trinary_minmax
+ && !other.amd_shader_trinary_minmax,
+ amd_texture_gather_bias_lod: self.amd_texture_gather_bias_lod
+ && !other.amd_texture_gather_bias_lod,
+ android_external_memory_android_hardware_buffer: self
+ .android_external_memory_android_hardware_buffer
+ && !other.android_external_memory_android_hardware_buffer,
+ arm_rasterization_order_attachment_access: self
+ .arm_rasterization_order_attachment_access
+ && !other.arm_rasterization_order_attachment_access,
+ arm_shader_core_builtins: self.arm_shader_core_builtins
+ && !other.arm_shader_core_builtins,
+ fuchsia_buffer_collection: self.fuchsia_buffer_collection
+ && !other.fuchsia_buffer_collection,
+ fuchsia_external_memory: self.fuchsia_external_memory && !other.fuchsia_external_memory,
+ fuchsia_external_semaphore: self.fuchsia_external_semaphore
+ && !other.fuchsia_external_semaphore,
+ ggp_frame_token: self.ggp_frame_token && !other.ggp_frame_token,
+ google_decorate_string: self.google_decorate_string && !other.google_decorate_string,
+ google_display_timing: self.google_display_timing && !other.google_display_timing,
+ google_hlsl_functionality1: self.google_hlsl_functionality1
+ && !other.google_hlsl_functionality1,
+ google_user_type: self.google_user_type && !other.google_user_type,
+ huawei_invocation_mask: self.huawei_invocation_mask && !other.huawei_invocation_mask,
+ huawei_subpass_shading: self.huawei_subpass_shading && !other.huawei_subpass_shading,
+ img_filter_cubic: self.img_filter_cubic && !other.img_filter_cubic,
+ img_format_pvrtc: self.img_format_pvrtc && !other.img_format_pvrtc,
+ intel_performance_query: self.intel_performance_query && !other.intel_performance_query,
+ intel_shader_integer_functions2: self.intel_shader_integer_functions2
+ && !other.intel_shader_integer_functions2,
+ nvx_binary_import: self.nvx_binary_import && !other.nvx_binary_import,
+ nvx_image_view_handle: self.nvx_image_view_handle && !other.nvx_image_view_handle,
+ nvx_multiview_per_view_attributes: self.nvx_multiview_per_view_attributes
+ && !other.nvx_multiview_per_view_attributes,
+ nv_acquire_winrt_display: self.nv_acquire_winrt_display
+ && !other.nv_acquire_winrt_display,
+ nv_clip_space_w_scaling: self.nv_clip_space_w_scaling && !other.nv_clip_space_w_scaling,
+ nv_compute_shader_derivatives: self.nv_compute_shader_derivatives
+ && !other.nv_compute_shader_derivatives,
+ nv_cooperative_matrix: self.nv_cooperative_matrix && !other.nv_cooperative_matrix,
+ nv_copy_memory_indirect: self.nv_copy_memory_indirect && !other.nv_copy_memory_indirect,
+ nv_corner_sampled_image: self.nv_corner_sampled_image && !other.nv_corner_sampled_image,
+ nv_coverage_reduction_mode: self.nv_coverage_reduction_mode
+ && !other.nv_coverage_reduction_mode,
+ nv_dedicated_allocation: self.nv_dedicated_allocation && !other.nv_dedicated_allocation,
+ nv_dedicated_allocation_image_aliasing: self.nv_dedicated_allocation_image_aliasing
+ && !other.nv_dedicated_allocation_image_aliasing,
+ nv_device_diagnostic_checkpoints: self.nv_device_diagnostic_checkpoints
+ && !other.nv_device_diagnostic_checkpoints,
+ nv_device_diagnostics_config: self.nv_device_diagnostics_config
+ && !other.nv_device_diagnostics_config,
+ nv_device_generated_commands: self.nv_device_generated_commands
+ && !other.nv_device_generated_commands,
+ nv_external_memory: self.nv_external_memory && !other.nv_external_memory,
+ nv_external_memory_rdma: self.nv_external_memory_rdma && !other.nv_external_memory_rdma,
+ nv_external_memory_win32: self.nv_external_memory_win32
+ && !other.nv_external_memory_win32,
+ nv_fill_rectangle: self.nv_fill_rectangle && !other.nv_fill_rectangle,
+ nv_fragment_coverage_to_color: self.nv_fragment_coverage_to_color
+ && !other.nv_fragment_coverage_to_color,
+ nv_fragment_shader_barycentric: self.nv_fragment_shader_barycentric
+ && !other.nv_fragment_shader_barycentric,
+ nv_fragment_shading_rate_enums: self.nv_fragment_shading_rate_enums
+ && !other.nv_fragment_shading_rate_enums,
+ nv_framebuffer_mixed_samples: self.nv_framebuffer_mixed_samples
+ && !other.nv_framebuffer_mixed_samples,
+ nv_geometry_shader_passthrough: self.nv_geometry_shader_passthrough
+ && !other.nv_geometry_shader_passthrough,
+ nv_glsl_shader: self.nv_glsl_shader && !other.nv_glsl_shader,
+ nv_inherited_viewport_scissor: self.nv_inherited_viewport_scissor
+ && !other.nv_inherited_viewport_scissor,
+ nv_linear_color_attachment: self.nv_linear_color_attachment
+ && !other.nv_linear_color_attachment,
+ nv_memory_decompression: self.nv_memory_decompression && !other.nv_memory_decompression,
+ nv_mesh_shader: self.nv_mesh_shader && !other.nv_mesh_shader,
+ nv_optical_flow: self.nv_optical_flow && !other.nv_optical_flow,
+ nv_present_barrier: self.nv_present_barrier && !other.nv_present_barrier,
+ nv_ray_tracing: self.nv_ray_tracing && !other.nv_ray_tracing,
+ nv_ray_tracing_invocation_reorder: self.nv_ray_tracing_invocation_reorder
+ && !other.nv_ray_tracing_invocation_reorder,
+ nv_ray_tracing_motion_blur: self.nv_ray_tracing_motion_blur
+ && !other.nv_ray_tracing_motion_blur,
+ nv_representative_fragment_test: self.nv_representative_fragment_test
+ && !other.nv_representative_fragment_test,
+ nv_sample_mask_override_coverage: self.nv_sample_mask_override_coverage
+ && !other.nv_sample_mask_override_coverage,
+ nv_scissor_exclusive: self.nv_scissor_exclusive && !other.nv_scissor_exclusive,
+ nv_shader_image_footprint: self.nv_shader_image_footprint
+ && !other.nv_shader_image_footprint,
+ nv_shader_sm_builtins: self.nv_shader_sm_builtins && !other.nv_shader_sm_builtins,
+ nv_shader_subgroup_partitioned: self.nv_shader_subgroup_partitioned
+ && !other.nv_shader_subgroup_partitioned,
+ nv_shading_rate_image: self.nv_shading_rate_image && !other.nv_shading_rate_image,
+ nv_viewport_array2: self.nv_viewport_array2 && !other.nv_viewport_array2,
+ nv_viewport_swizzle: self.nv_viewport_swizzle && !other.nv_viewport_swizzle,
+ nv_win32_keyed_mutex: self.nv_win32_keyed_mutex && !other.nv_win32_keyed_mutex,
+ qcom_fragment_density_map_offset: self.qcom_fragment_density_map_offset
+ && !other.qcom_fragment_density_map_offset,
+ qcom_image_processing: self.qcom_image_processing && !other.qcom_image_processing,
+ qcom_multiview_per_view_viewports: self.qcom_multiview_per_view_viewports
+ && !other.qcom_multiview_per_view_viewports,
+ qcom_render_pass_shader_resolve: self.qcom_render_pass_shader_resolve
+ && !other.qcom_render_pass_shader_resolve,
+ qcom_render_pass_store_ops: self.qcom_render_pass_store_ops
+ && !other.qcom_render_pass_store_ops,
+ qcom_render_pass_transform: self.qcom_render_pass_transform
+ && !other.qcom_render_pass_transform,
+ qcom_rotated_copy_commands: self.qcom_rotated_copy_commands
+ && !other.qcom_rotated_copy_commands,
+ qcom_tile_properties: self.qcom_tile_properties && !other.qcom_tile_properties,
+ sec_amigo_profiling: self.sec_amigo_profiling && !other.sec_amigo_profiling,
+ valve_descriptor_set_host_mapping: self.valve_descriptor_set_host_mapping
+ && !other.valve_descriptor_set_host_mapping,
+ valve_mutable_descriptor_type: self.valve_mutable_descriptor_type
+ && !other.valve_mutable_descriptor_type,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+ #[doc = r" Returns the members set in `self` or `other`, but not both."]
+ #[inline]
+ pub const fn symmetric_difference(&self, other: &Self) -> Self {
+ Self {
+ khr_16bit_storage: self.khr_16bit_storage ^ other.khr_16bit_storage,
+ khr_8bit_storage: self.khr_8bit_storage ^ other.khr_8bit_storage,
+ khr_acceleration_structure: self.khr_acceleration_structure
+ ^ other.khr_acceleration_structure,
+ khr_bind_memory2: self.khr_bind_memory2 ^ other.khr_bind_memory2,
+ khr_buffer_device_address: self.khr_buffer_device_address
+ ^ other.khr_buffer_device_address,
+ khr_copy_commands2: self.khr_copy_commands2 ^ other.khr_copy_commands2,
+ khr_create_renderpass2: self.khr_create_renderpass2 ^ other.khr_create_renderpass2,
+ khr_dedicated_allocation: self.khr_dedicated_allocation
+ ^ other.khr_dedicated_allocation,
+ khr_deferred_host_operations: self.khr_deferred_host_operations
+ ^ other.khr_deferred_host_operations,
+ khr_depth_stencil_resolve: self.khr_depth_stencil_resolve
+ ^ other.khr_depth_stencil_resolve,
+ khr_descriptor_update_template: self.khr_descriptor_update_template
+ ^ other.khr_descriptor_update_template,
+ khr_device_group: self.khr_device_group ^ other.khr_device_group,
+ khr_display_swapchain: self.khr_display_swapchain ^ other.khr_display_swapchain,
+ khr_draw_indirect_count: self.khr_draw_indirect_count ^ other.khr_draw_indirect_count,
+ khr_driver_properties: self.khr_driver_properties ^ other.khr_driver_properties,
+ khr_dynamic_rendering: self.khr_dynamic_rendering ^ other.khr_dynamic_rendering,
+ khr_external_fence: self.khr_external_fence ^ other.khr_external_fence,
+ khr_external_fence_fd: self.khr_external_fence_fd ^ other.khr_external_fence_fd,
+ khr_external_fence_win32: self.khr_external_fence_win32
+ ^ other.khr_external_fence_win32,
+ khr_external_memory: self.khr_external_memory ^ other.khr_external_memory,
+ khr_external_memory_fd: self.khr_external_memory_fd ^ other.khr_external_memory_fd,
+ khr_external_memory_win32: self.khr_external_memory_win32
+ ^ other.khr_external_memory_win32,
+ khr_external_semaphore: self.khr_external_semaphore ^ other.khr_external_semaphore,
+ khr_external_semaphore_fd: self.khr_external_semaphore_fd
+ ^ other.khr_external_semaphore_fd,
+ khr_external_semaphore_win32: self.khr_external_semaphore_win32
+ ^ other.khr_external_semaphore_win32,
+ khr_format_feature_flags2: self.khr_format_feature_flags2
+ ^ other.khr_format_feature_flags2,
+ khr_fragment_shader_barycentric: self.khr_fragment_shader_barycentric
+ ^ other.khr_fragment_shader_barycentric,
+ khr_fragment_shading_rate: self.khr_fragment_shading_rate
+ ^ other.khr_fragment_shading_rate,
+ khr_get_memory_requirements2: self.khr_get_memory_requirements2
+ ^ other.khr_get_memory_requirements2,
+ khr_global_priority: self.khr_global_priority ^ other.khr_global_priority,
+ khr_image_format_list: self.khr_image_format_list ^ other.khr_image_format_list,
+ khr_imageless_framebuffer: self.khr_imageless_framebuffer
+ ^ other.khr_imageless_framebuffer,
+ khr_incremental_present: self.khr_incremental_present ^ other.khr_incremental_present,
+ khr_maintenance1: self.khr_maintenance1 ^ other.khr_maintenance1,
+ khr_maintenance2: self.khr_maintenance2 ^ other.khr_maintenance2,
+ khr_maintenance3: self.khr_maintenance3 ^ other.khr_maintenance3,
+ khr_maintenance4: self.khr_maintenance4 ^ other.khr_maintenance4,
+ khr_multiview: self.khr_multiview ^ other.khr_multiview,
+ khr_performance_query: self.khr_performance_query ^ other.khr_performance_query,
+ khr_pipeline_executable_properties: self.khr_pipeline_executable_properties
+ ^ other.khr_pipeline_executable_properties,
+ khr_pipeline_library: self.khr_pipeline_library ^ other.khr_pipeline_library,
+ khr_portability_subset: self.khr_portability_subset ^ other.khr_portability_subset,
+ khr_present_id: self.khr_present_id ^ other.khr_present_id,
+ khr_present_wait: self.khr_present_wait ^ other.khr_present_wait,
+ khr_push_descriptor: self.khr_push_descriptor ^ other.khr_push_descriptor,
+ khr_ray_query: self.khr_ray_query ^ other.khr_ray_query,
+ khr_ray_tracing_maintenance1: self.khr_ray_tracing_maintenance1
+ ^ other.khr_ray_tracing_maintenance1,
+ khr_ray_tracing_pipeline: self.khr_ray_tracing_pipeline
+ ^ other.khr_ray_tracing_pipeline,
+ khr_relaxed_block_layout: self.khr_relaxed_block_layout
+ ^ other.khr_relaxed_block_layout,
+ khr_sampler_mirror_clamp_to_edge: self.khr_sampler_mirror_clamp_to_edge
+ ^ other.khr_sampler_mirror_clamp_to_edge,
+ khr_sampler_ycbcr_conversion: self.khr_sampler_ycbcr_conversion
+ ^ other.khr_sampler_ycbcr_conversion,
+ khr_separate_depth_stencil_layouts: self.khr_separate_depth_stencil_layouts
+ ^ other.khr_separate_depth_stencil_layouts,
+ khr_shader_atomic_int64: self.khr_shader_atomic_int64 ^ other.khr_shader_atomic_int64,
+ khr_shader_clock: self.khr_shader_clock ^ other.khr_shader_clock,
+ khr_shader_draw_parameters: self.khr_shader_draw_parameters
+ ^ other.khr_shader_draw_parameters,
+ khr_shader_float16_int8: self.khr_shader_float16_int8 ^ other.khr_shader_float16_int8,
+ khr_shader_float_controls: self.khr_shader_float_controls
+ ^ other.khr_shader_float_controls,
+ khr_shader_integer_dot_product: self.khr_shader_integer_dot_product
+ ^ other.khr_shader_integer_dot_product,
+ khr_shader_non_semantic_info: self.khr_shader_non_semantic_info
+ ^ other.khr_shader_non_semantic_info,
+ khr_shader_subgroup_extended_types: self.khr_shader_subgroup_extended_types
+ ^ other.khr_shader_subgroup_extended_types,
+ khr_shader_subgroup_uniform_control_flow: self.khr_shader_subgroup_uniform_control_flow
+ ^ other.khr_shader_subgroup_uniform_control_flow,
+ khr_shader_terminate_invocation: self.khr_shader_terminate_invocation
+ ^ other.khr_shader_terminate_invocation,
+ khr_shared_presentable_image: self.khr_shared_presentable_image
+ ^ other.khr_shared_presentable_image,
+ khr_spirv_1_4: self.khr_spirv_1_4 ^ other.khr_spirv_1_4,
+ khr_storage_buffer_storage_class: self.khr_storage_buffer_storage_class
+ ^ other.khr_storage_buffer_storage_class,
+ khr_swapchain: self.khr_swapchain ^ other.khr_swapchain,
+ khr_swapchain_mutable_format: self.khr_swapchain_mutable_format
+ ^ other.khr_swapchain_mutable_format,
+ khr_synchronization2: self.khr_synchronization2 ^ other.khr_synchronization2,
+ khr_timeline_semaphore: self.khr_timeline_semaphore ^ other.khr_timeline_semaphore,
+ khr_uniform_buffer_standard_layout: self.khr_uniform_buffer_standard_layout
+ ^ other.khr_uniform_buffer_standard_layout,
+ khr_variable_pointers: self.khr_variable_pointers ^ other.khr_variable_pointers,
+ khr_video_decode_h264: self.khr_video_decode_h264 ^ other.khr_video_decode_h264,
+ khr_video_decode_h265: self.khr_video_decode_h265 ^ other.khr_video_decode_h265,
+ khr_video_decode_queue: self.khr_video_decode_queue ^ other.khr_video_decode_queue,
+ khr_video_encode_queue: self.khr_video_encode_queue ^ other.khr_video_encode_queue,
+ khr_video_queue: self.khr_video_queue ^ other.khr_video_queue,
+ khr_vulkan_memory_model: self.khr_vulkan_memory_model ^ other.khr_vulkan_memory_model,
+ khr_win32_keyed_mutex: self.khr_win32_keyed_mutex ^ other.khr_win32_keyed_mutex,
+ khr_workgroup_memory_explicit_layout: self.khr_workgroup_memory_explicit_layout
+ ^ other.khr_workgroup_memory_explicit_layout,
+ khr_zero_initialize_workgroup_memory: self.khr_zero_initialize_workgroup_memory
+ ^ other.khr_zero_initialize_workgroup_memory,
+ ext_4444_formats: self.ext_4444_formats ^ other.ext_4444_formats,
+ ext_astc_decode_mode: self.ext_astc_decode_mode ^ other.ext_astc_decode_mode,
+ ext_attachment_feedback_loop_layout: self.ext_attachment_feedback_loop_layout
+ ^ other.ext_attachment_feedback_loop_layout,
+ ext_blend_operation_advanced: self.ext_blend_operation_advanced
+ ^ other.ext_blend_operation_advanced,
+ ext_border_color_swizzle: self.ext_border_color_swizzle
+ ^ other.ext_border_color_swizzle,
+ ext_buffer_device_address: self.ext_buffer_device_address
+ ^ other.ext_buffer_device_address,
+ ext_calibrated_timestamps: self.ext_calibrated_timestamps
+ ^ other.ext_calibrated_timestamps,
+ ext_color_write_enable: self.ext_color_write_enable ^ other.ext_color_write_enable,
+ ext_conditional_rendering: self.ext_conditional_rendering
+ ^ other.ext_conditional_rendering,
+ ext_conservative_rasterization: self.ext_conservative_rasterization
+ ^ other.ext_conservative_rasterization,
+ ext_custom_border_color: self.ext_custom_border_color ^ other.ext_custom_border_color,
+ ext_debug_marker: self.ext_debug_marker ^ other.ext_debug_marker,
+ ext_depth_clamp_zero_one: self.ext_depth_clamp_zero_one
+ ^ other.ext_depth_clamp_zero_one,
+ ext_depth_clip_control: self.ext_depth_clip_control ^ other.ext_depth_clip_control,
+ ext_depth_clip_enable: self.ext_depth_clip_enable ^ other.ext_depth_clip_enable,
+ ext_depth_range_unrestricted: self.ext_depth_range_unrestricted
+ ^ other.ext_depth_range_unrestricted,
+ ext_descriptor_buffer: self.ext_descriptor_buffer ^ other.ext_descriptor_buffer,
+ ext_descriptor_indexing: self.ext_descriptor_indexing ^ other.ext_descriptor_indexing,
+ ext_device_address_binding_report: self.ext_device_address_binding_report
+ ^ other.ext_device_address_binding_report,
+ ext_device_fault: self.ext_device_fault ^ other.ext_device_fault,
+ ext_device_memory_report: self.ext_device_memory_report
+ ^ other.ext_device_memory_report,
+ ext_discard_rectangles: self.ext_discard_rectangles ^ other.ext_discard_rectangles,
+ ext_display_control: self.ext_display_control ^ other.ext_display_control,
+ ext_extended_dynamic_state: self.ext_extended_dynamic_state
+ ^ other.ext_extended_dynamic_state,
+ ext_extended_dynamic_state2: self.ext_extended_dynamic_state2
+ ^ other.ext_extended_dynamic_state2,
+ ext_extended_dynamic_state3: self.ext_extended_dynamic_state3
+ ^ other.ext_extended_dynamic_state3,
+ ext_external_memory_dma_buf: self.ext_external_memory_dma_buf
+ ^ other.ext_external_memory_dma_buf,
+ ext_external_memory_host: self.ext_external_memory_host
+ ^ other.ext_external_memory_host,
+ ext_filter_cubic: self.ext_filter_cubic ^ other.ext_filter_cubic,
+ ext_fragment_density_map: self.ext_fragment_density_map
+ ^ other.ext_fragment_density_map,
+ ext_fragment_density_map2: self.ext_fragment_density_map2
+ ^ other.ext_fragment_density_map2,
+ ext_fragment_shader_interlock: self.ext_fragment_shader_interlock
+ ^ other.ext_fragment_shader_interlock,
+ ext_full_screen_exclusive: self.ext_full_screen_exclusive
+ ^ other.ext_full_screen_exclusive,
+ ext_global_priority: self.ext_global_priority ^ other.ext_global_priority,
+ ext_global_priority_query: self.ext_global_priority_query
+ ^ other.ext_global_priority_query,
+ ext_graphics_pipeline_library: self.ext_graphics_pipeline_library
+ ^ other.ext_graphics_pipeline_library,
+ ext_hdr_metadata: self.ext_hdr_metadata ^ other.ext_hdr_metadata,
+ ext_host_query_reset: self.ext_host_query_reset ^ other.ext_host_query_reset,
+ ext_image_2d_view_of_3d: self.ext_image_2d_view_of_3d ^ other.ext_image_2d_view_of_3d,
+ ext_image_compression_control: self.ext_image_compression_control
+ ^ other.ext_image_compression_control,
+ ext_image_compression_control_swapchain: self.ext_image_compression_control_swapchain
+ ^ other.ext_image_compression_control_swapchain,
+ ext_image_drm_format_modifier: self.ext_image_drm_format_modifier
+ ^ other.ext_image_drm_format_modifier,
+ ext_image_robustness: self.ext_image_robustness ^ other.ext_image_robustness,
+ ext_image_view_min_lod: self.ext_image_view_min_lod ^ other.ext_image_view_min_lod,
+ ext_index_type_uint8: self.ext_index_type_uint8 ^ other.ext_index_type_uint8,
+ ext_inline_uniform_block: self.ext_inline_uniform_block
+ ^ other.ext_inline_uniform_block,
+ ext_legacy_dithering: self.ext_legacy_dithering ^ other.ext_legacy_dithering,
+ ext_line_rasterization: self.ext_line_rasterization ^ other.ext_line_rasterization,
+ ext_load_store_op_none: self.ext_load_store_op_none ^ other.ext_load_store_op_none,
+ ext_memory_budget: self.ext_memory_budget ^ other.ext_memory_budget,
+ ext_memory_priority: self.ext_memory_priority ^ other.ext_memory_priority,
+ ext_mesh_shader: self.ext_mesh_shader ^ other.ext_mesh_shader,
+ ext_metal_objects: self.ext_metal_objects ^ other.ext_metal_objects,
+ ext_multi_draw: self.ext_multi_draw ^ other.ext_multi_draw,
+ ext_multisampled_render_to_single_sampled: self
+ .ext_multisampled_render_to_single_sampled
+ ^ other.ext_multisampled_render_to_single_sampled,
+ ext_mutable_descriptor_type: self.ext_mutable_descriptor_type
+ ^ other.ext_mutable_descriptor_type,
+ ext_non_seamless_cube_map: self.ext_non_seamless_cube_map
+ ^ other.ext_non_seamless_cube_map,
+ ext_opacity_micromap: self.ext_opacity_micromap ^ other.ext_opacity_micromap,
+ ext_pageable_device_local_memory: self.ext_pageable_device_local_memory
+ ^ other.ext_pageable_device_local_memory,
+ ext_pci_bus_info: self.ext_pci_bus_info ^ other.ext_pci_bus_info,
+ ext_physical_device_drm: self.ext_physical_device_drm ^ other.ext_physical_device_drm,
+ ext_pipeline_creation_cache_control: self.ext_pipeline_creation_cache_control
+ ^ other.ext_pipeline_creation_cache_control,
+ ext_pipeline_creation_feedback: self.ext_pipeline_creation_feedback
+ ^ other.ext_pipeline_creation_feedback,
+ ext_pipeline_properties: self.ext_pipeline_properties ^ other.ext_pipeline_properties,
+ ext_pipeline_protected_access: self.ext_pipeline_protected_access
+ ^ other.ext_pipeline_protected_access,
+ ext_pipeline_robustness: self.ext_pipeline_robustness ^ other.ext_pipeline_robustness,
+ ext_post_depth_coverage: self.ext_post_depth_coverage ^ other.ext_post_depth_coverage,
+ ext_primitive_topology_list_restart: self.ext_primitive_topology_list_restart
+ ^ other.ext_primitive_topology_list_restart,
+ ext_primitives_generated_query: self.ext_primitives_generated_query
+ ^ other.ext_primitives_generated_query,
+ ext_private_data: self.ext_private_data ^ other.ext_private_data,
+ ext_provoking_vertex: self.ext_provoking_vertex ^ other.ext_provoking_vertex,
+ ext_queue_family_foreign: self.ext_queue_family_foreign
+ ^ other.ext_queue_family_foreign,
+ ext_rasterization_order_attachment_access: self
+ .ext_rasterization_order_attachment_access
+ ^ other.ext_rasterization_order_attachment_access,
+ ext_rgba10x6_formats: self.ext_rgba10x6_formats ^ other.ext_rgba10x6_formats,
+ ext_robustness2: self.ext_robustness2 ^ other.ext_robustness2,
+ ext_sample_locations: self.ext_sample_locations ^ other.ext_sample_locations,
+ ext_sampler_filter_minmax: self.ext_sampler_filter_minmax
+ ^ other.ext_sampler_filter_minmax,
+ ext_scalar_block_layout: self.ext_scalar_block_layout ^ other.ext_scalar_block_layout,
+ ext_separate_stencil_usage: self.ext_separate_stencil_usage
+ ^ other.ext_separate_stencil_usage,
+ ext_shader_atomic_float: self.ext_shader_atomic_float ^ other.ext_shader_atomic_float,
+ ext_shader_atomic_float2: self.ext_shader_atomic_float2
+ ^ other.ext_shader_atomic_float2,
+ ext_shader_demote_to_helper_invocation: self.ext_shader_demote_to_helper_invocation
+ ^ other.ext_shader_demote_to_helper_invocation,
+ ext_shader_image_atomic_int64: self.ext_shader_image_atomic_int64
+ ^ other.ext_shader_image_atomic_int64,
+ ext_shader_module_identifier: self.ext_shader_module_identifier
+ ^ other.ext_shader_module_identifier,
+ ext_shader_stencil_export: self.ext_shader_stencil_export
+ ^ other.ext_shader_stencil_export,
+ ext_shader_subgroup_ballot: self.ext_shader_subgroup_ballot
+ ^ other.ext_shader_subgroup_ballot,
+ ext_shader_subgroup_vote: self.ext_shader_subgroup_vote
+ ^ other.ext_shader_subgroup_vote,
+ ext_shader_viewport_index_layer: self.ext_shader_viewport_index_layer
+ ^ other.ext_shader_viewport_index_layer,
+ ext_subgroup_size_control: self.ext_subgroup_size_control
+ ^ other.ext_subgroup_size_control,
+ ext_subpass_merge_feedback: self.ext_subpass_merge_feedback
+ ^ other.ext_subpass_merge_feedback,
+ ext_swapchain_maintenance1: self.ext_swapchain_maintenance1
+ ^ other.ext_swapchain_maintenance1,
+ ext_texel_buffer_alignment: self.ext_texel_buffer_alignment
+ ^ other.ext_texel_buffer_alignment,
+ ext_texture_compression_astc_hdr: self.ext_texture_compression_astc_hdr
+ ^ other.ext_texture_compression_astc_hdr,
+ ext_tooling_info: self.ext_tooling_info ^ other.ext_tooling_info,
+ ext_transform_feedback: self.ext_transform_feedback ^ other.ext_transform_feedback,
+ ext_validation_cache: self.ext_validation_cache ^ other.ext_validation_cache,
+ ext_vertex_attribute_divisor: self.ext_vertex_attribute_divisor
+ ^ other.ext_vertex_attribute_divisor,
+ ext_vertex_input_dynamic_state: self.ext_vertex_input_dynamic_state
+ ^ other.ext_vertex_input_dynamic_state,
+ ext_video_encode_h264: self.ext_video_encode_h264 ^ other.ext_video_encode_h264,
+ ext_video_encode_h265: self.ext_video_encode_h265 ^ other.ext_video_encode_h265,
+ ext_ycbcr_2plane_444_formats: self.ext_ycbcr_2plane_444_formats
+ ^ other.ext_ycbcr_2plane_444_formats,
+ ext_ycbcr_image_arrays: self.ext_ycbcr_image_arrays ^ other.ext_ycbcr_image_arrays,
+ amd_buffer_marker: self.amd_buffer_marker ^ other.amd_buffer_marker,
+ amd_device_coherent_memory: self.amd_device_coherent_memory
+ ^ other.amd_device_coherent_memory,
+ amd_display_native_hdr: self.amd_display_native_hdr ^ other.amd_display_native_hdr,
+ amd_draw_indirect_count: self.amd_draw_indirect_count ^ other.amd_draw_indirect_count,
+ amd_gcn_shader: self.amd_gcn_shader ^ other.amd_gcn_shader,
+ amd_gpu_shader_half_float: self.amd_gpu_shader_half_float
+ ^ other.amd_gpu_shader_half_float,
+ amd_gpu_shader_int16: self.amd_gpu_shader_int16 ^ other.amd_gpu_shader_int16,
+ amd_memory_overallocation_behavior: self.amd_memory_overallocation_behavior
+ ^ other.amd_memory_overallocation_behavior,
+ amd_mixed_attachment_samples: self.amd_mixed_attachment_samples
+ ^ other.amd_mixed_attachment_samples,
+ amd_pipeline_compiler_control: self.amd_pipeline_compiler_control
+ ^ other.amd_pipeline_compiler_control,
+ amd_rasterization_order: self.amd_rasterization_order ^ other.amd_rasterization_order,
+ amd_shader_ballot: self.amd_shader_ballot ^ other.amd_shader_ballot,
+ amd_shader_core_properties: self.amd_shader_core_properties
+ ^ other.amd_shader_core_properties,
+ amd_shader_core_properties2: self.amd_shader_core_properties2
+ ^ other.amd_shader_core_properties2,
+ amd_shader_early_and_late_fragment_tests: self.amd_shader_early_and_late_fragment_tests
+ ^ other.amd_shader_early_and_late_fragment_tests,
+ amd_shader_explicit_vertex_parameter: self.amd_shader_explicit_vertex_parameter
+ ^ other.amd_shader_explicit_vertex_parameter,
+ amd_shader_fragment_mask: self.amd_shader_fragment_mask
+ ^ other.amd_shader_fragment_mask,
+ amd_shader_image_load_store_lod: self.amd_shader_image_load_store_lod
+ ^ other.amd_shader_image_load_store_lod,
+ amd_shader_info: self.amd_shader_info ^ other.amd_shader_info,
+ amd_shader_trinary_minmax: self.amd_shader_trinary_minmax
+ ^ other.amd_shader_trinary_minmax,
+ amd_texture_gather_bias_lod: self.amd_texture_gather_bias_lod
+ ^ other.amd_texture_gather_bias_lod,
+ android_external_memory_android_hardware_buffer: self
+ .android_external_memory_android_hardware_buffer
+ ^ other.android_external_memory_android_hardware_buffer,
+ arm_rasterization_order_attachment_access: self
+ .arm_rasterization_order_attachment_access
+ ^ other.arm_rasterization_order_attachment_access,
+ arm_shader_core_builtins: self.arm_shader_core_builtins
+ ^ other.arm_shader_core_builtins,
+ fuchsia_buffer_collection: self.fuchsia_buffer_collection
+ ^ other.fuchsia_buffer_collection,
+ fuchsia_external_memory: self.fuchsia_external_memory ^ other.fuchsia_external_memory,
+ fuchsia_external_semaphore: self.fuchsia_external_semaphore
+ ^ other.fuchsia_external_semaphore,
+ ggp_frame_token: self.ggp_frame_token ^ other.ggp_frame_token,
+ google_decorate_string: self.google_decorate_string ^ other.google_decorate_string,
+ google_display_timing: self.google_display_timing ^ other.google_display_timing,
+ google_hlsl_functionality1: self.google_hlsl_functionality1
+ ^ other.google_hlsl_functionality1,
+ google_user_type: self.google_user_type ^ other.google_user_type,
+ huawei_invocation_mask: self.huawei_invocation_mask ^ other.huawei_invocation_mask,
+ huawei_subpass_shading: self.huawei_subpass_shading ^ other.huawei_subpass_shading,
+ img_filter_cubic: self.img_filter_cubic ^ other.img_filter_cubic,
+ img_format_pvrtc: self.img_format_pvrtc ^ other.img_format_pvrtc,
+ intel_performance_query: self.intel_performance_query ^ other.intel_performance_query,
+ intel_shader_integer_functions2: self.intel_shader_integer_functions2
+ ^ other.intel_shader_integer_functions2,
+ nvx_binary_import: self.nvx_binary_import ^ other.nvx_binary_import,
+ nvx_image_view_handle: self.nvx_image_view_handle ^ other.nvx_image_view_handle,
+ nvx_multiview_per_view_attributes: self.nvx_multiview_per_view_attributes
+ ^ other.nvx_multiview_per_view_attributes,
+ nv_acquire_winrt_display: self.nv_acquire_winrt_display
+ ^ other.nv_acquire_winrt_display,
+ nv_clip_space_w_scaling: self.nv_clip_space_w_scaling ^ other.nv_clip_space_w_scaling,
+ nv_compute_shader_derivatives: self.nv_compute_shader_derivatives
+ ^ other.nv_compute_shader_derivatives,
+ nv_cooperative_matrix: self.nv_cooperative_matrix ^ other.nv_cooperative_matrix,
+ nv_copy_memory_indirect: self.nv_copy_memory_indirect ^ other.nv_copy_memory_indirect,
+ nv_corner_sampled_image: self.nv_corner_sampled_image ^ other.nv_corner_sampled_image,
+ nv_coverage_reduction_mode: self.nv_coverage_reduction_mode
+ ^ other.nv_coverage_reduction_mode,
+ nv_dedicated_allocation: self.nv_dedicated_allocation ^ other.nv_dedicated_allocation,
+ nv_dedicated_allocation_image_aliasing: self.nv_dedicated_allocation_image_aliasing
+ ^ other.nv_dedicated_allocation_image_aliasing,
+ nv_device_diagnostic_checkpoints: self.nv_device_diagnostic_checkpoints
+ ^ other.nv_device_diagnostic_checkpoints,
+ nv_device_diagnostics_config: self.nv_device_diagnostics_config
+ ^ other.nv_device_diagnostics_config,
+ nv_device_generated_commands: self.nv_device_generated_commands
+ ^ other.nv_device_generated_commands,
+ nv_external_memory: self.nv_external_memory ^ other.nv_external_memory,
+ nv_external_memory_rdma: self.nv_external_memory_rdma ^ other.nv_external_memory_rdma,
+ nv_external_memory_win32: self.nv_external_memory_win32
+ ^ other.nv_external_memory_win32,
+ nv_fill_rectangle: self.nv_fill_rectangle ^ other.nv_fill_rectangle,
+ nv_fragment_coverage_to_color: self.nv_fragment_coverage_to_color
+ ^ other.nv_fragment_coverage_to_color,
+ nv_fragment_shader_barycentric: self.nv_fragment_shader_barycentric
+ ^ other.nv_fragment_shader_barycentric,
+ nv_fragment_shading_rate_enums: self.nv_fragment_shading_rate_enums
+ ^ other.nv_fragment_shading_rate_enums,
+ nv_framebuffer_mixed_samples: self.nv_framebuffer_mixed_samples
+ ^ other.nv_framebuffer_mixed_samples,
+ nv_geometry_shader_passthrough: self.nv_geometry_shader_passthrough
+ ^ other.nv_geometry_shader_passthrough,
+ nv_glsl_shader: self.nv_glsl_shader ^ other.nv_glsl_shader,
+ nv_inherited_viewport_scissor: self.nv_inherited_viewport_scissor
+ ^ other.nv_inherited_viewport_scissor,
+ nv_linear_color_attachment: self.nv_linear_color_attachment
+ ^ other.nv_linear_color_attachment,
+ nv_memory_decompression: self.nv_memory_decompression ^ other.nv_memory_decompression,
+ nv_mesh_shader: self.nv_mesh_shader ^ other.nv_mesh_shader,
+ nv_optical_flow: self.nv_optical_flow ^ other.nv_optical_flow,
+ nv_present_barrier: self.nv_present_barrier ^ other.nv_present_barrier,
+ nv_ray_tracing: self.nv_ray_tracing ^ other.nv_ray_tracing,
+ nv_ray_tracing_invocation_reorder: self.nv_ray_tracing_invocation_reorder
+ ^ other.nv_ray_tracing_invocation_reorder,
+ nv_ray_tracing_motion_blur: self.nv_ray_tracing_motion_blur
+ ^ other.nv_ray_tracing_motion_blur,
+ nv_representative_fragment_test: self.nv_representative_fragment_test
+ ^ other.nv_representative_fragment_test,
+ nv_sample_mask_override_coverage: self.nv_sample_mask_override_coverage
+ ^ other.nv_sample_mask_override_coverage,
+ nv_scissor_exclusive: self.nv_scissor_exclusive ^ other.nv_scissor_exclusive,
+ nv_shader_image_footprint: self.nv_shader_image_footprint
+ ^ other.nv_shader_image_footprint,
+ nv_shader_sm_builtins: self.nv_shader_sm_builtins ^ other.nv_shader_sm_builtins,
+ nv_shader_subgroup_partitioned: self.nv_shader_subgroup_partitioned
+ ^ other.nv_shader_subgroup_partitioned,
+ nv_shading_rate_image: self.nv_shading_rate_image ^ other.nv_shading_rate_image,
+ nv_viewport_array2: self.nv_viewport_array2 ^ other.nv_viewport_array2,
+ nv_viewport_swizzle: self.nv_viewport_swizzle ^ other.nv_viewport_swizzle,
+ nv_win32_keyed_mutex: self.nv_win32_keyed_mutex ^ other.nv_win32_keyed_mutex,
+ qcom_fragment_density_map_offset: self.qcom_fragment_density_map_offset
+ ^ other.qcom_fragment_density_map_offset,
+ qcom_image_processing: self.qcom_image_processing ^ other.qcom_image_processing,
+ qcom_multiview_per_view_viewports: self.qcom_multiview_per_view_viewports
+ ^ other.qcom_multiview_per_view_viewports,
+ qcom_render_pass_shader_resolve: self.qcom_render_pass_shader_resolve
+ ^ other.qcom_render_pass_shader_resolve,
+ qcom_render_pass_store_ops: self.qcom_render_pass_store_ops
+ ^ other.qcom_render_pass_store_ops,
+ qcom_render_pass_transform: self.qcom_render_pass_transform
+ ^ other.qcom_render_pass_transform,
+ qcom_rotated_copy_commands: self.qcom_rotated_copy_commands
+ ^ other.qcom_rotated_copy_commands,
+ qcom_tile_properties: self.qcom_tile_properties ^ other.qcom_tile_properties,
+ sec_amigo_profiling: self.sec_amigo_profiling ^ other.sec_amigo_profiling,
+ valve_descriptor_set_host_mapping: self.valve_descriptor_set_host_mapping
+ ^ other.valve_descriptor_set_host_mapping,
+ valve_mutable_descriptor_type: self.valve_mutable_descriptor_type
+ ^ other.valve_mutable_descriptor_type,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+impl std::ops::BitAnd for DeviceExtensions {
+ type Output = DeviceExtensions;
+ #[inline]
+ fn bitand(self, rhs: Self) -> Self::Output {
+ self.union(&rhs)
+ }
+}
+impl std::ops::BitAndAssign for DeviceExtensions {
+ #[inline]
+ fn bitand_assign(&mut self, rhs: Self) {
+ *self = self.union(&rhs);
+ }
+}
+impl std::ops::BitOr for DeviceExtensions {
+ type Output = DeviceExtensions;
+ #[inline]
+ fn bitor(self, rhs: Self) -> Self::Output {
+ self.intersection(&rhs)
+ }
+}
+impl std::ops::BitOrAssign for DeviceExtensions {
+ #[inline]
+ fn bitor_assign(&mut self, rhs: Self) {
+ *self = self.intersection(&rhs);
+ }
+}
+impl std::ops::BitXor for DeviceExtensions {
+ type Output = DeviceExtensions;
+ #[inline]
+ fn bitxor(self, rhs: Self) -> Self::Output {
+ self.symmetric_difference(&rhs)
+ }
+}
+impl std::ops::BitXorAssign for DeviceExtensions {
+ #[inline]
+ fn bitxor_assign(&mut self, rhs: Self) {
+ *self = self.symmetric_difference(&rhs);
+ }
+}
+impl std::ops::Sub for DeviceExtensions {
+ type Output = DeviceExtensions;
+ #[inline]
+ fn sub(self, rhs: Self) -> Self::Output {
+ self.difference(&rhs)
+ }
+}
+impl std::ops::SubAssign for DeviceExtensions {
+ #[inline]
+ fn sub_assign(&mut self, rhs: Self) {
+ *self = self.difference(&rhs);
+ }
+}
+impl std::fmt::Debug for DeviceExtensions {
+ #[allow(unused_assignments)]
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
+ write!(f, "[")?;
+ let mut first = true;
+ if self.khr_16bit_storage {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_16bit_storage")?;
+ }
+ if self.khr_8bit_storage {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_8bit_storage")?;
+ }
+ if self.khr_acceleration_structure {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_acceleration_structure")?;
+ }
+ if self.khr_bind_memory2 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_bind_memory2")?;
+ }
+ if self.khr_buffer_device_address {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_buffer_device_address")?;
+ }
+ if self.khr_copy_commands2 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_copy_commands2")?;
+ }
+ if self.khr_create_renderpass2 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_create_renderpass2")?;
+ }
+ if self.khr_dedicated_allocation {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_dedicated_allocation")?;
+ }
+ if self.khr_deferred_host_operations {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_deferred_host_operations")?;
+ }
+ if self.khr_depth_stencil_resolve {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_depth_stencil_resolve")?;
+ }
+ if self.khr_descriptor_update_template {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_descriptor_update_template")?;
+ }
+ if self.khr_device_group {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_device_group")?;
+ }
+ if self.khr_display_swapchain {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_display_swapchain")?;
+ }
+ if self.khr_draw_indirect_count {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_draw_indirect_count")?;
+ }
+ if self.khr_driver_properties {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_driver_properties")?;
+ }
+ if self.khr_dynamic_rendering {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_dynamic_rendering")?;
+ }
+ if self.khr_external_fence {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_external_fence")?;
+ }
+ if self.khr_external_fence_fd {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_external_fence_fd")?;
+ }
+ if self.khr_external_fence_win32 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_external_fence_win32")?;
+ }
+ if self.khr_external_memory {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_external_memory")?;
+ }
+ if self.khr_external_memory_fd {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_external_memory_fd")?;
+ }
+ if self.khr_external_memory_win32 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_external_memory_win32")?;
+ }
+ if self.khr_external_semaphore {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_external_semaphore")?;
+ }
+ if self.khr_external_semaphore_fd {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_external_semaphore_fd")?;
+ }
+ if self.khr_external_semaphore_win32 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_external_semaphore_win32")?;
+ }
+ if self.khr_format_feature_flags2 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_format_feature_flags2")?;
+ }
+ if self.khr_fragment_shader_barycentric {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_fragment_shader_barycentric")?;
+ }
+ if self.khr_fragment_shading_rate {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_fragment_shading_rate")?;
+ }
+ if self.khr_get_memory_requirements2 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_get_memory_requirements2")?;
+ }
+ if self.khr_global_priority {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_global_priority")?;
+ }
+ if self.khr_image_format_list {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_image_format_list")?;
+ }
+ if self.khr_imageless_framebuffer {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_imageless_framebuffer")?;
+ }
+ if self.khr_incremental_present {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_incremental_present")?;
+ }
+ if self.khr_maintenance1 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_maintenance1")?;
+ }
+ if self.khr_maintenance2 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_maintenance2")?;
+ }
+ if self.khr_maintenance3 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_maintenance3")?;
+ }
+ if self.khr_maintenance4 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_maintenance4")?;
+ }
+ if self.khr_multiview {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_multiview")?;
+ }
+ if self.khr_performance_query {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_performance_query")?;
+ }
+ if self.khr_pipeline_executable_properties {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_pipeline_executable_properties")?;
+ }
+ if self.khr_pipeline_library {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_pipeline_library")?;
+ }
+ if self.khr_portability_subset {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_portability_subset")?;
+ }
+ if self.khr_present_id {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_present_id")?;
+ }
+ if self.khr_present_wait {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_present_wait")?;
+ }
+ if self.khr_push_descriptor {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_push_descriptor")?;
+ }
+ if self.khr_ray_query {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_ray_query")?;
+ }
+ if self.khr_ray_tracing_maintenance1 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_ray_tracing_maintenance1")?;
+ }
+ if self.khr_ray_tracing_pipeline {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_ray_tracing_pipeline")?;
+ }
+ if self.khr_relaxed_block_layout {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_relaxed_block_layout")?;
+ }
+ if self.khr_sampler_mirror_clamp_to_edge {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_sampler_mirror_clamp_to_edge")?;
+ }
+ if self.khr_sampler_ycbcr_conversion {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_sampler_ycbcr_conversion")?;
+ }
+ if self.khr_separate_depth_stencil_layouts {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_separate_depth_stencil_layouts")?;
+ }
+ if self.khr_shader_atomic_int64 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_shader_atomic_int64")?;
+ }
+ if self.khr_shader_clock {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_shader_clock")?;
+ }
+ if self.khr_shader_draw_parameters {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_shader_draw_parameters")?;
+ }
+ if self.khr_shader_float16_int8 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_shader_float16_int8")?;
+ }
+ if self.khr_shader_float_controls {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_shader_float_controls")?;
+ }
+ if self.khr_shader_integer_dot_product {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_shader_integer_dot_product")?;
+ }
+ if self.khr_shader_non_semantic_info {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_shader_non_semantic_info")?;
+ }
+ if self.khr_shader_subgroup_extended_types {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_shader_subgroup_extended_types")?;
+ }
+ if self.khr_shader_subgroup_uniform_control_flow {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_shader_subgroup_uniform_control_flow")?;
+ }
+ if self.khr_shader_terminate_invocation {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_shader_terminate_invocation")?;
+ }
+ if self.khr_shared_presentable_image {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_shared_presentable_image")?;
+ }
+ if self.khr_spirv_1_4 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_spirv_1_4")?;
+ }
+ if self.khr_storage_buffer_storage_class {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_storage_buffer_storage_class")?;
+ }
+ if self.khr_swapchain {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_swapchain")?;
+ }
+ if self.khr_swapchain_mutable_format {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_swapchain_mutable_format")?;
+ }
+ if self.khr_synchronization2 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_synchronization2")?;
+ }
+ if self.khr_timeline_semaphore {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_timeline_semaphore")?;
+ }
+ if self.khr_uniform_buffer_standard_layout {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_uniform_buffer_standard_layout")?;
+ }
+ if self.khr_variable_pointers {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_variable_pointers")?;
+ }
+ if self.khr_video_decode_h264 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_video_decode_h264")?;
+ }
+ if self.khr_video_decode_h265 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_video_decode_h265")?;
+ }
+ if self.khr_video_decode_queue {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_video_decode_queue")?;
+ }
+ if self.khr_video_encode_queue {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_video_encode_queue")?;
+ }
+ if self.khr_video_queue {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_video_queue")?;
+ }
+ if self.khr_vulkan_memory_model {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_vulkan_memory_model")?;
+ }
+ if self.khr_win32_keyed_mutex {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_win32_keyed_mutex")?;
+ }
+ if self.khr_workgroup_memory_explicit_layout {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_workgroup_memory_explicit_layout")?;
+ }
+ if self.khr_zero_initialize_workgroup_memory {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_zero_initialize_workgroup_memory")?;
+ }
+ if self.ext_4444_formats {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_4444_formats")?;
+ }
+ if self.ext_astc_decode_mode {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_astc_decode_mode")?;
+ }
+ if self.ext_attachment_feedback_loop_layout {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_attachment_feedback_loop_layout")?;
+ }
+ if self.ext_blend_operation_advanced {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_blend_operation_advanced")?;
+ }
+ if self.ext_border_color_swizzle {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_border_color_swizzle")?;
+ }
+ if self.ext_buffer_device_address {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_buffer_device_address")?;
+ }
+ if self.ext_calibrated_timestamps {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_calibrated_timestamps")?;
+ }
+ if self.ext_color_write_enable {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_color_write_enable")?;
+ }
+ if self.ext_conditional_rendering {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_conditional_rendering")?;
+ }
+ if self.ext_conservative_rasterization {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_conservative_rasterization")?;
+ }
+ if self.ext_custom_border_color {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_custom_border_color")?;
+ }
+ if self.ext_debug_marker {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_debug_marker")?;
+ }
+ if self.ext_depth_clamp_zero_one {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_depth_clamp_zero_one")?;
+ }
+ if self.ext_depth_clip_control {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_depth_clip_control")?;
+ }
+ if self.ext_depth_clip_enable {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_depth_clip_enable")?;
+ }
+ if self.ext_depth_range_unrestricted {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_depth_range_unrestricted")?;
+ }
+ if self.ext_descriptor_buffer {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_descriptor_buffer")?;
+ }
+ if self.ext_descriptor_indexing {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_descriptor_indexing")?;
+ }
+ if self.ext_device_address_binding_report {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_device_address_binding_report")?;
+ }
+ if self.ext_device_fault {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_device_fault")?;
+ }
+ if self.ext_device_memory_report {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_device_memory_report")?;
+ }
+ if self.ext_discard_rectangles {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_discard_rectangles")?;
+ }
+ if self.ext_display_control {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_display_control")?;
+ }
+ if self.ext_extended_dynamic_state {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_extended_dynamic_state")?;
+ }
+ if self.ext_extended_dynamic_state2 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_extended_dynamic_state2")?;
+ }
+ if self.ext_extended_dynamic_state3 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_extended_dynamic_state3")?;
+ }
+ if self.ext_external_memory_dma_buf {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_external_memory_dma_buf")?;
+ }
+ if self.ext_external_memory_host {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_external_memory_host")?;
+ }
+ if self.ext_filter_cubic {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_filter_cubic")?;
+ }
+ if self.ext_fragment_density_map {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_fragment_density_map")?;
+ }
+ if self.ext_fragment_density_map2 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_fragment_density_map2")?;
+ }
+ if self.ext_fragment_shader_interlock {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_fragment_shader_interlock")?;
+ }
+ if self.ext_full_screen_exclusive {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_full_screen_exclusive")?;
+ }
+ if self.ext_global_priority {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_global_priority")?;
+ }
+ if self.ext_global_priority_query {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_global_priority_query")?;
+ }
+ if self.ext_graphics_pipeline_library {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_graphics_pipeline_library")?;
+ }
+ if self.ext_hdr_metadata {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_hdr_metadata")?;
+ }
+ if self.ext_host_query_reset {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_host_query_reset")?;
+ }
+ if self.ext_image_2d_view_of_3d {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_image_2d_view_of_3d")?;
+ }
+ if self.ext_image_compression_control {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_image_compression_control")?;
+ }
+ if self.ext_image_compression_control_swapchain {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_image_compression_control_swapchain")?;
+ }
+ if self.ext_image_drm_format_modifier {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_image_drm_format_modifier")?;
+ }
+ if self.ext_image_robustness {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_image_robustness")?;
+ }
+ if self.ext_image_view_min_lod {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_image_view_min_lod")?;
+ }
+ if self.ext_index_type_uint8 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_index_type_uint8")?;
+ }
+ if self.ext_inline_uniform_block {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_inline_uniform_block")?;
+ }
+ if self.ext_legacy_dithering {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_legacy_dithering")?;
+ }
+ if self.ext_line_rasterization {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_line_rasterization")?;
+ }
+ if self.ext_load_store_op_none {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_load_store_op_none")?;
+ }
+ if self.ext_memory_budget {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_memory_budget")?;
+ }
+ if self.ext_memory_priority {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_memory_priority")?;
+ }
+ if self.ext_mesh_shader {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_mesh_shader")?;
+ }
+ if self.ext_metal_objects {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_metal_objects")?;
+ }
+ if self.ext_multi_draw {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_multi_draw")?;
+ }
+ if self.ext_multisampled_render_to_single_sampled {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_multisampled_render_to_single_sampled")?;
+ }
+ if self.ext_mutable_descriptor_type {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_mutable_descriptor_type")?;
+ }
+ if self.ext_non_seamless_cube_map {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_non_seamless_cube_map")?;
+ }
+ if self.ext_opacity_micromap {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_opacity_micromap")?;
+ }
+ if self.ext_pageable_device_local_memory {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_pageable_device_local_memory")?;
+ }
+ if self.ext_pci_bus_info {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_pci_bus_info")?;
+ }
+ if self.ext_physical_device_drm {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_physical_device_drm")?;
+ }
+ if self.ext_pipeline_creation_cache_control {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_pipeline_creation_cache_control")?;
+ }
+ if self.ext_pipeline_creation_feedback {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_pipeline_creation_feedback")?;
+ }
+ if self.ext_pipeline_properties {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_pipeline_properties")?;
+ }
+ if self.ext_pipeline_protected_access {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_pipeline_protected_access")?;
+ }
+ if self.ext_pipeline_robustness {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_pipeline_robustness")?;
+ }
+ if self.ext_post_depth_coverage {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_post_depth_coverage")?;
+ }
+ if self.ext_primitive_topology_list_restart {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_primitive_topology_list_restart")?;
+ }
+ if self.ext_primitives_generated_query {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_primitives_generated_query")?;
+ }
+ if self.ext_private_data {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_private_data")?;
+ }
+ if self.ext_provoking_vertex {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_provoking_vertex")?;
+ }
+ if self.ext_queue_family_foreign {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_queue_family_foreign")?;
+ }
+ if self.ext_rasterization_order_attachment_access {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_rasterization_order_attachment_access")?;
+ }
+ if self.ext_rgba10x6_formats {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_rgba10x6_formats")?;
+ }
+ if self.ext_robustness2 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_robustness2")?;
+ }
+ if self.ext_sample_locations {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_sample_locations")?;
+ }
+ if self.ext_sampler_filter_minmax {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_sampler_filter_minmax")?;
+ }
+ if self.ext_scalar_block_layout {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_scalar_block_layout")?;
+ }
+ if self.ext_separate_stencil_usage {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_separate_stencil_usage")?;
+ }
+ if self.ext_shader_atomic_float {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_shader_atomic_float")?;
+ }
+ if self.ext_shader_atomic_float2 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_shader_atomic_float2")?;
+ }
+ if self.ext_shader_demote_to_helper_invocation {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_shader_demote_to_helper_invocation")?;
+ }
+ if self.ext_shader_image_atomic_int64 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_shader_image_atomic_int64")?;
+ }
+ if self.ext_shader_module_identifier {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_shader_module_identifier")?;
+ }
+ if self.ext_shader_stencil_export {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_shader_stencil_export")?;
+ }
+ if self.ext_shader_subgroup_ballot {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_shader_subgroup_ballot")?;
+ }
+ if self.ext_shader_subgroup_vote {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_shader_subgroup_vote")?;
+ }
+ if self.ext_shader_viewport_index_layer {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_shader_viewport_index_layer")?;
+ }
+ if self.ext_subgroup_size_control {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_subgroup_size_control")?;
+ }
+ if self.ext_subpass_merge_feedback {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_subpass_merge_feedback")?;
+ }
+ if self.ext_swapchain_maintenance1 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_swapchain_maintenance1")?;
+ }
+ if self.ext_texel_buffer_alignment {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_texel_buffer_alignment")?;
+ }
+ if self.ext_texture_compression_astc_hdr {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_texture_compression_astc_hdr")?;
+ }
+ if self.ext_tooling_info {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_tooling_info")?;
+ }
+ if self.ext_transform_feedback {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_transform_feedback")?;
+ }
+ if self.ext_validation_cache {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_validation_cache")?;
+ }
+ if self.ext_vertex_attribute_divisor {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_vertex_attribute_divisor")?;
+ }
+ if self.ext_vertex_input_dynamic_state {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_vertex_input_dynamic_state")?;
+ }
+ if self.ext_video_encode_h264 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_video_encode_h264")?;
+ }
+ if self.ext_video_encode_h265 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_video_encode_h265")?;
+ }
+ if self.ext_ycbcr_2plane_444_formats {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_ycbcr_2plane_444_formats")?;
+ }
+ if self.ext_ycbcr_image_arrays {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_ycbcr_image_arrays")?;
+ }
+ if self.amd_buffer_marker {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_AMD_buffer_marker")?;
+ }
+ if self.amd_device_coherent_memory {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_AMD_device_coherent_memory")?;
+ }
+ if self.amd_display_native_hdr {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_AMD_display_native_hdr")?;
+ }
+ if self.amd_draw_indirect_count {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_AMD_draw_indirect_count")?;
+ }
+ if self.amd_gcn_shader {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_AMD_gcn_shader")?;
+ }
+ if self.amd_gpu_shader_half_float {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_AMD_gpu_shader_half_float")?;
+ }
+ if self.amd_gpu_shader_int16 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_AMD_gpu_shader_int16")?;
+ }
+ if self.amd_memory_overallocation_behavior {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_AMD_memory_overallocation_behavior")?;
+ }
+ if self.amd_mixed_attachment_samples {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_AMD_mixed_attachment_samples")?;
+ }
+ if self.amd_pipeline_compiler_control {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_AMD_pipeline_compiler_control")?;
+ }
+ if self.amd_rasterization_order {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_AMD_rasterization_order")?;
+ }
+ if self.amd_shader_ballot {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_AMD_shader_ballot")?;
+ }
+ if self.amd_shader_core_properties {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_AMD_shader_core_properties")?;
+ }
+ if self.amd_shader_core_properties2 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_AMD_shader_core_properties2")?;
+ }
+ if self.amd_shader_early_and_late_fragment_tests {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_AMD_shader_early_and_late_fragment_tests")?;
+ }
+ if self.amd_shader_explicit_vertex_parameter {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_AMD_shader_explicit_vertex_parameter")?;
+ }
+ if self.amd_shader_fragment_mask {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_AMD_shader_fragment_mask")?;
+ }
+ if self.amd_shader_image_load_store_lod {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_AMD_shader_image_load_store_lod")?;
+ }
+ if self.amd_shader_info {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_AMD_shader_info")?;
+ }
+ if self.amd_shader_trinary_minmax {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_AMD_shader_trinary_minmax")?;
+ }
+ if self.amd_texture_gather_bias_lod {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_AMD_texture_gather_bias_lod")?;
+ }
+ if self.android_external_memory_android_hardware_buffer {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_ANDROID_external_memory_android_hardware_buffer")?;
+ }
+ if self.arm_rasterization_order_attachment_access {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_ARM_rasterization_order_attachment_access")?;
+ }
+ if self.arm_shader_core_builtins {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_ARM_shader_core_builtins")?;
+ }
+ if self.fuchsia_buffer_collection {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_FUCHSIA_buffer_collection")?;
+ }
+ if self.fuchsia_external_memory {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_FUCHSIA_external_memory")?;
+ }
+ if self.fuchsia_external_semaphore {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_FUCHSIA_external_semaphore")?;
+ }
+ if self.ggp_frame_token {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_GGP_frame_token")?;
+ }
+ if self.google_decorate_string {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_GOOGLE_decorate_string")?;
+ }
+ if self.google_display_timing {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_GOOGLE_display_timing")?;
+ }
+ if self.google_hlsl_functionality1 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_GOOGLE_hlsl_functionality1")?;
+ }
+ if self.google_user_type {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_GOOGLE_user_type")?;
+ }
+ if self.huawei_invocation_mask {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_HUAWEI_invocation_mask")?;
+ }
+ if self.huawei_subpass_shading {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_HUAWEI_subpass_shading")?;
+ }
+ if self.img_filter_cubic {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_IMG_filter_cubic")?;
+ }
+ if self.img_format_pvrtc {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_IMG_format_pvrtc")?;
+ }
+ if self.intel_performance_query {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_INTEL_performance_query")?;
+ }
+ if self.intel_shader_integer_functions2 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_INTEL_shader_integer_functions2")?;
+ }
+ if self.nvx_binary_import {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NVX_binary_import")?;
+ }
+ if self.nvx_image_view_handle {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NVX_image_view_handle")?;
+ }
+ if self.nvx_multiview_per_view_attributes {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NVX_multiview_per_view_attributes")?;
+ }
+ if self.nv_acquire_winrt_display {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_acquire_winrt_display")?;
+ }
+ if self.nv_clip_space_w_scaling {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_clip_space_w_scaling")?;
+ }
+ if self.nv_compute_shader_derivatives {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_compute_shader_derivatives")?;
+ }
+ if self.nv_cooperative_matrix {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_cooperative_matrix")?;
+ }
+ if self.nv_copy_memory_indirect {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_copy_memory_indirect")?;
+ }
+ if self.nv_corner_sampled_image {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_corner_sampled_image")?;
+ }
+ if self.nv_coverage_reduction_mode {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_coverage_reduction_mode")?;
+ }
+ if self.nv_dedicated_allocation {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_dedicated_allocation")?;
+ }
+ if self.nv_dedicated_allocation_image_aliasing {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_dedicated_allocation_image_aliasing")?;
+ }
+ if self.nv_device_diagnostic_checkpoints {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_device_diagnostic_checkpoints")?;
+ }
+ if self.nv_device_diagnostics_config {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_device_diagnostics_config")?;
+ }
+ if self.nv_device_generated_commands {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_device_generated_commands")?;
+ }
+ if self.nv_external_memory {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_external_memory")?;
+ }
+ if self.nv_external_memory_rdma {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_external_memory_rdma")?;
+ }
+ if self.nv_external_memory_win32 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_external_memory_win32")?;
+ }
+ if self.nv_fill_rectangle {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_fill_rectangle")?;
+ }
+ if self.nv_fragment_coverage_to_color {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_fragment_coverage_to_color")?;
+ }
+ if self.nv_fragment_shader_barycentric {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_fragment_shader_barycentric")?;
+ }
+ if self.nv_fragment_shading_rate_enums {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_fragment_shading_rate_enums")?;
+ }
+ if self.nv_framebuffer_mixed_samples {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_framebuffer_mixed_samples")?;
+ }
+ if self.nv_geometry_shader_passthrough {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_geometry_shader_passthrough")?;
+ }
+ if self.nv_glsl_shader {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_glsl_shader")?;
+ }
+ if self.nv_inherited_viewport_scissor {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_inherited_viewport_scissor")?;
+ }
+ if self.nv_linear_color_attachment {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_linear_color_attachment")?;
+ }
+ if self.nv_memory_decompression {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_memory_decompression")?;
+ }
+ if self.nv_mesh_shader {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_mesh_shader")?;
+ }
+ if self.nv_optical_flow {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_optical_flow")?;
+ }
+ if self.nv_present_barrier {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_present_barrier")?;
+ }
+ if self.nv_ray_tracing {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_ray_tracing")?;
+ }
+ if self.nv_ray_tracing_invocation_reorder {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_ray_tracing_invocation_reorder")?;
+ }
+ if self.nv_ray_tracing_motion_blur {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_ray_tracing_motion_blur")?;
+ }
+ if self.nv_representative_fragment_test {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_representative_fragment_test")?;
+ }
+ if self.nv_sample_mask_override_coverage {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_sample_mask_override_coverage")?;
+ }
+ if self.nv_scissor_exclusive {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_scissor_exclusive")?;
+ }
+ if self.nv_shader_image_footprint {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_shader_image_footprint")?;
+ }
+ if self.nv_shader_sm_builtins {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_shader_sm_builtins")?;
+ }
+ if self.nv_shader_subgroup_partitioned {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_shader_subgroup_partitioned")?;
+ }
+ if self.nv_shading_rate_image {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_shading_rate_image")?;
+ }
+ if self.nv_viewport_array2 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_viewport_array2")?;
+ }
+ if self.nv_viewport_swizzle {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_viewport_swizzle")?;
+ }
+ if self.nv_win32_keyed_mutex {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_win32_keyed_mutex")?;
+ }
+ if self.qcom_fragment_density_map_offset {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_QCOM_fragment_density_map_offset")?;
+ }
+ if self.qcom_image_processing {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_QCOM_image_processing")?;
+ }
+ if self.qcom_multiview_per_view_viewports {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_QCOM_multiview_per_view_viewports")?;
+ }
+ if self.qcom_render_pass_shader_resolve {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_QCOM_render_pass_shader_resolve")?;
+ }
+ if self.qcom_render_pass_store_ops {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_QCOM_render_pass_store_ops")?;
+ }
+ if self.qcom_render_pass_transform {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_QCOM_render_pass_transform")?;
+ }
+ if self.qcom_rotated_copy_commands {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_QCOM_rotated_copy_commands")?;
+ }
+ if self.qcom_tile_properties {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_QCOM_tile_properties")?;
+ }
+ if self.sec_amigo_profiling {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_SEC_amigo_profiling")?;
+ }
+ if self.valve_descriptor_set_host_mapping {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_VALVE_descriptor_set_host_mapping")?;
+ }
+ if self.valve_mutable_descriptor_type {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_VALVE_mutable_descriptor_type")?;
+ }
+ write!(f, "]")
+ }
+}
+impl<'a> FromIterator<&'a str> for DeviceExtensions {
+ fn from_iter<I>(iter: I) -> Self
+ where
+ I: IntoIterator<Item = &'a str>,
+ {
+ let mut extensions = Self::empty();
+ for name in iter {
+ match name {
+ "VK_KHR_16bit_storage" => {
+ extensions.khr_16bit_storage = true;
+ }
+ "VK_KHR_8bit_storage" => {
+ extensions.khr_8bit_storage = true;
+ }
+ "VK_KHR_acceleration_structure" => {
+ extensions.khr_acceleration_structure = true;
+ }
+ "VK_KHR_bind_memory2" => {
+ extensions.khr_bind_memory2 = true;
+ }
+ "VK_KHR_buffer_device_address" => {
+ extensions.khr_buffer_device_address = true;
+ }
+ "VK_KHR_copy_commands2" => {
+ extensions.khr_copy_commands2 = true;
+ }
+ "VK_KHR_create_renderpass2" => {
+ extensions.khr_create_renderpass2 = true;
+ }
+ "VK_KHR_dedicated_allocation" => {
+ extensions.khr_dedicated_allocation = true;
+ }
+ "VK_KHR_deferred_host_operations" => {
+ extensions.khr_deferred_host_operations = true;
+ }
+ "VK_KHR_depth_stencil_resolve" => {
+ extensions.khr_depth_stencil_resolve = true;
+ }
+ "VK_KHR_descriptor_update_template" => {
+ extensions.khr_descriptor_update_template = true;
+ }
+ "VK_KHR_device_group" => {
+ extensions.khr_device_group = true;
+ }
+ "VK_KHR_display_swapchain" => {
+ extensions.khr_display_swapchain = true;
+ }
+ "VK_KHR_draw_indirect_count" => {
+ extensions.khr_draw_indirect_count = true;
+ }
+ "VK_KHR_driver_properties" => {
+ extensions.khr_driver_properties = true;
+ }
+ "VK_KHR_dynamic_rendering" => {
+ extensions.khr_dynamic_rendering = true;
+ }
+ "VK_KHR_external_fence" => {
+ extensions.khr_external_fence = true;
+ }
+ "VK_KHR_external_fence_fd" => {
+ extensions.khr_external_fence_fd = true;
+ }
+ "VK_KHR_external_fence_win32" => {
+ extensions.khr_external_fence_win32 = true;
+ }
+ "VK_KHR_external_memory" => {
+ extensions.khr_external_memory = true;
+ }
+ "VK_KHR_external_memory_fd" => {
+ extensions.khr_external_memory_fd = true;
+ }
+ "VK_KHR_external_memory_win32" => {
+ extensions.khr_external_memory_win32 = true;
+ }
+ "VK_KHR_external_semaphore" => {
+ extensions.khr_external_semaphore = true;
+ }
+ "VK_KHR_external_semaphore_fd" => {
+ extensions.khr_external_semaphore_fd = true;
+ }
+ "VK_KHR_external_semaphore_win32" => {
+ extensions.khr_external_semaphore_win32 = true;
+ }
+ "VK_KHR_format_feature_flags2" => {
+ extensions.khr_format_feature_flags2 = true;
+ }
+ "VK_KHR_fragment_shader_barycentric" => {
+ extensions.khr_fragment_shader_barycentric = true;
+ }
+ "VK_KHR_fragment_shading_rate" => {
+ extensions.khr_fragment_shading_rate = true;
+ }
+ "VK_KHR_get_memory_requirements2" => {
+ extensions.khr_get_memory_requirements2 = true;
+ }
+ "VK_KHR_global_priority" => {
+ extensions.khr_global_priority = true;
+ }
+ "VK_KHR_image_format_list" => {
+ extensions.khr_image_format_list = true;
+ }
+ "VK_KHR_imageless_framebuffer" => {
+ extensions.khr_imageless_framebuffer = true;
+ }
+ "VK_KHR_incremental_present" => {
+ extensions.khr_incremental_present = true;
+ }
+ "VK_KHR_maintenance1" => {
+ extensions.khr_maintenance1 = true;
+ }
+ "VK_KHR_maintenance2" => {
+ extensions.khr_maintenance2 = true;
+ }
+ "VK_KHR_maintenance3" => {
+ extensions.khr_maintenance3 = true;
+ }
+ "VK_KHR_maintenance4" => {
+ extensions.khr_maintenance4 = true;
+ }
+ "VK_KHR_multiview" => {
+ extensions.khr_multiview = true;
+ }
+ "VK_KHR_performance_query" => {
+ extensions.khr_performance_query = true;
+ }
+ "VK_KHR_pipeline_executable_properties" => {
+ extensions.khr_pipeline_executable_properties = true;
+ }
+ "VK_KHR_pipeline_library" => {
+ extensions.khr_pipeline_library = true;
+ }
+ "VK_KHR_portability_subset" => {
+ extensions.khr_portability_subset = true;
+ }
+ "VK_KHR_present_id" => {
+ extensions.khr_present_id = true;
+ }
+ "VK_KHR_present_wait" => {
+ extensions.khr_present_wait = true;
+ }
+ "VK_KHR_push_descriptor" => {
+ extensions.khr_push_descriptor = true;
+ }
+ "VK_KHR_ray_query" => {
+ extensions.khr_ray_query = true;
+ }
+ "VK_KHR_ray_tracing_maintenance1" => {
+ extensions.khr_ray_tracing_maintenance1 = true;
+ }
+ "VK_KHR_ray_tracing_pipeline" => {
+ extensions.khr_ray_tracing_pipeline = true;
+ }
+ "VK_KHR_relaxed_block_layout" => {
+ extensions.khr_relaxed_block_layout = true;
+ }
+ "VK_KHR_sampler_mirror_clamp_to_edge" => {
+ extensions.khr_sampler_mirror_clamp_to_edge = true;
+ }
+ "VK_KHR_sampler_ycbcr_conversion" => {
+ extensions.khr_sampler_ycbcr_conversion = true;
+ }
+ "VK_KHR_separate_depth_stencil_layouts" => {
+ extensions.khr_separate_depth_stencil_layouts = true;
+ }
+ "VK_KHR_shader_atomic_int64" => {
+ extensions.khr_shader_atomic_int64 = true;
+ }
+ "VK_KHR_shader_clock" => {
+ extensions.khr_shader_clock = true;
+ }
+ "VK_KHR_shader_draw_parameters" => {
+ extensions.khr_shader_draw_parameters = true;
+ }
+ "VK_KHR_shader_float16_int8" => {
+ extensions.khr_shader_float16_int8 = true;
+ }
+ "VK_KHR_shader_float_controls" => {
+ extensions.khr_shader_float_controls = true;
+ }
+ "VK_KHR_shader_integer_dot_product" => {
+ extensions.khr_shader_integer_dot_product = true;
+ }
+ "VK_KHR_shader_non_semantic_info" => {
+ extensions.khr_shader_non_semantic_info = true;
+ }
+ "VK_KHR_shader_subgroup_extended_types" => {
+ extensions.khr_shader_subgroup_extended_types = true;
+ }
+ "VK_KHR_shader_subgroup_uniform_control_flow" => {
+ extensions.khr_shader_subgroup_uniform_control_flow = true;
+ }
+ "VK_KHR_shader_terminate_invocation" => {
+ extensions.khr_shader_terminate_invocation = true;
+ }
+ "VK_KHR_shared_presentable_image" => {
+ extensions.khr_shared_presentable_image = true;
+ }
+ "VK_KHR_spirv_1_4" => {
+ extensions.khr_spirv_1_4 = true;
+ }
+ "VK_KHR_storage_buffer_storage_class" => {
+ extensions.khr_storage_buffer_storage_class = true;
+ }
+ "VK_KHR_swapchain" => {
+ extensions.khr_swapchain = true;
+ }
+ "VK_KHR_swapchain_mutable_format" => {
+ extensions.khr_swapchain_mutable_format = true;
+ }
+ "VK_KHR_synchronization2" => {
+ extensions.khr_synchronization2 = true;
+ }
+ "VK_KHR_timeline_semaphore" => {
+ extensions.khr_timeline_semaphore = true;
+ }
+ "VK_KHR_uniform_buffer_standard_layout" => {
+ extensions.khr_uniform_buffer_standard_layout = true;
+ }
+ "VK_KHR_variable_pointers" => {
+ extensions.khr_variable_pointers = true;
+ }
+ "VK_KHR_video_decode_h264" => {
+ extensions.khr_video_decode_h264 = true;
+ }
+ "VK_KHR_video_decode_h265" => {
+ extensions.khr_video_decode_h265 = true;
+ }
+ "VK_KHR_video_decode_queue" => {
+ extensions.khr_video_decode_queue = true;
+ }
+ "VK_KHR_video_encode_queue" => {
+ extensions.khr_video_encode_queue = true;
+ }
+ "VK_KHR_video_queue" => {
+ extensions.khr_video_queue = true;
+ }
+ "VK_KHR_vulkan_memory_model" => {
+ extensions.khr_vulkan_memory_model = true;
+ }
+ "VK_KHR_win32_keyed_mutex" => {
+ extensions.khr_win32_keyed_mutex = true;
+ }
+ "VK_KHR_workgroup_memory_explicit_layout" => {
+ extensions.khr_workgroup_memory_explicit_layout = true;
+ }
+ "VK_KHR_zero_initialize_workgroup_memory" => {
+ extensions.khr_zero_initialize_workgroup_memory = true;
+ }
+ "VK_EXT_4444_formats" => {
+ extensions.ext_4444_formats = true;
+ }
+ "VK_EXT_astc_decode_mode" => {
+ extensions.ext_astc_decode_mode = true;
+ }
+ "VK_EXT_attachment_feedback_loop_layout" => {
+ extensions.ext_attachment_feedback_loop_layout = true;
+ }
+ "VK_EXT_blend_operation_advanced" => {
+ extensions.ext_blend_operation_advanced = true;
+ }
+ "VK_EXT_border_color_swizzle" => {
+ extensions.ext_border_color_swizzle = true;
+ }
+ "VK_EXT_buffer_device_address" => {
+ extensions.ext_buffer_device_address = true;
+ }
+ "VK_EXT_calibrated_timestamps" => {
+ extensions.ext_calibrated_timestamps = true;
+ }
+ "VK_EXT_color_write_enable" => {
+ extensions.ext_color_write_enable = true;
+ }
+ "VK_EXT_conditional_rendering" => {
+ extensions.ext_conditional_rendering = true;
+ }
+ "VK_EXT_conservative_rasterization" => {
+ extensions.ext_conservative_rasterization = true;
+ }
+ "VK_EXT_custom_border_color" => {
+ extensions.ext_custom_border_color = true;
+ }
+ "VK_EXT_debug_marker" => {
+ extensions.ext_debug_marker = true;
+ }
+ "VK_EXT_depth_clamp_zero_one" => {
+ extensions.ext_depth_clamp_zero_one = true;
+ }
+ "VK_EXT_depth_clip_control" => {
+ extensions.ext_depth_clip_control = true;
+ }
+ "VK_EXT_depth_clip_enable" => {
+ extensions.ext_depth_clip_enable = true;
+ }
+ "VK_EXT_depth_range_unrestricted" => {
+ extensions.ext_depth_range_unrestricted = true;
+ }
+ "VK_EXT_descriptor_buffer" => {
+ extensions.ext_descriptor_buffer = true;
+ }
+ "VK_EXT_descriptor_indexing" => {
+ extensions.ext_descriptor_indexing = true;
+ }
+ "VK_EXT_device_address_binding_report" => {
+ extensions.ext_device_address_binding_report = true;
+ }
+ "VK_EXT_device_fault" => {
+ extensions.ext_device_fault = true;
+ }
+ "VK_EXT_device_memory_report" => {
+ extensions.ext_device_memory_report = true;
+ }
+ "VK_EXT_discard_rectangles" => {
+ extensions.ext_discard_rectangles = true;
+ }
+ "VK_EXT_display_control" => {
+ extensions.ext_display_control = true;
+ }
+ "VK_EXT_extended_dynamic_state" => {
+ extensions.ext_extended_dynamic_state = true;
+ }
+ "VK_EXT_extended_dynamic_state2" => {
+ extensions.ext_extended_dynamic_state2 = true;
+ }
+ "VK_EXT_extended_dynamic_state3" => {
+ extensions.ext_extended_dynamic_state3 = true;
+ }
+ "VK_EXT_external_memory_dma_buf" => {
+ extensions.ext_external_memory_dma_buf = true;
+ }
+ "VK_EXT_external_memory_host" => {
+ extensions.ext_external_memory_host = true;
+ }
+ "VK_EXT_filter_cubic" => {
+ extensions.ext_filter_cubic = true;
+ }
+ "VK_EXT_fragment_density_map" => {
+ extensions.ext_fragment_density_map = true;
+ }
+ "VK_EXT_fragment_density_map2" => {
+ extensions.ext_fragment_density_map2 = true;
+ }
+ "VK_EXT_fragment_shader_interlock" => {
+ extensions.ext_fragment_shader_interlock = true;
+ }
+ "VK_EXT_full_screen_exclusive" => {
+ extensions.ext_full_screen_exclusive = true;
+ }
+ "VK_EXT_global_priority" => {
+ extensions.ext_global_priority = true;
+ }
+ "VK_EXT_global_priority_query" => {
+ extensions.ext_global_priority_query = true;
+ }
+ "VK_EXT_graphics_pipeline_library" => {
+ extensions.ext_graphics_pipeline_library = true;
+ }
+ "VK_EXT_hdr_metadata" => {
+ extensions.ext_hdr_metadata = true;
+ }
+ "VK_EXT_host_query_reset" => {
+ extensions.ext_host_query_reset = true;
+ }
+ "VK_EXT_image_2d_view_of_3d" => {
+ extensions.ext_image_2d_view_of_3d = true;
+ }
+ "VK_EXT_image_compression_control" => {
+ extensions.ext_image_compression_control = true;
+ }
+ "VK_EXT_image_compression_control_swapchain" => {
+ extensions.ext_image_compression_control_swapchain = true;
+ }
+ "VK_EXT_image_drm_format_modifier" => {
+ extensions.ext_image_drm_format_modifier = true;
+ }
+ "VK_EXT_image_robustness" => {
+ extensions.ext_image_robustness = true;
+ }
+ "VK_EXT_image_view_min_lod" => {
+ extensions.ext_image_view_min_lod = true;
+ }
+ "VK_EXT_index_type_uint8" => {
+ extensions.ext_index_type_uint8 = true;
+ }
+ "VK_EXT_inline_uniform_block" => {
+ extensions.ext_inline_uniform_block = true;
+ }
+ "VK_EXT_legacy_dithering" => {
+ extensions.ext_legacy_dithering = true;
+ }
+ "VK_EXT_line_rasterization" => {
+ extensions.ext_line_rasterization = true;
+ }
+ "VK_EXT_load_store_op_none" => {
+ extensions.ext_load_store_op_none = true;
+ }
+ "VK_EXT_memory_budget" => {
+ extensions.ext_memory_budget = true;
+ }
+ "VK_EXT_memory_priority" => {
+ extensions.ext_memory_priority = true;
+ }
+ "VK_EXT_mesh_shader" => {
+ extensions.ext_mesh_shader = true;
+ }
+ "VK_EXT_metal_objects" => {
+ extensions.ext_metal_objects = true;
+ }
+ "VK_EXT_multi_draw" => {
+ extensions.ext_multi_draw = true;
+ }
+ "VK_EXT_multisampled_render_to_single_sampled" => {
+ extensions.ext_multisampled_render_to_single_sampled = true;
+ }
+ "VK_EXT_mutable_descriptor_type" => {
+ extensions.ext_mutable_descriptor_type = true;
+ }
+ "VK_EXT_non_seamless_cube_map" => {
+ extensions.ext_non_seamless_cube_map = true;
+ }
+ "VK_EXT_opacity_micromap" => {
+ extensions.ext_opacity_micromap = true;
+ }
+ "VK_EXT_pageable_device_local_memory" => {
+ extensions.ext_pageable_device_local_memory = true;
+ }
+ "VK_EXT_pci_bus_info" => {
+ extensions.ext_pci_bus_info = true;
+ }
+ "VK_EXT_physical_device_drm" => {
+ extensions.ext_physical_device_drm = true;
+ }
+ "VK_EXT_pipeline_creation_cache_control" => {
+ extensions.ext_pipeline_creation_cache_control = true;
+ }
+ "VK_EXT_pipeline_creation_feedback" => {
+ extensions.ext_pipeline_creation_feedback = true;
+ }
+ "VK_EXT_pipeline_properties" => {
+ extensions.ext_pipeline_properties = true;
+ }
+ "VK_EXT_pipeline_protected_access" => {
+ extensions.ext_pipeline_protected_access = true;
+ }
+ "VK_EXT_pipeline_robustness" => {
+ extensions.ext_pipeline_robustness = true;
+ }
+ "VK_EXT_post_depth_coverage" => {
+ extensions.ext_post_depth_coverage = true;
+ }
+ "VK_EXT_primitive_topology_list_restart" => {
+ extensions.ext_primitive_topology_list_restart = true;
+ }
+ "VK_EXT_primitives_generated_query" => {
+ extensions.ext_primitives_generated_query = true;
+ }
+ "VK_EXT_private_data" => {
+ extensions.ext_private_data = true;
+ }
+ "VK_EXT_provoking_vertex" => {
+ extensions.ext_provoking_vertex = true;
+ }
+ "VK_EXT_queue_family_foreign" => {
+ extensions.ext_queue_family_foreign = true;
+ }
+ "VK_EXT_rasterization_order_attachment_access" => {
+ extensions.ext_rasterization_order_attachment_access = true;
+ }
+ "VK_EXT_rgba10x6_formats" => {
+ extensions.ext_rgba10x6_formats = true;
+ }
+ "VK_EXT_robustness2" => {
+ extensions.ext_robustness2 = true;
+ }
+ "VK_EXT_sample_locations" => {
+ extensions.ext_sample_locations = true;
+ }
+ "VK_EXT_sampler_filter_minmax" => {
+ extensions.ext_sampler_filter_minmax = true;
+ }
+ "VK_EXT_scalar_block_layout" => {
+ extensions.ext_scalar_block_layout = true;
+ }
+ "VK_EXT_separate_stencil_usage" => {
+ extensions.ext_separate_stencil_usage = true;
+ }
+ "VK_EXT_shader_atomic_float" => {
+ extensions.ext_shader_atomic_float = true;
+ }
+ "VK_EXT_shader_atomic_float2" => {
+ extensions.ext_shader_atomic_float2 = true;
+ }
+ "VK_EXT_shader_demote_to_helper_invocation" => {
+ extensions.ext_shader_demote_to_helper_invocation = true;
+ }
+ "VK_EXT_shader_image_atomic_int64" => {
+ extensions.ext_shader_image_atomic_int64 = true;
+ }
+ "VK_EXT_shader_module_identifier" => {
+ extensions.ext_shader_module_identifier = true;
+ }
+ "VK_EXT_shader_stencil_export" => {
+ extensions.ext_shader_stencil_export = true;
+ }
+ "VK_EXT_shader_subgroup_ballot" => {
+ extensions.ext_shader_subgroup_ballot = true;
+ }
+ "VK_EXT_shader_subgroup_vote" => {
+ extensions.ext_shader_subgroup_vote = true;
+ }
+ "VK_EXT_shader_viewport_index_layer" => {
+ extensions.ext_shader_viewport_index_layer = true;
+ }
+ "VK_EXT_subgroup_size_control" => {
+ extensions.ext_subgroup_size_control = true;
+ }
+ "VK_EXT_subpass_merge_feedback" => {
+ extensions.ext_subpass_merge_feedback = true;
+ }
+ "VK_EXT_swapchain_maintenance1" => {
+ extensions.ext_swapchain_maintenance1 = true;
+ }
+ "VK_EXT_texel_buffer_alignment" => {
+ extensions.ext_texel_buffer_alignment = true;
+ }
+ "VK_EXT_texture_compression_astc_hdr" => {
+ extensions.ext_texture_compression_astc_hdr = true;
+ }
+ "VK_EXT_tooling_info" => {
+ extensions.ext_tooling_info = true;
+ }
+ "VK_EXT_transform_feedback" => {
+ extensions.ext_transform_feedback = true;
+ }
+ "VK_EXT_validation_cache" => {
+ extensions.ext_validation_cache = true;
+ }
+ "VK_EXT_vertex_attribute_divisor" => {
+ extensions.ext_vertex_attribute_divisor = true;
+ }
+ "VK_EXT_vertex_input_dynamic_state" => {
+ extensions.ext_vertex_input_dynamic_state = true;
+ }
+ "VK_EXT_video_encode_h264" => {
+ extensions.ext_video_encode_h264 = true;
+ }
+ "VK_EXT_video_encode_h265" => {
+ extensions.ext_video_encode_h265 = true;
+ }
+ "VK_EXT_ycbcr_2plane_444_formats" => {
+ extensions.ext_ycbcr_2plane_444_formats = true;
+ }
+ "VK_EXT_ycbcr_image_arrays" => {
+ extensions.ext_ycbcr_image_arrays = true;
+ }
+ "VK_AMD_buffer_marker" => {
+ extensions.amd_buffer_marker = true;
+ }
+ "VK_AMD_device_coherent_memory" => {
+ extensions.amd_device_coherent_memory = true;
+ }
+ "VK_AMD_display_native_hdr" => {
+ extensions.amd_display_native_hdr = true;
+ }
+ "VK_AMD_draw_indirect_count" => {
+ extensions.amd_draw_indirect_count = true;
+ }
+ "VK_AMD_gcn_shader" => {
+ extensions.amd_gcn_shader = true;
+ }
+ "VK_AMD_gpu_shader_half_float" => {
+ extensions.amd_gpu_shader_half_float = true;
+ }
+ "VK_AMD_gpu_shader_int16" => {
+ extensions.amd_gpu_shader_int16 = true;
+ }
+ "VK_AMD_memory_overallocation_behavior" => {
+ extensions.amd_memory_overallocation_behavior = true;
+ }
+ "VK_AMD_mixed_attachment_samples" => {
+ extensions.amd_mixed_attachment_samples = true;
+ }
+ "VK_AMD_pipeline_compiler_control" => {
+ extensions.amd_pipeline_compiler_control = true;
+ }
+ "VK_AMD_rasterization_order" => {
+ extensions.amd_rasterization_order = true;
+ }
+ "VK_AMD_shader_ballot" => {
+ extensions.amd_shader_ballot = true;
+ }
+ "VK_AMD_shader_core_properties" => {
+ extensions.amd_shader_core_properties = true;
+ }
+ "VK_AMD_shader_core_properties2" => {
+ extensions.amd_shader_core_properties2 = true;
+ }
+ "VK_AMD_shader_early_and_late_fragment_tests" => {
+ extensions.amd_shader_early_and_late_fragment_tests = true;
+ }
+ "VK_AMD_shader_explicit_vertex_parameter" => {
+ extensions.amd_shader_explicit_vertex_parameter = true;
+ }
+ "VK_AMD_shader_fragment_mask" => {
+ extensions.amd_shader_fragment_mask = true;
+ }
+ "VK_AMD_shader_image_load_store_lod" => {
+ extensions.amd_shader_image_load_store_lod = true;
+ }
+ "VK_AMD_shader_info" => {
+ extensions.amd_shader_info = true;
+ }
+ "VK_AMD_shader_trinary_minmax" => {
+ extensions.amd_shader_trinary_minmax = true;
+ }
+ "VK_AMD_texture_gather_bias_lod" => {
+ extensions.amd_texture_gather_bias_lod = true;
+ }
+ "VK_ANDROID_external_memory_android_hardware_buffer" => {
+ extensions.android_external_memory_android_hardware_buffer = true;
+ }
+ "VK_ARM_rasterization_order_attachment_access" => {
+ extensions.arm_rasterization_order_attachment_access = true;
+ }
+ "VK_ARM_shader_core_builtins" => {
+ extensions.arm_shader_core_builtins = true;
+ }
+ "VK_FUCHSIA_buffer_collection" => {
+ extensions.fuchsia_buffer_collection = true;
+ }
+ "VK_FUCHSIA_external_memory" => {
+ extensions.fuchsia_external_memory = true;
+ }
+ "VK_FUCHSIA_external_semaphore" => {
+ extensions.fuchsia_external_semaphore = true;
+ }
+ "VK_GGP_frame_token" => {
+ extensions.ggp_frame_token = true;
+ }
+ "VK_GOOGLE_decorate_string" => {
+ extensions.google_decorate_string = true;
+ }
+ "VK_GOOGLE_display_timing" => {
+ extensions.google_display_timing = true;
+ }
+ "VK_GOOGLE_hlsl_functionality1" => {
+ extensions.google_hlsl_functionality1 = true;
+ }
+ "VK_GOOGLE_user_type" => {
+ extensions.google_user_type = true;
+ }
+ "VK_HUAWEI_invocation_mask" => {
+ extensions.huawei_invocation_mask = true;
+ }
+ "VK_HUAWEI_subpass_shading" => {
+ extensions.huawei_subpass_shading = true;
+ }
+ "VK_IMG_filter_cubic" => {
+ extensions.img_filter_cubic = true;
+ }
+ "VK_IMG_format_pvrtc" => {
+ extensions.img_format_pvrtc = true;
+ }
+ "VK_INTEL_performance_query" => {
+ extensions.intel_performance_query = true;
+ }
+ "VK_INTEL_shader_integer_functions2" => {
+ extensions.intel_shader_integer_functions2 = true;
+ }
+ "VK_NVX_binary_import" => {
+ extensions.nvx_binary_import = true;
+ }
+ "VK_NVX_image_view_handle" => {
+ extensions.nvx_image_view_handle = true;
+ }
+ "VK_NVX_multiview_per_view_attributes" => {
+ extensions.nvx_multiview_per_view_attributes = true;
+ }
+ "VK_NV_acquire_winrt_display" => {
+ extensions.nv_acquire_winrt_display = true;
+ }
+ "VK_NV_clip_space_w_scaling" => {
+ extensions.nv_clip_space_w_scaling = true;
+ }
+ "VK_NV_compute_shader_derivatives" => {
+ extensions.nv_compute_shader_derivatives = true;
+ }
+ "VK_NV_cooperative_matrix" => {
+ extensions.nv_cooperative_matrix = true;
+ }
+ "VK_NV_copy_memory_indirect" => {
+ extensions.nv_copy_memory_indirect = true;
+ }
+ "VK_NV_corner_sampled_image" => {
+ extensions.nv_corner_sampled_image = true;
+ }
+ "VK_NV_coverage_reduction_mode" => {
+ extensions.nv_coverage_reduction_mode = true;
+ }
+ "VK_NV_dedicated_allocation" => {
+ extensions.nv_dedicated_allocation = true;
+ }
+ "VK_NV_dedicated_allocation_image_aliasing" => {
+ extensions.nv_dedicated_allocation_image_aliasing = true;
+ }
+ "VK_NV_device_diagnostic_checkpoints" => {
+ extensions.nv_device_diagnostic_checkpoints = true;
+ }
+ "VK_NV_device_diagnostics_config" => {
+ extensions.nv_device_diagnostics_config = true;
+ }
+ "VK_NV_device_generated_commands" => {
+ extensions.nv_device_generated_commands = true;
+ }
+ "VK_NV_external_memory" => {
+ extensions.nv_external_memory = true;
+ }
+ "VK_NV_external_memory_rdma" => {
+ extensions.nv_external_memory_rdma = true;
+ }
+ "VK_NV_external_memory_win32" => {
+ extensions.nv_external_memory_win32 = true;
+ }
+ "VK_NV_fill_rectangle" => {
+ extensions.nv_fill_rectangle = true;
+ }
+ "VK_NV_fragment_coverage_to_color" => {
+ extensions.nv_fragment_coverage_to_color = true;
+ }
+ "VK_NV_fragment_shader_barycentric" => {
+ extensions.nv_fragment_shader_barycentric = true;
+ }
+ "VK_NV_fragment_shading_rate_enums" => {
+ extensions.nv_fragment_shading_rate_enums = true;
+ }
+ "VK_NV_framebuffer_mixed_samples" => {
+ extensions.nv_framebuffer_mixed_samples = true;
+ }
+ "VK_NV_geometry_shader_passthrough" => {
+ extensions.nv_geometry_shader_passthrough = true;
+ }
+ "VK_NV_glsl_shader" => {
+ extensions.nv_glsl_shader = true;
+ }
+ "VK_NV_inherited_viewport_scissor" => {
+ extensions.nv_inherited_viewport_scissor = true;
+ }
+ "VK_NV_linear_color_attachment" => {
+ extensions.nv_linear_color_attachment = true;
+ }
+ "VK_NV_memory_decompression" => {
+ extensions.nv_memory_decompression = true;
+ }
+ "VK_NV_mesh_shader" => {
+ extensions.nv_mesh_shader = true;
+ }
+ "VK_NV_optical_flow" => {
+ extensions.nv_optical_flow = true;
+ }
+ "VK_NV_present_barrier" => {
+ extensions.nv_present_barrier = true;
+ }
+ "VK_NV_ray_tracing" => {
+ extensions.nv_ray_tracing = true;
+ }
+ "VK_NV_ray_tracing_invocation_reorder" => {
+ extensions.nv_ray_tracing_invocation_reorder = true;
+ }
+ "VK_NV_ray_tracing_motion_blur" => {
+ extensions.nv_ray_tracing_motion_blur = true;
+ }
+ "VK_NV_representative_fragment_test" => {
+ extensions.nv_representative_fragment_test = true;
+ }
+ "VK_NV_sample_mask_override_coverage" => {
+ extensions.nv_sample_mask_override_coverage = true;
+ }
+ "VK_NV_scissor_exclusive" => {
+ extensions.nv_scissor_exclusive = true;
+ }
+ "VK_NV_shader_image_footprint" => {
+ extensions.nv_shader_image_footprint = true;
+ }
+ "VK_NV_shader_sm_builtins" => {
+ extensions.nv_shader_sm_builtins = true;
+ }
+ "VK_NV_shader_subgroup_partitioned" => {
+ extensions.nv_shader_subgroup_partitioned = true;
+ }
+ "VK_NV_shading_rate_image" => {
+ extensions.nv_shading_rate_image = true;
+ }
+ "VK_NV_viewport_array2" => {
+ extensions.nv_viewport_array2 = true;
+ }
+ "VK_NV_viewport_swizzle" => {
+ extensions.nv_viewport_swizzle = true;
+ }
+ "VK_NV_win32_keyed_mutex" => {
+ extensions.nv_win32_keyed_mutex = true;
+ }
+ "VK_QCOM_fragment_density_map_offset" => {
+ extensions.qcom_fragment_density_map_offset = true;
+ }
+ "VK_QCOM_image_processing" => {
+ extensions.qcom_image_processing = true;
+ }
+ "VK_QCOM_multiview_per_view_viewports" => {
+ extensions.qcom_multiview_per_view_viewports = true;
+ }
+ "VK_QCOM_render_pass_shader_resolve" => {
+ extensions.qcom_render_pass_shader_resolve = true;
+ }
+ "VK_QCOM_render_pass_store_ops" => {
+ extensions.qcom_render_pass_store_ops = true;
+ }
+ "VK_QCOM_render_pass_transform" => {
+ extensions.qcom_render_pass_transform = true;
+ }
+ "VK_QCOM_rotated_copy_commands" => {
+ extensions.qcom_rotated_copy_commands = true;
+ }
+ "VK_QCOM_tile_properties" => {
+ extensions.qcom_tile_properties = true;
+ }
+ "VK_SEC_amigo_profiling" => {
+ extensions.sec_amigo_profiling = true;
+ }
+ "VK_VALVE_descriptor_set_host_mapping" => {
+ extensions.valve_descriptor_set_host_mapping = true;
+ }
+ "VK_VALVE_mutable_descriptor_type" => {
+ extensions.valve_mutable_descriptor_type = true;
+ }
+ _ => (),
+ }
+ }
+ extensions
+ }
+}
+impl<'a> From<&'a DeviceExtensions> for Vec<std::ffi::CString> {
+ fn from(x: &'a DeviceExtensions) -> Self {
+ let mut data = Self::new();
+ if x.khr_16bit_storage {
+ data.push(std::ffi::CString::new("VK_KHR_16bit_storage").unwrap());
+ }
+ if x.khr_8bit_storage {
+ data.push(std::ffi::CString::new("VK_KHR_8bit_storage").unwrap());
+ }
+ if x.khr_acceleration_structure {
+ data.push(std::ffi::CString::new("VK_KHR_acceleration_structure").unwrap());
+ }
+ if x.khr_bind_memory2 {
+ data.push(std::ffi::CString::new("VK_KHR_bind_memory2").unwrap());
+ }
+ if x.khr_buffer_device_address {
+ data.push(std::ffi::CString::new("VK_KHR_buffer_device_address").unwrap());
+ }
+ if x.khr_copy_commands2 {
+ data.push(std::ffi::CString::new("VK_KHR_copy_commands2").unwrap());
+ }
+ if x.khr_create_renderpass2 {
+ data.push(std::ffi::CString::new("VK_KHR_create_renderpass2").unwrap());
+ }
+ if x.khr_dedicated_allocation {
+ data.push(std::ffi::CString::new("VK_KHR_dedicated_allocation").unwrap());
+ }
+ if x.khr_deferred_host_operations {
+ data.push(std::ffi::CString::new("VK_KHR_deferred_host_operations").unwrap());
+ }
+ if x.khr_depth_stencil_resolve {
+ data.push(std::ffi::CString::new("VK_KHR_depth_stencil_resolve").unwrap());
+ }
+ if x.khr_descriptor_update_template {
+ data.push(std::ffi::CString::new("VK_KHR_descriptor_update_template").unwrap());
+ }
+ if x.khr_device_group {
+ data.push(std::ffi::CString::new("VK_KHR_device_group").unwrap());
+ }
+ if x.khr_display_swapchain {
+ data.push(std::ffi::CString::new("VK_KHR_display_swapchain").unwrap());
+ }
+ if x.khr_draw_indirect_count {
+ data.push(std::ffi::CString::new("VK_KHR_draw_indirect_count").unwrap());
+ }
+ if x.khr_driver_properties {
+ data.push(std::ffi::CString::new("VK_KHR_driver_properties").unwrap());
+ }
+ if x.khr_dynamic_rendering {
+ data.push(std::ffi::CString::new("VK_KHR_dynamic_rendering").unwrap());
+ }
+ if x.khr_external_fence {
+ data.push(std::ffi::CString::new("VK_KHR_external_fence").unwrap());
+ }
+ if x.khr_external_fence_fd {
+ data.push(std::ffi::CString::new("VK_KHR_external_fence_fd").unwrap());
+ }
+ if x.khr_external_fence_win32 {
+ data.push(std::ffi::CString::new("VK_KHR_external_fence_win32").unwrap());
+ }
+ if x.khr_external_memory {
+ data.push(std::ffi::CString::new("VK_KHR_external_memory").unwrap());
+ }
+ if x.khr_external_memory_fd {
+ data.push(std::ffi::CString::new("VK_KHR_external_memory_fd").unwrap());
+ }
+ if x.khr_external_memory_win32 {
+ data.push(std::ffi::CString::new("VK_KHR_external_memory_win32").unwrap());
+ }
+ if x.khr_external_semaphore {
+ data.push(std::ffi::CString::new("VK_KHR_external_semaphore").unwrap());
+ }
+ if x.khr_external_semaphore_fd {
+ data.push(std::ffi::CString::new("VK_KHR_external_semaphore_fd").unwrap());
+ }
+ if x.khr_external_semaphore_win32 {
+ data.push(std::ffi::CString::new("VK_KHR_external_semaphore_win32").unwrap());
+ }
+ if x.khr_format_feature_flags2 {
+ data.push(std::ffi::CString::new("VK_KHR_format_feature_flags2").unwrap());
+ }
+ if x.khr_fragment_shader_barycentric {
+ data.push(std::ffi::CString::new("VK_KHR_fragment_shader_barycentric").unwrap());
+ }
+ if x.khr_fragment_shading_rate {
+ data.push(std::ffi::CString::new("VK_KHR_fragment_shading_rate").unwrap());
+ }
+ if x.khr_get_memory_requirements2 {
+ data.push(std::ffi::CString::new("VK_KHR_get_memory_requirements2").unwrap());
+ }
+ if x.khr_global_priority {
+ data.push(std::ffi::CString::new("VK_KHR_global_priority").unwrap());
+ }
+ if x.khr_image_format_list {
+ data.push(std::ffi::CString::new("VK_KHR_image_format_list").unwrap());
+ }
+ if x.khr_imageless_framebuffer {
+ data.push(std::ffi::CString::new("VK_KHR_imageless_framebuffer").unwrap());
+ }
+ if x.khr_incremental_present {
+ data.push(std::ffi::CString::new("VK_KHR_incremental_present").unwrap());
+ }
+ if x.khr_maintenance1 {
+ data.push(std::ffi::CString::new("VK_KHR_maintenance1").unwrap());
+ }
+ if x.khr_maintenance2 {
+ data.push(std::ffi::CString::new("VK_KHR_maintenance2").unwrap());
+ }
+ if x.khr_maintenance3 {
+ data.push(std::ffi::CString::new("VK_KHR_maintenance3").unwrap());
+ }
+ if x.khr_maintenance4 {
+ data.push(std::ffi::CString::new("VK_KHR_maintenance4").unwrap());
+ }
+ if x.khr_multiview {
+ data.push(std::ffi::CString::new("VK_KHR_multiview").unwrap());
+ }
+ if x.khr_performance_query {
+ data.push(std::ffi::CString::new("VK_KHR_performance_query").unwrap());
+ }
+ if x.khr_pipeline_executable_properties {
+ data.push(std::ffi::CString::new("VK_KHR_pipeline_executable_properties").unwrap());
+ }
+ if x.khr_pipeline_library {
+ data.push(std::ffi::CString::new("VK_KHR_pipeline_library").unwrap());
+ }
+ if x.khr_portability_subset {
+ data.push(std::ffi::CString::new("VK_KHR_portability_subset").unwrap());
+ }
+ if x.khr_present_id {
+ data.push(std::ffi::CString::new("VK_KHR_present_id").unwrap());
+ }
+ if x.khr_present_wait {
+ data.push(std::ffi::CString::new("VK_KHR_present_wait").unwrap());
+ }
+ if x.khr_push_descriptor {
+ data.push(std::ffi::CString::new("VK_KHR_push_descriptor").unwrap());
+ }
+ if x.khr_ray_query {
+ data.push(std::ffi::CString::new("VK_KHR_ray_query").unwrap());
+ }
+ if x.khr_ray_tracing_maintenance1 {
+ data.push(std::ffi::CString::new("VK_KHR_ray_tracing_maintenance1").unwrap());
+ }
+ if x.khr_ray_tracing_pipeline {
+ data.push(std::ffi::CString::new("VK_KHR_ray_tracing_pipeline").unwrap());
+ }
+ if x.khr_relaxed_block_layout {
+ data.push(std::ffi::CString::new("VK_KHR_relaxed_block_layout").unwrap());
+ }
+ if x.khr_sampler_mirror_clamp_to_edge {
+ data.push(std::ffi::CString::new("VK_KHR_sampler_mirror_clamp_to_edge").unwrap());
+ }
+ if x.khr_sampler_ycbcr_conversion {
+ data.push(std::ffi::CString::new("VK_KHR_sampler_ycbcr_conversion").unwrap());
+ }
+ if x.khr_separate_depth_stencil_layouts {
+ data.push(std::ffi::CString::new("VK_KHR_separate_depth_stencil_layouts").unwrap());
+ }
+ if x.khr_shader_atomic_int64 {
+ data.push(std::ffi::CString::new("VK_KHR_shader_atomic_int64").unwrap());
+ }
+ if x.khr_shader_clock {
+ data.push(std::ffi::CString::new("VK_KHR_shader_clock").unwrap());
+ }
+ if x.khr_shader_draw_parameters {
+ data.push(std::ffi::CString::new("VK_KHR_shader_draw_parameters").unwrap());
+ }
+ if x.khr_shader_float16_int8 {
+ data.push(std::ffi::CString::new("VK_KHR_shader_float16_int8").unwrap());
+ }
+ if x.khr_shader_float_controls {
+ data.push(std::ffi::CString::new("VK_KHR_shader_float_controls").unwrap());
+ }
+ if x.khr_shader_integer_dot_product {
+ data.push(std::ffi::CString::new("VK_KHR_shader_integer_dot_product").unwrap());
+ }
+ if x.khr_shader_non_semantic_info {
+ data.push(std::ffi::CString::new("VK_KHR_shader_non_semantic_info").unwrap());
+ }
+ if x.khr_shader_subgroup_extended_types {
+ data.push(std::ffi::CString::new("VK_KHR_shader_subgroup_extended_types").unwrap());
+ }
+ if x.khr_shader_subgroup_uniform_control_flow {
+ data.push(
+ std::ffi::CString::new("VK_KHR_shader_subgroup_uniform_control_flow").unwrap(),
+ );
+ }
+ if x.khr_shader_terminate_invocation {
+ data.push(std::ffi::CString::new("VK_KHR_shader_terminate_invocation").unwrap());
+ }
+ if x.khr_shared_presentable_image {
+ data.push(std::ffi::CString::new("VK_KHR_shared_presentable_image").unwrap());
+ }
+ if x.khr_spirv_1_4 {
+ data.push(std::ffi::CString::new("VK_KHR_spirv_1_4").unwrap());
+ }
+ if x.khr_storage_buffer_storage_class {
+ data.push(std::ffi::CString::new("VK_KHR_storage_buffer_storage_class").unwrap());
+ }
+ if x.khr_swapchain {
+ data.push(std::ffi::CString::new("VK_KHR_swapchain").unwrap());
+ }
+ if x.khr_swapchain_mutable_format {
+ data.push(std::ffi::CString::new("VK_KHR_swapchain_mutable_format").unwrap());
+ }
+ if x.khr_synchronization2 {
+ data.push(std::ffi::CString::new("VK_KHR_synchronization2").unwrap());
+ }
+ if x.khr_timeline_semaphore {
+ data.push(std::ffi::CString::new("VK_KHR_timeline_semaphore").unwrap());
+ }
+ if x.khr_uniform_buffer_standard_layout {
+ data.push(std::ffi::CString::new("VK_KHR_uniform_buffer_standard_layout").unwrap());
+ }
+ if x.khr_variable_pointers {
+ data.push(std::ffi::CString::new("VK_KHR_variable_pointers").unwrap());
+ }
+ if x.khr_video_decode_h264 {
+ data.push(std::ffi::CString::new("VK_KHR_video_decode_h264").unwrap());
+ }
+ if x.khr_video_decode_h265 {
+ data.push(std::ffi::CString::new("VK_KHR_video_decode_h265").unwrap());
+ }
+ if x.khr_video_decode_queue {
+ data.push(std::ffi::CString::new("VK_KHR_video_decode_queue").unwrap());
+ }
+ if x.khr_video_encode_queue {
+ data.push(std::ffi::CString::new("VK_KHR_video_encode_queue").unwrap());
+ }
+ if x.khr_video_queue {
+ data.push(std::ffi::CString::new("VK_KHR_video_queue").unwrap());
+ }
+ if x.khr_vulkan_memory_model {
+ data.push(std::ffi::CString::new("VK_KHR_vulkan_memory_model").unwrap());
+ }
+ if x.khr_win32_keyed_mutex {
+ data.push(std::ffi::CString::new("VK_KHR_win32_keyed_mutex").unwrap());
+ }
+ if x.khr_workgroup_memory_explicit_layout {
+ data.push(std::ffi::CString::new("VK_KHR_workgroup_memory_explicit_layout").unwrap());
+ }
+ if x.khr_zero_initialize_workgroup_memory {
+ data.push(std::ffi::CString::new("VK_KHR_zero_initialize_workgroup_memory").unwrap());
+ }
+ if x.ext_4444_formats {
+ data.push(std::ffi::CString::new("VK_EXT_4444_formats").unwrap());
+ }
+ if x.ext_astc_decode_mode {
+ data.push(std::ffi::CString::new("VK_EXT_astc_decode_mode").unwrap());
+ }
+ if x.ext_attachment_feedback_loop_layout {
+ data.push(std::ffi::CString::new("VK_EXT_attachment_feedback_loop_layout").unwrap());
+ }
+ if x.ext_blend_operation_advanced {
+ data.push(std::ffi::CString::new("VK_EXT_blend_operation_advanced").unwrap());
+ }
+ if x.ext_border_color_swizzle {
+ data.push(std::ffi::CString::new("VK_EXT_border_color_swizzle").unwrap());
+ }
+ if x.ext_buffer_device_address {
+ data.push(std::ffi::CString::new("VK_EXT_buffer_device_address").unwrap());
+ }
+ if x.ext_calibrated_timestamps {
+ data.push(std::ffi::CString::new("VK_EXT_calibrated_timestamps").unwrap());
+ }
+ if x.ext_color_write_enable {
+ data.push(std::ffi::CString::new("VK_EXT_color_write_enable").unwrap());
+ }
+ if x.ext_conditional_rendering {
+ data.push(std::ffi::CString::new("VK_EXT_conditional_rendering").unwrap());
+ }
+ if x.ext_conservative_rasterization {
+ data.push(std::ffi::CString::new("VK_EXT_conservative_rasterization").unwrap());
+ }
+ if x.ext_custom_border_color {
+ data.push(std::ffi::CString::new("VK_EXT_custom_border_color").unwrap());
+ }
+ if x.ext_debug_marker {
+ data.push(std::ffi::CString::new("VK_EXT_debug_marker").unwrap());
+ }
+ if x.ext_depth_clamp_zero_one {
+ data.push(std::ffi::CString::new("VK_EXT_depth_clamp_zero_one").unwrap());
+ }
+ if x.ext_depth_clip_control {
+ data.push(std::ffi::CString::new("VK_EXT_depth_clip_control").unwrap());
+ }
+ if x.ext_depth_clip_enable {
+ data.push(std::ffi::CString::new("VK_EXT_depth_clip_enable").unwrap());
+ }
+ if x.ext_depth_range_unrestricted {
+ data.push(std::ffi::CString::new("VK_EXT_depth_range_unrestricted").unwrap());
+ }
+ if x.ext_descriptor_buffer {
+ data.push(std::ffi::CString::new("VK_EXT_descriptor_buffer").unwrap());
+ }
+ if x.ext_descriptor_indexing {
+ data.push(std::ffi::CString::new("VK_EXT_descriptor_indexing").unwrap());
+ }
+ if x.ext_device_address_binding_report {
+ data.push(std::ffi::CString::new("VK_EXT_device_address_binding_report").unwrap());
+ }
+ if x.ext_device_fault {
+ data.push(std::ffi::CString::new("VK_EXT_device_fault").unwrap());
+ }
+ if x.ext_device_memory_report {
+ data.push(std::ffi::CString::new("VK_EXT_device_memory_report").unwrap());
+ }
+ if x.ext_discard_rectangles {
+ data.push(std::ffi::CString::new("VK_EXT_discard_rectangles").unwrap());
+ }
+ if x.ext_display_control {
+ data.push(std::ffi::CString::new("VK_EXT_display_control").unwrap());
+ }
+ if x.ext_extended_dynamic_state {
+ data.push(std::ffi::CString::new("VK_EXT_extended_dynamic_state").unwrap());
+ }
+ if x.ext_extended_dynamic_state2 {
+ data.push(std::ffi::CString::new("VK_EXT_extended_dynamic_state2").unwrap());
+ }
+ if x.ext_extended_dynamic_state3 {
+ data.push(std::ffi::CString::new("VK_EXT_extended_dynamic_state3").unwrap());
+ }
+ if x.ext_external_memory_dma_buf {
+ data.push(std::ffi::CString::new("VK_EXT_external_memory_dma_buf").unwrap());
+ }
+ if x.ext_external_memory_host {
+ data.push(std::ffi::CString::new("VK_EXT_external_memory_host").unwrap());
+ }
+ if x.ext_filter_cubic {
+ data.push(std::ffi::CString::new("VK_EXT_filter_cubic").unwrap());
+ }
+ if x.ext_fragment_density_map {
+ data.push(std::ffi::CString::new("VK_EXT_fragment_density_map").unwrap());
+ }
+ if x.ext_fragment_density_map2 {
+ data.push(std::ffi::CString::new("VK_EXT_fragment_density_map2").unwrap());
+ }
+ if x.ext_fragment_shader_interlock {
+ data.push(std::ffi::CString::new("VK_EXT_fragment_shader_interlock").unwrap());
+ }
+ if x.ext_full_screen_exclusive {
+ data.push(std::ffi::CString::new("VK_EXT_full_screen_exclusive").unwrap());
+ }
+ if x.ext_global_priority {
+ data.push(std::ffi::CString::new("VK_EXT_global_priority").unwrap());
+ }
+ if x.ext_global_priority_query {
+ data.push(std::ffi::CString::new("VK_EXT_global_priority_query").unwrap());
+ }
+ if x.ext_graphics_pipeline_library {
+ data.push(std::ffi::CString::new("VK_EXT_graphics_pipeline_library").unwrap());
+ }
+ if x.ext_hdr_metadata {
+ data.push(std::ffi::CString::new("VK_EXT_hdr_metadata").unwrap());
+ }
+ if x.ext_host_query_reset {
+ data.push(std::ffi::CString::new("VK_EXT_host_query_reset").unwrap());
+ }
+ if x.ext_image_2d_view_of_3d {
+ data.push(std::ffi::CString::new("VK_EXT_image_2d_view_of_3d").unwrap());
+ }
+ if x.ext_image_compression_control {
+ data.push(std::ffi::CString::new("VK_EXT_image_compression_control").unwrap());
+ }
+ if x.ext_image_compression_control_swapchain {
+ data.push(
+ std::ffi::CString::new("VK_EXT_image_compression_control_swapchain").unwrap(),
+ );
+ }
+ if x.ext_image_drm_format_modifier {
+ data.push(std::ffi::CString::new("VK_EXT_image_drm_format_modifier").unwrap());
+ }
+ if x.ext_image_robustness {
+ data.push(std::ffi::CString::new("VK_EXT_image_robustness").unwrap());
+ }
+ if x.ext_image_view_min_lod {
+ data.push(std::ffi::CString::new("VK_EXT_image_view_min_lod").unwrap());
+ }
+ if x.ext_index_type_uint8 {
+ data.push(std::ffi::CString::new("VK_EXT_index_type_uint8").unwrap());
+ }
+ if x.ext_inline_uniform_block {
+ data.push(std::ffi::CString::new("VK_EXT_inline_uniform_block").unwrap());
+ }
+ if x.ext_legacy_dithering {
+ data.push(std::ffi::CString::new("VK_EXT_legacy_dithering").unwrap());
+ }
+ if x.ext_line_rasterization {
+ data.push(std::ffi::CString::new("VK_EXT_line_rasterization").unwrap());
+ }
+ if x.ext_load_store_op_none {
+ data.push(std::ffi::CString::new("VK_EXT_load_store_op_none").unwrap());
+ }
+ if x.ext_memory_budget {
+ data.push(std::ffi::CString::new("VK_EXT_memory_budget").unwrap());
+ }
+ if x.ext_memory_priority {
+ data.push(std::ffi::CString::new("VK_EXT_memory_priority").unwrap());
+ }
+ if x.ext_mesh_shader {
+ data.push(std::ffi::CString::new("VK_EXT_mesh_shader").unwrap());
+ }
+ if x.ext_metal_objects {
+ data.push(std::ffi::CString::new("VK_EXT_metal_objects").unwrap());
+ }
+ if x.ext_multi_draw {
+ data.push(std::ffi::CString::new("VK_EXT_multi_draw").unwrap());
+ }
+ if x.ext_multisampled_render_to_single_sampled {
+ data.push(
+ std::ffi::CString::new("VK_EXT_multisampled_render_to_single_sampled").unwrap(),
+ );
+ }
+ if x.ext_mutable_descriptor_type {
+ data.push(std::ffi::CString::new("VK_EXT_mutable_descriptor_type").unwrap());
+ }
+ if x.ext_non_seamless_cube_map {
+ data.push(std::ffi::CString::new("VK_EXT_non_seamless_cube_map").unwrap());
+ }
+ if x.ext_opacity_micromap {
+ data.push(std::ffi::CString::new("VK_EXT_opacity_micromap").unwrap());
+ }
+ if x.ext_pageable_device_local_memory {
+ data.push(std::ffi::CString::new("VK_EXT_pageable_device_local_memory").unwrap());
+ }
+ if x.ext_pci_bus_info {
+ data.push(std::ffi::CString::new("VK_EXT_pci_bus_info").unwrap());
+ }
+ if x.ext_physical_device_drm {
+ data.push(std::ffi::CString::new("VK_EXT_physical_device_drm").unwrap());
+ }
+ if x.ext_pipeline_creation_cache_control {
+ data.push(std::ffi::CString::new("VK_EXT_pipeline_creation_cache_control").unwrap());
+ }
+ if x.ext_pipeline_creation_feedback {
+ data.push(std::ffi::CString::new("VK_EXT_pipeline_creation_feedback").unwrap());
+ }
+ if x.ext_pipeline_properties {
+ data.push(std::ffi::CString::new("VK_EXT_pipeline_properties").unwrap());
+ }
+ if x.ext_pipeline_protected_access {
+ data.push(std::ffi::CString::new("VK_EXT_pipeline_protected_access").unwrap());
+ }
+ if x.ext_pipeline_robustness {
+ data.push(std::ffi::CString::new("VK_EXT_pipeline_robustness").unwrap());
+ }
+ if x.ext_post_depth_coverage {
+ data.push(std::ffi::CString::new("VK_EXT_post_depth_coverage").unwrap());
+ }
+ if x.ext_primitive_topology_list_restart {
+ data.push(std::ffi::CString::new("VK_EXT_primitive_topology_list_restart").unwrap());
+ }
+ if x.ext_primitives_generated_query {
+ data.push(std::ffi::CString::new("VK_EXT_primitives_generated_query").unwrap());
+ }
+ if x.ext_private_data {
+ data.push(std::ffi::CString::new("VK_EXT_private_data").unwrap());
+ }
+ if x.ext_provoking_vertex {
+ data.push(std::ffi::CString::new("VK_EXT_provoking_vertex").unwrap());
+ }
+ if x.ext_queue_family_foreign {
+ data.push(std::ffi::CString::new("VK_EXT_queue_family_foreign").unwrap());
+ }
+ if x.ext_rasterization_order_attachment_access {
+ data.push(
+ std::ffi::CString::new("VK_EXT_rasterization_order_attachment_access").unwrap(),
+ );
+ }
+ if x.ext_rgba10x6_formats {
+ data.push(std::ffi::CString::new("VK_EXT_rgba10x6_formats").unwrap());
+ }
+ if x.ext_robustness2 {
+ data.push(std::ffi::CString::new("VK_EXT_robustness2").unwrap());
+ }
+ if x.ext_sample_locations {
+ data.push(std::ffi::CString::new("VK_EXT_sample_locations").unwrap());
+ }
+ if x.ext_sampler_filter_minmax {
+ data.push(std::ffi::CString::new("VK_EXT_sampler_filter_minmax").unwrap());
+ }
+ if x.ext_scalar_block_layout {
+ data.push(std::ffi::CString::new("VK_EXT_scalar_block_layout").unwrap());
+ }
+ if x.ext_separate_stencil_usage {
+ data.push(std::ffi::CString::new("VK_EXT_separate_stencil_usage").unwrap());
+ }
+ if x.ext_shader_atomic_float {
+ data.push(std::ffi::CString::new("VK_EXT_shader_atomic_float").unwrap());
+ }
+ if x.ext_shader_atomic_float2 {
+ data.push(std::ffi::CString::new("VK_EXT_shader_atomic_float2").unwrap());
+ }
+ if x.ext_shader_demote_to_helper_invocation {
+ data.push(std::ffi::CString::new("VK_EXT_shader_demote_to_helper_invocation").unwrap());
+ }
+ if x.ext_shader_image_atomic_int64 {
+ data.push(std::ffi::CString::new("VK_EXT_shader_image_atomic_int64").unwrap());
+ }
+ if x.ext_shader_module_identifier {
+ data.push(std::ffi::CString::new("VK_EXT_shader_module_identifier").unwrap());
+ }
+ if x.ext_shader_stencil_export {
+ data.push(std::ffi::CString::new("VK_EXT_shader_stencil_export").unwrap());
+ }
+ if x.ext_shader_subgroup_ballot {
+ data.push(std::ffi::CString::new("VK_EXT_shader_subgroup_ballot").unwrap());
+ }
+ if x.ext_shader_subgroup_vote {
+ data.push(std::ffi::CString::new("VK_EXT_shader_subgroup_vote").unwrap());
+ }
+ if x.ext_shader_viewport_index_layer {
+ data.push(std::ffi::CString::new("VK_EXT_shader_viewport_index_layer").unwrap());
+ }
+ if x.ext_subgroup_size_control {
+ data.push(std::ffi::CString::new("VK_EXT_subgroup_size_control").unwrap());
+ }
+ if x.ext_subpass_merge_feedback {
+ data.push(std::ffi::CString::new("VK_EXT_subpass_merge_feedback").unwrap());
+ }
+ if x.ext_swapchain_maintenance1 {
+ data.push(std::ffi::CString::new("VK_EXT_swapchain_maintenance1").unwrap());
+ }
+ if x.ext_texel_buffer_alignment {
+ data.push(std::ffi::CString::new("VK_EXT_texel_buffer_alignment").unwrap());
+ }
+ if x.ext_texture_compression_astc_hdr {
+ data.push(std::ffi::CString::new("VK_EXT_texture_compression_astc_hdr").unwrap());
+ }
+ if x.ext_tooling_info {
+ data.push(std::ffi::CString::new("VK_EXT_tooling_info").unwrap());
+ }
+ if x.ext_transform_feedback {
+ data.push(std::ffi::CString::new("VK_EXT_transform_feedback").unwrap());
+ }
+ if x.ext_validation_cache {
+ data.push(std::ffi::CString::new("VK_EXT_validation_cache").unwrap());
+ }
+ if x.ext_vertex_attribute_divisor {
+ data.push(std::ffi::CString::new("VK_EXT_vertex_attribute_divisor").unwrap());
+ }
+ if x.ext_vertex_input_dynamic_state {
+ data.push(std::ffi::CString::new("VK_EXT_vertex_input_dynamic_state").unwrap());
+ }
+ if x.ext_video_encode_h264 {
+ data.push(std::ffi::CString::new("VK_EXT_video_encode_h264").unwrap());
+ }
+ if x.ext_video_encode_h265 {
+ data.push(std::ffi::CString::new("VK_EXT_video_encode_h265").unwrap());
+ }
+ if x.ext_ycbcr_2plane_444_formats {
+ data.push(std::ffi::CString::new("VK_EXT_ycbcr_2plane_444_formats").unwrap());
+ }
+ if x.ext_ycbcr_image_arrays {
+ data.push(std::ffi::CString::new("VK_EXT_ycbcr_image_arrays").unwrap());
+ }
+ if x.amd_buffer_marker {
+ data.push(std::ffi::CString::new("VK_AMD_buffer_marker").unwrap());
+ }
+ if x.amd_device_coherent_memory {
+ data.push(std::ffi::CString::new("VK_AMD_device_coherent_memory").unwrap());
+ }
+ if x.amd_display_native_hdr {
+ data.push(std::ffi::CString::new("VK_AMD_display_native_hdr").unwrap());
+ }
+ if x.amd_draw_indirect_count {
+ data.push(std::ffi::CString::new("VK_AMD_draw_indirect_count").unwrap());
+ }
+ if x.amd_gcn_shader {
+ data.push(std::ffi::CString::new("VK_AMD_gcn_shader").unwrap());
+ }
+ if x.amd_gpu_shader_half_float {
+ data.push(std::ffi::CString::new("VK_AMD_gpu_shader_half_float").unwrap());
+ }
+ if x.amd_gpu_shader_int16 {
+ data.push(std::ffi::CString::new("VK_AMD_gpu_shader_int16").unwrap());
+ }
+ if x.amd_memory_overallocation_behavior {
+ data.push(std::ffi::CString::new("VK_AMD_memory_overallocation_behavior").unwrap());
+ }
+ if x.amd_mixed_attachment_samples {
+ data.push(std::ffi::CString::new("VK_AMD_mixed_attachment_samples").unwrap());
+ }
+ if x.amd_pipeline_compiler_control {
+ data.push(std::ffi::CString::new("VK_AMD_pipeline_compiler_control").unwrap());
+ }
+ if x.amd_rasterization_order {
+ data.push(std::ffi::CString::new("VK_AMD_rasterization_order").unwrap());
+ }
+ if x.amd_shader_ballot {
+ data.push(std::ffi::CString::new("VK_AMD_shader_ballot").unwrap());
+ }
+ if x.amd_shader_core_properties {
+ data.push(std::ffi::CString::new("VK_AMD_shader_core_properties").unwrap());
+ }
+ if x.amd_shader_core_properties2 {
+ data.push(std::ffi::CString::new("VK_AMD_shader_core_properties2").unwrap());
+ }
+ if x.amd_shader_early_and_late_fragment_tests {
+ data.push(
+ std::ffi::CString::new("VK_AMD_shader_early_and_late_fragment_tests").unwrap(),
+ );
+ }
+ if x.amd_shader_explicit_vertex_parameter {
+ data.push(std::ffi::CString::new("VK_AMD_shader_explicit_vertex_parameter").unwrap());
+ }
+ if x.amd_shader_fragment_mask {
+ data.push(std::ffi::CString::new("VK_AMD_shader_fragment_mask").unwrap());
+ }
+ if x.amd_shader_image_load_store_lod {
+ data.push(std::ffi::CString::new("VK_AMD_shader_image_load_store_lod").unwrap());
+ }
+ if x.amd_shader_info {
+ data.push(std::ffi::CString::new("VK_AMD_shader_info").unwrap());
+ }
+ if x.amd_shader_trinary_minmax {
+ data.push(std::ffi::CString::new("VK_AMD_shader_trinary_minmax").unwrap());
+ }
+ if x.amd_texture_gather_bias_lod {
+ data.push(std::ffi::CString::new("VK_AMD_texture_gather_bias_lod").unwrap());
+ }
+ if x.android_external_memory_android_hardware_buffer {
+ data.push(
+ std::ffi::CString::new("VK_ANDROID_external_memory_android_hardware_buffer")
+ .unwrap(),
+ );
+ }
+ if x.arm_rasterization_order_attachment_access {
+ data.push(
+ std::ffi::CString::new("VK_ARM_rasterization_order_attachment_access").unwrap(),
+ );
+ }
+ if x.arm_shader_core_builtins {
+ data.push(std::ffi::CString::new("VK_ARM_shader_core_builtins").unwrap());
+ }
+ if x.fuchsia_buffer_collection {
+ data.push(std::ffi::CString::new("VK_FUCHSIA_buffer_collection").unwrap());
+ }
+ if x.fuchsia_external_memory {
+ data.push(std::ffi::CString::new("VK_FUCHSIA_external_memory").unwrap());
+ }
+ if x.fuchsia_external_semaphore {
+ data.push(std::ffi::CString::new("VK_FUCHSIA_external_semaphore").unwrap());
+ }
+ if x.ggp_frame_token {
+ data.push(std::ffi::CString::new("VK_GGP_frame_token").unwrap());
+ }
+ if x.google_decorate_string {
+ data.push(std::ffi::CString::new("VK_GOOGLE_decorate_string").unwrap());
+ }
+ if x.google_display_timing {
+ data.push(std::ffi::CString::new("VK_GOOGLE_display_timing").unwrap());
+ }
+ if x.google_hlsl_functionality1 {
+ data.push(std::ffi::CString::new("VK_GOOGLE_hlsl_functionality1").unwrap());
+ }
+ if x.google_user_type {
+ data.push(std::ffi::CString::new("VK_GOOGLE_user_type").unwrap());
+ }
+ if x.huawei_invocation_mask {
+ data.push(std::ffi::CString::new("VK_HUAWEI_invocation_mask").unwrap());
+ }
+ if x.huawei_subpass_shading {
+ data.push(std::ffi::CString::new("VK_HUAWEI_subpass_shading").unwrap());
+ }
+ if x.img_filter_cubic {
+ data.push(std::ffi::CString::new("VK_IMG_filter_cubic").unwrap());
+ }
+ if x.img_format_pvrtc {
+ data.push(std::ffi::CString::new("VK_IMG_format_pvrtc").unwrap());
+ }
+ if x.intel_performance_query {
+ data.push(std::ffi::CString::new("VK_INTEL_performance_query").unwrap());
+ }
+ if x.intel_shader_integer_functions2 {
+ data.push(std::ffi::CString::new("VK_INTEL_shader_integer_functions2").unwrap());
+ }
+ if x.nvx_binary_import {
+ data.push(std::ffi::CString::new("VK_NVX_binary_import").unwrap());
+ }
+ if x.nvx_image_view_handle {
+ data.push(std::ffi::CString::new("VK_NVX_image_view_handle").unwrap());
+ }
+ if x.nvx_multiview_per_view_attributes {
+ data.push(std::ffi::CString::new("VK_NVX_multiview_per_view_attributes").unwrap());
+ }
+ if x.nv_acquire_winrt_display {
+ data.push(std::ffi::CString::new("VK_NV_acquire_winrt_display").unwrap());
+ }
+ if x.nv_clip_space_w_scaling {
+ data.push(std::ffi::CString::new("VK_NV_clip_space_w_scaling").unwrap());
+ }
+ if x.nv_compute_shader_derivatives {
+ data.push(std::ffi::CString::new("VK_NV_compute_shader_derivatives").unwrap());
+ }
+ if x.nv_cooperative_matrix {
+ data.push(std::ffi::CString::new("VK_NV_cooperative_matrix").unwrap());
+ }
+ if x.nv_copy_memory_indirect {
+ data.push(std::ffi::CString::new("VK_NV_copy_memory_indirect").unwrap());
+ }
+ if x.nv_corner_sampled_image {
+ data.push(std::ffi::CString::new("VK_NV_corner_sampled_image").unwrap());
+ }
+ if x.nv_coverage_reduction_mode {
+ data.push(std::ffi::CString::new("VK_NV_coverage_reduction_mode").unwrap());
+ }
+ if x.nv_dedicated_allocation {
+ data.push(std::ffi::CString::new("VK_NV_dedicated_allocation").unwrap());
+ }
+ if x.nv_dedicated_allocation_image_aliasing {
+ data.push(std::ffi::CString::new("VK_NV_dedicated_allocation_image_aliasing").unwrap());
+ }
+ if x.nv_device_diagnostic_checkpoints {
+ data.push(std::ffi::CString::new("VK_NV_device_diagnostic_checkpoints").unwrap());
+ }
+ if x.nv_device_diagnostics_config {
+ data.push(std::ffi::CString::new("VK_NV_device_diagnostics_config").unwrap());
+ }
+ if x.nv_device_generated_commands {
+ data.push(std::ffi::CString::new("VK_NV_device_generated_commands").unwrap());
+ }
+ if x.nv_external_memory {
+ data.push(std::ffi::CString::new("VK_NV_external_memory").unwrap());
+ }
+ if x.nv_external_memory_rdma {
+ data.push(std::ffi::CString::new("VK_NV_external_memory_rdma").unwrap());
+ }
+ if x.nv_external_memory_win32 {
+ data.push(std::ffi::CString::new("VK_NV_external_memory_win32").unwrap());
+ }
+ if x.nv_fill_rectangle {
+ data.push(std::ffi::CString::new("VK_NV_fill_rectangle").unwrap());
+ }
+ if x.nv_fragment_coverage_to_color {
+ data.push(std::ffi::CString::new("VK_NV_fragment_coverage_to_color").unwrap());
+ }
+ if x.nv_fragment_shader_barycentric {
+ data.push(std::ffi::CString::new("VK_NV_fragment_shader_barycentric").unwrap());
+ }
+ if x.nv_fragment_shading_rate_enums {
+ data.push(std::ffi::CString::new("VK_NV_fragment_shading_rate_enums").unwrap());
+ }
+ if x.nv_framebuffer_mixed_samples {
+ data.push(std::ffi::CString::new("VK_NV_framebuffer_mixed_samples").unwrap());
+ }
+ if x.nv_geometry_shader_passthrough {
+ data.push(std::ffi::CString::new("VK_NV_geometry_shader_passthrough").unwrap());
+ }
+ if x.nv_glsl_shader {
+ data.push(std::ffi::CString::new("VK_NV_glsl_shader").unwrap());
+ }
+ if x.nv_inherited_viewport_scissor {
+ data.push(std::ffi::CString::new("VK_NV_inherited_viewport_scissor").unwrap());
+ }
+ if x.nv_linear_color_attachment {
+ data.push(std::ffi::CString::new("VK_NV_linear_color_attachment").unwrap());
+ }
+ if x.nv_memory_decompression {
+ data.push(std::ffi::CString::new("VK_NV_memory_decompression").unwrap());
+ }
+ if x.nv_mesh_shader {
+ data.push(std::ffi::CString::new("VK_NV_mesh_shader").unwrap());
+ }
+ if x.nv_optical_flow {
+ data.push(std::ffi::CString::new("VK_NV_optical_flow").unwrap());
+ }
+ if x.nv_present_barrier {
+ data.push(std::ffi::CString::new("VK_NV_present_barrier").unwrap());
+ }
+ if x.nv_ray_tracing {
+ data.push(std::ffi::CString::new("VK_NV_ray_tracing").unwrap());
+ }
+ if x.nv_ray_tracing_invocation_reorder {
+ data.push(std::ffi::CString::new("VK_NV_ray_tracing_invocation_reorder").unwrap());
+ }
+ if x.nv_ray_tracing_motion_blur {
+ data.push(std::ffi::CString::new("VK_NV_ray_tracing_motion_blur").unwrap());
+ }
+ if x.nv_representative_fragment_test {
+ data.push(std::ffi::CString::new("VK_NV_representative_fragment_test").unwrap());
+ }
+ if x.nv_sample_mask_override_coverage {
+ data.push(std::ffi::CString::new("VK_NV_sample_mask_override_coverage").unwrap());
+ }
+ if x.nv_scissor_exclusive {
+ data.push(std::ffi::CString::new("VK_NV_scissor_exclusive").unwrap());
+ }
+ if x.nv_shader_image_footprint {
+ data.push(std::ffi::CString::new("VK_NV_shader_image_footprint").unwrap());
+ }
+ if x.nv_shader_sm_builtins {
+ data.push(std::ffi::CString::new("VK_NV_shader_sm_builtins").unwrap());
+ }
+ if x.nv_shader_subgroup_partitioned {
+ data.push(std::ffi::CString::new("VK_NV_shader_subgroup_partitioned").unwrap());
+ }
+ if x.nv_shading_rate_image {
+ data.push(std::ffi::CString::new("VK_NV_shading_rate_image").unwrap());
+ }
+ if x.nv_viewport_array2 {
+ data.push(std::ffi::CString::new("VK_NV_viewport_array2").unwrap());
+ }
+ if x.nv_viewport_swizzle {
+ data.push(std::ffi::CString::new("VK_NV_viewport_swizzle").unwrap());
+ }
+ if x.nv_win32_keyed_mutex {
+ data.push(std::ffi::CString::new("VK_NV_win32_keyed_mutex").unwrap());
+ }
+ if x.qcom_fragment_density_map_offset {
+ data.push(std::ffi::CString::new("VK_QCOM_fragment_density_map_offset").unwrap());
+ }
+ if x.qcom_image_processing {
+ data.push(std::ffi::CString::new("VK_QCOM_image_processing").unwrap());
+ }
+ if x.qcom_multiview_per_view_viewports {
+ data.push(std::ffi::CString::new("VK_QCOM_multiview_per_view_viewports").unwrap());
+ }
+ if x.qcom_render_pass_shader_resolve {
+ data.push(std::ffi::CString::new("VK_QCOM_render_pass_shader_resolve").unwrap());
+ }
+ if x.qcom_render_pass_store_ops {
+ data.push(std::ffi::CString::new("VK_QCOM_render_pass_store_ops").unwrap());
+ }
+ if x.qcom_render_pass_transform {
+ data.push(std::ffi::CString::new("VK_QCOM_render_pass_transform").unwrap());
+ }
+ if x.qcom_rotated_copy_commands {
+ data.push(std::ffi::CString::new("VK_QCOM_rotated_copy_commands").unwrap());
+ }
+ if x.qcom_tile_properties {
+ data.push(std::ffi::CString::new("VK_QCOM_tile_properties").unwrap());
+ }
+ if x.sec_amigo_profiling {
+ data.push(std::ffi::CString::new("VK_SEC_amigo_profiling").unwrap());
+ }
+ if x.valve_descriptor_set_host_mapping {
+ data.push(std::ffi::CString::new("VK_VALVE_descriptor_set_host_mapping").unwrap());
+ }
+ if x.valve_mutable_descriptor_type {
+ data.push(std::ffi::CString::new("VK_VALVE_mutable_descriptor_type").unwrap());
+ }
+ data
+ }
+}
+impl IntoIterator for DeviceExtensions {
+ type Item = (&'static str, bool);
+ type IntoIter = std::array::IntoIter<Self::Item, 275usize>;
+ #[inline]
+ fn into_iter(self) -> Self::IntoIter {
+ [
+ ("VK_KHR_16bit_storage", self.khr_16bit_storage),
+ ("VK_KHR_8bit_storage", self.khr_8bit_storage),
+ (
+ "VK_KHR_acceleration_structure",
+ self.khr_acceleration_structure,
+ ),
+ ("VK_KHR_bind_memory2", self.khr_bind_memory2),
+ (
+ "VK_KHR_buffer_device_address",
+ self.khr_buffer_device_address,
+ ),
+ ("VK_KHR_copy_commands2", self.khr_copy_commands2),
+ ("VK_KHR_create_renderpass2", self.khr_create_renderpass2),
+ ("VK_KHR_dedicated_allocation", self.khr_dedicated_allocation),
+ (
+ "VK_KHR_deferred_host_operations",
+ self.khr_deferred_host_operations,
+ ),
+ (
+ "VK_KHR_depth_stencil_resolve",
+ self.khr_depth_stencil_resolve,
+ ),
+ (
+ "VK_KHR_descriptor_update_template",
+ self.khr_descriptor_update_template,
+ ),
+ ("VK_KHR_device_group", self.khr_device_group),
+ ("VK_KHR_display_swapchain", self.khr_display_swapchain),
+ ("VK_KHR_draw_indirect_count", self.khr_draw_indirect_count),
+ ("VK_KHR_driver_properties", self.khr_driver_properties),
+ ("VK_KHR_dynamic_rendering", self.khr_dynamic_rendering),
+ ("VK_KHR_external_fence", self.khr_external_fence),
+ ("VK_KHR_external_fence_fd", self.khr_external_fence_fd),
+ ("VK_KHR_external_fence_win32", self.khr_external_fence_win32),
+ ("VK_KHR_external_memory", self.khr_external_memory),
+ ("VK_KHR_external_memory_fd", self.khr_external_memory_fd),
+ (
+ "VK_KHR_external_memory_win32",
+ self.khr_external_memory_win32,
+ ),
+ ("VK_KHR_external_semaphore", self.khr_external_semaphore),
+ (
+ "VK_KHR_external_semaphore_fd",
+ self.khr_external_semaphore_fd,
+ ),
+ (
+ "VK_KHR_external_semaphore_win32",
+ self.khr_external_semaphore_win32,
+ ),
+ (
+ "VK_KHR_format_feature_flags2",
+ self.khr_format_feature_flags2,
+ ),
+ (
+ "VK_KHR_fragment_shader_barycentric",
+ self.khr_fragment_shader_barycentric,
+ ),
+ (
+ "VK_KHR_fragment_shading_rate",
+ self.khr_fragment_shading_rate,
+ ),
+ (
+ "VK_KHR_get_memory_requirements2",
+ self.khr_get_memory_requirements2,
+ ),
+ ("VK_KHR_global_priority", self.khr_global_priority),
+ ("VK_KHR_image_format_list", self.khr_image_format_list),
+ (
+ "VK_KHR_imageless_framebuffer",
+ self.khr_imageless_framebuffer,
+ ),
+ ("VK_KHR_incremental_present", self.khr_incremental_present),
+ ("VK_KHR_maintenance1", self.khr_maintenance1),
+ ("VK_KHR_maintenance2", self.khr_maintenance2),
+ ("VK_KHR_maintenance3", self.khr_maintenance3),
+ ("VK_KHR_maintenance4", self.khr_maintenance4),
+ ("VK_KHR_multiview", self.khr_multiview),
+ ("VK_KHR_performance_query", self.khr_performance_query),
+ (
+ "VK_KHR_pipeline_executable_properties",
+ self.khr_pipeline_executable_properties,
+ ),
+ ("VK_KHR_pipeline_library", self.khr_pipeline_library),
+ ("VK_KHR_portability_subset", self.khr_portability_subset),
+ ("VK_KHR_present_id", self.khr_present_id),
+ ("VK_KHR_present_wait", self.khr_present_wait),
+ ("VK_KHR_push_descriptor", self.khr_push_descriptor),
+ ("VK_KHR_ray_query", self.khr_ray_query),
+ (
+ "VK_KHR_ray_tracing_maintenance1",
+ self.khr_ray_tracing_maintenance1,
+ ),
+ ("VK_KHR_ray_tracing_pipeline", self.khr_ray_tracing_pipeline),
+ ("VK_KHR_relaxed_block_layout", self.khr_relaxed_block_layout),
+ (
+ "VK_KHR_sampler_mirror_clamp_to_edge",
+ self.khr_sampler_mirror_clamp_to_edge,
+ ),
+ (
+ "VK_KHR_sampler_ycbcr_conversion",
+ self.khr_sampler_ycbcr_conversion,
+ ),
+ (
+ "VK_KHR_separate_depth_stencil_layouts",
+ self.khr_separate_depth_stencil_layouts,
+ ),
+ ("VK_KHR_shader_atomic_int64", self.khr_shader_atomic_int64),
+ ("VK_KHR_shader_clock", self.khr_shader_clock),
+ (
+ "VK_KHR_shader_draw_parameters",
+ self.khr_shader_draw_parameters,
+ ),
+ ("VK_KHR_shader_float16_int8", self.khr_shader_float16_int8),
+ (
+ "VK_KHR_shader_float_controls",
+ self.khr_shader_float_controls,
+ ),
+ (
+ "VK_KHR_shader_integer_dot_product",
+ self.khr_shader_integer_dot_product,
+ ),
+ (
+ "VK_KHR_shader_non_semantic_info",
+ self.khr_shader_non_semantic_info,
+ ),
+ (
+ "VK_KHR_shader_subgroup_extended_types",
+ self.khr_shader_subgroup_extended_types,
+ ),
+ (
+ "VK_KHR_shader_subgroup_uniform_control_flow",
+ self.khr_shader_subgroup_uniform_control_flow,
+ ),
+ (
+ "VK_KHR_shader_terminate_invocation",
+ self.khr_shader_terminate_invocation,
+ ),
+ (
+ "VK_KHR_shared_presentable_image",
+ self.khr_shared_presentable_image,
+ ),
+ ("VK_KHR_spirv_1_4", self.khr_spirv_1_4),
+ (
+ "VK_KHR_storage_buffer_storage_class",
+ self.khr_storage_buffer_storage_class,
+ ),
+ ("VK_KHR_swapchain", self.khr_swapchain),
+ (
+ "VK_KHR_swapchain_mutable_format",
+ self.khr_swapchain_mutable_format,
+ ),
+ ("VK_KHR_synchronization2", self.khr_synchronization2),
+ ("VK_KHR_timeline_semaphore", self.khr_timeline_semaphore),
+ (
+ "VK_KHR_uniform_buffer_standard_layout",
+ self.khr_uniform_buffer_standard_layout,
+ ),
+ ("VK_KHR_variable_pointers", self.khr_variable_pointers),
+ ("VK_KHR_video_decode_h264", self.khr_video_decode_h264),
+ ("VK_KHR_video_decode_h265", self.khr_video_decode_h265),
+ ("VK_KHR_video_decode_queue", self.khr_video_decode_queue),
+ ("VK_KHR_video_encode_queue", self.khr_video_encode_queue),
+ ("VK_KHR_video_queue", self.khr_video_queue),
+ ("VK_KHR_vulkan_memory_model", self.khr_vulkan_memory_model),
+ ("VK_KHR_win32_keyed_mutex", self.khr_win32_keyed_mutex),
+ (
+ "VK_KHR_workgroup_memory_explicit_layout",
+ self.khr_workgroup_memory_explicit_layout,
+ ),
+ (
+ "VK_KHR_zero_initialize_workgroup_memory",
+ self.khr_zero_initialize_workgroup_memory,
+ ),
+ ("VK_EXT_4444_formats", self.ext_4444_formats),
+ ("VK_EXT_astc_decode_mode", self.ext_astc_decode_mode),
+ (
+ "VK_EXT_attachment_feedback_loop_layout",
+ self.ext_attachment_feedback_loop_layout,
+ ),
+ (
+ "VK_EXT_blend_operation_advanced",
+ self.ext_blend_operation_advanced,
+ ),
+ ("VK_EXT_border_color_swizzle", self.ext_border_color_swizzle),
+ (
+ "VK_EXT_buffer_device_address",
+ self.ext_buffer_device_address,
+ ),
+ (
+ "VK_EXT_calibrated_timestamps",
+ self.ext_calibrated_timestamps,
+ ),
+ ("VK_EXT_color_write_enable", self.ext_color_write_enable),
+ (
+ "VK_EXT_conditional_rendering",
+ self.ext_conditional_rendering,
+ ),
+ (
+ "VK_EXT_conservative_rasterization",
+ self.ext_conservative_rasterization,
+ ),
+ ("VK_EXT_custom_border_color", self.ext_custom_border_color),
+ ("VK_EXT_debug_marker", self.ext_debug_marker),
+ ("VK_EXT_depth_clamp_zero_one", self.ext_depth_clamp_zero_one),
+ ("VK_EXT_depth_clip_control", self.ext_depth_clip_control),
+ ("VK_EXT_depth_clip_enable", self.ext_depth_clip_enable),
+ (
+ "VK_EXT_depth_range_unrestricted",
+ self.ext_depth_range_unrestricted,
+ ),
+ ("VK_EXT_descriptor_buffer", self.ext_descriptor_buffer),
+ ("VK_EXT_descriptor_indexing", self.ext_descriptor_indexing),
+ (
+ "VK_EXT_device_address_binding_report",
+ self.ext_device_address_binding_report,
+ ),
+ ("VK_EXT_device_fault", self.ext_device_fault),
+ ("VK_EXT_device_memory_report", self.ext_device_memory_report),
+ ("VK_EXT_discard_rectangles", self.ext_discard_rectangles),
+ ("VK_EXT_display_control", self.ext_display_control),
+ (
+ "VK_EXT_extended_dynamic_state",
+ self.ext_extended_dynamic_state,
+ ),
+ (
+ "VK_EXT_extended_dynamic_state2",
+ self.ext_extended_dynamic_state2,
+ ),
+ (
+ "VK_EXT_extended_dynamic_state3",
+ self.ext_extended_dynamic_state3,
+ ),
+ (
+ "VK_EXT_external_memory_dma_buf",
+ self.ext_external_memory_dma_buf,
+ ),
+ ("VK_EXT_external_memory_host", self.ext_external_memory_host),
+ ("VK_EXT_filter_cubic", self.ext_filter_cubic),
+ ("VK_EXT_fragment_density_map", self.ext_fragment_density_map),
+ (
+ "VK_EXT_fragment_density_map2",
+ self.ext_fragment_density_map2,
+ ),
+ (
+ "VK_EXT_fragment_shader_interlock",
+ self.ext_fragment_shader_interlock,
+ ),
+ (
+ "VK_EXT_full_screen_exclusive",
+ self.ext_full_screen_exclusive,
+ ),
+ ("VK_EXT_global_priority", self.ext_global_priority),
+ (
+ "VK_EXT_global_priority_query",
+ self.ext_global_priority_query,
+ ),
+ (
+ "VK_EXT_graphics_pipeline_library",
+ self.ext_graphics_pipeline_library,
+ ),
+ ("VK_EXT_hdr_metadata", self.ext_hdr_metadata),
+ ("VK_EXT_host_query_reset", self.ext_host_query_reset),
+ ("VK_EXT_image_2d_view_of_3d", self.ext_image_2d_view_of_3d),
+ (
+ "VK_EXT_image_compression_control",
+ self.ext_image_compression_control,
+ ),
+ (
+ "VK_EXT_image_compression_control_swapchain",
+ self.ext_image_compression_control_swapchain,
+ ),
+ (
+ "VK_EXT_image_drm_format_modifier",
+ self.ext_image_drm_format_modifier,
+ ),
+ ("VK_EXT_image_robustness", self.ext_image_robustness),
+ ("VK_EXT_image_view_min_lod", self.ext_image_view_min_lod),
+ ("VK_EXT_index_type_uint8", self.ext_index_type_uint8),
+ ("VK_EXT_inline_uniform_block", self.ext_inline_uniform_block),
+ ("VK_EXT_legacy_dithering", self.ext_legacy_dithering),
+ ("VK_EXT_line_rasterization", self.ext_line_rasterization),
+ ("VK_EXT_load_store_op_none", self.ext_load_store_op_none),
+ ("VK_EXT_memory_budget", self.ext_memory_budget),
+ ("VK_EXT_memory_priority", self.ext_memory_priority),
+ ("VK_EXT_mesh_shader", self.ext_mesh_shader),
+ ("VK_EXT_metal_objects", self.ext_metal_objects),
+ ("VK_EXT_multi_draw", self.ext_multi_draw),
+ (
+ "VK_EXT_multisampled_render_to_single_sampled",
+ self.ext_multisampled_render_to_single_sampled,
+ ),
+ (
+ "VK_EXT_mutable_descriptor_type",
+ self.ext_mutable_descriptor_type,
+ ),
+ (
+ "VK_EXT_non_seamless_cube_map",
+ self.ext_non_seamless_cube_map,
+ ),
+ ("VK_EXT_opacity_micromap", self.ext_opacity_micromap),
+ (
+ "VK_EXT_pageable_device_local_memory",
+ self.ext_pageable_device_local_memory,
+ ),
+ ("VK_EXT_pci_bus_info", self.ext_pci_bus_info),
+ ("VK_EXT_physical_device_drm", self.ext_physical_device_drm),
+ (
+ "VK_EXT_pipeline_creation_cache_control",
+ self.ext_pipeline_creation_cache_control,
+ ),
+ (
+ "VK_EXT_pipeline_creation_feedback",
+ self.ext_pipeline_creation_feedback,
+ ),
+ ("VK_EXT_pipeline_properties", self.ext_pipeline_properties),
+ (
+ "VK_EXT_pipeline_protected_access",
+ self.ext_pipeline_protected_access,
+ ),
+ ("VK_EXT_pipeline_robustness", self.ext_pipeline_robustness),
+ ("VK_EXT_post_depth_coverage", self.ext_post_depth_coverage),
+ (
+ "VK_EXT_primitive_topology_list_restart",
+ self.ext_primitive_topology_list_restart,
+ ),
+ (
+ "VK_EXT_primitives_generated_query",
+ self.ext_primitives_generated_query,
+ ),
+ ("VK_EXT_private_data", self.ext_private_data),
+ ("VK_EXT_provoking_vertex", self.ext_provoking_vertex),
+ ("VK_EXT_queue_family_foreign", self.ext_queue_family_foreign),
+ (
+ "VK_EXT_rasterization_order_attachment_access",
+ self.ext_rasterization_order_attachment_access,
+ ),
+ ("VK_EXT_rgba10x6_formats", self.ext_rgba10x6_formats),
+ ("VK_EXT_robustness2", self.ext_robustness2),
+ ("VK_EXT_sample_locations", self.ext_sample_locations),
+ (
+ "VK_EXT_sampler_filter_minmax",
+ self.ext_sampler_filter_minmax,
+ ),
+ ("VK_EXT_scalar_block_layout", self.ext_scalar_block_layout),
+ (
+ "VK_EXT_separate_stencil_usage",
+ self.ext_separate_stencil_usage,
+ ),
+ ("VK_EXT_shader_atomic_float", self.ext_shader_atomic_float),
+ ("VK_EXT_shader_atomic_float2", self.ext_shader_atomic_float2),
+ (
+ "VK_EXT_shader_demote_to_helper_invocation",
+ self.ext_shader_demote_to_helper_invocation,
+ ),
+ (
+ "VK_EXT_shader_image_atomic_int64",
+ self.ext_shader_image_atomic_int64,
+ ),
+ (
+ "VK_EXT_shader_module_identifier",
+ self.ext_shader_module_identifier,
+ ),
+ (
+ "VK_EXT_shader_stencil_export",
+ self.ext_shader_stencil_export,
+ ),
+ (
+ "VK_EXT_shader_subgroup_ballot",
+ self.ext_shader_subgroup_ballot,
+ ),
+ ("VK_EXT_shader_subgroup_vote", self.ext_shader_subgroup_vote),
+ (
+ "VK_EXT_shader_viewport_index_layer",
+ self.ext_shader_viewport_index_layer,
+ ),
+ (
+ "VK_EXT_subgroup_size_control",
+ self.ext_subgroup_size_control,
+ ),
+ (
+ "VK_EXT_subpass_merge_feedback",
+ self.ext_subpass_merge_feedback,
+ ),
+ (
+ "VK_EXT_swapchain_maintenance1",
+ self.ext_swapchain_maintenance1,
+ ),
+ (
+ "VK_EXT_texel_buffer_alignment",
+ self.ext_texel_buffer_alignment,
+ ),
+ (
+ "VK_EXT_texture_compression_astc_hdr",
+ self.ext_texture_compression_astc_hdr,
+ ),
+ ("VK_EXT_tooling_info", self.ext_tooling_info),
+ ("VK_EXT_transform_feedback", self.ext_transform_feedback),
+ ("VK_EXT_validation_cache", self.ext_validation_cache),
+ (
+ "VK_EXT_vertex_attribute_divisor",
+ self.ext_vertex_attribute_divisor,
+ ),
+ (
+ "VK_EXT_vertex_input_dynamic_state",
+ self.ext_vertex_input_dynamic_state,
+ ),
+ ("VK_EXT_video_encode_h264", self.ext_video_encode_h264),
+ ("VK_EXT_video_encode_h265", self.ext_video_encode_h265),
+ (
+ "VK_EXT_ycbcr_2plane_444_formats",
+ self.ext_ycbcr_2plane_444_formats,
+ ),
+ ("VK_EXT_ycbcr_image_arrays", self.ext_ycbcr_image_arrays),
+ ("VK_AMD_buffer_marker", self.amd_buffer_marker),
+ (
+ "VK_AMD_device_coherent_memory",
+ self.amd_device_coherent_memory,
+ ),
+ ("VK_AMD_display_native_hdr", self.amd_display_native_hdr),
+ ("VK_AMD_draw_indirect_count", self.amd_draw_indirect_count),
+ ("VK_AMD_gcn_shader", self.amd_gcn_shader),
+ (
+ "VK_AMD_gpu_shader_half_float",
+ self.amd_gpu_shader_half_float,
+ ),
+ ("VK_AMD_gpu_shader_int16", self.amd_gpu_shader_int16),
+ (
+ "VK_AMD_memory_overallocation_behavior",
+ self.amd_memory_overallocation_behavior,
+ ),
+ (
+ "VK_AMD_mixed_attachment_samples",
+ self.amd_mixed_attachment_samples,
+ ),
+ (
+ "VK_AMD_pipeline_compiler_control",
+ self.amd_pipeline_compiler_control,
+ ),
+ ("VK_AMD_rasterization_order", self.amd_rasterization_order),
+ ("VK_AMD_shader_ballot", self.amd_shader_ballot),
+ (
+ "VK_AMD_shader_core_properties",
+ self.amd_shader_core_properties,
+ ),
+ (
+ "VK_AMD_shader_core_properties2",
+ self.amd_shader_core_properties2,
+ ),
+ (
+ "VK_AMD_shader_early_and_late_fragment_tests",
+ self.amd_shader_early_and_late_fragment_tests,
+ ),
+ (
+ "VK_AMD_shader_explicit_vertex_parameter",
+ self.amd_shader_explicit_vertex_parameter,
+ ),
+ ("VK_AMD_shader_fragment_mask", self.amd_shader_fragment_mask),
+ (
+ "VK_AMD_shader_image_load_store_lod",
+ self.amd_shader_image_load_store_lod,
+ ),
+ ("VK_AMD_shader_info", self.amd_shader_info),
+ (
+ "VK_AMD_shader_trinary_minmax",
+ self.amd_shader_trinary_minmax,
+ ),
+ (
+ "VK_AMD_texture_gather_bias_lod",
+ self.amd_texture_gather_bias_lod,
+ ),
+ (
+ "VK_ANDROID_external_memory_android_hardware_buffer",
+ self.android_external_memory_android_hardware_buffer,
+ ),
+ (
+ "VK_ARM_rasterization_order_attachment_access",
+ self.arm_rasterization_order_attachment_access,
+ ),
+ ("VK_ARM_shader_core_builtins", self.arm_shader_core_builtins),
+ (
+ "VK_FUCHSIA_buffer_collection",
+ self.fuchsia_buffer_collection,
+ ),
+ ("VK_FUCHSIA_external_memory", self.fuchsia_external_memory),
+ (
+ "VK_FUCHSIA_external_semaphore",
+ self.fuchsia_external_semaphore,
+ ),
+ ("VK_GGP_frame_token", self.ggp_frame_token),
+ ("VK_GOOGLE_decorate_string", self.google_decorate_string),
+ ("VK_GOOGLE_display_timing", self.google_display_timing),
+ (
+ "VK_GOOGLE_hlsl_functionality1",
+ self.google_hlsl_functionality1,
+ ),
+ ("VK_GOOGLE_user_type", self.google_user_type),
+ ("VK_HUAWEI_invocation_mask", self.huawei_invocation_mask),
+ ("VK_HUAWEI_subpass_shading", self.huawei_subpass_shading),
+ ("VK_IMG_filter_cubic", self.img_filter_cubic),
+ ("VK_IMG_format_pvrtc", self.img_format_pvrtc),
+ ("VK_INTEL_performance_query", self.intel_performance_query),
+ (
+ "VK_INTEL_shader_integer_functions2",
+ self.intel_shader_integer_functions2,
+ ),
+ ("VK_NVX_binary_import", self.nvx_binary_import),
+ ("VK_NVX_image_view_handle", self.nvx_image_view_handle),
+ (
+ "VK_NVX_multiview_per_view_attributes",
+ self.nvx_multiview_per_view_attributes,
+ ),
+ ("VK_NV_acquire_winrt_display", self.nv_acquire_winrt_display),
+ ("VK_NV_clip_space_w_scaling", self.nv_clip_space_w_scaling),
+ (
+ "VK_NV_compute_shader_derivatives",
+ self.nv_compute_shader_derivatives,
+ ),
+ ("VK_NV_cooperative_matrix", self.nv_cooperative_matrix),
+ ("VK_NV_copy_memory_indirect", self.nv_copy_memory_indirect),
+ ("VK_NV_corner_sampled_image", self.nv_corner_sampled_image),
+ (
+ "VK_NV_coverage_reduction_mode",
+ self.nv_coverage_reduction_mode,
+ ),
+ ("VK_NV_dedicated_allocation", self.nv_dedicated_allocation),
+ (
+ "VK_NV_dedicated_allocation_image_aliasing",
+ self.nv_dedicated_allocation_image_aliasing,
+ ),
+ (
+ "VK_NV_device_diagnostic_checkpoints",
+ self.nv_device_diagnostic_checkpoints,
+ ),
+ (
+ "VK_NV_device_diagnostics_config",
+ self.nv_device_diagnostics_config,
+ ),
+ (
+ "VK_NV_device_generated_commands",
+ self.nv_device_generated_commands,
+ ),
+ ("VK_NV_external_memory", self.nv_external_memory),
+ ("VK_NV_external_memory_rdma", self.nv_external_memory_rdma),
+ ("VK_NV_external_memory_win32", self.nv_external_memory_win32),
+ ("VK_NV_fill_rectangle", self.nv_fill_rectangle),
+ (
+ "VK_NV_fragment_coverage_to_color",
+ self.nv_fragment_coverage_to_color,
+ ),
+ (
+ "VK_NV_fragment_shader_barycentric",
+ self.nv_fragment_shader_barycentric,
+ ),
+ (
+ "VK_NV_fragment_shading_rate_enums",
+ self.nv_fragment_shading_rate_enums,
+ ),
+ (
+ "VK_NV_framebuffer_mixed_samples",
+ self.nv_framebuffer_mixed_samples,
+ ),
+ (
+ "VK_NV_geometry_shader_passthrough",
+ self.nv_geometry_shader_passthrough,
+ ),
+ ("VK_NV_glsl_shader", self.nv_glsl_shader),
+ (
+ "VK_NV_inherited_viewport_scissor",
+ self.nv_inherited_viewport_scissor,
+ ),
+ (
+ "VK_NV_linear_color_attachment",
+ self.nv_linear_color_attachment,
+ ),
+ ("VK_NV_memory_decompression", self.nv_memory_decompression),
+ ("VK_NV_mesh_shader", self.nv_mesh_shader),
+ ("VK_NV_optical_flow", self.nv_optical_flow),
+ ("VK_NV_present_barrier", self.nv_present_barrier),
+ ("VK_NV_ray_tracing", self.nv_ray_tracing),
+ (
+ "VK_NV_ray_tracing_invocation_reorder",
+ self.nv_ray_tracing_invocation_reorder,
+ ),
+ (
+ "VK_NV_ray_tracing_motion_blur",
+ self.nv_ray_tracing_motion_blur,
+ ),
+ (
+ "VK_NV_representative_fragment_test",
+ self.nv_representative_fragment_test,
+ ),
+ (
+ "VK_NV_sample_mask_override_coverage",
+ self.nv_sample_mask_override_coverage,
+ ),
+ ("VK_NV_scissor_exclusive", self.nv_scissor_exclusive),
+ (
+ "VK_NV_shader_image_footprint",
+ self.nv_shader_image_footprint,
+ ),
+ ("VK_NV_shader_sm_builtins", self.nv_shader_sm_builtins),
+ (
+ "VK_NV_shader_subgroup_partitioned",
+ self.nv_shader_subgroup_partitioned,
+ ),
+ ("VK_NV_shading_rate_image", self.nv_shading_rate_image),
+ ("VK_NV_viewport_array2", self.nv_viewport_array2),
+ ("VK_NV_viewport_swizzle", self.nv_viewport_swizzle),
+ ("VK_NV_win32_keyed_mutex", self.nv_win32_keyed_mutex),
+ (
+ "VK_QCOM_fragment_density_map_offset",
+ self.qcom_fragment_density_map_offset,
+ ),
+ ("VK_QCOM_image_processing", self.qcom_image_processing),
+ (
+ "VK_QCOM_multiview_per_view_viewports",
+ self.qcom_multiview_per_view_viewports,
+ ),
+ (
+ "VK_QCOM_render_pass_shader_resolve",
+ self.qcom_render_pass_shader_resolve,
+ ),
+ (
+ "VK_QCOM_render_pass_store_ops",
+ self.qcom_render_pass_store_ops,
+ ),
+ (
+ "VK_QCOM_render_pass_transform",
+ self.qcom_render_pass_transform,
+ ),
+ (
+ "VK_QCOM_rotated_copy_commands",
+ self.qcom_rotated_copy_commands,
+ ),
+ ("VK_QCOM_tile_properties", self.qcom_tile_properties),
+ ("VK_SEC_amigo_profiling", self.sec_amigo_profiling),
+ (
+ "VK_VALVE_descriptor_set_host_mapping",
+ self.valve_descriptor_set_host_mapping,
+ ),
+ (
+ "VK_VALVE_mutable_descriptor_type",
+ self.valve_mutable_descriptor_type,
+ ),
+ ]
+ .into_iter()
+ }
+}
+impl DeviceExtensions {
+ #[doc = r" Checks enabled extensions against the device version, instance extensions and each other."]
+ pub(super) fn check_requirements(
+ &self,
+ supported: &DeviceExtensions,
+ api_version: crate::Version,
+ instance_extensions: &crate::instance::InstanceExtensions,
+ ) -> Result<(), crate::device::ExtensionRestrictionError> {
+ let device_extensions = self;
+ if self.khr_16bit_storage {
+ if !supported.khr_16bit_storage {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_16bit_storage",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_16bit_storage",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || device_extensions.khr_storage_buffer_storage_class)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_16bit_storage",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_storage_buffer_storage_class"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_8bit_storage {
+ if !supported.khr_8bit_storage {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_8bit_storage",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_8bit_storage",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || device_extensions.khr_storage_buffer_storage_class)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_8bit_storage",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_storage_buffer_storage_class"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_acceleration_structure {
+ if !supported.khr_acceleration_structure {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_acceleration_structure",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_acceleration_structure",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_2 || device_extensions.ext_descriptor_indexing) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_acceleration_structure",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_2),
+ device_extensions: &["ext_descriptor_indexing"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_2 || device_extensions.khr_buffer_device_address)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_acceleration_structure",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_2),
+ device_extensions: &["khr_buffer_device_address"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(device_extensions.khr_deferred_host_operations) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_acceleration_structure",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_deferred_host_operations"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_bind_memory2 {
+ if !supported.khr_bind_memory2 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_bind_memory2",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.khr_buffer_device_address {
+ if !supported.khr_buffer_device_address {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_buffer_device_address",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_buffer_device_address",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if self.ext_buffer_device_address {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_buffer_device_address",
+ restriction: crate::device::ExtensionRestriction::ConflictsDeviceExtension(
+ "ext_buffer_device_address",
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_copy_commands2 {
+ if !supported.khr_copy_commands2 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_copy_commands2",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.khr_create_renderpass2 {
+ if !supported.khr_create_renderpass2 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_create_renderpass2",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1 || device_extensions.khr_multiview) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_create_renderpass2",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_multiview"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_1 || device_extensions.khr_maintenance2) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_create_renderpass2",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_maintenance2"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_dedicated_allocation {
+ if !supported.khr_dedicated_allocation {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_dedicated_allocation",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || device_extensions.khr_get_memory_requirements2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_dedicated_allocation",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_get_memory_requirements2"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_deferred_host_operations {
+ if !supported.khr_deferred_host_operations {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_deferred_host_operations",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.khr_depth_stencil_resolve {
+ if !supported.khr_depth_stencil_resolve {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_depth_stencil_resolve",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_2 || device_extensions.khr_create_renderpass2) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_depth_stencil_resolve",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_2),
+ device_extensions: &["khr_create_renderpass2"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_descriptor_update_template {
+ if !supported.khr_descriptor_update_template {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_descriptor_update_template",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.khr_device_group {
+ if !supported.khr_device_group {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_device_group",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_device_group_creation)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_device_group",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_device_group_creation"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_display_swapchain {
+ if !supported.khr_display_swapchain {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_display_swapchain",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.khr_swapchain) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_display_swapchain",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_swapchain"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(instance_extensions.khr_display) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_display_swapchain",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_display"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_draw_indirect_count {
+ if !supported.khr_draw_indirect_count {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_draw_indirect_count",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.khr_driver_properties {
+ if !supported.khr_driver_properties {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_driver_properties",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_driver_properties",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_dynamic_rendering {
+ if !supported.khr_dynamic_rendering {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_dynamic_rendering",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_2 || device_extensions.khr_depth_stencil_resolve)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_dynamic_rendering",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_2),
+ device_extensions: &["khr_depth_stencil_resolve"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_dynamic_rendering",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_external_fence {
+ if !supported.khr_external_fence {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_external_fence",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_external_fence_capabilities)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_external_fence",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_external_fence_capabilities"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_external_fence_fd {
+ if !supported.khr_external_fence_fd {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_external_fence_fd",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1 || device_extensions.khr_external_fence) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_external_fence_fd",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_external_fence"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_external_fence_win32 {
+ if !supported.khr_external_fence_win32 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_external_fence_win32",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1 || device_extensions.khr_external_fence) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_external_fence_win32",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_external_fence"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_external_memory {
+ if !supported.khr_external_memory {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_external_memory",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_external_memory_capabilities)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_external_memory",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_external_memory_capabilities"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_external_memory_fd {
+ if !supported.khr_external_memory_fd {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_external_memory_fd",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1 || device_extensions.khr_external_memory) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_external_memory_fd",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_external_memory"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_external_memory_win32 {
+ if !supported.khr_external_memory_win32 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_external_memory_win32",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1 || device_extensions.khr_external_memory) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_external_memory_win32",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_external_memory"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_external_semaphore {
+ if !supported.khr_external_semaphore {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_external_semaphore",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_external_semaphore_capabilities)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_external_semaphore",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_external_semaphore_capabilities"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_external_semaphore_fd {
+ if !supported.khr_external_semaphore_fd {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_external_semaphore_fd",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1 || device_extensions.khr_external_semaphore) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_external_semaphore_fd",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_external_semaphore"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_external_semaphore_win32 {
+ if !supported.khr_external_semaphore_win32 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_external_semaphore_win32",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1 || device_extensions.khr_external_semaphore) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_external_semaphore_win32",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_external_semaphore"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_format_feature_flags2 {
+ if !supported.khr_format_feature_flags2 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_format_feature_flags2",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_format_feature_flags2",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_fragment_shader_barycentric {
+ if !supported.khr_fragment_shader_barycentric {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_fragment_shader_barycentric",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_fragment_shader_barycentric",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_fragment_shading_rate {
+ if !supported.khr_fragment_shading_rate {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_fragment_shading_rate",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_2 || device_extensions.khr_create_renderpass2) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_fragment_shading_rate",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_2),
+ device_extensions: &["khr_create_renderpass2"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_fragment_shading_rate",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_get_memory_requirements2 {
+ if !supported.khr_get_memory_requirements2 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_get_memory_requirements2",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.khr_global_priority {
+ if !supported.khr_global_priority {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_global_priority",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.khr_image_format_list {
+ if !supported.khr_image_format_list {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_image_format_list",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.khr_imageless_framebuffer {
+ if !supported.khr_imageless_framebuffer {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_imageless_framebuffer",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1 || device_extensions.khr_maintenance2) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_imageless_framebuffer",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_maintenance2"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_2 || device_extensions.khr_image_format_list) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_imageless_framebuffer",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_2),
+ device_extensions: &["khr_image_format_list"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_incremental_present {
+ if !supported.khr_incremental_present {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_incremental_present",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.khr_swapchain) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_incremental_present",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_swapchain"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_maintenance1 {
+ if !supported.khr_maintenance1 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_maintenance1",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.khr_maintenance2 {
+ if !supported.khr_maintenance2 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_maintenance2",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.khr_maintenance3 {
+ if !supported.khr_maintenance3 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_maintenance3",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_maintenance3",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_maintenance4 {
+ if !supported.khr_maintenance4 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_maintenance4",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_maintenance4",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_multiview {
+ if !supported.khr_multiview {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_multiview",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_multiview",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_performance_query {
+ if !supported.khr_performance_query {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_performance_query",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_performance_query",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_pipeline_executable_properties {
+ if !supported.khr_pipeline_executable_properties {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_pipeline_executable_properties",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_pipeline_executable_properties",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_pipeline_library {
+ if !supported.khr_pipeline_library {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_pipeline_library",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.khr_portability_subset {
+ if !supported.khr_portability_subset {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_portability_subset",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_portability_subset",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ if supported.khr_portability_subset {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_portability_subset",
+ restriction: crate::device::ExtensionRestriction::RequiredIfSupported,
+ });
+ }
+ }
+ if self.khr_present_id {
+ if !supported.khr_present_id {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_present_id",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.khr_swapchain) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_present_id",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_swapchain"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_present_wait {
+ if !supported.khr_present_wait {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_present_wait",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.khr_swapchain) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_present_wait",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_swapchain"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(device_extensions.khr_present_id) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_present_wait",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_present_id"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_push_descriptor {
+ if !supported.khr_push_descriptor {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_push_descriptor",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_push_descriptor",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_ray_query {
+ if !supported.khr_ray_query {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_ray_query",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_ray_query",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_2 || device_extensions.khr_spirv_1_4) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_ray_query",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_2),
+ device_extensions: &["khr_spirv_1_4"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(device_extensions.khr_acceleration_structure) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_ray_query",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_acceleration_structure"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_ray_tracing_maintenance1 {
+ if !supported.khr_ray_tracing_maintenance1 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_ray_tracing_maintenance1",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_ray_tracing_maintenance1",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(device_extensions.khr_acceleration_structure) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_ray_tracing_maintenance1",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_acceleration_structure"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_ray_tracing_pipeline {
+ if !supported.khr_ray_tracing_pipeline {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_ray_tracing_pipeline",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_ray_tracing_pipeline",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_2 || device_extensions.khr_spirv_1_4) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_ray_tracing_pipeline",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_2),
+ device_extensions: &["khr_spirv_1_4"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(device_extensions.khr_acceleration_structure) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_ray_tracing_pipeline",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_acceleration_structure"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_relaxed_block_layout {
+ if !supported.khr_relaxed_block_layout {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_relaxed_block_layout",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.khr_sampler_mirror_clamp_to_edge {
+ if !supported.khr_sampler_mirror_clamp_to_edge {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_sampler_mirror_clamp_to_edge",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.khr_sampler_ycbcr_conversion {
+ if !supported.khr_sampler_ycbcr_conversion {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_sampler_ycbcr_conversion",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1 || device_extensions.khr_maintenance1) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_sampler_ycbcr_conversion",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_maintenance1"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_1 || device_extensions.khr_bind_memory2) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_sampler_ycbcr_conversion",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_bind_memory2"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || device_extensions.khr_get_memory_requirements2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_sampler_ycbcr_conversion",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_get_memory_requirements2"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_sampler_ycbcr_conversion",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_separate_depth_stencil_layouts {
+ if !supported.khr_separate_depth_stencil_layouts {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_separate_depth_stencil_layouts",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_separate_depth_stencil_layouts",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_2 || device_extensions.khr_create_renderpass2) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_separate_depth_stencil_layouts",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_2),
+ device_extensions: &["khr_create_renderpass2"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_shader_atomic_int64 {
+ if !supported.khr_shader_atomic_int64 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_shader_atomic_int64",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_shader_atomic_int64",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_shader_clock {
+ if !supported.khr_shader_clock {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_shader_clock",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_shader_clock",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_shader_draw_parameters {
+ if !supported.khr_shader_draw_parameters {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_shader_draw_parameters",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.khr_shader_float16_int8 {
+ if !supported.khr_shader_float16_int8 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_shader_float16_int8",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_shader_float16_int8",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_shader_float_controls {
+ if !supported.khr_shader_float_controls {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_shader_float_controls",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_shader_float_controls",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_shader_integer_dot_product {
+ if !supported.khr_shader_integer_dot_product {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_shader_integer_dot_product",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_shader_integer_dot_product",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_shader_non_semantic_info {
+ if !supported.khr_shader_non_semantic_info {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_shader_non_semantic_info",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.khr_shader_subgroup_extended_types {
+ if !supported.khr_shader_subgroup_extended_types {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_shader_subgroup_extended_types",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_shader_subgroup_extended_types",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_shader_subgroup_uniform_control_flow {
+ if !supported.khr_shader_subgroup_uniform_control_flow {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_shader_subgroup_uniform_control_flow",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_shader_subgroup_uniform_control_flow",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_shader_terminate_invocation {
+ if !supported.khr_shader_terminate_invocation {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_shader_terminate_invocation",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_shader_terminate_invocation",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_shared_presentable_image {
+ if !supported.khr_shared_presentable_image {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_shared_presentable_image",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.khr_swapchain) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_shared_presentable_image",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_swapchain"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_shared_presentable_image",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(instance_extensions.khr_get_surface_capabilities2) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_shared_presentable_image",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_get_surface_capabilities2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_spirv_1_4 {
+ if !supported.khr_spirv_1_4 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_spirv_1_4",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_spirv_1_4",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_2 || device_extensions.khr_shader_float_controls)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_spirv_1_4",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_2),
+ device_extensions: &["khr_shader_float_controls"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_storage_buffer_storage_class {
+ if !supported.khr_storage_buffer_storage_class {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_storage_buffer_storage_class",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.khr_swapchain {
+ if !supported.khr_swapchain {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_swapchain",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(instance_extensions.khr_surface) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_swapchain",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_surface"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_swapchain_mutable_format {
+ if !supported.khr_swapchain_mutable_format {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_swapchain_mutable_format",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.khr_swapchain) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_swapchain_mutable_format",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_swapchain"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_1 || device_extensions.khr_maintenance2) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_swapchain_mutable_format",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_maintenance2"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_2 || device_extensions.khr_image_format_list) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_swapchain_mutable_format",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_2),
+ device_extensions: &["khr_image_format_list"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_synchronization2 {
+ if !supported.khr_synchronization2 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_synchronization2",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_synchronization2",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_timeline_semaphore {
+ if !supported.khr_timeline_semaphore {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_timeline_semaphore",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_timeline_semaphore",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_uniform_buffer_standard_layout {
+ if !supported.khr_uniform_buffer_standard_layout {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_uniform_buffer_standard_layout",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_uniform_buffer_standard_layout",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_variable_pointers {
+ if !supported.khr_variable_pointers {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_variable_pointers",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_variable_pointers",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || device_extensions.khr_storage_buffer_storage_class)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_variable_pointers",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_storage_buffer_storage_class"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_video_decode_h264 {
+ if !supported.khr_video_decode_h264 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_video_decode_h264",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.khr_video_decode_queue) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_video_decode_h264",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_video_decode_queue"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_video_decode_h265 {
+ if !supported.khr_video_decode_h265 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_video_decode_h265",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.khr_video_decode_queue) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_video_decode_h265",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_video_decode_queue"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_video_decode_queue {
+ if !supported.khr_video_decode_queue {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_video_decode_queue",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.khr_video_queue) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_video_decode_queue",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_video_queue"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_3 || device_extensions.khr_synchronization2) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_video_decode_queue",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["khr_synchronization2"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_video_encode_queue {
+ if !supported.khr_video_encode_queue {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_video_encode_queue",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.khr_video_queue) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_video_encode_queue",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_video_queue"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_3 || device_extensions.khr_synchronization2) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_video_encode_queue",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["khr_synchronization2"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_video_queue {
+ if !supported.khr_video_queue {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_video_queue",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_video_queue",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_video_queue",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_3 || device_extensions.khr_synchronization2) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_video_queue",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["khr_synchronization2"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_vulkan_memory_model {
+ if !supported.khr_vulkan_memory_model {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_vulkan_memory_model",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.khr_win32_keyed_mutex {
+ if !supported.khr_win32_keyed_mutex {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_win32_keyed_mutex",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.khr_external_memory_win32) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_win32_keyed_mutex",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_external_memory_win32"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_workgroup_memory_explicit_layout {
+ if !supported.khr_workgroup_memory_explicit_layout {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_workgroup_memory_explicit_layout",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_workgroup_memory_explicit_layout",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.khr_zero_initialize_workgroup_memory {
+ if !supported.khr_zero_initialize_workgroup_memory {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_zero_initialize_workgroup_memory",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "khr_zero_initialize_workgroup_memory",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_4444_formats {
+ if !supported.ext_4444_formats {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_4444_formats",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_4444_formats",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_astc_decode_mode {
+ if !supported.ext_astc_decode_mode {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_astc_decode_mode",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_astc_decode_mode",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_attachment_feedback_loop_layout {
+ if !supported.ext_attachment_feedback_loop_layout {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_attachment_feedback_loop_layout",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_attachment_feedback_loop_layout",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_blend_operation_advanced {
+ if !supported.ext_blend_operation_advanced {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_blend_operation_advanced",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_blend_operation_advanced",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_border_color_swizzle {
+ if !supported.ext_border_color_swizzle {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_border_color_swizzle",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.ext_custom_border_color) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_border_color_swizzle",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["ext_custom_border_color"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_buffer_device_address {
+ if !supported.ext_buffer_device_address {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_buffer_device_address",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_buffer_device_address",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if self.khr_buffer_device_address {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_buffer_device_address",
+ restriction: crate::device::ExtensionRestriction::ConflictsDeviceExtension(
+ "khr_buffer_device_address",
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_calibrated_timestamps {
+ if !supported.ext_calibrated_timestamps {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_calibrated_timestamps",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_calibrated_timestamps",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_color_write_enable {
+ if !supported.ext_color_write_enable {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_color_write_enable",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_color_write_enable",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_conditional_rendering {
+ if !supported.ext_conditional_rendering {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_conditional_rendering",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ext_conservative_rasterization {
+ if !supported.ext_conservative_rasterization {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_conservative_rasterization",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_conservative_rasterization",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_custom_border_color {
+ if !supported.ext_custom_border_color {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_custom_border_color",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ext_debug_marker {
+ if !supported.ext_debug_marker {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_debug_marker",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(instance_extensions.ext_debug_report) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_debug_marker",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["ext_debug_report"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_depth_clamp_zero_one {
+ if !supported.ext_depth_clamp_zero_one {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_depth_clamp_zero_one",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ext_depth_clip_control {
+ if !supported.ext_depth_clip_control {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_depth_clip_control",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_depth_clip_control",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_depth_clip_enable {
+ if !supported.ext_depth_clip_enable {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_depth_clip_enable",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ext_depth_range_unrestricted {
+ if !supported.ext_depth_range_unrestricted {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_depth_range_unrestricted",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ext_descriptor_buffer {
+ if !supported.ext_descriptor_buffer {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_descriptor_buffer",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_descriptor_buffer",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_2 || device_extensions.khr_buffer_device_address)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_descriptor_buffer",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_2),
+ device_extensions: &["khr_buffer_device_address"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_3 || device_extensions.khr_synchronization2) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_descriptor_buffer",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["khr_synchronization2"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_2 || device_extensions.ext_descriptor_indexing) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_descriptor_buffer",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_2),
+ device_extensions: &["ext_descriptor_indexing"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_descriptor_indexing {
+ if !supported.ext_descriptor_indexing {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_descriptor_indexing",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_descriptor_indexing",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_1 || device_extensions.khr_maintenance3) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_descriptor_indexing",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_maintenance3"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_device_address_binding_report {
+ if !supported.ext_device_address_binding_report {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_device_address_binding_report",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_device_address_binding_report",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(instance_extensions.ext_debug_utils) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_device_address_binding_report",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["ext_debug_utils"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_device_fault {
+ if !supported.ext_device_fault {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_device_fault",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_device_fault",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_device_memory_report {
+ if !supported.ext_device_memory_report {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_device_memory_report",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_device_memory_report",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_discard_rectangles {
+ if !supported.ext_discard_rectangles {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_discard_rectangles",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_discard_rectangles",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_display_control {
+ if !supported.ext_display_control {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_display_control",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(instance_extensions.ext_display_surface_counter) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_display_control",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["ext_display_surface_counter"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(device_extensions.khr_swapchain) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_display_control",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_swapchain"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_extended_dynamic_state {
+ if !supported.ext_extended_dynamic_state {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_extended_dynamic_state",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_extended_dynamic_state",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_extended_dynamic_state2 {
+ if !supported.ext_extended_dynamic_state2 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_extended_dynamic_state2",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_extended_dynamic_state2",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_extended_dynamic_state3 {
+ if !supported.ext_extended_dynamic_state3 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_extended_dynamic_state3",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_extended_dynamic_state3",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_external_memory_dma_buf {
+ if !supported.ext_external_memory_dma_buf {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_external_memory_dma_buf",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.khr_external_memory_fd) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_external_memory_dma_buf",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_external_memory_fd"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_external_memory_host {
+ if !supported.ext_external_memory_host {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_external_memory_host",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1 || device_extensions.khr_external_memory) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_external_memory_host",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_external_memory"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_filter_cubic {
+ if !supported.ext_filter_cubic {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_filter_cubic",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ext_fragment_density_map {
+ if !supported.ext_fragment_density_map {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_fragment_density_map",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_fragment_density_map",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_fragment_density_map2 {
+ if !supported.ext_fragment_density_map2 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_fragment_density_map2",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.ext_fragment_density_map) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_fragment_density_map2",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["ext_fragment_density_map"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_fragment_shader_interlock {
+ if !supported.ext_fragment_shader_interlock {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_fragment_shader_interlock",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_fragment_shader_interlock",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_full_screen_exclusive {
+ if !supported.ext_full_screen_exclusive {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_full_screen_exclusive",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_full_screen_exclusive",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(instance_extensions.khr_surface) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_full_screen_exclusive",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_surface"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(instance_extensions.khr_get_surface_capabilities2) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_full_screen_exclusive",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_get_surface_capabilities2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(device_extensions.khr_swapchain) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_full_screen_exclusive",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_swapchain"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_global_priority {
+ if !supported.ext_global_priority {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_global_priority",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ext_global_priority_query {
+ if !supported.ext_global_priority_query {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_global_priority_query",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.khr_global_priority || device_extensions.ext_global_priority) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_global_priority_query",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_global_priority", "ext_global_priority"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_global_priority_query",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_graphics_pipeline_library {
+ if !supported.ext_graphics_pipeline_library {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_graphics_pipeline_library",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_graphics_pipeline_library",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(device_extensions.khr_pipeline_library) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_graphics_pipeline_library",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_pipeline_library"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_hdr_metadata {
+ if !supported.ext_hdr_metadata {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_hdr_metadata",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.khr_swapchain) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_hdr_metadata",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_swapchain"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_host_query_reset {
+ if !supported.ext_host_query_reset {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_host_query_reset",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_host_query_reset",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_image_2d_view_of_3d {
+ if !supported.ext_image_2d_view_of_3d {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_image_2d_view_of_3d",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1 || device_extensions.khr_maintenance1) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_image_2d_view_of_3d",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_maintenance1"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_image_2d_view_of_3d",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_image_compression_control {
+ if !supported.ext_image_compression_control {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_image_compression_control",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ext_image_compression_control_swapchain {
+ if !supported.ext_image_compression_control_swapchain {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_image_compression_control_swapchain",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.ext_image_compression_control) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_image_compression_control_swapchain",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["ext_image_compression_control"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_image_drm_format_modifier {
+ if !supported.ext_image_drm_format_modifier {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_image_drm_format_modifier",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1 || device_extensions.khr_bind_memory2) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_image_drm_format_modifier",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_bind_memory2"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_image_drm_format_modifier",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_2 || device_extensions.khr_image_format_list) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_image_drm_format_modifier",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_2),
+ device_extensions: &["khr_image_format_list"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || device_extensions.khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_image_drm_format_modifier",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_image_robustness {
+ if !supported.ext_image_robustness {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_image_robustness",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_image_robustness",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_image_view_min_lod {
+ if !supported.ext_image_view_min_lod {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_image_view_min_lod",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_image_view_min_lod",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_index_type_uint8 {
+ if !supported.ext_index_type_uint8 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_index_type_uint8",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ext_inline_uniform_block {
+ if !supported.ext_inline_uniform_block {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_inline_uniform_block",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_inline_uniform_block",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_1 || device_extensions.khr_maintenance1) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_inline_uniform_block",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_maintenance1"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_legacy_dithering {
+ if !supported.ext_legacy_dithering {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_legacy_dithering",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_legacy_dithering",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_line_rasterization {
+ if !supported.ext_line_rasterization {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_line_rasterization",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_line_rasterization",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_load_store_op_none {
+ if !supported.ext_load_store_op_none {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_load_store_op_none",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ext_memory_budget {
+ if !supported.ext_memory_budget {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_memory_budget",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_memory_budget",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_memory_priority {
+ if !supported.ext_memory_priority {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_memory_priority",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_memory_priority",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_mesh_shader {
+ if !supported.ext_mesh_shader {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_mesh_shader",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_mesh_shader",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_mesh_shader",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_2 || device_extensions.khr_spirv_1_4) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_mesh_shader",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_2),
+ device_extensions: &["khr_spirv_1_4"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_metal_objects {
+ if !supported.ext_metal_objects {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_metal_objects",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ext_multi_draw {
+ if !supported.ext_multi_draw {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_multi_draw",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ext_multisampled_render_to_single_sampled {
+ if !supported.ext_multisampled_render_to_single_sampled {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_multisampled_render_to_single_sampled",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_2 || device_extensions.khr_create_renderpass2) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_multisampled_render_to_single_sampled",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_2),
+ device_extensions: &["khr_create_renderpass2"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_2 || device_extensions.khr_depth_stencil_resolve)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_multisampled_render_to_single_sampled",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_2),
+ device_extensions: &["khr_depth_stencil_resolve"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_mutable_descriptor_type {
+ if !supported.ext_mutable_descriptor_type {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_mutable_descriptor_type",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1 || device_extensions.khr_maintenance3) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_mutable_descriptor_type",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_maintenance3"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_non_seamless_cube_map {
+ if !supported.ext_non_seamless_cube_map {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_non_seamless_cube_map",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ext_opacity_micromap {
+ if !supported.ext_opacity_micromap {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_opacity_micromap",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.khr_acceleration_structure) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_opacity_micromap",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_acceleration_structure"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_3 || device_extensions.khr_synchronization2) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_opacity_micromap",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["khr_synchronization2"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_pageable_device_local_memory {
+ if !supported.ext_pageable_device_local_memory {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_pageable_device_local_memory",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.ext_memory_priority) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_pageable_device_local_memory",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["ext_memory_priority"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_pci_bus_info {
+ if !supported.ext_pci_bus_info {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_pci_bus_info",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_pci_bus_info",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_physical_device_drm {
+ if !supported.ext_physical_device_drm {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_physical_device_drm",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_physical_device_drm",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_pipeline_creation_cache_control {
+ if !supported.ext_pipeline_creation_cache_control {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_pipeline_creation_cache_control",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ext_pipeline_creation_feedback {
+ if !supported.ext_pipeline_creation_feedback {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_pipeline_creation_feedback",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ext_pipeline_properties {
+ if !supported.ext_pipeline_properties {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_pipeline_properties",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_pipeline_properties",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_pipeline_protected_access {
+ if !supported.ext_pipeline_protected_access {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_pipeline_protected_access",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_pipeline_protected_access",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_pipeline_robustness {
+ if !supported.ext_pipeline_robustness {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_pipeline_robustness",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_pipeline_robustness",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_post_depth_coverage {
+ if !supported.ext_post_depth_coverage {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_post_depth_coverage",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ext_primitive_topology_list_restart {
+ if !supported.ext_primitive_topology_list_restart {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_primitive_topology_list_restart",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ext_primitives_generated_query {
+ if !supported.ext_primitives_generated_query {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_primitives_generated_query",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.ext_transform_feedback) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_primitives_generated_query",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["ext_transform_feedback"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_private_data {
+ if !supported.ext_private_data {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_private_data",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ext_provoking_vertex {
+ if !supported.ext_provoking_vertex {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_provoking_vertex",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_provoking_vertex",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_queue_family_foreign {
+ if !supported.ext_queue_family_foreign {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_queue_family_foreign",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1 || device_extensions.khr_external_memory) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_queue_family_foreign",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_external_memory"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_rasterization_order_attachment_access {
+ if !supported.ext_rasterization_order_attachment_access {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_rasterization_order_attachment_access",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_rasterization_order_attachment_access",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_rgba10x6_formats {
+ if !supported.ext_rgba10x6_formats {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_rgba10x6_formats",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || device_extensions.khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_rgba10x6_formats",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_robustness2 {
+ if !supported.ext_robustness2 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_robustness2",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ext_sample_locations {
+ if !supported.ext_sample_locations {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_sample_locations",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_sample_locations",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_sampler_filter_minmax {
+ if !supported.ext_sampler_filter_minmax {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_sampler_filter_minmax",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_sampler_filter_minmax",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_scalar_block_layout {
+ if !supported.ext_scalar_block_layout {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_scalar_block_layout",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_scalar_block_layout",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_separate_stencil_usage {
+ if !supported.ext_separate_stencil_usage {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_separate_stencil_usage",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ext_shader_atomic_float {
+ if !supported.ext_shader_atomic_float {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_shader_atomic_float",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_shader_atomic_float",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_shader_atomic_float2 {
+ if !supported.ext_shader_atomic_float2 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_shader_atomic_float2",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.ext_shader_atomic_float) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_shader_atomic_float2",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["ext_shader_atomic_float"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_shader_demote_to_helper_invocation {
+ if !supported.ext_shader_demote_to_helper_invocation {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_shader_demote_to_helper_invocation",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_shader_demote_to_helper_invocation",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_shader_image_atomic_int64 {
+ if !supported.ext_shader_image_atomic_int64 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_shader_image_atomic_int64",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_shader_image_atomic_int64",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_shader_module_identifier {
+ if !supported.ext_shader_module_identifier {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_shader_module_identifier",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_shader_module_identifier",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_3
+ || device_extensions.ext_pipeline_creation_cache_control)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_shader_module_identifier",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_pipeline_creation_cache_control"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_shader_stencil_export {
+ if !supported.ext_shader_stencil_export {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_shader_stencil_export",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ext_shader_subgroup_ballot {
+ if !supported.ext_shader_subgroup_ballot {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_shader_subgroup_ballot",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ext_shader_subgroup_vote {
+ if !supported.ext_shader_subgroup_vote {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_shader_subgroup_vote",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ext_shader_viewport_index_layer {
+ if !supported.ext_shader_viewport_index_layer {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_shader_viewport_index_layer",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ext_subgroup_size_control {
+ if !supported.ext_subgroup_size_control {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_subgroup_size_control",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_subgroup_size_control",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_subpass_merge_feedback {
+ if !supported.ext_subpass_merge_feedback {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_subpass_merge_feedback",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ext_swapchain_maintenance1 {
+ if !supported.ext_swapchain_maintenance1 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_swapchain_maintenance1",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.khr_swapchain) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_swapchain_maintenance1",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_swapchain"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(instance_extensions.ext_surface_maintenance1) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_swapchain_maintenance1",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["ext_surface_maintenance1"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_swapchain_maintenance1",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_texel_buffer_alignment {
+ if !supported.ext_texel_buffer_alignment {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_texel_buffer_alignment",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_texel_buffer_alignment",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_texture_compression_astc_hdr {
+ if !supported.ext_texture_compression_astc_hdr {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_texture_compression_astc_hdr",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_texture_compression_astc_hdr",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_tooling_info {
+ if !supported.ext_tooling_info {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_tooling_info",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ext_transform_feedback {
+ if !supported.ext_transform_feedback {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_transform_feedback",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_transform_feedback",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_validation_cache {
+ if !supported.ext_validation_cache {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_validation_cache",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ext_vertex_attribute_divisor {
+ if !supported.ext_vertex_attribute_divisor {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_vertex_attribute_divisor",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_vertex_attribute_divisor",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_vertex_input_dynamic_state {
+ if !supported.ext_vertex_input_dynamic_state {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_vertex_input_dynamic_state",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_vertex_input_dynamic_state",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_video_encode_h264 {
+ if !supported.ext_video_encode_h264 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_video_encode_h264",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.khr_video_encode_queue) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_video_encode_h264",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_video_encode_queue"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_video_encode_h265 {
+ if !supported.ext_video_encode_h265 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_video_encode_h265",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.khr_video_encode_queue) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_video_encode_h265",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_video_encode_queue"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_ycbcr_2plane_444_formats {
+ if !supported.ext_ycbcr_2plane_444_formats {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_ycbcr_2plane_444_formats",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || device_extensions.khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_ycbcr_2plane_444_formats",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ext_ycbcr_image_arrays {
+ if !supported.ext_ycbcr_image_arrays {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_ycbcr_image_arrays",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || device_extensions.khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ext_ycbcr_image_arrays",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.amd_buffer_marker {
+ if !supported.amd_buffer_marker {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "amd_buffer_marker",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.amd_device_coherent_memory {
+ if !supported.amd_device_coherent_memory {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "amd_device_coherent_memory",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.amd_display_native_hdr {
+ if !supported.amd_display_native_hdr {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "amd_display_native_hdr",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "amd_display_native_hdr",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(instance_extensions.khr_get_surface_capabilities2) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "amd_display_native_hdr",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_get_surface_capabilities2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(device_extensions.khr_swapchain) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "amd_display_native_hdr",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_swapchain"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.amd_draw_indirect_count {
+ if !supported.amd_draw_indirect_count {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "amd_draw_indirect_count",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.amd_gcn_shader {
+ if !supported.amd_gcn_shader {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "amd_gcn_shader",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.amd_gpu_shader_half_float {
+ if !supported.amd_gpu_shader_half_float {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "amd_gpu_shader_half_float",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.amd_gpu_shader_int16 {
+ if !supported.amd_gpu_shader_int16 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "amd_gpu_shader_int16",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.amd_memory_overallocation_behavior {
+ if !supported.amd_memory_overallocation_behavior {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "amd_memory_overallocation_behavior",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.amd_mixed_attachment_samples {
+ if !supported.amd_mixed_attachment_samples {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "amd_mixed_attachment_samples",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.amd_pipeline_compiler_control {
+ if !supported.amd_pipeline_compiler_control {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "amd_pipeline_compiler_control",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.amd_rasterization_order {
+ if !supported.amd_rasterization_order {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "amd_rasterization_order",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.amd_shader_ballot {
+ if !supported.amd_shader_ballot {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "amd_shader_ballot",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.amd_shader_core_properties {
+ if !supported.amd_shader_core_properties {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "amd_shader_core_properties",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "amd_shader_core_properties",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.amd_shader_core_properties2 {
+ if !supported.amd_shader_core_properties2 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "amd_shader_core_properties2",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.amd_shader_core_properties) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "amd_shader_core_properties2",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["amd_shader_core_properties"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.amd_shader_early_and_late_fragment_tests {
+ if !supported.amd_shader_early_and_late_fragment_tests {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "amd_shader_early_and_late_fragment_tests",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.amd_shader_explicit_vertex_parameter {
+ if !supported.amd_shader_explicit_vertex_parameter {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "amd_shader_explicit_vertex_parameter",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.amd_shader_fragment_mask {
+ if !supported.amd_shader_fragment_mask {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "amd_shader_fragment_mask",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.amd_shader_image_load_store_lod {
+ if !supported.amd_shader_image_load_store_lod {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "amd_shader_image_load_store_lod",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.amd_shader_info {
+ if !supported.amd_shader_info {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "amd_shader_info",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.amd_shader_trinary_minmax {
+ if !supported.amd_shader_trinary_minmax {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "amd_shader_trinary_minmax",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.amd_texture_gather_bias_lod {
+ if !supported.amd_texture_gather_bias_lod {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "amd_texture_gather_bias_lod",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "amd_texture_gather_bias_lod",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.android_external_memory_android_hardware_buffer {
+ if !supported.android_external_memory_android_hardware_buffer {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "android_external_memory_android_hardware_buffer",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || device_extensions.khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "android_external_memory_android_hardware_buffer",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_1 || device_extensions.khr_external_memory) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "android_external_memory_android_hardware_buffer",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_external_memory"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(device_extensions.ext_queue_family_foreign) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "android_external_memory_android_hardware_buffer",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["ext_queue_family_foreign"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_1 || device_extensions.khr_dedicated_allocation)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "android_external_memory_android_hardware_buffer",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_dedicated_allocation"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.arm_rasterization_order_attachment_access {
+ if !supported.arm_rasterization_order_attachment_access {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "arm_rasterization_order_attachment_access",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "arm_rasterization_order_attachment_access",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.arm_shader_core_builtins {
+ if !supported.arm_shader_core_builtins {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "arm_shader_core_builtins",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.fuchsia_buffer_collection {
+ if !supported.fuchsia_buffer_collection {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "fuchsia_buffer_collection",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.fuchsia_external_memory) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "fuchsia_buffer_collection",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["fuchsia_external_memory"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || device_extensions.khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "fuchsia_buffer_collection",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.fuchsia_external_memory {
+ if !supported.fuchsia_external_memory {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "fuchsia_external_memory",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_external_memory_capabilities)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "fuchsia_external_memory",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_external_memory_capabilities"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_1 || device_extensions.khr_external_memory) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "fuchsia_external_memory",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_external_memory"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.fuchsia_external_semaphore {
+ if !supported.fuchsia_external_semaphore {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "fuchsia_external_semaphore",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_external_semaphore_capabilities)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "fuchsia_external_semaphore",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_external_semaphore_capabilities"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_1 || device_extensions.khr_external_semaphore) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "fuchsia_external_semaphore",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_external_semaphore"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.ggp_frame_token {
+ if !supported.ggp_frame_token {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ggp_frame_token",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.khr_swapchain) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ggp_frame_token",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_swapchain"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(instance_extensions.ggp_stream_descriptor_surface) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "ggp_frame_token",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["ggp_stream_descriptor_surface"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.google_decorate_string {
+ if !supported.google_decorate_string {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "google_decorate_string",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.google_display_timing {
+ if !supported.google_display_timing {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "google_display_timing",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.khr_swapchain) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "google_display_timing",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_swapchain"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.google_hlsl_functionality1 {
+ if !supported.google_hlsl_functionality1 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "google_hlsl_functionality1",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.google_user_type {
+ if !supported.google_user_type {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "google_user_type",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.huawei_invocation_mask {
+ if !supported.huawei_invocation_mask {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "huawei_invocation_mask",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.khr_ray_tracing_pipeline) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "huawei_invocation_mask",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_ray_tracing_pipeline"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_3 || device_extensions.khr_synchronization2) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "huawei_invocation_mask",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["khr_synchronization2"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.huawei_subpass_shading {
+ if !supported.huawei_subpass_shading {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "huawei_subpass_shading",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_2 || device_extensions.khr_create_renderpass2) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "huawei_subpass_shading",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_2),
+ device_extensions: &["khr_create_renderpass2"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_3 || device_extensions.khr_synchronization2) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "huawei_subpass_shading",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["khr_synchronization2"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.img_filter_cubic {
+ if !supported.img_filter_cubic {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "img_filter_cubic",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.img_format_pvrtc {
+ if !supported.img_format_pvrtc {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "img_format_pvrtc",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.intel_performance_query {
+ if !supported.intel_performance_query {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "intel_performance_query",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.intel_shader_integer_functions2 {
+ if !supported.intel_shader_integer_functions2 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "intel_shader_integer_functions2",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "intel_shader_integer_functions2",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.nvx_binary_import {
+ if !supported.nvx_binary_import {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nvx_binary_import",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.nvx_image_view_handle {
+ if !supported.nvx_image_view_handle {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nvx_image_view_handle",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.nvx_multiview_per_view_attributes {
+ if !supported.nvx_multiview_per_view_attributes {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nvx_multiview_per_view_attributes",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1 || device_extensions.khr_multiview) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nvx_multiview_per_view_attributes",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_multiview"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.nv_acquire_winrt_display {
+ if !supported.nv_acquire_winrt_display {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_acquire_winrt_display",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(instance_extensions.ext_direct_mode_display) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_acquire_winrt_display",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["ext_direct_mode_display"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.nv_clip_space_w_scaling {
+ if !supported.nv_clip_space_w_scaling {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_clip_space_w_scaling",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.nv_compute_shader_derivatives {
+ if !supported.nv_compute_shader_derivatives {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_compute_shader_derivatives",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_compute_shader_derivatives",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.nv_cooperative_matrix {
+ if !supported.nv_cooperative_matrix {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_cooperative_matrix",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_cooperative_matrix",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.nv_copy_memory_indirect {
+ if !supported.nv_copy_memory_indirect {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_copy_memory_indirect",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_copy_memory_indirect",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_2 || device_extensions.khr_buffer_device_address)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_copy_memory_indirect",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_2),
+ device_extensions: &["khr_buffer_device_address"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.nv_corner_sampled_image {
+ if !supported.nv_corner_sampled_image {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_corner_sampled_image",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_corner_sampled_image",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.nv_coverage_reduction_mode {
+ if !supported.nv_coverage_reduction_mode {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_coverage_reduction_mode",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.nv_framebuffer_mixed_samples) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_coverage_reduction_mode",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["nv_framebuffer_mixed_samples"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.nv_dedicated_allocation {
+ if !supported.nv_dedicated_allocation {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_dedicated_allocation",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.nv_dedicated_allocation_image_aliasing {
+ if !supported.nv_dedicated_allocation_image_aliasing {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_dedicated_allocation_image_aliasing",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1 || device_extensions.khr_dedicated_allocation)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_dedicated_allocation_image_aliasing",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_dedicated_allocation"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.nv_device_diagnostic_checkpoints {
+ if !supported.nv_device_diagnostic_checkpoints {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_device_diagnostic_checkpoints",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_device_diagnostic_checkpoints",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.nv_device_diagnostics_config {
+ if !supported.nv_device_diagnostics_config {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_device_diagnostics_config",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_device_diagnostics_config",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.nv_device_generated_commands {
+ if !supported.nv_device_generated_commands {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_device_generated_commands",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_device_generated_commands",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_2 || device_extensions.khr_buffer_device_address)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_device_generated_commands",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_2),
+ device_extensions: &["khr_buffer_device_address"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.nv_external_memory {
+ if !supported.nv_external_memory {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_external_memory",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(instance_extensions.nv_external_memory_capabilities) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_external_memory",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["nv_external_memory_capabilities"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.nv_external_memory_rdma {
+ if !supported.nv_external_memory_rdma {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_external_memory_rdma",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1 || device_extensions.khr_external_memory) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_external_memory_rdma",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_external_memory"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.nv_external_memory_win32 {
+ if !supported.nv_external_memory_win32 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_external_memory_win32",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.nv_external_memory) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_external_memory_win32",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["nv_external_memory"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.nv_fill_rectangle {
+ if !supported.nv_fill_rectangle {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_fill_rectangle",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.nv_fragment_coverage_to_color {
+ if !supported.nv_fragment_coverage_to_color {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_fragment_coverage_to_color",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.nv_fragment_shader_barycentric {
+ if !supported.nv_fragment_shader_barycentric {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_fragment_shader_barycentric",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_fragment_shader_barycentric",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.nv_fragment_shading_rate_enums {
+ if !supported.nv_fragment_shading_rate_enums {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_fragment_shading_rate_enums",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.khr_fragment_shading_rate) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_fragment_shading_rate_enums",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_fragment_shading_rate"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.nv_framebuffer_mixed_samples {
+ if !supported.nv_framebuffer_mixed_samples {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_framebuffer_mixed_samples",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.nv_geometry_shader_passthrough {
+ if !supported.nv_geometry_shader_passthrough {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_geometry_shader_passthrough",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.nv_glsl_shader {
+ if !supported.nv_glsl_shader {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_glsl_shader",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.nv_inherited_viewport_scissor {
+ if !supported.nv_inherited_viewport_scissor {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_inherited_viewport_scissor",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.nv_linear_color_attachment {
+ if !supported.nv_linear_color_attachment {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_linear_color_attachment",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.nv_memory_decompression {
+ if !supported.nv_memory_decompression {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_memory_decompression",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_memory_decompression",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_2 || device_extensions.khr_buffer_device_address)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_memory_decompression",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_2),
+ device_extensions: &["khr_buffer_device_address"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.nv_mesh_shader {
+ if !supported.nv_mesh_shader {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_mesh_shader",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_mesh_shader",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.nv_optical_flow {
+ if !supported.nv_optical_flow {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_optical_flow",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_optical_flow",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_3 || device_extensions.khr_format_feature_flags2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_optical_flow",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["khr_format_feature_flags2"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_3 || device_extensions.khr_synchronization2) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_optical_flow",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["khr_synchronization2"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.nv_present_barrier {
+ if !supported.nv_present_barrier {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_present_barrier",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_present_barrier",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(instance_extensions.khr_surface) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_present_barrier",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_surface"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(instance_extensions.khr_get_surface_capabilities2) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_present_barrier",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_get_surface_capabilities2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(device_extensions.khr_swapchain) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_present_barrier",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_swapchain"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.nv_ray_tracing {
+ if !supported.nv_ray_tracing {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_ray_tracing",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_ray_tracing",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || device_extensions.khr_get_memory_requirements2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_ray_tracing",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_get_memory_requirements2"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.nv_ray_tracing_invocation_reorder {
+ if !supported.nv_ray_tracing_invocation_reorder {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_ray_tracing_invocation_reorder",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.khr_ray_tracing_pipeline) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_ray_tracing_invocation_reorder",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_ray_tracing_pipeline"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.nv_ray_tracing_motion_blur {
+ if !supported.nv_ray_tracing_motion_blur {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_ray_tracing_motion_blur",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.khr_ray_tracing_pipeline) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_ray_tracing_motion_blur",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_ray_tracing_pipeline"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.nv_representative_fragment_test {
+ if !supported.nv_representative_fragment_test {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_representative_fragment_test",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.nv_sample_mask_override_coverage {
+ if !supported.nv_sample_mask_override_coverage {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_sample_mask_override_coverage",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.nv_scissor_exclusive {
+ if !supported.nv_scissor_exclusive {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_scissor_exclusive",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_scissor_exclusive",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.nv_shader_image_footprint {
+ if !supported.nv_shader_image_footprint {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_shader_image_footprint",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_shader_image_footprint",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.nv_shader_sm_builtins {
+ if !supported.nv_shader_sm_builtins {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_shader_sm_builtins",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_shader_sm_builtins",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.nv_shader_subgroup_partitioned {
+ if !supported.nv_shader_subgroup_partitioned {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_shader_subgroup_partitioned",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_shader_subgroup_partitioned",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.nv_shading_rate_image {
+ if !supported.nv_shading_rate_image {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_shading_rate_image",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_shading_rate_image",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.nv_viewport_array2 {
+ if !supported.nv_viewport_array2 {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_viewport_array2",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.nv_viewport_swizzle {
+ if !supported.nv_viewport_swizzle {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_viewport_swizzle",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.nv_win32_keyed_mutex {
+ if !supported.nv_win32_keyed_mutex {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_win32_keyed_mutex",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.nv_external_memory_win32) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "nv_win32_keyed_mutex",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["nv_external_memory_win32"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.qcom_fragment_density_map_offset {
+ if !supported.qcom_fragment_density_map_offset {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "qcom_fragment_density_map_offset",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "qcom_fragment_density_map_offset",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(device_extensions.ext_fragment_density_map) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "qcom_fragment_density_map_offset",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["ext_fragment_density_map"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.qcom_image_processing {
+ if !supported.qcom_image_processing {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "qcom_image_processing",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_3 || device_extensions.khr_format_feature_flags2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "qcom_image_processing",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["khr_format_feature_flags2"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.qcom_multiview_per_view_viewports {
+ if !supported.qcom_multiview_per_view_viewports {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "qcom_multiview_per_view_viewports",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.qcom_render_pass_shader_resolve {
+ if !supported.qcom_render_pass_shader_resolve {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "qcom_render_pass_shader_resolve",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.qcom_render_pass_store_ops {
+ if !supported.qcom_render_pass_store_ops {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "qcom_render_pass_store_ops",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.qcom_render_pass_transform {
+ if !supported.qcom_render_pass_transform {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "qcom_render_pass_transform",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.khr_swapchain) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "qcom_render_pass_transform",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_swapchain"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(instance_extensions.khr_surface) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "qcom_render_pass_transform",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_surface"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.qcom_rotated_copy_commands {
+ if !supported.qcom_rotated_copy_commands {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "qcom_rotated_copy_commands",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(device_extensions.khr_swapchain) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "qcom_rotated_copy_commands",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &["khr_swapchain"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(api_version >= crate::Version::V1_3 || device_extensions.khr_copy_commands2) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "qcom_rotated_copy_commands",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["khr_copy_commands2"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.qcom_tile_properties {
+ if !supported.qcom_tile_properties {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "qcom_tile_properties",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "qcom_tile_properties",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.sec_amigo_profiling {
+ if !supported.sec_amigo_profiling {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "sec_amigo_profiling",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "sec_amigo_profiling",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ if self.valve_descriptor_set_host_mapping {
+ if !supported.valve_descriptor_set_host_mapping {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "valve_descriptor_set_host_mapping",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.valve_mutable_descriptor_type {
+ if !supported.valve_mutable_descriptor_type {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "valve_mutable_descriptor_type",
+ restriction: crate::device::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1 || device_extensions.khr_maintenance3) {
+ return Err(crate::device::ExtensionRestrictionError {
+ extension: "valve_mutable_descriptor_type",
+ restriction: crate::device::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_maintenance3"],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ } else {
+ }
+ Ok(())
+ }
+}
diff --git a/out/errors.rs b/out/errors.rs
new file mode 100644
index 0000000..3003548
--- /dev/null
+++ b/out/errors.rs
@@ -0,0 +1,99 @@
+// This file is auto-generated by vulkano autogen from vk.xml header version 1.3.238.
+// It should not be edited manually. Changes should be made by editing autogen.
+
+#[doc = r" An enumeration of runtime errors that can be returned by Vulkan."]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+#[repr(i32)]
+#[non_exhaustive]
+pub enum VulkanError {
+ OutOfHostMemory,
+ OutOfDeviceMemory,
+ InitializationFailed,
+ DeviceLost,
+ MemoryMapFailed,
+ LayerNotPresent,
+ ExtensionNotPresent,
+ FeatureNotPresent,
+ IncompatibleDriver,
+ TooManyObjects,
+ FormatNotSupported,
+ FragmentedPool,
+ Unknown,
+ OutOfPoolMemory,
+ InvalidExternalHandle,
+ Fragmentation,
+ InvalidOpaqueCaptureAddress,
+ IncompatibleDisplay,
+ NotPermitted,
+ SurfaceLost,
+ NativeWindowInUse,
+ OutOfDate,
+ ImageUsageNotSupported,
+ VideoPictureLayoutNotSupported,
+ VideoProfileOperationNotSupported,
+ VideoProfileFormatNotSupported,
+ VideoProfileCodecNotSupported,
+ VideoStdVersionNotSupported,
+ ValidationFailed,
+ FullScreenExclusiveModeLost,
+ CompressionExhausted,
+ InvalidDrmFormatModifierPlaneLayout,
+ InvalidShader,
+ Unnamed(ash::vk::Result),
+}
+impl From<ash::vk::Result> for VulkanError {
+ fn from(val: ash::vk::Result) -> VulkanError {
+ match val {
+ ash::vk::Result::ERROR_OUT_OF_HOST_MEMORY => Self::OutOfHostMemory,
+ ash::vk::Result::ERROR_OUT_OF_DEVICE_MEMORY => Self::OutOfDeviceMemory,
+ ash::vk::Result::ERROR_INITIALIZATION_FAILED => Self::InitializationFailed,
+ ash::vk::Result::ERROR_DEVICE_LOST => Self::DeviceLost,
+ ash::vk::Result::ERROR_MEMORY_MAP_FAILED => Self::MemoryMapFailed,
+ ash::vk::Result::ERROR_LAYER_NOT_PRESENT => Self::LayerNotPresent,
+ ash::vk::Result::ERROR_EXTENSION_NOT_PRESENT => Self::ExtensionNotPresent,
+ ash::vk::Result::ERROR_FEATURE_NOT_PRESENT => Self::FeatureNotPresent,
+ ash::vk::Result::ERROR_INCOMPATIBLE_DRIVER => Self::IncompatibleDriver,
+ ash::vk::Result::ERROR_TOO_MANY_OBJECTS => Self::TooManyObjects,
+ ash::vk::Result::ERROR_FORMAT_NOT_SUPPORTED => Self::FormatNotSupported,
+ ash::vk::Result::ERROR_FRAGMENTED_POOL => Self::FragmentedPool,
+ ash::vk::Result::ERROR_UNKNOWN => Self::Unknown,
+ ash::vk::Result::ERROR_OUT_OF_POOL_MEMORY => Self::OutOfPoolMemory,
+ ash::vk::Result::ERROR_INVALID_EXTERNAL_HANDLE => Self::InvalidExternalHandle,
+ ash::vk::Result::ERROR_FRAGMENTATION => Self::Fragmentation,
+ ash::vk::Result::ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS => {
+ Self::InvalidOpaqueCaptureAddress
+ }
+ ash::vk::Result::ERROR_INCOMPATIBLE_DISPLAY_KHR => Self::IncompatibleDisplay,
+ ash::vk::Result::ERROR_NOT_PERMITTED_KHR => Self::NotPermitted,
+ ash::vk::Result::ERROR_SURFACE_LOST_KHR => Self::SurfaceLost,
+ ash::vk::Result::ERROR_NATIVE_WINDOW_IN_USE_KHR => Self::NativeWindowInUse,
+ ash::vk::Result::ERROR_OUT_OF_DATE_KHR => Self::OutOfDate,
+ ash::vk::Result::ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR => Self::ImageUsageNotSupported,
+ ash::vk::Result::ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR => {
+ Self::VideoPictureLayoutNotSupported
+ }
+ ash::vk::Result::ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR => {
+ Self::VideoProfileOperationNotSupported
+ }
+ ash::vk::Result::ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR => {
+ Self::VideoProfileFormatNotSupported
+ }
+ ash::vk::Result::ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR => {
+ Self::VideoProfileCodecNotSupported
+ }
+ ash::vk::Result::ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR => {
+ Self::VideoStdVersionNotSupported
+ }
+ ash::vk::Result::ERROR_VALIDATION_FAILED_EXT => Self::ValidationFailed,
+ ash::vk::Result::ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT => {
+ Self::FullScreenExclusiveModeLost
+ }
+ ash::vk::Result::ERROR_COMPRESSION_EXHAUSTED_EXT => Self::CompressionExhausted,
+ ash::vk::Result::ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT => {
+ Self::InvalidDrmFormatModifierPlaneLayout
+ }
+ ash::vk::Result::ERROR_INVALID_SHADER_NV => Self::InvalidShader,
+ x => Self::Unnamed(x),
+ }
+ }
+}
diff --git a/out/features.rs b/out/features.rs
new file mode 100644
index 0000000..6894b14
--- /dev/null
+++ b/out/features.rs
@@ -0,0 +1,21154 @@
+// This file is auto-generated by vulkano autogen from vk.xml header version 1.3.238.
+// It should not be edited manually. Changes should be made by editing autogen.
+
+#[doc = r" Represents all the features that are available on a physical device or enabled on"]
+#[doc = r" a logical device."]
+#[doc = r""]
+#[doc = r" Note that the `robust_buffer_access` is guaranteed to be supported by all Vulkan"]
+#[doc = r" implementations."]
+#[doc = r""]
+#[doc = r" # Examples"]
+#[doc = r""]
+#[doc = r" ```"]
+#[doc = r" use vulkano::device::Features;"]
+#[doc = r" # let physical_device: vulkano::device::physical::PhysicalDevice = return;"]
+#[doc = r" let minimal_features = Features {"]
+#[doc = r" geometry_shader: true,"]
+#[doc = r" ..Features::empty()"]
+#[doc = r" };"]
+#[doc = r""]
+#[doc = r" let optimal_features = vulkano::device::Features {"]
+#[doc = r" geometry_shader: true,"]
+#[doc = r" tessellation_shader: true,"]
+#[doc = r" ..Features::empty()"]
+#[doc = r" };"]
+#[doc = r""]
+#[doc = r" if !physical_device.supported_features().is_superset_of(&minimal_features) {"]
+#[doc = r#" panic!("The physical device is not good enough for this application.");"#]
+#[doc = r" }"]
+#[doc = r""]
+#[doc = r" assert!(optimal_features.is_superset_of(&minimal_features));"]
+#[doc = r" let features_to_request = optimal_features.intersection(physical_device.supported_features());"]
+#[doc = r" ```"]
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+pub struct Features {
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceAccelerationStructureFeaturesKHR.html#features-accelerationStructure)"]
+ pub acceleration_structure: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceAccelerationStructureFeaturesKHR.html#features-accelerationStructureCaptureReplay)"]
+ pub acceleration_structure_capture_replay: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceAccelerationStructureFeaturesKHR.html#features-accelerationStructureHostCommands)"]
+ pub acceleration_structure_host_commands: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceAccelerationStructureFeaturesKHR.html#features-accelerationStructureIndirectBuild)"]
+ pub acceleration_structure_indirect_build: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT.html#features-advancedBlendCoherentOperations)"]
+ pub advanced_blend_coherent_operations: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-alphaToOne)"]
+ pub alpha_to_one: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceAmigoProfilingFeaturesSEC.html#features-amigoProfiling)"]
+ pub amigo_profiling: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT.html#features-attachmentFeedbackLoopLayout)"]
+ pub attachment_feedback_loop_layout: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentShadingRateFeaturesKHR.html#features-attachmentFragmentShadingRate)\n- Conflicts with features: [`shading_rate_image`](crate::device::Features::shading_rate_image), [`fragment_density_map`](crate::device::Features::fragment_density_map)"]
+ pub attachment_fragment_shading_rate: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceBorderColorSwizzleFeaturesEXT.html#features-borderColorSwizzle)"]
+ pub border_color_swizzle: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceBorderColorSwizzleFeaturesEXT.html#features-borderColorSwizzleFromImage)"]
+ pub border_color_swizzle_from_image: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLineRasterizationFeaturesEXT.html#features-bresenhamLines)"]
+ pub bresenham_lines: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-bufferDeviceAddress)"]
+ pub buffer_device_address: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-bufferDeviceAddressCaptureReplay)"]
+ pub buffer_device_address_capture_replay: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-bufferDeviceAddressMultiDevice)"]
+ pub buffer_device_address_multi_device: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceColorWriteEnableFeaturesEXT.html#features-colorWriteEnable)"]
+ pub color_write_enable: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceComputeShaderDerivativesFeaturesNV.html#features-computeDerivativeGroupLinear)"]
+ pub compute_derivative_group_linear: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceComputeShaderDerivativesFeaturesNV.html#features-computeDerivativeGroupQuads)"]
+ pub compute_derivative_group_quads: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Features.html#features-computeFullSubgroups)"]
+ pub compute_full_subgroups: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceConditionalRenderingFeaturesEXT.html#features-conditionalRendering)"]
+ pub conditional_rendering: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePortabilitySubsetFeaturesKHR.html#features-constantAlphaColorBlendFactors)"]
+ pub constant_alpha_color_blend_factors: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceCooperativeMatrixFeaturesNV.html#features-cooperativeMatrix)"]
+ pub cooperative_matrix: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceCooperativeMatrixFeaturesNV.html#features-cooperativeMatrixRobustBufferAccess)"]
+ pub cooperative_matrix_robust_buffer_access: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceCornerSampledImageFeaturesNV.html#features-cornerSampledImage)"]
+ pub corner_sampled_image: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceCoverageReductionModeFeaturesNV.html#features-coverageReductionMode)"]
+ pub coverage_reduction_mode: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceCustomBorderColorFeaturesEXT.html#features-customBorderColorWithoutFormat)"]
+ pub custom_border_color_without_format: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceCustomBorderColorFeaturesEXT.html#features-customBorderColors)"]
+ pub custom_border_colors: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceASTCDecodeFeaturesEXT.html#features-decodeModeSharedExponent)"]
+ pub decode_mode_shared_exponent: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV.html#features-dedicatedAllocationImageAliasing)"]
+ pub dedicated_allocation_image_aliasing: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-depthBiasClamp)"]
+ pub depth_bias_clamp: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-depthBounds)"]
+ pub depth_bounds: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-depthClamp)"]
+ pub depth_clamp: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDepthClampZeroOneFeaturesEXT.html#features-depthClampZeroOne)"]
+ pub depth_clamp_zero_one: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDepthClipControlFeaturesEXT.html#features-depthClipControl)"]
+ pub depth_clip_control: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDepthClipEnableFeaturesEXT.html#features-depthClipEnable)"]
+ pub depth_clip_enable: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceAccelerationStructureFeaturesKHR.html#features-descriptorBindingAccelerationStructureUpdateAfterBind)"]
+ pub descriptor_binding_acceleration_structure_update_after_bind: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Features.html#features-descriptorBindingInlineUniformBlockUpdateAfterBind)"]
+ pub descriptor_binding_inline_uniform_block_update_after_bind: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-descriptorBindingPartiallyBound)"]
+ pub descriptor_binding_partially_bound: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-descriptorBindingSampledImageUpdateAfterBind)"]
+ pub descriptor_binding_sampled_image_update_after_bind: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-descriptorBindingStorageBufferUpdateAfterBind)"]
+ pub descriptor_binding_storage_buffer_update_after_bind: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-descriptorBindingStorageImageUpdateAfterBind)"]
+ pub descriptor_binding_storage_image_update_after_bind: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-descriptorBindingStorageTexelBufferUpdateAfterBind)"]
+ pub descriptor_binding_storage_texel_buffer_update_after_bind: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-descriptorBindingUniformBufferUpdateAfterBind)"]
+ pub descriptor_binding_uniform_buffer_update_after_bind: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-descriptorBindingUniformTexelBufferUpdateAfterBind)"]
+ pub descriptor_binding_uniform_texel_buffer_update_after_bind: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-descriptorBindingUpdateUnusedWhilePending)"]
+ pub descriptor_binding_update_unused_while_pending: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-descriptorBindingVariableDescriptorCount)"]
+ pub descriptor_binding_variable_descriptor_count: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferFeaturesEXT.html#features-descriptorBuffer)"]
+ pub descriptor_buffer: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferFeaturesEXT.html#features-descriptorBufferCaptureReplay)"]
+ pub descriptor_buffer_capture_replay: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferFeaturesEXT.html#features-descriptorBufferImageLayoutIgnored)"]
+ pub descriptor_buffer_image_layout_ignored: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferFeaturesEXT.html#features-descriptorBufferPushDescriptors)"]
+ pub descriptor_buffer_push_descriptors: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-descriptorIndexing)\n- Required by device extension: [`ext_descriptor_indexing`](crate::device::DeviceExtensions::ext_descriptor_indexing)"]
+ pub descriptor_indexing: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE.html#features-descriptorSetHostMapping)"]
+ pub descriptor_set_host_mapping: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceCoherentMemoryFeaturesAMD.html#features-deviceCoherentMemory)"]
+ pub device_coherent_memory: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFaultFeaturesEXT.html#features-deviceFault)"]
+ pub device_fault: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFaultFeaturesEXT.html#features-deviceFaultVendorBinary)"]
+ pub device_fault_vendor_binary: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV.html#features-deviceGeneratedCommands)"]
+ pub device_generated_commands: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDeviceMemoryReportFeaturesEXT.html#features-deviceMemoryReport)"]
+ pub device_memory_report: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDiagnosticsConfigFeaturesNV.html#features-diagnosticsConfig)"]
+ pub diagnostics_config: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-drawIndirectCount)\n- Required by device extension: [`khr_draw_indirect_count`](crate::device::DeviceExtensions::khr_draw_indirect_count)"]
+ pub draw_indirect_count: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-drawIndirectFirstInstance)"]
+ pub draw_indirect_first_instance: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-dualSrcBlend)"]
+ pub dual_src_blend: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Features.html#features-dynamicRendering)"]
+ pub dynamic_rendering: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePortabilitySubsetFeaturesKHR.html#features-events)"]
+ pub events: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExclusiveScissorFeaturesNV.html#features-exclusiveScissor)"]
+ pub exclusive_scissor: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicStateFeaturesEXT.html#features-extendedDynamicState)"]
+ pub extended_dynamic_state: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState2FeaturesEXT.html#features-extendedDynamicState2)"]
+ pub extended_dynamic_state2: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState2FeaturesEXT.html#features-extendedDynamicState2LogicOp)"]
+ pub extended_dynamic_state2_logic_op: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState2FeaturesEXT.html#features-extendedDynamicState2PatchControlPoints)"]
+ pub extended_dynamic_state2_patch_control_points: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3FeaturesEXT.html#features-extendedDynamicState3AlphaToCoverageEnable)"]
+ pub extended_dynamic_state3_alpha_to_coverage_enable: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3FeaturesEXT.html#features-extendedDynamicState3AlphaToOneEnable)"]
+ pub extended_dynamic_state3_alpha_to_one_enable: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3FeaturesEXT.html#features-extendedDynamicState3ColorBlendAdvanced)"]
+ pub extended_dynamic_state3_color_blend_advanced: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3FeaturesEXT.html#features-extendedDynamicState3ColorBlendEnable)"]
+ pub extended_dynamic_state3_color_blend_enable: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3FeaturesEXT.html#features-extendedDynamicState3ColorBlendEquation)"]
+ pub extended_dynamic_state3_color_blend_equation: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3FeaturesEXT.html#features-extendedDynamicState3ColorWriteMask)"]
+ pub extended_dynamic_state3_color_write_mask: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3FeaturesEXT.html#features-extendedDynamicState3ConservativeRasterizationMode)"]
+ pub extended_dynamic_state3_conservative_rasterization_mode: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3FeaturesEXT.html#features-extendedDynamicState3CoverageModulationMode)"]
+ pub extended_dynamic_state3_coverage_modulation_mode: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3FeaturesEXT.html#features-extendedDynamicState3CoverageModulationTable)"]
+ pub extended_dynamic_state3_coverage_modulation_table: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3FeaturesEXT.html#features-extendedDynamicState3CoverageModulationTableEnable)"]
+ pub extended_dynamic_state3_coverage_modulation_table_enable: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3FeaturesEXT.html#features-extendedDynamicState3CoverageReductionMode)"]
+ pub extended_dynamic_state3_coverage_reduction_mode: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3FeaturesEXT.html#features-extendedDynamicState3CoverageToColorEnable)"]
+ pub extended_dynamic_state3_coverage_to_color_enable: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3FeaturesEXT.html#features-extendedDynamicState3CoverageToColorLocation)"]
+ pub extended_dynamic_state3_coverage_to_color_location: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3FeaturesEXT.html#features-extendedDynamicState3DepthClampEnable)"]
+ pub extended_dynamic_state3_depth_clamp_enable: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3FeaturesEXT.html#features-extendedDynamicState3DepthClipEnable)"]
+ pub extended_dynamic_state3_depth_clip_enable: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3FeaturesEXT.html#features-extendedDynamicState3DepthClipNegativeOneToOne)"]
+ pub extended_dynamic_state3_depth_clip_negative_one_to_one: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3FeaturesEXT.html#features-extendedDynamicState3ExtraPrimitiveOverestimationSize)"]
+ pub extended_dynamic_state3_extra_primitive_overestimation_size: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3FeaturesEXT.html#features-extendedDynamicState3LineRasterizationMode)"]
+ pub extended_dynamic_state3_line_rasterization_mode: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3FeaturesEXT.html#features-extendedDynamicState3LineStippleEnable)"]
+ pub extended_dynamic_state3_line_stipple_enable: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3FeaturesEXT.html#features-extendedDynamicState3LogicOpEnable)"]
+ pub extended_dynamic_state3_logic_op_enable: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3FeaturesEXT.html#features-extendedDynamicState3PolygonMode)"]
+ pub extended_dynamic_state3_polygon_mode: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3FeaturesEXT.html#features-extendedDynamicState3ProvokingVertexMode)"]
+ pub extended_dynamic_state3_provoking_vertex_mode: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3FeaturesEXT.html#features-extendedDynamicState3RasterizationSamples)"]
+ pub extended_dynamic_state3_rasterization_samples: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3FeaturesEXT.html#features-extendedDynamicState3RasterizationStream)"]
+ pub extended_dynamic_state3_rasterization_stream: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3FeaturesEXT.html#features-extendedDynamicState3RepresentativeFragmentTestEnable)"]
+ pub extended_dynamic_state3_representative_fragment_test_enable: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3FeaturesEXT.html#features-extendedDynamicState3SampleLocationsEnable)"]
+ pub extended_dynamic_state3_sample_locations_enable: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3FeaturesEXT.html#features-extendedDynamicState3SampleMask)"]
+ pub extended_dynamic_state3_sample_mask: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3FeaturesEXT.html#features-extendedDynamicState3ShadingRateImageEnable)"]
+ pub extended_dynamic_state3_shading_rate_image_enable: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3FeaturesEXT.html#features-extendedDynamicState3TessellationDomainOrigin)"]
+ pub extended_dynamic_state3_tessellation_domain_origin: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3FeaturesEXT.html#features-extendedDynamicState3ViewportSwizzle)"]
+ pub extended_dynamic_state3_viewport_swizzle: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3FeaturesEXT.html#features-extendedDynamicState3ViewportWScalingEnable)"]
+ pub extended_dynamic_state3_viewport_w_scaling_enable: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExternalMemoryRDMAFeaturesNV.html#features-externalMemoryRDMA)"]
+ pub external_memory_rdma: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-fillModeNonSolid)"]
+ pub fill_mode_non_solid: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevice4444FormatsFeaturesEXT.html#features-formatA4B4G4R4)"]
+ pub format_a4b4g4r4: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevice4444FormatsFeaturesEXT.html#features-formatA4R4G4B4)"]
+ pub format_a4r4g4b4: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT.html#features-formatRgba10x6WithoutYCbCrSampler)"]
+ pub format_rgba10x6_without_y_cb_cr_sampler: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentDensityMapFeaturesEXT.html#features-fragmentDensityMap)\n- Conflicts with features: [`pipeline_fragment_shading_rate`](crate::device::Features::pipeline_fragment_shading_rate), [`primitive_fragment_shading_rate`](crate::device::Features::primitive_fragment_shading_rate), [`attachment_fragment_shading_rate`](crate::device::Features::attachment_fragment_shading_rate)"]
+ pub fragment_density_map: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentDensityMap2FeaturesEXT.html#features-fragmentDensityMapDeferred)"]
+ pub fragment_density_map_deferred: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentDensityMapFeaturesEXT.html#features-fragmentDensityMapDynamic)"]
+ pub fragment_density_map_dynamic: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentDensityMapFeaturesEXT.html#features-fragmentDensityMapNonSubsampledImages)"]
+ pub fragment_density_map_non_subsampled_images: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentDensityMapOffsetFeaturesQCOM.html#features-fragmentDensityMapOffset)"]
+ pub fragment_density_map_offset: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR.html#features-fragmentShaderBarycentric)"]
+ pub fragment_shader_barycentric: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT.html#features-fragmentShaderPixelInterlock)"]
+ pub fragment_shader_pixel_interlock: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT.html#features-fragmentShaderSampleInterlock)"]
+ pub fragment_shader_sample_interlock: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT.html#features-fragmentShaderShadingRateInterlock)"]
+ pub fragment_shader_shading_rate_interlock: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV.html#features-fragmentShadingRateEnums)"]
+ pub fragment_shading_rate_enums: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-fragmentStoresAndAtomics)"]
+ pub fragment_stores_and_atomics: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-fullDrawIndexUint32)"]
+ pub full_draw_index_uint32: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-geometryShader)"]
+ pub geometry_shader: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceTransformFeedbackFeaturesEXT.html#features-geometryStreams)"]
+ pub geometry_streams: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR.html#features-globalPriorityQuery)"]
+ pub global_priority_query: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT.html#features-graphicsPipelineLibrary)"]
+ pub graphics_pipeline_library: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-hostQueryReset)"]
+ pub host_query_reset: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceImage2DViewOf3DFeaturesEXT.html#features-image2DViewOf3D)"]
+ pub image2_d_view_of3_d: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceImageCompressionControlFeaturesEXT.html#features-imageCompressionControl)"]
+ pub image_compression_control: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT.html#features-imageCompressionControlSwapchain)"]
+ pub image_compression_control_swapchain: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-imageCubeArray)"]
+ pub image_cube_array: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderImageFootprintFeaturesNV.html#features-imageFootprint)"]
+ pub image_footprint: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePortabilitySubsetFeaturesKHR.html#features-imageView2DOn3DImage)"]
+ pub image_view2_d_on3_d_image: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePortabilitySubsetFeaturesKHR.html#features-imageViewFormatReinterpretation)"]
+ pub image_view_format_reinterpretation: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePortabilitySubsetFeaturesKHR.html#features-imageViewFormatSwizzle)"]
+ pub image_view_format_swizzle: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-imagelessFramebuffer)"]
+ pub imageless_framebuffer: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-independentBlend)"]
+ pub independent_blend: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceIndexTypeUint8FeaturesEXT.html#features-indexTypeUint8)"]
+ pub index_type_uint8: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceCopyMemoryIndirectFeaturesNV.html#features-indirectCopy)"]
+ pub indirect_copy: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceConditionalRenderingFeaturesEXT.html#features-inheritedConditionalRendering)"]
+ pub inherited_conditional_rendering: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-inheritedQueries)"]
+ pub inherited_queries: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceInheritedViewportScissorFeaturesNV.html#features-inheritedViewportScissor2D)"]
+ pub inherited_viewport_scissor2_d: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Features.html#features-inlineUniformBlock)"]
+ pub inline_uniform_block: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceInvocationMaskFeaturesHUAWEI.html#features-invocationMask)"]
+ pub invocation_mask: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-largePoints)"]
+ pub large_points: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLegacyDitheringFeaturesEXT.html#features-legacyDithering)"]
+ pub legacy_dithering: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLinearColorAttachmentFeaturesNV.html#features-linearColorAttachment)"]
+ pub linear_color_attachment: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-logicOp)"]
+ pub logic_op: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Features.html#features-maintenance4)"]
+ pub maintenance4: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMemoryDecompressionFeaturesNV.html#features-memoryDecompression)"]
+ pub memory_decompression: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMemoryPriorityFeaturesEXT.html#features-memoryPriority)"]
+ pub memory_priority: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderFeaturesEXT.html#features-meshShader)"]
+ pub mesh_shader: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderFeaturesEXT.html#features-meshShaderQueries)"]
+ pub mesh_shader_queries: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceOpacityMicromapFeaturesEXT.html#features-micromap)"]
+ pub micromap: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceOpacityMicromapFeaturesEXT.html#features-micromapCaptureReplay)"]
+ pub micromap_capture_replay: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceOpacityMicromapFeaturesEXT.html#features-micromapHostCommands)"]
+ pub micromap_host_commands: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceImageViewMinLodFeaturesEXT.html#features-minLod)"]
+ pub min_lod: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMultiDrawFeaturesEXT.html#features-multiDraw)"]
+ pub multi_draw: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-multiDrawIndirect)"]
+ pub multi_draw_indirect: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-multiViewport)"]
+ pub multi_viewport: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePortabilitySubsetFeaturesKHR.html#features-multisampleArrayImage)"]
+ pub multisample_array_image: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT.html#features-multisampledRenderToSingleSampled)"]
+ pub multisampled_render_to_single_sampled: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan11Features.html#features-multiview)"]
+ pub multiview: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan11Features.html#features-multiviewGeometryShader)"]
+ pub multiview_geometry_shader: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderFeaturesEXT.html#features-multiviewMeshShader)"]
+ pub multiview_mesh_shader: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMultiviewPerViewViewportsFeaturesQCOM.html#features-multiviewPerViewViewports)"]
+ pub multiview_per_view_viewports: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan11Features.html#features-multiviewTessellationShader)"]
+ pub multiview_tessellation_shader: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePortabilitySubsetFeaturesKHR.html#features-mutableComparisonSamplers)"]
+ pub mutable_comparison_samplers: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT.html#features-mutableDescriptorType)"]
+ pub mutable_descriptor_type: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV.html#features-noInvocationFragmentShadingRates)"]
+ pub no_invocation_fragment_shading_rates: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT.html#features-nonSeamlessCubeMap)"]
+ pub non_seamless_cube_map: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRobustness2FeaturesEXT.html#features-nullDescriptor)"]
+ pub null_descriptor: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-occlusionQueryPrecise)"]
+ pub occlusion_query_precise: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceOpticalFlowFeaturesNV.html#features-opticalFlow)"]
+ pub optical_flow: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT.html#features-pageableDeviceLocalMemory)"]
+ pub pageable_device_local_memory: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePerformanceQueryFeaturesKHR.html#features-performanceCounterMultipleQueryPools)"]
+ pub performance_counter_multiple_query_pools: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePerformanceQueryFeaturesKHR.html#features-performanceCounterQueryPools)"]
+ pub performance_counter_query_pools: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Features.html#features-pipelineCreationCacheControl)"]
+ pub pipeline_creation_cache_control: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePipelineExecutablePropertiesFeaturesKHR.html#features-pipelineExecutableInfo)"]
+ pub pipeline_executable_info: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentShadingRateFeaturesKHR.html#features-pipelineFragmentShadingRate)\n- Conflicts with features: [`shading_rate_image`](crate::device::Features::shading_rate_image), [`fragment_density_map`](crate::device::Features::fragment_density_map)"]
+ pub pipeline_fragment_shading_rate: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePipelinePropertiesFeaturesEXT.html#features-pipelinePropertiesIdentifier)"]
+ pub pipeline_properties_identifier: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePipelineProtectedAccessFeaturesEXT.html#features-pipelineProtectedAccess)"]
+ pub pipeline_protected_access: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePipelineRobustnessFeaturesEXT.html#features-pipelineRobustness)"]
+ pub pipeline_robustness: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-pipelineStatisticsQuery)"]
+ pub pipeline_statistics_query: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePortabilitySubsetFeaturesKHR.html#features-pointPolygons)"]
+ pub point_polygons: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePresentBarrierFeaturesNV.html#features-presentBarrier)"]
+ pub present_barrier: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePresentIdFeaturesKHR.html#features-presentId)"]
+ pub present_id: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePresentWaitFeaturesKHR.html#features-presentWait)"]
+ pub present_wait: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentShadingRateFeaturesKHR.html#features-primitiveFragmentShadingRate)\n- Conflicts with features: [`shading_rate_image`](crate::device::Features::shading_rate_image), [`fragment_density_map`](crate::device::Features::fragment_density_map)"]
+ pub primitive_fragment_shading_rate: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderFeaturesEXT.html#features-primitiveFragmentShadingRateMeshShader)"]
+ pub primitive_fragment_shading_rate_mesh_shader: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT.html#features-primitiveTopologyListRestart)"]
+ pub primitive_topology_list_restart: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT.html#features-primitiveTopologyPatchListRestart)"]
+ pub primitive_topology_patch_list_restart: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT.html#features-primitivesGeneratedQuery)"]
+ pub primitives_generated_query: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT.html#features-primitivesGeneratedQueryWithNonZeroStreams)"]
+ pub primitives_generated_query_with_non_zero_streams: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT.html#features-primitivesGeneratedQueryWithRasterizerDiscard)"]
+ pub primitives_generated_query_with_rasterizer_discard: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Features.html#features-privateData)"]
+ pub private_data: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan11Features.html#features-protectedMemory)"]
+ pub protected_memory: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceProvokingVertexFeaturesEXT.html#features-provokingVertexLast)"]
+ pub provoking_vertex_last: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT.html#features-rasterizationOrderColorAttachmentAccess)"]
+ pub rasterization_order_color_attachment_access: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT.html#features-rasterizationOrderDepthAttachmentAccess)"]
+ pub rasterization_order_depth_attachment_access: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT.html#features-rasterizationOrderStencilAttachmentAccess)"]
+ pub rasterization_order_stencil_attachment_access: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRayQueryFeaturesKHR.html#features-rayQuery)"]
+ pub ray_query: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRayTracingInvocationReorderFeaturesNV.html#features-rayTracingInvocationReorder)"]
+ pub ray_tracing_invocation_reorder: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR.html#features-rayTracingMaintenance1)"]
+ pub ray_tracing_maintenance1: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRayTracingMotionBlurFeaturesNV.html#features-rayTracingMotionBlur)"]
+ pub ray_tracing_motion_blur: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRayTracingMotionBlurFeaturesNV.html#features-rayTracingMotionBlurPipelineTraceRaysIndirect)"]
+ pub ray_tracing_motion_blur_pipeline_trace_rays_indirect: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRayTracingPipelineFeaturesKHR.html#features-rayTracingPipeline)"]
+ pub ray_tracing_pipeline: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRayTracingPipelineFeaturesKHR.html#features-rayTracingPipelineShaderGroupHandleCaptureReplay)"]
+ pub ray_tracing_pipeline_shader_group_handle_capture_replay: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRayTracingPipelineFeaturesKHR.html#features-rayTracingPipelineShaderGroupHandleCaptureReplayMixed)"]
+ pub ray_tracing_pipeline_shader_group_handle_capture_replay_mixed: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRayTracingPipelineFeaturesKHR.html#features-rayTracingPipelineTraceRaysIndirect)"]
+ pub ray_tracing_pipeline_trace_rays_indirect: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR.html#features-rayTracingPipelineTraceRaysIndirect2)"]
+ pub ray_tracing_pipeline_trace_rays_indirect2: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRayTracingPipelineFeaturesKHR.html#features-rayTraversalPrimitiveCulling)"]
+ pub ray_traversal_primitive_culling: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLineRasterizationFeaturesEXT.html#features-rectangularLines)"]
+ pub rectangular_lines: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceAddressBindingReportFeaturesEXT.html#features-reportAddressBinding)"]
+ pub report_address_binding: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV.html#features-representativeFragmentTest)"]
+ pub representative_fragment_test: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-robustBufferAccess)"]
+ pub robust_buffer_access: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRobustness2FeaturesEXT.html#features-robustBufferAccess2)"]
+ pub robust_buffer_access2: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Features.html#features-robustImageAccess)"]
+ pub robust_image_access: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRobustness2FeaturesEXT.html#features-robustImageAccess2)"]
+ pub robust_image_access2: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-runtimeDescriptorArray)"]
+ pub runtime_descriptor_array: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-sampleRateShading)"]
+ pub sample_rate_shading: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceImage2DViewOf3DFeaturesEXT.html#features-sampler2DViewOf3D)"]
+ pub sampler2_d_view_of3_d: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-samplerAnisotropy)"]
+ pub sampler_anisotropy: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-samplerFilterMinmax)\n- Required by device extension: [`ext_sampler_filter_minmax`](crate::device::DeviceExtensions::ext_sampler_filter_minmax)"]
+ pub sampler_filter_minmax: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePortabilitySubsetFeaturesKHR.html#features-samplerMipLodBias)"]
+ pub sampler_mip_lod_bias: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-samplerMirrorClampToEdge)\n- Required by device extension: [`khr_sampler_mirror_clamp_to_edge`](crate::device::DeviceExtensions::khr_sampler_mirror_clamp_to_edge)"]
+ pub sampler_mirror_clamp_to_edge: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan11Features.html#features-samplerYcbcrConversion)"]
+ pub sampler_ycbcr_conversion: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-scalarBlockLayout)"]
+ pub scalar_block_layout: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-separateDepthStencilLayouts)"]
+ pub separate_depth_stencil_layouts: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePortabilitySubsetFeaturesKHR.html#features-separateStencilMaskRef)"]
+ pub separate_stencil_mask_ref: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT.html#features-shaderBufferFloat16AtomicAdd)"]
+ pub shader_buffer_float16_atomic_add: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT.html#features-shaderBufferFloat16AtomicMinMax)"]
+ pub shader_buffer_float16_atomic_min_max: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT.html#features-shaderBufferFloat16Atomics)"]
+ pub shader_buffer_float16_atomics: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderAtomicFloatFeaturesEXT.html#features-shaderBufferFloat32AtomicAdd)"]
+ pub shader_buffer_float32_atomic_add: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT.html#features-shaderBufferFloat32AtomicMinMax)"]
+ pub shader_buffer_float32_atomic_min_max: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderAtomicFloatFeaturesEXT.html#features-shaderBufferFloat32Atomics)"]
+ pub shader_buffer_float32_atomics: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderAtomicFloatFeaturesEXT.html#features-shaderBufferFloat64AtomicAdd)"]
+ pub shader_buffer_float64_atomic_add: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT.html#features-shaderBufferFloat64AtomicMinMax)"]
+ pub shader_buffer_float64_atomic_min_max: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderAtomicFloatFeaturesEXT.html#features-shaderBufferFloat64Atomics)"]
+ pub shader_buffer_float64_atomics: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderBufferInt64Atomics)"]
+ pub shader_buffer_int64_atomics: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderClipDistance)"]
+ pub shader_clip_distance: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM.html#features-shaderCoreBuiltins)"]
+ pub shader_core_builtins: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderCullDistance)"]
+ pub shader_cull_distance: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Features.html#features-shaderDemoteToHelperInvocation)"]
+ pub shader_demote_to_helper_invocation: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderClockFeaturesKHR.html#features-shaderDeviceClock)"]
+ pub shader_device_clock: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan11Features.html#features-shaderDrawParameters)\n- Required by device extension: [`khr_shader_draw_parameters`](crate::device::DeviceExtensions::khr_shader_draw_parameters)"]
+ pub shader_draw_parameters: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderEarlyAndLateFragmentTestsFeaturesAMD.html#features-shaderEarlyAndLateFragmentTests)"]
+ pub shader_early_and_late_fragment_tests: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderFloat16)"]
+ pub shader_float16: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderFloat64)"]
+ pub shader_float64: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderAtomicFloatFeaturesEXT.html#features-shaderImageFloat32AtomicAdd)"]
+ pub shader_image_float32_atomic_add: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT.html#features-shaderImageFloat32AtomicMinMax)"]
+ pub shader_image_float32_atomic_min_max: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderAtomicFloatFeaturesEXT.html#features-shaderImageFloat32Atomics)"]
+ pub shader_image_float32_atomics: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderImageGatherExtended)"]
+ pub shader_image_gather_extended: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT.html#features-shaderImageInt64Atomics)"]
+ pub shader_image_int64_atomics: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderInputAttachmentArrayDynamicIndexing)"]
+ pub shader_input_attachment_array_dynamic_indexing: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderInputAttachmentArrayNonUniformIndexing)"]
+ pub shader_input_attachment_array_non_uniform_indexing: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderInt16)"]
+ pub shader_int16: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderInt64)"]
+ pub shader_int64: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderInt8)"]
+ pub shader_int8: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Features.html#features-shaderIntegerDotProduct)"]
+ pub shader_integer_dot_product: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL.html#features-shaderIntegerFunctions2)"]
+ pub shader_integer_functions2: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT.html#features-shaderModuleIdentifier)"]
+ pub shader_module_identifier: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderOutputLayer)\n- Required by device extension: [`ext_shader_viewport_index_layer`](crate::device::DeviceExtensions::ext_shader_viewport_index_layer)"]
+ pub shader_output_layer: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderOutputViewportIndex)\n- Required by device extension: [`ext_shader_viewport_index_layer`](crate::device::DeviceExtensions::ext_shader_viewport_index_layer)"]
+ pub shader_output_viewport_index: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderResourceMinLod)"]
+ pub shader_resource_min_lod: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderResourceResidency)"]
+ pub shader_resource_residency: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePortabilitySubsetFeaturesKHR.html#features-shaderSampleRateInterpolationFunctions)"]
+ pub shader_sample_rate_interpolation_functions: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderSampledImageArrayDynamicIndexing)"]
+ pub shader_sampled_image_array_dynamic_indexing: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderSampledImageArrayNonUniformIndexing)"]
+ pub shader_sampled_image_array_non_uniform_indexing: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT.html#features-shaderSharedFloat16AtomicAdd)"]
+ pub shader_shared_float16_atomic_add: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT.html#features-shaderSharedFloat16AtomicMinMax)"]
+ pub shader_shared_float16_atomic_min_max: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT.html#features-shaderSharedFloat16Atomics)"]
+ pub shader_shared_float16_atomics: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderAtomicFloatFeaturesEXT.html#features-shaderSharedFloat32AtomicAdd)"]
+ pub shader_shared_float32_atomic_add: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT.html#features-shaderSharedFloat32AtomicMinMax)"]
+ pub shader_shared_float32_atomic_min_max: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderAtomicFloatFeaturesEXT.html#features-shaderSharedFloat32Atomics)"]
+ pub shader_shared_float32_atomics: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderAtomicFloatFeaturesEXT.html#features-shaderSharedFloat64AtomicAdd)"]
+ pub shader_shared_float64_atomic_add: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT.html#features-shaderSharedFloat64AtomicMinMax)"]
+ pub shader_shared_float64_atomic_min_max: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderAtomicFloatFeaturesEXT.html#features-shaderSharedFloat64Atomics)"]
+ pub shader_shared_float64_atomics: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderSharedInt64Atomics)"]
+ pub shader_shared_int64_atomics: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderSMBuiltinsFeaturesNV.html#features-shaderSMBuiltins)"]
+ pub shader_sm_builtins: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderStorageBufferArrayDynamicIndexing)"]
+ pub shader_storage_buffer_array_dynamic_indexing: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderStorageBufferArrayNonUniformIndexing)"]
+ pub shader_storage_buffer_array_non_uniform_indexing: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderStorageImageArrayDynamicIndexing)"]
+ pub shader_storage_image_array_dynamic_indexing: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderStorageImageArrayNonUniformIndexing)"]
+ pub shader_storage_image_array_non_uniform_indexing: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderStorageImageExtendedFormats)"]
+ pub shader_storage_image_extended_formats: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderStorageImageMultisample)"]
+ pub shader_storage_image_multisample: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderStorageImageReadWithoutFormat)"]
+ pub shader_storage_image_read_without_format: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderStorageImageWriteWithoutFormat)"]
+ pub shader_storage_image_write_without_format: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderStorageTexelBufferArrayDynamicIndexing)"]
+ pub shader_storage_texel_buffer_array_dynamic_indexing: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderStorageTexelBufferArrayNonUniformIndexing)"]
+ pub shader_storage_texel_buffer_array_non_uniform_indexing: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderClockFeaturesKHR.html#features-shaderSubgroupClock)"]
+ pub shader_subgroup_clock: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderSubgroupExtendedTypes)"]
+ pub shader_subgroup_extended_types: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR.html#features-shaderSubgroupUniformControlFlow)"]
+ pub shader_subgroup_uniform_control_flow: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Features.html#features-shaderTerminateInvocation)"]
+ pub shader_terminate_invocation: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderTessellationAndGeometryPointSize)"]
+ pub shader_tessellation_and_geometry_point_size: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-shaderUniformBufferArrayDynamicIndexing)"]
+ pub shader_uniform_buffer_array_dynamic_indexing: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderUniformBufferArrayNonUniformIndexing)"]
+ pub shader_uniform_buffer_array_non_uniform_indexing: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderUniformTexelBufferArrayDynamicIndexing)"]
+ pub shader_uniform_texel_buffer_array_dynamic_indexing: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-shaderUniformTexelBufferArrayNonUniformIndexing)"]
+ pub shader_uniform_texel_buffer_array_non_uniform_indexing: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Features.html#features-shaderZeroInitializeWorkgroupMemory)"]
+ pub shader_zero_initialize_workgroup_memory: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShadingRateImageFeaturesNV.html#features-shadingRateCoarseSampleOrder)"]
+ pub shading_rate_coarse_sample_order: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShadingRateImageFeaturesNV.html#features-shadingRateImage)\n- Conflicts with features: [`pipeline_fragment_shading_rate`](crate::device::Features::pipeline_fragment_shading_rate), [`primitive_fragment_shading_rate`](crate::device::Features::primitive_fragment_shading_rate), [`attachment_fragment_shading_rate`](crate::device::Features::attachment_fragment_shading_rate)"]
+ pub shading_rate_image: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLineRasterizationFeaturesEXT.html#features-smoothLines)"]
+ pub smooth_lines: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-sparseBinding)"]
+ pub sparse_binding: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderAtomicFloatFeaturesEXT.html#features-sparseImageFloat32AtomicAdd)\n- Requires feature: [`shader_image_float32_atomic_add`](crate::device::Features::shader_image_float32_atomic_add)"]
+ pub sparse_image_float32_atomic_add: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT.html#features-sparseImageFloat32AtomicMinMax)\n- Requires feature: [`shader_image_float32_atomic_min_max`](crate::device::Features::shader_image_float32_atomic_min_max)"]
+ pub sparse_image_float32_atomic_min_max: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderAtomicFloatFeaturesEXT.html#features-sparseImageFloat32Atomics)\n- Requires feature: [`shader_image_float32_atomics`](crate::device::Features::shader_image_float32_atomics)"]
+ pub sparse_image_float32_atomics: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT.html#features-sparseImageInt64Atomics)\n- Requires feature: [`shader_image_int64_atomics`](crate::device::Features::shader_image_int64_atomics)"]
+ pub sparse_image_int64_atomics: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-sparseResidency16Samples)"]
+ pub sparse_residency16_samples: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-sparseResidency2Samples)"]
+ pub sparse_residency2_samples: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-sparseResidency4Samples)"]
+ pub sparse_residency4_samples: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-sparseResidency8Samples)"]
+ pub sparse_residency8_samples: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-sparseResidencyAliased)"]
+ pub sparse_residency_aliased: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-sparseResidencyBuffer)"]
+ pub sparse_residency_buffer: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-sparseResidencyImage2D)"]
+ pub sparse_residency_image2_d: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-sparseResidencyImage3D)"]
+ pub sparse_residency_image3_d: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLineRasterizationFeaturesEXT.html#features-stippledBresenhamLines)"]
+ pub stippled_bresenham_lines: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLineRasterizationFeaturesEXT.html#features-stippledRectangularLines)"]
+ pub stippled_rectangular_lines: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLineRasterizationFeaturesEXT.html#features-stippledSmoothLines)"]
+ pub stippled_smooth_lines: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan11Features.html#features-storageBuffer16BitAccess)"]
+ pub storage_buffer16_bit_access: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-storageBuffer8BitAccess)"]
+ pub storage_buffer8_bit_access: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan11Features.html#features-storageInputOutput16)"]
+ pub storage_input_output16: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan11Features.html#features-storagePushConstant16)"]
+ pub storage_push_constant16: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-storagePushConstant8)"]
+ pub storage_push_constant8: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-subgroupBroadcastDynamicId)"]
+ pub subgroup_broadcast_dynamic_id: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Features.html#features-subgroupSizeControl)"]
+ pub subgroup_size_control: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceSubpassMergeFeedbackFeaturesEXT.html#features-subpassMergeFeedback)"]
+ pub subpass_merge_feedback: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceSubpassShadingFeaturesHUAWEI.html#features-subpassShading)"]
+ pub subpass_shading: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV.html#features-supersampleFragmentShadingRates)"]
+ pub supersample_fragment_shading_rates: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT.html#features-swapchainMaintenance1)"]
+ pub swapchain_maintenance1: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Features.html#features-synchronization2)"]
+ pub synchronization2: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderFeaturesEXT.html#features-taskShader)"]
+ pub task_shader: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePortabilitySubsetFeaturesKHR.html#features-tessellationIsolines)"]
+ pub tessellation_isolines: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePortabilitySubsetFeaturesKHR.html#features-tessellationPointMode)"]
+ pub tessellation_point_mode: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-tessellationShader)"]
+ pub tessellation_shader: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT.html#features-texelBufferAlignment)"]
+ pub texel_buffer_alignment: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceImageProcessingFeaturesQCOM.html#features-textureBlockMatch)"]
+ pub texture_block_match: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceImageProcessingFeaturesQCOM.html#features-textureBoxFilter)"]
+ pub texture_box_filter: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Features.html#features-textureCompressionASTC_HDR)"]
+ pub texture_compression_astc_hdr: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-textureCompressionASTC_LDR)"]
+ pub texture_compression_astc_ldr: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-textureCompressionBC)"]
+ pub texture_compression_bc: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-textureCompressionETC2)"]
+ pub texture_compression_etc2: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceImageProcessingFeaturesQCOM.html#features-textureSampleWeighted)"]
+ pub texture_sample_weighted: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceTilePropertiesFeaturesQCOM.html#features-tileProperties)"]
+ pub tile_properties: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-timelineSemaphore)"]
+ pub timeline_semaphore: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceTransformFeedbackFeaturesEXT.html#features-transformFeedback)"]
+ pub transform_feedback: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceProvokingVertexFeaturesEXT.html#features-transformFeedbackPreservesProvokingVertex)"]
+ pub transform_feedback_preserves_provoking_vertex: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePortabilitySubsetFeaturesKHR.html#features-triangleFans)"]
+ pub triangle_fans: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan11Features.html#features-uniformAndStorageBuffer16BitAccess)"]
+ pub uniform_and_storage_buffer16_bit_access: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-uniformAndStorageBuffer8BitAccess)"]
+ pub uniform_and_storage_buffer8_bit_access: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-uniformBufferStandardLayout)"]
+ pub uniform_buffer_standard_layout: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-variableMultisampleRate)"]
+ pub variable_multisample_rate: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan11Features.html#features-variablePointers)"]
+ pub variable_pointers: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan11Features.html#features-variablePointersStorageBuffer)"]
+ pub variable_pointers_storage_buffer: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePortabilitySubsetFeaturesKHR.html#features-vertexAttributeAccessBeyondStride)"]
+ pub vertex_attribute_access_beyond_stride: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT.html#features-vertexAttributeInstanceRateDivisor)"]
+ pub vertex_attribute_instance_rate_divisor: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT.html#features-vertexAttributeInstanceRateZeroDivisor)"]
+ pub vertex_attribute_instance_rate_zero_divisor: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT.html#features-vertexInputDynamicState)"]
+ pub vertex_input_dynamic_state: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-vertexPipelineStoresAndAtomics)"]
+ pub vertex_pipeline_stores_and_atomics: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-vulkanMemoryModel)"]
+ pub vulkan_memory_model: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-vulkanMemoryModelAvailabilityVisibilityChains)"]
+ pub vulkan_memory_model_availability_visibility_chains: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Features.html#features-vulkanMemoryModelDeviceScope)"]
+ pub vulkan_memory_model_device_scope: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFeatures.html#features-wideLines)"]
+ pub wide_lines: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR.html#features-workgroupMemoryExplicitLayout)"]
+ pub workgroup_memory_explicit_layout: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR.html#features-workgroupMemoryExplicitLayout16BitAccess)"]
+ pub workgroup_memory_explicit_layout16_bit_access: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR.html#features-workgroupMemoryExplicitLayout8BitAccess)"]
+ pub workgroup_memory_explicit_layout8_bit_access: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR.html#features-workgroupMemoryExplicitLayoutScalarBlockLayout)"]
+ pub workgroup_memory_explicit_layout_scalar_block_layout: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT.html#features-ycbcr2plane444Formats)"]
+ pub ycbcr2plane444_formats: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceYcbcrImageArraysFeaturesEXT.html#features-ycbcrImageArrays)"]
+ pub ycbcr_image_arrays: bool,
+ pub _ne: crate::NonExhaustive,
+}
+impl Default for Features {
+ #[inline]
+ fn default() -> Self {
+ Self::empty()
+ }
+}
+impl Features {
+ #[doc = r" Checks enabled features against the device version, device extensions and each"]
+ #[doc = r" other."]
+ pub(super) fn check_requirements(
+ &self,
+ supported: &Features,
+ api_version: crate::Version,
+ extensions: &crate::device::DeviceExtensions,
+ ) -> Result<(), crate::device::FeatureRestrictionError> {
+ if self.acceleration_structure {
+ if !supported.acceleration_structure {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "acceleration_structure",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.acceleration_structure_capture_replay {
+ if !supported.acceleration_structure_capture_replay {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "acceleration_structure_capture_replay",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.acceleration_structure_host_commands {
+ if !supported.acceleration_structure_host_commands {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "acceleration_structure_host_commands",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.acceleration_structure_indirect_build {
+ if !supported.acceleration_structure_indirect_build {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "acceleration_structure_indirect_build",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.advanced_blend_coherent_operations {
+ if !supported.advanced_blend_coherent_operations {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "advanced_blend_coherent_operations",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.alpha_to_one {
+ if !supported.alpha_to_one {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "alpha_to_one",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.amigo_profiling {
+ if !supported.amigo_profiling {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "amigo_profiling",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.attachment_feedback_loop_layout {
+ if !supported.attachment_feedback_loop_layout {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "attachment_feedback_loop_layout",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.attachment_fragment_shading_rate {
+ if !supported.attachment_fragment_shading_rate {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "attachment_fragment_shading_rate",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ if self.shading_rate_image {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "attachment_fragment_shading_rate",
+ restriction: crate::device::FeatureRestriction::ConflictsFeature(
+ "shading_rate_image",
+ ),
+ });
+ }
+ if self.fragment_density_map {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "attachment_fragment_shading_rate",
+ restriction: crate::device::FeatureRestriction::ConflictsFeature(
+ "fragment_density_map",
+ ),
+ });
+ }
+ } else {
+ }
+ if self.border_color_swizzle {
+ if !supported.border_color_swizzle {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "border_color_swizzle",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.border_color_swizzle_from_image {
+ if !supported.border_color_swizzle_from_image {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "border_color_swizzle_from_image",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.bresenham_lines {
+ if !supported.bresenham_lines {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "bresenham_lines",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.buffer_device_address {
+ if !supported.buffer_device_address {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "buffer_device_address",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.buffer_device_address_capture_replay {
+ if !supported.buffer_device_address_capture_replay {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "buffer_device_address_capture_replay",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.buffer_device_address_multi_device {
+ if !supported.buffer_device_address_multi_device {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "buffer_device_address_multi_device",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.color_write_enable {
+ if !supported.color_write_enable {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "color_write_enable",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.compute_derivative_group_linear {
+ if !supported.compute_derivative_group_linear {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "compute_derivative_group_linear",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.compute_derivative_group_quads {
+ if !supported.compute_derivative_group_quads {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "compute_derivative_group_quads",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.compute_full_subgroups {
+ if !supported.compute_full_subgroups {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "compute_full_subgroups",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.conditional_rendering {
+ if !supported.conditional_rendering {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "conditional_rendering",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.constant_alpha_color_blend_factors {
+ if !supported.constant_alpha_color_blend_factors {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "constant_alpha_color_blend_factors",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.cooperative_matrix {
+ if !supported.cooperative_matrix {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "cooperative_matrix",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.cooperative_matrix_robust_buffer_access {
+ if !supported.cooperative_matrix_robust_buffer_access {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "cooperative_matrix_robust_buffer_access",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.corner_sampled_image {
+ if !supported.corner_sampled_image {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "corner_sampled_image",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.coverage_reduction_mode {
+ if !supported.coverage_reduction_mode {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "coverage_reduction_mode",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.custom_border_color_without_format {
+ if !supported.custom_border_color_without_format {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "custom_border_color_without_format",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.custom_border_colors {
+ if !supported.custom_border_colors {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "custom_border_colors",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.decode_mode_shared_exponent {
+ if !supported.decode_mode_shared_exponent {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "decode_mode_shared_exponent",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.dedicated_allocation_image_aliasing {
+ if !supported.dedicated_allocation_image_aliasing {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "dedicated_allocation_image_aliasing",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.depth_bias_clamp {
+ if !supported.depth_bias_clamp {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "depth_bias_clamp",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.depth_bounds {
+ if !supported.depth_bounds {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "depth_bounds",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.depth_clamp {
+ if !supported.depth_clamp {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "depth_clamp",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.depth_clamp_zero_one {
+ if !supported.depth_clamp_zero_one {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "depth_clamp_zero_one",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.depth_clip_control {
+ if !supported.depth_clip_control {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "depth_clip_control",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.depth_clip_enable {
+ if !supported.depth_clip_enable {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "depth_clip_enable",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.descriptor_binding_acceleration_structure_update_after_bind {
+ if !supported.descriptor_binding_acceleration_structure_update_after_bind {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "descriptor_binding_acceleration_structure_update_after_bind",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.descriptor_binding_inline_uniform_block_update_after_bind {
+ if !supported.descriptor_binding_inline_uniform_block_update_after_bind {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "descriptor_binding_inline_uniform_block_update_after_bind",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.descriptor_binding_partially_bound {
+ if !supported.descriptor_binding_partially_bound {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "descriptor_binding_partially_bound",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.descriptor_binding_sampled_image_update_after_bind {
+ if !supported.descriptor_binding_sampled_image_update_after_bind {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "descriptor_binding_sampled_image_update_after_bind",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.descriptor_binding_storage_buffer_update_after_bind {
+ if !supported.descriptor_binding_storage_buffer_update_after_bind {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "descriptor_binding_storage_buffer_update_after_bind",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.descriptor_binding_storage_image_update_after_bind {
+ if !supported.descriptor_binding_storage_image_update_after_bind {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "descriptor_binding_storage_image_update_after_bind",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.descriptor_binding_storage_texel_buffer_update_after_bind {
+ if !supported.descriptor_binding_storage_texel_buffer_update_after_bind {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "descriptor_binding_storage_texel_buffer_update_after_bind",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.descriptor_binding_uniform_buffer_update_after_bind {
+ if !supported.descriptor_binding_uniform_buffer_update_after_bind {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "descriptor_binding_uniform_buffer_update_after_bind",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.descriptor_binding_uniform_texel_buffer_update_after_bind {
+ if !supported.descriptor_binding_uniform_texel_buffer_update_after_bind {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "descriptor_binding_uniform_texel_buffer_update_after_bind",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.descriptor_binding_update_unused_while_pending {
+ if !supported.descriptor_binding_update_unused_while_pending {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "descriptor_binding_update_unused_while_pending",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.descriptor_binding_variable_descriptor_count {
+ if !supported.descriptor_binding_variable_descriptor_count {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "descriptor_binding_variable_descriptor_count",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.descriptor_buffer {
+ if !supported.descriptor_buffer {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "descriptor_buffer",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.descriptor_buffer_capture_replay {
+ if !supported.descriptor_buffer_capture_replay {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "descriptor_buffer_capture_replay",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.descriptor_buffer_image_layout_ignored {
+ if !supported.descriptor_buffer_image_layout_ignored {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "descriptor_buffer_image_layout_ignored",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.descriptor_buffer_push_descriptors {
+ if !supported.descriptor_buffer_push_descriptors {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "descriptor_buffer_push_descriptors",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.descriptor_indexing {
+ if !supported.descriptor_indexing {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "descriptor_indexing",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ if extensions.ext_descriptor_indexing && api_version >= crate::Version::V1_2 {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "descriptor_indexing",
+ restriction: crate::device::FeatureRestriction::RequiredByExtension(
+ "ext_descriptor_indexing",
+ ),
+ });
+ }
+ }
+ if self.descriptor_set_host_mapping {
+ if !supported.descriptor_set_host_mapping {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "descriptor_set_host_mapping",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.device_coherent_memory {
+ if !supported.device_coherent_memory {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "device_coherent_memory",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.device_fault {
+ if !supported.device_fault {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "device_fault",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.device_fault_vendor_binary {
+ if !supported.device_fault_vendor_binary {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "device_fault_vendor_binary",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.device_generated_commands {
+ if !supported.device_generated_commands {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "device_generated_commands",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.device_memory_report {
+ if !supported.device_memory_report {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "device_memory_report",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.diagnostics_config {
+ if !supported.diagnostics_config {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "diagnostics_config",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.draw_indirect_count {
+ if !supported.draw_indirect_count {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "draw_indirect_count",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ if extensions.khr_draw_indirect_count && api_version >= crate::Version::V1_2 {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "draw_indirect_count",
+ restriction: crate::device::FeatureRestriction::RequiredByExtension(
+ "khr_draw_indirect_count",
+ ),
+ });
+ }
+ }
+ if self.draw_indirect_first_instance {
+ if !supported.draw_indirect_first_instance {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "draw_indirect_first_instance",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.dual_src_blend {
+ if !supported.dual_src_blend {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "dual_src_blend",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.dynamic_rendering {
+ if !supported.dynamic_rendering {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "dynamic_rendering",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.events {
+ if !supported.events {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "events",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.exclusive_scissor {
+ if !supported.exclusive_scissor {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "exclusive_scissor",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state {
+ if !supported.extended_dynamic_state {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state2 {
+ if !supported.extended_dynamic_state2 {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state2",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state2_logic_op {
+ if !supported.extended_dynamic_state2_logic_op {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state2_logic_op",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state2_patch_control_points {
+ if !supported.extended_dynamic_state2_patch_control_points {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state2_patch_control_points",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state3_alpha_to_coverage_enable {
+ if !supported.extended_dynamic_state3_alpha_to_coverage_enable {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state3_alpha_to_coverage_enable",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state3_alpha_to_one_enable {
+ if !supported.extended_dynamic_state3_alpha_to_one_enable {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state3_alpha_to_one_enable",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state3_color_blend_advanced {
+ if !supported.extended_dynamic_state3_color_blend_advanced {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state3_color_blend_advanced",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state3_color_blend_enable {
+ if !supported.extended_dynamic_state3_color_blend_enable {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state3_color_blend_enable",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state3_color_blend_equation {
+ if !supported.extended_dynamic_state3_color_blend_equation {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state3_color_blend_equation",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state3_color_write_mask {
+ if !supported.extended_dynamic_state3_color_write_mask {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state3_color_write_mask",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state3_conservative_rasterization_mode {
+ if !supported.extended_dynamic_state3_conservative_rasterization_mode {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state3_conservative_rasterization_mode",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state3_coverage_modulation_mode {
+ if !supported.extended_dynamic_state3_coverage_modulation_mode {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state3_coverage_modulation_mode",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state3_coverage_modulation_table {
+ if !supported.extended_dynamic_state3_coverage_modulation_table {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state3_coverage_modulation_table",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state3_coverage_modulation_table_enable {
+ if !supported.extended_dynamic_state3_coverage_modulation_table_enable {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state3_coverage_modulation_table_enable",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state3_coverage_reduction_mode {
+ if !supported.extended_dynamic_state3_coverage_reduction_mode {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state3_coverage_reduction_mode",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state3_coverage_to_color_enable {
+ if !supported.extended_dynamic_state3_coverage_to_color_enable {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state3_coverage_to_color_enable",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state3_coverage_to_color_location {
+ if !supported.extended_dynamic_state3_coverage_to_color_location {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state3_coverage_to_color_location",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state3_depth_clamp_enable {
+ if !supported.extended_dynamic_state3_depth_clamp_enable {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state3_depth_clamp_enable",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state3_depth_clip_enable {
+ if !supported.extended_dynamic_state3_depth_clip_enable {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state3_depth_clip_enable",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state3_depth_clip_negative_one_to_one {
+ if !supported.extended_dynamic_state3_depth_clip_negative_one_to_one {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state3_depth_clip_negative_one_to_one",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state3_extra_primitive_overestimation_size {
+ if !supported.extended_dynamic_state3_extra_primitive_overestimation_size {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state3_extra_primitive_overestimation_size",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state3_line_rasterization_mode {
+ if !supported.extended_dynamic_state3_line_rasterization_mode {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state3_line_rasterization_mode",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state3_line_stipple_enable {
+ if !supported.extended_dynamic_state3_line_stipple_enable {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state3_line_stipple_enable",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state3_logic_op_enable {
+ if !supported.extended_dynamic_state3_logic_op_enable {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state3_logic_op_enable",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state3_polygon_mode {
+ if !supported.extended_dynamic_state3_polygon_mode {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state3_polygon_mode",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state3_provoking_vertex_mode {
+ if !supported.extended_dynamic_state3_provoking_vertex_mode {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state3_provoking_vertex_mode",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state3_rasterization_samples {
+ if !supported.extended_dynamic_state3_rasterization_samples {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state3_rasterization_samples",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state3_rasterization_stream {
+ if !supported.extended_dynamic_state3_rasterization_stream {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state3_rasterization_stream",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state3_representative_fragment_test_enable {
+ if !supported.extended_dynamic_state3_representative_fragment_test_enable {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state3_representative_fragment_test_enable",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state3_sample_locations_enable {
+ if !supported.extended_dynamic_state3_sample_locations_enable {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state3_sample_locations_enable",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state3_sample_mask {
+ if !supported.extended_dynamic_state3_sample_mask {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state3_sample_mask",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state3_shading_rate_image_enable {
+ if !supported.extended_dynamic_state3_shading_rate_image_enable {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state3_shading_rate_image_enable",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state3_tessellation_domain_origin {
+ if !supported.extended_dynamic_state3_tessellation_domain_origin {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state3_tessellation_domain_origin",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state3_viewport_swizzle {
+ if !supported.extended_dynamic_state3_viewport_swizzle {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state3_viewport_swizzle",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.extended_dynamic_state3_viewport_w_scaling_enable {
+ if !supported.extended_dynamic_state3_viewport_w_scaling_enable {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "extended_dynamic_state3_viewport_w_scaling_enable",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.external_memory_rdma {
+ if !supported.external_memory_rdma {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "external_memory_rdma",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.fill_mode_non_solid {
+ if !supported.fill_mode_non_solid {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "fill_mode_non_solid",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.format_a4b4g4r4 {
+ if !supported.format_a4b4g4r4 {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "format_a4b4g4r4",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.format_a4r4g4b4 {
+ if !supported.format_a4r4g4b4 {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "format_a4r4g4b4",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.format_rgba10x6_without_y_cb_cr_sampler {
+ if !supported.format_rgba10x6_without_y_cb_cr_sampler {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "format_rgba10x6_without_y_cb_cr_sampler",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.fragment_density_map {
+ if !supported.fragment_density_map {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "fragment_density_map",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ if self.pipeline_fragment_shading_rate {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "fragment_density_map",
+ restriction: crate::device::FeatureRestriction::ConflictsFeature(
+ "pipeline_fragment_shading_rate",
+ ),
+ });
+ }
+ if self.primitive_fragment_shading_rate {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "fragment_density_map",
+ restriction: crate::device::FeatureRestriction::ConflictsFeature(
+ "primitive_fragment_shading_rate",
+ ),
+ });
+ }
+ if self.attachment_fragment_shading_rate {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "fragment_density_map",
+ restriction: crate::device::FeatureRestriction::ConflictsFeature(
+ "attachment_fragment_shading_rate",
+ ),
+ });
+ }
+ } else {
+ }
+ if self.fragment_density_map_deferred {
+ if !supported.fragment_density_map_deferred {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "fragment_density_map_deferred",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.fragment_density_map_dynamic {
+ if !supported.fragment_density_map_dynamic {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "fragment_density_map_dynamic",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.fragment_density_map_non_subsampled_images {
+ if !supported.fragment_density_map_non_subsampled_images {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "fragment_density_map_non_subsampled_images",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.fragment_density_map_offset {
+ if !supported.fragment_density_map_offset {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "fragment_density_map_offset",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.fragment_shader_barycentric {
+ if !supported.fragment_shader_barycentric {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "fragment_shader_barycentric",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.fragment_shader_pixel_interlock {
+ if !supported.fragment_shader_pixel_interlock {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "fragment_shader_pixel_interlock",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.fragment_shader_sample_interlock {
+ if !supported.fragment_shader_sample_interlock {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "fragment_shader_sample_interlock",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.fragment_shader_shading_rate_interlock {
+ if !supported.fragment_shader_shading_rate_interlock {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "fragment_shader_shading_rate_interlock",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.fragment_shading_rate_enums {
+ if !supported.fragment_shading_rate_enums {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "fragment_shading_rate_enums",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.fragment_stores_and_atomics {
+ if !supported.fragment_stores_and_atomics {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "fragment_stores_and_atomics",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.full_draw_index_uint32 {
+ if !supported.full_draw_index_uint32 {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "full_draw_index_uint32",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.geometry_shader {
+ if !supported.geometry_shader {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "geometry_shader",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.geometry_streams {
+ if !supported.geometry_streams {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "geometry_streams",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.global_priority_query {
+ if !supported.global_priority_query {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "global_priority_query",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.graphics_pipeline_library {
+ if !supported.graphics_pipeline_library {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "graphics_pipeline_library",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.host_query_reset {
+ if !supported.host_query_reset {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "host_query_reset",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.image2_d_view_of3_d {
+ if !supported.image2_d_view_of3_d {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "image2_d_view_of3_d",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.image_compression_control {
+ if !supported.image_compression_control {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "image_compression_control",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.image_compression_control_swapchain {
+ if !supported.image_compression_control_swapchain {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "image_compression_control_swapchain",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.image_cube_array {
+ if !supported.image_cube_array {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "image_cube_array",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.image_footprint {
+ if !supported.image_footprint {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "image_footprint",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.image_view2_d_on3_d_image {
+ if !supported.image_view2_d_on3_d_image {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "image_view2_d_on3_d_image",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.image_view_format_reinterpretation {
+ if !supported.image_view_format_reinterpretation {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "image_view_format_reinterpretation",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.image_view_format_swizzle {
+ if !supported.image_view_format_swizzle {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "image_view_format_swizzle",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.imageless_framebuffer {
+ if !supported.imageless_framebuffer {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "imageless_framebuffer",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.independent_blend {
+ if !supported.independent_blend {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "independent_blend",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.index_type_uint8 {
+ if !supported.index_type_uint8 {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "index_type_uint8",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.indirect_copy {
+ if !supported.indirect_copy {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "indirect_copy",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.inherited_conditional_rendering {
+ if !supported.inherited_conditional_rendering {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "inherited_conditional_rendering",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.inherited_queries {
+ if !supported.inherited_queries {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "inherited_queries",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.inherited_viewport_scissor2_d {
+ if !supported.inherited_viewport_scissor2_d {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "inherited_viewport_scissor2_d",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.inline_uniform_block {
+ if !supported.inline_uniform_block {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "inline_uniform_block",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.invocation_mask {
+ if !supported.invocation_mask {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "invocation_mask",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.large_points {
+ if !supported.large_points {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "large_points",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.legacy_dithering {
+ if !supported.legacy_dithering {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "legacy_dithering",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.linear_color_attachment {
+ if !supported.linear_color_attachment {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "linear_color_attachment",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.logic_op {
+ if !supported.logic_op {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "logic_op",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.maintenance4 {
+ if !supported.maintenance4 {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "maintenance4",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.memory_decompression {
+ if !supported.memory_decompression {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "memory_decompression",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.memory_priority {
+ if !supported.memory_priority {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "memory_priority",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.mesh_shader {
+ if !supported.mesh_shader {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "mesh_shader",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.mesh_shader_queries {
+ if !supported.mesh_shader_queries {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "mesh_shader_queries",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.micromap {
+ if !supported.micromap {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "micromap",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.micromap_capture_replay {
+ if !supported.micromap_capture_replay {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "micromap_capture_replay",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.micromap_host_commands {
+ if !supported.micromap_host_commands {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "micromap_host_commands",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.min_lod {
+ if !supported.min_lod {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "min_lod",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.multi_draw {
+ if !supported.multi_draw {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "multi_draw",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.multi_draw_indirect {
+ if !supported.multi_draw_indirect {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "multi_draw_indirect",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.multi_viewport {
+ if !supported.multi_viewport {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "multi_viewport",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.multisample_array_image {
+ if !supported.multisample_array_image {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "multisample_array_image",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.multisampled_render_to_single_sampled {
+ if !supported.multisampled_render_to_single_sampled {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "multisampled_render_to_single_sampled",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.multiview {
+ if !supported.multiview {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "multiview",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.multiview_geometry_shader {
+ if !supported.multiview_geometry_shader {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "multiview_geometry_shader",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.multiview_mesh_shader {
+ if !supported.multiview_mesh_shader {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "multiview_mesh_shader",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.multiview_per_view_viewports {
+ if !supported.multiview_per_view_viewports {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "multiview_per_view_viewports",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.multiview_tessellation_shader {
+ if !supported.multiview_tessellation_shader {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "multiview_tessellation_shader",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.mutable_comparison_samplers {
+ if !supported.mutable_comparison_samplers {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "mutable_comparison_samplers",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.mutable_descriptor_type {
+ if !supported.mutable_descriptor_type {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "mutable_descriptor_type",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.no_invocation_fragment_shading_rates {
+ if !supported.no_invocation_fragment_shading_rates {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "no_invocation_fragment_shading_rates",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.non_seamless_cube_map {
+ if !supported.non_seamless_cube_map {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "non_seamless_cube_map",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.null_descriptor {
+ if !supported.null_descriptor {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "null_descriptor",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.occlusion_query_precise {
+ if !supported.occlusion_query_precise {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "occlusion_query_precise",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.optical_flow {
+ if !supported.optical_flow {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "optical_flow",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.pageable_device_local_memory {
+ if !supported.pageable_device_local_memory {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "pageable_device_local_memory",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.performance_counter_multiple_query_pools {
+ if !supported.performance_counter_multiple_query_pools {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "performance_counter_multiple_query_pools",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.performance_counter_query_pools {
+ if !supported.performance_counter_query_pools {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "performance_counter_query_pools",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.pipeline_creation_cache_control {
+ if !supported.pipeline_creation_cache_control {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "pipeline_creation_cache_control",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.pipeline_executable_info {
+ if !supported.pipeline_executable_info {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "pipeline_executable_info",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.pipeline_fragment_shading_rate {
+ if !supported.pipeline_fragment_shading_rate {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "pipeline_fragment_shading_rate",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ if self.shading_rate_image {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "pipeline_fragment_shading_rate",
+ restriction: crate::device::FeatureRestriction::ConflictsFeature(
+ "shading_rate_image",
+ ),
+ });
+ }
+ if self.fragment_density_map {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "pipeline_fragment_shading_rate",
+ restriction: crate::device::FeatureRestriction::ConflictsFeature(
+ "fragment_density_map",
+ ),
+ });
+ }
+ } else {
+ }
+ if self.pipeline_properties_identifier {
+ if !supported.pipeline_properties_identifier {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "pipeline_properties_identifier",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.pipeline_protected_access {
+ if !supported.pipeline_protected_access {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "pipeline_protected_access",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.pipeline_robustness {
+ if !supported.pipeline_robustness {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "pipeline_robustness",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.pipeline_statistics_query {
+ if !supported.pipeline_statistics_query {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "pipeline_statistics_query",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.point_polygons {
+ if !supported.point_polygons {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "point_polygons",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.present_barrier {
+ if !supported.present_barrier {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "present_barrier",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.present_id {
+ if !supported.present_id {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "present_id",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.present_wait {
+ if !supported.present_wait {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "present_wait",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.primitive_fragment_shading_rate {
+ if !supported.primitive_fragment_shading_rate {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "primitive_fragment_shading_rate",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ if self.shading_rate_image {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "primitive_fragment_shading_rate",
+ restriction: crate::device::FeatureRestriction::ConflictsFeature(
+ "shading_rate_image",
+ ),
+ });
+ }
+ if self.fragment_density_map {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "primitive_fragment_shading_rate",
+ restriction: crate::device::FeatureRestriction::ConflictsFeature(
+ "fragment_density_map",
+ ),
+ });
+ }
+ } else {
+ }
+ if self.primitive_fragment_shading_rate_mesh_shader {
+ if !supported.primitive_fragment_shading_rate_mesh_shader {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "primitive_fragment_shading_rate_mesh_shader",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.primitive_topology_list_restart {
+ if !supported.primitive_topology_list_restart {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "primitive_topology_list_restart",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.primitive_topology_patch_list_restart {
+ if !supported.primitive_topology_patch_list_restart {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "primitive_topology_patch_list_restart",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.primitives_generated_query {
+ if !supported.primitives_generated_query {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "primitives_generated_query",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.primitives_generated_query_with_non_zero_streams {
+ if !supported.primitives_generated_query_with_non_zero_streams {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "primitives_generated_query_with_non_zero_streams",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.primitives_generated_query_with_rasterizer_discard {
+ if !supported.primitives_generated_query_with_rasterizer_discard {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "primitives_generated_query_with_rasterizer_discard",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.private_data {
+ if !supported.private_data {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "private_data",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.protected_memory {
+ if !supported.protected_memory {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "protected_memory",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.provoking_vertex_last {
+ if !supported.provoking_vertex_last {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "provoking_vertex_last",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.rasterization_order_color_attachment_access {
+ if !supported.rasterization_order_color_attachment_access {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "rasterization_order_color_attachment_access",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.rasterization_order_depth_attachment_access {
+ if !supported.rasterization_order_depth_attachment_access {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "rasterization_order_depth_attachment_access",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.rasterization_order_stencil_attachment_access {
+ if !supported.rasterization_order_stencil_attachment_access {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "rasterization_order_stencil_attachment_access",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ray_query {
+ if !supported.ray_query {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "ray_query",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ray_tracing_invocation_reorder {
+ if !supported.ray_tracing_invocation_reorder {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "ray_tracing_invocation_reorder",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ray_tracing_maintenance1 {
+ if !supported.ray_tracing_maintenance1 {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "ray_tracing_maintenance1",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ray_tracing_motion_blur {
+ if !supported.ray_tracing_motion_blur {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "ray_tracing_motion_blur",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ray_tracing_motion_blur_pipeline_trace_rays_indirect {
+ if !supported.ray_tracing_motion_blur_pipeline_trace_rays_indirect {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "ray_tracing_motion_blur_pipeline_trace_rays_indirect",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ray_tracing_pipeline {
+ if !supported.ray_tracing_pipeline {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "ray_tracing_pipeline",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ray_tracing_pipeline_shader_group_handle_capture_replay {
+ if !supported.ray_tracing_pipeline_shader_group_handle_capture_replay {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "ray_tracing_pipeline_shader_group_handle_capture_replay",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ray_tracing_pipeline_shader_group_handle_capture_replay_mixed {
+ if !supported.ray_tracing_pipeline_shader_group_handle_capture_replay_mixed {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "ray_tracing_pipeline_shader_group_handle_capture_replay_mixed",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ray_tracing_pipeline_trace_rays_indirect {
+ if !supported.ray_tracing_pipeline_trace_rays_indirect {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "ray_tracing_pipeline_trace_rays_indirect",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ray_tracing_pipeline_trace_rays_indirect2 {
+ if !supported.ray_tracing_pipeline_trace_rays_indirect2 {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "ray_tracing_pipeline_trace_rays_indirect2",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ray_traversal_primitive_culling {
+ if !supported.ray_traversal_primitive_culling {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "ray_traversal_primitive_culling",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.rectangular_lines {
+ if !supported.rectangular_lines {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "rectangular_lines",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.report_address_binding {
+ if !supported.report_address_binding {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "report_address_binding",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.representative_fragment_test {
+ if !supported.representative_fragment_test {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "representative_fragment_test",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.robust_buffer_access {
+ if !supported.robust_buffer_access {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "robust_buffer_access",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.robust_buffer_access2 {
+ if !supported.robust_buffer_access2 {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "robust_buffer_access2",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.robust_image_access {
+ if !supported.robust_image_access {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "robust_image_access",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.robust_image_access2 {
+ if !supported.robust_image_access2 {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "robust_image_access2",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.runtime_descriptor_array {
+ if !supported.runtime_descriptor_array {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "runtime_descriptor_array",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.sample_rate_shading {
+ if !supported.sample_rate_shading {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "sample_rate_shading",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.sampler2_d_view_of3_d {
+ if !supported.sampler2_d_view_of3_d {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "sampler2_d_view_of3_d",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.sampler_anisotropy {
+ if !supported.sampler_anisotropy {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "sampler_anisotropy",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.sampler_filter_minmax {
+ if !supported.sampler_filter_minmax {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "sampler_filter_minmax",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ if extensions.ext_sampler_filter_minmax && api_version >= crate::Version::V1_2 {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "sampler_filter_minmax",
+ restriction: crate::device::FeatureRestriction::RequiredByExtension(
+ "ext_sampler_filter_minmax",
+ ),
+ });
+ }
+ }
+ if self.sampler_mip_lod_bias {
+ if !supported.sampler_mip_lod_bias {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "sampler_mip_lod_bias",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.sampler_mirror_clamp_to_edge {
+ if !supported.sampler_mirror_clamp_to_edge {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "sampler_mirror_clamp_to_edge",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ if extensions.khr_sampler_mirror_clamp_to_edge && api_version >= crate::Version::V1_2 {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "sampler_mirror_clamp_to_edge",
+ restriction: crate::device::FeatureRestriction::RequiredByExtension(
+ "khr_sampler_mirror_clamp_to_edge",
+ ),
+ });
+ }
+ }
+ if self.sampler_ycbcr_conversion {
+ if !supported.sampler_ycbcr_conversion {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "sampler_ycbcr_conversion",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.scalar_block_layout {
+ if !supported.scalar_block_layout {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "scalar_block_layout",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.separate_depth_stencil_layouts {
+ if !supported.separate_depth_stencil_layouts {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "separate_depth_stencil_layouts",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.separate_stencil_mask_ref {
+ if !supported.separate_stencil_mask_ref {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "separate_stencil_mask_ref",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_buffer_float16_atomic_add {
+ if !supported.shader_buffer_float16_atomic_add {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_buffer_float16_atomic_add",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_buffer_float16_atomic_min_max {
+ if !supported.shader_buffer_float16_atomic_min_max {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_buffer_float16_atomic_min_max",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_buffer_float16_atomics {
+ if !supported.shader_buffer_float16_atomics {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_buffer_float16_atomics",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_buffer_float32_atomic_add {
+ if !supported.shader_buffer_float32_atomic_add {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_buffer_float32_atomic_add",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_buffer_float32_atomic_min_max {
+ if !supported.shader_buffer_float32_atomic_min_max {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_buffer_float32_atomic_min_max",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_buffer_float32_atomics {
+ if !supported.shader_buffer_float32_atomics {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_buffer_float32_atomics",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_buffer_float64_atomic_add {
+ if !supported.shader_buffer_float64_atomic_add {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_buffer_float64_atomic_add",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_buffer_float64_atomic_min_max {
+ if !supported.shader_buffer_float64_atomic_min_max {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_buffer_float64_atomic_min_max",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_buffer_float64_atomics {
+ if !supported.shader_buffer_float64_atomics {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_buffer_float64_atomics",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_buffer_int64_atomics {
+ if !supported.shader_buffer_int64_atomics {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_buffer_int64_atomics",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_clip_distance {
+ if !supported.shader_clip_distance {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_clip_distance",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_core_builtins {
+ if !supported.shader_core_builtins {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_core_builtins",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_cull_distance {
+ if !supported.shader_cull_distance {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_cull_distance",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_demote_to_helper_invocation {
+ if !supported.shader_demote_to_helper_invocation {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_demote_to_helper_invocation",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_device_clock {
+ if !supported.shader_device_clock {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_device_clock",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_draw_parameters {
+ if !supported.shader_draw_parameters {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_draw_parameters",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ if extensions.khr_shader_draw_parameters && api_version >= crate::Version::V1_2 {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_draw_parameters",
+ restriction: crate::device::FeatureRestriction::RequiredByExtension(
+ "khr_shader_draw_parameters",
+ ),
+ });
+ }
+ }
+ if self.shader_early_and_late_fragment_tests {
+ if !supported.shader_early_and_late_fragment_tests {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_early_and_late_fragment_tests",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_float16 {
+ if !supported.shader_float16 {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_float16",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_float64 {
+ if !supported.shader_float64 {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_float64",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_image_float32_atomic_add {
+ if !supported.shader_image_float32_atomic_add {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_image_float32_atomic_add",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_image_float32_atomic_min_max {
+ if !supported.shader_image_float32_atomic_min_max {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_image_float32_atomic_min_max",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_image_float32_atomics {
+ if !supported.shader_image_float32_atomics {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_image_float32_atomics",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_image_gather_extended {
+ if !supported.shader_image_gather_extended {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_image_gather_extended",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_image_int64_atomics {
+ if !supported.shader_image_int64_atomics {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_image_int64_atomics",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_input_attachment_array_dynamic_indexing {
+ if !supported.shader_input_attachment_array_dynamic_indexing {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_input_attachment_array_dynamic_indexing",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_input_attachment_array_non_uniform_indexing {
+ if !supported.shader_input_attachment_array_non_uniform_indexing {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_input_attachment_array_non_uniform_indexing",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_int16 {
+ if !supported.shader_int16 {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_int16",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_int64 {
+ if !supported.shader_int64 {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_int64",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_int8 {
+ if !supported.shader_int8 {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_int8",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_integer_dot_product {
+ if !supported.shader_integer_dot_product {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_integer_dot_product",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_integer_functions2 {
+ if !supported.shader_integer_functions2 {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_integer_functions2",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_module_identifier {
+ if !supported.shader_module_identifier {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_module_identifier",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_output_layer {
+ if !supported.shader_output_layer {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_output_layer",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ if extensions.ext_shader_viewport_index_layer && api_version >= crate::Version::V1_2 {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_output_layer",
+ restriction: crate::device::FeatureRestriction::RequiredByExtension(
+ "ext_shader_viewport_index_layer",
+ ),
+ });
+ }
+ }
+ if self.shader_output_viewport_index {
+ if !supported.shader_output_viewport_index {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_output_viewport_index",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ if extensions.ext_shader_viewport_index_layer && api_version >= crate::Version::V1_2 {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_output_viewport_index",
+ restriction: crate::device::FeatureRestriction::RequiredByExtension(
+ "ext_shader_viewport_index_layer",
+ ),
+ });
+ }
+ }
+ if self.shader_resource_min_lod {
+ if !supported.shader_resource_min_lod {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_resource_min_lod",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_resource_residency {
+ if !supported.shader_resource_residency {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_resource_residency",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_sample_rate_interpolation_functions {
+ if !supported.shader_sample_rate_interpolation_functions {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_sample_rate_interpolation_functions",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_sampled_image_array_dynamic_indexing {
+ if !supported.shader_sampled_image_array_dynamic_indexing {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_sampled_image_array_dynamic_indexing",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_sampled_image_array_non_uniform_indexing {
+ if !supported.shader_sampled_image_array_non_uniform_indexing {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_sampled_image_array_non_uniform_indexing",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_shared_float16_atomic_add {
+ if !supported.shader_shared_float16_atomic_add {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_shared_float16_atomic_add",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_shared_float16_atomic_min_max {
+ if !supported.shader_shared_float16_atomic_min_max {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_shared_float16_atomic_min_max",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_shared_float16_atomics {
+ if !supported.shader_shared_float16_atomics {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_shared_float16_atomics",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_shared_float32_atomic_add {
+ if !supported.shader_shared_float32_atomic_add {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_shared_float32_atomic_add",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_shared_float32_atomic_min_max {
+ if !supported.shader_shared_float32_atomic_min_max {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_shared_float32_atomic_min_max",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_shared_float32_atomics {
+ if !supported.shader_shared_float32_atomics {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_shared_float32_atomics",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_shared_float64_atomic_add {
+ if !supported.shader_shared_float64_atomic_add {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_shared_float64_atomic_add",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_shared_float64_atomic_min_max {
+ if !supported.shader_shared_float64_atomic_min_max {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_shared_float64_atomic_min_max",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_shared_float64_atomics {
+ if !supported.shader_shared_float64_atomics {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_shared_float64_atomics",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_shared_int64_atomics {
+ if !supported.shader_shared_int64_atomics {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_shared_int64_atomics",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_sm_builtins {
+ if !supported.shader_sm_builtins {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_sm_builtins",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_storage_buffer_array_dynamic_indexing {
+ if !supported.shader_storage_buffer_array_dynamic_indexing {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_storage_buffer_array_dynamic_indexing",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_storage_buffer_array_non_uniform_indexing {
+ if !supported.shader_storage_buffer_array_non_uniform_indexing {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_storage_buffer_array_non_uniform_indexing",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_storage_image_array_dynamic_indexing {
+ if !supported.shader_storage_image_array_dynamic_indexing {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_storage_image_array_dynamic_indexing",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_storage_image_array_non_uniform_indexing {
+ if !supported.shader_storage_image_array_non_uniform_indexing {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_storage_image_array_non_uniform_indexing",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_storage_image_extended_formats {
+ if !supported.shader_storage_image_extended_formats {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_storage_image_extended_formats",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_storage_image_multisample {
+ if !supported.shader_storage_image_multisample {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_storage_image_multisample",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_storage_image_read_without_format {
+ if !supported.shader_storage_image_read_without_format {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_storage_image_read_without_format",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_storage_image_write_without_format {
+ if !supported.shader_storage_image_write_without_format {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_storage_image_write_without_format",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_storage_texel_buffer_array_dynamic_indexing {
+ if !supported.shader_storage_texel_buffer_array_dynamic_indexing {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_storage_texel_buffer_array_dynamic_indexing",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_storage_texel_buffer_array_non_uniform_indexing {
+ if !supported.shader_storage_texel_buffer_array_non_uniform_indexing {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_storage_texel_buffer_array_non_uniform_indexing",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_subgroup_clock {
+ if !supported.shader_subgroup_clock {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_subgroup_clock",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_subgroup_extended_types {
+ if !supported.shader_subgroup_extended_types {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_subgroup_extended_types",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_subgroup_uniform_control_flow {
+ if !supported.shader_subgroup_uniform_control_flow {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_subgroup_uniform_control_flow",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_terminate_invocation {
+ if !supported.shader_terminate_invocation {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_terminate_invocation",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_tessellation_and_geometry_point_size {
+ if !supported.shader_tessellation_and_geometry_point_size {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_tessellation_and_geometry_point_size",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_uniform_buffer_array_dynamic_indexing {
+ if !supported.shader_uniform_buffer_array_dynamic_indexing {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_uniform_buffer_array_dynamic_indexing",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_uniform_buffer_array_non_uniform_indexing {
+ if !supported.shader_uniform_buffer_array_non_uniform_indexing {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_uniform_buffer_array_non_uniform_indexing",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_uniform_texel_buffer_array_dynamic_indexing {
+ if !supported.shader_uniform_texel_buffer_array_dynamic_indexing {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_uniform_texel_buffer_array_dynamic_indexing",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_uniform_texel_buffer_array_non_uniform_indexing {
+ if !supported.shader_uniform_texel_buffer_array_non_uniform_indexing {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_uniform_texel_buffer_array_non_uniform_indexing",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shader_zero_initialize_workgroup_memory {
+ if !supported.shader_zero_initialize_workgroup_memory {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shader_zero_initialize_workgroup_memory",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shading_rate_coarse_sample_order {
+ if !supported.shading_rate_coarse_sample_order {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shading_rate_coarse_sample_order",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.shading_rate_image {
+ if !supported.shading_rate_image {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shading_rate_image",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ if self.pipeline_fragment_shading_rate {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shading_rate_image",
+ restriction: crate::device::FeatureRestriction::ConflictsFeature(
+ "pipeline_fragment_shading_rate",
+ ),
+ });
+ }
+ if self.primitive_fragment_shading_rate {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shading_rate_image",
+ restriction: crate::device::FeatureRestriction::ConflictsFeature(
+ "primitive_fragment_shading_rate",
+ ),
+ });
+ }
+ if self.attachment_fragment_shading_rate {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "shading_rate_image",
+ restriction: crate::device::FeatureRestriction::ConflictsFeature(
+ "attachment_fragment_shading_rate",
+ ),
+ });
+ }
+ } else {
+ }
+ if self.smooth_lines {
+ if !supported.smooth_lines {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "smooth_lines",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.sparse_binding {
+ if !supported.sparse_binding {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "sparse_binding",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.sparse_image_float32_atomic_add {
+ if !supported.sparse_image_float32_atomic_add {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "sparse_image_float32_atomic_add",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ if !self.shader_image_float32_atomic_add {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "sparse_image_float32_atomic_add",
+ restriction: crate::device::FeatureRestriction::RequiresFeature(
+ "shader_image_float32_atomic_add",
+ ),
+ });
+ }
+ } else {
+ }
+ if self.sparse_image_float32_atomic_min_max {
+ if !supported.sparse_image_float32_atomic_min_max {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "sparse_image_float32_atomic_min_max",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ if !self.shader_image_float32_atomic_min_max {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "sparse_image_float32_atomic_min_max",
+ restriction: crate::device::FeatureRestriction::RequiresFeature(
+ "shader_image_float32_atomic_min_max",
+ ),
+ });
+ }
+ } else {
+ }
+ if self.sparse_image_float32_atomics {
+ if !supported.sparse_image_float32_atomics {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "sparse_image_float32_atomics",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ if !self.shader_image_float32_atomics {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "sparse_image_float32_atomics",
+ restriction: crate::device::FeatureRestriction::RequiresFeature(
+ "shader_image_float32_atomics",
+ ),
+ });
+ }
+ } else {
+ }
+ if self.sparse_image_int64_atomics {
+ if !supported.sparse_image_int64_atomics {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "sparse_image_int64_atomics",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ if !self.shader_image_int64_atomics {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "sparse_image_int64_atomics",
+ restriction: crate::device::FeatureRestriction::RequiresFeature(
+ "shader_image_int64_atomics",
+ ),
+ });
+ }
+ } else {
+ }
+ if self.sparse_residency16_samples {
+ if !supported.sparse_residency16_samples {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "sparse_residency16_samples",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.sparse_residency2_samples {
+ if !supported.sparse_residency2_samples {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "sparse_residency2_samples",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.sparse_residency4_samples {
+ if !supported.sparse_residency4_samples {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "sparse_residency4_samples",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.sparse_residency8_samples {
+ if !supported.sparse_residency8_samples {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "sparse_residency8_samples",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.sparse_residency_aliased {
+ if !supported.sparse_residency_aliased {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "sparse_residency_aliased",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.sparse_residency_buffer {
+ if !supported.sparse_residency_buffer {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "sparse_residency_buffer",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.sparse_residency_image2_d {
+ if !supported.sparse_residency_image2_d {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "sparse_residency_image2_d",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.sparse_residency_image3_d {
+ if !supported.sparse_residency_image3_d {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "sparse_residency_image3_d",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.stippled_bresenham_lines {
+ if !supported.stippled_bresenham_lines {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "stippled_bresenham_lines",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.stippled_rectangular_lines {
+ if !supported.stippled_rectangular_lines {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "stippled_rectangular_lines",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.stippled_smooth_lines {
+ if !supported.stippled_smooth_lines {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "stippled_smooth_lines",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.storage_buffer16_bit_access {
+ if !supported.storage_buffer16_bit_access {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "storage_buffer16_bit_access",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.storage_buffer8_bit_access {
+ if !supported.storage_buffer8_bit_access {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "storage_buffer8_bit_access",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.storage_input_output16 {
+ if !supported.storage_input_output16 {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "storage_input_output16",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.storage_push_constant16 {
+ if !supported.storage_push_constant16 {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "storage_push_constant16",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.storage_push_constant8 {
+ if !supported.storage_push_constant8 {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "storage_push_constant8",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.subgroup_broadcast_dynamic_id {
+ if !supported.subgroup_broadcast_dynamic_id {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "subgroup_broadcast_dynamic_id",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.subgroup_size_control {
+ if !supported.subgroup_size_control {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "subgroup_size_control",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.subpass_merge_feedback {
+ if !supported.subpass_merge_feedback {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "subpass_merge_feedback",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.subpass_shading {
+ if !supported.subpass_shading {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "subpass_shading",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.supersample_fragment_shading_rates {
+ if !supported.supersample_fragment_shading_rates {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "supersample_fragment_shading_rates",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.swapchain_maintenance1 {
+ if !supported.swapchain_maintenance1 {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "swapchain_maintenance1",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.synchronization2 {
+ if !supported.synchronization2 {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "synchronization2",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.task_shader {
+ if !supported.task_shader {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "task_shader",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.tessellation_isolines {
+ if !supported.tessellation_isolines {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "tessellation_isolines",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.tessellation_point_mode {
+ if !supported.tessellation_point_mode {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "tessellation_point_mode",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.tessellation_shader {
+ if !supported.tessellation_shader {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "tessellation_shader",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.texel_buffer_alignment {
+ if !supported.texel_buffer_alignment {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "texel_buffer_alignment",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.texture_block_match {
+ if !supported.texture_block_match {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "texture_block_match",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.texture_box_filter {
+ if !supported.texture_box_filter {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "texture_box_filter",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.texture_compression_astc_hdr {
+ if !supported.texture_compression_astc_hdr {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "texture_compression_astc_hdr",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.texture_compression_astc_ldr {
+ if !supported.texture_compression_astc_ldr {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "texture_compression_astc_ldr",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.texture_compression_bc {
+ if !supported.texture_compression_bc {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "texture_compression_bc",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.texture_compression_etc2 {
+ if !supported.texture_compression_etc2 {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "texture_compression_etc2",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.texture_sample_weighted {
+ if !supported.texture_sample_weighted {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "texture_sample_weighted",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.tile_properties {
+ if !supported.tile_properties {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "tile_properties",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.timeline_semaphore {
+ if !supported.timeline_semaphore {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "timeline_semaphore",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.transform_feedback {
+ if !supported.transform_feedback {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "transform_feedback",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.transform_feedback_preserves_provoking_vertex {
+ if !supported.transform_feedback_preserves_provoking_vertex {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "transform_feedback_preserves_provoking_vertex",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.triangle_fans {
+ if !supported.triangle_fans {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "triangle_fans",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.uniform_and_storage_buffer16_bit_access {
+ if !supported.uniform_and_storage_buffer16_bit_access {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "uniform_and_storage_buffer16_bit_access",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.uniform_and_storage_buffer8_bit_access {
+ if !supported.uniform_and_storage_buffer8_bit_access {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "uniform_and_storage_buffer8_bit_access",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.uniform_buffer_standard_layout {
+ if !supported.uniform_buffer_standard_layout {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "uniform_buffer_standard_layout",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.variable_multisample_rate {
+ if !supported.variable_multisample_rate {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "variable_multisample_rate",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.variable_pointers {
+ if !supported.variable_pointers {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "variable_pointers",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.variable_pointers_storage_buffer {
+ if !supported.variable_pointers_storage_buffer {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "variable_pointers_storage_buffer",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.vertex_attribute_access_beyond_stride {
+ if !supported.vertex_attribute_access_beyond_stride {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "vertex_attribute_access_beyond_stride",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.vertex_attribute_instance_rate_divisor {
+ if !supported.vertex_attribute_instance_rate_divisor {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "vertex_attribute_instance_rate_divisor",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.vertex_attribute_instance_rate_zero_divisor {
+ if !supported.vertex_attribute_instance_rate_zero_divisor {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "vertex_attribute_instance_rate_zero_divisor",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.vertex_input_dynamic_state {
+ if !supported.vertex_input_dynamic_state {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "vertex_input_dynamic_state",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.vertex_pipeline_stores_and_atomics {
+ if !supported.vertex_pipeline_stores_and_atomics {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "vertex_pipeline_stores_and_atomics",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.vulkan_memory_model {
+ if !supported.vulkan_memory_model {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "vulkan_memory_model",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.vulkan_memory_model_availability_visibility_chains {
+ if !supported.vulkan_memory_model_availability_visibility_chains {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "vulkan_memory_model_availability_visibility_chains",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.vulkan_memory_model_device_scope {
+ if !supported.vulkan_memory_model_device_scope {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "vulkan_memory_model_device_scope",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.wide_lines {
+ if !supported.wide_lines {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "wide_lines",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.workgroup_memory_explicit_layout {
+ if !supported.workgroup_memory_explicit_layout {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "workgroup_memory_explicit_layout",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.workgroup_memory_explicit_layout16_bit_access {
+ if !supported.workgroup_memory_explicit_layout16_bit_access {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "workgroup_memory_explicit_layout16_bit_access",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.workgroup_memory_explicit_layout8_bit_access {
+ if !supported.workgroup_memory_explicit_layout8_bit_access {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "workgroup_memory_explicit_layout8_bit_access",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.workgroup_memory_explicit_layout_scalar_block_layout {
+ if !supported.workgroup_memory_explicit_layout_scalar_block_layout {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "workgroup_memory_explicit_layout_scalar_block_layout",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ycbcr2plane444_formats {
+ if !supported.ycbcr2plane444_formats {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "ycbcr2plane444_formats",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ if self.ycbcr_image_arrays {
+ if !supported.ycbcr_image_arrays {
+ return Err(crate::device::FeatureRestrictionError {
+ feature: "ycbcr_image_arrays",
+ restriction: crate::device::FeatureRestriction::NotSupported,
+ });
+ }
+ } else {
+ }
+ Ok(())
+ }
+ #[doc = r" Returns an `Features` object with none of the members set."]
+ #[inline]
+ pub const fn empty() -> Self {
+ Self {
+ acceleration_structure: false,
+ acceleration_structure_capture_replay: false,
+ acceleration_structure_host_commands: false,
+ acceleration_structure_indirect_build: false,
+ advanced_blend_coherent_operations: false,
+ alpha_to_one: false,
+ amigo_profiling: false,
+ attachment_feedback_loop_layout: false,
+ attachment_fragment_shading_rate: false,
+ border_color_swizzle: false,
+ border_color_swizzle_from_image: false,
+ bresenham_lines: false,
+ buffer_device_address: false,
+ buffer_device_address_capture_replay: false,
+ buffer_device_address_multi_device: false,
+ color_write_enable: false,
+ compute_derivative_group_linear: false,
+ compute_derivative_group_quads: false,
+ compute_full_subgroups: false,
+ conditional_rendering: false,
+ constant_alpha_color_blend_factors: false,
+ cooperative_matrix: false,
+ cooperative_matrix_robust_buffer_access: false,
+ corner_sampled_image: false,
+ coverage_reduction_mode: false,
+ custom_border_color_without_format: false,
+ custom_border_colors: false,
+ decode_mode_shared_exponent: false,
+ dedicated_allocation_image_aliasing: false,
+ depth_bias_clamp: false,
+ depth_bounds: false,
+ depth_clamp: false,
+ depth_clamp_zero_one: false,
+ depth_clip_control: false,
+ depth_clip_enable: false,
+ descriptor_binding_acceleration_structure_update_after_bind: false,
+ descriptor_binding_inline_uniform_block_update_after_bind: false,
+ descriptor_binding_partially_bound: false,
+ descriptor_binding_sampled_image_update_after_bind: false,
+ descriptor_binding_storage_buffer_update_after_bind: false,
+ descriptor_binding_storage_image_update_after_bind: false,
+ descriptor_binding_storage_texel_buffer_update_after_bind: false,
+ descriptor_binding_uniform_buffer_update_after_bind: false,
+ descriptor_binding_uniform_texel_buffer_update_after_bind: false,
+ descriptor_binding_update_unused_while_pending: false,
+ descriptor_binding_variable_descriptor_count: false,
+ descriptor_buffer: false,
+ descriptor_buffer_capture_replay: false,
+ descriptor_buffer_image_layout_ignored: false,
+ descriptor_buffer_push_descriptors: false,
+ descriptor_indexing: false,
+ descriptor_set_host_mapping: false,
+ device_coherent_memory: false,
+ device_fault: false,
+ device_fault_vendor_binary: false,
+ device_generated_commands: false,
+ device_memory_report: false,
+ diagnostics_config: false,
+ draw_indirect_count: false,
+ draw_indirect_first_instance: false,
+ dual_src_blend: false,
+ dynamic_rendering: false,
+ events: false,
+ exclusive_scissor: false,
+ extended_dynamic_state: false,
+ extended_dynamic_state2: false,
+ extended_dynamic_state2_logic_op: false,
+ extended_dynamic_state2_patch_control_points: false,
+ extended_dynamic_state3_alpha_to_coverage_enable: false,
+ extended_dynamic_state3_alpha_to_one_enable: false,
+ extended_dynamic_state3_color_blend_advanced: false,
+ extended_dynamic_state3_color_blend_enable: false,
+ extended_dynamic_state3_color_blend_equation: false,
+ extended_dynamic_state3_color_write_mask: false,
+ extended_dynamic_state3_conservative_rasterization_mode: false,
+ extended_dynamic_state3_coverage_modulation_mode: false,
+ extended_dynamic_state3_coverage_modulation_table: false,
+ extended_dynamic_state3_coverage_modulation_table_enable: false,
+ extended_dynamic_state3_coverage_reduction_mode: false,
+ extended_dynamic_state3_coverage_to_color_enable: false,
+ extended_dynamic_state3_coverage_to_color_location: false,
+ extended_dynamic_state3_depth_clamp_enable: false,
+ extended_dynamic_state3_depth_clip_enable: false,
+ extended_dynamic_state3_depth_clip_negative_one_to_one: false,
+ extended_dynamic_state3_extra_primitive_overestimation_size: false,
+ extended_dynamic_state3_line_rasterization_mode: false,
+ extended_dynamic_state3_line_stipple_enable: false,
+ extended_dynamic_state3_logic_op_enable: false,
+ extended_dynamic_state3_polygon_mode: false,
+ extended_dynamic_state3_provoking_vertex_mode: false,
+ extended_dynamic_state3_rasterization_samples: false,
+ extended_dynamic_state3_rasterization_stream: false,
+ extended_dynamic_state3_representative_fragment_test_enable: false,
+ extended_dynamic_state3_sample_locations_enable: false,
+ extended_dynamic_state3_sample_mask: false,
+ extended_dynamic_state3_shading_rate_image_enable: false,
+ extended_dynamic_state3_tessellation_domain_origin: false,
+ extended_dynamic_state3_viewport_swizzle: false,
+ extended_dynamic_state3_viewport_w_scaling_enable: false,
+ external_memory_rdma: false,
+ fill_mode_non_solid: false,
+ format_a4b4g4r4: false,
+ format_a4r4g4b4: false,
+ format_rgba10x6_without_y_cb_cr_sampler: false,
+ fragment_density_map: false,
+ fragment_density_map_deferred: false,
+ fragment_density_map_dynamic: false,
+ fragment_density_map_non_subsampled_images: false,
+ fragment_density_map_offset: false,
+ fragment_shader_barycentric: false,
+ fragment_shader_pixel_interlock: false,
+ fragment_shader_sample_interlock: false,
+ fragment_shader_shading_rate_interlock: false,
+ fragment_shading_rate_enums: false,
+ fragment_stores_and_atomics: false,
+ full_draw_index_uint32: false,
+ geometry_shader: false,
+ geometry_streams: false,
+ global_priority_query: false,
+ graphics_pipeline_library: false,
+ host_query_reset: false,
+ image2_d_view_of3_d: false,
+ image_compression_control: false,
+ image_compression_control_swapchain: false,
+ image_cube_array: false,
+ image_footprint: false,
+ image_view2_d_on3_d_image: false,
+ image_view_format_reinterpretation: false,
+ image_view_format_swizzle: false,
+ imageless_framebuffer: false,
+ independent_blend: false,
+ index_type_uint8: false,
+ indirect_copy: false,
+ inherited_conditional_rendering: false,
+ inherited_queries: false,
+ inherited_viewport_scissor2_d: false,
+ inline_uniform_block: false,
+ invocation_mask: false,
+ large_points: false,
+ legacy_dithering: false,
+ linear_color_attachment: false,
+ logic_op: false,
+ maintenance4: false,
+ memory_decompression: false,
+ memory_priority: false,
+ mesh_shader: false,
+ mesh_shader_queries: false,
+ micromap: false,
+ micromap_capture_replay: false,
+ micromap_host_commands: false,
+ min_lod: false,
+ multi_draw: false,
+ multi_draw_indirect: false,
+ multi_viewport: false,
+ multisample_array_image: false,
+ multisampled_render_to_single_sampled: false,
+ multiview: false,
+ multiview_geometry_shader: false,
+ multiview_mesh_shader: false,
+ multiview_per_view_viewports: false,
+ multiview_tessellation_shader: false,
+ mutable_comparison_samplers: false,
+ mutable_descriptor_type: false,
+ no_invocation_fragment_shading_rates: false,
+ non_seamless_cube_map: false,
+ null_descriptor: false,
+ occlusion_query_precise: false,
+ optical_flow: false,
+ pageable_device_local_memory: false,
+ performance_counter_multiple_query_pools: false,
+ performance_counter_query_pools: false,
+ pipeline_creation_cache_control: false,
+ pipeline_executable_info: false,
+ pipeline_fragment_shading_rate: false,
+ pipeline_properties_identifier: false,
+ pipeline_protected_access: false,
+ pipeline_robustness: false,
+ pipeline_statistics_query: false,
+ point_polygons: false,
+ present_barrier: false,
+ present_id: false,
+ present_wait: false,
+ primitive_fragment_shading_rate: false,
+ primitive_fragment_shading_rate_mesh_shader: false,
+ primitive_topology_list_restart: false,
+ primitive_topology_patch_list_restart: false,
+ primitives_generated_query: false,
+ primitives_generated_query_with_non_zero_streams: false,
+ primitives_generated_query_with_rasterizer_discard: false,
+ private_data: false,
+ protected_memory: false,
+ provoking_vertex_last: false,
+ rasterization_order_color_attachment_access: false,
+ rasterization_order_depth_attachment_access: false,
+ rasterization_order_stencil_attachment_access: false,
+ ray_query: false,
+ ray_tracing_invocation_reorder: false,
+ ray_tracing_maintenance1: false,
+ ray_tracing_motion_blur: false,
+ ray_tracing_motion_blur_pipeline_trace_rays_indirect: false,
+ ray_tracing_pipeline: false,
+ ray_tracing_pipeline_shader_group_handle_capture_replay: false,
+ ray_tracing_pipeline_shader_group_handle_capture_replay_mixed: false,
+ ray_tracing_pipeline_trace_rays_indirect: false,
+ ray_tracing_pipeline_trace_rays_indirect2: false,
+ ray_traversal_primitive_culling: false,
+ rectangular_lines: false,
+ report_address_binding: false,
+ representative_fragment_test: false,
+ robust_buffer_access: false,
+ robust_buffer_access2: false,
+ robust_image_access: false,
+ robust_image_access2: false,
+ runtime_descriptor_array: false,
+ sample_rate_shading: false,
+ sampler2_d_view_of3_d: false,
+ sampler_anisotropy: false,
+ sampler_filter_minmax: false,
+ sampler_mip_lod_bias: false,
+ sampler_mirror_clamp_to_edge: false,
+ sampler_ycbcr_conversion: false,
+ scalar_block_layout: false,
+ separate_depth_stencil_layouts: false,
+ separate_stencil_mask_ref: false,
+ shader_buffer_float16_atomic_add: false,
+ shader_buffer_float16_atomic_min_max: false,
+ shader_buffer_float16_atomics: false,
+ shader_buffer_float32_atomic_add: false,
+ shader_buffer_float32_atomic_min_max: false,
+ shader_buffer_float32_atomics: false,
+ shader_buffer_float64_atomic_add: false,
+ shader_buffer_float64_atomic_min_max: false,
+ shader_buffer_float64_atomics: false,
+ shader_buffer_int64_atomics: false,
+ shader_clip_distance: false,
+ shader_core_builtins: false,
+ shader_cull_distance: false,
+ shader_demote_to_helper_invocation: false,
+ shader_device_clock: false,
+ shader_draw_parameters: false,
+ shader_early_and_late_fragment_tests: false,
+ shader_float16: false,
+ shader_float64: false,
+ shader_image_float32_atomic_add: false,
+ shader_image_float32_atomic_min_max: false,
+ shader_image_float32_atomics: false,
+ shader_image_gather_extended: false,
+ shader_image_int64_atomics: false,
+ shader_input_attachment_array_dynamic_indexing: false,
+ shader_input_attachment_array_non_uniform_indexing: false,
+ shader_int16: false,
+ shader_int64: false,
+ shader_int8: false,
+ shader_integer_dot_product: false,
+ shader_integer_functions2: false,
+ shader_module_identifier: false,
+ shader_output_layer: false,
+ shader_output_viewport_index: false,
+ shader_resource_min_lod: false,
+ shader_resource_residency: false,
+ shader_sample_rate_interpolation_functions: false,
+ shader_sampled_image_array_dynamic_indexing: false,
+ shader_sampled_image_array_non_uniform_indexing: false,
+ shader_shared_float16_atomic_add: false,
+ shader_shared_float16_atomic_min_max: false,
+ shader_shared_float16_atomics: false,
+ shader_shared_float32_atomic_add: false,
+ shader_shared_float32_atomic_min_max: false,
+ shader_shared_float32_atomics: false,
+ shader_shared_float64_atomic_add: false,
+ shader_shared_float64_atomic_min_max: false,
+ shader_shared_float64_atomics: false,
+ shader_shared_int64_atomics: false,
+ shader_sm_builtins: false,
+ shader_storage_buffer_array_dynamic_indexing: false,
+ shader_storage_buffer_array_non_uniform_indexing: false,
+ shader_storage_image_array_dynamic_indexing: false,
+ shader_storage_image_array_non_uniform_indexing: false,
+ shader_storage_image_extended_formats: false,
+ shader_storage_image_multisample: false,
+ shader_storage_image_read_without_format: false,
+ shader_storage_image_write_without_format: false,
+ shader_storage_texel_buffer_array_dynamic_indexing: false,
+ shader_storage_texel_buffer_array_non_uniform_indexing: false,
+ shader_subgroup_clock: false,
+ shader_subgroup_extended_types: false,
+ shader_subgroup_uniform_control_flow: false,
+ shader_terminate_invocation: false,
+ shader_tessellation_and_geometry_point_size: false,
+ shader_uniform_buffer_array_dynamic_indexing: false,
+ shader_uniform_buffer_array_non_uniform_indexing: false,
+ shader_uniform_texel_buffer_array_dynamic_indexing: false,
+ shader_uniform_texel_buffer_array_non_uniform_indexing: false,
+ shader_zero_initialize_workgroup_memory: false,
+ shading_rate_coarse_sample_order: false,
+ shading_rate_image: false,
+ smooth_lines: false,
+ sparse_binding: false,
+ sparse_image_float32_atomic_add: false,
+ sparse_image_float32_atomic_min_max: false,
+ sparse_image_float32_atomics: false,
+ sparse_image_int64_atomics: false,
+ sparse_residency16_samples: false,
+ sparse_residency2_samples: false,
+ sparse_residency4_samples: false,
+ sparse_residency8_samples: false,
+ sparse_residency_aliased: false,
+ sparse_residency_buffer: false,
+ sparse_residency_image2_d: false,
+ sparse_residency_image3_d: false,
+ stippled_bresenham_lines: false,
+ stippled_rectangular_lines: false,
+ stippled_smooth_lines: false,
+ storage_buffer16_bit_access: false,
+ storage_buffer8_bit_access: false,
+ storage_input_output16: false,
+ storage_push_constant16: false,
+ storage_push_constant8: false,
+ subgroup_broadcast_dynamic_id: false,
+ subgroup_size_control: false,
+ subpass_merge_feedback: false,
+ subpass_shading: false,
+ supersample_fragment_shading_rates: false,
+ swapchain_maintenance1: false,
+ synchronization2: false,
+ task_shader: false,
+ tessellation_isolines: false,
+ tessellation_point_mode: false,
+ tessellation_shader: false,
+ texel_buffer_alignment: false,
+ texture_block_match: false,
+ texture_box_filter: false,
+ texture_compression_astc_hdr: false,
+ texture_compression_astc_ldr: false,
+ texture_compression_bc: false,
+ texture_compression_etc2: false,
+ texture_sample_weighted: false,
+ tile_properties: false,
+ timeline_semaphore: false,
+ transform_feedback: false,
+ transform_feedback_preserves_provoking_vertex: false,
+ triangle_fans: false,
+ uniform_and_storage_buffer16_bit_access: false,
+ uniform_and_storage_buffer8_bit_access: false,
+ uniform_buffer_standard_layout: false,
+ variable_multisample_rate: false,
+ variable_pointers: false,
+ variable_pointers_storage_buffer: false,
+ vertex_attribute_access_beyond_stride: false,
+ vertex_attribute_instance_rate_divisor: false,
+ vertex_attribute_instance_rate_zero_divisor: false,
+ vertex_input_dynamic_state: false,
+ vertex_pipeline_stores_and_atomics: false,
+ vulkan_memory_model: false,
+ vulkan_memory_model_availability_visibility_chains: false,
+ vulkan_memory_model_device_scope: false,
+ wide_lines: false,
+ workgroup_memory_explicit_layout: false,
+ workgroup_memory_explicit_layout16_bit_access: false,
+ workgroup_memory_explicit_layout8_bit_access: false,
+ workgroup_memory_explicit_layout_scalar_block_layout: false,
+ ycbcr2plane444_formats: false,
+ ycbcr_image_arrays: false,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+ #[doc = r" Returns an `Features` object with none of the members set."]
+ #[deprecated(since = "0.31.0", note = "Use `empty` instead.")]
+ #[inline]
+ pub const fn none() -> Self {
+ Self::empty()
+ }
+ #[doc = r" Returns a `Features` object with all of the members set."]
+ #[cfg(test)]
+ pub(crate) const fn all() -> Features {
+ Features {
+ acceleration_structure: true,
+ acceleration_structure_capture_replay: true,
+ acceleration_structure_host_commands: true,
+ acceleration_structure_indirect_build: true,
+ advanced_blend_coherent_operations: true,
+ alpha_to_one: true,
+ amigo_profiling: true,
+ attachment_feedback_loop_layout: true,
+ attachment_fragment_shading_rate: true,
+ border_color_swizzle: true,
+ border_color_swizzle_from_image: true,
+ bresenham_lines: true,
+ buffer_device_address: true,
+ buffer_device_address_capture_replay: true,
+ buffer_device_address_multi_device: true,
+ color_write_enable: true,
+ compute_derivative_group_linear: true,
+ compute_derivative_group_quads: true,
+ compute_full_subgroups: true,
+ conditional_rendering: true,
+ constant_alpha_color_blend_factors: true,
+ cooperative_matrix: true,
+ cooperative_matrix_robust_buffer_access: true,
+ corner_sampled_image: true,
+ coverage_reduction_mode: true,
+ custom_border_color_without_format: true,
+ custom_border_colors: true,
+ decode_mode_shared_exponent: true,
+ dedicated_allocation_image_aliasing: true,
+ depth_bias_clamp: true,
+ depth_bounds: true,
+ depth_clamp: true,
+ depth_clamp_zero_one: true,
+ depth_clip_control: true,
+ depth_clip_enable: true,
+ descriptor_binding_acceleration_structure_update_after_bind: true,
+ descriptor_binding_inline_uniform_block_update_after_bind: true,
+ descriptor_binding_partially_bound: true,
+ descriptor_binding_sampled_image_update_after_bind: true,
+ descriptor_binding_storage_buffer_update_after_bind: true,
+ descriptor_binding_storage_image_update_after_bind: true,
+ descriptor_binding_storage_texel_buffer_update_after_bind: true,
+ descriptor_binding_uniform_buffer_update_after_bind: true,
+ descriptor_binding_uniform_texel_buffer_update_after_bind: true,
+ descriptor_binding_update_unused_while_pending: true,
+ descriptor_binding_variable_descriptor_count: true,
+ descriptor_buffer: true,
+ descriptor_buffer_capture_replay: true,
+ descriptor_buffer_image_layout_ignored: true,
+ descriptor_buffer_push_descriptors: true,
+ descriptor_indexing: true,
+ descriptor_set_host_mapping: true,
+ device_coherent_memory: true,
+ device_fault: true,
+ device_fault_vendor_binary: true,
+ device_generated_commands: true,
+ device_memory_report: true,
+ diagnostics_config: true,
+ draw_indirect_count: true,
+ draw_indirect_first_instance: true,
+ dual_src_blend: true,
+ dynamic_rendering: true,
+ events: true,
+ exclusive_scissor: true,
+ extended_dynamic_state: true,
+ extended_dynamic_state2: true,
+ extended_dynamic_state2_logic_op: true,
+ extended_dynamic_state2_patch_control_points: true,
+ extended_dynamic_state3_alpha_to_coverage_enable: true,
+ extended_dynamic_state3_alpha_to_one_enable: true,
+ extended_dynamic_state3_color_blend_advanced: true,
+ extended_dynamic_state3_color_blend_enable: true,
+ extended_dynamic_state3_color_blend_equation: true,
+ extended_dynamic_state3_color_write_mask: true,
+ extended_dynamic_state3_conservative_rasterization_mode: true,
+ extended_dynamic_state3_coverage_modulation_mode: true,
+ extended_dynamic_state3_coverage_modulation_table: true,
+ extended_dynamic_state3_coverage_modulation_table_enable: true,
+ extended_dynamic_state3_coverage_reduction_mode: true,
+ extended_dynamic_state3_coverage_to_color_enable: true,
+ extended_dynamic_state3_coverage_to_color_location: true,
+ extended_dynamic_state3_depth_clamp_enable: true,
+ extended_dynamic_state3_depth_clip_enable: true,
+ extended_dynamic_state3_depth_clip_negative_one_to_one: true,
+ extended_dynamic_state3_extra_primitive_overestimation_size: true,
+ extended_dynamic_state3_line_rasterization_mode: true,
+ extended_dynamic_state3_line_stipple_enable: true,
+ extended_dynamic_state3_logic_op_enable: true,
+ extended_dynamic_state3_polygon_mode: true,
+ extended_dynamic_state3_provoking_vertex_mode: true,
+ extended_dynamic_state3_rasterization_samples: true,
+ extended_dynamic_state3_rasterization_stream: true,
+ extended_dynamic_state3_representative_fragment_test_enable: true,
+ extended_dynamic_state3_sample_locations_enable: true,
+ extended_dynamic_state3_sample_mask: true,
+ extended_dynamic_state3_shading_rate_image_enable: true,
+ extended_dynamic_state3_tessellation_domain_origin: true,
+ extended_dynamic_state3_viewport_swizzle: true,
+ extended_dynamic_state3_viewport_w_scaling_enable: true,
+ external_memory_rdma: true,
+ fill_mode_non_solid: true,
+ format_a4b4g4r4: true,
+ format_a4r4g4b4: true,
+ format_rgba10x6_without_y_cb_cr_sampler: true,
+ fragment_density_map: true,
+ fragment_density_map_deferred: true,
+ fragment_density_map_dynamic: true,
+ fragment_density_map_non_subsampled_images: true,
+ fragment_density_map_offset: true,
+ fragment_shader_barycentric: true,
+ fragment_shader_pixel_interlock: true,
+ fragment_shader_sample_interlock: true,
+ fragment_shader_shading_rate_interlock: true,
+ fragment_shading_rate_enums: true,
+ fragment_stores_and_atomics: true,
+ full_draw_index_uint32: true,
+ geometry_shader: true,
+ geometry_streams: true,
+ global_priority_query: true,
+ graphics_pipeline_library: true,
+ host_query_reset: true,
+ image2_d_view_of3_d: true,
+ image_compression_control: true,
+ image_compression_control_swapchain: true,
+ image_cube_array: true,
+ image_footprint: true,
+ image_view2_d_on3_d_image: true,
+ image_view_format_reinterpretation: true,
+ image_view_format_swizzle: true,
+ imageless_framebuffer: true,
+ independent_blend: true,
+ index_type_uint8: true,
+ indirect_copy: true,
+ inherited_conditional_rendering: true,
+ inherited_queries: true,
+ inherited_viewport_scissor2_d: true,
+ inline_uniform_block: true,
+ invocation_mask: true,
+ large_points: true,
+ legacy_dithering: true,
+ linear_color_attachment: true,
+ logic_op: true,
+ maintenance4: true,
+ memory_decompression: true,
+ memory_priority: true,
+ mesh_shader: true,
+ mesh_shader_queries: true,
+ micromap: true,
+ micromap_capture_replay: true,
+ micromap_host_commands: true,
+ min_lod: true,
+ multi_draw: true,
+ multi_draw_indirect: true,
+ multi_viewport: true,
+ multisample_array_image: true,
+ multisampled_render_to_single_sampled: true,
+ multiview: true,
+ multiview_geometry_shader: true,
+ multiview_mesh_shader: true,
+ multiview_per_view_viewports: true,
+ multiview_tessellation_shader: true,
+ mutable_comparison_samplers: true,
+ mutable_descriptor_type: true,
+ no_invocation_fragment_shading_rates: true,
+ non_seamless_cube_map: true,
+ null_descriptor: true,
+ occlusion_query_precise: true,
+ optical_flow: true,
+ pageable_device_local_memory: true,
+ performance_counter_multiple_query_pools: true,
+ performance_counter_query_pools: true,
+ pipeline_creation_cache_control: true,
+ pipeline_executable_info: true,
+ pipeline_fragment_shading_rate: true,
+ pipeline_properties_identifier: true,
+ pipeline_protected_access: true,
+ pipeline_robustness: true,
+ pipeline_statistics_query: true,
+ point_polygons: true,
+ present_barrier: true,
+ present_id: true,
+ present_wait: true,
+ primitive_fragment_shading_rate: true,
+ primitive_fragment_shading_rate_mesh_shader: true,
+ primitive_topology_list_restart: true,
+ primitive_topology_patch_list_restart: true,
+ primitives_generated_query: true,
+ primitives_generated_query_with_non_zero_streams: true,
+ primitives_generated_query_with_rasterizer_discard: true,
+ private_data: true,
+ protected_memory: true,
+ provoking_vertex_last: true,
+ rasterization_order_color_attachment_access: true,
+ rasterization_order_depth_attachment_access: true,
+ rasterization_order_stencil_attachment_access: true,
+ ray_query: true,
+ ray_tracing_invocation_reorder: true,
+ ray_tracing_maintenance1: true,
+ ray_tracing_motion_blur: true,
+ ray_tracing_motion_blur_pipeline_trace_rays_indirect: true,
+ ray_tracing_pipeline: true,
+ ray_tracing_pipeline_shader_group_handle_capture_replay: true,
+ ray_tracing_pipeline_shader_group_handle_capture_replay_mixed: true,
+ ray_tracing_pipeline_trace_rays_indirect: true,
+ ray_tracing_pipeline_trace_rays_indirect2: true,
+ ray_traversal_primitive_culling: true,
+ rectangular_lines: true,
+ report_address_binding: true,
+ representative_fragment_test: true,
+ robust_buffer_access: true,
+ robust_buffer_access2: true,
+ robust_image_access: true,
+ robust_image_access2: true,
+ runtime_descriptor_array: true,
+ sample_rate_shading: true,
+ sampler2_d_view_of3_d: true,
+ sampler_anisotropy: true,
+ sampler_filter_minmax: true,
+ sampler_mip_lod_bias: true,
+ sampler_mirror_clamp_to_edge: true,
+ sampler_ycbcr_conversion: true,
+ scalar_block_layout: true,
+ separate_depth_stencil_layouts: true,
+ separate_stencil_mask_ref: true,
+ shader_buffer_float16_atomic_add: true,
+ shader_buffer_float16_atomic_min_max: true,
+ shader_buffer_float16_atomics: true,
+ shader_buffer_float32_atomic_add: true,
+ shader_buffer_float32_atomic_min_max: true,
+ shader_buffer_float32_atomics: true,
+ shader_buffer_float64_atomic_add: true,
+ shader_buffer_float64_atomic_min_max: true,
+ shader_buffer_float64_atomics: true,
+ shader_buffer_int64_atomics: true,
+ shader_clip_distance: true,
+ shader_core_builtins: true,
+ shader_cull_distance: true,
+ shader_demote_to_helper_invocation: true,
+ shader_device_clock: true,
+ shader_draw_parameters: true,
+ shader_early_and_late_fragment_tests: true,
+ shader_float16: true,
+ shader_float64: true,
+ shader_image_float32_atomic_add: true,
+ shader_image_float32_atomic_min_max: true,
+ shader_image_float32_atomics: true,
+ shader_image_gather_extended: true,
+ shader_image_int64_atomics: true,
+ shader_input_attachment_array_dynamic_indexing: true,
+ shader_input_attachment_array_non_uniform_indexing: true,
+ shader_int16: true,
+ shader_int64: true,
+ shader_int8: true,
+ shader_integer_dot_product: true,
+ shader_integer_functions2: true,
+ shader_module_identifier: true,
+ shader_output_layer: true,
+ shader_output_viewport_index: true,
+ shader_resource_min_lod: true,
+ shader_resource_residency: true,
+ shader_sample_rate_interpolation_functions: true,
+ shader_sampled_image_array_dynamic_indexing: true,
+ shader_sampled_image_array_non_uniform_indexing: true,
+ shader_shared_float16_atomic_add: true,
+ shader_shared_float16_atomic_min_max: true,
+ shader_shared_float16_atomics: true,
+ shader_shared_float32_atomic_add: true,
+ shader_shared_float32_atomic_min_max: true,
+ shader_shared_float32_atomics: true,
+ shader_shared_float64_atomic_add: true,
+ shader_shared_float64_atomic_min_max: true,
+ shader_shared_float64_atomics: true,
+ shader_shared_int64_atomics: true,
+ shader_sm_builtins: true,
+ shader_storage_buffer_array_dynamic_indexing: true,
+ shader_storage_buffer_array_non_uniform_indexing: true,
+ shader_storage_image_array_dynamic_indexing: true,
+ shader_storage_image_array_non_uniform_indexing: true,
+ shader_storage_image_extended_formats: true,
+ shader_storage_image_multisample: true,
+ shader_storage_image_read_without_format: true,
+ shader_storage_image_write_without_format: true,
+ shader_storage_texel_buffer_array_dynamic_indexing: true,
+ shader_storage_texel_buffer_array_non_uniform_indexing: true,
+ shader_subgroup_clock: true,
+ shader_subgroup_extended_types: true,
+ shader_subgroup_uniform_control_flow: true,
+ shader_terminate_invocation: true,
+ shader_tessellation_and_geometry_point_size: true,
+ shader_uniform_buffer_array_dynamic_indexing: true,
+ shader_uniform_buffer_array_non_uniform_indexing: true,
+ shader_uniform_texel_buffer_array_dynamic_indexing: true,
+ shader_uniform_texel_buffer_array_non_uniform_indexing: true,
+ shader_zero_initialize_workgroup_memory: true,
+ shading_rate_coarse_sample_order: true,
+ shading_rate_image: true,
+ smooth_lines: true,
+ sparse_binding: true,
+ sparse_image_float32_atomic_add: true,
+ sparse_image_float32_atomic_min_max: true,
+ sparse_image_float32_atomics: true,
+ sparse_image_int64_atomics: true,
+ sparse_residency16_samples: true,
+ sparse_residency2_samples: true,
+ sparse_residency4_samples: true,
+ sparse_residency8_samples: true,
+ sparse_residency_aliased: true,
+ sparse_residency_buffer: true,
+ sparse_residency_image2_d: true,
+ sparse_residency_image3_d: true,
+ stippled_bresenham_lines: true,
+ stippled_rectangular_lines: true,
+ stippled_smooth_lines: true,
+ storage_buffer16_bit_access: true,
+ storage_buffer8_bit_access: true,
+ storage_input_output16: true,
+ storage_push_constant16: true,
+ storage_push_constant8: true,
+ subgroup_broadcast_dynamic_id: true,
+ subgroup_size_control: true,
+ subpass_merge_feedback: true,
+ subpass_shading: true,
+ supersample_fragment_shading_rates: true,
+ swapchain_maintenance1: true,
+ synchronization2: true,
+ task_shader: true,
+ tessellation_isolines: true,
+ tessellation_point_mode: true,
+ tessellation_shader: true,
+ texel_buffer_alignment: true,
+ texture_block_match: true,
+ texture_box_filter: true,
+ texture_compression_astc_hdr: true,
+ texture_compression_astc_ldr: true,
+ texture_compression_bc: true,
+ texture_compression_etc2: true,
+ texture_sample_weighted: true,
+ tile_properties: true,
+ timeline_semaphore: true,
+ transform_feedback: true,
+ transform_feedback_preserves_provoking_vertex: true,
+ triangle_fans: true,
+ uniform_and_storage_buffer16_bit_access: true,
+ uniform_and_storage_buffer8_bit_access: true,
+ uniform_buffer_standard_layout: true,
+ variable_multisample_rate: true,
+ variable_pointers: true,
+ variable_pointers_storage_buffer: true,
+ vertex_attribute_access_beyond_stride: true,
+ vertex_attribute_instance_rate_divisor: true,
+ vertex_attribute_instance_rate_zero_divisor: true,
+ vertex_input_dynamic_state: true,
+ vertex_pipeline_stores_and_atomics: true,
+ vulkan_memory_model: true,
+ vulkan_memory_model_availability_visibility_chains: true,
+ vulkan_memory_model_device_scope: true,
+ wide_lines: true,
+ workgroup_memory_explicit_layout: true,
+ workgroup_memory_explicit_layout16_bit_access: true,
+ workgroup_memory_explicit_layout8_bit_access: true,
+ workgroup_memory_explicit_layout_scalar_block_layout: true,
+ ycbcr2plane444_formats: true,
+ ycbcr_image_arrays: true,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+ #[doc = r" Returns whether any members are set in both `self` and `other`."]
+ #[inline]
+ pub const fn intersects(&self, other: &Self) -> bool {
+ (self.acceleration_structure && other.acceleration_structure)
+ || (self.acceleration_structure_capture_replay
+ && other.acceleration_structure_capture_replay)
+ || (self.acceleration_structure_host_commands
+ && other.acceleration_structure_host_commands)
+ || (self.acceleration_structure_indirect_build
+ && other.acceleration_structure_indirect_build)
+ || (self.advanced_blend_coherent_operations && other.advanced_blend_coherent_operations)
+ || (self.alpha_to_one && other.alpha_to_one)
+ || (self.amigo_profiling && other.amigo_profiling)
+ || (self.attachment_feedback_loop_layout && other.attachment_feedback_loop_layout)
+ || (self.attachment_fragment_shading_rate && other.attachment_fragment_shading_rate)
+ || (self.border_color_swizzle && other.border_color_swizzle)
+ || (self.border_color_swizzle_from_image && other.border_color_swizzle_from_image)
+ || (self.bresenham_lines && other.bresenham_lines)
+ || (self.buffer_device_address && other.buffer_device_address)
+ || (self.buffer_device_address_capture_replay
+ && other.buffer_device_address_capture_replay)
+ || (self.buffer_device_address_multi_device && other.buffer_device_address_multi_device)
+ || (self.color_write_enable && other.color_write_enable)
+ || (self.compute_derivative_group_linear && other.compute_derivative_group_linear)
+ || (self.compute_derivative_group_quads && other.compute_derivative_group_quads)
+ || (self.compute_full_subgroups && other.compute_full_subgroups)
+ || (self.conditional_rendering && other.conditional_rendering)
+ || (self.constant_alpha_color_blend_factors && other.constant_alpha_color_blend_factors)
+ || (self.cooperative_matrix && other.cooperative_matrix)
+ || (self.cooperative_matrix_robust_buffer_access
+ && other.cooperative_matrix_robust_buffer_access)
+ || (self.corner_sampled_image && other.corner_sampled_image)
+ || (self.coverage_reduction_mode && other.coverage_reduction_mode)
+ || (self.custom_border_color_without_format && other.custom_border_color_without_format)
+ || (self.custom_border_colors && other.custom_border_colors)
+ || (self.decode_mode_shared_exponent && other.decode_mode_shared_exponent)
+ || (self.dedicated_allocation_image_aliasing
+ && other.dedicated_allocation_image_aliasing)
+ || (self.depth_bias_clamp && other.depth_bias_clamp)
+ || (self.depth_bounds && other.depth_bounds)
+ || (self.depth_clamp && other.depth_clamp)
+ || (self.depth_clamp_zero_one && other.depth_clamp_zero_one)
+ || (self.depth_clip_control && other.depth_clip_control)
+ || (self.depth_clip_enable && other.depth_clip_enable)
+ || (self.descriptor_binding_acceleration_structure_update_after_bind
+ && other.descriptor_binding_acceleration_structure_update_after_bind)
+ || (self.descriptor_binding_inline_uniform_block_update_after_bind
+ && other.descriptor_binding_inline_uniform_block_update_after_bind)
+ || (self.descriptor_binding_partially_bound && other.descriptor_binding_partially_bound)
+ || (self.descriptor_binding_sampled_image_update_after_bind
+ && other.descriptor_binding_sampled_image_update_after_bind)
+ || (self.descriptor_binding_storage_buffer_update_after_bind
+ && other.descriptor_binding_storage_buffer_update_after_bind)
+ || (self.descriptor_binding_storage_image_update_after_bind
+ && other.descriptor_binding_storage_image_update_after_bind)
+ || (self.descriptor_binding_storage_texel_buffer_update_after_bind
+ && other.descriptor_binding_storage_texel_buffer_update_after_bind)
+ || (self.descriptor_binding_uniform_buffer_update_after_bind
+ && other.descriptor_binding_uniform_buffer_update_after_bind)
+ || (self.descriptor_binding_uniform_texel_buffer_update_after_bind
+ && other.descriptor_binding_uniform_texel_buffer_update_after_bind)
+ || (self.descriptor_binding_update_unused_while_pending
+ && other.descriptor_binding_update_unused_while_pending)
+ || (self.descriptor_binding_variable_descriptor_count
+ && other.descriptor_binding_variable_descriptor_count)
+ || (self.descriptor_buffer && other.descriptor_buffer)
+ || (self.descriptor_buffer_capture_replay && other.descriptor_buffer_capture_replay)
+ || (self.descriptor_buffer_image_layout_ignored
+ && other.descriptor_buffer_image_layout_ignored)
+ || (self.descriptor_buffer_push_descriptors && other.descriptor_buffer_push_descriptors)
+ || (self.descriptor_indexing && other.descriptor_indexing)
+ || (self.descriptor_set_host_mapping && other.descriptor_set_host_mapping)
+ || (self.device_coherent_memory && other.device_coherent_memory)
+ || (self.device_fault && other.device_fault)
+ || (self.device_fault_vendor_binary && other.device_fault_vendor_binary)
+ || (self.device_generated_commands && other.device_generated_commands)
+ || (self.device_memory_report && other.device_memory_report)
+ || (self.diagnostics_config && other.diagnostics_config)
+ || (self.draw_indirect_count && other.draw_indirect_count)
+ || (self.draw_indirect_first_instance && other.draw_indirect_first_instance)
+ || (self.dual_src_blend && other.dual_src_blend)
+ || (self.dynamic_rendering && other.dynamic_rendering)
+ || (self.events && other.events)
+ || (self.exclusive_scissor && other.exclusive_scissor)
+ || (self.extended_dynamic_state && other.extended_dynamic_state)
+ || (self.extended_dynamic_state2 && other.extended_dynamic_state2)
+ || (self.extended_dynamic_state2_logic_op && other.extended_dynamic_state2_logic_op)
+ || (self.extended_dynamic_state2_patch_control_points
+ && other.extended_dynamic_state2_patch_control_points)
+ || (self.extended_dynamic_state3_alpha_to_coverage_enable
+ && other.extended_dynamic_state3_alpha_to_coverage_enable)
+ || (self.extended_dynamic_state3_alpha_to_one_enable
+ && other.extended_dynamic_state3_alpha_to_one_enable)
+ || (self.extended_dynamic_state3_color_blend_advanced
+ && other.extended_dynamic_state3_color_blend_advanced)
+ || (self.extended_dynamic_state3_color_blend_enable
+ && other.extended_dynamic_state3_color_blend_enable)
+ || (self.extended_dynamic_state3_color_blend_equation
+ && other.extended_dynamic_state3_color_blend_equation)
+ || (self.extended_dynamic_state3_color_write_mask
+ && other.extended_dynamic_state3_color_write_mask)
+ || (self.extended_dynamic_state3_conservative_rasterization_mode
+ && other.extended_dynamic_state3_conservative_rasterization_mode)
+ || (self.extended_dynamic_state3_coverage_modulation_mode
+ && other.extended_dynamic_state3_coverage_modulation_mode)
+ || (self.extended_dynamic_state3_coverage_modulation_table
+ && other.extended_dynamic_state3_coverage_modulation_table)
+ || (self.extended_dynamic_state3_coverage_modulation_table_enable
+ && other.extended_dynamic_state3_coverage_modulation_table_enable)
+ || (self.extended_dynamic_state3_coverage_reduction_mode
+ && other.extended_dynamic_state3_coverage_reduction_mode)
+ || (self.extended_dynamic_state3_coverage_to_color_enable
+ && other.extended_dynamic_state3_coverage_to_color_enable)
+ || (self.extended_dynamic_state3_coverage_to_color_location
+ && other.extended_dynamic_state3_coverage_to_color_location)
+ || (self.extended_dynamic_state3_depth_clamp_enable
+ && other.extended_dynamic_state3_depth_clamp_enable)
+ || (self.extended_dynamic_state3_depth_clip_enable
+ && other.extended_dynamic_state3_depth_clip_enable)
+ || (self.extended_dynamic_state3_depth_clip_negative_one_to_one
+ && other.extended_dynamic_state3_depth_clip_negative_one_to_one)
+ || (self.extended_dynamic_state3_extra_primitive_overestimation_size
+ && other.extended_dynamic_state3_extra_primitive_overestimation_size)
+ || (self.extended_dynamic_state3_line_rasterization_mode
+ && other.extended_dynamic_state3_line_rasterization_mode)
+ || (self.extended_dynamic_state3_line_stipple_enable
+ && other.extended_dynamic_state3_line_stipple_enable)
+ || (self.extended_dynamic_state3_logic_op_enable
+ && other.extended_dynamic_state3_logic_op_enable)
+ || (self.extended_dynamic_state3_polygon_mode
+ && other.extended_dynamic_state3_polygon_mode)
+ || (self.extended_dynamic_state3_provoking_vertex_mode
+ && other.extended_dynamic_state3_provoking_vertex_mode)
+ || (self.extended_dynamic_state3_rasterization_samples
+ && other.extended_dynamic_state3_rasterization_samples)
+ || (self.extended_dynamic_state3_rasterization_stream
+ && other.extended_dynamic_state3_rasterization_stream)
+ || (self.extended_dynamic_state3_representative_fragment_test_enable
+ && other.extended_dynamic_state3_representative_fragment_test_enable)
+ || (self.extended_dynamic_state3_sample_locations_enable
+ && other.extended_dynamic_state3_sample_locations_enable)
+ || (self.extended_dynamic_state3_sample_mask
+ && other.extended_dynamic_state3_sample_mask)
+ || (self.extended_dynamic_state3_shading_rate_image_enable
+ && other.extended_dynamic_state3_shading_rate_image_enable)
+ || (self.extended_dynamic_state3_tessellation_domain_origin
+ && other.extended_dynamic_state3_tessellation_domain_origin)
+ || (self.extended_dynamic_state3_viewport_swizzle
+ && other.extended_dynamic_state3_viewport_swizzle)
+ || (self.extended_dynamic_state3_viewport_w_scaling_enable
+ && other.extended_dynamic_state3_viewport_w_scaling_enable)
+ || (self.external_memory_rdma && other.external_memory_rdma)
+ || (self.fill_mode_non_solid && other.fill_mode_non_solid)
+ || (self.format_a4b4g4r4 && other.format_a4b4g4r4)
+ || (self.format_a4r4g4b4 && other.format_a4r4g4b4)
+ || (self.format_rgba10x6_without_y_cb_cr_sampler
+ && other.format_rgba10x6_without_y_cb_cr_sampler)
+ || (self.fragment_density_map && other.fragment_density_map)
+ || (self.fragment_density_map_deferred && other.fragment_density_map_deferred)
+ || (self.fragment_density_map_dynamic && other.fragment_density_map_dynamic)
+ || (self.fragment_density_map_non_subsampled_images
+ && other.fragment_density_map_non_subsampled_images)
+ || (self.fragment_density_map_offset && other.fragment_density_map_offset)
+ || (self.fragment_shader_barycentric && other.fragment_shader_barycentric)
+ || (self.fragment_shader_pixel_interlock && other.fragment_shader_pixel_interlock)
+ || (self.fragment_shader_sample_interlock && other.fragment_shader_sample_interlock)
+ || (self.fragment_shader_shading_rate_interlock
+ && other.fragment_shader_shading_rate_interlock)
+ || (self.fragment_shading_rate_enums && other.fragment_shading_rate_enums)
+ || (self.fragment_stores_and_atomics && other.fragment_stores_and_atomics)
+ || (self.full_draw_index_uint32 && other.full_draw_index_uint32)
+ || (self.geometry_shader && other.geometry_shader)
+ || (self.geometry_streams && other.geometry_streams)
+ || (self.global_priority_query && other.global_priority_query)
+ || (self.graphics_pipeline_library && other.graphics_pipeline_library)
+ || (self.host_query_reset && other.host_query_reset)
+ || (self.image2_d_view_of3_d && other.image2_d_view_of3_d)
+ || (self.image_compression_control && other.image_compression_control)
+ || (self.image_compression_control_swapchain
+ && other.image_compression_control_swapchain)
+ || (self.image_cube_array && other.image_cube_array)
+ || (self.image_footprint && other.image_footprint)
+ || (self.image_view2_d_on3_d_image && other.image_view2_d_on3_d_image)
+ || (self.image_view_format_reinterpretation && other.image_view_format_reinterpretation)
+ || (self.image_view_format_swizzle && other.image_view_format_swizzle)
+ || (self.imageless_framebuffer && other.imageless_framebuffer)
+ || (self.independent_blend && other.independent_blend)
+ || (self.index_type_uint8 && other.index_type_uint8)
+ || (self.indirect_copy && other.indirect_copy)
+ || (self.inherited_conditional_rendering && other.inherited_conditional_rendering)
+ || (self.inherited_queries && other.inherited_queries)
+ || (self.inherited_viewport_scissor2_d && other.inherited_viewport_scissor2_d)
+ || (self.inline_uniform_block && other.inline_uniform_block)
+ || (self.invocation_mask && other.invocation_mask)
+ || (self.large_points && other.large_points)
+ || (self.legacy_dithering && other.legacy_dithering)
+ || (self.linear_color_attachment && other.linear_color_attachment)
+ || (self.logic_op && other.logic_op)
+ || (self.maintenance4 && other.maintenance4)
+ || (self.memory_decompression && other.memory_decompression)
+ || (self.memory_priority && other.memory_priority)
+ || (self.mesh_shader && other.mesh_shader)
+ || (self.mesh_shader_queries && other.mesh_shader_queries)
+ || (self.micromap && other.micromap)
+ || (self.micromap_capture_replay && other.micromap_capture_replay)
+ || (self.micromap_host_commands && other.micromap_host_commands)
+ || (self.min_lod && other.min_lod)
+ || (self.multi_draw && other.multi_draw)
+ || (self.multi_draw_indirect && other.multi_draw_indirect)
+ || (self.multi_viewport && other.multi_viewport)
+ || (self.multisample_array_image && other.multisample_array_image)
+ || (self.multisampled_render_to_single_sampled
+ && other.multisampled_render_to_single_sampled)
+ || (self.multiview && other.multiview)
+ || (self.multiview_geometry_shader && other.multiview_geometry_shader)
+ || (self.multiview_mesh_shader && other.multiview_mesh_shader)
+ || (self.multiview_per_view_viewports && other.multiview_per_view_viewports)
+ || (self.multiview_tessellation_shader && other.multiview_tessellation_shader)
+ || (self.mutable_comparison_samplers && other.mutable_comparison_samplers)
+ || (self.mutable_descriptor_type && other.mutable_descriptor_type)
+ || (self.no_invocation_fragment_shading_rates
+ && other.no_invocation_fragment_shading_rates)
+ || (self.non_seamless_cube_map && other.non_seamless_cube_map)
+ || (self.null_descriptor && other.null_descriptor)
+ || (self.occlusion_query_precise && other.occlusion_query_precise)
+ || (self.optical_flow && other.optical_flow)
+ || (self.pageable_device_local_memory && other.pageable_device_local_memory)
+ || (self.performance_counter_multiple_query_pools
+ && other.performance_counter_multiple_query_pools)
+ || (self.performance_counter_query_pools && other.performance_counter_query_pools)
+ || (self.pipeline_creation_cache_control && other.pipeline_creation_cache_control)
+ || (self.pipeline_executable_info && other.pipeline_executable_info)
+ || (self.pipeline_fragment_shading_rate && other.pipeline_fragment_shading_rate)
+ || (self.pipeline_properties_identifier && other.pipeline_properties_identifier)
+ || (self.pipeline_protected_access && other.pipeline_protected_access)
+ || (self.pipeline_robustness && other.pipeline_robustness)
+ || (self.pipeline_statistics_query && other.pipeline_statistics_query)
+ || (self.point_polygons && other.point_polygons)
+ || (self.present_barrier && other.present_barrier)
+ || (self.present_id && other.present_id)
+ || (self.present_wait && other.present_wait)
+ || (self.primitive_fragment_shading_rate && other.primitive_fragment_shading_rate)
+ || (self.primitive_fragment_shading_rate_mesh_shader
+ && other.primitive_fragment_shading_rate_mesh_shader)
+ || (self.primitive_topology_list_restart && other.primitive_topology_list_restart)
+ || (self.primitive_topology_patch_list_restart
+ && other.primitive_topology_patch_list_restart)
+ || (self.primitives_generated_query && other.primitives_generated_query)
+ || (self.primitives_generated_query_with_non_zero_streams
+ && other.primitives_generated_query_with_non_zero_streams)
+ || (self.primitives_generated_query_with_rasterizer_discard
+ && other.primitives_generated_query_with_rasterizer_discard)
+ || (self.private_data && other.private_data)
+ || (self.protected_memory && other.protected_memory)
+ || (self.provoking_vertex_last && other.provoking_vertex_last)
+ || (self.rasterization_order_color_attachment_access
+ && other.rasterization_order_color_attachment_access)
+ || (self.rasterization_order_depth_attachment_access
+ && other.rasterization_order_depth_attachment_access)
+ || (self.rasterization_order_stencil_attachment_access
+ && other.rasterization_order_stencil_attachment_access)
+ || (self.ray_query && other.ray_query)
+ || (self.ray_tracing_invocation_reorder && other.ray_tracing_invocation_reorder)
+ || (self.ray_tracing_maintenance1 && other.ray_tracing_maintenance1)
+ || (self.ray_tracing_motion_blur && other.ray_tracing_motion_blur)
+ || (self.ray_tracing_motion_blur_pipeline_trace_rays_indirect
+ && other.ray_tracing_motion_blur_pipeline_trace_rays_indirect)
+ || (self.ray_tracing_pipeline && other.ray_tracing_pipeline)
+ || (self.ray_tracing_pipeline_shader_group_handle_capture_replay
+ && other.ray_tracing_pipeline_shader_group_handle_capture_replay)
+ || (self.ray_tracing_pipeline_shader_group_handle_capture_replay_mixed
+ && other.ray_tracing_pipeline_shader_group_handle_capture_replay_mixed)
+ || (self.ray_tracing_pipeline_trace_rays_indirect
+ && other.ray_tracing_pipeline_trace_rays_indirect)
+ || (self.ray_tracing_pipeline_trace_rays_indirect2
+ && other.ray_tracing_pipeline_trace_rays_indirect2)
+ || (self.ray_traversal_primitive_culling && other.ray_traversal_primitive_culling)
+ || (self.rectangular_lines && other.rectangular_lines)
+ || (self.report_address_binding && other.report_address_binding)
+ || (self.representative_fragment_test && other.representative_fragment_test)
+ || (self.robust_buffer_access && other.robust_buffer_access)
+ || (self.robust_buffer_access2 && other.robust_buffer_access2)
+ || (self.robust_image_access && other.robust_image_access)
+ || (self.robust_image_access2 && other.robust_image_access2)
+ || (self.runtime_descriptor_array && other.runtime_descriptor_array)
+ || (self.sample_rate_shading && other.sample_rate_shading)
+ || (self.sampler2_d_view_of3_d && other.sampler2_d_view_of3_d)
+ || (self.sampler_anisotropy && other.sampler_anisotropy)
+ || (self.sampler_filter_minmax && other.sampler_filter_minmax)
+ || (self.sampler_mip_lod_bias && other.sampler_mip_lod_bias)
+ || (self.sampler_mirror_clamp_to_edge && other.sampler_mirror_clamp_to_edge)
+ || (self.sampler_ycbcr_conversion && other.sampler_ycbcr_conversion)
+ || (self.scalar_block_layout && other.scalar_block_layout)
+ || (self.separate_depth_stencil_layouts && other.separate_depth_stencil_layouts)
+ || (self.separate_stencil_mask_ref && other.separate_stencil_mask_ref)
+ || (self.shader_buffer_float16_atomic_add && other.shader_buffer_float16_atomic_add)
+ || (self.shader_buffer_float16_atomic_min_max
+ && other.shader_buffer_float16_atomic_min_max)
+ || (self.shader_buffer_float16_atomics && other.shader_buffer_float16_atomics)
+ || (self.shader_buffer_float32_atomic_add && other.shader_buffer_float32_atomic_add)
+ || (self.shader_buffer_float32_atomic_min_max
+ && other.shader_buffer_float32_atomic_min_max)
+ || (self.shader_buffer_float32_atomics && other.shader_buffer_float32_atomics)
+ || (self.shader_buffer_float64_atomic_add && other.shader_buffer_float64_atomic_add)
+ || (self.shader_buffer_float64_atomic_min_max
+ && other.shader_buffer_float64_atomic_min_max)
+ || (self.shader_buffer_float64_atomics && other.shader_buffer_float64_atomics)
+ || (self.shader_buffer_int64_atomics && other.shader_buffer_int64_atomics)
+ || (self.shader_clip_distance && other.shader_clip_distance)
+ || (self.shader_core_builtins && other.shader_core_builtins)
+ || (self.shader_cull_distance && other.shader_cull_distance)
+ || (self.shader_demote_to_helper_invocation && other.shader_demote_to_helper_invocation)
+ || (self.shader_device_clock && other.shader_device_clock)
+ || (self.shader_draw_parameters && other.shader_draw_parameters)
+ || (self.shader_early_and_late_fragment_tests
+ && other.shader_early_and_late_fragment_tests)
+ || (self.shader_float16 && other.shader_float16)
+ || (self.shader_float64 && other.shader_float64)
+ || (self.shader_image_float32_atomic_add && other.shader_image_float32_atomic_add)
+ || (self.shader_image_float32_atomic_min_max
+ && other.shader_image_float32_atomic_min_max)
+ || (self.shader_image_float32_atomics && other.shader_image_float32_atomics)
+ || (self.shader_image_gather_extended && other.shader_image_gather_extended)
+ || (self.shader_image_int64_atomics && other.shader_image_int64_atomics)
+ || (self.shader_input_attachment_array_dynamic_indexing
+ && other.shader_input_attachment_array_dynamic_indexing)
+ || (self.shader_input_attachment_array_non_uniform_indexing
+ && other.shader_input_attachment_array_non_uniform_indexing)
+ || (self.shader_int16 && other.shader_int16)
+ || (self.shader_int64 && other.shader_int64)
+ || (self.shader_int8 && other.shader_int8)
+ || (self.shader_integer_dot_product && other.shader_integer_dot_product)
+ || (self.shader_integer_functions2 && other.shader_integer_functions2)
+ || (self.shader_module_identifier && other.shader_module_identifier)
+ || (self.shader_output_layer && other.shader_output_layer)
+ || (self.shader_output_viewport_index && other.shader_output_viewport_index)
+ || (self.shader_resource_min_lod && other.shader_resource_min_lod)
+ || (self.shader_resource_residency && other.shader_resource_residency)
+ || (self.shader_sample_rate_interpolation_functions
+ && other.shader_sample_rate_interpolation_functions)
+ || (self.shader_sampled_image_array_dynamic_indexing
+ && other.shader_sampled_image_array_dynamic_indexing)
+ || (self.shader_sampled_image_array_non_uniform_indexing
+ && other.shader_sampled_image_array_non_uniform_indexing)
+ || (self.shader_shared_float16_atomic_add && other.shader_shared_float16_atomic_add)
+ || (self.shader_shared_float16_atomic_min_max
+ && other.shader_shared_float16_atomic_min_max)
+ || (self.shader_shared_float16_atomics && other.shader_shared_float16_atomics)
+ || (self.shader_shared_float32_atomic_add && other.shader_shared_float32_atomic_add)
+ || (self.shader_shared_float32_atomic_min_max
+ && other.shader_shared_float32_atomic_min_max)
+ || (self.shader_shared_float32_atomics && other.shader_shared_float32_atomics)
+ || (self.shader_shared_float64_atomic_add && other.shader_shared_float64_atomic_add)
+ || (self.shader_shared_float64_atomic_min_max
+ && other.shader_shared_float64_atomic_min_max)
+ || (self.shader_shared_float64_atomics && other.shader_shared_float64_atomics)
+ || (self.shader_shared_int64_atomics && other.shader_shared_int64_atomics)
+ || (self.shader_sm_builtins && other.shader_sm_builtins)
+ || (self.shader_storage_buffer_array_dynamic_indexing
+ && other.shader_storage_buffer_array_dynamic_indexing)
+ || (self.shader_storage_buffer_array_non_uniform_indexing
+ && other.shader_storage_buffer_array_non_uniform_indexing)
+ || (self.shader_storage_image_array_dynamic_indexing
+ && other.shader_storage_image_array_dynamic_indexing)
+ || (self.shader_storage_image_array_non_uniform_indexing
+ && other.shader_storage_image_array_non_uniform_indexing)
+ || (self.shader_storage_image_extended_formats
+ && other.shader_storage_image_extended_formats)
+ || (self.shader_storage_image_multisample && other.shader_storage_image_multisample)
+ || (self.shader_storage_image_read_without_format
+ && other.shader_storage_image_read_without_format)
+ || (self.shader_storage_image_write_without_format
+ && other.shader_storage_image_write_without_format)
+ || (self.shader_storage_texel_buffer_array_dynamic_indexing
+ && other.shader_storage_texel_buffer_array_dynamic_indexing)
+ || (self.shader_storage_texel_buffer_array_non_uniform_indexing
+ && other.shader_storage_texel_buffer_array_non_uniform_indexing)
+ || (self.shader_subgroup_clock && other.shader_subgroup_clock)
+ || (self.shader_subgroup_extended_types && other.shader_subgroup_extended_types)
+ || (self.shader_subgroup_uniform_control_flow
+ && other.shader_subgroup_uniform_control_flow)
+ || (self.shader_terminate_invocation && other.shader_terminate_invocation)
+ || (self.shader_tessellation_and_geometry_point_size
+ && other.shader_tessellation_and_geometry_point_size)
+ || (self.shader_uniform_buffer_array_dynamic_indexing
+ && other.shader_uniform_buffer_array_dynamic_indexing)
+ || (self.shader_uniform_buffer_array_non_uniform_indexing
+ && other.shader_uniform_buffer_array_non_uniform_indexing)
+ || (self.shader_uniform_texel_buffer_array_dynamic_indexing
+ && other.shader_uniform_texel_buffer_array_dynamic_indexing)
+ || (self.shader_uniform_texel_buffer_array_non_uniform_indexing
+ && other.shader_uniform_texel_buffer_array_non_uniform_indexing)
+ || (self.shader_zero_initialize_workgroup_memory
+ && other.shader_zero_initialize_workgroup_memory)
+ || (self.shading_rate_coarse_sample_order && other.shading_rate_coarse_sample_order)
+ || (self.shading_rate_image && other.shading_rate_image)
+ || (self.smooth_lines && other.smooth_lines)
+ || (self.sparse_binding && other.sparse_binding)
+ || (self.sparse_image_float32_atomic_add && other.sparse_image_float32_atomic_add)
+ || (self.sparse_image_float32_atomic_min_max
+ && other.sparse_image_float32_atomic_min_max)
+ || (self.sparse_image_float32_atomics && other.sparse_image_float32_atomics)
+ || (self.sparse_image_int64_atomics && other.sparse_image_int64_atomics)
+ || (self.sparse_residency16_samples && other.sparse_residency16_samples)
+ || (self.sparse_residency2_samples && other.sparse_residency2_samples)
+ || (self.sparse_residency4_samples && other.sparse_residency4_samples)
+ || (self.sparse_residency8_samples && other.sparse_residency8_samples)
+ || (self.sparse_residency_aliased && other.sparse_residency_aliased)
+ || (self.sparse_residency_buffer && other.sparse_residency_buffer)
+ || (self.sparse_residency_image2_d && other.sparse_residency_image2_d)
+ || (self.sparse_residency_image3_d && other.sparse_residency_image3_d)
+ || (self.stippled_bresenham_lines && other.stippled_bresenham_lines)
+ || (self.stippled_rectangular_lines && other.stippled_rectangular_lines)
+ || (self.stippled_smooth_lines && other.stippled_smooth_lines)
+ || (self.storage_buffer16_bit_access && other.storage_buffer16_bit_access)
+ || (self.storage_buffer8_bit_access && other.storage_buffer8_bit_access)
+ || (self.storage_input_output16 && other.storage_input_output16)
+ || (self.storage_push_constant16 && other.storage_push_constant16)
+ || (self.storage_push_constant8 && other.storage_push_constant8)
+ || (self.subgroup_broadcast_dynamic_id && other.subgroup_broadcast_dynamic_id)
+ || (self.subgroup_size_control && other.subgroup_size_control)
+ || (self.subpass_merge_feedback && other.subpass_merge_feedback)
+ || (self.subpass_shading && other.subpass_shading)
+ || (self.supersample_fragment_shading_rates && other.supersample_fragment_shading_rates)
+ || (self.swapchain_maintenance1 && other.swapchain_maintenance1)
+ || (self.synchronization2 && other.synchronization2)
+ || (self.task_shader && other.task_shader)
+ || (self.tessellation_isolines && other.tessellation_isolines)
+ || (self.tessellation_point_mode && other.tessellation_point_mode)
+ || (self.tessellation_shader && other.tessellation_shader)
+ || (self.texel_buffer_alignment && other.texel_buffer_alignment)
+ || (self.texture_block_match && other.texture_block_match)
+ || (self.texture_box_filter && other.texture_box_filter)
+ || (self.texture_compression_astc_hdr && other.texture_compression_astc_hdr)
+ || (self.texture_compression_astc_ldr && other.texture_compression_astc_ldr)
+ || (self.texture_compression_bc && other.texture_compression_bc)
+ || (self.texture_compression_etc2 && other.texture_compression_etc2)
+ || (self.texture_sample_weighted && other.texture_sample_weighted)
+ || (self.tile_properties && other.tile_properties)
+ || (self.timeline_semaphore && other.timeline_semaphore)
+ || (self.transform_feedback && other.transform_feedback)
+ || (self.transform_feedback_preserves_provoking_vertex
+ && other.transform_feedback_preserves_provoking_vertex)
+ || (self.triangle_fans && other.triangle_fans)
+ || (self.uniform_and_storage_buffer16_bit_access
+ && other.uniform_and_storage_buffer16_bit_access)
+ || (self.uniform_and_storage_buffer8_bit_access
+ && other.uniform_and_storage_buffer8_bit_access)
+ || (self.uniform_buffer_standard_layout && other.uniform_buffer_standard_layout)
+ || (self.variable_multisample_rate && other.variable_multisample_rate)
+ || (self.variable_pointers && other.variable_pointers)
+ || (self.variable_pointers_storage_buffer && other.variable_pointers_storage_buffer)
+ || (self.vertex_attribute_access_beyond_stride
+ && other.vertex_attribute_access_beyond_stride)
+ || (self.vertex_attribute_instance_rate_divisor
+ && other.vertex_attribute_instance_rate_divisor)
+ || (self.vertex_attribute_instance_rate_zero_divisor
+ && other.vertex_attribute_instance_rate_zero_divisor)
+ || (self.vertex_input_dynamic_state && other.vertex_input_dynamic_state)
+ || (self.vertex_pipeline_stores_and_atomics && other.vertex_pipeline_stores_and_atomics)
+ || (self.vulkan_memory_model && other.vulkan_memory_model)
+ || (self.vulkan_memory_model_availability_visibility_chains
+ && other.vulkan_memory_model_availability_visibility_chains)
+ || (self.vulkan_memory_model_device_scope && other.vulkan_memory_model_device_scope)
+ || (self.wide_lines && other.wide_lines)
+ || (self.workgroup_memory_explicit_layout && other.workgroup_memory_explicit_layout)
+ || (self.workgroup_memory_explicit_layout16_bit_access
+ && other.workgroup_memory_explicit_layout16_bit_access)
+ || (self.workgroup_memory_explicit_layout8_bit_access
+ && other.workgroup_memory_explicit_layout8_bit_access)
+ || (self.workgroup_memory_explicit_layout_scalar_block_layout
+ && other.workgroup_memory_explicit_layout_scalar_block_layout)
+ || (self.ycbcr2plane444_formats && other.ycbcr2plane444_formats)
+ || (self.ycbcr_image_arrays && other.ycbcr_image_arrays)
+ }
+ #[doc = r" Returns whether all members in `other` are set in `self`."]
+ #[inline]
+ pub const fn contains(&self, other: &Self) -> bool {
+ (self.acceleration_structure || !other.acceleration_structure)
+ && (self.acceleration_structure_capture_replay
+ || !other.acceleration_structure_capture_replay)
+ && (self.acceleration_structure_host_commands
+ || !other.acceleration_structure_host_commands)
+ && (self.acceleration_structure_indirect_build
+ || !other.acceleration_structure_indirect_build)
+ && (self.advanced_blend_coherent_operations
+ || !other.advanced_blend_coherent_operations)
+ && (self.alpha_to_one || !other.alpha_to_one)
+ && (self.amigo_profiling || !other.amigo_profiling)
+ && (self.attachment_feedback_loop_layout || !other.attachment_feedback_loop_layout)
+ && (self.attachment_fragment_shading_rate || !other.attachment_fragment_shading_rate)
+ && (self.border_color_swizzle || !other.border_color_swizzle)
+ && (self.border_color_swizzle_from_image || !other.border_color_swizzle_from_image)
+ && (self.bresenham_lines || !other.bresenham_lines)
+ && (self.buffer_device_address || !other.buffer_device_address)
+ && (self.buffer_device_address_capture_replay
+ || !other.buffer_device_address_capture_replay)
+ && (self.buffer_device_address_multi_device
+ || !other.buffer_device_address_multi_device)
+ && (self.color_write_enable || !other.color_write_enable)
+ && (self.compute_derivative_group_linear || !other.compute_derivative_group_linear)
+ && (self.compute_derivative_group_quads || !other.compute_derivative_group_quads)
+ && (self.compute_full_subgroups || !other.compute_full_subgroups)
+ && (self.conditional_rendering || !other.conditional_rendering)
+ && (self.constant_alpha_color_blend_factors
+ || !other.constant_alpha_color_blend_factors)
+ && (self.cooperative_matrix || !other.cooperative_matrix)
+ && (self.cooperative_matrix_robust_buffer_access
+ || !other.cooperative_matrix_robust_buffer_access)
+ && (self.corner_sampled_image || !other.corner_sampled_image)
+ && (self.coverage_reduction_mode || !other.coverage_reduction_mode)
+ && (self.custom_border_color_without_format
+ || !other.custom_border_color_without_format)
+ && (self.custom_border_colors || !other.custom_border_colors)
+ && (self.decode_mode_shared_exponent || !other.decode_mode_shared_exponent)
+ && (self.dedicated_allocation_image_aliasing
+ || !other.dedicated_allocation_image_aliasing)
+ && (self.depth_bias_clamp || !other.depth_bias_clamp)
+ && (self.depth_bounds || !other.depth_bounds)
+ && (self.depth_clamp || !other.depth_clamp)
+ && (self.depth_clamp_zero_one || !other.depth_clamp_zero_one)
+ && (self.depth_clip_control || !other.depth_clip_control)
+ && (self.depth_clip_enable || !other.depth_clip_enable)
+ && (self.descriptor_binding_acceleration_structure_update_after_bind
+ || !other.descriptor_binding_acceleration_structure_update_after_bind)
+ && (self.descriptor_binding_inline_uniform_block_update_after_bind
+ || !other.descriptor_binding_inline_uniform_block_update_after_bind)
+ && (self.descriptor_binding_partially_bound
+ || !other.descriptor_binding_partially_bound)
+ && (self.descriptor_binding_sampled_image_update_after_bind
+ || !other.descriptor_binding_sampled_image_update_after_bind)
+ && (self.descriptor_binding_storage_buffer_update_after_bind
+ || !other.descriptor_binding_storage_buffer_update_after_bind)
+ && (self.descriptor_binding_storage_image_update_after_bind
+ || !other.descriptor_binding_storage_image_update_after_bind)
+ && (self.descriptor_binding_storage_texel_buffer_update_after_bind
+ || !other.descriptor_binding_storage_texel_buffer_update_after_bind)
+ && (self.descriptor_binding_uniform_buffer_update_after_bind
+ || !other.descriptor_binding_uniform_buffer_update_after_bind)
+ && (self.descriptor_binding_uniform_texel_buffer_update_after_bind
+ || !other.descriptor_binding_uniform_texel_buffer_update_after_bind)
+ && (self.descriptor_binding_update_unused_while_pending
+ || !other.descriptor_binding_update_unused_while_pending)
+ && (self.descriptor_binding_variable_descriptor_count
+ || !other.descriptor_binding_variable_descriptor_count)
+ && (self.descriptor_buffer || !other.descriptor_buffer)
+ && (self.descriptor_buffer_capture_replay || !other.descriptor_buffer_capture_replay)
+ && (self.descriptor_buffer_image_layout_ignored
+ || !other.descriptor_buffer_image_layout_ignored)
+ && (self.descriptor_buffer_push_descriptors
+ || !other.descriptor_buffer_push_descriptors)
+ && (self.descriptor_indexing || !other.descriptor_indexing)
+ && (self.descriptor_set_host_mapping || !other.descriptor_set_host_mapping)
+ && (self.device_coherent_memory || !other.device_coherent_memory)
+ && (self.device_fault || !other.device_fault)
+ && (self.device_fault_vendor_binary || !other.device_fault_vendor_binary)
+ && (self.device_generated_commands || !other.device_generated_commands)
+ && (self.device_memory_report || !other.device_memory_report)
+ && (self.diagnostics_config || !other.diagnostics_config)
+ && (self.draw_indirect_count || !other.draw_indirect_count)
+ && (self.draw_indirect_first_instance || !other.draw_indirect_first_instance)
+ && (self.dual_src_blend || !other.dual_src_blend)
+ && (self.dynamic_rendering || !other.dynamic_rendering)
+ && (self.events || !other.events)
+ && (self.exclusive_scissor || !other.exclusive_scissor)
+ && (self.extended_dynamic_state || !other.extended_dynamic_state)
+ && (self.extended_dynamic_state2 || !other.extended_dynamic_state2)
+ && (self.extended_dynamic_state2_logic_op || !other.extended_dynamic_state2_logic_op)
+ && (self.extended_dynamic_state2_patch_control_points
+ || !other.extended_dynamic_state2_patch_control_points)
+ && (self.extended_dynamic_state3_alpha_to_coverage_enable
+ || !other.extended_dynamic_state3_alpha_to_coverage_enable)
+ && (self.extended_dynamic_state3_alpha_to_one_enable
+ || !other.extended_dynamic_state3_alpha_to_one_enable)
+ && (self.extended_dynamic_state3_color_blend_advanced
+ || !other.extended_dynamic_state3_color_blend_advanced)
+ && (self.extended_dynamic_state3_color_blend_enable
+ || !other.extended_dynamic_state3_color_blend_enable)
+ && (self.extended_dynamic_state3_color_blend_equation
+ || !other.extended_dynamic_state3_color_blend_equation)
+ && (self.extended_dynamic_state3_color_write_mask
+ || !other.extended_dynamic_state3_color_write_mask)
+ && (self.extended_dynamic_state3_conservative_rasterization_mode
+ || !other.extended_dynamic_state3_conservative_rasterization_mode)
+ && (self.extended_dynamic_state3_coverage_modulation_mode
+ || !other.extended_dynamic_state3_coverage_modulation_mode)
+ && (self.extended_dynamic_state3_coverage_modulation_table
+ || !other.extended_dynamic_state3_coverage_modulation_table)
+ && (self.extended_dynamic_state3_coverage_modulation_table_enable
+ || !other.extended_dynamic_state3_coverage_modulation_table_enable)
+ && (self.extended_dynamic_state3_coverage_reduction_mode
+ || !other.extended_dynamic_state3_coverage_reduction_mode)
+ && (self.extended_dynamic_state3_coverage_to_color_enable
+ || !other.extended_dynamic_state3_coverage_to_color_enable)
+ && (self.extended_dynamic_state3_coverage_to_color_location
+ || !other.extended_dynamic_state3_coverage_to_color_location)
+ && (self.extended_dynamic_state3_depth_clamp_enable
+ || !other.extended_dynamic_state3_depth_clamp_enable)
+ && (self.extended_dynamic_state3_depth_clip_enable
+ || !other.extended_dynamic_state3_depth_clip_enable)
+ && (self.extended_dynamic_state3_depth_clip_negative_one_to_one
+ || !other.extended_dynamic_state3_depth_clip_negative_one_to_one)
+ && (self.extended_dynamic_state3_extra_primitive_overestimation_size
+ || !other.extended_dynamic_state3_extra_primitive_overestimation_size)
+ && (self.extended_dynamic_state3_line_rasterization_mode
+ || !other.extended_dynamic_state3_line_rasterization_mode)
+ && (self.extended_dynamic_state3_line_stipple_enable
+ || !other.extended_dynamic_state3_line_stipple_enable)
+ && (self.extended_dynamic_state3_logic_op_enable
+ || !other.extended_dynamic_state3_logic_op_enable)
+ && (self.extended_dynamic_state3_polygon_mode
+ || !other.extended_dynamic_state3_polygon_mode)
+ && (self.extended_dynamic_state3_provoking_vertex_mode
+ || !other.extended_dynamic_state3_provoking_vertex_mode)
+ && (self.extended_dynamic_state3_rasterization_samples
+ || !other.extended_dynamic_state3_rasterization_samples)
+ && (self.extended_dynamic_state3_rasterization_stream
+ || !other.extended_dynamic_state3_rasterization_stream)
+ && (self.extended_dynamic_state3_representative_fragment_test_enable
+ || !other.extended_dynamic_state3_representative_fragment_test_enable)
+ && (self.extended_dynamic_state3_sample_locations_enable
+ || !other.extended_dynamic_state3_sample_locations_enable)
+ && (self.extended_dynamic_state3_sample_mask
+ || !other.extended_dynamic_state3_sample_mask)
+ && (self.extended_dynamic_state3_shading_rate_image_enable
+ || !other.extended_dynamic_state3_shading_rate_image_enable)
+ && (self.extended_dynamic_state3_tessellation_domain_origin
+ || !other.extended_dynamic_state3_tessellation_domain_origin)
+ && (self.extended_dynamic_state3_viewport_swizzle
+ || !other.extended_dynamic_state3_viewport_swizzle)
+ && (self.extended_dynamic_state3_viewport_w_scaling_enable
+ || !other.extended_dynamic_state3_viewport_w_scaling_enable)
+ && (self.external_memory_rdma || !other.external_memory_rdma)
+ && (self.fill_mode_non_solid || !other.fill_mode_non_solid)
+ && (self.format_a4b4g4r4 || !other.format_a4b4g4r4)
+ && (self.format_a4r4g4b4 || !other.format_a4r4g4b4)
+ && (self.format_rgba10x6_without_y_cb_cr_sampler
+ || !other.format_rgba10x6_without_y_cb_cr_sampler)
+ && (self.fragment_density_map || !other.fragment_density_map)
+ && (self.fragment_density_map_deferred || !other.fragment_density_map_deferred)
+ && (self.fragment_density_map_dynamic || !other.fragment_density_map_dynamic)
+ && (self.fragment_density_map_non_subsampled_images
+ || !other.fragment_density_map_non_subsampled_images)
+ && (self.fragment_density_map_offset || !other.fragment_density_map_offset)
+ && (self.fragment_shader_barycentric || !other.fragment_shader_barycentric)
+ && (self.fragment_shader_pixel_interlock || !other.fragment_shader_pixel_interlock)
+ && (self.fragment_shader_sample_interlock || !other.fragment_shader_sample_interlock)
+ && (self.fragment_shader_shading_rate_interlock
+ || !other.fragment_shader_shading_rate_interlock)
+ && (self.fragment_shading_rate_enums || !other.fragment_shading_rate_enums)
+ && (self.fragment_stores_and_atomics || !other.fragment_stores_and_atomics)
+ && (self.full_draw_index_uint32 || !other.full_draw_index_uint32)
+ && (self.geometry_shader || !other.geometry_shader)
+ && (self.geometry_streams || !other.geometry_streams)
+ && (self.global_priority_query || !other.global_priority_query)
+ && (self.graphics_pipeline_library || !other.graphics_pipeline_library)
+ && (self.host_query_reset || !other.host_query_reset)
+ && (self.image2_d_view_of3_d || !other.image2_d_view_of3_d)
+ && (self.image_compression_control || !other.image_compression_control)
+ && (self.image_compression_control_swapchain
+ || !other.image_compression_control_swapchain)
+ && (self.image_cube_array || !other.image_cube_array)
+ && (self.image_footprint || !other.image_footprint)
+ && (self.image_view2_d_on3_d_image || !other.image_view2_d_on3_d_image)
+ && (self.image_view_format_reinterpretation
+ || !other.image_view_format_reinterpretation)
+ && (self.image_view_format_swizzle || !other.image_view_format_swizzle)
+ && (self.imageless_framebuffer || !other.imageless_framebuffer)
+ && (self.independent_blend || !other.independent_blend)
+ && (self.index_type_uint8 || !other.index_type_uint8)
+ && (self.indirect_copy || !other.indirect_copy)
+ && (self.inherited_conditional_rendering || !other.inherited_conditional_rendering)
+ && (self.inherited_queries || !other.inherited_queries)
+ && (self.inherited_viewport_scissor2_d || !other.inherited_viewport_scissor2_d)
+ && (self.inline_uniform_block || !other.inline_uniform_block)
+ && (self.invocation_mask || !other.invocation_mask)
+ && (self.large_points || !other.large_points)
+ && (self.legacy_dithering || !other.legacy_dithering)
+ && (self.linear_color_attachment || !other.linear_color_attachment)
+ && (self.logic_op || !other.logic_op)
+ && (self.maintenance4 || !other.maintenance4)
+ && (self.memory_decompression || !other.memory_decompression)
+ && (self.memory_priority || !other.memory_priority)
+ && (self.mesh_shader || !other.mesh_shader)
+ && (self.mesh_shader_queries || !other.mesh_shader_queries)
+ && (self.micromap || !other.micromap)
+ && (self.micromap_capture_replay || !other.micromap_capture_replay)
+ && (self.micromap_host_commands || !other.micromap_host_commands)
+ && (self.min_lod || !other.min_lod)
+ && (self.multi_draw || !other.multi_draw)
+ && (self.multi_draw_indirect || !other.multi_draw_indirect)
+ && (self.multi_viewport || !other.multi_viewport)
+ && (self.multisample_array_image || !other.multisample_array_image)
+ && (self.multisampled_render_to_single_sampled
+ || !other.multisampled_render_to_single_sampled)
+ && (self.multiview || !other.multiview)
+ && (self.multiview_geometry_shader || !other.multiview_geometry_shader)
+ && (self.multiview_mesh_shader || !other.multiview_mesh_shader)
+ && (self.multiview_per_view_viewports || !other.multiview_per_view_viewports)
+ && (self.multiview_tessellation_shader || !other.multiview_tessellation_shader)
+ && (self.mutable_comparison_samplers || !other.mutable_comparison_samplers)
+ && (self.mutable_descriptor_type || !other.mutable_descriptor_type)
+ && (self.no_invocation_fragment_shading_rates
+ || !other.no_invocation_fragment_shading_rates)
+ && (self.non_seamless_cube_map || !other.non_seamless_cube_map)
+ && (self.null_descriptor || !other.null_descriptor)
+ && (self.occlusion_query_precise || !other.occlusion_query_precise)
+ && (self.optical_flow || !other.optical_flow)
+ && (self.pageable_device_local_memory || !other.pageable_device_local_memory)
+ && (self.performance_counter_multiple_query_pools
+ || !other.performance_counter_multiple_query_pools)
+ && (self.performance_counter_query_pools || !other.performance_counter_query_pools)
+ && (self.pipeline_creation_cache_control || !other.pipeline_creation_cache_control)
+ && (self.pipeline_executable_info || !other.pipeline_executable_info)
+ && (self.pipeline_fragment_shading_rate || !other.pipeline_fragment_shading_rate)
+ && (self.pipeline_properties_identifier || !other.pipeline_properties_identifier)
+ && (self.pipeline_protected_access || !other.pipeline_protected_access)
+ && (self.pipeline_robustness || !other.pipeline_robustness)
+ && (self.pipeline_statistics_query || !other.pipeline_statistics_query)
+ && (self.point_polygons || !other.point_polygons)
+ && (self.present_barrier || !other.present_barrier)
+ && (self.present_id || !other.present_id)
+ && (self.present_wait || !other.present_wait)
+ && (self.primitive_fragment_shading_rate || !other.primitive_fragment_shading_rate)
+ && (self.primitive_fragment_shading_rate_mesh_shader
+ || !other.primitive_fragment_shading_rate_mesh_shader)
+ && (self.primitive_topology_list_restart || !other.primitive_topology_list_restart)
+ && (self.primitive_topology_patch_list_restart
+ || !other.primitive_topology_patch_list_restart)
+ && (self.primitives_generated_query || !other.primitives_generated_query)
+ && (self.primitives_generated_query_with_non_zero_streams
+ || !other.primitives_generated_query_with_non_zero_streams)
+ && (self.primitives_generated_query_with_rasterizer_discard
+ || !other.primitives_generated_query_with_rasterizer_discard)
+ && (self.private_data || !other.private_data)
+ && (self.protected_memory || !other.protected_memory)
+ && (self.provoking_vertex_last || !other.provoking_vertex_last)
+ && (self.rasterization_order_color_attachment_access
+ || !other.rasterization_order_color_attachment_access)
+ && (self.rasterization_order_depth_attachment_access
+ || !other.rasterization_order_depth_attachment_access)
+ && (self.rasterization_order_stencil_attachment_access
+ || !other.rasterization_order_stencil_attachment_access)
+ && (self.ray_query || !other.ray_query)
+ && (self.ray_tracing_invocation_reorder || !other.ray_tracing_invocation_reorder)
+ && (self.ray_tracing_maintenance1 || !other.ray_tracing_maintenance1)
+ && (self.ray_tracing_motion_blur || !other.ray_tracing_motion_blur)
+ && (self.ray_tracing_motion_blur_pipeline_trace_rays_indirect
+ || !other.ray_tracing_motion_blur_pipeline_trace_rays_indirect)
+ && (self.ray_tracing_pipeline || !other.ray_tracing_pipeline)
+ && (self.ray_tracing_pipeline_shader_group_handle_capture_replay
+ || !other.ray_tracing_pipeline_shader_group_handle_capture_replay)
+ && (self.ray_tracing_pipeline_shader_group_handle_capture_replay_mixed
+ || !other.ray_tracing_pipeline_shader_group_handle_capture_replay_mixed)
+ && (self.ray_tracing_pipeline_trace_rays_indirect
+ || !other.ray_tracing_pipeline_trace_rays_indirect)
+ && (self.ray_tracing_pipeline_trace_rays_indirect2
+ || !other.ray_tracing_pipeline_trace_rays_indirect2)
+ && (self.ray_traversal_primitive_culling || !other.ray_traversal_primitive_culling)
+ && (self.rectangular_lines || !other.rectangular_lines)
+ && (self.report_address_binding || !other.report_address_binding)
+ && (self.representative_fragment_test || !other.representative_fragment_test)
+ && (self.robust_buffer_access || !other.robust_buffer_access)
+ && (self.robust_buffer_access2 || !other.robust_buffer_access2)
+ && (self.robust_image_access || !other.robust_image_access)
+ && (self.robust_image_access2 || !other.robust_image_access2)
+ && (self.runtime_descriptor_array || !other.runtime_descriptor_array)
+ && (self.sample_rate_shading || !other.sample_rate_shading)
+ && (self.sampler2_d_view_of3_d || !other.sampler2_d_view_of3_d)
+ && (self.sampler_anisotropy || !other.sampler_anisotropy)
+ && (self.sampler_filter_minmax || !other.sampler_filter_minmax)
+ && (self.sampler_mip_lod_bias || !other.sampler_mip_lod_bias)
+ && (self.sampler_mirror_clamp_to_edge || !other.sampler_mirror_clamp_to_edge)
+ && (self.sampler_ycbcr_conversion || !other.sampler_ycbcr_conversion)
+ && (self.scalar_block_layout || !other.scalar_block_layout)
+ && (self.separate_depth_stencil_layouts || !other.separate_depth_stencil_layouts)
+ && (self.separate_stencil_mask_ref || !other.separate_stencil_mask_ref)
+ && (self.shader_buffer_float16_atomic_add || !other.shader_buffer_float16_atomic_add)
+ && (self.shader_buffer_float16_atomic_min_max
+ || !other.shader_buffer_float16_atomic_min_max)
+ && (self.shader_buffer_float16_atomics || !other.shader_buffer_float16_atomics)
+ && (self.shader_buffer_float32_atomic_add || !other.shader_buffer_float32_atomic_add)
+ && (self.shader_buffer_float32_atomic_min_max
+ || !other.shader_buffer_float32_atomic_min_max)
+ && (self.shader_buffer_float32_atomics || !other.shader_buffer_float32_atomics)
+ && (self.shader_buffer_float64_atomic_add || !other.shader_buffer_float64_atomic_add)
+ && (self.shader_buffer_float64_atomic_min_max
+ || !other.shader_buffer_float64_atomic_min_max)
+ && (self.shader_buffer_float64_atomics || !other.shader_buffer_float64_atomics)
+ && (self.shader_buffer_int64_atomics || !other.shader_buffer_int64_atomics)
+ && (self.shader_clip_distance || !other.shader_clip_distance)
+ && (self.shader_core_builtins || !other.shader_core_builtins)
+ && (self.shader_cull_distance || !other.shader_cull_distance)
+ && (self.shader_demote_to_helper_invocation
+ || !other.shader_demote_to_helper_invocation)
+ && (self.shader_device_clock || !other.shader_device_clock)
+ && (self.shader_draw_parameters || !other.shader_draw_parameters)
+ && (self.shader_early_and_late_fragment_tests
+ || !other.shader_early_and_late_fragment_tests)
+ && (self.shader_float16 || !other.shader_float16)
+ && (self.shader_float64 || !other.shader_float64)
+ && (self.shader_image_float32_atomic_add || !other.shader_image_float32_atomic_add)
+ && (self.shader_image_float32_atomic_min_max
+ || !other.shader_image_float32_atomic_min_max)
+ && (self.shader_image_float32_atomics || !other.shader_image_float32_atomics)
+ && (self.shader_image_gather_extended || !other.shader_image_gather_extended)
+ && (self.shader_image_int64_atomics || !other.shader_image_int64_atomics)
+ && (self.shader_input_attachment_array_dynamic_indexing
+ || !other.shader_input_attachment_array_dynamic_indexing)
+ && (self.shader_input_attachment_array_non_uniform_indexing
+ || !other.shader_input_attachment_array_non_uniform_indexing)
+ && (self.shader_int16 || !other.shader_int16)
+ && (self.shader_int64 || !other.shader_int64)
+ && (self.shader_int8 || !other.shader_int8)
+ && (self.shader_integer_dot_product || !other.shader_integer_dot_product)
+ && (self.shader_integer_functions2 || !other.shader_integer_functions2)
+ && (self.shader_module_identifier || !other.shader_module_identifier)
+ && (self.shader_output_layer || !other.shader_output_layer)
+ && (self.shader_output_viewport_index || !other.shader_output_viewport_index)
+ && (self.shader_resource_min_lod || !other.shader_resource_min_lod)
+ && (self.shader_resource_residency || !other.shader_resource_residency)
+ && (self.shader_sample_rate_interpolation_functions
+ || !other.shader_sample_rate_interpolation_functions)
+ && (self.shader_sampled_image_array_dynamic_indexing
+ || !other.shader_sampled_image_array_dynamic_indexing)
+ && (self.shader_sampled_image_array_non_uniform_indexing
+ || !other.shader_sampled_image_array_non_uniform_indexing)
+ && (self.shader_shared_float16_atomic_add || !other.shader_shared_float16_atomic_add)
+ && (self.shader_shared_float16_atomic_min_max
+ || !other.shader_shared_float16_atomic_min_max)
+ && (self.shader_shared_float16_atomics || !other.shader_shared_float16_atomics)
+ && (self.shader_shared_float32_atomic_add || !other.shader_shared_float32_atomic_add)
+ && (self.shader_shared_float32_atomic_min_max
+ || !other.shader_shared_float32_atomic_min_max)
+ && (self.shader_shared_float32_atomics || !other.shader_shared_float32_atomics)
+ && (self.shader_shared_float64_atomic_add || !other.shader_shared_float64_atomic_add)
+ && (self.shader_shared_float64_atomic_min_max
+ || !other.shader_shared_float64_atomic_min_max)
+ && (self.shader_shared_float64_atomics || !other.shader_shared_float64_atomics)
+ && (self.shader_shared_int64_atomics || !other.shader_shared_int64_atomics)
+ && (self.shader_sm_builtins || !other.shader_sm_builtins)
+ && (self.shader_storage_buffer_array_dynamic_indexing
+ || !other.shader_storage_buffer_array_dynamic_indexing)
+ && (self.shader_storage_buffer_array_non_uniform_indexing
+ || !other.shader_storage_buffer_array_non_uniform_indexing)
+ && (self.shader_storage_image_array_dynamic_indexing
+ || !other.shader_storage_image_array_dynamic_indexing)
+ && (self.shader_storage_image_array_non_uniform_indexing
+ || !other.shader_storage_image_array_non_uniform_indexing)
+ && (self.shader_storage_image_extended_formats
+ || !other.shader_storage_image_extended_formats)
+ && (self.shader_storage_image_multisample || !other.shader_storage_image_multisample)
+ && (self.shader_storage_image_read_without_format
+ || !other.shader_storage_image_read_without_format)
+ && (self.shader_storage_image_write_without_format
+ || !other.shader_storage_image_write_without_format)
+ && (self.shader_storage_texel_buffer_array_dynamic_indexing
+ || !other.shader_storage_texel_buffer_array_dynamic_indexing)
+ && (self.shader_storage_texel_buffer_array_non_uniform_indexing
+ || !other.shader_storage_texel_buffer_array_non_uniform_indexing)
+ && (self.shader_subgroup_clock || !other.shader_subgroup_clock)
+ && (self.shader_subgroup_extended_types || !other.shader_subgroup_extended_types)
+ && (self.shader_subgroup_uniform_control_flow
+ || !other.shader_subgroup_uniform_control_flow)
+ && (self.shader_terminate_invocation || !other.shader_terminate_invocation)
+ && (self.shader_tessellation_and_geometry_point_size
+ || !other.shader_tessellation_and_geometry_point_size)
+ && (self.shader_uniform_buffer_array_dynamic_indexing
+ || !other.shader_uniform_buffer_array_dynamic_indexing)
+ && (self.shader_uniform_buffer_array_non_uniform_indexing
+ || !other.shader_uniform_buffer_array_non_uniform_indexing)
+ && (self.shader_uniform_texel_buffer_array_dynamic_indexing
+ || !other.shader_uniform_texel_buffer_array_dynamic_indexing)
+ && (self.shader_uniform_texel_buffer_array_non_uniform_indexing
+ || !other.shader_uniform_texel_buffer_array_non_uniform_indexing)
+ && (self.shader_zero_initialize_workgroup_memory
+ || !other.shader_zero_initialize_workgroup_memory)
+ && (self.shading_rate_coarse_sample_order || !other.shading_rate_coarse_sample_order)
+ && (self.shading_rate_image || !other.shading_rate_image)
+ && (self.smooth_lines || !other.smooth_lines)
+ && (self.sparse_binding || !other.sparse_binding)
+ && (self.sparse_image_float32_atomic_add || !other.sparse_image_float32_atomic_add)
+ && (self.sparse_image_float32_atomic_min_max
+ || !other.sparse_image_float32_atomic_min_max)
+ && (self.sparse_image_float32_atomics || !other.sparse_image_float32_atomics)
+ && (self.sparse_image_int64_atomics || !other.sparse_image_int64_atomics)
+ && (self.sparse_residency16_samples || !other.sparse_residency16_samples)
+ && (self.sparse_residency2_samples || !other.sparse_residency2_samples)
+ && (self.sparse_residency4_samples || !other.sparse_residency4_samples)
+ && (self.sparse_residency8_samples || !other.sparse_residency8_samples)
+ && (self.sparse_residency_aliased || !other.sparse_residency_aliased)
+ && (self.sparse_residency_buffer || !other.sparse_residency_buffer)
+ && (self.sparse_residency_image2_d || !other.sparse_residency_image2_d)
+ && (self.sparse_residency_image3_d || !other.sparse_residency_image3_d)
+ && (self.stippled_bresenham_lines || !other.stippled_bresenham_lines)
+ && (self.stippled_rectangular_lines || !other.stippled_rectangular_lines)
+ && (self.stippled_smooth_lines || !other.stippled_smooth_lines)
+ && (self.storage_buffer16_bit_access || !other.storage_buffer16_bit_access)
+ && (self.storage_buffer8_bit_access || !other.storage_buffer8_bit_access)
+ && (self.storage_input_output16 || !other.storage_input_output16)
+ && (self.storage_push_constant16 || !other.storage_push_constant16)
+ && (self.storage_push_constant8 || !other.storage_push_constant8)
+ && (self.subgroup_broadcast_dynamic_id || !other.subgroup_broadcast_dynamic_id)
+ && (self.subgroup_size_control || !other.subgroup_size_control)
+ && (self.subpass_merge_feedback || !other.subpass_merge_feedback)
+ && (self.subpass_shading || !other.subpass_shading)
+ && (self.supersample_fragment_shading_rates
+ || !other.supersample_fragment_shading_rates)
+ && (self.swapchain_maintenance1 || !other.swapchain_maintenance1)
+ && (self.synchronization2 || !other.synchronization2)
+ && (self.task_shader || !other.task_shader)
+ && (self.tessellation_isolines || !other.tessellation_isolines)
+ && (self.tessellation_point_mode || !other.tessellation_point_mode)
+ && (self.tessellation_shader || !other.tessellation_shader)
+ && (self.texel_buffer_alignment || !other.texel_buffer_alignment)
+ && (self.texture_block_match || !other.texture_block_match)
+ && (self.texture_box_filter || !other.texture_box_filter)
+ && (self.texture_compression_astc_hdr || !other.texture_compression_astc_hdr)
+ && (self.texture_compression_astc_ldr || !other.texture_compression_astc_ldr)
+ && (self.texture_compression_bc || !other.texture_compression_bc)
+ && (self.texture_compression_etc2 || !other.texture_compression_etc2)
+ && (self.texture_sample_weighted || !other.texture_sample_weighted)
+ && (self.tile_properties || !other.tile_properties)
+ && (self.timeline_semaphore || !other.timeline_semaphore)
+ && (self.transform_feedback || !other.transform_feedback)
+ && (self.transform_feedback_preserves_provoking_vertex
+ || !other.transform_feedback_preserves_provoking_vertex)
+ && (self.triangle_fans || !other.triangle_fans)
+ && (self.uniform_and_storage_buffer16_bit_access
+ || !other.uniform_and_storage_buffer16_bit_access)
+ && (self.uniform_and_storage_buffer8_bit_access
+ || !other.uniform_and_storage_buffer8_bit_access)
+ && (self.uniform_buffer_standard_layout || !other.uniform_buffer_standard_layout)
+ && (self.variable_multisample_rate || !other.variable_multisample_rate)
+ && (self.variable_pointers || !other.variable_pointers)
+ && (self.variable_pointers_storage_buffer || !other.variable_pointers_storage_buffer)
+ && (self.vertex_attribute_access_beyond_stride
+ || !other.vertex_attribute_access_beyond_stride)
+ && (self.vertex_attribute_instance_rate_divisor
+ || !other.vertex_attribute_instance_rate_divisor)
+ && (self.vertex_attribute_instance_rate_zero_divisor
+ || !other.vertex_attribute_instance_rate_zero_divisor)
+ && (self.vertex_input_dynamic_state || !other.vertex_input_dynamic_state)
+ && (self.vertex_pipeline_stores_and_atomics
+ || !other.vertex_pipeline_stores_and_atomics)
+ && (self.vulkan_memory_model || !other.vulkan_memory_model)
+ && (self.vulkan_memory_model_availability_visibility_chains
+ || !other.vulkan_memory_model_availability_visibility_chains)
+ && (self.vulkan_memory_model_device_scope || !other.vulkan_memory_model_device_scope)
+ && (self.wide_lines || !other.wide_lines)
+ && (self.workgroup_memory_explicit_layout || !other.workgroup_memory_explicit_layout)
+ && (self.workgroup_memory_explicit_layout16_bit_access
+ || !other.workgroup_memory_explicit_layout16_bit_access)
+ && (self.workgroup_memory_explicit_layout8_bit_access
+ || !other.workgroup_memory_explicit_layout8_bit_access)
+ && (self.workgroup_memory_explicit_layout_scalar_block_layout
+ || !other.workgroup_memory_explicit_layout_scalar_block_layout)
+ && (self.ycbcr2plane444_formats || !other.ycbcr2plane444_formats)
+ && (self.ycbcr_image_arrays || !other.ycbcr_image_arrays)
+ }
+ #[doc = r" Returns whether all members in `other` are set in `self`."]
+ #[deprecated(since = "0.31.0", note = "Use `contains` instead.")]
+ #[inline]
+ pub const fn is_superset_of(&self, other: &Self) -> bool {
+ self.contains(other)
+ }
+ #[doc = r" Returns the union of `self` and `other`."]
+ #[inline]
+ pub const fn union(&self, other: &Self) -> Self {
+ Self {
+ acceleration_structure: self.acceleration_structure || other.acceleration_structure,
+ acceleration_structure_capture_replay: self.acceleration_structure_capture_replay
+ || other.acceleration_structure_capture_replay,
+ acceleration_structure_host_commands: self.acceleration_structure_host_commands
+ || other.acceleration_structure_host_commands,
+ acceleration_structure_indirect_build: self.acceleration_structure_indirect_build
+ || other.acceleration_structure_indirect_build,
+ advanced_blend_coherent_operations: self.advanced_blend_coherent_operations
+ || other.advanced_blend_coherent_operations,
+ alpha_to_one: self.alpha_to_one || other.alpha_to_one,
+ amigo_profiling: self.amigo_profiling || other.amigo_profiling,
+ attachment_feedback_loop_layout: self.attachment_feedback_loop_layout
+ || other.attachment_feedback_loop_layout,
+ attachment_fragment_shading_rate: self.attachment_fragment_shading_rate
+ || other.attachment_fragment_shading_rate,
+ border_color_swizzle: self.border_color_swizzle || other.border_color_swizzle,
+ border_color_swizzle_from_image: self.border_color_swizzle_from_image
+ || other.border_color_swizzle_from_image,
+ bresenham_lines: self.bresenham_lines || other.bresenham_lines,
+ buffer_device_address: self.buffer_device_address || other.buffer_device_address,
+ buffer_device_address_capture_replay: self.buffer_device_address_capture_replay
+ || other.buffer_device_address_capture_replay,
+ buffer_device_address_multi_device: self.buffer_device_address_multi_device
+ || other.buffer_device_address_multi_device,
+ color_write_enable: self.color_write_enable || other.color_write_enable,
+ compute_derivative_group_linear: self.compute_derivative_group_linear
+ || other.compute_derivative_group_linear,
+ compute_derivative_group_quads: self.compute_derivative_group_quads
+ || other.compute_derivative_group_quads,
+ compute_full_subgroups: self.compute_full_subgroups || other.compute_full_subgroups,
+ conditional_rendering: self.conditional_rendering || other.conditional_rendering,
+ constant_alpha_color_blend_factors: self.constant_alpha_color_blend_factors
+ || other.constant_alpha_color_blend_factors,
+ cooperative_matrix: self.cooperative_matrix || other.cooperative_matrix,
+ cooperative_matrix_robust_buffer_access: self.cooperative_matrix_robust_buffer_access
+ || other.cooperative_matrix_robust_buffer_access,
+ corner_sampled_image: self.corner_sampled_image || other.corner_sampled_image,
+ coverage_reduction_mode: self.coverage_reduction_mode || other.coverage_reduction_mode,
+ custom_border_color_without_format: self.custom_border_color_without_format
+ || other.custom_border_color_without_format,
+ custom_border_colors: self.custom_border_colors || other.custom_border_colors,
+ decode_mode_shared_exponent: self.decode_mode_shared_exponent
+ || other.decode_mode_shared_exponent,
+ dedicated_allocation_image_aliasing: self.dedicated_allocation_image_aliasing
+ || other.dedicated_allocation_image_aliasing,
+ depth_bias_clamp: self.depth_bias_clamp || other.depth_bias_clamp,
+ depth_bounds: self.depth_bounds || other.depth_bounds,
+ depth_clamp: self.depth_clamp || other.depth_clamp,
+ depth_clamp_zero_one: self.depth_clamp_zero_one || other.depth_clamp_zero_one,
+ depth_clip_control: self.depth_clip_control || other.depth_clip_control,
+ depth_clip_enable: self.depth_clip_enable || other.depth_clip_enable,
+ descriptor_binding_acceleration_structure_update_after_bind: self
+ .descriptor_binding_acceleration_structure_update_after_bind
+ || other.descriptor_binding_acceleration_structure_update_after_bind,
+ descriptor_binding_inline_uniform_block_update_after_bind: self
+ .descriptor_binding_inline_uniform_block_update_after_bind
+ || other.descriptor_binding_inline_uniform_block_update_after_bind,
+ descriptor_binding_partially_bound: self.descriptor_binding_partially_bound
+ || other.descriptor_binding_partially_bound,
+ descriptor_binding_sampled_image_update_after_bind: self
+ .descriptor_binding_sampled_image_update_after_bind
+ || other.descriptor_binding_sampled_image_update_after_bind,
+ descriptor_binding_storage_buffer_update_after_bind: self
+ .descriptor_binding_storage_buffer_update_after_bind
+ || other.descriptor_binding_storage_buffer_update_after_bind,
+ descriptor_binding_storage_image_update_after_bind: self
+ .descriptor_binding_storage_image_update_after_bind
+ || other.descriptor_binding_storage_image_update_after_bind,
+ descriptor_binding_storage_texel_buffer_update_after_bind: self
+ .descriptor_binding_storage_texel_buffer_update_after_bind
+ || other.descriptor_binding_storage_texel_buffer_update_after_bind,
+ descriptor_binding_uniform_buffer_update_after_bind: self
+ .descriptor_binding_uniform_buffer_update_after_bind
+ || other.descriptor_binding_uniform_buffer_update_after_bind,
+ descriptor_binding_uniform_texel_buffer_update_after_bind: self
+ .descriptor_binding_uniform_texel_buffer_update_after_bind
+ || other.descriptor_binding_uniform_texel_buffer_update_after_bind,
+ descriptor_binding_update_unused_while_pending: self
+ .descriptor_binding_update_unused_while_pending
+ || other.descriptor_binding_update_unused_while_pending,
+ descriptor_binding_variable_descriptor_count: self
+ .descriptor_binding_variable_descriptor_count
+ || other.descriptor_binding_variable_descriptor_count,
+ descriptor_buffer: self.descriptor_buffer || other.descriptor_buffer,
+ descriptor_buffer_capture_replay: self.descriptor_buffer_capture_replay
+ || other.descriptor_buffer_capture_replay,
+ descriptor_buffer_image_layout_ignored: self.descriptor_buffer_image_layout_ignored
+ || other.descriptor_buffer_image_layout_ignored,
+ descriptor_buffer_push_descriptors: self.descriptor_buffer_push_descriptors
+ || other.descriptor_buffer_push_descriptors,
+ descriptor_indexing: self.descriptor_indexing || other.descriptor_indexing,
+ descriptor_set_host_mapping: self.descriptor_set_host_mapping
+ || other.descriptor_set_host_mapping,
+ device_coherent_memory: self.device_coherent_memory || other.device_coherent_memory,
+ device_fault: self.device_fault || other.device_fault,
+ device_fault_vendor_binary: self.device_fault_vendor_binary
+ || other.device_fault_vendor_binary,
+ device_generated_commands: self.device_generated_commands
+ || other.device_generated_commands,
+ device_memory_report: self.device_memory_report || other.device_memory_report,
+ diagnostics_config: self.diagnostics_config || other.diagnostics_config,
+ draw_indirect_count: self.draw_indirect_count || other.draw_indirect_count,
+ draw_indirect_first_instance: self.draw_indirect_first_instance
+ || other.draw_indirect_first_instance,
+ dual_src_blend: self.dual_src_blend || other.dual_src_blend,
+ dynamic_rendering: self.dynamic_rendering || other.dynamic_rendering,
+ events: self.events || other.events,
+ exclusive_scissor: self.exclusive_scissor || other.exclusive_scissor,
+ extended_dynamic_state: self.extended_dynamic_state || other.extended_dynamic_state,
+ extended_dynamic_state2: self.extended_dynamic_state2 || other.extended_dynamic_state2,
+ extended_dynamic_state2_logic_op: self.extended_dynamic_state2_logic_op
+ || other.extended_dynamic_state2_logic_op,
+ extended_dynamic_state2_patch_control_points: self
+ .extended_dynamic_state2_patch_control_points
+ || other.extended_dynamic_state2_patch_control_points,
+ extended_dynamic_state3_alpha_to_coverage_enable: self
+ .extended_dynamic_state3_alpha_to_coverage_enable
+ || other.extended_dynamic_state3_alpha_to_coverage_enable,
+ extended_dynamic_state3_alpha_to_one_enable: self
+ .extended_dynamic_state3_alpha_to_one_enable
+ || other.extended_dynamic_state3_alpha_to_one_enable,
+ extended_dynamic_state3_color_blend_advanced: self
+ .extended_dynamic_state3_color_blend_advanced
+ || other.extended_dynamic_state3_color_blend_advanced,
+ extended_dynamic_state3_color_blend_enable: self
+ .extended_dynamic_state3_color_blend_enable
+ || other.extended_dynamic_state3_color_blend_enable,
+ extended_dynamic_state3_color_blend_equation: self
+ .extended_dynamic_state3_color_blend_equation
+ || other.extended_dynamic_state3_color_blend_equation,
+ extended_dynamic_state3_color_write_mask: self.extended_dynamic_state3_color_write_mask
+ || other.extended_dynamic_state3_color_write_mask,
+ extended_dynamic_state3_conservative_rasterization_mode: self
+ .extended_dynamic_state3_conservative_rasterization_mode
+ || other.extended_dynamic_state3_conservative_rasterization_mode,
+ extended_dynamic_state3_coverage_modulation_mode: self
+ .extended_dynamic_state3_coverage_modulation_mode
+ || other.extended_dynamic_state3_coverage_modulation_mode,
+ extended_dynamic_state3_coverage_modulation_table: self
+ .extended_dynamic_state3_coverage_modulation_table
+ || other.extended_dynamic_state3_coverage_modulation_table,
+ extended_dynamic_state3_coverage_modulation_table_enable: self
+ .extended_dynamic_state3_coverage_modulation_table_enable
+ || other.extended_dynamic_state3_coverage_modulation_table_enable,
+ extended_dynamic_state3_coverage_reduction_mode: self
+ .extended_dynamic_state3_coverage_reduction_mode
+ || other.extended_dynamic_state3_coverage_reduction_mode,
+ extended_dynamic_state3_coverage_to_color_enable: self
+ .extended_dynamic_state3_coverage_to_color_enable
+ || other.extended_dynamic_state3_coverage_to_color_enable,
+ extended_dynamic_state3_coverage_to_color_location: self
+ .extended_dynamic_state3_coverage_to_color_location
+ || other.extended_dynamic_state3_coverage_to_color_location,
+ extended_dynamic_state3_depth_clamp_enable: self
+ .extended_dynamic_state3_depth_clamp_enable
+ || other.extended_dynamic_state3_depth_clamp_enable,
+ extended_dynamic_state3_depth_clip_enable: self
+ .extended_dynamic_state3_depth_clip_enable
+ || other.extended_dynamic_state3_depth_clip_enable,
+ extended_dynamic_state3_depth_clip_negative_one_to_one: self
+ .extended_dynamic_state3_depth_clip_negative_one_to_one
+ || other.extended_dynamic_state3_depth_clip_negative_one_to_one,
+ extended_dynamic_state3_extra_primitive_overestimation_size: self
+ .extended_dynamic_state3_extra_primitive_overestimation_size
+ || other.extended_dynamic_state3_extra_primitive_overestimation_size,
+ extended_dynamic_state3_line_rasterization_mode: self
+ .extended_dynamic_state3_line_rasterization_mode
+ || other.extended_dynamic_state3_line_rasterization_mode,
+ extended_dynamic_state3_line_stipple_enable: self
+ .extended_dynamic_state3_line_stipple_enable
+ || other.extended_dynamic_state3_line_stipple_enable,
+ extended_dynamic_state3_logic_op_enable: self.extended_dynamic_state3_logic_op_enable
+ || other.extended_dynamic_state3_logic_op_enable,
+ extended_dynamic_state3_polygon_mode: self.extended_dynamic_state3_polygon_mode
+ || other.extended_dynamic_state3_polygon_mode,
+ extended_dynamic_state3_provoking_vertex_mode: self
+ .extended_dynamic_state3_provoking_vertex_mode
+ || other.extended_dynamic_state3_provoking_vertex_mode,
+ extended_dynamic_state3_rasterization_samples: self
+ .extended_dynamic_state3_rasterization_samples
+ || other.extended_dynamic_state3_rasterization_samples,
+ extended_dynamic_state3_rasterization_stream: self
+ .extended_dynamic_state3_rasterization_stream
+ || other.extended_dynamic_state3_rasterization_stream,
+ extended_dynamic_state3_representative_fragment_test_enable: self
+ .extended_dynamic_state3_representative_fragment_test_enable
+ || other.extended_dynamic_state3_representative_fragment_test_enable,
+ extended_dynamic_state3_sample_locations_enable: self
+ .extended_dynamic_state3_sample_locations_enable
+ || other.extended_dynamic_state3_sample_locations_enable,
+ extended_dynamic_state3_sample_mask: self.extended_dynamic_state3_sample_mask
+ || other.extended_dynamic_state3_sample_mask,
+ extended_dynamic_state3_shading_rate_image_enable: self
+ .extended_dynamic_state3_shading_rate_image_enable
+ || other.extended_dynamic_state3_shading_rate_image_enable,
+ extended_dynamic_state3_tessellation_domain_origin: self
+ .extended_dynamic_state3_tessellation_domain_origin
+ || other.extended_dynamic_state3_tessellation_domain_origin,
+ extended_dynamic_state3_viewport_swizzle: self.extended_dynamic_state3_viewport_swizzle
+ || other.extended_dynamic_state3_viewport_swizzle,
+ extended_dynamic_state3_viewport_w_scaling_enable: self
+ .extended_dynamic_state3_viewport_w_scaling_enable
+ || other.extended_dynamic_state3_viewport_w_scaling_enable,
+ external_memory_rdma: self.external_memory_rdma || other.external_memory_rdma,
+ fill_mode_non_solid: self.fill_mode_non_solid || other.fill_mode_non_solid,
+ format_a4b4g4r4: self.format_a4b4g4r4 || other.format_a4b4g4r4,
+ format_a4r4g4b4: self.format_a4r4g4b4 || other.format_a4r4g4b4,
+ format_rgba10x6_without_y_cb_cr_sampler: self.format_rgba10x6_without_y_cb_cr_sampler
+ || other.format_rgba10x6_without_y_cb_cr_sampler,
+ fragment_density_map: self.fragment_density_map || other.fragment_density_map,
+ fragment_density_map_deferred: self.fragment_density_map_deferred
+ || other.fragment_density_map_deferred,
+ fragment_density_map_dynamic: self.fragment_density_map_dynamic
+ || other.fragment_density_map_dynamic,
+ fragment_density_map_non_subsampled_images: self
+ .fragment_density_map_non_subsampled_images
+ || other.fragment_density_map_non_subsampled_images,
+ fragment_density_map_offset: self.fragment_density_map_offset
+ || other.fragment_density_map_offset,
+ fragment_shader_barycentric: self.fragment_shader_barycentric
+ || other.fragment_shader_barycentric,
+ fragment_shader_pixel_interlock: self.fragment_shader_pixel_interlock
+ || other.fragment_shader_pixel_interlock,
+ fragment_shader_sample_interlock: self.fragment_shader_sample_interlock
+ || other.fragment_shader_sample_interlock,
+ fragment_shader_shading_rate_interlock: self.fragment_shader_shading_rate_interlock
+ || other.fragment_shader_shading_rate_interlock,
+ fragment_shading_rate_enums: self.fragment_shading_rate_enums
+ || other.fragment_shading_rate_enums,
+ fragment_stores_and_atomics: self.fragment_stores_and_atomics
+ || other.fragment_stores_and_atomics,
+ full_draw_index_uint32: self.full_draw_index_uint32 || other.full_draw_index_uint32,
+ geometry_shader: self.geometry_shader || other.geometry_shader,
+ geometry_streams: self.geometry_streams || other.geometry_streams,
+ global_priority_query: self.global_priority_query || other.global_priority_query,
+ graphics_pipeline_library: self.graphics_pipeline_library
+ || other.graphics_pipeline_library,
+ host_query_reset: self.host_query_reset || other.host_query_reset,
+ image2_d_view_of3_d: self.image2_d_view_of3_d || other.image2_d_view_of3_d,
+ image_compression_control: self.image_compression_control
+ || other.image_compression_control,
+ image_compression_control_swapchain: self.image_compression_control_swapchain
+ || other.image_compression_control_swapchain,
+ image_cube_array: self.image_cube_array || other.image_cube_array,
+ image_footprint: self.image_footprint || other.image_footprint,
+ image_view2_d_on3_d_image: self.image_view2_d_on3_d_image
+ || other.image_view2_d_on3_d_image,
+ image_view_format_reinterpretation: self.image_view_format_reinterpretation
+ || other.image_view_format_reinterpretation,
+ image_view_format_swizzle: self.image_view_format_swizzle
+ || other.image_view_format_swizzle,
+ imageless_framebuffer: self.imageless_framebuffer || other.imageless_framebuffer,
+ independent_blend: self.independent_blend || other.independent_blend,
+ index_type_uint8: self.index_type_uint8 || other.index_type_uint8,
+ indirect_copy: self.indirect_copy || other.indirect_copy,
+ inherited_conditional_rendering: self.inherited_conditional_rendering
+ || other.inherited_conditional_rendering,
+ inherited_queries: self.inherited_queries || other.inherited_queries,
+ inherited_viewport_scissor2_d: self.inherited_viewport_scissor2_d
+ || other.inherited_viewport_scissor2_d,
+ inline_uniform_block: self.inline_uniform_block || other.inline_uniform_block,
+ invocation_mask: self.invocation_mask || other.invocation_mask,
+ large_points: self.large_points || other.large_points,
+ legacy_dithering: self.legacy_dithering || other.legacy_dithering,
+ linear_color_attachment: self.linear_color_attachment || other.linear_color_attachment,
+ logic_op: self.logic_op || other.logic_op,
+ maintenance4: self.maintenance4 || other.maintenance4,
+ memory_decompression: self.memory_decompression || other.memory_decompression,
+ memory_priority: self.memory_priority || other.memory_priority,
+ mesh_shader: self.mesh_shader || other.mesh_shader,
+ mesh_shader_queries: self.mesh_shader_queries || other.mesh_shader_queries,
+ micromap: self.micromap || other.micromap,
+ micromap_capture_replay: self.micromap_capture_replay || other.micromap_capture_replay,
+ micromap_host_commands: self.micromap_host_commands || other.micromap_host_commands,
+ min_lod: self.min_lod || other.min_lod,
+ multi_draw: self.multi_draw || other.multi_draw,
+ multi_draw_indirect: self.multi_draw_indirect || other.multi_draw_indirect,
+ multi_viewport: self.multi_viewport || other.multi_viewport,
+ multisample_array_image: self.multisample_array_image || other.multisample_array_image,
+ multisampled_render_to_single_sampled: self.multisampled_render_to_single_sampled
+ || other.multisampled_render_to_single_sampled,
+ multiview: self.multiview || other.multiview,
+ multiview_geometry_shader: self.multiview_geometry_shader
+ || other.multiview_geometry_shader,
+ multiview_mesh_shader: self.multiview_mesh_shader || other.multiview_mesh_shader,
+ multiview_per_view_viewports: self.multiview_per_view_viewports
+ || other.multiview_per_view_viewports,
+ multiview_tessellation_shader: self.multiview_tessellation_shader
+ || other.multiview_tessellation_shader,
+ mutable_comparison_samplers: self.mutable_comparison_samplers
+ || other.mutable_comparison_samplers,
+ mutable_descriptor_type: self.mutable_descriptor_type || other.mutable_descriptor_type,
+ no_invocation_fragment_shading_rates: self.no_invocation_fragment_shading_rates
+ || other.no_invocation_fragment_shading_rates,
+ non_seamless_cube_map: self.non_seamless_cube_map || other.non_seamless_cube_map,
+ null_descriptor: self.null_descriptor || other.null_descriptor,
+ occlusion_query_precise: self.occlusion_query_precise || other.occlusion_query_precise,
+ optical_flow: self.optical_flow || other.optical_flow,
+ pageable_device_local_memory: self.pageable_device_local_memory
+ || other.pageable_device_local_memory,
+ performance_counter_multiple_query_pools: self.performance_counter_multiple_query_pools
+ || other.performance_counter_multiple_query_pools,
+ performance_counter_query_pools: self.performance_counter_query_pools
+ || other.performance_counter_query_pools,
+ pipeline_creation_cache_control: self.pipeline_creation_cache_control
+ || other.pipeline_creation_cache_control,
+ pipeline_executable_info: self.pipeline_executable_info
+ || other.pipeline_executable_info,
+ pipeline_fragment_shading_rate: self.pipeline_fragment_shading_rate
+ || other.pipeline_fragment_shading_rate,
+ pipeline_properties_identifier: self.pipeline_properties_identifier
+ || other.pipeline_properties_identifier,
+ pipeline_protected_access: self.pipeline_protected_access
+ || other.pipeline_protected_access,
+ pipeline_robustness: self.pipeline_robustness || other.pipeline_robustness,
+ pipeline_statistics_query: self.pipeline_statistics_query
+ || other.pipeline_statistics_query,
+ point_polygons: self.point_polygons || other.point_polygons,
+ present_barrier: self.present_barrier || other.present_barrier,
+ present_id: self.present_id || other.present_id,
+ present_wait: self.present_wait || other.present_wait,
+ primitive_fragment_shading_rate: self.primitive_fragment_shading_rate
+ || other.primitive_fragment_shading_rate,
+ primitive_fragment_shading_rate_mesh_shader: self
+ .primitive_fragment_shading_rate_mesh_shader
+ || other.primitive_fragment_shading_rate_mesh_shader,
+ primitive_topology_list_restart: self.primitive_topology_list_restart
+ || other.primitive_topology_list_restart,
+ primitive_topology_patch_list_restart: self.primitive_topology_patch_list_restart
+ || other.primitive_topology_patch_list_restart,
+ primitives_generated_query: self.primitives_generated_query
+ || other.primitives_generated_query,
+ primitives_generated_query_with_non_zero_streams: self
+ .primitives_generated_query_with_non_zero_streams
+ || other.primitives_generated_query_with_non_zero_streams,
+ primitives_generated_query_with_rasterizer_discard: self
+ .primitives_generated_query_with_rasterizer_discard
+ || other.primitives_generated_query_with_rasterizer_discard,
+ private_data: self.private_data || other.private_data,
+ protected_memory: self.protected_memory || other.protected_memory,
+ provoking_vertex_last: self.provoking_vertex_last || other.provoking_vertex_last,
+ rasterization_order_color_attachment_access: self
+ .rasterization_order_color_attachment_access
+ || other.rasterization_order_color_attachment_access,
+ rasterization_order_depth_attachment_access: self
+ .rasterization_order_depth_attachment_access
+ || other.rasterization_order_depth_attachment_access,
+ rasterization_order_stencil_attachment_access: self
+ .rasterization_order_stencil_attachment_access
+ || other.rasterization_order_stencil_attachment_access,
+ ray_query: self.ray_query || other.ray_query,
+ ray_tracing_invocation_reorder: self.ray_tracing_invocation_reorder
+ || other.ray_tracing_invocation_reorder,
+ ray_tracing_maintenance1: self.ray_tracing_maintenance1
+ || other.ray_tracing_maintenance1,
+ ray_tracing_motion_blur: self.ray_tracing_motion_blur || other.ray_tracing_motion_blur,
+ ray_tracing_motion_blur_pipeline_trace_rays_indirect: self
+ .ray_tracing_motion_blur_pipeline_trace_rays_indirect
+ || other.ray_tracing_motion_blur_pipeline_trace_rays_indirect,
+ ray_tracing_pipeline: self.ray_tracing_pipeline || other.ray_tracing_pipeline,
+ ray_tracing_pipeline_shader_group_handle_capture_replay: self
+ .ray_tracing_pipeline_shader_group_handle_capture_replay
+ || other.ray_tracing_pipeline_shader_group_handle_capture_replay,
+ ray_tracing_pipeline_shader_group_handle_capture_replay_mixed: self
+ .ray_tracing_pipeline_shader_group_handle_capture_replay_mixed
+ || other.ray_tracing_pipeline_shader_group_handle_capture_replay_mixed,
+ ray_tracing_pipeline_trace_rays_indirect: self.ray_tracing_pipeline_trace_rays_indirect
+ || other.ray_tracing_pipeline_trace_rays_indirect,
+ ray_tracing_pipeline_trace_rays_indirect2: self
+ .ray_tracing_pipeline_trace_rays_indirect2
+ || other.ray_tracing_pipeline_trace_rays_indirect2,
+ ray_traversal_primitive_culling: self.ray_traversal_primitive_culling
+ || other.ray_traversal_primitive_culling,
+ rectangular_lines: self.rectangular_lines || other.rectangular_lines,
+ report_address_binding: self.report_address_binding || other.report_address_binding,
+ representative_fragment_test: self.representative_fragment_test
+ || other.representative_fragment_test,
+ robust_buffer_access: self.robust_buffer_access || other.robust_buffer_access,
+ robust_buffer_access2: self.robust_buffer_access2 || other.robust_buffer_access2,
+ robust_image_access: self.robust_image_access || other.robust_image_access,
+ robust_image_access2: self.robust_image_access2 || other.robust_image_access2,
+ runtime_descriptor_array: self.runtime_descriptor_array
+ || other.runtime_descriptor_array,
+ sample_rate_shading: self.sample_rate_shading || other.sample_rate_shading,
+ sampler2_d_view_of3_d: self.sampler2_d_view_of3_d || other.sampler2_d_view_of3_d,
+ sampler_anisotropy: self.sampler_anisotropy || other.sampler_anisotropy,
+ sampler_filter_minmax: self.sampler_filter_minmax || other.sampler_filter_minmax,
+ sampler_mip_lod_bias: self.sampler_mip_lod_bias || other.sampler_mip_lod_bias,
+ sampler_mirror_clamp_to_edge: self.sampler_mirror_clamp_to_edge
+ || other.sampler_mirror_clamp_to_edge,
+ sampler_ycbcr_conversion: self.sampler_ycbcr_conversion
+ || other.sampler_ycbcr_conversion,
+ scalar_block_layout: self.scalar_block_layout || other.scalar_block_layout,
+ separate_depth_stencil_layouts: self.separate_depth_stencil_layouts
+ || other.separate_depth_stencil_layouts,
+ separate_stencil_mask_ref: self.separate_stencil_mask_ref
+ || other.separate_stencil_mask_ref,
+ shader_buffer_float16_atomic_add: self.shader_buffer_float16_atomic_add
+ || other.shader_buffer_float16_atomic_add,
+ shader_buffer_float16_atomic_min_max: self.shader_buffer_float16_atomic_min_max
+ || other.shader_buffer_float16_atomic_min_max,
+ shader_buffer_float16_atomics: self.shader_buffer_float16_atomics
+ || other.shader_buffer_float16_atomics,
+ shader_buffer_float32_atomic_add: self.shader_buffer_float32_atomic_add
+ || other.shader_buffer_float32_atomic_add,
+ shader_buffer_float32_atomic_min_max: self.shader_buffer_float32_atomic_min_max
+ || other.shader_buffer_float32_atomic_min_max,
+ shader_buffer_float32_atomics: self.shader_buffer_float32_atomics
+ || other.shader_buffer_float32_atomics,
+ shader_buffer_float64_atomic_add: self.shader_buffer_float64_atomic_add
+ || other.shader_buffer_float64_atomic_add,
+ shader_buffer_float64_atomic_min_max: self.shader_buffer_float64_atomic_min_max
+ || other.shader_buffer_float64_atomic_min_max,
+ shader_buffer_float64_atomics: self.shader_buffer_float64_atomics
+ || other.shader_buffer_float64_atomics,
+ shader_buffer_int64_atomics: self.shader_buffer_int64_atomics
+ || other.shader_buffer_int64_atomics,
+ shader_clip_distance: self.shader_clip_distance || other.shader_clip_distance,
+ shader_core_builtins: self.shader_core_builtins || other.shader_core_builtins,
+ shader_cull_distance: self.shader_cull_distance || other.shader_cull_distance,
+ shader_demote_to_helper_invocation: self.shader_demote_to_helper_invocation
+ || other.shader_demote_to_helper_invocation,
+ shader_device_clock: self.shader_device_clock || other.shader_device_clock,
+ shader_draw_parameters: self.shader_draw_parameters || other.shader_draw_parameters,
+ shader_early_and_late_fragment_tests: self.shader_early_and_late_fragment_tests
+ || other.shader_early_and_late_fragment_tests,
+ shader_float16: self.shader_float16 || other.shader_float16,
+ shader_float64: self.shader_float64 || other.shader_float64,
+ shader_image_float32_atomic_add: self.shader_image_float32_atomic_add
+ || other.shader_image_float32_atomic_add,
+ shader_image_float32_atomic_min_max: self.shader_image_float32_atomic_min_max
+ || other.shader_image_float32_atomic_min_max,
+ shader_image_float32_atomics: self.shader_image_float32_atomics
+ || other.shader_image_float32_atomics,
+ shader_image_gather_extended: self.shader_image_gather_extended
+ || other.shader_image_gather_extended,
+ shader_image_int64_atomics: self.shader_image_int64_atomics
+ || other.shader_image_int64_atomics,
+ shader_input_attachment_array_dynamic_indexing: self
+ .shader_input_attachment_array_dynamic_indexing
+ || other.shader_input_attachment_array_dynamic_indexing,
+ shader_input_attachment_array_non_uniform_indexing: self
+ .shader_input_attachment_array_non_uniform_indexing
+ || other.shader_input_attachment_array_non_uniform_indexing,
+ shader_int16: self.shader_int16 || other.shader_int16,
+ shader_int64: self.shader_int64 || other.shader_int64,
+ shader_int8: self.shader_int8 || other.shader_int8,
+ shader_integer_dot_product: self.shader_integer_dot_product
+ || other.shader_integer_dot_product,
+ shader_integer_functions2: self.shader_integer_functions2
+ || other.shader_integer_functions2,
+ shader_module_identifier: self.shader_module_identifier
+ || other.shader_module_identifier,
+ shader_output_layer: self.shader_output_layer || other.shader_output_layer,
+ shader_output_viewport_index: self.shader_output_viewport_index
+ || other.shader_output_viewport_index,
+ shader_resource_min_lod: self.shader_resource_min_lod || other.shader_resource_min_lod,
+ shader_resource_residency: self.shader_resource_residency
+ || other.shader_resource_residency,
+ shader_sample_rate_interpolation_functions: self
+ .shader_sample_rate_interpolation_functions
+ || other.shader_sample_rate_interpolation_functions,
+ shader_sampled_image_array_dynamic_indexing: self
+ .shader_sampled_image_array_dynamic_indexing
+ || other.shader_sampled_image_array_dynamic_indexing,
+ shader_sampled_image_array_non_uniform_indexing: self
+ .shader_sampled_image_array_non_uniform_indexing
+ || other.shader_sampled_image_array_non_uniform_indexing,
+ shader_shared_float16_atomic_add: self.shader_shared_float16_atomic_add
+ || other.shader_shared_float16_atomic_add,
+ shader_shared_float16_atomic_min_max: self.shader_shared_float16_atomic_min_max
+ || other.shader_shared_float16_atomic_min_max,
+ shader_shared_float16_atomics: self.shader_shared_float16_atomics
+ || other.shader_shared_float16_atomics,
+ shader_shared_float32_atomic_add: self.shader_shared_float32_atomic_add
+ || other.shader_shared_float32_atomic_add,
+ shader_shared_float32_atomic_min_max: self.shader_shared_float32_atomic_min_max
+ || other.shader_shared_float32_atomic_min_max,
+ shader_shared_float32_atomics: self.shader_shared_float32_atomics
+ || other.shader_shared_float32_atomics,
+ shader_shared_float64_atomic_add: self.shader_shared_float64_atomic_add
+ || other.shader_shared_float64_atomic_add,
+ shader_shared_float64_atomic_min_max: self.shader_shared_float64_atomic_min_max
+ || other.shader_shared_float64_atomic_min_max,
+ shader_shared_float64_atomics: self.shader_shared_float64_atomics
+ || other.shader_shared_float64_atomics,
+ shader_shared_int64_atomics: self.shader_shared_int64_atomics
+ || other.shader_shared_int64_atomics,
+ shader_sm_builtins: self.shader_sm_builtins || other.shader_sm_builtins,
+ shader_storage_buffer_array_dynamic_indexing: self
+ .shader_storage_buffer_array_dynamic_indexing
+ || other.shader_storage_buffer_array_dynamic_indexing,
+ shader_storage_buffer_array_non_uniform_indexing: self
+ .shader_storage_buffer_array_non_uniform_indexing
+ || other.shader_storage_buffer_array_non_uniform_indexing,
+ shader_storage_image_array_dynamic_indexing: self
+ .shader_storage_image_array_dynamic_indexing
+ || other.shader_storage_image_array_dynamic_indexing,
+ shader_storage_image_array_non_uniform_indexing: self
+ .shader_storage_image_array_non_uniform_indexing
+ || other.shader_storage_image_array_non_uniform_indexing,
+ shader_storage_image_extended_formats: self.shader_storage_image_extended_formats
+ || other.shader_storage_image_extended_formats,
+ shader_storage_image_multisample: self.shader_storage_image_multisample
+ || other.shader_storage_image_multisample,
+ shader_storage_image_read_without_format: self.shader_storage_image_read_without_format
+ || other.shader_storage_image_read_without_format,
+ shader_storage_image_write_without_format: self
+ .shader_storage_image_write_without_format
+ || other.shader_storage_image_write_without_format,
+ shader_storage_texel_buffer_array_dynamic_indexing: self
+ .shader_storage_texel_buffer_array_dynamic_indexing
+ || other.shader_storage_texel_buffer_array_dynamic_indexing,
+ shader_storage_texel_buffer_array_non_uniform_indexing: self
+ .shader_storage_texel_buffer_array_non_uniform_indexing
+ || other.shader_storage_texel_buffer_array_non_uniform_indexing,
+ shader_subgroup_clock: self.shader_subgroup_clock || other.shader_subgroup_clock,
+ shader_subgroup_extended_types: self.shader_subgroup_extended_types
+ || other.shader_subgroup_extended_types,
+ shader_subgroup_uniform_control_flow: self.shader_subgroup_uniform_control_flow
+ || other.shader_subgroup_uniform_control_flow,
+ shader_terminate_invocation: self.shader_terminate_invocation
+ || other.shader_terminate_invocation,
+ shader_tessellation_and_geometry_point_size: self
+ .shader_tessellation_and_geometry_point_size
+ || other.shader_tessellation_and_geometry_point_size,
+ shader_uniform_buffer_array_dynamic_indexing: self
+ .shader_uniform_buffer_array_dynamic_indexing
+ || other.shader_uniform_buffer_array_dynamic_indexing,
+ shader_uniform_buffer_array_non_uniform_indexing: self
+ .shader_uniform_buffer_array_non_uniform_indexing
+ || other.shader_uniform_buffer_array_non_uniform_indexing,
+ shader_uniform_texel_buffer_array_dynamic_indexing: self
+ .shader_uniform_texel_buffer_array_dynamic_indexing
+ || other.shader_uniform_texel_buffer_array_dynamic_indexing,
+ shader_uniform_texel_buffer_array_non_uniform_indexing: self
+ .shader_uniform_texel_buffer_array_non_uniform_indexing
+ || other.shader_uniform_texel_buffer_array_non_uniform_indexing,
+ shader_zero_initialize_workgroup_memory: self.shader_zero_initialize_workgroup_memory
+ || other.shader_zero_initialize_workgroup_memory,
+ shading_rate_coarse_sample_order: self.shading_rate_coarse_sample_order
+ || other.shading_rate_coarse_sample_order,
+ shading_rate_image: self.shading_rate_image || other.shading_rate_image,
+ smooth_lines: self.smooth_lines || other.smooth_lines,
+ sparse_binding: self.sparse_binding || other.sparse_binding,
+ sparse_image_float32_atomic_add: self.sparse_image_float32_atomic_add
+ || other.sparse_image_float32_atomic_add,
+ sparse_image_float32_atomic_min_max: self.sparse_image_float32_atomic_min_max
+ || other.sparse_image_float32_atomic_min_max,
+ sparse_image_float32_atomics: self.sparse_image_float32_atomics
+ || other.sparse_image_float32_atomics,
+ sparse_image_int64_atomics: self.sparse_image_int64_atomics
+ || other.sparse_image_int64_atomics,
+ sparse_residency16_samples: self.sparse_residency16_samples
+ || other.sparse_residency16_samples,
+ sparse_residency2_samples: self.sparse_residency2_samples
+ || other.sparse_residency2_samples,
+ sparse_residency4_samples: self.sparse_residency4_samples
+ || other.sparse_residency4_samples,
+ sparse_residency8_samples: self.sparse_residency8_samples
+ || other.sparse_residency8_samples,
+ sparse_residency_aliased: self.sparse_residency_aliased
+ || other.sparse_residency_aliased,
+ sparse_residency_buffer: self.sparse_residency_buffer || other.sparse_residency_buffer,
+ sparse_residency_image2_d: self.sparse_residency_image2_d
+ || other.sparse_residency_image2_d,
+ sparse_residency_image3_d: self.sparse_residency_image3_d
+ || other.sparse_residency_image3_d,
+ stippled_bresenham_lines: self.stippled_bresenham_lines
+ || other.stippled_bresenham_lines,
+ stippled_rectangular_lines: self.stippled_rectangular_lines
+ || other.stippled_rectangular_lines,
+ stippled_smooth_lines: self.stippled_smooth_lines || other.stippled_smooth_lines,
+ storage_buffer16_bit_access: self.storage_buffer16_bit_access
+ || other.storage_buffer16_bit_access,
+ storage_buffer8_bit_access: self.storage_buffer8_bit_access
+ || other.storage_buffer8_bit_access,
+ storage_input_output16: self.storage_input_output16 || other.storage_input_output16,
+ storage_push_constant16: self.storage_push_constant16 || other.storage_push_constant16,
+ storage_push_constant8: self.storage_push_constant8 || other.storage_push_constant8,
+ subgroup_broadcast_dynamic_id: self.subgroup_broadcast_dynamic_id
+ || other.subgroup_broadcast_dynamic_id,
+ subgroup_size_control: self.subgroup_size_control || other.subgroup_size_control,
+ subpass_merge_feedback: self.subpass_merge_feedback || other.subpass_merge_feedback,
+ subpass_shading: self.subpass_shading || other.subpass_shading,
+ supersample_fragment_shading_rates: self.supersample_fragment_shading_rates
+ || other.supersample_fragment_shading_rates,
+ swapchain_maintenance1: self.swapchain_maintenance1 || other.swapchain_maintenance1,
+ synchronization2: self.synchronization2 || other.synchronization2,
+ task_shader: self.task_shader || other.task_shader,
+ tessellation_isolines: self.tessellation_isolines || other.tessellation_isolines,
+ tessellation_point_mode: self.tessellation_point_mode || other.tessellation_point_mode,
+ tessellation_shader: self.tessellation_shader || other.tessellation_shader,
+ texel_buffer_alignment: self.texel_buffer_alignment || other.texel_buffer_alignment,
+ texture_block_match: self.texture_block_match || other.texture_block_match,
+ texture_box_filter: self.texture_box_filter || other.texture_box_filter,
+ texture_compression_astc_hdr: self.texture_compression_astc_hdr
+ || other.texture_compression_astc_hdr,
+ texture_compression_astc_ldr: self.texture_compression_astc_ldr
+ || other.texture_compression_astc_ldr,
+ texture_compression_bc: self.texture_compression_bc || other.texture_compression_bc,
+ texture_compression_etc2: self.texture_compression_etc2
+ || other.texture_compression_etc2,
+ texture_sample_weighted: self.texture_sample_weighted || other.texture_sample_weighted,
+ tile_properties: self.tile_properties || other.tile_properties,
+ timeline_semaphore: self.timeline_semaphore || other.timeline_semaphore,
+ transform_feedback: self.transform_feedback || other.transform_feedback,
+ transform_feedback_preserves_provoking_vertex: self
+ .transform_feedback_preserves_provoking_vertex
+ || other.transform_feedback_preserves_provoking_vertex,
+ triangle_fans: self.triangle_fans || other.triangle_fans,
+ uniform_and_storage_buffer16_bit_access: self.uniform_and_storage_buffer16_bit_access
+ || other.uniform_and_storage_buffer16_bit_access,
+ uniform_and_storage_buffer8_bit_access: self.uniform_and_storage_buffer8_bit_access
+ || other.uniform_and_storage_buffer8_bit_access,
+ uniform_buffer_standard_layout: self.uniform_buffer_standard_layout
+ || other.uniform_buffer_standard_layout,
+ variable_multisample_rate: self.variable_multisample_rate
+ || other.variable_multisample_rate,
+ variable_pointers: self.variable_pointers || other.variable_pointers,
+ variable_pointers_storage_buffer: self.variable_pointers_storage_buffer
+ || other.variable_pointers_storage_buffer,
+ vertex_attribute_access_beyond_stride: self.vertex_attribute_access_beyond_stride
+ || other.vertex_attribute_access_beyond_stride,
+ vertex_attribute_instance_rate_divisor: self.vertex_attribute_instance_rate_divisor
+ || other.vertex_attribute_instance_rate_divisor,
+ vertex_attribute_instance_rate_zero_divisor: self
+ .vertex_attribute_instance_rate_zero_divisor
+ || other.vertex_attribute_instance_rate_zero_divisor,
+ vertex_input_dynamic_state: self.vertex_input_dynamic_state
+ || other.vertex_input_dynamic_state,
+ vertex_pipeline_stores_and_atomics: self.vertex_pipeline_stores_and_atomics
+ || other.vertex_pipeline_stores_and_atomics,
+ vulkan_memory_model: self.vulkan_memory_model || other.vulkan_memory_model,
+ vulkan_memory_model_availability_visibility_chains: self
+ .vulkan_memory_model_availability_visibility_chains
+ || other.vulkan_memory_model_availability_visibility_chains,
+ vulkan_memory_model_device_scope: self.vulkan_memory_model_device_scope
+ || other.vulkan_memory_model_device_scope,
+ wide_lines: self.wide_lines || other.wide_lines,
+ workgroup_memory_explicit_layout: self.workgroup_memory_explicit_layout
+ || other.workgroup_memory_explicit_layout,
+ workgroup_memory_explicit_layout16_bit_access: self
+ .workgroup_memory_explicit_layout16_bit_access
+ || other.workgroup_memory_explicit_layout16_bit_access,
+ workgroup_memory_explicit_layout8_bit_access: self
+ .workgroup_memory_explicit_layout8_bit_access
+ || other.workgroup_memory_explicit_layout8_bit_access,
+ workgroup_memory_explicit_layout_scalar_block_layout: self
+ .workgroup_memory_explicit_layout_scalar_block_layout
+ || other.workgroup_memory_explicit_layout_scalar_block_layout,
+ ycbcr2plane444_formats: self.ycbcr2plane444_formats || other.ycbcr2plane444_formats,
+ ycbcr_image_arrays: self.ycbcr_image_arrays || other.ycbcr_image_arrays,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+ #[doc = r" Returns the intersection of `self` and `other`."]
+ #[inline]
+ pub const fn intersection(&self, other: &Self) -> Self {
+ Self {
+ acceleration_structure: self.acceleration_structure && other.acceleration_structure,
+ acceleration_structure_capture_replay: self.acceleration_structure_capture_replay
+ && other.acceleration_structure_capture_replay,
+ acceleration_structure_host_commands: self.acceleration_structure_host_commands
+ && other.acceleration_structure_host_commands,
+ acceleration_structure_indirect_build: self.acceleration_structure_indirect_build
+ && other.acceleration_structure_indirect_build,
+ advanced_blend_coherent_operations: self.advanced_blend_coherent_operations
+ && other.advanced_blend_coherent_operations,
+ alpha_to_one: self.alpha_to_one && other.alpha_to_one,
+ amigo_profiling: self.amigo_profiling && other.amigo_profiling,
+ attachment_feedback_loop_layout: self.attachment_feedback_loop_layout
+ && other.attachment_feedback_loop_layout,
+ attachment_fragment_shading_rate: self.attachment_fragment_shading_rate
+ && other.attachment_fragment_shading_rate,
+ border_color_swizzle: self.border_color_swizzle && other.border_color_swizzle,
+ border_color_swizzle_from_image: self.border_color_swizzle_from_image
+ && other.border_color_swizzle_from_image,
+ bresenham_lines: self.bresenham_lines && other.bresenham_lines,
+ buffer_device_address: self.buffer_device_address && other.buffer_device_address,
+ buffer_device_address_capture_replay: self.buffer_device_address_capture_replay
+ && other.buffer_device_address_capture_replay,
+ buffer_device_address_multi_device: self.buffer_device_address_multi_device
+ && other.buffer_device_address_multi_device,
+ color_write_enable: self.color_write_enable && other.color_write_enable,
+ compute_derivative_group_linear: self.compute_derivative_group_linear
+ && other.compute_derivative_group_linear,
+ compute_derivative_group_quads: self.compute_derivative_group_quads
+ && other.compute_derivative_group_quads,
+ compute_full_subgroups: self.compute_full_subgroups && other.compute_full_subgroups,
+ conditional_rendering: self.conditional_rendering && other.conditional_rendering,
+ constant_alpha_color_blend_factors: self.constant_alpha_color_blend_factors
+ && other.constant_alpha_color_blend_factors,
+ cooperative_matrix: self.cooperative_matrix && other.cooperative_matrix,
+ cooperative_matrix_robust_buffer_access: self.cooperative_matrix_robust_buffer_access
+ && other.cooperative_matrix_robust_buffer_access,
+ corner_sampled_image: self.corner_sampled_image && other.corner_sampled_image,
+ coverage_reduction_mode: self.coverage_reduction_mode && other.coverage_reduction_mode,
+ custom_border_color_without_format: self.custom_border_color_without_format
+ && other.custom_border_color_without_format,
+ custom_border_colors: self.custom_border_colors && other.custom_border_colors,
+ decode_mode_shared_exponent: self.decode_mode_shared_exponent
+ && other.decode_mode_shared_exponent,
+ dedicated_allocation_image_aliasing: self.dedicated_allocation_image_aliasing
+ && other.dedicated_allocation_image_aliasing,
+ depth_bias_clamp: self.depth_bias_clamp && other.depth_bias_clamp,
+ depth_bounds: self.depth_bounds && other.depth_bounds,
+ depth_clamp: self.depth_clamp && other.depth_clamp,
+ depth_clamp_zero_one: self.depth_clamp_zero_one && other.depth_clamp_zero_one,
+ depth_clip_control: self.depth_clip_control && other.depth_clip_control,
+ depth_clip_enable: self.depth_clip_enable && other.depth_clip_enable,
+ descriptor_binding_acceleration_structure_update_after_bind: self
+ .descriptor_binding_acceleration_structure_update_after_bind
+ && other.descriptor_binding_acceleration_structure_update_after_bind,
+ descriptor_binding_inline_uniform_block_update_after_bind: self
+ .descriptor_binding_inline_uniform_block_update_after_bind
+ && other.descriptor_binding_inline_uniform_block_update_after_bind,
+ descriptor_binding_partially_bound: self.descriptor_binding_partially_bound
+ && other.descriptor_binding_partially_bound,
+ descriptor_binding_sampled_image_update_after_bind: self
+ .descriptor_binding_sampled_image_update_after_bind
+ && other.descriptor_binding_sampled_image_update_after_bind,
+ descriptor_binding_storage_buffer_update_after_bind: self
+ .descriptor_binding_storage_buffer_update_after_bind
+ && other.descriptor_binding_storage_buffer_update_after_bind,
+ descriptor_binding_storage_image_update_after_bind: self
+ .descriptor_binding_storage_image_update_after_bind
+ && other.descriptor_binding_storage_image_update_after_bind,
+ descriptor_binding_storage_texel_buffer_update_after_bind: self
+ .descriptor_binding_storage_texel_buffer_update_after_bind
+ && other.descriptor_binding_storage_texel_buffer_update_after_bind,
+ descriptor_binding_uniform_buffer_update_after_bind: self
+ .descriptor_binding_uniform_buffer_update_after_bind
+ && other.descriptor_binding_uniform_buffer_update_after_bind,
+ descriptor_binding_uniform_texel_buffer_update_after_bind: self
+ .descriptor_binding_uniform_texel_buffer_update_after_bind
+ && other.descriptor_binding_uniform_texel_buffer_update_after_bind,
+ descriptor_binding_update_unused_while_pending: self
+ .descriptor_binding_update_unused_while_pending
+ && other.descriptor_binding_update_unused_while_pending,
+ descriptor_binding_variable_descriptor_count: self
+ .descriptor_binding_variable_descriptor_count
+ && other.descriptor_binding_variable_descriptor_count,
+ descriptor_buffer: self.descriptor_buffer && other.descriptor_buffer,
+ descriptor_buffer_capture_replay: self.descriptor_buffer_capture_replay
+ && other.descriptor_buffer_capture_replay,
+ descriptor_buffer_image_layout_ignored: self.descriptor_buffer_image_layout_ignored
+ && other.descriptor_buffer_image_layout_ignored,
+ descriptor_buffer_push_descriptors: self.descriptor_buffer_push_descriptors
+ && other.descriptor_buffer_push_descriptors,
+ descriptor_indexing: self.descriptor_indexing && other.descriptor_indexing,
+ descriptor_set_host_mapping: self.descriptor_set_host_mapping
+ && other.descriptor_set_host_mapping,
+ device_coherent_memory: self.device_coherent_memory && other.device_coherent_memory,
+ device_fault: self.device_fault && other.device_fault,
+ device_fault_vendor_binary: self.device_fault_vendor_binary
+ && other.device_fault_vendor_binary,
+ device_generated_commands: self.device_generated_commands
+ && other.device_generated_commands,
+ device_memory_report: self.device_memory_report && other.device_memory_report,
+ diagnostics_config: self.diagnostics_config && other.diagnostics_config,
+ draw_indirect_count: self.draw_indirect_count && other.draw_indirect_count,
+ draw_indirect_first_instance: self.draw_indirect_first_instance
+ && other.draw_indirect_first_instance,
+ dual_src_blend: self.dual_src_blend && other.dual_src_blend,
+ dynamic_rendering: self.dynamic_rendering && other.dynamic_rendering,
+ events: self.events && other.events,
+ exclusive_scissor: self.exclusive_scissor && other.exclusive_scissor,
+ extended_dynamic_state: self.extended_dynamic_state && other.extended_dynamic_state,
+ extended_dynamic_state2: self.extended_dynamic_state2 && other.extended_dynamic_state2,
+ extended_dynamic_state2_logic_op: self.extended_dynamic_state2_logic_op
+ && other.extended_dynamic_state2_logic_op,
+ extended_dynamic_state2_patch_control_points: self
+ .extended_dynamic_state2_patch_control_points
+ && other.extended_dynamic_state2_patch_control_points,
+ extended_dynamic_state3_alpha_to_coverage_enable: self
+ .extended_dynamic_state3_alpha_to_coverage_enable
+ && other.extended_dynamic_state3_alpha_to_coverage_enable,
+ extended_dynamic_state3_alpha_to_one_enable: self
+ .extended_dynamic_state3_alpha_to_one_enable
+ && other.extended_dynamic_state3_alpha_to_one_enable,
+ extended_dynamic_state3_color_blend_advanced: self
+ .extended_dynamic_state3_color_blend_advanced
+ && other.extended_dynamic_state3_color_blend_advanced,
+ extended_dynamic_state3_color_blend_enable: self
+ .extended_dynamic_state3_color_blend_enable
+ && other.extended_dynamic_state3_color_blend_enable,
+ extended_dynamic_state3_color_blend_equation: self
+ .extended_dynamic_state3_color_blend_equation
+ && other.extended_dynamic_state3_color_blend_equation,
+ extended_dynamic_state3_color_write_mask: self.extended_dynamic_state3_color_write_mask
+ && other.extended_dynamic_state3_color_write_mask,
+ extended_dynamic_state3_conservative_rasterization_mode: self
+ .extended_dynamic_state3_conservative_rasterization_mode
+ && other.extended_dynamic_state3_conservative_rasterization_mode,
+ extended_dynamic_state3_coverage_modulation_mode: self
+ .extended_dynamic_state3_coverage_modulation_mode
+ && other.extended_dynamic_state3_coverage_modulation_mode,
+ extended_dynamic_state3_coverage_modulation_table: self
+ .extended_dynamic_state3_coverage_modulation_table
+ && other.extended_dynamic_state3_coverage_modulation_table,
+ extended_dynamic_state3_coverage_modulation_table_enable: self
+ .extended_dynamic_state3_coverage_modulation_table_enable
+ && other.extended_dynamic_state3_coverage_modulation_table_enable,
+ extended_dynamic_state3_coverage_reduction_mode: self
+ .extended_dynamic_state3_coverage_reduction_mode
+ && other.extended_dynamic_state3_coverage_reduction_mode,
+ extended_dynamic_state3_coverage_to_color_enable: self
+ .extended_dynamic_state3_coverage_to_color_enable
+ && other.extended_dynamic_state3_coverage_to_color_enable,
+ extended_dynamic_state3_coverage_to_color_location: self
+ .extended_dynamic_state3_coverage_to_color_location
+ && other.extended_dynamic_state3_coverage_to_color_location,
+ extended_dynamic_state3_depth_clamp_enable: self
+ .extended_dynamic_state3_depth_clamp_enable
+ && other.extended_dynamic_state3_depth_clamp_enable,
+ extended_dynamic_state3_depth_clip_enable: self
+ .extended_dynamic_state3_depth_clip_enable
+ && other.extended_dynamic_state3_depth_clip_enable,
+ extended_dynamic_state3_depth_clip_negative_one_to_one: self
+ .extended_dynamic_state3_depth_clip_negative_one_to_one
+ && other.extended_dynamic_state3_depth_clip_negative_one_to_one,
+ extended_dynamic_state3_extra_primitive_overestimation_size: self
+ .extended_dynamic_state3_extra_primitive_overestimation_size
+ && other.extended_dynamic_state3_extra_primitive_overestimation_size,
+ extended_dynamic_state3_line_rasterization_mode: self
+ .extended_dynamic_state3_line_rasterization_mode
+ && other.extended_dynamic_state3_line_rasterization_mode,
+ extended_dynamic_state3_line_stipple_enable: self
+ .extended_dynamic_state3_line_stipple_enable
+ && other.extended_dynamic_state3_line_stipple_enable,
+ extended_dynamic_state3_logic_op_enable: self.extended_dynamic_state3_logic_op_enable
+ && other.extended_dynamic_state3_logic_op_enable,
+ extended_dynamic_state3_polygon_mode: self.extended_dynamic_state3_polygon_mode
+ && other.extended_dynamic_state3_polygon_mode,
+ extended_dynamic_state3_provoking_vertex_mode: self
+ .extended_dynamic_state3_provoking_vertex_mode
+ && other.extended_dynamic_state3_provoking_vertex_mode,
+ extended_dynamic_state3_rasterization_samples: self
+ .extended_dynamic_state3_rasterization_samples
+ && other.extended_dynamic_state3_rasterization_samples,
+ extended_dynamic_state3_rasterization_stream: self
+ .extended_dynamic_state3_rasterization_stream
+ && other.extended_dynamic_state3_rasterization_stream,
+ extended_dynamic_state3_representative_fragment_test_enable: self
+ .extended_dynamic_state3_representative_fragment_test_enable
+ && other.extended_dynamic_state3_representative_fragment_test_enable,
+ extended_dynamic_state3_sample_locations_enable: self
+ .extended_dynamic_state3_sample_locations_enable
+ && other.extended_dynamic_state3_sample_locations_enable,
+ extended_dynamic_state3_sample_mask: self.extended_dynamic_state3_sample_mask
+ && other.extended_dynamic_state3_sample_mask,
+ extended_dynamic_state3_shading_rate_image_enable: self
+ .extended_dynamic_state3_shading_rate_image_enable
+ && other.extended_dynamic_state3_shading_rate_image_enable,
+ extended_dynamic_state3_tessellation_domain_origin: self
+ .extended_dynamic_state3_tessellation_domain_origin
+ && other.extended_dynamic_state3_tessellation_domain_origin,
+ extended_dynamic_state3_viewport_swizzle: self.extended_dynamic_state3_viewport_swizzle
+ && other.extended_dynamic_state3_viewport_swizzle,
+ extended_dynamic_state3_viewport_w_scaling_enable: self
+ .extended_dynamic_state3_viewport_w_scaling_enable
+ && other.extended_dynamic_state3_viewport_w_scaling_enable,
+ external_memory_rdma: self.external_memory_rdma && other.external_memory_rdma,
+ fill_mode_non_solid: self.fill_mode_non_solid && other.fill_mode_non_solid,
+ format_a4b4g4r4: self.format_a4b4g4r4 && other.format_a4b4g4r4,
+ format_a4r4g4b4: self.format_a4r4g4b4 && other.format_a4r4g4b4,
+ format_rgba10x6_without_y_cb_cr_sampler: self.format_rgba10x6_without_y_cb_cr_sampler
+ && other.format_rgba10x6_without_y_cb_cr_sampler,
+ fragment_density_map: self.fragment_density_map && other.fragment_density_map,
+ fragment_density_map_deferred: self.fragment_density_map_deferred
+ && other.fragment_density_map_deferred,
+ fragment_density_map_dynamic: self.fragment_density_map_dynamic
+ && other.fragment_density_map_dynamic,
+ fragment_density_map_non_subsampled_images: self
+ .fragment_density_map_non_subsampled_images
+ && other.fragment_density_map_non_subsampled_images,
+ fragment_density_map_offset: self.fragment_density_map_offset
+ && other.fragment_density_map_offset,
+ fragment_shader_barycentric: self.fragment_shader_barycentric
+ && other.fragment_shader_barycentric,
+ fragment_shader_pixel_interlock: self.fragment_shader_pixel_interlock
+ && other.fragment_shader_pixel_interlock,
+ fragment_shader_sample_interlock: self.fragment_shader_sample_interlock
+ && other.fragment_shader_sample_interlock,
+ fragment_shader_shading_rate_interlock: self.fragment_shader_shading_rate_interlock
+ && other.fragment_shader_shading_rate_interlock,
+ fragment_shading_rate_enums: self.fragment_shading_rate_enums
+ && other.fragment_shading_rate_enums,
+ fragment_stores_and_atomics: self.fragment_stores_and_atomics
+ && other.fragment_stores_and_atomics,
+ full_draw_index_uint32: self.full_draw_index_uint32 && other.full_draw_index_uint32,
+ geometry_shader: self.geometry_shader && other.geometry_shader,
+ geometry_streams: self.geometry_streams && other.geometry_streams,
+ global_priority_query: self.global_priority_query && other.global_priority_query,
+ graphics_pipeline_library: self.graphics_pipeline_library
+ && other.graphics_pipeline_library,
+ host_query_reset: self.host_query_reset && other.host_query_reset,
+ image2_d_view_of3_d: self.image2_d_view_of3_d && other.image2_d_view_of3_d,
+ image_compression_control: self.image_compression_control
+ && other.image_compression_control,
+ image_compression_control_swapchain: self.image_compression_control_swapchain
+ && other.image_compression_control_swapchain,
+ image_cube_array: self.image_cube_array && other.image_cube_array,
+ image_footprint: self.image_footprint && other.image_footprint,
+ image_view2_d_on3_d_image: self.image_view2_d_on3_d_image
+ && other.image_view2_d_on3_d_image,
+ image_view_format_reinterpretation: self.image_view_format_reinterpretation
+ && other.image_view_format_reinterpretation,
+ image_view_format_swizzle: self.image_view_format_swizzle
+ && other.image_view_format_swizzle,
+ imageless_framebuffer: self.imageless_framebuffer && other.imageless_framebuffer,
+ independent_blend: self.independent_blend && other.independent_blend,
+ index_type_uint8: self.index_type_uint8 && other.index_type_uint8,
+ indirect_copy: self.indirect_copy && other.indirect_copy,
+ inherited_conditional_rendering: self.inherited_conditional_rendering
+ && other.inherited_conditional_rendering,
+ inherited_queries: self.inherited_queries && other.inherited_queries,
+ inherited_viewport_scissor2_d: self.inherited_viewport_scissor2_d
+ && other.inherited_viewport_scissor2_d,
+ inline_uniform_block: self.inline_uniform_block && other.inline_uniform_block,
+ invocation_mask: self.invocation_mask && other.invocation_mask,
+ large_points: self.large_points && other.large_points,
+ legacy_dithering: self.legacy_dithering && other.legacy_dithering,
+ linear_color_attachment: self.linear_color_attachment && other.linear_color_attachment,
+ logic_op: self.logic_op && other.logic_op,
+ maintenance4: self.maintenance4 && other.maintenance4,
+ memory_decompression: self.memory_decompression && other.memory_decompression,
+ memory_priority: self.memory_priority && other.memory_priority,
+ mesh_shader: self.mesh_shader && other.mesh_shader,
+ mesh_shader_queries: self.mesh_shader_queries && other.mesh_shader_queries,
+ micromap: self.micromap && other.micromap,
+ micromap_capture_replay: self.micromap_capture_replay && other.micromap_capture_replay,
+ micromap_host_commands: self.micromap_host_commands && other.micromap_host_commands,
+ min_lod: self.min_lod && other.min_lod,
+ multi_draw: self.multi_draw && other.multi_draw,
+ multi_draw_indirect: self.multi_draw_indirect && other.multi_draw_indirect,
+ multi_viewport: self.multi_viewport && other.multi_viewport,
+ multisample_array_image: self.multisample_array_image && other.multisample_array_image,
+ multisampled_render_to_single_sampled: self.multisampled_render_to_single_sampled
+ && other.multisampled_render_to_single_sampled,
+ multiview: self.multiview && other.multiview,
+ multiview_geometry_shader: self.multiview_geometry_shader
+ && other.multiview_geometry_shader,
+ multiview_mesh_shader: self.multiview_mesh_shader && other.multiview_mesh_shader,
+ multiview_per_view_viewports: self.multiview_per_view_viewports
+ && other.multiview_per_view_viewports,
+ multiview_tessellation_shader: self.multiview_tessellation_shader
+ && other.multiview_tessellation_shader,
+ mutable_comparison_samplers: self.mutable_comparison_samplers
+ && other.mutable_comparison_samplers,
+ mutable_descriptor_type: self.mutable_descriptor_type && other.mutable_descriptor_type,
+ no_invocation_fragment_shading_rates: self.no_invocation_fragment_shading_rates
+ && other.no_invocation_fragment_shading_rates,
+ non_seamless_cube_map: self.non_seamless_cube_map && other.non_seamless_cube_map,
+ null_descriptor: self.null_descriptor && other.null_descriptor,
+ occlusion_query_precise: self.occlusion_query_precise && other.occlusion_query_precise,
+ optical_flow: self.optical_flow && other.optical_flow,
+ pageable_device_local_memory: self.pageable_device_local_memory
+ && other.pageable_device_local_memory,
+ performance_counter_multiple_query_pools: self.performance_counter_multiple_query_pools
+ && other.performance_counter_multiple_query_pools,
+ performance_counter_query_pools: self.performance_counter_query_pools
+ && other.performance_counter_query_pools,
+ pipeline_creation_cache_control: self.pipeline_creation_cache_control
+ && other.pipeline_creation_cache_control,
+ pipeline_executable_info: self.pipeline_executable_info
+ && other.pipeline_executable_info,
+ pipeline_fragment_shading_rate: self.pipeline_fragment_shading_rate
+ && other.pipeline_fragment_shading_rate,
+ pipeline_properties_identifier: self.pipeline_properties_identifier
+ && other.pipeline_properties_identifier,
+ pipeline_protected_access: self.pipeline_protected_access
+ && other.pipeline_protected_access,
+ pipeline_robustness: self.pipeline_robustness && other.pipeline_robustness,
+ pipeline_statistics_query: self.pipeline_statistics_query
+ && other.pipeline_statistics_query,
+ point_polygons: self.point_polygons && other.point_polygons,
+ present_barrier: self.present_barrier && other.present_barrier,
+ present_id: self.present_id && other.present_id,
+ present_wait: self.present_wait && other.present_wait,
+ primitive_fragment_shading_rate: self.primitive_fragment_shading_rate
+ && other.primitive_fragment_shading_rate,
+ primitive_fragment_shading_rate_mesh_shader: self
+ .primitive_fragment_shading_rate_mesh_shader
+ && other.primitive_fragment_shading_rate_mesh_shader,
+ primitive_topology_list_restart: self.primitive_topology_list_restart
+ && other.primitive_topology_list_restart,
+ primitive_topology_patch_list_restart: self.primitive_topology_patch_list_restart
+ && other.primitive_topology_patch_list_restart,
+ primitives_generated_query: self.primitives_generated_query
+ && other.primitives_generated_query,
+ primitives_generated_query_with_non_zero_streams: self
+ .primitives_generated_query_with_non_zero_streams
+ && other.primitives_generated_query_with_non_zero_streams,
+ primitives_generated_query_with_rasterizer_discard: self
+ .primitives_generated_query_with_rasterizer_discard
+ && other.primitives_generated_query_with_rasterizer_discard,
+ private_data: self.private_data && other.private_data,
+ protected_memory: self.protected_memory && other.protected_memory,
+ provoking_vertex_last: self.provoking_vertex_last && other.provoking_vertex_last,
+ rasterization_order_color_attachment_access: self
+ .rasterization_order_color_attachment_access
+ && other.rasterization_order_color_attachment_access,
+ rasterization_order_depth_attachment_access: self
+ .rasterization_order_depth_attachment_access
+ && other.rasterization_order_depth_attachment_access,
+ rasterization_order_stencil_attachment_access: self
+ .rasterization_order_stencil_attachment_access
+ && other.rasterization_order_stencil_attachment_access,
+ ray_query: self.ray_query && other.ray_query,
+ ray_tracing_invocation_reorder: self.ray_tracing_invocation_reorder
+ && other.ray_tracing_invocation_reorder,
+ ray_tracing_maintenance1: self.ray_tracing_maintenance1
+ && other.ray_tracing_maintenance1,
+ ray_tracing_motion_blur: self.ray_tracing_motion_blur && other.ray_tracing_motion_blur,
+ ray_tracing_motion_blur_pipeline_trace_rays_indirect: self
+ .ray_tracing_motion_blur_pipeline_trace_rays_indirect
+ && other.ray_tracing_motion_blur_pipeline_trace_rays_indirect,
+ ray_tracing_pipeline: self.ray_tracing_pipeline && other.ray_tracing_pipeline,
+ ray_tracing_pipeline_shader_group_handle_capture_replay: self
+ .ray_tracing_pipeline_shader_group_handle_capture_replay
+ && other.ray_tracing_pipeline_shader_group_handle_capture_replay,
+ ray_tracing_pipeline_shader_group_handle_capture_replay_mixed: self
+ .ray_tracing_pipeline_shader_group_handle_capture_replay_mixed
+ && other.ray_tracing_pipeline_shader_group_handle_capture_replay_mixed,
+ ray_tracing_pipeline_trace_rays_indirect: self.ray_tracing_pipeline_trace_rays_indirect
+ && other.ray_tracing_pipeline_trace_rays_indirect,
+ ray_tracing_pipeline_trace_rays_indirect2: self
+ .ray_tracing_pipeline_trace_rays_indirect2
+ && other.ray_tracing_pipeline_trace_rays_indirect2,
+ ray_traversal_primitive_culling: self.ray_traversal_primitive_culling
+ && other.ray_traversal_primitive_culling,
+ rectangular_lines: self.rectangular_lines && other.rectangular_lines,
+ report_address_binding: self.report_address_binding && other.report_address_binding,
+ representative_fragment_test: self.representative_fragment_test
+ && other.representative_fragment_test,
+ robust_buffer_access: self.robust_buffer_access && other.robust_buffer_access,
+ robust_buffer_access2: self.robust_buffer_access2 && other.robust_buffer_access2,
+ robust_image_access: self.robust_image_access && other.robust_image_access,
+ robust_image_access2: self.robust_image_access2 && other.robust_image_access2,
+ runtime_descriptor_array: self.runtime_descriptor_array
+ && other.runtime_descriptor_array,
+ sample_rate_shading: self.sample_rate_shading && other.sample_rate_shading,
+ sampler2_d_view_of3_d: self.sampler2_d_view_of3_d && other.sampler2_d_view_of3_d,
+ sampler_anisotropy: self.sampler_anisotropy && other.sampler_anisotropy,
+ sampler_filter_minmax: self.sampler_filter_minmax && other.sampler_filter_minmax,
+ sampler_mip_lod_bias: self.sampler_mip_lod_bias && other.sampler_mip_lod_bias,
+ sampler_mirror_clamp_to_edge: self.sampler_mirror_clamp_to_edge
+ && other.sampler_mirror_clamp_to_edge,
+ sampler_ycbcr_conversion: self.sampler_ycbcr_conversion
+ && other.sampler_ycbcr_conversion,
+ scalar_block_layout: self.scalar_block_layout && other.scalar_block_layout,
+ separate_depth_stencil_layouts: self.separate_depth_stencil_layouts
+ && other.separate_depth_stencil_layouts,
+ separate_stencil_mask_ref: self.separate_stencil_mask_ref
+ && other.separate_stencil_mask_ref,
+ shader_buffer_float16_atomic_add: self.shader_buffer_float16_atomic_add
+ && other.shader_buffer_float16_atomic_add,
+ shader_buffer_float16_atomic_min_max: self.shader_buffer_float16_atomic_min_max
+ && other.shader_buffer_float16_atomic_min_max,
+ shader_buffer_float16_atomics: self.shader_buffer_float16_atomics
+ && other.shader_buffer_float16_atomics,
+ shader_buffer_float32_atomic_add: self.shader_buffer_float32_atomic_add
+ && other.shader_buffer_float32_atomic_add,
+ shader_buffer_float32_atomic_min_max: self.shader_buffer_float32_atomic_min_max
+ && other.shader_buffer_float32_atomic_min_max,
+ shader_buffer_float32_atomics: self.shader_buffer_float32_atomics
+ && other.shader_buffer_float32_atomics,
+ shader_buffer_float64_atomic_add: self.shader_buffer_float64_atomic_add
+ && other.shader_buffer_float64_atomic_add,
+ shader_buffer_float64_atomic_min_max: self.shader_buffer_float64_atomic_min_max
+ && other.shader_buffer_float64_atomic_min_max,
+ shader_buffer_float64_atomics: self.shader_buffer_float64_atomics
+ && other.shader_buffer_float64_atomics,
+ shader_buffer_int64_atomics: self.shader_buffer_int64_atomics
+ && other.shader_buffer_int64_atomics,
+ shader_clip_distance: self.shader_clip_distance && other.shader_clip_distance,
+ shader_core_builtins: self.shader_core_builtins && other.shader_core_builtins,
+ shader_cull_distance: self.shader_cull_distance && other.shader_cull_distance,
+ shader_demote_to_helper_invocation: self.shader_demote_to_helper_invocation
+ && other.shader_demote_to_helper_invocation,
+ shader_device_clock: self.shader_device_clock && other.shader_device_clock,
+ shader_draw_parameters: self.shader_draw_parameters && other.shader_draw_parameters,
+ shader_early_and_late_fragment_tests: self.shader_early_and_late_fragment_tests
+ && other.shader_early_and_late_fragment_tests,
+ shader_float16: self.shader_float16 && other.shader_float16,
+ shader_float64: self.shader_float64 && other.shader_float64,
+ shader_image_float32_atomic_add: self.shader_image_float32_atomic_add
+ && other.shader_image_float32_atomic_add,
+ shader_image_float32_atomic_min_max: self.shader_image_float32_atomic_min_max
+ && other.shader_image_float32_atomic_min_max,
+ shader_image_float32_atomics: self.shader_image_float32_atomics
+ && other.shader_image_float32_atomics,
+ shader_image_gather_extended: self.shader_image_gather_extended
+ && other.shader_image_gather_extended,
+ shader_image_int64_atomics: self.shader_image_int64_atomics
+ && other.shader_image_int64_atomics,
+ shader_input_attachment_array_dynamic_indexing: self
+ .shader_input_attachment_array_dynamic_indexing
+ && other.shader_input_attachment_array_dynamic_indexing,
+ shader_input_attachment_array_non_uniform_indexing: self
+ .shader_input_attachment_array_non_uniform_indexing
+ && other.shader_input_attachment_array_non_uniform_indexing,
+ shader_int16: self.shader_int16 && other.shader_int16,
+ shader_int64: self.shader_int64 && other.shader_int64,
+ shader_int8: self.shader_int8 && other.shader_int8,
+ shader_integer_dot_product: self.shader_integer_dot_product
+ && other.shader_integer_dot_product,
+ shader_integer_functions2: self.shader_integer_functions2
+ && other.shader_integer_functions2,
+ shader_module_identifier: self.shader_module_identifier
+ && other.shader_module_identifier,
+ shader_output_layer: self.shader_output_layer && other.shader_output_layer,
+ shader_output_viewport_index: self.shader_output_viewport_index
+ && other.shader_output_viewport_index,
+ shader_resource_min_lod: self.shader_resource_min_lod && other.shader_resource_min_lod,
+ shader_resource_residency: self.shader_resource_residency
+ && other.shader_resource_residency,
+ shader_sample_rate_interpolation_functions: self
+ .shader_sample_rate_interpolation_functions
+ && other.shader_sample_rate_interpolation_functions,
+ shader_sampled_image_array_dynamic_indexing: self
+ .shader_sampled_image_array_dynamic_indexing
+ && other.shader_sampled_image_array_dynamic_indexing,
+ shader_sampled_image_array_non_uniform_indexing: self
+ .shader_sampled_image_array_non_uniform_indexing
+ && other.shader_sampled_image_array_non_uniform_indexing,
+ shader_shared_float16_atomic_add: self.shader_shared_float16_atomic_add
+ && other.shader_shared_float16_atomic_add,
+ shader_shared_float16_atomic_min_max: self.shader_shared_float16_atomic_min_max
+ && other.shader_shared_float16_atomic_min_max,
+ shader_shared_float16_atomics: self.shader_shared_float16_atomics
+ && other.shader_shared_float16_atomics,
+ shader_shared_float32_atomic_add: self.shader_shared_float32_atomic_add
+ && other.shader_shared_float32_atomic_add,
+ shader_shared_float32_atomic_min_max: self.shader_shared_float32_atomic_min_max
+ && other.shader_shared_float32_atomic_min_max,
+ shader_shared_float32_atomics: self.shader_shared_float32_atomics
+ && other.shader_shared_float32_atomics,
+ shader_shared_float64_atomic_add: self.shader_shared_float64_atomic_add
+ && other.shader_shared_float64_atomic_add,
+ shader_shared_float64_atomic_min_max: self.shader_shared_float64_atomic_min_max
+ && other.shader_shared_float64_atomic_min_max,
+ shader_shared_float64_atomics: self.shader_shared_float64_atomics
+ && other.shader_shared_float64_atomics,
+ shader_shared_int64_atomics: self.shader_shared_int64_atomics
+ && other.shader_shared_int64_atomics,
+ shader_sm_builtins: self.shader_sm_builtins && other.shader_sm_builtins,
+ shader_storage_buffer_array_dynamic_indexing: self
+ .shader_storage_buffer_array_dynamic_indexing
+ && other.shader_storage_buffer_array_dynamic_indexing,
+ shader_storage_buffer_array_non_uniform_indexing: self
+ .shader_storage_buffer_array_non_uniform_indexing
+ && other.shader_storage_buffer_array_non_uniform_indexing,
+ shader_storage_image_array_dynamic_indexing: self
+ .shader_storage_image_array_dynamic_indexing
+ && other.shader_storage_image_array_dynamic_indexing,
+ shader_storage_image_array_non_uniform_indexing: self
+ .shader_storage_image_array_non_uniform_indexing
+ && other.shader_storage_image_array_non_uniform_indexing,
+ shader_storage_image_extended_formats: self.shader_storage_image_extended_formats
+ && other.shader_storage_image_extended_formats,
+ shader_storage_image_multisample: self.shader_storage_image_multisample
+ && other.shader_storage_image_multisample,
+ shader_storage_image_read_without_format: self.shader_storage_image_read_without_format
+ && other.shader_storage_image_read_without_format,
+ shader_storage_image_write_without_format: self
+ .shader_storage_image_write_without_format
+ && other.shader_storage_image_write_without_format,
+ shader_storage_texel_buffer_array_dynamic_indexing: self
+ .shader_storage_texel_buffer_array_dynamic_indexing
+ && other.shader_storage_texel_buffer_array_dynamic_indexing,
+ shader_storage_texel_buffer_array_non_uniform_indexing: self
+ .shader_storage_texel_buffer_array_non_uniform_indexing
+ && other.shader_storage_texel_buffer_array_non_uniform_indexing,
+ shader_subgroup_clock: self.shader_subgroup_clock && other.shader_subgroup_clock,
+ shader_subgroup_extended_types: self.shader_subgroup_extended_types
+ && other.shader_subgroup_extended_types,
+ shader_subgroup_uniform_control_flow: self.shader_subgroup_uniform_control_flow
+ && other.shader_subgroup_uniform_control_flow,
+ shader_terminate_invocation: self.shader_terminate_invocation
+ && other.shader_terminate_invocation,
+ shader_tessellation_and_geometry_point_size: self
+ .shader_tessellation_and_geometry_point_size
+ && other.shader_tessellation_and_geometry_point_size,
+ shader_uniform_buffer_array_dynamic_indexing: self
+ .shader_uniform_buffer_array_dynamic_indexing
+ && other.shader_uniform_buffer_array_dynamic_indexing,
+ shader_uniform_buffer_array_non_uniform_indexing: self
+ .shader_uniform_buffer_array_non_uniform_indexing
+ && other.shader_uniform_buffer_array_non_uniform_indexing,
+ shader_uniform_texel_buffer_array_dynamic_indexing: self
+ .shader_uniform_texel_buffer_array_dynamic_indexing
+ && other.shader_uniform_texel_buffer_array_dynamic_indexing,
+ shader_uniform_texel_buffer_array_non_uniform_indexing: self
+ .shader_uniform_texel_buffer_array_non_uniform_indexing
+ && other.shader_uniform_texel_buffer_array_non_uniform_indexing,
+ shader_zero_initialize_workgroup_memory: self.shader_zero_initialize_workgroup_memory
+ && other.shader_zero_initialize_workgroup_memory,
+ shading_rate_coarse_sample_order: self.shading_rate_coarse_sample_order
+ && other.shading_rate_coarse_sample_order,
+ shading_rate_image: self.shading_rate_image && other.shading_rate_image,
+ smooth_lines: self.smooth_lines && other.smooth_lines,
+ sparse_binding: self.sparse_binding && other.sparse_binding,
+ sparse_image_float32_atomic_add: self.sparse_image_float32_atomic_add
+ && other.sparse_image_float32_atomic_add,
+ sparse_image_float32_atomic_min_max: self.sparse_image_float32_atomic_min_max
+ && other.sparse_image_float32_atomic_min_max,
+ sparse_image_float32_atomics: self.sparse_image_float32_atomics
+ && other.sparse_image_float32_atomics,
+ sparse_image_int64_atomics: self.sparse_image_int64_atomics
+ && other.sparse_image_int64_atomics,
+ sparse_residency16_samples: self.sparse_residency16_samples
+ && other.sparse_residency16_samples,
+ sparse_residency2_samples: self.sparse_residency2_samples
+ && other.sparse_residency2_samples,
+ sparse_residency4_samples: self.sparse_residency4_samples
+ && other.sparse_residency4_samples,
+ sparse_residency8_samples: self.sparse_residency8_samples
+ && other.sparse_residency8_samples,
+ sparse_residency_aliased: self.sparse_residency_aliased
+ && other.sparse_residency_aliased,
+ sparse_residency_buffer: self.sparse_residency_buffer && other.sparse_residency_buffer,
+ sparse_residency_image2_d: self.sparse_residency_image2_d
+ && other.sparse_residency_image2_d,
+ sparse_residency_image3_d: self.sparse_residency_image3_d
+ && other.sparse_residency_image3_d,
+ stippled_bresenham_lines: self.stippled_bresenham_lines
+ && other.stippled_bresenham_lines,
+ stippled_rectangular_lines: self.stippled_rectangular_lines
+ && other.stippled_rectangular_lines,
+ stippled_smooth_lines: self.stippled_smooth_lines && other.stippled_smooth_lines,
+ storage_buffer16_bit_access: self.storage_buffer16_bit_access
+ && other.storage_buffer16_bit_access,
+ storage_buffer8_bit_access: self.storage_buffer8_bit_access
+ && other.storage_buffer8_bit_access,
+ storage_input_output16: self.storage_input_output16 && other.storage_input_output16,
+ storage_push_constant16: self.storage_push_constant16 && other.storage_push_constant16,
+ storage_push_constant8: self.storage_push_constant8 && other.storage_push_constant8,
+ subgroup_broadcast_dynamic_id: self.subgroup_broadcast_dynamic_id
+ && other.subgroup_broadcast_dynamic_id,
+ subgroup_size_control: self.subgroup_size_control && other.subgroup_size_control,
+ subpass_merge_feedback: self.subpass_merge_feedback && other.subpass_merge_feedback,
+ subpass_shading: self.subpass_shading && other.subpass_shading,
+ supersample_fragment_shading_rates: self.supersample_fragment_shading_rates
+ && other.supersample_fragment_shading_rates,
+ swapchain_maintenance1: self.swapchain_maintenance1 && other.swapchain_maintenance1,
+ synchronization2: self.synchronization2 && other.synchronization2,
+ task_shader: self.task_shader && other.task_shader,
+ tessellation_isolines: self.tessellation_isolines && other.tessellation_isolines,
+ tessellation_point_mode: self.tessellation_point_mode && other.tessellation_point_mode,
+ tessellation_shader: self.tessellation_shader && other.tessellation_shader,
+ texel_buffer_alignment: self.texel_buffer_alignment && other.texel_buffer_alignment,
+ texture_block_match: self.texture_block_match && other.texture_block_match,
+ texture_box_filter: self.texture_box_filter && other.texture_box_filter,
+ texture_compression_astc_hdr: self.texture_compression_astc_hdr
+ && other.texture_compression_astc_hdr,
+ texture_compression_astc_ldr: self.texture_compression_astc_ldr
+ && other.texture_compression_astc_ldr,
+ texture_compression_bc: self.texture_compression_bc && other.texture_compression_bc,
+ texture_compression_etc2: self.texture_compression_etc2
+ && other.texture_compression_etc2,
+ texture_sample_weighted: self.texture_sample_weighted && other.texture_sample_weighted,
+ tile_properties: self.tile_properties && other.tile_properties,
+ timeline_semaphore: self.timeline_semaphore && other.timeline_semaphore,
+ transform_feedback: self.transform_feedback && other.transform_feedback,
+ transform_feedback_preserves_provoking_vertex: self
+ .transform_feedback_preserves_provoking_vertex
+ && other.transform_feedback_preserves_provoking_vertex,
+ triangle_fans: self.triangle_fans && other.triangle_fans,
+ uniform_and_storage_buffer16_bit_access: self.uniform_and_storage_buffer16_bit_access
+ && other.uniform_and_storage_buffer16_bit_access,
+ uniform_and_storage_buffer8_bit_access: self.uniform_and_storage_buffer8_bit_access
+ && other.uniform_and_storage_buffer8_bit_access,
+ uniform_buffer_standard_layout: self.uniform_buffer_standard_layout
+ && other.uniform_buffer_standard_layout,
+ variable_multisample_rate: self.variable_multisample_rate
+ && other.variable_multisample_rate,
+ variable_pointers: self.variable_pointers && other.variable_pointers,
+ variable_pointers_storage_buffer: self.variable_pointers_storage_buffer
+ && other.variable_pointers_storage_buffer,
+ vertex_attribute_access_beyond_stride: self.vertex_attribute_access_beyond_stride
+ && other.vertex_attribute_access_beyond_stride,
+ vertex_attribute_instance_rate_divisor: self.vertex_attribute_instance_rate_divisor
+ && other.vertex_attribute_instance_rate_divisor,
+ vertex_attribute_instance_rate_zero_divisor: self
+ .vertex_attribute_instance_rate_zero_divisor
+ && other.vertex_attribute_instance_rate_zero_divisor,
+ vertex_input_dynamic_state: self.vertex_input_dynamic_state
+ && other.vertex_input_dynamic_state,
+ vertex_pipeline_stores_and_atomics: self.vertex_pipeline_stores_and_atomics
+ && other.vertex_pipeline_stores_and_atomics,
+ vulkan_memory_model: self.vulkan_memory_model && other.vulkan_memory_model,
+ vulkan_memory_model_availability_visibility_chains: self
+ .vulkan_memory_model_availability_visibility_chains
+ && other.vulkan_memory_model_availability_visibility_chains,
+ vulkan_memory_model_device_scope: self.vulkan_memory_model_device_scope
+ && other.vulkan_memory_model_device_scope,
+ wide_lines: self.wide_lines && other.wide_lines,
+ workgroup_memory_explicit_layout: self.workgroup_memory_explicit_layout
+ && other.workgroup_memory_explicit_layout,
+ workgroup_memory_explicit_layout16_bit_access: self
+ .workgroup_memory_explicit_layout16_bit_access
+ && other.workgroup_memory_explicit_layout16_bit_access,
+ workgroup_memory_explicit_layout8_bit_access: self
+ .workgroup_memory_explicit_layout8_bit_access
+ && other.workgroup_memory_explicit_layout8_bit_access,
+ workgroup_memory_explicit_layout_scalar_block_layout: self
+ .workgroup_memory_explicit_layout_scalar_block_layout
+ && other.workgroup_memory_explicit_layout_scalar_block_layout,
+ ycbcr2plane444_formats: self.ycbcr2plane444_formats && other.ycbcr2plane444_formats,
+ ycbcr_image_arrays: self.ycbcr_image_arrays && other.ycbcr_image_arrays,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+ #[doc = r" Returns `self` without the members set in `other`."]
+ #[inline]
+ pub const fn difference(&self, other: &Self) -> Self {
+ Self {
+ acceleration_structure: self.acceleration_structure && !other.acceleration_structure,
+ acceleration_structure_capture_replay: self.acceleration_structure_capture_replay
+ && !other.acceleration_structure_capture_replay,
+ acceleration_structure_host_commands: self.acceleration_structure_host_commands
+ && !other.acceleration_structure_host_commands,
+ acceleration_structure_indirect_build: self.acceleration_structure_indirect_build
+ && !other.acceleration_structure_indirect_build,
+ advanced_blend_coherent_operations: self.advanced_blend_coherent_operations
+ && !other.advanced_blend_coherent_operations,
+ alpha_to_one: self.alpha_to_one && !other.alpha_to_one,
+ amigo_profiling: self.amigo_profiling && !other.amigo_profiling,
+ attachment_feedback_loop_layout: self.attachment_feedback_loop_layout
+ && !other.attachment_feedback_loop_layout,
+ attachment_fragment_shading_rate: self.attachment_fragment_shading_rate
+ && !other.attachment_fragment_shading_rate,
+ border_color_swizzle: self.border_color_swizzle && !other.border_color_swizzle,
+ border_color_swizzle_from_image: self.border_color_swizzle_from_image
+ && !other.border_color_swizzle_from_image,
+ bresenham_lines: self.bresenham_lines && !other.bresenham_lines,
+ buffer_device_address: self.buffer_device_address && !other.buffer_device_address,
+ buffer_device_address_capture_replay: self.buffer_device_address_capture_replay
+ && !other.buffer_device_address_capture_replay,
+ buffer_device_address_multi_device: self.buffer_device_address_multi_device
+ && !other.buffer_device_address_multi_device,
+ color_write_enable: self.color_write_enable && !other.color_write_enable,
+ compute_derivative_group_linear: self.compute_derivative_group_linear
+ && !other.compute_derivative_group_linear,
+ compute_derivative_group_quads: self.compute_derivative_group_quads
+ && !other.compute_derivative_group_quads,
+ compute_full_subgroups: self.compute_full_subgroups && !other.compute_full_subgroups,
+ conditional_rendering: self.conditional_rendering && !other.conditional_rendering,
+ constant_alpha_color_blend_factors: self.constant_alpha_color_blend_factors
+ && !other.constant_alpha_color_blend_factors,
+ cooperative_matrix: self.cooperative_matrix && !other.cooperative_matrix,
+ cooperative_matrix_robust_buffer_access: self.cooperative_matrix_robust_buffer_access
+ && !other.cooperative_matrix_robust_buffer_access,
+ corner_sampled_image: self.corner_sampled_image && !other.corner_sampled_image,
+ coverage_reduction_mode: self.coverage_reduction_mode && !other.coverage_reduction_mode,
+ custom_border_color_without_format: self.custom_border_color_without_format
+ && !other.custom_border_color_without_format,
+ custom_border_colors: self.custom_border_colors && !other.custom_border_colors,
+ decode_mode_shared_exponent: self.decode_mode_shared_exponent
+ && !other.decode_mode_shared_exponent,
+ dedicated_allocation_image_aliasing: self.dedicated_allocation_image_aliasing
+ && !other.dedicated_allocation_image_aliasing,
+ depth_bias_clamp: self.depth_bias_clamp && !other.depth_bias_clamp,
+ depth_bounds: self.depth_bounds && !other.depth_bounds,
+ depth_clamp: self.depth_clamp && !other.depth_clamp,
+ depth_clamp_zero_one: self.depth_clamp_zero_one && !other.depth_clamp_zero_one,
+ depth_clip_control: self.depth_clip_control && !other.depth_clip_control,
+ depth_clip_enable: self.depth_clip_enable && !other.depth_clip_enable,
+ descriptor_binding_acceleration_structure_update_after_bind: self
+ .descriptor_binding_acceleration_structure_update_after_bind
+ && !other.descriptor_binding_acceleration_structure_update_after_bind,
+ descriptor_binding_inline_uniform_block_update_after_bind: self
+ .descriptor_binding_inline_uniform_block_update_after_bind
+ && !other.descriptor_binding_inline_uniform_block_update_after_bind,
+ descriptor_binding_partially_bound: self.descriptor_binding_partially_bound
+ && !other.descriptor_binding_partially_bound,
+ descriptor_binding_sampled_image_update_after_bind: self
+ .descriptor_binding_sampled_image_update_after_bind
+ && !other.descriptor_binding_sampled_image_update_after_bind,
+ descriptor_binding_storage_buffer_update_after_bind: self
+ .descriptor_binding_storage_buffer_update_after_bind
+ && !other.descriptor_binding_storage_buffer_update_after_bind,
+ descriptor_binding_storage_image_update_after_bind: self
+ .descriptor_binding_storage_image_update_after_bind
+ && !other.descriptor_binding_storage_image_update_after_bind,
+ descriptor_binding_storage_texel_buffer_update_after_bind: self
+ .descriptor_binding_storage_texel_buffer_update_after_bind
+ && !other.descriptor_binding_storage_texel_buffer_update_after_bind,
+ descriptor_binding_uniform_buffer_update_after_bind: self
+ .descriptor_binding_uniform_buffer_update_after_bind
+ && !other.descriptor_binding_uniform_buffer_update_after_bind,
+ descriptor_binding_uniform_texel_buffer_update_after_bind: self
+ .descriptor_binding_uniform_texel_buffer_update_after_bind
+ && !other.descriptor_binding_uniform_texel_buffer_update_after_bind,
+ descriptor_binding_update_unused_while_pending: self
+ .descriptor_binding_update_unused_while_pending
+ && !other.descriptor_binding_update_unused_while_pending,
+ descriptor_binding_variable_descriptor_count: self
+ .descriptor_binding_variable_descriptor_count
+ && !other.descriptor_binding_variable_descriptor_count,
+ descriptor_buffer: self.descriptor_buffer && !other.descriptor_buffer,
+ descriptor_buffer_capture_replay: self.descriptor_buffer_capture_replay
+ && !other.descriptor_buffer_capture_replay,
+ descriptor_buffer_image_layout_ignored: self.descriptor_buffer_image_layout_ignored
+ && !other.descriptor_buffer_image_layout_ignored,
+ descriptor_buffer_push_descriptors: self.descriptor_buffer_push_descriptors
+ && !other.descriptor_buffer_push_descriptors,
+ descriptor_indexing: self.descriptor_indexing && !other.descriptor_indexing,
+ descriptor_set_host_mapping: self.descriptor_set_host_mapping
+ && !other.descriptor_set_host_mapping,
+ device_coherent_memory: self.device_coherent_memory && !other.device_coherent_memory,
+ device_fault: self.device_fault && !other.device_fault,
+ device_fault_vendor_binary: self.device_fault_vendor_binary
+ && !other.device_fault_vendor_binary,
+ device_generated_commands: self.device_generated_commands
+ && !other.device_generated_commands,
+ device_memory_report: self.device_memory_report && !other.device_memory_report,
+ diagnostics_config: self.diagnostics_config && !other.diagnostics_config,
+ draw_indirect_count: self.draw_indirect_count && !other.draw_indirect_count,
+ draw_indirect_first_instance: self.draw_indirect_first_instance
+ && !other.draw_indirect_first_instance,
+ dual_src_blend: self.dual_src_blend && !other.dual_src_blend,
+ dynamic_rendering: self.dynamic_rendering && !other.dynamic_rendering,
+ events: self.events && !other.events,
+ exclusive_scissor: self.exclusive_scissor && !other.exclusive_scissor,
+ extended_dynamic_state: self.extended_dynamic_state && !other.extended_dynamic_state,
+ extended_dynamic_state2: self.extended_dynamic_state2 && !other.extended_dynamic_state2,
+ extended_dynamic_state2_logic_op: self.extended_dynamic_state2_logic_op
+ && !other.extended_dynamic_state2_logic_op,
+ extended_dynamic_state2_patch_control_points: self
+ .extended_dynamic_state2_patch_control_points
+ && !other.extended_dynamic_state2_patch_control_points,
+ extended_dynamic_state3_alpha_to_coverage_enable: self
+ .extended_dynamic_state3_alpha_to_coverage_enable
+ && !other.extended_dynamic_state3_alpha_to_coverage_enable,
+ extended_dynamic_state3_alpha_to_one_enable: self
+ .extended_dynamic_state3_alpha_to_one_enable
+ && !other.extended_dynamic_state3_alpha_to_one_enable,
+ extended_dynamic_state3_color_blend_advanced: self
+ .extended_dynamic_state3_color_blend_advanced
+ && !other.extended_dynamic_state3_color_blend_advanced,
+ extended_dynamic_state3_color_blend_enable: self
+ .extended_dynamic_state3_color_blend_enable
+ && !other.extended_dynamic_state3_color_blend_enable,
+ extended_dynamic_state3_color_blend_equation: self
+ .extended_dynamic_state3_color_blend_equation
+ && !other.extended_dynamic_state3_color_blend_equation,
+ extended_dynamic_state3_color_write_mask: self.extended_dynamic_state3_color_write_mask
+ && !other.extended_dynamic_state3_color_write_mask,
+ extended_dynamic_state3_conservative_rasterization_mode: self
+ .extended_dynamic_state3_conservative_rasterization_mode
+ && !other.extended_dynamic_state3_conservative_rasterization_mode,
+ extended_dynamic_state3_coverage_modulation_mode: self
+ .extended_dynamic_state3_coverage_modulation_mode
+ && !other.extended_dynamic_state3_coverage_modulation_mode,
+ extended_dynamic_state3_coverage_modulation_table: self
+ .extended_dynamic_state3_coverage_modulation_table
+ && !other.extended_dynamic_state3_coverage_modulation_table,
+ extended_dynamic_state3_coverage_modulation_table_enable: self
+ .extended_dynamic_state3_coverage_modulation_table_enable
+ && !other.extended_dynamic_state3_coverage_modulation_table_enable,
+ extended_dynamic_state3_coverage_reduction_mode: self
+ .extended_dynamic_state3_coverage_reduction_mode
+ && !other.extended_dynamic_state3_coverage_reduction_mode,
+ extended_dynamic_state3_coverage_to_color_enable: self
+ .extended_dynamic_state3_coverage_to_color_enable
+ && !other.extended_dynamic_state3_coverage_to_color_enable,
+ extended_dynamic_state3_coverage_to_color_location: self
+ .extended_dynamic_state3_coverage_to_color_location
+ && !other.extended_dynamic_state3_coverage_to_color_location,
+ extended_dynamic_state3_depth_clamp_enable: self
+ .extended_dynamic_state3_depth_clamp_enable
+ && !other.extended_dynamic_state3_depth_clamp_enable,
+ extended_dynamic_state3_depth_clip_enable: self
+ .extended_dynamic_state3_depth_clip_enable
+ && !other.extended_dynamic_state3_depth_clip_enable,
+ extended_dynamic_state3_depth_clip_negative_one_to_one: self
+ .extended_dynamic_state3_depth_clip_negative_one_to_one
+ && !other.extended_dynamic_state3_depth_clip_negative_one_to_one,
+ extended_dynamic_state3_extra_primitive_overestimation_size: self
+ .extended_dynamic_state3_extra_primitive_overestimation_size
+ && !other.extended_dynamic_state3_extra_primitive_overestimation_size,
+ extended_dynamic_state3_line_rasterization_mode: self
+ .extended_dynamic_state3_line_rasterization_mode
+ && !other.extended_dynamic_state3_line_rasterization_mode,
+ extended_dynamic_state3_line_stipple_enable: self
+ .extended_dynamic_state3_line_stipple_enable
+ && !other.extended_dynamic_state3_line_stipple_enable,
+ extended_dynamic_state3_logic_op_enable: self.extended_dynamic_state3_logic_op_enable
+ && !other.extended_dynamic_state3_logic_op_enable,
+ extended_dynamic_state3_polygon_mode: self.extended_dynamic_state3_polygon_mode
+ && !other.extended_dynamic_state3_polygon_mode,
+ extended_dynamic_state3_provoking_vertex_mode: self
+ .extended_dynamic_state3_provoking_vertex_mode
+ && !other.extended_dynamic_state3_provoking_vertex_mode,
+ extended_dynamic_state3_rasterization_samples: self
+ .extended_dynamic_state3_rasterization_samples
+ && !other.extended_dynamic_state3_rasterization_samples,
+ extended_dynamic_state3_rasterization_stream: self
+ .extended_dynamic_state3_rasterization_stream
+ && !other.extended_dynamic_state3_rasterization_stream,
+ extended_dynamic_state3_representative_fragment_test_enable: self
+ .extended_dynamic_state3_representative_fragment_test_enable
+ && !other.extended_dynamic_state3_representative_fragment_test_enable,
+ extended_dynamic_state3_sample_locations_enable: self
+ .extended_dynamic_state3_sample_locations_enable
+ && !other.extended_dynamic_state3_sample_locations_enable,
+ extended_dynamic_state3_sample_mask: self.extended_dynamic_state3_sample_mask
+ && !other.extended_dynamic_state3_sample_mask,
+ extended_dynamic_state3_shading_rate_image_enable: self
+ .extended_dynamic_state3_shading_rate_image_enable
+ && !other.extended_dynamic_state3_shading_rate_image_enable,
+ extended_dynamic_state3_tessellation_domain_origin: self
+ .extended_dynamic_state3_tessellation_domain_origin
+ && !other.extended_dynamic_state3_tessellation_domain_origin,
+ extended_dynamic_state3_viewport_swizzle: self.extended_dynamic_state3_viewport_swizzle
+ && !other.extended_dynamic_state3_viewport_swizzle,
+ extended_dynamic_state3_viewport_w_scaling_enable: self
+ .extended_dynamic_state3_viewport_w_scaling_enable
+ && !other.extended_dynamic_state3_viewport_w_scaling_enable,
+ external_memory_rdma: self.external_memory_rdma && !other.external_memory_rdma,
+ fill_mode_non_solid: self.fill_mode_non_solid && !other.fill_mode_non_solid,
+ format_a4b4g4r4: self.format_a4b4g4r4 && !other.format_a4b4g4r4,
+ format_a4r4g4b4: self.format_a4r4g4b4 && !other.format_a4r4g4b4,
+ format_rgba10x6_without_y_cb_cr_sampler: self.format_rgba10x6_without_y_cb_cr_sampler
+ && !other.format_rgba10x6_without_y_cb_cr_sampler,
+ fragment_density_map: self.fragment_density_map && !other.fragment_density_map,
+ fragment_density_map_deferred: self.fragment_density_map_deferred
+ && !other.fragment_density_map_deferred,
+ fragment_density_map_dynamic: self.fragment_density_map_dynamic
+ && !other.fragment_density_map_dynamic,
+ fragment_density_map_non_subsampled_images: self
+ .fragment_density_map_non_subsampled_images
+ && !other.fragment_density_map_non_subsampled_images,
+ fragment_density_map_offset: self.fragment_density_map_offset
+ && !other.fragment_density_map_offset,
+ fragment_shader_barycentric: self.fragment_shader_barycentric
+ && !other.fragment_shader_barycentric,
+ fragment_shader_pixel_interlock: self.fragment_shader_pixel_interlock
+ && !other.fragment_shader_pixel_interlock,
+ fragment_shader_sample_interlock: self.fragment_shader_sample_interlock
+ && !other.fragment_shader_sample_interlock,
+ fragment_shader_shading_rate_interlock: self.fragment_shader_shading_rate_interlock
+ && !other.fragment_shader_shading_rate_interlock,
+ fragment_shading_rate_enums: self.fragment_shading_rate_enums
+ && !other.fragment_shading_rate_enums,
+ fragment_stores_and_atomics: self.fragment_stores_and_atomics
+ && !other.fragment_stores_and_atomics,
+ full_draw_index_uint32: self.full_draw_index_uint32 && !other.full_draw_index_uint32,
+ geometry_shader: self.geometry_shader && !other.geometry_shader,
+ geometry_streams: self.geometry_streams && !other.geometry_streams,
+ global_priority_query: self.global_priority_query && !other.global_priority_query,
+ graphics_pipeline_library: self.graphics_pipeline_library
+ && !other.graphics_pipeline_library,
+ host_query_reset: self.host_query_reset && !other.host_query_reset,
+ image2_d_view_of3_d: self.image2_d_view_of3_d && !other.image2_d_view_of3_d,
+ image_compression_control: self.image_compression_control
+ && !other.image_compression_control,
+ image_compression_control_swapchain: self.image_compression_control_swapchain
+ && !other.image_compression_control_swapchain,
+ image_cube_array: self.image_cube_array && !other.image_cube_array,
+ image_footprint: self.image_footprint && !other.image_footprint,
+ image_view2_d_on3_d_image: self.image_view2_d_on3_d_image
+ && !other.image_view2_d_on3_d_image,
+ image_view_format_reinterpretation: self.image_view_format_reinterpretation
+ && !other.image_view_format_reinterpretation,
+ image_view_format_swizzle: self.image_view_format_swizzle
+ && !other.image_view_format_swizzle,
+ imageless_framebuffer: self.imageless_framebuffer && !other.imageless_framebuffer,
+ independent_blend: self.independent_blend && !other.independent_blend,
+ index_type_uint8: self.index_type_uint8 && !other.index_type_uint8,
+ indirect_copy: self.indirect_copy && !other.indirect_copy,
+ inherited_conditional_rendering: self.inherited_conditional_rendering
+ && !other.inherited_conditional_rendering,
+ inherited_queries: self.inherited_queries && !other.inherited_queries,
+ inherited_viewport_scissor2_d: self.inherited_viewport_scissor2_d
+ && !other.inherited_viewport_scissor2_d,
+ inline_uniform_block: self.inline_uniform_block && !other.inline_uniform_block,
+ invocation_mask: self.invocation_mask && !other.invocation_mask,
+ large_points: self.large_points && !other.large_points,
+ legacy_dithering: self.legacy_dithering && !other.legacy_dithering,
+ linear_color_attachment: self.linear_color_attachment && !other.linear_color_attachment,
+ logic_op: self.logic_op && !other.logic_op,
+ maintenance4: self.maintenance4 && !other.maintenance4,
+ memory_decompression: self.memory_decompression && !other.memory_decompression,
+ memory_priority: self.memory_priority && !other.memory_priority,
+ mesh_shader: self.mesh_shader && !other.mesh_shader,
+ mesh_shader_queries: self.mesh_shader_queries && !other.mesh_shader_queries,
+ micromap: self.micromap && !other.micromap,
+ micromap_capture_replay: self.micromap_capture_replay && !other.micromap_capture_replay,
+ micromap_host_commands: self.micromap_host_commands && !other.micromap_host_commands,
+ min_lod: self.min_lod && !other.min_lod,
+ multi_draw: self.multi_draw && !other.multi_draw,
+ multi_draw_indirect: self.multi_draw_indirect && !other.multi_draw_indirect,
+ multi_viewport: self.multi_viewport && !other.multi_viewport,
+ multisample_array_image: self.multisample_array_image && !other.multisample_array_image,
+ multisampled_render_to_single_sampled: self.multisampled_render_to_single_sampled
+ && !other.multisampled_render_to_single_sampled,
+ multiview: self.multiview && !other.multiview,
+ multiview_geometry_shader: self.multiview_geometry_shader
+ && !other.multiview_geometry_shader,
+ multiview_mesh_shader: self.multiview_mesh_shader && !other.multiview_mesh_shader,
+ multiview_per_view_viewports: self.multiview_per_view_viewports
+ && !other.multiview_per_view_viewports,
+ multiview_tessellation_shader: self.multiview_tessellation_shader
+ && !other.multiview_tessellation_shader,
+ mutable_comparison_samplers: self.mutable_comparison_samplers
+ && !other.mutable_comparison_samplers,
+ mutable_descriptor_type: self.mutable_descriptor_type && !other.mutable_descriptor_type,
+ no_invocation_fragment_shading_rates: self.no_invocation_fragment_shading_rates
+ && !other.no_invocation_fragment_shading_rates,
+ non_seamless_cube_map: self.non_seamless_cube_map && !other.non_seamless_cube_map,
+ null_descriptor: self.null_descriptor && !other.null_descriptor,
+ occlusion_query_precise: self.occlusion_query_precise && !other.occlusion_query_precise,
+ optical_flow: self.optical_flow && !other.optical_flow,
+ pageable_device_local_memory: self.pageable_device_local_memory
+ && !other.pageable_device_local_memory,
+ performance_counter_multiple_query_pools: self.performance_counter_multiple_query_pools
+ && !other.performance_counter_multiple_query_pools,
+ performance_counter_query_pools: self.performance_counter_query_pools
+ && !other.performance_counter_query_pools,
+ pipeline_creation_cache_control: self.pipeline_creation_cache_control
+ && !other.pipeline_creation_cache_control,
+ pipeline_executable_info: self.pipeline_executable_info
+ && !other.pipeline_executable_info,
+ pipeline_fragment_shading_rate: self.pipeline_fragment_shading_rate
+ && !other.pipeline_fragment_shading_rate,
+ pipeline_properties_identifier: self.pipeline_properties_identifier
+ && !other.pipeline_properties_identifier,
+ pipeline_protected_access: self.pipeline_protected_access
+ && !other.pipeline_protected_access,
+ pipeline_robustness: self.pipeline_robustness && !other.pipeline_robustness,
+ pipeline_statistics_query: self.pipeline_statistics_query
+ && !other.pipeline_statistics_query,
+ point_polygons: self.point_polygons && !other.point_polygons,
+ present_barrier: self.present_barrier && !other.present_barrier,
+ present_id: self.present_id && !other.present_id,
+ present_wait: self.present_wait && !other.present_wait,
+ primitive_fragment_shading_rate: self.primitive_fragment_shading_rate
+ && !other.primitive_fragment_shading_rate,
+ primitive_fragment_shading_rate_mesh_shader: self
+ .primitive_fragment_shading_rate_mesh_shader
+ && !other.primitive_fragment_shading_rate_mesh_shader,
+ primitive_topology_list_restart: self.primitive_topology_list_restart
+ && !other.primitive_topology_list_restart,
+ primitive_topology_patch_list_restart: self.primitive_topology_patch_list_restart
+ && !other.primitive_topology_patch_list_restart,
+ primitives_generated_query: self.primitives_generated_query
+ && !other.primitives_generated_query,
+ primitives_generated_query_with_non_zero_streams: self
+ .primitives_generated_query_with_non_zero_streams
+ && !other.primitives_generated_query_with_non_zero_streams,
+ primitives_generated_query_with_rasterizer_discard: self
+ .primitives_generated_query_with_rasterizer_discard
+ && !other.primitives_generated_query_with_rasterizer_discard,
+ private_data: self.private_data && !other.private_data,
+ protected_memory: self.protected_memory && !other.protected_memory,
+ provoking_vertex_last: self.provoking_vertex_last && !other.provoking_vertex_last,
+ rasterization_order_color_attachment_access: self
+ .rasterization_order_color_attachment_access
+ && !other.rasterization_order_color_attachment_access,
+ rasterization_order_depth_attachment_access: self
+ .rasterization_order_depth_attachment_access
+ && !other.rasterization_order_depth_attachment_access,
+ rasterization_order_stencil_attachment_access: self
+ .rasterization_order_stencil_attachment_access
+ && !other.rasterization_order_stencil_attachment_access,
+ ray_query: self.ray_query && !other.ray_query,
+ ray_tracing_invocation_reorder: self.ray_tracing_invocation_reorder
+ && !other.ray_tracing_invocation_reorder,
+ ray_tracing_maintenance1: self.ray_tracing_maintenance1
+ && !other.ray_tracing_maintenance1,
+ ray_tracing_motion_blur: self.ray_tracing_motion_blur && !other.ray_tracing_motion_blur,
+ ray_tracing_motion_blur_pipeline_trace_rays_indirect: self
+ .ray_tracing_motion_blur_pipeline_trace_rays_indirect
+ && !other.ray_tracing_motion_blur_pipeline_trace_rays_indirect,
+ ray_tracing_pipeline: self.ray_tracing_pipeline && !other.ray_tracing_pipeline,
+ ray_tracing_pipeline_shader_group_handle_capture_replay: self
+ .ray_tracing_pipeline_shader_group_handle_capture_replay
+ && !other.ray_tracing_pipeline_shader_group_handle_capture_replay,
+ ray_tracing_pipeline_shader_group_handle_capture_replay_mixed: self
+ .ray_tracing_pipeline_shader_group_handle_capture_replay_mixed
+ && !other.ray_tracing_pipeline_shader_group_handle_capture_replay_mixed,
+ ray_tracing_pipeline_trace_rays_indirect: self.ray_tracing_pipeline_trace_rays_indirect
+ && !other.ray_tracing_pipeline_trace_rays_indirect,
+ ray_tracing_pipeline_trace_rays_indirect2: self
+ .ray_tracing_pipeline_trace_rays_indirect2
+ && !other.ray_tracing_pipeline_trace_rays_indirect2,
+ ray_traversal_primitive_culling: self.ray_traversal_primitive_culling
+ && !other.ray_traversal_primitive_culling,
+ rectangular_lines: self.rectangular_lines && !other.rectangular_lines,
+ report_address_binding: self.report_address_binding && !other.report_address_binding,
+ representative_fragment_test: self.representative_fragment_test
+ && !other.representative_fragment_test,
+ robust_buffer_access: self.robust_buffer_access && !other.robust_buffer_access,
+ robust_buffer_access2: self.robust_buffer_access2 && !other.robust_buffer_access2,
+ robust_image_access: self.robust_image_access && !other.robust_image_access,
+ robust_image_access2: self.robust_image_access2 && !other.robust_image_access2,
+ runtime_descriptor_array: self.runtime_descriptor_array
+ && !other.runtime_descriptor_array,
+ sample_rate_shading: self.sample_rate_shading && !other.sample_rate_shading,
+ sampler2_d_view_of3_d: self.sampler2_d_view_of3_d && !other.sampler2_d_view_of3_d,
+ sampler_anisotropy: self.sampler_anisotropy && !other.sampler_anisotropy,
+ sampler_filter_minmax: self.sampler_filter_minmax && !other.sampler_filter_minmax,
+ sampler_mip_lod_bias: self.sampler_mip_lod_bias && !other.sampler_mip_lod_bias,
+ sampler_mirror_clamp_to_edge: self.sampler_mirror_clamp_to_edge
+ && !other.sampler_mirror_clamp_to_edge,
+ sampler_ycbcr_conversion: self.sampler_ycbcr_conversion
+ && !other.sampler_ycbcr_conversion,
+ scalar_block_layout: self.scalar_block_layout && !other.scalar_block_layout,
+ separate_depth_stencil_layouts: self.separate_depth_stencil_layouts
+ && !other.separate_depth_stencil_layouts,
+ separate_stencil_mask_ref: self.separate_stencil_mask_ref
+ && !other.separate_stencil_mask_ref,
+ shader_buffer_float16_atomic_add: self.shader_buffer_float16_atomic_add
+ && !other.shader_buffer_float16_atomic_add,
+ shader_buffer_float16_atomic_min_max: self.shader_buffer_float16_atomic_min_max
+ && !other.shader_buffer_float16_atomic_min_max,
+ shader_buffer_float16_atomics: self.shader_buffer_float16_atomics
+ && !other.shader_buffer_float16_atomics,
+ shader_buffer_float32_atomic_add: self.shader_buffer_float32_atomic_add
+ && !other.shader_buffer_float32_atomic_add,
+ shader_buffer_float32_atomic_min_max: self.shader_buffer_float32_atomic_min_max
+ && !other.shader_buffer_float32_atomic_min_max,
+ shader_buffer_float32_atomics: self.shader_buffer_float32_atomics
+ && !other.shader_buffer_float32_atomics,
+ shader_buffer_float64_atomic_add: self.shader_buffer_float64_atomic_add
+ && !other.shader_buffer_float64_atomic_add,
+ shader_buffer_float64_atomic_min_max: self.shader_buffer_float64_atomic_min_max
+ && !other.shader_buffer_float64_atomic_min_max,
+ shader_buffer_float64_atomics: self.shader_buffer_float64_atomics
+ && !other.shader_buffer_float64_atomics,
+ shader_buffer_int64_atomics: self.shader_buffer_int64_atomics
+ && !other.shader_buffer_int64_atomics,
+ shader_clip_distance: self.shader_clip_distance && !other.shader_clip_distance,
+ shader_core_builtins: self.shader_core_builtins && !other.shader_core_builtins,
+ shader_cull_distance: self.shader_cull_distance && !other.shader_cull_distance,
+ shader_demote_to_helper_invocation: self.shader_demote_to_helper_invocation
+ && !other.shader_demote_to_helper_invocation,
+ shader_device_clock: self.shader_device_clock && !other.shader_device_clock,
+ shader_draw_parameters: self.shader_draw_parameters && !other.shader_draw_parameters,
+ shader_early_and_late_fragment_tests: self.shader_early_and_late_fragment_tests
+ && !other.shader_early_and_late_fragment_tests,
+ shader_float16: self.shader_float16 && !other.shader_float16,
+ shader_float64: self.shader_float64 && !other.shader_float64,
+ shader_image_float32_atomic_add: self.shader_image_float32_atomic_add
+ && !other.shader_image_float32_atomic_add,
+ shader_image_float32_atomic_min_max: self.shader_image_float32_atomic_min_max
+ && !other.shader_image_float32_atomic_min_max,
+ shader_image_float32_atomics: self.shader_image_float32_atomics
+ && !other.shader_image_float32_atomics,
+ shader_image_gather_extended: self.shader_image_gather_extended
+ && !other.shader_image_gather_extended,
+ shader_image_int64_atomics: self.shader_image_int64_atomics
+ && !other.shader_image_int64_atomics,
+ shader_input_attachment_array_dynamic_indexing: self
+ .shader_input_attachment_array_dynamic_indexing
+ && !other.shader_input_attachment_array_dynamic_indexing,
+ shader_input_attachment_array_non_uniform_indexing: self
+ .shader_input_attachment_array_non_uniform_indexing
+ && !other.shader_input_attachment_array_non_uniform_indexing,
+ shader_int16: self.shader_int16 && !other.shader_int16,
+ shader_int64: self.shader_int64 && !other.shader_int64,
+ shader_int8: self.shader_int8 && !other.shader_int8,
+ shader_integer_dot_product: self.shader_integer_dot_product
+ && !other.shader_integer_dot_product,
+ shader_integer_functions2: self.shader_integer_functions2
+ && !other.shader_integer_functions2,
+ shader_module_identifier: self.shader_module_identifier
+ && !other.shader_module_identifier,
+ shader_output_layer: self.shader_output_layer && !other.shader_output_layer,
+ shader_output_viewport_index: self.shader_output_viewport_index
+ && !other.shader_output_viewport_index,
+ shader_resource_min_lod: self.shader_resource_min_lod && !other.shader_resource_min_lod,
+ shader_resource_residency: self.shader_resource_residency
+ && !other.shader_resource_residency,
+ shader_sample_rate_interpolation_functions: self
+ .shader_sample_rate_interpolation_functions
+ && !other.shader_sample_rate_interpolation_functions,
+ shader_sampled_image_array_dynamic_indexing: self
+ .shader_sampled_image_array_dynamic_indexing
+ && !other.shader_sampled_image_array_dynamic_indexing,
+ shader_sampled_image_array_non_uniform_indexing: self
+ .shader_sampled_image_array_non_uniform_indexing
+ && !other.shader_sampled_image_array_non_uniform_indexing,
+ shader_shared_float16_atomic_add: self.shader_shared_float16_atomic_add
+ && !other.shader_shared_float16_atomic_add,
+ shader_shared_float16_atomic_min_max: self.shader_shared_float16_atomic_min_max
+ && !other.shader_shared_float16_atomic_min_max,
+ shader_shared_float16_atomics: self.shader_shared_float16_atomics
+ && !other.shader_shared_float16_atomics,
+ shader_shared_float32_atomic_add: self.shader_shared_float32_atomic_add
+ && !other.shader_shared_float32_atomic_add,
+ shader_shared_float32_atomic_min_max: self.shader_shared_float32_atomic_min_max
+ && !other.shader_shared_float32_atomic_min_max,
+ shader_shared_float32_atomics: self.shader_shared_float32_atomics
+ && !other.shader_shared_float32_atomics,
+ shader_shared_float64_atomic_add: self.shader_shared_float64_atomic_add
+ && !other.shader_shared_float64_atomic_add,
+ shader_shared_float64_atomic_min_max: self.shader_shared_float64_atomic_min_max
+ && !other.shader_shared_float64_atomic_min_max,
+ shader_shared_float64_atomics: self.shader_shared_float64_atomics
+ && !other.shader_shared_float64_atomics,
+ shader_shared_int64_atomics: self.shader_shared_int64_atomics
+ && !other.shader_shared_int64_atomics,
+ shader_sm_builtins: self.shader_sm_builtins && !other.shader_sm_builtins,
+ shader_storage_buffer_array_dynamic_indexing: self
+ .shader_storage_buffer_array_dynamic_indexing
+ && !other.shader_storage_buffer_array_dynamic_indexing,
+ shader_storage_buffer_array_non_uniform_indexing: self
+ .shader_storage_buffer_array_non_uniform_indexing
+ && !other.shader_storage_buffer_array_non_uniform_indexing,
+ shader_storage_image_array_dynamic_indexing: self
+ .shader_storage_image_array_dynamic_indexing
+ && !other.shader_storage_image_array_dynamic_indexing,
+ shader_storage_image_array_non_uniform_indexing: self
+ .shader_storage_image_array_non_uniform_indexing
+ && !other.shader_storage_image_array_non_uniform_indexing,
+ shader_storage_image_extended_formats: self.shader_storage_image_extended_formats
+ && !other.shader_storage_image_extended_formats,
+ shader_storage_image_multisample: self.shader_storage_image_multisample
+ && !other.shader_storage_image_multisample,
+ shader_storage_image_read_without_format: self.shader_storage_image_read_without_format
+ && !other.shader_storage_image_read_without_format,
+ shader_storage_image_write_without_format: self
+ .shader_storage_image_write_without_format
+ && !other.shader_storage_image_write_without_format,
+ shader_storage_texel_buffer_array_dynamic_indexing: self
+ .shader_storage_texel_buffer_array_dynamic_indexing
+ && !other.shader_storage_texel_buffer_array_dynamic_indexing,
+ shader_storage_texel_buffer_array_non_uniform_indexing: self
+ .shader_storage_texel_buffer_array_non_uniform_indexing
+ && !other.shader_storage_texel_buffer_array_non_uniform_indexing,
+ shader_subgroup_clock: self.shader_subgroup_clock && !other.shader_subgroup_clock,
+ shader_subgroup_extended_types: self.shader_subgroup_extended_types
+ && !other.shader_subgroup_extended_types,
+ shader_subgroup_uniform_control_flow: self.shader_subgroup_uniform_control_flow
+ && !other.shader_subgroup_uniform_control_flow,
+ shader_terminate_invocation: self.shader_terminate_invocation
+ && !other.shader_terminate_invocation,
+ shader_tessellation_and_geometry_point_size: self
+ .shader_tessellation_and_geometry_point_size
+ && !other.shader_tessellation_and_geometry_point_size,
+ shader_uniform_buffer_array_dynamic_indexing: self
+ .shader_uniform_buffer_array_dynamic_indexing
+ && !other.shader_uniform_buffer_array_dynamic_indexing,
+ shader_uniform_buffer_array_non_uniform_indexing: self
+ .shader_uniform_buffer_array_non_uniform_indexing
+ && !other.shader_uniform_buffer_array_non_uniform_indexing,
+ shader_uniform_texel_buffer_array_dynamic_indexing: self
+ .shader_uniform_texel_buffer_array_dynamic_indexing
+ && !other.shader_uniform_texel_buffer_array_dynamic_indexing,
+ shader_uniform_texel_buffer_array_non_uniform_indexing: self
+ .shader_uniform_texel_buffer_array_non_uniform_indexing
+ && !other.shader_uniform_texel_buffer_array_non_uniform_indexing,
+ shader_zero_initialize_workgroup_memory: self.shader_zero_initialize_workgroup_memory
+ && !other.shader_zero_initialize_workgroup_memory,
+ shading_rate_coarse_sample_order: self.shading_rate_coarse_sample_order
+ && !other.shading_rate_coarse_sample_order,
+ shading_rate_image: self.shading_rate_image && !other.shading_rate_image,
+ smooth_lines: self.smooth_lines && !other.smooth_lines,
+ sparse_binding: self.sparse_binding && !other.sparse_binding,
+ sparse_image_float32_atomic_add: self.sparse_image_float32_atomic_add
+ && !other.sparse_image_float32_atomic_add,
+ sparse_image_float32_atomic_min_max: self.sparse_image_float32_atomic_min_max
+ && !other.sparse_image_float32_atomic_min_max,
+ sparse_image_float32_atomics: self.sparse_image_float32_atomics
+ && !other.sparse_image_float32_atomics,
+ sparse_image_int64_atomics: self.sparse_image_int64_atomics
+ && !other.sparse_image_int64_atomics,
+ sparse_residency16_samples: self.sparse_residency16_samples
+ && !other.sparse_residency16_samples,
+ sparse_residency2_samples: self.sparse_residency2_samples
+ && !other.sparse_residency2_samples,
+ sparse_residency4_samples: self.sparse_residency4_samples
+ && !other.sparse_residency4_samples,
+ sparse_residency8_samples: self.sparse_residency8_samples
+ && !other.sparse_residency8_samples,
+ sparse_residency_aliased: self.sparse_residency_aliased
+ && !other.sparse_residency_aliased,
+ sparse_residency_buffer: self.sparse_residency_buffer && !other.sparse_residency_buffer,
+ sparse_residency_image2_d: self.sparse_residency_image2_d
+ && !other.sparse_residency_image2_d,
+ sparse_residency_image3_d: self.sparse_residency_image3_d
+ && !other.sparse_residency_image3_d,
+ stippled_bresenham_lines: self.stippled_bresenham_lines
+ && !other.stippled_bresenham_lines,
+ stippled_rectangular_lines: self.stippled_rectangular_lines
+ && !other.stippled_rectangular_lines,
+ stippled_smooth_lines: self.stippled_smooth_lines && !other.stippled_smooth_lines,
+ storage_buffer16_bit_access: self.storage_buffer16_bit_access
+ && !other.storage_buffer16_bit_access,
+ storage_buffer8_bit_access: self.storage_buffer8_bit_access
+ && !other.storage_buffer8_bit_access,
+ storage_input_output16: self.storage_input_output16 && !other.storage_input_output16,
+ storage_push_constant16: self.storage_push_constant16 && !other.storage_push_constant16,
+ storage_push_constant8: self.storage_push_constant8 && !other.storage_push_constant8,
+ subgroup_broadcast_dynamic_id: self.subgroup_broadcast_dynamic_id
+ && !other.subgroup_broadcast_dynamic_id,
+ subgroup_size_control: self.subgroup_size_control && !other.subgroup_size_control,
+ subpass_merge_feedback: self.subpass_merge_feedback && !other.subpass_merge_feedback,
+ subpass_shading: self.subpass_shading && !other.subpass_shading,
+ supersample_fragment_shading_rates: self.supersample_fragment_shading_rates
+ && !other.supersample_fragment_shading_rates,
+ swapchain_maintenance1: self.swapchain_maintenance1 && !other.swapchain_maintenance1,
+ synchronization2: self.synchronization2 && !other.synchronization2,
+ task_shader: self.task_shader && !other.task_shader,
+ tessellation_isolines: self.tessellation_isolines && !other.tessellation_isolines,
+ tessellation_point_mode: self.tessellation_point_mode && !other.tessellation_point_mode,
+ tessellation_shader: self.tessellation_shader && !other.tessellation_shader,
+ texel_buffer_alignment: self.texel_buffer_alignment && !other.texel_buffer_alignment,
+ texture_block_match: self.texture_block_match && !other.texture_block_match,
+ texture_box_filter: self.texture_box_filter && !other.texture_box_filter,
+ texture_compression_astc_hdr: self.texture_compression_astc_hdr
+ && !other.texture_compression_astc_hdr,
+ texture_compression_astc_ldr: self.texture_compression_astc_ldr
+ && !other.texture_compression_astc_ldr,
+ texture_compression_bc: self.texture_compression_bc && !other.texture_compression_bc,
+ texture_compression_etc2: self.texture_compression_etc2
+ && !other.texture_compression_etc2,
+ texture_sample_weighted: self.texture_sample_weighted && !other.texture_sample_weighted,
+ tile_properties: self.tile_properties && !other.tile_properties,
+ timeline_semaphore: self.timeline_semaphore && !other.timeline_semaphore,
+ transform_feedback: self.transform_feedback && !other.transform_feedback,
+ transform_feedback_preserves_provoking_vertex: self
+ .transform_feedback_preserves_provoking_vertex
+ && !other.transform_feedback_preserves_provoking_vertex,
+ triangle_fans: self.triangle_fans && !other.triangle_fans,
+ uniform_and_storage_buffer16_bit_access: self.uniform_and_storage_buffer16_bit_access
+ && !other.uniform_and_storage_buffer16_bit_access,
+ uniform_and_storage_buffer8_bit_access: self.uniform_and_storage_buffer8_bit_access
+ && !other.uniform_and_storage_buffer8_bit_access,
+ uniform_buffer_standard_layout: self.uniform_buffer_standard_layout
+ && !other.uniform_buffer_standard_layout,
+ variable_multisample_rate: self.variable_multisample_rate
+ && !other.variable_multisample_rate,
+ variable_pointers: self.variable_pointers && !other.variable_pointers,
+ variable_pointers_storage_buffer: self.variable_pointers_storage_buffer
+ && !other.variable_pointers_storage_buffer,
+ vertex_attribute_access_beyond_stride: self.vertex_attribute_access_beyond_stride
+ && !other.vertex_attribute_access_beyond_stride,
+ vertex_attribute_instance_rate_divisor: self.vertex_attribute_instance_rate_divisor
+ && !other.vertex_attribute_instance_rate_divisor,
+ vertex_attribute_instance_rate_zero_divisor: self
+ .vertex_attribute_instance_rate_zero_divisor
+ && !other.vertex_attribute_instance_rate_zero_divisor,
+ vertex_input_dynamic_state: self.vertex_input_dynamic_state
+ && !other.vertex_input_dynamic_state,
+ vertex_pipeline_stores_and_atomics: self.vertex_pipeline_stores_and_atomics
+ && !other.vertex_pipeline_stores_and_atomics,
+ vulkan_memory_model: self.vulkan_memory_model && !other.vulkan_memory_model,
+ vulkan_memory_model_availability_visibility_chains: self
+ .vulkan_memory_model_availability_visibility_chains
+ && !other.vulkan_memory_model_availability_visibility_chains,
+ vulkan_memory_model_device_scope: self.vulkan_memory_model_device_scope
+ && !other.vulkan_memory_model_device_scope,
+ wide_lines: self.wide_lines && !other.wide_lines,
+ workgroup_memory_explicit_layout: self.workgroup_memory_explicit_layout
+ && !other.workgroup_memory_explicit_layout,
+ workgroup_memory_explicit_layout16_bit_access: self
+ .workgroup_memory_explicit_layout16_bit_access
+ && !other.workgroup_memory_explicit_layout16_bit_access,
+ workgroup_memory_explicit_layout8_bit_access: self
+ .workgroup_memory_explicit_layout8_bit_access
+ && !other.workgroup_memory_explicit_layout8_bit_access,
+ workgroup_memory_explicit_layout_scalar_block_layout: self
+ .workgroup_memory_explicit_layout_scalar_block_layout
+ && !other.workgroup_memory_explicit_layout_scalar_block_layout,
+ ycbcr2plane444_formats: self.ycbcr2plane444_formats && !other.ycbcr2plane444_formats,
+ ycbcr_image_arrays: self.ycbcr_image_arrays && !other.ycbcr_image_arrays,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+ #[doc = r" Returns the members set in `self` or `other`, but not both."]
+ #[inline]
+ pub const fn symmetric_difference(&self, other: &Self) -> Self {
+ Self {
+ acceleration_structure: self.acceleration_structure ^ other.acceleration_structure,
+ acceleration_structure_capture_replay: self.acceleration_structure_capture_replay
+ ^ other.acceleration_structure_capture_replay,
+ acceleration_structure_host_commands: self.acceleration_structure_host_commands
+ ^ other.acceleration_structure_host_commands,
+ acceleration_structure_indirect_build: self.acceleration_structure_indirect_build
+ ^ other.acceleration_structure_indirect_build,
+ advanced_blend_coherent_operations: self.advanced_blend_coherent_operations
+ ^ other.advanced_blend_coherent_operations,
+ alpha_to_one: self.alpha_to_one ^ other.alpha_to_one,
+ amigo_profiling: self.amigo_profiling ^ other.amigo_profiling,
+ attachment_feedback_loop_layout: self.attachment_feedback_loop_layout
+ ^ other.attachment_feedback_loop_layout,
+ attachment_fragment_shading_rate: self.attachment_fragment_shading_rate
+ ^ other.attachment_fragment_shading_rate,
+ border_color_swizzle: self.border_color_swizzle ^ other.border_color_swizzle,
+ border_color_swizzle_from_image: self.border_color_swizzle_from_image
+ ^ other.border_color_swizzle_from_image,
+ bresenham_lines: self.bresenham_lines ^ other.bresenham_lines,
+ buffer_device_address: self.buffer_device_address ^ other.buffer_device_address,
+ buffer_device_address_capture_replay: self.buffer_device_address_capture_replay
+ ^ other.buffer_device_address_capture_replay,
+ buffer_device_address_multi_device: self.buffer_device_address_multi_device
+ ^ other.buffer_device_address_multi_device,
+ color_write_enable: self.color_write_enable ^ other.color_write_enable,
+ compute_derivative_group_linear: self.compute_derivative_group_linear
+ ^ other.compute_derivative_group_linear,
+ compute_derivative_group_quads: self.compute_derivative_group_quads
+ ^ other.compute_derivative_group_quads,
+ compute_full_subgroups: self.compute_full_subgroups ^ other.compute_full_subgroups,
+ conditional_rendering: self.conditional_rendering ^ other.conditional_rendering,
+ constant_alpha_color_blend_factors: self.constant_alpha_color_blend_factors
+ ^ other.constant_alpha_color_blend_factors,
+ cooperative_matrix: self.cooperative_matrix ^ other.cooperative_matrix,
+ cooperative_matrix_robust_buffer_access: self.cooperative_matrix_robust_buffer_access
+ ^ other.cooperative_matrix_robust_buffer_access,
+ corner_sampled_image: self.corner_sampled_image ^ other.corner_sampled_image,
+ coverage_reduction_mode: self.coverage_reduction_mode ^ other.coverage_reduction_mode,
+ custom_border_color_without_format: self.custom_border_color_without_format
+ ^ other.custom_border_color_without_format,
+ custom_border_colors: self.custom_border_colors ^ other.custom_border_colors,
+ decode_mode_shared_exponent: self.decode_mode_shared_exponent
+ ^ other.decode_mode_shared_exponent,
+ dedicated_allocation_image_aliasing: self.dedicated_allocation_image_aliasing
+ ^ other.dedicated_allocation_image_aliasing,
+ depth_bias_clamp: self.depth_bias_clamp ^ other.depth_bias_clamp,
+ depth_bounds: self.depth_bounds ^ other.depth_bounds,
+ depth_clamp: self.depth_clamp ^ other.depth_clamp,
+ depth_clamp_zero_one: self.depth_clamp_zero_one ^ other.depth_clamp_zero_one,
+ depth_clip_control: self.depth_clip_control ^ other.depth_clip_control,
+ depth_clip_enable: self.depth_clip_enable ^ other.depth_clip_enable,
+ descriptor_binding_acceleration_structure_update_after_bind: self
+ .descriptor_binding_acceleration_structure_update_after_bind
+ ^ other.descriptor_binding_acceleration_structure_update_after_bind,
+ descriptor_binding_inline_uniform_block_update_after_bind: self
+ .descriptor_binding_inline_uniform_block_update_after_bind
+ ^ other.descriptor_binding_inline_uniform_block_update_after_bind,
+ descriptor_binding_partially_bound: self.descriptor_binding_partially_bound
+ ^ other.descriptor_binding_partially_bound,
+ descriptor_binding_sampled_image_update_after_bind: self
+ .descriptor_binding_sampled_image_update_after_bind
+ ^ other.descriptor_binding_sampled_image_update_after_bind,
+ descriptor_binding_storage_buffer_update_after_bind: self
+ .descriptor_binding_storage_buffer_update_after_bind
+ ^ other.descriptor_binding_storage_buffer_update_after_bind,
+ descriptor_binding_storage_image_update_after_bind: self
+ .descriptor_binding_storage_image_update_after_bind
+ ^ other.descriptor_binding_storage_image_update_after_bind,
+ descriptor_binding_storage_texel_buffer_update_after_bind: self
+ .descriptor_binding_storage_texel_buffer_update_after_bind
+ ^ other.descriptor_binding_storage_texel_buffer_update_after_bind,
+ descriptor_binding_uniform_buffer_update_after_bind: self
+ .descriptor_binding_uniform_buffer_update_after_bind
+ ^ other.descriptor_binding_uniform_buffer_update_after_bind,
+ descriptor_binding_uniform_texel_buffer_update_after_bind: self
+ .descriptor_binding_uniform_texel_buffer_update_after_bind
+ ^ other.descriptor_binding_uniform_texel_buffer_update_after_bind,
+ descriptor_binding_update_unused_while_pending: self
+ .descriptor_binding_update_unused_while_pending
+ ^ other.descriptor_binding_update_unused_while_pending,
+ descriptor_binding_variable_descriptor_count: self
+ .descriptor_binding_variable_descriptor_count
+ ^ other.descriptor_binding_variable_descriptor_count,
+ descriptor_buffer: self.descriptor_buffer ^ other.descriptor_buffer,
+ descriptor_buffer_capture_replay: self.descriptor_buffer_capture_replay
+ ^ other.descriptor_buffer_capture_replay,
+ descriptor_buffer_image_layout_ignored: self.descriptor_buffer_image_layout_ignored
+ ^ other.descriptor_buffer_image_layout_ignored,
+ descriptor_buffer_push_descriptors: self.descriptor_buffer_push_descriptors
+ ^ other.descriptor_buffer_push_descriptors,
+ descriptor_indexing: self.descriptor_indexing ^ other.descriptor_indexing,
+ descriptor_set_host_mapping: self.descriptor_set_host_mapping
+ ^ other.descriptor_set_host_mapping,
+ device_coherent_memory: self.device_coherent_memory ^ other.device_coherent_memory,
+ device_fault: self.device_fault ^ other.device_fault,
+ device_fault_vendor_binary: self.device_fault_vendor_binary
+ ^ other.device_fault_vendor_binary,
+ device_generated_commands: self.device_generated_commands
+ ^ other.device_generated_commands,
+ device_memory_report: self.device_memory_report ^ other.device_memory_report,
+ diagnostics_config: self.diagnostics_config ^ other.diagnostics_config,
+ draw_indirect_count: self.draw_indirect_count ^ other.draw_indirect_count,
+ draw_indirect_first_instance: self.draw_indirect_first_instance
+ ^ other.draw_indirect_first_instance,
+ dual_src_blend: self.dual_src_blend ^ other.dual_src_blend,
+ dynamic_rendering: self.dynamic_rendering ^ other.dynamic_rendering,
+ events: self.events ^ other.events,
+ exclusive_scissor: self.exclusive_scissor ^ other.exclusive_scissor,
+ extended_dynamic_state: self.extended_dynamic_state ^ other.extended_dynamic_state,
+ extended_dynamic_state2: self.extended_dynamic_state2 ^ other.extended_dynamic_state2,
+ extended_dynamic_state2_logic_op: self.extended_dynamic_state2_logic_op
+ ^ other.extended_dynamic_state2_logic_op,
+ extended_dynamic_state2_patch_control_points: self
+ .extended_dynamic_state2_patch_control_points
+ ^ other.extended_dynamic_state2_patch_control_points,
+ extended_dynamic_state3_alpha_to_coverage_enable: self
+ .extended_dynamic_state3_alpha_to_coverage_enable
+ ^ other.extended_dynamic_state3_alpha_to_coverage_enable,
+ extended_dynamic_state3_alpha_to_one_enable: self
+ .extended_dynamic_state3_alpha_to_one_enable
+ ^ other.extended_dynamic_state3_alpha_to_one_enable,
+ extended_dynamic_state3_color_blend_advanced: self
+ .extended_dynamic_state3_color_blend_advanced
+ ^ other.extended_dynamic_state3_color_blend_advanced,
+ extended_dynamic_state3_color_blend_enable: self
+ .extended_dynamic_state3_color_blend_enable
+ ^ other.extended_dynamic_state3_color_blend_enable,
+ extended_dynamic_state3_color_blend_equation: self
+ .extended_dynamic_state3_color_blend_equation
+ ^ other.extended_dynamic_state3_color_blend_equation,
+ extended_dynamic_state3_color_write_mask: self.extended_dynamic_state3_color_write_mask
+ ^ other.extended_dynamic_state3_color_write_mask,
+ extended_dynamic_state3_conservative_rasterization_mode: self
+ .extended_dynamic_state3_conservative_rasterization_mode
+ ^ other.extended_dynamic_state3_conservative_rasterization_mode,
+ extended_dynamic_state3_coverage_modulation_mode: self
+ .extended_dynamic_state3_coverage_modulation_mode
+ ^ other.extended_dynamic_state3_coverage_modulation_mode,
+ extended_dynamic_state3_coverage_modulation_table: self
+ .extended_dynamic_state3_coverage_modulation_table
+ ^ other.extended_dynamic_state3_coverage_modulation_table,
+ extended_dynamic_state3_coverage_modulation_table_enable: self
+ .extended_dynamic_state3_coverage_modulation_table_enable
+ ^ other.extended_dynamic_state3_coverage_modulation_table_enable,
+ extended_dynamic_state3_coverage_reduction_mode: self
+ .extended_dynamic_state3_coverage_reduction_mode
+ ^ other.extended_dynamic_state3_coverage_reduction_mode,
+ extended_dynamic_state3_coverage_to_color_enable: self
+ .extended_dynamic_state3_coverage_to_color_enable
+ ^ other.extended_dynamic_state3_coverage_to_color_enable,
+ extended_dynamic_state3_coverage_to_color_location: self
+ .extended_dynamic_state3_coverage_to_color_location
+ ^ other.extended_dynamic_state3_coverage_to_color_location,
+ extended_dynamic_state3_depth_clamp_enable: self
+ .extended_dynamic_state3_depth_clamp_enable
+ ^ other.extended_dynamic_state3_depth_clamp_enable,
+ extended_dynamic_state3_depth_clip_enable: self
+ .extended_dynamic_state3_depth_clip_enable
+ ^ other.extended_dynamic_state3_depth_clip_enable,
+ extended_dynamic_state3_depth_clip_negative_one_to_one: self
+ .extended_dynamic_state3_depth_clip_negative_one_to_one
+ ^ other.extended_dynamic_state3_depth_clip_negative_one_to_one,
+ extended_dynamic_state3_extra_primitive_overestimation_size: self
+ .extended_dynamic_state3_extra_primitive_overestimation_size
+ ^ other.extended_dynamic_state3_extra_primitive_overestimation_size,
+ extended_dynamic_state3_line_rasterization_mode: self
+ .extended_dynamic_state3_line_rasterization_mode
+ ^ other.extended_dynamic_state3_line_rasterization_mode,
+ extended_dynamic_state3_line_stipple_enable: self
+ .extended_dynamic_state3_line_stipple_enable
+ ^ other.extended_dynamic_state3_line_stipple_enable,
+ extended_dynamic_state3_logic_op_enable: self.extended_dynamic_state3_logic_op_enable
+ ^ other.extended_dynamic_state3_logic_op_enable,
+ extended_dynamic_state3_polygon_mode: self.extended_dynamic_state3_polygon_mode
+ ^ other.extended_dynamic_state3_polygon_mode,
+ extended_dynamic_state3_provoking_vertex_mode: self
+ .extended_dynamic_state3_provoking_vertex_mode
+ ^ other.extended_dynamic_state3_provoking_vertex_mode,
+ extended_dynamic_state3_rasterization_samples: self
+ .extended_dynamic_state3_rasterization_samples
+ ^ other.extended_dynamic_state3_rasterization_samples,
+ extended_dynamic_state3_rasterization_stream: self
+ .extended_dynamic_state3_rasterization_stream
+ ^ other.extended_dynamic_state3_rasterization_stream,
+ extended_dynamic_state3_representative_fragment_test_enable: self
+ .extended_dynamic_state3_representative_fragment_test_enable
+ ^ other.extended_dynamic_state3_representative_fragment_test_enable,
+ extended_dynamic_state3_sample_locations_enable: self
+ .extended_dynamic_state3_sample_locations_enable
+ ^ other.extended_dynamic_state3_sample_locations_enable,
+ extended_dynamic_state3_sample_mask: self.extended_dynamic_state3_sample_mask
+ ^ other.extended_dynamic_state3_sample_mask,
+ extended_dynamic_state3_shading_rate_image_enable: self
+ .extended_dynamic_state3_shading_rate_image_enable
+ ^ other.extended_dynamic_state3_shading_rate_image_enable,
+ extended_dynamic_state3_tessellation_domain_origin: self
+ .extended_dynamic_state3_tessellation_domain_origin
+ ^ other.extended_dynamic_state3_tessellation_domain_origin,
+ extended_dynamic_state3_viewport_swizzle: self.extended_dynamic_state3_viewport_swizzle
+ ^ other.extended_dynamic_state3_viewport_swizzle,
+ extended_dynamic_state3_viewport_w_scaling_enable: self
+ .extended_dynamic_state3_viewport_w_scaling_enable
+ ^ other.extended_dynamic_state3_viewport_w_scaling_enable,
+ external_memory_rdma: self.external_memory_rdma ^ other.external_memory_rdma,
+ fill_mode_non_solid: self.fill_mode_non_solid ^ other.fill_mode_non_solid,
+ format_a4b4g4r4: self.format_a4b4g4r4 ^ other.format_a4b4g4r4,
+ format_a4r4g4b4: self.format_a4r4g4b4 ^ other.format_a4r4g4b4,
+ format_rgba10x6_without_y_cb_cr_sampler: self.format_rgba10x6_without_y_cb_cr_sampler
+ ^ other.format_rgba10x6_without_y_cb_cr_sampler,
+ fragment_density_map: self.fragment_density_map ^ other.fragment_density_map,
+ fragment_density_map_deferred: self.fragment_density_map_deferred
+ ^ other.fragment_density_map_deferred,
+ fragment_density_map_dynamic: self.fragment_density_map_dynamic
+ ^ other.fragment_density_map_dynamic,
+ fragment_density_map_non_subsampled_images: self
+ .fragment_density_map_non_subsampled_images
+ ^ other.fragment_density_map_non_subsampled_images,
+ fragment_density_map_offset: self.fragment_density_map_offset
+ ^ other.fragment_density_map_offset,
+ fragment_shader_barycentric: self.fragment_shader_barycentric
+ ^ other.fragment_shader_barycentric,
+ fragment_shader_pixel_interlock: self.fragment_shader_pixel_interlock
+ ^ other.fragment_shader_pixel_interlock,
+ fragment_shader_sample_interlock: self.fragment_shader_sample_interlock
+ ^ other.fragment_shader_sample_interlock,
+ fragment_shader_shading_rate_interlock: self.fragment_shader_shading_rate_interlock
+ ^ other.fragment_shader_shading_rate_interlock,
+ fragment_shading_rate_enums: self.fragment_shading_rate_enums
+ ^ other.fragment_shading_rate_enums,
+ fragment_stores_and_atomics: self.fragment_stores_and_atomics
+ ^ other.fragment_stores_and_atomics,
+ full_draw_index_uint32: self.full_draw_index_uint32 ^ other.full_draw_index_uint32,
+ geometry_shader: self.geometry_shader ^ other.geometry_shader,
+ geometry_streams: self.geometry_streams ^ other.geometry_streams,
+ global_priority_query: self.global_priority_query ^ other.global_priority_query,
+ graphics_pipeline_library: self.graphics_pipeline_library
+ ^ other.graphics_pipeline_library,
+ host_query_reset: self.host_query_reset ^ other.host_query_reset,
+ image2_d_view_of3_d: self.image2_d_view_of3_d ^ other.image2_d_view_of3_d,
+ image_compression_control: self.image_compression_control
+ ^ other.image_compression_control,
+ image_compression_control_swapchain: self.image_compression_control_swapchain
+ ^ other.image_compression_control_swapchain,
+ image_cube_array: self.image_cube_array ^ other.image_cube_array,
+ image_footprint: self.image_footprint ^ other.image_footprint,
+ image_view2_d_on3_d_image: self.image_view2_d_on3_d_image
+ ^ other.image_view2_d_on3_d_image,
+ image_view_format_reinterpretation: self.image_view_format_reinterpretation
+ ^ other.image_view_format_reinterpretation,
+ image_view_format_swizzle: self.image_view_format_swizzle
+ ^ other.image_view_format_swizzle,
+ imageless_framebuffer: self.imageless_framebuffer ^ other.imageless_framebuffer,
+ independent_blend: self.independent_blend ^ other.independent_blend,
+ index_type_uint8: self.index_type_uint8 ^ other.index_type_uint8,
+ indirect_copy: self.indirect_copy ^ other.indirect_copy,
+ inherited_conditional_rendering: self.inherited_conditional_rendering
+ ^ other.inherited_conditional_rendering,
+ inherited_queries: self.inherited_queries ^ other.inherited_queries,
+ inherited_viewport_scissor2_d: self.inherited_viewport_scissor2_d
+ ^ other.inherited_viewport_scissor2_d,
+ inline_uniform_block: self.inline_uniform_block ^ other.inline_uniform_block,
+ invocation_mask: self.invocation_mask ^ other.invocation_mask,
+ large_points: self.large_points ^ other.large_points,
+ legacy_dithering: self.legacy_dithering ^ other.legacy_dithering,
+ linear_color_attachment: self.linear_color_attachment ^ other.linear_color_attachment,
+ logic_op: self.logic_op ^ other.logic_op,
+ maintenance4: self.maintenance4 ^ other.maintenance4,
+ memory_decompression: self.memory_decompression ^ other.memory_decompression,
+ memory_priority: self.memory_priority ^ other.memory_priority,
+ mesh_shader: self.mesh_shader ^ other.mesh_shader,
+ mesh_shader_queries: self.mesh_shader_queries ^ other.mesh_shader_queries,
+ micromap: self.micromap ^ other.micromap,
+ micromap_capture_replay: self.micromap_capture_replay ^ other.micromap_capture_replay,
+ micromap_host_commands: self.micromap_host_commands ^ other.micromap_host_commands,
+ min_lod: self.min_lod ^ other.min_lod,
+ multi_draw: self.multi_draw ^ other.multi_draw,
+ multi_draw_indirect: self.multi_draw_indirect ^ other.multi_draw_indirect,
+ multi_viewport: self.multi_viewport ^ other.multi_viewport,
+ multisample_array_image: self.multisample_array_image ^ other.multisample_array_image,
+ multisampled_render_to_single_sampled: self.multisampled_render_to_single_sampled
+ ^ other.multisampled_render_to_single_sampled,
+ multiview: self.multiview ^ other.multiview,
+ multiview_geometry_shader: self.multiview_geometry_shader
+ ^ other.multiview_geometry_shader,
+ multiview_mesh_shader: self.multiview_mesh_shader ^ other.multiview_mesh_shader,
+ multiview_per_view_viewports: self.multiview_per_view_viewports
+ ^ other.multiview_per_view_viewports,
+ multiview_tessellation_shader: self.multiview_tessellation_shader
+ ^ other.multiview_tessellation_shader,
+ mutable_comparison_samplers: self.mutable_comparison_samplers
+ ^ other.mutable_comparison_samplers,
+ mutable_descriptor_type: self.mutable_descriptor_type ^ other.mutable_descriptor_type,
+ no_invocation_fragment_shading_rates: self.no_invocation_fragment_shading_rates
+ ^ other.no_invocation_fragment_shading_rates,
+ non_seamless_cube_map: self.non_seamless_cube_map ^ other.non_seamless_cube_map,
+ null_descriptor: self.null_descriptor ^ other.null_descriptor,
+ occlusion_query_precise: self.occlusion_query_precise ^ other.occlusion_query_precise,
+ optical_flow: self.optical_flow ^ other.optical_flow,
+ pageable_device_local_memory: self.pageable_device_local_memory
+ ^ other.pageable_device_local_memory,
+ performance_counter_multiple_query_pools: self.performance_counter_multiple_query_pools
+ ^ other.performance_counter_multiple_query_pools,
+ performance_counter_query_pools: self.performance_counter_query_pools
+ ^ other.performance_counter_query_pools,
+ pipeline_creation_cache_control: self.pipeline_creation_cache_control
+ ^ other.pipeline_creation_cache_control,
+ pipeline_executable_info: self.pipeline_executable_info
+ ^ other.pipeline_executable_info,
+ pipeline_fragment_shading_rate: self.pipeline_fragment_shading_rate
+ ^ other.pipeline_fragment_shading_rate,
+ pipeline_properties_identifier: self.pipeline_properties_identifier
+ ^ other.pipeline_properties_identifier,
+ pipeline_protected_access: self.pipeline_protected_access
+ ^ other.pipeline_protected_access,
+ pipeline_robustness: self.pipeline_robustness ^ other.pipeline_robustness,
+ pipeline_statistics_query: self.pipeline_statistics_query
+ ^ other.pipeline_statistics_query,
+ point_polygons: self.point_polygons ^ other.point_polygons,
+ present_barrier: self.present_barrier ^ other.present_barrier,
+ present_id: self.present_id ^ other.present_id,
+ present_wait: self.present_wait ^ other.present_wait,
+ primitive_fragment_shading_rate: self.primitive_fragment_shading_rate
+ ^ other.primitive_fragment_shading_rate,
+ primitive_fragment_shading_rate_mesh_shader: self
+ .primitive_fragment_shading_rate_mesh_shader
+ ^ other.primitive_fragment_shading_rate_mesh_shader,
+ primitive_topology_list_restart: self.primitive_topology_list_restart
+ ^ other.primitive_topology_list_restart,
+ primitive_topology_patch_list_restart: self.primitive_topology_patch_list_restart
+ ^ other.primitive_topology_patch_list_restart,
+ primitives_generated_query: self.primitives_generated_query
+ ^ other.primitives_generated_query,
+ primitives_generated_query_with_non_zero_streams: self
+ .primitives_generated_query_with_non_zero_streams
+ ^ other.primitives_generated_query_with_non_zero_streams,
+ primitives_generated_query_with_rasterizer_discard: self
+ .primitives_generated_query_with_rasterizer_discard
+ ^ other.primitives_generated_query_with_rasterizer_discard,
+ private_data: self.private_data ^ other.private_data,
+ protected_memory: self.protected_memory ^ other.protected_memory,
+ provoking_vertex_last: self.provoking_vertex_last ^ other.provoking_vertex_last,
+ rasterization_order_color_attachment_access: self
+ .rasterization_order_color_attachment_access
+ ^ other.rasterization_order_color_attachment_access,
+ rasterization_order_depth_attachment_access: self
+ .rasterization_order_depth_attachment_access
+ ^ other.rasterization_order_depth_attachment_access,
+ rasterization_order_stencil_attachment_access: self
+ .rasterization_order_stencil_attachment_access
+ ^ other.rasterization_order_stencil_attachment_access,
+ ray_query: self.ray_query ^ other.ray_query,
+ ray_tracing_invocation_reorder: self.ray_tracing_invocation_reorder
+ ^ other.ray_tracing_invocation_reorder,
+ ray_tracing_maintenance1: self.ray_tracing_maintenance1
+ ^ other.ray_tracing_maintenance1,
+ ray_tracing_motion_blur: self.ray_tracing_motion_blur ^ other.ray_tracing_motion_blur,
+ ray_tracing_motion_blur_pipeline_trace_rays_indirect: self
+ .ray_tracing_motion_blur_pipeline_trace_rays_indirect
+ ^ other.ray_tracing_motion_blur_pipeline_trace_rays_indirect,
+ ray_tracing_pipeline: self.ray_tracing_pipeline ^ other.ray_tracing_pipeline,
+ ray_tracing_pipeline_shader_group_handle_capture_replay: self
+ .ray_tracing_pipeline_shader_group_handle_capture_replay
+ ^ other.ray_tracing_pipeline_shader_group_handle_capture_replay,
+ ray_tracing_pipeline_shader_group_handle_capture_replay_mixed: self
+ .ray_tracing_pipeline_shader_group_handle_capture_replay_mixed
+ ^ other.ray_tracing_pipeline_shader_group_handle_capture_replay_mixed,
+ ray_tracing_pipeline_trace_rays_indirect: self.ray_tracing_pipeline_trace_rays_indirect
+ ^ other.ray_tracing_pipeline_trace_rays_indirect,
+ ray_tracing_pipeline_trace_rays_indirect2: self
+ .ray_tracing_pipeline_trace_rays_indirect2
+ ^ other.ray_tracing_pipeline_trace_rays_indirect2,
+ ray_traversal_primitive_culling: self.ray_traversal_primitive_culling
+ ^ other.ray_traversal_primitive_culling,
+ rectangular_lines: self.rectangular_lines ^ other.rectangular_lines,
+ report_address_binding: self.report_address_binding ^ other.report_address_binding,
+ representative_fragment_test: self.representative_fragment_test
+ ^ other.representative_fragment_test,
+ robust_buffer_access: self.robust_buffer_access ^ other.robust_buffer_access,
+ robust_buffer_access2: self.robust_buffer_access2 ^ other.robust_buffer_access2,
+ robust_image_access: self.robust_image_access ^ other.robust_image_access,
+ robust_image_access2: self.robust_image_access2 ^ other.robust_image_access2,
+ runtime_descriptor_array: self.runtime_descriptor_array
+ ^ other.runtime_descriptor_array,
+ sample_rate_shading: self.sample_rate_shading ^ other.sample_rate_shading,
+ sampler2_d_view_of3_d: self.sampler2_d_view_of3_d ^ other.sampler2_d_view_of3_d,
+ sampler_anisotropy: self.sampler_anisotropy ^ other.sampler_anisotropy,
+ sampler_filter_minmax: self.sampler_filter_minmax ^ other.sampler_filter_minmax,
+ sampler_mip_lod_bias: self.sampler_mip_lod_bias ^ other.sampler_mip_lod_bias,
+ sampler_mirror_clamp_to_edge: self.sampler_mirror_clamp_to_edge
+ ^ other.sampler_mirror_clamp_to_edge,
+ sampler_ycbcr_conversion: self.sampler_ycbcr_conversion
+ ^ other.sampler_ycbcr_conversion,
+ scalar_block_layout: self.scalar_block_layout ^ other.scalar_block_layout,
+ separate_depth_stencil_layouts: self.separate_depth_stencil_layouts
+ ^ other.separate_depth_stencil_layouts,
+ separate_stencil_mask_ref: self.separate_stencil_mask_ref
+ ^ other.separate_stencil_mask_ref,
+ shader_buffer_float16_atomic_add: self.shader_buffer_float16_atomic_add
+ ^ other.shader_buffer_float16_atomic_add,
+ shader_buffer_float16_atomic_min_max: self.shader_buffer_float16_atomic_min_max
+ ^ other.shader_buffer_float16_atomic_min_max,
+ shader_buffer_float16_atomics: self.shader_buffer_float16_atomics
+ ^ other.shader_buffer_float16_atomics,
+ shader_buffer_float32_atomic_add: self.shader_buffer_float32_atomic_add
+ ^ other.shader_buffer_float32_atomic_add,
+ shader_buffer_float32_atomic_min_max: self.shader_buffer_float32_atomic_min_max
+ ^ other.shader_buffer_float32_atomic_min_max,
+ shader_buffer_float32_atomics: self.shader_buffer_float32_atomics
+ ^ other.shader_buffer_float32_atomics,
+ shader_buffer_float64_atomic_add: self.shader_buffer_float64_atomic_add
+ ^ other.shader_buffer_float64_atomic_add,
+ shader_buffer_float64_atomic_min_max: self.shader_buffer_float64_atomic_min_max
+ ^ other.shader_buffer_float64_atomic_min_max,
+ shader_buffer_float64_atomics: self.shader_buffer_float64_atomics
+ ^ other.shader_buffer_float64_atomics,
+ shader_buffer_int64_atomics: self.shader_buffer_int64_atomics
+ ^ other.shader_buffer_int64_atomics,
+ shader_clip_distance: self.shader_clip_distance ^ other.shader_clip_distance,
+ shader_core_builtins: self.shader_core_builtins ^ other.shader_core_builtins,
+ shader_cull_distance: self.shader_cull_distance ^ other.shader_cull_distance,
+ shader_demote_to_helper_invocation: self.shader_demote_to_helper_invocation
+ ^ other.shader_demote_to_helper_invocation,
+ shader_device_clock: self.shader_device_clock ^ other.shader_device_clock,
+ shader_draw_parameters: self.shader_draw_parameters ^ other.shader_draw_parameters,
+ shader_early_and_late_fragment_tests: self.shader_early_and_late_fragment_tests
+ ^ other.shader_early_and_late_fragment_tests,
+ shader_float16: self.shader_float16 ^ other.shader_float16,
+ shader_float64: self.shader_float64 ^ other.shader_float64,
+ shader_image_float32_atomic_add: self.shader_image_float32_atomic_add
+ ^ other.shader_image_float32_atomic_add,
+ shader_image_float32_atomic_min_max: self.shader_image_float32_atomic_min_max
+ ^ other.shader_image_float32_atomic_min_max,
+ shader_image_float32_atomics: self.shader_image_float32_atomics
+ ^ other.shader_image_float32_atomics,
+ shader_image_gather_extended: self.shader_image_gather_extended
+ ^ other.shader_image_gather_extended,
+ shader_image_int64_atomics: self.shader_image_int64_atomics
+ ^ other.shader_image_int64_atomics,
+ shader_input_attachment_array_dynamic_indexing: self
+ .shader_input_attachment_array_dynamic_indexing
+ ^ other.shader_input_attachment_array_dynamic_indexing,
+ shader_input_attachment_array_non_uniform_indexing: self
+ .shader_input_attachment_array_non_uniform_indexing
+ ^ other.shader_input_attachment_array_non_uniform_indexing,
+ shader_int16: self.shader_int16 ^ other.shader_int16,
+ shader_int64: self.shader_int64 ^ other.shader_int64,
+ shader_int8: self.shader_int8 ^ other.shader_int8,
+ shader_integer_dot_product: self.shader_integer_dot_product
+ ^ other.shader_integer_dot_product,
+ shader_integer_functions2: self.shader_integer_functions2
+ ^ other.shader_integer_functions2,
+ shader_module_identifier: self.shader_module_identifier
+ ^ other.shader_module_identifier,
+ shader_output_layer: self.shader_output_layer ^ other.shader_output_layer,
+ shader_output_viewport_index: self.shader_output_viewport_index
+ ^ other.shader_output_viewport_index,
+ shader_resource_min_lod: self.shader_resource_min_lod ^ other.shader_resource_min_lod,
+ shader_resource_residency: self.shader_resource_residency
+ ^ other.shader_resource_residency,
+ shader_sample_rate_interpolation_functions: self
+ .shader_sample_rate_interpolation_functions
+ ^ other.shader_sample_rate_interpolation_functions,
+ shader_sampled_image_array_dynamic_indexing: self
+ .shader_sampled_image_array_dynamic_indexing
+ ^ other.shader_sampled_image_array_dynamic_indexing,
+ shader_sampled_image_array_non_uniform_indexing: self
+ .shader_sampled_image_array_non_uniform_indexing
+ ^ other.shader_sampled_image_array_non_uniform_indexing,
+ shader_shared_float16_atomic_add: self.shader_shared_float16_atomic_add
+ ^ other.shader_shared_float16_atomic_add,
+ shader_shared_float16_atomic_min_max: self.shader_shared_float16_atomic_min_max
+ ^ other.shader_shared_float16_atomic_min_max,
+ shader_shared_float16_atomics: self.shader_shared_float16_atomics
+ ^ other.shader_shared_float16_atomics,
+ shader_shared_float32_atomic_add: self.shader_shared_float32_atomic_add
+ ^ other.shader_shared_float32_atomic_add,
+ shader_shared_float32_atomic_min_max: self.shader_shared_float32_atomic_min_max
+ ^ other.shader_shared_float32_atomic_min_max,
+ shader_shared_float32_atomics: self.shader_shared_float32_atomics
+ ^ other.shader_shared_float32_atomics,
+ shader_shared_float64_atomic_add: self.shader_shared_float64_atomic_add
+ ^ other.shader_shared_float64_atomic_add,
+ shader_shared_float64_atomic_min_max: self.shader_shared_float64_atomic_min_max
+ ^ other.shader_shared_float64_atomic_min_max,
+ shader_shared_float64_atomics: self.shader_shared_float64_atomics
+ ^ other.shader_shared_float64_atomics,
+ shader_shared_int64_atomics: self.shader_shared_int64_atomics
+ ^ other.shader_shared_int64_atomics,
+ shader_sm_builtins: self.shader_sm_builtins ^ other.shader_sm_builtins,
+ shader_storage_buffer_array_dynamic_indexing: self
+ .shader_storage_buffer_array_dynamic_indexing
+ ^ other.shader_storage_buffer_array_dynamic_indexing,
+ shader_storage_buffer_array_non_uniform_indexing: self
+ .shader_storage_buffer_array_non_uniform_indexing
+ ^ other.shader_storage_buffer_array_non_uniform_indexing,
+ shader_storage_image_array_dynamic_indexing: self
+ .shader_storage_image_array_dynamic_indexing
+ ^ other.shader_storage_image_array_dynamic_indexing,
+ shader_storage_image_array_non_uniform_indexing: self
+ .shader_storage_image_array_non_uniform_indexing
+ ^ other.shader_storage_image_array_non_uniform_indexing,
+ shader_storage_image_extended_formats: self.shader_storage_image_extended_formats
+ ^ other.shader_storage_image_extended_formats,
+ shader_storage_image_multisample: self.shader_storage_image_multisample
+ ^ other.shader_storage_image_multisample,
+ shader_storage_image_read_without_format: self.shader_storage_image_read_without_format
+ ^ other.shader_storage_image_read_without_format,
+ shader_storage_image_write_without_format: self
+ .shader_storage_image_write_without_format
+ ^ other.shader_storage_image_write_without_format,
+ shader_storage_texel_buffer_array_dynamic_indexing: self
+ .shader_storage_texel_buffer_array_dynamic_indexing
+ ^ other.shader_storage_texel_buffer_array_dynamic_indexing,
+ shader_storage_texel_buffer_array_non_uniform_indexing: self
+ .shader_storage_texel_buffer_array_non_uniform_indexing
+ ^ other.shader_storage_texel_buffer_array_non_uniform_indexing,
+ shader_subgroup_clock: self.shader_subgroup_clock ^ other.shader_subgroup_clock,
+ shader_subgroup_extended_types: self.shader_subgroup_extended_types
+ ^ other.shader_subgroup_extended_types,
+ shader_subgroup_uniform_control_flow: self.shader_subgroup_uniform_control_flow
+ ^ other.shader_subgroup_uniform_control_flow,
+ shader_terminate_invocation: self.shader_terminate_invocation
+ ^ other.shader_terminate_invocation,
+ shader_tessellation_and_geometry_point_size: self
+ .shader_tessellation_and_geometry_point_size
+ ^ other.shader_tessellation_and_geometry_point_size,
+ shader_uniform_buffer_array_dynamic_indexing: self
+ .shader_uniform_buffer_array_dynamic_indexing
+ ^ other.shader_uniform_buffer_array_dynamic_indexing,
+ shader_uniform_buffer_array_non_uniform_indexing: self
+ .shader_uniform_buffer_array_non_uniform_indexing
+ ^ other.shader_uniform_buffer_array_non_uniform_indexing,
+ shader_uniform_texel_buffer_array_dynamic_indexing: self
+ .shader_uniform_texel_buffer_array_dynamic_indexing
+ ^ other.shader_uniform_texel_buffer_array_dynamic_indexing,
+ shader_uniform_texel_buffer_array_non_uniform_indexing: self
+ .shader_uniform_texel_buffer_array_non_uniform_indexing
+ ^ other.shader_uniform_texel_buffer_array_non_uniform_indexing,
+ shader_zero_initialize_workgroup_memory: self.shader_zero_initialize_workgroup_memory
+ ^ other.shader_zero_initialize_workgroup_memory,
+ shading_rate_coarse_sample_order: self.shading_rate_coarse_sample_order
+ ^ other.shading_rate_coarse_sample_order,
+ shading_rate_image: self.shading_rate_image ^ other.shading_rate_image,
+ smooth_lines: self.smooth_lines ^ other.smooth_lines,
+ sparse_binding: self.sparse_binding ^ other.sparse_binding,
+ sparse_image_float32_atomic_add: self.sparse_image_float32_atomic_add
+ ^ other.sparse_image_float32_atomic_add,
+ sparse_image_float32_atomic_min_max: self.sparse_image_float32_atomic_min_max
+ ^ other.sparse_image_float32_atomic_min_max,
+ sparse_image_float32_atomics: self.sparse_image_float32_atomics
+ ^ other.sparse_image_float32_atomics,
+ sparse_image_int64_atomics: self.sparse_image_int64_atomics
+ ^ other.sparse_image_int64_atomics,
+ sparse_residency16_samples: self.sparse_residency16_samples
+ ^ other.sparse_residency16_samples,
+ sparse_residency2_samples: self.sparse_residency2_samples
+ ^ other.sparse_residency2_samples,
+ sparse_residency4_samples: self.sparse_residency4_samples
+ ^ other.sparse_residency4_samples,
+ sparse_residency8_samples: self.sparse_residency8_samples
+ ^ other.sparse_residency8_samples,
+ sparse_residency_aliased: self.sparse_residency_aliased
+ ^ other.sparse_residency_aliased,
+ sparse_residency_buffer: self.sparse_residency_buffer ^ other.sparse_residency_buffer,
+ sparse_residency_image2_d: self.sparse_residency_image2_d
+ ^ other.sparse_residency_image2_d,
+ sparse_residency_image3_d: self.sparse_residency_image3_d
+ ^ other.sparse_residency_image3_d,
+ stippled_bresenham_lines: self.stippled_bresenham_lines
+ ^ other.stippled_bresenham_lines,
+ stippled_rectangular_lines: self.stippled_rectangular_lines
+ ^ other.stippled_rectangular_lines,
+ stippled_smooth_lines: self.stippled_smooth_lines ^ other.stippled_smooth_lines,
+ storage_buffer16_bit_access: self.storage_buffer16_bit_access
+ ^ other.storage_buffer16_bit_access,
+ storage_buffer8_bit_access: self.storage_buffer8_bit_access
+ ^ other.storage_buffer8_bit_access,
+ storage_input_output16: self.storage_input_output16 ^ other.storage_input_output16,
+ storage_push_constant16: self.storage_push_constant16 ^ other.storage_push_constant16,
+ storage_push_constant8: self.storage_push_constant8 ^ other.storage_push_constant8,
+ subgroup_broadcast_dynamic_id: self.subgroup_broadcast_dynamic_id
+ ^ other.subgroup_broadcast_dynamic_id,
+ subgroup_size_control: self.subgroup_size_control ^ other.subgroup_size_control,
+ subpass_merge_feedback: self.subpass_merge_feedback ^ other.subpass_merge_feedback,
+ subpass_shading: self.subpass_shading ^ other.subpass_shading,
+ supersample_fragment_shading_rates: self.supersample_fragment_shading_rates
+ ^ other.supersample_fragment_shading_rates,
+ swapchain_maintenance1: self.swapchain_maintenance1 ^ other.swapchain_maintenance1,
+ synchronization2: self.synchronization2 ^ other.synchronization2,
+ task_shader: self.task_shader ^ other.task_shader,
+ tessellation_isolines: self.tessellation_isolines ^ other.tessellation_isolines,
+ tessellation_point_mode: self.tessellation_point_mode ^ other.tessellation_point_mode,
+ tessellation_shader: self.tessellation_shader ^ other.tessellation_shader,
+ texel_buffer_alignment: self.texel_buffer_alignment ^ other.texel_buffer_alignment,
+ texture_block_match: self.texture_block_match ^ other.texture_block_match,
+ texture_box_filter: self.texture_box_filter ^ other.texture_box_filter,
+ texture_compression_astc_hdr: self.texture_compression_astc_hdr
+ ^ other.texture_compression_astc_hdr,
+ texture_compression_astc_ldr: self.texture_compression_astc_ldr
+ ^ other.texture_compression_astc_ldr,
+ texture_compression_bc: self.texture_compression_bc ^ other.texture_compression_bc,
+ texture_compression_etc2: self.texture_compression_etc2
+ ^ other.texture_compression_etc2,
+ texture_sample_weighted: self.texture_sample_weighted ^ other.texture_sample_weighted,
+ tile_properties: self.tile_properties ^ other.tile_properties,
+ timeline_semaphore: self.timeline_semaphore ^ other.timeline_semaphore,
+ transform_feedback: self.transform_feedback ^ other.transform_feedback,
+ transform_feedback_preserves_provoking_vertex: self
+ .transform_feedback_preserves_provoking_vertex
+ ^ other.transform_feedback_preserves_provoking_vertex,
+ triangle_fans: self.triangle_fans ^ other.triangle_fans,
+ uniform_and_storage_buffer16_bit_access: self.uniform_and_storage_buffer16_bit_access
+ ^ other.uniform_and_storage_buffer16_bit_access,
+ uniform_and_storage_buffer8_bit_access: self.uniform_and_storage_buffer8_bit_access
+ ^ other.uniform_and_storage_buffer8_bit_access,
+ uniform_buffer_standard_layout: self.uniform_buffer_standard_layout
+ ^ other.uniform_buffer_standard_layout,
+ variable_multisample_rate: self.variable_multisample_rate
+ ^ other.variable_multisample_rate,
+ variable_pointers: self.variable_pointers ^ other.variable_pointers,
+ variable_pointers_storage_buffer: self.variable_pointers_storage_buffer
+ ^ other.variable_pointers_storage_buffer,
+ vertex_attribute_access_beyond_stride: self.vertex_attribute_access_beyond_stride
+ ^ other.vertex_attribute_access_beyond_stride,
+ vertex_attribute_instance_rate_divisor: self.vertex_attribute_instance_rate_divisor
+ ^ other.vertex_attribute_instance_rate_divisor,
+ vertex_attribute_instance_rate_zero_divisor: self
+ .vertex_attribute_instance_rate_zero_divisor
+ ^ other.vertex_attribute_instance_rate_zero_divisor,
+ vertex_input_dynamic_state: self.vertex_input_dynamic_state
+ ^ other.vertex_input_dynamic_state,
+ vertex_pipeline_stores_and_atomics: self.vertex_pipeline_stores_and_atomics
+ ^ other.vertex_pipeline_stores_and_atomics,
+ vulkan_memory_model: self.vulkan_memory_model ^ other.vulkan_memory_model,
+ vulkan_memory_model_availability_visibility_chains: self
+ .vulkan_memory_model_availability_visibility_chains
+ ^ other.vulkan_memory_model_availability_visibility_chains,
+ vulkan_memory_model_device_scope: self.vulkan_memory_model_device_scope
+ ^ other.vulkan_memory_model_device_scope,
+ wide_lines: self.wide_lines ^ other.wide_lines,
+ workgroup_memory_explicit_layout: self.workgroup_memory_explicit_layout
+ ^ other.workgroup_memory_explicit_layout,
+ workgroup_memory_explicit_layout16_bit_access: self
+ .workgroup_memory_explicit_layout16_bit_access
+ ^ other.workgroup_memory_explicit_layout16_bit_access,
+ workgroup_memory_explicit_layout8_bit_access: self
+ .workgroup_memory_explicit_layout8_bit_access
+ ^ other.workgroup_memory_explicit_layout8_bit_access,
+ workgroup_memory_explicit_layout_scalar_block_layout: self
+ .workgroup_memory_explicit_layout_scalar_block_layout
+ ^ other.workgroup_memory_explicit_layout_scalar_block_layout,
+ ycbcr2plane444_formats: self.ycbcr2plane444_formats ^ other.ycbcr2plane444_formats,
+ ycbcr_image_arrays: self.ycbcr_image_arrays ^ other.ycbcr_image_arrays,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+impl std::ops::BitAnd for Features {
+ type Output = Features;
+ #[inline]
+ fn bitand(self, rhs: Self) -> Self::Output {
+ self.intersection(&rhs)
+ }
+}
+impl std::ops::BitAndAssign for Features {
+ #[inline]
+ fn bitand_assign(&mut self, rhs: Self) {
+ *self = self.intersection(&rhs);
+ }
+}
+impl std::ops::BitOr for Features {
+ type Output = Features;
+ #[inline]
+ fn bitor(self, rhs: Self) -> Self::Output {
+ self.union(&rhs)
+ }
+}
+impl std::ops::BitOrAssign for Features {
+ #[inline]
+ fn bitor_assign(&mut self, rhs: Self) {
+ *self = self.union(&rhs);
+ }
+}
+impl std::ops::BitXor for Features {
+ type Output = Features;
+ #[inline]
+ fn bitxor(self, rhs: Self) -> Self::Output {
+ self.symmetric_difference(&rhs)
+ }
+}
+impl std::ops::BitXorAssign for Features {
+ #[inline]
+ fn bitxor_assign(&mut self, rhs: Self) {
+ *self = self.symmetric_difference(&rhs);
+ }
+}
+impl std::ops::Sub for Features {
+ type Output = Features;
+ #[inline]
+ fn sub(self, rhs: Self) -> Self::Output {
+ self.difference(&rhs)
+ }
+}
+impl std::ops::SubAssign for Features {
+ #[inline]
+ fn sub_assign(&mut self, rhs: Self) {
+ *self = self.difference(&rhs);
+ }
+}
+impl std::fmt::Debug for Features {
+ #[allow(unused_assignments)]
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
+ write!(f, "[")?;
+ let mut first = true;
+ if self.acceleration_structure {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("accelerationStructure")?;
+ }
+ if self.acceleration_structure_capture_replay {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("accelerationStructureCaptureReplay")?;
+ }
+ if self.acceleration_structure_host_commands {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("accelerationStructureHostCommands")?;
+ }
+ if self.acceleration_structure_indirect_build {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("accelerationStructureIndirectBuild")?;
+ }
+ if self.advanced_blend_coherent_operations {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("advancedBlendCoherentOperations")?;
+ }
+ if self.alpha_to_one {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("alphaToOne")?;
+ }
+ if self.amigo_profiling {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("amigoProfiling")?;
+ }
+ if self.attachment_feedback_loop_layout {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("attachmentFeedbackLoopLayout")?;
+ }
+ if self.attachment_fragment_shading_rate {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("attachmentFragmentShadingRate")?;
+ }
+ if self.border_color_swizzle {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("borderColorSwizzle")?;
+ }
+ if self.border_color_swizzle_from_image {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("borderColorSwizzleFromImage")?;
+ }
+ if self.bresenham_lines {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("bresenhamLines")?;
+ }
+ if self.buffer_device_address {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("bufferDeviceAddress")?;
+ }
+ if self.buffer_device_address_capture_replay {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("bufferDeviceAddressCaptureReplay")?;
+ }
+ if self.buffer_device_address_multi_device {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("bufferDeviceAddressMultiDevice")?;
+ }
+ if self.color_write_enable {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("colorWriteEnable")?;
+ }
+ if self.compute_derivative_group_linear {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("computeDerivativeGroupLinear")?;
+ }
+ if self.compute_derivative_group_quads {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("computeDerivativeGroupQuads")?;
+ }
+ if self.compute_full_subgroups {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("computeFullSubgroups")?;
+ }
+ if self.conditional_rendering {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("conditionalRendering")?;
+ }
+ if self.constant_alpha_color_blend_factors {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("constantAlphaColorBlendFactors")?;
+ }
+ if self.cooperative_matrix {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("cooperativeMatrix")?;
+ }
+ if self.cooperative_matrix_robust_buffer_access {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("cooperativeMatrixRobustBufferAccess")?;
+ }
+ if self.corner_sampled_image {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("cornerSampledImage")?;
+ }
+ if self.coverage_reduction_mode {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("coverageReductionMode")?;
+ }
+ if self.custom_border_color_without_format {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("customBorderColorWithoutFormat")?;
+ }
+ if self.custom_border_colors {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("customBorderColors")?;
+ }
+ if self.decode_mode_shared_exponent {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("decodeModeSharedExponent")?;
+ }
+ if self.dedicated_allocation_image_aliasing {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("dedicatedAllocationImageAliasing")?;
+ }
+ if self.depth_bias_clamp {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("depthBiasClamp")?;
+ }
+ if self.depth_bounds {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("depthBounds")?;
+ }
+ if self.depth_clamp {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("depthClamp")?;
+ }
+ if self.depth_clamp_zero_one {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("depthClampZeroOne")?;
+ }
+ if self.depth_clip_control {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("depthClipControl")?;
+ }
+ if self.depth_clip_enable {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("depthClipEnable")?;
+ }
+ if self.descriptor_binding_acceleration_structure_update_after_bind {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("descriptorBindingAccelerationStructureUpdateAfterBind")?;
+ }
+ if self.descriptor_binding_inline_uniform_block_update_after_bind {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("descriptorBindingInlineUniformBlockUpdateAfterBind")?;
+ }
+ if self.descriptor_binding_partially_bound {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("descriptorBindingPartiallyBound")?;
+ }
+ if self.descriptor_binding_sampled_image_update_after_bind {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("descriptorBindingSampledImageUpdateAfterBind")?;
+ }
+ if self.descriptor_binding_storage_buffer_update_after_bind {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("descriptorBindingStorageBufferUpdateAfterBind")?;
+ }
+ if self.descriptor_binding_storage_image_update_after_bind {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("descriptorBindingStorageImageUpdateAfterBind")?;
+ }
+ if self.descriptor_binding_storage_texel_buffer_update_after_bind {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("descriptorBindingStorageTexelBufferUpdateAfterBind")?;
+ }
+ if self.descriptor_binding_uniform_buffer_update_after_bind {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("descriptorBindingUniformBufferUpdateAfterBind")?;
+ }
+ if self.descriptor_binding_uniform_texel_buffer_update_after_bind {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("descriptorBindingUniformTexelBufferUpdateAfterBind")?;
+ }
+ if self.descriptor_binding_update_unused_while_pending {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("descriptorBindingUpdateUnusedWhilePending")?;
+ }
+ if self.descriptor_binding_variable_descriptor_count {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("descriptorBindingVariableDescriptorCount")?;
+ }
+ if self.descriptor_buffer {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("descriptorBuffer")?;
+ }
+ if self.descriptor_buffer_capture_replay {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("descriptorBufferCaptureReplay")?;
+ }
+ if self.descriptor_buffer_image_layout_ignored {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("descriptorBufferImageLayoutIgnored")?;
+ }
+ if self.descriptor_buffer_push_descriptors {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("descriptorBufferPushDescriptors")?;
+ }
+ if self.descriptor_indexing {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("descriptorIndexing")?;
+ }
+ if self.descriptor_set_host_mapping {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("descriptorSetHostMapping")?;
+ }
+ if self.device_coherent_memory {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("deviceCoherentMemory")?;
+ }
+ if self.device_fault {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("deviceFault")?;
+ }
+ if self.device_fault_vendor_binary {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("deviceFaultVendorBinary")?;
+ }
+ if self.device_generated_commands {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("deviceGeneratedCommands")?;
+ }
+ if self.device_memory_report {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("deviceMemoryReport")?;
+ }
+ if self.diagnostics_config {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("diagnosticsConfig")?;
+ }
+ if self.draw_indirect_count {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("drawIndirectCount")?;
+ }
+ if self.draw_indirect_first_instance {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("drawIndirectFirstInstance")?;
+ }
+ if self.dual_src_blend {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("dualSrcBlend")?;
+ }
+ if self.dynamic_rendering {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("dynamicRendering")?;
+ }
+ if self.events {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("events")?;
+ }
+ if self.exclusive_scissor {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("exclusiveScissor")?;
+ }
+ if self.extended_dynamic_state {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState")?;
+ }
+ if self.extended_dynamic_state2 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState2")?;
+ }
+ if self.extended_dynamic_state2_logic_op {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState2LogicOp")?;
+ }
+ if self.extended_dynamic_state2_patch_control_points {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState2PatchControlPoints")?;
+ }
+ if self.extended_dynamic_state3_alpha_to_coverage_enable {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState3AlphaToCoverageEnable")?;
+ }
+ if self.extended_dynamic_state3_alpha_to_one_enable {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState3AlphaToOneEnable")?;
+ }
+ if self.extended_dynamic_state3_color_blend_advanced {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState3ColorBlendAdvanced")?;
+ }
+ if self.extended_dynamic_state3_color_blend_enable {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState3ColorBlendEnable")?;
+ }
+ if self.extended_dynamic_state3_color_blend_equation {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState3ColorBlendEquation")?;
+ }
+ if self.extended_dynamic_state3_color_write_mask {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState3ColorWriteMask")?;
+ }
+ if self.extended_dynamic_state3_conservative_rasterization_mode {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState3ConservativeRasterizationMode")?;
+ }
+ if self.extended_dynamic_state3_coverage_modulation_mode {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState3CoverageModulationMode")?;
+ }
+ if self.extended_dynamic_state3_coverage_modulation_table {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState3CoverageModulationTable")?;
+ }
+ if self.extended_dynamic_state3_coverage_modulation_table_enable {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState3CoverageModulationTableEnable")?;
+ }
+ if self.extended_dynamic_state3_coverage_reduction_mode {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState3CoverageReductionMode")?;
+ }
+ if self.extended_dynamic_state3_coverage_to_color_enable {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState3CoverageToColorEnable")?;
+ }
+ if self.extended_dynamic_state3_coverage_to_color_location {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState3CoverageToColorLocation")?;
+ }
+ if self.extended_dynamic_state3_depth_clamp_enable {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState3DepthClampEnable")?;
+ }
+ if self.extended_dynamic_state3_depth_clip_enable {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState3DepthClipEnable")?;
+ }
+ if self.extended_dynamic_state3_depth_clip_negative_one_to_one {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState3DepthClipNegativeOneToOne")?;
+ }
+ if self.extended_dynamic_state3_extra_primitive_overestimation_size {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState3ExtraPrimitiveOverestimationSize")?;
+ }
+ if self.extended_dynamic_state3_line_rasterization_mode {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState3LineRasterizationMode")?;
+ }
+ if self.extended_dynamic_state3_line_stipple_enable {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState3LineStippleEnable")?;
+ }
+ if self.extended_dynamic_state3_logic_op_enable {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState3LogicOpEnable")?;
+ }
+ if self.extended_dynamic_state3_polygon_mode {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState3PolygonMode")?;
+ }
+ if self.extended_dynamic_state3_provoking_vertex_mode {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState3ProvokingVertexMode")?;
+ }
+ if self.extended_dynamic_state3_rasterization_samples {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState3RasterizationSamples")?;
+ }
+ if self.extended_dynamic_state3_rasterization_stream {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState3RasterizationStream")?;
+ }
+ if self.extended_dynamic_state3_representative_fragment_test_enable {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState3RepresentativeFragmentTestEnable")?;
+ }
+ if self.extended_dynamic_state3_sample_locations_enable {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState3SampleLocationsEnable")?;
+ }
+ if self.extended_dynamic_state3_sample_mask {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState3SampleMask")?;
+ }
+ if self.extended_dynamic_state3_shading_rate_image_enable {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState3ShadingRateImageEnable")?;
+ }
+ if self.extended_dynamic_state3_tessellation_domain_origin {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState3TessellationDomainOrigin")?;
+ }
+ if self.extended_dynamic_state3_viewport_swizzle {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState3ViewportSwizzle")?;
+ }
+ if self.extended_dynamic_state3_viewport_w_scaling_enable {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("extendedDynamicState3ViewportWScalingEnable")?;
+ }
+ if self.external_memory_rdma {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("externalMemoryRDMA")?;
+ }
+ if self.fill_mode_non_solid {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("fillModeNonSolid")?;
+ }
+ if self.format_a4b4g4r4 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("formatA4B4G4R4")?;
+ }
+ if self.format_a4r4g4b4 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("formatA4R4G4B4")?;
+ }
+ if self.format_rgba10x6_without_y_cb_cr_sampler {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("formatRgba10x6WithoutYCbCrSampler")?;
+ }
+ if self.fragment_density_map {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("fragmentDensityMap")?;
+ }
+ if self.fragment_density_map_deferred {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("fragmentDensityMapDeferred")?;
+ }
+ if self.fragment_density_map_dynamic {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("fragmentDensityMapDynamic")?;
+ }
+ if self.fragment_density_map_non_subsampled_images {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("fragmentDensityMapNonSubsampledImages")?;
+ }
+ if self.fragment_density_map_offset {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("fragmentDensityMapOffset")?;
+ }
+ if self.fragment_shader_barycentric {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("fragmentShaderBarycentric")?;
+ }
+ if self.fragment_shader_pixel_interlock {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("fragmentShaderPixelInterlock")?;
+ }
+ if self.fragment_shader_sample_interlock {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("fragmentShaderSampleInterlock")?;
+ }
+ if self.fragment_shader_shading_rate_interlock {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("fragmentShaderShadingRateInterlock")?;
+ }
+ if self.fragment_shading_rate_enums {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("fragmentShadingRateEnums")?;
+ }
+ if self.fragment_stores_and_atomics {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("fragmentStoresAndAtomics")?;
+ }
+ if self.full_draw_index_uint32 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("fullDrawIndexUint32")?;
+ }
+ if self.geometry_shader {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("geometryShader")?;
+ }
+ if self.geometry_streams {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("geometryStreams")?;
+ }
+ if self.global_priority_query {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("globalPriorityQuery")?;
+ }
+ if self.graphics_pipeline_library {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("graphicsPipelineLibrary")?;
+ }
+ if self.host_query_reset {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("hostQueryReset")?;
+ }
+ if self.image2_d_view_of3_d {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("image2DViewOf3D")?;
+ }
+ if self.image_compression_control {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("imageCompressionControl")?;
+ }
+ if self.image_compression_control_swapchain {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("imageCompressionControlSwapchain")?;
+ }
+ if self.image_cube_array {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("imageCubeArray")?;
+ }
+ if self.image_footprint {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("imageFootprint")?;
+ }
+ if self.image_view2_d_on3_d_image {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("imageView2DOn3DImage")?;
+ }
+ if self.image_view_format_reinterpretation {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("imageViewFormatReinterpretation")?;
+ }
+ if self.image_view_format_swizzle {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("imageViewFormatSwizzle")?;
+ }
+ if self.imageless_framebuffer {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("imagelessFramebuffer")?;
+ }
+ if self.independent_blend {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("independentBlend")?;
+ }
+ if self.index_type_uint8 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("indexTypeUint8")?;
+ }
+ if self.indirect_copy {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("indirectCopy")?;
+ }
+ if self.inherited_conditional_rendering {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("inheritedConditionalRendering")?;
+ }
+ if self.inherited_queries {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("inheritedQueries")?;
+ }
+ if self.inherited_viewport_scissor2_d {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("inheritedViewportScissor2D")?;
+ }
+ if self.inline_uniform_block {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("inlineUniformBlock")?;
+ }
+ if self.invocation_mask {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("invocationMask")?;
+ }
+ if self.large_points {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("largePoints")?;
+ }
+ if self.legacy_dithering {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("legacyDithering")?;
+ }
+ if self.linear_color_attachment {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("linearColorAttachment")?;
+ }
+ if self.logic_op {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("logicOp")?;
+ }
+ if self.maintenance4 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("maintenance4")?;
+ }
+ if self.memory_decompression {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("memoryDecompression")?;
+ }
+ if self.memory_priority {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("memoryPriority")?;
+ }
+ if self.mesh_shader {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("meshShader")?;
+ }
+ if self.mesh_shader_queries {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("meshShaderQueries")?;
+ }
+ if self.micromap {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("micromap")?;
+ }
+ if self.micromap_capture_replay {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("micromapCaptureReplay")?;
+ }
+ if self.micromap_host_commands {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("micromapHostCommands")?;
+ }
+ if self.min_lod {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("minLod")?;
+ }
+ if self.multi_draw {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("multiDraw")?;
+ }
+ if self.multi_draw_indirect {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("multiDrawIndirect")?;
+ }
+ if self.multi_viewport {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("multiViewport")?;
+ }
+ if self.multisample_array_image {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("multisampleArrayImage")?;
+ }
+ if self.multisampled_render_to_single_sampled {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("multisampledRenderToSingleSampled")?;
+ }
+ if self.multiview {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("multiview")?;
+ }
+ if self.multiview_geometry_shader {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("multiviewGeometryShader")?;
+ }
+ if self.multiview_mesh_shader {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("multiviewMeshShader")?;
+ }
+ if self.multiview_per_view_viewports {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("multiviewPerViewViewports")?;
+ }
+ if self.multiview_tessellation_shader {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("multiviewTessellationShader")?;
+ }
+ if self.mutable_comparison_samplers {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("mutableComparisonSamplers")?;
+ }
+ if self.mutable_descriptor_type {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("mutableDescriptorType")?;
+ }
+ if self.no_invocation_fragment_shading_rates {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("noInvocationFragmentShadingRates")?;
+ }
+ if self.non_seamless_cube_map {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("nonSeamlessCubeMap")?;
+ }
+ if self.null_descriptor {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("nullDescriptor")?;
+ }
+ if self.occlusion_query_precise {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("occlusionQueryPrecise")?;
+ }
+ if self.optical_flow {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("opticalFlow")?;
+ }
+ if self.pageable_device_local_memory {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("pageableDeviceLocalMemory")?;
+ }
+ if self.performance_counter_multiple_query_pools {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("performanceCounterMultipleQueryPools")?;
+ }
+ if self.performance_counter_query_pools {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("performanceCounterQueryPools")?;
+ }
+ if self.pipeline_creation_cache_control {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("pipelineCreationCacheControl")?;
+ }
+ if self.pipeline_executable_info {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("pipelineExecutableInfo")?;
+ }
+ if self.pipeline_fragment_shading_rate {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("pipelineFragmentShadingRate")?;
+ }
+ if self.pipeline_properties_identifier {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("pipelinePropertiesIdentifier")?;
+ }
+ if self.pipeline_protected_access {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("pipelineProtectedAccess")?;
+ }
+ if self.pipeline_robustness {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("pipelineRobustness")?;
+ }
+ if self.pipeline_statistics_query {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("pipelineStatisticsQuery")?;
+ }
+ if self.point_polygons {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("pointPolygons")?;
+ }
+ if self.present_barrier {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("presentBarrier")?;
+ }
+ if self.present_id {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("presentId")?;
+ }
+ if self.present_wait {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("presentWait")?;
+ }
+ if self.primitive_fragment_shading_rate {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("primitiveFragmentShadingRate")?;
+ }
+ if self.primitive_fragment_shading_rate_mesh_shader {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("primitiveFragmentShadingRateMeshShader")?;
+ }
+ if self.primitive_topology_list_restart {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("primitiveTopologyListRestart")?;
+ }
+ if self.primitive_topology_patch_list_restart {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("primitiveTopologyPatchListRestart")?;
+ }
+ if self.primitives_generated_query {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("primitivesGeneratedQuery")?;
+ }
+ if self.primitives_generated_query_with_non_zero_streams {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("primitivesGeneratedQueryWithNonZeroStreams")?;
+ }
+ if self.primitives_generated_query_with_rasterizer_discard {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("primitivesGeneratedQueryWithRasterizerDiscard")?;
+ }
+ if self.private_data {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("privateData")?;
+ }
+ if self.protected_memory {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("protectedMemory")?;
+ }
+ if self.provoking_vertex_last {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("provokingVertexLast")?;
+ }
+ if self.rasterization_order_color_attachment_access {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("rasterizationOrderColorAttachmentAccess")?;
+ }
+ if self.rasterization_order_depth_attachment_access {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("rasterizationOrderDepthAttachmentAccess")?;
+ }
+ if self.rasterization_order_stencil_attachment_access {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("rasterizationOrderStencilAttachmentAccess")?;
+ }
+ if self.ray_query {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("rayQuery")?;
+ }
+ if self.ray_tracing_invocation_reorder {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("rayTracingInvocationReorder")?;
+ }
+ if self.ray_tracing_maintenance1 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("rayTracingMaintenance1")?;
+ }
+ if self.ray_tracing_motion_blur {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("rayTracingMotionBlur")?;
+ }
+ if self.ray_tracing_motion_blur_pipeline_trace_rays_indirect {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("rayTracingMotionBlurPipelineTraceRaysIndirect")?;
+ }
+ if self.ray_tracing_pipeline {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("rayTracingPipeline")?;
+ }
+ if self.ray_tracing_pipeline_shader_group_handle_capture_replay {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("rayTracingPipelineShaderGroupHandleCaptureReplay")?;
+ }
+ if self.ray_tracing_pipeline_shader_group_handle_capture_replay_mixed {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("rayTracingPipelineShaderGroupHandleCaptureReplayMixed")?;
+ }
+ if self.ray_tracing_pipeline_trace_rays_indirect {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("rayTracingPipelineTraceRaysIndirect")?;
+ }
+ if self.ray_tracing_pipeline_trace_rays_indirect2 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("rayTracingPipelineTraceRaysIndirect2")?;
+ }
+ if self.ray_traversal_primitive_culling {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("rayTraversalPrimitiveCulling")?;
+ }
+ if self.rectangular_lines {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("rectangularLines")?;
+ }
+ if self.report_address_binding {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("reportAddressBinding")?;
+ }
+ if self.representative_fragment_test {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("representativeFragmentTest")?;
+ }
+ if self.robust_buffer_access {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("robustBufferAccess")?;
+ }
+ if self.robust_buffer_access2 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("robustBufferAccess2")?;
+ }
+ if self.robust_image_access {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("robustImageAccess")?;
+ }
+ if self.robust_image_access2 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("robustImageAccess2")?;
+ }
+ if self.runtime_descriptor_array {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("runtimeDescriptorArray")?;
+ }
+ if self.sample_rate_shading {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("sampleRateShading")?;
+ }
+ if self.sampler2_d_view_of3_d {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("sampler2DViewOf3D")?;
+ }
+ if self.sampler_anisotropy {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("samplerAnisotropy")?;
+ }
+ if self.sampler_filter_minmax {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("samplerFilterMinmax")?;
+ }
+ if self.sampler_mip_lod_bias {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("samplerMipLodBias")?;
+ }
+ if self.sampler_mirror_clamp_to_edge {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("samplerMirrorClampToEdge")?;
+ }
+ if self.sampler_ycbcr_conversion {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("samplerYcbcrConversion")?;
+ }
+ if self.scalar_block_layout {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("scalarBlockLayout")?;
+ }
+ if self.separate_depth_stencil_layouts {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("separateDepthStencilLayouts")?;
+ }
+ if self.separate_stencil_mask_ref {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("separateStencilMaskRef")?;
+ }
+ if self.shader_buffer_float16_atomic_add {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderBufferFloat16AtomicAdd")?;
+ }
+ if self.shader_buffer_float16_atomic_min_max {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderBufferFloat16AtomicMinMax")?;
+ }
+ if self.shader_buffer_float16_atomics {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderBufferFloat16Atomics")?;
+ }
+ if self.shader_buffer_float32_atomic_add {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderBufferFloat32AtomicAdd")?;
+ }
+ if self.shader_buffer_float32_atomic_min_max {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderBufferFloat32AtomicMinMax")?;
+ }
+ if self.shader_buffer_float32_atomics {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderBufferFloat32Atomics")?;
+ }
+ if self.shader_buffer_float64_atomic_add {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderBufferFloat64AtomicAdd")?;
+ }
+ if self.shader_buffer_float64_atomic_min_max {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderBufferFloat64AtomicMinMax")?;
+ }
+ if self.shader_buffer_float64_atomics {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderBufferFloat64Atomics")?;
+ }
+ if self.shader_buffer_int64_atomics {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderBufferInt64Atomics")?;
+ }
+ if self.shader_clip_distance {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderClipDistance")?;
+ }
+ if self.shader_core_builtins {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderCoreBuiltins")?;
+ }
+ if self.shader_cull_distance {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderCullDistance")?;
+ }
+ if self.shader_demote_to_helper_invocation {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderDemoteToHelperInvocation")?;
+ }
+ if self.shader_device_clock {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderDeviceClock")?;
+ }
+ if self.shader_draw_parameters {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderDrawParameters")?;
+ }
+ if self.shader_early_and_late_fragment_tests {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderEarlyAndLateFragmentTests")?;
+ }
+ if self.shader_float16 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderFloat16")?;
+ }
+ if self.shader_float64 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderFloat64")?;
+ }
+ if self.shader_image_float32_atomic_add {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderImageFloat32AtomicAdd")?;
+ }
+ if self.shader_image_float32_atomic_min_max {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderImageFloat32AtomicMinMax")?;
+ }
+ if self.shader_image_float32_atomics {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderImageFloat32Atomics")?;
+ }
+ if self.shader_image_gather_extended {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderImageGatherExtended")?;
+ }
+ if self.shader_image_int64_atomics {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderImageInt64Atomics")?;
+ }
+ if self.shader_input_attachment_array_dynamic_indexing {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderInputAttachmentArrayDynamicIndexing")?;
+ }
+ if self.shader_input_attachment_array_non_uniform_indexing {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderInputAttachmentArrayNonUniformIndexing")?;
+ }
+ if self.shader_int16 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderInt16")?;
+ }
+ if self.shader_int64 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderInt64")?;
+ }
+ if self.shader_int8 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderInt8")?;
+ }
+ if self.shader_integer_dot_product {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderIntegerDotProduct")?;
+ }
+ if self.shader_integer_functions2 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderIntegerFunctions2")?;
+ }
+ if self.shader_module_identifier {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderModuleIdentifier")?;
+ }
+ if self.shader_output_layer {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderOutputLayer")?;
+ }
+ if self.shader_output_viewport_index {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderOutputViewportIndex")?;
+ }
+ if self.shader_resource_min_lod {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderResourceMinLod")?;
+ }
+ if self.shader_resource_residency {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderResourceResidency")?;
+ }
+ if self.shader_sample_rate_interpolation_functions {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderSampleRateInterpolationFunctions")?;
+ }
+ if self.shader_sampled_image_array_dynamic_indexing {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderSampledImageArrayDynamicIndexing")?;
+ }
+ if self.shader_sampled_image_array_non_uniform_indexing {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderSampledImageArrayNonUniformIndexing")?;
+ }
+ if self.shader_shared_float16_atomic_add {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderSharedFloat16AtomicAdd")?;
+ }
+ if self.shader_shared_float16_atomic_min_max {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderSharedFloat16AtomicMinMax")?;
+ }
+ if self.shader_shared_float16_atomics {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderSharedFloat16Atomics")?;
+ }
+ if self.shader_shared_float32_atomic_add {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderSharedFloat32AtomicAdd")?;
+ }
+ if self.shader_shared_float32_atomic_min_max {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderSharedFloat32AtomicMinMax")?;
+ }
+ if self.shader_shared_float32_atomics {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderSharedFloat32Atomics")?;
+ }
+ if self.shader_shared_float64_atomic_add {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderSharedFloat64AtomicAdd")?;
+ }
+ if self.shader_shared_float64_atomic_min_max {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderSharedFloat64AtomicMinMax")?;
+ }
+ if self.shader_shared_float64_atomics {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderSharedFloat64Atomics")?;
+ }
+ if self.shader_shared_int64_atomics {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderSharedInt64Atomics")?;
+ }
+ if self.shader_sm_builtins {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderSMBuiltins")?;
+ }
+ if self.shader_storage_buffer_array_dynamic_indexing {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderStorageBufferArrayDynamicIndexing")?;
+ }
+ if self.shader_storage_buffer_array_non_uniform_indexing {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderStorageBufferArrayNonUniformIndexing")?;
+ }
+ if self.shader_storage_image_array_dynamic_indexing {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderStorageImageArrayDynamicIndexing")?;
+ }
+ if self.shader_storage_image_array_non_uniform_indexing {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderStorageImageArrayNonUniformIndexing")?;
+ }
+ if self.shader_storage_image_extended_formats {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderStorageImageExtendedFormats")?;
+ }
+ if self.shader_storage_image_multisample {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderStorageImageMultisample")?;
+ }
+ if self.shader_storage_image_read_without_format {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderStorageImageReadWithoutFormat")?;
+ }
+ if self.shader_storage_image_write_without_format {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderStorageImageWriteWithoutFormat")?;
+ }
+ if self.shader_storage_texel_buffer_array_dynamic_indexing {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderStorageTexelBufferArrayDynamicIndexing")?;
+ }
+ if self.shader_storage_texel_buffer_array_non_uniform_indexing {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderStorageTexelBufferArrayNonUniformIndexing")?;
+ }
+ if self.shader_subgroup_clock {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderSubgroupClock")?;
+ }
+ if self.shader_subgroup_extended_types {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderSubgroupExtendedTypes")?;
+ }
+ if self.shader_subgroup_uniform_control_flow {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderSubgroupUniformControlFlow")?;
+ }
+ if self.shader_terminate_invocation {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderTerminateInvocation")?;
+ }
+ if self.shader_tessellation_and_geometry_point_size {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderTessellationAndGeometryPointSize")?;
+ }
+ if self.shader_uniform_buffer_array_dynamic_indexing {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderUniformBufferArrayDynamicIndexing")?;
+ }
+ if self.shader_uniform_buffer_array_non_uniform_indexing {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderUniformBufferArrayNonUniformIndexing")?;
+ }
+ if self.shader_uniform_texel_buffer_array_dynamic_indexing {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderUniformTexelBufferArrayDynamicIndexing")?;
+ }
+ if self.shader_uniform_texel_buffer_array_non_uniform_indexing {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderUniformTexelBufferArrayNonUniformIndexing")?;
+ }
+ if self.shader_zero_initialize_workgroup_memory {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shaderZeroInitializeWorkgroupMemory")?;
+ }
+ if self.shading_rate_coarse_sample_order {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shadingRateCoarseSampleOrder")?;
+ }
+ if self.shading_rate_image {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("shadingRateImage")?;
+ }
+ if self.smooth_lines {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("smoothLines")?;
+ }
+ if self.sparse_binding {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("sparseBinding")?;
+ }
+ if self.sparse_image_float32_atomic_add {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("sparseImageFloat32AtomicAdd")?;
+ }
+ if self.sparse_image_float32_atomic_min_max {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("sparseImageFloat32AtomicMinMax")?;
+ }
+ if self.sparse_image_float32_atomics {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("sparseImageFloat32Atomics")?;
+ }
+ if self.sparse_image_int64_atomics {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("sparseImageInt64Atomics")?;
+ }
+ if self.sparse_residency16_samples {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("sparseResidency16Samples")?;
+ }
+ if self.sparse_residency2_samples {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("sparseResidency2Samples")?;
+ }
+ if self.sparse_residency4_samples {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("sparseResidency4Samples")?;
+ }
+ if self.sparse_residency8_samples {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("sparseResidency8Samples")?;
+ }
+ if self.sparse_residency_aliased {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("sparseResidencyAliased")?;
+ }
+ if self.sparse_residency_buffer {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("sparseResidencyBuffer")?;
+ }
+ if self.sparse_residency_image2_d {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("sparseResidencyImage2D")?;
+ }
+ if self.sparse_residency_image3_d {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("sparseResidencyImage3D")?;
+ }
+ if self.stippled_bresenham_lines {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("stippledBresenhamLines")?;
+ }
+ if self.stippled_rectangular_lines {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("stippledRectangularLines")?;
+ }
+ if self.stippled_smooth_lines {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("stippledSmoothLines")?;
+ }
+ if self.storage_buffer16_bit_access {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("storageBuffer16BitAccess")?;
+ }
+ if self.storage_buffer8_bit_access {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("storageBuffer8BitAccess")?;
+ }
+ if self.storage_input_output16 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("storageInputOutput16")?;
+ }
+ if self.storage_push_constant16 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("storagePushConstant16")?;
+ }
+ if self.storage_push_constant8 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("storagePushConstant8")?;
+ }
+ if self.subgroup_broadcast_dynamic_id {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("subgroupBroadcastDynamicId")?;
+ }
+ if self.subgroup_size_control {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("subgroupSizeControl")?;
+ }
+ if self.subpass_merge_feedback {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("subpassMergeFeedback")?;
+ }
+ if self.subpass_shading {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("subpassShading")?;
+ }
+ if self.supersample_fragment_shading_rates {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("supersampleFragmentShadingRates")?;
+ }
+ if self.swapchain_maintenance1 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("swapchainMaintenance1")?;
+ }
+ if self.synchronization2 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("synchronization2")?;
+ }
+ if self.task_shader {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("taskShader")?;
+ }
+ if self.tessellation_isolines {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("tessellationIsolines")?;
+ }
+ if self.tessellation_point_mode {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("tessellationPointMode")?;
+ }
+ if self.tessellation_shader {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("tessellationShader")?;
+ }
+ if self.texel_buffer_alignment {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("texelBufferAlignment")?;
+ }
+ if self.texture_block_match {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("textureBlockMatch")?;
+ }
+ if self.texture_box_filter {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("textureBoxFilter")?;
+ }
+ if self.texture_compression_astc_hdr {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("textureCompressionASTC_HDR")?;
+ }
+ if self.texture_compression_astc_ldr {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("textureCompressionASTC_LDR")?;
+ }
+ if self.texture_compression_bc {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("textureCompressionBC")?;
+ }
+ if self.texture_compression_etc2 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("textureCompressionETC2")?;
+ }
+ if self.texture_sample_weighted {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("textureSampleWeighted")?;
+ }
+ if self.tile_properties {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("tileProperties")?;
+ }
+ if self.timeline_semaphore {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("timelineSemaphore")?;
+ }
+ if self.transform_feedback {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("transformFeedback")?;
+ }
+ if self.transform_feedback_preserves_provoking_vertex {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("transformFeedbackPreservesProvokingVertex")?;
+ }
+ if self.triangle_fans {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("triangleFans")?;
+ }
+ if self.uniform_and_storage_buffer16_bit_access {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("uniformAndStorageBuffer16BitAccess")?;
+ }
+ if self.uniform_and_storage_buffer8_bit_access {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("uniformAndStorageBuffer8BitAccess")?;
+ }
+ if self.uniform_buffer_standard_layout {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("uniformBufferStandardLayout")?;
+ }
+ if self.variable_multisample_rate {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("variableMultisampleRate")?;
+ }
+ if self.variable_pointers {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("variablePointers")?;
+ }
+ if self.variable_pointers_storage_buffer {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("variablePointersStorageBuffer")?;
+ }
+ if self.vertex_attribute_access_beyond_stride {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("vertexAttributeAccessBeyondStride")?;
+ }
+ if self.vertex_attribute_instance_rate_divisor {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("vertexAttributeInstanceRateDivisor")?;
+ }
+ if self.vertex_attribute_instance_rate_zero_divisor {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("vertexAttributeInstanceRateZeroDivisor")?;
+ }
+ if self.vertex_input_dynamic_state {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("vertexInputDynamicState")?;
+ }
+ if self.vertex_pipeline_stores_and_atomics {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("vertexPipelineStoresAndAtomics")?;
+ }
+ if self.vulkan_memory_model {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("vulkanMemoryModel")?;
+ }
+ if self.vulkan_memory_model_availability_visibility_chains {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("vulkanMemoryModelAvailabilityVisibilityChains")?;
+ }
+ if self.vulkan_memory_model_device_scope {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("vulkanMemoryModelDeviceScope")?;
+ }
+ if self.wide_lines {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("wideLines")?;
+ }
+ if self.workgroup_memory_explicit_layout {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("workgroupMemoryExplicitLayout")?;
+ }
+ if self.workgroup_memory_explicit_layout16_bit_access {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("workgroupMemoryExplicitLayout16BitAccess")?;
+ }
+ if self.workgroup_memory_explicit_layout8_bit_access {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("workgroupMemoryExplicitLayout8BitAccess")?;
+ }
+ if self.workgroup_memory_explicit_layout_scalar_block_layout {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("workgroupMemoryExplicitLayoutScalarBlockLayout")?;
+ }
+ if self.ycbcr2plane444_formats {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("ycbcr2plane444Formats")?;
+ }
+ if self.ycbcr_image_arrays {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("ycbcrImageArrays")?;
+ }
+ write!(f, "]")
+ }
+}
+impl FeaturesFfi {
+ pub(crate) fn write(&mut self, features: &Features) {
+ if let Some(f) = [self
+ .features_acceleration_structure_khr
+ .as_mut()
+ .map(|s| &mut s.acceleration_structure)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.acceleration_structure as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_acceleration_structure_khr
+ .as_mut()
+ .map(|s| &mut s.acceleration_structure_capture_replay)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.acceleration_structure_capture_replay as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_acceleration_structure_khr
+ .as_mut()
+ .map(|s| &mut s.acceleration_structure_host_commands)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.acceleration_structure_host_commands as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_acceleration_structure_khr
+ .as_mut()
+ .map(|s| &mut s.acceleration_structure_indirect_build)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.acceleration_structure_indirect_build as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_blend_operation_advanced_ext
+ .as_mut()
+ .map(|s| &mut s.advanced_blend_coherent_operations)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.advanced_blend_coherent_operations as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.alpha_to_one]
+ .into_iter()
+ .next()
+ {
+ *f = features.alpha_to_one as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_amigo_profiling_sec
+ .as_mut()
+ .map(|s| &mut s.amigo_profiling)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.amigo_profiling as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_attachment_feedback_loop_layout_ext
+ .as_mut()
+ .map(|s| &mut s.attachment_feedback_loop_layout)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.attachment_feedback_loop_layout as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_fragment_shading_rate_khr
+ .as_mut()
+ .map(|s| &mut s.attachment_fragment_shading_rate)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.attachment_fragment_shading_rate as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_border_color_swizzle_ext
+ .as_mut()
+ .map(|s| &mut s.border_color_swizzle)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.border_color_swizzle as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_border_color_swizzle_ext
+ .as_mut()
+ .map(|s| &mut s.border_color_swizzle_from_image)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.border_color_swizzle_from_image as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_line_rasterization_ext
+ .as_mut()
+ .map(|s| &mut s.bresenham_lines)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.bresenham_lines as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.buffer_device_address),
+ self.features_buffer_device_address
+ .as_mut()
+ .map(|s| &mut s.buffer_device_address),
+ self.features_buffer_device_address_ext
+ .as_mut()
+ .map(|s| &mut s.buffer_device_address),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.buffer_device_address as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.buffer_device_address_capture_replay),
+ self.features_buffer_device_address
+ .as_mut()
+ .map(|s| &mut s.buffer_device_address_capture_replay),
+ self.features_buffer_device_address_ext
+ .as_mut()
+ .map(|s| &mut s.buffer_device_address_capture_replay),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.buffer_device_address_capture_replay as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.buffer_device_address_multi_device),
+ self.features_buffer_device_address
+ .as_mut()
+ .map(|s| &mut s.buffer_device_address_multi_device),
+ self.features_buffer_device_address_ext
+ .as_mut()
+ .map(|s| &mut s.buffer_device_address_multi_device),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.buffer_device_address_multi_device as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_color_write_enable_ext
+ .as_mut()
+ .map(|s| &mut s.color_write_enable)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.color_write_enable as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_compute_shader_derivatives_nv
+ .as_mut()
+ .map(|s| &mut s.compute_derivative_group_linear)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.compute_derivative_group_linear as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_compute_shader_derivatives_nv
+ .as_mut()
+ .map(|s| &mut s.compute_derivative_group_quads)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.compute_derivative_group_quads as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan13
+ .as_mut()
+ .map(|s| &mut s.compute_full_subgroups),
+ self.features_subgroup_size_control
+ .as_mut()
+ .map(|s| &mut s.compute_full_subgroups),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.compute_full_subgroups as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_conditional_rendering_ext
+ .as_mut()
+ .map(|s| &mut s.conditional_rendering)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.conditional_rendering as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_portability_subset_khr
+ .as_mut()
+ .map(|s| &mut s.constant_alpha_color_blend_factors)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.constant_alpha_color_blend_factors as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_cooperative_matrix_nv
+ .as_mut()
+ .map(|s| &mut s.cooperative_matrix)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.cooperative_matrix as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_cooperative_matrix_nv
+ .as_mut()
+ .map(|s| &mut s.cooperative_matrix_robust_buffer_access)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.cooperative_matrix_robust_buffer_access as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_corner_sampled_image_nv
+ .as_mut()
+ .map(|s| &mut s.corner_sampled_image)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.corner_sampled_image as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_coverage_reduction_mode_nv
+ .as_mut()
+ .map(|s| &mut s.coverage_reduction_mode)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.coverage_reduction_mode as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_custom_border_color_ext
+ .as_mut()
+ .map(|s| &mut s.custom_border_color_without_format)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.custom_border_color_without_format as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_custom_border_color_ext
+ .as_mut()
+ .map(|s| &mut s.custom_border_colors)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.custom_border_colors as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_astc_decode_ext
+ .as_mut()
+ .map(|s| &mut s.decode_mode_shared_exponent)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.decode_mode_shared_exponent as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_dedicated_allocation_image_aliasing_nv
+ .as_mut()
+ .map(|s| &mut s.dedicated_allocation_image_aliasing)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.dedicated_allocation_image_aliasing as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.depth_bias_clamp]
+ .into_iter()
+ .next()
+ {
+ *f = features.depth_bias_clamp as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.depth_bounds]
+ .into_iter()
+ .next()
+ {
+ *f = features.depth_bounds as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.depth_clamp]
+ .into_iter()
+ .next()
+ {
+ *f = features.depth_clamp as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_depth_clamp_zero_one_ext
+ .as_mut()
+ .map(|s| &mut s.depth_clamp_zero_one)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.depth_clamp_zero_one as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_depth_clip_control_ext
+ .as_mut()
+ .map(|s| &mut s.depth_clip_control)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.depth_clip_control as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_depth_clip_enable_ext
+ .as_mut()
+ .map(|s| &mut s.depth_clip_enable)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.depth_clip_enable as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_acceleration_structure_khr
+ .as_mut()
+ .map(|s| &mut s.descriptor_binding_acceleration_structure_update_after_bind)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.descriptor_binding_acceleration_structure_update_after_bind
+ as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan13
+ .as_mut()
+ .map(|s| &mut s.descriptor_binding_inline_uniform_block_update_after_bind),
+ self.features_inline_uniform_block
+ .as_mut()
+ .map(|s| &mut s.descriptor_binding_inline_uniform_block_update_after_bind),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.descriptor_binding_inline_uniform_block_update_after_bind
+ as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.descriptor_binding_partially_bound),
+ self.features_descriptor_indexing
+ .as_mut()
+ .map(|s| &mut s.descriptor_binding_partially_bound),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.descriptor_binding_partially_bound as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.descriptor_binding_sampled_image_update_after_bind),
+ self.features_descriptor_indexing
+ .as_mut()
+ .map(|s| &mut s.descriptor_binding_sampled_image_update_after_bind),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.descriptor_binding_sampled_image_update_after_bind as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.descriptor_binding_storage_buffer_update_after_bind),
+ self.features_descriptor_indexing
+ .as_mut()
+ .map(|s| &mut s.descriptor_binding_storage_buffer_update_after_bind),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.descriptor_binding_storage_buffer_update_after_bind as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.descriptor_binding_storage_image_update_after_bind),
+ self.features_descriptor_indexing
+ .as_mut()
+ .map(|s| &mut s.descriptor_binding_storage_image_update_after_bind),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.descriptor_binding_storage_image_update_after_bind as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.descriptor_binding_storage_texel_buffer_update_after_bind),
+ self.features_descriptor_indexing
+ .as_mut()
+ .map(|s| &mut s.descriptor_binding_storage_texel_buffer_update_after_bind),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.descriptor_binding_storage_texel_buffer_update_after_bind
+ as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.descriptor_binding_uniform_buffer_update_after_bind),
+ self.features_descriptor_indexing
+ .as_mut()
+ .map(|s| &mut s.descriptor_binding_uniform_buffer_update_after_bind),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.descriptor_binding_uniform_buffer_update_after_bind as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.descriptor_binding_uniform_texel_buffer_update_after_bind),
+ self.features_descriptor_indexing
+ .as_mut()
+ .map(|s| &mut s.descriptor_binding_uniform_texel_buffer_update_after_bind),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.descriptor_binding_uniform_texel_buffer_update_after_bind
+ as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.descriptor_binding_update_unused_while_pending),
+ self.features_descriptor_indexing
+ .as_mut()
+ .map(|s| &mut s.descriptor_binding_update_unused_while_pending),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.descriptor_binding_update_unused_while_pending as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.descriptor_binding_variable_descriptor_count),
+ self.features_descriptor_indexing
+ .as_mut()
+ .map(|s| &mut s.descriptor_binding_variable_descriptor_count),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.descriptor_binding_variable_descriptor_count as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_descriptor_buffer_ext
+ .as_mut()
+ .map(|s| &mut s.descriptor_buffer)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.descriptor_buffer as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_descriptor_buffer_ext
+ .as_mut()
+ .map(|s| &mut s.descriptor_buffer_capture_replay)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.descriptor_buffer_capture_replay as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_descriptor_buffer_ext
+ .as_mut()
+ .map(|s| &mut s.descriptor_buffer_image_layout_ignored)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.descriptor_buffer_image_layout_ignored as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_descriptor_buffer_ext
+ .as_mut()
+ .map(|s| &mut s.descriptor_buffer_push_descriptors)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.descriptor_buffer_push_descriptors as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.descriptor_indexing)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.descriptor_indexing as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_descriptor_set_host_mapping_valve
+ .as_mut()
+ .map(|s| &mut s.descriptor_set_host_mapping)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.descriptor_set_host_mapping as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_coherent_memory_amd
+ .as_mut()
+ .map(|s| &mut s.device_coherent_memory)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.device_coherent_memory as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_fault_ext
+ .as_mut()
+ .map(|s| &mut s.device_fault)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.device_fault as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_fault_ext
+ .as_mut()
+ .map(|s| &mut s.device_fault_vendor_binary)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.device_fault_vendor_binary as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_device_generated_commands_nv
+ .as_mut()
+ .map(|s| &mut s.device_generated_commands)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.device_generated_commands as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_device_memory_report_ext
+ .as_mut()
+ .map(|s| &mut s.device_memory_report)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.device_memory_report as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_diagnostics_config_nv
+ .as_mut()
+ .map(|s| &mut s.diagnostics_config)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.diagnostics_config as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.draw_indirect_count)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.draw_indirect_count as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.draw_indirect_first_instance]
+ .into_iter()
+ .next()
+ {
+ *f = features.draw_indirect_first_instance as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.dual_src_blend]
+ .into_iter()
+ .next()
+ {
+ *f = features.dual_src_blend as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan13
+ .as_mut()
+ .map(|s| &mut s.dynamic_rendering),
+ self.features_dynamic_rendering
+ .as_mut()
+ .map(|s| &mut s.dynamic_rendering),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.dynamic_rendering as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_portability_subset_khr
+ .as_mut()
+ .map(|s| &mut s.events)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.events as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_exclusive_scissor_nv
+ .as_mut()
+ .map(|s| &mut s.exclusive_scissor)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.exclusive_scissor as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state2_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state2)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state2 as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state2_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state2_logic_op)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state2_logic_op as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state2_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state2_patch_control_points)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state2_patch_control_points as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state3_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state3_alpha_to_coverage_enable)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state3_alpha_to_coverage_enable as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state3_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state3_alpha_to_one_enable)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state3_alpha_to_one_enable as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state3_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state3_color_blend_advanced)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state3_color_blend_advanced as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state3_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state3_color_blend_enable)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state3_color_blend_enable as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state3_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state3_color_blend_equation)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state3_color_blend_equation as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state3_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state3_color_write_mask)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state3_color_write_mask as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state3_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state3_conservative_rasterization_mode)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f =
+ features.extended_dynamic_state3_conservative_rasterization_mode as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state3_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state3_coverage_modulation_mode)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state3_coverage_modulation_mode as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state3_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state3_coverage_modulation_table)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state3_coverage_modulation_table as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state3_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state3_coverage_modulation_table_enable)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state3_coverage_modulation_table_enable
+ as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state3_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state3_coverage_reduction_mode)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state3_coverage_reduction_mode as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state3_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state3_coverage_to_color_enable)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state3_coverage_to_color_enable as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state3_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state3_coverage_to_color_location)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state3_coverage_to_color_location as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state3_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state3_depth_clamp_enable)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state3_depth_clamp_enable as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state3_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state3_depth_clip_enable)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state3_depth_clip_enable as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state3_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state3_depth_clip_negative_one_to_one)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state3_depth_clip_negative_one_to_one as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state3_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state3_extra_primitive_overestimation_size)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state3_extra_primitive_overestimation_size
+ as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state3_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state3_line_rasterization_mode)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state3_line_rasterization_mode as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state3_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state3_line_stipple_enable)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state3_line_stipple_enable as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state3_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state3_logic_op_enable)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state3_logic_op_enable as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state3_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state3_polygon_mode)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state3_polygon_mode as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state3_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state3_provoking_vertex_mode)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state3_provoking_vertex_mode as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state3_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state3_rasterization_samples)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state3_rasterization_samples as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state3_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state3_rasterization_stream)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state3_rasterization_stream as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state3_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state3_representative_fragment_test_enable)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state3_representative_fragment_test_enable
+ as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state3_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state3_sample_locations_enable)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state3_sample_locations_enable as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state3_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state3_sample_mask)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state3_sample_mask as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state3_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state3_shading_rate_image_enable)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state3_shading_rate_image_enable as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state3_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state3_tessellation_domain_origin)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state3_tessellation_domain_origin as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state3_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state3_viewport_swizzle)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state3_viewport_swizzle as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_extended_dynamic_state3_ext
+ .as_mut()
+ .map(|s| &mut s.extended_dynamic_state3_viewport_w_scaling_enable)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.extended_dynamic_state3_viewport_w_scaling_enable as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_external_memory_rdma_nv
+ .as_mut()
+ .map(|s| &mut s.external_memory_rdma)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.external_memory_rdma as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.fill_mode_non_solid]
+ .into_iter()
+ .next()
+ {
+ *f = features.fill_mode_non_solid as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_4444formats_ext
+ .as_mut()
+ .map(|s| &mut s.format_a4b4g4r4)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.format_a4b4g4r4 as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_4444formats_ext
+ .as_mut()
+ .map(|s| &mut s.format_a4r4g4b4)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.format_a4r4g4b4 as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_rgba10x6_formats_ext
+ .as_mut()
+ .map(|s| &mut s.format_rgba10x6_without_y_cb_cr_sampler)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.format_rgba10x6_without_y_cb_cr_sampler as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_fragment_density_map_ext
+ .as_mut()
+ .map(|s| &mut s.fragment_density_map)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.fragment_density_map as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_fragment_density_map2_ext
+ .as_mut()
+ .map(|s| &mut s.fragment_density_map_deferred)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.fragment_density_map_deferred as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_fragment_density_map_ext
+ .as_mut()
+ .map(|s| &mut s.fragment_density_map_dynamic)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.fragment_density_map_dynamic as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_fragment_density_map_ext
+ .as_mut()
+ .map(|s| &mut s.fragment_density_map_non_subsampled_images)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.fragment_density_map_non_subsampled_images as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_fragment_density_map_offset_qcom
+ .as_mut()
+ .map(|s| &mut s.fragment_density_map_offset)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.fragment_density_map_offset as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_fragment_shader_barycentric_khr
+ .as_mut()
+ .map(|s| &mut s.fragment_shader_barycentric)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.fragment_shader_barycentric as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_fragment_shader_interlock_ext
+ .as_mut()
+ .map(|s| &mut s.fragment_shader_pixel_interlock)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.fragment_shader_pixel_interlock as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_fragment_shader_interlock_ext
+ .as_mut()
+ .map(|s| &mut s.fragment_shader_sample_interlock)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.fragment_shader_sample_interlock as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_fragment_shader_interlock_ext
+ .as_mut()
+ .map(|s| &mut s.fragment_shader_shading_rate_interlock)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.fragment_shader_shading_rate_interlock as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_fragment_shading_rate_enums_nv
+ .as_mut()
+ .map(|s| &mut s.fragment_shading_rate_enums)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.fragment_shading_rate_enums as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.fragment_stores_and_atomics]
+ .into_iter()
+ .next()
+ {
+ *f = features.fragment_stores_and_atomics as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.full_draw_index_uint32]
+ .into_iter()
+ .next()
+ {
+ *f = features.full_draw_index_uint32 as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.geometry_shader]
+ .into_iter()
+ .next()
+ {
+ *f = features.geometry_shader as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_transform_feedback_ext
+ .as_mut()
+ .map(|s| &mut s.geometry_streams)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.geometry_streams as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_global_priority_query_khr
+ .as_mut()
+ .map(|s| &mut s.global_priority_query)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.global_priority_query as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_graphics_pipeline_library_ext
+ .as_mut()
+ .map(|s| &mut s.graphics_pipeline_library)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.graphics_pipeline_library as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.host_query_reset),
+ self.features_host_query_reset
+ .as_mut()
+ .map(|s| &mut s.host_query_reset),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.host_query_reset as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_image2_d_view_of3_d_ext
+ .as_mut()
+ .map(|s| &mut s.image2_d_view_of3_d)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.image2_d_view_of3_d as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_image_compression_control_ext
+ .as_mut()
+ .map(|s| &mut s.image_compression_control)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.image_compression_control as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_image_compression_control_swapchain_ext
+ .as_mut()
+ .map(|s| &mut s.image_compression_control_swapchain)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.image_compression_control_swapchain as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.image_cube_array]
+ .into_iter()
+ .next()
+ {
+ *f = features.image_cube_array as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_image_footprint_nv
+ .as_mut()
+ .map(|s| &mut s.image_footprint)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.image_footprint as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_portability_subset_khr
+ .as_mut()
+ .map(|s| &mut s.image_view2_d_on3_d_image)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.image_view2_d_on3_d_image as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_portability_subset_khr
+ .as_mut()
+ .map(|s| &mut s.image_view_format_reinterpretation)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.image_view_format_reinterpretation as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_portability_subset_khr
+ .as_mut()
+ .map(|s| &mut s.image_view_format_swizzle)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.image_view_format_swizzle as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.imageless_framebuffer),
+ self.features_imageless_framebuffer
+ .as_mut()
+ .map(|s| &mut s.imageless_framebuffer),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.imageless_framebuffer as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.independent_blend]
+ .into_iter()
+ .next()
+ {
+ *f = features.independent_blend as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_index_type_uint8_ext
+ .as_mut()
+ .map(|s| &mut s.index_type_uint8)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.index_type_uint8 as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_copy_memory_indirect_nv
+ .as_mut()
+ .map(|s| &mut s.indirect_copy)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.indirect_copy as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_conditional_rendering_ext
+ .as_mut()
+ .map(|s| &mut s.inherited_conditional_rendering)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.inherited_conditional_rendering as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.inherited_queries]
+ .into_iter()
+ .next()
+ {
+ *f = features.inherited_queries as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_inherited_viewport_scissor_nv
+ .as_mut()
+ .map(|s| &mut s.inherited_viewport_scissor2_d)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.inherited_viewport_scissor2_d as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan13
+ .as_mut()
+ .map(|s| &mut s.inline_uniform_block),
+ self.features_inline_uniform_block
+ .as_mut()
+ .map(|s| &mut s.inline_uniform_block),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.inline_uniform_block as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_invocation_mask_huawei
+ .as_mut()
+ .map(|s| &mut s.invocation_mask)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.invocation_mask as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.large_points]
+ .into_iter()
+ .next()
+ {
+ *f = features.large_points as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_legacy_dithering_ext
+ .as_mut()
+ .map(|s| &mut s.legacy_dithering)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.legacy_dithering as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_linear_color_attachment_nv
+ .as_mut()
+ .map(|s| &mut s.linear_color_attachment)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.linear_color_attachment as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.logic_op]
+ .into_iter()
+ .next()
+ {
+ *f = features.logic_op as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan13.as_mut().map(|s| &mut s.maintenance4),
+ self.features_maintenance4
+ .as_mut()
+ .map(|s| &mut s.maintenance4),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.maintenance4 as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_memory_decompression_nv
+ .as_mut()
+ .map(|s| &mut s.memory_decompression)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.memory_decompression as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_memory_priority_ext
+ .as_mut()
+ .map(|s| &mut s.memory_priority)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.memory_priority as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_mesh_shader_ext
+ .as_mut()
+ .map(|s| &mut s.mesh_shader),
+ self.features_mesh_shader_nv
+ .as_mut()
+ .map(|s| &mut s.mesh_shader),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.mesh_shader as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_mesh_shader_ext
+ .as_mut()
+ .map(|s| &mut s.mesh_shader_queries)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.mesh_shader_queries as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_opacity_micromap_ext
+ .as_mut()
+ .map(|s| &mut s.micromap)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.micromap as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_opacity_micromap_ext
+ .as_mut()
+ .map(|s| &mut s.micromap_capture_replay)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.micromap_capture_replay as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_opacity_micromap_ext
+ .as_mut()
+ .map(|s| &mut s.micromap_host_commands)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.micromap_host_commands as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_image_view_min_lod_ext
+ .as_mut()
+ .map(|s| &mut s.min_lod)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.min_lod as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_multi_draw_ext
+ .as_mut()
+ .map(|s| &mut s.multi_draw)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.multi_draw as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.multi_draw_indirect]
+ .into_iter()
+ .next()
+ {
+ *f = features.multi_draw_indirect as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.multi_viewport]
+ .into_iter()
+ .next()
+ {
+ *f = features.multi_viewport as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_portability_subset_khr
+ .as_mut()
+ .map(|s| &mut s.multisample_array_image)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.multisample_array_image as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_multisampled_render_to_single_sampled_ext
+ .as_mut()
+ .map(|s| &mut s.multisampled_render_to_single_sampled)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.multisampled_render_to_single_sampled as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan11.as_mut().map(|s| &mut s.multiview),
+ self.features_multiview.as_mut().map(|s| &mut s.multiview),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.multiview as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan11
+ .as_mut()
+ .map(|s| &mut s.multiview_geometry_shader),
+ self.features_multiview
+ .as_mut()
+ .map(|s| &mut s.multiview_geometry_shader),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.multiview_geometry_shader as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_mesh_shader_ext
+ .as_mut()
+ .map(|s| &mut s.multiview_mesh_shader)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.multiview_mesh_shader as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_multiview_per_view_viewports_qcom
+ .as_mut()
+ .map(|s| &mut s.multiview_per_view_viewports)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.multiview_per_view_viewports as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan11
+ .as_mut()
+ .map(|s| &mut s.multiview_tessellation_shader),
+ self.features_multiview
+ .as_mut()
+ .map(|s| &mut s.multiview_tessellation_shader),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.multiview_tessellation_shader as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_portability_subset_khr
+ .as_mut()
+ .map(|s| &mut s.mutable_comparison_samplers)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.mutable_comparison_samplers as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_mutable_descriptor_type_ext
+ .as_mut()
+ .map(|s| &mut s.mutable_descriptor_type)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.mutable_descriptor_type as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_fragment_shading_rate_enums_nv
+ .as_mut()
+ .map(|s| &mut s.no_invocation_fragment_shading_rates)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.no_invocation_fragment_shading_rates as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_non_seamless_cube_map_ext
+ .as_mut()
+ .map(|s| &mut s.non_seamless_cube_map)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.non_seamless_cube_map as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_robustness2_ext
+ .as_mut()
+ .map(|s| &mut s.null_descriptor)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.null_descriptor as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.occlusion_query_precise]
+ .into_iter()
+ .next()
+ {
+ *f = features.occlusion_query_precise as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_optical_flow_nv
+ .as_mut()
+ .map(|s| &mut s.optical_flow)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.optical_flow as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_pageable_device_local_memory_ext
+ .as_mut()
+ .map(|s| &mut s.pageable_device_local_memory)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.pageable_device_local_memory as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_performance_query_khr
+ .as_mut()
+ .map(|s| &mut s.performance_counter_multiple_query_pools)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.performance_counter_multiple_query_pools as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_performance_query_khr
+ .as_mut()
+ .map(|s| &mut s.performance_counter_query_pools)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.performance_counter_query_pools as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan13
+ .as_mut()
+ .map(|s| &mut s.pipeline_creation_cache_control),
+ self.features_pipeline_creation_cache_control
+ .as_mut()
+ .map(|s| &mut s.pipeline_creation_cache_control),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.pipeline_creation_cache_control as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_pipeline_executable_properties_khr
+ .as_mut()
+ .map(|s| &mut s.pipeline_executable_info)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.pipeline_executable_info as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_fragment_shading_rate_khr
+ .as_mut()
+ .map(|s| &mut s.pipeline_fragment_shading_rate)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.pipeline_fragment_shading_rate as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_pipeline_properties_ext
+ .as_mut()
+ .map(|s| &mut s.pipeline_properties_identifier)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.pipeline_properties_identifier as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_pipeline_protected_access_ext
+ .as_mut()
+ .map(|s| &mut s.pipeline_protected_access)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.pipeline_protected_access as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_pipeline_robustness_ext
+ .as_mut()
+ .map(|s| &mut s.pipeline_robustness)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.pipeline_robustness as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.pipeline_statistics_query]
+ .into_iter()
+ .next()
+ {
+ *f = features.pipeline_statistics_query as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_portability_subset_khr
+ .as_mut()
+ .map(|s| &mut s.point_polygons)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.point_polygons as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_present_barrier_nv
+ .as_mut()
+ .map(|s| &mut s.present_barrier)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.present_barrier as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_present_id_khr
+ .as_mut()
+ .map(|s| &mut s.present_id)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.present_id as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_present_wait_khr
+ .as_mut()
+ .map(|s| &mut s.present_wait)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.present_wait as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_fragment_shading_rate_khr
+ .as_mut()
+ .map(|s| &mut s.primitive_fragment_shading_rate)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.primitive_fragment_shading_rate as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_mesh_shader_ext
+ .as_mut()
+ .map(|s| &mut s.primitive_fragment_shading_rate_mesh_shader)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.primitive_fragment_shading_rate_mesh_shader as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_primitive_topology_list_restart_ext
+ .as_mut()
+ .map(|s| &mut s.primitive_topology_list_restart)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.primitive_topology_list_restart as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_primitive_topology_list_restart_ext
+ .as_mut()
+ .map(|s| &mut s.primitive_topology_patch_list_restart)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.primitive_topology_patch_list_restart as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_primitives_generated_query_ext
+ .as_mut()
+ .map(|s| &mut s.primitives_generated_query)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.primitives_generated_query as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_primitives_generated_query_ext
+ .as_mut()
+ .map(|s| &mut s.primitives_generated_query_with_non_zero_streams)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.primitives_generated_query_with_non_zero_streams as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_primitives_generated_query_ext
+ .as_mut()
+ .map(|s| &mut s.primitives_generated_query_with_rasterizer_discard)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.primitives_generated_query_with_rasterizer_discard as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan13.as_mut().map(|s| &mut s.private_data),
+ self.features_private_data
+ .as_mut()
+ .map(|s| &mut s.private_data),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.private_data as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan11
+ .as_mut()
+ .map(|s| &mut s.protected_memory),
+ self.features_protected_memory
+ .as_mut()
+ .map(|s| &mut s.protected_memory),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.protected_memory as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_provoking_vertex_ext
+ .as_mut()
+ .map(|s| &mut s.provoking_vertex_last)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.provoking_vertex_last as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_rasterization_order_attachment_access_ext
+ .as_mut()
+ .map(|s| &mut s.rasterization_order_color_attachment_access)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.rasterization_order_color_attachment_access as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_rasterization_order_attachment_access_ext
+ .as_mut()
+ .map(|s| &mut s.rasterization_order_depth_attachment_access)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.rasterization_order_depth_attachment_access as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_rasterization_order_attachment_access_ext
+ .as_mut()
+ .map(|s| &mut s.rasterization_order_stencil_attachment_access)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.rasterization_order_stencil_attachment_access as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_ray_query_khr
+ .as_mut()
+ .map(|s| &mut s.ray_query)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.ray_query as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_ray_tracing_invocation_reorder_nv
+ .as_mut()
+ .map(|s| &mut s.ray_tracing_invocation_reorder)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.ray_tracing_invocation_reorder as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_ray_tracing_maintenance1_khr
+ .as_mut()
+ .map(|s| &mut s.ray_tracing_maintenance1)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.ray_tracing_maintenance1 as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_ray_tracing_motion_blur_nv
+ .as_mut()
+ .map(|s| &mut s.ray_tracing_motion_blur)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.ray_tracing_motion_blur as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_ray_tracing_motion_blur_nv
+ .as_mut()
+ .map(|s| &mut s.ray_tracing_motion_blur_pipeline_trace_rays_indirect)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.ray_tracing_motion_blur_pipeline_trace_rays_indirect as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_ray_tracing_pipeline_khr
+ .as_mut()
+ .map(|s| &mut s.ray_tracing_pipeline)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.ray_tracing_pipeline as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_ray_tracing_pipeline_khr
+ .as_mut()
+ .map(|s| &mut s.ray_tracing_pipeline_shader_group_handle_capture_replay)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f =
+ features.ray_tracing_pipeline_shader_group_handle_capture_replay as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_ray_tracing_pipeline_khr
+ .as_mut()
+ .map(|s| &mut s.ray_tracing_pipeline_shader_group_handle_capture_replay_mixed)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.ray_tracing_pipeline_shader_group_handle_capture_replay_mixed
+ as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_ray_tracing_pipeline_khr
+ .as_mut()
+ .map(|s| &mut s.ray_tracing_pipeline_trace_rays_indirect)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.ray_tracing_pipeline_trace_rays_indirect as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_ray_tracing_maintenance1_khr
+ .as_mut()
+ .map(|s| &mut s.ray_tracing_pipeline_trace_rays_indirect2)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.ray_tracing_pipeline_trace_rays_indirect2 as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_ray_tracing_pipeline_khr
+ .as_mut()
+ .map(|s| &mut s.ray_traversal_primitive_culling)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.ray_traversal_primitive_culling as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_line_rasterization_ext
+ .as_mut()
+ .map(|s| &mut s.rectangular_lines)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.rectangular_lines as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_address_binding_report_ext
+ .as_mut()
+ .map(|s| &mut s.report_address_binding)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.report_address_binding as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_representative_fragment_test_nv
+ .as_mut()
+ .map(|s| &mut s.representative_fragment_test)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.representative_fragment_test as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.robust_buffer_access]
+ .into_iter()
+ .next()
+ {
+ *f = features.robust_buffer_access as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_robustness2_ext
+ .as_mut()
+ .map(|s| &mut s.robust_buffer_access2)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.robust_buffer_access2 as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan13
+ .as_mut()
+ .map(|s| &mut s.robust_image_access),
+ self.features_image_robustness
+ .as_mut()
+ .map(|s| &mut s.robust_image_access),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.robust_image_access as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_robustness2_ext
+ .as_mut()
+ .map(|s| &mut s.robust_image_access2)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.robust_image_access2 as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.runtime_descriptor_array),
+ self.features_descriptor_indexing
+ .as_mut()
+ .map(|s| &mut s.runtime_descriptor_array),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.runtime_descriptor_array as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.sample_rate_shading]
+ .into_iter()
+ .next()
+ {
+ *f = features.sample_rate_shading as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_image2_d_view_of3_d_ext
+ .as_mut()
+ .map(|s| &mut s.sampler2_d_view_of3_d)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.sampler2_d_view_of3_d as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.sampler_anisotropy]
+ .into_iter()
+ .next()
+ {
+ *f = features.sampler_anisotropy as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.sampler_filter_minmax)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.sampler_filter_minmax as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_portability_subset_khr
+ .as_mut()
+ .map(|s| &mut s.sampler_mip_lod_bias)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.sampler_mip_lod_bias as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.sampler_mirror_clamp_to_edge)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.sampler_mirror_clamp_to_edge as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan11
+ .as_mut()
+ .map(|s| &mut s.sampler_ycbcr_conversion),
+ self.features_sampler_ycbcr_conversion
+ .as_mut()
+ .map(|s| &mut s.sampler_ycbcr_conversion),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.sampler_ycbcr_conversion as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.scalar_block_layout),
+ self.features_scalar_block_layout
+ .as_mut()
+ .map(|s| &mut s.scalar_block_layout),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.scalar_block_layout as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.separate_depth_stencil_layouts),
+ self.features_separate_depth_stencil_layouts
+ .as_mut()
+ .map(|s| &mut s.separate_depth_stencil_layouts),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.separate_depth_stencil_layouts as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_portability_subset_khr
+ .as_mut()
+ .map(|s| &mut s.separate_stencil_mask_ref)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.separate_stencil_mask_ref as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_atomic_float2_ext
+ .as_mut()
+ .map(|s| &mut s.shader_buffer_float16_atomic_add)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_buffer_float16_atomic_add as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_atomic_float2_ext
+ .as_mut()
+ .map(|s| &mut s.shader_buffer_float16_atomic_min_max)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_buffer_float16_atomic_min_max as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_atomic_float2_ext
+ .as_mut()
+ .map(|s| &mut s.shader_buffer_float16_atomics)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_buffer_float16_atomics as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_atomic_float_ext
+ .as_mut()
+ .map(|s| &mut s.shader_buffer_float32_atomic_add)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_buffer_float32_atomic_add as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_atomic_float2_ext
+ .as_mut()
+ .map(|s| &mut s.shader_buffer_float32_atomic_min_max)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_buffer_float32_atomic_min_max as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_atomic_float_ext
+ .as_mut()
+ .map(|s| &mut s.shader_buffer_float32_atomics)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_buffer_float32_atomics as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_atomic_float_ext
+ .as_mut()
+ .map(|s| &mut s.shader_buffer_float64_atomic_add)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_buffer_float64_atomic_add as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_atomic_float2_ext
+ .as_mut()
+ .map(|s| &mut s.shader_buffer_float64_atomic_min_max)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_buffer_float64_atomic_min_max as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_atomic_float_ext
+ .as_mut()
+ .map(|s| &mut s.shader_buffer_float64_atomics)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_buffer_float64_atomics as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.shader_buffer_int64_atomics),
+ self.features_shader_atomic_int64
+ .as_mut()
+ .map(|s| &mut s.shader_buffer_int64_atomics),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_buffer_int64_atomics as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.shader_clip_distance]
+ .into_iter()
+ .next()
+ {
+ *f = features.shader_clip_distance as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_core_builtins_arm
+ .as_mut()
+ .map(|s| &mut s.shader_core_builtins)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_core_builtins as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.shader_cull_distance]
+ .into_iter()
+ .next()
+ {
+ *f = features.shader_cull_distance as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan13
+ .as_mut()
+ .map(|s| &mut s.shader_demote_to_helper_invocation),
+ self.features_shader_demote_to_helper_invocation
+ .as_mut()
+ .map(|s| &mut s.shader_demote_to_helper_invocation),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_demote_to_helper_invocation as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_clock_khr
+ .as_mut()
+ .map(|s| &mut s.shader_device_clock)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_device_clock as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan11
+ .as_mut()
+ .map(|s| &mut s.shader_draw_parameters),
+ self.features_shader_draw_parameters
+ .as_mut()
+ .map(|s| &mut s.shader_draw_parameters),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_draw_parameters as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_early_and_late_fragment_tests_amd
+ .as_mut()
+ .map(|s| &mut s.shader_early_and_late_fragment_tests)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_early_and_late_fragment_tests as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.shader_float16),
+ self.features_shader_float16_int8
+ .as_mut()
+ .map(|s| &mut s.shader_float16),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_float16 as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.shader_float64]
+ .into_iter()
+ .next()
+ {
+ *f = features.shader_float64 as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_atomic_float_ext
+ .as_mut()
+ .map(|s| &mut s.shader_image_float32_atomic_add)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_image_float32_atomic_add as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_atomic_float2_ext
+ .as_mut()
+ .map(|s| &mut s.shader_image_float32_atomic_min_max)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_image_float32_atomic_min_max as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_atomic_float_ext
+ .as_mut()
+ .map(|s| &mut s.shader_image_float32_atomics)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_image_float32_atomics as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.shader_image_gather_extended]
+ .into_iter()
+ .next()
+ {
+ *f = features.shader_image_gather_extended as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_image_atomic_int64_ext
+ .as_mut()
+ .map(|s| &mut s.shader_image_int64_atomics)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_image_int64_atomics as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.shader_input_attachment_array_dynamic_indexing),
+ self.features_descriptor_indexing
+ .as_mut()
+ .map(|s| &mut s.shader_input_attachment_array_dynamic_indexing),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_input_attachment_array_dynamic_indexing as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.shader_input_attachment_array_non_uniform_indexing),
+ self.features_descriptor_indexing
+ .as_mut()
+ .map(|s| &mut s.shader_input_attachment_array_non_uniform_indexing),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_input_attachment_array_non_uniform_indexing as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.shader_int16]
+ .into_iter()
+ .next()
+ {
+ *f = features.shader_int16 as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.shader_int64]
+ .into_iter()
+ .next()
+ {
+ *f = features.shader_int64 as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12.as_mut().map(|s| &mut s.shader_int8),
+ self.features_shader_float16_int8
+ .as_mut()
+ .map(|s| &mut s.shader_int8),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_int8 as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan13
+ .as_mut()
+ .map(|s| &mut s.shader_integer_dot_product),
+ self.features_shader_integer_dot_product
+ .as_mut()
+ .map(|s| &mut s.shader_integer_dot_product),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_integer_dot_product as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_integer_functions2_intel
+ .as_mut()
+ .map(|s| &mut s.shader_integer_functions2)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_integer_functions2 as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_module_identifier_ext
+ .as_mut()
+ .map(|s| &mut s.shader_module_identifier)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_module_identifier as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.shader_output_layer)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_output_layer as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.shader_output_viewport_index)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_output_viewport_index as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.shader_resource_min_lod]
+ .into_iter()
+ .next()
+ {
+ *f = features.shader_resource_min_lod as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.shader_resource_residency]
+ .into_iter()
+ .next()
+ {
+ *f = features.shader_resource_residency as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_portability_subset_khr
+ .as_mut()
+ .map(|s| &mut s.shader_sample_rate_interpolation_functions)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_sample_rate_interpolation_functions as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self
+ .features_vulkan10
+ .features
+ .shader_sampled_image_array_dynamic_indexing]
+ .into_iter()
+ .next()
+ {
+ *f = features.shader_sampled_image_array_dynamic_indexing as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.shader_sampled_image_array_non_uniform_indexing),
+ self.features_descriptor_indexing
+ .as_mut()
+ .map(|s| &mut s.shader_sampled_image_array_non_uniform_indexing),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_sampled_image_array_non_uniform_indexing as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_atomic_float2_ext
+ .as_mut()
+ .map(|s| &mut s.shader_shared_float16_atomic_add)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_shared_float16_atomic_add as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_atomic_float2_ext
+ .as_mut()
+ .map(|s| &mut s.shader_shared_float16_atomic_min_max)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_shared_float16_atomic_min_max as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_atomic_float2_ext
+ .as_mut()
+ .map(|s| &mut s.shader_shared_float16_atomics)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_shared_float16_atomics as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_atomic_float_ext
+ .as_mut()
+ .map(|s| &mut s.shader_shared_float32_atomic_add)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_shared_float32_atomic_add as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_atomic_float2_ext
+ .as_mut()
+ .map(|s| &mut s.shader_shared_float32_atomic_min_max)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_shared_float32_atomic_min_max as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_atomic_float_ext
+ .as_mut()
+ .map(|s| &mut s.shader_shared_float32_atomics)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_shared_float32_atomics as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_atomic_float_ext
+ .as_mut()
+ .map(|s| &mut s.shader_shared_float64_atomic_add)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_shared_float64_atomic_add as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_atomic_float2_ext
+ .as_mut()
+ .map(|s| &mut s.shader_shared_float64_atomic_min_max)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_shared_float64_atomic_min_max as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_atomic_float_ext
+ .as_mut()
+ .map(|s| &mut s.shader_shared_float64_atomics)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_shared_float64_atomics as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.shader_shared_int64_atomics),
+ self.features_shader_atomic_int64
+ .as_mut()
+ .map(|s| &mut s.shader_shared_int64_atomics),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_shared_int64_atomics as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_sm_builtins_nv
+ .as_mut()
+ .map(|s| &mut s.shader_sm_builtins)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_sm_builtins as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self
+ .features_vulkan10
+ .features
+ .shader_storage_buffer_array_dynamic_indexing]
+ .into_iter()
+ .next()
+ {
+ *f = features.shader_storage_buffer_array_dynamic_indexing as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.shader_storage_buffer_array_non_uniform_indexing),
+ self.features_descriptor_indexing
+ .as_mut()
+ .map(|s| &mut s.shader_storage_buffer_array_non_uniform_indexing),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_storage_buffer_array_non_uniform_indexing as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self
+ .features_vulkan10
+ .features
+ .shader_storage_image_array_dynamic_indexing]
+ .into_iter()
+ .next()
+ {
+ *f = features.shader_storage_image_array_dynamic_indexing as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.shader_storage_image_array_non_uniform_indexing),
+ self.features_descriptor_indexing
+ .as_mut()
+ .map(|s| &mut s.shader_storage_image_array_non_uniform_indexing),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_storage_image_array_non_uniform_indexing as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self
+ .features_vulkan10
+ .features
+ .shader_storage_image_extended_formats]
+ .into_iter()
+ .next()
+ {
+ *f = features.shader_storage_image_extended_formats as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self
+ .features_vulkan10
+ .features
+ .shader_storage_image_multisample]
+ .into_iter()
+ .next()
+ {
+ *f = features.shader_storage_image_multisample as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self
+ .features_vulkan10
+ .features
+ .shader_storage_image_read_without_format]
+ .into_iter()
+ .next()
+ {
+ *f = features.shader_storage_image_read_without_format as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self
+ .features_vulkan10
+ .features
+ .shader_storage_image_write_without_format]
+ .into_iter()
+ .next()
+ {
+ *f = features.shader_storage_image_write_without_format as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.shader_storage_texel_buffer_array_dynamic_indexing),
+ self.features_descriptor_indexing
+ .as_mut()
+ .map(|s| &mut s.shader_storage_texel_buffer_array_dynamic_indexing),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_storage_texel_buffer_array_dynamic_indexing as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.shader_storage_texel_buffer_array_non_uniform_indexing),
+ self.features_descriptor_indexing
+ .as_mut()
+ .map(|s| &mut s.shader_storage_texel_buffer_array_non_uniform_indexing),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_storage_texel_buffer_array_non_uniform_indexing as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_clock_khr
+ .as_mut()
+ .map(|s| &mut s.shader_subgroup_clock)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_subgroup_clock as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.shader_subgroup_extended_types),
+ self.features_shader_subgroup_extended_types
+ .as_mut()
+ .map(|s| &mut s.shader_subgroup_extended_types),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_subgroup_extended_types as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_subgroup_uniform_control_flow_khr
+ .as_mut()
+ .map(|s| &mut s.shader_subgroup_uniform_control_flow)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_subgroup_uniform_control_flow as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan13
+ .as_mut()
+ .map(|s| &mut s.shader_terminate_invocation),
+ self.features_shader_terminate_invocation
+ .as_mut()
+ .map(|s| &mut s.shader_terminate_invocation),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_terminate_invocation as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self
+ .features_vulkan10
+ .features
+ .shader_tessellation_and_geometry_point_size]
+ .into_iter()
+ .next()
+ {
+ *f = features.shader_tessellation_and_geometry_point_size as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self
+ .features_vulkan10
+ .features
+ .shader_uniform_buffer_array_dynamic_indexing]
+ .into_iter()
+ .next()
+ {
+ *f = features.shader_uniform_buffer_array_dynamic_indexing as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.shader_uniform_buffer_array_non_uniform_indexing),
+ self.features_descriptor_indexing
+ .as_mut()
+ .map(|s| &mut s.shader_uniform_buffer_array_non_uniform_indexing),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_uniform_buffer_array_non_uniform_indexing as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.shader_uniform_texel_buffer_array_dynamic_indexing),
+ self.features_descriptor_indexing
+ .as_mut()
+ .map(|s| &mut s.shader_uniform_texel_buffer_array_dynamic_indexing),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_uniform_texel_buffer_array_dynamic_indexing as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.shader_uniform_texel_buffer_array_non_uniform_indexing),
+ self.features_descriptor_indexing
+ .as_mut()
+ .map(|s| &mut s.shader_uniform_texel_buffer_array_non_uniform_indexing),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_uniform_texel_buffer_array_non_uniform_indexing as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan13
+ .as_mut()
+ .map(|s| &mut s.shader_zero_initialize_workgroup_memory),
+ self.features_zero_initialize_workgroup_memory
+ .as_mut()
+ .map(|s| &mut s.shader_zero_initialize_workgroup_memory),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shader_zero_initialize_workgroup_memory as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shading_rate_image_nv
+ .as_mut()
+ .map(|s| &mut s.shading_rate_coarse_sample_order)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shading_rate_coarse_sample_order as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shading_rate_image_nv
+ .as_mut()
+ .map(|s| &mut s.shading_rate_image)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.shading_rate_image as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_line_rasterization_ext
+ .as_mut()
+ .map(|s| &mut s.smooth_lines)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.smooth_lines as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.sparse_binding]
+ .into_iter()
+ .next()
+ {
+ *f = features.sparse_binding as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_atomic_float_ext
+ .as_mut()
+ .map(|s| &mut s.sparse_image_float32_atomic_add)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.sparse_image_float32_atomic_add as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_atomic_float2_ext
+ .as_mut()
+ .map(|s| &mut s.sparse_image_float32_atomic_min_max)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.sparse_image_float32_atomic_min_max as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_atomic_float_ext
+ .as_mut()
+ .map(|s| &mut s.sparse_image_float32_atomics)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.sparse_image_float32_atomics as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_shader_image_atomic_int64_ext
+ .as_mut()
+ .map(|s| &mut s.sparse_image_int64_atomics)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.sparse_image_int64_atomics as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.sparse_residency16_samples]
+ .into_iter()
+ .next()
+ {
+ *f = features.sparse_residency16_samples as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.sparse_residency2_samples]
+ .into_iter()
+ .next()
+ {
+ *f = features.sparse_residency2_samples as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.sparse_residency4_samples]
+ .into_iter()
+ .next()
+ {
+ *f = features.sparse_residency4_samples as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.sparse_residency8_samples]
+ .into_iter()
+ .next()
+ {
+ *f = features.sparse_residency8_samples as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.sparse_residency_aliased]
+ .into_iter()
+ .next()
+ {
+ *f = features.sparse_residency_aliased as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.sparse_residency_buffer]
+ .into_iter()
+ .next()
+ {
+ *f = features.sparse_residency_buffer as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.sparse_residency_image2_d]
+ .into_iter()
+ .next()
+ {
+ *f = features.sparse_residency_image2_d as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.sparse_residency_image3_d]
+ .into_iter()
+ .next()
+ {
+ *f = features.sparse_residency_image3_d as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_line_rasterization_ext
+ .as_mut()
+ .map(|s| &mut s.stippled_bresenham_lines)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.stippled_bresenham_lines as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_line_rasterization_ext
+ .as_mut()
+ .map(|s| &mut s.stippled_rectangular_lines)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.stippled_rectangular_lines as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_line_rasterization_ext
+ .as_mut()
+ .map(|s| &mut s.stippled_smooth_lines)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.stippled_smooth_lines as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan11
+ .as_mut()
+ .map(|s| &mut s.storage_buffer16_bit_access),
+ self.features_16bit_storage
+ .as_mut()
+ .map(|s| &mut s.storage_buffer16_bit_access),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.storage_buffer16_bit_access as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.storage_buffer8_bit_access),
+ self.features_8bit_storage
+ .as_mut()
+ .map(|s| &mut s.storage_buffer8_bit_access),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.storage_buffer8_bit_access as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan11
+ .as_mut()
+ .map(|s| &mut s.storage_input_output16),
+ self.features_16bit_storage
+ .as_mut()
+ .map(|s| &mut s.storage_input_output16),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.storage_input_output16 as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan11
+ .as_mut()
+ .map(|s| &mut s.storage_push_constant16),
+ self.features_16bit_storage
+ .as_mut()
+ .map(|s| &mut s.storage_push_constant16),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.storage_push_constant16 as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.storage_push_constant8),
+ self.features_8bit_storage
+ .as_mut()
+ .map(|s| &mut s.storage_push_constant8),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.storage_push_constant8 as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.subgroup_broadcast_dynamic_id)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.subgroup_broadcast_dynamic_id as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan13
+ .as_mut()
+ .map(|s| &mut s.subgroup_size_control),
+ self.features_subgroup_size_control
+ .as_mut()
+ .map(|s| &mut s.subgroup_size_control),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.subgroup_size_control as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_subpass_merge_feedback_ext
+ .as_mut()
+ .map(|s| &mut s.subpass_merge_feedback)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.subpass_merge_feedback as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_subpass_shading_huawei
+ .as_mut()
+ .map(|s| &mut s.subpass_shading)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.subpass_shading as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_fragment_shading_rate_enums_nv
+ .as_mut()
+ .map(|s| &mut s.supersample_fragment_shading_rates)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.supersample_fragment_shading_rates as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_swapchain_maintenance1_ext
+ .as_mut()
+ .map(|s| &mut s.swapchain_maintenance1)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.swapchain_maintenance1 as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan13
+ .as_mut()
+ .map(|s| &mut s.synchronization2),
+ self.features_synchronization2
+ .as_mut()
+ .map(|s| &mut s.synchronization2),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.synchronization2 as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_mesh_shader_ext
+ .as_mut()
+ .map(|s| &mut s.task_shader),
+ self.features_mesh_shader_nv
+ .as_mut()
+ .map(|s| &mut s.task_shader),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.task_shader as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_portability_subset_khr
+ .as_mut()
+ .map(|s| &mut s.tessellation_isolines)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.tessellation_isolines as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_portability_subset_khr
+ .as_mut()
+ .map(|s| &mut s.tessellation_point_mode)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.tessellation_point_mode as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.tessellation_shader]
+ .into_iter()
+ .next()
+ {
+ *f = features.tessellation_shader as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_texel_buffer_alignment_ext
+ .as_mut()
+ .map(|s| &mut s.texel_buffer_alignment)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.texel_buffer_alignment as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_image_processing_qcom
+ .as_mut()
+ .map(|s| &mut s.texture_block_match)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.texture_block_match as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_image_processing_qcom
+ .as_mut()
+ .map(|s| &mut s.texture_box_filter)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.texture_box_filter as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan13
+ .as_mut()
+ .map(|s| &mut s.texture_compression_astc_hdr),
+ self.features_texture_compression_astchdr
+ .as_mut()
+ .map(|s| &mut s.texture_compression_astc_hdr),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.texture_compression_astc_hdr as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.texture_compression_astc_ldr]
+ .into_iter()
+ .next()
+ {
+ *f = features.texture_compression_astc_ldr as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.texture_compression_bc]
+ .into_iter()
+ .next()
+ {
+ *f = features.texture_compression_bc as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.texture_compression_etc2]
+ .into_iter()
+ .next()
+ {
+ *f = features.texture_compression_etc2 as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_image_processing_qcom
+ .as_mut()
+ .map(|s| &mut s.texture_sample_weighted)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.texture_sample_weighted as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_tile_properties_qcom
+ .as_mut()
+ .map(|s| &mut s.tile_properties)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.tile_properties as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.timeline_semaphore),
+ self.features_timeline_semaphore
+ .as_mut()
+ .map(|s| &mut s.timeline_semaphore),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.timeline_semaphore as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_transform_feedback_ext
+ .as_mut()
+ .map(|s| &mut s.transform_feedback)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.transform_feedback as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_provoking_vertex_ext
+ .as_mut()
+ .map(|s| &mut s.transform_feedback_preserves_provoking_vertex)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.transform_feedback_preserves_provoking_vertex as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_portability_subset_khr
+ .as_mut()
+ .map(|s| &mut s.triangle_fans)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.triangle_fans as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan11
+ .as_mut()
+ .map(|s| &mut s.uniform_and_storage_buffer16_bit_access),
+ self.features_16bit_storage
+ .as_mut()
+ .map(|s| &mut s.uniform_and_storage_buffer16_bit_access),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.uniform_and_storage_buffer16_bit_access as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.uniform_and_storage_buffer8_bit_access),
+ self.features_8bit_storage
+ .as_mut()
+ .map(|s| &mut s.uniform_and_storage_buffer8_bit_access),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.uniform_and_storage_buffer8_bit_access as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.uniform_buffer_standard_layout),
+ self.features_uniform_buffer_standard_layout
+ .as_mut()
+ .map(|s| &mut s.uniform_buffer_standard_layout),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.uniform_buffer_standard_layout as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.variable_multisample_rate]
+ .into_iter()
+ .next()
+ {
+ *f = features.variable_multisample_rate as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan11
+ .as_mut()
+ .map(|s| &mut s.variable_pointers),
+ self.features_variable_pointers
+ .as_mut()
+ .map(|s| &mut s.variable_pointers),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.variable_pointers as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan11
+ .as_mut()
+ .map(|s| &mut s.variable_pointers_storage_buffer),
+ self.features_variable_pointers
+ .as_mut()
+ .map(|s| &mut s.variable_pointers_storage_buffer),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.variable_pointers_storage_buffer as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_portability_subset_khr
+ .as_mut()
+ .map(|s| &mut s.vertex_attribute_access_beyond_stride)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.vertex_attribute_access_beyond_stride as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_vertex_attribute_divisor_ext
+ .as_mut()
+ .map(|s| &mut s.vertex_attribute_instance_rate_divisor)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.vertex_attribute_instance_rate_divisor as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_vertex_attribute_divisor_ext
+ .as_mut()
+ .map(|s| &mut s.vertex_attribute_instance_rate_zero_divisor)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.vertex_attribute_instance_rate_zero_divisor as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_vertex_input_dynamic_state_ext
+ .as_mut()
+ .map(|s| &mut s.vertex_input_dynamic_state)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.vertex_input_dynamic_state as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self
+ .features_vulkan10
+ .features
+ .vertex_pipeline_stores_and_atomics]
+ .into_iter()
+ .next()
+ {
+ *f = features.vertex_pipeline_stores_and_atomics as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.vulkan_memory_model),
+ self.features_vulkan_memory_model
+ .as_mut()
+ .map(|s| &mut s.vulkan_memory_model),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.vulkan_memory_model as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.vulkan_memory_model_availability_visibility_chains),
+ self.features_vulkan_memory_model
+ .as_mut()
+ .map(|s| &mut s.vulkan_memory_model_availability_visibility_chains),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.vulkan_memory_model_availability_visibility_chains as ash::vk::Bool32;
+ }
+ if let Some(f) = [
+ self.features_vulkan12
+ .as_mut()
+ .map(|s| &mut s.vulkan_memory_model_device_scope),
+ self.features_vulkan_memory_model
+ .as_mut()
+ .map(|s| &mut s.vulkan_memory_model_device_scope),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.vulkan_memory_model_device_scope as ash::vk::Bool32;
+ }
+ if let Some(f) = [&mut self.features_vulkan10.features.wide_lines]
+ .into_iter()
+ .next()
+ {
+ *f = features.wide_lines as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_workgroup_memory_explicit_layout_khr
+ .as_mut()
+ .map(|s| &mut s.workgroup_memory_explicit_layout)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.workgroup_memory_explicit_layout as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_workgroup_memory_explicit_layout_khr
+ .as_mut()
+ .map(|s| &mut s.workgroup_memory_explicit_layout16_bit_access)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.workgroup_memory_explicit_layout16_bit_access as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_workgroup_memory_explicit_layout_khr
+ .as_mut()
+ .map(|s| &mut s.workgroup_memory_explicit_layout8_bit_access)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.workgroup_memory_explicit_layout8_bit_access as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_workgroup_memory_explicit_layout_khr
+ .as_mut()
+ .map(|s| &mut s.workgroup_memory_explicit_layout_scalar_block_layout)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.workgroup_memory_explicit_layout_scalar_block_layout as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_ycbcr2_plane444_formats_ext
+ .as_mut()
+ .map(|s| &mut s.ycbcr2plane444_formats)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.ycbcr2plane444_formats as ash::vk::Bool32;
+ }
+ if let Some(f) = [self
+ .features_ycbcr_image_arrays_ext
+ .as_mut()
+ .map(|s| &mut s.ycbcr_image_arrays)]
+ .into_iter()
+ .flatten()
+ .next()
+ {
+ *f = features.ycbcr_image_arrays as ash::vk::Bool32;
+ }
+ }
+}
+impl From<&FeaturesFfi> for Features {
+ fn from(features_ffi: &FeaturesFfi) -> Self {
+ Features {
+ acceleration_structure: [features_ffi
+ .features_acceleration_structure_khr
+ .map(|s| s.acceleration_structure)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ acceleration_structure_capture_replay: [features_ffi
+ .features_acceleration_structure_khr
+ .map(|s| s.acceleration_structure_capture_replay)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ acceleration_structure_host_commands: [features_ffi
+ .features_acceleration_structure_khr
+ .map(|s| s.acceleration_structure_host_commands)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ acceleration_structure_indirect_build: [features_ffi
+ .features_acceleration_structure_khr
+ .map(|s| s.acceleration_structure_indirect_build)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ advanced_blend_coherent_operations: [features_ffi
+ .features_blend_operation_advanced_ext
+ .map(|s| s.advanced_blend_coherent_operations)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ alpha_to_one: [features_ffi.features_vulkan10.features.alpha_to_one]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ amigo_profiling: [features_ffi
+ .features_amigo_profiling_sec
+ .map(|s| s.amigo_profiling)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ attachment_feedback_loop_layout: [features_ffi
+ .features_attachment_feedback_loop_layout_ext
+ .map(|s| s.attachment_feedback_loop_layout)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ attachment_fragment_shading_rate: [features_ffi
+ .features_fragment_shading_rate_khr
+ .map(|s| s.attachment_fragment_shading_rate)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ border_color_swizzle: [features_ffi
+ .features_border_color_swizzle_ext
+ .map(|s| s.border_color_swizzle)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ border_color_swizzle_from_image: [features_ffi
+ .features_border_color_swizzle_ext
+ .map(|s| s.border_color_swizzle_from_image)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ bresenham_lines: [features_ffi
+ .features_line_rasterization_ext
+ .map(|s| s.bresenham_lines)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ buffer_device_address: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.buffer_device_address),
+ features_ffi
+ .features_buffer_device_address
+ .map(|s| s.buffer_device_address),
+ features_ffi
+ .features_buffer_device_address_ext
+ .map(|s| s.buffer_device_address),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ buffer_device_address_capture_replay: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.buffer_device_address_capture_replay),
+ features_ffi
+ .features_buffer_device_address
+ .map(|s| s.buffer_device_address_capture_replay),
+ features_ffi
+ .features_buffer_device_address_ext
+ .map(|s| s.buffer_device_address_capture_replay),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ buffer_device_address_multi_device: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.buffer_device_address_multi_device),
+ features_ffi
+ .features_buffer_device_address
+ .map(|s| s.buffer_device_address_multi_device),
+ features_ffi
+ .features_buffer_device_address_ext
+ .map(|s| s.buffer_device_address_multi_device),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ color_write_enable: [features_ffi
+ .features_color_write_enable_ext
+ .map(|s| s.color_write_enable)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ compute_derivative_group_linear: [features_ffi
+ .features_compute_shader_derivatives_nv
+ .map(|s| s.compute_derivative_group_linear)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ compute_derivative_group_quads: [features_ffi
+ .features_compute_shader_derivatives_nv
+ .map(|s| s.compute_derivative_group_quads)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ compute_full_subgroups: [
+ features_ffi
+ .features_vulkan13
+ .map(|s| s.compute_full_subgroups),
+ features_ffi
+ .features_subgroup_size_control
+ .map(|s| s.compute_full_subgroups),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ conditional_rendering: [features_ffi
+ .features_conditional_rendering_ext
+ .map(|s| s.conditional_rendering)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ constant_alpha_color_blend_factors: [features_ffi
+ .features_portability_subset_khr
+ .map(|s| s.constant_alpha_color_blend_factors)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ cooperative_matrix: [features_ffi
+ .features_cooperative_matrix_nv
+ .map(|s| s.cooperative_matrix)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ cooperative_matrix_robust_buffer_access: [features_ffi
+ .features_cooperative_matrix_nv
+ .map(|s| s.cooperative_matrix_robust_buffer_access)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ corner_sampled_image: [features_ffi
+ .features_corner_sampled_image_nv
+ .map(|s| s.corner_sampled_image)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ coverage_reduction_mode: [features_ffi
+ .features_coverage_reduction_mode_nv
+ .map(|s| s.coverage_reduction_mode)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ custom_border_color_without_format: [features_ffi
+ .features_custom_border_color_ext
+ .map(|s| s.custom_border_color_without_format)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ custom_border_colors: [features_ffi
+ .features_custom_border_color_ext
+ .map(|s| s.custom_border_colors)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ decode_mode_shared_exponent: [features_ffi
+ .features_astc_decode_ext
+ .map(|s| s.decode_mode_shared_exponent)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ dedicated_allocation_image_aliasing: [features_ffi
+ .features_dedicated_allocation_image_aliasing_nv
+ .map(|s| s.dedicated_allocation_image_aliasing)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ depth_bias_clamp: [features_ffi.features_vulkan10.features.depth_bias_clamp]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ depth_bounds: [features_ffi.features_vulkan10.features.depth_bounds]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ depth_clamp: [features_ffi.features_vulkan10.features.depth_clamp]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ depth_clamp_zero_one: [features_ffi
+ .features_depth_clamp_zero_one_ext
+ .map(|s| s.depth_clamp_zero_one)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ depth_clip_control: [features_ffi
+ .features_depth_clip_control_ext
+ .map(|s| s.depth_clip_control)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ depth_clip_enable: [features_ffi
+ .features_depth_clip_enable_ext
+ .map(|s| s.depth_clip_enable)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ descriptor_binding_acceleration_structure_update_after_bind: [features_ffi
+ .features_acceleration_structure_khr
+ .map(|s| s.descriptor_binding_acceleration_structure_update_after_bind)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ descriptor_binding_inline_uniform_block_update_after_bind: [
+ features_ffi
+ .features_vulkan13
+ .map(|s| s.descriptor_binding_inline_uniform_block_update_after_bind),
+ features_ffi
+ .features_inline_uniform_block
+ .map(|s| s.descriptor_binding_inline_uniform_block_update_after_bind),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ descriptor_binding_partially_bound: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.descriptor_binding_partially_bound),
+ features_ffi
+ .features_descriptor_indexing
+ .map(|s| s.descriptor_binding_partially_bound),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ descriptor_binding_sampled_image_update_after_bind: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.descriptor_binding_sampled_image_update_after_bind),
+ features_ffi
+ .features_descriptor_indexing
+ .map(|s| s.descriptor_binding_sampled_image_update_after_bind),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ descriptor_binding_storage_buffer_update_after_bind: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.descriptor_binding_storage_buffer_update_after_bind),
+ features_ffi
+ .features_descriptor_indexing
+ .map(|s| s.descriptor_binding_storage_buffer_update_after_bind),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ descriptor_binding_storage_image_update_after_bind: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.descriptor_binding_storage_image_update_after_bind),
+ features_ffi
+ .features_descriptor_indexing
+ .map(|s| s.descriptor_binding_storage_image_update_after_bind),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ descriptor_binding_storage_texel_buffer_update_after_bind: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.descriptor_binding_storage_texel_buffer_update_after_bind),
+ features_ffi
+ .features_descriptor_indexing
+ .map(|s| s.descriptor_binding_storage_texel_buffer_update_after_bind),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ descriptor_binding_uniform_buffer_update_after_bind: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.descriptor_binding_uniform_buffer_update_after_bind),
+ features_ffi
+ .features_descriptor_indexing
+ .map(|s| s.descriptor_binding_uniform_buffer_update_after_bind),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ descriptor_binding_uniform_texel_buffer_update_after_bind: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.descriptor_binding_uniform_texel_buffer_update_after_bind),
+ features_ffi
+ .features_descriptor_indexing
+ .map(|s| s.descriptor_binding_uniform_texel_buffer_update_after_bind),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ descriptor_binding_update_unused_while_pending: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.descriptor_binding_update_unused_while_pending),
+ features_ffi
+ .features_descriptor_indexing
+ .map(|s| s.descriptor_binding_update_unused_while_pending),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ descriptor_binding_variable_descriptor_count: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.descriptor_binding_variable_descriptor_count),
+ features_ffi
+ .features_descriptor_indexing
+ .map(|s| s.descriptor_binding_variable_descriptor_count),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ descriptor_buffer: [features_ffi
+ .features_descriptor_buffer_ext
+ .map(|s| s.descriptor_buffer)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ descriptor_buffer_capture_replay: [features_ffi
+ .features_descriptor_buffer_ext
+ .map(|s| s.descriptor_buffer_capture_replay)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ descriptor_buffer_image_layout_ignored: [features_ffi
+ .features_descriptor_buffer_ext
+ .map(|s| s.descriptor_buffer_image_layout_ignored)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ descriptor_buffer_push_descriptors: [features_ffi
+ .features_descriptor_buffer_ext
+ .map(|s| s.descriptor_buffer_push_descriptors)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ descriptor_indexing: [features_ffi
+ .features_vulkan12
+ .map(|s| s.descriptor_indexing)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ descriptor_set_host_mapping: [features_ffi
+ .features_descriptor_set_host_mapping_valve
+ .map(|s| s.descriptor_set_host_mapping)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ device_coherent_memory: [features_ffi
+ .features_coherent_memory_amd
+ .map(|s| s.device_coherent_memory)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ device_fault: [features_ffi.features_fault_ext.map(|s| s.device_fault)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ device_fault_vendor_binary: [features_ffi
+ .features_fault_ext
+ .map(|s| s.device_fault_vendor_binary)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ device_generated_commands: [features_ffi
+ .features_device_generated_commands_nv
+ .map(|s| s.device_generated_commands)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ device_memory_report: [features_ffi
+ .features_device_memory_report_ext
+ .map(|s| s.device_memory_report)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ diagnostics_config: [features_ffi
+ .features_diagnostics_config_nv
+ .map(|s| s.diagnostics_config)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ draw_indirect_count: [features_ffi
+ .features_vulkan12
+ .map(|s| s.draw_indirect_count)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ draw_indirect_first_instance: [features_ffi
+ .features_vulkan10
+ .features
+ .draw_indirect_first_instance]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ dual_src_blend: [features_ffi.features_vulkan10.features.dual_src_blend]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ dynamic_rendering: [
+ features_ffi.features_vulkan13.map(|s| s.dynamic_rendering),
+ features_ffi
+ .features_dynamic_rendering
+ .map(|s| s.dynamic_rendering),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ events: [features_ffi
+ .features_portability_subset_khr
+ .map(|s| s.events)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ exclusive_scissor: [features_ffi
+ .features_exclusive_scissor_nv
+ .map(|s| s.exclusive_scissor)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state: [features_ffi
+ .features_extended_dynamic_state_ext
+ .map(|s| s.extended_dynamic_state)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state2: [features_ffi
+ .features_extended_dynamic_state2_ext
+ .map(|s| s.extended_dynamic_state2)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state2_logic_op: [features_ffi
+ .features_extended_dynamic_state2_ext
+ .map(|s| s.extended_dynamic_state2_logic_op)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state2_patch_control_points: [features_ffi
+ .features_extended_dynamic_state2_ext
+ .map(|s| s.extended_dynamic_state2_patch_control_points)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state3_alpha_to_coverage_enable: [features_ffi
+ .features_extended_dynamic_state3_ext
+ .map(|s| s.extended_dynamic_state3_alpha_to_coverage_enable)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state3_alpha_to_one_enable: [features_ffi
+ .features_extended_dynamic_state3_ext
+ .map(|s| s.extended_dynamic_state3_alpha_to_one_enable)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state3_color_blend_advanced: [features_ffi
+ .features_extended_dynamic_state3_ext
+ .map(|s| s.extended_dynamic_state3_color_blend_advanced)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state3_color_blend_enable: [features_ffi
+ .features_extended_dynamic_state3_ext
+ .map(|s| s.extended_dynamic_state3_color_blend_enable)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state3_color_blend_equation: [features_ffi
+ .features_extended_dynamic_state3_ext
+ .map(|s| s.extended_dynamic_state3_color_blend_equation)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state3_color_write_mask: [features_ffi
+ .features_extended_dynamic_state3_ext
+ .map(|s| s.extended_dynamic_state3_color_write_mask)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state3_conservative_rasterization_mode: [features_ffi
+ .features_extended_dynamic_state3_ext
+ .map(|s| s.extended_dynamic_state3_conservative_rasterization_mode)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state3_coverage_modulation_mode: [features_ffi
+ .features_extended_dynamic_state3_ext
+ .map(|s| s.extended_dynamic_state3_coverage_modulation_mode)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state3_coverage_modulation_table: [features_ffi
+ .features_extended_dynamic_state3_ext
+ .map(|s| s.extended_dynamic_state3_coverage_modulation_table)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state3_coverage_modulation_table_enable: [features_ffi
+ .features_extended_dynamic_state3_ext
+ .map(|s| s.extended_dynamic_state3_coverage_modulation_table_enable)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state3_coverage_reduction_mode: [features_ffi
+ .features_extended_dynamic_state3_ext
+ .map(|s| s.extended_dynamic_state3_coverage_reduction_mode)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state3_coverage_to_color_enable: [features_ffi
+ .features_extended_dynamic_state3_ext
+ .map(|s| s.extended_dynamic_state3_coverage_to_color_enable)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state3_coverage_to_color_location: [features_ffi
+ .features_extended_dynamic_state3_ext
+ .map(|s| s.extended_dynamic_state3_coverage_to_color_location)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state3_depth_clamp_enable: [features_ffi
+ .features_extended_dynamic_state3_ext
+ .map(|s| s.extended_dynamic_state3_depth_clamp_enable)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state3_depth_clip_enable: [features_ffi
+ .features_extended_dynamic_state3_ext
+ .map(|s| s.extended_dynamic_state3_depth_clip_enable)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state3_depth_clip_negative_one_to_one: [features_ffi
+ .features_extended_dynamic_state3_ext
+ .map(|s| s.extended_dynamic_state3_depth_clip_negative_one_to_one)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state3_extra_primitive_overestimation_size: [features_ffi
+ .features_extended_dynamic_state3_ext
+ .map(|s| s.extended_dynamic_state3_extra_primitive_overestimation_size)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state3_line_rasterization_mode: [features_ffi
+ .features_extended_dynamic_state3_ext
+ .map(|s| s.extended_dynamic_state3_line_rasterization_mode)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state3_line_stipple_enable: [features_ffi
+ .features_extended_dynamic_state3_ext
+ .map(|s| s.extended_dynamic_state3_line_stipple_enable)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state3_logic_op_enable: [features_ffi
+ .features_extended_dynamic_state3_ext
+ .map(|s| s.extended_dynamic_state3_logic_op_enable)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state3_polygon_mode: [features_ffi
+ .features_extended_dynamic_state3_ext
+ .map(|s| s.extended_dynamic_state3_polygon_mode)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state3_provoking_vertex_mode: [features_ffi
+ .features_extended_dynamic_state3_ext
+ .map(|s| s.extended_dynamic_state3_provoking_vertex_mode)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state3_rasterization_samples: [features_ffi
+ .features_extended_dynamic_state3_ext
+ .map(|s| s.extended_dynamic_state3_rasterization_samples)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state3_rasterization_stream: [features_ffi
+ .features_extended_dynamic_state3_ext
+ .map(|s| s.extended_dynamic_state3_rasterization_stream)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state3_representative_fragment_test_enable: [features_ffi
+ .features_extended_dynamic_state3_ext
+ .map(|s| s.extended_dynamic_state3_representative_fragment_test_enable)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state3_sample_locations_enable: [features_ffi
+ .features_extended_dynamic_state3_ext
+ .map(|s| s.extended_dynamic_state3_sample_locations_enable)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state3_sample_mask: [features_ffi
+ .features_extended_dynamic_state3_ext
+ .map(|s| s.extended_dynamic_state3_sample_mask)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state3_shading_rate_image_enable: [features_ffi
+ .features_extended_dynamic_state3_ext
+ .map(|s| s.extended_dynamic_state3_shading_rate_image_enable)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state3_tessellation_domain_origin: [features_ffi
+ .features_extended_dynamic_state3_ext
+ .map(|s| s.extended_dynamic_state3_tessellation_domain_origin)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state3_viewport_swizzle: [features_ffi
+ .features_extended_dynamic_state3_ext
+ .map(|s| s.extended_dynamic_state3_viewport_swizzle)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ extended_dynamic_state3_viewport_w_scaling_enable: [features_ffi
+ .features_extended_dynamic_state3_ext
+ .map(|s| s.extended_dynamic_state3_viewport_w_scaling_enable)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ external_memory_rdma: [features_ffi
+ .features_external_memory_rdma_nv
+ .map(|s| s.external_memory_rdma)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ fill_mode_non_solid: [features_ffi.features_vulkan10.features.fill_mode_non_solid]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ format_a4b4g4r4: [features_ffi
+ .features_4444formats_ext
+ .map(|s| s.format_a4b4g4r4)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ format_a4r4g4b4: [features_ffi
+ .features_4444formats_ext
+ .map(|s| s.format_a4r4g4b4)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ format_rgba10x6_without_y_cb_cr_sampler: [features_ffi
+ .features_rgba10x6_formats_ext
+ .map(|s| s.format_rgba10x6_without_y_cb_cr_sampler)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ fragment_density_map: [features_ffi
+ .features_fragment_density_map_ext
+ .map(|s| s.fragment_density_map)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ fragment_density_map_deferred: [features_ffi
+ .features_fragment_density_map2_ext
+ .map(|s| s.fragment_density_map_deferred)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ fragment_density_map_dynamic: [features_ffi
+ .features_fragment_density_map_ext
+ .map(|s| s.fragment_density_map_dynamic)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ fragment_density_map_non_subsampled_images: [features_ffi
+ .features_fragment_density_map_ext
+ .map(|s| s.fragment_density_map_non_subsampled_images)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ fragment_density_map_offset: [features_ffi
+ .features_fragment_density_map_offset_qcom
+ .map(|s| s.fragment_density_map_offset)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ fragment_shader_barycentric: [features_ffi
+ .features_fragment_shader_barycentric_khr
+ .map(|s| s.fragment_shader_barycentric)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ fragment_shader_pixel_interlock: [features_ffi
+ .features_fragment_shader_interlock_ext
+ .map(|s| s.fragment_shader_pixel_interlock)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ fragment_shader_sample_interlock: [features_ffi
+ .features_fragment_shader_interlock_ext
+ .map(|s| s.fragment_shader_sample_interlock)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ fragment_shader_shading_rate_interlock: [features_ffi
+ .features_fragment_shader_interlock_ext
+ .map(|s| s.fragment_shader_shading_rate_interlock)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ fragment_shading_rate_enums: [features_ffi
+ .features_fragment_shading_rate_enums_nv
+ .map(|s| s.fragment_shading_rate_enums)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ fragment_stores_and_atomics: [features_ffi
+ .features_vulkan10
+ .features
+ .fragment_stores_and_atomics]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ full_draw_index_uint32: [features_ffi
+ .features_vulkan10
+ .features
+ .full_draw_index_uint32]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ geometry_shader: [features_ffi.features_vulkan10.features.geometry_shader]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ geometry_streams: [features_ffi
+ .features_transform_feedback_ext
+ .map(|s| s.geometry_streams)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ global_priority_query: [features_ffi
+ .features_global_priority_query_khr
+ .map(|s| s.global_priority_query)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ graphics_pipeline_library: [features_ffi
+ .features_graphics_pipeline_library_ext
+ .map(|s| s.graphics_pipeline_library)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ host_query_reset: [
+ features_ffi.features_vulkan12.map(|s| s.host_query_reset),
+ features_ffi
+ .features_host_query_reset
+ .map(|s| s.host_query_reset),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ image2_d_view_of3_d: [features_ffi
+ .features_image2_d_view_of3_d_ext
+ .map(|s| s.image2_d_view_of3_d)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ image_compression_control: [features_ffi
+ .features_image_compression_control_ext
+ .map(|s| s.image_compression_control)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ image_compression_control_swapchain: [features_ffi
+ .features_image_compression_control_swapchain_ext
+ .map(|s| s.image_compression_control_swapchain)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ image_cube_array: [features_ffi.features_vulkan10.features.image_cube_array]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ image_footprint: [features_ffi
+ .features_shader_image_footprint_nv
+ .map(|s| s.image_footprint)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ image_view2_d_on3_d_image: [features_ffi
+ .features_portability_subset_khr
+ .map(|s| s.image_view2_d_on3_d_image)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ image_view_format_reinterpretation: [features_ffi
+ .features_portability_subset_khr
+ .map(|s| s.image_view_format_reinterpretation)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ image_view_format_swizzle: [features_ffi
+ .features_portability_subset_khr
+ .map(|s| s.image_view_format_swizzle)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ imageless_framebuffer: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.imageless_framebuffer),
+ features_ffi
+ .features_imageless_framebuffer
+ .map(|s| s.imageless_framebuffer),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ independent_blend: [features_ffi.features_vulkan10.features.independent_blend]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ index_type_uint8: [features_ffi
+ .features_index_type_uint8_ext
+ .map(|s| s.index_type_uint8)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ indirect_copy: [features_ffi
+ .features_copy_memory_indirect_nv
+ .map(|s| s.indirect_copy)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ inherited_conditional_rendering: [features_ffi
+ .features_conditional_rendering_ext
+ .map(|s| s.inherited_conditional_rendering)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ inherited_queries: [features_ffi.features_vulkan10.features.inherited_queries]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ inherited_viewport_scissor2_d: [features_ffi
+ .features_inherited_viewport_scissor_nv
+ .map(|s| s.inherited_viewport_scissor2_d)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ inline_uniform_block: [
+ features_ffi
+ .features_vulkan13
+ .map(|s| s.inline_uniform_block),
+ features_ffi
+ .features_inline_uniform_block
+ .map(|s| s.inline_uniform_block),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ invocation_mask: [features_ffi
+ .features_invocation_mask_huawei
+ .map(|s| s.invocation_mask)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ large_points: [features_ffi.features_vulkan10.features.large_points]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ legacy_dithering: [features_ffi
+ .features_legacy_dithering_ext
+ .map(|s| s.legacy_dithering)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ linear_color_attachment: [features_ffi
+ .features_linear_color_attachment_nv
+ .map(|s| s.linear_color_attachment)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ logic_op: [features_ffi.features_vulkan10.features.logic_op]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ maintenance4: [
+ features_ffi.features_vulkan13.map(|s| s.maintenance4),
+ features_ffi.features_maintenance4.map(|s| s.maintenance4),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ memory_decompression: [features_ffi
+ .features_memory_decompression_nv
+ .map(|s| s.memory_decompression)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ memory_priority: [features_ffi
+ .features_memory_priority_ext
+ .map(|s| s.memory_priority)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ mesh_shader: [
+ features_ffi.features_mesh_shader_ext.map(|s| s.mesh_shader),
+ features_ffi.features_mesh_shader_nv.map(|s| s.mesh_shader),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ mesh_shader_queries: [features_ffi
+ .features_mesh_shader_ext
+ .map(|s| s.mesh_shader_queries)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ micromap: [features_ffi
+ .features_opacity_micromap_ext
+ .map(|s| s.micromap)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ micromap_capture_replay: [features_ffi
+ .features_opacity_micromap_ext
+ .map(|s| s.micromap_capture_replay)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ micromap_host_commands: [features_ffi
+ .features_opacity_micromap_ext
+ .map(|s| s.micromap_host_commands)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ min_lod: [features_ffi
+ .features_image_view_min_lod_ext
+ .map(|s| s.min_lod)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ multi_draw: [features_ffi.features_multi_draw_ext.map(|s| s.multi_draw)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ multi_draw_indirect: [features_ffi.features_vulkan10.features.multi_draw_indirect]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ multi_viewport: [features_ffi.features_vulkan10.features.multi_viewport]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ multisample_array_image: [features_ffi
+ .features_portability_subset_khr
+ .map(|s| s.multisample_array_image)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ multisampled_render_to_single_sampled: [features_ffi
+ .features_multisampled_render_to_single_sampled_ext
+ .map(|s| s.multisampled_render_to_single_sampled)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ multiview: [
+ features_ffi.features_vulkan11.map(|s| s.multiview),
+ features_ffi.features_multiview.map(|s| s.multiview),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ multiview_geometry_shader: [
+ features_ffi
+ .features_vulkan11
+ .map(|s| s.multiview_geometry_shader),
+ features_ffi
+ .features_multiview
+ .map(|s| s.multiview_geometry_shader),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ multiview_mesh_shader: [features_ffi
+ .features_mesh_shader_ext
+ .map(|s| s.multiview_mesh_shader)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ multiview_per_view_viewports: [features_ffi
+ .features_multiview_per_view_viewports_qcom
+ .map(|s| s.multiview_per_view_viewports)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ multiview_tessellation_shader: [
+ features_ffi
+ .features_vulkan11
+ .map(|s| s.multiview_tessellation_shader),
+ features_ffi
+ .features_multiview
+ .map(|s| s.multiview_tessellation_shader),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ mutable_comparison_samplers: [features_ffi
+ .features_portability_subset_khr
+ .map(|s| s.mutable_comparison_samplers)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ mutable_descriptor_type: [features_ffi
+ .features_mutable_descriptor_type_ext
+ .map(|s| s.mutable_descriptor_type)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ no_invocation_fragment_shading_rates: [features_ffi
+ .features_fragment_shading_rate_enums_nv
+ .map(|s| s.no_invocation_fragment_shading_rates)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ non_seamless_cube_map: [features_ffi
+ .features_non_seamless_cube_map_ext
+ .map(|s| s.non_seamless_cube_map)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ null_descriptor: [features_ffi
+ .features_robustness2_ext
+ .map(|s| s.null_descriptor)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ occlusion_query_precise: [features_ffi
+ .features_vulkan10
+ .features
+ .occlusion_query_precise]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ optical_flow: [features_ffi
+ .features_optical_flow_nv
+ .map(|s| s.optical_flow)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ pageable_device_local_memory: [features_ffi
+ .features_pageable_device_local_memory_ext
+ .map(|s| s.pageable_device_local_memory)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ performance_counter_multiple_query_pools: [features_ffi
+ .features_performance_query_khr
+ .map(|s| s.performance_counter_multiple_query_pools)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ performance_counter_query_pools: [features_ffi
+ .features_performance_query_khr
+ .map(|s| s.performance_counter_query_pools)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ pipeline_creation_cache_control: [
+ features_ffi
+ .features_vulkan13
+ .map(|s| s.pipeline_creation_cache_control),
+ features_ffi
+ .features_pipeline_creation_cache_control
+ .map(|s| s.pipeline_creation_cache_control),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ pipeline_executable_info: [features_ffi
+ .features_pipeline_executable_properties_khr
+ .map(|s| s.pipeline_executable_info)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ pipeline_fragment_shading_rate: [features_ffi
+ .features_fragment_shading_rate_khr
+ .map(|s| s.pipeline_fragment_shading_rate)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ pipeline_properties_identifier: [features_ffi
+ .features_pipeline_properties_ext
+ .map(|s| s.pipeline_properties_identifier)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ pipeline_protected_access: [features_ffi
+ .features_pipeline_protected_access_ext
+ .map(|s| s.pipeline_protected_access)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ pipeline_robustness: [features_ffi
+ .features_pipeline_robustness_ext
+ .map(|s| s.pipeline_robustness)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ pipeline_statistics_query: [features_ffi
+ .features_vulkan10
+ .features
+ .pipeline_statistics_query]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ point_polygons: [features_ffi
+ .features_portability_subset_khr
+ .map(|s| s.point_polygons)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ present_barrier: [features_ffi
+ .features_present_barrier_nv
+ .map(|s| s.present_barrier)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ present_id: [features_ffi.features_present_id_khr.map(|s| s.present_id)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ present_wait: [features_ffi
+ .features_present_wait_khr
+ .map(|s| s.present_wait)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ primitive_fragment_shading_rate: [features_ffi
+ .features_fragment_shading_rate_khr
+ .map(|s| s.primitive_fragment_shading_rate)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ primitive_fragment_shading_rate_mesh_shader: [features_ffi
+ .features_mesh_shader_ext
+ .map(|s| s.primitive_fragment_shading_rate_mesh_shader)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ primitive_topology_list_restart: [features_ffi
+ .features_primitive_topology_list_restart_ext
+ .map(|s| s.primitive_topology_list_restart)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ primitive_topology_patch_list_restart: [features_ffi
+ .features_primitive_topology_list_restart_ext
+ .map(|s| s.primitive_topology_patch_list_restart)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ primitives_generated_query: [features_ffi
+ .features_primitives_generated_query_ext
+ .map(|s| s.primitives_generated_query)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ primitives_generated_query_with_non_zero_streams: [features_ffi
+ .features_primitives_generated_query_ext
+ .map(|s| s.primitives_generated_query_with_non_zero_streams)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ primitives_generated_query_with_rasterizer_discard: [features_ffi
+ .features_primitives_generated_query_ext
+ .map(|s| s.primitives_generated_query_with_rasterizer_discard)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ private_data: [
+ features_ffi.features_vulkan13.map(|s| s.private_data),
+ features_ffi.features_private_data.map(|s| s.private_data),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ protected_memory: [
+ features_ffi.features_vulkan11.map(|s| s.protected_memory),
+ features_ffi
+ .features_protected_memory
+ .map(|s| s.protected_memory),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ provoking_vertex_last: [features_ffi
+ .features_provoking_vertex_ext
+ .map(|s| s.provoking_vertex_last)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ rasterization_order_color_attachment_access: [features_ffi
+ .features_rasterization_order_attachment_access_ext
+ .map(|s| s.rasterization_order_color_attachment_access)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ rasterization_order_depth_attachment_access: [features_ffi
+ .features_rasterization_order_attachment_access_ext
+ .map(|s| s.rasterization_order_depth_attachment_access)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ rasterization_order_stencil_attachment_access: [features_ffi
+ .features_rasterization_order_attachment_access_ext
+ .map(|s| s.rasterization_order_stencil_attachment_access)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ ray_query: [features_ffi.features_ray_query_khr.map(|s| s.ray_query)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ ray_tracing_invocation_reorder: [features_ffi
+ .features_ray_tracing_invocation_reorder_nv
+ .map(|s| s.ray_tracing_invocation_reorder)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ ray_tracing_maintenance1: [features_ffi
+ .features_ray_tracing_maintenance1_khr
+ .map(|s| s.ray_tracing_maintenance1)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ ray_tracing_motion_blur: [features_ffi
+ .features_ray_tracing_motion_blur_nv
+ .map(|s| s.ray_tracing_motion_blur)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ ray_tracing_motion_blur_pipeline_trace_rays_indirect: [features_ffi
+ .features_ray_tracing_motion_blur_nv
+ .map(|s| s.ray_tracing_motion_blur_pipeline_trace_rays_indirect)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ ray_tracing_pipeline: [features_ffi
+ .features_ray_tracing_pipeline_khr
+ .map(|s| s.ray_tracing_pipeline)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ ray_tracing_pipeline_shader_group_handle_capture_replay: [features_ffi
+ .features_ray_tracing_pipeline_khr
+ .map(|s| s.ray_tracing_pipeline_shader_group_handle_capture_replay)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ ray_tracing_pipeline_shader_group_handle_capture_replay_mixed: [features_ffi
+ .features_ray_tracing_pipeline_khr
+ .map(|s| s.ray_tracing_pipeline_shader_group_handle_capture_replay_mixed)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ ray_tracing_pipeline_trace_rays_indirect: [features_ffi
+ .features_ray_tracing_pipeline_khr
+ .map(|s| s.ray_tracing_pipeline_trace_rays_indirect)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ ray_tracing_pipeline_trace_rays_indirect2: [features_ffi
+ .features_ray_tracing_maintenance1_khr
+ .map(|s| s.ray_tracing_pipeline_trace_rays_indirect2)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ ray_traversal_primitive_culling: [features_ffi
+ .features_ray_tracing_pipeline_khr
+ .map(|s| s.ray_traversal_primitive_culling)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ rectangular_lines: [features_ffi
+ .features_line_rasterization_ext
+ .map(|s| s.rectangular_lines)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ report_address_binding: [features_ffi
+ .features_address_binding_report_ext
+ .map(|s| s.report_address_binding)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ representative_fragment_test: [features_ffi
+ .features_representative_fragment_test_nv
+ .map(|s| s.representative_fragment_test)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ robust_buffer_access: [features_ffi.features_vulkan10.features.robust_buffer_access]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ robust_buffer_access2: [features_ffi
+ .features_robustness2_ext
+ .map(|s| s.robust_buffer_access2)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ robust_image_access: [
+ features_ffi
+ .features_vulkan13
+ .map(|s| s.robust_image_access),
+ features_ffi
+ .features_image_robustness
+ .map(|s| s.robust_image_access),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ robust_image_access2: [features_ffi
+ .features_robustness2_ext
+ .map(|s| s.robust_image_access2)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ runtime_descriptor_array: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.runtime_descriptor_array),
+ features_ffi
+ .features_descriptor_indexing
+ .map(|s| s.runtime_descriptor_array),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ sample_rate_shading: [features_ffi.features_vulkan10.features.sample_rate_shading]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ sampler2_d_view_of3_d: [features_ffi
+ .features_image2_d_view_of3_d_ext
+ .map(|s| s.sampler2_d_view_of3_d)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ sampler_anisotropy: [features_ffi.features_vulkan10.features.sampler_anisotropy]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ sampler_filter_minmax: [features_ffi
+ .features_vulkan12
+ .map(|s| s.sampler_filter_minmax)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ sampler_mip_lod_bias: [features_ffi
+ .features_portability_subset_khr
+ .map(|s| s.sampler_mip_lod_bias)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ sampler_mirror_clamp_to_edge: [features_ffi
+ .features_vulkan12
+ .map(|s| s.sampler_mirror_clamp_to_edge)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ sampler_ycbcr_conversion: [
+ features_ffi
+ .features_vulkan11
+ .map(|s| s.sampler_ycbcr_conversion),
+ features_ffi
+ .features_sampler_ycbcr_conversion
+ .map(|s| s.sampler_ycbcr_conversion),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ scalar_block_layout: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.scalar_block_layout),
+ features_ffi
+ .features_scalar_block_layout
+ .map(|s| s.scalar_block_layout),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ separate_depth_stencil_layouts: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.separate_depth_stencil_layouts),
+ features_ffi
+ .features_separate_depth_stencil_layouts
+ .map(|s| s.separate_depth_stencil_layouts),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ separate_stencil_mask_ref: [features_ffi
+ .features_portability_subset_khr
+ .map(|s| s.separate_stencil_mask_ref)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_buffer_float16_atomic_add: [features_ffi
+ .features_shader_atomic_float2_ext
+ .map(|s| s.shader_buffer_float16_atomic_add)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_buffer_float16_atomic_min_max: [features_ffi
+ .features_shader_atomic_float2_ext
+ .map(|s| s.shader_buffer_float16_atomic_min_max)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_buffer_float16_atomics: [features_ffi
+ .features_shader_atomic_float2_ext
+ .map(|s| s.shader_buffer_float16_atomics)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_buffer_float32_atomic_add: [features_ffi
+ .features_shader_atomic_float_ext
+ .map(|s| s.shader_buffer_float32_atomic_add)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_buffer_float32_atomic_min_max: [features_ffi
+ .features_shader_atomic_float2_ext
+ .map(|s| s.shader_buffer_float32_atomic_min_max)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_buffer_float32_atomics: [features_ffi
+ .features_shader_atomic_float_ext
+ .map(|s| s.shader_buffer_float32_atomics)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_buffer_float64_atomic_add: [features_ffi
+ .features_shader_atomic_float_ext
+ .map(|s| s.shader_buffer_float64_atomic_add)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_buffer_float64_atomic_min_max: [features_ffi
+ .features_shader_atomic_float2_ext
+ .map(|s| s.shader_buffer_float64_atomic_min_max)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_buffer_float64_atomics: [features_ffi
+ .features_shader_atomic_float_ext
+ .map(|s| s.shader_buffer_float64_atomics)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_buffer_int64_atomics: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.shader_buffer_int64_atomics),
+ features_ffi
+ .features_shader_atomic_int64
+ .map(|s| s.shader_buffer_int64_atomics),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_clip_distance: [features_ffi.features_vulkan10.features.shader_clip_distance]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_core_builtins: [features_ffi
+ .features_shader_core_builtins_arm
+ .map(|s| s.shader_core_builtins)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_cull_distance: [features_ffi.features_vulkan10.features.shader_cull_distance]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_demote_to_helper_invocation: [
+ features_ffi
+ .features_vulkan13
+ .map(|s| s.shader_demote_to_helper_invocation),
+ features_ffi
+ .features_shader_demote_to_helper_invocation
+ .map(|s| s.shader_demote_to_helper_invocation),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_device_clock: [features_ffi
+ .features_shader_clock_khr
+ .map(|s| s.shader_device_clock)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_draw_parameters: [
+ features_ffi
+ .features_vulkan11
+ .map(|s| s.shader_draw_parameters),
+ features_ffi
+ .features_shader_draw_parameters
+ .map(|s| s.shader_draw_parameters),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_early_and_late_fragment_tests: [features_ffi
+ .features_shader_early_and_late_fragment_tests_amd
+ .map(|s| s.shader_early_and_late_fragment_tests)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_float16: [
+ features_ffi.features_vulkan12.map(|s| s.shader_float16),
+ features_ffi
+ .features_shader_float16_int8
+ .map(|s| s.shader_float16),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_float64: [features_ffi.features_vulkan10.features.shader_float64]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_image_float32_atomic_add: [features_ffi
+ .features_shader_atomic_float_ext
+ .map(|s| s.shader_image_float32_atomic_add)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_image_float32_atomic_min_max: [features_ffi
+ .features_shader_atomic_float2_ext
+ .map(|s| s.shader_image_float32_atomic_min_max)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_image_float32_atomics: [features_ffi
+ .features_shader_atomic_float_ext
+ .map(|s| s.shader_image_float32_atomics)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_image_gather_extended: [features_ffi
+ .features_vulkan10
+ .features
+ .shader_image_gather_extended]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_image_int64_atomics: [features_ffi
+ .features_shader_image_atomic_int64_ext
+ .map(|s| s.shader_image_int64_atomics)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_input_attachment_array_dynamic_indexing: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.shader_input_attachment_array_dynamic_indexing),
+ features_ffi
+ .features_descriptor_indexing
+ .map(|s| s.shader_input_attachment_array_dynamic_indexing),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_input_attachment_array_non_uniform_indexing: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.shader_input_attachment_array_non_uniform_indexing),
+ features_ffi
+ .features_descriptor_indexing
+ .map(|s| s.shader_input_attachment_array_non_uniform_indexing),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_int16: [features_ffi.features_vulkan10.features.shader_int16]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_int64: [features_ffi.features_vulkan10.features.shader_int64]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_int8: [
+ features_ffi.features_vulkan12.map(|s| s.shader_int8),
+ features_ffi
+ .features_shader_float16_int8
+ .map(|s| s.shader_int8),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_integer_dot_product: [
+ features_ffi
+ .features_vulkan13
+ .map(|s| s.shader_integer_dot_product),
+ features_ffi
+ .features_shader_integer_dot_product
+ .map(|s| s.shader_integer_dot_product),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_integer_functions2: [features_ffi
+ .features_shader_integer_functions2_intel
+ .map(|s| s.shader_integer_functions2)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_module_identifier: [features_ffi
+ .features_shader_module_identifier_ext
+ .map(|s| s.shader_module_identifier)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_output_layer: [features_ffi
+ .features_vulkan12
+ .map(|s| s.shader_output_layer)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_output_viewport_index: [features_ffi
+ .features_vulkan12
+ .map(|s| s.shader_output_viewport_index)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_resource_min_lod: [features_ffi
+ .features_vulkan10
+ .features
+ .shader_resource_min_lod]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_resource_residency: [features_ffi
+ .features_vulkan10
+ .features
+ .shader_resource_residency]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_sample_rate_interpolation_functions: [features_ffi
+ .features_portability_subset_khr
+ .map(|s| s.shader_sample_rate_interpolation_functions)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_sampled_image_array_dynamic_indexing: [features_ffi
+ .features_vulkan10
+ .features
+ .shader_sampled_image_array_dynamic_indexing]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_sampled_image_array_non_uniform_indexing: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.shader_sampled_image_array_non_uniform_indexing),
+ features_ffi
+ .features_descriptor_indexing
+ .map(|s| s.shader_sampled_image_array_non_uniform_indexing),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_shared_float16_atomic_add: [features_ffi
+ .features_shader_atomic_float2_ext
+ .map(|s| s.shader_shared_float16_atomic_add)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_shared_float16_atomic_min_max: [features_ffi
+ .features_shader_atomic_float2_ext
+ .map(|s| s.shader_shared_float16_atomic_min_max)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_shared_float16_atomics: [features_ffi
+ .features_shader_atomic_float2_ext
+ .map(|s| s.shader_shared_float16_atomics)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_shared_float32_atomic_add: [features_ffi
+ .features_shader_atomic_float_ext
+ .map(|s| s.shader_shared_float32_atomic_add)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_shared_float32_atomic_min_max: [features_ffi
+ .features_shader_atomic_float2_ext
+ .map(|s| s.shader_shared_float32_atomic_min_max)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_shared_float32_atomics: [features_ffi
+ .features_shader_atomic_float_ext
+ .map(|s| s.shader_shared_float32_atomics)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_shared_float64_atomic_add: [features_ffi
+ .features_shader_atomic_float_ext
+ .map(|s| s.shader_shared_float64_atomic_add)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_shared_float64_atomic_min_max: [features_ffi
+ .features_shader_atomic_float2_ext
+ .map(|s| s.shader_shared_float64_atomic_min_max)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_shared_float64_atomics: [features_ffi
+ .features_shader_atomic_float_ext
+ .map(|s| s.shader_shared_float64_atomics)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_shared_int64_atomics: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.shader_shared_int64_atomics),
+ features_ffi
+ .features_shader_atomic_int64
+ .map(|s| s.shader_shared_int64_atomics),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_sm_builtins: [features_ffi
+ .features_shader_sm_builtins_nv
+ .map(|s| s.shader_sm_builtins)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_storage_buffer_array_dynamic_indexing: [features_ffi
+ .features_vulkan10
+ .features
+ .shader_storage_buffer_array_dynamic_indexing]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_storage_buffer_array_non_uniform_indexing: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.shader_storage_buffer_array_non_uniform_indexing),
+ features_ffi
+ .features_descriptor_indexing
+ .map(|s| s.shader_storage_buffer_array_non_uniform_indexing),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_storage_image_array_dynamic_indexing: [features_ffi
+ .features_vulkan10
+ .features
+ .shader_storage_image_array_dynamic_indexing]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_storage_image_array_non_uniform_indexing: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.shader_storage_image_array_non_uniform_indexing),
+ features_ffi
+ .features_descriptor_indexing
+ .map(|s| s.shader_storage_image_array_non_uniform_indexing),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_storage_image_extended_formats: [features_ffi
+ .features_vulkan10
+ .features
+ .shader_storage_image_extended_formats]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_storage_image_multisample: [features_ffi
+ .features_vulkan10
+ .features
+ .shader_storage_image_multisample]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_storage_image_read_without_format: [features_ffi
+ .features_vulkan10
+ .features
+ .shader_storage_image_read_without_format]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_storage_image_write_without_format: [features_ffi
+ .features_vulkan10
+ .features
+ .shader_storage_image_write_without_format]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_storage_texel_buffer_array_dynamic_indexing: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.shader_storage_texel_buffer_array_dynamic_indexing),
+ features_ffi
+ .features_descriptor_indexing
+ .map(|s| s.shader_storage_texel_buffer_array_dynamic_indexing),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_storage_texel_buffer_array_non_uniform_indexing: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.shader_storage_texel_buffer_array_non_uniform_indexing),
+ features_ffi
+ .features_descriptor_indexing
+ .map(|s| s.shader_storage_texel_buffer_array_non_uniform_indexing),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_subgroup_clock: [features_ffi
+ .features_shader_clock_khr
+ .map(|s| s.shader_subgroup_clock)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_subgroup_extended_types: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.shader_subgroup_extended_types),
+ features_ffi
+ .features_shader_subgroup_extended_types
+ .map(|s| s.shader_subgroup_extended_types),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_subgroup_uniform_control_flow: [features_ffi
+ .features_shader_subgroup_uniform_control_flow_khr
+ .map(|s| s.shader_subgroup_uniform_control_flow)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_terminate_invocation: [
+ features_ffi
+ .features_vulkan13
+ .map(|s| s.shader_terminate_invocation),
+ features_ffi
+ .features_shader_terminate_invocation
+ .map(|s| s.shader_terminate_invocation),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_tessellation_and_geometry_point_size: [features_ffi
+ .features_vulkan10
+ .features
+ .shader_tessellation_and_geometry_point_size]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_uniform_buffer_array_dynamic_indexing: [features_ffi
+ .features_vulkan10
+ .features
+ .shader_uniform_buffer_array_dynamic_indexing]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_uniform_buffer_array_non_uniform_indexing: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.shader_uniform_buffer_array_non_uniform_indexing),
+ features_ffi
+ .features_descriptor_indexing
+ .map(|s| s.shader_uniform_buffer_array_non_uniform_indexing),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_uniform_texel_buffer_array_dynamic_indexing: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.shader_uniform_texel_buffer_array_dynamic_indexing),
+ features_ffi
+ .features_descriptor_indexing
+ .map(|s| s.shader_uniform_texel_buffer_array_dynamic_indexing),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_uniform_texel_buffer_array_non_uniform_indexing: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.shader_uniform_texel_buffer_array_non_uniform_indexing),
+ features_ffi
+ .features_descriptor_indexing
+ .map(|s| s.shader_uniform_texel_buffer_array_non_uniform_indexing),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shader_zero_initialize_workgroup_memory: [
+ features_ffi
+ .features_vulkan13
+ .map(|s| s.shader_zero_initialize_workgroup_memory),
+ features_ffi
+ .features_zero_initialize_workgroup_memory
+ .map(|s| s.shader_zero_initialize_workgroup_memory),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shading_rate_coarse_sample_order: [features_ffi
+ .features_shading_rate_image_nv
+ .map(|s| s.shading_rate_coarse_sample_order)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ shading_rate_image: [features_ffi
+ .features_shading_rate_image_nv
+ .map(|s| s.shading_rate_image)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ smooth_lines: [features_ffi
+ .features_line_rasterization_ext
+ .map(|s| s.smooth_lines)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ sparse_binding: [features_ffi.features_vulkan10.features.sparse_binding]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ sparse_image_float32_atomic_add: [features_ffi
+ .features_shader_atomic_float_ext
+ .map(|s| s.sparse_image_float32_atomic_add)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ sparse_image_float32_atomic_min_max: [features_ffi
+ .features_shader_atomic_float2_ext
+ .map(|s| s.sparse_image_float32_atomic_min_max)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ sparse_image_float32_atomics: [features_ffi
+ .features_shader_atomic_float_ext
+ .map(|s| s.sparse_image_float32_atomics)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ sparse_image_int64_atomics: [features_ffi
+ .features_shader_image_atomic_int64_ext
+ .map(|s| s.sparse_image_int64_atomics)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ sparse_residency16_samples: [features_ffi
+ .features_vulkan10
+ .features
+ .sparse_residency16_samples]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ sparse_residency2_samples: [features_ffi
+ .features_vulkan10
+ .features
+ .sparse_residency2_samples]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ sparse_residency4_samples: [features_ffi
+ .features_vulkan10
+ .features
+ .sparse_residency4_samples]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ sparse_residency8_samples: [features_ffi
+ .features_vulkan10
+ .features
+ .sparse_residency8_samples]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ sparse_residency_aliased: [features_ffi
+ .features_vulkan10
+ .features
+ .sparse_residency_aliased]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ sparse_residency_buffer: [features_ffi
+ .features_vulkan10
+ .features
+ .sparse_residency_buffer]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ sparse_residency_image2_d: [features_ffi
+ .features_vulkan10
+ .features
+ .sparse_residency_image2_d]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ sparse_residency_image3_d: [features_ffi
+ .features_vulkan10
+ .features
+ .sparse_residency_image3_d]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ stippled_bresenham_lines: [features_ffi
+ .features_line_rasterization_ext
+ .map(|s| s.stippled_bresenham_lines)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ stippled_rectangular_lines: [features_ffi
+ .features_line_rasterization_ext
+ .map(|s| s.stippled_rectangular_lines)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ stippled_smooth_lines: [features_ffi
+ .features_line_rasterization_ext
+ .map(|s| s.stippled_smooth_lines)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ storage_buffer16_bit_access: [
+ features_ffi
+ .features_vulkan11
+ .map(|s| s.storage_buffer16_bit_access),
+ features_ffi
+ .features_16bit_storage
+ .map(|s| s.storage_buffer16_bit_access),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ storage_buffer8_bit_access: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.storage_buffer8_bit_access),
+ features_ffi
+ .features_8bit_storage
+ .map(|s| s.storage_buffer8_bit_access),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ storage_input_output16: [
+ features_ffi
+ .features_vulkan11
+ .map(|s| s.storage_input_output16),
+ features_ffi
+ .features_16bit_storage
+ .map(|s| s.storage_input_output16),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ storage_push_constant16: [
+ features_ffi
+ .features_vulkan11
+ .map(|s| s.storage_push_constant16),
+ features_ffi
+ .features_16bit_storage
+ .map(|s| s.storage_push_constant16),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ storage_push_constant8: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.storage_push_constant8),
+ features_ffi
+ .features_8bit_storage
+ .map(|s| s.storage_push_constant8),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ subgroup_broadcast_dynamic_id: [features_ffi
+ .features_vulkan12
+ .map(|s| s.subgroup_broadcast_dynamic_id)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ subgroup_size_control: [
+ features_ffi
+ .features_vulkan13
+ .map(|s| s.subgroup_size_control),
+ features_ffi
+ .features_subgroup_size_control
+ .map(|s| s.subgroup_size_control),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ subpass_merge_feedback: [features_ffi
+ .features_subpass_merge_feedback_ext
+ .map(|s| s.subpass_merge_feedback)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ subpass_shading: [features_ffi
+ .features_subpass_shading_huawei
+ .map(|s| s.subpass_shading)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ supersample_fragment_shading_rates: [features_ffi
+ .features_fragment_shading_rate_enums_nv
+ .map(|s| s.supersample_fragment_shading_rates)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ swapchain_maintenance1: [features_ffi
+ .features_swapchain_maintenance1_ext
+ .map(|s| s.swapchain_maintenance1)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ synchronization2: [
+ features_ffi.features_vulkan13.map(|s| s.synchronization2),
+ features_ffi
+ .features_synchronization2
+ .map(|s| s.synchronization2),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ task_shader: [
+ features_ffi.features_mesh_shader_ext.map(|s| s.task_shader),
+ features_ffi.features_mesh_shader_nv.map(|s| s.task_shader),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ tessellation_isolines: [features_ffi
+ .features_portability_subset_khr
+ .map(|s| s.tessellation_isolines)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ tessellation_point_mode: [features_ffi
+ .features_portability_subset_khr
+ .map(|s| s.tessellation_point_mode)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ tessellation_shader: [features_ffi.features_vulkan10.features.tessellation_shader]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ texel_buffer_alignment: [features_ffi
+ .features_texel_buffer_alignment_ext
+ .map(|s| s.texel_buffer_alignment)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ texture_block_match: [features_ffi
+ .features_image_processing_qcom
+ .map(|s| s.texture_block_match)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ texture_box_filter: [features_ffi
+ .features_image_processing_qcom
+ .map(|s| s.texture_box_filter)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ texture_compression_astc_hdr: [
+ features_ffi
+ .features_vulkan13
+ .map(|s| s.texture_compression_astc_hdr),
+ features_ffi
+ .features_texture_compression_astchdr
+ .map(|s| s.texture_compression_astc_hdr),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ texture_compression_astc_ldr: [features_ffi
+ .features_vulkan10
+ .features
+ .texture_compression_astc_ldr]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ texture_compression_bc: [features_ffi
+ .features_vulkan10
+ .features
+ .texture_compression_bc]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ texture_compression_etc2: [features_ffi
+ .features_vulkan10
+ .features
+ .texture_compression_etc2]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ texture_sample_weighted: [features_ffi
+ .features_image_processing_qcom
+ .map(|s| s.texture_sample_weighted)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ tile_properties: [features_ffi
+ .features_tile_properties_qcom
+ .map(|s| s.tile_properties)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ timeline_semaphore: [
+ features_ffi.features_vulkan12.map(|s| s.timeline_semaphore),
+ features_ffi
+ .features_timeline_semaphore
+ .map(|s| s.timeline_semaphore),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ transform_feedback: [features_ffi
+ .features_transform_feedback_ext
+ .map(|s| s.transform_feedback)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ transform_feedback_preserves_provoking_vertex: [features_ffi
+ .features_provoking_vertex_ext
+ .map(|s| s.transform_feedback_preserves_provoking_vertex)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ triangle_fans: [features_ffi
+ .features_portability_subset_khr
+ .map(|s| s.triangle_fans)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ uniform_and_storage_buffer16_bit_access: [
+ features_ffi
+ .features_vulkan11
+ .map(|s| s.uniform_and_storage_buffer16_bit_access),
+ features_ffi
+ .features_16bit_storage
+ .map(|s| s.uniform_and_storage_buffer16_bit_access),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ uniform_and_storage_buffer8_bit_access: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.uniform_and_storage_buffer8_bit_access),
+ features_ffi
+ .features_8bit_storage
+ .map(|s| s.uniform_and_storage_buffer8_bit_access),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ uniform_buffer_standard_layout: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.uniform_buffer_standard_layout),
+ features_ffi
+ .features_uniform_buffer_standard_layout
+ .map(|s| s.uniform_buffer_standard_layout),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ variable_multisample_rate: [features_ffi
+ .features_vulkan10
+ .features
+ .variable_multisample_rate]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ variable_pointers: [
+ features_ffi.features_vulkan11.map(|s| s.variable_pointers),
+ features_ffi
+ .features_variable_pointers
+ .map(|s| s.variable_pointers),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ variable_pointers_storage_buffer: [
+ features_ffi
+ .features_vulkan11
+ .map(|s| s.variable_pointers_storage_buffer),
+ features_ffi
+ .features_variable_pointers
+ .map(|s| s.variable_pointers_storage_buffer),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ vertex_attribute_access_beyond_stride: [features_ffi
+ .features_portability_subset_khr
+ .map(|s| s.vertex_attribute_access_beyond_stride)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ vertex_attribute_instance_rate_divisor: [features_ffi
+ .features_vertex_attribute_divisor_ext
+ .map(|s| s.vertex_attribute_instance_rate_divisor)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ vertex_attribute_instance_rate_zero_divisor: [features_ffi
+ .features_vertex_attribute_divisor_ext
+ .map(|s| s.vertex_attribute_instance_rate_zero_divisor)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ vertex_input_dynamic_state: [features_ffi
+ .features_vertex_input_dynamic_state_ext
+ .map(|s| s.vertex_input_dynamic_state)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ vertex_pipeline_stores_and_atomics: [features_ffi
+ .features_vulkan10
+ .features
+ .vertex_pipeline_stores_and_atomics]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ vulkan_memory_model: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.vulkan_memory_model),
+ features_ffi
+ .features_vulkan_memory_model
+ .map(|s| s.vulkan_memory_model),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ vulkan_memory_model_availability_visibility_chains: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.vulkan_memory_model_availability_visibility_chains),
+ features_ffi
+ .features_vulkan_memory_model
+ .map(|s| s.vulkan_memory_model_availability_visibility_chains),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ vulkan_memory_model_device_scope: [
+ features_ffi
+ .features_vulkan12
+ .map(|s| s.vulkan_memory_model_device_scope),
+ features_ffi
+ .features_vulkan_memory_model
+ .map(|s| s.vulkan_memory_model_device_scope),
+ ]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ wide_lines: [features_ffi.features_vulkan10.features.wide_lines]
+ .into_iter()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ workgroup_memory_explicit_layout: [features_ffi
+ .features_workgroup_memory_explicit_layout_khr
+ .map(|s| s.workgroup_memory_explicit_layout)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ workgroup_memory_explicit_layout16_bit_access: [features_ffi
+ .features_workgroup_memory_explicit_layout_khr
+ .map(|s| s.workgroup_memory_explicit_layout16_bit_access)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ workgroup_memory_explicit_layout8_bit_access: [features_ffi
+ .features_workgroup_memory_explicit_layout_khr
+ .map(|s| s.workgroup_memory_explicit_layout8_bit_access)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ workgroup_memory_explicit_layout_scalar_block_layout: [features_ffi
+ .features_workgroup_memory_explicit_layout_khr
+ .map(|s| s.workgroup_memory_explicit_layout_scalar_block_layout)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ ycbcr2plane444_formats: [features_ffi
+ .features_ycbcr2_plane444_formats_ext
+ .map(|s| s.ycbcr2plane444_formats)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ ycbcr_image_arrays: [features_ffi
+ .features_ycbcr_image_arrays_ext
+ .map(|s| s.ycbcr_image_arrays)]
+ .into_iter()
+ .flatten()
+ .next()
+ .unwrap_or(0)
+ != 0,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+impl IntoIterator for Features {
+ type Item = (&'static str, bool);
+ type IntoIter = std::array::IntoIter<Self::Item, 363usize>;
+ #[inline]
+ fn into_iter(self) -> Self::IntoIter {
+ [
+ ("accelerationStructure", self.acceleration_structure),
+ (
+ "accelerationStructureCaptureReplay",
+ self.acceleration_structure_capture_replay,
+ ),
+ (
+ "accelerationStructureHostCommands",
+ self.acceleration_structure_host_commands,
+ ),
+ (
+ "accelerationStructureIndirectBuild",
+ self.acceleration_structure_indirect_build,
+ ),
+ (
+ "advancedBlendCoherentOperations",
+ self.advanced_blend_coherent_operations,
+ ),
+ ("alphaToOne", self.alpha_to_one),
+ ("amigoProfiling", self.amigo_profiling),
+ (
+ "attachmentFeedbackLoopLayout",
+ self.attachment_feedback_loop_layout,
+ ),
+ (
+ "attachmentFragmentShadingRate",
+ self.attachment_fragment_shading_rate,
+ ),
+ ("borderColorSwizzle", self.border_color_swizzle),
+ (
+ "borderColorSwizzleFromImage",
+ self.border_color_swizzle_from_image,
+ ),
+ ("bresenhamLines", self.bresenham_lines),
+ ("bufferDeviceAddress", self.buffer_device_address),
+ (
+ "bufferDeviceAddressCaptureReplay",
+ self.buffer_device_address_capture_replay,
+ ),
+ (
+ "bufferDeviceAddressMultiDevice",
+ self.buffer_device_address_multi_device,
+ ),
+ ("colorWriteEnable", self.color_write_enable),
+ (
+ "computeDerivativeGroupLinear",
+ self.compute_derivative_group_linear,
+ ),
+ (
+ "computeDerivativeGroupQuads",
+ self.compute_derivative_group_quads,
+ ),
+ ("computeFullSubgroups", self.compute_full_subgroups),
+ ("conditionalRendering", self.conditional_rendering),
+ (
+ "constantAlphaColorBlendFactors",
+ self.constant_alpha_color_blend_factors,
+ ),
+ ("cooperativeMatrix", self.cooperative_matrix),
+ (
+ "cooperativeMatrixRobustBufferAccess",
+ self.cooperative_matrix_robust_buffer_access,
+ ),
+ ("cornerSampledImage", self.corner_sampled_image),
+ ("coverageReductionMode", self.coverage_reduction_mode),
+ (
+ "customBorderColorWithoutFormat",
+ self.custom_border_color_without_format,
+ ),
+ ("customBorderColors", self.custom_border_colors),
+ ("decodeModeSharedExponent", self.decode_mode_shared_exponent),
+ (
+ "dedicatedAllocationImageAliasing",
+ self.dedicated_allocation_image_aliasing,
+ ),
+ ("depthBiasClamp", self.depth_bias_clamp),
+ ("depthBounds", self.depth_bounds),
+ ("depthClamp", self.depth_clamp),
+ ("depthClampZeroOne", self.depth_clamp_zero_one),
+ ("depthClipControl", self.depth_clip_control),
+ ("depthClipEnable", self.depth_clip_enable),
+ (
+ "descriptorBindingAccelerationStructureUpdateAfterBind",
+ self.descriptor_binding_acceleration_structure_update_after_bind,
+ ),
+ (
+ "descriptorBindingInlineUniformBlockUpdateAfterBind",
+ self.descriptor_binding_inline_uniform_block_update_after_bind,
+ ),
+ (
+ "descriptorBindingPartiallyBound",
+ self.descriptor_binding_partially_bound,
+ ),
+ (
+ "descriptorBindingSampledImageUpdateAfterBind",
+ self.descriptor_binding_sampled_image_update_after_bind,
+ ),
+ (
+ "descriptorBindingStorageBufferUpdateAfterBind",
+ self.descriptor_binding_storage_buffer_update_after_bind,
+ ),
+ (
+ "descriptorBindingStorageImageUpdateAfterBind",
+ self.descriptor_binding_storage_image_update_after_bind,
+ ),
+ (
+ "descriptorBindingStorageTexelBufferUpdateAfterBind",
+ self.descriptor_binding_storage_texel_buffer_update_after_bind,
+ ),
+ (
+ "descriptorBindingUniformBufferUpdateAfterBind",
+ self.descriptor_binding_uniform_buffer_update_after_bind,
+ ),
+ (
+ "descriptorBindingUniformTexelBufferUpdateAfterBind",
+ self.descriptor_binding_uniform_texel_buffer_update_after_bind,
+ ),
+ (
+ "descriptorBindingUpdateUnusedWhilePending",
+ self.descriptor_binding_update_unused_while_pending,
+ ),
+ (
+ "descriptorBindingVariableDescriptorCount",
+ self.descriptor_binding_variable_descriptor_count,
+ ),
+ ("descriptorBuffer", self.descriptor_buffer),
+ (
+ "descriptorBufferCaptureReplay",
+ self.descriptor_buffer_capture_replay,
+ ),
+ (
+ "descriptorBufferImageLayoutIgnored",
+ self.descriptor_buffer_image_layout_ignored,
+ ),
+ (
+ "descriptorBufferPushDescriptors",
+ self.descriptor_buffer_push_descriptors,
+ ),
+ ("descriptorIndexing", self.descriptor_indexing),
+ ("descriptorSetHostMapping", self.descriptor_set_host_mapping),
+ ("deviceCoherentMemory", self.device_coherent_memory),
+ ("deviceFault", self.device_fault),
+ ("deviceFaultVendorBinary", self.device_fault_vendor_binary),
+ ("deviceGeneratedCommands", self.device_generated_commands),
+ ("deviceMemoryReport", self.device_memory_report),
+ ("diagnosticsConfig", self.diagnostics_config),
+ ("drawIndirectCount", self.draw_indirect_count),
+ (
+ "drawIndirectFirstInstance",
+ self.draw_indirect_first_instance,
+ ),
+ ("dualSrcBlend", self.dual_src_blend),
+ ("dynamicRendering", self.dynamic_rendering),
+ ("events", self.events),
+ ("exclusiveScissor", self.exclusive_scissor),
+ ("extendedDynamicState", self.extended_dynamic_state),
+ ("extendedDynamicState2", self.extended_dynamic_state2),
+ (
+ "extendedDynamicState2LogicOp",
+ self.extended_dynamic_state2_logic_op,
+ ),
+ (
+ "extendedDynamicState2PatchControlPoints",
+ self.extended_dynamic_state2_patch_control_points,
+ ),
+ (
+ "extendedDynamicState3AlphaToCoverageEnable",
+ self.extended_dynamic_state3_alpha_to_coverage_enable,
+ ),
+ (
+ "extendedDynamicState3AlphaToOneEnable",
+ self.extended_dynamic_state3_alpha_to_one_enable,
+ ),
+ (
+ "extendedDynamicState3ColorBlendAdvanced",
+ self.extended_dynamic_state3_color_blend_advanced,
+ ),
+ (
+ "extendedDynamicState3ColorBlendEnable",
+ self.extended_dynamic_state3_color_blend_enable,
+ ),
+ (
+ "extendedDynamicState3ColorBlendEquation",
+ self.extended_dynamic_state3_color_blend_equation,
+ ),
+ (
+ "extendedDynamicState3ColorWriteMask",
+ self.extended_dynamic_state3_color_write_mask,
+ ),
+ (
+ "extendedDynamicState3ConservativeRasterizationMode",
+ self.extended_dynamic_state3_conservative_rasterization_mode,
+ ),
+ (
+ "extendedDynamicState3CoverageModulationMode",
+ self.extended_dynamic_state3_coverage_modulation_mode,
+ ),
+ (
+ "extendedDynamicState3CoverageModulationTable",
+ self.extended_dynamic_state3_coverage_modulation_table,
+ ),
+ (
+ "extendedDynamicState3CoverageModulationTableEnable",
+ self.extended_dynamic_state3_coverage_modulation_table_enable,
+ ),
+ (
+ "extendedDynamicState3CoverageReductionMode",
+ self.extended_dynamic_state3_coverage_reduction_mode,
+ ),
+ (
+ "extendedDynamicState3CoverageToColorEnable",
+ self.extended_dynamic_state3_coverage_to_color_enable,
+ ),
+ (
+ "extendedDynamicState3CoverageToColorLocation",
+ self.extended_dynamic_state3_coverage_to_color_location,
+ ),
+ (
+ "extendedDynamicState3DepthClampEnable",
+ self.extended_dynamic_state3_depth_clamp_enable,
+ ),
+ (
+ "extendedDynamicState3DepthClipEnable",
+ self.extended_dynamic_state3_depth_clip_enable,
+ ),
+ (
+ "extendedDynamicState3DepthClipNegativeOneToOne",
+ self.extended_dynamic_state3_depth_clip_negative_one_to_one,
+ ),
+ (
+ "extendedDynamicState3ExtraPrimitiveOverestimationSize",
+ self.extended_dynamic_state3_extra_primitive_overestimation_size,
+ ),
+ (
+ "extendedDynamicState3LineRasterizationMode",
+ self.extended_dynamic_state3_line_rasterization_mode,
+ ),
+ (
+ "extendedDynamicState3LineStippleEnable",
+ self.extended_dynamic_state3_line_stipple_enable,
+ ),
+ (
+ "extendedDynamicState3LogicOpEnable",
+ self.extended_dynamic_state3_logic_op_enable,
+ ),
+ (
+ "extendedDynamicState3PolygonMode",
+ self.extended_dynamic_state3_polygon_mode,
+ ),
+ (
+ "extendedDynamicState3ProvokingVertexMode",
+ self.extended_dynamic_state3_provoking_vertex_mode,
+ ),
+ (
+ "extendedDynamicState3RasterizationSamples",
+ self.extended_dynamic_state3_rasterization_samples,
+ ),
+ (
+ "extendedDynamicState3RasterizationStream",
+ self.extended_dynamic_state3_rasterization_stream,
+ ),
+ (
+ "extendedDynamicState3RepresentativeFragmentTestEnable",
+ self.extended_dynamic_state3_representative_fragment_test_enable,
+ ),
+ (
+ "extendedDynamicState3SampleLocationsEnable",
+ self.extended_dynamic_state3_sample_locations_enable,
+ ),
+ (
+ "extendedDynamicState3SampleMask",
+ self.extended_dynamic_state3_sample_mask,
+ ),
+ (
+ "extendedDynamicState3ShadingRateImageEnable",
+ self.extended_dynamic_state3_shading_rate_image_enable,
+ ),
+ (
+ "extendedDynamicState3TessellationDomainOrigin",
+ self.extended_dynamic_state3_tessellation_domain_origin,
+ ),
+ (
+ "extendedDynamicState3ViewportSwizzle",
+ self.extended_dynamic_state3_viewport_swizzle,
+ ),
+ (
+ "extendedDynamicState3ViewportWScalingEnable",
+ self.extended_dynamic_state3_viewport_w_scaling_enable,
+ ),
+ ("externalMemoryRDMA", self.external_memory_rdma),
+ ("fillModeNonSolid", self.fill_mode_non_solid),
+ ("formatA4B4G4R4", self.format_a4b4g4r4),
+ ("formatA4R4G4B4", self.format_a4r4g4b4),
+ (
+ "formatRgba10x6WithoutYCbCrSampler",
+ self.format_rgba10x6_without_y_cb_cr_sampler,
+ ),
+ ("fragmentDensityMap", self.fragment_density_map),
+ (
+ "fragmentDensityMapDeferred",
+ self.fragment_density_map_deferred,
+ ),
+ (
+ "fragmentDensityMapDynamic",
+ self.fragment_density_map_dynamic,
+ ),
+ (
+ "fragmentDensityMapNonSubsampledImages",
+ self.fragment_density_map_non_subsampled_images,
+ ),
+ ("fragmentDensityMapOffset", self.fragment_density_map_offset),
+ (
+ "fragmentShaderBarycentric",
+ self.fragment_shader_barycentric,
+ ),
+ (
+ "fragmentShaderPixelInterlock",
+ self.fragment_shader_pixel_interlock,
+ ),
+ (
+ "fragmentShaderSampleInterlock",
+ self.fragment_shader_sample_interlock,
+ ),
+ (
+ "fragmentShaderShadingRateInterlock",
+ self.fragment_shader_shading_rate_interlock,
+ ),
+ ("fragmentShadingRateEnums", self.fragment_shading_rate_enums),
+ ("fragmentStoresAndAtomics", self.fragment_stores_and_atomics),
+ ("fullDrawIndexUint32", self.full_draw_index_uint32),
+ ("geometryShader", self.geometry_shader),
+ ("geometryStreams", self.geometry_streams),
+ ("globalPriorityQuery", self.global_priority_query),
+ ("graphicsPipelineLibrary", self.graphics_pipeline_library),
+ ("hostQueryReset", self.host_query_reset),
+ ("image2DViewOf3D", self.image2_d_view_of3_d),
+ ("imageCompressionControl", self.image_compression_control),
+ (
+ "imageCompressionControlSwapchain",
+ self.image_compression_control_swapchain,
+ ),
+ ("imageCubeArray", self.image_cube_array),
+ ("imageFootprint", self.image_footprint),
+ ("imageView2DOn3DImage", self.image_view2_d_on3_d_image),
+ (
+ "imageViewFormatReinterpretation",
+ self.image_view_format_reinterpretation,
+ ),
+ ("imageViewFormatSwizzle", self.image_view_format_swizzle),
+ ("imagelessFramebuffer", self.imageless_framebuffer),
+ ("independentBlend", self.independent_blend),
+ ("indexTypeUint8", self.index_type_uint8),
+ ("indirectCopy", self.indirect_copy),
+ (
+ "inheritedConditionalRendering",
+ self.inherited_conditional_rendering,
+ ),
+ ("inheritedQueries", self.inherited_queries),
+ (
+ "inheritedViewportScissor2D",
+ self.inherited_viewport_scissor2_d,
+ ),
+ ("inlineUniformBlock", self.inline_uniform_block),
+ ("invocationMask", self.invocation_mask),
+ ("largePoints", self.large_points),
+ ("legacyDithering", self.legacy_dithering),
+ ("linearColorAttachment", self.linear_color_attachment),
+ ("logicOp", self.logic_op),
+ ("maintenance4", self.maintenance4),
+ ("memoryDecompression", self.memory_decompression),
+ ("memoryPriority", self.memory_priority),
+ ("meshShader", self.mesh_shader),
+ ("meshShaderQueries", self.mesh_shader_queries),
+ ("micromap", self.micromap),
+ ("micromapCaptureReplay", self.micromap_capture_replay),
+ ("micromapHostCommands", self.micromap_host_commands),
+ ("minLod", self.min_lod),
+ ("multiDraw", self.multi_draw),
+ ("multiDrawIndirect", self.multi_draw_indirect),
+ ("multiViewport", self.multi_viewport),
+ ("multisampleArrayImage", self.multisample_array_image),
+ (
+ "multisampledRenderToSingleSampled",
+ self.multisampled_render_to_single_sampled,
+ ),
+ ("multiview", self.multiview),
+ ("multiviewGeometryShader", self.multiview_geometry_shader),
+ ("multiviewMeshShader", self.multiview_mesh_shader),
+ (
+ "multiviewPerViewViewports",
+ self.multiview_per_view_viewports,
+ ),
+ (
+ "multiviewTessellationShader",
+ self.multiview_tessellation_shader,
+ ),
+ (
+ "mutableComparisonSamplers",
+ self.mutable_comparison_samplers,
+ ),
+ ("mutableDescriptorType", self.mutable_descriptor_type),
+ (
+ "noInvocationFragmentShadingRates",
+ self.no_invocation_fragment_shading_rates,
+ ),
+ ("nonSeamlessCubeMap", self.non_seamless_cube_map),
+ ("nullDescriptor", self.null_descriptor),
+ ("occlusionQueryPrecise", self.occlusion_query_precise),
+ ("opticalFlow", self.optical_flow),
+ (
+ "pageableDeviceLocalMemory",
+ self.pageable_device_local_memory,
+ ),
+ (
+ "performanceCounterMultipleQueryPools",
+ self.performance_counter_multiple_query_pools,
+ ),
+ (
+ "performanceCounterQueryPools",
+ self.performance_counter_query_pools,
+ ),
+ (
+ "pipelineCreationCacheControl",
+ self.pipeline_creation_cache_control,
+ ),
+ ("pipelineExecutableInfo", self.pipeline_executable_info),
+ (
+ "pipelineFragmentShadingRate",
+ self.pipeline_fragment_shading_rate,
+ ),
+ (
+ "pipelinePropertiesIdentifier",
+ self.pipeline_properties_identifier,
+ ),
+ ("pipelineProtectedAccess", self.pipeline_protected_access),
+ ("pipelineRobustness", self.pipeline_robustness),
+ ("pipelineStatisticsQuery", self.pipeline_statistics_query),
+ ("pointPolygons", self.point_polygons),
+ ("presentBarrier", self.present_barrier),
+ ("presentId", self.present_id),
+ ("presentWait", self.present_wait),
+ (
+ "primitiveFragmentShadingRate",
+ self.primitive_fragment_shading_rate,
+ ),
+ (
+ "primitiveFragmentShadingRateMeshShader",
+ self.primitive_fragment_shading_rate_mesh_shader,
+ ),
+ (
+ "primitiveTopologyListRestart",
+ self.primitive_topology_list_restart,
+ ),
+ (
+ "primitiveTopologyPatchListRestart",
+ self.primitive_topology_patch_list_restart,
+ ),
+ ("primitivesGeneratedQuery", self.primitives_generated_query),
+ (
+ "primitivesGeneratedQueryWithNonZeroStreams",
+ self.primitives_generated_query_with_non_zero_streams,
+ ),
+ (
+ "primitivesGeneratedQueryWithRasterizerDiscard",
+ self.primitives_generated_query_with_rasterizer_discard,
+ ),
+ ("privateData", self.private_data),
+ ("protectedMemory", self.protected_memory),
+ ("provokingVertexLast", self.provoking_vertex_last),
+ (
+ "rasterizationOrderColorAttachmentAccess",
+ self.rasterization_order_color_attachment_access,
+ ),
+ (
+ "rasterizationOrderDepthAttachmentAccess",
+ self.rasterization_order_depth_attachment_access,
+ ),
+ (
+ "rasterizationOrderStencilAttachmentAccess",
+ self.rasterization_order_stencil_attachment_access,
+ ),
+ ("rayQuery", self.ray_query),
+ (
+ "rayTracingInvocationReorder",
+ self.ray_tracing_invocation_reorder,
+ ),
+ ("rayTracingMaintenance1", self.ray_tracing_maintenance1),
+ ("rayTracingMotionBlur", self.ray_tracing_motion_blur),
+ (
+ "rayTracingMotionBlurPipelineTraceRaysIndirect",
+ self.ray_tracing_motion_blur_pipeline_trace_rays_indirect,
+ ),
+ ("rayTracingPipeline", self.ray_tracing_pipeline),
+ (
+ "rayTracingPipelineShaderGroupHandleCaptureReplay",
+ self.ray_tracing_pipeline_shader_group_handle_capture_replay,
+ ),
+ (
+ "rayTracingPipelineShaderGroupHandleCaptureReplayMixed",
+ self.ray_tracing_pipeline_shader_group_handle_capture_replay_mixed,
+ ),
+ (
+ "rayTracingPipelineTraceRaysIndirect",
+ self.ray_tracing_pipeline_trace_rays_indirect,
+ ),
+ (
+ "rayTracingPipelineTraceRaysIndirect2",
+ self.ray_tracing_pipeline_trace_rays_indirect2,
+ ),
+ (
+ "rayTraversalPrimitiveCulling",
+ self.ray_traversal_primitive_culling,
+ ),
+ ("rectangularLines", self.rectangular_lines),
+ ("reportAddressBinding", self.report_address_binding),
+ (
+ "representativeFragmentTest",
+ self.representative_fragment_test,
+ ),
+ ("robustBufferAccess", self.robust_buffer_access),
+ ("robustBufferAccess2", self.robust_buffer_access2),
+ ("robustImageAccess", self.robust_image_access),
+ ("robustImageAccess2", self.robust_image_access2),
+ ("runtimeDescriptorArray", self.runtime_descriptor_array),
+ ("sampleRateShading", self.sample_rate_shading),
+ ("sampler2DViewOf3D", self.sampler2_d_view_of3_d),
+ ("samplerAnisotropy", self.sampler_anisotropy),
+ ("samplerFilterMinmax", self.sampler_filter_minmax),
+ ("samplerMipLodBias", self.sampler_mip_lod_bias),
+ (
+ "samplerMirrorClampToEdge",
+ self.sampler_mirror_clamp_to_edge,
+ ),
+ ("samplerYcbcrConversion", self.sampler_ycbcr_conversion),
+ ("scalarBlockLayout", self.scalar_block_layout),
+ (
+ "separateDepthStencilLayouts",
+ self.separate_depth_stencil_layouts,
+ ),
+ ("separateStencilMaskRef", self.separate_stencil_mask_ref),
+ (
+ "shaderBufferFloat16AtomicAdd",
+ self.shader_buffer_float16_atomic_add,
+ ),
+ (
+ "shaderBufferFloat16AtomicMinMax",
+ self.shader_buffer_float16_atomic_min_max,
+ ),
+ (
+ "shaderBufferFloat16Atomics",
+ self.shader_buffer_float16_atomics,
+ ),
+ (
+ "shaderBufferFloat32AtomicAdd",
+ self.shader_buffer_float32_atomic_add,
+ ),
+ (
+ "shaderBufferFloat32AtomicMinMax",
+ self.shader_buffer_float32_atomic_min_max,
+ ),
+ (
+ "shaderBufferFloat32Atomics",
+ self.shader_buffer_float32_atomics,
+ ),
+ (
+ "shaderBufferFloat64AtomicAdd",
+ self.shader_buffer_float64_atomic_add,
+ ),
+ (
+ "shaderBufferFloat64AtomicMinMax",
+ self.shader_buffer_float64_atomic_min_max,
+ ),
+ (
+ "shaderBufferFloat64Atomics",
+ self.shader_buffer_float64_atomics,
+ ),
+ ("shaderBufferInt64Atomics", self.shader_buffer_int64_atomics),
+ ("shaderClipDistance", self.shader_clip_distance),
+ ("shaderCoreBuiltins", self.shader_core_builtins),
+ ("shaderCullDistance", self.shader_cull_distance),
+ (
+ "shaderDemoteToHelperInvocation",
+ self.shader_demote_to_helper_invocation,
+ ),
+ ("shaderDeviceClock", self.shader_device_clock),
+ ("shaderDrawParameters", self.shader_draw_parameters),
+ (
+ "shaderEarlyAndLateFragmentTests",
+ self.shader_early_and_late_fragment_tests,
+ ),
+ ("shaderFloat16", self.shader_float16),
+ ("shaderFloat64", self.shader_float64),
+ (
+ "shaderImageFloat32AtomicAdd",
+ self.shader_image_float32_atomic_add,
+ ),
+ (
+ "shaderImageFloat32AtomicMinMax",
+ self.shader_image_float32_atomic_min_max,
+ ),
+ (
+ "shaderImageFloat32Atomics",
+ self.shader_image_float32_atomics,
+ ),
+ (
+ "shaderImageGatherExtended",
+ self.shader_image_gather_extended,
+ ),
+ ("shaderImageInt64Atomics", self.shader_image_int64_atomics),
+ (
+ "shaderInputAttachmentArrayDynamicIndexing",
+ self.shader_input_attachment_array_dynamic_indexing,
+ ),
+ (
+ "shaderInputAttachmentArrayNonUniformIndexing",
+ self.shader_input_attachment_array_non_uniform_indexing,
+ ),
+ ("shaderInt16", self.shader_int16),
+ ("shaderInt64", self.shader_int64),
+ ("shaderInt8", self.shader_int8),
+ ("shaderIntegerDotProduct", self.shader_integer_dot_product),
+ ("shaderIntegerFunctions2", self.shader_integer_functions2),
+ ("shaderModuleIdentifier", self.shader_module_identifier),
+ ("shaderOutputLayer", self.shader_output_layer),
+ (
+ "shaderOutputViewportIndex",
+ self.shader_output_viewport_index,
+ ),
+ ("shaderResourceMinLod", self.shader_resource_min_lod),
+ ("shaderResourceResidency", self.shader_resource_residency),
+ (
+ "shaderSampleRateInterpolationFunctions",
+ self.shader_sample_rate_interpolation_functions,
+ ),
+ (
+ "shaderSampledImageArrayDynamicIndexing",
+ self.shader_sampled_image_array_dynamic_indexing,
+ ),
+ (
+ "shaderSampledImageArrayNonUniformIndexing",
+ self.shader_sampled_image_array_non_uniform_indexing,
+ ),
+ (
+ "shaderSharedFloat16AtomicAdd",
+ self.shader_shared_float16_atomic_add,
+ ),
+ (
+ "shaderSharedFloat16AtomicMinMax",
+ self.shader_shared_float16_atomic_min_max,
+ ),
+ (
+ "shaderSharedFloat16Atomics",
+ self.shader_shared_float16_atomics,
+ ),
+ (
+ "shaderSharedFloat32AtomicAdd",
+ self.shader_shared_float32_atomic_add,
+ ),
+ (
+ "shaderSharedFloat32AtomicMinMax",
+ self.shader_shared_float32_atomic_min_max,
+ ),
+ (
+ "shaderSharedFloat32Atomics",
+ self.shader_shared_float32_atomics,
+ ),
+ (
+ "shaderSharedFloat64AtomicAdd",
+ self.shader_shared_float64_atomic_add,
+ ),
+ (
+ "shaderSharedFloat64AtomicMinMax",
+ self.shader_shared_float64_atomic_min_max,
+ ),
+ (
+ "shaderSharedFloat64Atomics",
+ self.shader_shared_float64_atomics,
+ ),
+ ("shaderSharedInt64Atomics", self.shader_shared_int64_atomics),
+ ("shaderSMBuiltins", self.shader_sm_builtins),
+ (
+ "shaderStorageBufferArrayDynamicIndexing",
+ self.shader_storage_buffer_array_dynamic_indexing,
+ ),
+ (
+ "shaderStorageBufferArrayNonUniformIndexing",
+ self.shader_storage_buffer_array_non_uniform_indexing,
+ ),
+ (
+ "shaderStorageImageArrayDynamicIndexing",
+ self.shader_storage_image_array_dynamic_indexing,
+ ),
+ (
+ "shaderStorageImageArrayNonUniformIndexing",
+ self.shader_storage_image_array_non_uniform_indexing,
+ ),
+ (
+ "shaderStorageImageExtendedFormats",
+ self.shader_storage_image_extended_formats,
+ ),
+ (
+ "shaderStorageImageMultisample",
+ self.shader_storage_image_multisample,
+ ),
+ (
+ "shaderStorageImageReadWithoutFormat",
+ self.shader_storage_image_read_without_format,
+ ),
+ (
+ "shaderStorageImageWriteWithoutFormat",
+ self.shader_storage_image_write_without_format,
+ ),
+ (
+ "shaderStorageTexelBufferArrayDynamicIndexing",
+ self.shader_storage_texel_buffer_array_dynamic_indexing,
+ ),
+ (
+ "shaderStorageTexelBufferArrayNonUniformIndexing",
+ self.shader_storage_texel_buffer_array_non_uniform_indexing,
+ ),
+ ("shaderSubgroupClock", self.shader_subgroup_clock),
+ (
+ "shaderSubgroupExtendedTypes",
+ self.shader_subgroup_extended_types,
+ ),
+ (
+ "shaderSubgroupUniformControlFlow",
+ self.shader_subgroup_uniform_control_flow,
+ ),
+ (
+ "shaderTerminateInvocation",
+ self.shader_terminate_invocation,
+ ),
+ (
+ "shaderTessellationAndGeometryPointSize",
+ self.shader_tessellation_and_geometry_point_size,
+ ),
+ (
+ "shaderUniformBufferArrayDynamicIndexing",
+ self.shader_uniform_buffer_array_dynamic_indexing,
+ ),
+ (
+ "shaderUniformBufferArrayNonUniformIndexing",
+ self.shader_uniform_buffer_array_non_uniform_indexing,
+ ),
+ (
+ "shaderUniformTexelBufferArrayDynamicIndexing",
+ self.shader_uniform_texel_buffer_array_dynamic_indexing,
+ ),
+ (
+ "shaderUniformTexelBufferArrayNonUniformIndexing",
+ self.shader_uniform_texel_buffer_array_non_uniform_indexing,
+ ),
+ (
+ "shaderZeroInitializeWorkgroupMemory",
+ self.shader_zero_initialize_workgroup_memory,
+ ),
+ (
+ "shadingRateCoarseSampleOrder",
+ self.shading_rate_coarse_sample_order,
+ ),
+ ("shadingRateImage", self.shading_rate_image),
+ ("smoothLines", self.smooth_lines),
+ ("sparseBinding", self.sparse_binding),
+ (
+ "sparseImageFloat32AtomicAdd",
+ self.sparse_image_float32_atomic_add,
+ ),
+ (
+ "sparseImageFloat32AtomicMinMax",
+ self.sparse_image_float32_atomic_min_max,
+ ),
+ (
+ "sparseImageFloat32Atomics",
+ self.sparse_image_float32_atomics,
+ ),
+ ("sparseImageInt64Atomics", self.sparse_image_int64_atomics),
+ ("sparseResidency16Samples", self.sparse_residency16_samples),
+ ("sparseResidency2Samples", self.sparse_residency2_samples),
+ ("sparseResidency4Samples", self.sparse_residency4_samples),
+ ("sparseResidency8Samples", self.sparse_residency8_samples),
+ ("sparseResidencyAliased", self.sparse_residency_aliased),
+ ("sparseResidencyBuffer", self.sparse_residency_buffer),
+ ("sparseResidencyImage2D", self.sparse_residency_image2_d),
+ ("sparseResidencyImage3D", self.sparse_residency_image3_d),
+ ("stippledBresenhamLines", self.stippled_bresenham_lines),
+ ("stippledRectangularLines", self.stippled_rectangular_lines),
+ ("stippledSmoothLines", self.stippled_smooth_lines),
+ ("storageBuffer16BitAccess", self.storage_buffer16_bit_access),
+ ("storageBuffer8BitAccess", self.storage_buffer8_bit_access),
+ ("storageInputOutput16", self.storage_input_output16),
+ ("storagePushConstant16", self.storage_push_constant16),
+ ("storagePushConstant8", self.storage_push_constant8),
+ (
+ "subgroupBroadcastDynamicId",
+ self.subgroup_broadcast_dynamic_id,
+ ),
+ ("subgroupSizeControl", self.subgroup_size_control),
+ ("subpassMergeFeedback", self.subpass_merge_feedback),
+ ("subpassShading", self.subpass_shading),
+ (
+ "supersampleFragmentShadingRates",
+ self.supersample_fragment_shading_rates,
+ ),
+ ("swapchainMaintenance1", self.swapchain_maintenance1),
+ ("synchronization2", self.synchronization2),
+ ("taskShader", self.task_shader),
+ ("tessellationIsolines", self.tessellation_isolines),
+ ("tessellationPointMode", self.tessellation_point_mode),
+ ("tessellationShader", self.tessellation_shader),
+ ("texelBufferAlignment", self.texel_buffer_alignment),
+ ("textureBlockMatch", self.texture_block_match),
+ ("textureBoxFilter", self.texture_box_filter),
+ (
+ "textureCompressionASTC_HDR",
+ self.texture_compression_astc_hdr,
+ ),
+ (
+ "textureCompressionASTC_LDR",
+ self.texture_compression_astc_ldr,
+ ),
+ ("textureCompressionBC", self.texture_compression_bc),
+ ("textureCompressionETC2", self.texture_compression_etc2),
+ ("textureSampleWeighted", self.texture_sample_weighted),
+ ("tileProperties", self.tile_properties),
+ ("timelineSemaphore", self.timeline_semaphore),
+ ("transformFeedback", self.transform_feedback),
+ (
+ "transformFeedbackPreservesProvokingVertex",
+ self.transform_feedback_preserves_provoking_vertex,
+ ),
+ ("triangleFans", self.triangle_fans),
+ (
+ "uniformAndStorageBuffer16BitAccess",
+ self.uniform_and_storage_buffer16_bit_access,
+ ),
+ (
+ "uniformAndStorageBuffer8BitAccess",
+ self.uniform_and_storage_buffer8_bit_access,
+ ),
+ (
+ "uniformBufferStandardLayout",
+ self.uniform_buffer_standard_layout,
+ ),
+ ("variableMultisampleRate", self.variable_multisample_rate),
+ ("variablePointers", self.variable_pointers),
+ (
+ "variablePointersStorageBuffer",
+ self.variable_pointers_storage_buffer,
+ ),
+ (
+ "vertexAttributeAccessBeyondStride",
+ self.vertex_attribute_access_beyond_stride,
+ ),
+ (
+ "vertexAttributeInstanceRateDivisor",
+ self.vertex_attribute_instance_rate_divisor,
+ ),
+ (
+ "vertexAttributeInstanceRateZeroDivisor",
+ self.vertex_attribute_instance_rate_zero_divisor,
+ ),
+ ("vertexInputDynamicState", self.vertex_input_dynamic_state),
+ (
+ "vertexPipelineStoresAndAtomics",
+ self.vertex_pipeline_stores_and_atomics,
+ ),
+ ("vulkanMemoryModel", self.vulkan_memory_model),
+ (
+ "vulkanMemoryModelAvailabilityVisibilityChains",
+ self.vulkan_memory_model_availability_visibility_chains,
+ ),
+ (
+ "vulkanMemoryModelDeviceScope",
+ self.vulkan_memory_model_device_scope,
+ ),
+ ("wideLines", self.wide_lines),
+ (
+ "workgroupMemoryExplicitLayout",
+ self.workgroup_memory_explicit_layout,
+ ),
+ (
+ "workgroupMemoryExplicitLayout16BitAccess",
+ self.workgroup_memory_explicit_layout16_bit_access,
+ ),
+ (
+ "workgroupMemoryExplicitLayout8BitAccess",
+ self.workgroup_memory_explicit_layout8_bit_access,
+ ),
+ (
+ "workgroupMemoryExplicitLayoutScalarBlockLayout",
+ self.workgroup_memory_explicit_layout_scalar_block_layout,
+ ),
+ ("ycbcr2plane444Formats", self.ycbcr2plane444_formats),
+ ("ycbcrImageArrays", self.ycbcr_image_arrays),
+ ]
+ .into_iter()
+ }
+}
+#[derive(Default)]
+pub(crate) struct FeaturesFfi {
+ features_vulkan10: ash::vk::PhysicalDeviceFeatures2KHR,
+ features_vulkan11: Option<ash::vk::PhysicalDeviceVulkan11Features>,
+ features_vulkan12: Option<ash::vk::PhysicalDeviceVulkan12Features>,
+ features_vulkan13: Option<ash::vk::PhysicalDeviceVulkan13Features>,
+ features_16bit_storage: Option<ash::vk::PhysicalDevice16BitStorageFeatures>,
+ features_multiview: Option<ash::vk::PhysicalDeviceMultiviewFeatures>,
+ features_protected_memory: Option<ash::vk::PhysicalDeviceProtectedMemoryFeatures>,
+ features_sampler_ycbcr_conversion:
+ Option<ash::vk::PhysicalDeviceSamplerYcbcrConversionFeatures>,
+ features_shader_draw_parameters: Option<ash::vk::PhysicalDeviceShaderDrawParametersFeatures>,
+ features_variable_pointers: Option<ash::vk::PhysicalDeviceVariablePointersFeatures>,
+ features_8bit_storage: Option<ash::vk::PhysicalDevice8BitStorageFeatures>,
+ features_buffer_device_address: Option<ash::vk::PhysicalDeviceBufferDeviceAddressFeatures>,
+ features_descriptor_indexing: Option<ash::vk::PhysicalDeviceDescriptorIndexingFeatures>,
+ features_host_query_reset: Option<ash::vk::PhysicalDeviceHostQueryResetFeatures>,
+ features_imageless_framebuffer: Option<ash::vk::PhysicalDeviceImagelessFramebufferFeatures>,
+ features_scalar_block_layout: Option<ash::vk::PhysicalDeviceScalarBlockLayoutFeatures>,
+ features_separate_depth_stencil_layouts:
+ Option<ash::vk::PhysicalDeviceSeparateDepthStencilLayoutsFeatures>,
+ features_shader_atomic_int64: Option<ash::vk::PhysicalDeviceShaderAtomicInt64Features>,
+ features_shader_float16_int8: Option<ash::vk::PhysicalDeviceShaderFloat16Int8Features>,
+ features_shader_subgroup_extended_types:
+ Option<ash::vk::PhysicalDeviceShaderSubgroupExtendedTypesFeatures>,
+ features_timeline_semaphore: Option<ash::vk::PhysicalDeviceTimelineSemaphoreFeatures>,
+ features_uniform_buffer_standard_layout:
+ Option<ash::vk::PhysicalDeviceUniformBufferStandardLayoutFeatures>,
+ features_vulkan_memory_model: Option<ash::vk::PhysicalDeviceVulkanMemoryModelFeatures>,
+ features_dynamic_rendering: Option<ash::vk::PhysicalDeviceDynamicRenderingFeatures>,
+ features_image_robustness: Option<ash::vk::PhysicalDeviceImageRobustnessFeatures>,
+ features_inline_uniform_block: Option<ash::vk::PhysicalDeviceInlineUniformBlockFeatures>,
+ features_maintenance4: Option<ash::vk::PhysicalDeviceMaintenance4Features>,
+ features_pipeline_creation_cache_control:
+ Option<ash::vk::PhysicalDevicePipelineCreationCacheControlFeatures>,
+ features_private_data: Option<ash::vk::PhysicalDevicePrivateDataFeatures>,
+ features_shader_demote_to_helper_invocation:
+ Option<ash::vk::PhysicalDeviceShaderDemoteToHelperInvocationFeatures>,
+ features_shader_integer_dot_product:
+ Option<ash::vk::PhysicalDeviceShaderIntegerDotProductFeatures>,
+ features_shader_terminate_invocation:
+ Option<ash::vk::PhysicalDeviceShaderTerminateInvocationFeatures>,
+ features_subgroup_size_control: Option<ash::vk::PhysicalDeviceSubgroupSizeControlFeatures>,
+ features_synchronization2: Option<ash::vk::PhysicalDeviceSynchronization2Features>,
+ features_texture_compression_astchdr:
+ Option<ash::vk::PhysicalDeviceTextureCompressionASTCHDRFeatures>,
+ features_zero_initialize_workgroup_memory:
+ Option<ash::vk::PhysicalDeviceZeroInitializeWorkgroupMemoryFeatures>,
+ features_acceleration_structure_khr:
+ Option<ash::vk::PhysicalDeviceAccelerationStructureFeaturesKHR>,
+ features_fragment_shader_barycentric_khr:
+ Option<ash::vk::PhysicalDeviceFragmentShaderBarycentricFeaturesKHR>,
+ features_fragment_shading_rate_khr:
+ Option<ash::vk::PhysicalDeviceFragmentShadingRateFeaturesKHR>,
+ features_global_priority_query_khr:
+ Option<ash::vk::PhysicalDeviceGlobalPriorityQueryFeaturesKHR>,
+ features_performance_query_khr: Option<ash::vk::PhysicalDevicePerformanceQueryFeaturesKHR>,
+ features_pipeline_executable_properties_khr:
+ Option<ash::vk::PhysicalDevicePipelineExecutablePropertiesFeaturesKHR>,
+ features_portability_subset_khr: Option<ash::vk::PhysicalDevicePortabilitySubsetFeaturesKHR>,
+ features_present_id_khr: Option<ash::vk::PhysicalDevicePresentIdFeaturesKHR>,
+ features_present_wait_khr: Option<ash::vk::PhysicalDevicePresentWaitFeaturesKHR>,
+ features_ray_query_khr: Option<ash::vk::PhysicalDeviceRayQueryFeaturesKHR>,
+ features_ray_tracing_maintenance1_khr:
+ Option<ash::vk::PhysicalDeviceRayTracingMaintenance1FeaturesKHR>,
+ features_ray_tracing_pipeline_khr: Option<ash::vk::PhysicalDeviceRayTracingPipelineFeaturesKHR>,
+ features_shader_clock_khr: Option<ash::vk::PhysicalDeviceShaderClockFeaturesKHR>,
+ features_shader_subgroup_uniform_control_flow_khr:
+ Option<ash::vk::PhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR>,
+ features_workgroup_memory_explicit_layout_khr:
+ Option<ash::vk::PhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR>,
+ features_4444formats_ext: Option<ash::vk::PhysicalDevice4444FormatsFeaturesEXT>,
+ features_astc_decode_ext: Option<ash::vk::PhysicalDeviceASTCDecodeFeaturesEXT>,
+ features_address_binding_report_ext:
+ Option<ash::vk::PhysicalDeviceAddressBindingReportFeaturesEXT>,
+ features_attachment_feedback_loop_layout_ext:
+ Option<ash::vk::PhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT>,
+ features_blend_operation_advanced_ext:
+ Option<ash::vk::PhysicalDeviceBlendOperationAdvancedFeaturesEXT>,
+ features_border_color_swizzle_ext: Option<ash::vk::PhysicalDeviceBorderColorSwizzleFeaturesEXT>,
+ features_buffer_device_address_ext:
+ Option<ash::vk::PhysicalDeviceBufferDeviceAddressFeaturesEXT>,
+ features_color_write_enable_ext: Option<ash::vk::PhysicalDeviceColorWriteEnableFeaturesEXT>,
+ features_conditional_rendering_ext:
+ Option<ash::vk::PhysicalDeviceConditionalRenderingFeaturesEXT>,
+ features_custom_border_color_ext: Option<ash::vk::PhysicalDeviceCustomBorderColorFeaturesEXT>,
+ features_depth_clamp_zero_one_ext: Option<ash::vk::PhysicalDeviceDepthClampZeroOneFeaturesEXT>,
+ features_depth_clip_control_ext: Option<ash::vk::PhysicalDeviceDepthClipControlFeaturesEXT>,
+ features_depth_clip_enable_ext: Option<ash::vk::PhysicalDeviceDepthClipEnableFeaturesEXT>,
+ features_descriptor_buffer_ext: Option<ash::vk::PhysicalDeviceDescriptorBufferFeaturesEXT>,
+ features_device_memory_report_ext: Option<ash::vk::PhysicalDeviceDeviceMemoryReportFeaturesEXT>,
+ features_extended_dynamic_state2_ext:
+ Option<ash::vk::PhysicalDeviceExtendedDynamicState2FeaturesEXT>,
+ features_extended_dynamic_state3_ext:
+ Option<ash::vk::PhysicalDeviceExtendedDynamicState3FeaturesEXT>,
+ features_extended_dynamic_state_ext:
+ Option<ash::vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>,
+ features_fault_ext: Option<ash::vk::PhysicalDeviceFaultFeaturesEXT>,
+ features_fragment_density_map2_ext:
+ Option<ash::vk::PhysicalDeviceFragmentDensityMap2FeaturesEXT>,
+ features_fragment_density_map_ext: Option<ash::vk::PhysicalDeviceFragmentDensityMapFeaturesEXT>,
+ features_fragment_shader_interlock_ext:
+ Option<ash::vk::PhysicalDeviceFragmentShaderInterlockFeaturesEXT>,
+ features_graphics_pipeline_library_ext:
+ Option<ash::vk::PhysicalDeviceGraphicsPipelineLibraryFeaturesEXT>,
+ features_image2_d_view_of3_d_ext: Option<ash::vk::PhysicalDeviceImage2DViewOf3DFeaturesEXT>,
+ features_image_compression_control_ext:
+ Option<ash::vk::PhysicalDeviceImageCompressionControlFeaturesEXT>,
+ features_image_compression_control_swapchain_ext:
+ Option<ash::vk::PhysicalDeviceImageCompressionControlSwapchainFeaturesEXT>,
+ features_image_view_min_lod_ext: Option<ash::vk::PhysicalDeviceImageViewMinLodFeaturesEXT>,
+ features_index_type_uint8_ext: Option<ash::vk::PhysicalDeviceIndexTypeUint8FeaturesEXT>,
+ features_legacy_dithering_ext: Option<ash::vk::PhysicalDeviceLegacyDitheringFeaturesEXT>,
+ features_line_rasterization_ext: Option<ash::vk::PhysicalDeviceLineRasterizationFeaturesEXT>,
+ features_memory_priority_ext: Option<ash::vk::PhysicalDeviceMemoryPriorityFeaturesEXT>,
+ features_mesh_shader_ext: Option<ash::vk::PhysicalDeviceMeshShaderFeaturesEXT>,
+ features_multi_draw_ext: Option<ash::vk::PhysicalDeviceMultiDrawFeaturesEXT>,
+ features_multisampled_render_to_single_sampled_ext:
+ Option<ash::vk::PhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT>,
+ features_mutable_descriptor_type_ext:
+ Option<ash::vk::PhysicalDeviceMutableDescriptorTypeFeaturesEXT>,
+ features_non_seamless_cube_map_ext:
+ Option<ash::vk::PhysicalDeviceNonSeamlessCubeMapFeaturesEXT>,
+ features_opacity_micromap_ext: Option<ash::vk::PhysicalDeviceOpacityMicromapFeaturesEXT>,
+ features_pageable_device_local_memory_ext:
+ Option<ash::vk::PhysicalDevicePageableDeviceLocalMemoryFeaturesEXT>,
+ features_pipeline_properties_ext: Option<ash::vk::PhysicalDevicePipelinePropertiesFeaturesEXT>,
+ features_pipeline_protected_access_ext:
+ Option<ash::vk::PhysicalDevicePipelineProtectedAccessFeaturesEXT>,
+ features_pipeline_robustness_ext: Option<ash::vk::PhysicalDevicePipelineRobustnessFeaturesEXT>,
+ features_primitive_topology_list_restart_ext:
+ Option<ash::vk::PhysicalDevicePrimitiveTopologyListRestartFeaturesEXT>,
+ features_primitives_generated_query_ext:
+ Option<ash::vk::PhysicalDevicePrimitivesGeneratedQueryFeaturesEXT>,
+ features_provoking_vertex_ext: Option<ash::vk::PhysicalDeviceProvokingVertexFeaturesEXT>,
+ features_rgba10x6_formats_ext: Option<ash::vk::PhysicalDeviceRGBA10X6FormatsFeaturesEXT>,
+ features_rasterization_order_attachment_access_ext:
+ Option<ash::vk::PhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT>,
+ features_robustness2_ext: Option<ash::vk::PhysicalDeviceRobustness2FeaturesEXT>,
+ features_shader_atomic_float2_ext: Option<ash::vk::PhysicalDeviceShaderAtomicFloat2FeaturesEXT>,
+ features_shader_atomic_float_ext: Option<ash::vk::PhysicalDeviceShaderAtomicFloatFeaturesEXT>,
+ features_shader_image_atomic_int64_ext:
+ Option<ash::vk::PhysicalDeviceShaderImageAtomicInt64FeaturesEXT>,
+ features_shader_module_identifier_ext:
+ Option<ash::vk::PhysicalDeviceShaderModuleIdentifierFeaturesEXT>,
+ features_subpass_merge_feedback_ext:
+ Option<ash::vk::PhysicalDeviceSubpassMergeFeedbackFeaturesEXT>,
+ features_swapchain_maintenance1_ext:
+ Option<ash::vk::PhysicalDeviceSwapchainMaintenance1FeaturesEXT>,
+ features_texel_buffer_alignment_ext:
+ Option<ash::vk::PhysicalDeviceTexelBufferAlignmentFeaturesEXT>,
+ features_transform_feedback_ext: Option<ash::vk::PhysicalDeviceTransformFeedbackFeaturesEXT>,
+ features_vertex_attribute_divisor_ext:
+ Option<ash::vk::PhysicalDeviceVertexAttributeDivisorFeaturesEXT>,
+ features_vertex_input_dynamic_state_ext:
+ Option<ash::vk::PhysicalDeviceVertexInputDynamicStateFeaturesEXT>,
+ features_ycbcr2_plane444_formats_ext:
+ Option<ash::vk::PhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT>,
+ features_ycbcr_image_arrays_ext: Option<ash::vk::PhysicalDeviceYcbcrImageArraysFeaturesEXT>,
+ features_amigo_profiling_sec: Option<ash::vk::PhysicalDeviceAmigoProfilingFeaturesSEC>,
+ features_coherent_memory_amd: Option<ash::vk::PhysicalDeviceCoherentMemoryFeaturesAMD>,
+ features_compute_shader_derivatives_nv:
+ Option<ash::vk::PhysicalDeviceComputeShaderDerivativesFeaturesNV>,
+ features_cooperative_matrix_nv: Option<ash::vk::PhysicalDeviceCooperativeMatrixFeaturesNV>,
+ features_copy_memory_indirect_nv: Option<ash::vk::PhysicalDeviceCopyMemoryIndirectFeaturesNV>,
+ features_corner_sampled_image_nv: Option<ash::vk::PhysicalDeviceCornerSampledImageFeaturesNV>,
+ features_coverage_reduction_mode_nv:
+ Option<ash::vk::PhysicalDeviceCoverageReductionModeFeaturesNV>,
+ features_dedicated_allocation_image_aliasing_nv:
+ Option<ash::vk::PhysicalDeviceDedicatedAllocationImageAliasingFeaturesNV>,
+ features_descriptor_set_host_mapping_valve:
+ Option<ash::vk::PhysicalDeviceDescriptorSetHostMappingFeaturesVALVE>,
+ features_device_generated_commands_nv:
+ Option<ash::vk::PhysicalDeviceDeviceGeneratedCommandsFeaturesNV>,
+ features_diagnostics_config_nv: Option<ash::vk::PhysicalDeviceDiagnosticsConfigFeaturesNV>,
+ features_exclusive_scissor_nv: Option<ash::vk::PhysicalDeviceExclusiveScissorFeaturesNV>,
+ features_external_memory_rdma_nv: Option<ash::vk::PhysicalDeviceExternalMemoryRDMAFeaturesNV>,
+ features_fragment_density_map_offset_qcom:
+ Option<ash::vk::PhysicalDeviceFragmentDensityMapOffsetFeaturesQCOM>,
+ features_fragment_shading_rate_enums_nv:
+ Option<ash::vk::PhysicalDeviceFragmentShadingRateEnumsFeaturesNV>,
+ features_image_processing_qcom: Option<ash::vk::PhysicalDeviceImageProcessingFeaturesQCOM>,
+ features_inherited_viewport_scissor_nv:
+ Option<ash::vk::PhysicalDeviceInheritedViewportScissorFeaturesNV>,
+ features_invocation_mask_huawei: Option<ash::vk::PhysicalDeviceInvocationMaskFeaturesHUAWEI>,
+ features_linear_color_attachment_nv:
+ Option<ash::vk::PhysicalDeviceLinearColorAttachmentFeaturesNV>,
+ features_memory_decompression_nv: Option<ash::vk::PhysicalDeviceMemoryDecompressionFeaturesNV>,
+ features_mesh_shader_nv: Option<ash::vk::PhysicalDeviceMeshShaderFeaturesNV>,
+ features_multiview_per_view_viewports_qcom:
+ Option<ash::vk::PhysicalDeviceMultiviewPerViewViewportsFeaturesQCOM>,
+ features_optical_flow_nv: Option<ash::vk::PhysicalDeviceOpticalFlowFeaturesNV>,
+ features_present_barrier_nv: Option<ash::vk::PhysicalDevicePresentBarrierFeaturesNV>,
+ features_ray_tracing_invocation_reorder_nv:
+ Option<ash::vk::PhysicalDeviceRayTracingInvocationReorderFeaturesNV>,
+ features_ray_tracing_motion_blur_nv:
+ Option<ash::vk::PhysicalDeviceRayTracingMotionBlurFeaturesNV>,
+ features_representative_fragment_test_nv:
+ Option<ash::vk::PhysicalDeviceRepresentativeFragmentTestFeaturesNV>,
+ features_shader_core_builtins_arm: Option<ash::vk::PhysicalDeviceShaderCoreBuiltinsFeaturesARM>,
+ features_shader_early_and_late_fragment_tests_amd:
+ Option<ash::vk::PhysicalDeviceShaderEarlyAndLateFragmentTestsFeaturesAMD>,
+ features_shader_image_footprint_nv:
+ Option<ash::vk::PhysicalDeviceShaderImageFootprintFeaturesNV>,
+ features_shader_integer_functions2_intel:
+ Option<ash::vk::PhysicalDeviceShaderIntegerFunctions2FeaturesINTEL>,
+ features_shader_sm_builtins_nv: Option<ash::vk::PhysicalDeviceShaderSMBuiltinsFeaturesNV>,
+ features_shading_rate_image_nv: Option<ash::vk::PhysicalDeviceShadingRateImageFeaturesNV>,
+ features_subpass_shading_huawei: Option<ash::vk::PhysicalDeviceSubpassShadingFeaturesHUAWEI>,
+ features_tile_properties_qcom: Option<ash::vk::PhysicalDeviceTilePropertiesFeaturesQCOM>,
+}
+impl FeaturesFfi {
+ pub(crate) fn make_chain(
+ &mut self,
+ api_version: crate::Version,
+ device_extensions: &crate::device::DeviceExtensions,
+ _instance_extensions: &crate::instance::InstanceExtensions,
+ ) {
+ self.features_vulkan10 = Default::default();
+ let head = &mut self.features_vulkan10;
+ if [api_version >= crate::Version::V1_2].into_iter().any(|x| x) && [].into_iter().all(|x| x)
+ {
+ self.features_vulkan11 = Some(Default::default());
+ let member = self.features_vulkan11.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [api_version >= crate::Version::V1_2].into_iter().any(|x| x) && [].into_iter().all(|x| x)
+ {
+ self.features_vulkan12 = Some(Default::default());
+ let member = self.features_vulkan12.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [api_version >= crate::Version::V1_3].into_iter().any(|x| x) && [].into_iter().all(|x| x)
+ {
+ self.features_vulkan13 = Some(Default::default());
+ let member = self.features_vulkan13.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= crate::Version::V1_1,
+ device_extensions.khr_16bit_storage,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.features_vulkan11.is_none()].into_iter().all(|x| x)
+ {
+ self.features_16bit_storage = Some(Default::default());
+ let member = self.features_16bit_storage.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= crate::Version::V1_1,
+ device_extensions.khr_multiview,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.features_vulkan11.is_none()].into_iter().all(|x| x)
+ {
+ self.features_multiview = Some(Default::default());
+ let member = self.features_multiview.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [api_version >= crate::Version::V1_1].into_iter().any(|x| x)
+ && [self.features_vulkan11.is_none()].into_iter().all(|x| x)
+ {
+ self.features_protected_memory = Some(Default::default());
+ let member = self.features_protected_memory.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= crate::Version::V1_1,
+ device_extensions.khr_sampler_ycbcr_conversion,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.features_vulkan11.is_none()].into_iter().all(|x| x)
+ {
+ self.features_sampler_ycbcr_conversion = Some(Default::default());
+ let member = self.features_sampler_ycbcr_conversion.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [api_version >= crate::Version::V1_1].into_iter().any(|x| x)
+ && [self.features_vulkan11.is_none()].into_iter().all(|x| x)
+ {
+ self.features_shader_draw_parameters = Some(Default::default());
+ let member = self.features_shader_draw_parameters.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= crate::Version::V1_1,
+ device_extensions.khr_variable_pointers,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.features_vulkan11.is_none()].into_iter().all(|x| x)
+ {
+ self.features_variable_pointers = Some(Default::default());
+ let member = self.features_variable_pointers.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= crate::Version::V1_2,
+ device_extensions.khr_8bit_storage,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.features_vulkan12.is_none()].into_iter().all(|x| x)
+ {
+ self.features_8bit_storage = Some(Default::default());
+ let member = self.features_8bit_storage.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= crate::Version::V1_2,
+ device_extensions.khr_buffer_device_address,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.features_vulkan12.is_none()].into_iter().all(|x| x)
+ {
+ self.features_buffer_device_address = Some(Default::default());
+ let member = self.features_buffer_device_address.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= crate::Version::V1_2,
+ device_extensions.ext_descriptor_indexing,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.features_vulkan12.is_none()].into_iter().all(|x| x)
+ {
+ self.features_descriptor_indexing = Some(Default::default());
+ let member = self.features_descriptor_indexing.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= crate::Version::V1_2,
+ device_extensions.ext_host_query_reset,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.features_vulkan12.is_none()].into_iter().all(|x| x)
+ {
+ self.features_host_query_reset = Some(Default::default());
+ let member = self.features_host_query_reset.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= crate::Version::V1_2,
+ device_extensions.khr_imageless_framebuffer,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.features_vulkan12.is_none()].into_iter().all(|x| x)
+ {
+ self.features_imageless_framebuffer = Some(Default::default());
+ let member = self.features_imageless_framebuffer.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= crate::Version::V1_2,
+ device_extensions.ext_scalar_block_layout,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.features_vulkan12.is_none()].into_iter().all(|x| x)
+ {
+ self.features_scalar_block_layout = Some(Default::default());
+ let member = self.features_scalar_block_layout.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= crate::Version::V1_2,
+ device_extensions.khr_separate_depth_stencil_layouts,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.features_vulkan12.is_none()].into_iter().all(|x| x)
+ {
+ self.features_separate_depth_stencil_layouts = Some(Default::default());
+ let member = self
+ .features_separate_depth_stencil_layouts
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= crate::Version::V1_2,
+ device_extensions.khr_shader_atomic_int64,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.features_vulkan12.is_none()].into_iter().all(|x| x)
+ {
+ self.features_shader_atomic_int64 = Some(Default::default());
+ let member = self.features_shader_atomic_int64.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= crate::Version::V1_2,
+ device_extensions.khr_shader_float16_int8,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.features_vulkan12.is_none()].into_iter().all(|x| x)
+ {
+ self.features_shader_float16_int8 = Some(Default::default());
+ let member = self.features_shader_float16_int8.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= crate::Version::V1_2,
+ device_extensions.khr_shader_subgroup_extended_types,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.features_vulkan12.is_none()].into_iter().all(|x| x)
+ {
+ self.features_shader_subgroup_extended_types = Some(Default::default());
+ let member = self
+ .features_shader_subgroup_extended_types
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= crate::Version::V1_2,
+ device_extensions.khr_timeline_semaphore,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.features_vulkan12.is_none()].into_iter().all(|x| x)
+ {
+ self.features_timeline_semaphore = Some(Default::default());
+ let member = self.features_timeline_semaphore.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= crate::Version::V1_2,
+ device_extensions.khr_uniform_buffer_standard_layout,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.features_vulkan12.is_none()].into_iter().all(|x| x)
+ {
+ self.features_uniform_buffer_standard_layout = Some(Default::default());
+ let member = self
+ .features_uniform_buffer_standard_layout
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= crate::Version::V1_2,
+ device_extensions.khr_vulkan_memory_model,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.features_vulkan12.is_none()].into_iter().all(|x| x)
+ {
+ self.features_vulkan_memory_model = Some(Default::default());
+ let member = self.features_vulkan_memory_model.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= crate::Version::V1_3,
+ device_extensions.khr_dynamic_rendering,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.features_vulkan13.is_none()].into_iter().all(|x| x)
+ {
+ self.features_dynamic_rendering = Some(Default::default());
+ let member = self.features_dynamic_rendering.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= crate::Version::V1_3,
+ device_extensions.ext_image_robustness,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.features_vulkan13.is_none()].into_iter().all(|x| x)
+ {
+ self.features_image_robustness = Some(Default::default());
+ let member = self.features_image_robustness.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= crate::Version::V1_3,
+ device_extensions.ext_inline_uniform_block,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.features_vulkan13.is_none()].into_iter().all(|x| x)
+ {
+ self.features_inline_uniform_block = Some(Default::default());
+ let member = self.features_inline_uniform_block.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= crate::Version::V1_3,
+ device_extensions.khr_maintenance4,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.features_vulkan13.is_none()].into_iter().all(|x| x)
+ {
+ self.features_maintenance4 = Some(Default::default());
+ let member = self.features_maintenance4.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= crate::Version::V1_3,
+ device_extensions.ext_pipeline_creation_cache_control,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.features_vulkan13.is_none()].into_iter().all(|x| x)
+ {
+ self.features_pipeline_creation_cache_control = Some(Default::default());
+ let member = self
+ .features_pipeline_creation_cache_control
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= crate::Version::V1_3,
+ device_extensions.ext_private_data,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.features_vulkan13.is_none()].into_iter().all(|x| x)
+ {
+ self.features_private_data = Some(Default::default());
+ let member = self.features_private_data.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= crate::Version::V1_3,
+ device_extensions.ext_shader_demote_to_helper_invocation,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.features_vulkan13.is_none()].into_iter().all(|x| x)
+ {
+ self.features_shader_demote_to_helper_invocation = Some(Default::default());
+ let member = self
+ .features_shader_demote_to_helper_invocation
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= crate::Version::V1_3,
+ device_extensions.khr_shader_integer_dot_product,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.features_vulkan13.is_none()].into_iter().all(|x| x)
+ {
+ self.features_shader_integer_dot_product = Some(Default::default());
+ let member = self.features_shader_integer_dot_product.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= crate::Version::V1_3,
+ device_extensions.khr_shader_terminate_invocation,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.features_vulkan13.is_none()].into_iter().all(|x| x)
+ {
+ self.features_shader_terminate_invocation = Some(Default::default());
+ let member = self.features_shader_terminate_invocation.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= crate::Version::V1_3,
+ device_extensions.ext_subgroup_size_control,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.features_vulkan13.is_none()].into_iter().all(|x| x)
+ {
+ self.features_subgroup_size_control = Some(Default::default());
+ let member = self.features_subgroup_size_control.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= crate::Version::V1_3,
+ device_extensions.khr_synchronization2,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.features_vulkan13.is_none()].into_iter().all(|x| x)
+ {
+ self.features_synchronization2 = Some(Default::default());
+ let member = self.features_synchronization2.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= crate::Version::V1_3,
+ device_extensions.ext_texture_compression_astc_hdr,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.features_vulkan13.is_none()].into_iter().all(|x| x)
+ {
+ self.features_texture_compression_astchdr = Some(Default::default());
+ let member = self.features_texture_compression_astchdr.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= crate::Version::V1_3,
+ device_extensions.khr_zero_initialize_workgroup_memory,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.features_vulkan13.is_none()].into_iter().all(|x| x)
+ {
+ self.features_zero_initialize_workgroup_memory = Some(Default::default());
+ let member = self
+ .features_zero_initialize_workgroup_memory
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.khr_acceleration_structure]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_acceleration_structure_khr = Some(Default::default());
+ let member = self.features_acceleration_structure_khr.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ device_extensions.khr_fragment_shader_barycentric,
+ device_extensions.nv_fragment_shader_barycentric,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_fragment_shader_barycentric_khr = Some(Default::default());
+ let member = self
+ .features_fragment_shader_barycentric_khr
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.khr_fragment_shading_rate]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_fragment_shading_rate_khr = Some(Default::default());
+ let member = self.features_fragment_shading_rate_khr.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ device_extensions.khr_global_priority,
+ device_extensions.ext_global_priority_query,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_global_priority_query_khr = Some(Default::default());
+ let member = self.features_global_priority_query_khr.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.khr_performance_query]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_performance_query_khr = Some(Default::default());
+ let member = self.features_performance_query_khr.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.khr_pipeline_executable_properties]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_pipeline_executable_properties_khr = Some(Default::default());
+ let member = self
+ .features_pipeline_executable_properties_khr
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.khr_portability_subset]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_portability_subset_khr = Some(Default::default());
+ let member = self.features_portability_subset_khr.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.khr_present_id].into_iter().any(|x| x) && [].into_iter().all(|x| x) {
+ self.features_present_id_khr = Some(Default::default());
+ let member = self.features_present_id_khr.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.khr_present_wait].into_iter().any(|x| x) && [].into_iter().all(|x| x)
+ {
+ self.features_present_wait_khr = Some(Default::default());
+ let member = self.features_present_wait_khr.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.khr_ray_query].into_iter().any(|x| x) && [].into_iter().all(|x| x) {
+ self.features_ray_query_khr = Some(Default::default());
+ let member = self.features_ray_query_khr.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.khr_ray_tracing_maintenance1]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_ray_tracing_maintenance1_khr = Some(Default::default());
+ let member = self.features_ray_tracing_maintenance1_khr.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.khr_ray_tracing_pipeline]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_ray_tracing_pipeline_khr = Some(Default::default());
+ let member = self.features_ray_tracing_pipeline_khr.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.khr_shader_clock].into_iter().any(|x| x) && [].into_iter().all(|x| x)
+ {
+ self.features_shader_clock_khr = Some(Default::default());
+ let member = self.features_shader_clock_khr.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.khr_shader_subgroup_uniform_control_flow]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_shader_subgroup_uniform_control_flow_khr = Some(Default::default());
+ let member = self
+ .features_shader_subgroup_uniform_control_flow_khr
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.khr_workgroup_memory_explicit_layout]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_workgroup_memory_explicit_layout_khr = Some(Default::default());
+ let member = self
+ .features_workgroup_memory_explicit_layout_khr
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_4444_formats].into_iter().any(|x| x) && [].into_iter().all(|x| x)
+ {
+ self.features_4444formats_ext = Some(Default::default());
+ let member = self.features_4444formats_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_astc_decode_mode]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_astc_decode_ext = Some(Default::default());
+ let member = self.features_astc_decode_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_device_address_binding_report]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_address_binding_report_ext = Some(Default::default());
+ let member = self.features_address_binding_report_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_attachment_feedback_loop_layout]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_attachment_feedback_loop_layout_ext = Some(Default::default());
+ let member = self
+ .features_attachment_feedback_loop_layout_ext
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_blend_operation_advanced]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_blend_operation_advanced_ext = Some(Default::default());
+ let member = self.features_blend_operation_advanced_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_border_color_swizzle]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_border_color_swizzle_ext = Some(Default::default());
+ let member = self.features_border_color_swizzle_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_buffer_device_address]
+ .into_iter()
+ .any(|x| x)
+ && [
+ self.features_vulkan12.is_none(),
+ self.features_buffer_device_address.is_none(),
+ ]
+ .into_iter()
+ .all(|x| x)
+ {
+ self.features_buffer_device_address_ext = Some(Default::default());
+ let member = self.features_buffer_device_address_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_color_write_enable]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_color_write_enable_ext = Some(Default::default());
+ let member = self.features_color_write_enable_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_conditional_rendering]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_conditional_rendering_ext = Some(Default::default());
+ let member = self.features_conditional_rendering_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_custom_border_color]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_custom_border_color_ext = Some(Default::default());
+ let member = self.features_custom_border_color_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_depth_clamp_zero_one]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_depth_clamp_zero_one_ext = Some(Default::default());
+ let member = self.features_depth_clamp_zero_one_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_depth_clip_control]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_depth_clip_control_ext = Some(Default::default());
+ let member = self.features_depth_clip_control_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_depth_clip_enable]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_depth_clip_enable_ext = Some(Default::default());
+ let member = self.features_depth_clip_enable_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_descriptor_buffer]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_descriptor_buffer_ext = Some(Default::default());
+ let member = self.features_descriptor_buffer_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_device_memory_report]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_device_memory_report_ext = Some(Default::default());
+ let member = self.features_device_memory_report_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_extended_dynamic_state2]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_extended_dynamic_state2_ext = Some(Default::default());
+ let member = self.features_extended_dynamic_state2_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_extended_dynamic_state3]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_extended_dynamic_state3_ext = Some(Default::default());
+ let member = self.features_extended_dynamic_state3_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_extended_dynamic_state]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_extended_dynamic_state_ext = Some(Default::default());
+ let member = self.features_extended_dynamic_state_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_device_fault].into_iter().any(|x| x) && [].into_iter().all(|x| x)
+ {
+ self.features_fault_ext = Some(Default::default());
+ let member = self.features_fault_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_fragment_density_map2]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_fragment_density_map2_ext = Some(Default::default());
+ let member = self.features_fragment_density_map2_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_fragment_density_map]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_fragment_density_map_ext = Some(Default::default());
+ let member = self.features_fragment_density_map_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_fragment_shader_interlock]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_fragment_shader_interlock_ext = Some(Default::default());
+ let member = self
+ .features_fragment_shader_interlock_ext
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_graphics_pipeline_library]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_graphics_pipeline_library_ext = Some(Default::default());
+ let member = self
+ .features_graphics_pipeline_library_ext
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_image_2d_view_of_3d]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_image2_d_view_of3_d_ext = Some(Default::default());
+ let member = self.features_image2_d_view_of3_d_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_image_compression_control]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_image_compression_control_ext = Some(Default::default());
+ let member = self
+ .features_image_compression_control_ext
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_image_compression_control_swapchain]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_image_compression_control_swapchain_ext = Some(Default::default());
+ let member = self
+ .features_image_compression_control_swapchain_ext
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_image_view_min_lod]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_image_view_min_lod_ext = Some(Default::default());
+ let member = self.features_image_view_min_lod_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_index_type_uint8]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_index_type_uint8_ext = Some(Default::default());
+ let member = self.features_index_type_uint8_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_legacy_dithering]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_legacy_dithering_ext = Some(Default::default());
+ let member = self.features_legacy_dithering_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_line_rasterization]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_line_rasterization_ext = Some(Default::default());
+ let member = self.features_line_rasterization_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_memory_priority]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_memory_priority_ext = Some(Default::default());
+ let member = self.features_memory_priority_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_mesh_shader].into_iter().any(|x| x) && [].into_iter().all(|x| x) {
+ self.features_mesh_shader_ext = Some(Default::default());
+ let member = self.features_mesh_shader_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_multi_draw].into_iter().any(|x| x) && [].into_iter().all(|x| x) {
+ self.features_multi_draw_ext = Some(Default::default());
+ let member = self.features_multi_draw_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_multisampled_render_to_single_sampled]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_multisampled_render_to_single_sampled_ext = Some(Default::default());
+ let member = self
+ .features_multisampled_render_to_single_sampled_ext
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ device_extensions.ext_mutable_descriptor_type,
+ device_extensions.valve_mutable_descriptor_type,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_mutable_descriptor_type_ext = Some(Default::default());
+ let member = self.features_mutable_descriptor_type_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_non_seamless_cube_map]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_non_seamless_cube_map_ext = Some(Default::default());
+ let member = self.features_non_seamless_cube_map_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_opacity_micromap]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_opacity_micromap_ext = Some(Default::default());
+ let member = self.features_opacity_micromap_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_pageable_device_local_memory]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_pageable_device_local_memory_ext = Some(Default::default());
+ let member = self
+ .features_pageable_device_local_memory_ext
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_pipeline_properties]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_pipeline_properties_ext = Some(Default::default());
+ let member = self.features_pipeline_properties_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_pipeline_protected_access]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_pipeline_protected_access_ext = Some(Default::default());
+ let member = self
+ .features_pipeline_protected_access_ext
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_pipeline_robustness]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_pipeline_robustness_ext = Some(Default::default());
+ let member = self.features_pipeline_robustness_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_primitive_topology_list_restart]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_primitive_topology_list_restart_ext = Some(Default::default());
+ let member = self
+ .features_primitive_topology_list_restart_ext
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_primitives_generated_query]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_primitives_generated_query_ext = Some(Default::default());
+ let member = self
+ .features_primitives_generated_query_ext
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_provoking_vertex]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_provoking_vertex_ext = Some(Default::default());
+ let member = self.features_provoking_vertex_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_rgba10x6_formats]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_rgba10x6_formats_ext = Some(Default::default());
+ let member = self.features_rgba10x6_formats_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ device_extensions.ext_rasterization_order_attachment_access,
+ device_extensions.arm_rasterization_order_attachment_access,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_rasterization_order_attachment_access_ext = Some(Default::default());
+ let member = self
+ .features_rasterization_order_attachment_access_ext
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_robustness2].into_iter().any(|x| x) && [].into_iter().all(|x| x) {
+ self.features_robustness2_ext = Some(Default::default());
+ let member = self.features_robustness2_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_shader_atomic_float2]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_shader_atomic_float2_ext = Some(Default::default());
+ let member = self.features_shader_atomic_float2_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_shader_atomic_float]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_shader_atomic_float_ext = Some(Default::default());
+ let member = self.features_shader_atomic_float_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_shader_image_atomic_int64]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_shader_image_atomic_int64_ext = Some(Default::default());
+ let member = self
+ .features_shader_image_atomic_int64_ext
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_shader_module_identifier]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_shader_module_identifier_ext = Some(Default::default());
+ let member = self.features_shader_module_identifier_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_subpass_merge_feedback]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_subpass_merge_feedback_ext = Some(Default::default());
+ let member = self.features_subpass_merge_feedback_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_swapchain_maintenance1]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_swapchain_maintenance1_ext = Some(Default::default());
+ let member = self.features_swapchain_maintenance1_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_texel_buffer_alignment]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_texel_buffer_alignment_ext = Some(Default::default());
+ let member = self.features_texel_buffer_alignment_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_transform_feedback]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_transform_feedback_ext = Some(Default::default());
+ let member = self.features_transform_feedback_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_vertex_attribute_divisor]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_vertex_attribute_divisor_ext = Some(Default::default());
+ let member = self.features_vertex_attribute_divisor_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_vertex_input_dynamic_state]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_vertex_input_dynamic_state_ext = Some(Default::default());
+ let member = self
+ .features_vertex_input_dynamic_state_ext
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_ycbcr_2plane_444_formats]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_ycbcr2_plane444_formats_ext = Some(Default::default());
+ let member = self.features_ycbcr2_plane444_formats_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_ycbcr_image_arrays]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_ycbcr_image_arrays_ext = Some(Default::default());
+ let member = self.features_ycbcr_image_arrays_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.sec_amigo_profiling]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_amigo_profiling_sec = Some(Default::default());
+ let member = self.features_amigo_profiling_sec.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.amd_device_coherent_memory]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_coherent_memory_amd = Some(Default::default());
+ let member = self.features_coherent_memory_amd.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_compute_shader_derivatives]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_compute_shader_derivatives_nv = Some(Default::default());
+ let member = self
+ .features_compute_shader_derivatives_nv
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_cooperative_matrix]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_cooperative_matrix_nv = Some(Default::default());
+ let member = self.features_cooperative_matrix_nv.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_copy_memory_indirect]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_copy_memory_indirect_nv = Some(Default::default());
+ let member = self.features_copy_memory_indirect_nv.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_corner_sampled_image]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_corner_sampled_image_nv = Some(Default::default());
+ let member = self.features_corner_sampled_image_nv.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_coverage_reduction_mode]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_coverage_reduction_mode_nv = Some(Default::default());
+ let member = self.features_coverage_reduction_mode_nv.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_dedicated_allocation_image_aliasing]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_dedicated_allocation_image_aliasing_nv = Some(Default::default());
+ let member = self
+ .features_dedicated_allocation_image_aliasing_nv
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.valve_descriptor_set_host_mapping]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_descriptor_set_host_mapping_valve = Some(Default::default());
+ let member = self
+ .features_descriptor_set_host_mapping_valve
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_device_generated_commands]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_device_generated_commands_nv = Some(Default::default());
+ let member = self.features_device_generated_commands_nv.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_device_diagnostics_config]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_diagnostics_config_nv = Some(Default::default());
+ let member = self.features_diagnostics_config_nv.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_scissor_exclusive]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_exclusive_scissor_nv = Some(Default::default());
+ let member = self.features_exclusive_scissor_nv.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_external_memory_rdma]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_external_memory_rdma_nv = Some(Default::default());
+ let member = self.features_external_memory_rdma_nv.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.qcom_fragment_density_map_offset]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_fragment_density_map_offset_qcom = Some(Default::default());
+ let member = self
+ .features_fragment_density_map_offset_qcom
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_fragment_shading_rate_enums]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_fragment_shading_rate_enums_nv = Some(Default::default());
+ let member = self
+ .features_fragment_shading_rate_enums_nv
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.qcom_image_processing]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_image_processing_qcom = Some(Default::default());
+ let member = self.features_image_processing_qcom.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_inherited_viewport_scissor]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_inherited_viewport_scissor_nv = Some(Default::default());
+ let member = self
+ .features_inherited_viewport_scissor_nv
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.huawei_invocation_mask]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_invocation_mask_huawei = Some(Default::default());
+ let member = self.features_invocation_mask_huawei.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_linear_color_attachment]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_linear_color_attachment_nv = Some(Default::default());
+ let member = self.features_linear_color_attachment_nv.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_memory_decompression]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_memory_decompression_nv = Some(Default::default());
+ let member = self.features_memory_decompression_nv.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_mesh_shader].into_iter().any(|x| x)
+ && [self.features_mesh_shader_ext.is_none()]
+ .into_iter()
+ .all(|x| x)
+ {
+ self.features_mesh_shader_nv = Some(Default::default());
+ let member = self.features_mesh_shader_nv.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.qcom_multiview_per_view_viewports]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_multiview_per_view_viewports_qcom = Some(Default::default());
+ let member = self
+ .features_multiview_per_view_viewports_qcom
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_optical_flow].into_iter().any(|x| x) && [].into_iter().all(|x| x) {
+ self.features_optical_flow_nv = Some(Default::default());
+ let member = self.features_optical_flow_nv.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_present_barrier]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_present_barrier_nv = Some(Default::default());
+ let member = self.features_present_barrier_nv.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_ray_tracing_invocation_reorder]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_ray_tracing_invocation_reorder_nv = Some(Default::default());
+ let member = self
+ .features_ray_tracing_invocation_reorder_nv
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_ray_tracing_motion_blur]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_ray_tracing_motion_blur_nv = Some(Default::default());
+ let member = self.features_ray_tracing_motion_blur_nv.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_representative_fragment_test]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_representative_fragment_test_nv = Some(Default::default());
+ let member = self
+ .features_representative_fragment_test_nv
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.arm_shader_core_builtins]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_shader_core_builtins_arm = Some(Default::default());
+ let member = self.features_shader_core_builtins_arm.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.amd_shader_early_and_late_fragment_tests]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_shader_early_and_late_fragment_tests_amd = Some(Default::default());
+ let member = self
+ .features_shader_early_and_late_fragment_tests_amd
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_shader_image_footprint]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_shader_image_footprint_nv = Some(Default::default());
+ let member = self.features_shader_image_footprint_nv.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.intel_shader_integer_functions2]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_shader_integer_functions2_intel = Some(Default::default());
+ let member = self
+ .features_shader_integer_functions2_intel
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_shader_sm_builtins]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_shader_sm_builtins_nv = Some(Default::default());
+ let member = self.features_shader_sm_builtins_nv.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_shading_rate_image]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_shading_rate_image_nv = Some(Default::default());
+ let member = self.features_shading_rate_image_nv.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.huawei_subpass_shading]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_subpass_shading_huawei = Some(Default::default());
+ let member = self.features_subpass_shading_huawei.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.qcom_tile_properties]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.features_tile_properties_qcom = Some(Default::default());
+ let member = self.features_tile_properties_qcom.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ }
+ pub(crate) fn head_as_ref(&self) -> &ash::vk::PhysicalDeviceFeatures2KHR {
+ &self.features_vulkan10
+ }
+ pub(crate) fn head_as_mut(&mut self) -> &mut ash::vk::PhysicalDeviceFeatures2KHR {
+ &mut self.features_vulkan10
+ }
+}
diff --git a/out/fns.rs b/out/fns.rs
new file mode 100644
index 0000000..0a2fe6f
--- /dev/null
+++ b/out/fns.rs
@@ -0,0 +1,408 @@
+// This file is auto-generated by vulkano autogen from vk.xml header version 1.3.238.
+// It should not be edited manually. Changes should be made by editing autogen.
+
+#[doc = "Raw Vulkan global entry point-level functions.\n\nTo use these, you need to include the Ash crate, using the same version Vulkano uses."]
+#[allow(missing_docs)]
+pub struct EntryFunctions {
+ pub v1_0: ash::vk::EntryFnV1_0,
+ pub v1_1: ash::vk::EntryFnV1_1,
+ pub v1_2: ash::vk::EntryFnV1_2,
+ pub v1_3: ash::vk::EntryFnV1_3,
+ pub _ne: crate::NonExhaustive,
+}
+impl EntryFunctions {
+ pub(crate) fn load<F>(mut load_fn: F) -> EntryFunctions
+ where
+ F: FnMut(&CStr) -> *const c_void,
+ {
+ EntryFunctions {
+ v1_0: ash::vk::EntryFnV1_0::load(&mut load_fn),
+ v1_1: ash::vk::EntryFnV1_1::load(&mut load_fn),
+ v1_2: ash::vk::EntryFnV1_2::load(&mut load_fn),
+ v1_3: ash::vk::EntryFnV1_3::load(&mut load_fn),
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+impl std::fmt::Debug for EntryFunctions {
+ #[inline]
+ fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
+ Ok(())
+ }
+}
+#[doc = "Raw Vulkan instance-level functions.\n\nTo use these, you need to include the Ash crate, using the same version Vulkano uses."]
+#[allow(missing_docs)]
+pub struct InstanceFunctions {
+ pub v1_0: ash::vk::InstanceFnV1_0,
+ pub v1_1: ash::vk::InstanceFnV1_1,
+ pub v1_2: ash::vk::InstanceFnV1_2,
+ pub v1_3: ash::vk::InstanceFnV1_3,
+ pub khr_android_surface: ash::vk::KhrAndroidSurfaceFn,
+ pub khr_device_group: ash::vk::KhrDeviceGroupFn,
+ pub khr_device_group_creation: ash::vk::KhrDeviceGroupCreationFn,
+ pub khr_display: ash::vk::KhrDisplayFn,
+ pub khr_external_fence_capabilities: ash::vk::KhrExternalFenceCapabilitiesFn,
+ pub khr_external_memory_capabilities: ash::vk::KhrExternalMemoryCapabilitiesFn,
+ pub khr_external_semaphore_capabilities: ash::vk::KhrExternalSemaphoreCapabilitiesFn,
+ pub khr_fragment_shading_rate: ash::vk::KhrFragmentShadingRateFn,
+ pub khr_get_display_properties2: ash::vk::KhrGetDisplayProperties2Fn,
+ pub khr_get_physical_device_properties2: ash::vk::KhrGetPhysicalDeviceProperties2Fn,
+ pub khr_get_surface_capabilities2: ash::vk::KhrGetSurfaceCapabilities2Fn,
+ pub khr_performance_query: ash::vk::KhrPerformanceQueryFn,
+ pub khr_surface: ash::vk::KhrSurfaceFn,
+ pub khr_swapchain: ash::vk::KhrSwapchainFn,
+ pub khr_video_queue: ash::vk::KhrVideoQueueFn,
+ pub khr_wayland_surface: ash::vk::KhrWaylandSurfaceFn,
+ pub khr_win32_surface: ash::vk::KhrWin32SurfaceFn,
+ pub khr_xcb_surface: ash::vk::KhrXcbSurfaceFn,
+ pub khr_xlib_surface: ash::vk::KhrXlibSurfaceFn,
+ pub ext_acquire_drm_display: ash::vk::ExtAcquireDrmDisplayFn,
+ pub ext_acquire_xlib_display: ash::vk::ExtAcquireXlibDisplayFn,
+ pub ext_calibrated_timestamps: ash::vk::ExtCalibratedTimestampsFn,
+ pub ext_debug_report: ash::vk::ExtDebugReportFn,
+ pub ext_debug_utils: ash::vk::ExtDebugUtilsFn,
+ pub ext_direct_mode_display: ash::vk::ExtDirectModeDisplayFn,
+ pub ext_directfb_surface: ash::vk::ExtDirectfbSurfaceFn,
+ pub ext_display_surface_counter: ash::vk::ExtDisplaySurfaceCounterFn,
+ pub ext_full_screen_exclusive: ash::vk::ExtFullScreenExclusiveFn,
+ pub ext_headless_surface: ash::vk::ExtHeadlessSurfaceFn,
+ pub ext_metal_surface: ash::vk::ExtMetalSurfaceFn,
+ pub ext_sample_locations: ash::vk::ExtSampleLocationsFn,
+ pub ext_tooling_info: ash::vk::ExtToolingInfoFn,
+ pub fuchsia_imagepipe_surface: ash::vk::FuchsiaImagepipeSurfaceFn,
+ pub ggp_stream_descriptor_surface: ash::vk::GgpStreamDescriptorSurfaceFn,
+ pub mvk_ios_surface: ash::vk::MvkIosSurfaceFn,
+ pub mvk_macos_surface: ash::vk::MvkMacosSurfaceFn,
+ pub nn_vi_surface: ash::vk::NnViSurfaceFn,
+ pub nv_cooperative_matrix: ash::vk::NvCooperativeMatrixFn,
+ pub nv_coverage_reduction_mode: ash::vk::NvCoverageReductionModeFn,
+ pub nv_external_memory_capabilities: ash::vk::NvExternalMemoryCapabilitiesFn,
+ pub nv_optical_flow: ash::vk::NvOpticalFlowFn,
+ pub qnx_screen_surface: ash::vk::QnxScreenSurfaceFn,
+ pub _ne: crate::NonExhaustive,
+}
+impl InstanceFunctions {
+ pub(crate) fn load<F>(mut load_fn: F) -> InstanceFunctions
+ where
+ F: FnMut(&CStr) -> *const c_void,
+ {
+ InstanceFunctions {
+ v1_0: ash::vk::InstanceFnV1_0::load(&mut load_fn),
+ v1_1: ash::vk::InstanceFnV1_1::load(&mut load_fn),
+ v1_2: ash::vk::InstanceFnV1_2::load(&mut load_fn),
+ v1_3: ash::vk::InstanceFnV1_3::load(&mut load_fn),
+ khr_android_surface: ash::vk::KhrAndroidSurfaceFn::load(&mut load_fn),
+ khr_device_group: ash::vk::KhrDeviceGroupFn::load(&mut load_fn),
+ khr_device_group_creation: ash::vk::KhrDeviceGroupCreationFn::load(&mut load_fn),
+ khr_display: ash::vk::KhrDisplayFn::load(&mut load_fn),
+ khr_external_fence_capabilities: ash::vk::KhrExternalFenceCapabilitiesFn::load(
+ &mut load_fn,
+ ),
+ khr_external_memory_capabilities: ash::vk::KhrExternalMemoryCapabilitiesFn::load(
+ &mut load_fn,
+ ),
+ khr_external_semaphore_capabilities: ash::vk::KhrExternalSemaphoreCapabilitiesFn::load(
+ &mut load_fn,
+ ),
+ khr_fragment_shading_rate: ash::vk::KhrFragmentShadingRateFn::load(&mut load_fn),
+ khr_get_display_properties2: ash::vk::KhrGetDisplayProperties2Fn::load(&mut load_fn),
+ khr_get_physical_device_properties2: ash::vk::KhrGetPhysicalDeviceProperties2Fn::load(
+ &mut load_fn,
+ ),
+ khr_get_surface_capabilities2: ash::vk::KhrGetSurfaceCapabilities2Fn::load(
+ &mut load_fn,
+ ),
+ khr_performance_query: ash::vk::KhrPerformanceQueryFn::load(&mut load_fn),
+ khr_surface: ash::vk::KhrSurfaceFn::load(&mut load_fn),
+ khr_swapchain: ash::vk::KhrSwapchainFn::load(&mut load_fn),
+ khr_video_queue: ash::vk::KhrVideoQueueFn::load(&mut load_fn),
+ khr_wayland_surface: ash::vk::KhrWaylandSurfaceFn::load(&mut load_fn),
+ khr_win32_surface: ash::vk::KhrWin32SurfaceFn::load(&mut load_fn),
+ khr_xcb_surface: ash::vk::KhrXcbSurfaceFn::load(&mut load_fn),
+ khr_xlib_surface: ash::vk::KhrXlibSurfaceFn::load(&mut load_fn),
+ ext_acquire_drm_display: ash::vk::ExtAcquireDrmDisplayFn::load(&mut load_fn),
+ ext_acquire_xlib_display: ash::vk::ExtAcquireXlibDisplayFn::load(&mut load_fn),
+ ext_calibrated_timestamps: ash::vk::ExtCalibratedTimestampsFn::load(&mut load_fn),
+ ext_debug_report: ash::vk::ExtDebugReportFn::load(&mut load_fn),
+ ext_debug_utils: ash::vk::ExtDebugUtilsFn::load(&mut load_fn),
+ ext_direct_mode_display: ash::vk::ExtDirectModeDisplayFn::load(&mut load_fn),
+ ext_directfb_surface: ash::vk::ExtDirectfbSurfaceFn::load(&mut load_fn),
+ ext_display_surface_counter: ash::vk::ExtDisplaySurfaceCounterFn::load(&mut load_fn),
+ ext_full_screen_exclusive: ash::vk::ExtFullScreenExclusiveFn::load(&mut load_fn),
+ ext_headless_surface: ash::vk::ExtHeadlessSurfaceFn::load(&mut load_fn),
+ ext_metal_surface: ash::vk::ExtMetalSurfaceFn::load(&mut load_fn),
+ ext_sample_locations: ash::vk::ExtSampleLocationsFn::load(&mut load_fn),
+ ext_tooling_info: ash::vk::ExtToolingInfoFn::load(&mut load_fn),
+ fuchsia_imagepipe_surface: ash::vk::FuchsiaImagepipeSurfaceFn::load(&mut load_fn),
+ ggp_stream_descriptor_surface: ash::vk::GgpStreamDescriptorSurfaceFn::load(
+ &mut load_fn,
+ ),
+ mvk_ios_surface: ash::vk::MvkIosSurfaceFn::load(&mut load_fn),
+ mvk_macos_surface: ash::vk::MvkMacosSurfaceFn::load(&mut load_fn),
+ nn_vi_surface: ash::vk::NnViSurfaceFn::load(&mut load_fn),
+ nv_cooperative_matrix: ash::vk::NvCooperativeMatrixFn::load(&mut load_fn),
+ nv_coverage_reduction_mode: ash::vk::NvCoverageReductionModeFn::load(&mut load_fn),
+ nv_external_memory_capabilities: ash::vk::NvExternalMemoryCapabilitiesFn::load(
+ &mut load_fn,
+ ),
+ nv_optical_flow: ash::vk::NvOpticalFlowFn::load(&mut load_fn),
+ qnx_screen_surface: ash::vk::QnxScreenSurfaceFn::load(&mut load_fn),
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+impl std::fmt::Debug for InstanceFunctions {
+ #[inline]
+ fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
+ Ok(())
+ }
+}
+#[doc = "Raw Vulkan device-level functions.\n\nTo use these, you need to include the Ash crate, using the same version Vulkano uses."]
+#[allow(missing_docs)]
+pub struct DeviceFunctions {
+ pub v1_0: ash::vk::DeviceFnV1_0,
+ pub v1_1: ash::vk::DeviceFnV1_1,
+ pub v1_2: ash::vk::DeviceFnV1_2,
+ pub v1_3: ash::vk::DeviceFnV1_3,
+ pub khr_acceleration_structure: ash::vk::KhrAccelerationStructureFn,
+ pub khr_bind_memory2: ash::vk::KhrBindMemory2Fn,
+ pub khr_buffer_device_address: ash::vk::KhrBufferDeviceAddressFn,
+ pub khr_copy_commands2: ash::vk::KhrCopyCommands2Fn,
+ pub khr_create_renderpass2: ash::vk::KhrCreateRenderpass2Fn,
+ pub khr_deferred_host_operations: ash::vk::KhrDeferredHostOperationsFn,
+ pub khr_descriptor_update_template: ash::vk::KhrDescriptorUpdateTemplateFn,
+ pub khr_device_group: ash::vk::KhrDeviceGroupFn,
+ pub khr_display_swapchain: ash::vk::KhrDisplaySwapchainFn,
+ pub khr_draw_indirect_count: ash::vk::KhrDrawIndirectCountFn,
+ pub khr_dynamic_rendering: ash::vk::KhrDynamicRenderingFn,
+ pub khr_external_fence_fd: ash::vk::KhrExternalFenceFdFn,
+ pub khr_external_fence_win32: ash::vk::KhrExternalFenceWin32Fn,
+ pub khr_external_memory_fd: ash::vk::KhrExternalMemoryFdFn,
+ pub khr_external_memory_win32: ash::vk::KhrExternalMemoryWin32Fn,
+ pub khr_external_semaphore_fd: ash::vk::KhrExternalSemaphoreFdFn,
+ pub khr_external_semaphore_win32: ash::vk::KhrExternalSemaphoreWin32Fn,
+ pub khr_fragment_shading_rate: ash::vk::KhrFragmentShadingRateFn,
+ pub khr_get_memory_requirements2: ash::vk::KhrGetMemoryRequirements2Fn,
+ pub khr_maintenance1: ash::vk::KhrMaintenance1Fn,
+ pub khr_maintenance3: ash::vk::KhrMaintenance3Fn,
+ pub khr_maintenance4: ash::vk::KhrMaintenance4Fn,
+ pub khr_performance_query: ash::vk::KhrPerformanceQueryFn,
+ pub khr_pipeline_executable_properties: ash::vk::KhrPipelineExecutablePropertiesFn,
+ pub khr_present_wait: ash::vk::KhrPresentWaitFn,
+ pub khr_push_descriptor: ash::vk::KhrPushDescriptorFn,
+ pub khr_ray_tracing_maintenance1: ash::vk::KhrRayTracingMaintenance1Fn,
+ pub khr_ray_tracing_pipeline: ash::vk::KhrRayTracingPipelineFn,
+ pub khr_sampler_ycbcr_conversion: ash::vk::KhrSamplerYcbcrConversionFn,
+ pub khr_shared_presentable_image: ash::vk::KhrSharedPresentableImageFn,
+ pub khr_swapchain: ash::vk::KhrSwapchainFn,
+ pub khr_synchronization2: ash::vk::KhrSynchronization2Fn,
+ pub khr_timeline_semaphore: ash::vk::KhrTimelineSemaphoreFn,
+ pub khr_video_decode_queue: ash::vk::KhrVideoDecodeQueueFn,
+ pub khr_video_encode_queue: ash::vk::KhrVideoEncodeQueueFn,
+ pub khr_video_queue: ash::vk::KhrVideoQueueFn,
+ pub ext_buffer_device_address: ash::vk::ExtBufferDeviceAddressFn,
+ pub ext_calibrated_timestamps: ash::vk::ExtCalibratedTimestampsFn,
+ pub ext_color_write_enable: ash::vk::ExtColorWriteEnableFn,
+ pub ext_conditional_rendering: ash::vk::ExtConditionalRenderingFn,
+ pub ext_debug_marker: ash::vk::ExtDebugMarkerFn,
+ pub ext_descriptor_buffer: ash::vk::ExtDescriptorBufferFn,
+ pub ext_device_fault: ash::vk::ExtDeviceFaultFn,
+ pub ext_discard_rectangles: ash::vk::ExtDiscardRectanglesFn,
+ pub ext_display_control: ash::vk::ExtDisplayControlFn,
+ pub ext_extended_dynamic_state: ash::vk::ExtExtendedDynamicStateFn,
+ pub ext_extended_dynamic_state2: ash::vk::ExtExtendedDynamicState2Fn,
+ pub ext_extended_dynamic_state3: ash::vk::ExtExtendedDynamicState3Fn,
+ pub ext_external_memory_host: ash::vk::ExtExternalMemoryHostFn,
+ pub ext_full_screen_exclusive: ash::vk::ExtFullScreenExclusiveFn,
+ pub ext_hdr_metadata: ash::vk::ExtHdrMetadataFn,
+ pub ext_host_query_reset: ash::vk::ExtHostQueryResetFn,
+ pub ext_image_compression_control: ash::vk::ExtImageCompressionControlFn,
+ pub ext_image_drm_format_modifier: ash::vk::ExtImageDrmFormatModifierFn,
+ pub ext_line_rasterization: ash::vk::ExtLineRasterizationFn,
+ pub ext_mesh_shader: ash::vk::ExtMeshShaderFn,
+ pub ext_metal_objects: ash::vk::ExtMetalObjectsFn,
+ pub ext_multi_draw: ash::vk::ExtMultiDrawFn,
+ pub ext_opacity_micromap: ash::vk::ExtOpacityMicromapFn,
+ pub ext_pageable_device_local_memory: ash::vk::ExtPageableDeviceLocalMemoryFn,
+ pub ext_pipeline_properties: ash::vk::ExtPipelinePropertiesFn,
+ pub ext_private_data: ash::vk::ExtPrivateDataFn,
+ pub ext_sample_locations: ash::vk::ExtSampleLocationsFn,
+ pub ext_shader_module_identifier: ash::vk::ExtShaderModuleIdentifierFn,
+ pub ext_swapchain_maintenance1: ash::vk::ExtSwapchainMaintenance1Fn,
+ pub ext_tooling_info: ash::vk::ExtToolingInfoFn,
+ pub ext_transform_feedback: ash::vk::ExtTransformFeedbackFn,
+ pub ext_validation_cache: ash::vk::ExtValidationCacheFn,
+ pub ext_vertex_input_dynamic_state: ash::vk::ExtVertexInputDynamicStateFn,
+ pub amd_buffer_marker: ash::vk::AmdBufferMarkerFn,
+ pub amd_display_native_hdr: ash::vk::AmdDisplayNativeHdrFn,
+ pub amd_draw_indirect_count: ash::vk::AmdDrawIndirectCountFn,
+ pub amd_shader_info: ash::vk::AmdShaderInfoFn,
+ pub android_external_memory_android_hardware_buffer:
+ ash::vk::AndroidExternalMemoryAndroidHardwareBufferFn,
+ pub fuchsia_buffer_collection: ash::vk::FuchsiaBufferCollectionFn,
+ pub fuchsia_external_memory: ash::vk::FuchsiaExternalMemoryFn,
+ pub fuchsia_external_semaphore: ash::vk::FuchsiaExternalSemaphoreFn,
+ pub google_display_timing: ash::vk::GoogleDisplayTimingFn,
+ pub huawei_invocation_mask: ash::vk::HuaweiInvocationMaskFn,
+ pub huawei_subpass_shading: ash::vk::HuaweiSubpassShadingFn,
+ pub intel_performance_query: ash::vk::IntelPerformanceQueryFn,
+ pub nvx_binary_import: ash::vk::NvxBinaryImportFn,
+ pub nvx_image_view_handle: ash::vk::NvxImageViewHandleFn,
+ pub nv_acquire_winrt_display: ash::vk::NvAcquireWinrtDisplayFn,
+ pub nv_clip_space_w_scaling: ash::vk::NvClipSpaceWScalingFn,
+ pub nv_cooperative_matrix: ash::vk::NvCooperativeMatrixFn,
+ pub nv_copy_memory_indirect: ash::vk::NvCopyMemoryIndirectFn,
+ pub nv_coverage_reduction_mode: ash::vk::NvCoverageReductionModeFn,
+ pub nv_device_diagnostic_checkpoints: ash::vk::NvDeviceDiagnosticCheckpointsFn,
+ pub nv_device_generated_commands: ash::vk::NvDeviceGeneratedCommandsFn,
+ pub nv_external_memory_rdma: ash::vk::NvExternalMemoryRdmaFn,
+ pub nv_external_memory_win32: ash::vk::NvExternalMemoryWin32Fn,
+ pub nv_fragment_shading_rate_enums: ash::vk::NvFragmentShadingRateEnumsFn,
+ pub nv_memory_decompression: ash::vk::NvMemoryDecompressionFn,
+ pub nv_mesh_shader: ash::vk::NvMeshShaderFn,
+ pub nv_optical_flow: ash::vk::NvOpticalFlowFn,
+ pub nv_ray_tracing: ash::vk::NvRayTracingFn,
+ pub nv_scissor_exclusive: ash::vk::NvScissorExclusiveFn,
+ pub nv_shading_rate_image: ash::vk::NvShadingRateImageFn,
+ pub qcom_tile_properties: ash::vk::QcomTilePropertiesFn,
+ pub valve_descriptor_set_host_mapping: ash::vk::ValveDescriptorSetHostMappingFn,
+ pub _ne: crate::NonExhaustive,
+}
+impl DeviceFunctions {
+ pub(crate) fn load<F>(mut load_fn: F) -> DeviceFunctions
+ where
+ F: FnMut(&CStr) -> *const c_void,
+ {
+ DeviceFunctions {
+ v1_0: ash::vk::DeviceFnV1_0::load(&mut load_fn),
+ v1_1: ash::vk::DeviceFnV1_1::load(&mut load_fn),
+ v1_2: ash::vk::DeviceFnV1_2::load(&mut load_fn),
+ v1_3: ash::vk::DeviceFnV1_3::load(&mut load_fn),
+ khr_acceleration_structure: ash::vk::KhrAccelerationStructureFn::load(&mut load_fn),
+ khr_bind_memory2: ash::vk::KhrBindMemory2Fn::load(&mut load_fn),
+ khr_buffer_device_address: ash::vk::KhrBufferDeviceAddressFn::load(&mut load_fn),
+ khr_copy_commands2: ash::vk::KhrCopyCommands2Fn::load(&mut load_fn),
+ khr_create_renderpass2: ash::vk::KhrCreateRenderpass2Fn::load(&mut load_fn),
+ khr_deferred_host_operations: ash::vk::KhrDeferredHostOperationsFn::load(&mut load_fn),
+ khr_descriptor_update_template: ash::vk::KhrDescriptorUpdateTemplateFn::load(
+ &mut load_fn,
+ ),
+ khr_device_group: ash::vk::KhrDeviceGroupFn::load(&mut load_fn),
+ khr_display_swapchain: ash::vk::KhrDisplaySwapchainFn::load(&mut load_fn),
+ khr_draw_indirect_count: ash::vk::KhrDrawIndirectCountFn::load(&mut load_fn),
+ khr_dynamic_rendering: ash::vk::KhrDynamicRenderingFn::load(&mut load_fn),
+ khr_external_fence_fd: ash::vk::KhrExternalFenceFdFn::load(&mut load_fn),
+ khr_external_fence_win32: ash::vk::KhrExternalFenceWin32Fn::load(&mut load_fn),
+ khr_external_memory_fd: ash::vk::KhrExternalMemoryFdFn::load(&mut load_fn),
+ khr_external_memory_win32: ash::vk::KhrExternalMemoryWin32Fn::load(&mut load_fn),
+ khr_external_semaphore_fd: ash::vk::KhrExternalSemaphoreFdFn::load(&mut load_fn),
+ khr_external_semaphore_win32: ash::vk::KhrExternalSemaphoreWin32Fn::load(&mut load_fn),
+ khr_fragment_shading_rate: ash::vk::KhrFragmentShadingRateFn::load(&mut load_fn),
+ khr_get_memory_requirements2: ash::vk::KhrGetMemoryRequirements2Fn::load(&mut load_fn),
+ khr_maintenance1: ash::vk::KhrMaintenance1Fn::load(&mut load_fn),
+ khr_maintenance3: ash::vk::KhrMaintenance3Fn::load(&mut load_fn),
+ khr_maintenance4: ash::vk::KhrMaintenance4Fn::load(&mut load_fn),
+ khr_performance_query: ash::vk::KhrPerformanceQueryFn::load(&mut load_fn),
+ khr_pipeline_executable_properties: ash::vk::KhrPipelineExecutablePropertiesFn::load(
+ &mut load_fn,
+ ),
+ khr_present_wait: ash::vk::KhrPresentWaitFn::load(&mut load_fn),
+ khr_push_descriptor: ash::vk::KhrPushDescriptorFn::load(&mut load_fn),
+ khr_ray_tracing_maintenance1: ash::vk::KhrRayTracingMaintenance1Fn::load(&mut load_fn),
+ khr_ray_tracing_pipeline: ash::vk::KhrRayTracingPipelineFn::load(&mut load_fn),
+ khr_sampler_ycbcr_conversion: ash::vk::KhrSamplerYcbcrConversionFn::load(&mut load_fn),
+ khr_shared_presentable_image: ash::vk::KhrSharedPresentableImageFn::load(&mut load_fn),
+ khr_swapchain: ash::vk::KhrSwapchainFn::load(&mut load_fn),
+ khr_synchronization2: ash::vk::KhrSynchronization2Fn::load(&mut load_fn),
+ khr_timeline_semaphore: ash::vk::KhrTimelineSemaphoreFn::load(&mut load_fn),
+ khr_video_decode_queue: ash::vk::KhrVideoDecodeQueueFn::load(&mut load_fn),
+ khr_video_encode_queue: ash::vk::KhrVideoEncodeQueueFn::load(&mut load_fn),
+ khr_video_queue: ash::vk::KhrVideoQueueFn::load(&mut load_fn),
+ ext_buffer_device_address: ash::vk::ExtBufferDeviceAddressFn::load(&mut load_fn),
+ ext_calibrated_timestamps: ash::vk::ExtCalibratedTimestampsFn::load(&mut load_fn),
+ ext_color_write_enable: ash::vk::ExtColorWriteEnableFn::load(&mut load_fn),
+ ext_conditional_rendering: ash::vk::ExtConditionalRenderingFn::load(&mut load_fn),
+ ext_debug_marker: ash::vk::ExtDebugMarkerFn::load(&mut load_fn),
+ ext_descriptor_buffer: ash::vk::ExtDescriptorBufferFn::load(&mut load_fn),
+ ext_device_fault: ash::vk::ExtDeviceFaultFn::load(&mut load_fn),
+ ext_discard_rectangles: ash::vk::ExtDiscardRectanglesFn::load(&mut load_fn),
+ ext_display_control: ash::vk::ExtDisplayControlFn::load(&mut load_fn),
+ ext_extended_dynamic_state: ash::vk::ExtExtendedDynamicStateFn::load(&mut load_fn),
+ ext_extended_dynamic_state2: ash::vk::ExtExtendedDynamicState2Fn::load(&mut load_fn),
+ ext_extended_dynamic_state3: ash::vk::ExtExtendedDynamicState3Fn::load(&mut load_fn),
+ ext_external_memory_host: ash::vk::ExtExternalMemoryHostFn::load(&mut load_fn),
+ ext_full_screen_exclusive: ash::vk::ExtFullScreenExclusiveFn::load(&mut load_fn),
+ ext_hdr_metadata: ash::vk::ExtHdrMetadataFn::load(&mut load_fn),
+ ext_host_query_reset: ash::vk::ExtHostQueryResetFn::load(&mut load_fn),
+ ext_image_compression_control: ash::vk::ExtImageCompressionControlFn::load(
+ &mut load_fn,
+ ),
+ ext_image_drm_format_modifier: ash::vk::ExtImageDrmFormatModifierFn::load(&mut load_fn),
+ ext_line_rasterization: ash::vk::ExtLineRasterizationFn::load(&mut load_fn),
+ ext_mesh_shader: ash::vk::ExtMeshShaderFn::load(&mut load_fn),
+ ext_metal_objects: ash::vk::ExtMetalObjectsFn::load(&mut load_fn),
+ ext_multi_draw: ash::vk::ExtMultiDrawFn::load(&mut load_fn),
+ ext_opacity_micromap: ash::vk::ExtOpacityMicromapFn::load(&mut load_fn),
+ ext_pageable_device_local_memory: ash::vk::ExtPageableDeviceLocalMemoryFn::load(
+ &mut load_fn,
+ ),
+ ext_pipeline_properties: ash::vk::ExtPipelinePropertiesFn::load(&mut load_fn),
+ ext_private_data: ash::vk::ExtPrivateDataFn::load(&mut load_fn),
+ ext_sample_locations: ash::vk::ExtSampleLocationsFn::load(&mut load_fn),
+ ext_shader_module_identifier: ash::vk::ExtShaderModuleIdentifierFn::load(&mut load_fn),
+ ext_swapchain_maintenance1: ash::vk::ExtSwapchainMaintenance1Fn::load(&mut load_fn),
+ ext_tooling_info: ash::vk::ExtToolingInfoFn::load(&mut load_fn),
+ ext_transform_feedback: ash::vk::ExtTransformFeedbackFn::load(&mut load_fn),
+ ext_validation_cache: ash::vk::ExtValidationCacheFn::load(&mut load_fn),
+ ext_vertex_input_dynamic_state: ash::vk::ExtVertexInputDynamicStateFn::load(
+ &mut load_fn,
+ ),
+ amd_buffer_marker: ash::vk::AmdBufferMarkerFn::load(&mut load_fn),
+ amd_display_native_hdr: ash::vk::AmdDisplayNativeHdrFn::load(&mut load_fn),
+ amd_draw_indirect_count: ash::vk::AmdDrawIndirectCountFn::load(&mut load_fn),
+ amd_shader_info: ash::vk::AmdShaderInfoFn::load(&mut load_fn),
+ android_external_memory_android_hardware_buffer:
+ ash::vk::AndroidExternalMemoryAndroidHardwareBufferFn::load(&mut load_fn),
+ fuchsia_buffer_collection: ash::vk::FuchsiaBufferCollectionFn::load(&mut load_fn),
+ fuchsia_external_memory: ash::vk::FuchsiaExternalMemoryFn::load(&mut load_fn),
+ fuchsia_external_semaphore: ash::vk::FuchsiaExternalSemaphoreFn::load(&mut load_fn),
+ google_display_timing: ash::vk::GoogleDisplayTimingFn::load(&mut load_fn),
+ huawei_invocation_mask: ash::vk::HuaweiInvocationMaskFn::load(&mut load_fn),
+ huawei_subpass_shading: ash::vk::HuaweiSubpassShadingFn::load(&mut load_fn),
+ intel_performance_query: ash::vk::IntelPerformanceQueryFn::load(&mut load_fn),
+ nvx_binary_import: ash::vk::NvxBinaryImportFn::load(&mut load_fn),
+ nvx_image_view_handle: ash::vk::NvxImageViewHandleFn::load(&mut load_fn),
+ nv_acquire_winrt_display: ash::vk::NvAcquireWinrtDisplayFn::load(&mut load_fn),
+ nv_clip_space_w_scaling: ash::vk::NvClipSpaceWScalingFn::load(&mut load_fn),
+ nv_cooperative_matrix: ash::vk::NvCooperativeMatrixFn::load(&mut load_fn),
+ nv_copy_memory_indirect: ash::vk::NvCopyMemoryIndirectFn::load(&mut load_fn),
+ nv_coverage_reduction_mode: ash::vk::NvCoverageReductionModeFn::load(&mut load_fn),
+ nv_device_diagnostic_checkpoints: ash::vk::NvDeviceDiagnosticCheckpointsFn::load(
+ &mut load_fn,
+ ),
+ nv_device_generated_commands: ash::vk::NvDeviceGeneratedCommandsFn::load(&mut load_fn),
+ nv_external_memory_rdma: ash::vk::NvExternalMemoryRdmaFn::load(&mut load_fn),
+ nv_external_memory_win32: ash::vk::NvExternalMemoryWin32Fn::load(&mut load_fn),
+ nv_fragment_shading_rate_enums: ash::vk::NvFragmentShadingRateEnumsFn::load(
+ &mut load_fn,
+ ),
+ nv_memory_decompression: ash::vk::NvMemoryDecompressionFn::load(&mut load_fn),
+ nv_mesh_shader: ash::vk::NvMeshShaderFn::load(&mut load_fn),
+ nv_optical_flow: ash::vk::NvOpticalFlowFn::load(&mut load_fn),
+ nv_ray_tracing: ash::vk::NvRayTracingFn::load(&mut load_fn),
+ nv_scissor_exclusive: ash::vk::NvScissorExclusiveFn::load(&mut load_fn),
+ nv_shading_rate_image: ash::vk::NvShadingRateImageFn::load(&mut load_fn),
+ qcom_tile_properties: ash::vk::QcomTilePropertiesFn::load(&mut load_fn),
+ valve_descriptor_set_host_mapping: ash::vk::ValveDescriptorSetHostMappingFn::load(
+ &mut load_fn,
+ ),
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+impl std::fmt::Debug for DeviceFunctions {
+ #[inline]
+ fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
+ Ok(())
+ }
+}
diff --git a/out/formats.rs b/out/formats.rs
new file mode 100644
index 0000000..1b0c31c
--- /dev/null
+++ b/out/formats.rs
@@ -0,0 +1,4625 @@
+// This file is auto-generated by vulkano autogen from vk.xml header version 1.3.238.
+// It should not be edited manually. Changes should be made by editing autogen.
+
+#[doc = r" An enumeration of all the possible formats."]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+#[repr(i32)]
+#[allow(non_camel_case_types)]
+#[non_exhaustive]
+pub enum Format {
+ R4G4_UNORM_PACK8 = ash::vk::Format::R4G4_UNORM_PACK8.as_raw(),
+ R4G4B4A4_UNORM_PACK16 = ash::vk::Format::R4G4B4A4_UNORM_PACK16.as_raw(),
+ B4G4R4A4_UNORM_PACK16 = ash::vk::Format::B4G4R4A4_UNORM_PACK16.as_raw(),
+ R5G6B5_UNORM_PACK16 = ash::vk::Format::R5G6B5_UNORM_PACK16.as_raw(),
+ B5G6R5_UNORM_PACK16 = ash::vk::Format::B5G6R5_UNORM_PACK16.as_raw(),
+ R5G5B5A1_UNORM_PACK16 = ash::vk::Format::R5G5B5A1_UNORM_PACK16.as_raw(),
+ B5G5R5A1_UNORM_PACK16 = ash::vk::Format::B5G5R5A1_UNORM_PACK16.as_raw(),
+ A1R5G5B5_UNORM_PACK16 = ash::vk::Format::A1R5G5B5_UNORM_PACK16.as_raw(),
+ R8_UNORM = ash::vk::Format::R8_UNORM.as_raw(),
+ R8_SNORM = ash::vk::Format::R8_SNORM.as_raw(),
+ R8_USCALED = ash::vk::Format::R8_USCALED.as_raw(),
+ R8_SSCALED = ash::vk::Format::R8_SSCALED.as_raw(),
+ R8_UINT = ash::vk::Format::R8_UINT.as_raw(),
+ R8_SINT = ash::vk::Format::R8_SINT.as_raw(),
+ R8_SRGB = ash::vk::Format::R8_SRGB.as_raw(),
+ R8G8_UNORM = ash::vk::Format::R8G8_UNORM.as_raw(),
+ R8G8_SNORM = ash::vk::Format::R8G8_SNORM.as_raw(),
+ R8G8_USCALED = ash::vk::Format::R8G8_USCALED.as_raw(),
+ R8G8_SSCALED = ash::vk::Format::R8G8_SSCALED.as_raw(),
+ R8G8_UINT = ash::vk::Format::R8G8_UINT.as_raw(),
+ R8G8_SINT = ash::vk::Format::R8G8_SINT.as_raw(),
+ R8G8_SRGB = ash::vk::Format::R8G8_SRGB.as_raw(),
+ R8G8B8_UNORM = ash::vk::Format::R8G8B8_UNORM.as_raw(),
+ R8G8B8_SNORM = ash::vk::Format::R8G8B8_SNORM.as_raw(),
+ R8G8B8_USCALED = ash::vk::Format::R8G8B8_USCALED.as_raw(),
+ R8G8B8_SSCALED = ash::vk::Format::R8G8B8_SSCALED.as_raw(),
+ R8G8B8_UINT = ash::vk::Format::R8G8B8_UINT.as_raw(),
+ R8G8B8_SINT = ash::vk::Format::R8G8B8_SINT.as_raw(),
+ R8G8B8_SRGB = ash::vk::Format::R8G8B8_SRGB.as_raw(),
+ B8G8R8_UNORM = ash::vk::Format::B8G8R8_UNORM.as_raw(),
+ B8G8R8_SNORM = ash::vk::Format::B8G8R8_SNORM.as_raw(),
+ B8G8R8_USCALED = ash::vk::Format::B8G8R8_USCALED.as_raw(),
+ B8G8R8_SSCALED = ash::vk::Format::B8G8R8_SSCALED.as_raw(),
+ B8G8R8_UINT = ash::vk::Format::B8G8R8_UINT.as_raw(),
+ B8G8R8_SINT = ash::vk::Format::B8G8R8_SINT.as_raw(),
+ B8G8R8_SRGB = ash::vk::Format::B8G8R8_SRGB.as_raw(),
+ R8G8B8A8_UNORM = ash::vk::Format::R8G8B8A8_UNORM.as_raw(),
+ R8G8B8A8_SNORM = ash::vk::Format::R8G8B8A8_SNORM.as_raw(),
+ R8G8B8A8_USCALED = ash::vk::Format::R8G8B8A8_USCALED.as_raw(),
+ R8G8B8A8_SSCALED = ash::vk::Format::R8G8B8A8_SSCALED.as_raw(),
+ R8G8B8A8_UINT = ash::vk::Format::R8G8B8A8_UINT.as_raw(),
+ R8G8B8A8_SINT = ash::vk::Format::R8G8B8A8_SINT.as_raw(),
+ R8G8B8A8_SRGB = ash::vk::Format::R8G8B8A8_SRGB.as_raw(),
+ B8G8R8A8_UNORM = ash::vk::Format::B8G8R8A8_UNORM.as_raw(),
+ B8G8R8A8_SNORM = ash::vk::Format::B8G8R8A8_SNORM.as_raw(),
+ B8G8R8A8_USCALED = ash::vk::Format::B8G8R8A8_USCALED.as_raw(),
+ B8G8R8A8_SSCALED = ash::vk::Format::B8G8R8A8_SSCALED.as_raw(),
+ B8G8R8A8_UINT = ash::vk::Format::B8G8R8A8_UINT.as_raw(),
+ B8G8R8A8_SINT = ash::vk::Format::B8G8R8A8_SINT.as_raw(),
+ B8G8R8A8_SRGB = ash::vk::Format::B8G8R8A8_SRGB.as_raw(),
+ A8B8G8R8_UNORM_PACK32 = ash::vk::Format::A8B8G8R8_UNORM_PACK32.as_raw(),
+ A8B8G8R8_SNORM_PACK32 = ash::vk::Format::A8B8G8R8_SNORM_PACK32.as_raw(),
+ A8B8G8R8_USCALED_PACK32 = ash::vk::Format::A8B8G8R8_USCALED_PACK32.as_raw(),
+ A8B8G8R8_SSCALED_PACK32 = ash::vk::Format::A8B8G8R8_SSCALED_PACK32.as_raw(),
+ A8B8G8R8_UINT_PACK32 = ash::vk::Format::A8B8G8R8_UINT_PACK32.as_raw(),
+ A8B8G8R8_SINT_PACK32 = ash::vk::Format::A8B8G8R8_SINT_PACK32.as_raw(),
+ A8B8G8R8_SRGB_PACK32 = ash::vk::Format::A8B8G8R8_SRGB_PACK32.as_raw(),
+ A2R10G10B10_UNORM_PACK32 = ash::vk::Format::A2R10G10B10_UNORM_PACK32.as_raw(),
+ A2R10G10B10_SNORM_PACK32 = ash::vk::Format::A2R10G10B10_SNORM_PACK32.as_raw(),
+ A2R10G10B10_USCALED_PACK32 = ash::vk::Format::A2R10G10B10_USCALED_PACK32.as_raw(),
+ A2R10G10B10_SSCALED_PACK32 = ash::vk::Format::A2R10G10B10_SSCALED_PACK32.as_raw(),
+ A2R10G10B10_UINT_PACK32 = ash::vk::Format::A2R10G10B10_UINT_PACK32.as_raw(),
+ A2R10G10B10_SINT_PACK32 = ash::vk::Format::A2R10G10B10_SINT_PACK32.as_raw(),
+ A2B10G10R10_UNORM_PACK32 = ash::vk::Format::A2B10G10R10_UNORM_PACK32.as_raw(),
+ A2B10G10R10_SNORM_PACK32 = ash::vk::Format::A2B10G10R10_SNORM_PACK32.as_raw(),
+ A2B10G10R10_USCALED_PACK32 = ash::vk::Format::A2B10G10R10_USCALED_PACK32.as_raw(),
+ A2B10G10R10_SSCALED_PACK32 = ash::vk::Format::A2B10G10R10_SSCALED_PACK32.as_raw(),
+ A2B10G10R10_UINT_PACK32 = ash::vk::Format::A2B10G10R10_UINT_PACK32.as_raw(),
+ A2B10G10R10_SINT_PACK32 = ash::vk::Format::A2B10G10R10_SINT_PACK32.as_raw(),
+ R16_UNORM = ash::vk::Format::R16_UNORM.as_raw(),
+ R16_SNORM = ash::vk::Format::R16_SNORM.as_raw(),
+ R16_USCALED = ash::vk::Format::R16_USCALED.as_raw(),
+ R16_SSCALED = ash::vk::Format::R16_SSCALED.as_raw(),
+ R16_UINT = ash::vk::Format::R16_UINT.as_raw(),
+ R16_SINT = ash::vk::Format::R16_SINT.as_raw(),
+ R16_SFLOAT = ash::vk::Format::R16_SFLOAT.as_raw(),
+ R16G16_UNORM = ash::vk::Format::R16G16_UNORM.as_raw(),
+ R16G16_SNORM = ash::vk::Format::R16G16_SNORM.as_raw(),
+ R16G16_USCALED = ash::vk::Format::R16G16_USCALED.as_raw(),
+ R16G16_SSCALED = ash::vk::Format::R16G16_SSCALED.as_raw(),
+ R16G16_UINT = ash::vk::Format::R16G16_UINT.as_raw(),
+ R16G16_SINT = ash::vk::Format::R16G16_SINT.as_raw(),
+ R16G16_SFLOAT = ash::vk::Format::R16G16_SFLOAT.as_raw(),
+ R16G16B16_UNORM = ash::vk::Format::R16G16B16_UNORM.as_raw(),
+ R16G16B16_SNORM = ash::vk::Format::R16G16B16_SNORM.as_raw(),
+ R16G16B16_USCALED = ash::vk::Format::R16G16B16_USCALED.as_raw(),
+ R16G16B16_SSCALED = ash::vk::Format::R16G16B16_SSCALED.as_raw(),
+ R16G16B16_UINT = ash::vk::Format::R16G16B16_UINT.as_raw(),
+ R16G16B16_SINT = ash::vk::Format::R16G16B16_SINT.as_raw(),
+ R16G16B16_SFLOAT = ash::vk::Format::R16G16B16_SFLOAT.as_raw(),
+ R16G16B16A16_UNORM = ash::vk::Format::R16G16B16A16_UNORM.as_raw(),
+ R16G16B16A16_SNORM = ash::vk::Format::R16G16B16A16_SNORM.as_raw(),
+ R16G16B16A16_USCALED = ash::vk::Format::R16G16B16A16_USCALED.as_raw(),
+ R16G16B16A16_SSCALED = ash::vk::Format::R16G16B16A16_SSCALED.as_raw(),
+ R16G16B16A16_UINT = ash::vk::Format::R16G16B16A16_UINT.as_raw(),
+ R16G16B16A16_SINT = ash::vk::Format::R16G16B16A16_SINT.as_raw(),
+ R16G16B16A16_SFLOAT = ash::vk::Format::R16G16B16A16_SFLOAT.as_raw(),
+ R32_UINT = ash::vk::Format::R32_UINT.as_raw(),
+ R32_SINT = ash::vk::Format::R32_SINT.as_raw(),
+ R32_SFLOAT = ash::vk::Format::R32_SFLOAT.as_raw(),
+ R32G32_UINT = ash::vk::Format::R32G32_UINT.as_raw(),
+ R32G32_SINT = ash::vk::Format::R32G32_SINT.as_raw(),
+ R32G32_SFLOAT = ash::vk::Format::R32G32_SFLOAT.as_raw(),
+ R32G32B32_UINT = ash::vk::Format::R32G32B32_UINT.as_raw(),
+ R32G32B32_SINT = ash::vk::Format::R32G32B32_SINT.as_raw(),
+ R32G32B32_SFLOAT = ash::vk::Format::R32G32B32_SFLOAT.as_raw(),
+ R32G32B32A32_UINT = ash::vk::Format::R32G32B32A32_UINT.as_raw(),
+ R32G32B32A32_SINT = ash::vk::Format::R32G32B32A32_SINT.as_raw(),
+ R32G32B32A32_SFLOAT = ash::vk::Format::R32G32B32A32_SFLOAT.as_raw(),
+ R64_UINT = ash::vk::Format::R64_UINT.as_raw(),
+ R64_SINT = ash::vk::Format::R64_SINT.as_raw(),
+ R64_SFLOAT = ash::vk::Format::R64_SFLOAT.as_raw(),
+ R64G64_UINT = ash::vk::Format::R64G64_UINT.as_raw(),
+ R64G64_SINT = ash::vk::Format::R64G64_SINT.as_raw(),
+ R64G64_SFLOAT = ash::vk::Format::R64G64_SFLOAT.as_raw(),
+ R64G64B64_UINT = ash::vk::Format::R64G64B64_UINT.as_raw(),
+ R64G64B64_SINT = ash::vk::Format::R64G64B64_SINT.as_raw(),
+ R64G64B64_SFLOAT = ash::vk::Format::R64G64B64_SFLOAT.as_raw(),
+ R64G64B64A64_UINT = ash::vk::Format::R64G64B64A64_UINT.as_raw(),
+ R64G64B64A64_SINT = ash::vk::Format::R64G64B64A64_SINT.as_raw(),
+ R64G64B64A64_SFLOAT = ash::vk::Format::R64G64B64A64_SFLOAT.as_raw(),
+ B10G11R11_UFLOAT_PACK32 = ash::vk::Format::B10G11R11_UFLOAT_PACK32.as_raw(),
+ E5B9G9R9_UFLOAT_PACK32 = ash::vk::Format::E5B9G9R9_UFLOAT_PACK32.as_raw(),
+ D16_UNORM = ash::vk::Format::D16_UNORM.as_raw(),
+ X8_D24_UNORM_PACK32 = ash::vk::Format::X8_D24_UNORM_PACK32.as_raw(),
+ D32_SFLOAT = ash::vk::Format::D32_SFLOAT.as_raw(),
+ S8_UINT = ash::vk::Format::S8_UINT.as_raw(),
+ D16_UNORM_S8_UINT = ash::vk::Format::D16_UNORM_S8_UINT.as_raw(),
+ D24_UNORM_S8_UINT = ash::vk::Format::D24_UNORM_S8_UINT.as_raw(),
+ D32_SFLOAT_S8_UINT = ash::vk::Format::D32_SFLOAT_S8_UINT.as_raw(),
+ BC1_RGB_UNORM_BLOCK = ash::vk::Format::BC1_RGB_UNORM_BLOCK.as_raw(),
+ BC1_RGB_SRGB_BLOCK = ash::vk::Format::BC1_RGB_SRGB_BLOCK.as_raw(),
+ BC1_RGBA_UNORM_BLOCK = ash::vk::Format::BC1_RGBA_UNORM_BLOCK.as_raw(),
+ BC1_RGBA_SRGB_BLOCK = ash::vk::Format::BC1_RGBA_SRGB_BLOCK.as_raw(),
+ BC2_UNORM_BLOCK = ash::vk::Format::BC2_UNORM_BLOCK.as_raw(),
+ BC2_SRGB_BLOCK = ash::vk::Format::BC2_SRGB_BLOCK.as_raw(),
+ BC3_UNORM_BLOCK = ash::vk::Format::BC3_UNORM_BLOCK.as_raw(),
+ BC3_SRGB_BLOCK = ash::vk::Format::BC3_SRGB_BLOCK.as_raw(),
+ BC4_UNORM_BLOCK = ash::vk::Format::BC4_UNORM_BLOCK.as_raw(),
+ BC4_SNORM_BLOCK = ash::vk::Format::BC4_SNORM_BLOCK.as_raw(),
+ BC5_UNORM_BLOCK = ash::vk::Format::BC5_UNORM_BLOCK.as_raw(),
+ BC5_SNORM_BLOCK = ash::vk::Format::BC5_SNORM_BLOCK.as_raw(),
+ BC6H_UFLOAT_BLOCK = ash::vk::Format::BC6H_UFLOAT_BLOCK.as_raw(),
+ BC6H_SFLOAT_BLOCK = ash::vk::Format::BC6H_SFLOAT_BLOCK.as_raw(),
+ BC7_UNORM_BLOCK = ash::vk::Format::BC7_UNORM_BLOCK.as_raw(),
+ BC7_SRGB_BLOCK = ash::vk::Format::BC7_SRGB_BLOCK.as_raw(),
+ ETC2_R8G8B8_UNORM_BLOCK = ash::vk::Format::ETC2_R8G8B8_UNORM_BLOCK.as_raw(),
+ ETC2_R8G8B8_SRGB_BLOCK = ash::vk::Format::ETC2_R8G8B8_SRGB_BLOCK.as_raw(),
+ ETC2_R8G8B8A1_UNORM_BLOCK = ash::vk::Format::ETC2_R8G8B8A1_UNORM_BLOCK.as_raw(),
+ ETC2_R8G8B8A1_SRGB_BLOCK = ash::vk::Format::ETC2_R8G8B8A1_SRGB_BLOCK.as_raw(),
+ ETC2_R8G8B8A8_UNORM_BLOCK = ash::vk::Format::ETC2_R8G8B8A8_UNORM_BLOCK.as_raw(),
+ ETC2_R8G8B8A8_SRGB_BLOCK = ash::vk::Format::ETC2_R8G8B8A8_SRGB_BLOCK.as_raw(),
+ EAC_R11_UNORM_BLOCK = ash::vk::Format::EAC_R11_UNORM_BLOCK.as_raw(),
+ EAC_R11_SNORM_BLOCK = ash::vk::Format::EAC_R11_SNORM_BLOCK.as_raw(),
+ EAC_R11G11_UNORM_BLOCK = ash::vk::Format::EAC_R11G11_UNORM_BLOCK.as_raw(),
+ EAC_R11G11_SNORM_BLOCK = ash::vk::Format::EAC_R11G11_SNORM_BLOCK.as_raw(),
+ ASTC_4x4_UNORM_BLOCK = ash::vk::Format::ASTC_4X4_UNORM_BLOCK.as_raw(),
+ ASTC_4x4_SRGB_BLOCK = ash::vk::Format::ASTC_4X4_SRGB_BLOCK.as_raw(),
+ ASTC_5x4_UNORM_BLOCK = ash::vk::Format::ASTC_5X4_UNORM_BLOCK.as_raw(),
+ ASTC_5x4_SRGB_BLOCK = ash::vk::Format::ASTC_5X4_SRGB_BLOCK.as_raw(),
+ ASTC_5x5_UNORM_BLOCK = ash::vk::Format::ASTC_5X5_UNORM_BLOCK.as_raw(),
+ ASTC_5x5_SRGB_BLOCK = ash::vk::Format::ASTC_5X5_SRGB_BLOCK.as_raw(),
+ ASTC_6x5_UNORM_BLOCK = ash::vk::Format::ASTC_6X5_UNORM_BLOCK.as_raw(),
+ ASTC_6x5_SRGB_BLOCK = ash::vk::Format::ASTC_6X5_SRGB_BLOCK.as_raw(),
+ ASTC_6x6_UNORM_BLOCK = ash::vk::Format::ASTC_6X6_UNORM_BLOCK.as_raw(),
+ ASTC_6x6_SRGB_BLOCK = ash::vk::Format::ASTC_6X6_SRGB_BLOCK.as_raw(),
+ ASTC_8x5_UNORM_BLOCK = ash::vk::Format::ASTC_8X5_UNORM_BLOCK.as_raw(),
+ ASTC_8x5_SRGB_BLOCK = ash::vk::Format::ASTC_8X5_SRGB_BLOCK.as_raw(),
+ ASTC_8x6_UNORM_BLOCK = ash::vk::Format::ASTC_8X6_UNORM_BLOCK.as_raw(),
+ ASTC_8x6_SRGB_BLOCK = ash::vk::Format::ASTC_8X6_SRGB_BLOCK.as_raw(),
+ ASTC_8x8_UNORM_BLOCK = ash::vk::Format::ASTC_8X8_UNORM_BLOCK.as_raw(),
+ ASTC_8x8_SRGB_BLOCK = ash::vk::Format::ASTC_8X8_SRGB_BLOCK.as_raw(),
+ ASTC_10x5_UNORM_BLOCK = ash::vk::Format::ASTC_10X5_UNORM_BLOCK.as_raw(),
+ ASTC_10x5_SRGB_BLOCK = ash::vk::Format::ASTC_10X5_SRGB_BLOCK.as_raw(),
+ ASTC_10x6_UNORM_BLOCK = ash::vk::Format::ASTC_10X6_UNORM_BLOCK.as_raw(),
+ ASTC_10x6_SRGB_BLOCK = ash::vk::Format::ASTC_10X6_SRGB_BLOCK.as_raw(),
+ ASTC_10x8_UNORM_BLOCK = ash::vk::Format::ASTC_10X8_UNORM_BLOCK.as_raw(),
+ ASTC_10x8_SRGB_BLOCK = ash::vk::Format::ASTC_10X8_SRGB_BLOCK.as_raw(),
+ ASTC_10x10_UNORM_BLOCK = ash::vk::Format::ASTC_10X10_UNORM_BLOCK.as_raw(),
+ ASTC_10x10_SRGB_BLOCK = ash::vk::Format::ASTC_10X10_SRGB_BLOCK.as_raw(),
+ ASTC_12x10_UNORM_BLOCK = ash::vk::Format::ASTC_12X10_UNORM_BLOCK.as_raw(),
+ ASTC_12x10_SRGB_BLOCK = ash::vk::Format::ASTC_12X10_SRGB_BLOCK.as_raw(),
+ ASTC_12x12_UNORM_BLOCK = ash::vk::Format::ASTC_12X12_UNORM_BLOCK.as_raw(),
+ ASTC_12x12_SRGB_BLOCK = ash::vk::Format::ASTC_12X12_SRGB_BLOCK.as_raw(),
+ G8B8G8R8_422_UNORM = ash::vk::Format::G8B8G8R8_422_UNORM.as_raw(),
+ B8G8R8G8_422_UNORM = ash::vk::Format::B8G8R8G8_422_UNORM.as_raw(),
+ G8_B8_R8_3PLANE_420_UNORM = ash::vk::Format::G8_B8_R8_3PLANE_420_UNORM.as_raw(),
+ G8_B8R8_2PLANE_420_UNORM = ash::vk::Format::G8_B8R8_2PLANE_420_UNORM.as_raw(),
+ G8_B8_R8_3PLANE_422_UNORM = ash::vk::Format::G8_B8_R8_3PLANE_422_UNORM.as_raw(),
+ G8_B8R8_2PLANE_422_UNORM = ash::vk::Format::G8_B8R8_2PLANE_422_UNORM.as_raw(),
+ G8_B8_R8_3PLANE_444_UNORM = ash::vk::Format::G8_B8_R8_3PLANE_444_UNORM.as_raw(),
+ R10X6_UNORM_PACK16 = ash::vk::Format::R10X6_UNORM_PACK16.as_raw(),
+ R10X6G10X6_UNORM_2PACK16 = ash::vk::Format::R10X6G10X6_UNORM_2PACK16.as_raw(),
+ R10X6G10X6B10X6A10X6_UNORM_4PACK16 =
+ ash::vk::Format::R10X6G10X6B10X6A10X6_UNORM_4PACK16.as_raw(),
+ G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 =
+ ash::vk::Format::G10X6B10X6G10X6R10X6_422_UNORM_4PACK16.as_raw(),
+ B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 =
+ ash::vk::Format::B10X6G10X6R10X6G10X6_422_UNORM_4PACK16.as_raw(),
+ G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 =
+ ash::vk::Format::G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16.as_raw(),
+ G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 =
+ ash::vk::Format::G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16.as_raw(),
+ G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 =
+ ash::vk::Format::G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16.as_raw(),
+ G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 =
+ ash::vk::Format::G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16.as_raw(),
+ G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 =
+ ash::vk::Format::G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16.as_raw(),
+ R12X4_UNORM_PACK16 = ash::vk::Format::R12X4_UNORM_PACK16.as_raw(),
+ R12X4G12X4_UNORM_2PACK16 = ash::vk::Format::R12X4G12X4_UNORM_2PACK16.as_raw(),
+ R12X4G12X4B12X4A12X4_UNORM_4PACK16 =
+ ash::vk::Format::R12X4G12X4B12X4A12X4_UNORM_4PACK16.as_raw(),
+ G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 =
+ ash::vk::Format::G12X4B12X4G12X4R12X4_422_UNORM_4PACK16.as_raw(),
+ B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 =
+ ash::vk::Format::B12X4G12X4R12X4G12X4_422_UNORM_4PACK16.as_raw(),
+ G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 =
+ ash::vk::Format::G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16.as_raw(),
+ G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 =
+ ash::vk::Format::G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16.as_raw(),
+ G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 =
+ ash::vk::Format::G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16.as_raw(),
+ G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 =
+ ash::vk::Format::G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16.as_raw(),
+ G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 =
+ ash::vk::Format::G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16.as_raw(),
+ G16B16G16R16_422_UNORM = ash::vk::Format::G16B16G16R16_422_UNORM.as_raw(),
+ B16G16R16G16_422_UNORM = ash::vk::Format::B16G16R16G16_422_UNORM.as_raw(),
+ G16_B16_R16_3PLANE_420_UNORM = ash::vk::Format::G16_B16_R16_3PLANE_420_UNORM.as_raw(),
+ G16_B16R16_2PLANE_420_UNORM = ash::vk::Format::G16_B16R16_2PLANE_420_UNORM.as_raw(),
+ G16_B16_R16_3PLANE_422_UNORM = ash::vk::Format::G16_B16_R16_3PLANE_422_UNORM.as_raw(),
+ G16_B16R16_2PLANE_422_UNORM = ash::vk::Format::G16_B16R16_2PLANE_422_UNORM.as_raw(),
+ G16_B16_R16_3PLANE_444_UNORM = ash::vk::Format::G16_B16_R16_3PLANE_444_UNORM.as_raw(),
+ PVRTC1_2BPP_UNORM_BLOCK = ash::vk::Format::PVRTC1_2BPP_UNORM_BLOCK_IMG.as_raw(),
+ PVRTC1_4BPP_UNORM_BLOCK = ash::vk::Format::PVRTC1_4BPP_UNORM_BLOCK_IMG.as_raw(),
+ PVRTC2_2BPP_UNORM_BLOCK = ash::vk::Format::PVRTC2_2BPP_UNORM_BLOCK_IMG.as_raw(),
+ PVRTC2_4BPP_UNORM_BLOCK = ash::vk::Format::PVRTC2_4BPP_UNORM_BLOCK_IMG.as_raw(),
+ PVRTC1_2BPP_SRGB_BLOCK = ash::vk::Format::PVRTC1_2BPP_SRGB_BLOCK_IMG.as_raw(),
+ PVRTC1_4BPP_SRGB_BLOCK = ash::vk::Format::PVRTC1_4BPP_SRGB_BLOCK_IMG.as_raw(),
+ PVRTC2_2BPP_SRGB_BLOCK = ash::vk::Format::PVRTC2_2BPP_SRGB_BLOCK_IMG.as_raw(),
+ PVRTC2_4BPP_SRGB_BLOCK = ash::vk::Format::PVRTC2_4BPP_SRGB_BLOCK_IMG.as_raw(),
+ ASTC_4x4_SFLOAT_BLOCK = ash::vk::Format::ASTC_4X4_SFLOAT_BLOCK.as_raw(),
+ ASTC_5x4_SFLOAT_BLOCK = ash::vk::Format::ASTC_5X4_SFLOAT_BLOCK.as_raw(),
+ ASTC_5x5_SFLOAT_BLOCK = ash::vk::Format::ASTC_5X5_SFLOAT_BLOCK.as_raw(),
+ ASTC_6x5_SFLOAT_BLOCK = ash::vk::Format::ASTC_6X5_SFLOAT_BLOCK.as_raw(),
+ ASTC_6x6_SFLOAT_BLOCK = ash::vk::Format::ASTC_6X6_SFLOAT_BLOCK.as_raw(),
+ ASTC_8x5_SFLOAT_BLOCK = ash::vk::Format::ASTC_8X5_SFLOAT_BLOCK.as_raw(),
+ ASTC_8x6_SFLOAT_BLOCK = ash::vk::Format::ASTC_8X6_SFLOAT_BLOCK.as_raw(),
+ ASTC_8x8_SFLOAT_BLOCK = ash::vk::Format::ASTC_8X8_SFLOAT_BLOCK.as_raw(),
+ ASTC_10x5_SFLOAT_BLOCK = ash::vk::Format::ASTC_10X5_SFLOAT_BLOCK.as_raw(),
+ ASTC_10x6_SFLOAT_BLOCK = ash::vk::Format::ASTC_10X6_SFLOAT_BLOCK.as_raw(),
+ ASTC_10x8_SFLOAT_BLOCK = ash::vk::Format::ASTC_10X8_SFLOAT_BLOCK.as_raw(),
+ ASTC_10x10_SFLOAT_BLOCK = ash::vk::Format::ASTC_10X10_SFLOAT_BLOCK.as_raw(),
+ ASTC_12x10_SFLOAT_BLOCK = ash::vk::Format::ASTC_12X10_SFLOAT_BLOCK.as_raw(),
+ ASTC_12x12_SFLOAT_BLOCK = ash::vk::Format::ASTC_12X12_SFLOAT_BLOCK.as_raw(),
+ G8_B8R8_2PLANE_444_UNORM = ash::vk::Format::G8_B8R8_2PLANE_444_UNORM.as_raw(),
+ G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16 =
+ ash::vk::Format::G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16.as_raw(),
+ G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16 =
+ ash::vk::Format::G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16.as_raw(),
+ G16_B16R16_2PLANE_444_UNORM = ash::vk::Format::G16_B16R16_2PLANE_444_UNORM.as_raw(),
+ A4R4G4B4_UNORM_PACK16 = ash::vk::Format::A4R4G4B4_UNORM_PACK16.as_raw(),
+ A4B4G4R4_UNORM_PACK16 = ash::vk::Format::A4B4G4R4_UNORM_PACK16.as_raw(),
+ R16G16_S10_5_NV = ash::vk::Format::R16G16_S10_5_NV.as_raw(),
+}
+impl Format {
+ #[doc = r" Returns the aspects that images of this format have."]
+ pub fn aspects(self) -> ImageAspects {
+ match self {
+ Self::R4G4_UNORM_PACK8 => crate::image::ImageAspects::COLOR,
+ Self::R4G4B4A4_UNORM_PACK16 => crate::image::ImageAspects::COLOR,
+ Self::B4G4R4A4_UNORM_PACK16 => crate::image::ImageAspects::COLOR,
+ Self::R5G6B5_UNORM_PACK16 => crate::image::ImageAspects::COLOR,
+ Self::B5G6R5_UNORM_PACK16 => crate::image::ImageAspects::COLOR,
+ Self::R5G5B5A1_UNORM_PACK16 => crate::image::ImageAspects::COLOR,
+ Self::B5G5R5A1_UNORM_PACK16 => crate::image::ImageAspects::COLOR,
+ Self::A1R5G5B5_UNORM_PACK16 => crate::image::ImageAspects::COLOR,
+ Self::R8_UNORM => crate::image::ImageAspects::COLOR,
+ Self::R8_SNORM => crate::image::ImageAspects::COLOR,
+ Self::R8_USCALED => crate::image::ImageAspects::COLOR,
+ Self::R8_SSCALED => crate::image::ImageAspects::COLOR,
+ Self::R8_UINT => crate::image::ImageAspects::COLOR,
+ Self::R8_SINT => crate::image::ImageAspects::COLOR,
+ Self::R8_SRGB => crate::image::ImageAspects::COLOR,
+ Self::R8G8_UNORM => crate::image::ImageAspects::COLOR,
+ Self::R8G8_SNORM => crate::image::ImageAspects::COLOR,
+ Self::R8G8_USCALED => crate::image::ImageAspects::COLOR,
+ Self::R8G8_SSCALED => crate::image::ImageAspects::COLOR,
+ Self::R8G8_UINT => crate::image::ImageAspects::COLOR,
+ Self::R8G8_SINT => crate::image::ImageAspects::COLOR,
+ Self::R8G8_SRGB => crate::image::ImageAspects::COLOR,
+ Self::R8G8B8_UNORM => crate::image::ImageAspects::COLOR,
+ Self::R8G8B8_SNORM => crate::image::ImageAspects::COLOR,
+ Self::R8G8B8_USCALED => crate::image::ImageAspects::COLOR,
+ Self::R8G8B8_SSCALED => crate::image::ImageAspects::COLOR,
+ Self::R8G8B8_UINT => crate::image::ImageAspects::COLOR,
+ Self::R8G8B8_SINT => crate::image::ImageAspects::COLOR,
+ Self::R8G8B8_SRGB => crate::image::ImageAspects::COLOR,
+ Self::B8G8R8_UNORM => crate::image::ImageAspects::COLOR,
+ Self::B8G8R8_SNORM => crate::image::ImageAspects::COLOR,
+ Self::B8G8R8_USCALED => crate::image::ImageAspects::COLOR,
+ Self::B8G8R8_SSCALED => crate::image::ImageAspects::COLOR,
+ Self::B8G8R8_UINT => crate::image::ImageAspects::COLOR,
+ Self::B8G8R8_SINT => crate::image::ImageAspects::COLOR,
+ Self::B8G8R8_SRGB => crate::image::ImageAspects::COLOR,
+ Self::R8G8B8A8_UNORM => crate::image::ImageAspects::COLOR,
+ Self::R8G8B8A8_SNORM => crate::image::ImageAspects::COLOR,
+ Self::R8G8B8A8_USCALED => crate::image::ImageAspects::COLOR,
+ Self::R8G8B8A8_SSCALED => crate::image::ImageAspects::COLOR,
+ Self::R8G8B8A8_UINT => crate::image::ImageAspects::COLOR,
+ Self::R8G8B8A8_SINT => crate::image::ImageAspects::COLOR,
+ Self::R8G8B8A8_SRGB => crate::image::ImageAspects::COLOR,
+ Self::B8G8R8A8_UNORM => crate::image::ImageAspects::COLOR,
+ Self::B8G8R8A8_SNORM => crate::image::ImageAspects::COLOR,
+ Self::B8G8R8A8_USCALED => crate::image::ImageAspects::COLOR,
+ Self::B8G8R8A8_SSCALED => crate::image::ImageAspects::COLOR,
+ Self::B8G8R8A8_UINT => crate::image::ImageAspects::COLOR,
+ Self::B8G8R8A8_SINT => crate::image::ImageAspects::COLOR,
+ Self::B8G8R8A8_SRGB => crate::image::ImageAspects::COLOR,
+ Self::A8B8G8R8_UNORM_PACK32 => crate::image::ImageAspects::COLOR,
+ Self::A8B8G8R8_SNORM_PACK32 => crate::image::ImageAspects::COLOR,
+ Self::A8B8G8R8_USCALED_PACK32 => crate::image::ImageAspects::COLOR,
+ Self::A8B8G8R8_SSCALED_PACK32 => crate::image::ImageAspects::COLOR,
+ Self::A8B8G8R8_UINT_PACK32 => crate::image::ImageAspects::COLOR,
+ Self::A8B8G8R8_SINT_PACK32 => crate::image::ImageAspects::COLOR,
+ Self::A8B8G8R8_SRGB_PACK32 => crate::image::ImageAspects::COLOR,
+ Self::A2R10G10B10_UNORM_PACK32 => crate::image::ImageAspects::COLOR,
+ Self::A2R10G10B10_SNORM_PACK32 => crate::image::ImageAspects::COLOR,
+ Self::A2R10G10B10_USCALED_PACK32 => crate::image::ImageAspects::COLOR,
+ Self::A2R10G10B10_SSCALED_PACK32 => crate::image::ImageAspects::COLOR,
+ Self::A2R10G10B10_UINT_PACK32 => crate::image::ImageAspects::COLOR,
+ Self::A2R10G10B10_SINT_PACK32 => crate::image::ImageAspects::COLOR,
+ Self::A2B10G10R10_UNORM_PACK32 => crate::image::ImageAspects::COLOR,
+ Self::A2B10G10R10_SNORM_PACK32 => crate::image::ImageAspects::COLOR,
+ Self::A2B10G10R10_USCALED_PACK32 => crate::image::ImageAspects::COLOR,
+ Self::A2B10G10R10_SSCALED_PACK32 => crate::image::ImageAspects::COLOR,
+ Self::A2B10G10R10_UINT_PACK32 => crate::image::ImageAspects::COLOR,
+ Self::A2B10G10R10_SINT_PACK32 => crate::image::ImageAspects::COLOR,
+ Self::R16_UNORM => crate::image::ImageAspects::COLOR,
+ Self::R16_SNORM => crate::image::ImageAspects::COLOR,
+ Self::R16_USCALED => crate::image::ImageAspects::COLOR,
+ Self::R16_SSCALED => crate::image::ImageAspects::COLOR,
+ Self::R16_UINT => crate::image::ImageAspects::COLOR,
+ Self::R16_SINT => crate::image::ImageAspects::COLOR,
+ Self::R16_SFLOAT => crate::image::ImageAspects::COLOR,
+ Self::R16G16_UNORM => crate::image::ImageAspects::COLOR,
+ Self::R16G16_SNORM => crate::image::ImageAspects::COLOR,
+ Self::R16G16_USCALED => crate::image::ImageAspects::COLOR,
+ Self::R16G16_SSCALED => crate::image::ImageAspects::COLOR,
+ Self::R16G16_UINT => crate::image::ImageAspects::COLOR,
+ Self::R16G16_SINT => crate::image::ImageAspects::COLOR,
+ Self::R16G16_SFLOAT => crate::image::ImageAspects::COLOR,
+ Self::R16G16B16_UNORM => crate::image::ImageAspects::COLOR,
+ Self::R16G16B16_SNORM => crate::image::ImageAspects::COLOR,
+ Self::R16G16B16_USCALED => crate::image::ImageAspects::COLOR,
+ Self::R16G16B16_SSCALED => crate::image::ImageAspects::COLOR,
+ Self::R16G16B16_UINT => crate::image::ImageAspects::COLOR,
+ Self::R16G16B16_SINT => crate::image::ImageAspects::COLOR,
+ Self::R16G16B16_SFLOAT => crate::image::ImageAspects::COLOR,
+ Self::R16G16B16A16_UNORM => crate::image::ImageAspects::COLOR,
+ Self::R16G16B16A16_SNORM => crate::image::ImageAspects::COLOR,
+ Self::R16G16B16A16_USCALED => crate::image::ImageAspects::COLOR,
+ Self::R16G16B16A16_SSCALED => crate::image::ImageAspects::COLOR,
+ Self::R16G16B16A16_UINT => crate::image::ImageAspects::COLOR,
+ Self::R16G16B16A16_SINT => crate::image::ImageAspects::COLOR,
+ Self::R16G16B16A16_SFLOAT => crate::image::ImageAspects::COLOR,
+ Self::R32_UINT => crate::image::ImageAspects::COLOR,
+ Self::R32_SINT => crate::image::ImageAspects::COLOR,
+ Self::R32_SFLOAT => crate::image::ImageAspects::COLOR,
+ Self::R32G32_UINT => crate::image::ImageAspects::COLOR,
+ Self::R32G32_SINT => crate::image::ImageAspects::COLOR,
+ Self::R32G32_SFLOAT => crate::image::ImageAspects::COLOR,
+ Self::R32G32B32_UINT => crate::image::ImageAspects::COLOR,
+ Self::R32G32B32_SINT => crate::image::ImageAspects::COLOR,
+ Self::R32G32B32_SFLOAT => crate::image::ImageAspects::COLOR,
+ Self::R32G32B32A32_UINT => crate::image::ImageAspects::COLOR,
+ Self::R32G32B32A32_SINT => crate::image::ImageAspects::COLOR,
+ Self::R32G32B32A32_SFLOAT => crate::image::ImageAspects::COLOR,
+ Self::R64_UINT => crate::image::ImageAspects::COLOR,
+ Self::R64_SINT => crate::image::ImageAspects::COLOR,
+ Self::R64_SFLOAT => crate::image::ImageAspects::COLOR,
+ Self::R64G64_UINT => crate::image::ImageAspects::COLOR,
+ Self::R64G64_SINT => crate::image::ImageAspects::COLOR,
+ Self::R64G64_SFLOAT => crate::image::ImageAspects::COLOR,
+ Self::R64G64B64_UINT => crate::image::ImageAspects::COLOR,
+ Self::R64G64B64_SINT => crate::image::ImageAspects::COLOR,
+ Self::R64G64B64_SFLOAT => crate::image::ImageAspects::COLOR,
+ Self::R64G64B64A64_UINT => crate::image::ImageAspects::COLOR,
+ Self::R64G64B64A64_SINT => crate::image::ImageAspects::COLOR,
+ Self::R64G64B64A64_SFLOAT => crate::image::ImageAspects::COLOR,
+ Self::B10G11R11_UFLOAT_PACK32 => crate::image::ImageAspects::COLOR,
+ Self::E5B9G9R9_UFLOAT_PACK32 => crate::image::ImageAspects::COLOR,
+ Self::D16_UNORM => crate::image::ImageAspects::DEPTH,
+ Self::X8_D24_UNORM_PACK32 => crate::image::ImageAspects::DEPTH,
+ Self::D32_SFLOAT => crate::image::ImageAspects::DEPTH,
+ Self::S8_UINT => crate::image::ImageAspects::STENCIL,
+ Self::D16_UNORM_S8_UINT => {
+ crate::image::ImageAspects::DEPTH | crate::image::ImageAspects::STENCIL
+ }
+ Self::D24_UNORM_S8_UINT => {
+ crate::image::ImageAspects::DEPTH | crate::image::ImageAspects::STENCIL
+ }
+ Self::D32_SFLOAT_S8_UINT => {
+ crate::image::ImageAspects::DEPTH | crate::image::ImageAspects::STENCIL
+ }
+ Self::BC1_RGB_UNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::BC1_RGB_SRGB_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::BC1_RGBA_UNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::BC1_RGBA_SRGB_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::BC2_UNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::BC2_SRGB_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::BC3_UNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::BC3_SRGB_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::BC4_UNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::BC4_SNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::BC5_UNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::BC5_SNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::BC6H_UFLOAT_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::BC6H_SFLOAT_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::BC7_UNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::BC7_SRGB_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ETC2_R8G8B8_UNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ETC2_R8G8B8_SRGB_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ETC2_R8G8B8A1_UNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ETC2_R8G8B8A1_SRGB_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ETC2_R8G8B8A8_UNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ETC2_R8G8B8A8_SRGB_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::EAC_R11_UNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::EAC_R11_SNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::EAC_R11G11_UNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::EAC_R11G11_SNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_4x4_UNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_4x4_SRGB_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_5x4_UNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_5x4_SRGB_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_5x5_UNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_5x5_SRGB_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_6x5_UNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_6x5_SRGB_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_6x6_UNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_6x6_SRGB_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_8x5_UNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_8x5_SRGB_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_8x6_UNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_8x6_SRGB_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_8x8_UNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_8x8_SRGB_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_10x5_UNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_10x5_SRGB_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_10x6_UNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_10x6_SRGB_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_10x8_UNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_10x8_SRGB_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_10x10_UNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_10x10_SRGB_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_12x10_UNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_12x10_SRGB_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_12x12_UNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_12x12_SRGB_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::G8B8G8R8_422_UNORM => crate::image::ImageAspects::COLOR,
+ Self::B8G8R8G8_422_UNORM => crate::image::ImageAspects::COLOR,
+ Self::G8_B8_R8_3PLANE_420_UNORM => {
+ crate::image::ImageAspects::COLOR
+ | crate::image::ImageAspects::PLANE_0
+ | crate::image::ImageAspects::PLANE_1
+ | crate::image::ImageAspects::PLANE_2
+ }
+ Self::G8_B8R8_2PLANE_420_UNORM => {
+ crate::image::ImageAspects::COLOR
+ | crate::image::ImageAspects::PLANE_0
+ | crate::image::ImageAspects::PLANE_1
+ }
+ Self::G8_B8_R8_3PLANE_422_UNORM => {
+ crate::image::ImageAspects::COLOR
+ | crate::image::ImageAspects::PLANE_0
+ | crate::image::ImageAspects::PLANE_1
+ | crate::image::ImageAspects::PLANE_2
+ }
+ Self::G8_B8R8_2PLANE_422_UNORM => {
+ crate::image::ImageAspects::COLOR
+ | crate::image::ImageAspects::PLANE_0
+ | crate::image::ImageAspects::PLANE_1
+ }
+ Self::G8_B8_R8_3PLANE_444_UNORM => {
+ crate::image::ImageAspects::COLOR
+ | crate::image::ImageAspects::PLANE_0
+ | crate::image::ImageAspects::PLANE_1
+ | crate::image::ImageAspects::PLANE_2
+ }
+ Self::R10X6_UNORM_PACK16 => crate::image::ImageAspects::COLOR,
+ Self::R10X6G10X6_UNORM_2PACK16 => crate::image::ImageAspects::COLOR,
+ Self::R10X6G10X6B10X6A10X6_UNORM_4PACK16 => crate::image::ImageAspects::COLOR,
+ Self::G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 => crate::image::ImageAspects::COLOR,
+ Self::B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 => crate::image::ImageAspects::COLOR,
+ Self::G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 => {
+ crate::image::ImageAspects::COLOR
+ | crate::image::ImageAspects::PLANE_0
+ | crate::image::ImageAspects::PLANE_1
+ | crate::image::ImageAspects::PLANE_2
+ }
+ Self::G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 => {
+ crate::image::ImageAspects::COLOR
+ | crate::image::ImageAspects::PLANE_0
+ | crate::image::ImageAspects::PLANE_1
+ }
+ Self::G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 => {
+ crate::image::ImageAspects::COLOR
+ | crate::image::ImageAspects::PLANE_0
+ | crate::image::ImageAspects::PLANE_1
+ | crate::image::ImageAspects::PLANE_2
+ }
+ Self::G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 => {
+ crate::image::ImageAspects::COLOR
+ | crate::image::ImageAspects::PLANE_0
+ | crate::image::ImageAspects::PLANE_1
+ }
+ Self::G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 => {
+ crate::image::ImageAspects::COLOR
+ | crate::image::ImageAspects::PLANE_0
+ | crate::image::ImageAspects::PLANE_1
+ | crate::image::ImageAspects::PLANE_2
+ }
+ Self::R12X4_UNORM_PACK16 => crate::image::ImageAspects::COLOR,
+ Self::R12X4G12X4_UNORM_2PACK16 => crate::image::ImageAspects::COLOR,
+ Self::R12X4G12X4B12X4A12X4_UNORM_4PACK16 => crate::image::ImageAspects::COLOR,
+ Self::G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 => crate::image::ImageAspects::COLOR,
+ Self::B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 => crate::image::ImageAspects::COLOR,
+ Self::G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 => {
+ crate::image::ImageAspects::COLOR
+ | crate::image::ImageAspects::PLANE_0
+ | crate::image::ImageAspects::PLANE_1
+ | crate::image::ImageAspects::PLANE_2
+ }
+ Self::G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 => {
+ crate::image::ImageAspects::COLOR
+ | crate::image::ImageAspects::PLANE_0
+ | crate::image::ImageAspects::PLANE_1
+ }
+ Self::G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 => {
+ crate::image::ImageAspects::COLOR
+ | crate::image::ImageAspects::PLANE_0
+ | crate::image::ImageAspects::PLANE_1
+ | crate::image::ImageAspects::PLANE_2
+ }
+ Self::G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 => {
+ crate::image::ImageAspects::COLOR
+ | crate::image::ImageAspects::PLANE_0
+ | crate::image::ImageAspects::PLANE_1
+ }
+ Self::G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 => {
+ crate::image::ImageAspects::COLOR
+ | crate::image::ImageAspects::PLANE_0
+ | crate::image::ImageAspects::PLANE_1
+ | crate::image::ImageAspects::PLANE_2
+ }
+ Self::G16B16G16R16_422_UNORM => crate::image::ImageAspects::COLOR,
+ Self::B16G16R16G16_422_UNORM => crate::image::ImageAspects::COLOR,
+ Self::G16_B16_R16_3PLANE_420_UNORM => {
+ crate::image::ImageAspects::COLOR
+ | crate::image::ImageAspects::PLANE_0
+ | crate::image::ImageAspects::PLANE_1
+ | crate::image::ImageAspects::PLANE_2
+ }
+ Self::G16_B16R16_2PLANE_420_UNORM => {
+ crate::image::ImageAspects::COLOR
+ | crate::image::ImageAspects::PLANE_0
+ | crate::image::ImageAspects::PLANE_1
+ }
+ Self::G16_B16_R16_3PLANE_422_UNORM => {
+ crate::image::ImageAspects::COLOR
+ | crate::image::ImageAspects::PLANE_0
+ | crate::image::ImageAspects::PLANE_1
+ | crate::image::ImageAspects::PLANE_2
+ }
+ Self::G16_B16R16_2PLANE_422_UNORM => {
+ crate::image::ImageAspects::COLOR
+ | crate::image::ImageAspects::PLANE_0
+ | crate::image::ImageAspects::PLANE_1
+ }
+ Self::G16_B16_R16_3PLANE_444_UNORM => {
+ crate::image::ImageAspects::COLOR
+ | crate::image::ImageAspects::PLANE_0
+ | crate::image::ImageAspects::PLANE_1
+ | crate::image::ImageAspects::PLANE_2
+ }
+ Self::PVRTC1_2BPP_UNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::PVRTC1_4BPP_UNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::PVRTC2_2BPP_UNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::PVRTC2_4BPP_UNORM_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::PVRTC1_2BPP_SRGB_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::PVRTC1_4BPP_SRGB_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::PVRTC2_2BPP_SRGB_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::PVRTC2_4BPP_SRGB_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_4x4_SFLOAT_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_5x4_SFLOAT_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_5x5_SFLOAT_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_6x5_SFLOAT_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_6x6_SFLOAT_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_8x5_SFLOAT_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_8x6_SFLOAT_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_8x8_SFLOAT_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_10x5_SFLOAT_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_10x6_SFLOAT_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_10x8_SFLOAT_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_10x10_SFLOAT_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_12x10_SFLOAT_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::ASTC_12x12_SFLOAT_BLOCK => crate::image::ImageAspects::COLOR,
+ Self::G8_B8R8_2PLANE_444_UNORM => {
+ crate::image::ImageAspects::COLOR
+ | crate::image::ImageAspects::PLANE_0
+ | crate::image::ImageAspects::PLANE_1
+ }
+ Self::G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16 => {
+ crate::image::ImageAspects::COLOR
+ | crate::image::ImageAspects::PLANE_0
+ | crate::image::ImageAspects::PLANE_1
+ }
+ Self::G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16 => {
+ crate::image::ImageAspects::COLOR
+ | crate::image::ImageAspects::PLANE_0
+ | crate::image::ImageAspects::PLANE_1
+ }
+ Self::G16_B16R16_2PLANE_444_UNORM => {
+ crate::image::ImageAspects::COLOR
+ | crate::image::ImageAspects::PLANE_0
+ | crate::image::ImageAspects::PLANE_1
+ }
+ Self::A4R4G4B4_UNORM_PACK16 => crate::image::ImageAspects::COLOR,
+ Self::A4B4G4R4_UNORM_PACK16 => crate::image::ImageAspects::COLOR,
+ Self::R16G16_S10_5_NV => crate::image::ImageAspects::COLOR,
+ }
+ }
+ #[doc = r" Returns the extent in texels (horizontally and vertically) of a single texel"]
+ #[doc = r" block of this format. A texel block is a rectangle of pixels that is represented by"]
+ #[doc = r" a single element of this format. It is also the minimum granularity of the extent of"]
+ #[doc = r" an image; images must always have an extent that's a multiple of the block extent."]
+ #[doc = r""]
+ #[doc = r" For normal formats, the block extent is [1, 1, 1], meaning that each element of the"]
+ #[doc = r" format represents one texel. Block-compressed formats encode multiple texels into"]
+ #[doc = r" a single element. The 422 and 420 YCbCr formats have a block extent of [2, 1, 1] and"]
+ #[doc = r" [2, 2, 1] respectively, as the red and blue components are shared across multiple"]
+ #[doc = r" texels."]
+ pub fn block_extent(self) -> [u32; 3] {
+ match self {
+ Self::BC1_RGB_UNORM_BLOCK => [4, 4, 1],
+ Self::BC1_RGB_SRGB_BLOCK => [4, 4, 1],
+ Self::BC1_RGBA_UNORM_BLOCK => [4, 4, 1],
+ Self::BC1_RGBA_SRGB_BLOCK => [4, 4, 1],
+ Self::BC2_UNORM_BLOCK => [4, 4, 1],
+ Self::BC2_SRGB_BLOCK => [4, 4, 1],
+ Self::BC3_UNORM_BLOCK => [4, 4, 1],
+ Self::BC3_SRGB_BLOCK => [4, 4, 1],
+ Self::BC4_UNORM_BLOCK => [4, 4, 1],
+ Self::BC4_SNORM_BLOCK => [4, 4, 1],
+ Self::BC5_UNORM_BLOCK => [4, 4, 1],
+ Self::BC5_SNORM_BLOCK => [4, 4, 1],
+ Self::BC6H_UFLOAT_BLOCK => [4, 4, 1],
+ Self::BC6H_SFLOAT_BLOCK => [4, 4, 1],
+ Self::BC7_UNORM_BLOCK => [4, 4, 1],
+ Self::BC7_SRGB_BLOCK => [4, 4, 1],
+ Self::ETC2_R8G8B8_UNORM_BLOCK => [4, 4, 1],
+ Self::ETC2_R8G8B8_SRGB_BLOCK => [4, 4, 1],
+ Self::ETC2_R8G8B8A1_UNORM_BLOCK => [4, 4, 1],
+ Self::ETC2_R8G8B8A1_SRGB_BLOCK => [4, 4, 1],
+ Self::ETC2_R8G8B8A8_UNORM_BLOCK => [4, 4, 1],
+ Self::ETC2_R8G8B8A8_SRGB_BLOCK => [4, 4, 1],
+ Self::EAC_R11_UNORM_BLOCK => [4, 4, 1],
+ Self::EAC_R11_SNORM_BLOCK => [4, 4, 1],
+ Self::EAC_R11G11_UNORM_BLOCK => [4, 4, 1],
+ Self::EAC_R11G11_SNORM_BLOCK => [4, 4, 1],
+ Self::ASTC_4x4_UNORM_BLOCK => [4, 4, 1],
+ Self::ASTC_4x4_SRGB_BLOCK => [4, 4, 1],
+ Self::ASTC_5x4_UNORM_BLOCK => [5, 4, 1],
+ Self::ASTC_5x4_SRGB_BLOCK => [5, 4, 1],
+ Self::ASTC_5x5_UNORM_BLOCK => [5, 5, 1],
+ Self::ASTC_5x5_SRGB_BLOCK => [5, 5, 1],
+ Self::ASTC_6x5_UNORM_BLOCK => [6, 5, 1],
+ Self::ASTC_6x5_SRGB_BLOCK => [6, 5, 1],
+ Self::ASTC_6x6_UNORM_BLOCK => [6, 6, 1],
+ Self::ASTC_6x6_SRGB_BLOCK => [6, 6, 1],
+ Self::ASTC_8x5_UNORM_BLOCK => [8, 5, 1],
+ Self::ASTC_8x5_SRGB_BLOCK => [8, 5, 1],
+ Self::ASTC_8x6_UNORM_BLOCK => [8, 6, 1],
+ Self::ASTC_8x6_SRGB_BLOCK => [8, 6, 1],
+ Self::ASTC_8x8_UNORM_BLOCK => [8, 8, 1],
+ Self::ASTC_8x8_SRGB_BLOCK => [8, 8, 1],
+ Self::ASTC_10x5_UNORM_BLOCK => [10, 5, 1],
+ Self::ASTC_10x5_SRGB_BLOCK => [10, 5, 1],
+ Self::ASTC_10x6_UNORM_BLOCK => [10, 6, 1],
+ Self::ASTC_10x6_SRGB_BLOCK => [10, 6, 1],
+ Self::ASTC_10x8_UNORM_BLOCK => [10, 8, 1],
+ Self::ASTC_10x8_SRGB_BLOCK => [10, 8, 1],
+ Self::ASTC_10x10_UNORM_BLOCK => [10, 10, 1],
+ Self::ASTC_10x10_SRGB_BLOCK => [10, 10, 1],
+ Self::ASTC_12x10_UNORM_BLOCK => [12, 10, 1],
+ Self::ASTC_12x10_SRGB_BLOCK => [12, 10, 1],
+ Self::ASTC_12x12_UNORM_BLOCK => [12, 12, 1],
+ Self::ASTC_12x12_SRGB_BLOCK => [12, 12, 1],
+ Self::G8B8G8R8_422_UNORM => [2, 1, 1],
+ Self::B8G8R8G8_422_UNORM => [2, 1, 1],
+ Self::G8_B8_R8_3PLANE_420_UNORM => [2, 2, 1],
+ Self::G8_B8R8_2PLANE_420_UNORM => [2, 2, 1],
+ Self::G8_B8_R8_3PLANE_422_UNORM => [2, 1, 1],
+ Self::G8_B8R8_2PLANE_422_UNORM => [2, 1, 1],
+ Self::G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 => [2, 1, 1],
+ Self::B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 => [2, 1, 1],
+ Self::G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 => [2, 2, 1],
+ Self::G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 => [2, 2, 1],
+ Self::G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 => [2, 1, 1],
+ Self::G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 => [2, 1, 1],
+ Self::G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 => [2, 1, 1],
+ Self::B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 => [2, 1, 1],
+ Self::G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 => [2, 2, 1],
+ Self::G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 => [2, 2, 1],
+ Self::G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 => [2, 1, 1],
+ Self::G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 => [2, 1, 1],
+ Self::G16B16G16R16_422_UNORM => [2, 1, 1],
+ Self::B16G16R16G16_422_UNORM => [2, 1, 1],
+ Self::G16_B16_R16_3PLANE_420_UNORM => [2, 2, 1],
+ Self::G16_B16R16_2PLANE_420_UNORM => [2, 2, 1],
+ Self::G16_B16_R16_3PLANE_422_UNORM => [2, 1, 1],
+ Self::G16_B16R16_2PLANE_422_UNORM => [2, 1, 1],
+ Self::PVRTC1_2BPP_UNORM_BLOCK => [8, 4, 1],
+ Self::PVRTC1_4BPP_UNORM_BLOCK => [4, 4, 1],
+ Self::PVRTC2_2BPP_UNORM_BLOCK => [8, 4, 1],
+ Self::PVRTC2_4BPP_UNORM_BLOCK => [4, 4, 1],
+ Self::PVRTC1_2BPP_SRGB_BLOCK => [8, 4, 1],
+ Self::PVRTC1_4BPP_SRGB_BLOCK => [4, 4, 1],
+ Self::PVRTC2_2BPP_SRGB_BLOCK => [8, 4, 1],
+ Self::PVRTC2_4BPP_SRGB_BLOCK => [4, 4, 1],
+ Self::ASTC_4x4_SFLOAT_BLOCK => [4, 4, 1],
+ Self::ASTC_5x4_SFLOAT_BLOCK => [5, 4, 1],
+ Self::ASTC_5x5_SFLOAT_BLOCK => [5, 5, 1],
+ Self::ASTC_6x5_SFLOAT_BLOCK => [6, 5, 1],
+ Self::ASTC_6x6_SFLOAT_BLOCK => [6, 6, 1],
+ Self::ASTC_8x5_SFLOAT_BLOCK => [8, 5, 1],
+ Self::ASTC_8x6_SFLOAT_BLOCK => [8, 6, 1],
+ Self::ASTC_8x8_SFLOAT_BLOCK => [8, 8, 1],
+ Self::ASTC_10x5_SFLOAT_BLOCK => [10, 5, 1],
+ Self::ASTC_10x6_SFLOAT_BLOCK => [10, 6, 1],
+ Self::ASTC_10x8_SFLOAT_BLOCK => [10, 8, 1],
+ Self::ASTC_10x10_SFLOAT_BLOCK => [10, 10, 1],
+ Self::ASTC_12x10_SFLOAT_BLOCK => [12, 10, 1],
+ Self::ASTC_12x12_SFLOAT_BLOCK => [12, 12, 1],
+ _ => [1, 1, 1],
+ }
+ }
+ #[doc = r" Returns the size in bytes of a single texel block of this format. Returns `None`"]
+ #[doc = r" if the texel block size is not well-defined for this format."]
+ #[doc = r""]
+ #[doc = r" For regular formats, this is the size of a single texel, but for more specialized"]
+ #[doc = r" formats this may be the size of multiple texels."]
+ #[doc = r""]
+ #[doc = r" Depth/stencil formats are considered to have an opaque memory representation, and do"]
+ #[doc = r" not have a well-defined size. Multi-planar formats store the color components"]
+ #[doc = r" disjointly in memory, and therefore do not have a well-defined size for all"]
+ #[doc = r" components as a whole. The individual planes do have a well-defined size."]
+ pub fn block_size(self) -> Option<DeviceSize> {
+ match self {
+ Self::R4G4_UNORM_PACK8 => Some(1),
+ Self::R4G4B4A4_UNORM_PACK16 => Some(2),
+ Self::B4G4R4A4_UNORM_PACK16 => Some(2),
+ Self::R5G6B5_UNORM_PACK16 => Some(2),
+ Self::B5G6R5_UNORM_PACK16 => Some(2),
+ Self::R5G5B5A1_UNORM_PACK16 => Some(2),
+ Self::B5G5R5A1_UNORM_PACK16 => Some(2),
+ Self::A1R5G5B5_UNORM_PACK16 => Some(2),
+ Self::R8_UNORM => Some(1),
+ Self::R8_SNORM => Some(1),
+ Self::R8_USCALED => Some(1),
+ Self::R8_SSCALED => Some(1),
+ Self::R8_UINT => Some(1),
+ Self::R8_SINT => Some(1),
+ Self::R8_SRGB => Some(1),
+ Self::R8G8_UNORM => Some(2),
+ Self::R8G8_SNORM => Some(2),
+ Self::R8G8_USCALED => Some(2),
+ Self::R8G8_SSCALED => Some(2),
+ Self::R8G8_UINT => Some(2),
+ Self::R8G8_SINT => Some(2),
+ Self::R8G8_SRGB => Some(2),
+ Self::R8G8B8_UNORM => Some(3),
+ Self::R8G8B8_SNORM => Some(3),
+ Self::R8G8B8_USCALED => Some(3),
+ Self::R8G8B8_SSCALED => Some(3),
+ Self::R8G8B8_UINT => Some(3),
+ Self::R8G8B8_SINT => Some(3),
+ Self::R8G8B8_SRGB => Some(3),
+ Self::B8G8R8_UNORM => Some(3),
+ Self::B8G8R8_SNORM => Some(3),
+ Self::B8G8R8_USCALED => Some(3),
+ Self::B8G8R8_SSCALED => Some(3),
+ Self::B8G8R8_UINT => Some(3),
+ Self::B8G8R8_SINT => Some(3),
+ Self::B8G8R8_SRGB => Some(3),
+ Self::R8G8B8A8_UNORM => Some(4),
+ Self::R8G8B8A8_SNORM => Some(4),
+ Self::R8G8B8A8_USCALED => Some(4),
+ Self::R8G8B8A8_SSCALED => Some(4),
+ Self::R8G8B8A8_UINT => Some(4),
+ Self::R8G8B8A8_SINT => Some(4),
+ Self::R8G8B8A8_SRGB => Some(4),
+ Self::B8G8R8A8_UNORM => Some(4),
+ Self::B8G8R8A8_SNORM => Some(4),
+ Self::B8G8R8A8_USCALED => Some(4),
+ Self::B8G8R8A8_SSCALED => Some(4),
+ Self::B8G8R8A8_UINT => Some(4),
+ Self::B8G8R8A8_SINT => Some(4),
+ Self::B8G8R8A8_SRGB => Some(4),
+ Self::A8B8G8R8_UNORM_PACK32 => Some(4),
+ Self::A8B8G8R8_SNORM_PACK32 => Some(4),
+ Self::A8B8G8R8_USCALED_PACK32 => Some(4),
+ Self::A8B8G8R8_SSCALED_PACK32 => Some(4),
+ Self::A8B8G8R8_UINT_PACK32 => Some(4),
+ Self::A8B8G8R8_SINT_PACK32 => Some(4),
+ Self::A8B8G8R8_SRGB_PACK32 => Some(4),
+ Self::A2R10G10B10_UNORM_PACK32 => Some(4),
+ Self::A2R10G10B10_SNORM_PACK32 => Some(4),
+ Self::A2R10G10B10_USCALED_PACK32 => Some(4),
+ Self::A2R10G10B10_SSCALED_PACK32 => Some(4),
+ Self::A2R10G10B10_UINT_PACK32 => Some(4),
+ Self::A2R10G10B10_SINT_PACK32 => Some(4),
+ Self::A2B10G10R10_UNORM_PACK32 => Some(4),
+ Self::A2B10G10R10_SNORM_PACK32 => Some(4),
+ Self::A2B10G10R10_USCALED_PACK32 => Some(4),
+ Self::A2B10G10R10_SSCALED_PACK32 => Some(4),
+ Self::A2B10G10R10_UINT_PACK32 => Some(4),
+ Self::A2B10G10R10_SINT_PACK32 => Some(4),
+ Self::R16_UNORM => Some(2),
+ Self::R16_SNORM => Some(2),
+ Self::R16_USCALED => Some(2),
+ Self::R16_SSCALED => Some(2),
+ Self::R16_UINT => Some(2),
+ Self::R16_SINT => Some(2),
+ Self::R16_SFLOAT => Some(2),
+ Self::R16G16_UNORM => Some(4),
+ Self::R16G16_SNORM => Some(4),
+ Self::R16G16_USCALED => Some(4),
+ Self::R16G16_SSCALED => Some(4),
+ Self::R16G16_UINT => Some(4),
+ Self::R16G16_SINT => Some(4),
+ Self::R16G16_SFLOAT => Some(4),
+ Self::R16G16B16_UNORM => Some(6),
+ Self::R16G16B16_SNORM => Some(6),
+ Self::R16G16B16_USCALED => Some(6),
+ Self::R16G16B16_SSCALED => Some(6),
+ Self::R16G16B16_UINT => Some(6),
+ Self::R16G16B16_SINT => Some(6),
+ Self::R16G16B16_SFLOAT => Some(6),
+ Self::R16G16B16A16_UNORM => Some(8),
+ Self::R16G16B16A16_SNORM => Some(8),
+ Self::R16G16B16A16_USCALED => Some(8),
+ Self::R16G16B16A16_SSCALED => Some(8),
+ Self::R16G16B16A16_UINT => Some(8),
+ Self::R16G16B16A16_SINT => Some(8),
+ Self::R16G16B16A16_SFLOAT => Some(8),
+ Self::R32_UINT => Some(4),
+ Self::R32_SINT => Some(4),
+ Self::R32_SFLOAT => Some(4),
+ Self::R32G32_UINT => Some(8),
+ Self::R32G32_SINT => Some(8),
+ Self::R32G32_SFLOAT => Some(8),
+ Self::R32G32B32_UINT => Some(12),
+ Self::R32G32B32_SINT => Some(12),
+ Self::R32G32B32_SFLOAT => Some(12),
+ Self::R32G32B32A32_UINT => Some(16),
+ Self::R32G32B32A32_SINT => Some(16),
+ Self::R32G32B32A32_SFLOAT => Some(16),
+ Self::R64_UINT => Some(8),
+ Self::R64_SINT => Some(8),
+ Self::R64_SFLOAT => Some(8),
+ Self::R64G64_UINT => Some(16),
+ Self::R64G64_SINT => Some(16),
+ Self::R64G64_SFLOAT => Some(16),
+ Self::R64G64B64_UINT => Some(24),
+ Self::R64G64B64_SINT => Some(24),
+ Self::R64G64B64_SFLOAT => Some(24),
+ Self::R64G64B64A64_UINT => Some(32),
+ Self::R64G64B64A64_SINT => Some(32),
+ Self::R64G64B64A64_SFLOAT => Some(32),
+ Self::B10G11R11_UFLOAT_PACK32 => Some(4),
+ Self::E5B9G9R9_UFLOAT_PACK32 => Some(4),
+ Self::BC1_RGB_UNORM_BLOCK => Some(8),
+ Self::BC1_RGB_SRGB_BLOCK => Some(8),
+ Self::BC1_RGBA_UNORM_BLOCK => Some(8),
+ Self::BC1_RGBA_SRGB_BLOCK => Some(8),
+ Self::BC2_UNORM_BLOCK => Some(16),
+ Self::BC2_SRGB_BLOCK => Some(16),
+ Self::BC3_UNORM_BLOCK => Some(16),
+ Self::BC3_SRGB_BLOCK => Some(16),
+ Self::BC4_UNORM_BLOCK => Some(8),
+ Self::BC4_SNORM_BLOCK => Some(8),
+ Self::BC5_UNORM_BLOCK => Some(16),
+ Self::BC5_SNORM_BLOCK => Some(16),
+ Self::BC6H_UFLOAT_BLOCK => Some(16),
+ Self::BC6H_SFLOAT_BLOCK => Some(16),
+ Self::BC7_UNORM_BLOCK => Some(16),
+ Self::BC7_SRGB_BLOCK => Some(16),
+ Self::ETC2_R8G8B8_UNORM_BLOCK => Some(8),
+ Self::ETC2_R8G8B8_SRGB_BLOCK => Some(8),
+ Self::ETC2_R8G8B8A1_UNORM_BLOCK => Some(8),
+ Self::ETC2_R8G8B8A1_SRGB_BLOCK => Some(8),
+ Self::ETC2_R8G8B8A8_UNORM_BLOCK => Some(16),
+ Self::ETC2_R8G8B8A8_SRGB_BLOCK => Some(16),
+ Self::EAC_R11_UNORM_BLOCK => Some(8),
+ Self::EAC_R11_SNORM_BLOCK => Some(8),
+ Self::EAC_R11G11_UNORM_BLOCK => Some(16),
+ Self::EAC_R11G11_SNORM_BLOCK => Some(16),
+ Self::ASTC_4x4_UNORM_BLOCK => Some(16),
+ Self::ASTC_4x4_SRGB_BLOCK => Some(16),
+ Self::ASTC_5x4_UNORM_BLOCK => Some(16),
+ Self::ASTC_5x4_SRGB_BLOCK => Some(16),
+ Self::ASTC_5x5_UNORM_BLOCK => Some(16),
+ Self::ASTC_5x5_SRGB_BLOCK => Some(16),
+ Self::ASTC_6x5_UNORM_BLOCK => Some(16),
+ Self::ASTC_6x5_SRGB_BLOCK => Some(16),
+ Self::ASTC_6x6_UNORM_BLOCK => Some(16),
+ Self::ASTC_6x6_SRGB_BLOCK => Some(16),
+ Self::ASTC_8x5_UNORM_BLOCK => Some(16),
+ Self::ASTC_8x5_SRGB_BLOCK => Some(16),
+ Self::ASTC_8x6_UNORM_BLOCK => Some(16),
+ Self::ASTC_8x6_SRGB_BLOCK => Some(16),
+ Self::ASTC_8x8_UNORM_BLOCK => Some(16),
+ Self::ASTC_8x8_SRGB_BLOCK => Some(16),
+ Self::ASTC_10x5_UNORM_BLOCK => Some(16),
+ Self::ASTC_10x5_SRGB_BLOCK => Some(16),
+ Self::ASTC_10x6_UNORM_BLOCK => Some(16),
+ Self::ASTC_10x6_SRGB_BLOCK => Some(16),
+ Self::ASTC_10x8_UNORM_BLOCK => Some(16),
+ Self::ASTC_10x8_SRGB_BLOCK => Some(16),
+ Self::ASTC_10x10_UNORM_BLOCK => Some(16),
+ Self::ASTC_10x10_SRGB_BLOCK => Some(16),
+ Self::ASTC_12x10_UNORM_BLOCK => Some(16),
+ Self::ASTC_12x10_SRGB_BLOCK => Some(16),
+ Self::ASTC_12x12_UNORM_BLOCK => Some(16),
+ Self::ASTC_12x12_SRGB_BLOCK => Some(16),
+ Self::G8B8G8R8_422_UNORM => Some(4),
+ Self::B8G8R8G8_422_UNORM => Some(4),
+ Self::R10X6_UNORM_PACK16 => Some(2),
+ Self::R10X6G10X6_UNORM_2PACK16 => Some(4),
+ Self::R10X6G10X6B10X6A10X6_UNORM_4PACK16 => Some(8),
+ Self::G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 => Some(8),
+ Self::B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 => Some(8),
+ Self::R12X4_UNORM_PACK16 => Some(2),
+ Self::R12X4G12X4_UNORM_2PACK16 => Some(4),
+ Self::R12X4G12X4B12X4A12X4_UNORM_4PACK16 => Some(8),
+ Self::G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 => Some(8),
+ Self::B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 => Some(8),
+ Self::G16B16G16R16_422_UNORM => Some(8),
+ Self::B16G16R16G16_422_UNORM => Some(8),
+ Self::PVRTC1_2BPP_UNORM_BLOCK => Some(8),
+ Self::PVRTC1_4BPP_UNORM_BLOCK => Some(8),
+ Self::PVRTC2_2BPP_UNORM_BLOCK => Some(8),
+ Self::PVRTC2_4BPP_UNORM_BLOCK => Some(8),
+ Self::PVRTC1_2BPP_SRGB_BLOCK => Some(8),
+ Self::PVRTC1_4BPP_SRGB_BLOCK => Some(8),
+ Self::PVRTC2_2BPP_SRGB_BLOCK => Some(8),
+ Self::PVRTC2_4BPP_SRGB_BLOCK => Some(8),
+ Self::ASTC_4x4_SFLOAT_BLOCK => Some(16),
+ Self::ASTC_5x4_SFLOAT_BLOCK => Some(16),
+ Self::ASTC_5x5_SFLOAT_BLOCK => Some(16),
+ Self::ASTC_6x5_SFLOAT_BLOCK => Some(16),
+ Self::ASTC_6x6_SFLOAT_BLOCK => Some(16),
+ Self::ASTC_8x5_SFLOAT_BLOCK => Some(16),
+ Self::ASTC_8x6_SFLOAT_BLOCK => Some(16),
+ Self::ASTC_8x8_SFLOAT_BLOCK => Some(16),
+ Self::ASTC_10x5_SFLOAT_BLOCK => Some(16),
+ Self::ASTC_10x6_SFLOAT_BLOCK => Some(16),
+ Self::ASTC_10x8_SFLOAT_BLOCK => Some(16),
+ Self::ASTC_10x10_SFLOAT_BLOCK => Some(16),
+ Self::ASTC_12x10_SFLOAT_BLOCK => Some(16),
+ Self::ASTC_12x12_SFLOAT_BLOCK => Some(16),
+ Self::A4R4G4B4_UNORM_PACK16 => Some(2),
+ Self::A4B4G4R4_UNORM_PACK16 => Some(2),
+ Self::R16G16_S10_5_NV => Some(4),
+ _ => None,
+ }
+ }
+ #[doc = r" Returns the an opaque object representing the compatibility class of the format."]
+ #[doc = r" This can be used to determine whether two formats are compatible for the purposes"]
+ #[doc = r" of certain Vulkan operations, such as image copying."]
+ pub fn compatibility(self) -> FormatCompatibility {
+ FormatCompatibility(match self {
+ Self::R4G4_UNORM_PACK8 => &FormatCompatibilityInner::Class_8bit,
+ Self::R4G4B4A4_UNORM_PACK16 => &FormatCompatibilityInner::Class_16bit,
+ Self::B4G4R4A4_UNORM_PACK16 => &FormatCompatibilityInner::Class_16bit,
+ Self::R5G6B5_UNORM_PACK16 => &FormatCompatibilityInner::Class_16bit,
+ Self::B5G6R5_UNORM_PACK16 => &FormatCompatibilityInner::Class_16bit,
+ Self::R5G5B5A1_UNORM_PACK16 => &FormatCompatibilityInner::Class_16bit,
+ Self::B5G5R5A1_UNORM_PACK16 => &FormatCompatibilityInner::Class_16bit,
+ Self::A1R5G5B5_UNORM_PACK16 => &FormatCompatibilityInner::Class_16bit,
+ Self::R8_UNORM => &FormatCompatibilityInner::Class_8bit,
+ Self::R8_SNORM => &FormatCompatibilityInner::Class_8bit,
+ Self::R8_USCALED => &FormatCompatibilityInner::Class_8bit,
+ Self::R8_SSCALED => &FormatCompatibilityInner::Class_8bit,
+ Self::R8_UINT => &FormatCompatibilityInner::Class_8bit,
+ Self::R8_SINT => &FormatCompatibilityInner::Class_8bit,
+ Self::R8_SRGB => &FormatCompatibilityInner::Class_8bit,
+ Self::R8G8_UNORM => &FormatCompatibilityInner::Class_16bit,
+ Self::R8G8_SNORM => &FormatCompatibilityInner::Class_16bit,
+ Self::R8G8_USCALED => &FormatCompatibilityInner::Class_16bit,
+ Self::R8G8_SSCALED => &FormatCompatibilityInner::Class_16bit,
+ Self::R8G8_UINT => &FormatCompatibilityInner::Class_16bit,
+ Self::R8G8_SINT => &FormatCompatibilityInner::Class_16bit,
+ Self::R8G8_SRGB => &FormatCompatibilityInner::Class_16bit,
+ Self::R8G8B8_UNORM => &FormatCompatibilityInner::Class_24bit,
+ Self::R8G8B8_SNORM => &FormatCompatibilityInner::Class_24bit,
+ Self::R8G8B8_USCALED => &FormatCompatibilityInner::Class_24bit,
+ Self::R8G8B8_SSCALED => &FormatCompatibilityInner::Class_24bit,
+ Self::R8G8B8_UINT => &FormatCompatibilityInner::Class_24bit,
+ Self::R8G8B8_SINT => &FormatCompatibilityInner::Class_24bit,
+ Self::R8G8B8_SRGB => &FormatCompatibilityInner::Class_24bit,
+ Self::B8G8R8_UNORM => &FormatCompatibilityInner::Class_24bit,
+ Self::B8G8R8_SNORM => &FormatCompatibilityInner::Class_24bit,
+ Self::B8G8R8_USCALED => &FormatCompatibilityInner::Class_24bit,
+ Self::B8G8R8_SSCALED => &FormatCompatibilityInner::Class_24bit,
+ Self::B8G8R8_UINT => &FormatCompatibilityInner::Class_24bit,
+ Self::B8G8R8_SINT => &FormatCompatibilityInner::Class_24bit,
+ Self::B8G8R8_SRGB => &FormatCompatibilityInner::Class_24bit,
+ Self::R8G8B8A8_UNORM => &FormatCompatibilityInner::Class_32bit,
+ Self::R8G8B8A8_SNORM => &FormatCompatibilityInner::Class_32bit,
+ Self::R8G8B8A8_USCALED => &FormatCompatibilityInner::Class_32bit,
+ Self::R8G8B8A8_SSCALED => &FormatCompatibilityInner::Class_32bit,
+ Self::R8G8B8A8_UINT => &FormatCompatibilityInner::Class_32bit,
+ Self::R8G8B8A8_SINT => &FormatCompatibilityInner::Class_32bit,
+ Self::R8G8B8A8_SRGB => &FormatCompatibilityInner::Class_32bit,
+ Self::B8G8R8A8_UNORM => &FormatCompatibilityInner::Class_32bit,
+ Self::B8G8R8A8_SNORM => &FormatCompatibilityInner::Class_32bit,
+ Self::B8G8R8A8_USCALED => &FormatCompatibilityInner::Class_32bit,
+ Self::B8G8R8A8_SSCALED => &FormatCompatibilityInner::Class_32bit,
+ Self::B8G8R8A8_UINT => &FormatCompatibilityInner::Class_32bit,
+ Self::B8G8R8A8_SINT => &FormatCompatibilityInner::Class_32bit,
+ Self::B8G8R8A8_SRGB => &FormatCompatibilityInner::Class_32bit,
+ Self::A8B8G8R8_UNORM_PACK32 => &FormatCompatibilityInner::Class_32bit,
+ Self::A8B8G8R8_SNORM_PACK32 => &FormatCompatibilityInner::Class_32bit,
+ Self::A8B8G8R8_USCALED_PACK32 => &FormatCompatibilityInner::Class_32bit,
+ Self::A8B8G8R8_SSCALED_PACK32 => &FormatCompatibilityInner::Class_32bit,
+ Self::A8B8G8R8_UINT_PACK32 => &FormatCompatibilityInner::Class_32bit,
+ Self::A8B8G8R8_SINT_PACK32 => &FormatCompatibilityInner::Class_32bit,
+ Self::A8B8G8R8_SRGB_PACK32 => &FormatCompatibilityInner::Class_32bit,
+ Self::A2R10G10B10_UNORM_PACK32 => &FormatCompatibilityInner::Class_32bit,
+ Self::A2R10G10B10_SNORM_PACK32 => &FormatCompatibilityInner::Class_32bit,
+ Self::A2R10G10B10_USCALED_PACK32 => &FormatCompatibilityInner::Class_32bit,
+ Self::A2R10G10B10_SSCALED_PACK32 => &FormatCompatibilityInner::Class_32bit,
+ Self::A2R10G10B10_UINT_PACK32 => &FormatCompatibilityInner::Class_32bit,
+ Self::A2R10G10B10_SINT_PACK32 => &FormatCompatibilityInner::Class_32bit,
+ Self::A2B10G10R10_UNORM_PACK32 => &FormatCompatibilityInner::Class_32bit,
+ Self::A2B10G10R10_SNORM_PACK32 => &FormatCompatibilityInner::Class_32bit,
+ Self::A2B10G10R10_USCALED_PACK32 => &FormatCompatibilityInner::Class_32bit,
+ Self::A2B10G10R10_SSCALED_PACK32 => &FormatCompatibilityInner::Class_32bit,
+ Self::A2B10G10R10_UINT_PACK32 => &FormatCompatibilityInner::Class_32bit,
+ Self::A2B10G10R10_SINT_PACK32 => &FormatCompatibilityInner::Class_32bit,
+ Self::R16_UNORM => &FormatCompatibilityInner::Class_16bit,
+ Self::R16_SNORM => &FormatCompatibilityInner::Class_16bit,
+ Self::R16_USCALED => &FormatCompatibilityInner::Class_16bit,
+ Self::R16_SSCALED => &FormatCompatibilityInner::Class_16bit,
+ Self::R16_UINT => &FormatCompatibilityInner::Class_16bit,
+ Self::R16_SINT => &FormatCompatibilityInner::Class_16bit,
+ Self::R16_SFLOAT => &FormatCompatibilityInner::Class_16bit,
+ Self::R16G16_UNORM => &FormatCompatibilityInner::Class_32bit,
+ Self::R16G16_SNORM => &FormatCompatibilityInner::Class_32bit,
+ Self::R16G16_USCALED => &FormatCompatibilityInner::Class_32bit,
+ Self::R16G16_SSCALED => &FormatCompatibilityInner::Class_32bit,
+ Self::R16G16_UINT => &FormatCompatibilityInner::Class_32bit,
+ Self::R16G16_SINT => &FormatCompatibilityInner::Class_32bit,
+ Self::R16G16_SFLOAT => &FormatCompatibilityInner::Class_32bit,
+ Self::R16G16B16_UNORM => &FormatCompatibilityInner::Class_48bit,
+ Self::R16G16B16_SNORM => &FormatCompatibilityInner::Class_48bit,
+ Self::R16G16B16_USCALED => &FormatCompatibilityInner::Class_48bit,
+ Self::R16G16B16_SSCALED => &FormatCompatibilityInner::Class_48bit,
+ Self::R16G16B16_UINT => &FormatCompatibilityInner::Class_48bit,
+ Self::R16G16B16_SINT => &FormatCompatibilityInner::Class_48bit,
+ Self::R16G16B16_SFLOAT => &FormatCompatibilityInner::Class_48bit,
+ Self::R16G16B16A16_UNORM => &FormatCompatibilityInner::Class_64bit,
+ Self::R16G16B16A16_SNORM => &FormatCompatibilityInner::Class_64bit,
+ Self::R16G16B16A16_USCALED => &FormatCompatibilityInner::Class_64bit,
+ Self::R16G16B16A16_SSCALED => &FormatCompatibilityInner::Class_64bit,
+ Self::R16G16B16A16_UINT => &FormatCompatibilityInner::Class_64bit,
+ Self::R16G16B16A16_SINT => &FormatCompatibilityInner::Class_64bit,
+ Self::R16G16B16A16_SFLOAT => &FormatCompatibilityInner::Class_64bit,
+ Self::R32_UINT => &FormatCompatibilityInner::Class_32bit,
+ Self::R32_SINT => &FormatCompatibilityInner::Class_32bit,
+ Self::R32_SFLOAT => &FormatCompatibilityInner::Class_32bit,
+ Self::R32G32_UINT => &FormatCompatibilityInner::Class_64bit,
+ Self::R32G32_SINT => &FormatCompatibilityInner::Class_64bit,
+ Self::R32G32_SFLOAT => &FormatCompatibilityInner::Class_64bit,
+ Self::R32G32B32_UINT => &FormatCompatibilityInner::Class_96bit,
+ Self::R32G32B32_SINT => &FormatCompatibilityInner::Class_96bit,
+ Self::R32G32B32_SFLOAT => &FormatCompatibilityInner::Class_96bit,
+ Self::R32G32B32A32_UINT => &FormatCompatibilityInner::Class_128bit,
+ Self::R32G32B32A32_SINT => &FormatCompatibilityInner::Class_128bit,
+ Self::R32G32B32A32_SFLOAT => &FormatCompatibilityInner::Class_128bit,
+ Self::R64_UINT => &FormatCompatibilityInner::Class_64bit,
+ Self::R64_SINT => &FormatCompatibilityInner::Class_64bit,
+ Self::R64_SFLOAT => &FormatCompatibilityInner::Class_64bit,
+ Self::R64G64_UINT => &FormatCompatibilityInner::Class_128bit,
+ Self::R64G64_SINT => &FormatCompatibilityInner::Class_128bit,
+ Self::R64G64_SFLOAT => &FormatCompatibilityInner::Class_128bit,
+ Self::R64G64B64_UINT => &FormatCompatibilityInner::Class_192bit,
+ Self::R64G64B64_SINT => &FormatCompatibilityInner::Class_192bit,
+ Self::R64G64B64_SFLOAT => &FormatCompatibilityInner::Class_192bit,
+ Self::R64G64B64A64_UINT => &FormatCompatibilityInner::Class_256bit,
+ Self::R64G64B64A64_SINT => &FormatCompatibilityInner::Class_256bit,
+ Self::R64G64B64A64_SFLOAT => &FormatCompatibilityInner::Class_256bit,
+ Self::B10G11R11_UFLOAT_PACK32 => &FormatCompatibilityInner::Class_32bit,
+ Self::E5B9G9R9_UFLOAT_PACK32 => &FormatCompatibilityInner::Class_32bit,
+ Self::D16_UNORM => &FormatCompatibilityInner::Class_D16,
+ Self::X8_D24_UNORM_PACK32 => &FormatCompatibilityInner::Class_D24,
+ Self::D32_SFLOAT => &FormatCompatibilityInner::Class_D32,
+ Self::S8_UINT => &FormatCompatibilityInner::Class_S8,
+ Self::D16_UNORM_S8_UINT => &FormatCompatibilityInner::Class_D16S8,
+ Self::D24_UNORM_S8_UINT => &FormatCompatibilityInner::Class_D24S8,
+ Self::D32_SFLOAT_S8_UINT => &FormatCompatibilityInner::Class_D32S8,
+ Self::BC1_RGB_UNORM_BLOCK => &FormatCompatibilityInner::Class_BC1_RGB,
+ Self::BC1_RGB_SRGB_BLOCK => &FormatCompatibilityInner::Class_BC1_RGB,
+ Self::BC1_RGBA_UNORM_BLOCK => &FormatCompatibilityInner::Class_BC1_RGBA,
+ Self::BC1_RGBA_SRGB_BLOCK => &FormatCompatibilityInner::Class_BC1_RGBA,
+ Self::BC2_UNORM_BLOCK => &FormatCompatibilityInner::Class_BC2,
+ Self::BC2_SRGB_BLOCK => &FormatCompatibilityInner::Class_BC2,
+ Self::BC3_UNORM_BLOCK => &FormatCompatibilityInner::Class_BC3,
+ Self::BC3_SRGB_BLOCK => &FormatCompatibilityInner::Class_BC3,
+ Self::BC4_UNORM_BLOCK => &FormatCompatibilityInner::Class_BC4,
+ Self::BC4_SNORM_BLOCK => &FormatCompatibilityInner::Class_BC4,
+ Self::BC5_UNORM_BLOCK => &FormatCompatibilityInner::Class_BC5,
+ Self::BC5_SNORM_BLOCK => &FormatCompatibilityInner::Class_BC5,
+ Self::BC6H_UFLOAT_BLOCK => &FormatCompatibilityInner::Class_BC6H,
+ Self::BC6H_SFLOAT_BLOCK => &FormatCompatibilityInner::Class_BC6H,
+ Self::BC7_UNORM_BLOCK => &FormatCompatibilityInner::Class_BC7,
+ Self::BC7_SRGB_BLOCK => &FormatCompatibilityInner::Class_BC7,
+ Self::ETC2_R8G8B8_UNORM_BLOCK => &FormatCompatibilityInner::Class_ETC2_RGB,
+ Self::ETC2_R8G8B8_SRGB_BLOCK => &FormatCompatibilityInner::Class_ETC2_RGB,
+ Self::ETC2_R8G8B8A1_UNORM_BLOCK => &FormatCompatibilityInner::Class_ETC2_RGBA,
+ Self::ETC2_R8G8B8A1_SRGB_BLOCK => &FormatCompatibilityInner::Class_ETC2_RGBA,
+ Self::ETC2_R8G8B8A8_UNORM_BLOCK => &FormatCompatibilityInner::Class_ETC2_EAC_RGBA,
+ Self::ETC2_R8G8B8A8_SRGB_BLOCK => &FormatCompatibilityInner::Class_ETC2_EAC_RGBA,
+ Self::EAC_R11_UNORM_BLOCK => &FormatCompatibilityInner::Class_EAC_R,
+ Self::EAC_R11_SNORM_BLOCK => &FormatCompatibilityInner::Class_EAC_R,
+ Self::EAC_R11G11_UNORM_BLOCK => &FormatCompatibilityInner::Class_EAC_RG,
+ Self::EAC_R11G11_SNORM_BLOCK => &FormatCompatibilityInner::Class_EAC_RG,
+ Self::ASTC_4x4_UNORM_BLOCK => &FormatCompatibilityInner::Class_ASTC_4x4,
+ Self::ASTC_4x4_SRGB_BLOCK => &FormatCompatibilityInner::Class_ASTC_4x4,
+ Self::ASTC_5x4_UNORM_BLOCK => &FormatCompatibilityInner::Class_ASTC_5x4,
+ Self::ASTC_5x4_SRGB_BLOCK => &FormatCompatibilityInner::Class_ASTC_5x4,
+ Self::ASTC_5x5_UNORM_BLOCK => &FormatCompatibilityInner::Class_ASTC_5x5,
+ Self::ASTC_5x5_SRGB_BLOCK => &FormatCompatibilityInner::Class_ASTC_5x5,
+ Self::ASTC_6x5_UNORM_BLOCK => &FormatCompatibilityInner::Class_ASTC_6x5,
+ Self::ASTC_6x5_SRGB_BLOCK => &FormatCompatibilityInner::Class_ASTC_6x5,
+ Self::ASTC_6x6_UNORM_BLOCK => &FormatCompatibilityInner::Class_ASTC_6x6,
+ Self::ASTC_6x6_SRGB_BLOCK => &FormatCompatibilityInner::Class_ASTC_6x6,
+ Self::ASTC_8x5_UNORM_BLOCK => &FormatCompatibilityInner::Class_ASTC_8x5,
+ Self::ASTC_8x5_SRGB_BLOCK => &FormatCompatibilityInner::Class_ASTC_8x5,
+ Self::ASTC_8x6_UNORM_BLOCK => &FormatCompatibilityInner::Class_ASTC_8x6,
+ Self::ASTC_8x6_SRGB_BLOCK => &FormatCompatibilityInner::Class_ASTC_8x6,
+ Self::ASTC_8x8_UNORM_BLOCK => &FormatCompatibilityInner::Class_ASTC_8x8,
+ Self::ASTC_8x8_SRGB_BLOCK => &FormatCompatibilityInner::Class_ASTC_8x8,
+ Self::ASTC_10x5_UNORM_BLOCK => &FormatCompatibilityInner::Class_ASTC_10x5,
+ Self::ASTC_10x5_SRGB_BLOCK => &FormatCompatibilityInner::Class_ASTC_10x5,
+ Self::ASTC_10x6_UNORM_BLOCK => &FormatCompatibilityInner::Class_ASTC_10x6,
+ Self::ASTC_10x6_SRGB_BLOCK => &FormatCompatibilityInner::Class_ASTC_10x6,
+ Self::ASTC_10x8_UNORM_BLOCK => &FormatCompatibilityInner::Class_ASTC_10x8,
+ Self::ASTC_10x8_SRGB_BLOCK => &FormatCompatibilityInner::Class_ASTC_10x8,
+ Self::ASTC_10x10_UNORM_BLOCK => &FormatCompatibilityInner::Class_ASTC_10x10,
+ Self::ASTC_10x10_SRGB_BLOCK => &FormatCompatibilityInner::Class_ASTC_10x10,
+ Self::ASTC_12x10_UNORM_BLOCK => &FormatCompatibilityInner::Class_ASTC_12x10,
+ Self::ASTC_12x10_SRGB_BLOCK => &FormatCompatibilityInner::Class_ASTC_12x10,
+ Self::ASTC_12x12_UNORM_BLOCK => &FormatCompatibilityInner::Class_ASTC_12x12,
+ Self::ASTC_12x12_SRGB_BLOCK => &FormatCompatibilityInner::Class_ASTC_12x12,
+ Self::G8B8G8R8_422_UNORM => &FormatCompatibilityInner::Class_32bit_G8B8G8R8,
+ Self::B8G8R8G8_422_UNORM => &FormatCompatibilityInner::Class_32bit_B8G8R8G8,
+ Self::G8_B8_R8_3PLANE_420_UNORM => &FormatCompatibilityInner::Class_8bit_3plane_420,
+ Self::G8_B8R8_2PLANE_420_UNORM => &FormatCompatibilityInner::Class_8bit_2plane_420,
+ Self::G8_B8_R8_3PLANE_422_UNORM => &FormatCompatibilityInner::Class_8bit_3plane_422,
+ Self::G8_B8R8_2PLANE_422_UNORM => &FormatCompatibilityInner::Class_8bit_2plane_422,
+ Self::G8_B8_R8_3PLANE_444_UNORM => &FormatCompatibilityInner::Class_8bit_3plane_444,
+ Self::R10X6_UNORM_PACK16 => &FormatCompatibilityInner::Class_16bit,
+ Self::R10X6G10X6_UNORM_2PACK16 => &FormatCompatibilityInner::Class_32bit,
+ Self::R10X6G10X6B10X6A10X6_UNORM_4PACK16 => {
+ &FormatCompatibilityInner::Class_64bit_R10G10B10A10
+ }
+ Self::G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 => {
+ &FormatCompatibilityInner::Class_64bit_G10B10G10R10
+ }
+ Self::B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 => {
+ &FormatCompatibilityInner::Class_64bit_B10G10R10G10
+ }
+ Self::G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 => {
+ &FormatCompatibilityInner::Class_10bit_3plane_420
+ }
+ Self::G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 => {
+ &FormatCompatibilityInner::Class_10bit_2plane_420
+ }
+ Self::G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 => {
+ &FormatCompatibilityInner::Class_10bit_3plane_422
+ }
+ Self::G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 => {
+ &FormatCompatibilityInner::Class_10bit_2plane_422
+ }
+ Self::G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 => {
+ &FormatCompatibilityInner::Class_10bit_3plane_444
+ }
+ Self::R12X4_UNORM_PACK16 => &FormatCompatibilityInner::Class_16bit,
+ Self::R12X4G12X4_UNORM_2PACK16 => &FormatCompatibilityInner::Class_32bit,
+ Self::R12X4G12X4B12X4A12X4_UNORM_4PACK16 => {
+ &FormatCompatibilityInner::Class_64bit_R12G12B12A12
+ }
+ Self::G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 => {
+ &FormatCompatibilityInner::Class_64bit_G12B12G12R12
+ }
+ Self::B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 => {
+ &FormatCompatibilityInner::Class_64bit_B12G12R12G12
+ }
+ Self::G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 => {
+ &FormatCompatibilityInner::Class_12bit_3plane_420
+ }
+ Self::G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 => {
+ &FormatCompatibilityInner::Class_12bit_2plane_420
+ }
+ Self::G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 => {
+ &FormatCompatibilityInner::Class_12bit_3plane_422
+ }
+ Self::G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 => {
+ &FormatCompatibilityInner::Class_12bit_2plane_422
+ }
+ Self::G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 => {
+ &FormatCompatibilityInner::Class_12bit_3plane_444
+ }
+ Self::G16B16G16R16_422_UNORM => &FormatCompatibilityInner::Class_64bit_G16B16G16R16,
+ Self::B16G16R16G16_422_UNORM => &FormatCompatibilityInner::Class_64bit_B16G16R16G16,
+ Self::G16_B16_R16_3PLANE_420_UNORM => &FormatCompatibilityInner::Class_16bit_3plane_420,
+ Self::G16_B16R16_2PLANE_420_UNORM => &FormatCompatibilityInner::Class_16bit_2plane_420,
+ Self::G16_B16_R16_3PLANE_422_UNORM => &FormatCompatibilityInner::Class_16bit_3plane_422,
+ Self::G16_B16R16_2PLANE_422_UNORM => &FormatCompatibilityInner::Class_16bit_2plane_422,
+ Self::G16_B16_R16_3PLANE_444_UNORM => &FormatCompatibilityInner::Class_16bit_3plane_444,
+ Self::PVRTC1_2BPP_UNORM_BLOCK => &FormatCompatibilityInner::Class_PVRTC1_2BPP,
+ Self::PVRTC1_4BPP_UNORM_BLOCK => &FormatCompatibilityInner::Class_PVRTC1_4BPP,
+ Self::PVRTC2_2BPP_UNORM_BLOCK => &FormatCompatibilityInner::Class_PVRTC2_2BPP,
+ Self::PVRTC2_4BPP_UNORM_BLOCK => &FormatCompatibilityInner::Class_PVRTC2_4BPP,
+ Self::PVRTC1_2BPP_SRGB_BLOCK => &FormatCompatibilityInner::Class_PVRTC1_2BPP,
+ Self::PVRTC1_4BPP_SRGB_BLOCK => &FormatCompatibilityInner::Class_PVRTC1_4BPP,
+ Self::PVRTC2_2BPP_SRGB_BLOCK => &FormatCompatibilityInner::Class_PVRTC2_2BPP,
+ Self::PVRTC2_4BPP_SRGB_BLOCK => &FormatCompatibilityInner::Class_PVRTC2_4BPP,
+ Self::ASTC_4x4_SFLOAT_BLOCK => &FormatCompatibilityInner::Class_ASTC_4x4,
+ Self::ASTC_5x4_SFLOAT_BLOCK => &FormatCompatibilityInner::Class_ASTC_5x4,
+ Self::ASTC_5x5_SFLOAT_BLOCK => &FormatCompatibilityInner::Class_ASTC_5x5,
+ Self::ASTC_6x5_SFLOAT_BLOCK => &FormatCompatibilityInner::Class_ASTC_6x5,
+ Self::ASTC_6x6_SFLOAT_BLOCK => &FormatCompatibilityInner::Class_ASTC_6x6,
+ Self::ASTC_8x5_SFLOAT_BLOCK => &FormatCompatibilityInner::Class_ASTC_8x5,
+ Self::ASTC_8x6_SFLOAT_BLOCK => &FormatCompatibilityInner::Class_ASTC_8x6,
+ Self::ASTC_8x8_SFLOAT_BLOCK => &FormatCompatibilityInner::Class_ASTC_8x8,
+ Self::ASTC_10x5_SFLOAT_BLOCK => &FormatCompatibilityInner::Class_ASTC_10x5,
+ Self::ASTC_10x6_SFLOAT_BLOCK => &FormatCompatibilityInner::Class_ASTC_10x6,
+ Self::ASTC_10x8_SFLOAT_BLOCK => &FormatCompatibilityInner::Class_ASTC_10x8,
+ Self::ASTC_10x10_SFLOAT_BLOCK => &FormatCompatibilityInner::Class_ASTC_10x10,
+ Self::ASTC_12x10_SFLOAT_BLOCK => &FormatCompatibilityInner::Class_ASTC_12x10,
+ Self::ASTC_12x12_SFLOAT_BLOCK => &FormatCompatibilityInner::Class_ASTC_12x12,
+ Self::G8_B8R8_2PLANE_444_UNORM => &FormatCompatibilityInner::Class_8bit_2plane_444,
+ Self::G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16 => {
+ &FormatCompatibilityInner::Class_10bit_2plane_444
+ }
+ Self::G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16 => {
+ &FormatCompatibilityInner::Class_12bit_2plane_444
+ }
+ Self::G16_B16R16_2PLANE_444_UNORM => &FormatCompatibilityInner::Class_16bit_2plane_444,
+ Self::A4R4G4B4_UNORM_PACK16 => &FormatCompatibilityInner::Class_16bit,
+ Self::A4B4G4R4_UNORM_PACK16 => &FormatCompatibilityInner::Class_16bit,
+ Self::R16G16_S10_5_NV => &FormatCompatibilityInner::Class_32bit,
+ })
+ }
+ #[doc = r" Returns the number of bits per texel block that each component (R, G, B, A) is"]
+ #[doc = r" represented with. Components that are not present in the format have 0 bits."]
+ #[doc = r""]
+ #[doc = r" For depth/stencil formats, the depth component is the first, stencil the second. For"]
+ #[doc = r" multi-planar formats, this is the number of bits across all planes."]
+ #[doc = r""]
+ #[doc = r" For block-compressed formats, the number of bits in individual components is not"]
+ #[doc = r" well-defined, and the return value is merely binary: 1 indicates a component"]
+ #[doc = r" that is present in the format, 0 indicates one that is absent."]
+ pub fn components(self) -> [u8; 4] {
+ match self {
+ Self::R4G4_UNORM_PACK8 => [4, 4, 0, 0],
+ Self::R4G4B4A4_UNORM_PACK16 => [4, 4, 4, 4],
+ Self::B4G4R4A4_UNORM_PACK16 => [4, 4, 4, 4],
+ Self::R5G6B5_UNORM_PACK16 => [5, 6, 5, 0],
+ Self::B5G6R5_UNORM_PACK16 => [5, 6, 5, 0],
+ Self::R5G5B5A1_UNORM_PACK16 => [5, 5, 5, 1],
+ Self::B5G5R5A1_UNORM_PACK16 => [5, 5, 5, 1],
+ Self::A1R5G5B5_UNORM_PACK16 => [5, 5, 5, 1],
+ Self::R8_UNORM => [8, 0, 0, 0],
+ Self::R8_SNORM => [8, 0, 0, 0],
+ Self::R8_USCALED => [8, 0, 0, 0],
+ Self::R8_SSCALED => [8, 0, 0, 0],
+ Self::R8_UINT => [8, 0, 0, 0],
+ Self::R8_SINT => [8, 0, 0, 0],
+ Self::R8_SRGB => [8, 0, 0, 0],
+ Self::R8G8_UNORM => [8, 8, 0, 0],
+ Self::R8G8_SNORM => [8, 8, 0, 0],
+ Self::R8G8_USCALED => [8, 8, 0, 0],
+ Self::R8G8_SSCALED => [8, 8, 0, 0],
+ Self::R8G8_UINT => [8, 8, 0, 0],
+ Self::R8G8_SINT => [8, 8, 0, 0],
+ Self::R8G8_SRGB => [8, 8, 0, 0],
+ Self::R8G8B8_UNORM => [8, 8, 8, 0],
+ Self::R8G8B8_SNORM => [8, 8, 8, 0],
+ Self::R8G8B8_USCALED => [8, 8, 8, 0],
+ Self::R8G8B8_SSCALED => [8, 8, 8, 0],
+ Self::R8G8B8_UINT => [8, 8, 8, 0],
+ Self::R8G8B8_SINT => [8, 8, 8, 0],
+ Self::R8G8B8_SRGB => [8, 8, 8, 0],
+ Self::B8G8R8_UNORM => [8, 8, 8, 0],
+ Self::B8G8R8_SNORM => [8, 8, 8, 0],
+ Self::B8G8R8_USCALED => [8, 8, 8, 0],
+ Self::B8G8R8_SSCALED => [8, 8, 8, 0],
+ Self::B8G8R8_UINT => [8, 8, 8, 0],
+ Self::B8G8R8_SINT => [8, 8, 8, 0],
+ Self::B8G8R8_SRGB => [8, 8, 8, 0],
+ Self::R8G8B8A8_UNORM => [8, 8, 8, 8],
+ Self::R8G8B8A8_SNORM => [8, 8, 8, 8],
+ Self::R8G8B8A8_USCALED => [8, 8, 8, 8],
+ Self::R8G8B8A8_SSCALED => [8, 8, 8, 8],
+ Self::R8G8B8A8_UINT => [8, 8, 8, 8],
+ Self::R8G8B8A8_SINT => [8, 8, 8, 8],
+ Self::R8G8B8A8_SRGB => [8, 8, 8, 8],
+ Self::B8G8R8A8_UNORM => [8, 8, 8, 8],
+ Self::B8G8R8A8_SNORM => [8, 8, 8, 8],
+ Self::B8G8R8A8_USCALED => [8, 8, 8, 8],
+ Self::B8G8R8A8_SSCALED => [8, 8, 8, 8],
+ Self::B8G8R8A8_UINT => [8, 8, 8, 8],
+ Self::B8G8R8A8_SINT => [8, 8, 8, 8],
+ Self::B8G8R8A8_SRGB => [8, 8, 8, 8],
+ Self::A8B8G8R8_UNORM_PACK32 => [8, 8, 8, 8],
+ Self::A8B8G8R8_SNORM_PACK32 => [8, 8, 8, 8],
+ Self::A8B8G8R8_USCALED_PACK32 => [8, 8, 8, 8],
+ Self::A8B8G8R8_SSCALED_PACK32 => [8, 8, 8, 8],
+ Self::A8B8G8R8_UINT_PACK32 => [8, 8, 8, 8],
+ Self::A8B8G8R8_SINT_PACK32 => [8, 8, 8, 8],
+ Self::A8B8G8R8_SRGB_PACK32 => [8, 8, 8, 8],
+ Self::A2R10G10B10_UNORM_PACK32 => [10, 10, 10, 2],
+ Self::A2R10G10B10_SNORM_PACK32 => [10, 10, 10, 2],
+ Self::A2R10G10B10_USCALED_PACK32 => [10, 10, 10, 2],
+ Self::A2R10G10B10_SSCALED_PACK32 => [10, 10, 10, 2],
+ Self::A2R10G10B10_UINT_PACK32 => [10, 10, 10, 2],
+ Self::A2R10G10B10_SINT_PACK32 => [10, 10, 10, 2],
+ Self::A2B10G10R10_UNORM_PACK32 => [10, 10, 10, 2],
+ Self::A2B10G10R10_SNORM_PACK32 => [10, 10, 10, 2],
+ Self::A2B10G10R10_USCALED_PACK32 => [10, 10, 10, 2],
+ Self::A2B10G10R10_SSCALED_PACK32 => [10, 10, 10, 2],
+ Self::A2B10G10R10_UINT_PACK32 => [10, 10, 10, 2],
+ Self::A2B10G10R10_SINT_PACK32 => [10, 10, 10, 2],
+ Self::R16_UNORM => [16, 0, 0, 0],
+ Self::R16_SNORM => [16, 0, 0, 0],
+ Self::R16_USCALED => [16, 0, 0, 0],
+ Self::R16_SSCALED => [16, 0, 0, 0],
+ Self::R16_UINT => [16, 0, 0, 0],
+ Self::R16_SINT => [16, 0, 0, 0],
+ Self::R16_SFLOAT => [16, 0, 0, 0],
+ Self::R16G16_UNORM => [16, 16, 0, 0],
+ Self::R16G16_SNORM => [16, 16, 0, 0],
+ Self::R16G16_USCALED => [16, 16, 0, 0],
+ Self::R16G16_SSCALED => [16, 16, 0, 0],
+ Self::R16G16_UINT => [16, 16, 0, 0],
+ Self::R16G16_SINT => [16, 16, 0, 0],
+ Self::R16G16_SFLOAT => [16, 16, 0, 0],
+ Self::R16G16B16_UNORM => [16, 16, 16, 0],
+ Self::R16G16B16_SNORM => [16, 16, 16, 0],
+ Self::R16G16B16_USCALED => [16, 16, 16, 0],
+ Self::R16G16B16_SSCALED => [16, 16, 16, 0],
+ Self::R16G16B16_UINT => [16, 16, 16, 0],
+ Self::R16G16B16_SINT => [16, 16, 16, 0],
+ Self::R16G16B16_SFLOAT => [16, 16, 16, 0],
+ Self::R16G16B16A16_UNORM => [16, 16, 16, 16],
+ Self::R16G16B16A16_SNORM => [16, 16, 16, 16],
+ Self::R16G16B16A16_USCALED => [16, 16, 16, 16],
+ Self::R16G16B16A16_SSCALED => [16, 16, 16, 16],
+ Self::R16G16B16A16_UINT => [16, 16, 16, 16],
+ Self::R16G16B16A16_SINT => [16, 16, 16, 16],
+ Self::R16G16B16A16_SFLOAT => [16, 16, 16, 16],
+ Self::R32_UINT => [32, 0, 0, 0],
+ Self::R32_SINT => [32, 0, 0, 0],
+ Self::R32_SFLOAT => [32, 0, 0, 0],
+ Self::R32G32_UINT => [32, 32, 0, 0],
+ Self::R32G32_SINT => [32, 32, 0, 0],
+ Self::R32G32_SFLOAT => [32, 32, 0, 0],
+ Self::R32G32B32_UINT => [32, 32, 32, 0],
+ Self::R32G32B32_SINT => [32, 32, 32, 0],
+ Self::R32G32B32_SFLOAT => [32, 32, 32, 0],
+ Self::R32G32B32A32_UINT => [32, 32, 32, 32],
+ Self::R32G32B32A32_SINT => [32, 32, 32, 32],
+ Self::R32G32B32A32_SFLOAT => [32, 32, 32, 32],
+ Self::R64_UINT => [64, 0, 0, 0],
+ Self::R64_SINT => [64, 0, 0, 0],
+ Self::R64_SFLOAT => [64, 0, 0, 0],
+ Self::R64G64_UINT => [64, 0, 64, 0],
+ Self::R64G64_SINT => [64, 0, 64, 0],
+ Self::R64G64_SFLOAT => [64, 0, 64, 0],
+ Self::R64G64B64_UINT => [64, 64, 64, 0],
+ Self::R64G64B64_SINT => [64, 64, 64, 0],
+ Self::R64G64B64_SFLOAT => [64, 64, 64, 0],
+ Self::R64G64B64A64_UINT => [64, 64, 64, 64],
+ Self::R64G64B64A64_SINT => [64, 64, 64, 64],
+ Self::R64G64B64A64_SFLOAT => [64, 64, 64, 64],
+ Self::B10G11R11_UFLOAT_PACK32 => [10, 11, 10, 0],
+ Self::E5B9G9R9_UFLOAT_PACK32 => [9, 9, 9, 0],
+ Self::D16_UNORM => [16, 0, 0, 0],
+ Self::X8_D24_UNORM_PACK32 => [24, 0, 0, 0],
+ Self::D32_SFLOAT => [32, 0, 0, 0],
+ Self::S8_UINT => [0, 8, 0, 0],
+ Self::D16_UNORM_S8_UINT => [16, 8, 0, 0],
+ Self::D24_UNORM_S8_UINT => [24, 8, 0, 0],
+ Self::D32_SFLOAT_S8_UINT => [32, 8, 0, 0],
+ Self::BC1_RGB_UNORM_BLOCK => [1, 1, 1, 0],
+ Self::BC1_RGB_SRGB_BLOCK => [1, 1, 1, 0],
+ Self::BC1_RGBA_UNORM_BLOCK => [1, 1, 1, 1],
+ Self::BC1_RGBA_SRGB_BLOCK => [1, 1, 1, 1],
+ Self::BC2_UNORM_BLOCK => [1, 1, 1, 1],
+ Self::BC2_SRGB_BLOCK => [1, 1, 1, 1],
+ Self::BC3_UNORM_BLOCK => [1, 1, 1, 1],
+ Self::BC3_SRGB_BLOCK => [1, 1, 1, 1],
+ Self::BC4_UNORM_BLOCK => [1, 0, 0, 0],
+ Self::BC4_SNORM_BLOCK => [1, 0, 0, 0],
+ Self::BC5_UNORM_BLOCK => [1, 1, 0, 0],
+ Self::BC5_SNORM_BLOCK => [1, 1, 0, 0],
+ Self::BC6H_UFLOAT_BLOCK => [1, 1, 1, 0],
+ Self::BC6H_SFLOAT_BLOCK => [1, 1, 1, 0],
+ Self::BC7_UNORM_BLOCK => [1, 1, 1, 1],
+ Self::BC7_SRGB_BLOCK => [1, 1, 1, 1],
+ Self::ETC2_R8G8B8_UNORM_BLOCK => [1, 1, 1, 0],
+ Self::ETC2_R8G8B8_SRGB_BLOCK => [1, 1, 1, 0],
+ Self::ETC2_R8G8B8A1_UNORM_BLOCK => [1, 1, 1, 1],
+ Self::ETC2_R8G8B8A1_SRGB_BLOCK => [1, 1, 1, 1],
+ Self::ETC2_R8G8B8A8_UNORM_BLOCK => [1, 1, 1, 1],
+ Self::ETC2_R8G8B8A8_SRGB_BLOCK => [1, 1, 1, 1],
+ Self::EAC_R11_UNORM_BLOCK => [11, 0, 0, 0],
+ Self::EAC_R11_SNORM_BLOCK => [11, 0, 0, 0],
+ Self::EAC_R11G11_UNORM_BLOCK => [11, 11, 0, 0],
+ Self::EAC_R11G11_SNORM_BLOCK => [11, 11, 0, 0],
+ Self::ASTC_4x4_UNORM_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_4x4_SRGB_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_5x4_UNORM_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_5x4_SRGB_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_5x5_UNORM_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_5x5_SRGB_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_6x5_UNORM_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_6x5_SRGB_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_6x6_UNORM_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_6x6_SRGB_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_8x5_UNORM_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_8x5_SRGB_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_8x6_UNORM_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_8x6_SRGB_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_8x8_UNORM_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_8x8_SRGB_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_10x5_UNORM_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_10x5_SRGB_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_10x6_UNORM_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_10x6_SRGB_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_10x8_UNORM_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_10x8_SRGB_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_10x10_UNORM_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_10x10_SRGB_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_12x10_UNORM_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_12x10_SRGB_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_12x12_UNORM_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_12x12_SRGB_BLOCK => [1, 1, 1, 1],
+ Self::G8B8G8R8_422_UNORM => [8, 16, 8, 0],
+ Self::B8G8R8G8_422_UNORM => [8, 16, 8, 0],
+ Self::G8_B8_R8_3PLANE_420_UNORM => [8, 8, 8, 0],
+ Self::G8_B8R8_2PLANE_420_UNORM => [8, 8, 8, 0],
+ Self::G8_B8_R8_3PLANE_422_UNORM => [8, 8, 8, 0],
+ Self::G8_B8R8_2PLANE_422_UNORM => [8, 8, 8, 0],
+ Self::G8_B8_R8_3PLANE_444_UNORM => [8, 8, 8, 0],
+ Self::R10X6_UNORM_PACK16 => [10, 0, 0, 0],
+ Self::R10X6G10X6_UNORM_2PACK16 => [10, 10, 0, 0],
+ Self::R10X6G10X6B10X6A10X6_UNORM_4PACK16 => [10, 10, 10, 10],
+ Self::G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 => [10, 20, 10, 0],
+ Self::B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 => [10, 20, 10, 0],
+ Self::G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 => [10, 10, 10, 0],
+ Self::G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 => [10, 10, 10, 0],
+ Self::G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 => [10, 10, 10, 0],
+ Self::G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 => [10, 10, 10, 0],
+ Self::G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 => [10, 10, 10, 0],
+ Self::R12X4_UNORM_PACK16 => [12, 0, 0, 0],
+ Self::R12X4G12X4_UNORM_2PACK16 => [12, 12, 0, 0],
+ Self::R12X4G12X4B12X4A12X4_UNORM_4PACK16 => [12, 12, 12, 12],
+ Self::G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 => [12, 24, 12, 0],
+ Self::B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 => [12, 24, 12, 0],
+ Self::G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 => [12, 12, 12, 0],
+ Self::G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 => [12, 12, 12, 0],
+ Self::G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 => [12, 12, 12, 0],
+ Self::G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 => [12, 12, 12, 0],
+ Self::G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 => [12, 12, 12, 0],
+ Self::G16B16G16R16_422_UNORM => [16, 32, 16, 0],
+ Self::B16G16R16G16_422_UNORM => [16, 32, 16, 0],
+ Self::G16_B16_R16_3PLANE_420_UNORM => [16, 16, 16, 0],
+ Self::G16_B16R16_2PLANE_420_UNORM => [16, 16, 16, 0],
+ Self::G16_B16_R16_3PLANE_422_UNORM => [16, 16, 16, 0],
+ Self::G16_B16R16_2PLANE_422_UNORM => [16, 16, 16, 0],
+ Self::G16_B16_R16_3PLANE_444_UNORM => [16, 16, 16, 0],
+ Self::PVRTC1_2BPP_UNORM_BLOCK => [1, 1, 1, 1],
+ Self::PVRTC1_4BPP_UNORM_BLOCK => [1, 1, 1, 1],
+ Self::PVRTC2_2BPP_UNORM_BLOCK => [1, 1, 1, 1],
+ Self::PVRTC2_4BPP_UNORM_BLOCK => [1, 1, 1, 1],
+ Self::PVRTC1_2BPP_SRGB_BLOCK => [1, 1, 1, 1],
+ Self::PVRTC1_4BPP_SRGB_BLOCK => [1, 1, 1, 1],
+ Self::PVRTC2_2BPP_SRGB_BLOCK => [1, 1, 1, 1],
+ Self::PVRTC2_4BPP_SRGB_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_4x4_SFLOAT_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_5x4_SFLOAT_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_5x5_SFLOAT_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_6x5_SFLOAT_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_6x6_SFLOAT_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_8x5_SFLOAT_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_8x6_SFLOAT_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_8x8_SFLOAT_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_10x5_SFLOAT_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_10x6_SFLOAT_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_10x8_SFLOAT_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_10x10_SFLOAT_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_12x10_SFLOAT_BLOCK => [1, 1, 1, 1],
+ Self::ASTC_12x12_SFLOAT_BLOCK => [1, 1, 1, 1],
+ Self::G8_B8R8_2PLANE_444_UNORM => [8, 8, 8, 0],
+ Self::G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16 => [10, 10, 10, 0],
+ Self::G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16 => [12, 12, 12, 0],
+ Self::G16_B16R16_2PLANE_444_UNORM => [16, 16, 16, 0],
+ Self::A4R4G4B4_UNORM_PACK16 => [4, 4, 4, 4],
+ Self::A4B4G4R4_UNORM_PACK16 => [4, 4, 4, 4],
+ Self::R16G16_S10_5_NV => [16, 16, 0, 0],
+ }
+ }
+ #[doc = r" Returns the block compression scheme used for this format, if any. Returns `None` if"]
+ #[doc = r" the format does not use compression."]
+ pub fn compression(self) -> Option<CompressionType> {
+ match self {
+ Self::BC1_RGB_UNORM_BLOCK => Some(CompressionType::BC),
+ Self::BC1_RGB_SRGB_BLOCK => Some(CompressionType::BC),
+ Self::BC1_RGBA_UNORM_BLOCK => Some(CompressionType::BC),
+ Self::BC1_RGBA_SRGB_BLOCK => Some(CompressionType::BC),
+ Self::BC2_UNORM_BLOCK => Some(CompressionType::BC),
+ Self::BC2_SRGB_BLOCK => Some(CompressionType::BC),
+ Self::BC3_UNORM_BLOCK => Some(CompressionType::BC),
+ Self::BC3_SRGB_BLOCK => Some(CompressionType::BC),
+ Self::BC4_UNORM_BLOCK => Some(CompressionType::BC),
+ Self::BC4_SNORM_BLOCK => Some(CompressionType::BC),
+ Self::BC5_UNORM_BLOCK => Some(CompressionType::BC),
+ Self::BC5_SNORM_BLOCK => Some(CompressionType::BC),
+ Self::BC6H_UFLOAT_BLOCK => Some(CompressionType::BC),
+ Self::BC6H_SFLOAT_BLOCK => Some(CompressionType::BC),
+ Self::BC7_UNORM_BLOCK => Some(CompressionType::BC),
+ Self::BC7_SRGB_BLOCK => Some(CompressionType::BC),
+ Self::ETC2_R8G8B8_UNORM_BLOCK => Some(CompressionType::ETC2),
+ Self::ETC2_R8G8B8_SRGB_BLOCK => Some(CompressionType::ETC2),
+ Self::ETC2_R8G8B8A1_UNORM_BLOCK => Some(CompressionType::ETC2),
+ Self::ETC2_R8G8B8A1_SRGB_BLOCK => Some(CompressionType::ETC2),
+ Self::ETC2_R8G8B8A8_UNORM_BLOCK => Some(CompressionType::ETC2),
+ Self::ETC2_R8G8B8A8_SRGB_BLOCK => Some(CompressionType::ETC2),
+ Self::EAC_R11_UNORM_BLOCK => Some(CompressionType::EAC),
+ Self::EAC_R11_SNORM_BLOCK => Some(CompressionType::EAC),
+ Self::EAC_R11G11_UNORM_BLOCK => Some(CompressionType::EAC),
+ Self::EAC_R11G11_SNORM_BLOCK => Some(CompressionType::EAC),
+ Self::ASTC_4x4_UNORM_BLOCK => Some(CompressionType::ASTC_LDR),
+ Self::ASTC_4x4_SRGB_BLOCK => Some(CompressionType::ASTC_LDR),
+ Self::ASTC_5x4_UNORM_BLOCK => Some(CompressionType::ASTC_LDR),
+ Self::ASTC_5x4_SRGB_BLOCK => Some(CompressionType::ASTC_LDR),
+ Self::ASTC_5x5_UNORM_BLOCK => Some(CompressionType::ASTC_LDR),
+ Self::ASTC_5x5_SRGB_BLOCK => Some(CompressionType::ASTC_LDR),
+ Self::ASTC_6x5_UNORM_BLOCK => Some(CompressionType::ASTC_LDR),
+ Self::ASTC_6x5_SRGB_BLOCK => Some(CompressionType::ASTC_LDR),
+ Self::ASTC_6x6_UNORM_BLOCK => Some(CompressionType::ASTC_LDR),
+ Self::ASTC_6x6_SRGB_BLOCK => Some(CompressionType::ASTC_LDR),
+ Self::ASTC_8x5_UNORM_BLOCK => Some(CompressionType::ASTC_LDR),
+ Self::ASTC_8x5_SRGB_BLOCK => Some(CompressionType::ASTC_LDR),
+ Self::ASTC_8x6_UNORM_BLOCK => Some(CompressionType::ASTC_LDR),
+ Self::ASTC_8x6_SRGB_BLOCK => Some(CompressionType::ASTC_LDR),
+ Self::ASTC_8x8_UNORM_BLOCK => Some(CompressionType::ASTC_LDR),
+ Self::ASTC_8x8_SRGB_BLOCK => Some(CompressionType::ASTC_LDR),
+ Self::ASTC_10x5_UNORM_BLOCK => Some(CompressionType::ASTC_LDR),
+ Self::ASTC_10x5_SRGB_BLOCK => Some(CompressionType::ASTC_LDR),
+ Self::ASTC_10x6_UNORM_BLOCK => Some(CompressionType::ASTC_LDR),
+ Self::ASTC_10x6_SRGB_BLOCK => Some(CompressionType::ASTC_LDR),
+ Self::ASTC_10x8_UNORM_BLOCK => Some(CompressionType::ASTC_LDR),
+ Self::ASTC_10x8_SRGB_BLOCK => Some(CompressionType::ASTC_LDR),
+ Self::ASTC_10x10_UNORM_BLOCK => Some(CompressionType::ASTC_LDR),
+ Self::ASTC_10x10_SRGB_BLOCK => Some(CompressionType::ASTC_LDR),
+ Self::ASTC_12x10_UNORM_BLOCK => Some(CompressionType::ASTC_LDR),
+ Self::ASTC_12x10_SRGB_BLOCK => Some(CompressionType::ASTC_LDR),
+ Self::ASTC_12x12_UNORM_BLOCK => Some(CompressionType::ASTC_LDR),
+ Self::ASTC_12x12_SRGB_BLOCK => Some(CompressionType::ASTC_LDR),
+ Self::PVRTC1_2BPP_UNORM_BLOCK => Some(CompressionType::PVRTC),
+ Self::PVRTC1_4BPP_UNORM_BLOCK => Some(CompressionType::PVRTC),
+ Self::PVRTC2_2BPP_UNORM_BLOCK => Some(CompressionType::PVRTC),
+ Self::PVRTC2_4BPP_UNORM_BLOCK => Some(CompressionType::PVRTC),
+ Self::PVRTC1_2BPP_SRGB_BLOCK => Some(CompressionType::PVRTC),
+ Self::PVRTC1_4BPP_SRGB_BLOCK => Some(CompressionType::PVRTC),
+ Self::PVRTC2_2BPP_SRGB_BLOCK => Some(CompressionType::PVRTC),
+ Self::PVRTC2_4BPP_SRGB_BLOCK => Some(CompressionType::PVRTC),
+ Self::ASTC_4x4_SFLOAT_BLOCK => Some(CompressionType::ASTC_HDR),
+ Self::ASTC_5x4_SFLOAT_BLOCK => Some(CompressionType::ASTC_HDR),
+ Self::ASTC_5x5_SFLOAT_BLOCK => Some(CompressionType::ASTC_HDR),
+ Self::ASTC_6x5_SFLOAT_BLOCK => Some(CompressionType::ASTC_HDR),
+ Self::ASTC_6x6_SFLOAT_BLOCK => Some(CompressionType::ASTC_HDR),
+ Self::ASTC_8x5_SFLOAT_BLOCK => Some(CompressionType::ASTC_HDR),
+ Self::ASTC_8x6_SFLOAT_BLOCK => Some(CompressionType::ASTC_HDR),
+ Self::ASTC_8x8_SFLOAT_BLOCK => Some(CompressionType::ASTC_HDR),
+ Self::ASTC_10x5_SFLOAT_BLOCK => Some(CompressionType::ASTC_HDR),
+ Self::ASTC_10x6_SFLOAT_BLOCK => Some(CompressionType::ASTC_HDR),
+ Self::ASTC_10x8_SFLOAT_BLOCK => Some(CompressionType::ASTC_HDR),
+ Self::ASTC_10x10_SFLOAT_BLOCK => Some(CompressionType::ASTC_HDR),
+ Self::ASTC_12x10_SFLOAT_BLOCK => Some(CompressionType::ASTC_HDR),
+ Self::ASTC_12x12_SFLOAT_BLOCK => Some(CompressionType::ASTC_HDR),
+ _ => None,
+ }
+ }
+ #[doc = r" For multi-planar formats, returns a slice of length 2 or 3, containing the"]
+ #[doc = r" equivalent regular format of each plane."]
+ #[doc = r""]
+ #[doc = r" For non-planar formats, returns the empty slice."]
+ pub fn planes(self) -> &'static [Self] {
+ match self {
+ Self::G8_B8_R8_3PLANE_420_UNORM => &[Self::R8_UNORM, Self::R8_UNORM, Self::R8_UNORM],
+ Self::G8_B8R8_2PLANE_420_UNORM => &[Self::R8_UNORM, Self::R8G8_UNORM],
+ Self::G8_B8_R8_3PLANE_422_UNORM => &[Self::R8_UNORM, Self::R8_UNORM, Self::R8_UNORM],
+ Self::G8_B8R8_2PLANE_422_UNORM => &[Self::R8_UNORM, Self::R8G8_UNORM],
+ Self::G8_B8_R8_3PLANE_444_UNORM => &[Self::R8_UNORM, Self::R8_UNORM, Self::R8_UNORM],
+ Self::G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 => &[
+ Self::R10X6_UNORM_PACK16,
+ Self::R10X6_UNORM_PACK16,
+ Self::R10X6_UNORM_PACK16,
+ ],
+ Self::G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 => {
+ &[Self::R10X6_UNORM_PACK16, Self::R10X6G10X6_UNORM_2PACK16]
+ }
+ Self::G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 => &[
+ Self::R10X6_UNORM_PACK16,
+ Self::R10X6_UNORM_PACK16,
+ Self::R10X6_UNORM_PACK16,
+ ],
+ Self::G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 => {
+ &[Self::R10X6_UNORM_PACK16, Self::R10X6G10X6_UNORM_2PACK16]
+ }
+ Self::G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 => &[
+ Self::R10X6_UNORM_PACK16,
+ Self::R10X6_UNORM_PACK16,
+ Self::R10X6_UNORM_PACK16,
+ ],
+ Self::G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 => &[
+ Self::R12X4_UNORM_PACK16,
+ Self::R12X4_UNORM_PACK16,
+ Self::R12X4_UNORM_PACK16,
+ ],
+ Self::G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 => {
+ &[Self::R12X4_UNORM_PACK16, Self::R12X4G12X4_UNORM_2PACK16]
+ }
+ Self::G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 => &[
+ Self::R12X4_UNORM_PACK16,
+ Self::R12X4_UNORM_PACK16,
+ Self::R12X4_UNORM_PACK16,
+ ],
+ Self::G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 => {
+ &[Self::R12X4_UNORM_PACK16, Self::R12X4G12X4_UNORM_2PACK16]
+ }
+ Self::G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 => &[
+ Self::R12X4_UNORM_PACK16,
+ Self::R12X4_UNORM_PACK16,
+ Self::R12X4_UNORM_PACK16,
+ ],
+ Self::G16_B16_R16_3PLANE_420_UNORM => {
+ &[Self::R16_UNORM, Self::R16_UNORM, Self::R16_UNORM]
+ }
+ Self::G16_B16R16_2PLANE_420_UNORM => &[Self::R16_UNORM, Self::R16G16_UNORM],
+ Self::G16_B16_R16_3PLANE_422_UNORM => {
+ &[Self::R16_UNORM, Self::R16_UNORM, Self::R16_UNORM]
+ }
+ Self::G16_B16R16_2PLANE_422_UNORM => &[Self::R16_UNORM, Self::R16G16_UNORM],
+ Self::G16_B16_R16_3PLANE_444_UNORM => {
+ &[Self::R16_UNORM, Self::R16_UNORM, Self::R16_UNORM]
+ }
+ Self::G8_B8R8_2PLANE_444_UNORM => &[Self::R8_UNORM, Self::R8G8_UNORM],
+ Self::G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16 => {
+ &[Self::R10X6_UNORM_PACK16, Self::R10X6G10X6_UNORM_2PACK16]
+ }
+ Self::G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16 => {
+ &[Self::R12X4_UNORM_PACK16, Self::R12X4G12X4_UNORM_2PACK16]
+ }
+ Self::G16_B16R16_2PLANE_444_UNORM => &[Self::R16_UNORM, Self::R16G16_UNORM],
+ _ => &[],
+ }
+ }
+ #[doc = r" Returns the number of texels for a single texel block. For most formats, this is"]
+ #[doc = r" the product of the `block_extent` elements, but for some it differs."]
+ pub fn texels_per_block(self) -> u8 {
+ match self {
+ Self::BC1_RGB_UNORM_BLOCK => 16,
+ Self::BC1_RGB_SRGB_BLOCK => 16,
+ Self::BC1_RGBA_UNORM_BLOCK => 16,
+ Self::BC1_RGBA_SRGB_BLOCK => 16,
+ Self::BC2_UNORM_BLOCK => 16,
+ Self::BC2_SRGB_BLOCK => 16,
+ Self::BC3_UNORM_BLOCK => 16,
+ Self::BC3_SRGB_BLOCK => 16,
+ Self::BC4_UNORM_BLOCK => 16,
+ Self::BC4_SNORM_BLOCK => 16,
+ Self::BC5_UNORM_BLOCK => 16,
+ Self::BC5_SNORM_BLOCK => 16,
+ Self::BC6H_UFLOAT_BLOCK => 16,
+ Self::BC6H_SFLOAT_BLOCK => 16,
+ Self::BC7_UNORM_BLOCK => 16,
+ Self::BC7_SRGB_BLOCK => 16,
+ Self::ETC2_R8G8B8_UNORM_BLOCK => 16,
+ Self::ETC2_R8G8B8_SRGB_BLOCK => 16,
+ Self::ETC2_R8G8B8A1_UNORM_BLOCK => 16,
+ Self::ETC2_R8G8B8A1_SRGB_BLOCK => 16,
+ Self::ETC2_R8G8B8A8_UNORM_BLOCK => 16,
+ Self::ETC2_R8G8B8A8_SRGB_BLOCK => 16,
+ Self::EAC_R11_UNORM_BLOCK => 16,
+ Self::EAC_R11_SNORM_BLOCK => 16,
+ Self::EAC_R11G11_UNORM_BLOCK => 16,
+ Self::EAC_R11G11_SNORM_BLOCK => 16,
+ Self::ASTC_4x4_UNORM_BLOCK => 16,
+ Self::ASTC_4x4_SRGB_BLOCK => 16,
+ Self::ASTC_5x4_UNORM_BLOCK => 20,
+ Self::ASTC_5x4_SRGB_BLOCK => 20,
+ Self::ASTC_5x5_UNORM_BLOCK => 25,
+ Self::ASTC_5x5_SRGB_BLOCK => 25,
+ Self::ASTC_6x5_UNORM_BLOCK => 30,
+ Self::ASTC_6x5_SRGB_BLOCK => 30,
+ Self::ASTC_6x6_UNORM_BLOCK => 36,
+ Self::ASTC_6x6_SRGB_BLOCK => 36,
+ Self::ASTC_8x5_UNORM_BLOCK => 40,
+ Self::ASTC_8x5_SRGB_BLOCK => 40,
+ Self::ASTC_8x6_UNORM_BLOCK => 48,
+ Self::ASTC_8x6_SRGB_BLOCK => 48,
+ Self::ASTC_8x8_UNORM_BLOCK => 64,
+ Self::ASTC_8x8_SRGB_BLOCK => 64,
+ Self::ASTC_10x5_UNORM_BLOCK => 50,
+ Self::ASTC_10x5_SRGB_BLOCK => 50,
+ Self::ASTC_10x6_UNORM_BLOCK => 60,
+ Self::ASTC_10x6_SRGB_BLOCK => 60,
+ Self::ASTC_10x8_UNORM_BLOCK => 80,
+ Self::ASTC_10x8_SRGB_BLOCK => 80,
+ Self::ASTC_10x10_UNORM_BLOCK => 100,
+ Self::ASTC_10x10_SRGB_BLOCK => 100,
+ Self::ASTC_12x10_UNORM_BLOCK => 120,
+ Self::ASTC_12x10_SRGB_BLOCK => 120,
+ Self::ASTC_12x12_UNORM_BLOCK => 144,
+ Self::ASTC_12x12_SRGB_BLOCK => 144,
+ Self::ASTC_4x4_SFLOAT_BLOCK => 16,
+ Self::ASTC_5x4_SFLOAT_BLOCK => 20,
+ Self::ASTC_5x5_SFLOAT_BLOCK => 25,
+ Self::ASTC_6x5_SFLOAT_BLOCK => 30,
+ Self::ASTC_6x6_SFLOAT_BLOCK => 36,
+ Self::ASTC_8x5_SFLOAT_BLOCK => 40,
+ Self::ASTC_8x6_SFLOAT_BLOCK => 48,
+ Self::ASTC_8x8_SFLOAT_BLOCK => 64,
+ Self::ASTC_10x5_SFLOAT_BLOCK => 50,
+ Self::ASTC_10x6_SFLOAT_BLOCK => 60,
+ Self::ASTC_10x8_SFLOAT_BLOCK => 80,
+ Self::ASTC_10x10_SFLOAT_BLOCK => 100,
+ Self::ASTC_12x10_SFLOAT_BLOCK => 120,
+ Self::ASTC_12x12_SFLOAT_BLOCK => 144,
+ _ => 1,
+ }
+ }
+ #[doc = r" Returns the numeric data type of the color aspect of this format. Returns `None`"]
+ #[doc = r" for depth/stencil formats."]
+ pub fn type_color(self) -> Option<NumericType> {
+ match self {
+ Self::R4G4_UNORM_PACK8 => Some(NumericType::UNORM),
+ Self::R4G4B4A4_UNORM_PACK16 => Some(NumericType::UNORM),
+ Self::B4G4R4A4_UNORM_PACK16 => Some(NumericType::UNORM),
+ Self::R5G6B5_UNORM_PACK16 => Some(NumericType::UNORM),
+ Self::B5G6R5_UNORM_PACK16 => Some(NumericType::UNORM),
+ Self::R5G5B5A1_UNORM_PACK16 => Some(NumericType::UNORM),
+ Self::B5G5R5A1_UNORM_PACK16 => Some(NumericType::UNORM),
+ Self::A1R5G5B5_UNORM_PACK16 => Some(NumericType::UNORM),
+ Self::R8_UNORM => Some(NumericType::UNORM),
+ Self::R8_SNORM => Some(NumericType::SNORM),
+ Self::R8_USCALED => Some(NumericType::USCALED),
+ Self::R8_SSCALED => Some(NumericType::SSCALED),
+ Self::R8_UINT => Some(NumericType::UINT),
+ Self::R8_SINT => Some(NumericType::SINT),
+ Self::R8_SRGB => Some(NumericType::SRGB),
+ Self::R8G8_UNORM => Some(NumericType::UNORM),
+ Self::R8G8_SNORM => Some(NumericType::SNORM),
+ Self::R8G8_USCALED => Some(NumericType::USCALED),
+ Self::R8G8_SSCALED => Some(NumericType::SSCALED),
+ Self::R8G8_UINT => Some(NumericType::UINT),
+ Self::R8G8_SINT => Some(NumericType::SINT),
+ Self::R8G8_SRGB => Some(NumericType::SRGB),
+ Self::R8G8B8_UNORM => Some(NumericType::UNORM),
+ Self::R8G8B8_SNORM => Some(NumericType::SNORM),
+ Self::R8G8B8_USCALED => Some(NumericType::USCALED),
+ Self::R8G8B8_SSCALED => Some(NumericType::SSCALED),
+ Self::R8G8B8_UINT => Some(NumericType::UINT),
+ Self::R8G8B8_SINT => Some(NumericType::SINT),
+ Self::R8G8B8_SRGB => Some(NumericType::SRGB),
+ Self::B8G8R8_UNORM => Some(NumericType::UNORM),
+ Self::B8G8R8_SNORM => Some(NumericType::SNORM),
+ Self::B8G8R8_USCALED => Some(NumericType::USCALED),
+ Self::B8G8R8_SSCALED => Some(NumericType::SSCALED),
+ Self::B8G8R8_UINT => Some(NumericType::UINT),
+ Self::B8G8R8_SINT => Some(NumericType::SINT),
+ Self::B8G8R8_SRGB => Some(NumericType::SRGB),
+ Self::R8G8B8A8_UNORM => Some(NumericType::UNORM),
+ Self::R8G8B8A8_SNORM => Some(NumericType::SNORM),
+ Self::R8G8B8A8_USCALED => Some(NumericType::USCALED),
+ Self::R8G8B8A8_SSCALED => Some(NumericType::SSCALED),
+ Self::R8G8B8A8_UINT => Some(NumericType::UINT),
+ Self::R8G8B8A8_SINT => Some(NumericType::SINT),
+ Self::R8G8B8A8_SRGB => Some(NumericType::SRGB),
+ Self::B8G8R8A8_UNORM => Some(NumericType::UNORM),
+ Self::B8G8R8A8_SNORM => Some(NumericType::SNORM),
+ Self::B8G8R8A8_USCALED => Some(NumericType::USCALED),
+ Self::B8G8R8A8_SSCALED => Some(NumericType::SSCALED),
+ Self::B8G8R8A8_UINT => Some(NumericType::UINT),
+ Self::B8G8R8A8_SINT => Some(NumericType::SINT),
+ Self::B8G8R8A8_SRGB => Some(NumericType::SRGB),
+ Self::A8B8G8R8_UNORM_PACK32 => Some(NumericType::UNORM),
+ Self::A8B8G8R8_SNORM_PACK32 => Some(NumericType::SNORM),
+ Self::A8B8G8R8_USCALED_PACK32 => Some(NumericType::USCALED),
+ Self::A8B8G8R8_SSCALED_PACK32 => Some(NumericType::SSCALED),
+ Self::A8B8G8R8_UINT_PACK32 => Some(NumericType::UINT),
+ Self::A8B8G8R8_SINT_PACK32 => Some(NumericType::SINT),
+ Self::A8B8G8R8_SRGB_PACK32 => Some(NumericType::SRGB),
+ Self::A2R10G10B10_UNORM_PACK32 => Some(NumericType::UNORM),
+ Self::A2R10G10B10_SNORM_PACK32 => Some(NumericType::SNORM),
+ Self::A2R10G10B10_USCALED_PACK32 => Some(NumericType::USCALED),
+ Self::A2R10G10B10_SSCALED_PACK32 => Some(NumericType::SSCALED),
+ Self::A2R10G10B10_UINT_PACK32 => Some(NumericType::UINT),
+ Self::A2R10G10B10_SINT_PACK32 => Some(NumericType::SINT),
+ Self::A2B10G10R10_UNORM_PACK32 => Some(NumericType::UNORM),
+ Self::A2B10G10R10_SNORM_PACK32 => Some(NumericType::SNORM),
+ Self::A2B10G10R10_USCALED_PACK32 => Some(NumericType::USCALED),
+ Self::A2B10G10R10_SSCALED_PACK32 => Some(NumericType::SSCALED),
+ Self::A2B10G10R10_UINT_PACK32 => Some(NumericType::UINT),
+ Self::A2B10G10R10_SINT_PACK32 => Some(NumericType::SINT),
+ Self::R16_UNORM => Some(NumericType::UNORM),
+ Self::R16_SNORM => Some(NumericType::SNORM),
+ Self::R16_USCALED => Some(NumericType::USCALED),
+ Self::R16_SSCALED => Some(NumericType::SSCALED),
+ Self::R16_UINT => Some(NumericType::UINT),
+ Self::R16_SINT => Some(NumericType::SINT),
+ Self::R16_SFLOAT => Some(NumericType::SFLOAT),
+ Self::R16G16_UNORM => Some(NumericType::UNORM),
+ Self::R16G16_SNORM => Some(NumericType::SNORM),
+ Self::R16G16_USCALED => Some(NumericType::USCALED),
+ Self::R16G16_SSCALED => Some(NumericType::SSCALED),
+ Self::R16G16_UINT => Some(NumericType::UINT),
+ Self::R16G16_SINT => Some(NumericType::SINT),
+ Self::R16G16_SFLOAT => Some(NumericType::SFLOAT),
+ Self::R16G16B16_UNORM => Some(NumericType::UNORM),
+ Self::R16G16B16_SNORM => Some(NumericType::SNORM),
+ Self::R16G16B16_USCALED => Some(NumericType::USCALED),
+ Self::R16G16B16_SSCALED => Some(NumericType::SSCALED),
+ Self::R16G16B16_UINT => Some(NumericType::UINT),
+ Self::R16G16B16_SINT => Some(NumericType::SINT),
+ Self::R16G16B16_SFLOAT => Some(NumericType::SFLOAT),
+ Self::R16G16B16A16_UNORM => Some(NumericType::UNORM),
+ Self::R16G16B16A16_SNORM => Some(NumericType::SNORM),
+ Self::R16G16B16A16_USCALED => Some(NumericType::USCALED),
+ Self::R16G16B16A16_SSCALED => Some(NumericType::SSCALED),
+ Self::R16G16B16A16_UINT => Some(NumericType::UINT),
+ Self::R16G16B16A16_SINT => Some(NumericType::SINT),
+ Self::R16G16B16A16_SFLOAT => Some(NumericType::SFLOAT),
+ Self::R32_UINT => Some(NumericType::UINT),
+ Self::R32_SINT => Some(NumericType::SINT),
+ Self::R32_SFLOAT => Some(NumericType::SFLOAT),
+ Self::R32G32_UINT => Some(NumericType::UINT),
+ Self::R32G32_SINT => Some(NumericType::SINT),
+ Self::R32G32_SFLOAT => Some(NumericType::SFLOAT),
+ Self::R32G32B32_UINT => Some(NumericType::UINT),
+ Self::R32G32B32_SINT => Some(NumericType::SINT),
+ Self::R32G32B32_SFLOAT => Some(NumericType::SFLOAT),
+ Self::R32G32B32A32_UINT => Some(NumericType::UINT),
+ Self::R32G32B32A32_SINT => Some(NumericType::SINT),
+ Self::R32G32B32A32_SFLOAT => Some(NumericType::SFLOAT),
+ Self::R64_UINT => Some(NumericType::UINT),
+ Self::R64_SINT => Some(NumericType::SINT),
+ Self::R64_SFLOAT => Some(NumericType::SFLOAT),
+ Self::R64G64_UINT => Some(NumericType::UINT),
+ Self::R64G64_SINT => Some(NumericType::SINT),
+ Self::R64G64_SFLOAT => Some(NumericType::SFLOAT),
+ Self::R64G64B64_UINT => Some(NumericType::UINT),
+ Self::R64G64B64_SINT => Some(NumericType::SINT),
+ Self::R64G64B64_SFLOAT => Some(NumericType::SFLOAT),
+ Self::R64G64B64A64_UINT => Some(NumericType::UINT),
+ Self::R64G64B64A64_SINT => Some(NumericType::SINT),
+ Self::R64G64B64A64_SFLOAT => Some(NumericType::SFLOAT),
+ Self::B10G11R11_UFLOAT_PACK32 => Some(NumericType::UFLOAT),
+ Self::E5B9G9R9_UFLOAT_PACK32 => Some(NumericType::UFLOAT),
+ Self::BC1_RGB_UNORM_BLOCK => Some(NumericType::UNORM),
+ Self::BC1_RGB_SRGB_BLOCK => Some(NumericType::SRGB),
+ Self::BC1_RGBA_UNORM_BLOCK => Some(NumericType::UNORM),
+ Self::BC1_RGBA_SRGB_BLOCK => Some(NumericType::SRGB),
+ Self::BC2_UNORM_BLOCK => Some(NumericType::UNORM),
+ Self::BC2_SRGB_BLOCK => Some(NumericType::SRGB),
+ Self::BC3_UNORM_BLOCK => Some(NumericType::UNORM),
+ Self::BC3_SRGB_BLOCK => Some(NumericType::SRGB),
+ Self::BC4_UNORM_BLOCK => Some(NumericType::UNORM),
+ Self::BC4_SNORM_BLOCK => Some(NumericType::SRGB),
+ Self::BC5_UNORM_BLOCK => Some(NumericType::UNORM),
+ Self::BC5_SNORM_BLOCK => Some(NumericType::SRGB),
+ Self::BC6H_UFLOAT_BLOCK => Some(NumericType::UFLOAT),
+ Self::BC6H_SFLOAT_BLOCK => Some(NumericType::SFLOAT),
+ Self::BC7_UNORM_BLOCK => Some(NumericType::UNORM),
+ Self::BC7_SRGB_BLOCK => Some(NumericType::SRGB),
+ Self::ETC2_R8G8B8_UNORM_BLOCK => Some(NumericType::UNORM),
+ Self::ETC2_R8G8B8_SRGB_BLOCK => Some(NumericType::SRGB),
+ Self::ETC2_R8G8B8A1_UNORM_BLOCK => Some(NumericType::UNORM),
+ Self::ETC2_R8G8B8A1_SRGB_BLOCK => Some(NumericType::SRGB),
+ Self::ETC2_R8G8B8A8_UNORM_BLOCK => Some(NumericType::UNORM),
+ Self::ETC2_R8G8B8A8_SRGB_BLOCK => Some(NumericType::SRGB),
+ Self::EAC_R11_UNORM_BLOCK => Some(NumericType::UNORM),
+ Self::EAC_R11_SNORM_BLOCK => Some(NumericType::SNORM),
+ Self::EAC_R11G11_UNORM_BLOCK => Some(NumericType::UNORM),
+ Self::EAC_R11G11_SNORM_BLOCK => Some(NumericType::SNORM),
+ Self::ASTC_4x4_UNORM_BLOCK => Some(NumericType::UNORM),
+ Self::ASTC_4x4_SRGB_BLOCK => Some(NumericType::SRGB),
+ Self::ASTC_5x4_UNORM_BLOCK => Some(NumericType::UNORM),
+ Self::ASTC_5x4_SRGB_BLOCK => Some(NumericType::SRGB),
+ Self::ASTC_5x5_UNORM_BLOCK => Some(NumericType::UNORM),
+ Self::ASTC_5x5_SRGB_BLOCK => Some(NumericType::SRGB),
+ Self::ASTC_6x5_UNORM_BLOCK => Some(NumericType::UNORM),
+ Self::ASTC_6x5_SRGB_BLOCK => Some(NumericType::SRGB),
+ Self::ASTC_6x6_UNORM_BLOCK => Some(NumericType::UNORM),
+ Self::ASTC_6x6_SRGB_BLOCK => Some(NumericType::SRGB),
+ Self::ASTC_8x5_UNORM_BLOCK => Some(NumericType::UNORM),
+ Self::ASTC_8x5_SRGB_BLOCK => Some(NumericType::SRGB),
+ Self::ASTC_8x6_UNORM_BLOCK => Some(NumericType::UNORM),
+ Self::ASTC_8x6_SRGB_BLOCK => Some(NumericType::SRGB),
+ Self::ASTC_8x8_UNORM_BLOCK => Some(NumericType::UNORM),
+ Self::ASTC_8x8_SRGB_BLOCK => Some(NumericType::SRGB),
+ Self::ASTC_10x5_UNORM_BLOCK => Some(NumericType::UNORM),
+ Self::ASTC_10x5_SRGB_BLOCK => Some(NumericType::SRGB),
+ Self::ASTC_10x6_UNORM_BLOCK => Some(NumericType::UNORM),
+ Self::ASTC_10x6_SRGB_BLOCK => Some(NumericType::SRGB),
+ Self::ASTC_10x8_UNORM_BLOCK => Some(NumericType::UNORM),
+ Self::ASTC_10x8_SRGB_BLOCK => Some(NumericType::SRGB),
+ Self::ASTC_10x10_UNORM_BLOCK => Some(NumericType::UNORM),
+ Self::ASTC_10x10_SRGB_BLOCK => Some(NumericType::SRGB),
+ Self::ASTC_12x10_UNORM_BLOCK => Some(NumericType::UNORM),
+ Self::ASTC_12x10_SRGB_BLOCK => Some(NumericType::SRGB),
+ Self::ASTC_12x12_UNORM_BLOCK => Some(NumericType::UNORM),
+ Self::ASTC_12x12_SRGB_BLOCK => Some(NumericType::SRGB),
+ Self::G8B8G8R8_422_UNORM => Some(NumericType::UNORM),
+ Self::B8G8R8G8_422_UNORM => Some(NumericType::UNORM),
+ Self::G8_B8_R8_3PLANE_420_UNORM => Some(NumericType::UNORM),
+ Self::G8_B8R8_2PLANE_420_UNORM => Some(NumericType::UNORM),
+ Self::G8_B8_R8_3PLANE_422_UNORM => Some(NumericType::UNORM),
+ Self::G8_B8R8_2PLANE_422_UNORM => Some(NumericType::UNORM),
+ Self::G8_B8_R8_3PLANE_444_UNORM => Some(NumericType::UNORM),
+ Self::R10X6_UNORM_PACK16 => Some(NumericType::UNORM),
+ Self::R10X6G10X6_UNORM_2PACK16 => Some(NumericType::UNORM),
+ Self::R10X6G10X6B10X6A10X6_UNORM_4PACK16 => Some(NumericType::UNORM),
+ Self::G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 => Some(NumericType::UNORM),
+ Self::B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 => Some(NumericType::UNORM),
+ Self::G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 => Some(NumericType::UNORM),
+ Self::G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 => Some(NumericType::UNORM),
+ Self::G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 => Some(NumericType::UNORM),
+ Self::G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 => Some(NumericType::UNORM),
+ Self::G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 => Some(NumericType::UNORM),
+ Self::R12X4_UNORM_PACK16 => Some(NumericType::UNORM),
+ Self::R12X4G12X4_UNORM_2PACK16 => Some(NumericType::UNORM),
+ Self::R12X4G12X4B12X4A12X4_UNORM_4PACK16 => Some(NumericType::UNORM),
+ Self::G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 => Some(NumericType::UNORM),
+ Self::B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 => Some(NumericType::UNORM),
+ Self::G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 => Some(NumericType::UNORM),
+ Self::G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 => Some(NumericType::UNORM),
+ Self::G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 => Some(NumericType::UNORM),
+ Self::G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 => Some(NumericType::UNORM),
+ Self::G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 => Some(NumericType::UNORM),
+ Self::G16B16G16R16_422_UNORM => Some(NumericType::UNORM),
+ Self::B16G16R16G16_422_UNORM => Some(NumericType::UNORM),
+ Self::G16_B16_R16_3PLANE_420_UNORM => Some(NumericType::UNORM),
+ Self::G16_B16R16_2PLANE_420_UNORM => Some(NumericType::UNORM),
+ Self::G16_B16_R16_3PLANE_422_UNORM => Some(NumericType::UNORM),
+ Self::G16_B16R16_2PLANE_422_UNORM => Some(NumericType::UNORM),
+ Self::G16_B16_R16_3PLANE_444_UNORM => Some(NumericType::UNORM),
+ Self::PVRTC1_2BPP_UNORM_BLOCK => Some(NumericType::UNORM),
+ Self::PVRTC1_4BPP_UNORM_BLOCK => Some(NumericType::UNORM),
+ Self::PVRTC2_2BPP_UNORM_BLOCK => Some(NumericType::UNORM),
+ Self::PVRTC2_4BPP_UNORM_BLOCK => Some(NumericType::UNORM),
+ Self::PVRTC1_2BPP_SRGB_BLOCK => Some(NumericType::SRGB),
+ Self::PVRTC1_4BPP_SRGB_BLOCK => Some(NumericType::SRGB),
+ Self::PVRTC2_2BPP_SRGB_BLOCK => Some(NumericType::SRGB),
+ Self::PVRTC2_4BPP_SRGB_BLOCK => Some(NumericType::SRGB),
+ Self::ASTC_4x4_SFLOAT_BLOCK => Some(NumericType::SFLOAT),
+ Self::ASTC_5x4_SFLOAT_BLOCK => Some(NumericType::SFLOAT),
+ Self::ASTC_5x5_SFLOAT_BLOCK => Some(NumericType::SFLOAT),
+ Self::ASTC_6x5_SFLOAT_BLOCK => Some(NumericType::SFLOAT),
+ Self::ASTC_6x6_SFLOAT_BLOCK => Some(NumericType::SFLOAT),
+ Self::ASTC_8x5_SFLOAT_BLOCK => Some(NumericType::SFLOAT),
+ Self::ASTC_8x6_SFLOAT_BLOCK => Some(NumericType::SFLOAT),
+ Self::ASTC_8x8_SFLOAT_BLOCK => Some(NumericType::SFLOAT),
+ Self::ASTC_10x5_SFLOAT_BLOCK => Some(NumericType::SFLOAT),
+ Self::ASTC_10x6_SFLOAT_BLOCK => Some(NumericType::SFLOAT),
+ Self::ASTC_10x8_SFLOAT_BLOCK => Some(NumericType::SFLOAT),
+ Self::ASTC_10x10_SFLOAT_BLOCK => Some(NumericType::SFLOAT),
+ Self::ASTC_12x10_SFLOAT_BLOCK => Some(NumericType::SFLOAT),
+ Self::ASTC_12x12_SFLOAT_BLOCK => Some(NumericType::SFLOAT),
+ Self::G8_B8R8_2PLANE_444_UNORM => Some(NumericType::UNORM),
+ Self::G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16 => Some(NumericType::UNORM),
+ Self::G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16 => Some(NumericType::UNORM),
+ Self::G16_B16R16_2PLANE_444_UNORM => Some(NumericType::UNORM),
+ Self::A4R4G4B4_UNORM_PACK16 => Some(NumericType::UNORM),
+ Self::A4B4G4R4_UNORM_PACK16 => Some(NumericType::UNORM),
+ Self::R16G16_S10_5_NV => Some(NumericType::SINT),
+ _ => None,
+ }
+ }
+ #[doc = r" Returns the numeric data type of the depth aspect of this format. Returns `None`"]
+ #[doc = r" color and stencil-only formats."]
+ pub fn type_depth(self) -> Option<NumericType> {
+ match self {
+ Self::D16_UNORM => Some(NumericType::UNORM),
+ Self::X8_D24_UNORM_PACK32 => Some(NumericType::UNORM),
+ Self::D32_SFLOAT => Some(NumericType::SFLOAT),
+ Self::D16_UNORM_S8_UINT => Some(NumericType::UNORM),
+ Self::D24_UNORM_S8_UINT => Some(NumericType::UNORM),
+ Self::D32_SFLOAT_S8_UINT => Some(NumericType::SFLOAT),
+ _ => None,
+ }
+ }
+ #[doc = r" Returns the numeric data type of the stencil aspect of this format. Returns `None`"]
+ #[doc = r" for color and depth-only formats."]
+ pub fn type_stencil(self) -> Option<NumericType> {
+ match self {
+ Self::S8_UINT => Some(NumericType::UINT),
+ Self::D16_UNORM_S8_UINT => Some(NumericType::UINT),
+ Self::D24_UNORM_S8_UINT => Some(NumericType::UINT),
+ Self::D32_SFLOAT_S8_UINT => Some(NumericType::UINT),
+ _ => None,
+ }
+ }
+ #[doc = r" For YCbCr (YUV) formats, returns the way in which the chroma components are"]
+ #[doc = r" represented. Returns `None` for non-YCbCr formats."]
+ #[doc = r""]
+ #[doc = r" If an image view is created for one of the formats for which this function returns"]
+ #[doc = r" `Some`, with the `color` aspect selected, then the view and any samplers that sample"]
+ #[doc = r" it must be created with an attached sampler YCbCr conversion object."]
+ pub fn ycbcr_chroma_sampling(self) -> Option<ChromaSampling> {
+ match self {
+ Self::G8B8G8R8_422_UNORM => Some(ChromaSampling::Mode422),
+ Self::B8G8R8G8_422_UNORM => Some(ChromaSampling::Mode422),
+ Self::G8_B8_R8_3PLANE_420_UNORM => Some(ChromaSampling::Mode420),
+ Self::G8_B8R8_2PLANE_420_UNORM => Some(ChromaSampling::Mode420),
+ Self::G8_B8_R8_3PLANE_422_UNORM => Some(ChromaSampling::Mode422),
+ Self::G8_B8R8_2PLANE_422_UNORM => Some(ChromaSampling::Mode422),
+ Self::G8_B8_R8_3PLANE_444_UNORM => Some(ChromaSampling::Mode444),
+ Self::R10X6G10X6B10X6A10X6_UNORM_4PACK16 => Some(ChromaSampling::Mode444),
+ Self::G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 => Some(ChromaSampling::Mode422),
+ Self::B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 => Some(ChromaSampling::Mode422),
+ Self::G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 => Some(ChromaSampling::Mode420),
+ Self::G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 => Some(ChromaSampling::Mode420),
+ Self::G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 => Some(ChromaSampling::Mode422),
+ Self::G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 => Some(ChromaSampling::Mode422),
+ Self::G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 => Some(ChromaSampling::Mode444),
+ Self::R12X4G12X4B12X4A12X4_UNORM_4PACK16 => Some(ChromaSampling::Mode444),
+ Self::G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 => Some(ChromaSampling::Mode422),
+ Self::B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 => Some(ChromaSampling::Mode422),
+ Self::G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 => Some(ChromaSampling::Mode420),
+ Self::G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 => Some(ChromaSampling::Mode420),
+ Self::G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 => Some(ChromaSampling::Mode422),
+ Self::G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 => Some(ChromaSampling::Mode422),
+ Self::G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 => Some(ChromaSampling::Mode444),
+ Self::G16B16G16R16_422_UNORM => Some(ChromaSampling::Mode422),
+ Self::B16G16R16G16_422_UNORM => Some(ChromaSampling::Mode422),
+ Self::G16_B16_R16_3PLANE_420_UNORM => Some(ChromaSampling::Mode420),
+ Self::G16_B16R16_2PLANE_420_UNORM => Some(ChromaSampling::Mode420),
+ Self::G16_B16_R16_3PLANE_422_UNORM => Some(ChromaSampling::Mode422),
+ Self::G16_B16R16_2PLANE_422_UNORM => Some(ChromaSampling::Mode422),
+ Self::G16_B16_R16_3PLANE_444_UNORM => Some(ChromaSampling::Mode444),
+ Self::G8_B8R8_2PLANE_444_UNORM => Some(ChromaSampling::Mode444),
+ Self::G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16 => Some(ChromaSampling::Mode444),
+ Self::G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16 => Some(ChromaSampling::Mode444),
+ Self::G16_B16R16_2PLANE_444_UNORM => Some(ChromaSampling::Mode444),
+ _ => None,
+ }
+ }
+ #[allow(dead_code)]
+ pub(crate) fn validate_device(
+ self,
+ #[allow(unused_variables)] device: &crate::device::Device,
+ ) -> Result<(), crate::RequirementNotMet> {
+ match self {
+ Self::R4G4_UNORM_PACK8 => {}
+ Self::R4G4B4A4_UNORM_PACK16 => {}
+ Self::B4G4R4A4_UNORM_PACK16 => {}
+ Self::R5G6B5_UNORM_PACK16 => {}
+ Self::B5G6R5_UNORM_PACK16 => {}
+ Self::R5G5B5A1_UNORM_PACK16 => {}
+ Self::B5G5R5A1_UNORM_PACK16 => {}
+ Self::A1R5G5B5_UNORM_PACK16 => {}
+ Self::R8_UNORM => {}
+ Self::R8_SNORM => {}
+ Self::R8_USCALED => {}
+ Self::R8_SSCALED => {}
+ Self::R8_UINT => {}
+ Self::R8_SINT => {}
+ Self::R8_SRGB => {}
+ Self::R8G8_UNORM => {}
+ Self::R8G8_SNORM => {}
+ Self::R8G8_USCALED => {}
+ Self::R8G8_SSCALED => {}
+ Self::R8G8_UINT => {}
+ Self::R8G8_SINT => {}
+ Self::R8G8_SRGB => {}
+ Self::R8G8B8_UNORM => {}
+ Self::R8G8B8_SNORM => {}
+ Self::R8G8B8_USCALED => {}
+ Self::R8G8B8_SSCALED => {}
+ Self::R8G8B8_UINT => {}
+ Self::R8G8B8_SINT => {}
+ Self::R8G8B8_SRGB => {}
+ Self::B8G8R8_UNORM => {}
+ Self::B8G8R8_SNORM => {}
+ Self::B8G8R8_USCALED => {}
+ Self::B8G8R8_SSCALED => {}
+ Self::B8G8R8_UINT => {}
+ Self::B8G8R8_SINT => {}
+ Self::B8G8R8_SRGB => {}
+ Self::R8G8B8A8_UNORM => {}
+ Self::R8G8B8A8_SNORM => {}
+ Self::R8G8B8A8_USCALED => {}
+ Self::R8G8B8A8_SSCALED => {}
+ Self::R8G8B8A8_UINT => {}
+ Self::R8G8B8A8_SINT => {}
+ Self::R8G8B8A8_SRGB => {}
+ Self::B8G8R8A8_UNORM => {}
+ Self::B8G8R8A8_SNORM => {}
+ Self::B8G8R8A8_USCALED => {}
+ Self::B8G8R8A8_SSCALED => {}
+ Self::B8G8R8A8_UINT => {}
+ Self::B8G8R8A8_SINT => {}
+ Self::B8G8R8A8_SRGB => {}
+ Self::A8B8G8R8_UNORM_PACK32 => {}
+ Self::A8B8G8R8_SNORM_PACK32 => {}
+ Self::A8B8G8R8_USCALED_PACK32 => {}
+ Self::A8B8G8R8_SSCALED_PACK32 => {}
+ Self::A8B8G8R8_UINT_PACK32 => {}
+ Self::A8B8G8R8_SINT_PACK32 => {}
+ Self::A8B8G8R8_SRGB_PACK32 => {}
+ Self::A2R10G10B10_UNORM_PACK32 => {}
+ Self::A2R10G10B10_SNORM_PACK32 => {}
+ Self::A2R10G10B10_USCALED_PACK32 => {}
+ Self::A2R10G10B10_SSCALED_PACK32 => {}
+ Self::A2R10G10B10_UINT_PACK32 => {}
+ Self::A2R10G10B10_SINT_PACK32 => {}
+ Self::A2B10G10R10_UNORM_PACK32 => {}
+ Self::A2B10G10R10_SNORM_PACK32 => {}
+ Self::A2B10G10R10_USCALED_PACK32 => {}
+ Self::A2B10G10R10_SSCALED_PACK32 => {}
+ Self::A2B10G10R10_UINT_PACK32 => {}
+ Self::A2B10G10R10_SINT_PACK32 => {}
+ Self::R16_UNORM => {}
+ Self::R16_SNORM => {}
+ Self::R16_USCALED => {}
+ Self::R16_SSCALED => {}
+ Self::R16_UINT => {}
+ Self::R16_SINT => {}
+ Self::R16_SFLOAT => {}
+ Self::R16G16_UNORM => {}
+ Self::R16G16_SNORM => {}
+ Self::R16G16_USCALED => {}
+ Self::R16G16_SSCALED => {}
+ Self::R16G16_UINT => {}
+ Self::R16G16_SINT => {}
+ Self::R16G16_SFLOAT => {}
+ Self::R16G16B16_UNORM => {}
+ Self::R16G16B16_SNORM => {}
+ Self::R16G16B16_USCALED => {}
+ Self::R16G16B16_SSCALED => {}
+ Self::R16G16B16_UINT => {}
+ Self::R16G16B16_SINT => {}
+ Self::R16G16B16_SFLOAT => {}
+ Self::R16G16B16A16_UNORM => {}
+ Self::R16G16B16A16_SNORM => {}
+ Self::R16G16B16A16_USCALED => {}
+ Self::R16G16B16A16_SSCALED => {}
+ Self::R16G16B16A16_UINT => {}
+ Self::R16G16B16A16_SINT => {}
+ Self::R16G16B16A16_SFLOAT => {}
+ Self::R32_UINT => {}
+ Self::R32_SINT => {}
+ Self::R32_SFLOAT => {}
+ Self::R32G32_UINT => {}
+ Self::R32G32_SINT => {}
+ Self::R32G32_SFLOAT => {}
+ Self::R32G32B32_UINT => {}
+ Self::R32G32B32_SINT => {}
+ Self::R32G32B32_SFLOAT => {}
+ Self::R32G32B32A32_UINT => {}
+ Self::R32G32B32A32_SINT => {}
+ Self::R32G32B32A32_SFLOAT => {}
+ Self::R64_UINT => {}
+ Self::R64_SINT => {}
+ Self::R64_SFLOAT => {}
+ Self::R64G64_UINT => {}
+ Self::R64G64_SINT => {}
+ Self::R64G64_SFLOAT => {}
+ Self::R64G64B64_UINT => {}
+ Self::R64G64B64_SINT => {}
+ Self::R64G64B64_SFLOAT => {}
+ Self::R64G64B64A64_UINT => {}
+ Self::R64G64B64A64_SINT => {}
+ Self::R64G64B64A64_SFLOAT => {}
+ Self::B10G11R11_UFLOAT_PACK32 => {}
+ Self::E5B9G9R9_UFLOAT_PACK32 => {}
+ Self::D16_UNORM => {}
+ Self::X8_D24_UNORM_PACK32 => {}
+ Self::D32_SFLOAT => {}
+ Self::S8_UINT => {}
+ Self::D16_UNORM_S8_UINT => {}
+ Self::D24_UNORM_S8_UINT => {}
+ Self::D32_SFLOAT_S8_UINT => {}
+ Self::BC1_RGB_UNORM_BLOCK => {}
+ Self::BC1_RGB_SRGB_BLOCK => {}
+ Self::BC1_RGBA_UNORM_BLOCK => {}
+ Self::BC1_RGBA_SRGB_BLOCK => {}
+ Self::BC2_UNORM_BLOCK => {}
+ Self::BC2_SRGB_BLOCK => {}
+ Self::BC3_UNORM_BLOCK => {}
+ Self::BC3_SRGB_BLOCK => {}
+ Self::BC4_UNORM_BLOCK => {}
+ Self::BC4_SNORM_BLOCK => {}
+ Self::BC5_UNORM_BLOCK => {}
+ Self::BC5_SNORM_BLOCK => {}
+ Self::BC6H_UFLOAT_BLOCK => {}
+ Self::BC6H_SFLOAT_BLOCK => {}
+ Self::BC7_UNORM_BLOCK => {}
+ Self::BC7_SRGB_BLOCK => {}
+ Self::ETC2_R8G8B8_UNORM_BLOCK => {}
+ Self::ETC2_R8G8B8_SRGB_BLOCK => {}
+ Self::ETC2_R8G8B8A1_UNORM_BLOCK => {}
+ Self::ETC2_R8G8B8A1_SRGB_BLOCK => {}
+ Self::ETC2_R8G8B8A8_UNORM_BLOCK => {}
+ Self::ETC2_R8G8B8A8_SRGB_BLOCK => {}
+ Self::EAC_R11_UNORM_BLOCK => {}
+ Self::EAC_R11_SNORM_BLOCK => {}
+ Self::EAC_R11G11_UNORM_BLOCK => {}
+ Self::EAC_R11G11_SNORM_BLOCK => {}
+ Self::ASTC_4x4_UNORM_BLOCK => {}
+ Self::ASTC_4x4_SRGB_BLOCK => {}
+ Self::ASTC_5x4_UNORM_BLOCK => {}
+ Self::ASTC_5x4_SRGB_BLOCK => {}
+ Self::ASTC_5x5_UNORM_BLOCK => {}
+ Self::ASTC_5x5_SRGB_BLOCK => {}
+ Self::ASTC_6x5_UNORM_BLOCK => {}
+ Self::ASTC_6x5_SRGB_BLOCK => {}
+ Self::ASTC_6x6_UNORM_BLOCK => {}
+ Self::ASTC_6x6_SRGB_BLOCK => {}
+ Self::ASTC_8x5_UNORM_BLOCK => {}
+ Self::ASTC_8x5_SRGB_BLOCK => {}
+ Self::ASTC_8x6_UNORM_BLOCK => {}
+ Self::ASTC_8x6_SRGB_BLOCK => {}
+ Self::ASTC_8x8_UNORM_BLOCK => {}
+ Self::ASTC_8x8_SRGB_BLOCK => {}
+ Self::ASTC_10x5_UNORM_BLOCK => {}
+ Self::ASTC_10x5_SRGB_BLOCK => {}
+ Self::ASTC_10x6_UNORM_BLOCK => {}
+ Self::ASTC_10x6_SRGB_BLOCK => {}
+ Self::ASTC_10x8_UNORM_BLOCK => {}
+ Self::ASTC_10x8_SRGB_BLOCK => {}
+ Self::ASTC_10x10_UNORM_BLOCK => {}
+ Self::ASTC_10x10_SRGB_BLOCK => {}
+ Self::ASTC_12x10_UNORM_BLOCK => {}
+ Self::ASTC_12x10_SRGB_BLOCK => {}
+ Self::ASTC_12x12_UNORM_BLOCK => {}
+ Self::ASTC_12x12_SRGB_BLOCK => {}
+ Self::G8B8G8R8_422_UNORM => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G8B8G8R8_422_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::B8G8R8G8_422_UNORM => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::B8G8R8G8_422_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G8_B8_R8_3PLANE_420_UNORM => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G8_B8_R8_3PLANE_420_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G8_B8R8_2PLANE_420_UNORM => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G8_B8R8_2PLANE_420_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G8_B8_R8_3PLANE_422_UNORM => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G8_B8_R8_3PLANE_422_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G8_B8R8_2PLANE_422_UNORM => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G8_B8R8_2PLANE_422_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G8_B8_R8_3PLANE_444_UNORM => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G8_B8_R8_3PLANE_444_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::R10X6_UNORM_PACK16 => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::R10X6_UNORM_PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::R10X6G10X6_UNORM_2PACK16 => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::R10X6G10X6_UNORM_2PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::R10X6G10X6B10X6A10X6_UNORM_4PACK16 => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::R10X6G10X6B10X6A10X6_UNORM_4PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G10X6B10X6G10X6R10X6_422_UNORM_4PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::B10X6G10X6R10X6G10X6_422_UNORM_4PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::R12X4_UNORM_PACK16 => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::R12X4_UNORM_PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::R12X4G12X4_UNORM_2PACK16 => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::R12X4G12X4_UNORM_2PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::R12X4G12X4B12X4A12X4_UNORM_4PACK16 => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::R12X4G12X4B12X4A12X4_UNORM_4PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G12X4B12X4G12X4R12X4_422_UNORM_4PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::B12X4G12X4R12X4G12X4_422_UNORM_4PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G16B16G16R16_422_UNORM => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G16B16G16R16_422_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::B16G16R16G16_422_UNORM => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::B16G16R16G16_422_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G16_B16_R16_3PLANE_420_UNORM => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G16_B16_R16_3PLANE_420_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G16_B16R16_2PLANE_420_UNORM => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G16_B16R16_2PLANE_420_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G16_B16_R16_3PLANE_422_UNORM => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G16_B16_R16_3PLANE_422_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G16_B16R16_2PLANE_422_UNORM => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G16_B16R16_2PLANE_422_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G16_B16_R16_3PLANE_444_UNORM => {
+ if !(device.api_version() >= crate::Version::V1_1
+ || device.enabled_extensions().khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G16_B16_R16_3PLANE_444_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::PVRTC1_2BPP_UNORM_BLOCK => {
+ if !(device.enabled_extensions().img_format_pvrtc) {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::PVRTC1_2BPP_UNORM_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ device_extensions: &["img_format_pvrtc"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::PVRTC1_4BPP_UNORM_BLOCK => {
+ if !(device.enabled_extensions().img_format_pvrtc) {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::PVRTC1_4BPP_UNORM_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ device_extensions: &["img_format_pvrtc"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::PVRTC2_2BPP_UNORM_BLOCK => {
+ if !(device.enabled_extensions().img_format_pvrtc) {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::PVRTC2_2BPP_UNORM_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ device_extensions: &["img_format_pvrtc"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::PVRTC2_4BPP_UNORM_BLOCK => {
+ if !(device.enabled_extensions().img_format_pvrtc) {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::PVRTC2_4BPP_UNORM_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ device_extensions: &["img_format_pvrtc"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::PVRTC1_2BPP_SRGB_BLOCK => {
+ if !(device.enabled_extensions().img_format_pvrtc) {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::PVRTC1_2BPP_SRGB_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ device_extensions: &["img_format_pvrtc"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::PVRTC1_4BPP_SRGB_BLOCK => {
+ if !(device.enabled_extensions().img_format_pvrtc) {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::PVRTC1_4BPP_SRGB_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ device_extensions: &["img_format_pvrtc"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::PVRTC2_2BPP_SRGB_BLOCK => {
+ if !(device.enabled_extensions().img_format_pvrtc) {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::PVRTC2_2BPP_SRGB_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ device_extensions: &["img_format_pvrtc"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::PVRTC2_4BPP_SRGB_BLOCK => {
+ if !(device.enabled_extensions().img_format_pvrtc) {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::PVRTC2_4BPP_SRGB_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ device_extensions: &["img_format_pvrtc"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::ASTC_4x4_SFLOAT_BLOCK => {
+ if !(device.api_version() >= crate::Version::V1_3
+ || device.enabled_extensions().ext_texture_compression_astc_hdr)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::ASTC_4x4_SFLOAT_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_texture_compression_astc_hdr"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::ASTC_5x4_SFLOAT_BLOCK => {
+ if !(device.api_version() >= crate::Version::V1_3
+ || device.enabled_extensions().ext_texture_compression_astc_hdr)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::ASTC_5x4_SFLOAT_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_texture_compression_astc_hdr"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::ASTC_5x5_SFLOAT_BLOCK => {
+ if !(device.api_version() >= crate::Version::V1_3
+ || device.enabled_extensions().ext_texture_compression_astc_hdr)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::ASTC_5x5_SFLOAT_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_texture_compression_astc_hdr"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::ASTC_6x5_SFLOAT_BLOCK => {
+ if !(device.api_version() >= crate::Version::V1_3
+ || device.enabled_extensions().ext_texture_compression_astc_hdr)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::ASTC_6x5_SFLOAT_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_texture_compression_astc_hdr"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::ASTC_6x6_SFLOAT_BLOCK => {
+ if !(device.api_version() >= crate::Version::V1_3
+ || device.enabled_extensions().ext_texture_compression_astc_hdr)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::ASTC_6x6_SFLOAT_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_texture_compression_astc_hdr"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::ASTC_8x5_SFLOAT_BLOCK => {
+ if !(device.api_version() >= crate::Version::V1_3
+ || device.enabled_extensions().ext_texture_compression_astc_hdr)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::ASTC_8x5_SFLOAT_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_texture_compression_astc_hdr"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::ASTC_8x6_SFLOAT_BLOCK => {
+ if !(device.api_version() >= crate::Version::V1_3
+ || device.enabled_extensions().ext_texture_compression_astc_hdr)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::ASTC_8x6_SFLOAT_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_texture_compression_astc_hdr"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::ASTC_8x8_SFLOAT_BLOCK => {
+ if !(device.api_version() >= crate::Version::V1_3
+ || device.enabled_extensions().ext_texture_compression_astc_hdr)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::ASTC_8x8_SFLOAT_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_texture_compression_astc_hdr"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::ASTC_10x5_SFLOAT_BLOCK => {
+ if !(device.api_version() >= crate::Version::V1_3
+ || device.enabled_extensions().ext_texture_compression_astc_hdr)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::ASTC_10x5_SFLOAT_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_texture_compression_astc_hdr"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::ASTC_10x6_SFLOAT_BLOCK => {
+ if !(device.api_version() >= crate::Version::V1_3
+ || device.enabled_extensions().ext_texture_compression_astc_hdr)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::ASTC_10x6_SFLOAT_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_texture_compression_astc_hdr"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::ASTC_10x8_SFLOAT_BLOCK => {
+ if !(device.api_version() >= crate::Version::V1_3
+ || device.enabled_extensions().ext_texture_compression_astc_hdr)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::ASTC_10x8_SFLOAT_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_texture_compression_astc_hdr"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::ASTC_10x10_SFLOAT_BLOCK => {
+ if !(device.api_version() >= crate::Version::V1_3
+ || device.enabled_extensions().ext_texture_compression_astc_hdr)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::ASTC_10x10_SFLOAT_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_texture_compression_astc_hdr"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::ASTC_12x10_SFLOAT_BLOCK => {
+ if !(device.api_version() >= crate::Version::V1_3
+ || device.enabled_extensions().ext_texture_compression_astc_hdr)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::ASTC_12x10_SFLOAT_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_texture_compression_astc_hdr"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::ASTC_12x12_SFLOAT_BLOCK => {
+ if !(device.api_version() >= crate::Version::V1_3
+ || device.enabled_extensions().ext_texture_compression_astc_hdr)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::ASTC_12x12_SFLOAT_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_texture_compression_astc_hdr"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G8_B8R8_2PLANE_444_UNORM => {
+ if !(device.api_version() >= crate::Version::V1_3
+ || device.enabled_extensions().ext_ycbcr_2plane_444_formats)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G8_B8R8_2PLANE_444_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_ycbcr_2plane_444_formats"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16 => {
+ if !(device.api_version() >= crate::Version::V1_3
+ || device.enabled_extensions().ext_ycbcr_2plane_444_formats)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_ycbcr_2plane_444_formats"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16 => {
+ if !(device.api_version() >= crate::Version::V1_3
+ || device.enabled_extensions().ext_ycbcr_2plane_444_formats)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_ycbcr_2plane_444_formats"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G16_B16R16_2PLANE_444_UNORM => {
+ if !(device.api_version() >= crate::Version::V1_3
+ || device.enabled_extensions().ext_ycbcr_2plane_444_formats)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G16_B16R16_2PLANE_444_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_ycbcr_2plane_444_formats"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::A4R4G4B4_UNORM_PACK16 => {
+ if !(device.api_version() >= crate::Version::V1_3
+ || device.enabled_extensions().ext_4444_formats)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::A4R4G4B4_UNORM_PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_4444_formats"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::A4B4G4R4_UNORM_PACK16 => {
+ if !(device.api_version() >= crate::Version::V1_3
+ || device.enabled_extensions().ext_4444_formats)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::A4B4G4R4_UNORM_PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_4444_formats"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::R16G16_S10_5_NV => {
+ if !(device.enabled_extensions().nv_optical_flow) {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::R16G16_S10_5_NV`",
+ requires_one_of: crate::RequiresOneOf {
+ device_extensions: &["nv_optical_flow"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ }
+ Ok(())
+ }
+ #[allow(dead_code)]
+ pub(crate) fn validate_physical_device(
+ self,
+ #[allow(unused_variables)] physical_device: &crate::device::physical::PhysicalDevice,
+ ) -> Result<(), crate::RequirementNotMet> {
+ match self {
+ Self::R4G4_UNORM_PACK8 => {}
+ Self::R4G4B4A4_UNORM_PACK16 => {}
+ Self::B4G4R4A4_UNORM_PACK16 => {}
+ Self::R5G6B5_UNORM_PACK16 => {}
+ Self::B5G6R5_UNORM_PACK16 => {}
+ Self::R5G5B5A1_UNORM_PACK16 => {}
+ Self::B5G5R5A1_UNORM_PACK16 => {}
+ Self::A1R5G5B5_UNORM_PACK16 => {}
+ Self::R8_UNORM => {}
+ Self::R8_SNORM => {}
+ Self::R8_USCALED => {}
+ Self::R8_SSCALED => {}
+ Self::R8_UINT => {}
+ Self::R8_SINT => {}
+ Self::R8_SRGB => {}
+ Self::R8G8_UNORM => {}
+ Self::R8G8_SNORM => {}
+ Self::R8G8_USCALED => {}
+ Self::R8G8_SSCALED => {}
+ Self::R8G8_UINT => {}
+ Self::R8G8_SINT => {}
+ Self::R8G8_SRGB => {}
+ Self::R8G8B8_UNORM => {}
+ Self::R8G8B8_SNORM => {}
+ Self::R8G8B8_USCALED => {}
+ Self::R8G8B8_SSCALED => {}
+ Self::R8G8B8_UINT => {}
+ Self::R8G8B8_SINT => {}
+ Self::R8G8B8_SRGB => {}
+ Self::B8G8R8_UNORM => {}
+ Self::B8G8R8_SNORM => {}
+ Self::B8G8R8_USCALED => {}
+ Self::B8G8R8_SSCALED => {}
+ Self::B8G8R8_UINT => {}
+ Self::B8G8R8_SINT => {}
+ Self::B8G8R8_SRGB => {}
+ Self::R8G8B8A8_UNORM => {}
+ Self::R8G8B8A8_SNORM => {}
+ Self::R8G8B8A8_USCALED => {}
+ Self::R8G8B8A8_SSCALED => {}
+ Self::R8G8B8A8_UINT => {}
+ Self::R8G8B8A8_SINT => {}
+ Self::R8G8B8A8_SRGB => {}
+ Self::B8G8R8A8_UNORM => {}
+ Self::B8G8R8A8_SNORM => {}
+ Self::B8G8R8A8_USCALED => {}
+ Self::B8G8R8A8_SSCALED => {}
+ Self::B8G8R8A8_UINT => {}
+ Self::B8G8R8A8_SINT => {}
+ Self::B8G8R8A8_SRGB => {}
+ Self::A8B8G8R8_UNORM_PACK32 => {}
+ Self::A8B8G8R8_SNORM_PACK32 => {}
+ Self::A8B8G8R8_USCALED_PACK32 => {}
+ Self::A8B8G8R8_SSCALED_PACK32 => {}
+ Self::A8B8G8R8_UINT_PACK32 => {}
+ Self::A8B8G8R8_SINT_PACK32 => {}
+ Self::A8B8G8R8_SRGB_PACK32 => {}
+ Self::A2R10G10B10_UNORM_PACK32 => {}
+ Self::A2R10G10B10_SNORM_PACK32 => {}
+ Self::A2R10G10B10_USCALED_PACK32 => {}
+ Self::A2R10G10B10_SSCALED_PACK32 => {}
+ Self::A2R10G10B10_UINT_PACK32 => {}
+ Self::A2R10G10B10_SINT_PACK32 => {}
+ Self::A2B10G10R10_UNORM_PACK32 => {}
+ Self::A2B10G10R10_SNORM_PACK32 => {}
+ Self::A2B10G10R10_USCALED_PACK32 => {}
+ Self::A2B10G10R10_SSCALED_PACK32 => {}
+ Self::A2B10G10R10_UINT_PACK32 => {}
+ Self::A2B10G10R10_SINT_PACK32 => {}
+ Self::R16_UNORM => {}
+ Self::R16_SNORM => {}
+ Self::R16_USCALED => {}
+ Self::R16_SSCALED => {}
+ Self::R16_UINT => {}
+ Self::R16_SINT => {}
+ Self::R16_SFLOAT => {}
+ Self::R16G16_UNORM => {}
+ Self::R16G16_SNORM => {}
+ Self::R16G16_USCALED => {}
+ Self::R16G16_SSCALED => {}
+ Self::R16G16_UINT => {}
+ Self::R16G16_SINT => {}
+ Self::R16G16_SFLOAT => {}
+ Self::R16G16B16_UNORM => {}
+ Self::R16G16B16_SNORM => {}
+ Self::R16G16B16_USCALED => {}
+ Self::R16G16B16_SSCALED => {}
+ Self::R16G16B16_UINT => {}
+ Self::R16G16B16_SINT => {}
+ Self::R16G16B16_SFLOAT => {}
+ Self::R16G16B16A16_UNORM => {}
+ Self::R16G16B16A16_SNORM => {}
+ Self::R16G16B16A16_USCALED => {}
+ Self::R16G16B16A16_SSCALED => {}
+ Self::R16G16B16A16_UINT => {}
+ Self::R16G16B16A16_SINT => {}
+ Self::R16G16B16A16_SFLOAT => {}
+ Self::R32_UINT => {}
+ Self::R32_SINT => {}
+ Self::R32_SFLOAT => {}
+ Self::R32G32_UINT => {}
+ Self::R32G32_SINT => {}
+ Self::R32G32_SFLOAT => {}
+ Self::R32G32B32_UINT => {}
+ Self::R32G32B32_SINT => {}
+ Self::R32G32B32_SFLOAT => {}
+ Self::R32G32B32A32_UINT => {}
+ Self::R32G32B32A32_SINT => {}
+ Self::R32G32B32A32_SFLOAT => {}
+ Self::R64_UINT => {}
+ Self::R64_SINT => {}
+ Self::R64_SFLOAT => {}
+ Self::R64G64_UINT => {}
+ Self::R64G64_SINT => {}
+ Self::R64G64_SFLOAT => {}
+ Self::R64G64B64_UINT => {}
+ Self::R64G64B64_SINT => {}
+ Self::R64G64B64_SFLOAT => {}
+ Self::R64G64B64A64_UINT => {}
+ Self::R64G64B64A64_SINT => {}
+ Self::R64G64B64A64_SFLOAT => {}
+ Self::B10G11R11_UFLOAT_PACK32 => {}
+ Self::E5B9G9R9_UFLOAT_PACK32 => {}
+ Self::D16_UNORM => {}
+ Self::X8_D24_UNORM_PACK32 => {}
+ Self::D32_SFLOAT => {}
+ Self::S8_UINT => {}
+ Self::D16_UNORM_S8_UINT => {}
+ Self::D24_UNORM_S8_UINT => {}
+ Self::D32_SFLOAT_S8_UINT => {}
+ Self::BC1_RGB_UNORM_BLOCK => {}
+ Self::BC1_RGB_SRGB_BLOCK => {}
+ Self::BC1_RGBA_UNORM_BLOCK => {}
+ Self::BC1_RGBA_SRGB_BLOCK => {}
+ Self::BC2_UNORM_BLOCK => {}
+ Self::BC2_SRGB_BLOCK => {}
+ Self::BC3_UNORM_BLOCK => {}
+ Self::BC3_SRGB_BLOCK => {}
+ Self::BC4_UNORM_BLOCK => {}
+ Self::BC4_SNORM_BLOCK => {}
+ Self::BC5_UNORM_BLOCK => {}
+ Self::BC5_SNORM_BLOCK => {}
+ Self::BC6H_UFLOAT_BLOCK => {}
+ Self::BC6H_SFLOAT_BLOCK => {}
+ Self::BC7_UNORM_BLOCK => {}
+ Self::BC7_SRGB_BLOCK => {}
+ Self::ETC2_R8G8B8_UNORM_BLOCK => {}
+ Self::ETC2_R8G8B8_SRGB_BLOCK => {}
+ Self::ETC2_R8G8B8A1_UNORM_BLOCK => {}
+ Self::ETC2_R8G8B8A1_SRGB_BLOCK => {}
+ Self::ETC2_R8G8B8A8_UNORM_BLOCK => {}
+ Self::ETC2_R8G8B8A8_SRGB_BLOCK => {}
+ Self::EAC_R11_UNORM_BLOCK => {}
+ Self::EAC_R11_SNORM_BLOCK => {}
+ Self::EAC_R11G11_UNORM_BLOCK => {}
+ Self::EAC_R11G11_SNORM_BLOCK => {}
+ Self::ASTC_4x4_UNORM_BLOCK => {}
+ Self::ASTC_4x4_SRGB_BLOCK => {}
+ Self::ASTC_5x4_UNORM_BLOCK => {}
+ Self::ASTC_5x4_SRGB_BLOCK => {}
+ Self::ASTC_5x5_UNORM_BLOCK => {}
+ Self::ASTC_5x5_SRGB_BLOCK => {}
+ Self::ASTC_6x5_UNORM_BLOCK => {}
+ Self::ASTC_6x5_SRGB_BLOCK => {}
+ Self::ASTC_6x6_UNORM_BLOCK => {}
+ Self::ASTC_6x6_SRGB_BLOCK => {}
+ Self::ASTC_8x5_UNORM_BLOCK => {}
+ Self::ASTC_8x5_SRGB_BLOCK => {}
+ Self::ASTC_8x6_UNORM_BLOCK => {}
+ Self::ASTC_8x6_SRGB_BLOCK => {}
+ Self::ASTC_8x8_UNORM_BLOCK => {}
+ Self::ASTC_8x8_SRGB_BLOCK => {}
+ Self::ASTC_10x5_UNORM_BLOCK => {}
+ Self::ASTC_10x5_SRGB_BLOCK => {}
+ Self::ASTC_10x6_UNORM_BLOCK => {}
+ Self::ASTC_10x6_SRGB_BLOCK => {}
+ Self::ASTC_10x8_UNORM_BLOCK => {}
+ Self::ASTC_10x8_SRGB_BLOCK => {}
+ Self::ASTC_10x10_UNORM_BLOCK => {}
+ Self::ASTC_10x10_SRGB_BLOCK => {}
+ Self::ASTC_12x10_UNORM_BLOCK => {}
+ Self::ASTC_12x10_SRGB_BLOCK => {}
+ Self::ASTC_12x12_UNORM_BLOCK => {}
+ Self::ASTC_12x12_SRGB_BLOCK => {}
+ Self::G8B8G8R8_422_UNORM => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G8B8G8R8_422_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::B8G8R8G8_422_UNORM => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::B8G8R8G8_422_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G8_B8_R8_3PLANE_420_UNORM => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G8_B8_R8_3PLANE_420_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G8_B8R8_2PLANE_420_UNORM => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G8_B8R8_2PLANE_420_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G8_B8_R8_3PLANE_422_UNORM => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G8_B8_R8_3PLANE_422_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G8_B8R8_2PLANE_422_UNORM => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G8_B8R8_2PLANE_422_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G8_B8_R8_3PLANE_444_UNORM => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G8_B8_R8_3PLANE_444_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::R10X6_UNORM_PACK16 => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::R10X6_UNORM_PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::R10X6G10X6_UNORM_2PACK16 => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::R10X6G10X6_UNORM_2PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::R10X6G10X6B10X6A10X6_UNORM_4PACK16 => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::R10X6G10X6B10X6A10X6_UNORM_4PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G10X6B10X6G10X6R10X6_422_UNORM_4PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::B10X6G10X6R10X6G10X6_422_UNORM_4PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::R12X4_UNORM_PACK16 => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::R12X4_UNORM_PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::R12X4G12X4_UNORM_2PACK16 => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::R12X4G12X4_UNORM_2PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::R12X4G12X4B12X4A12X4_UNORM_4PACK16 => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::R12X4G12X4B12X4A12X4_UNORM_4PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G12X4B12X4G12X4R12X4_422_UNORM_4PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::B12X4G12X4R12X4G12X4_422_UNORM_4PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G16B16G16R16_422_UNORM => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G16B16G16R16_422_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::B16G16R16G16_422_UNORM => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::B16G16R16G16_422_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G16_B16_R16_3PLANE_420_UNORM => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G16_B16_R16_3PLANE_420_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G16_B16R16_2PLANE_420_UNORM => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G16_B16R16_2PLANE_420_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G16_B16_R16_3PLANE_422_UNORM => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G16_B16_R16_3PLANE_422_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G16_B16R16_2PLANE_422_UNORM => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G16_B16R16_2PLANE_422_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G16_B16_R16_3PLANE_444_UNORM => {
+ if !(physical_device.api_version() >= crate::Version::V1_1
+ || physical_device
+ .supported_extensions()
+ .khr_sampler_ycbcr_conversion)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G16_B16_R16_3PLANE_444_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &["khr_sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::PVRTC1_2BPP_UNORM_BLOCK => {
+ if !(physical_device.supported_extensions().img_format_pvrtc) {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::PVRTC1_2BPP_UNORM_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ device_extensions: &["img_format_pvrtc"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::PVRTC1_4BPP_UNORM_BLOCK => {
+ if !(physical_device.supported_extensions().img_format_pvrtc) {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::PVRTC1_4BPP_UNORM_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ device_extensions: &["img_format_pvrtc"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::PVRTC2_2BPP_UNORM_BLOCK => {
+ if !(physical_device.supported_extensions().img_format_pvrtc) {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::PVRTC2_2BPP_UNORM_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ device_extensions: &["img_format_pvrtc"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::PVRTC2_4BPP_UNORM_BLOCK => {
+ if !(physical_device.supported_extensions().img_format_pvrtc) {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::PVRTC2_4BPP_UNORM_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ device_extensions: &["img_format_pvrtc"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::PVRTC1_2BPP_SRGB_BLOCK => {
+ if !(physical_device.supported_extensions().img_format_pvrtc) {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::PVRTC1_2BPP_SRGB_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ device_extensions: &["img_format_pvrtc"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::PVRTC1_4BPP_SRGB_BLOCK => {
+ if !(physical_device.supported_extensions().img_format_pvrtc) {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::PVRTC1_4BPP_SRGB_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ device_extensions: &["img_format_pvrtc"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::PVRTC2_2BPP_SRGB_BLOCK => {
+ if !(physical_device.supported_extensions().img_format_pvrtc) {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::PVRTC2_2BPP_SRGB_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ device_extensions: &["img_format_pvrtc"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::PVRTC2_4BPP_SRGB_BLOCK => {
+ if !(physical_device.supported_extensions().img_format_pvrtc) {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::PVRTC2_4BPP_SRGB_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ device_extensions: &["img_format_pvrtc"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::ASTC_4x4_SFLOAT_BLOCK => {
+ if !(physical_device.api_version() >= crate::Version::V1_3
+ || physical_device
+ .supported_extensions()
+ .ext_texture_compression_astc_hdr)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::ASTC_4x4_SFLOAT_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_texture_compression_astc_hdr"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::ASTC_5x4_SFLOAT_BLOCK => {
+ if !(physical_device.api_version() >= crate::Version::V1_3
+ || physical_device
+ .supported_extensions()
+ .ext_texture_compression_astc_hdr)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::ASTC_5x4_SFLOAT_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_texture_compression_astc_hdr"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::ASTC_5x5_SFLOAT_BLOCK => {
+ if !(physical_device.api_version() >= crate::Version::V1_3
+ || physical_device
+ .supported_extensions()
+ .ext_texture_compression_astc_hdr)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::ASTC_5x5_SFLOAT_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_texture_compression_astc_hdr"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::ASTC_6x5_SFLOAT_BLOCK => {
+ if !(physical_device.api_version() >= crate::Version::V1_3
+ || physical_device
+ .supported_extensions()
+ .ext_texture_compression_astc_hdr)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::ASTC_6x5_SFLOAT_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_texture_compression_astc_hdr"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::ASTC_6x6_SFLOAT_BLOCK => {
+ if !(physical_device.api_version() >= crate::Version::V1_3
+ || physical_device
+ .supported_extensions()
+ .ext_texture_compression_astc_hdr)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::ASTC_6x6_SFLOAT_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_texture_compression_astc_hdr"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::ASTC_8x5_SFLOAT_BLOCK => {
+ if !(physical_device.api_version() >= crate::Version::V1_3
+ || physical_device
+ .supported_extensions()
+ .ext_texture_compression_astc_hdr)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::ASTC_8x5_SFLOAT_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_texture_compression_astc_hdr"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::ASTC_8x6_SFLOAT_BLOCK => {
+ if !(physical_device.api_version() >= crate::Version::V1_3
+ || physical_device
+ .supported_extensions()
+ .ext_texture_compression_astc_hdr)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::ASTC_8x6_SFLOAT_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_texture_compression_astc_hdr"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::ASTC_8x8_SFLOAT_BLOCK => {
+ if !(physical_device.api_version() >= crate::Version::V1_3
+ || physical_device
+ .supported_extensions()
+ .ext_texture_compression_astc_hdr)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::ASTC_8x8_SFLOAT_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_texture_compression_astc_hdr"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::ASTC_10x5_SFLOAT_BLOCK => {
+ if !(physical_device.api_version() >= crate::Version::V1_3
+ || physical_device
+ .supported_extensions()
+ .ext_texture_compression_astc_hdr)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::ASTC_10x5_SFLOAT_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_texture_compression_astc_hdr"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::ASTC_10x6_SFLOAT_BLOCK => {
+ if !(physical_device.api_version() >= crate::Version::V1_3
+ || physical_device
+ .supported_extensions()
+ .ext_texture_compression_astc_hdr)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::ASTC_10x6_SFLOAT_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_texture_compression_astc_hdr"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::ASTC_10x8_SFLOAT_BLOCK => {
+ if !(physical_device.api_version() >= crate::Version::V1_3
+ || physical_device
+ .supported_extensions()
+ .ext_texture_compression_astc_hdr)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::ASTC_10x8_SFLOAT_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_texture_compression_astc_hdr"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::ASTC_10x10_SFLOAT_BLOCK => {
+ if !(physical_device.api_version() >= crate::Version::V1_3
+ || physical_device
+ .supported_extensions()
+ .ext_texture_compression_astc_hdr)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::ASTC_10x10_SFLOAT_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_texture_compression_astc_hdr"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::ASTC_12x10_SFLOAT_BLOCK => {
+ if !(physical_device.api_version() >= crate::Version::V1_3
+ || physical_device
+ .supported_extensions()
+ .ext_texture_compression_astc_hdr)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::ASTC_12x10_SFLOAT_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_texture_compression_astc_hdr"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::ASTC_12x12_SFLOAT_BLOCK => {
+ if !(physical_device.api_version() >= crate::Version::V1_3
+ || physical_device
+ .supported_extensions()
+ .ext_texture_compression_astc_hdr)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::ASTC_12x12_SFLOAT_BLOCK`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_texture_compression_astc_hdr"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G8_B8R8_2PLANE_444_UNORM => {
+ if !(physical_device.api_version() >= crate::Version::V1_3
+ || physical_device
+ .supported_extensions()
+ .ext_ycbcr_2plane_444_formats)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G8_B8R8_2PLANE_444_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_ycbcr_2plane_444_formats"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16 => {
+ if !(physical_device.api_version() >= crate::Version::V1_3
+ || physical_device
+ .supported_extensions()
+ .ext_ycbcr_2plane_444_formats)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_ycbcr_2plane_444_formats"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16 => {
+ if !(physical_device.api_version() >= crate::Version::V1_3
+ || physical_device
+ .supported_extensions()
+ .ext_ycbcr_2plane_444_formats)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_ycbcr_2plane_444_formats"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::G16_B16R16_2PLANE_444_UNORM => {
+ if !(physical_device.api_version() >= crate::Version::V1_3
+ || physical_device
+ .supported_extensions()
+ .ext_ycbcr_2plane_444_formats)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::G16_B16R16_2PLANE_444_UNORM`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_ycbcr_2plane_444_formats"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::A4R4G4B4_UNORM_PACK16 => {
+ if !(physical_device.api_version() >= crate::Version::V1_3
+ || physical_device.supported_extensions().ext_4444_formats)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::A4R4G4B4_UNORM_PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_4444_formats"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::A4B4G4R4_UNORM_PACK16 => {
+ if !(physical_device.api_version() >= crate::Version::V1_3
+ || physical_device.supported_extensions().ext_4444_formats)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::A4B4G4R4_UNORM_PACK16`",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_3),
+ device_extensions: &["ext_4444_formats"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ Self::R16G16_S10_5_NV => {
+ if !(physical_device.supported_extensions().nv_optical_flow) {
+ return Err(crate::RequirementNotMet {
+ required_for: "`Format::R16G16_S10_5_NV`",
+ requires_one_of: crate::RequiresOneOf {
+ device_extensions: &["nv_optical_flow"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ }
+ Ok(())
+ }
+}
+impl TryFrom<ash::vk::Format> for Format {
+ type Error = ();
+ fn try_from(val: ash::vk::Format) -> Result<Format, ()> {
+ match val {
+ ash::vk::Format::R4G4_UNORM_PACK8 => Ok(Self::R4G4_UNORM_PACK8),
+ ash::vk::Format::R4G4B4A4_UNORM_PACK16 => Ok(Self::R4G4B4A4_UNORM_PACK16),
+ ash::vk::Format::B4G4R4A4_UNORM_PACK16 => Ok(Self::B4G4R4A4_UNORM_PACK16),
+ ash::vk::Format::R5G6B5_UNORM_PACK16 => Ok(Self::R5G6B5_UNORM_PACK16),
+ ash::vk::Format::B5G6R5_UNORM_PACK16 => Ok(Self::B5G6R5_UNORM_PACK16),
+ ash::vk::Format::R5G5B5A1_UNORM_PACK16 => Ok(Self::R5G5B5A1_UNORM_PACK16),
+ ash::vk::Format::B5G5R5A1_UNORM_PACK16 => Ok(Self::B5G5R5A1_UNORM_PACK16),
+ ash::vk::Format::A1R5G5B5_UNORM_PACK16 => Ok(Self::A1R5G5B5_UNORM_PACK16),
+ ash::vk::Format::R8_UNORM => Ok(Self::R8_UNORM),
+ ash::vk::Format::R8_SNORM => Ok(Self::R8_SNORM),
+ ash::vk::Format::R8_USCALED => Ok(Self::R8_USCALED),
+ ash::vk::Format::R8_SSCALED => Ok(Self::R8_SSCALED),
+ ash::vk::Format::R8_UINT => Ok(Self::R8_UINT),
+ ash::vk::Format::R8_SINT => Ok(Self::R8_SINT),
+ ash::vk::Format::R8_SRGB => Ok(Self::R8_SRGB),
+ ash::vk::Format::R8G8_UNORM => Ok(Self::R8G8_UNORM),
+ ash::vk::Format::R8G8_SNORM => Ok(Self::R8G8_SNORM),
+ ash::vk::Format::R8G8_USCALED => Ok(Self::R8G8_USCALED),
+ ash::vk::Format::R8G8_SSCALED => Ok(Self::R8G8_SSCALED),
+ ash::vk::Format::R8G8_UINT => Ok(Self::R8G8_UINT),
+ ash::vk::Format::R8G8_SINT => Ok(Self::R8G8_SINT),
+ ash::vk::Format::R8G8_SRGB => Ok(Self::R8G8_SRGB),
+ ash::vk::Format::R8G8B8_UNORM => Ok(Self::R8G8B8_UNORM),
+ ash::vk::Format::R8G8B8_SNORM => Ok(Self::R8G8B8_SNORM),
+ ash::vk::Format::R8G8B8_USCALED => Ok(Self::R8G8B8_USCALED),
+ ash::vk::Format::R8G8B8_SSCALED => Ok(Self::R8G8B8_SSCALED),
+ ash::vk::Format::R8G8B8_UINT => Ok(Self::R8G8B8_UINT),
+ ash::vk::Format::R8G8B8_SINT => Ok(Self::R8G8B8_SINT),
+ ash::vk::Format::R8G8B8_SRGB => Ok(Self::R8G8B8_SRGB),
+ ash::vk::Format::B8G8R8_UNORM => Ok(Self::B8G8R8_UNORM),
+ ash::vk::Format::B8G8R8_SNORM => Ok(Self::B8G8R8_SNORM),
+ ash::vk::Format::B8G8R8_USCALED => Ok(Self::B8G8R8_USCALED),
+ ash::vk::Format::B8G8R8_SSCALED => Ok(Self::B8G8R8_SSCALED),
+ ash::vk::Format::B8G8R8_UINT => Ok(Self::B8G8R8_UINT),
+ ash::vk::Format::B8G8R8_SINT => Ok(Self::B8G8R8_SINT),
+ ash::vk::Format::B8G8R8_SRGB => Ok(Self::B8G8R8_SRGB),
+ ash::vk::Format::R8G8B8A8_UNORM => Ok(Self::R8G8B8A8_UNORM),
+ ash::vk::Format::R8G8B8A8_SNORM => Ok(Self::R8G8B8A8_SNORM),
+ ash::vk::Format::R8G8B8A8_USCALED => Ok(Self::R8G8B8A8_USCALED),
+ ash::vk::Format::R8G8B8A8_SSCALED => Ok(Self::R8G8B8A8_SSCALED),
+ ash::vk::Format::R8G8B8A8_UINT => Ok(Self::R8G8B8A8_UINT),
+ ash::vk::Format::R8G8B8A8_SINT => Ok(Self::R8G8B8A8_SINT),
+ ash::vk::Format::R8G8B8A8_SRGB => Ok(Self::R8G8B8A8_SRGB),
+ ash::vk::Format::B8G8R8A8_UNORM => Ok(Self::B8G8R8A8_UNORM),
+ ash::vk::Format::B8G8R8A8_SNORM => Ok(Self::B8G8R8A8_SNORM),
+ ash::vk::Format::B8G8R8A8_USCALED => Ok(Self::B8G8R8A8_USCALED),
+ ash::vk::Format::B8G8R8A8_SSCALED => Ok(Self::B8G8R8A8_SSCALED),
+ ash::vk::Format::B8G8R8A8_UINT => Ok(Self::B8G8R8A8_UINT),
+ ash::vk::Format::B8G8R8A8_SINT => Ok(Self::B8G8R8A8_SINT),
+ ash::vk::Format::B8G8R8A8_SRGB => Ok(Self::B8G8R8A8_SRGB),
+ ash::vk::Format::A8B8G8R8_UNORM_PACK32 => Ok(Self::A8B8G8R8_UNORM_PACK32),
+ ash::vk::Format::A8B8G8R8_SNORM_PACK32 => Ok(Self::A8B8G8R8_SNORM_PACK32),
+ ash::vk::Format::A8B8G8R8_USCALED_PACK32 => Ok(Self::A8B8G8R8_USCALED_PACK32),
+ ash::vk::Format::A8B8G8R8_SSCALED_PACK32 => Ok(Self::A8B8G8R8_SSCALED_PACK32),
+ ash::vk::Format::A8B8G8R8_UINT_PACK32 => Ok(Self::A8B8G8R8_UINT_PACK32),
+ ash::vk::Format::A8B8G8R8_SINT_PACK32 => Ok(Self::A8B8G8R8_SINT_PACK32),
+ ash::vk::Format::A8B8G8R8_SRGB_PACK32 => Ok(Self::A8B8G8R8_SRGB_PACK32),
+ ash::vk::Format::A2R10G10B10_UNORM_PACK32 => Ok(Self::A2R10G10B10_UNORM_PACK32),
+ ash::vk::Format::A2R10G10B10_SNORM_PACK32 => Ok(Self::A2R10G10B10_SNORM_PACK32),
+ ash::vk::Format::A2R10G10B10_USCALED_PACK32 => Ok(Self::A2R10G10B10_USCALED_PACK32),
+ ash::vk::Format::A2R10G10B10_SSCALED_PACK32 => Ok(Self::A2R10G10B10_SSCALED_PACK32),
+ ash::vk::Format::A2R10G10B10_UINT_PACK32 => Ok(Self::A2R10G10B10_UINT_PACK32),
+ ash::vk::Format::A2R10G10B10_SINT_PACK32 => Ok(Self::A2R10G10B10_SINT_PACK32),
+ ash::vk::Format::A2B10G10R10_UNORM_PACK32 => Ok(Self::A2B10G10R10_UNORM_PACK32),
+ ash::vk::Format::A2B10G10R10_SNORM_PACK32 => Ok(Self::A2B10G10R10_SNORM_PACK32),
+ ash::vk::Format::A2B10G10R10_USCALED_PACK32 => Ok(Self::A2B10G10R10_USCALED_PACK32),
+ ash::vk::Format::A2B10G10R10_SSCALED_PACK32 => Ok(Self::A2B10G10R10_SSCALED_PACK32),
+ ash::vk::Format::A2B10G10R10_UINT_PACK32 => Ok(Self::A2B10G10R10_UINT_PACK32),
+ ash::vk::Format::A2B10G10R10_SINT_PACK32 => Ok(Self::A2B10G10R10_SINT_PACK32),
+ ash::vk::Format::R16_UNORM => Ok(Self::R16_UNORM),
+ ash::vk::Format::R16_SNORM => Ok(Self::R16_SNORM),
+ ash::vk::Format::R16_USCALED => Ok(Self::R16_USCALED),
+ ash::vk::Format::R16_SSCALED => Ok(Self::R16_SSCALED),
+ ash::vk::Format::R16_UINT => Ok(Self::R16_UINT),
+ ash::vk::Format::R16_SINT => Ok(Self::R16_SINT),
+ ash::vk::Format::R16_SFLOAT => Ok(Self::R16_SFLOAT),
+ ash::vk::Format::R16G16_UNORM => Ok(Self::R16G16_UNORM),
+ ash::vk::Format::R16G16_SNORM => Ok(Self::R16G16_SNORM),
+ ash::vk::Format::R16G16_USCALED => Ok(Self::R16G16_USCALED),
+ ash::vk::Format::R16G16_SSCALED => Ok(Self::R16G16_SSCALED),
+ ash::vk::Format::R16G16_UINT => Ok(Self::R16G16_UINT),
+ ash::vk::Format::R16G16_SINT => Ok(Self::R16G16_SINT),
+ ash::vk::Format::R16G16_SFLOAT => Ok(Self::R16G16_SFLOAT),
+ ash::vk::Format::R16G16B16_UNORM => Ok(Self::R16G16B16_UNORM),
+ ash::vk::Format::R16G16B16_SNORM => Ok(Self::R16G16B16_SNORM),
+ ash::vk::Format::R16G16B16_USCALED => Ok(Self::R16G16B16_USCALED),
+ ash::vk::Format::R16G16B16_SSCALED => Ok(Self::R16G16B16_SSCALED),
+ ash::vk::Format::R16G16B16_UINT => Ok(Self::R16G16B16_UINT),
+ ash::vk::Format::R16G16B16_SINT => Ok(Self::R16G16B16_SINT),
+ ash::vk::Format::R16G16B16_SFLOAT => Ok(Self::R16G16B16_SFLOAT),
+ ash::vk::Format::R16G16B16A16_UNORM => Ok(Self::R16G16B16A16_UNORM),
+ ash::vk::Format::R16G16B16A16_SNORM => Ok(Self::R16G16B16A16_SNORM),
+ ash::vk::Format::R16G16B16A16_USCALED => Ok(Self::R16G16B16A16_USCALED),
+ ash::vk::Format::R16G16B16A16_SSCALED => Ok(Self::R16G16B16A16_SSCALED),
+ ash::vk::Format::R16G16B16A16_UINT => Ok(Self::R16G16B16A16_UINT),
+ ash::vk::Format::R16G16B16A16_SINT => Ok(Self::R16G16B16A16_SINT),
+ ash::vk::Format::R16G16B16A16_SFLOAT => Ok(Self::R16G16B16A16_SFLOAT),
+ ash::vk::Format::R32_UINT => Ok(Self::R32_UINT),
+ ash::vk::Format::R32_SINT => Ok(Self::R32_SINT),
+ ash::vk::Format::R32_SFLOAT => Ok(Self::R32_SFLOAT),
+ ash::vk::Format::R32G32_UINT => Ok(Self::R32G32_UINT),
+ ash::vk::Format::R32G32_SINT => Ok(Self::R32G32_SINT),
+ ash::vk::Format::R32G32_SFLOAT => Ok(Self::R32G32_SFLOAT),
+ ash::vk::Format::R32G32B32_UINT => Ok(Self::R32G32B32_UINT),
+ ash::vk::Format::R32G32B32_SINT => Ok(Self::R32G32B32_SINT),
+ ash::vk::Format::R32G32B32_SFLOAT => Ok(Self::R32G32B32_SFLOAT),
+ ash::vk::Format::R32G32B32A32_UINT => Ok(Self::R32G32B32A32_UINT),
+ ash::vk::Format::R32G32B32A32_SINT => Ok(Self::R32G32B32A32_SINT),
+ ash::vk::Format::R32G32B32A32_SFLOAT => Ok(Self::R32G32B32A32_SFLOAT),
+ ash::vk::Format::R64_UINT => Ok(Self::R64_UINT),
+ ash::vk::Format::R64_SINT => Ok(Self::R64_SINT),
+ ash::vk::Format::R64_SFLOAT => Ok(Self::R64_SFLOAT),
+ ash::vk::Format::R64G64_UINT => Ok(Self::R64G64_UINT),
+ ash::vk::Format::R64G64_SINT => Ok(Self::R64G64_SINT),
+ ash::vk::Format::R64G64_SFLOAT => Ok(Self::R64G64_SFLOAT),
+ ash::vk::Format::R64G64B64_UINT => Ok(Self::R64G64B64_UINT),
+ ash::vk::Format::R64G64B64_SINT => Ok(Self::R64G64B64_SINT),
+ ash::vk::Format::R64G64B64_SFLOAT => Ok(Self::R64G64B64_SFLOAT),
+ ash::vk::Format::R64G64B64A64_UINT => Ok(Self::R64G64B64A64_UINT),
+ ash::vk::Format::R64G64B64A64_SINT => Ok(Self::R64G64B64A64_SINT),
+ ash::vk::Format::R64G64B64A64_SFLOAT => Ok(Self::R64G64B64A64_SFLOAT),
+ ash::vk::Format::B10G11R11_UFLOAT_PACK32 => Ok(Self::B10G11R11_UFLOAT_PACK32),
+ ash::vk::Format::E5B9G9R9_UFLOAT_PACK32 => Ok(Self::E5B9G9R9_UFLOAT_PACK32),
+ ash::vk::Format::D16_UNORM => Ok(Self::D16_UNORM),
+ ash::vk::Format::X8_D24_UNORM_PACK32 => Ok(Self::X8_D24_UNORM_PACK32),
+ ash::vk::Format::D32_SFLOAT => Ok(Self::D32_SFLOAT),
+ ash::vk::Format::S8_UINT => Ok(Self::S8_UINT),
+ ash::vk::Format::D16_UNORM_S8_UINT => Ok(Self::D16_UNORM_S8_UINT),
+ ash::vk::Format::D24_UNORM_S8_UINT => Ok(Self::D24_UNORM_S8_UINT),
+ ash::vk::Format::D32_SFLOAT_S8_UINT => Ok(Self::D32_SFLOAT_S8_UINT),
+ ash::vk::Format::BC1_RGB_UNORM_BLOCK => Ok(Self::BC1_RGB_UNORM_BLOCK),
+ ash::vk::Format::BC1_RGB_SRGB_BLOCK => Ok(Self::BC1_RGB_SRGB_BLOCK),
+ ash::vk::Format::BC1_RGBA_UNORM_BLOCK => Ok(Self::BC1_RGBA_UNORM_BLOCK),
+ ash::vk::Format::BC1_RGBA_SRGB_BLOCK => Ok(Self::BC1_RGBA_SRGB_BLOCK),
+ ash::vk::Format::BC2_UNORM_BLOCK => Ok(Self::BC2_UNORM_BLOCK),
+ ash::vk::Format::BC2_SRGB_BLOCK => Ok(Self::BC2_SRGB_BLOCK),
+ ash::vk::Format::BC3_UNORM_BLOCK => Ok(Self::BC3_UNORM_BLOCK),
+ ash::vk::Format::BC3_SRGB_BLOCK => Ok(Self::BC3_SRGB_BLOCK),
+ ash::vk::Format::BC4_UNORM_BLOCK => Ok(Self::BC4_UNORM_BLOCK),
+ ash::vk::Format::BC4_SNORM_BLOCK => Ok(Self::BC4_SNORM_BLOCK),
+ ash::vk::Format::BC5_UNORM_BLOCK => Ok(Self::BC5_UNORM_BLOCK),
+ ash::vk::Format::BC5_SNORM_BLOCK => Ok(Self::BC5_SNORM_BLOCK),
+ ash::vk::Format::BC6H_UFLOAT_BLOCK => Ok(Self::BC6H_UFLOAT_BLOCK),
+ ash::vk::Format::BC6H_SFLOAT_BLOCK => Ok(Self::BC6H_SFLOAT_BLOCK),
+ ash::vk::Format::BC7_UNORM_BLOCK => Ok(Self::BC7_UNORM_BLOCK),
+ ash::vk::Format::BC7_SRGB_BLOCK => Ok(Self::BC7_SRGB_BLOCK),
+ ash::vk::Format::ETC2_R8G8B8_UNORM_BLOCK => Ok(Self::ETC2_R8G8B8_UNORM_BLOCK),
+ ash::vk::Format::ETC2_R8G8B8_SRGB_BLOCK => Ok(Self::ETC2_R8G8B8_SRGB_BLOCK),
+ ash::vk::Format::ETC2_R8G8B8A1_UNORM_BLOCK => Ok(Self::ETC2_R8G8B8A1_UNORM_BLOCK),
+ ash::vk::Format::ETC2_R8G8B8A1_SRGB_BLOCK => Ok(Self::ETC2_R8G8B8A1_SRGB_BLOCK),
+ ash::vk::Format::ETC2_R8G8B8A8_UNORM_BLOCK => Ok(Self::ETC2_R8G8B8A8_UNORM_BLOCK),
+ ash::vk::Format::ETC2_R8G8B8A8_SRGB_BLOCK => Ok(Self::ETC2_R8G8B8A8_SRGB_BLOCK),
+ ash::vk::Format::EAC_R11_UNORM_BLOCK => Ok(Self::EAC_R11_UNORM_BLOCK),
+ ash::vk::Format::EAC_R11_SNORM_BLOCK => Ok(Self::EAC_R11_SNORM_BLOCK),
+ ash::vk::Format::EAC_R11G11_UNORM_BLOCK => Ok(Self::EAC_R11G11_UNORM_BLOCK),
+ ash::vk::Format::EAC_R11G11_SNORM_BLOCK => Ok(Self::EAC_R11G11_SNORM_BLOCK),
+ ash::vk::Format::ASTC_4X4_UNORM_BLOCK => Ok(Self::ASTC_4x4_UNORM_BLOCK),
+ ash::vk::Format::ASTC_4X4_SRGB_BLOCK => Ok(Self::ASTC_4x4_SRGB_BLOCK),
+ ash::vk::Format::ASTC_5X4_UNORM_BLOCK => Ok(Self::ASTC_5x4_UNORM_BLOCK),
+ ash::vk::Format::ASTC_5X4_SRGB_BLOCK => Ok(Self::ASTC_5x4_SRGB_BLOCK),
+ ash::vk::Format::ASTC_5X5_UNORM_BLOCK => Ok(Self::ASTC_5x5_UNORM_BLOCK),
+ ash::vk::Format::ASTC_5X5_SRGB_BLOCK => Ok(Self::ASTC_5x5_SRGB_BLOCK),
+ ash::vk::Format::ASTC_6X5_UNORM_BLOCK => Ok(Self::ASTC_6x5_UNORM_BLOCK),
+ ash::vk::Format::ASTC_6X5_SRGB_BLOCK => Ok(Self::ASTC_6x5_SRGB_BLOCK),
+ ash::vk::Format::ASTC_6X6_UNORM_BLOCK => Ok(Self::ASTC_6x6_UNORM_BLOCK),
+ ash::vk::Format::ASTC_6X6_SRGB_BLOCK => Ok(Self::ASTC_6x6_SRGB_BLOCK),
+ ash::vk::Format::ASTC_8X5_UNORM_BLOCK => Ok(Self::ASTC_8x5_UNORM_BLOCK),
+ ash::vk::Format::ASTC_8X5_SRGB_BLOCK => Ok(Self::ASTC_8x5_SRGB_BLOCK),
+ ash::vk::Format::ASTC_8X6_UNORM_BLOCK => Ok(Self::ASTC_8x6_UNORM_BLOCK),
+ ash::vk::Format::ASTC_8X6_SRGB_BLOCK => Ok(Self::ASTC_8x6_SRGB_BLOCK),
+ ash::vk::Format::ASTC_8X8_UNORM_BLOCK => Ok(Self::ASTC_8x8_UNORM_BLOCK),
+ ash::vk::Format::ASTC_8X8_SRGB_BLOCK => Ok(Self::ASTC_8x8_SRGB_BLOCK),
+ ash::vk::Format::ASTC_10X5_UNORM_BLOCK => Ok(Self::ASTC_10x5_UNORM_BLOCK),
+ ash::vk::Format::ASTC_10X5_SRGB_BLOCK => Ok(Self::ASTC_10x5_SRGB_BLOCK),
+ ash::vk::Format::ASTC_10X6_UNORM_BLOCK => Ok(Self::ASTC_10x6_UNORM_BLOCK),
+ ash::vk::Format::ASTC_10X6_SRGB_BLOCK => Ok(Self::ASTC_10x6_SRGB_BLOCK),
+ ash::vk::Format::ASTC_10X8_UNORM_BLOCK => Ok(Self::ASTC_10x8_UNORM_BLOCK),
+ ash::vk::Format::ASTC_10X8_SRGB_BLOCK => Ok(Self::ASTC_10x8_SRGB_BLOCK),
+ ash::vk::Format::ASTC_10X10_UNORM_BLOCK => Ok(Self::ASTC_10x10_UNORM_BLOCK),
+ ash::vk::Format::ASTC_10X10_SRGB_BLOCK => Ok(Self::ASTC_10x10_SRGB_BLOCK),
+ ash::vk::Format::ASTC_12X10_UNORM_BLOCK => Ok(Self::ASTC_12x10_UNORM_BLOCK),
+ ash::vk::Format::ASTC_12X10_SRGB_BLOCK => Ok(Self::ASTC_12x10_SRGB_BLOCK),
+ ash::vk::Format::ASTC_12X12_UNORM_BLOCK => Ok(Self::ASTC_12x12_UNORM_BLOCK),
+ ash::vk::Format::ASTC_12X12_SRGB_BLOCK => Ok(Self::ASTC_12x12_SRGB_BLOCK),
+ ash::vk::Format::G8B8G8R8_422_UNORM => Ok(Self::G8B8G8R8_422_UNORM),
+ ash::vk::Format::B8G8R8G8_422_UNORM => Ok(Self::B8G8R8G8_422_UNORM),
+ ash::vk::Format::G8_B8_R8_3PLANE_420_UNORM => Ok(Self::G8_B8_R8_3PLANE_420_UNORM),
+ ash::vk::Format::G8_B8R8_2PLANE_420_UNORM => Ok(Self::G8_B8R8_2PLANE_420_UNORM),
+ ash::vk::Format::G8_B8_R8_3PLANE_422_UNORM => Ok(Self::G8_B8_R8_3PLANE_422_UNORM),
+ ash::vk::Format::G8_B8R8_2PLANE_422_UNORM => Ok(Self::G8_B8R8_2PLANE_422_UNORM),
+ ash::vk::Format::G8_B8_R8_3PLANE_444_UNORM => Ok(Self::G8_B8_R8_3PLANE_444_UNORM),
+ ash::vk::Format::R10X6_UNORM_PACK16 => Ok(Self::R10X6_UNORM_PACK16),
+ ash::vk::Format::R10X6G10X6_UNORM_2PACK16 => Ok(Self::R10X6G10X6_UNORM_2PACK16),
+ ash::vk::Format::R10X6G10X6B10X6A10X6_UNORM_4PACK16 => {
+ Ok(Self::R10X6G10X6B10X6A10X6_UNORM_4PACK16)
+ }
+ ash::vk::Format::G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 => {
+ Ok(Self::G10X6B10X6G10X6R10X6_422_UNORM_4PACK16)
+ }
+ ash::vk::Format::B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 => {
+ Ok(Self::B10X6G10X6R10X6G10X6_422_UNORM_4PACK16)
+ }
+ ash::vk::Format::G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 => {
+ Ok(Self::G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16)
+ }
+ ash::vk::Format::G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 => {
+ Ok(Self::G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16)
+ }
+ ash::vk::Format::G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 => {
+ Ok(Self::G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16)
+ }
+ ash::vk::Format::G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 => {
+ Ok(Self::G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16)
+ }
+ ash::vk::Format::G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 => {
+ Ok(Self::G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16)
+ }
+ ash::vk::Format::R12X4_UNORM_PACK16 => Ok(Self::R12X4_UNORM_PACK16),
+ ash::vk::Format::R12X4G12X4_UNORM_2PACK16 => Ok(Self::R12X4G12X4_UNORM_2PACK16),
+ ash::vk::Format::R12X4G12X4B12X4A12X4_UNORM_4PACK16 => {
+ Ok(Self::R12X4G12X4B12X4A12X4_UNORM_4PACK16)
+ }
+ ash::vk::Format::G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 => {
+ Ok(Self::G12X4B12X4G12X4R12X4_422_UNORM_4PACK16)
+ }
+ ash::vk::Format::B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 => {
+ Ok(Self::B12X4G12X4R12X4G12X4_422_UNORM_4PACK16)
+ }
+ ash::vk::Format::G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 => {
+ Ok(Self::G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16)
+ }
+ ash::vk::Format::G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 => {
+ Ok(Self::G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16)
+ }
+ ash::vk::Format::G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 => {
+ Ok(Self::G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16)
+ }
+ ash::vk::Format::G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 => {
+ Ok(Self::G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16)
+ }
+ ash::vk::Format::G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 => {
+ Ok(Self::G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16)
+ }
+ ash::vk::Format::G16B16G16R16_422_UNORM => Ok(Self::G16B16G16R16_422_UNORM),
+ ash::vk::Format::B16G16R16G16_422_UNORM => Ok(Self::B16G16R16G16_422_UNORM),
+ ash::vk::Format::G16_B16_R16_3PLANE_420_UNORM => Ok(Self::G16_B16_R16_3PLANE_420_UNORM),
+ ash::vk::Format::G16_B16R16_2PLANE_420_UNORM => Ok(Self::G16_B16R16_2PLANE_420_UNORM),
+ ash::vk::Format::G16_B16_R16_3PLANE_422_UNORM => Ok(Self::G16_B16_R16_3PLANE_422_UNORM),
+ ash::vk::Format::G16_B16R16_2PLANE_422_UNORM => Ok(Self::G16_B16R16_2PLANE_422_UNORM),
+ ash::vk::Format::G16_B16_R16_3PLANE_444_UNORM => Ok(Self::G16_B16_R16_3PLANE_444_UNORM),
+ ash::vk::Format::PVRTC1_2BPP_UNORM_BLOCK_IMG => Ok(Self::PVRTC1_2BPP_UNORM_BLOCK),
+ ash::vk::Format::PVRTC1_4BPP_UNORM_BLOCK_IMG => Ok(Self::PVRTC1_4BPP_UNORM_BLOCK),
+ ash::vk::Format::PVRTC2_2BPP_UNORM_BLOCK_IMG => Ok(Self::PVRTC2_2BPP_UNORM_BLOCK),
+ ash::vk::Format::PVRTC2_4BPP_UNORM_BLOCK_IMG => Ok(Self::PVRTC2_4BPP_UNORM_BLOCK),
+ ash::vk::Format::PVRTC1_2BPP_SRGB_BLOCK_IMG => Ok(Self::PVRTC1_2BPP_SRGB_BLOCK),
+ ash::vk::Format::PVRTC1_4BPP_SRGB_BLOCK_IMG => Ok(Self::PVRTC1_4BPP_SRGB_BLOCK),
+ ash::vk::Format::PVRTC2_2BPP_SRGB_BLOCK_IMG => Ok(Self::PVRTC2_2BPP_SRGB_BLOCK),
+ ash::vk::Format::PVRTC2_4BPP_SRGB_BLOCK_IMG => Ok(Self::PVRTC2_4BPP_SRGB_BLOCK),
+ ash::vk::Format::ASTC_4X4_SFLOAT_BLOCK => Ok(Self::ASTC_4x4_SFLOAT_BLOCK),
+ ash::vk::Format::ASTC_5X4_SFLOAT_BLOCK => Ok(Self::ASTC_5x4_SFLOAT_BLOCK),
+ ash::vk::Format::ASTC_5X5_SFLOAT_BLOCK => Ok(Self::ASTC_5x5_SFLOAT_BLOCK),
+ ash::vk::Format::ASTC_6X5_SFLOAT_BLOCK => Ok(Self::ASTC_6x5_SFLOAT_BLOCK),
+ ash::vk::Format::ASTC_6X6_SFLOAT_BLOCK => Ok(Self::ASTC_6x6_SFLOAT_BLOCK),
+ ash::vk::Format::ASTC_8X5_SFLOAT_BLOCK => Ok(Self::ASTC_8x5_SFLOAT_BLOCK),
+ ash::vk::Format::ASTC_8X6_SFLOAT_BLOCK => Ok(Self::ASTC_8x6_SFLOAT_BLOCK),
+ ash::vk::Format::ASTC_8X8_SFLOAT_BLOCK => Ok(Self::ASTC_8x8_SFLOAT_BLOCK),
+ ash::vk::Format::ASTC_10X5_SFLOAT_BLOCK => Ok(Self::ASTC_10x5_SFLOAT_BLOCK),
+ ash::vk::Format::ASTC_10X6_SFLOAT_BLOCK => Ok(Self::ASTC_10x6_SFLOAT_BLOCK),
+ ash::vk::Format::ASTC_10X8_SFLOAT_BLOCK => Ok(Self::ASTC_10x8_SFLOAT_BLOCK),
+ ash::vk::Format::ASTC_10X10_SFLOAT_BLOCK => Ok(Self::ASTC_10x10_SFLOAT_BLOCK),
+ ash::vk::Format::ASTC_12X10_SFLOAT_BLOCK => Ok(Self::ASTC_12x10_SFLOAT_BLOCK),
+ ash::vk::Format::ASTC_12X12_SFLOAT_BLOCK => Ok(Self::ASTC_12x12_SFLOAT_BLOCK),
+ ash::vk::Format::G8_B8R8_2PLANE_444_UNORM => Ok(Self::G8_B8R8_2PLANE_444_UNORM),
+ ash::vk::Format::G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16 => {
+ Ok(Self::G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16)
+ }
+ ash::vk::Format::G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16 => {
+ Ok(Self::G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16)
+ }
+ ash::vk::Format::G16_B16R16_2PLANE_444_UNORM => Ok(Self::G16_B16R16_2PLANE_444_UNORM),
+ ash::vk::Format::A4R4G4B4_UNORM_PACK16 => Ok(Self::A4R4G4B4_UNORM_PACK16),
+ ash::vk::Format::A4B4G4R4_UNORM_PACK16 => Ok(Self::A4B4G4R4_UNORM_PACK16),
+ ash::vk::Format::R16G16_S10_5_NV => Ok(Self::R16G16_S10_5_NV),
+ _ => Err(()),
+ }
+ }
+}
+#[doc = r" Converts a format enum identifier to a standard Rust type that is suitable for"]
+#[doc = r" representing the format in a buffer or image."]
+#[doc = r""]
+#[doc = r" This macro returns one possible suitable representation, but there are usually other"]
+#[doc = r" possibilities for a given format. A compile error occurs for formats that have no"]
+#[doc = r" well-defined size (the `size` method returns `None`)."]
+#[doc = r""]
+#[doc = r" - For regular unpacked formats with one component, this returns a single floating point,"]
+#[doc = r" signed or unsigned integer with the appropriate number of bits. For formats with"]
+#[doc = r" multiple components, an array is returned."]
+#[doc = r" - For packed formats, this returns an unsigned integer with the size of the packed"]
+#[doc = r" element. For multi-packed formats (such as `2PACK16`), an array is returned."]
+#[doc = r" - For compressed formats, this returns `[u8; N]` where N is the size of a block."]
+#[doc = r""]
+#[doc = r" Note: for 16-bit floating point values, you need to import the [`half::f16`] type."]
+#[doc = r""]
+#[doc = r" # Examples"]
+#[doc = r""]
+#[doc = r" For arrays:"]
+#[doc = r""]
+#[doc = r" ```"]
+#[doc = r" # use vulkano::type_for_format;"]
+#[doc = r" let pixel: type_for_format!(R32G32B32A32_SFLOAT);"]
+#[doc = r" pixel = [1.0f32, 0.0, 0.0, 1.0];"]
+#[doc = r" ```"]
+#[doc = r""]
+#[doc = r" For [`cgmath`]:"]
+#[doc = r""]
+#[doc = r" ```"]
+#[doc = r" # use vulkano::type_for_format;"]
+#[doc = r" let pixel: type_for_format!(cgmath, R32G32B32A32_SFLOAT);"]
+#[doc = r" pixel = cgmath::Vector4::new(1.0f32, 0.0, 0.0, 1.0);"]
+#[doc = r" ```"]
+#[doc = r""]
+#[doc = r" For [`nalgebra`]:"]
+#[doc = r""]
+#[doc = r" ```"]
+#[doc = r" # use vulkano::type_for_format;"]
+#[doc = r" let pixel: type_for_format!(nalgebra, R32G32B32A32_SFLOAT);"]
+#[doc = r" pixel = nalgebra::vector![1.0f32, 0.0, 0.0, 1.0];"]
+#[doc = r" ```"]
+#[doc = r""]
+#[doc = r" [`cgmath`]: https://crates.io/crates/cgmath"]
+#[doc = r" [`nalgebra`]: https://crates.io/crates/nalgebra"]
+#[macro_export]
+macro_rules ! type_for_format { (R4G4_UNORM_PACK8) => { u8 } ; (R4G4B4A4_UNORM_PACK16) => { u16 } ; (B4G4R4A4_UNORM_PACK16) => { u16 } ; (R5G6B5_UNORM_PACK16) => { u16 } ; (B5G6R5_UNORM_PACK16) => { u16 } ; (R5G5B5A1_UNORM_PACK16) => { u16 } ; (B5G5R5A1_UNORM_PACK16) => { u16 } ; (A1R5G5B5_UNORM_PACK16) => { u16 } ; (R8_UNORM) => { u8 } ; (R8_SNORM) => { i8 } ; (R8_USCALED) => { u8 } ; (R8_SSCALED) => { i8 } ; (R8_UINT) => { u8 } ; (R8_SINT) => { i8 } ; (R8_SRGB) => { u8 } ; (R8G8_UNORM) => { [u8 ; 2] } ; (R8G8_SNORM) => { [i8 ; 2] } ; (R8G8_USCALED) => { [u8 ; 2] } ; (R8G8_SSCALED) => { [i8 ; 2] } ; (R8G8_UINT) => { [u8 ; 2] } ; (R8G8_SINT) => { [i8 ; 2] } ; (R8G8_SRGB) => { [u8 ; 2] } ; (R8G8B8_UNORM) => { [u8 ; 3] } ; (R8G8B8_SNORM) => { [i8 ; 3] } ; (R8G8B8_USCALED) => { [u8 ; 3] } ; (R8G8B8_SSCALED) => { [i8 ; 3] } ; (R8G8B8_UINT) => { [u8 ; 3] } ; (R8G8B8_SINT) => { [i8 ; 3] } ; (R8G8B8_SRGB) => { [u8 ; 3] } ; (B8G8R8_UNORM) => { [u8 ; 3] } ; (B8G8R8_SNORM) => { [i8 ; 3] } ; (B8G8R8_USCALED) => { [u8 ; 3] } ; (B8G8R8_SSCALED) => { [i8 ; 3] } ; (B8G8R8_UINT) => { [u8 ; 3] } ; (B8G8R8_SINT) => { [i8 ; 3] } ; (B8G8R8_SRGB) => { [u8 ; 3] } ; (R8G8B8A8_UNORM) => { [u8 ; 4] } ; (R8G8B8A8_SNORM) => { [i8 ; 4] } ; (R8G8B8A8_USCALED) => { [u8 ; 4] } ; (R8G8B8A8_SSCALED) => { [i8 ; 4] } ; (R8G8B8A8_UINT) => { [u8 ; 4] } ; (R8G8B8A8_SINT) => { [i8 ; 4] } ; (R8G8B8A8_SRGB) => { [u8 ; 4] } ; (B8G8R8A8_UNORM) => { [u8 ; 4] } ; (B8G8R8A8_SNORM) => { [i8 ; 4] } ; (B8G8R8A8_USCALED) => { [u8 ; 4] } ; (B8G8R8A8_SSCALED) => { [i8 ; 4] } ; (B8G8R8A8_UINT) => { [u8 ; 4] } ; (B8G8R8A8_SINT) => { [i8 ; 4] } ; (B8G8R8A8_SRGB) => { [u8 ; 4] } ; (A8B8G8R8_UNORM_PACK32) => { u32 } ; (A8B8G8R8_SNORM_PACK32) => { u32 } ; (A8B8G8R8_USCALED_PACK32) => { u32 } ; (A8B8G8R8_SSCALED_PACK32) => { u32 } ; (A8B8G8R8_UINT_PACK32) => { u32 } ; (A8B8G8R8_SINT_PACK32) => { u32 } ; (A8B8G8R8_SRGB_PACK32) => { u32 } ; (A2R10G10B10_UNORM_PACK32) => { u32 } ; (A2R10G10B10_SNORM_PACK32) => { u32 } ; (A2R10G10B10_USCALED_PACK32) => { u32 } ; (A2R10G10B10_SSCALED_PACK32) => { u32 } ; (A2R10G10B10_UINT_PACK32) => { u32 } ; (A2R10G10B10_SINT_PACK32) => { u32 } ; (A2B10G10R10_UNORM_PACK32) => { u32 } ; (A2B10G10R10_SNORM_PACK32) => { u32 } ; (A2B10G10R10_USCALED_PACK32) => { u32 } ; (A2B10G10R10_SSCALED_PACK32) => { u32 } ; (A2B10G10R10_UINT_PACK32) => { u32 } ; (A2B10G10R10_SINT_PACK32) => { u32 } ; (R16_UNORM) => { u16 } ; (R16_SNORM) => { i16 } ; (R16_USCALED) => { u16 } ; (R16_SSCALED) => { i16 } ; (R16_UINT) => { u16 } ; (R16_SINT) => { i16 } ; (R16_SFLOAT) => { f16 } ; (R16G16_UNORM) => { [u16 ; 2] } ; (R16G16_SNORM) => { [i16 ; 2] } ; (R16G16_USCALED) => { [u16 ; 2] } ; (R16G16_SSCALED) => { [i16 ; 2] } ; (R16G16_UINT) => { [u16 ; 2] } ; (R16G16_SINT) => { [i16 ; 2] } ; (R16G16_SFLOAT) => { [f16 ; 2] } ; (R16G16B16_UNORM) => { [u16 ; 3] } ; (R16G16B16_SNORM) => { [i16 ; 3] } ; (R16G16B16_USCALED) => { [u16 ; 3] } ; (R16G16B16_SSCALED) => { [i16 ; 3] } ; (R16G16B16_UINT) => { [u16 ; 3] } ; (R16G16B16_SINT) => { [i16 ; 3] } ; (R16G16B16_SFLOAT) => { [f16 ; 3] } ; (R16G16B16A16_UNORM) => { [u16 ; 4] } ; (R16G16B16A16_SNORM) => { [i16 ; 4] } ; (R16G16B16A16_USCALED) => { [u16 ; 4] } ; (R16G16B16A16_SSCALED) => { [i16 ; 4] } ; (R16G16B16A16_UINT) => { [u16 ; 4] } ; (R16G16B16A16_SINT) => { [i16 ; 4] } ; (R16G16B16A16_SFLOAT) => { [f16 ; 4] } ; (R32_UINT) => { u32 } ; (R32_SINT) => { i32 } ; (R32_SFLOAT) => { f32 } ; (R32G32_UINT) => { [u32 ; 2] } ; (R32G32_SINT) => { [i32 ; 2] } ; (R32G32_SFLOAT) => { [f32 ; 2] } ; (R32G32B32_UINT) => { [u32 ; 3] } ; (R32G32B32_SINT) => { [i32 ; 3] } ; (R32G32B32_SFLOAT) => { [f32 ; 3] } ; (R32G32B32A32_UINT) => { [u32 ; 4] } ; (R32G32B32A32_SINT) => { [i32 ; 4] } ; (R32G32B32A32_SFLOAT) => { [f32 ; 4] } ; (R64_UINT) => { u64 } ; (R64_SINT) => { i64 } ; (R64_SFLOAT) => { f64 } ; (R64G64_UINT) => { [u64 ; 2] } ; (R64G64_SINT) => { [i64 ; 2] } ; (R64G64_SFLOAT) => { [f64 ; 2] } ; (R64G64B64_UINT) => { [u64 ; 3] } ; (R64G64B64_SINT) => { [i64 ; 3] } ; (R64G64B64_SFLOAT) => { [f64 ; 3] } ; (R64G64B64A64_UINT) => { [u64 ; 4] } ; (R64G64B64A64_SINT) => { [i64 ; 4] } ; (R64G64B64A64_SFLOAT) => { [f64 ; 4] } ; (B10G11R11_UFLOAT_PACK32) => { u32 } ; (E5B9G9R9_UFLOAT_PACK32) => { u32 } ; (BC1_RGB_UNORM_BLOCK) => { [u8 ; 8] } ; (BC1_RGB_SRGB_BLOCK) => { [u8 ; 8] } ; (BC1_RGBA_UNORM_BLOCK) => { [u8 ; 8] } ; (BC1_RGBA_SRGB_BLOCK) => { [u8 ; 8] } ; (BC2_UNORM_BLOCK) => { [u8 ; 16] } ; (BC2_SRGB_BLOCK) => { [u8 ; 16] } ; (BC3_UNORM_BLOCK) => { [u8 ; 16] } ; (BC3_SRGB_BLOCK) => { [u8 ; 16] } ; (BC4_UNORM_BLOCK) => { [u8 ; 8] } ; (BC4_SNORM_BLOCK) => { [u8 ; 8] } ; (BC5_UNORM_BLOCK) => { [u8 ; 16] } ; (BC5_SNORM_BLOCK) => { [u8 ; 16] } ; (BC6H_UFLOAT_BLOCK) => { [u8 ; 16] } ; (BC6H_SFLOAT_BLOCK) => { [u8 ; 16] } ; (BC7_UNORM_BLOCK) => { [u8 ; 16] } ; (BC7_SRGB_BLOCK) => { [u8 ; 16] } ; (ETC2_R8G8B8_UNORM_BLOCK) => { [u8 ; 8] } ; (ETC2_R8G8B8_SRGB_BLOCK) => { [u8 ; 8] } ; (ETC2_R8G8B8A1_UNORM_BLOCK) => { [u8 ; 8] } ; (ETC2_R8G8B8A1_SRGB_BLOCK) => { [u8 ; 8] } ; (ETC2_R8G8B8A8_UNORM_BLOCK) => { [u8 ; 16] } ; (ETC2_R8G8B8A8_SRGB_BLOCK) => { [u8 ; 16] } ; (EAC_R11_UNORM_BLOCK) => { [u8 ; 8] } ; (EAC_R11_SNORM_BLOCK) => { [u8 ; 8] } ; (EAC_R11G11_UNORM_BLOCK) => { [u8 ; 16] } ; (EAC_R11G11_SNORM_BLOCK) => { [u8 ; 16] } ; (ASTC_4x4_UNORM_BLOCK) => { [u8 ; 16] } ; (ASTC_4x4_SRGB_BLOCK) => { [u8 ; 16] } ; (ASTC_5x4_UNORM_BLOCK) => { [u8 ; 16] } ; (ASTC_5x4_SRGB_BLOCK) => { [u8 ; 16] } ; (ASTC_5x5_UNORM_BLOCK) => { [u8 ; 16] } ; (ASTC_5x5_SRGB_BLOCK) => { [u8 ; 16] } ; (ASTC_6x5_UNORM_BLOCK) => { [u8 ; 16] } ; (ASTC_6x5_SRGB_BLOCK) => { [u8 ; 16] } ; (ASTC_6x6_UNORM_BLOCK) => { [u8 ; 16] } ; (ASTC_6x6_SRGB_BLOCK) => { [u8 ; 16] } ; (ASTC_8x5_UNORM_BLOCK) => { [u8 ; 16] } ; (ASTC_8x5_SRGB_BLOCK) => { [u8 ; 16] } ; (ASTC_8x6_UNORM_BLOCK) => { [u8 ; 16] } ; (ASTC_8x6_SRGB_BLOCK) => { [u8 ; 16] } ; (ASTC_8x8_UNORM_BLOCK) => { [u8 ; 16] } ; (ASTC_8x8_SRGB_BLOCK) => { [u8 ; 16] } ; (ASTC_10x5_UNORM_BLOCK) => { [u8 ; 16] } ; (ASTC_10x5_SRGB_BLOCK) => { [u8 ; 16] } ; (ASTC_10x6_UNORM_BLOCK) => { [u8 ; 16] } ; (ASTC_10x6_SRGB_BLOCK) => { [u8 ; 16] } ; (ASTC_10x8_UNORM_BLOCK) => { [u8 ; 16] } ; (ASTC_10x8_SRGB_BLOCK) => { [u8 ; 16] } ; (ASTC_10x10_UNORM_BLOCK) => { [u8 ; 16] } ; (ASTC_10x10_SRGB_BLOCK) => { [u8 ; 16] } ; (ASTC_12x10_UNORM_BLOCK) => { [u8 ; 16] } ; (ASTC_12x10_SRGB_BLOCK) => { [u8 ; 16] } ; (ASTC_12x12_UNORM_BLOCK) => { [u8 ; 16] } ; (ASTC_12x12_SRGB_BLOCK) => { [u8 ; 16] } ; (G8B8G8R8_422_UNORM) => { [u8 ; 4] } ; (B8G8R8G8_422_UNORM) => { [u8 ; 4] } ; (R10X6_UNORM_PACK16) => { u16 } ; (R10X6G10X6_UNORM_2PACK16) => { [u16 ; 2] } ; (R10X6G10X6B10X6A10X6_UNORM_4PACK16) => { [u16 ; 4] } ; (G10X6B10X6G10X6R10X6_422_UNORM_4PACK16) => { [u16 ; 4] } ; (B10X6G10X6R10X6G10X6_422_UNORM_4PACK16) => { [u16 ; 4] } ; (R12X4_UNORM_PACK16) => { u16 } ; (R12X4G12X4_UNORM_2PACK16) => { [u16 ; 2] } ; (R12X4G12X4B12X4A12X4_UNORM_4PACK16) => { [u16 ; 4] } ; (G12X4B12X4G12X4R12X4_422_UNORM_4PACK16) => { [u16 ; 4] } ; (B12X4G12X4R12X4G12X4_422_UNORM_4PACK16) => { [u16 ; 4] } ; (G16B16G16R16_422_UNORM) => { [u16 ; 4] } ; (B16G16R16G16_422_UNORM) => { [u16 ; 4] } ; (PVRTC1_2BPP_UNORM_BLOCK) => { [u8 ; 8] } ; (PVRTC1_4BPP_UNORM_BLOCK) => { [u8 ; 8] } ; (PVRTC2_2BPP_UNORM_BLOCK) => { [u8 ; 8] } ; (PVRTC2_4BPP_UNORM_BLOCK) => { [u8 ; 8] } ; (PVRTC1_2BPP_SRGB_BLOCK) => { [u8 ; 8] } ; (PVRTC1_4BPP_SRGB_BLOCK) => { [u8 ; 8] } ; (PVRTC2_2BPP_SRGB_BLOCK) => { [u8 ; 8] } ; (PVRTC2_4BPP_SRGB_BLOCK) => { [u8 ; 8] } ; (ASTC_4x4_SFLOAT_BLOCK) => { [u8 ; 16] } ; (ASTC_5x4_SFLOAT_BLOCK) => { [u8 ; 16] } ; (ASTC_5x5_SFLOAT_BLOCK) => { [u8 ; 16] } ; (ASTC_6x5_SFLOAT_BLOCK) => { [u8 ; 16] } ; (ASTC_6x6_SFLOAT_BLOCK) => { [u8 ; 16] } ; (ASTC_8x5_SFLOAT_BLOCK) => { [u8 ; 16] } ; (ASTC_8x6_SFLOAT_BLOCK) => { [u8 ; 16] } ; (ASTC_8x8_SFLOAT_BLOCK) => { [u8 ; 16] } ; (ASTC_10x5_SFLOAT_BLOCK) => { [u8 ; 16] } ; (ASTC_10x6_SFLOAT_BLOCK) => { [u8 ; 16] } ; (ASTC_10x8_SFLOAT_BLOCK) => { [u8 ; 16] } ; (ASTC_10x10_SFLOAT_BLOCK) => { [u8 ; 16] } ; (ASTC_12x10_SFLOAT_BLOCK) => { [u8 ; 16] } ; (ASTC_12x12_SFLOAT_BLOCK) => { [u8 ; 16] } ; (A4R4G4B4_UNORM_PACK16) => { u16 } ; (A4B4G4R4_UNORM_PACK16) => { u16 } ; (R16G16_S10_5_NV) => { [i16 ; 2] } ; (cgmath , R4G4_UNORM_PACK8) => { u8 } ; (cgmath , R4G4B4A4_UNORM_PACK16) => { u16 } ; (cgmath , B4G4R4A4_UNORM_PACK16) => { u16 } ; (cgmath , R5G6B5_UNORM_PACK16) => { u16 } ; (cgmath , B5G6R5_UNORM_PACK16) => { u16 } ; (cgmath , R5G5B5A1_UNORM_PACK16) => { u16 } ; (cgmath , B5G5R5A1_UNORM_PACK16) => { u16 } ; (cgmath , A1R5G5B5_UNORM_PACK16) => { u16 } ; (cgmath , R8_UNORM) => { u8 } ; (cgmath , R8_SNORM) => { i8 } ; (cgmath , R8_USCALED) => { u8 } ; (cgmath , R8_SSCALED) => { i8 } ; (cgmath , R8_UINT) => { u8 } ; (cgmath , R8_SINT) => { i8 } ; (cgmath , R8_SRGB) => { u8 } ; (cgmath , R8G8_UNORM) => { cgmath :: Vector2 < u8 > } ; (cgmath , R8G8_SNORM) => { cgmath :: Vector2 < i8 > } ; (cgmath , R8G8_USCALED) => { cgmath :: Vector2 < u8 > } ; (cgmath , R8G8_SSCALED) => { cgmath :: Vector2 < i8 > } ; (cgmath , R8G8_UINT) => { cgmath :: Vector2 < u8 > } ; (cgmath , R8G8_SINT) => { cgmath :: Vector2 < i8 > } ; (cgmath , R8G8_SRGB) => { cgmath :: Vector2 < u8 > } ; (cgmath , R8G8B8_UNORM) => { cgmath :: Vector3 < u8 > } ; (cgmath , R8G8B8_SNORM) => { cgmath :: Vector3 < i8 > } ; (cgmath , R8G8B8_USCALED) => { cgmath :: Vector3 < u8 > } ; (cgmath , R8G8B8_SSCALED) => { cgmath :: Vector3 < i8 > } ; (cgmath , R8G8B8_UINT) => { cgmath :: Vector3 < u8 > } ; (cgmath , R8G8B8_SINT) => { cgmath :: Vector3 < i8 > } ; (cgmath , R8G8B8_SRGB) => { cgmath :: Vector3 < u8 > } ; (cgmath , B8G8R8_UNORM) => { cgmath :: Vector3 < u8 > } ; (cgmath , B8G8R8_SNORM) => { cgmath :: Vector3 < i8 > } ; (cgmath , B8G8R8_USCALED) => { cgmath :: Vector3 < u8 > } ; (cgmath , B8G8R8_SSCALED) => { cgmath :: Vector3 < i8 > } ; (cgmath , B8G8R8_UINT) => { cgmath :: Vector3 < u8 > } ; (cgmath , B8G8R8_SINT) => { cgmath :: Vector3 < i8 > } ; (cgmath , B8G8R8_SRGB) => { cgmath :: Vector3 < u8 > } ; (cgmath , R8G8B8A8_UNORM) => { cgmath :: Vector4 < u8 > } ; (cgmath , R8G8B8A8_SNORM) => { cgmath :: Vector4 < i8 > } ; (cgmath , R8G8B8A8_USCALED) => { cgmath :: Vector4 < u8 > } ; (cgmath , R8G8B8A8_SSCALED) => { cgmath :: Vector4 < i8 > } ; (cgmath , R8G8B8A8_UINT) => { cgmath :: Vector4 < u8 > } ; (cgmath , R8G8B8A8_SINT) => { cgmath :: Vector4 < i8 > } ; (cgmath , R8G8B8A8_SRGB) => { cgmath :: Vector4 < u8 > } ; (cgmath , B8G8R8A8_UNORM) => { cgmath :: Vector4 < u8 > } ; (cgmath , B8G8R8A8_SNORM) => { cgmath :: Vector4 < i8 > } ; (cgmath , B8G8R8A8_USCALED) => { cgmath :: Vector4 < u8 > } ; (cgmath , B8G8R8A8_SSCALED) => { cgmath :: Vector4 < i8 > } ; (cgmath , B8G8R8A8_UINT) => { cgmath :: Vector4 < u8 > } ; (cgmath , B8G8R8A8_SINT) => { cgmath :: Vector4 < i8 > } ; (cgmath , B8G8R8A8_SRGB) => { cgmath :: Vector4 < u8 > } ; (cgmath , A8B8G8R8_UNORM_PACK32) => { u32 } ; (cgmath , A8B8G8R8_SNORM_PACK32) => { u32 } ; (cgmath , A8B8G8R8_USCALED_PACK32) => { u32 } ; (cgmath , A8B8G8R8_SSCALED_PACK32) => { u32 } ; (cgmath , A8B8G8R8_UINT_PACK32) => { u32 } ; (cgmath , A8B8G8R8_SINT_PACK32) => { u32 } ; (cgmath , A8B8G8R8_SRGB_PACK32) => { u32 } ; (cgmath , A2R10G10B10_UNORM_PACK32) => { u32 } ; (cgmath , A2R10G10B10_SNORM_PACK32) => { u32 } ; (cgmath , A2R10G10B10_USCALED_PACK32) => { u32 } ; (cgmath , A2R10G10B10_SSCALED_PACK32) => { u32 } ; (cgmath , A2R10G10B10_UINT_PACK32) => { u32 } ; (cgmath , A2R10G10B10_SINT_PACK32) => { u32 } ; (cgmath , A2B10G10R10_UNORM_PACK32) => { u32 } ; (cgmath , A2B10G10R10_SNORM_PACK32) => { u32 } ; (cgmath , A2B10G10R10_USCALED_PACK32) => { u32 } ; (cgmath , A2B10G10R10_SSCALED_PACK32) => { u32 } ; (cgmath , A2B10G10R10_UINT_PACK32) => { u32 } ; (cgmath , A2B10G10R10_SINT_PACK32) => { u32 } ; (cgmath , R16_UNORM) => { u16 } ; (cgmath , R16_SNORM) => { i16 } ; (cgmath , R16_USCALED) => { u16 } ; (cgmath , R16_SSCALED) => { i16 } ; (cgmath , R16_UINT) => { u16 } ; (cgmath , R16_SINT) => { i16 } ; (cgmath , R16_SFLOAT) => { f16 } ; (cgmath , R16G16_UNORM) => { cgmath :: Vector2 < u16 > } ; (cgmath , R16G16_SNORM) => { cgmath :: Vector2 < i16 > } ; (cgmath , R16G16_USCALED) => { cgmath :: Vector2 < u16 > } ; (cgmath , R16G16_SSCALED) => { cgmath :: Vector2 < i16 > } ; (cgmath , R16G16_UINT) => { cgmath :: Vector2 < u16 > } ; (cgmath , R16G16_SINT) => { cgmath :: Vector2 < i16 > } ; (cgmath , R16G16_SFLOAT) => { cgmath :: Vector2 < f16 > } ; (cgmath , R16G16B16_UNORM) => { cgmath :: Vector3 < u16 > } ; (cgmath , R16G16B16_SNORM) => { cgmath :: Vector3 < i16 > } ; (cgmath , R16G16B16_USCALED) => { cgmath :: Vector3 < u16 > } ; (cgmath , R16G16B16_SSCALED) => { cgmath :: Vector3 < i16 > } ; (cgmath , R16G16B16_UINT) => { cgmath :: Vector3 < u16 > } ; (cgmath , R16G16B16_SINT) => { cgmath :: Vector3 < i16 > } ; (cgmath , R16G16B16_SFLOAT) => { cgmath :: Vector3 < f16 > } ; (cgmath , R16G16B16A16_UNORM) => { cgmath :: Vector4 < u16 > } ; (cgmath , R16G16B16A16_SNORM) => { cgmath :: Vector4 < i16 > } ; (cgmath , R16G16B16A16_USCALED) => { cgmath :: Vector4 < u16 > } ; (cgmath , R16G16B16A16_SSCALED) => { cgmath :: Vector4 < i16 > } ; (cgmath , R16G16B16A16_UINT) => { cgmath :: Vector4 < u16 > } ; (cgmath , R16G16B16A16_SINT) => { cgmath :: Vector4 < i16 > } ; (cgmath , R16G16B16A16_SFLOAT) => { cgmath :: Vector4 < f16 > } ; (cgmath , R32_UINT) => { u32 } ; (cgmath , R32_SINT) => { i32 } ; (cgmath , R32_SFLOAT) => { f32 } ; (cgmath , R32G32_UINT) => { cgmath :: Vector2 < u32 > } ; (cgmath , R32G32_SINT) => { cgmath :: Vector2 < i32 > } ; (cgmath , R32G32_SFLOAT) => { cgmath :: Vector2 < f32 > } ; (cgmath , R32G32B32_UINT) => { cgmath :: Vector3 < u32 > } ; (cgmath , R32G32B32_SINT) => { cgmath :: Vector3 < i32 > } ; (cgmath , R32G32B32_SFLOAT) => { cgmath :: Vector3 < f32 > } ; (cgmath , R32G32B32A32_UINT) => { cgmath :: Vector4 < u32 > } ; (cgmath , R32G32B32A32_SINT) => { cgmath :: Vector4 < i32 > } ; (cgmath , R32G32B32A32_SFLOAT) => { cgmath :: Vector4 < f32 > } ; (cgmath , R64_UINT) => { u64 } ; (cgmath , R64_SINT) => { i64 } ; (cgmath , R64_SFLOAT) => { f64 } ; (cgmath , R64G64_UINT) => { cgmath :: Vector2 < u64 > } ; (cgmath , R64G64_SINT) => { cgmath :: Vector2 < i64 > } ; (cgmath , R64G64_SFLOAT) => { cgmath :: Vector2 < f64 > } ; (cgmath , R64G64B64_UINT) => { cgmath :: Vector3 < u64 > } ; (cgmath , R64G64B64_SINT) => { cgmath :: Vector3 < i64 > } ; (cgmath , R64G64B64_SFLOAT) => { cgmath :: Vector3 < f64 > } ; (cgmath , R64G64B64A64_UINT) => { cgmath :: Vector4 < u64 > } ; (cgmath , R64G64B64A64_SINT) => { cgmath :: Vector4 < i64 > } ; (cgmath , R64G64B64A64_SFLOAT) => { cgmath :: Vector4 < f64 > } ; (cgmath , B10G11R11_UFLOAT_PACK32) => { u32 } ; (cgmath , E5B9G9R9_UFLOAT_PACK32) => { u32 } ; (cgmath , BC1_RGB_UNORM_BLOCK) => { [u8 ; 8] } ; (cgmath , BC1_RGB_SRGB_BLOCK) => { [u8 ; 8] } ; (cgmath , BC1_RGBA_UNORM_BLOCK) => { [u8 ; 8] } ; (cgmath , BC1_RGBA_SRGB_BLOCK) => { [u8 ; 8] } ; (cgmath , BC2_UNORM_BLOCK) => { [u8 ; 16] } ; (cgmath , BC2_SRGB_BLOCK) => { [u8 ; 16] } ; (cgmath , BC3_UNORM_BLOCK) => { [u8 ; 16] } ; (cgmath , BC3_SRGB_BLOCK) => { [u8 ; 16] } ; (cgmath , BC4_UNORM_BLOCK) => { [u8 ; 8] } ; (cgmath , BC4_SNORM_BLOCK) => { [u8 ; 8] } ; (cgmath , BC5_UNORM_BLOCK) => { [u8 ; 16] } ; (cgmath , BC5_SNORM_BLOCK) => { [u8 ; 16] } ; (cgmath , BC6H_UFLOAT_BLOCK) => { [u8 ; 16] } ; (cgmath , BC6H_SFLOAT_BLOCK) => { [u8 ; 16] } ; (cgmath , BC7_UNORM_BLOCK) => { [u8 ; 16] } ; (cgmath , BC7_SRGB_BLOCK) => { [u8 ; 16] } ; (cgmath , ETC2_R8G8B8_UNORM_BLOCK) => { [u8 ; 8] } ; (cgmath , ETC2_R8G8B8_SRGB_BLOCK) => { [u8 ; 8] } ; (cgmath , ETC2_R8G8B8A1_UNORM_BLOCK) => { [u8 ; 8] } ; (cgmath , ETC2_R8G8B8A1_SRGB_BLOCK) => { [u8 ; 8] } ; (cgmath , ETC2_R8G8B8A8_UNORM_BLOCK) => { [u8 ; 16] } ; (cgmath , ETC2_R8G8B8A8_SRGB_BLOCK) => { [u8 ; 16] } ; (cgmath , EAC_R11_UNORM_BLOCK) => { [u8 ; 8] } ; (cgmath , EAC_R11_SNORM_BLOCK) => { [u8 ; 8] } ; (cgmath , EAC_R11G11_UNORM_BLOCK) => { [u8 ; 16] } ; (cgmath , EAC_R11G11_SNORM_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_4x4_UNORM_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_4x4_SRGB_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_5x4_UNORM_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_5x4_SRGB_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_5x5_UNORM_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_5x5_SRGB_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_6x5_UNORM_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_6x5_SRGB_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_6x6_UNORM_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_6x6_SRGB_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_8x5_UNORM_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_8x5_SRGB_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_8x6_UNORM_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_8x6_SRGB_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_8x8_UNORM_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_8x8_SRGB_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_10x5_UNORM_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_10x5_SRGB_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_10x6_UNORM_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_10x6_SRGB_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_10x8_UNORM_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_10x8_SRGB_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_10x10_UNORM_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_10x10_SRGB_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_12x10_UNORM_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_12x10_SRGB_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_12x12_UNORM_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_12x12_SRGB_BLOCK) => { [u8 ; 16] } ; (cgmath , G8B8G8R8_422_UNORM) => { cgmath :: Vector4 < u8 > } ; (cgmath , B8G8R8G8_422_UNORM) => { cgmath :: Vector4 < u8 > } ; (cgmath , R10X6_UNORM_PACK16) => { u16 } ; (cgmath , R10X6G10X6_UNORM_2PACK16) => { [u16 ; 2] } ; (cgmath , R10X6G10X6B10X6A10X6_UNORM_4PACK16) => { [u16 ; 4] } ; (cgmath , G10X6B10X6G10X6R10X6_422_UNORM_4PACK16) => { [u16 ; 4] } ; (cgmath , B10X6G10X6R10X6G10X6_422_UNORM_4PACK16) => { [u16 ; 4] } ; (cgmath , R12X4_UNORM_PACK16) => { u16 } ; (cgmath , R12X4G12X4_UNORM_2PACK16) => { [u16 ; 2] } ; (cgmath , R12X4G12X4B12X4A12X4_UNORM_4PACK16) => { [u16 ; 4] } ; (cgmath , G12X4B12X4G12X4R12X4_422_UNORM_4PACK16) => { [u16 ; 4] } ; (cgmath , B12X4G12X4R12X4G12X4_422_UNORM_4PACK16) => { [u16 ; 4] } ; (cgmath , G16B16G16R16_422_UNORM) => { cgmath :: Vector4 < u16 > } ; (cgmath , B16G16R16G16_422_UNORM) => { cgmath :: Vector4 < u16 > } ; (cgmath , PVRTC1_2BPP_UNORM_BLOCK) => { [u8 ; 8] } ; (cgmath , PVRTC1_4BPP_UNORM_BLOCK) => { [u8 ; 8] } ; (cgmath , PVRTC2_2BPP_UNORM_BLOCK) => { [u8 ; 8] } ; (cgmath , PVRTC2_4BPP_UNORM_BLOCK) => { [u8 ; 8] } ; (cgmath , PVRTC1_2BPP_SRGB_BLOCK) => { [u8 ; 8] } ; (cgmath , PVRTC1_4BPP_SRGB_BLOCK) => { [u8 ; 8] } ; (cgmath , PVRTC2_2BPP_SRGB_BLOCK) => { [u8 ; 8] } ; (cgmath , PVRTC2_4BPP_SRGB_BLOCK) => { [u8 ; 8] } ; (cgmath , ASTC_4x4_SFLOAT_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_5x4_SFLOAT_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_5x5_SFLOAT_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_6x5_SFLOAT_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_6x6_SFLOAT_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_8x5_SFLOAT_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_8x6_SFLOAT_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_8x8_SFLOAT_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_10x5_SFLOAT_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_10x6_SFLOAT_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_10x8_SFLOAT_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_10x10_SFLOAT_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_12x10_SFLOAT_BLOCK) => { [u8 ; 16] } ; (cgmath , ASTC_12x12_SFLOAT_BLOCK) => { [u8 ; 16] } ; (cgmath , A4R4G4B4_UNORM_PACK16) => { u16 } ; (cgmath , A4B4G4R4_UNORM_PACK16) => { u16 } ; (cgmath , R16G16_S10_5_NV) => { cgmath :: Vector2 < i16 > } ; (nalgebra , R4G4_UNORM_PACK8) => { u8 } ; (nalgebra , R4G4B4A4_UNORM_PACK16) => { u16 } ; (nalgebra , B4G4R4A4_UNORM_PACK16) => { u16 } ; (nalgebra , R5G6B5_UNORM_PACK16) => { u16 } ; (nalgebra , B5G6R5_UNORM_PACK16) => { u16 } ; (nalgebra , R5G5B5A1_UNORM_PACK16) => { u16 } ; (nalgebra , B5G5R5A1_UNORM_PACK16) => { u16 } ; (nalgebra , A1R5G5B5_UNORM_PACK16) => { u16 } ; (nalgebra , R8_UNORM) => { u8 } ; (nalgebra , R8_SNORM) => { i8 } ; (nalgebra , R8_USCALED) => { u8 } ; (nalgebra , R8_SSCALED) => { i8 } ; (nalgebra , R8_UINT) => { u8 } ; (nalgebra , R8_SINT) => { i8 } ; (nalgebra , R8_SRGB) => { u8 } ; (nalgebra , R8G8_UNORM) => { nalgebra :: base :: SVector < u8 , 2usize > } ; (nalgebra , R8G8_SNORM) => { nalgebra :: base :: SVector < i8 , 2usize > } ; (nalgebra , R8G8_USCALED) => { nalgebra :: base :: SVector < u8 , 2usize > } ; (nalgebra , R8G8_SSCALED) => { nalgebra :: base :: SVector < i8 , 2usize > } ; (nalgebra , R8G8_UINT) => { nalgebra :: base :: SVector < u8 , 2usize > } ; (nalgebra , R8G8_SINT) => { nalgebra :: base :: SVector < i8 , 2usize > } ; (nalgebra , R8G8_SRGB) => { nalgebra :: base :: SVector < u8 , 2usize > } ; (nalgebra , R8G8B8_UNORM) => { nalgebra :: base :: SVector < u8 , 3usize > } ; (nalgebra , R8G8B8_SNORM) => { nalgebra :: base :: SVector < i8 , 3usize > } ; (nalgebra , R8G8B8_USCALED) => { nalgebra :: base :: SVector < u8 , 3usize > } ; (nalgebra , R8G8B8_SSCALED) => { nalgebra :: base :: SVector < i8 , 3usize > } ; (nalgebra , R8G8B8_UINT) => { nalgebra :: base :: SVector < u8 , 3usize > } ; (nalgebra , R8G8B8_SINT) => { nalgebra :: base :: SVector < i8 , 3usize > } ; (nalgebra , R8G8B8_SRGB) => { nalgebra :: base :: SVector < u8 , 3usize > } ; (nalgebra , B8G8R8_UNORM) => { nalgebra :: base :: SVector < u8 , 3usize > } ; (nalgebra , B8G8R8_SNORM) => { nalgebra :: base :: SVector < i8 , 3usize > } ; (nalgebra , B8G8R8_USCALED) => { nalgebra :: base :: SVector < u8 , 3usize > } ; (nalgebra , B8G8R8_SSCALED) => { nalgebra :: base :: SVector < i8 , 3usize > } ; (nalgebra , B8G8R8_UINT) => { nalgebra :: base :: SVector < u8 , 3usize > } ; (nalgebra , B8G8R8_SINT) => { nalgebra :: base :: SVector < i8 , 3usize > } ; (nalgebra , B8G8R8_SRGB) => { nalgebra :: base :: SVector < u8 , 3usize > } ; (nalgebra , R8G8B8A8_UNORM) => { nalgebra :: base :: SVector < u8 , 4usize > } ; (nalgebra , R8G8B8A8_SNORM) => { nalgebra :: base :: SVector < i8 , 4usize > } ; (nalgebra , R8G8B8A8_USCALED) => { nalgebra :: base :: SVector < u8 , 4usize > } ; (nalgebra , R8G8B8A8_SSCALED) => { nalgebra :: base :: SVector < i8 , 4usize > } ; (nalgebra , R8G8B8A8_UINT) => { nalgebra :: base :: SVector < u8 , 4usize > } ; (nalgebra , R8G8B8A8_SINT) => { nalgebra :: base :: SVector < i8 , 4usize > } ; (nalgebra , R8G8B8A8_SRGB) => { nalgebra :: base :: SVector < u8 , 4usize > } ; (nalgebra , B8G8R8A8_UNORM) => { nalgebra :: base :: SVector < u8 , 4usize > } ; (nalgebra , B8G8R8A8_SNORM) => { nalgebra :: base :: SVector < i8 , 4usize > } ; (nalgebra , B8G8R8A8_USCALED) => { nalgebra :: base :: SVector < u8 , 4usize > } ; (nalgebra , B8G8R8A8_SSCALED) => { nalgebra :: base :: SVector < i8 , 4usize > } ; (nalgebra , B8G8R8A8_UINT) => { nalgebra :: base :: SVector < u8 , 4usize > } ; (nalgebra , B8G8R8A8_SINT) => { nalgebra :: base :: SVector < i8 , 4usize > } ; (nalgebra , B8G8R8A8_SRGB) => { nalgebra :: base :: SVector < u8 , 4usize > } ; (nalgebra , A8B8G8R8_UNORM_PACK32) => { u32 } ; (nalgebra , A8B8G8R8_SNORM_PACK32) => { u32 } ; (nalgebra , A8B8G8R8_USCALED_PACK32) => { u32 } ; (nalgebra , A8B8G8R8_SSCALED_PACK32) => { u32 } ; (nalgebra , A8B8G8R8_UINT_PACK32) => { u32 } ; (nalgebra , A8B8G8R8_SINT_PACK32) => { u32 } ; (nalgebra , A8B8G8R8_SRGB_PACK32) => { u32 } ; (nalgebra , A2R10G10B10_UNORM_PACK32) => { u32 } ; (nalgebra , A2R10G10B10_SNORM_PACK32) => { u32 } ; (nalgebra , A2R10G10B10_USCALED_PACK32) => { u32 } ; (nalgebra , A2R10G10B10_SSCALED_PACK32) => { u32 } ; (nalgebra , A2R10G10B10_UINT_PACK32) => { u32 } ; (nalgebra , A2R10G10B10_SINT_PACK32) => { u32 } ; (nalgebra , A2B10G10R10_UNORM_PACK32) => { u32 } ; (nalgebra , A2B10G10R10_SNORM_PACK32) => { u32 } ; (nalgebra , A2B10G10R10_USCALED_PACK32) => { u32 } ; (nalgebra , A2B10G10R10_SSCALED_PACK32) => { u32 } ; (nalgebra , A2B10G10R10_UINT_PACK32) => { u32 } ; (nalgebra , A2B10G10R10_SINT_PACK32) => { u32 } ; (nalgebra , R16_UNORM) => { u16 } ; (nalgebra , R16_SNORM) => { i16 } ; (nalgebra , R16_USCALED) => { u16 } ; (nalgebra , R16_SSCALED) => { i16 } ; (nalgebra , R16_UINT) => { u16 } ; (nalgebra , R16_SINT) => { i16 } ; (nalgebra , R16_SFLOAT) => { f16 } ; (nalgebra , R16G16_UNORM) => { nalgebra :: base :: SVector < u16 , 2usize > } ; (nalgebra , R16G16_SNORM) => { nalgebra :: base :: SVector < i16 , 2usize > } ; (nalgebra , R16G16_USCALED) => { nalgebra :: base :: SVector < u16 , 2usize > } ; (nalgebra , R16G16_SSCALED) => { nalgebra :: base :: SVector < i16 , 2usize > } ; (nalgebra , R16G16_UINT) => { nalgebra :: base :: SVector < u16 , 2usize > } ; (nalgebra , R16G16_SINT) => { nalgebra :: base :: SVector < i16 , 2usize > } ; (nalgebra , R16G16_SFLOAT) => { nalgebra :: base :: SVector < f16 , 2usize > } ; (nalgebra , R16G16B16_UNORM) => { nalgebra :: base :: SVector < u16 , 3usize > } ; (nalgebra , R16G16B16_SNORM) => { nalgebra :: base :: SVector < i16 , 3usize > } ; (nalgebra , R16G16B16_USCALED) => { nalgebra :: base :: SVector < u16 , 3usize > } ; (nalgebra , R16G16B16_SSCALED) => { nalgebra :: base :: SVector < i16 , 3usize > } ; (nalgebra , R16G16B16_UINT) => { nalgebra :: base :: SVector < u16 , 3usize > } ; (nalgebra , R16G16B16_SINT) => { nalgebra :: base :: SVector < i16 , 3usize > } ; (nalgebra , R16G16B16_SFLOAT) => { nalgebra :: base :: SVector < f16 , 3usize > } ; (nalgebra , R16G16B16A16_UNORM) => { nalgebra :: base :: SVector < u16 , 4usize > } ; (nalgebra , R16G16B16A16_SNORM) => { nalgebra :: base :: SVector < i16 , 4usize > } ; (nalgebra , R16G16B16A16_USCALED) => { nalgebra :: base :: SVector < u16 , 4usize > } ; (nalgebra , R16G16B16A16_SSCALED) => { nalgebra :: base :: SVector < i16 , 4usize > } ; (nalgebra , R16G16B16A16_UINT) => { nalgebra :: base :: SVector < u16 , 4usize > } ; (nalgebra , R16G16B16A16_SINT) => { nalgebra :: base :: SVector < i16 , 4usize > } ; (nalgebra , R16G16B16A16_SFLOAT) => { nalgebra :: base :: SVector < f16 , 4usize > } ; (nalgebra , R32_UINT) => { u32 } ; (nalgebra , R32_SINT) => { i32 } ; (nalgebra , R32_SFLOAT) => { f32 } ; (nalgebra , R32G32_UINT) => { nalgebra :: base :: SVector < u32 , 2usize > } ; (nalgebra , R32G32_SINT) => { nalgebra :: base :: SVector < i32 , 2usize > } ; (nalgebra , R32G32_SFLOAT) => { nalgebra :: base :: SVector < f32 , 2usize > } ; (nalgebra , R32G32B32_UINT) => { nalgebra :: base :: SVector < u32 , 3usize > } ; (nalgebra , R32G32B32_SINT) => { nalgebra :: base :: SVector < i32 , 3usize > } ; (nalgebra , R32G32B32_SFLOAT) => { nalgebra :: base :: SVector < f32 , 3usize > } ; (nalgebra , R32G32B32A32_UINT) => { nalgebra :: base :: SVector < u32 , 4usize > } ; (nalgebra , R32G32B32A32_SINT) => { nalgebra :: base :: SVector < i32 , 4usize > } ; (nalgebra , R32G32B32A32_SFLOAT) => { nalgebra :: base :: SVector < f32 , 4usize > } ; (nalgebra , R64_UINT) => { u64 } ; (nalgebra , R64_SINT) => { i64 } ; (nalgebra , R64_SFLOAT) => { f64 } ; (nalgebra , R64G64_UINT) => { nalgebra :: base :: SVector < u64 , 2usize > } ; (nalgebra , R64G64_SINT) => { nalgebra :: base :: SVector < i64 , 2usize > } ; (nalgebra , R64G64_SFLOAT) => { nalgebra :: base :: SVector < f64 , 2usize > } ; (nalgebra , R64G64B64_UINT) => { nalgebra :: base :: SVector < u64 , 3usize > } ; (nalgebra , R64G64B64_SINT) => { nalgebra :: base :: SVector < i64 , 3usize > } ; (nalgebra , R64G64B64_SFLOAT) => { nalgebra :: base :: SVector < f64 , 3usize > } ; (nalgebra , R64G64B64A64_UINT) => { nalgebra :: base :: SVector < u64 , 4usize > } ; (nalgebra , R64G64B64A64_SINT) => { nalgebra :: base :: SVector < i64 , 4usize > } ; (nalgebra , R64G64B64A64_SFLOAT) => { nalgebra :: base :: SVector < f64 , 4usize > } ; (nalgebra , B10G11R11_UFLOAT_PACK32) => { u32 } ; (nalgebra , E5B9G9R9_UFLOAT_PACK32) => { u32 } ; (nalgebra , BC1_RGB_UNORM_BLOCK) => { [u8 ; 8] } ; (nalgebra , BC1_RGB_SRGB_BLOCK) => { [u8 ; 8] } ; (nalgebra , BC1_RGBA_UNORM_BLOCK) => { [u8 ; 8] } ; (nalgebra , BC1_RGBA_SRGB_BLOCK) => { [u8 ; 8] } ; (nalgebra , BC2_UNORM_BLOCK) => { [u8 ; 16] } ; (nalgebra , BC2_SRGB_BLOCK) => { [u8 ; 16] } ; (nalgebra , BC3_UNORM_BLOCK) => { [u8 ; 16] } ; (nalgebra , BC3_SRGB_BLOCK) => { [u8 ; 16] } ; (nalgebra , BC4_UNORM_BLOCK) => { [u8 ; 8] } ; (nalgebra , BC4_SNORM_BLOCK) => { [u8 ; 8] } ; (nalgebra , BC5_UNORM_BLOCK) => { [u8 ; 16] } ; (nalgebra , BC5_SNORM_BLOCK) => { [u8 ; 16] } ; (nalgebra , BC6H_UFLOAT_BLOCK) => { [u8 ; 16] } ; (nalgebra , BC6H_SFLOAT_BLOCK) => { [u8 ; 16] } ; (nalgebra , BC7_UNORM_BLOCK) => { [u8 ; 16] } ; (nalgebra , BC7_SRGB_BLOCK) => { [u8 ; 16] } ; (nalgebra , ETC2_R8G8B8_UNORM_BLOCK) => { [u8 ; 8] } ; (nalgebra , ETC2_R8G8B8_SRGB_BLOCK) => { [u8 ; 8] } ; (nalgebra , ETC2_R8G8B8A1_UNORM_BLOCK) => { [u8 ; 8] } ; (nalgebra , ETC2_R8G8B8A1_SRGB_BLOCK) => { [u8 ; 8] } ; (nalgebra , ETC2_R8G8B8A8_UNORM_BLOCK) => { [u8 ; 16] } ; (nalgebra , ETC2_R8G8B8A8_SRGB_BLOCK) => { [u8 ; 16] } ; (nalgebra , EAC_R11_UNORM_BLOCK) => { [u8 ; 8] } ; (nalgebra , EAC_R11_SNORM_BLOCK) => { [u8 ; 8] } ; (nalgebra , EAC_R11G11_UNORM_BLOCK) => { [u8 ; 16] } ; (nalgebra , EAC_R11G11_SNORM_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_4x4_UNORM_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_4x4_SRGB_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_5x4_UNORM_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_5x4_SRGB_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_5x5_UNORM_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_5x5_SRGB_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_6x5_UNORM_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_6x5_SRGB_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_6x6_UNORM_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_6x6_SRGB_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_8x5_UNORM_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_8x5_SRGB_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_8x6_UNORM_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_8x6_SRGB_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_8x8_UNORM_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_8x8_SRGB_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_10x5_UNORM_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_10x5_SRGB_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_10x6_UNORM_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_10x6_SRGB_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_10x8_UNORM_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_10x8_SRGB_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_10x10_UNORM_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_10x10_SRGB_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_12x10_UNORM_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_12x10_SRGB_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_12x12_UNORM_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_12x12_SRGB_BLOCK) => { [u8 ; 16] } ; (nalgebra , G8B8G8R8_422_UNORM) => { nalgebra :: base :: SVector < u8 , 4usize > } ; (nalgebra , B8G8R8G8_422_UNORM) => { nalgebra :: base :: SVector < u8 , 4usize > } ; (nalgebra , R10X6_UNORM_PACK16) => { u16 } ; (nalgebra , R10X6G10X6_UNORM_2PACK16) => { [u16 ; 2] } ; (nalgebra , R10X6G10X6B10X6A10X6_UNORM_4PACK16) => { [u16 ; 4] } ; (nalgebra , G10X6B10X6G10X6R10X6_422_UNORM_4PACK16) => { [u16 ; 4] } ; (nalgebra , B10X6G10X6R10X6G10X6_422_UNORM_4PACK16) => { [u16 ; 4] } ; (nalgebra , R12X4_UNORM_PACK16) => { u16 } ; (nalgebra , R12X4G12X4_UNORM_2PACK16) => { [u16 ; 2] } ; (nalgebra , R12X4G12X4B12X4A12X4_UNORM_4PACK16) => { [u16 ; 4] } ; (nalgebra , G12X4B12X4G12X4R12X4_422_UNORM_4PACK16) => { [u16 ; 4] } ; (nalgebra , B12X4G12X4R12X4G12X4_422_UNORM_4PACK16) => { [u16 ; 4] } ; (nalgebra , G16B16G16R16_422_UNORM) => { nalgebra :: base :: SVector < u16 , 4usize > } ; (nalgebra , B16G16R16G16_422_UNORM) => { nalgebra :: base :: SVector < u16 , 4usize > } ; (nalgebra , PVRTC1_2BPP_UNORM_BLOCK) => { [u8 ; 8] } ; (nalgebra , PVRTC1_4BPP_UNORM_BLOCK) => { [u8 ; 8] } ; (nalgebra , PVRTC2_2BPP_UNORM_BLOCK) => { [u8 ; 8] } ; (nalgebra , PVRTC2_4BPP_UNORM_BLOCK) => { [u8 ; 8] } ; (nalgebra , PVRTC1_2BPP_SRGB_BLOCK) => { [u8 ; 8] } ; (nalgebra , PVRTC1_4BPP_SRGB_BLOCK) => { [u8 ; 8] } ; (nalgebra , PVRTC2_2BPP_SRGB_BLOCK) => { [u8 ; 8] } ; (nalgebra , PVRTC2_4BPP_SRGB_BLOCK) => { [u8 ; 8] } ; (nalgebra , ASTC_4x4_SFLOAT_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_5x4_SFLOAT_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_5x5_SFLOAT_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_6x5_SFLOAT_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_6x6_SFLOAT_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_8x5_SFLOAT_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_8x6_SFLOAT_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_8x8_SFLOAT_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_10x5_SFLOAT_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_10x6_SFLOAT_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_10x8_SFLOAT_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_10x10_SFLOAT_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_12x10_SFLOAT_BLOCK) => { [u8 ; 16] } ; (nalgebra , ASTC_12x12_SFLOAT_BLOCK) => { [u8 ; 16] } ; (nalgebra , A4R4G4B4_UNORM_PACK16) => { u16 } ; (nalgebra , A4B4G4R4_UNORM_PACK16) => { u16 } ; (nalgebra , R16G16_S10_5_NV) => { nalgebra :: base :: SVector < i16 , 2usize > } ; }
diff --git a/out/instance_extensions.rs b/out/instance_extensions.rs
new file mode 100644
index 0000000..4e395da
--- /dev/null
+++ b/out/instance_extensions.rs
@@ -0,0 +1,1903 @@
+// This file is auto-generated by vulkano autogen from vk.xml header version 1.3.238.
+// It should not be edited manually. Changes should be made by editing autogen.
+
+#[doc = r" List of extensions that are enabled or available."]
+#[derive(Copy, Clone, PartialEq, Eq)]
+pub struct InstanceExtensions {
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_android_surface.html)\n- Requires:\n - instance extension [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)"]
+ pub khr_android_surface: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_device_group_creation.html)\n- Promoted to Vulkan 1.1"]
+ pub khr_device_group_creation: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_display.html)\n- Requires:\n - instance extension [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)"]
+ pub khr_display: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_external_fence_capabilities.html)\n- Promoted to Vulkan 1.1\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub khr_external_fence_capabilities: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_external_memory_capabilities.html)\n- Promoted to Vulkan 1.1\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub khr_external_memory_capabilities: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_external_semaphore_capabilities.html)\n- Promoted to Vulkan 1.1\n- Requires:\n - One of: Vulkan API version 1.1, instance extension [`khr_get_physical_device_properties2`](crate::instance::InstanceExtensions::khr_get_physical_device_properties2)"]
+ pub khr_external_semaphore_capabilities: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_get_display_properties2.html)\n- Requires:\n - instance extension [`khr_display`](crate::instance::InstanceExtensions::khr_display)"]
+ pub khr_get_display_properties2: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_get_physical_device_properties2.html)\n- Promoted to Vulkan 1.1"]
+ pub khr_get_physical_device_properties2: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_get_surface_capabilities2.html)\n- Requires:\n - instance extension [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)"]
+ pub khr_get_surface_capabilities2: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_portability_enumeration.html)"]
+ pub khr_portability_enumeration: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_surface.html)"]
+ pub khr_surface: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_surface_protected_capabilities.html)\n- Requires:\n - Vulkan API version 1.1\n - instance extension [`khr_get_surface_capabilities2`](crate::instance::InstanceExtensions::khr_get_surface_capabilities2)"]
+ pub khr_surface_protected_capabilities: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_wayland_surface.html)\n- Requires:\n - instance extension [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)"]
+ pub khr_wayland_surface: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_win32_surface.html)\n- Requires:\n - instance extension [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)"]
+ pub khr_win32_surface: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_xcb_surface.html)\n- Requires:\n - instance extension [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)"]
+ pub khr_xcb_surface: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_xlib_surface.html)\n- Requires:\n - instance extension [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)"]
+ pub khr_xlib_surface: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_acquire_drm_display.html)\n- Requires:\n - instance extension [`ext_direct_mode_display`](crate::instance::InstanceExtensions::ext_direct_mode_display)"]
+ pub ext_acquire_drm_display: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_acquire_xlib_display.html)\n- Requires:\n - instance extension [`ext_direct_mode_display`](crate::instance::InstanceExtensions::ext_direct_mode_display)"]
+ pub ext_acquire_xlib_display: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_debug_report.html)\n- Deprecated by [`ext_debug_utils`](crate::instance::InstanceExtensions::ext_debug_utils)"]
+ pub ext_debug_report: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_debug_utils.html)"]
+ pub ext_debug_utils: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_direct_mode_display.html)\n- Requires:\n - instance extension [`khr_display`](crate::instance::InstanceExtensions::khr_display)"]
+ pub ext_direct_mode_display: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_directfb_surface.html)\n- Requires:\n - instance extension [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)"]
+ pub ext_directfb_surface: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_display_surface_counter.html)\n- Requires:\n - instance extension [`khr_display`](crate::instance::InstanceExtensions::khr_display)"]
+ pub ext_display_surface_counter: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_headless_surface.html)\n- Requires:\n - instance extension [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)"]
+ pub ext_headless_surface: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_metal_surface.html)\n- Requires:\n - instance extension [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)"]
+ pub ext_metal_surface: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_surface_maintenance1.html)\n- Requires:\n - instance extension [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)\n - instance extension [`khr_get_surface_capabilities2`](crate::instance::InstanceExtensions::khr_get_surface_capabilities2)"]
+ pub ext_surface_maintenance1: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_swapchain_colorspace.html)\n- Requires:\n - instance extension [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)"]
+ pub ext_swapchain_colorspace: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_validation_features.html)"]
+ pub ext_validation_features: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_validation_flags.html)\n- Deprecated by [`ext_validation_features`](crate::instance::InstanceExtensions::ext_validation_features)"]
+ pub ext_validation_flags: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_FUCHSIA_imagepipe_surface.html)\n- Requires:\n - instance extension [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)"]
+ pub fuchsia_imagepipe_surface: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_GGP_stream_descriptor_surface.html)\n- Requires:\n - instance extension [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)"]
+ pub ggp_stream_descriptor_surface: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_GOOGLE_surfaceless_query.html)\n- Requires:\n - instance extension [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)"]
+ pub google_surfaceless_query: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_LUNARG_direct_driver_loading.html)"]
+ pub lunarg_direct_driver_loading: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_MVK_ios_surface.html)\n- Deprecated by [`ext_metal_surface`](crate::instance::InstanceExtensions::ext_metal_surface)\n- Requires:\n - instance extension [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)"]
+ pub mvk_ios_surface: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_MVK_macos_surface.html)\n- Deprecated by [`ext_metal_surface`](crate::instance::InstanceExtensions::ext_metal_surface)\n- Requires:\n - instance extension [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)"]
+ pub mvk_macos_surface: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NN_vi_surface.html)\n- Requires:\n - instance extension [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)"]
+ pub nn_vi_surface: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_NV_external_memory_capabilities.html)\n- Deprecated by [`khr_external_memory_capabilities`](crate::instance::InstanceExtensions::khr_external_memory_capabilities)"]
+ pub nv_external_memory_capabilities: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_QNX_screen_surface.html)\n- Requires:\n - instance extension [`khr_surface`](crate::instance::InstanceExtensions::khr_surface)"]
+ pub qnx_screen_surface: bool,
+ pub _ne: crate::NonExhaustive,
+}
+impl Default for InstanceExtensions {
+ #[inline]
+ fn default() -> Self {
+ Self::empty()
+ }
+}
+impl InstanceExtensions {
+ #[doc = r" Returns an `Extensions` object with none of the members set."]
+ #[inline]
+ pub const fn empty() -> Self {
+ Self {
+ khr_android_surface: false,
+ khr_device_group_creation: false,
+ khr_display: false,
+ khr_external_fence_capabilities: false,
+ khr_external_memory_capabilities: false,
+ khr_external_semaphore_capabilities: false,
+ khr_get_display_properties2: false,
+ khr_get_physical_device_properties2: false,
+ khr_get_surface_capabilities2: false,
+ khr_portability_enumeration: false,
+ khr_surface: false,
+ khr_surface_protected_capabilities: false,
+ khr_wayland_surface: false,
+ khr_win32_surface: false,
+ khr_xcb_surface: false,
+ khr_xlib_surface: false,
+ ext_acquire_drm_display: false,
+ ext_acquire_xlib_display: false,
+ ext_debug_report: false,
+ ext_debug_utils: false,
+ ext_direct_mode_display: false,
+ ext_directfb_surface: false,
+ ext_display_surface_counter: false,
+ ext_headless_surface: false,
+ ext_metal_surface: false,
+ ext_surface_maintenance1: false,
+ ext_swapchain_colorspace: false,
+ ext_validation_features: false,
+ ext_validation_flags: false,
+ fuchsia_imagepipe_surface: false,
+ ggp_stream_descriptor_surface: false,
+ google_surfaceless_query: false,
+ lunarg_direct_driver_loading: false,
+ mvk_ios_surface: false,
+ mvk_macos_surface: false,
+ nn_vi_surface: false,
+ nv_external_memory_capabilities: false,
+ qnx_screen_surface: false,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+ #[doc = r" Returns an `Extensions` object with none of the members set."]
+ #[deprecated(since = "0.31.0", note = "Use `empty` instead.")]
+ #[inline]
+ pub const fn none() -> Self {
+ Self::empty()
+ }
+ #[doc = r" Returns whether any members are set in both `self` and `other`."]
+ #[inline]
+ pub const fn intersects(&self, other: &Self) -> bool {
+ (self.khr_android_surface && other.khr_android_surface)
+ || (self.khr_device_group_creation && other.khr_device_group_creation)
+ || (self.khr_display && other.khr_display)
+ || (self.khr_external_fence_capabilities && other.khr_external_fence_capabilities)
+ || (self.khr_external_memory_capabilities && other.khr_external_memory_capabilities)
+ || (self.khr_external_semaphore_capabilities
+ && other.khr_external_semaphore_capabilities)
+ || (self.khr_get_display_properties2 && other.khr_get_display_properties2)
+ || (self.khr_get_physical_device_properties2
+ && other.khr_get_physical_device_properties2)
+ || (self.khr_get_surface_capabilities2 && other.khr_get_surface_capabilities2)
+ || (self.khr_portability_enumeration && other.khr_portability_enumeration)
+ || (self.khr_surface && other.khr_surface)
+ || (self.khr_surface_protected_capabilities && other.khr_surface_protected_capabilities)
+ || (self.khr_wayland_surface && other.khr_wayland_surface)
+ || (self.khr_win32_surface && other.khr_win32_surface)
+ || (self.khr_xcb_surface && other.khr_xcb_surface)
+ || (self.khr_xlib_surface && other.khr_xlib_surface)
+ || (self.ext_acquire_drm_display && other.ext_acquire_drm_display)
+ || (self.ext_acquire_xlib_display && other.ext_acquire_xlib_display)
+ || (self.ext_debug_report && other.ext_debug_report)
+ || (self.ext_debug_utils && other.ext_debug_utils)
+ || (self.ext_direct_mode_display && other.ext_direct_mode_display)
+ || (self.ext_directfb_surface && other.ext_directfb_surface)
+ || (self.ext_display_surface_counter && other.ext_display_surface_counter)
+ || (self.ext_headless_surface && other.ext_headless_surface)
+ || (self.ext_metal_surface && other.ext_metal_surface)
+ || (self.ext_surface_maintenance1 && other.ext_surface_maintenance1)
+ || (self.ext_swapchain_colorspace && other.ext_swapchain_colorspace)
+ || (self.ext_validation_features && other.ext_validation_features)
+ || (self.ext_validation_flags && other.ext_validation_flags)
+ || (self.fuchsia_imagepipe_surface && other.fuchsia_imagepipe_surface)
+ || (self.ggp_stream_descriptor_surface && other.ggp_stream_descriptor_surface)
+ || (self.google_surfaceless_query && other.google_surfaceless_query)
+ || (self.lunarg_direct_driver_loading && other.lunarg_direct_driver_loading)
+ || (self.mvk_ios_surface && other.mvk_ios_surface)
+ || (self.mvk_macos_surface && other.mvk_macos_surface)
+ || (self.nn_vi_surface && other.nn_vi_surface)
+ || (self.nv_external_memory_capabilities && other.nv_external_memory_capabilities)
+ || (self.qnx_screen_surface && other.qnx_screen_surface)
+ }
+ #[doc = r" Returns whether all members in `other` are set in `self`."]
+ #[inline]
+ pub const fn contains(&self, other: &Self) -> bool {
+ (self.khr_android_surface || !other.khr_android_surface)
+ && (self.khr_device_group_creation || !other.khr_device_group_creation)
+ && (self.khr_display || !other.khr_display)
+ && (self.khr_external_fence_capabilities || !other.khr_external_fence_capabilities)
+ && (self.khr_external_memory_capabilities || !other.khr_external_memory_capabilities)
+ && (self.khr_external_semaphore_capabilities
+ || !other.khr_external_semaphore_capabilities)
+ && (self.khr_get_display_properties2 || !other.khr_get_display_properties2)
+ && (self.khr_get_physical_device_properties2
+ || !other.khr_get_physical_device_properties2)
+ && (self.khr_get_surface_capabilities2 || !other.khr_get_surface_capabilities2)
+ && (self.khr_portability_enumeration || !other.khr_portability_enumeration)
+ && (self.khr_surface || !other.khr_surface)
+ && (self.khr_surface_protected_capabilities
+ || !other.khr_surface_protected_capabilities)
+ && (self.khr_wayland_surface || !other.khr_wayland_surface)
+ && (self.khr_win32_surface || !other.khr_win32_surface)
+ && (self.khr_xcb_surface || !other.khr_xcb_surface)
+ && (self.khr_xlib_surface || !other.khr_xlib_surface)
+ && (self.ext_acquire_drm_display || !other.ext_acquire_drm_display)
+ && (self.ext_acquire_xlib_display || !other.ext_acquire_xlib_display)
+ && (self.ext_debug_report || !other.ext_debug_report)
+ && (self.ext_debug_utils || !other.ext_debug_utils)
+ && (self.ext_direct_mode_display || !other.ext_direct_mode_display)
+ && (self.ext_directfb_surface || !other.ext_directfb_surface)
+ && (self.ext_display_surface_counter || !other.ext_display_surface_counter)
+ && (self.ext_headless_surface || !other.ext_headless_surface)
+ && (self.ext_metal_surface || !other.ext_metal_surface)
+ && (self.ext_surface_maintenance1 || !other.ext_surface_maintenance1)
+ && (self.ext_swapchain_colorspace || !other.ext_swapchain_colorspace)
+ && (self.ext_validation_features || !other.ext_validation_features)
+ && (self.ext_validation_flags || !other.ext_validation_flags)
+ && (self.fuchsia_imagepipe_surface || !other.fuchsia_imagepipe_surface)
+ && (self.ggp_stream_descriptor_surface || !other.ggp_stream_descriptor_surface)
+ && (self.google_surfaceless_query || !other.google_surfaceless_query)
+ && (self.lunarg_direct_driver_loading || !other.lunarg_direct_driver_loading)
+ && (self.mvk_ios_surface || !other.mvk_ios_surface)
+ && (self.mvk_macos_surface || !other.mvk_macos_surface)
+ && (self.nn_vi_surface || !other.nn_vi_surface)
+ && (self.nv_external_memory_capabilities || !other.nv_external_memory_capabilities)
+ && (self.qnx_screen_surface || !other.qnx_screen_surface)
+ }
+ #[doc = r" Returns whether all members in `other` are set in `self`."]
+ #[deprecated(since = "0.31.0", note = "Use `contains` instead.")]
+ #[inline]
+ pub const fn is_superset_of(&self, other: &Self) -> bool {
+ self.contains(other)
+ }
+ #[doc = r" Returns the union of `self` and `other`."]
+ #[inline]
+ pub const fn union(&self, other: &Self) -> Self {
+ Self {
+ khr_android_surface: self.khr_android_surface || other.khr_android_surface,
+ khr_device_group_creation: self.khr_device_group_creation
+ || other.khr_device_group_creation,
+ khr_display: self.khr_display || other.khr_display,
+ khr_external_fence_capabilities: self.khr_external_fence_capabilities
+ || other.khr_external_fence_capabilities,
+ khr_external_memory_capabilities: self.khr_external_memory_capabilities
+ || other.khr_external_memory_capabilities,
+ khr_external_semaphore_capabilities: self.khr_external_semaphore_capabilities
+ || other.khr_external_semaphore_capabilities,
+ khr_get_display_properties2: self.khr_get_display_properties2
+ || other.khr_get_display_properties2,
+ khr_get_physical_device_properties2: self.khr_get_physical_device_properties2
+ || other.khr_get_physical_device_properties2,
+ khr_get_surface_capabilities2: self.khr_get_surface_capabilities2
+ || other.khr_get_surface_capabilities2,
+ khr_portability_enumeration: self.khr_portability_enumeration
+ || other.khr_portability_enumeration,
+ khr_surface: self.khr_surface || other.khr_surface,
+ khr_surface_protected_capabilities: self.khr_surface_protected_capabilities
+ || other.khr_surface_protected_capabilities,
+ khr_wayland_surface: self.khr_wayland_surface || other.khr_wayland_surface,
+ khr_win32_surface: self.khr_win32_surface || other.khr_win32_surface,
+ khr_xcb_surface: self.khr_xcb_surface || other.khr_xcb_surface,
+ khr_xlib_surface: self.khr_xlib_surface || other.khr_xlib_surface,
+ ext_acquire_drm_display: self.ext_acquire_drm_display || other.ext_acquire_drm_display,
+ ext_acquire_xlib_display: self.ext_acquire_xlib_display
+ || other.ext_acquire_xlib_display,
+ ext_debug_report: self.ext_debug_report || other.ext_debug_report,
+ ext_debug_utils: self.ext_debug_utils || other.ext_debug_utils,
+ ext_direct_mode_display: self.ext_direct_mode_display || other.ext_direct_mode_display,
+ ext_directfb_surface: self.ext_directfb_surface || other.ext_directfb_surface,
+ ext_display_surface_counter: self.ext_display_surface_counter
+ || other.ext_display_surface_counter,
+ ext_headless_surface: self.ext_headless_surface || other.ext_headless_surface,
+ ext_metal_surface: self.ext_metal_surface || other.ext_metal_surface,
+ ext_surface_maintenance1: self.ext_surface_maintenance1
+ || other.ext_surface_maintenance1,
+ ext_swapchain_colorspace: self.ext_swapchain_colorspace
+ || other.ext_swapchain_colorspace,
+ ext_validation_features: self.ext_validation_features || other.ext_validation_features,
+ ext_validation_flags: self.ext_validation_flags || other.ext_validation_flags,
+ fuchsia_imagepipe_surface: self.fuchsia_imagepipe_surface
+ || other.fuchsia_imagepipe_surface,
+ ggp_stream_descriptor_surface: self.ggp_stream_descriptor_surface
+ || other.ggp_stream_descriptor_surface,
+ google_surfaceless_query: self.google_surfaceless_query
+ || other.google_surfaceless_query,
+ lunarg_direct_driver_loading: self.lunarg_direct_driver_loading
+ || other.lunarg_direct_driver_loading,
+ mvk_ios_surface: self.mvk_ios_surface || other.mvk_ios_surface,
+ mvk_macos_surface: self.mvk_macos_surface || other.mvk_macos_surface,
+ nn_vi_surface: self.nn_vi_surface || other.nn_vi_surface,
+ nv_external_memory_capabilities: self.nv_external_memory_capabilities
+ || other.nv_external_memory_capabilities,
+ qnx_screen_surface: self.qnx_screen_surface || other.qnx_screen_surface,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+ #[doc = r" Returns the intersection of `self` and `other`."]
+ #[inline]
+ pub const fn intersection(&self, other: &Self) -> Self {
+ Self {
+ khr_android_surface: self.khr_android_surface && other.khr_android_surface,
+ khr_device_group_creation: self.khr_device_group_creation
+ && other.khr_device_group_creation,
+ khr_display: self.khr_display && other.khr_display,
+ khr_external_fence_capabilities: self.khr_external_fence_capabilities
+ && other.khr_external_fence_capabilities,
+ khr_external_memory_capabilities: self.khr_external_memory_capabilities
+ && other.khr_external_memory_capabilities,
+ khr_external_semaphore_capabilities: self.khr_external_semaphore_capabilities
+ && other.khr_external_semaphore_capabilities,
+ khr_get_display_properties2: self.khr_get_display_properties2
+ && other.khr_get_display_properties2,
+ khr_get_physical_device_properties2: self.khr_get_physical_device_properties2
+ && other.khr_get_physical_device_properties2,
+ khr_get_surface_capabilities2: self.khr_get_surface_capabilities2
+ && other.khr_get_surface_capabilities2,
+ khr_portability_enumeration: self.khr_portability_enumeration
+ && other.khr_portability_enumeration,
+ khr_surface: self.khr_surface && other.khr_surface,
+ khr_surface_protected_capabilities: self.khr_surface_protected_capabilities
+ && other.khr_surface_protected_capabilities,
+ khr_wayland_surface: self.khr_wayland_surface && other.khr_wayland_surface,
+ khr_win32_surface: self.khr_win32_surface && other.khr_win32_surface,
+ khr_xcb_surface: self.khr_xcb_surface && other.khr_xcb_surface,
+ khr_xlib_surface: self.khr_xlib_surface && other.khr_xlib_surface,
+ ext_acquire_drm_display: self.ext_acquire_drm_display && other.ext_acquire_drm_display,
+ ext_acquire_xlib_display: self.ext_acquire_xlib_display
+ && other.ext_acquire_xlib_display,
+ ext_debug_report: self.ext_debug_report && other.ext_debug_report,
+ ext_debug_utils: self.ext_debug_utils && other.ext_debug_utils,
+ ext_direct_mode_display: self.ext_direct_mode_display && other.ext_direct_mode_display,
+ ext_directfb_surface: self.ext_directfb_surface && other.ext_directfb_surface,
+ ext_display_surface_counter: self.ext_display_surface_counter
+ && other.ext_display_surface_counter,
+ ext_headless_surface: self.ext_headless_surface && other.ext_headless_surface,
+ ext_metal_surface: self.ext_metal_surface && other.ext_metal_surface,
+ ext_surface_maintenance1: self.ext_surface_maintenance1
+ && other.ext_surface_maintenance1,
+ ext_swapchain_colorspace: self.ext_swapchain_colorspace
+ && other.ext_swapchain_colorspace,
+ ext_validation_features: self.ext_validation_features && other.ext_validation_features,
+ ext_validation_flags: self.ext_validation_flags && other.ext_validation_flags,
+ fuchsia_imagepipe_surface: self.fuchsia_imagepipe_surface
+ && other.fuchsia_imagepipe_surface,
+ ggp_stream_descriptor_surface: self.ggp_stream_descriptor_surface
+ && other.ggp_stream_descriptor_surface,
+ google_surfaceless_query: self.google_surfaceless_query
+ && other.google_surfaceless_query,
+ lunarg_direct_driver_loading: self.lunarg_direct_driver_loading
+ && other.lunarg_direct_driver_loading,
+ mvk_ios_surface: self.mvk_ios_surface && other.mvk_ios_surface,
+ mvk_macos_surface: self.mvk_macos_surface && other.mvk_macos_surface,
+ nn_vi_surface: self.nn_vi_surface && other.nn_vi_surface,
+ nv_external_memory_capabilities: self.nv_external_memory_capabilities
+ && other.nv_external_memory_capabilities,
+ qnx_screen_surface: self.qnx_screen_surface && other.qnx_screen_surface,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+ #[doc = r" Returns `self` without the members set in `other`."]
+ #[inline]
+ pub const fn difference(&self, other: &Self) -> Self {
+ Self {
+ khr_android_surface: self.khr_android_surface && !other.khr_android_surface,
+ khr_device_group_creation: self.khr_device_group_creation
+ && !other.khr_device_group_creation,
+ khr_display: self.khr_display && !other.khr_display,
+ khr_external_fence_capabilities: self.khr_external_fence_capabilities
+ && !other.khr_external_fence_capabilities,
+ khr_external_memory_capabilities: self.khr_external_memory_capabilities
+ && !other.khr_external_memory_capabilities,
+ khr_external_semaphore_capabilities: self.khr_external_semaphore_capabilities
+ && !other.khr_external_semaphore_capabilities,
+ khr_get_display_properties2: self.khr_get_display_properties2
+ && !other.khr_get_display_properties2,
+ khr_get_physical_device_properties2: self.khr_get_physical_device_properties2
+ && !other.khr_get_physical_device_properties2,
+ khr_get_surface_capabilities2: self.khr_get_surface_capabilities2
+ && !other.khr_get_surface_capabilities2,
+ khr_portability_enumeration: self.khr_portability_enumeration
+ && !other.khr_portability_enumeration,
+ khr_surface: self.khr_surface && !other.khr_surface,
+ khr_surface_protected_capabilities: self.khr_surface_protected_capabilities
+ && !other.khr_surface_protected_capabilities,
+ khr_wayland_surface: self.khr_wayland_surface && !other.khr_wayland_surface,
+ khr_win32_surface: self.khr_win32_surface && !other.khr_win32_surface,
+ khr_xcb_surface: self.khr_xcb_surface && !other.khr_xcb_surface,
+ khr_xlib_surface: self.khr_xlib_surface && !other.khr_xlib_surface,
+ ext_acquire_drm_display: self.ext_acquire_drm_display && !other.ext_acquire_drm_display,
+ ext_acquire_xlib_display: self.ext_acquire_xlib_display
+ && !other.ext_acquire_xlib_display,
+ ext_debug_report: self.ext_debug_report && !other.ext_debug_report,
+ ext_debug_utils: self.ext_debug_utils && !other.ext_debug_utils,
+ ext_direct_mode_display: self.ext_direct_mode_display && !other.ext_direct_mode_display,
+ ext_directfb_surface: self.ext_directfb_surface && !other.ext_directfb_surface,
+ ext_display_surface_counter: self.ext_display_surface_counter
+ && !other.ext_display_surface_counter,
+ ext_headless_surface: self.ext_headless_surface && !other.ext_headless_surface,
+ ext_metal_surface: self.ext_metal_surface && !other.ext_metal_surface,
+ ext_surface_maintenance1: self.ext_surface_maintenance1
+ && !other.ext_surface_maintenance1,
+ ext_swapchain_colorspace: self.ext_swapchain_colorspace
+ && !other.ext_swapchain_colorspace,
+ ext_validation_features: self.ext_validation_features && !other.ext_validation_features,
+ ext_validation_flags: self.ext_validation_flags && !other.ext_validation_flags,
+ fuchsia_imagepipe_surface: self.fuchsia_imagepipe_surface
+ && !other.fuchsia_imagepipe_surface,
+ ggp_stream_descriptor_surface: self.ggp_stream_descriptor_surface
+ && !other.ggp_stream_descriptor_surface,
+ google_surfaceless_query: self.google_surfaceless_query
+ && !other.google_surfaceless_query,
+ lunarg_direct_driver_loading: self.lunarg_direct_driver_loading
+ && !other.lunarg_direct_driver_loading,
+ mvk_ios_surface: self.mvk_ios_surface && !other.mvk_ios_surface,
+ mvk_macos_surface: self.mvk_macos_surface && !other.mvk_macos_surface,
+ nn_vi_surface: self.nn_vi_surface && !other.nn_vi_surface,
+ nv_external_memory_capabilities: self.nv_external_memory_capabilities
+ && !other.nv_external_memory_capabilities,
+ qnx_screen_surface: self.qnx_screen_surface && !other.qnx_screen_surface,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+ #[doc = r" Returns the members set in `self` or `other`, but not both."]
+ #[inline]
+ pub const fn symmetric_difference(&self, other: &Self) -> Self {
+ Self {
+ khr_android_surface: self.khr_android_surface ^ other.khr_android_surface,
+ khr_device_group_creation: self.khr_device_group_creation
+ ^ other.khr_device_group_creation,
+ khr_display: self.khr_display ^ other.khr_display,
+ khr_external_fence_capabilities: self.khr_external_fence_capabilities
+ ^ other.khr_external_fence_capabilities,
+ khr_external_memory_capabilities: self.khr_external_memory_capabilities
+ ^ other.khr_external_memory_capabilities,
+ khr_external_semaphore_capabilities: self.khr_external_semaphore_capabilities
+ ^ other.khr_external_semaphore_capabilities,
+ khr_get_display_properties2: self.khr_get_display_properties2
+ ^ other.khr_get_display_properties2,
+ khr_get_physical_device_properties2: self.khr_get_physical_device_properties2
+ ^ other.khr_get_physical_device_properties2,
+ khr_get_surface_capabilities2: self.khr_get_surface_capabilities2
+ ^ other.khr_get_surface_capabilities2,
+ khr_portability_enumeration: self.khr_portability_enumeration
+ ^ other.khr_portability_enumeration,
+ khr_surface: self.khr_surface ^ other.khr_surface,
+ khr_surface_protected_capabilities: self.khr_surface_protected_capabilities
+ ^ other.khr_surface_protected_capabilities,
+ khr_wayland_surface: self.khr_wayland_surface ^ other.khr_wayland_surface,
+ khr_win32_surface: self.khr_win32_surface ^ other.khr_win32_surface,
+ khr_xcb_surface: self.khr_xcb_surface ^ other.khr_xcb_surface,
+ khr_xlib_surface: self.khr_xlib_surface ^ other.khr_xlib_surface,
+ ext_acquire_drm_display: self.ext_acquire_drm_display ^ other.ext_acquire_drm_display,
+ ext_acquire_xlib_display: self.ext_acquire_xlib_display
+ ^ other.ext_acquire_xlib_display,
+ ext_debug_report: self.ext_debug_report ^ other.ext_debug_report,
+ ext_debug_utils: self.ext_debug_utils ^ other.ext_debug_utils,
+ ext_direct_mode_display: self.ext_direct_mode_display ^ other.ext_direct_mode_display,
+ ext_directfb_surface: self.ext_directfb_surface ^ other.ext_directfb_surface,
+ ext_display_surface_counter: self.ext_display_surface_counter
+ ^ other.ext_display_surface_counter,
+ ext_headless_surface: self.ext_headless_surface ^ other.ext_headless_surface,
+ ext_metal_surface: self.ext_metal_surface ^ other.ext_metal_surface,
+ ext_surface_maintenance1: self.ext_surface_maintenance1
+ ^ other.ext_surface_maintenance1,
+ ext_swapchain_colorspace: self.ext_swapchain_colorspace
+ ^ other.ext_swapchain_colorspace,
+ ext_validation_features: self.ext_validation_features ^ other.ext_validation_features,
+ ext_validation_flags: self.ext_validation_flags ^ other.ext_validation_flags,
+ fuchsia_imagepipe_surface: self.fuchsia_imagepipe_surface
+ ^ other.fuchsia_imagepipe_surface,
+ ggp_stream_descriptor_surface: self.ggp_stream_descriptor_surface
+ ^ other.ggp_stream_descriptor_surface,
+ google_surfaceless_query: self.google_surfaceless_query
+ ^ other.google_surfaceless_query,
+ lunarg_direct_driver_loading: self.lunarg_direct_driver_loading
+ ^ other.lunarg_direct_driver_loading,
+ mvk_ios_surface: self.mvk_ios_surface ^ other.mvk_ios_surface,
+ mvk_macos_surface: self.mvk_macos_surface ^ other.mvk_macos_surface,
+ nn_vi_surface: self.nn_vi_surface ^ other.nn_vi_surface,
+ nv_external_memory_capabilities: self.nv_external_memory_capabilities
+ ^ other.nv_external_memory_capabilities,
+ qnx_screen_surface: self.qnx_screen_surface ^ other.qnx_screen_surface,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+impl std::ops::BitAnd for InstanceExtensions {
+ type Output = InstanceExtensions;
+ #[inline]
+ fn bitand(self, rhs: Self) -> Self::Output {
+ self.union(&rhs)
+ }
+}
+impl std::ops::BitAndAssign for InstanceExtensions {
+ #[inline]
+ fn bitand_assign(&mut self, rhs: Self) {
+ *self = self.union(&rhs);
+ }
+}
+impl std::ops::BitOr for InstanceExtensions {
+ type Output = InstanceExtensions;
+ #[inline]
+ fn bitor(self, rhs: Self) -> Self::Output {
+ self.intersection(&rhs)
+ }
+}
+impl std::ops::BitOrAssign for InstanceExtensions {
+ #[inline]
+ fn bitor_assign(&mut self, rhs: Self) {
+ *self = self.intersection(&rhs);
+ }
+}
+impl std::ops::BitXor for InstanceExtensions {
+ type Output = InstanceExtensions;
+ #[inline]
+ fn bitxor(self, rhs: Self) -> Self::Output {
+ self.symmetric_difference(&rhs)
+ }
+}
+impl std::ops::BitXorAssign for InstanceExtensions {
+ #[inline]
+ fn bitxor_assign(&mut self, rhs: Self) {
+ *self = self.symmetric_difference(&rhs);
+ }
+}
+impl std::ops::Sub for InstanceExtensions {
+ type Output = InstanceExtensions;
+ #[inline]
+ fn sub(self, rhs: Self) -> Self::Output {
+ self.difference(&rhs)
+ }
+}
+impl std::ops::SubAssign for InstanceExtensions {
+ #[inline]
+ fn sub_assign(&mut self, rhs: Self) {
+ *self = self.difference(&rhs);
+ }
+}
+impl std::fmt::Debug for InstanceExtensions {
+ #[allow(unused_assignments)]
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
+ write!(f, "[")?;
+ let mut first = true;
+ if self.khr_android_surface {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_android_surface")?;
+ }
+ if self.khr_device_group_creation {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_device_group_creation")?;
+ }
+ if self.khr_display {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_display")?;
+ }
+ if self.khr_external_fence_capabilities {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_external_fence_capabilities")?;
+ }
+ if self.khr_external_memory_capabilities {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_external_memory_capabilities")?;
+ }
+ if self.khr_external_semaphore_capabilities {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_external_semaphore_capabilities")?;
+ }
+ if self.khr_get_display_properties2 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_get_display_properties2")?;
+ }
+ if self.khr_get_physical_device_properties2 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_get_physical_device_properties2")?;
+ }
+ if self.khr_get_surface_capabilities2 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_get_surface_capabilities2")?;
+ }
+ if self.khr_portability_enumeration {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_portability_enumeration")?;
+ }
+ if self.khr_surface {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_surface")?;
+ }
+ if self.khr_surface_protected_capabilities {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_surface_protected_capabilities")?;
+ }
+ if self.khr_wayland_surface {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_wayland_surface")?;
+ }
+ if self.khr_win32_surface {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_win32_surface")?;
+ }
+ if self.khr_xcb_surface {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_xcb_surface")?;
+ }
+ if self.khr_xlib_surface {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_KHR_xlib_surface")?;
+ }
+ if self.ext_acquire_drm_display {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_acquire_drm_display")?;
+ }
+ if self.ext_acquire_xlib_display {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_acquire_xlib_display")?;
+ }
+ if self.ext_debug_report {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_debug_report")?;
+ }
+ if self.ext_debug_utils {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_debug_utils")?;
+ }
+ if self.ext_direct_mode_display {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_direct_mode_display")?;
+ }
+ if self.ext_directfb_surface {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_directfb_surface")?;
+ }
+ if self.ext_display_surface_counter {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_display_surface_counter")?;
+ }
+ if self.ext_headless_surface {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_headless_surface")?;
+ }
+ if self.ext_metal_surface {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_metal_surface")?;
+ }
+ if self.ext_surface_maintenance1 {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_surface_maintenance1")?;
+ }
+ if self.ext_swapchain_colorspace {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_swapchain_colorspace")?;
+ }
+ if self.ext_validation_features {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_validation_features")?;
+ }
+ if self.ext_validation_flags {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_EXT_validation_flags")?;
+ }
+ if self.fuchsia_imagepipe_surface {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_FUCHSIA_imagepipe_surface")?;
+ }
+ if self.ggp_stream_descriptor_surface {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_GGP_stream_descriptor_surface")?;
+ }
+ if self.google_surfaceless_query {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_GOOGLE_surfaceless_query")?;
+ }
+ if self.lunarg_direct_driver_loading {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_LUNARG_direct_driver_loading")?;
+ }
+ if self.mvk_ios_surface {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_MVK_ios_surface")?;
+ }
+ if self.mvk_macos_surface {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_MVK_macos_surface")?;
+ }
+ if self.nn_vi_surface {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NN_vi_surface")?;
+ }
+ if self.nv_external_memory_capabilities {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_NV_external_memory_capabilities")?;
+ }
+ if self.qnx_screen_surface {
+ if !first {
+ write!(f, ", ")?
+ } else {
+ first = false;
+ }
+ f.write_str("VK_QNX_screen_surface")?;
+ }
+ write!(f, "]")
+ }
+}
+impl<'a> FromIterator<&'a str> for InstanceExtensions {
+ fn from_iter<I>(iter: I) -> Self
+ where
+ I: IntoIterator<Item = &'a str>,
+ {
+ let mut extensions = Self::empty();
+ for name in iter {
+ match name {
+ "VK_KHR_android_surface" => {
+ extensions.khr_android_surface = true;
+ }
+ "VK_KHR_device_group_creation" => {
+ extensions.khr_device_group_creation = true;
+ }
+ "VK_KHR_display" => {
+ extensions.khr_display = true;
+ }
+ "VK_KHR_external_fence_capabilities" => {
+ extensions.khr_external_fence_capabilities = true;
+ }
+ "VK_KHR_external_memory_capabilities" => {
+ extensions.khr_external_memory_capabilities = true;
+ }
+ "VK_KHR_external_semaphore_capabilities" => {
+ extensions.khr_external_semaphore_capabilities = true;
+ }
+ "VK_KHR_get_display_properties2" => {
+ extensions.khr_get_display_properties2 = true;
+ }
+ "VK_KHR_get_physical_device_properties2" => {
+ extensions.khr_get_physical_device_properties2 = true;
+ }
+ "VK_KHR_get_surface_capabilities2" => {
+ extensions.khr_get_surface_capabilities2 = true;
+ }
+ "VK_KHR_portability_enumeration" => {
+ extensions.khr_portability_enumeration = true;
+ }
+ "VK_KHR_surface" => {
+ extensions.khr_surface = true;
+ }
+ "VK_KHR_surface_protected_capabilities" => {
+ extensions.khr_surface_protected_capabilities = true;
+ }
+ "VK_KHR_wayland_surface" => {
+ extensions.khr_wayland_surface = true;
+ }
+ "VK_KHR_win32_surface" => {
+ extensions.khr_win32_surface = true;
+ }
+ "VK_KHR_xcb_surface" => {
+ extensions.khr_xcb_surface = true;
+ }
+ "VK_KHR_xlib_surface" => {
+ extensions.khr_xlib_surface = true;
+ }
+ "VK_EXT_acquire_drm_display" => {
+ extensions.ext_acquire_drm_display = true;
+ }
+ "VK_EXT_acquire_xlib_display" => {
+ extensions.ext_acquire_xlib_display = true;
+ }
+ "VK_EXT_debug_report" => {
+ extensions.ext_debug_report = true;
+ }
+ "VK_EXT_debug_utils" => {
+ extensions.ext_debug_utils = true;
+ }
+ "VK_EXT_direct_mode_display" => {
+ extensions.ext_direct_mode_display = true;
+ }
+ "VK_EXT_directfb_surface" => {
+ extensions.ext_directfb_surface = true;
+ }
+ "VK_EXT_display_surface_counter" => {
+ extensions.ext_display_surface_counter = true;
+ }
+ "VK_EXT_headless_surface" => {
+ extensions.ext_headless_surface = true;
+ }
+ "VK_EXT_metal_surface" => {
+ extensions.ext_metal_surface = true;
+ }
+ "VK_EXT_surface_maintenance1" => {
+ extensions.ext_surface_maintenance1 = true;
+ }
+ "VK_EXT_swapchain_colorspace" => {
+ extensions.ext_swapchain_colorspace = true;
+ }
+ "VK_EXT_validation_features" => {
+ extensions.ext_validation_features = true;
+ }
+ "VK_EXT_validation_flags" => {
+ extensions.ext_validation_flags = true;
+ }
+ "VK_FUCHSIA_imagepipe_surface" => {
+ extensions.fuchsia_imagepipe_surface = true;
+ }
+ "VK_GGP_stream_descriptor_surface" => {
+ extensions.ggp_stream_descriptor_surface = true;
+ }
+ "VK_GOOGLE_surfaceless_query" => {
+ extensions.google_surfaceless_query = true;
+ }
+ "VK_LUNARG_direct_driver_loading" => {
+ extensions.lunarg_direct_driver_loading = true;
+ }
+ "VK_MVK_ios_surface" => {
+ extensions.mvk_ios_surface = true;
+ }
+ "VK_MVK_macos_surface" => {
+ extensions.mvk_macos_surface = true;
+ }
+ "VK_NN_vi_surface" => {
+ extensions.nn_vi_surface = true;
+ }
+ "VK_NV_external_memory_capabilities" => {
+ extensions.nv_external_memory_capabilities = true;
+ }
+ "VK_QNX_screen_surface" => {
+ extensions.qnx_screen_surface = true;
+ }
+ _ => (),
+ }
+ }
+ extensions
+ }
+}
+impl<'a> From<&'a InstanceExtensions> for Vec<std::ffi::CString> {
+ fn from(x: &'a InstanceExtensions) -> Self {
+ let mut data = Self::new();
+ if x.khr_android_surface {
+ data.push(std::ffi::CString::new("VK_KHR_android_surface").unwrap());
+ }
+ if x.khr_device_group_creation {
+ data.push(std::ffi::CString::new("VK_KHR_device_group_creation").unwrap());
+ }
+ if x.khr_display {
+ data.push(std::ffi::CString::new("VK_KHR_display").unwrap());
+ }
+ if x.khr_external_fence_capabilities {
+ data.push(std::ffi::CString::new("VK_KHR_external_fence_capabilities").unwrap());
+ }
+ if x.khr_external_memory_capabilities {
+ data.push(std::ffi::CString::new("VK_KHR_external_memory_capabilities").unwrap());
+ }
+ if x.khr_external_semaphore_capabilities {
+ data.push(std::ffi::CString::new("VK_KHR_external_semaphore_capabilities").unwrap());
+ }
+ if x.khr_get_display_properties2 {
+ data.push(std::ffi::CString::new("VK_KHR_get_display_properties2").unwrap());
+ }
+ if x.khr_get_physical_device_properties2 {
+ data.push(std::ffi::CString::new("VK_KHR_get_physical_device_properties2").unwrap());
+ }
+ if x.khr_get_surface_capabilities2 {
+ data.push(std::ffi::CString::new("VK_KHR_get_surface_capabilities2").unwrap());
+ }
+ if x.khr_portability_enumeration {
+ data.push(std::ffi::CString::new("VK_KHR_portability_enumeration").unwrap());
+ }
+ if x.khr_surface {
+ data.push(std::ffi::CString::new("VK_KHR_surface").unwrap());
+ }
+ if x.khr_surface_protected_capabilities {
+ data.push(std::ffi::CString::new("VK_KHR_surface_protected_capabilities").unwrap());
+ }
+ if x.khr_wayland_surface {
+ data.push(std::ffi::CString::new("VK_KHR_wayland_surface").unwrap());
+ }
+ if x.khr_win32_surface {
+ data.push(std::ffi::CString::new("VK_KHR_win32_surface").unwrap());
+ }
+ if x.khr_xcb_surface {
+ data.push(std::ffi::CString::new("VK_KHR_xcb_surface").unwrap());
+ }
+ if x.khr_xlib_surface {
+ data.push(std::ffi::CString::new("VK_KHR_xlib_surface").unwrap());
+ }
+ if x.ext_acquire_drm_display {
+ data.push(std::ffi::CString::new("VK_EXT_acquire_drm_display").unwrap());
+ }
+ if x.ext_acquire_xlib_display {
+ data.push(std::ffi::CString::new("VK_EXT_acquire_xlib_display").unwrap());
+ }
+ if x.ext_debug_report {
+ data.push(std::ffi::CString::new("VK_EXT_debug_report").unwrap());
+ }
+ if x.ext_debug_utils {
+ data.push(std::ffi::CString::new("VK_EXT_debug_utils").unwrap());
+ }
+ if x.ext_direct_mode_display {
+ data.push(std::ffi::CString::new("VK_EXT_direct_mode_display").unwrap());
+ }
+ if x.ext_directfb_surface {
+ data.push(std::ffi::CString::new("VK_EXT_directfb_surface").unwrap());
+ }
+ if x.ext_display_surface_counter {
+ data.push(std::ffi::CString::new("VK_EXT_display_surface_counter").unwrap());
+ }
+ if x.ext_headless_surface {
+ data.push(std::ffi::CString::new("VK_EXT_headless_surface").unwrap());
+ }
+ if x.ext_metal_surface {
+ data.push(std::ffi::CString::new("VK_EXT_metal_surface").unwrap());
+ }
+ if x.ext_surface_maintenance1 {
+ data.push(std::ffi::CString::new("VK_EXT_surface_maintenance1").unwrap());
+ }
+ if x.ext_swapchain_colorspace {
+ data.push(std::ffi::CString::new("VK_EXT_swapchain_colorspace").unwrap());
+ }
+ if x.ext_validation_features {
+ data.push(std::ffi::CString::new("VK_EXT_validation_features").unwrap());
+ }
+ if x.ext_validation_flags {
+ data.push(std::ffi::CString::new("VK_EXT_validation_flags").unwrap());
+ }
+ if x.fuchsia_imagepipe_surface {
+ data.push(std::ffi::CString::new("VK_FUCHSIA_imagepipe_surface").unwrap());
+ }
+ if x.ggp_stream_descriptor_surface {
+ data.push(std::ffi::CString::new("VK_GGP_stream_descriptor_surface").unwrap());
+ }
+ if x.google_surfaceless_query {
+ data.push(std::ffi::CString::new("VK_GOOGLE_surfaceless_query").unwrap());
+ }
+ if x.lunarg_direct_driver_loading {
+ data.push(std::ffi::CString::new("VK_LUNARG_direct_driver_loading").unwrap());
+ }
+ if x.mvk_ios_surface {
+ data.push(std::ffi::CString::new("VK_MVK_ios_surface").unwrap());
+ }
+ if x.mvk_macos_surface {
+ data.push(std::ffi::CString::new("VK_MVK_macos_surface").unwrap());
+ }
+ if x.nn_vi_surface {
+ data.push(std::ffi::CString::new("VK_NN_vi_surface").unwrap());
+ }
+ if x.nv_external_memory_capabilities {
+ data.push(std::ffi::CString::new("VK_NV_external_memory_capabilities").unwrap());
+ }
+ if x.qnx_screen_surface {
+ data.push(std::ffi::CString::new("VK_QNX_screen_surface").unwrap());
+ }
+ data
+ }
+}
+impl IntoIterator for InstanceExtensions {
+ type Item = (&'static str, bool);
+ type IntoIter = std::array::IntoIter<Self::Item, 38usize>;
+ #[inline]
+ fn into_iter(self) -> Self::IntoIter {
+ [
+ ("VK_KHR_android_surface", self.khr_android_surface),
+ (
+ "VK_KHR_device_group_creation",
+ self.khr_device_group_creation,
+ ),
+ ("VK_KHR_display", self.khr_display),
+ (
+ "VK_KHR_external_fence_capabilities",
+ self.khr_external_fence_capabilities,
+ ),
+ (
+ "VK_KHR_external_memory_capabilities",
+ self.khr_external_memory_capabilities,
+ ),
+ (
+ "VK_KHR_external_semaphore_capabilities",
+ self.khr_external_semaphore_capabilities,
+ ),
+ (
+ "VK_KHR_get_display_properties2",
+ self.khr_get_display_properties2,
+ ),
+ (
+ "VK_KHR_get_physical_device_properties2",
+ self.khr_get_physical_device_properties2,
+ ),
+ (
+ "VK_KHR_get_surface_capabilities2",
+ self.khr_get_surface_capabilities2,
+ ),
+ (
+ "VK_KHR_portability_enumeration",
+ self.khr_portability_enumeration,
+ ),
+ ("VK_KHR_surface", self.khr_surface),
+ (
+ "VK_KHR_surface_protected_capabilities",
+ self.khr_surface_protected_capabilities,
+ ),
+ ("VK_KHR_wayland_surface", self.khr_wayland_surface),
+ ("VK_KHR_win32_surface", self.khr_win32_surface),
+ ("VK_KHR_xcb_surface", self.khr_xcb_surface),
+ ("VK_KHR_xlib_surface", self.khr_xlib_surface),
+ ("VK_EXT_acquire_drm_display", self.ext_acquire_drm_display),
+ ("VK_EXT_acquire_xlib_display", self.ext_acquire_xlib_display),
+ ("VK_EXT_debug_report", self.ext_debug_report),
+ ("VK_EXT_debug_utils", self.ext_debug_utils),
+ ("VK_EXT_direct_mode_display", self.ext_direct_mode_display),
+ ("VK_EXT_directfb_surface", self.ext_directfb_surface),
+ (
+ "VK_EXT_display_surface_counter",
+ self.ext_display_surface_counter,
+ ),
+ ("VK_EXT_headless_surface", self.ext_headless_surface),
+ ("VK_EXT_metal_surface", self.ext_metal_surface),
+ ("VK_EXT_surface_maintenance1", self.ext_surface_maintenance1),
+ ("VK_EXT_swapchain_colorspace", self.ext_swapchain_colorspace),
+ ("VK_EXT_validation_features", self.ext_validation_features),
+ ("VK_EXT_validation_flags", self.ext_validation_flags),
+ (
+ "VK_FUCHSIA_imagepipe_surface",
+ self.fuchsia_imagepipe_surface,
+ ),
+ (
+ "VK_GGP_stream_descriptor_surface",
+ self.ggp_stream_descriptor_surface,
+ ),
+ ("VK_GOOGLE_surfaceless_query", self.google_surfaceless_query),
+ (
+ "VK_LUNARG_direct_driver_loading",
+ self.lunarg_direct_driver_loading,
+ ),
+ ("VK_MVK_ios_surface", self.mvk_ios_surface),
+ ("VK_MVK_macos_surface", self.mvk_macos_surface),
+ ("VK_NN_vi_surface", self.nn_vi_surface),
+ (
+ "VK_NV_external_memory_capabilities",
+ self.nv_external_memory_capabilities,
+ ),
+ ("VK_QNX_screen_surface", self.qnx_screen_surface),
+ ]
+ .into_iter()
+ }
+}
+impl InstanceExtensions {
+ #[doc = r" Checks enabled extensions against the instance version and each other."]
+ pub(super) fn check_requirements(
+ &self,
+ supported: &InstanceExtensions,
+ api_version: crate::Version,
+ ) -> Result<(), crate::instance::ExtensionRestrictionError> {
+ let instance_extensions = self;
+ if self.khr_android_surface {
+ if !supported.khr_android_surface {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "khr_android_surface",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(instance_extensions.khr_surface) {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "khr_android_surface",
+ restriction: crate::instance::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_surface"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ }
+ if self.khr_device_group_creation {
+ if !supported.khr_device_group_creation {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "khr_device_group_creation",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ }
+ if self.khr_display {
+ if !supported.khr_display {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "khr_display",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(instance_extensions.khr_surface) {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "khr_display",
+ restriction: crate::instance::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_surface"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ }
+ if self.khr_external_fence_capabilities {
+ if !supported.khr_external_fence_capabilities {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "khr_external_fence_capabilities",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "khr_external_fence_capabilities",
+ restriction: crate::instance::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ }
+ if self.khr_external_memory_capabilities {
+ if !supported.khr_external_memory_capabilities {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "khr_external_memory_capabilities",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "khr_external_memory_capabilities",
+ restriction: crate::instance::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ }
+ if self.khr_external_semaphore_capabilities {
+ if !supported.khr_external_semaphore_capabilities {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "khr_external_semaphore_capabilities",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1
+ || instance_extensions.khr_get_physical_device_properties2)
+ {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "khr_external_semaphore_capabilities",
+ restriction: crate::instance::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &["khr_get_physical_device_properties2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ }
+ if self.khr_get_display_properties2 {
+ if !supported.khr_get_display_properties2 {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "khr_get_display_properties2",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(instance_extensions.khr_display) {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "khr_get_display_properties2",
+ restriction: crate::instance::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_display"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ }
+ if self.khr_get_physical_device_properties2 {
+ if !supported.khr_get_physical_device_properties2 {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "khr_get_physical_device_properties2",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ }
+ if self.khr_get_surface_capabilities2 {
+ if !supported.khr_get_surface_capabilities2 {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "khr_get_surface_capabilities2",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(instance_extensions.khr_surface) {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "khr_get_surface_capabilities2",
+ restriction: crate::instance::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_surface"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ }
+ if self.khr_portability_enumeration {
+ if !supported.khr_portability_enumeration {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "khr_portability_enumeration",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ }
+ if self.khr_surface {
+ if !supported.khr_surface {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "khr_surface",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ }
+ if self.khr_surface_protected_capabilities {
+ if !supported.khr_surface_protected_capabilities {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "khr_surface_protected_capabilities",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(api_version >= crate::Version::V1_1) {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "khr_surface_protected_capabilities",
+ restriction: crate::instance::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: Some(crate::Version::V1_1),
+ device_extensions: &[],
+ instance_extensions: &[],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(instance_extensions.khr_get_surface_capabilities2) {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "khr_surface_protected_capabilities",
+ restriction: crate::instance::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_get_surface_capabilities2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ }
+ if self.khr_wayland_surface {
+ if !supported.khr_wayland_surface {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "khr_wayland_surface",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(instance_extensions.khr_surface) {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "khr_wayland_surface",
+ restriction: crate::instance::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_surface"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ }
+ if self.khr_win32_surface {
+ if !supported.khr_win32_surface {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "khr_win32_surface",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(instance_extensions.khr_surface) {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "khr_win32_surface",
+ restriction: crate::instance::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_surface"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ }
+ if self.khr_xcb_surface {
+ if !supported.khr_xcb_surface {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "khr_xcb_surface",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(instance_extensions.khr_surface) {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "khr_xcb_surface",
+ restriction: crate::instance::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_surface"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ }
+ if self.khr_xlib_surface {
+ if !supported.khr_xlib_surface {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "khr_xlib_surface",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(instance_extensions.khr_surface) {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "khr_xlib_surface",
+ restriction: crate::instance::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_surface"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ }
+ if self.ext_acquire_drm_display {
+ if !supported.ext_acquire_drm_display {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "ext_acquire_drm_display",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(instance_extensions.ext_direct_mode_display) {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "ext_acquire_drm_display",
+ restriction: crate::instance::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["ext_direct_mode_display"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ }
+ if self.ext_acquire_xlib_display {
+ if !supported.ext_acquire_xlib_display {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "ext_acquire_xlib_display",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(instance_extensions.ext_direct_mode_display) {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "ext_acquire_xlib_display",
+ restriction: crate::instance::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["ext_direct_mode_display"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ }
+ if self.ext_debug_report {
+ if !supported.ext_debug_report {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "ext_debug_report",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ }
+ if self.ext_debug_utils {
+ if !supported.ext_debug_utils {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "ext_debug_utils",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ }
+ if self.ext_direct_mode_display {
+ if !supported.ext_direct_mode_display {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "ext_direct_mode_display",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(instance_extensions.khr_display) {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "ext_direct_mode_display",
+ restriction: crate::instance::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_display"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ }
+ if self.ext_directfb_surface {
+ if !supported.ext_directfb_surface {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "ext_directfb_surface",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(instance_extensions.khr_surface) {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "ext_directfb_surface",
+ restriction: crate::instance::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_surface"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ }
+ if self.ext_display_surface_counter {
+ if !supported.ext_display_surface_counter {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "ext_display_surface_counter",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(instance_extensions.khr_display) {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "ext_display_surface_counter",
+ restriction: crate::instance::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_display"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ }
+ if self.ext_headless_surface {
+ if !supported.ext_headless_surface {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "ext_headless_surface",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(instance_extensions.khr_surface) {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "ext_headless_surface",
+ restriction: crate::instance::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_surface"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ }
+ if self.ext_metal_surface {
+ if !supported.ext_metal_surface {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "ext_metal_surface",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(instance_extensions.khr_surface) {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "ext_metal_surface",
+ restriction: crate::instance::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_surface"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ }
+ if self.ext_surface_maintenance1 {
+ if !supported.ext_surface_maintenance1 {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "ext_surface_maintenance1",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(instance_extensions.khr_surface) {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "ext_surface_maintenance1",
+ restriction: crate::instance::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_surface"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ if !(instance_extensions.khr_get_surface_capabilities2) {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "ext_surface_maintenance1",
+ restriction: crate::instance::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_get_surface_capabilities2"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ }
+ if self.ext_swapchain_colorspace {
+ if !supported.ext_swapchain_colorspace {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "ext_swapchain_colorspace",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(instance_extensions.khr_surface) {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "ext_swapchain_colorspace",
+ restriction: crate::instance::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_surface"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ }
+ if self.ext_validation_features {
+ if !supported.ext_validation_features {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "ext_validation_features",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ }
+ if self.ext_validation_flags {
+ if !supported.ext_validation_flags {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "ext_validation_flags",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ }
+ if self.fuchsia_imagepipe_surface {
+ if !supported.fuchsia_imagepipe_surface {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "fuchsia_imagepipe_surface",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(instance_extensions.khr_surface) {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "fuchsia_imagepipe_surface",
+ restriction: crate::instance::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_surface"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ }
+ if self.ggp_stream_descriptor_surface {
+ if !supported.ggp_stream_descriptor_surface {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "ggp_stream_descriptor_surface",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(instance_extensions.khr_surface) {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "ggp_stream_descriptor_surface",
+ restriction: crate::instance::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_surface"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ }
+ if self.google_surfaceless_query {
+ if !supported.google_surfaceless_query {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "google_surfaceless_query",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(instance_extensions.khr_surface) {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "google_surfaceless_query",
+ restriction: crate::instance::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_surface"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ }
+ if self.lunarg_direct_driver_loading {
+ if !supported.lunarg_direct_driver_loading {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "lunarg_direct_driver_loading",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ }
+ if self.mvk_ios_surface {
+ if !supported.mvk_ios_surface {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "mvk_ios_surface",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(instance_extensions.khr_surface) {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "mvk_ios_surface",
+ restriction: crate::instance::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_surface"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ }
+ if self.mvk_macos_surface {
+ if !supported.mvk_macos_surface {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "mvk_macos_surface",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(instance_extensions.khr_surface) {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "mvk_macos_surface",
+ restriction: crate::instance::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_surface"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ }
+ if self.nn_vi_surface {
+ if !supported.nn_vi_surface {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "nn_vi_surface",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(instance_extensions.khr_surface) {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "nn_vi_surface",
+ restriction: crate::instance::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_surface"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ }
+ if self.nv_external_memory_capabilities {
+ if !supported.nv_external_memory_capabilities {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "nv_external_memory_capabilities",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ }
+ if self.qnx_screen_surface {
+ if !supported.qnx_screen_surface {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "qnx_screen_surface",
+ restriction: crate::instance::ExtensionRestriction::NotSupported,
+ });
+ }
+ if !(instance_extensions.khr_surface) {
+ return Err(crate::instance::ExtensionRestrictionError {
+ extension: "qnx_screen_surface",
+ restriction: crate::instance::ExtensionRestriction::Requires(
+ crate::RequiresOneOf {
+ api_version: None,
+ device_extensions: &[],
+ instance_extensions: &["khr_surface"],
+ ..Default::default()
+ },
+ ),
+ });
+ }
+ }
+ Ok(())
+ }
+}
diff --git a/out/properties.rs b/out/properties.rs
new file mode 100644
index 0000000..8ae2135
--- /dev/null
+++ b/out/properties.rs
@@ -0,0 +1,1812 @@
+// This file is auto-generated by vulkano autogen from vk.xml header version 1.3.238.
+// It should not be edited manually. Changes should be made by editing autogen.
+
+#[doc = r" Represents all the properties of a physical device."]
+#[doc = r""]
+#[doc = r" Depending on the highest version of Vulkan supported by the physical device, and the"]
+#[doc = r" available extensions, not every property may be available. For that reason, some"]
+#[doc = r" properties are wrapped in an `Option`."]
+#[derive(Clone, Debug)]
+pub struct Properties {
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-accelerationStructureCaptureReplayDescriptorDataSize)"]
+ pub acceleration_structure_capture_replay_descriptor_data_size: Option<usize>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-accelerationStructureDescriptorSize)"]
+ pub acceleration_structure_descriptor_size: Option<usize>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderCoreProperties2AMD.html#limits-activeComputeUnitCount)"]
+ pub active_compute_unit_count: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT.html#limits-advancedBlendAllOperations)"]
+ pub advanced_blend_all_operations: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT.html#limits-advancedBlendCorrelatedOverlap)"]
+ pub advanced_blend_correlated_overlap: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT.html#limits-advancedBlendIndependentBlend)"]
+ pub advanced_blend_independent_blend: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT.html#limits-advancedBlendMaxColorAttachments)"]
+ pub advanced_blend_max_color_attachments: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT.html#limits-advancedBlendNonPremultipliedDstColor)"]
+ pub advanced_blend_non_premultiplied_dst_color: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT.html#limits-advancedBlendNonPremultipliedSrcColor)"]
+ pub advanced_blend_non_premultiplied_src_color: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePerformanceQueryPropertiesKHR.html#limits-allowCommandBufferQueryCopies)"]
+ pub allow_command_buffer_query_copies: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-allowSamplerImageViewPostSubmitCreation)"]
+ pub allow_sampler_image_view_post_submit_creation: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceProperties.html#limits-apiVersion)"]
+ pub api_version: Version,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceOpticalFlowPropertiesNV.html#limits-bidirectionalFlowSupported)"]
+ pub bidirectional_flow_supported: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-bufferCaptureReplayDescriptorDataSize)"]
+ pub buffer_capture_replay_descriptor_data_size: Option<usize>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-bufferImageGranularity)"]
+ pub buffer_image_granularity: DeviceAlignment,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-bufferlessPushDescriptors)"]
+ pub bufferless_push_descriptors: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferDensityMapPropertiesEXT.html#limits-combinedImageSamplerDensityMapDescriptorSize)"]
+ pub combined_image_sampler_density_map_descriptor_size: Option<usize>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-combinedImageSamplerDescriptorSingleArray)"]
+ pub combined_image_sampler_descriptor_single_array: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-combinedImageSamplerDescriptorSize)"]
+ pub combined_image_sampler_descriptor_size: Option<usize>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderCorePropertiesAMD.html#limits-computeUnitsPerShaderArray)"]
+ pub compute_units_per_shader_array: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-conformanceVersion)"]
+ pub conformance_version: Option<ConformanceVersion>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceConservativeRasterizationPropertiesEXT.html#limits-conservativePointAndLineRasterization)"]
+ pub conservative_point_and_line_rasterization: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceConservativeRasterizationPropertiesEXT.html#limits-conservativeRasterizationPostDepthCoverage)"]
+ pub conservative_rasterization_post_depth_coverage: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceCooperativeMatrixPropertiesNV.html#limits-cooperativeMatrixSupportedStages)"]
+ pub cooperative_matrix_supported_stages: Option<ShaderStages>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceOpticalFlowPropertiesNV.html#limits-costSupported)"]
+ pub cost_supported: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMemoryDecompressionPropertiesNV.html#limits-decompressionMethods)"]
+ pub decompression_methods: Option<MemoryDecompressionMethods>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePipelineRobustnessPropertiesEXT.html#limits-defaultRobustnessImages)"]
+ pub default_robustness_images: Option<PipelineRobustnessImageBehavior>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePipelineRobustnessPropertiesEXT.html#limits-defaultRobustnessStorageBuffers)"]
+ pub default_robustness_storage_buffers: Option<PipelineRobustnessBufferBehavior>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePipelineRobustnessPropertiesEXT.html#limits-defaultRobustnessUniformBuffers)"]
+ pub default_robustness_uniform_buffers: Option<PipelineRobustnessBufferBehavior>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePipelineRobustnessPropertiesEXT.html#limits-defaultRobustnessVertexInputs)"]
+ pub default_robustness_vertex_inputs: Option<PipelineRobustnessBufferBehavior>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceConservativeRasterizationPropertiesEXT.html#limits-degenerateLinesRasterized)"]
+ pub degenerate_lines_rasterized: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceConservativeRasterizationPropertiesEXT.html#limits-degenerateTrianglesRasterized)"]
+ pub degenerate_triangles_rasterized: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-denormBehaviorIndependence)"]
+ pub denorm_behavior_independence: Option<ShaderFloatControlsIndependence>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-descriptorBufferAddressSpaceSize)"]
+ pub descriptor_buffer_address_space_size: Option<DeviceSize>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-descriptorBufferOffsetAlignment)"]
+ pub descriptor_buffer_offset_alignment: Option<DeviceSize>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceProperties.html#limits-deviceID)"]
+ pub device_id: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan11Properties.html#limits-deviceLUID)"]
+ pub device_luid: Option<[u8; 8]>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan11Properties.html#limits-deviceLUIDValid)"]
+ pub device_luid_valid: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceProperties.html#limits-deviceName)"]
+ pub device_name: String,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan11Properties.html#limits-deviceNodeMask)"]
+ pub device_node_mask: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceProperties.html#limits-deviceType)"]
+ pub device_type: PhysicalDeviceType,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan11Properties.html#limits-deviceUUID)"]
+ pub device_uuid: Option<[u8; 16]>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-discreteQueuePriorities)"]
+ pub discrete_queue_priorities: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-driverID)"]
+ pub driver_id: Option<DriverId>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-driverInfo)"]
+ pub driver_info: Option<String>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-driverName)"]
+ pub driver_name: Option<String>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan11Properties.html#limits-driverUUID)"]
+ pub driver_uuid: Option<[u8; 16]>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceProperties.html#limits-driverVersion)"]
+ pub driver_version: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExtendedDynamicState3PropertiesEXT.html#limits-dynamicPrimitiveTopologyUnrestricted)"]
+ pub dynamic_primitive_topology_unrestricted: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceConservativeRasterizationPropertiesEXT.html#limits-extraPrimitiveOverestimationSizeGranularity)"]
+ pub extra_primitive_overestimation_size_granularity: Option<f32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-filterMinmaxImageComponentMapping)"]
+ pub filter_minmax_image_component_mapping: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-filterMinmaxSingleComponentFormats)"]
+ pub filter_minmax_single_component_formats: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentDensityMapPropertiesEXT.html#limits-fragmentDensityInvocations)"]
+ pub fragment_density_invocations: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentDensityMapOffsetPropertiesQCOM.html#limits-fragmentDensityOffsetGranularity)"]
+ pub fragment_density_offset_granularity: Option<[u32; 2]>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-fragmentShadingRateNonTrivialCombinerOps)"]
+ pub fragment_shading_rate_non_trivial_combiner_ops: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-fragmentShadingRateStrictMultiplyCombiner)"]
+ pub fragment_shading_rate_strict_multiply_combiner: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-fragmentShadingRateWithConservativeRasterization)"]
+ pub fragment_shading_rate_with_conservative_rasterization: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-fragmentShadingRateWithCustomSampleLocations)"]
+ pub fragment_shading_rate_with_custom_sample_locations: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-fragmentShadingRateWithFragmentShaderInterlock)"]
+ pub fragment_shading_rate_with_fragment_shader_interlock: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-fragmentShadingRateWithSampleMask)"]
+ pub fragment_shading_rate_with_sample_mask: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-fragmentShadingRateWithShaderDepthStencilWrites)"]
+ pub fragment_shading_rate_with_shader_depth_stencil_writes: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-fragmentShadingRateWithShaderSampleMask)"]
+ pub fragment_shading_rate_with_shader_sample_mask: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-framebufferColorSampleCounts)"]
+ pub framebuffer_color_sample_counts: SampleCounts,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-framebufferDepthSampleCounts)"]
+ pub framebuffer_depth_sample_counts: SampleCounts,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-framebufferIntegerColorSampleCounts)"]
+ pub framebuffer_integer_color_sample_counts: Option<SampleCounts>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-framebufferNoAttachmentsSampleCounts)"]
+ pub framebuffer_no_attachments_sample_counts: SampleCounts,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-framebufferStencilSampleCounts)"]
+ pub framebuffer_stencil_sample_counts: SampleCounts,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceConservativeRasterizationPropertiesEXT.html#limits-fullyCoveredFragmentShaderInputVariable)"]
+ pub fully_covered_fragment_shader_input_variable: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceOpticalFlowPropertiesNV.html#limits-globalFlowSupported)"]
+ pub global_flow_supported: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT.html#limits-graphicsPipelineLibraryFastLinking)"]
+ pub graphics_pipeline_library_fast_linking: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT.html#limits-graphicsPipelineLibraryIndependentInterpolationDecoration)"]
+ pub graphics_pipeline_library_independent_interpolation_decoration: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDrmPropertiesEXT.html#limits-hasPrimary)"]
+ pub has_primary: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDrmPropertiesEXT.html#limits-hasRender)"]
+ pub has_render: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceOpticalFlowPropertiesNV.html#limits-hintSupported)"]
+ pub hint_supported: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-imageCaptureReplayDescriptorDataSize)"]
+ pub image_capture_replay_descriptor_data_size: Option<usize>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-imageViewCaptureReplayDescriptorDataSize)"]
+ pub image_view_capture_replay_descriptor_data_size: Option<usize>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-independentResolve)"]
+ pub independent_resolve: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-independentResolveNone)"]
+ pub independent_resolve_none: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-inputAttachmentDescriptorSize)"]
+ pub input_attachment_descriptor_size: Option<usize>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-integerDotProduct16BitMixedSignednessAccelerated)"]
+ pub integer_dot_product16_bit_mixed_signedness_accelerated: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-integerDotProduct16BitSignedAccelerated)"]
+ pub integer_dot_product16_bit_signed_accelerated: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-integerDotProduct16BitUnsignedAccelerated)"]
+ pub integer_dot_product16_bit_unsigned_accelerated: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-integerDotProduct32BitMixedSignednessAccelerated)"]
+ pub integer_dot_product32_bit_mixed_signedness_accelerated: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-integerDotProduct32BitSignedAccelerated)"]
+ pub integer_dot_product32_bit_signed_accelerated: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-integerDotProduct32BitUnsignedAccelerated)"]
+ pub integer_dot_product32_bit_unsigned_accelerated: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-integerDotProduct4x8BitPackedMixedSignednessAccelerated)"]
+ pub integer_dot_product4x8_bit_packed_mixed_signedness_accelerated: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-integerDotProduct4x8BitPackedSignedAccelerated)"]
+ pub integer_dot_product4x8_bit_packed_signed_accelerated: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-integerDotProduct4x8BitPackedUnsignedAccelerated)"]
+ pub integer_dot_product4x8_bit_packed_unsigned_accelerated: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-integerDotProduct64BitMixedSignednessAccelerated)"]
+ pub integer_dot_product64_bit_mixed_signedness_accelerated: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-integerDotProduct64BitSignedAccelerated)"]
+ pub integer_dot_product64_bit_signed_accelerated: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-integerDotProduct64BitUnsignedAccelerated)"]
+ pub integer_dot_product64_bit_unsigned_accelerated: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-integerDotProduct8BitMixedSignednessAccelerated)"]
+ pub integer_dot_product8_bit_mixed_signedness_accelerated: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-integerDotProduct8BitSignedAccelerated)"]
+ pub integer_dot_product8_bit_signed_accelerated: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-integerDotProduct8BitUnsignedAccelerated)"]
+ pub integer_dot_product8_bit_unsigned_accelerated: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated)"]
+ pub integer_dot_product_accumulating_saturating16_bit_mixed_signedness_accelerated:
+ Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-integerDotProductAccumulatingSaturating16BitSignedAccelerated)"]
+ pub integer_dot_product_accumulating_saturating16_bit_signed_accelerated: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-integerDotProductAccumulatingSaturating16BitUnsignedAccelerated)"]
+ pub integer_dot_product_accumulating_saturating16_bit_unsigned_accelerated: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated)"]
+ pub integer_dot_product_accumulating_saturating32_bit_mixed_signedness_accelerated:
+ Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-integerDotProductAccumulatingSaturating32BitSignedAccelerated)"]
+ pub integer_dot_product_accumulating_saturating32_bit_signed_accelerated: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-integerDotProductAccumulatingSaturating32BitUnsignedAccelerated)"]
+ pub integer_dot_product_accumulating_saturating32_bit_unsigned_accelerated: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated)"]
+ pub integer_dot_product_accumulating_saturating4x8_bit_packed_mixed_signedness_accelerated:
+ Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated)"]
+ pub integer_dot_product_accumulating_saturating4x8_bit_packed_signed_accelerated: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated)"]
+ pub integer_dot_product_accumulating_saturating4x8_bit_packed_unsigned_accelerated:
+ Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated)"]
+ pub integer_dot_product_accumulating_saturating64_bit_mixed_signedness_accelerated:
+ Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-integerDotProductAccumulatingSaturating64BitSignedAccelerated)"]
+ pub integer_dot_product_accumulating_saturating64_bit_signed_accelerated: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-integerDotProductAccumulatingSaturating64BitUnsignedAccelerated)"]
+ pub integer_dot_product_accumulating_saturating64_bit_unsigned_accelerated: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated)"]
+ pub integer_dot_product_accumulating_saturating8_bit_mixed_signedness_accelerated: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-integerDotProductAccumulatingSaturating8BitSignedAccelerated)"]
+ pub integer_dot_product_accumulating_saturating8_bit_signed_accelerated: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-integerDotProductAccumulatingSaturating8BitUnsignedAccelerated)"]
+ pub integer_dot_product_accumulating_saturating8_bit_unsigned_accelerated: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-layeredShadingRateAttachments)"]
+ pub layered_shading_rate_attachments: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLineRasterizationPropertiesEXT.html#limits-lineSubPixelPrecisionBits)"]
+ pub line_sub_pixel_precision_bits: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-lineWidthGranularity)"]
+ pub line_width_granularity: f32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-lineWidthRange)"]
+ pub line_width_range: [f32; 2],
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceImageProcessingPropertiesQCOM.html#limits-maxBlockMatchRegion)"]
+ pub max_block_match_region: Option<[u32; 2]>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxBoundDescriptorSets)"]
+ pub max_bound_descriptor_sets: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceImageProcessingPropertiesQCOM.html#limits-maxBoxFilterBlockSize)"]
+ pub max_box_filter_block_size: Option<[u32; 2]>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-maxBufferSize)"]
+ pub max_buffer_size: Option<DeviceSize>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxClipDistances)"]
+ pub max_clip_distances: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxColorAttachments)"]
+ pub max_color_attachments: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxCombinedClipAndCullDistances)"]
+ pub max_combined_clip_and_cull_distances: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxComputeSharedMemorySize)"]
+ pub max_compute_shared_memory_size: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxComputeWorkGroupCount)"]
+ pub max_compute_work_group_count: [u32; 3],
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxComputeWorkGroupInvocations)"]
+ pub max_compute_work_group_invocations: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxComputeWorkGroupSize)"]
+ pub max_compute_work_group_size: [u32; 3],
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-maxComputeWorkgroupSubgroups)"]
+ pub max_compute_workgroup_subgroups: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxCullDistances)"]
+ pub max_cull_distances: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceCustomBorderColorPropertiesEXT.html#limits-maxCustomBorderColorSamplers)"]
+ pub max_custom_border_color_samplers: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMemoryDecompressionPropertiesNV.html#limits-maxDecompressionIndirectCount)"]
+ pub max_decompression_indirect_count: Option<u64>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-maxDescriptorBufferBindings)"]
+ pub max_descriptor_buffer_bindings: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceAccelerationStructurePropertiesKHR.html#limits-maxDescriptorSetAccelerationStructures)"]
+ pub max_descriptor_set_acceleration_structures: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-maxDescriptorSetInlineUniformBlocks)"]
+ pub max_descriptor_set_inline_uniform_blocks: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxDescriptorSetInputAttachments)"]
+ pub max_descriptor_set_input_attachments: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxDescriptorSetSampledImages)"]
+ pub max_descriptor_set_sampled_images: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxDescriptorSetSamplers)"]
+ pub max_descriptor_set_samplers: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxDescriptorSetStorageBuffers)"]
+ pub max_descriptor_set_storage_buffers: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxDescriptorSetStorageBuffersDynamic)"]
+ pub max_descriptor_set_storage_buffers_dynamic: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxDescriptorSetStorageImages)"]
+ pub max_descriptor_set_storage_images: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentDensityMap2PropertiesEXT.html#limits-maxDescriptorSetSubsampledSamplers)"]
+ pub max_descriptor_set_subsampled_samplers: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxDescriptorSetUniformBuffers)"]
+ pub max_descriptor_set_uniform_buffers: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxDescriptorSetUniformBuffersDynamic)"]
+ pub max_descriptor_set_uniform_buffers_dynamic: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceAccelerationStructurePropertiesKHR.html#limits-maxDescriptorSetUpdateAfterBindAccelerationStructures)"]
+ pub max_descriptor_set_update_after_bind_acceleration_structures: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-maxDescriptorSetUpdateAfterBindInlineUniformBlocks)"]
+ pub max_descriptor_set_update_after_bind_inline_uniform_blocks: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxDescriptorSetUpdateAfterBindInputAttachments)"]
+ pub max_descriptor_set_update_after_bind_input_attachments: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxDescriptorSetUpdateAfterBindSampledImages)"]
+ pub max_descriptor_set_update_after_bind_sampled_images: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxDescriptorSetUpdateAfterBindSamplers)"]
+ pub max_descriptor_set_update_after_bind_samplers: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxDescriptorSetUpdateAfterBindStorageBuffers)"]
+ pub max_descriptor_set_update_after_bind_storage_buffers: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxDescriptorSetUpdateAfterBindStorageBuffersDynamic)"]
+ pub max_descriptor_set_update_after_bind_storage_buffers_dynamic: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxDescriptorSetUpdateAfterBindStorageImages)"]
+ pub max_descriptor_set_update_after_bind_storage_images: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxDescriptorSetUpdateAfterBindUniformBuffers)"]
+ pub max_descriptor_set_update_after_bind_uniform_buffers: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxDescriptorSetUpdateAfterBindUniformBuffersDynamic)"]
+ pub max_descriptor_set_update_after_bind_uniform_buffers_dynamic: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDiscardRectanglePropertiesEXT.html#limits-maxDiscardRectangles)"]
+ pub max_discard_rectangles: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxDrawIndexedIndexValue)"]
+ pub max_draw_indexed_index_value: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxDrawIndirectCount)"]
+ pub max_draw_indirect_count: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesNV.html#limits-maxDrawMeshTasksCount)"]
+ pub max_draw_mesh_tasks_count: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-maxEmbeddedImmutableSamplerBindings)"]
+ pub max_embedded_immutable_sampler_bindings: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-maxEmbeddedImmutableSamplers)"]
+ pub max_embedded_immutable_samplers: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceConservativeRasterizationPropertiesEXT.html#limits-maxExtraPrimitiveOverestimationSize)"]
+ pub max_extra_primitive_overestimation_size: Option<f32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxFragmentCombinedOutputResources)"]
+ pub max_fragment_combined_output_resources: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentDensityMapPropertiesEXT.html#limits-maxFragmentDensityTexelSize)"]
+ pub max_fragment_density_texel_size: Option<[u32; 2]>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxFragmentDualSrcAttachments)"]
+ pub max_fragment_dual_src_attachments: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxFragmentInputComponents)"]
+ pub max_fragment_input_components: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxFragmentOutputAttachments)"]
+ pub max_fragment_output_attachments: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-maxFragmentShadingRateAttachmentTexelSize)"]
+ pub max_fragment_shading_rate_attachment_texel_size: Option<[u32; 2]>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-maxFragmentShadingRateAttachmentTexelSizeAspectRatio)"]
+ pub max_fragment_shading_rate_attachment_texel_size_aspect_ratio: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-maxFragmentShadingRateCoverageSamples)"]
+ pub max_fragment_shading_rate_coverage_samples: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentShadingRateEnumsPropertiesNV.html#limits-maxFragmentShadingRateInvocationCount)"]
+ pub max_fragment_shading_rate_invocation_count: Option<SampleCount>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-maxFragmentShadingRateRasterizationSamples)"]
+ pub max_fragment_shading_rate_rasterization_samples: Option<SampleCount>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-maxFragmentSize)"]
+ pub max_fragment_size: Option<[u32; 2]>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-maxFragmentSizeAspectRatio)"]
+ pub max_fragment_size_aspect_ratio: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxFramebufferHeight)"]
+ pub max_framebuffer_height: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxFramebufferLayers)"]
+ pub max_framebuffer_layers: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxFramebufferWidth)"]
+ pub max_framebuffer_width: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceAccelerationStructurePropertiesKHR.html#limits-maxGeometryCount)"]
+ pub max_geometry_count: Option<u64>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxGeometryInputComponents)"]
+ pub max_geometry_input_components: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxGeometryOutputComponents)"]
+ pub max_geometry_output_components: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxGeometryOutputVertices)"]
+ pub max_geometry_output_vertices: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxGeometryShaderInvocations)"]
+ pub max_geometry_shader_invocations: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxGeometryTotalOutputComponents)"]
+ pub max_geometry_total_output_components: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV.html#limits-maxGraphicsShaderGroupCount)"]
+ pub max_graphics_shader_group_count: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceOpticalFlowPropertiesNV.html#limits-maxHeight)"]
+ pub max_height: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxImageArrayLayers)"]
+ pub max_image_array_layers: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxImageDimension1D)"]
+ pub max_image_dimension1_d: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxImageDimension2D)"]
+ pub max_image_dimension2_d: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxImageDimension3D)"]
+ pub max_image_dimension3_d: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxImageDimensionCube)"]
+ pub max_image_dimension_cube: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV.html#limits-maxIndirectCommandsStreamCount)"]
+ pub max_indirect_commands_stream_count: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV.html#limits-maxIndirectCommandsStreamStride)"]
+ pub max_indirect_commands_stream_stride: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV.html#limits-maxIndirectCommandsTokenCount)"]
+ pub max_indirect_commands_token_count: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV.html#limits-maxIndirectCommandsTokenOffset)"]
+ pub max_indirect_commands_token_offset: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV.html#limits-maxIndirectSequenceCount)"]
+ pub max_indirect_sequence_count: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-maxInlineUniformBlockSize)"]
+ pub max_inline_uniform_block_size: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-maxInlineUniformTotalSize)"]
+ pub max_inline_uniform_total_size: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceAccelerationStructurePropertiesKHR.html#limits-maxInstanceCount)"]
+ pub max_instance_count: Option<u64>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxInterpolationOffset)"]
+ pub max_interpolation_offset: f32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxMemoryAllocationCount)"]
+ pub max_memory_allocation_count: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan11Properties.html#limits-maxMemoryAllocationSize)"]
+ pub max_memory_allocation_size: Option<DeviceSize>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesEXT.html#limits-maxMeshMultiviewViewCount)"]
+ pub max_mesh_multiview_view_count: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesEXT.html#limits-maxMeshOutputComponents)"]
+ pub max_mesh_output_components: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesEXT.html#limits-maxMeshOutputLayers)"]
+ pub max_mesh_output_layers: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesEXT.html#limits-maxMeshOutputMemorySize)"]
+ pub max_mesh_output_memory_size: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesEXT.html#limits-maxMeshOutputPrimitives)"]
+ pub max_mesh_output_primitives: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesEXT.html#limits-maxMeshOutputVertices)"]
+ pub max_mesh_output_vertices: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesEXT.html#limits-maxMeshPayloadAndOutputMemorySize)"]
+ pub max_mesh_payload_and_output_memory_size: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesEXT.html#limits-maxMeshPayloadAndSharedMemorySize)"]
+ pub max_mesh_payload_and_shared_memory_size: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesEXT.html#limits-maxMeshSharedMemorySize)"]
+ pub max_mesh_shared_memory_size: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesNV.html#limits-maxMeshTotalMemorySize)"]
+ pub max_mesh_total_memory_size: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesEXT.html#limits-maxMeshWorkGroupCount)"]
+ pub max_mesh_work_group_count: Option<[u32; 3]>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesEXT.html#limits-maxMeshWorkGroupInvocations)"]
+ pub max_mesh_work_group_invocations: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesEXT.html#limits-maxMeshWorkGroupSize)"]
+ pub max_mesh_work_group_size: Option<[u32; 3]>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesEXT.html#limits-maxMeshWorkGroupTotalCount)"]
+ pub max_mesh_work_group_total_count: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMultiDrawPropertiesEXT.html#limits-maxMultiDrawCount)"]
+ pub max_multi_draw_count: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan11Properties.html#limits-maxMultiviewInstanceIndex)"]
+ pub max_multiview_instance_index: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan11Properties.html#limits-maxMultiviewViewCount)"]
+ pub max_multiview_view_count: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceOpticalFlowPropertiesNV.html#limits-maxNumRegionsOfInterest)"]
+ pub max_num_regions_of_interest: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceOpacityMicromapPropertiesEXT.html#limits-maxOpacity2StateSubdivisionLevel)"]
+ pub max_opacity2_state_subdivision_level: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceOpacityMicromapPropertiesEXT.html#limits-maxOpacity4StateSubdivisionLevel)"]
+ pub max_opacity4_state_subdivision_level: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan11Properties.html#limits-maxPerSetDescriptors)"]
+ pub max_per_set_descriptors: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceAccelerationStructurePropertiesKHR.html#limits-maxPerStageDescriptorAccelerationStructures)"]
+ pub max_per_stage_descriptor_acceleration_structures: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-maxPerStageDescriptorInlineUniformBlocks)"]
+ pub max_per_stage_descriptor_inline_uniform_blocks: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxPerStageDescriptorInputAttachments)"]
+ pub max_per_stage_descriptor_input_attachments: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxPerStageDescriptorSampledImages)"]
+ pub max_per_stage_descriptor_sampled_images: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxPerStageDescriptorSamplers)"]
+ pub max_per_stage_descriptor_samplers: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxPerStageDescriptorStorageBuffers)"]
+ pub max_per_stage_descriptor_storage_buffers: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxPerStageDescriptorStorageImages)"]
+ pub max_per_stage_descriptor_storage_images: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxPerStageDescriptorUniformBuffers)"]
+ pub max_per_stage_descriptor_uniform_buffers: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceAccelerationStructurePropertiesKHR.html#limits-maxPerStageDescriptorUpdateAfterBindAccelerationStructures)"]
+ pub max_per_stage_descriptor_update_after_bind_acceleration_structures: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks)"]
+ pub max_per_stage_descriptor_update_after_bind_inline_uniform_blocks: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxPerStageDescriptorUpdateAfterBindInputAttachments)"]
+ pub max_per_stage_descriptor_update_after_bind_input_attachments: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxPerStageDescriptorUpdateAfterBindSampledImages)"]
+ pub max_per_stage_descriptor_update_after_bind_sampled_images: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxPerStageDescriptorUpdateAfterBindSamplers)"]
+ pub max_per_stage_descriptor_update_after_bind_samplers: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxPerStageDescriptorUpdateAfterBindStorageBuffers)"]
+ pub max_per_stage_descriptor_update_after_bind_storage_buffers: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxPerStageDescriptorUpdateAfterBindStorageImages)"]
+ pub max_per_stage_descriptor_update_after_bind_storage_images: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxPerStageDescriptorUpdateAfterBindUniformBuffers)"]
+ pub max_per_stage_descriptor_update_after_bind_uniform_buffers: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxPerStageResources)"]
+ pub max_per_stage_resources: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxPerStageUpdateAfterBindResources)"]
+ pub max_per_stage_update_after_bind_resources: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesEXT.html#limits-maxPreferredMeshWorkGroupInvocations)"]
+ pub max_preferred_mesh_work_group_invocations: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesEXT.html#limits-maxPreferredTaskWorkGroupInvocations)"]
+ pub max_preferred_task_work_group_invocations: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceAccelerationStructurePropertiesKHR.html#limits-maxPrimitiveCount)"]
+ pub max_primitive_count: Option<u64>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxPushConstantsSize)"]
+ pub max_push_constants_size: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePushDescriptorPropertiesKHR.html#limits-maxPushDescriptors)"]
+ pub max_push_descriptors: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRayTracingPipelinePropertiesKHR.html#limits-maxRayDispatchInvocationCount)"]
+ pub max_ray_dispatch_invocation_count: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRayTracingPipelinePropertiesKHR.html#limits-maxRayHitAttributeSize)"]
+ pub max_ray_hit_attribute_size: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRayTracingPipelinePropertiesKHR.html#limits-maxRayRecursionDepth)"]
+ pub max_ray_recursion_depth: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRayTracingPropertiesNV.html#limits-maxRecursionDepth)"]
+ pub max_recursion_depth: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-maxResourceDescriptorBufferBindings)"]
+ pub max_resource_descriptor_buffer_bindings: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-maxResourceDescriptorBufferRange)"]
+ pub max_resource_descriptor_buffer_range: Option<DeviceSize>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceSampleLocationsPropertiesEXT.html#limits-maxSampleLocationGridSize)"]
+ pub max_sample_location_grid_size: Option<[u32; 2]>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxSampleMaskWords)"]
+ pub max_sample_mask_words: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxSamplerAllocationCount)"]
+ pub max_sampler_allocation_count: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxSamplerAnisotropy)"]
+ pub max_sampler_anisotropy: f32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-maxSamplerDescriptorBufferBindings)"]
+ pub max_sampler_descriptor_buffer_bindings: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-maxSamplerDescriptorBufferRange)"]
+ pub max_sampler_descriptor_buffer_range: Option<DeviceSize>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxSamplerLodBias)"]
+ pub max_sampler_lod_bias: f32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderCorePropertiesAMD.html#limits-maxSgprAllocation)"]
+ pub max_sgpr_allocation: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRayTracingPipelinePropertiesKHR.html#limits-maxShaderGroupStride)"]
+ pub max_shader_group_stride: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxStorageBufferRange)"]
+ pub max_storage_buffer_range: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-maxSubgroupSize)"]
+ pub max_subgroup_size: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceSubpassShadingPropertiesHUAWEI.html#limits-maxSubpassShadingWorkgroupSizeAspectRatio)"]
+ pub max_subpass_shading_workgroup_size_aspect_ratio: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentDensityMap2PropertiesEXT.html#limits-maxSubsampledArrayLayers)"]
+ pub max_subsampled_array_layers: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesNV.html#limits-maxTaskOutputCount)"]
+ pub max_task_output_count: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesEXT.html#limits-maxTaskPayloadAndSharedMemorySize)"]
+ pub max_task_payload_and_shared_memory_size: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesEXT.html#limits-maxTaskPayloadSize)"]
+ pub max_task_payload_size: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesEXT.html#limits-maxTaskSharedMemorySize)"]
+ pub max_task_shared_memory_size: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesNV.html#limits-maxTaskTotalMemorySize)"]
+ pub max_task_total_memory_size: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesEXT.html#limits-maxTaskWorkGroupCount)"]
+ pub max_task_work_group_count: Option<[u32; 3]>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesEXT.html#limits-maxTaskWorkGroupInvocations)"]
+ pub max_task_work_group_invocations: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesEXT.html#limits-maxTaskWorkGroupSize)"]
+ pub max_task_work_group_size: Option<[u32; 3]>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesEXT.html#limits-maxTaskWorkGroupTotalCount)"]
+ pub max_task_work_group_total_count: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxTessellationControlPerPatchOutputComponents)"]
+ pub max_tessellation_control_per_patch_output_components: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxTessellationControlPerVertexInputComponents)"]
+ pub max_tessellation_control_per_vertex_input_components: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxTessellationControlPerVertexOutputComponents)"]
+ pub max_tessellation_control_per_vertex_output_components: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxTessellationControlTotalOutputComponents)"]
+ pub max_tessellation_control_total_output_components: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxTessellationEvaluationInputComponents)"]
+ pub max_tessellation_evaluation_input_components: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxTessellationEvaluationOutputComponents)"]
+ pub max_tessellation_evaluation_output_components: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxTessellationGenerationLevel)"]
+ pub max_tessellation_generation_level: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxTessellationPatchSize)"]
+ pub max_tessellation_patch_size: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxTexelBufferElements)"]
+ pub max_texel_buffer_elements: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxTexelGatherOffset)"]
+ pub max_texel_gather_offset: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxTexelOffset)"]
+ pub max_texel_offset: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxTimelineSemaphoreValueDifference)"]
+ pub max_timeline_semaphore_value_difference: Option<u64>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceTransformFeedbackPropertiesEXT.html#limits-maxTransformFeedbackBufferDataSize)"]
+ pub max_transform_feedback_buffer_data_size: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceTransformFeedbackPropertiesEXT.html#limits-maxTransformFeedbackBufferDataStride)"]
+ pub max_transform_feedback_buffer_data_stride: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceTransformFeedbackPropertiesEXT.html#limits-maxTransformFeedbackBufferSize)"]
+ pub max_transform_feedback_buffer_size: Option<DeviceSize>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceTransformFeedbackPropertiesEXT.html#limits-maxTransformFeedbackBuffers)"]
+ pub max_transform_feedback_buffers: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceTransformFeedbackPropertiesEXT.html#limits-maxTransformFeedbackStreamDataSize)"]
+ pub max_transform_feedback_stream_data_size: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceTransformFeedbackPropertiesEXT.html#limits-maxTransformFeedbackStreams)"]
+ pub max_transform_feedback_streams: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRayTracingPropertiesNV.html#limits-maxTriangleCount)"]
+ pub max_triangle_count: Option<u64>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxUniformBufferRange)"]
+ pub max_uniform_buffer_range: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-maxUpdateAfterBindDescriptorsInAllPools)"]
+ pub max_update_after_bind_descriptors_in_all_pools: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT.html#limits-maxVertexAttribDivisor)"]
+ pub max_vertex_attrib_divisor: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxVertexInputAttributeOffset)"]
+ pub max_vertex_input_attribute_offset: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxVertexInputAttributes)"]
+ pub max_vertex_input_attributes: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxVertexInputBindingStride)"]
+ pub max_vertex_input_binding_stride: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxVertexInputBindings)"]
+ pub max_vertex_input_bindings: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxVertexOutputComponents)"]
+ pub max_vertex_output_components: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderCorePropertiesAMD.html#limits-maxVgprAllocation)"]
+ pub max_vgpr_allocation: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxViewportDimensions)"]
+ pub max_viewport_dimensions: [u32; 2],
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-maxViewports)"]
+ pub max_viewports: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceImageProcessingPropertiesQCOM.html#limits-maxWeightFilterDimension)"]
+ pub max_weight_filter_dimension: Option<[u32; 2]>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceImageProcessingPropertiesQCOM.html#limits-maxWeightFilterPhases)"]
+ pub max_weight_filter_phases: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceOpticalFlowPropertiesNV.html#limits-maxWidth)"]
+ pub max_width: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesEXT.html#limits-meshOutputPerPrimitiveGranularity)"]
+ pub mesh_output_per_primitive_granularity: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesEXT.html#limits-meshOutputPerVertexGranularity)"]
+ pub mesh_output_per_vertex_granularity: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceAccelerationStructurePropertiesKHR.html#limits-minAccelerationStructureScratchOffsetAlignment)"]
+ pub min_acceleration_structure_scratch_offset_alignment: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentDensityMapPropertiesEXT.html#limits-minFragmentDensityTexelSize)"]
+ pub min_fragment_density_texel_size: Option<[u32; 2]>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-minFragmentShadingRateAttachmentTexelSize)"]
+ pub min_fragment_shading_rate_attachment_texel_size: Option<[u32; 2]>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceOpticalFlowPropertiesNV.html#limits-minHeight)"]
+ pub min_height: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceExternalMemoryHostPropertiesEXT.html#limits-minImportedHostPointerAlignment)"]
+ pub min_imported_host_pointer_alignment: Option<DeviceSize>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV.html#limits-minIndirectCommandsBufferOffsetAlignment)"]
+ pub min_indirect_commands_buffer_offset_alignment: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-minInterpolationOffset)"]
+ pub min_interpolation_offset: f32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-minMemoryMapAlignment)"]
+ pub min_memory_map_alignment: usize,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV.html#limits-minSequencesCountBufferOffsetAlignment)"]
+ pub min_sequences_count_buffer_offset_alignment: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV.html#limits-minSequencesIndexBufferOffsetAlignment)"]
+ pub min_sequences_index_buffer_offset_alignment: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderCorePropertiesAMD.html#limits-minSgprAllocation)"]
+ pub min_sgpr_allocation: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-minStorageBufferOffsetAlignment)"]
+ pub min_storage_buffer_offset_alignment: DeviceAlignment,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-minSubgroupSize)"]
+ pub min_subgroup_size: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-minTexelBufferOffsetAlignment)"]
+ pub min_texel_buffer_offset_alignment: DeviceAlignment,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-minTexelGatherOffset)"]
+ pub min_texel_gather_offset: i32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-minTexelOffset)"]
+ pub min_texel_offset: i32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-minUniformBufferOffsetAlignment)"]
+ pub min_uniform_buffer_offset_alignment: DeviceAlignment,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePortabilitySubsetPropertiesKHR.html#limits-minVertexInputBindingStrideAlignment)"]
+ pub min_vertex_input_binding_stride_alignment: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderCorePropertiesAMD.html#limits-minVgprAllocation)"]
+ pub min_vgpr_allocation: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceOpticalFlowPropertiesNV.html#limits-minWidth)"]
+ pub min_width: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-mipmapPrecisionBits)"]
+ pub mipmap_precision_bits: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-nonCoherentAtomSize)"]
+ pub non_coherent_atom_size: DeviceAlignment,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-optimalBufferCopyOffsetAlignment)"]
+ pub optimal_buffer_copy_offset_alignment: DeviceAlignment,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-optimalBufferCopyRowPitchAlignment)"]
+ pub optimal_buffer_copy_row_pitch_alignment: DeviceAlignment,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePCIBusInfoPropertiesEXT.html#limits-pciBus)"]
+ pub pci_bus: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePCIBusInfoPropertiesEXT.html#limits-pciDevice)"]
+ pub pci_device: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePCIBusInfoPropertiesEXT.html#limits-pciDomain)"]
+ pub pci_domain: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDevicePCIBusInfoPropertiesEXT.html#limits-pciFunction)"]
+ pub pci_function: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX.html#limits-perViewPositionAllComponents)"]
+ pub per_view_position_all_components: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceProperties.html#limits-pipelineCacheUUID)"]
+ pub pipeline_cache_uuid: [u8; 16],
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan11Properties.html#limits-pointClippingBehavior)"]
+ pub point_clipping_behavior: Option<PointClippingBehavior>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-pointSizeGranularity)"]
+ pub point_size_granularity: f32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-pointSizeRange)"]
+ pub point_size_range: [f32; 2],
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesEXT.html#limits-prefersCompactPrimitiveOutput)"]
+ pub prefers_compact_primitive_output: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesEXT.html#limits-prefersCompactVertexOutput)"]
+ pub prefers_compact_vertex_output: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesEXT.html#limits-prefersLocalInvocationPrimitiveOutput)"]
+ pub prefers_local_invocation_primitive_output: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceMeshShaderPropertiesEXT.html#limits-prefersLocalInvocationVertexOutput)"]
+ pub prefers_local_invocation_vertex_output: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDrmPropertiesEXT.html#limits-primaryMajor)"]
+ pub primary_major: Option<i64>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDrmPropertiesEXT.html#limits-primaryMinor)"]
+ pub primary_minor: Option<i64>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentShadingRatePropertiesKHR.html#limits-primitiveFragmentShadingRateWithMultipleViewports)"]
+ pub primitive_fragment_shading_rate_with_multiple_viewports: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceConservativeRasterizationPropertiesEXT.html#limits-primitiveOverestimationSize)"]
+ pub primitive_overestimation_size: Option<f32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceConservativeRasterizationPropertiesEXT.html#limits-primitiveUnderestimation)"]
+ pub primitive_underestimation: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan11Properties.html#limits-protectedNoFault)"]
+ pub protected_no_fault: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceProvokingVertexPropertiesEXT.html#limits-provokingVertexModePerPipeline)"]
+ pub provoking_vertex_mode_per_pipeline: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-quadDivergentImplicitLod)"]
+ pub quad_divergent_implicit_lod: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceSubgroupProperties.html#limits-quadOperationsInAllStages)"]
+ pub quad_operations_in_all_stages: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRayTracingInvocationReorderPropertiesNV.html#limits-rayTracingInvocationReorderReorderingHint)"]
+ pub ray_tracing_invocation_reorder_reordering_hint: Option<RayTracingInvocationReorderMode>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDrmPropertiesEXT.html#limits-renderMajor)"]
+ pub render_major: Option<i64>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDrmPropertiesEXT.html#limits-renderMinor)"]
+ pub render_minor: Option<i64>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-requiredSubgroupSizeStages)"]
+ pub required_subgroup_size_stages: Option<ShaderStages>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceSparseProperties.html#limits-residencyAlignedMipSize)"]
+ pub residency_aligned_mip_size: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceSparseProperties.html#limits-residencyNonResidentStrict)"]
+ pub residency_non_resident_strict: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceSparseProperties.html#limits-residencyStandard2DBlockShape)"]
+ pub residency_standard2_d_block_shape: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceSparseProperties.html#limits-residencyStandard2DMultisampleBlockShape)"]
+ pub residency_standard2_d_multisample_block_shape: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceSparseProperties.html#limits-residencyStandard3DBlockShape)"]
+ pub residency_standard3_d_block_shape: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-resourceDescriptorBufferAddressSpaceSize)"]
+ pub resource_descriptor_buffer_address_space_size: Option<DeviceSize>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-robustBufferAccessUpdateAfterBind)"]
+ pub robust_buffer_access_update_after_bind: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRobustness2PropertiesEXT.html#limits-robustStorageBufferAccessSizeAlignment)"]
+ pub robust_storage_buffer_access_size_alignment: Option<DeviceAlignment>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-robustStorageBufferDescriptorSize)"]
+ pub robust_storage_buffer_descriptor_size: Option<usize>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-robustStorageTexelBufferDescriptorSize)"]
+ pub robust_storage_texel_buffer_descriptor_size: Option<usize>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRobustness2PropertiesEXT.html#limits-robustUniformBufferAccessSizeAlignment)"]
+ pub robust_uniform_buffer_access_size_alignment: Option<DeviceAlignment>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-robustUniformBufferDescriptorSize)"]
+ pub robust_uniform_buffer_descriptor_size: Option<usize>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-robustUniformTexelBufferDescriptorSize)"]
+ pub robust_uniform_texel_buffer_descriptor_size: Option<usize>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-roundingModeIndependence)"]
+ pub rounding_mode_independence: Option<ShaderFloatControlsIndependence>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceSampleLocationsPropertiesEXT.html#limits-sampleLocationCoordinateRange)"]
+ pub sample_location_coordinate_range: Option<[f32; 2]>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceSampleLocationsPropertiesEXT.html#limits-sampleLocationSampleCounts)"]
+ pub sample_location_sample_counts: Option<SampleCounts>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceSampleLocationsPropertiesEXT.html#limits-sampleLocationSubPixelBits)"]
+ pub sample_location_sub_pixel_bits: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-sampledImageColorSampleCounts)"]
+ pub sampled_image_color_sample_counts: SampleCounts,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-sampledImageDepthSampleCounts)"]
+ pub sampled_image_depth_sample_counts: SampleCounts,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-sampledImageDescriptorSize)"]
+ pub sampled_image_descriptor_size: Option<usize>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-sampledImageIntegerSampleCounts)"]
+ pub sampled_image_integer_sample_counts: SampleCounts,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-sampledImageStencilSampleCounts)"]
+ pub sampled_image_stencil_sample_counts: SampleCounts,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-samplerCaptureReplayDescriptorDataSize)"]
+ pub sampler_capture_replay_descriptor_data_size: Option<usize>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-samplerDescriptorBufferAddressSpaceSize)"]
+ pub sampler_descriptor_buffer_address_space_size: Option<DeviceSize>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-samplerDescriptorSize)"]
+ pub sampler_descriptor_size: Option<usize>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderCorePropertiesAMD.html#limits-sgprAllocationGranularity)"]
+ pub sgpr_allocation_granularity: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderCorePropertiesAMD.html#limits-sgprsPerSimd)"]
+ pub sgprs_per_simd: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderCorePropertiesAMD.html#limits-shaderArraysPerEngineCount)"]
+ pub shader_arrays_per_engine_count: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderCoreBuiltinsPropertiesARM.html#limits-shaderCoreCount)"]
+ pub shader_core_count: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderCoreProperties2AMD.html#limits-shaderCoreFeatures)"]
+ pub shader_core_features: Option<ShaderCoreProperties>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderCoreBuiltinsPropertiesARM.html#limits-shaderCoreMask)"]
+ pub shader_core_mask: Option<u64>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderDenormFlushToZeroFloat16)"]
+ pub shader_denorm_flush_to_zero_float16: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderDenormFlushToZeroFloat32)"]
+ pub shader_denorm_flush_to_zero_float32: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderDenormFlushToZeroFloat64)"]
+ pub shader_denorm_flush_to_zero_float64: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderDenormPreserveFloat16)"]
+ pub shader_denorm_preserve_float16: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderDenormPreserveFloat32)"]
+ pub shader_denorm_preserve_float32: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderDenormPreserveFloat64)"]
+ pub shader_denorm_preserve_float64: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderCorePropertiesAMD.html#limits-shaderEngineCount)"]
+ pub shader_engine_count: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRayTracingPipelinePropertiesKHR.html#limits-shaderGroupBaseAlignment)"]
+ pub shader_group_base_alignment: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRayTracingPipelinePropertiesKHR.html#limits-shaderGroupHandleAlignment)"]
+ pub shader_group_handle_alignment: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRayTracingPipelinePropertiesKHR.html#limits-shaderGroupHandleCaptureReplaySize)"]
+ pub shader_group_handle_capture_replay_size: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRayTracingPipelinePropertiesKHR.html#limits-shaderGroupHandleSize)"]
+ pub shader_group_handle_size: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderInputAttachmentArrayNonUniformIndexingNative)"]
+ pub shader_input_attachment_array_non_uniform_indexing_native: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderModuleIdentifierPropertiesEXT.html#limits-shaderModuleIdentifierAlgorithmUUID)"]
+ pub shader_module_identifier_algorithm_uuid: Option<[u8; 16]>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderRoundingModeRTEFloat16)"]
+ pub shader_rounding_mode_rte_float16: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderRoundingModeRTEFloat32)"]
+ pub shader_rounding_mode_rte_float32: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderRoundingModeRTEFloat64)"]
+ pub shader_rounding_mode_rte_float64: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderRoundingModeRTZFloat16)"]
+ pub shader_rounding_mode_rtz_float16: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderRoundingModeRTZFloat32)"]
+ pub shader_rounding_mode_rtz_float32: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderRoundingModeRTZFloat64)"]
+ pub shader_rounding_mode_rtz_float64: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderSampledImageArrayNonUniformIndexingNative)"]
+ pub shader_sampled_image_array_non_uniform_indexing_native: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderSignedZeroInfNanPreserveFloat16)"]
+ pub shader_signed_zero_inf_nan_preserve_float16: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderSignedZeroInfNanPreserveFloat32)"]
+ pub shader_signed_zero_inf_nan_preserve_float32: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderSignedZeroInfNanPreserveFloat64)"]
+ pub shader_signed_zero_inf_nan_preserve_float64: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderSMBuiltinsPropertiesNV.html#limits-shaderSMCount)"]
+ pub shader_sm_count: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderStorageBufferArrayNonUniformIndexingNative)"]
+ pub shader_storage_buffer_array_non_uniform_indexing_native: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderStorageImageArrayNonUniformIndexingNative)"]
+ pub shader_storage_image_array_non_uniform_indexing_native: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-shaderUniformBufferArrayNonUniformIndexingNative)"]
+ pub shader_uniform_buffer_array_non_uniform_indexing_native: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderCoreBuiltinsPropertiesARM.html#limits-shaderWarpsPerCore)"]
+ pub shader_warps_per_core: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderSMBuiltinsPropertiesNV.html#limits-shaderWarpsPerSM)"]
+ pub shader_warps_per_sm: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShadingRateImagePropertiesNV.html#limits-shadingRateMaxCoarseSamples)"]
+ pub shading_rate_max_coarse_samples: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShadingRateImagePropertiesNV.html#limits-shadingRatePaletteSize)"]
+ pub shading_rate_palette_size: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShadingRateImagePropertiesNV.html#limits-shadingRateTexelSize)"]
+ pub shading_rate_texel_size: Option<[u32; 2]>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderCorePropertiesAMD.html#limits-simdPerComputeUnit)"]
+ pub simd_per_compute_unit: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-sparseAddressSpaceSize)"]
+ pub sparse_address_space_size: DeviceSize,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-standardSampleLocations)"]
+ pub standard_sample_locations: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-storageBufferDescriptorSize)"]
+ pub storage_buffer_descriptor_size: Option<usize>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-storageImageDescriptorSize)"]
+ pub storage_image_descriptor_size: Option<usize>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-storageImageSampleCounts)"]
+ pub storage_image_sample_counts: SampleCounts,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-storageTexelBufferDescriptorSize)"]
+ pub storage_texel_buffer_descriptor_size: Option<usize>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-storageTexelBufferOffsetAlignmentBytes)"]
+ pub storage_texel_buffer_offset_alignment_bytes: Option<DeviceAlignment>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-storageTexelBufferOffsetSingleTexelAlignment)"]
+ pub storage_texel_buffer_offset_single_texel_alignment: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-strictLines)"]
+ pub strict_lines: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-subPixelInterpolationOffsetBits)"]
+ pub sub_pixel_interpolation_offset_bits: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-subPixelPrecisionBits)"]
+ pub sub_pixel_precision_bits: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-subTexelPrecisionBits)"]
+ pub sub_texel_precision_bits: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan11Properties.html#limits-subgroupQuadOperationsInAllStages)"]
+ pub subgroup_quad_operations_in_all_stages: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan11Properties.html#limits-subgroupSize)"]
+ pub subgroup_size: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan11Properties.html#limits-subgroupSupportedOperations)"]
+ pub subgroup_supported_operations: Option<SubgroupFeatures>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan11Properties.html#limits-subgroupSupportedStages)"]
+ pub subgroup_supported_stages: Option<ShaderStages>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentDensityMap2PropertiesEXT.html#limits-subsampledCoarseReconstructionEarlyAccess)"]
+ pub subsampled_coarse_reconstruction_early_access: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentDensityMap2PropertiesEXT.html#limits-subsampledLoads)"]
+ pub subsampled_loads: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-supportedDepthResolveModes)"]
+ pub supported_depth_resolve_modes: Option<ResolveModes>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceOpticalFlowPropertiesNV.html#limits-supportedHintGridSizes)"]
+ pub supported_hint_grid_sizes: Option<OpticalFlowGridSizes>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceSubgroupProperties.html#limits-supportedOperations)"]
+ pub supported_operations: Option<SubgroupFeatures>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceOpticalFlowPropertiesNV.html#limits-supportedOutputGridSizes)"]
+ pub supported_output_grid_sizes: Option<OpticalFlowGridSizes>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceCopyMemoryIndirectPropertiesNV.html#limits-supportedQueues)"]
+ pub supported_queues: Option<QueueFlags>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceSubgroupProperties.html#limits-supportedStages)"]
+ pub supported_stages: Option<ShaderStages>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan12Properties.html#limits-supportedStencilResolveModes)"]
+ pub supported_stencil_resolve_modes: Option<ResolveModes>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-timestampComputeAndGraphics)"]
+ pub timestamp_compute_and_graphics: bool,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-timestampPeriod)"]
+ pub timestamp_period: f32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceTransformFeedbackPropertiesEXT.html#limits-transformFeedbackDraw)"]
+ pub transform_feedback_draw: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceProvokingVertexPropertiesEXT.html#limits-transformFeedbackPreservesTriangleFanProvokingVertex)"]
+ pub transform_feedback_preserves_triangle_fan_provoking_vertex: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceTransformFeedbackPropertiesEXT.html#limits-transformFeedbackQueries)"]
+ pub transform_feedback_queries: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceTransformFeedbackPropertiesEXT.html#limits-transformFeedbackRasterizationStreamSelect)"]
+ pub transform_feedback_rasterization_stream_select: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceTransformFeedbackPropertiesEXT.html#limits-transformFeedbackStreamsLinesTriangles)"]
+ pub transform_feedback_streams_lines_triangles: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceFragmentShaderBarycentricPropertiesKHR.html#limits-triStripVertexOrderIndependentOfProvokingVertex)"]
+ pub tri_strip_vertex_order_independent_of_provoking_vertex: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-uniformBufferDescriptorSize)"]
+ pub uniform_buffer_descriptor_size: Option<usize>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceDescriptorBufferPropertiesEXT.html#limits-uniformTexelBufferDescriptorSize)"]
+ pub uniform_texel_buffer_descriptor_size: Option<usize>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-uniformTexelBufferOffsetAlignmentBytes)"]
+ pub uniform_texel_buffer_offset_alignment_bytes: Option<DeviceAlignment>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceVulkan13Properties.html#limits-uniformTexelBufferOffsetSingleTexelAlignment)"]
+ pub uniform_texel_buffer_offset_single_texel_alignment: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceSampleLocationsPropertiesEXT.html#limits-variableSampleLocations)"]
+ pub variable_sample_locations: Option<bool>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceProperties.html#limits-vendorID)"]
+ pub vendor_id: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderCorePropertiesAMD.html#limits-vgprAllocationGranularity)"]
+ pub vgpr_allocation_granularity: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderCorePropertiesAMD.html#limits-vgprsPerSimd)"]
+ pub vgprs_per_simd: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-viewportBoundsRange)"]
+ pub viewport_bounds_range: [f32; 2],
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceLimits.html#limits-viewportSubPixelBits)"]
+ pub viewport_sub_pixel_bits: u32,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderCorePropertiesAMD.html#limits-wavefrontSize)"]
+ pub wavefront_size: Option<u32>,
+ #[doc = "- [Vulkan documentation](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceShaderCorePropertiesAMD.html#limits-wavefrontsPerSimd)"]
+ pub wavefronts_per_simd: Option<u32>,
+ pub _ne: crate::NonExhaustive,
+}
+impl Default for Properties {
+ fn default() -> Self {
+ Properties { acceleration_structure_capture_replay_descriptor_data_size : Default :: default () , acceleration_structure_descriptor_size : Default :: default () , active_compute_unit_count : Default :: default () , advanced_blend_all_operations : Default :: default () , advanced_blend_correlated_overlap : Default :: default () , advanced_blend_independent_blend : Default :: default () , advanced_blend_max_color_attachments : Default :: default () , advanced_blend_non_premultiplied_dst_color : Default :: default () , advanced_blend_non_premultiplied_src_color : Default :: default () , allow_command_buffer_query_copies : Default :: default () , allow_sampler_image_view_post_submit_creation : Default :: default () , api_version : Default :: default () , bidirectional_flow_supported : Default :: default () , buffer_capture_replay_descriptor_data_size : Default :: default () , buffer_image_granularity : Default :: default () , bufferless_push_descriptors : Default :: default () , combined_image_sampler_density_map_descriptor_size : Default :: default () , combined_image_sampler_descriptor_single_array : Default :: default () , combined_image_sampler_descriptor_size : Default :: default () , compute_units_per_shader_array : Default :: default () , conformance_version : Default :: default () , conservative_point_and_line_rasterization : Default :: default () , conservative_rasterization_post_depth_coverage : Default :: default () , cooperative_matrix_supported_stages : Default :: default () , cost_supported : Default :: default () , decompression_methods : Default :: default () , default_robustness_images : Default :: default () , default_robustness_storage_buffers : Default :: default () , default_robustness_uniform_buffers : Default :: default () , default_robustness_vertex_inputs : Default :: default () , degenerate_lines_rasterized : Default :: default () , degenerate_triangles_rasterized : Default :: default () , denorm_behavior_independence : Default :: default () , descriptor_buffer_address_space_size : Default :: default () , descriptor_buffer_offset_alignment : Default :: default () , device_id : Default :: default () , device_luid : Default :: default () , device_luid_valid : Default :: default () , device_name : Default :: default () , device_node_mask : Default :: default () , device_type : Default :: default () , device_uuid : Default :: default () , discrete_queue_priorities : Default :: default () , driver_id : Default :: default () , driver_info : Default :: default () , driver_name : Default :: default () , driver_uuid : Default :: default () , driver_version : Default :: default () , dynamic_primitive_topology_unrestricted : Default :: default () , extra_primitive_overestimation_size_granularity : Default :: default () , filter_minmax_image_component_mapping : Default :: default () , filter_minmax_single_component_formats : Default :: default () , fragment_density_invocations : Default :: default () , fragment_density_offset_granularity : Default :: default () , fragment_shading_rate_non_trivial_combiner_ops : Default :: default () , fragment_shading_rate_strict_multiply_combiner : Default :: default () , fragment_shading_rate_with_conservative_rasterization : Default :: default () , fragment_shading_rate_with_custom_sample_locations : Default :: default () , fragment_shading_rate_with_fragment_shader_interlock : Default :: default () , fragment_shading_rate_with_sample_mask : Default :: default () , fragment_shading_rate_with_shader_depth_stencil_writes : Default :: default () , fragment_shading_rate_with_shader_sample_mask : Default :: default () , framebuffer_color_sample_counts : Default :: default () , framebuffer_depth_sample_counts : Default :: default () , framebuffer_integer_color_sample_counts : Default :: default () , framebuffer_no_attachments_sample_counts : Default :: default () , framebuffer_stencil_sample_counts : Default :: default () , fully_covered_fragment_shader_input_variable : Default :: default () , global_flow_supported : Default :: default () , graphics_pipeline_library_fast_linking : Default :: default () , graphics_pipeline_library_independent_interpolation_decoration : Default :: default () , has_primary : Default :: default () , has_render : Default :: default () , hint_supported : Default :: default () , image_capture_replay_descriptor_data_size : Default :: default () , image_view_capture_replay_descriptor_data_size : Default :: default () , independent_resolve : Default :: default () , independent_resolve_none : Default :: default () , input_attachment_descriptor_size : Default :: default () , integer_dot_product16_bit_mixed_signedness_accelerated : Default :: default () , integer_dot_product16_bit_signed_accelerated : Default :: default () , integer_dot_product16_bit_unsigned_accelerated : Default :: default () , integer_dot_product32_bit_mixed_signedness_accelerated : Default :: default () , integer_dot_product32_bit_signed_accelerated : Default :: default () , integer_dot_product32_bit_unsigned_accelerated : Default :: default () , integer_dot_product4x8_bit_packed_mixed_signedness_accelerated : Default :: default () , integer_dot_product4x8_bit_packed_signed_accelerated : Default :: default () , integer_dot_product4x8_bit_packed_unsigned_accelerated : Default :: default () , integer_dot_product64_bit_mixed_signedness_accelerated : Default :: default () , integer_dot_product64_bit_signed_accelerated : Default :: default () , integer_dot_product64_bit_unsigned_accelerated : Default :: default () , integer_dot_product8_bit_mixed_signedness_accelerated : Default :: default () , integer_dot_product8_bit_signed_accelerated : Default :: default () , integer_dot_product8_bit_unsigned_accelerated : Default :: default () , integer_dot_product_accumulating_saturating16_bit_mixed_signedness_accelerated : Default :: default () , integer_dot_product_accumulating_saturating16_bit_signed_accelerated : Default :: default () , integer_dot_product_accumulating_saturating16_bit_unsigned_accelerated : Default :: default () , integer_dot_product_accumulating_saturating32_bit_mixed_signedness_accelerated : Default :: default () , integer_dot_product_accumulating_saturating32_bit_signed_accelerated : Default :: default () , integer_dot_product_accumulating_saturating32_bit_unsigned_accelerated : Default :: default () , integer_dot_product_accumulating_saturating4x8_bit_packed_mixed_signedness_accelerated : Default :: default () , integer_dot_product_accumulating_saturating4x8_bit_packed_signed_accelerated : Default :: default () , integer_dot_product_accumulating_saturating4x8_bit_packed_unsigned_accelerated : Default :: default () , integer_dot_product_accumulating_saturating64_bit_mixed_signedness_accelerated : Default :: default () , integer_dot_product_accumulating_saturating64_bit_signed_accelerated : Default :: default () , integer_dot_product_accumulating_saturating64_bit_unsigned_accelerated : Default :: default () , integer_dot_product_accumulating_saturating8_bit_mixed_signedness_accelerated : Default :: default () , integer_dot_product_accumulating_saturating8_bit_signed_accelerated : Default :: default () , integer_dot_product_accumulating_saturating8_bit_unsigned_accelerated : Default :: default () , layered_shading_rate_attachments : Default :: default () , line_sub_pixel_precision_bits : Default :: default () , line_width_granularity : Default :: default () , line_width_range : Default :: default () , max_block_match_region : Default :: default () , max_bound_descriptor_sets : Default :: default () , max_box_filter_block_size : Default :: default () , max_buffer_size : Default :: default () , max_clip_distances : Default :: default () , max_color_attachments : Default :: default () , max_combined_clip_and_cull_distances : Default :: default () , max_compute_shared_memory_size : Default :: default () , max_compute_work_group_count : Default :: default () , max_compute_work_group_invocations : Default :: default () , max_compute_work_group_size : Default :: default () , max_compute_workgroup_subgroups : Default :: default () , max_cull_distances : Default :: default () , max_custom_border_color_samplers : Default :: default () , max_decompression_indirect_count : Default :: default () , max_descriptor_buffer_bindings : Default :: default () , max_descriptor_set_acceleration_structures : Default :: default () , max_descriptor_set_inline_uniform_blocks : Default :: default () , max_descriptor_set_input_attachments : Default :: default () , max_descriptor_set_sampled_images : Default :: default () , max_descriptor_set_samplers : Default :: default () , max_descriptor_set_storage_buffers : Default :: default () , max_descriptor_set_storage_buffers_dynamic : Default :: default () , max_descriptor_set_storage_images : Default :: default () , max_descriptor_set_subsampled_samplers : Default :: default () , max_descriptor_set_uniform_buffers : Default :: default () , max_descriptor_set_uniform_buffers_dynamic : Default :: default () , max_descriptor_set_update_after_bind_acceleration_structures : Default :: default () , max_descriptor_set_update_after_bind_inline_uniform_blocks : Default :: default () , max_descriptor_set_update_after_bind_input_attachments : Default :: default () , max_descriptor_set_update_after_bind_sampled_images : Default :: default () , max_descriptor_set_update_after_bind_samplers : Default :: default () , max_descriptor_set_update_after_bind_storage_buffers : Default :: default () , max_descriptor_set_update_after_bind_storage_buffers_dynamic : Default :: default () , max_descriptor_set_update_after_bind_storage_images : Default :: default () , max_descriptor_set_update_after_bind_uniform_buffers : Default :: default () , max_descriptor_set_update_after_bind_uniform_buffers_dynamic : Default :: default () , max_discard_rectangles : Default :: default () , max_draw_indexed_index_value : Default :: default () , max_draw_indirect_count : Default :: default () , max_draw_mesh_tasks_count : Default :: default () , max_embedded_immutable_sampler_bindings : Default :: default () , max_embedded_immutable_samplers : Default :: default () , max_extra_primitive_overestimation_size : Default :: default () , max_fragment_combined_output_resources : Default :: default () , max_fragment_density_texel_size : Default :: default () , max_fragment_dual_src_attachments : Default :: default () , max_fragment_input_components : Default :: default () , max_fragment_output_attachments : Default :: default () , max_fragment_shading_rate_attachment_texel_size : Default :: default () , max_fragment_shading_rate_attachment_texel_size_aspect_ratio : Default :: default () , max_fragment_shading_rate_coverage_samples : Default :: default () , max_fragment_shading_rate_invocation_count : Default :: default () , max_fragment_shading_rate_rasterization_samples : Default :: default () , max_fragment_size : Default :: default () , max_fragment_size_aspect_ratio : Default :: default () , max_framebuffer_height : Default :: default () , max_framebuffer_layers : Default :: default () , max_framebuffer_width : Default :: default () , max_geometry_count : Default :: default () , max_geometry_input_components : Default :: default () , max_geometry_output_components : Default :: default () , max_geometry_output_vertices : Default :: default () , max_geometry_shader_invocations : Default :: default () , max_geometry_total_output_components : Default :: default () , max_graphics_shader_group_count : Default :: default () , max_height : Default :: default () , max_image_array_layers : Default :: default () , max_image_dimension1_d : Default :: default () , max_image_dimension2_d : Default :: default () , max_image_dimension3_d : Default :: default () , max_image_dimension_cube : Default :: default () , max_indirect_commands_stream_count : Default :: default () , max_indirect_commands_stream_stride : Default :: default () , max_indirect_commands_token_count : Default :: default () , max_indirect_commands_token_offset : Default :: default () , max_indirect_sequence_count : Default :: default () , max_inline_uniform_block_size : Default :: default () , max_inline_uniform_total_size : Default :: default () , max_instance_count : Default :: default () , max_interpolation_offset : Default :: default () , max_memory_allocation_count : Default :: default () , max_memory_allocation_size : Default :: default () , max_mesh_multiview_view_count : Default :: default () , max_mesh_output_components : Default :: default () , max_mesh_output_layers : Default :: default () , max_mesh_output_memory_size : Default :: default () , max_mesh_output_primitives : Default :: default () , max_mesh_output_vertices : Default :: default () , max_mesh_payload_and_output_memory_size : Default :: default () , max_mesh_payload_and_shared_memory_size : Default :: default () , max_mesh_shared_memory_size : Default :: default () , max_mesh_total_memory_size : Default :: default () , max_mesh_work_group_count : Default :: default () , max_mesh_work_group_invocations : Default :: default () , max_mesh_work_group_size : Default :: default () , max_mesh_work_group_total_count : Default :: default () , max_multi_draw_count : Default :: default () , max_multiview_instance_index : Default :: default () , max_multiview_view_count : Default :: default () , max_num_regions_of_interest : Default :: default () , max_opacity2_state_subdivision_level : Default :: default () , max_opacity4_state_subdivision_level : Default :: default () , max_per_set_descriptors : Default :: default () , max_per_stage_descriptor_acceleration_structures : Default :: default () , max_per_stage_descriptor_inline_uniform_blocks : Default :: default () , max_per_stage_descriptor_input_attachments : Default :: default () , max_per_stage_descriptor_sampled_images : Default :: default () , max_per_stage_descriptor_samplers : Default :: default () , max_per_stage_descriptor_storage_buffers : Default :: default () , max_per_stage_descriptor_storage_images : Default :: default () , max_per_stage_descriptor_uniform_buffers : Default :: default () , max_per_stage_descriptor_update_after_bind_acceleration_structures : Default :: default () , max_per_stage_descriptor_update_after_bind_inline_uniform_blocks : Default :: default () , max_per_stage_descriptor_update_after_bind_input_attachments : Default :: default () , max_per_stage_descriptor_update_after_bind_sampled_images : Default :: default () , max_per_stage_descriptor_update_after_bind_samplers : Default :: default () , max_per_stage_descriptor_update_after_bind_storage_buffers : Default :: default () , max_per_stage_descriptor_update_after_bind_storage_images : Default :: default () , max_per_stage_descriptor_update_after_bind_uniform_buffers : Default :: default () , max_per_stage_resources : Default :: default () , max_per_stage_update_after_bind_resources : Default :: default () , max_preferred_mesh_work_group_invocations : Default :: default () , max_preferred_task_work_group_invocations : Default :: default () , max_primitive_count : Default :: default () , max_push_constants_size : Default :: default () , max_push_descriptors : Default :: default () , max_ray_dispatch_invocation_count : Default :: default () , max_ray_hit_attribute_size : Default :: default () , max_ray_recursion_depth : Default :: default () , max_recursion_depth : Default :: default () , max_resource_descriptor_buffer_bindings : Default :: default () , max_resource_descriptor_buffer_range : Default :: default () , max_sample_location_grid_size : Default :: default () , max_sample_mask_words : Default :: default () , max_sampler_allocation_count : Default :: default () , max_sampler_anisotropy : Default :: default () , max_sampler_descriptor_buffer_bindings : Default :: default () , max_sampler_descriptor_buffer_range : Default :: default () , max_sampler_lod_bias : Default :: default () , max_sgpr_allocation : Default :: default () , max_shader_group_stride : Default :: default () , max_storage_buffer_range : Default :: default () , max_subgroup_size : Default :: default () , max_subpass_shading_workgroup_size_aspect_ratio : Default :: default () , max_subsampled_array_layers : Default :: default () , max_task_output_count : Default :: default () , max_task_payload_and_shared_memory_size : Default :: default () , max_task_payload_size : Default :: default () , max_task_shared_memory_size : Default :: default () , max_task_total_memory_size : Default :: default () , max_task_work_group_count : Default :: default () , max_task_work_group_invocations : Default :: default () , max_task_work_group_size : Default :: default () , max_task_work_group_total_count : Default :: default () , max_tessellation_control_per_patch_output_components : Default :: default () , max_tessellation_control_per_vertex_input_components : Default :: default () , max_tessellation_control_per_vertex_output_components : Default :: default () , max_tessellation_control_total_output_components : Default :: default () , max_tessellation_evaluation_input_components : Default :: default () , max_tessellation_evaluation_output_components : Default :: default () , max_tessellation_generation_level : Default :: default () , max_tessellation_patch_size : Default :: default () , max_texel_buffer_elements : Default :: default () , max_texel_gather_offset : Default :: default () , max_texel_offset : Default :: default () , max_timeline_semaphore_value_difference : Default :: default () , max_transform_feedback_buffer_data_size : Default :: default () , max_transform_feedback_buffer_data_stride : Default :: default () , max_transform_feedback_buffer_size : Default :: default () , max_transform_feedback_buffers : Default :: default () , max_transform_feedback_stream_data_size : Default :: default () , max_transform_feedback_streams : Default :: default () , max_triangle_count : Default :: default () , max_uniform_buffer_range : Default :: default () , max_update_after_bind_descriptors_in_all_pools : Default :: default () , max_vertex_attrib_divisor : Default :: default () , max_vertex_input_attribute_offset : Default :: default () , max_vertex_input_attributes : Default :: default () , max_vertex_input_binding_stride : Default :: default () , max_vertex_input_bindings : Default :: default () , max_vertex_output_components : Default :: default () , max_vgpr_allocation : Default :: default () , max_viewport_dimensions : Default :: default () , max_viewports : Default :: default () , max_weight_filter_dimension : Default :: default () , max_weight_filter_phases : Default :: default () , max_width : Default :: default () , mesh_output_per_primitive_granularity : Default :: default () , mesh_output_per_vertex_granularity : Default :: default () , min_acceleration_structure_scratch_offset_alignment : Default :: default () , min_fragment_density_texel_size : Default :: default () , min_fragment_shading_rate_attachment_texel_size : Default :: default () , min_height : Default :: default () , min_imported_host_pointer_alignment : Default :: default () , min_indirect_commands_buffer_offset_alignment : Default :: default () , min_interpolation_offset : Default :: default () , min_memory_map_alignment : Default :: default () , min_sequences_count_buffer_offset_alignment : Default :: default () , min_sequences_index_buffer_offset_alignment : Default :: default () , min_sgpr_allocation : Default :: default () , min_storage_buffer_offset_alignment : Default :: default () , min_subgroup_size : Default :: default () , min_texel_buffer_offset_alignment : Default :: default () , min_texel_gather_offset : Default :: default () , min_texel_offset : Default :: default () , min_uniform_buffer_offset_alignment : Default :: default () , min_vertex_input_binding_stride_alignment : Default :: default () , min_vgpr_allocation : Default :: default () , min_width : Default :: default () , mipmap_precision_bits : Default :: default () , non_coherent_atom_size : Default :: default () , optimal_buffer_copy_offset_alignment : Default :: default () , optimal_buffer_copy_row_pitch_alignment : Default :: default () , pci_bus : Default :: default () , pci_device : Default :: default () , pci_domain : Default :: default () , pci_function : Default :: default () , per_view_position_all_components : Default :: default () , pipeline_cache_uuid : Default :: default () , point_clipping_behavior : Default :: default () , point_size_granularity : Default :: default () , point_size_range : Default :: default () , prefers_compact_primitive_output : Default :: default () , prefers_compact_vertex_output : Default :: default () , prefers_local_invocation_primitive_output : Default :: default () , prefers_local_invocation_vertex_output : Default :: default () , primary_major : Default :: default () , primary_minor : Default :: default () , primitive_fragment_shading_rate_with_multiple_viewports : Default :: default () , primitive_overestimation_size : Default :: default () , primitive_underestimation : Default :: default () , protected_no_fault : Default :: default () , provoking_vertex_mode_per_pipeline : Default :: default () , quad_divergent_implicit_lod : Default :: default () , quad_operations_in_all_stages : Default :: default () , ray_tracing_invocation_reorder_reordering_hint : Default :: default () , render_major : Default :: default () , render_minor : Default :: default () , required_subgroup_size_stages : Default :: default () , residency_aligned_mip_size : Default :: default () , residency_non_resident_strict : Default :: default () , residency_standard2_d_block_shape : Default :: default () , residency_standard2_d_multisample_block_shape : Default :: default () , residency_standard3_d_block_shape : Default :: default () , resource_descriptor_buffer_address_space_size : Default :: default () , robust_buffer_access_update_after_bind : Default :: default () , robust_storage_buffer_access_size_alignment : Default :: default () , robust_storage_buffer_descriptor_size : Default :: default () , robust_storage_texel_buffer_descriptor_size : Default :: default () , robust_uniform_buffer_access_size_alignment : Default :: default () , robust_uniform_buffer_descriptor_size : Default :: default () , robust_uniform_texel_buffer_descriptor_size : Default :: default () , rounding_mode_independence : Default :: default () , sample_location_coordinate_range : Default :: default () , sample_location_sample_counts : Default :: default () , sample_location_sub_pixel_bits : Default :: default () , sampled_image_color_sample_counts : Default :: default () , sampled_image_depth_sample_counts : Default :: default () , sampled_image_descriptor_size : Default :: default () , sampled_image_integer_sample_counts : Default :: default () , sampled_image_stencil_sample_counts : Default :: default () , sampler_capture_replay_descriptor_data_size : Default :: default () , sampler_descriptor_buffer_address_space_size : Default :: default () , sampler_descriptor_size : Default :: default () , sgpr_allocation_granularity : Default :: default () , sgprs_per_simd : Default :: default () , shader_arrays_per_engine_count : Default :: default () , shader_core_count : Default :: default () , shader_core_features : Default :: default () , shader_core_mask : Default :: default () , shader_denorm_flush_to_zero_float16 : Default :: default () , shader_denorm_flush_to_zero_float32 : Default :: default () , shader_denorm_flush_to_zero_float64 : Default :: default () , shader_denorm_preserve_float16 : Default :: default () , shader_denorm_preserve_float32 : Default :: default () , shader_denorm_preserve_float64 : Default :: default () , shader_engine_count : Default :: default () , shader_group_base_alignment : Default :: default () , shader_group_handle_alignment : Default :: default () , shader_group_handle_capture_replay_size : Default :: default () , shader_group_handle_size : Default :: default () , shader_input_attachment_array_non_uniform_indexing_native : Default :: default () , shader_module_identifier_algorithm_uuid : Default :: default () , shader_rounding_mode_rte_float16 : Default :: default () , shader_rounding_mode_rte_float32 : Default :: default () , shader_rounding_mode_rte_float64 : Default :: default () , shader_rounding_mode_rtz_float16 : Default :: default () , shader_rounding_mode_rtz_float32 : Default :: default () , shader_rounding_mode_rtz_float64 : Default :: default () , shader_sampled_image_array_non_uniform_indexing_native : Default :: default () , shader_signed_zero_inf_nan_preserve_float16 : Default :: default () , shader_signed_zero_inf_nan_preserve_float32 : Default :: default () , shader_signed_zero_inf_nan_preserve_float64 : Default :: default () , shader_sm_count : Default :: default () , shader_storage_buffer_array_non_uniform_indexing_native : Default :: default () , shader_storage_image_array_non_uniform_indexing_native : Default :: default () , shader_uniform_buffer_array_non_uniform_indexing_native : Default :: default () , shader_warps_per_core : Default :: default () , shader_warps_per_sm : Default :: default () , shading_rate_max_coarse_samples : Default :: default () , shading_rate_palette_size : Default :: default () , shading_rate_texel_size : Default :: default () , simd_per_compute_unit : Default :: default () , sparse_address_space_size : Default :: default () , standard_sample_locations : Default :: default () , storage_buffer_descriptor_size : Default :: default () , storage_image_descriptor_size : Default :: default () , storage_image_sample_counts : Default :: default () , storage_texel_buffer_descriptor_size : Default :: default () , storage_texel_buffer_offset_alignment_bytes : Default :: default () , storage_texel_buffer_offset_single_texel_alignment : Default :: default () , strict_lines : Default :: default () , sub_pixel_interpolation_offset_bits : Default :: default () , sub_pixel_precision_bits : Default :: default () , sub_texel_precision_bits : Default :: default () , subgroup_quad_operations_in_all_stages : Default :: default () , subgroup_size : Default :: default () , subgroup_supported_operations : Default :: default () , subgroup_supported_stages : Default :: default () , subsampled_coarse_reconstruction_early_access : Default :: default () , subsampled_loads : Default :: default () , supported_depth_resolve_modes : Default :: default () , supported_hint_grid_sizes : Default :: default () , supported_operations : Default :: default () , supported_output_grid_sizes : Default :: default () , supported_queues : Default :: default () , supported_stages : Default :: default () , supported_stencil_resolve_modes : Default :: default () , timestamp_compute_and_graphics : Default :: default () , timestamp_period : Default :: default () , transform_feedback_draw : Default :: default () , transform_feedback_preserves_triangle_fan_provoking_vertex : Default :: default () , transform_feedback_queries : Default :: default () , transform_feedback_rasterization_stream_select : Default :: default () , transform_feedback_streams_lines_triangles : Default :: default () , tri_strip_vertex_order_independent_of_provoking_vertex : Default :: default () , uniform_buffer_descriptor_size : Default :: default () , uniform_texel_buffer_descriptor_size : Default :: default () , uniform_texel_buffer_offset_alignment_bytes : Default :: default () , uniform_texel_buffer_offset_single_texel_alignment : Default :: default () , variable_sample_locations : Default :: default () , vendor_id : Default :: default () , vgpr_allocation_granularity : Default :: default () , vgprs_per_simd : Default :: default () , viewport_bounds_range : Default :: default () , viewport_sub_pixel_bits : Default :: default () , wavefront_size : Default :: default () , wavefronts_per_simd : Default :: default () , _ne : crate :: NonExhaustive (()) , }
+ }
+}
+impl From<&PropertiesFfi> for Properties {
+ fn from(properties_ffi: &PropertiesFfi) -> Self {
+ Properties { acceleration_structure_capture_replay_descriptor_data_size : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . acceleration_structure_capture_replay_descriptor_data_size)] . into_iter () . flatten () . next () . and_then (< usize > :: from_vulkan) , acceleration_structure_descriptor_size : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . acceleration_structure_descriptor_size)] . into_iter () . flatten () . next () . and_then (< usize > :: from_vulkan) , active_compute_unit_count : [properties_ffi . properties_shader_core2_amd . map (| s | s . active_compute_unit_count)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , advanced_blend_all_operations : [properties_ffi . properties_blend_operation_advanced_ext . map (| s | s . advanced_blend_all_operations)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , advanced_blend_correlated_overlap : [properties_ffi . properties_blend_operation_advanced_ext . map (| s | s . advanced_blend_correlated_overlap)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , advanced_blend_independent_blend : [properties_ffi . properties_blend_operation_advanced_ext . map (| s | s . advanced_blend_independent_blend)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , advanced_blend_max_color_attachments : [properties_ffi . properties_blend_operation_advanced_ext . map (| s | s . advanced_blend_max_color_attachments)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , advanced_blend_non_premultiplied_dst_color : [properties_ffi . properties_blend_operation_advanced_ext . map (| s | s . advanced_blend_non_premultiplied_dst_color)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , advanced_blend_non_premultiplied_src_color : [properties_ffi . properties_blend_operation_advanced_ext . map (| s | s . advanced_blend_non_premultiplied_src_color)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , allow_command_buffer_query_copies : [properties_ffi . properties_performance_query_khr . map (| s | s . allow_command_buffer_query_copies)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , allow_sampler_image_view_post_submit_creation : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . allow_sampler_image_view_post_submit_creation)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , api_version : [properties_ffi . properties_vulkan10 . properties . api_version] . into_iter () . next () . and_then (< Version > :: from_vulkan) . unwrap () , bidirectional_flow_supported : [properties_ffi . properties_optical_flow_nv . map (| s | s . bidirectional_flow_supported)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , buffer_capture_replay_descriptor_data_size : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . buffer_capture_replay_descriptor_data_size)] . into_iter () . flatten () . next () . and_then (< usize > :: from_vulkan) , buffer_image_granularity : [properties_ffi . properties_vulkan10 . properties . limits . buffer_image_granularity] . into_iter () . next () . and_then (< DeviceAlignment > :: from_vulkan) . unwrap () , bufferless_push_descriptors : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . bufferless_push_descriptors)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , combined_image_sampler_density_map_descriptor_size : [properties_ffi . properties_descriptor_buffer_density_map_ext . map (| s | s . combined_image_sampler_density_map_descriptor_size)] . into_iter () . flatten () . next () . and_then (< usize > :: from_vulkan) , combined_image_sampler_descriptor_single_array : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . combined_image_sampler_descriptor_single_array)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , combined_image_sampler_descriptor_size : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . combined_image_sampler_descriptor_size)] . into_iter () . flatten () . next () . and_then (< usize > :: from_vulkan) , compute_units_per_shader_array : [properties_ffi . properties_shader_core_amd . map (| s | s . compute_units_per_shader_array)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , conformance_version : [properties_ffi . properties_vulkan12 . map (| s | s . conformance_version) , properties_ffi . properties_driver . map (| s | s . conformance_version)] . into_iter () . flatten () . next () . and_then (< ConformanceVersion > :: from_vulkan) , conservative_point_and_line_rasterization : [properties_ffi . properties_conservative_rasterization_ext . map (| s | s . conservative_point_and_line_rasterization)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , conservative_rasterization_post_depth_coverage : [properties_ffi . properties_conservative_rasterization_ext . map (| s | s . conservative_rasterization_post_depth_coverage)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , cooperative_matrix_supported_stages : [properties_ffi . properties_cooperative_matrix_nv . map (| s | s . cooperative_matrix_supported_stages)] . into_iter () . flatten () . next () . and_then (< ShaderStages > :: from_vulkan) , cost_supported : [properties_ffi . properties_optical_flow_nv . map (| s | s . cost_supported)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , decompression_methods : [properties_ffi . properties_memory_decompression_nv . map (| s | s . decompression_methods)] . into_iter () . flatten () . next () . and_then (< MemoryDecompressionMethods > :: from_vulkan) , default_robustness_images : [properties_ffi . properties_pipeline_robustness_ext . map (| s | s . default_robustness_images)] . into_iter () . flatten () . next () . and_then (< PipelineRobustnessImageBehavior > :: from_vulkan) , default_robustness_storage_buffers : [properties_ffi . properties_pipeline_robustness_ext . map (| s | s . default_robustness_storage_buffers)] . into_iter () . flatten () . next () . and_then (< PipelineRobustnessBufferBehavior > :: from_vulkan) , default_robustness_uniform_buffers : [properties_ffi . properties_pipeline_robustness_ext . map (| s | s . default_robustness_uniform_buffers)] . into_iter () . flatten () . next () . and_then (< PipelineRobustnessBufferBehavior > :: from_vulkan) , default_robustness_vertex_inputs : [properties_ffi . properties_pipeline_robustness_ext . map (| s | s . default_robustness_vertex_inputs)] . into_iter () . flatten () . next () . and_then (< PipelineRobustnessBufferBehavior > :: from_vulkan) , degenerate_lines_rasterized : [properties_ffi . properties_conservative_rasterization_ext . map (| s | s . degenerate_lines_rasterized)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , degenerate_triangles_rasterized : [properties_ffi . properties_conservative_rasterization_ext . map (| s | s . degenerate_triangles_rasterized)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , denorm_behavior_independence : [properties_ffi . properties_vulkan12 . map (| s | s . denorm_behavior_independence) , properties_ffi . properties_float_controls . map (| s | s . denorm_behavior_independence)] . into_iter () . flatten () . next () . and_then (< ShaderFloatControlsIndependence > :: from_vulkan) , descriptor_buffer_address_space_size : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . descriptor_buffer_address_space_size)] . into_iter () . flatten () . next () . and_then (< DeviceSize > :: from_vulkan) , descriptor_buffer_offset_alignment : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . descriptor_buffer_offset_alignment)] . into_iter () . flatten () . next () . and_then (< DeviceSize > :: from_vulkan) , device_id : [properties_ffi . properties_vulkan10 . properties . device_id] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , device_luid : [properties_ffi . properties_vulkan11 . map (| s | s . device_luid) , properties_ffi . properties_id . map (| s | s . device_luid)] . into_iter () . flatten () . next () . and_then (< [u8 ; 8] > :: from_vulkan) , device_luid_valid : [properties_ffi . properties_vulkan11 . map (| s | s . device_luid_valid) , properties_ffi . properties_id . map (| s | s . device_luid_valid)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , device_name : [properties_ffi . properties_vulkan10 . properties . device_name] . into_iter () . next () . and_then (< String > :: from_vulkan) . unwrap () , device_node_mask : [properties_ffi . properties_vulkan11 . map (| s | s . device_node_mask) , properties_ffi . properties_id . map (| s | s . device_node_mask)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , device_type : [properties_ffi . properties_vulkan10 . properties . device_type] . into_iter () . next () . and_then (< PhysicalDeviceType > :: from_vulkan) . unwrap () , device_uuid : [properties_ffi . properties_vulkan11 . map (| s | s . device_uuid) , properties_ffi . properties_id . map (| s | s . device_uuid)] . into_iter () . flatten () . next () . and_then (< [u8 ; 16] > :: from_vulkan) , discrete_queue_priorities : [properties_ffi . properties_vulkan10 . properties . limits . discrete_queue_priorities] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , driver_id : [properties_ffi . properties_vulkan12 . map (| s | s . driver_id) , properties_ffi . properties_driver . map (| s | s . driver_id)] . into_iter () . flatten () . next () . and_then (< DriverId > :: from_vulkan) , driver_info : [properties_ffi . properties_vulkan12 . map (| s | s . driver_info) , properties_ffi . properties_driver . map (| s | s . driver_info)] . into_iter () . flatten () . next () . and_then (< String > :: from_vulkan) , driver_name : [properties_ffi . properties_vulkan12 . map (| s | s . driver_name) , properties_ffi . properties_driver . map (| s | s . driver_name)] . into_iter () . flatten () . next () . and_then (< String > :: from_vulkan) , driver_uuid : [properties_ffi . properties_vulkan11 . map (| s | s . driver_uuid) , properties_ffi . properties_id . map (| s | s . driver_uuid)] . into_iter () . flatten () . next () . and_then (< [u8 ; 16] > :: from_vulkan) , driver_version : [properties_ffi . properties_vulkan10 . properties . driver_version] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , dynamic_primitive_topology_unrestricted : [properties_ffi . properties_extended_dynamic_state3_ext . map (| s | s . dynamic_primitive_topology_unrestricted)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , extra_primitive_overestimation_size_granularity : [properties_ffi . properties_conservative_rasterization_ext . map (| s | s . extra_primitive_overestimation_size_granularity)] . into_iter () . flatten () . next () . and_then (< f32 > :: from_vulkan) , filter_minmax_image_component_mapping : [properties_ffi . properties_vulkan12 . map (| s | s . filter_minmax_image_component_mapping) , properties_ffi . properties_sampler_filter_minmax . map (| s | s . filter_minmax_image_component_mapping)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , filter_minmax_single_component_formats : [properties_ffi . properties_vulkan12 . map (| s | s . filter_minmax_single_component_formats) , properties_ffi . properties_sampler_filter_minmax . map (| s | s . filter_minmax_single_component_formats)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , fragment_density_invocations : [properties_ffi . properties_fragment_density_map_ext . map (| s | s . fragment_density_invocations)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , fragment_density_offset_granularity : [properties_ffi . properties_fragment_density_map_offset_qcom . map (| s | s . fragment_density_offset_granularity)] . into_iter () . flatten () . next () . and_then (< [u32 ; 2] > :: from_vulkan) , fragment_shading_rate_non_trivial_combiner_ops : [properties_ffi . properties_fragment_shading_rate_khr . map (| s | s . fragment_shading_rate_non_trivial_combiner_ops)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , fragment_shading_rate_strict_multiply_combiner : [properties_ffi . properties_fragment_shading_rate_khr . map (| s | s . fragment_shading_rate_strict_multiply_combiner)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , fragment_shading_rate_with_conservative_rasterization : [properties_ffi . properties_fragment_shading_rate_khr . map (| s | s . fragment_shading_rate_with_conservative_rasterization)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , fragment_shading_rate_with_custom_sample_locations : [properties_ffi . properties_fragment_shading_rate_khr . map (| s | s . fragment_shading_rate_with_custom_sample_locations)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , fragment_shading_rate_with_fragment_shader_interlock : [properties_ffi . properties_fragment_shading_rate_khr . map (| s | s . fragment_shading_rate_with_fragment_shader_interlock)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , fragment_shading_rate_with_sample_mask : [properties_ffi . properties_fragment_shading_rate_khr . map (| s | s . fragment_shading_rate_with_sample_mask)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , fragment_shading_rate_with_shader_depth_stencil_writes : [properties_ffi . properties_fragment_shading_rate_khr . map (| s | s . fragment_shading_rate_with_shader_depth_stencil_writes)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , fragment_shading_rate_with_shader_sample_mask : [properties_ffi . properties_fragment_shading_rate_khr . map (| s | s . fragment_shading_rate_with_shader_sample_mask)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , framebuffer_color_sample_counts : [properties_ffi . properties_vulkan10 . properties . limits . framebuffer_color_sample_counts] . into_iter () . next () . and_then (< SampleCounts > :: from_vulkan) . unwrap () , framebuffer_depth_sample_counts : [properties_ffi . properties_vulkan10 . properties . limits . framebuffer_depth_sample_counts] . into_iter () . next () . and_then (< SampleCounts > :: from_vulkan) . unwrap () , framebuffer_integer_color_sample_counts : [properties_ffi . properties_vulkan12 . map (| s | s . framebuffer_integer_color_sample_counts)] . into_iter () . flatten () . next () . and_then (< SampleCounts > :: from_vulkan) , framebuffer_no_attachments_sample_counts : [properties_ffi . properties_vulkan10 . properties . limits . framebuffer_no_attachments_sample_counts] . into_iter () . next () . and_then (< SampleCounts > :: from_vulkan) . unwrap () , framebuffer_stencil_sample_counts : [properties_ffi . properties_vulkan10 . properties . limits . framebuffer_stencil_sample_counts] . into_iter () . next () . and_then (< SampleCounts > :: from_vulkan) . unwrap () , fully_covered_fragment_shader_input_variable : [properties_ffi . properties_conservative_rasterization_ext . map (| s | s . fully_covered_fragment_shader_input_variable)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , global_flow_supported : [properties_ffi . properties_optical_flow_nv . map (| s | s . global_flow_supported)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , graphics_pipeline_library_fast_linking : [properties_ffi . properties_graphics_pipeline_library_ext . map (| s | s . graphics_pipeline_library_fast_linking)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , graphics_pipeline_library_independent_interpolation_decoration : [properties_ffi . properties_graphics_pipeline_library_ext . map (| s | s . graphics_pipeline_library_independent_interpolation_decoration)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , has_primary : [properties_ffi . properties_drm_ext . map (| s | s . has_primary)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , has_render : [properties_ffi . properties_drm_ext . map (| s | s . has_render)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , hint_supported : [properties_ffi . properties_optical_flow_nv . map (| s | s . hint_supported)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , image_capture_replay_descriptor_data_size : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . image_capture_replay_descriptor_data_size)] . into_iter () . flatten () . next () . and_then (< usize > :: from_vulkan) , image_view_capture_replay_descriptor_data_size : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . image_view_capture_replay_descriptor_data_size)] . into_iter () . flatten () . next () . and_then (< usize > :: from_vulkan) , independent_resolve : [properties_ffi . properties_vulkan12 . map (| s | s . independent_resolve) , properties_ffi . properties_depth_stencil_resolve . map (| s | s . independent_resolve)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , independent_resolve_none : [properties_ffi . properties_vulkan12 . map (| s | s . independent_resolve_none) , properties_ffi . properties_depth_stencil_resolve . map (| s | s . independent_resolve_none)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , input_attachment_descriptor_size : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . input_attachment_descriptor_size)] . into_iter () . flatten () . next () . and_then (< usize > :: from_vulkan) , integer_dot_product16_bit_mixed_signedness_accelerated : [properties_ffi . properties_vulkan13 . map (| s | s . integer_dot_product16_bit_mixed_signedness_accelerated) , properties_ffi . properties_shader_integer_dot_product . map (| s | s . integer_dot_product16_bit_mixed_signedness_accelerated)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , integer_dot_product16_bit_signed_accelerated : [properties_ffi . properties_vulkan13 . map (| s | s . integer_dot_product16_bit_signed_accelerated) , properties_ffi . properties_shader_integer_dot_product . map (| s | s . integer_dot_product16_bit_signed_accelerated)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , integer_dot_product16_bit_unsigned_accelerated : [properties_ffi . properties_vulkan13 . map (| s | s . integer_dot_product16_bit_unsigned_accelerated) , properties_ffi . properties_shader_integer_dot_product . map (| s | s . integer_dot_product16_bit_unsigned_accelerated)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , integer_dot_product32_bit_mixed_signedness_accelerated : [properties_ffi . properties_vulkan13 . map (| s | s . integer_dot_product32_bit_mixed_signedness_accelerated) , properties_ffi . properties_shader_integer_dot_product . map (| s | s . integer_dot_product32_bit_mixed_signedness_accelerated)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , integer_dot_product32_bit_signed_accelerated : [properties_ffi . properties_vulkan13 . map (| s | s . integer_dot_product32_bit_signed_accelerated) , properties_ffi . properties_shader_integer_dot_product . map (| s | s . integer_dot_product32_bit_signed_accelerated)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , integer_dot_product32_bit_unsigned_accelerated : [properties_ffi . properties_vulkan13 . map (| s | s . integer_dot_product32_bit_unsigned_accelerated) , properties_ffi . properties_shader_integer_dot_product . map (| s | s . integer_dot_product32_bit_unsigned_accelerated)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , integer_dot_product4x8_bit_packed_mixed_signedness_accelerated : [properties_ffi . properties_vulkan13 . map (| s | s . integer_dot_product4x8_bit_packed_mixed_signedness_accelerated) , properties_ffi . properties_shader_integer_dot_product . map (| s | s . integer_dot_product4x8_bit_packed_mixed_signedness_accelerated)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , integer_dot_product4x8_bit_packed_signed_accelerated : [properties_ffi . properties_vulkan13 . map (| s | s . integer_dot_product4x8_bit_packed_signed_accelerated) , properties_ffi . properties_shader_integer_dot_product . map (| s | s . integer_dot_product4x8_bit_packed_signed_accelerated)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , integer_dot_product4x8_bit_packed_unsigned_accelerated : [properties_ffi . properties_vulkan13 . map (| s | s . integer_dot_product4x8_bit_packed_unsigned_accelerated) , properties_ffi . properties_shader_integer_dot_product . map (| s | s . integer_dot_product4x8_bit_packed_unsigned_accelerated)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , integer_dot_product64_bit_mixed_signedness_accelerated : [properties_ffi . properties_vulkan13 . map (| s | s . integer_dot_product64_bit_mixed_signedness_accelerated) , properties_ffi . properties_shader_integer_dot_product . map (| s | s . integer_dot_product64_bit_mixed_signedness_accelerated)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , integer_dot_product64_bit_signed_accelerated : [properties_ffi . properties_vulkan13 . map (| s | s . integer_dot_product64_bit_signed_accelerated) , properties_ffi . properties_shader_integer_dot_product . map (| s | s . integer_dot_product64_bit_signed_accelerated)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , integer_dot_product64_bit_unsigned_accelerated : [properties_ffi . properties_vulkan13 . map (| s | s . integer_dot_product64_bit_unsigned_accelerated) , properties_ffi . properties_shader_integer_dot_product . map (| s | s . integer_dot_product64_bit_unsigned_accelerated)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , integer_dot_product8_bit_mixed_signedness_accelerated : [properties_ffi . properties_vulkan13 . map (| s | s . integer_dot_product8_bit_mixed_signedness_accelerated) , properties_ffi . properties_shader_integer_dot_product . map (| s | s . integer_dot_product8_bit_mixed_signedness_accelerated)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , integer_dot_product8_bit_signed_accelerated : [properties_ffi . properties_vulkan13 . map (| s | s . integer_dot_product8_bit_signed_accelerated) , properties_ffi . properties_shader_integer_dot_product . map (| s | s . integer_dot_product8_bit_signed_accelerated)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , integer_dot_product8_bit_unsigned_accelerated : [properties_ffi . properties_vulkan13 . map (| s | s . integer_dot_product8_bit_unsigned_accelerated) , properties_ffi . properties_shader_integer_dot_product . map (| s | s . integer_dot_product8_bit_unsigned_accelerated)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , integer_dot_product_accumulating_saturating16_bit_mixed_signedness_accelerated : [properties_ffi . properties_vulkan13 . map (| s | s . integer_dot_product_accumulating_saturating16_bit_mixed_signedness_accelerated) , properties_ffi . properties_shader_integer_dot_product . map (| s | s . integer_dot_product_accumulating_saturating16_bit_mixed_signedness_accelerated)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , integer_dot_product_accumulating_saturating16_bit_signed_accelerated : [properties_ffi . properties_vulkan13 . map (| s | s . integer_dot_product_accumulating_saturating16_bit_signed_accelerated) , properties_ffi . properties_shader_integer_dot_product . map (| s | s . integer_dot_product_accumulating_saturating16_bit_signed_accelerated)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , integer_dot_product_accumulating_saturating16_bit_unsigned_accelerated : [properties_ffi . properties_vulkan13 . map (| s | s . integer_dot_product_accumulating_saturating16_bit_unsigned_accelerated) , properties_ffi . properties_shader_integer_dot_product . map (| s | s . integer_dot_product_accumulating_saturating16_bit_unsigned_accelerated)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , integer_dot_product_accumulating_saturating32_bit_mixed_signedness_accelerated : [properties_ffi . properties_vulkan13 . map (| s | s . integer_dot_product_accumulating_saturating32_bit_mixed_signedness_accelerated) , properties_ffi . properties_shader_integer_dot_product . map (| s | s . integer_dot_product_accumulating_saturating32_bit_mixed_signedness_accelerated)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , integer_dot_product_accumulating_saturating32_bit_signed_accelerated : [properties_ffi . properties_vulkan13 . map (| s | s . integer_dot_product_accumulating_saturating32_bit_signed_accelerated) , properties_ffi . properties_shader_integer_dot_product . map (| s | s . integer_dot_product_accumulating_saturating32_bit_signed_accelerated)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , integer_dot_product_accumulating_saturating32_bit_unsigned_accelerated : [properties_ffi . properties_vulkan13 . map (| s | s . integer_dot_product_accumulating_saturating32_bit_unsigned_accelerated) , properties_ffi . properties_shader_integer_dot_product . map (| s | s . integer_dot_product_accumulating_saturating32_bit_unsigned_accelerated)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , integer_dot_product_accumulating_saturating4x8_bit_packed_mixed_signedness_accelerated : [properties_ffi . properties_vulkan13 . map (| s | s . integer_dot_product_accumulating_saturating4x8_bit_packed_mixed_signedness_accelerated) , properties_ffi . properties_shader_integer_dot_product . map (| s | s . integer_dot_product_accumulating_saturating4x8_bit_packed_mixed_signedness_accelerated)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , integer_dot_product_accumulating_saturating4x8_bit_packed_signed_accelerated : [properties_ffi . properties_vulkan13 . map (| s | s . integer_dot_product_accumulating_saturating4x8_bit_packed_signed_accelerated) , properties_ffi . properties_shader_integer_dot_product . map (| s | s . integer_dot_product_accumulating_saturating4x8_bit_packed_signed_accelerated)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , integer_dot_product_accumulating_saturating4x8_bit_packed_unsigned_accelerated : [properties_ffi . properties_vulkan13 . map (| s | s . integer_dot_product_accumulating_saturating4x8_bit_packed_unsigned_accelerated) , properties_ffi . properties_shader_integer_dot_product . map (| s | s . integer_dot_product_accumulating_saturating4x8_bit_packed_unsigned_accelerated)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , integer_dot_product_accumulating_saturating64_bit_mixed_signedness_accelerated : [properties_ffi . properties_vulkan13 . map (| s | s . integer_dot_product_accumulating_saturating64_bit_mixed_signedness_accelerated) , properties_ffi . properties_shader_integer_dot_product . map (| s | s . integer_dot_product_accumulating_saturating64_bit_mixed_signedness_accelerated)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , integer_dot_product_accumulating_saturating64_bit_signed_accelerated : [properties_ffi . properties_vulkan13 . map (| s | s . integer_dot_product_accumulating_saturating64_bit_signed_accelerated) , properties_ffi . properties_shader_integer_dot_product . map (| s | s . integer_dot_product_accumulating_saturating64_bit_signed_accelerated)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , integer_dot_product_accumulating_saturating64_bit_unsigned_accelerated : [properties_ffi . properties_vulkan13 . map (| s | s . integer_dot_product_accumulating_saturating64_bit_unsigned_accelerated) , properties_ffi . properties_shader_integer_dot_product . map (| s | s . integer_dot_product_accumulating_saturating64_bit_unsigned_accelerated)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , integer_dot_product_accumulating_saturating8_bit_mixed_signedness_accelerated : [properties_ffi . properties_vulkan13 . map (| s | s . integer_dot_product_accumulating_saturating8_bit_mixed_signedness_accelerated) , properties_ffi . properties_shader_integer_dot_product . map (| s | s . integer_dot_product_accumulating_saturating8_bit_mixed_signedness_accelerated)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , integer_dot_product_accumulating_saturating8_bit_signed_accelerated : [properties_ffi . properties_vulkan13 . map (| s | s . integer_dot_product_accumulating_saturating8_bit_signed_accelerated) , properties_ffi . properties_shader_integer_dot_product . map (| s | s . integer_dot_product_accumulating_saturating8_bit_signed_accelerated)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , integer_dot_product_accumulating_saturating8_bit_unsigned_accelerated : [properties_ffi . properties_vulkan13 . map (| s | s . integer_dot_product_accumulating_saturating8_bit_unsigned_accelerated) , properties_ffi . properties_shader_integer_dot_product . map (| s | s . integer_dot_product_accumulating_saturating8_bit_unsigned_accelerated)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , layered_shading_rate_attachments : [properties_ffi . properties_fragment_shading_rate_khr . map (| s | s . layered_shading_rate_attachments)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , line_sub_pixel_precision_bits : [properties_ffi . properties_line_rasterization_ext . map (| s | s . line_sub_pixel_precision_bits)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , line_width_granularity : [properties_ffi . properties_vulkan10 . properties . limits . line_width_granularity] . into_iter () . next () . and_then (< f32 > :: from_vulkan) . unwrap () , line_width_range : [properties_ffi . properties_vulkan10 . properties . limits . line_width_range] . into_iter () . next () . and_then (< [f32 ; 2] > :: from_vulkan) . unwrap () , max_block_match_region : [properties_ffi . properties_image_processing_qcom . map (| s | s . max_block_match_region)] . into_iter () . flatten () . next () . and_then (< [u32 ; 2] > :: from_vulkan) , max_bound_descriptor_sets : [properties_ffi . properties_vulkan10 . properties . limits . max_bound_descriptor_sets] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_box_filter_block_size : [properties_ffi . properties_image_processing_qcom . map (| s | s . max_box_filter_block_size)] . into_iter () . flatten () . next () . and_then (< [u32 ; 2] > :: from_vulkan) , max_buffer_size : [properties_ffi . properties_vulkan13 . map (| s | s . max_buffer_size) , properties_ffi . properties_maintenance4 . map (| s | s . max_buffer_size)] . into_iter () . flatten () . next () . and_then (< DeviceSize > :: from_vulkan) , max_clip_distances : [properties_ffi . properties_vulkan10 . properties . limits . max_clip_distances] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_color_attachments : [properties_ffi . properties_vulkan10 . properties . limits . max_color_attachments] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_combined_clip_and_cull_distances : [properties_ffi . properties_vulkan10 . properties . limits . max_combined_clip_and_cull_distances] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_compute_shared_memory_size : [properties_ffi . properties_vulkan10 . properties . limits . max_compute_shared_memory_size] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_compute_work_group_count : [properties_ffi . properties_vulkan10 . properties . limits . max_compute_work_group_count] . into_iter () . next () . and_then (< [u32 ; 3] > :: from_vulkan) . unwrap () , max_compute_work_group_invocations : [properties_ffi . properties_vulkan10 . properties . limits . max_compute_work_group_invocations] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_compute_work_group_size : [properties_ffi . properties_vulkan10 . properties . limits . max_compute_work_group_size] . into_iter () . next () . and_then (< [u32 ; 3] > :: from_vulkan) . unwrap () , max_compute_workgroup_subgroups : [properties_ffi . properties_vulkan13 . map (| s | s . max_compute_workgroup_subgroups) , properties_ffi . properties_subgroup_size_control . map (| s | s . max_compute_workgroup_subgroups)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_cull_distances : [properties_ffi . properties_vulkan10 . properties . limits . max_cull_distances] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_custom_border_color_samplers : [properties_ffi . properties_custom_border_color_ext . map (| s | s . max_custom_border_color_samplers)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_decompression_indirect_count : [properties_ffi . properties_memory_decompression_nv . map (| s | s . max_decompression_indirect_count)] . into_iter () . flatten () . next () . and_then (< u64 > :: from_vulkan) , max_descriptor_buffer_bindings : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . max_descriptor_buffer_bindings)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_descriptor_set_acceleration_structures : [properties_ffi . properties_acceleration_structure_khr . map (| s | s . max_descriptor_set_acceleration_structures) , properties_ffi . properties_ray_tracing_nv . map (| s | s . max_descriptor_set_acceleration_structures)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_descriptor_set_inline_uniform_blocks : [properties_ffi . properties_vulkan13 . map (| s | s . max_descriptor_set_inline_uniform_blocks) , properties_ffi . properties_inline_uniform_block . map (| s | s . max_descriptor_set_inline_uniform_blocks)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_descriptor_set_input_attachments : [properties_ffi . properties_vulkan10 . properties . limits . max_descriptor_set_input_attachments] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_descriptor_set_sampled_images : [properties_ffi . properties_vulkan10 . properties . limits . max_descriptor_set_sampled_images] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_descriptor_set_samplers : [properties_ffi . properties_vulkan10 . properties . limits . max_descriptor_set_samplers] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_descriptor_set_storage_buffers : [properties_ffi . properties_vulkan10 . properties . limits . max_descriptor_set_storage_buffers] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_descriptor_set_storage_buffers_dynamic : [properties_ffi . properties_vulkan10 . properties . limits . max_descriptor_set_storage_buffers_dynamic] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_descriptor_set_storage_images : [properties_ffi . properties_vulkan10 . properties . limits . max_descriptor_set_storage_images] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_descriptor_set_subsampled_samplers : [properties_ffi . properties_fragment_density_map2_ext . map (| s | s . max_descriptor_set_subsampled_samplers)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_descriptor_set_uniform_buffers : [properties_ffi . properties_vulkan10 . properties . limits . max_descriptor_set_uniform_buffers] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_descriptor_set_uniform_buffers_dynamic : [properties_ffi . properties_vulkan10 . properties . limits . max_descriptor_set_uniform_buffers_dynamic] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_descriptor_set_update_after_bind_acceleration_structures : [properties_ffi . properties_acceleration_structure_khr . map (| s | s . max_descriptor_set_update_after_bind_acceleration_structures)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_descriptor_set_update_after_bind_inline_uniform_blocks : [properties_ffi . properties_vulkan13 . map (| s | s . max_descriptor_set_update_after_bind_inline_uniform_blocks) , properties_ffi . properties_inline_uniform_block . map (| s | s . max_descriptor_set_update_after_bind_inline_uniform_blocks)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_descriptor_set_update_after_bind_input_attachments : [properties_ffi . properties_vulkan12 . map (| s | s . max_descriptor_set_update_after_bind_input_attachments) , properties_ffi . properties_descriptor_indexing . map (| s | s . max_descriptor_set_update_after_bind_input_attachments)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_descriptor_set_update_after_bind_sampled_images : [properties_ffi . properties_vulkan12 . map (| s | s . max_descriptor_set_update_after_bind_sampled_images) , properties_ffi . properties_descriptor_indexing . map (| s | s . max_descriptor_set_update_after_bind_sampled_images)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_descriptor_set_update_after_bind_samplers : [properties_ffi . properties_vulkan12 . map (| s | s . max_descriptor_set_update_after_bind_samplers) , properties_ffi . properties_descriptor_indexing . map (| s | s . max_descriptor_set_update_after_bind_samplers)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_descriptor_set_update_after_bind_storage_buffers : [properties_ffi . properties_vulkan12 . map (| s | s . max_descriptor_set_update_after_bind_storage_buffers) , properties_ffi . properties_descriptor_indexing . map (| s | s . max_descriptor_set_update_after_bind_storage_buffers)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_descriptor_set_update_after_bind_storage_buffers_dynamic : [properties_ffi . properties_vulkan12 . map (| s | s . max_descriptor_set_update_after_bind_storage_buffers_dynamic) , properties_ffi . properties_descriptor_indexing . map (| s | s . max_descriptor_set_update_after_bind_storage_buffers_dynamic)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_descriptor_set_update_after_bind_storage_images : [properties_ffi . properties_vulkan12 . map (| s | s . max_descriptor_set_update_after_bind_storage_images) , properties_ffi . properties_descriptor_indexing . map (| s | s . max_descriptor_set_update_after_bind_storage_images)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_descriptor_set_update_after_bind_uniform_buffers : [properties_ffi . properties_vulkan12 . map (| s | s . max_descriptor_set_update_after_bind_uniform_buffers) , properties_ffi . properties_descriptor_indexing . map (| s | s . max_descriptor_set_update_after_bind_uniform_buffers)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_descriptor_set_update_after_bind_uniform_buffers_dynamic : [properties_ffi . properties_vulkan12 . map (| s | s . max_descriptor_set_update_after_bind_uniform_buffers_dynamic) , properties_ffi . properties_descriptor_indexing . map (| s | s . max_descriptor_set_update_after_bind_uniform_buffers_dynamic)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_discard_rectangles : [properties_ffi . properties_discard_rectangle_ext . map (| s | s . max_discard_rectangles)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_draw_indexed_index_value : [properties_ffi . properties_vulkan10 . properties . limits . max_draw_indexed_index_value] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_draw_indirect_count : [properties_ffi . properties_vulkan10 . properties . limits . max_draw_indirect_count] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_draw_mesh_tasks_count : [properties_ffi . properties_mesh_shader_nv . map (| s | s . max_draw_mesh_tasks_count)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_embedded_immutable_sampler_bindings : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . max_embedded_immutable_sampler_bindings)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_embedded_immutable_samplers : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . max_embedded_immutable_samplers)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_extra_primitive_overestimation_size : [properties_ffi . properties_conservative_rasterization_ext . map (| s | s . max_extra_primitive_overestimation_size)] . into_iter () . flatten () . next () . and_then (< f32 > :: from_vulkan) , max_fragment_combined_output_resources : [properties_ffi . properties_vulkan10 . properties . limits . max_fragment_combined_output_resources] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_fragment_density_texel_size : [properties_ffi . properties_fragment_density_map_ext . map (| s | s . max_fragment_density_texel_size)] . into_iter () . flatten () . next () . and_then (< [u32 ; 2] > :: from_vulkan) , max_fragment_dual_src_attachments : [properties_ffi . properties_vulkan10 . properties . limits . max_fragment_dual_src_attachments] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_fragment_input_components : [properties_ffi . properties_vulkan10 . properties . limits . max_fragment_input_components] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_fragment_output_attachments : [properties_ffi . properties_vulkan10 . properties . limits . max_fragment_output_attachments] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_fragment_shading_rate_attachment_texel_size : [properties_ffi . properties_fragment_shading_rate_khr . map (| s | s . max_fragment_shading_rate_attachment_texel_size)] . into_iter () . flatten () . next () . and_then (< [u32 ; 2] > :: from_vulkan) , max_fragment_shading_rate_attachment_texel_size_aspect_ratio : [properties_ffi . properties_fragment_shading_rate_khr . map (| s | s . max_fragment_shading_rate_attachment_texel_size_aspect_ratio)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_fragment_shading_rate_coverage_samples : [properties_ffi . properties_fragment_shading_rate_khr . map (| s | s . max_fragment_shading_rate_coverage_samples)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_fragment_shading_rate_invocation_count : [properties_ffi . properties_fragment_shading_rate_enums_nv . map (| s | s . max_fragment_shading_rate_invocation_count)] . into_iter () . flatten () . next () . and_then (< SampleCount > :: from_vulkan) , max_fragment_shading_rate_rasterization_samples : [properties_ffi . properties_fragment_shading_rate_khr . map (| s | s . max_fragment_shading_rate_rasterization_samples)] . into_iter () . flatten () . next () . and_then (< SampleCount > :: from_vulkan) , max_fragment_size : [properties_ffi . properties_fragment_shading_rate_khr . map (| s | s . max_fragment_size)] . into_iter () . flatten () . next () . and_then (< [u32 ; 2] > :: from_vulkan) , max_fragment_size_aspect_ratio : [properties_ffi . properties_fragment_shading_rate_khr . map (| s | s . max_fragment_size_aspect_ratio)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_framebuffer_height : [properties_ffi . properties_vulkan10 . properties . limits . max_framebuffer_height] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_framebuffer_layers : [properties_ffi . properties_vulkan10 . properties . limits . max_framebuffer_layers] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_framebuffer_width : [properties_ffi . properties_vulkan10 . properties . limits . max_framebuffer_width] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_geometry_count : [properties_ffi . properties_acceleration_structure_khr . map (| s | s . max_geometry_count) , properties_ffi . properties_ray_tracing_nv . map (| s | s . max_geometry_count)] . into_iter () . flatten () . next () . and_then (< u64 > :: from_vulkan) , max_geometry_input_components : [properties_ffi . properties_vulkan10 . properties . limits . max_geometry_input_components] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_geometry_output_components : [properties_ffi . properties_vulkan10 . properties . limits . max_geometry_output_components] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_geometry_output_vertices : [properties_ffi . properties_vulkan10 . properties . limits . max_geometry_output_vertices] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_geometry_shader_invocations : [properties_ffi . properties_vulkan10 . properties . limits . max_geometry_shader_invocations] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_geometry_total_output_components : [properties_ffi . properties_vulkan10 . properties . limits . max_geometry_total_output_components] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_graphics_shader_group_count : [properties_ffi . properties_device_generated_commands_nv . map (| s | s . max_graphics_shader_group_count)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_height : [properties_ffi . properties_optical_flow_nv . map (| s | s . max_height)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_image_array_layers : [properties_ffi . properties_vulkan10 . properties . limits . max_image_array_layers] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_image_dimension1_d : [properties_ffi . properties_vulkan10 . properties . limits . max_image_dimension1_d] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_image_dimension2_d : [properties_ffi . properties_vulkan10 . properties . limits . max_image_dimension2_d] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_image_dimension3_d : [properties_ffi . properties_vulkan10 . properties . limits . max_image_dimension3_d] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_image_dimension_cube : [properties_ffi . properties_vulkan10 . properties . limits . max_image_dimension_cube] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_indirect_commands_stream_count : [properties_ffi . properties_device_generated_commands_nv . map (| s | s . max_indirect_commands_stream_count)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_indirect_commands_stream_stride : [properties_ffi . properties_device_generated_commands_nv . map (| s | s . max_indirect_commands_stream_stride)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_indirect_commands_token_count : [properties_ffi . properties_device_generated_commands_nv . map (| s | s . max_indirect_commands_token_count)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_indirect_commands_token_offset : [properties_ffi . properties_device_generated_commands_nv . map (| s | s . max_indirect_commands_token_offset)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_indirect_sequence_count : [properties_ffi . properties_device_generated_commands_nv . map (| s | s . max_indirect_sequence_count)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_inline_uniform_block_size : [properties_ffi . properties_vulkan13 . map (| s | s . max_inline_uniform_block_size) , properties_ffi . properties_inline_uniform_block . map (| s | s . max_inline_uniform_block_size)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_inline_uniform_total_size : [properties_ffi . properties_vulkan13 . map (| s | s . max_inline_uniform_total_size)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_instance_count : [properties_ffi . properties_acceleration_structure_khr . map (| s | s . max_instance_count) , properties_ffi . properties_ray_tracing_nv . map (| s | s . max_instance_count)] . into_iter () . flatten () . next () . and_then (< u64 > :: from_vulkan) , max_interpolation_offset : [properties_ffi . properties_vulkan10 . properties . limits . max_interpolation_offset] . into_iter () . next () . and_then (< f32 > :: from_vulkan) . unwrap () , max_memory_allocation_count : [properties_ffi . properties_vulkan10 . properties . limits . max_memory_allocation_count] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_memory_allocation_size : [properties_ffi . properties_vulkan11 . map (| s | s . max_memory_allocation_size) , properties_ffi . properties_maintenance3 . map (| s | s . max_memory_allocation_size)] . into_iter () . flatten () . next () . and_then (< DeviceSize > :: from_vulkan) , max_mesh_multiview_view_count : [properties_ffi . properties_mesh_shader_ext . map (| s | s . max_mesh_multiview_view_count) , properties_ffi . properties_mesh_shader_nv . map (| s | s . max_mesh_multiview_view_count)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_mesh_output_components : [properties_ffi . properties_mesh_shader_ext . map (| s | s . max_mesh_output_components)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_mesh_output_layers : [properties_ffi . properties_mesh_shader_ext . map (| s | s . max_mesh_output_layers)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_mesh_output_memory_size : [properties_ffi . properties_mesh_shader_ext . map (| s | s . max_mesh_output_memory_size)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_mesh_output_primitives : [properties_ffi . properties_mesh_shader_ext . map (| s | s . max_mesh_output_primitives) , properties_ffi . properties_mesh_shader_nv . map (| s | s . max_mesh_output_primitives)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_mesh_output_vertices : [properties_ffi . properties_mesh_shader_ext . map (| s | s . max_mesh_output_vertices) , properties_ffi . properties_mesh_shader_nv . map (| s | s . max_mesh_output_vertices)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_mesh_payload_and_output_memory_size : [properties_ffi . properties_mesh_shader_ext . map (| s | s . max_mesh_payload_and_output_memory_size)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_mesh_payload_and_shared_memory_size : [properties_ffi . properties_mesh_shader_ext . map (| s | s . max_mesh_payload_and_shared_memory_size)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_mesh_shared_memory_size : [properties_ffi . properties_mesh_shader_ext . map (| s | s . max_mesh_shared_memory_size)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_mesh_total_memory_size : [properties_ffi . properties_mesh_shader_nv . map (| s | s . max_mesh_total_memory_size)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_mesh_work_group_count : [properties_ffi . properties_mesh_shader_ext . map (| s | s . max_mesh_work_group_count)] . into_iter () . flatten () . next () . and_then (< [u32 ; 3] > :: from_vulkan) , max_mesh_work_group_invocations : [properties_ffi . properties_mesh_shader_ext . map (| s | s . max_mesh_work_group_invocations) , properties_ffi . properties_mesh_shader_nv . map (| s | s . max_mesh_work_group_invocations)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_mesh_work_group_size : [properties_ffi . properties_mesh_shader_ext . map (| s | s . max_mesh_work_group_size) , properties_ffi . properties_mesh_shader_nv . map (| s | s . max_mesh_work_group_size)] . into_iter () . flatten () . next () . and_then (< [u32 ; 3] > :: from_vulkan) , max_mesh_work_group_total_count : [properties_ffi . properties_mesh_shader_ext . map (| s | s . max_mesh_work_group_total_count)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_multi_draw_count : [properties_ffi . properties_multi_draw_ext . map (| s | s . max_multi_draw_count)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_multiview_instance_index : [properties_ffi . properties_vulkan11 . map (| s | s . max_multiview_instance_index) , properties_ffi . properties_multiview . map (| s | s . max_multiview_instance_index)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_multiview_view_count : [properties_ffi . properties_vulkan11 . map (| s | s . max_multiview_view_count) , properties_ffi . properties_multiview . map (| s | s . max_multiview_view_count)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_num_regions_of_interest : [properties_ffi . properties_optical_flow_nv . map (| s | s . max_num_regions_of_interest)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_opacity2_state_subdivision_level : [properties_ffi . properties_opacity_micromap_ext . map (| s | s . max_opacity2_state_subdivision_level)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_opacity4_state_subdivision_level : [properties_ffi . properties_opacity_micromap_ext . map (| s | s . max_opacity4_state_subdivision_level)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_per_set_descriptors : [properties_ffi . properties_vulkan11 . map (| s | s . max_per_set_descriptors) , properties_ffi . properties_maintenance3 . map (| s | s . max_per_set_descriptors)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_per_stage_descriptor_acceleration_structures : [properties_ffi . properties_acceleration_structure_khr . map (| s | s . max_per_stage_descriptor_acceleration_structures)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_per_stage_descriptor_inline_uniform_blocks : [properties_ffi . properties_vulkan13 . map (| s | s . max_per_stage_descriptor_inline_uniform_blocks) , properties_ffi . properties_inline_uniform_block . map (| s | s . max_per_stage_descriptor_inline_uniform_blocks)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_per_stage_descriptor_input_attachments : [properties_ffi . properties_vulkan10 . properties . limits . max_per_stage_descriptor_input_attachments] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_per_stage_descriptor_sampled_images : [properties_ffi . properties_vulkan10 . properties . limits . max_per_stage_descriptor_sampled_images] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_per_stage_descriptor_samplers : [properties_ffi . properties_vulkan10 . properties . limits . max_per_stage_descriptor_samplers] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_per_stage_descriptor_storage_buffers : [properties_ffi . properties_vulkan10 . properties . limits . max_per_stage_descriptor_storage_buffers] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_per_stage_descriptor_storage_images : [properties_ffi . properties_vulkan10 . properties . limits . max_per_stage_descriptor_storage_images] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_per_stage_descriptor_uniform_buffers : [properties_ffi . properties_vulkan10 . properties . limits . max_per_stage_descriptor_uniform_buffers] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_per_stage_descriptor_update_after_bind_acceleration_structures : [properties_ffi . properties_acceleration_structure_khr . map (| s | s . max_per_stage_descriptor_update_after_bind_acceleration_structures)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_per_stage_descriptor_update_after_bind_inline_uniform_blocks : [properties_ffi . properties_vulkan13 . map (| s | s . max_per_stage_descriptor_update_after_bind_inline_uniform_blocks) , properties_ffi . properties_inline_uniform_block . map (| s | s . max_per_stage_descriptor_update_after_bind_inline_uniform_blocks)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_per_stage_descriptor_update_after_bind_input_attachments : [properties_ffi . properties_vulkan12 . map (| s | s . max_per_stage_descriptor_update_after_bind_input_attachments) , properties_ffi . properties_descriptor_indexing . map (| s | s . max_per_stage_descriptor_update_after_bind_input_attachments)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_per_stage_descriptor_update_after_bind_sampled_images : [properties_ffi . properties_vulkan12 . map (| s | s . max_per_stage_descriptor_update_after_bind_sampled_images) , properties_ffi . properties_descriptor_indexing . map (| s | s . max_per_stage_descriptor_update_after_bind_sampled_images)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_per_stage_descriptor_update_after_bind_samplers : [properties_ffi . properties_vulkan12 . map (| s | s . max_per_stage_descriptor_update_after_bind_samplers) , properties_ffi . properties_descriptor_indexing . map (| s | s . max_per_stage_descriptor_update_after_bind_samplers)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_per_stage_descriptor_update_after_bind_storage_buffers : [properties_ffi . properties_vulkan12 . map (| s | s . max_per_stage_descriptor_update_after_bind_storage_buffers) , properties_ffi . properties_descriptor_indexing . map (| s | s . max_per_stage_descriptor_update_after_bind_storage_buffers)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_per_stage_descriptor_update_after_bind_storage_images : [properties_ffi . properties_vulkan12 . map (| s | s . max_per_stage_descriptor_update_after_bind_storage_images) , properties_ffi . properties_descriptor_indexing . map (| s | s . max_per_stage_descriptor_update_after_bind_storage_images)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_per_stage_descriptor_update_after_bind_uniform_buffers : [properties_ffi . properties_vulkan12 . map (| s | s . max_per_stage_descriptor_update_after_bind_uniform_buffers) , properties_ffi . properties_descriptor_indexing . map (| s | s . max_per_stage_descriptor_update_after_bind_uniform_buffers)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_per_stage_resources : [properties_ffi . properties_vulkan10 . properties . limits . max_per_stage_resources] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_per_stage_update_after_bind_resources : [properties_ffi . properties_vulkan12 . map (| s | s . max_per_stage_update_after_bind_resources) , properties_ffi . properties_descriptor_indexing . map (| s | s . max_per_stage_update_after_bind_resources)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_preferred_mesh_work_group_invocations : [properties_ffi . properties_mesh_shader_ext . map (| s | s . max_preferred_mesh_work_group_invocations)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_preferred_task_work_group_invocations : [properties_ffi . properties_mesh_shader_ext . map (| s | s . max_preferred_task_work_group_invocations)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_primitive_count : [properties_ffi . properties_acceleration_structure_khr . map (| s | s . max_primitive_count)] . into_iter () . flatten () . next () . and_then (< u64 > :: from_vulkan) , max_push_constants_size : [properties_ffi . properties_vulkan10 . properties . limits . max_push_constants_size] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_push_descriptors : [properties_ffi . properties_push_descriptor_khr . map (| s | s . max_push_descriptors)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_ray_dispatch_invocation_count : [properties_ffi . properties_ray_tracing_pipeline_khr . map (| s | s . max_ray_dispatch_invocation_count)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_ray_hit_attribute_size : [properties_ffi . properties_ray_tracing_pipeline_khr . map (| s | s . max_ray_hit_attribute_size)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_ray_recursion_depth : [properties_ffi . properties_ray_tracing_pipeline_khr . map (| s | s . max_ray_recursion_depth)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_recursion_depth : [properties_ffi . properties_ray_tracing_nv . map (| s | s . max_recursion_depth)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_resource_descriptor_buffer_bindings : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . max_resource_descriptor_buffer_bindings)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_resource_descriptor_buffer_range : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . max_resource_descriptor_buffer_range)] . into_iter () . flatten () . next () . and_then (< DeviceSize > :: from_vulkan) , max_sample_location_grid_size : [properties_ffi . properties_sample_locations_ext . map (| s | s . max_sample_location_grid_size)] . into_iter () . flatten () . next () . and_then (< [u32 ; 2] > :: from_vulkan) , max_sample_mask_words : [properties_ffi . properties_vulkan10 . properties . limits . max_sample_mask_words] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_sampler_allocation_count : [properties_ffi . properties_vulkan10 . properties . limits . max_sampler_allocation_count] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_sampler_anisotropy : [properties_ffi . properties_vulkan10 . properties . limits . max_sampler_anisotropy] . into_iter () . next () . and_then (< f32 > :: from_vulkan) . unwrap () , max_sampler_descriptor_buffer_bindings : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . max_sampler_descriptor_buffer_bindings)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_sampler_descriptor_buffer_range : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . max_sampler_descriptor_buffer_range)] . into_iter () . flatten () . next () . and_then (< DeviceSize > :: from_vulkan) , max_sampler_lod_bias : [properties_ffi . properties_vulkan10 . properties . limits . max_sampler_lod_bias] . into_iter () . next () . and_then (< f32 > :: from_vulkan) . unwrap () , max_sgpr_allocation : [properties_ffi . properties_shader_core_amd . map (| s | s . max_sgpr_allocation)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_shader_group_stride : [properties_ffi . properties_ray_tracing_pipeline_khr . map (| s | s . max_shader_group_stride) , properties_ffi . properties_ray_tracing_nv . map (| s | s . max_shader_group_stride)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_storage_buffer_range : [properties_ffi . properties_vulkan10 . properties . limits . max_storage_buffer_range] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_subgroup_size : [properties_ffi . properties_vulkan13 . map (| s | s . max_subgroup_size) , properties_ffi . properties_subgroup_size_control . map (| s | s . max_subgroup_size)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_subpass_shading_workgroup_size_aspect_ratio : [properties_ffi . properties_subpass_shading_huawei . map (| s | s . max_subpass_shading_workgroup_size_aspect_ratio)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_subsampled_array_layers : [properties_ffi . properties_fragment_density_map2_ext . map (| s | s . max_subsampled_array_layers)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_task_output_count : [properties_ffi . properties_mesh_shader_nv . map (| s | s . max_task_output_count)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_task_payload_and_shared_memory_size : [properties_ffi . properties_mesh_shader_ext . map (| s | s . max_task_payload_and_shared_memory_size)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_task_payload_size : [properties_ffi . properties_mesh_shader_ext . map (| s | s . max_task_payload_size)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_task_shared_memory_size : [properties_ffi . properties_mesh_shader_ext . map (| s | s . max_task_shared_memory_size)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_task_total_memory_size : [properties_ffi . properties_mesh_shader_nv . map (| s | s . max_task_total_memory_size)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_task_work_group_count : [properties_ffi . properties_mesh_shader_ext . map (| s | s . max_task_work_group_count)] . into_iter () . flatten () . next () . and_then (< [u32 ; 3] > :: from_vulkan) , max_task_work_group_invocations : [properties_ffi . properties_mesh_shader_ext . map (| s | s . max_task_work_group_invocations) , properties_ffi . properties_mesh_shader_nv . map (| s | s . max_task_work_group_invocations)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_task_work_group_size : [properties_ffi . properties_mesh_shader_ext . map (| s | s . max_task_work_group_size) , properties_ffi . properties_mesh_shader_nv . map (| s | s . max_task_work_group_size)] . into_iter () . flatten () . next () . and_then (< [u32 ; 3] > :: from_vulkan) , max_task_work_group_total_count : [properties_ffi . properties_mesh_shader_ext . map (| s | s . max_task_work_group_total_count)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_tessellation_control_per_patch_output_components : [properties_ffi . properties_vulkan10 . properties . limits . max_tessellation_control_per_patch_output_components] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_tessellation_control_per_vertex_input_components : [properties_ffi . properties_vulkan10 . properties . limits . max_tessellation_control_per_vertex_input_components] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_tessellation_control_per_vertex_output_components : [properties_ffi . properties_vulkan10 . properties . limits . max_tessellation_control_per_vertex_output_components] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_tessellation_control_total_output_components : [properties_ffi . properties_vulkan10 . properties . limits . max_tessellation_control_total_output_components] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_tessellation_evaluation_input_components : [properties_ffi . properties_vulkan10 . properties . limits . max_tessellation_evaluation_input_components] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_tessellation_evaluation_output_components : [properties_ffi . properties_vulkan10 . properties . limits . max_tessellation_evaluation_output_components] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_tessellation_generation_level : [properties_ffi . properties_vulkan10 . properties . limits . max_tessellation_generation_level] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_tessellation_patch_size : [properties_ffi . properties_vulkan10 . properties . limits . max_tessellation_patch_size] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_texel_buffer_elements : [properties_ffi . properties_vulkan10 . properties . limits . max_texel_buffer_elements] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_texel_gather_offset : [properties_ffi . properties_vulkan10 . properties . limits . max_texel_gather_offset] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_texel_offset : [properties_ffi . properties_vulkan10 . properties . limits . max_texel_offset] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_timeline_semaphore_value_difference : [properties_ffi . properties_vulkan12 . map (| s | s . max_timeline_semaphore_value_difference) , properties_ffi . properties_timeline_semaphore . map (| s | s . max_timeline_semaphore_value_difference)] . into_iter () . flatten () . next () . and_then (< u64 > :: from_vulkan) , max_transform_feedback_buffer_data_size : [properties_ffi . properties_transform_feedback_ext . map (| s | s . max_transform_feedback_buffer_data_size)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_transform_feedback_buffer_data_stride : [properties_ffi . properties_transform_feedback_ext . map (| s | s . max_transform_feedback_buffer_data_stride)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_transform_feedback_buffer_size : [properties_ffi . properties_transform_feedback_ext . map (| s | s . max_transform_feedback_buffer_size)] . into_iter () . flatten () . next () . and_then (< DeviceSize > :: from_vulkan) , max_transform_feedback_buffers : [properties_ffi . properties_transform_feedback_ext . map (| s | s . max_transform_feedback_buffers)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_transform_feedback_stream_data_size : [properties_ffi . properties_transform_feedback_ext . map (| s | s . max_transform_feedback_stream_data_size)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_transform_feedback_streams : [properties_ffi . properties_transform_feedback_ext . map (| s | s . max_transform_feedback_streams)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_triangle_count : [properties_ffi . properties_ray_tracing_nv . map (| s | s . max_triangle_count)] . into_iter () . flatten () . next () . and_then (< u64 > :: from_vulkan) , max_uniform_buffer_range : [properties_ffi . properties_vulkan10 . properties . limits . max_uniform_buffer_range] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_update_after_bind_descriptors_in_all_pools : [properties_ffi . properties_vulkan12 . map (| s | s . max_update_after_bind_descriptors_in_all_pools) , properties_ffi . properties_descriptor_indexing . map (| s | s . max_update_after_bind_descriptors_in_all_pools)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_vertex_attrib_divisor : [properties_ffi . properties_vertex_attribute_divisor_ext . map (| s | s . max_vertex_attrib_divisor)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_vertex_input_attribute_offset : [properties_ffi . properties_vulkan10 . properties . limits . max_vertex_input_attribute_offset] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_vertex_input_attributes : [properties_ffi . properties_vulkan10 . properties . limits . max_vertex_input_attributes] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_vertex_input_binding_stride : [properties_ffi . properties_vulkan10 . properties . limits . max_vertex_input_binding_stride] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_vertex_input_bindings : [properties_ffi . properties_vulkan10 . properties . limits . max_vertex_input_bindings] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_vertex_output_components : [properties_ffi . properties_vulkan10 . properties . limits . max_vertex_output_components] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_vgpr_allocation : [properties_ffi . properties_shader_core_amd . map (| s | s . max_vgpr_allocation)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_viewport_dimensions : [properties_ffi . properties_vulkan10 . properties . limits . max_viewport_dimensions] . into_iter () . next () . and_then (< [u32 ; 2] > :: from_vulkan) . unwrap () , max_viewports : [properties_ffi . properties_vulkan10 . properties . limits . max_viewports] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , max_weight_filter_dimension : [properties_ffi . properties_image_processing_qcom . map (| s | s . max_weight_filter_dimension)] . into_iter () . flatten () . next () . and_then (< [u32 ; 2] > :: from_vulkan) , max_weight_filter_phases : [properties_ffi . properties_image_processing_qcom . map (| s | s . max_weight_filter_phases)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , max_width : [properties_ffi . properties_optical_flow_nv . map (| s | s . max_width)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , mesh_output_per_primitive_granularity : [properties_ffi . properties_mesh_shader_ext . map (| s | s . mesh_output_per_primitive_granularity) , properties_ffi . properties_mesh_shader_nv . map (| s | s . mesh_output_per_primitive_granularity)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , mesh_output_per_vertex_granularity : [properties_ffi . properties_mesh_shader_ext . map (| s | s . mesh_output_per_vertex_granularity) , properties_ffi . properties_mesh_shader_nv . map (| s | s . mesh_output_per_vertex_granularity)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , min_acceleration_structure_scratch_offset_alignment : [properties_ffi . properties_acceleration_structure_khr . map (| s | s . min_acceleration_structure_scratch_offset_alignment)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , min_fragment_density_texel_size : [properties_ffi . properties_fragment_density_map_ext . map (| s | s . min_fragment_density_texel_size)] . into_iter () . flatten () . next () . and_then (< [u32 ; 2] > :: from_vulkan) , min_fragment_shading_rate_attachment_texel_size : [properties_ffi . properties_fragment_shading_rate_khr . map (| s | s . min_fragment_shading_rate_attachment_texel_size)] . into_iter () . flatten () . next () . and_then (< [u32 ; 2] > :: from_vulkan) , min_height : [properties_ffi . properties_optical_flow_nv . map (| s | s . min_height)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , min_imported_host_pointer_alignment : [properties_ffi . properties_external_memory_host_ext . map (| s | s . min_imported_host_pointer_alignment)] . into_iter () . flatten () . next () . and_then (< DeviceSize > :: from_vulkan) , min_indirect_commands_buffer_offset_alignment : [properties_ffi . properties_device_generated_commands_nv . map (| s | s . min_indirect_commands_buffer_offset_alignment)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , min_interpolation_offset : [properties_ffi . properties_vulkan10 . properties . limits . min_interpolation_offset] . into_iter () . next () . and_then (< f32 > :: from_vulkan) . unwrap () , min_memory_map_alignment : [properties_ffi . properties_vulkan10 . properties . limits . min_memory_map_alignment] . into_iter () . next () . and_then (< usize > :: from_vulkan) . unwrap () , min_sequences_count_buffer_offset_alignment : [properties_ffi . properties_device_generated_commands_nv . map (| s | s . min_sequences_count_buffer_offset_alignment)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , min_sequences_index_buffer_offset_alignment : [properties_ffi . properties_device_generated_commands_nv . map (| s | s . min_sequences_index_buffer_offset_alignment)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , min_sgpr_allocation : [properties_ffi . properties_shader_core_amd . map (| s | s . min_sgpr_allocation)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , min_storage_buffer_offset_alignment : [properties_ffi . properties_vulkan10 . properties . limits . min_storage_buffer_offset_alignment] . into_iter () . next () . and_then (< DeviceAlignment > :: from_vulkan) . unwrap () , min_subgroup_size : [properties_ffi . properties_vulkan13 . map (| s | s . min_subgroup_size) , properties_ffi . properties_subgroup_size_control . map (| s | s . min_subgroup_size)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , min_texel_buffer_offset_alignment : [properties_ffi . properties_vulkan10 . properties . limits . min_texel_buffer_offset_alignment] . into_iter () . next () . and_then (< DeviceAlignment > :: from_vulkan) . unwrap () , min_texel_gather_offset : [properties_ffi . properties_vulkan10 . properties . limits . min_texel_gather_offset] . into_iter () . next () . and_then (< i32 > :: from_vulkan) . unwrap () , min_texel_offset : [properties_ffi . properties_vulkan10 . properties . limits . min_texel_offset] . into_iter () . next () . and_then (< i32 > :: from_vulkan) . unwrap () , min_uniform_buffer_offset_alignment : [properties_ffi . properties_vulkan10 . properties . limits . min_uniform_buffer_offset_alignment] . into_iter () . next () . and_then (< DeviceAlignment > :: from_vulkan) . unwrap () , min_vertex_input_binding_stride_alignment : [properties_ffi . properties_portability_subset_khr . map (| s | s . min_vertex_input_binding_stride_alignment)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , min_vgpr_allocation : [properties_ffi . properties_shader_core_amd . map (| s | s . min_vgpr_allocation)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , min_width : [properties_ffi . properties_optical_flow_nv . map (| s | s . min_width)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , mipmap_precision_bits : [properties_ffi . properties_vulkan10 . properties . limits . mipmap_precision_bits] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , non_coherent_atom_size : [properties_ffi . properties_vulkan10 . properties . limits . non_coherent_atom_size] . into_iter () . next () . and_then (< DeviceAlignment > :: from_vulkan) . unwrap () , optimal_buffer_copy_offset_alignment : [properties_ffi . properties_vulkan10 . properties . limits . optimal_buffer_copy_offset_alignment] . into_iter () . next () . and_then (< DeviceAlignment > :: from_vulkan) . unwrap () , optimal_buffer_copy_row_pitch_alignment : [properties_ffi . properties_vulkan10 . properties . limits . optimal_buffer_copy_row_pitch_alignment] . into_iter () . next () . and_then (< DeviceAlignment > :: from_vulkan) . unwrap () , pci_bus : [properties_ffi . properties_pci_bus_info_ext . map (| s | s . pci_bus)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , pci_device : [properties_ffi . properties_pci_bus_info_ext . map (| s | s . pci_device)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , pci_domain : [properties_ffi . properties_pci_bus_info_ext . map (| s | s . pci_domain)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , pci_function : [properties_ffi . properties_pci_bus_info_ext . map (| s | s . pci_function)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , per_view_position_all_components : [properties_ffi . properties_multiview_per_view_attributes_nvx . map (| s | s . per_view_position_all_components)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , pipeline_cache_uuid : [properties_ffi . properties_vulkan10 . properties . pipeline_cache_uuid] . into_iter () . next () . and_then (< [u8 ; 16] > :: from_vulkan) . unwrap () , point_clipping_behavior : [properties_ffi . properties_vulkan11 . map (| s | s . point_clipping_behavior) , properties_ffi . properties_point_clipping . map (| s | s . point_clipping_behavior)] . into_iter () . flatten () . next () . and_then (< PointClippingBehavior > :: from_vulkan) , point_size_granularity : [properties_ffi . properties_vulkan10 . properties . limits . point_size_granularity] . into_iter () . next () . and_then (< f32 > :: from_vulkan) . unwrap () , point_size_range : [properties_ffi . properties_vulkan10 . properties . limits . point_size_range] . into_iter () . next () . and_then (< [f32 ; 2] > :: from_vulkan) . unwrap () , prefers_compact_primitive_output : [properties_ffi . properties_mesh_shader_ext . map (| s | s . prefers_compact_primitive_output)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , prefers_compact_vertex_output : [properties_ffi . properties_mesh_shader_ext . map (| s | s . prefers_compact_vertex_output)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , prefers_local_invocation_primitive_output : [properties_ffi . properties_mesh_shader_ext . map (| s | s . prefers_local_invocation_primitive_output)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , prefers_local_invocation_vertex_output : [properties_ffi . properties_mesh_shader_ext . map (| s | s . prefers_local_invocation_vertex_output)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , primary_major : [properties_ffi . properties_drm_ext . map (| s | s . primary_major)] . into_iter () . flatten () . next () . and_then (< i64 > :: from_vulkan) , primary_minor : [properties_ffi . properties_drm_ext . map (| s | s . primary_minor)] . into_iter () . flatten () . next () . and_then (< i64 > :: from_vulkan) , primitive_fragment_shading_rate_with_multiple_viewports : [properties_ffi . properties_fragment_shading_rate_khr . map (| s | s . primitive_fragment_shading_rate_with_multiple_viewports)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , primitive_overestimation_size : [properties_ffi . properties_conservative_rasterization_ext . map (| s | s . primitive_overestimation_size)] . into_iter () . flatten () . next () . and_then (< f32 > :: from_vulkan) , primitive_underestimation : [properties_ffi . properties_conservative_rasterization_ext . map (| s | s . primitive_underestimation)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , protected_no_fault : [properties_ffi . properties_vulkan11 . map (| s | s . protected_no_fault) , properties_ffi . properties_protected_memory . map (| s | s . protected_no_fault)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , provoking_vertex_mode_per_pipeline : [properties_ffi . properties_provoking_vertex_ext . map (| s | s . provoking_vertex_mode_per_pipeline)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , quad_divergent_implicit_lod : [properties_ffi . properties_vulkan12 . map (| s | s . quad_divergent_implicit_lod) , properties_ffi . properties_descriptor_indexing . map (| s | s . quad_divergent_implicit_lod)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , quad_operations_in_all_stages : [properties_ffi . properties_subgroup . map (| s | s . quad_operations_in_all_stages)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , ray_tracing_invocation_reorder_reordering_hint : [properties_ffi . properties_ray_tracing_invocation_reorder_nv . map (| s | s . ray_tracing_invocation_reorder_reordering_hint)] . into_iter () . flatten () . next () . and_then (< RayTracingInvocationReorderMode > :: from_vulkan) , render_major : [properties_ffi . properties_drm_ext . map (| s | s . render_major)] . into_iter () . flatten () . next () . and_then (< i64 > :: from_vulkan) , render_minor : [properties_ffi . properties_drm_ext . map (| s | s . render_minor)] . into_iter () . flatten () . next () . and_then (< i64 > :: from_vulkan) , required_subgroup_size_stages : [properties_ffi . properties_vulkan13 . map (| s | s . required_subgroup_size_stages) , properties_ffi . properties_subgroup_size_control . map (| s | s . required_subgroup_size_stages)] . into_iter () . flatten () . next () . and_then (< ShaderStages > :: from_vulkan) , residency_aligned_mip_size : [properties_ffi . properties_vulkan10 . properties . sparse_properties . residency_aligned_mip_size] . into_iter () . next () . and_then (< bool > :: from_vulkan) . unwrap () , residency_non_resident_strict : [properties_ffi . properties_vulkan10 . properties . sparse_properties . residency_non_resident_strict] . into_iter () . next () . and_then (< bool > :: from_vulkan) . unwrap () , residency_standard2_d_block_shape : [properties_ffi . properties_vulkan10 . properties . sparse_properties . residency_standard2_d_block_shape] . into_iter () . next () . and_then (< bool > :: from_vulkan) . unwrap () , residency_standard2_d_multisample_block_shape : [properties_ffi . properties_vulkan10 . properties . sparse_properties . residency_standard2_d_multisample_block_shape] . into_iter () . next () . and_then (< bool > :: from_vulkan) . unwrap () , residency_standard3_d_block_shape : [properties_ffi . properties_vulkan10 . properties . sparse_properties . residency_standard3_d_block_shape] . into_iter () . next () . and_then (< bool > :: from_vulkan) . unwrap () , resource_descriptor_buffer_address_space_size : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . resource_descriptor_buffer_address_space_size)] . into_iter () . flatten () . next () . and_then (< DeviceSize > :: from_vulkan) , robust_buffer_access_update_after_bind : [properties_ffi . properties_vulkan12 . map (| s | s . robust_buffer_access_update_after_bind) , properties_ffi . properties_descriptor_indexing . map (| s | s . robust_buffer_access_update_after_bind)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , robust_storage_buffer_access_size_alignment : [properties_ffi . properties_robustness2_ext . map (| s | s . robust_storage_buffer_access_size_alignment)] . into_iter () . flatten () . next () . and_then (< DeviceAlignment > :: from_vulkan) , robust_storage_buffer_descriptor_size : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . robust_storage_buffer_descriptor_size)] . into_iter () . flatten () . next () . and_then (< usize > :: from_vulkan) , robust_storage_texel_buffer_descriptor_size : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . robust_storage_texel_buffer_descriptor_size)] . into_iter () . flatten () . next () . and_then (< usize > :: from_vulkan) , robust_uniform_buffer_access_size_alignment : [properties_ffi . properties_robustness2_ext . map (| s | s . robust_uniform_buffer_access_size_alignment)] . into_iter () . flatten () . next () . and_then (< DeviceAlignment > :: from_vulkan) , robust_uniform_buffer_descriptor_size : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . robust_uniform_buffer_descriptor_size)] . into_iter () . flatten () . next () . and_then (< usize > :: from_vulkan) , robust_uniform_texel_buffer_descriptor_size : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . robust_uniform_texel_buffer_descriptor_size)] . into_iter () . flatten () . next () . and_then (< usize > :: from_vulkan) , rounding_mode_independence : [properties_ffi . properties_vulkan12 . map (| s | s . rounding_mode_independence) , properties_ffi . properties_float_controls . map (| s | s . rounding_mode_independence)] . into_iter () . flatten () . next () . and_then (< ShaderFloatControlsIndependence > :: from_vulkan) , sample_location_coordinate_range : [properties_ffi . properties_sample_locations_ext . map (| s | s . sample_location_coordinate_range)] . into_iter () . flatten () . next () . and_then (< [f32 ; 2] > :: from_vulkan) , sample_location_sample_counts : [properties_ffi . properties_sample_locations_ext . map (| s | s . sample_location_sample_counts)] . into_iter () . flatten () . next () . and_then (< SampleCounts > :: from_vulkan) , sample_location_sub_pixel_bits : [properties_ffi . properties_sample_locations_ext . map (| s | s . sample_location_sub_pixel_bits)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , sampled_image_color_sample_counts : [properties_ffi . properties_vulkan10 . properties . limits . sampled_image_color_sample_counts] . into_iter () . next () . and_then (< SampleCounts > :: from_vulkan) . unwrap () , sampled_image_depth_sample_counts : [properties_ffi . properties_vulkan10 . properties . limits . sampled_image_depth_sample_counts] . into_iter () . next () . and_then (< SampleCounts > :: from_vulkan) . unwrap () , sampled_image_descriptor_size : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . sampled_image_descriptor_size)] . into_iter () . flatten () . next () . and_then (< usize > :: from_vulkan) , sampled_image_integer_sample_counts : [properties_ffi . properties_vulkan10 . properties . limits . sampled_image_integer_sample_counts] . into_iter () . next () . and_then (< SampleCounts > :: from_vulkan) . unwrap () , sampled_image_stencil_sample_counts : [properties_ffi . properties_vulkan10 . properties . limits . sampled_image_stencil_sample_counts] . into_iter () . next () . and_then (< SampleCounts > :: from_vulkan) . unwrap () , sampler_capture_replay_descriptor_data_size : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . sampler_capture_replay_descriptor_data_size)] . into_iter () . flatten () . next () . and_then (< usize > :: from_vulkan) , sampler_descriptor_buffer_address_space_size : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . sampler_descriptor_buffer_address_space_size)] . into_iter () . flatten () . next () . and_then (< DeviceSize > :: from_vulkan) , sampler_descriptor_size : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . sampler_descriptor_size)] . into_iter () . flatten () . next () . and_then (< usize > :: from_vulkan) , sgpr_allocation_granularity : [properties_ffi . properties_shader_core_amd . map (| s | s . sgpr_allocation_granularity)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , sgprs_per_simd : [properties_ffi . properties_shader_core_amd . map (| s | s . sgprs_per_simd)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , shader_arrays_per_engine_count : [properties_ffi . properties_shader_core_amd . map (| s | s . shader_arrays_per_engine_count)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , shader_core_count : [properties_ffi . properties_shader_core_builtins_arm . map (| s | s . shader_core_count)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , shader_core_features : [properties_ffi . properties_shader_core2_amd . map (| s | s . shader_core_features)] . into_iter () . flatten () . next () . and_then (< ShaderCoreProperties > :: from_vulkan) , shader_core_mask : [properties_ffi . properties_shader_core_builtins_arm . map (| s | s . shader_core_mask)] . into_iter () . flatten () . next () . and_then (< u64 > :: from_vulkan) , shader_denorm_flush_to_zero_float16 : [properties_ffi . properties_vulkan12 . map (| s | s . shader_denorm_flush_to_zero_float16) , properties_ffi . properties_float_controls . map (| s | s . shader_denorm_flush_to_zero_float16)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , shader_denorm_flush_to_zero_float32 : [properties_ffi . properties_vulkan12 . map (| s | s . shader_denorm_flush_to_zero_float32) , properties_ffi . properties_float_controls . map (| s | s . shader_denorm_flush_to_zero_float32)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , shader_denorm_flush_to_zero_float64 : [properties_ffi . properties_vulkan12 . map (| s | s . shader_denorm_flush_to_zero_float64) , properties_ffi . properties_float_controls . map (| s | s . shader_denorm_flush_to_zero_float64)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , shader_denorm_preserve_float16 : [properties_ffi . properties_vulkan12 . map (| s | s . shader_denorm_preserve_float16) , properties_ffi . properties_float_controls . map (| s | s . shader_denorm_preserve_float16)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , shader_denorm_preserve_float32 : [properties_ffi . properties_vulkan12 . map (| s | s . shader_denorm_preserve_float32) , properties_ffi . properties_float_controls . map (| s | s . shader_denorm_preserve_float32)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , shader_denorm_preserve_float64 : [properties_ffi . properties_vulkan12 . map (| s | s . shader_denorm_preserve_float64) , properties_ffi . properties_float_controls . map (| s | s . shader_denorm_preserve_float64)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , shader_engine_count : [properties_ffi . properties_shader_core_amd . map (| s | s . shader_engine_count)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , shader_group_base_alignment : [properties_ffi . properties_ray_tracing_pipeline_khr . map (| s | s . shader_group_base_alignment) , properties_ffi . properties_ray_tracing_nv . map (| s | s . shader_group_base_alignment)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , shader_group_handle_alignment : [properties_ffi . properties_ray_tracing_pipeline_khr . map (| s | s . shader_group_handle_alignment)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , shader_group_handle_capture_replay_size : [properties_ffi . properties_ray_tracing_pipeline_khr . map (| s | s . shader_group_handle_capture_replay_size)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , shader_group_handle_size : [properties_ffi . properties_ray_tracing_pipeline_khr . map (| s | s . shader_group_handle_size) , properties_ffi . properties_ray_tracing_nv . map (| s | s . shader_group_handle_size)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , shader_input_attachment_array_non_uniform_indexing_native : [properties_ffi . properties_vulkan12 . map (| s | s . shader_input_attachment_array_non_uniform_indexing_native) , properties_ffi . properties_descriptor_indexing . map (| s | s . shader_input_attachment_array_non_uniform_indexing_native)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , shader_module_identifier_algorithm_uuid : [properties_ffi . properties_shader_module_identifier_ext . map (| s | s . shader_module_identifier_algorithm_uuid)] . into_iter () . flatten () . next () . and_then (< [u8 ; 16] > :: from_vulkan) , shader_rounding_mode_rte_float16 : [properties_ffi . properties_vulkan12 . map (| s | s . shader_rounding_mode_rte_float16) , properties_ffi . properties_float_controls . map (| s | s . shader_rounding_mode_rte_float16)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , shader_rounding_mode_rte_float32 : [properties_ffi . properties_vulkan12 . map (| s | s . shader_rounding_mode_rte_float32) , properties_ffi . properties_float_controls . map (| s | s . shader_rounding_mode_rte_float32)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , shader_rounding_mode_rte_float64 : [properties_ffi . properties_vulkan12 . map (| s | s . shader_rounding_mode_rte_float64) , properties_ffi . properties_float_controls . map (| s | s . shader_rounding_mode_rte_float64)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , shader_rounding_mode_rtz_float16 : [properties_ffi . properties_vulkan12 . map (| s | s . shader_rounding_mode_rtz_float16) , properties_ffi . properties_float_controls . map (| s | s . shader_rounding_mode_rtz_float16)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , shader_rounding_mode_rtz_float32 : [properties_ffi . properties_vulkan12 . map (| s | s . shader_rounding_mode_rtz_float32) , properties_ffi . properties_float_controls . map (| s | s . shader_rounding_mode_rtz_float32)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , shader_rounding_mode_rtz_float64 : [properties_ffi . properties_vulkan12 . map (| s | s . shader_rounding_mode_rtz_float64) , properties_ffi . properties_float_controls . map (| s | s . shader_rounding_mode_rtz_float64)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , shader_sampled_image_array_non_uniform_indexing_native : [properties_ffi . properties_vulkan12 . map (| s | s . shader_sampled_image_array_non_uniform_indexing_native) , properties_ffi . properties_descriptor_indexing . map (| s | s . shader_sampled_image_array_non_uniform_indexing_native)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , shader_signed_zero_inf_nan_preserve_float16 : [properties_ffi . properties_vulkan12 . map (| s | s . shader_signed_zero_inf_nan_preserve_float16) , properties_ffi . properties_float_controls . map (| s | s . shader_signed_zero_inf_nan_preserve_float16)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , shader_signed_zero_inf_nan_preserve_float32 : [properties_ffi . properties_vulkan12 . map (| s | s . shader_signed_zero_inf_nan_preserve_float32) , properties_ffi . properties_float_controls . map (| s | s . shader_signed_zero_inf_nan_preserve_float32)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , shader_signed_zero_inf_nan_preserve_float64 : [properties_ffi . properties_vulkan12 . map (| s | s . shader_signed_zero_inf_nan_preserve_float64) , properties_ffi . properties_float_controls . map (| s | s . shader_signed_zero_inf_nan_preserve_float64)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , shader_sm_count : [properties_ffi . properties_shader_sm_builtins_nv . map (| s | s . shader_sm_count)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , shader_storage_buffer_array_non_uniform_indexing_native : [properties_ffi . properties_vulkan12 . map (| s | s . shader_storage_buffer_array_non_uniform_indexing_native) , properties_ffi . properties_descriptor_indexing . map (| s | s . shader_storage_buffer_array_non_uniform_indexing_native)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , shader_storage_image_array_non_uniform_indexing_native : [properties_ffi . properties_vulkan12 . map (| s | s . shader_storage_image_array_non_uniform_indexing_native) , properties_ffi . properties_descriptor_indexing . map (| s | s . shader_storage_image_array_non_uniform_indexing_native)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , shader_uniform_buffer_array_non_uniform_indexing_native : [properties_ffi . properties_vulkan12 . map (| s | s . shader_uniform_buffer_array_non_uniform_indexing_native) , properties_ffi . properties_descriptor_indexing . map (| s | s . shader_uniform_buffer_array_non_uniform_indexing_native)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , shader_warps_per_core : [properties_ffi . properties_shader_core_builtins_arm . map (| s | s . shader_warps_per_core)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , shader_warps_per_sm : [properties_ffi . properties_shader_sm_builtins_nv . map (| s | s . shader_warps_per_sm)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , shading_rate_max_coarse_samples : [properties_ffi . properties_shading_rate_image_nv . map (| s | s . shading_rate_max_coarse_samples)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , shading_rate_palette_size : [properties_ffi . properties_shading_rate_image_nv . map (| s | s . shading_rate_palette_size)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , shading_rate_texel_size : [properties_ffi . properties_shading_rate_image_nv . map (| s | s . shading_rate_texel_size)] . into_iter () . flatten () . next () . and_then (< [u32 ; 2] > :: from_vulkan) , simd_per_compute_unit : [properties_ffi . properties_shader_core_amd . map (| s | s . simd_per_compute_unit)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , sparse_address_space_size : [properties_ffi . properties_vulkan10 . properties . limits . sparse_address_space_size] . into_iter () . next () . and_then (< DeviceSize > :: from_vulkan) . unwrap () , standard_sample_locations : [properties_ffi . properties_vulkan10 . properties . limits . standard_sample_locations] . into_iter () . next () . and_then (< bool > :: from_vulkan) . unwrap () , storage_buffer_descriptor_size : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . storage_buffer_descriptor_size)] . into_iter () . flatten () . next () . and_then (< usize > :: from_vulkan) , storage_image_descriptor_size : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . storage_image_descriptor_size)] . into_iter () . flatten () . next () . and_then (< usize > :: from_vulkan) , storage_image_sample_counts : [properties_ffi . properties_vulkan10 . properties . limits . storage_image_sample_counts] . into_iter () . next () . and_then (< SampleCounts > :: from_vulkan) . unwrap () , storage_texel_buffer_descriptor_size : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . storage_texel_buffer_descriptor_size)] . into_iter () . flatten () . next () . and_then (< usize > :: from_vulkan) , storage_texel_buffer_offset_alignment_bytes : [properties_ffi . properties_vulkan13 . map (| s | s . storage_texel_buffer_offset_alignment_bytes) , properties_ffi . properties_texel_buffer_alignment . map (| s | s . storage_texel_buffer_offset_alignment_bytes)] . into_iter () . flatten () . next () . and_then (< DeviceAlignment > :: from_vulkan) , storage_texel_buffer_offset_single_texel_alignment : [properties_ffi . properties_vulkan13 . map (| s | s . storage_texel_buffer_offset_single_texel_alignment) , properties_ffi . properties_texel_buffer_alignment . map (| s | s . storage_texel_buffer_offset_single_texel_alignment)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , strict_lines : [properties_ffi . properties_vulkan10 . properties . limits . strict_lines] . into_iter () . next () . and_then (< bool > :: from_vulkan) . unwrap () , sub_pixel_interpolation_offset_bits : [properties_ffi . properties_vulkan10 . properties . limits . sub_pixel_interpolation_offset_bits] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , sub_pixel_precision_bits : [properties_ffi . properties_vulkan10 . properties . limits . sub_pixel_precision_bits] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , sub_texel_precision_bits : [properties_ffi . properties_vulkan10 . properties . limits . sub_texel_precision_bits] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , subgroup_quad_operations_in_all_stages : [properties_ffi . properties_vulkan11 . map (| s | s . subgroup_quad_operations_in_all_stages)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , subgroup_size : [properties_ffi . properties_vulkan11 . map (| s | s . subgroup_size) , properties_ffi . properties_subgroup . map (| s | s . subgroup_size)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , subgroup_supported_operations : [properties_ffi . properties_vulkan11 . map (| s | s . subgroup_supported_operations)] . into_iter () . flatten () . next () . and_then (< SubgroupFeatures > :: from_vulkan) , subgroup_supported_stages : [properties_ffi . properties_vulkan11 . map (| s | s . subgroup_supported_stages)] . into_iter () . flatten () . next () . and_then (< ShaderStages > :: from_vulkan) , subsampled_coarse_reconstruction_early_access : [properties_ffi . properties_fragment_density_map2_ext . map (| s | s . subsampled_coarse_reconstruction_early_access)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , subsampled_loads : [properties_ffi . properties_fragment_density_map2_ext . map (| s | s . subsampled_loads)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , supported_depth_resolve_modes : [properties_ffi . properties_vulkan12 . map (| s | s . supported_depth_resolve_modes) , properties_ffi . properties_depth_stencil_resolve . map (| s | s . supported_depth_resolve_modes)] . into_iter () . flatten () . next () . and_then (< ResolveModes > :: from_vulkan) , supported_hint_grid_sizes : [properties_ffi . properties_optical_flow_nv . map (| s | s . supported_hint_grid_sizes)] . into_iter () . flatten () . next () . and_then (< OpticalFlowGridSizes > :: from_vulkan) , supported_operations : [properties_ffi . properties_subgroup . map (| s | s . supported_operations)] . into_iter () . flatten () . next () . and_then (< SubgroupFeatures > :: from_vulkan) , supported_output_grid_sizes : [properties_ffi . properties_optical_flow_nv . map (| s | s . supported_output_grid_sizes)] . into_iter () . flatten () . next () . and_then (< OpticalFlowGridSizes > :: from_vulkan) , supported_queues : [properties_ffi . properties_copy_memory_indirect_nv . map (| s | s . supported_queues)] . into_iter () . flatten () . next () . and_then (< QueueFlags > :: from_vulkan) , supported_stages : [properties_ffi . properties_subgroup . map (| s | s . supported_stages)] . into_iter () . flatten () . next () . and_then (< ShaderStages > :: from_vulkan) , supported_stencil_resolve_modes : [properties_ffi . properties_vulkan12 . map (| s | s . supported_stencil_resolve_modes) , properties_ffi . properties_depth_stencil_resolve . map (| s | s . supported_stencil_resolve_modes)] . into_iter () . flatten () . next () . and_then (< ResolveModes > :: from_vulkan) , timestamp_compute_and_graphics : [properties_ffi . properties_vulkan10 . properties . limits . timestamp_compute_and_graphics] . into_iter () . next () . and_then (< bool > :: from_vulkan) . unwrap () , timestamp_period : [properties_ffi . properties_vulkan10 . properties . limits . timestamp_period] . into_iter () . next () . and_then (< f32 > :: from_vulkan) . unwrap () , transform_feedback_draw : [properties_ffi . properties_transform_feedback_ext . map (| s | s . transform_feedback_draw)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , transform_feedback_preserves_triangle_fan_provoking_vertex : [properties_ffi . properties_provoking_vertex_ext . map (| s | s . transform_feedback_preserves_triangle_fan_provoking_vertex)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , transform_feedback_queries : [properties_ffi . properties_transform_feedback_ext . map (| s | s . transform_feedback_queries)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , transform_feedback_rasterization_stream_select : [properties_ffi . properties_transform_feedback_ext . map (| s | s . transform_feedback_rasterization_stream_select)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , transform_feedback_streams_lines_triangles : [properties_ffi . properties_transform_feedback_ext . map (| s | s . transform_feedback_streams_lines_triangles)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , tri_strip_vertex_order_independent_of_provoking_vertex : [properties_ffi . properties_fragment_shader_barycentric_khr . map (| s | s . tri_strip_vertex_order_independent_of_provoking_vertex)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , uniform_buffer_descriptor_size : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . uniform_buffer_descriptor_size)] . into_iter () . flatten () . next () . and_then (< usize > :: from_vulkan) , uniform_texel_buffer_descriptor_size : [properties_ffi . properties_descriptor_buffer_ext . map (| s | s . uniform_texel_buffer_descriptor_size)] . into_iter () . flatten () . next () . and_then (< usize > :: from_vulkan) , uniform_texel_buffer_offset_alignment_bytes : [properties_ffi . properties_vulkan13 . map (| s | s . uniform_texel_buffer_offset_alignment_bytes) , properties_ffi . properties_texel_buffer_alignment . map (| s | s . uniform_texel_buffer_offset_alignment_bytes)] . into_iter () . flatten () . next () . and_then (< DeviceAlignment > :: from_vulkan) , uniform_texel_buffer_offset_single_texel_alignment : [properties_ffi . properties_vulkan13 . map (| s | s . uniform_texel_buffer_offset_single_texel_alignment) , properties_ffi . properties_texel_buffer_alignment . map (| s | s . uniform_texel_buffer_offset_single_texel_alignment)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , variable_sample_locations : [properties_ffi . properties_sample_locations_ext . map (| s | s . variable_sample_locations)] . into_iter () . flatten () . next () . and_then (< bool > :: from_vulkan) , vendor_id : [properties_ffi . properties_vulkan10 . properties . vendor_id] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , vgpr_allocation_granularity : [properties_ffi . properties_shader_core_amd . map (| s | s . vgpr_allocation_granularity)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , vgprs_per_simd : [properties_ffi . properties_shader_core_amd . map (| s | s . vgprs_per_simd)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , viewport_bounds_range : [properties_ffi . properties_vulkan10 . properties . limits . viewport_bounds_range] . into_iter () . next () . and_then (< [f32 ; 2] > :: from_vulkan) . unwrap () , viewport_sub_pixel_bits : [properties_ffi . properties_vulkan10 . properties . limits . viewport_sub_pixel_bits] . into_iter () . next () . and_then (< u32 > :: from_vulkan) . unwrap () , wavefront_size : [properties_ffi . properties_shader_core_amd . map (| s | s . wavefront_size)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , wavefronts_per_simd : [properties_ffi . properties_shader_core_amd . map (| s | s . wavefronts_per_simd)] . into_iter () . flatten () . next () . and_then (< u32 > :: from_vulkan) , _ne : crate :: NonExhaustive (()) , }
+ }
+}
+#[derive(Default)]
+pub(crate) struct PropertiesFfi {
+ properties_vulkan10: ash::vk::PhysicalDeviceProperties2KHR,
+ properties_vulkan11: Option<ash::vk::PhysicalDeviceVulkan11Properties>,
+ properties_vulkan12: Option<ash::vk::PhysicalDeviceVulkan12Properties>,
+ properties_vulkan13: Option<ash::vk::PhysicalDeviceVulkan13Properties>,
+ properties_id: Option<ash::vk::PhysicalDeviceIDProperties>,
+ properties_maintenance3: Option<ash::vk::PhysicalDeviceMaintenance3Properties>,
+ properties_multiview: Option<ash::vk::PhysicalDeviceMultiviewProperties>,
+ properties_point_clipping: Option<ash::vk::PhysicalDevicePointClippingProperties>,
+ properties_protected_memory: Option<ash::vk::PhysicalDeviceProtectedMemoryProperties>,
+ properties_subgroup: Option<ash::vk::PhysicalDeviceSubgroupProperties>,
+ properties_depth_stencil_resolve: Option<ash::vk::PhysicalDeviceDepthStencilResolveProperties>,
+ properties_descriptor_indexing: Option<ash::vk::PhysicalDeviceDescriptorIndexingProperties>,
+ properties_driver: Option<ash::vk::PhysicalDeviceDriverProperties>,
+ properties_float_controls: Option<ash::vk::PhysicalDeviceFloatControlsProperties>,
+ properties_sampler_filter_minmax: Option<ash::vk::PhysicalDeviceSamplerFilterMinmaxProperties>,
+ properties_timeline_semaphore: Option<ash::vk::PhysicalDeviceTimelineSemaphoreProperties>,
+ properties_inline_uniform_block: Option<ash::vk::PhysicalDeviceInlineUniformBlockProperties>,
+ properties_maintenance4: Option<ash::vk::PhysicalDeviceMaintenance4Properties>,
+ properties_shader_integer_dot_product:
+ Option<ash::vk::PhysicalDeviceShaderIntegerDotProductProperties>,
+ properties_subgroup_size_control: Option<ash::vk::PhysicalDeviceSubgroupSizeControlProperties>,
+ properties_texel_buffer_alignment:
+ Option<ash::vk::PhysicalDeviceTexelBufferAlignmentProperties>,
+ properties_acceleration_structure_khr:
+ Option<ash::vk::PhysicalDeviceAccelerationStructurePropertiesKHR>,
+ properties_fragment_shader_barycentric_khr:
+ Option<ash::vk::PhysicalDeviceFragmentShaderBarycentricPropertiesKHR>,
+ properties_fragment_shading_rate_khr:
+ Option<ash::vk::PhysicalDeviceFragmentShadingRatePropertiesKHR>,
+ properties_performance_query_khr: Option<ash::vk::PhysicalDevicePerformanceQueryPropertiesKHR>,
+ properties_portability_subset_khr:
+ Option<ash::vk::PhysicalDevicePortabilitySubsetPropertiesKHR>,
+ properties_push_descriptor_khr: Option<ash::vk::PhysicalDevicePushDescriptorPropertiesKHR>,
+ properties_ray_tracing_pipeline_khr:
+ Option<ash::vk::PhysicalDeviceRayTracingPipelinePropertiesKHR>,
+ properties_blend_operation_advanced_ext:
+ Option<ash::vk::PhysicalDeviceBlendOperationAdvancedPropertiesEXT>,
+ properties_conservative_rasterization_ext:
+ Option<ash::vk::PhysicalDeviceConservativeRasterizationPropertiesEXT>,
+ properties_custom_border_color_ext:
+ Option<ash::vk::PhysicalDeviceCustomBorderColorPropertiesEXT>,
+ properties_descriptor_buffer_density_map_ext:
+ Option<ash::vk::PhysicalDeviceDescriptorBufferDensityMapPropertiesEXT>,
+ properties_descriptor_buffer_ext: Option<ash::vk::PhysicalDeviceDescriptorBufferPropertiesEXT>,
+ properties_discard_rectangle_ext: Option<ash::vk::PhysicalDeviceDiscardRectanglePropertiesEXT>,
+ properties_drm_ext: Option<ash::vk::PhysicalDeviceDrmPropertiesEXT>,
+ properties_extended_dynamic_state3_ext:
+ Option<ash::vk::PhysicalDeviceExtendedDynamicState3PropertiesEXT>,
+ properties_external_memory_host_ext:
+ Option<ash::vk::PhysicalDeviceExternalMemoryHostPropertiesEXT>,
+ properties_fragment_density_map2_ext:
+ Option<ash::vk::PhysicalDeviceFragmentDensityMap2PropertiesEXT>,
+ properties_fragment_density_map_ext:
+ Option<ash::vk::PhysicalDeviceFragmentDensityMapPropertiesEXT>,
+ properties_graphics_pipeline_library_ext:
+ Option<ash::vk::PhysicalDeviceGraphicsPipelineLibraryPropertiesEXT>,
+ properties_line_rasterization_ext:
+ Option<ash::vk::PhysicalDeviceLineRasterizationPropertiesEXT>,
+ properties_mesh_shader_ext: Option<ash::vk::PhysicalDeviceMeshShaderPropertiesEXT>,
+ properties_multi_draw_ext: Option<ash::vk::PhysicalDeviceMultiDrawPropertiesEXT>,
+ properties_opacity_micromap_ext: Option<ash::vk::PhysicalDeviceOpacityMicromapPropertiesEXT>,
+ properties_pci_bus_info_ext: Option<ash::vk::PhysicalDevicePCIBusInfoPropertiesEXT>,
+ properties_pipeline_robustness_ext:
+ Option<ash::vk::PhysicalDevicePipelineRobustnessPropertiesEXT>,
+ properties_provoking_vertex_ext: Option<ash::vk::PhysicalDeviceProvokingVertexPropertiesEXT>,
+ properties_robustness2_ext: Option<ash::vk::PhysicalDeviceRobustness2PropertiesEXT>,
+ properties_sample_locations_ext: Option<ash::vk::PhysicalDeviceSampleLocationsPropertiesEXT>,
+ properties_shader_module_identifier_ext:
+ Option<ash::vk::PhysicalDeviceShaderModuleIdentifierPropertiesEXT>,
+ properties_transform_feedback_ext:
+ Option<ash::vk::PhysicalDeviceTransformFeedbackPropertiesEXT>,
+ properties_vertex_attribute_divisor_ext:
+ Option<ash::vk::PhysicalDeviceVertexAttributeDivisorPropertiesEXT>,
+ properties_cooperative_matrix_nv: Option<ash::vk::PhysicalDeviceCooperativeMatrixPropertiesNV>,
+ properties_copy_memory_indirect_nv:
+ Option<ash::vk::PhysicalDeviceCopyMemoryIndirectPropertiesNV>,
+ properties_device_generated_commands_nv:
+ Option<ash::vk::PhysicalDeviceDeviceGeneratedCommandsPropertiesNV>,
+ properties_fragment_density_map_offset_qcom:
+ Option<ash::vk::PhysicalDeviceFragmentDensityMapOffsetPropertiesQCOM>,
+ properties_fragment_shading_rate_enums_nv:
+ Option<ash::vk::PhysicalDeviceFragmentShadingRateEnumsPropertiesNV>,
+ properties_image_processing_qcom: Option<ash::vk::PhysicalDeviceImageProcessingPropertiesQCOM>,
+ properties_memory_decompression_nv:
+ Option<ash::vk::PhysicalDeviceMemoryDecompressionPropertiesNV>,
+ properties_mesh_shader_nv: Option<ash::vk::PhysicalDeviceMeshShaderPropertiesNV>,
+ properties_multiview_per_view_attributes_nvx:
+ Option<ash::vk::PhysicalDeviceMultiviewPerViewAttributesPropertiesNVX>,
+ properties_optical_flow_nv: Option<ash::vk::PhysicalDeviceOpticalFlowPropertiesNV>,
+ properties_ray_tracing_invocation_reorder_nv:
+ Option<ash::vk::PhysicalDeviceRayTracingInvocationReorderPropertiesNV>,
+ properties_ray_tracing_nv: Option<ash::vk::PhysicalDeviceRayTracingPropertiesNV>,
+ properties_shader_core_builtins_arm:
+ Option<ash::vk::PhysicalDeviceShaderCoreBuiltinsPropertiesARM>,
+ properties_shader_core2_amd: Option<ash::vk::PhysicalDeviceShaderCoreProperties2AMD>,
+ properties_shader_core_amd: Option<ash::vk::PhysicalDeviceShaderCorePropertiesAMD>,
+ properties_shader_sm_builtins_nv: Option<ash::vk::PhysicalDeviceShaderSMBuiltinsPropertiesNV>,
+ properties_shading_rate_image_nv: Option<ash::vk::PhysicalDeviceShadingRateImagePropertiesNV>,
+ properties_subpass_shading_huawei:
+ Option<ash::vk::PhysicalDeviceSubpassShadingPropertiesHUAWEI>,
+}
+impl PropertiesFfi {
+ pub(crate) fn make_chain(
+ &mut self,
+ api_version: Version,
+ device_extensions: &DeviceExtensions,
+ instance_extensions: &InstanceExtensions,
+ ) {
+ self.properties_vulkan10 = Default::default();
+ let head = &mut self.properties_vulkan10;
+ if [api_version >= Version::V1_2].into_iter().any(|x| x) && [].into_iter().all(|x| x) {
+ self.properties_vulkan11 = Some(Default::default());
+ let member = self.properties_vulkan11.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [api_version >= Version::V1_2].into_iter().any(|x| x) && [].into_iter().all(|x| x) {
+ self.properties_vulkan12 = Some(Default::default());
+ let member = self.properties_vulkan12.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [api_version >= Version::V1_3].into_iter().any(|x| x) && [].into_iter().all(|x| x) {
+ self.properties_vulkan13 = Some(Default::default());
+ let member = self.properties_vulkan13.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= Version::V1_1,
+ instance_extensions.khr_external_fence_capabilities,
+ instance_extensions.khr_external_memory_capabilities,
+ instance_extensions.khr_external_semaphore_capabilities,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.properties_vulkan11.is_none()].into_iter().all(|x| x)
+ {
+ self.properties_id = Some(Default::default());
+ let member = self.properties_id.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= Version::V1_1,
+ device_extensions.khr_maintenance3,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.properties_vulkan11.is_none()].into_iter().all(|x| x)
+ {
+ self.properties_maintenance3 = Some(Default::default());
+ let member = self.properties_maintenance3.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= Version::V1_1,
+ device_extensions.khr_multiview,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.properties_vulkan11.is_none()].into_iter().all(|x| x)
+ {
+ self.properties_multiview = Some(Default::default());
+ let member = self.properties_multiview.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= Version::V1_1,
+ device_extensions.khr_maintenance2,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.properties_vulkan11.is_none()].into_iter().all(|x| x)
+ {
+ self.properties_point_clipping = Some(Default::default());
+ let member = self.properties_point_clipping.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [api_version >= Version::V1_1].into_iter().any(|x| x)
+ && [self.properties_vulkan11.is_none()].into_iter().all(|x| x)
+ {
+ self.properties_protected_memory = Some(Default::default());
+ let member = self.properties_protected_memory.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [api_version >= Version::V1_1].into_iter().any(|x| x)
+ && [self.properties_vulkan11.is_none()].into_iter().all(|x| x)
+ {
+ self.properties_subgroup = Some(Default::default());
+ let member = self.properties_subgroup.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= Version::V1_2,
+ device_extensions.khr_depth_stencil_resolve,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.properties_vulkan12.is_none()].into_iter().all(|x| x)
+ {
+ self.properties_depth_stencil_resolve = Some(Default::default());
+ let member = self.properties_depth_stencil_resolve.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= Version::V1_2,
+ device_extensions.ext_descriptor_indexing,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.properties_vulkan12.is_none()].into_iter().all(|x| x)
+ {
+ self.properties_descriptor_indexing = Some(Default::default());
+ let member = self.properties_descriptor_indexing.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= Version::V1_2,
+ device_extensions.khr_driver_properties,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.properties_vulkan12.is_none()].into_iter().all(|x| x)
+ {
+ self.properties_driver = Some(Default::default());
+ let member = self.properties_driver.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= Version::V1_2,
+ device_extensions.khr_shader_float_controls,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.properties_vulkan12.is_none()].into_iter().all(|x| x)
+ {
+ self.properties_float_controls = Some(Default::default());
+ let member = self.properties_float_controls.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= Version::V1_2,
+ device_extensions.ext_sampler_filter_minmax,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.properties_vulkan12.is_none()].into_iter().all(|x| x)
+ {
+ self.properties_sampler_filter_minmax = Some(Default::default());
+ let member = self.properties_sampler_filter_minmax.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= Version::V1_2,
+ device_extensions.khr_timeline_semaphore,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.properties_vulkan12.is_none()].into_iter().all(|x| x)
+ {
+ self.properties_timeline_semaphore = Some(Default::default());
+ let member = self.properties_timeline_semaphore.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= Version::V1_3,
+ device_extensions.ext_inline_uniform_block,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.properties_vulkan13.is_none()].into_iter().all(|x| x)
+ {
+ self.properties_inline_uniform_block = Some(Default::default());
+ let member = self.properties_inline_uniform_block.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= Version::V1_3,
+ device_extensions.khr_maintenance4,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.properties_vulkan13.is_none()].into_iter().all(|x| x)
+ {
+ self.properties_maintenance4 = Some(Default::default());
+ let member = self.properties_maintenance4.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= Version::V1_3,
+ device_extensions.khr_shader_integer_dot_product,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.properties_vulkan13.is_none()].into_iter().all(|x| x)
+ {
+ self.properties_shader_integer_dot_product = Some(Default::default());
+ let member = self.properties_shader_integer_dot_product.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= Version::V1_3,
+ device_extensions.ext_subgroup_size_control,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.properties_vulkan13.is_none()].into_iter().all(|x| x)
+ {
+ self.properties_subgroup_size_control = Some(Default::default());
+ let member = self.properties_subgroup_size_control.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [
+ api_version >= Version::V1_3,
+ device_extensions.ext_texel_buffer_alignment,
+ ]
+ .into_iter()
+ .any(|x| x)
+ && [self.properties_vulkan13.is_none()].into_iter().all(|x| x)
+ {
+ self.properties_texel_buffer_alignment = Some(Default::default());
+ let member = self.properties_texel_buffer_alignment.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.khr_acceleration_structure]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_acceleration_structure_khr = Some(Default::default());
+ let member = self.properties_acceleration_structure_khr.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.khr_fragment_shader_barycentric]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_fragment_shader_barycentric_khr = Some(Default::default());
+ let member = self
+ .properties_fragment_shader_barycentric_khr
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.khr_fragment_shading_rate]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_fragment_shading_rate_khr = Some(Default::default());
+ let member = self.properties_fragment_shading_rate_khr.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.khr_performance_query]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_performance_query_khr = Some(Default::default());
+ let member = self.properties_performance_query_khr.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.khr_portability_subset]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_portability_subset_khr = Some(Default::default());
+ let member = self.properties_portability_subset_khr.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.khr_push_descriptor]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_push_descriptor_khr = Some(Default::default());
+ let member = self.properties_push_descriptor_khr.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.khr_ray_tracing_pipeline]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_ray_tracing_pipeline_khr = Some(Default::default());
+ let member = self.properties_ray_tracing_pipeline_khr.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_blend_operation_advanced]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_blend_operation_advanced_ext = Some(Default::default());
+ let member = self
+ .properties_blend_operation_advanced_ext
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_conservative_rasterization]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_conservative_rasterization_ext = Some(Default::default());
+ let member = self
+ .properties_conservative_rasterization_ext
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_custom_border_color]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_custom_border_color_ext = Some(Default::default());
+ let member = self.properties_custom_border_color_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_descriptor_buffer]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_descriptor_buffer_density_map_ext = Some(Default::default());
+ let member = self
+ .properties_descriptor_buffer_density_map_ext
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_descriptor_buffer]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_descriptor_buffer_ext = Some(Default::default());
+ let member = self.properties_descriptor_buffer_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_discard_rectangles]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_discard_rectangle_ext = Some(Default::default());
+ let member = self.properties_discard_rectangle_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_physical_device_drm]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_drm_ext = Some(Default::default());
+ let member = self.properties_drm_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_extended_dynamic_state3]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_extended_dynamic_state3_ext = Some(Default::default());
+ let member = self
+ .properties_extended_dynamic_state3_ext
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_external_memory_host]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_external_memory_host_ext = Some(Default::default());
+ let member = self.properties_external_memory_host_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_fragment_density_map2]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_fragment_density_map2_ext = Some(Default::default());
+ let member = self.properties_fragment_density_map2_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_fragment_density_map]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_fragment_density_map_ext = Some(Default::default());
+ let member = self.properties_fragment_density_map_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_graphics_pipeline_library]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_graphics_pipeline_library_ext = Some(Default::default());
+ let member = self
+ .properties_graphics_pipeline_library_ext
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_line_rasterization]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_line_rasterization_ext = Some(Default::default());
+ let member = self.properties_line_rasterization_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_mesh_shader].into_iter().any(|x| x) && [].into_iter().all(|x| x) {
+ self.properties_mesh_shader_ext = Some(Default::default());
+ let member = self.properties_mesh_shader_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_multi_draw].into_iter().any(|x| x) && [].into_iter().all(|x| x) {
+ self.properties_multi_draw_ext = Some(Default::default());
+ let member = self.properties_multi_draw_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_opacity_micromap]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_opacity_micromap_ext = Some(Default::default());
+ let member = self.properties_opacity_micromap_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_pci_bus_info].into_iter().any(|x| x) && [].into_iter().all(|x| x)
+ {
+ self.properties_pci_bus_info_ext = Some(Default::default());
+ let member = self.properties_pci_bus_info_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_pipeline_robustness]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_pipeline_robustness_ext = Some(Default::default());
+ let member = self.properties_pipeline_robustness_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_provoking_vertex]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_provoking_vertex_ext = Some(Default::default());
+ let member = self.properties_provoking_vertex_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_robustness2].into_iter().any(|x| x) && [].into_iter().all(|x| x) {
+ self.properties_robustness2_ext = Some(Default::default());
+ let member = self.properties_robustness2_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_sample_locations]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_sample_locations_ext = Some(Default::default());
+ let member = self.properties_sample_locations_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_shader_module_identifier]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_shader_module_identifier_ext = Some(Default::default());
+ let member = self
+ .properties_shader_module_identifier_ext
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_transform_feedback]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_transform_feedback_ext = Some(Default::default());
+ let member = self.properties_transform_feedback_ext.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.ext_vertex_attribute_divisor]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_vertex_attribute_divisor_ext = Some(Default::default());
+ let member = self
+ .properties_vertex_attribute_divisor_ext
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_cooperative_matrix]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_cooperative_matrix_nv = Some(Default::default());
+ let member = self.properties_cooperative_matrix_nv.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_copy_memory_indirect]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_copy_memory_indirect_nv = Some(Default::default());
+ let member = self.properties_copy_memory_indirect_nv.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_device_generated_commands]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_device_generated_commands_nv = Some(Default::default());
+ let member = self
+ .properties_device_generated_commands_nv
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.qcom_fragment_density_map_offset]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_fragment_density_map_offset_qcom = Some(Default::default());
+ let member = self
+ .properties_fragment_density_map_offset_qcom
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_fragment_shading_rate_enums]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_fragment_shading_rate_enums_nv = Some(Default::default());
+ let member = self
+ .properties_fragment_shading_rate_enums_nv
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.qcom_image_processing]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_image_processing_qcom = Some(Default::default());
+ let member = self.properties_image_processing_qcom.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_memory_decompression]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_memory_decompression_nv = Some(Default::default());
+ let member = self.properties_memory_decompression_nv.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_mesh_shader].into_iter().any(|x| x)
+ && [self.properties_mesh_shader_ext.is_none()]
+ .into_iter()
+ .all(|x| x)
+ {
+ self.properties_mesh_shader_nv = Some(Default::default());
+ let member = self.properties_mesh_shader_nv.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nvx_multiview_per_view_attributes]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_multiview_per_view_attributes_nvx = Some(Default::default());
+ let member = self
+ .properties_multiview_per_view_attributes_nvx
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_optical_flow].into_iter().any(|x| x) && [].into_iter().all(|x| x) {
+ self.properties_optical_flow_nv = Some(Default::default());
+ let member = self.properties_optical_flow_nv.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_ray_tracing_invocation_reorder]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_ray_tracing_invocation_reorder_nv = Some(Default::default());
+ let member = self
+ .properties_ray_tracing_invocation_reorder_nv
+ .as_mut()
+ .unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_ray_tracing].into_iter().any(|x| x)
+ && [
+ self.properties_ray_tracing_pipeline_khr.is_none(),
+ self.properties_acceleration_structure_khr.is_none(),
+ ]
+ .into_iter()
+ .all(|x| x)
+ {
+ self.properties_ray_tracing_nv = Some(Default::default());
+ let member = self.properties_ray_tracing_nv.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.arm_shader_core_builtins]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_shader_core_builtins_arm = Some(Default::default());
+ let member = self.properties_shader_core_builtins_arm.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.amd_shader_core_properties2]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_shader_core2_amd = Some(Default::default());
+ let member = self.properties_shader_core2_amd.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.amd_shader_core_properties]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_shader_core_amd = Some(Default::default());
+ let member = self.properties_shader_core_amd.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_shader_sm_builtins]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_shader_sm_builtins_nv = Some(Default::default());
+ let member = self.properties_shader_sm_builtins_nv.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.nv_shading_rate_image]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_shading_rate_image_nv = Some(Default::default());
+ let member = self.properties_shading_rate_image_nv.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ if [device_extensions.huawei_subpass_shading]
+ .into_iter()
+ .any(|x| x)
+ && [].into_iter().all(|x| x)
+ {
+ self.properties_subpass_shading_huawei = Some(Default::default());
+ let member = self.properties_subpass_shading_huawei.as_mut().unwrap();
+ member.p_next = head.p_next;
+ head.p_next = member as *mut _ as _;
+ }
+ }
+ pub(crate) fn head_as_mut(&mut self) -> &mut ash::vk::PhysicalDeviceProperties2KHR {
+ &mut self.properties_vulkan10
+ }
+}
diff --git a/out/spirv_parse.rs b/out/spirv_parse.rs
new file mode 100644
index 0000000..5ae19f9
--- /dev/null
+++ b/out/spirv_parse.rs
@@ -0,0 +1,11909 @@
+// This file is auto-generated by vulkano autogen from SPIR-V grammar version 1.6.1.
+// It should not be edited manually. Changes should be made by editing autogen.
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+#[doc = "A parsed SPIR-V instruction."]
+pub enum Instruction {
+ Nop,
+ Undef {
+ result_type_id: Id,
+ result_id: Id,
+ },
+ SourceContinued {
+ continued_source: String,
+ },
+ Source {
+ source_language: SourceLanguage,
+ version: u32,
+ file: Option<Id>,
+ source: Option<String>,
+ },
+ SourceExtension {
+ extension: String,
+ },
+ Name {
+ target: Id,
+ name: String,
+ },
+ MemberName {
+ ty: Id,
+ member: u32,
+ name: String,
+ },
+ String {
+ result_id: Id,
+ string: String,
+ },
+ Line {
+ file: Id,
+ line: u32,
+ column: u32,
+ },
+ Extension {
+ name: String,
+ },
+ ExtInstImport {
+ result_id: Id,
+ name: String,
+ },
+ ExtInst {
+ result_type_id: Id,
+ result_id: Id,
+ set: Id,
+ instruction: u32,
+ operands: Vec<Id>,
+ },
+ MemoryModel {
+ addressing_model: AddressingModel,
+ memory_model: MemoryModel,
+ },
+ EntryPoint {
+ execution_model: ExecutionModel,
+ entry_point: Id,
+ name: String,
+ interface: Vec<Id>,
+ },
+ ExecutionMode {
+ entry_point: Id,
+ mode: ExecutionMode,
+ },
+ Capability {
+ capability: Capability,
+ },
+ TypeVoid {
+ result_id: Id,
+ },
+ TypeBool {
+ result_id: Id,
+ },
+ TypeInt {
+ result_id: Id,
+ width: u32,
+ signedness: u32,
+ },
+ TypeFloat {
+ result_id: Id,
+ width: u32,
+ },
+ TypeVector {
+ result_id: Id,
+ component_type: Id,
+ component_count: u32,
+ },
+ TypeMatrix {
+ result_id: Id,
+ column_type: Id,
+ column_count: u32,
+ },
+ TypeImage {
+ result_id: Id,
+ sampled_type: Id,
+ dim: Dim,
+ depth: u32,
+ arrayed: u32,
+ ms: u32,
+ sampled: u32,
+ image_format: ImageFormat,
+ access_qualifier: Option<AccessQualifier>,
+ },
+ TypeSampler {
+ result_id: Id,
+ },
+ TypeSampledImage {
+ result_id: Id,
+ image_type: Id,
+ },
+ TypeArray {
+ result_id: Id,
+ element_type: Id,
+ length: Id,
+ },
+ TypeRuntimeArray {
+ result_id: Id,
+ element_type: Id,
+ },
+ TypeStruct {
+ result_id: Id,
+ member_types: Vec<Id>,
+ },
+ TypeOpaque {
+ result_id: Id,
+ name: String,
+ },
+ TypePointer {
+ result_id: Id,
+ storage_class: StorageClass,
+ ty: Id,
+ },
+ TypeFunction {
+ result_id: Id,
+ return_type: Id,
+ parameter_types: Vec<Id>,
+ },
+ TypeEvent {
+ result_id: Id,
+ },
+ TypeDeviceEvent {
+ result_id: Id,
+ },
+ TypeReserveId {
+ result_id: Id,
+ },
+ TypeQueue {
+ result_id: Id,
+ },
+ TypePipe {
+ result_id: Id,
+ qualifier: AccessQualifier,
+ },
+ TypeForwardPointer {
+ pointer_type: Id,
+ storage_class: StorageClass,
+ },
+ ConstantTrue {
+ result_type_id: Id,
+ result_id: Id,
+ },
+ ConstantFalse {
+ result_type_id: Id,
+ result_id: Id,
+ },
+ Constant {
+ result_type_id: Id,
+ result_id: Id,
+ value: Vec<u32>,
+ },
+ ConstantComposite {
+ result_type_id: Id,
+ result_id: Id,
+ constituents: Vec<Id>,
+ },
+ ConstantSampler {
+ result_type_id: Id,
+ result_id: Id,
+ sampler_addressing_mode: SamplerAddressingMode,
+ param: u32,
+ sampler_filter_mode: SamplerFilterMode,
+ },
+ ConstantNull {
+ result_type_id: Id,
+ result_id: Id,
+ },
+ SpecConstantTrue {
+ result_type_id: Id,
+ result_id: Id,
+ },
+ SpecConstantFalse {
+ result_type_id: Id,
+ result_id: Id,
+ },
+ SpecConstant {
+ result_type_id: Id,
+ result_id: Id,
+ value: Vec<u32>,
+ },
+ SpecConstantComposite {
+ result_type_id: Id,
+ result_id: Id,
+ constituents: Vec<Id>,
+ },
+ SpecConstantOp {
+ result_type_id: Id,
+ result_id: Id,
+ opcode: SpecConstantInstruction,
+ },
+ Function {
+ result_type_id: Id,
+ result_id: Id,
+ function_control: FunctionControl,
+ function_type: Id,
+ },
+ FunctionParameter {
+ result_type_id: Id,
+ result_id: Id,
+ },
+ FunctionEnd,
+ FunctionCall {
+ result_type_id: Id,
+ result_id: Id,
+ function: Id,
+ arguments: Vec<Id>,
+ },
+ Variable {
+ result_type_id: Id,
+ result_id: Id,
+ storage_class: StorageClass,
+ initializer: Option<Id>,
+ },
+ ImageTexelPointer {
+ result_type_id: Id,
+ result_id: Id,
+ image: Id,
+ coordinate: Id,
+ sample: Id,
+ },
+ Load {
+ result_type_id: Id,
+ result_id: Id,
+ pointer: Id,
+ memory_access: Option<MemoryAccess>,
+ },
+ Store {
+ pointer: Id,
+ object: Id,
+ memory_access: Option<MemoryAccess>,
+ },
+ CopyMemory {
+ target: Id,
+ source: Id,
+ memory_access1: Option<MemoryAccess>,
+ memory_access2: Option<MemoryAccess>,
+ },
+ CopyMemorySized {
+ target: Id,
+ source: Id,
+ size: Id,
+ memory_access1: Option<MemoryAccess>,
+ memory_access2: Option<MemoryAccess>,
+ },
+ AccessChain {
+ result_type_id: Id,
+ result_id: Id,
+ base: Id,
+ indexes: Vec<Id>,
+ },
+ InBoundsAccessChain {
+ result_type_id: Id,
+ result_id: Id,
+ base: Id,
+ indexes: Vec<Id>,
+ },
+ PtrAccessChain {
+ result_type_id: Id,
+ result_id: Id,
+ base: Id,
+ element: Id,
+ indexes: Vec<Id>,
+ },
+ ArrayLength {
+ result_type_id: Id,
+ result_id: Id,
+ structure: Id,
+ array_member: u32,
+ },
+ GenericPtrMemSemantics {
+ result_type_id: Id,
+ result_id: Id,
+ pointer: Id,
+ },
+ InBoundsPtrAccessChain {
+ result_type_id: Id,
+ result_id: Id,
+ base: Id,
+ element: Id,
+ indexes: Vec<Id>,
+ },
+ Decorate {
+ target: Id,
+ decoration: Decoration,
+ },
+ MemberDecorate {
+ structure_type: Id,
+ member: u32,
+ decoration: Decoration,
+ },
+ DecorationGroup {
+ result_id: Id,
+ },
+ GroupDecorate {
+ decoration_group: Id,
+ targets: Vec<Id>,
+ },
+ GroupMemberDecorate {
+ decoration_group: Id,
+ targets: Vec<(Id, u32)>,
+ },
+ VectorExtractDynamic {
+ result_type_id: Id,
+ result_id: Id,
+ vector: Id,
+ index: Id,
+ },
+ VectorInsertDynamic {
+ result_type_id: Id,
+ result_id: Id,
+ vector: Id,
+ component: Id,
+ index: Id,
+ },
+ VectorShuffle {
+ result_type_id: Id,
+ result_id: Id,
+ vector_1: Id,
+ vector_2: Id,
+ components: Vec<u32>,
+ },
+ CompositeConstruct {
+ result_type_id: Id,
+ result_id: Id,
+ constituents: Vec<Id>,
+ },
+ CompositeExtract {
+ result_type_id: Id,
+ result_id: Id,
+ composite: Id,
+ indexes: Vec<u32>,
+ },
+ CompositeInsert {
+ result_type_id: Id,
+ result_id: Id,
+ object: Id,
+ composite: Id,
+ indexes: Vec<u32>,
+ },
+ CopyObject {
+ result_type_id: Id,
+ result_id: Id,
+ operand: Id,
+ },
+ Transpose {
+ result_type_id: Id,
+ result_id: Id,
+ matrix: Id,
+ },
+ SampledImage {
+ result_type_id: Id,
+ result_id: Id,
+ image: Id,
+ sampler: Id,
+ },
+ ImageSampleImplicitLod {
+ result_type_id: Id,
+ result_id: Id,
+ sampled_image: Id,
+ coordinate: Id,
+ image_operands: Option<ImageOperands>,
+ },
+ ImageSampleExplicitLod {
+ result_type_id: Id,
+ result_id: Id,
+ sampled_image: Id,
+ coordinate: Id,
+ image_operands: ImageOperands,
+ },
+ ImageSampleDrefImplicitLod {
+ result_type_id: Id,
+ result_id: Id,
+ sampled_image: Id,
+ coordinate: Id,
+ dref: Id,
+ image_operands: Option<ImageOperands>,
+ },
+ ImageSampleDrefExplicitLod {
+ result_type_id: Id,
+ result_id: Id,
+ sampled_image: Id,
+ coordinate: Id,
+ dref: Id,
+ image_operands: ImageOperands,
+ },
+ ImageSampleProjImplicitLod {
+ result_type_id: Id,
+ result_id: Id,
+ sampled_image: Id,
+ coordinate: Id,
+ image_operands: Option<ImageOperands>,
+ },
+ ImageSampleProjExplicitLod {
+ result_type_id: Id,
+ result_id: Id,
+ sampled_image: Id,
+ coordinate: Id,
+ image_operands: ImageOperands,
+ },
+ ImageSampleProjDrefImplicitLod {
+ result_type_id: Id,
+ result_id: Id,
+ sampled_image: Id,
+ coordinate: Id,
+ dref: Id,
+ image_operands: Option<ImageOperands>,
+ },
+ ImageSampleProjDrefExplicitLod {
+ result_type_id: Id,
+ result_id: Id,
+ sampled_image: Id,
+ coordinate: Id,
+ dref: Id,
+ image_operands: ImageOperands,
+ },
+ ImageFetch {
+ result_type_id: Id,
+ result_id: Id,
+ image: Id,
+ coordinate: Id,
+ image_operands: Option<ImageOperands>,
+ },
+ ImageGather {
+ result_type_id: Id,
+ result_id: Id,
+ sampled_image: Id,
+ coordinate: Id,
+ component: Id,
+ image_operands: Option<ImageOperands>,
+ },
+ ImageDrefGather {
+ result_type_id: Id,
+ result_id: Id,
+ sampled_image: Id,
+ coordinate: Id,
+ dref: Id,
+ image_operands: Option<ImageOperands>,
+ },
+ ImageRead {
+ result_type_id: Id,
+ result_id: Id,
+ image: Id,
+ coordinate: Id,
+ image_operands: Option<ImageOperands>,
+ },
+ ImageWrite {
+ image: Id,
+ coordinate: Id,
+ texel: Id,
+ image_operands: Option<ImageOperands>,
+ },
+ Image {
+ result_type_id: Id,
+ result_id: Id,
+ sampled_image: Id,
+ },
+ ImageQueryFormat {
+ result_type_id: Id,
+ result_id: Id,
+ image: Id,
+ },
+ ImageQueryOrder {
+ result_type_id: Id,
+ result_id: Id,
+ image: Id,
+ },
+ ImageQuerySizeLod {
+ result_type_id: Id,
+ result_id: Id,
+ image: Id,
+ level_of_detail: Id,
+ },
+ ImageQuerySize {
+ result_type_id: Id,
+ result_id: Id,
+ image: Id,
+ },
+ ImageQueryLod {
+ result_type_id: Id,
+ result_id: Id,
+ sampled_image: Id,
+ coordinate: Id,
+ },
+ ImageQueryLevels {
+ result_type_id: Id,
+ result_id: Id,
+ image: Id,
+ },
+ ImageQuerySamples {
+ result_type_id: Id,
+ result_id: Id,
+ image: Id,
+ },
+ ConvertFToU {
+ result_type_id: Id,
+ result_id: Id,
+ float_value: Id,
+ },
+ ConvertFToS {
+ result_type_id: Id,
+ result_id: Id,
+ float_value: Id,
+ },
+ ConvertSToF {
+ result_type_id: Id,
+ result_id: Id,
+ signed_value: Id,
+ },
+ ConvertUToF {
+ result_type_id: Id,
+ result_id: Id,
+ unsigned_value: Id,
+ },
+ UConvert {
+ result_type_id: Id,
+ result_id: Id,
+ unsigned_value: Id,
+ },
+ SConvert {
+ result_type_id: Id,
+ result_id: Id,
+ signed_value: Id,
+ },
+ FConvert {
+ result_type_id: Id,
+ result_id: Id,
+ float_value: Id,
+ },
+ QuantizeToF16 {
+ result_type_id: Id,
+ result_id: Id,
+ value: Id,
+ },
+ ConvertPtrToU {
+ result_type_id: Id,
+ result_id: Id,
+ pointer: Id,
+ },
+ SatConvertSToU {
+ result_type_id: Id,
+ result_id: Id,
+ signed_value: Id,
+ },
+ SatConvertUToS {
+ result_type_id: Id,
+ result_id: Id,
+ unsigned_value: Id,
+ },
+ ConvertUToPtr {
+ result_type_id: Id,
+ result_id: Id,
+ integer_value: Id,
+ },
+ PtrCastToGeneric {
+ result_type_id: Id,
+ result_id: Id,
+ pointer: Id,
+ },
+ GenericCastToPtr {
+ result_type_id: Id,
+ result_id: Id,
+ pointer: Id,
+ },
+ GenericCastToPtrExplicit {
+ result_type_id: Id,
+ result_id: Id,
+ pointer: Id,
+ storage: StorageClass,
+ },
+ Bitcast {
+ result_type_id: Id,
+ result_id: Id,
+ operand: Id,
+ },
+ SNegate {
+ result_type_id: Id,
+ result_id: Id,
+ operand: Id,
+ },
+ FNegate {
+ result_type_id: Id,
+ result_id: Id,
+ operand: Id,
+ },
+ IAdd {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ FAdd {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ ISub {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ FSub {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ IMul {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ FMul {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ UDiv {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ SDiv {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ FDiv {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ UMod {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ SRem {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ SMod {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ FRem {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ FMod {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ VectorTimesScalar {
+ result_type_id: Id,
+ result_id: Id,
+ vector: Id,
+ scalar: Id,
+ },
+ MatrixTimesScalar {
+ result_type_id: Id,
+ result_id: Id,
+ matrix: Id,
+ scalar: Id,
+ },
+ VectorTimesMatrix {
+ result_type_id: Id,
+ result_id: Id,
+ vector: Id,
+ matrix: Id,
+ },
+ MatrixTimesVector {
+ result_type_id: Id,
+ result_id: Id,
+ matrix: Id,
+ vector: Id,
+ },
+ MatrixTimesMatrix {
+ result_type_id: Id,
+ result_id: Id,
+ left_matrix: Id,
+ right_matrix: Id,
+ },
+ OuterProduct {
+ result_type_id: Id,
+ result_id: Id,
+ vector_1: Id,
+ vector_2: Id,
+ },
+ Dot {
+ result_type_id: Id,
+ result_id: Id,
+ vector_1: Id,
+ vector_2: Id,
+ },
+ IAddCarry {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ ISubBorrow {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ UMulExtended {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ SMulExtended {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ Any {
+ result_type_id: Id,
+ result_id: Id,
+ vector: Id,
+ },
+ All {
+ result_type_id: Id,
+ result_id: Id,
+ vector: Id,
+ },
+ IsNan {
+ result_type_id: Id,
+ result_id: Id,
+ x: Id,
+ },
+ IsInf {
+ result_type_id: Id,
+ result_id: Id,
+ x: Id,
+ },
+ IsFinite {
+ result_type_id: Id,
+ result_id: Id,
+ x: Id,
+ },
+ IsNormal {
+ result_type_id: Id,
+ result_id: Id,
+ x: Id,
+ },
+ SignBitSet {
+ result_type_id: Id,
+ result_id: Id,
+ x: Id,
+ },
+ LessOrGreater {
+ result_type_id: Id,
+ result_id: Id,
+ x: Id,
+ y: Id,
+ },
+ Ordered {
+ result_type_id: Id,
+ result_id: Id,
+ x: Id,
+ y: Id,
+ },
+ Unordered {
+ result_type_id: Id,
+ result_id: Id,
+ x: Id,
+ y: Id,
+ },
+ LogicalEqual {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ LogicalNotEqual {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ LogicalOr {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ LogicalAnd {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ LogicalNot {
+ result_type_id: Id,
+ result_id: Id,
+ operand: Id,
+ },
+ Select {
+ result_type_id: Id,
+ result_id: Id,
+ condition: Id,
+ object_1: Id,
+ object_2: Id,
+ },
+ IEqual {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ INotEqual {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ UGreaterThan {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ SGreaterThan {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ UGreaterThanEqual {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ SGreaterThanEqual {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ ULessThan {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ SLessThan {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ ULessThanEqual {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ SLessThanEqual {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ FOrdEqual {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ FUnordEqual {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ FOrdNotEqual {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ FUnordNotEqual {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ FOrdLessThan {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ FUnordLessThan {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ FOrdGreaterThan {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ FUnordGreaterThan {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ FOrdLessThanEqual {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ FUnordLessThanEqual {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ FOrdGreaterThanEqual {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ FUnordGreaterThanEqual {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ ShiftRightLogical {
+ result_type_id: Id,
+ result_id: Id,
+ base: Id,
+ shift: Id,
+ },
+ ShiftRightArithmetic {
+ result_type_id: Id,
+ result_id: Id,
+ base: Id,
+ shift: Id,
+ },
+ ShiftLeftLogical {
+ result_type_id: Id,
+ result_id: Id,
+ base: Id,
+ shift: Id,
+ },
+ BitwiseOr {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ BitwiseXor {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ BitwiseAnd {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ Not {
+ result_type_id: Id,
+ result_id: Id,
+ operand: Id,
+ },
+ BitFieldInsert {
+ result_type_id: Id,
+ result_id: Id,
+ base: Id,
+ insert: Id,
+ offset: Id,
+ count: Id,
+ },
+ BitFieldSExtract {
+ result_type_id: Id,
+ result_id: Id,
+ base: Id,
+ offset: Id,
+ count: Id,
+ },
+ BitFieldUExtract {
+ result_type_id: Id,
+ result_id: Id,
+ base: Id,
+ offset: Id,
+ count: Id,
+ },
+ BitReverse {
+ result_type_id: Id,
+ result_id: Id,
+ base: Id,
+ },
+ BitCount {
+ result_type_id: Id,
+ result_id: Id,
+ base: Id,
+ },
+ DPdx {
+ result_type_id: Id,
+ result_id: Id,
+ p: Id,
+ },
+ DPdy {
+ result_type_id: Id,
+ result_id: Id,
+ p: Id,
+ },
+ Fwidth {
+ result_type_id: Id,
+ result_id: Id,
+ p: Id,
+ },
+ DPdxFine {
+ result_type_id: Id,
+ result_id: Id,
+ p: Id,
+ },
+ DPdyFine {
+ result_type_id: Id,
+ result_id: Id,
+ p: Id,
+ },
+ FwidthFine {
+ result_type_id: Id,
+ result_id: Id,
+ p: Id,
+ },
+ DPdxCoarse {
+ result_type_id: Id,
+ result_id: Id,
+ p: Id,
+ },
+ DPdyCoarse {
+ result_type_id: Id,
+ result_id: Id,
+ p: Id,
+ },
+ FwidthCoarse {
+ result_type_id: Id,
+ result_id: Id,
+ p: Id,
+ },
+ EmitVertex,
+ EndPrimitive,
+ EmitStreamVertex {
+ stream: Id,
+ },
+ EndStreamPrimitive {
+ stream: Id,
+ },
+ ControlBarrier {
+ execution: Id,
+ memory: Id,
+ semantics: Id,
+ },
+ MemoryBarrier {
+ memory: Id,
+ semantics: Id,
+ },
+ AtomicLoad {
+ result_type_id: Id,
+ result_id: Id,
+ pointer: Id,
+ memory: Id,
+ semantics: Id,
+ },
+ AtomicStore {
+ pointer: Id,
+ memory: Id,
+ semantics: Id,
+ value: Id,
+ },
+ AtomicExchange {
+ result_type_id: Id,
+ result_id: Id,
+ pointer: Id,
+ memory: Id,
+ semantics: Id,
+ value: Id,
+ },
+ AtomicCompareExchange {
+ result_type_id: Id,
+ result_id: Id,
+ pointer: Id,
+ memory: Id,
+ equal: Id,
+ unequal: Id,
+ value: Id,
+ comparator: Id,
+ },
+ AtomicCompareExchangeWeak {
+ result_type_id: Id,
+ result_id: Id,
+ pointer: Id,
+ memory: Id,
+ equal: Id,
+ unequal: Id,
+ value: Id,
+ comparator: Id,
+ },
+ AtomicIIncrement {
+ result_type_id: Id,
+ result_id: Id,
+ pointer: Id,
+ memory: Id,
+ semantics: Id,
+ },
+ AtomicIDecrement {
+ result_type_id: Id,
+ result_id: Id,
+ pointer: Id,
+ memory: Id,
+ semantics: Id,
+ },
+ AtomicIAdd {
+ result_type_id: Id,
+ result_id: Id,
+ pointer: Id,
+ memory: Id,
+ semantics: Id,
+ value: Id,
+ },
+ AtomicISub {
+ result_type_id: Id,
+ result_id: Id,
+ pointer: Id,
+ memory: Id,
+ semantics: Id,
+ value: Id,
+ },
+ AtomicSMin {
+ result_type_id: Id,
+ result_id: Id,
+ pointer: Id,
+ memory: Id,
+ semantics: Id,
+ value: Id,
+ },
+ AtomicUMin {
+ result_type_id: Id,
+ result_id: Id,
+ pointer: Id,
+ memory: Id,
+ semantics: Id,
+ value: Id,
+ },
+ AtomicSMax {
+ result_type_id: Id,
+ result_id: Id,
+ pointer: Id,
+ memory: Id,
+ semantics: Id,
+ value: Id,
+ },
+ AtomicUMax {
+ result_type_id: Id,
+ result_id: Id,
+ pointer: Id,
+ memory: Id,
+ semantics: Id,
+ value: Id,
+ },
+ AtomicAnd {
+ result_type_id: Id,
+ result_id: Id,
+ pointer: Id,
+ memory: Id,
+ semantics: Id,
+ value: Id,
+ },
+ AtomicOr {
+ result_type_id: Id,
+ result_id: Id,
+ pointer: Id,
+ memory: Id,
+ semantics: Id,
+ value: Id,
+ },
+ AtomicXor {
+ result_type_id: Id,
+ result_id: Id,
+ pointer: Id,
+ memory: Id,
+ semantics: Id,
+ value: Id,
+ },
+ Phi {
+ result_type_id: Id,
+ result_id: Id,
+ variable_parent: Vec<(Id, Id)>,
+ },
+ LoopMerge {
+ merge_block: Id,
+ continue_target: Id,
+ loop_control: LoopControl,
+ },
+ SelectionMerge {
+ merge_block: Id,
+ selection_control: SelectionControl,
+ },
+ Label {
+ result_id: Id,
+ },
+ Branch {
+ target_label: Id,
+ },
+ BranchConditional {
+ condition: Id,
+ true_label: Id,
+ false_label: Id,
+ branch_weights: Vec<u32>,
+ },
+ Switch {
+ selector: Id,
+ default: Id,
+ target: Vec<(u32, Id)>,
+ },
+ Kill,
+ Return,
+ ReturnValue {
+ value: Id,
+ },
+ Unreachable,
+ LifetimeStart {
+ pointer: Id,
+ size: u32,
+ },
+ LifetimeStop {
+ pointer: Id,
+ size: u32,
+ },
+ GroupAsyncCopy {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ destination: Id,
+ source: Id,
+ num_elements: Id,
+ stride: Id,
+ event: Id,
+ },
+ GroupWaitEvents {
+ execution: Id,
+ num_events: Id,
+ events_list: Id,
+ },
+ GroupAll {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ predicate: Id,
+ },
+ GroupAny {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ predicate: Id,
+ },
+ GroupBroadcast {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ value: Id,
+ local_id: Id,
+ },
+ GroupIAdd {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ x: Id,
+ },
+ GroupFAdd {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ x: Id,
+ },
+ GroupFMin {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ x: Id,
+ },
+ GroupUMin {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ x: Id,
+ },
+ GroupSMin {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ x: Id,
+ },
+ GroupFMax {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ x: Id,
+ },
+ GroupUMax {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ x: Id,
+ },
+ GroupSMax {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ x: Id,
+ },
+ ReadPipe {
+ result_type_id: Id,
+ result_id: Id,
+ pipe: Id,
+ pointer: Id,
+ packet_size: Id,
+ packet_alignment: Id,
+ },
+ WritePipe {
+ result_type_id: Id,
+ result_id: Id,
+ pipe: Id,
+ pointer: Id,
+ packet_size: Id,
+ packet_alignment: Id,
+ },
+ ReservedReadPipe {
+ result_type_id: Id,
+ result_id: Id,
+ pipe: Id,
+ reserve_id: Id,
+ index: Id,
+ pointer: Id,
+ packet_size: Id,
+ packet_alignment: Id,
+ },
+ ReservedWritePipe {
+ result_type_id: Id,
+ result_id: Id,
+ pipe: Id,
+ reserve_id: Id,
+ index: Id,
+ pointer: Id,
+ packet_size: Id,
+ packet_alignment: Id,
+ },
+ ReserveReadPipePackets {
+ result_type_id: Id,
+ result_id: Id,
+ pipe: Id,
+ num_packets: Id,
+ packet_size: Id,
+ packet_alignment: Id,
+ },
+ ReserveWritePipePackets {
+ result_type_id: Id,
+ result_id: Id,
+ pipe: Id,
+ num_packets: Id,
+ packet_size: Id,
+ packet_alignment: Id,
+ },
+ CommitReadPipe {
+ pipe: Id,
+ reserve_id: Id,
+ packet_size: Id,
+ packet_alignment: Id,
+ },
+ CommitWritePipe {
+ pipe: Id,
+ reserve_id: Id,
+ packet_size: Id,
+ packet_alignment: Id,
+ },
+ IsValidReserveId {
+ result_type_id: Id,
+ result_id: Id,
+ reserve_id: Id,
+ },
+ GetNumPipePackets {
+ result_type_id: Id,
+ result_id: Id,
+ pipe: Id,
+ packet_size: Id,
+ packet_alignment: Id,
+ },
+ GetMaxPipePackets {
+ result_type_id: Id,
+ result_id: Id,
+ pipe: Id,
+ packet_size: Id,
+ packet_alignment: Id,
+ },
+ GroupReserveReadPipePackets {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ pipe: Id,
+ num_packets: Id,
+ packet_size: Id,
+ packet_alignment: Id,
+ },
+ GroupReserveWritePipePackets {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ pipe: Id,
+ num_packets: Id,
+ packet_size: Id,
+ packet_alignment: Id,
+ },
+ GroupCommitReadPipe {
+ execution: Id,
+ pipe: Id,
+ reserve_id: Id,
+ packet_size: Id,
+ packet_alignment: Id,
+ },
+ GroupCommitWritePipe {
+ execution: Id,
+ pipe: Id,
+ reserve_id: Id,
+ packet_size: Id,
+ packet_alignment: Id,
+ },
+ EnqueueMarker {
+ result_type_id: Id,
+ result_id: Id,
+ queue: Id,
+ num_events: Id,
+ wait_events: Id,
+ ret_event: Id,
+ },
+ EnqueueKernel {
+ result_type_id: Id,
+ result_id: Id,
+ queue: Id,
+ flags: Id,
+ nd_range: Id,
+ num_events: Id,
+ wait_events: Id,
+ ret_event: Id,
+ invoke: Id,
+ param: Id,
+ param_size: Id,
+ param_align: Id,
+ local_size: Vec<Id>,
+ },
+ GetKernelNDrangeSubGroupCount {
+ result_type_id: Id,
+ result_id: Id,
+ nd_range: Id,
+ invoke: Id,
+ param: Id,
+ param_size: Id,
+ param_align: Id,
+ },
+ GetKernelNDrangeMaxSubGroupSize {
+ result_type_id: Id,
+ result_id: Id,
+ nd_range: Id,
+ invoke: Id,
+ param: Id,
+ param_size: Id,
+ param_align: Id,
+ },
+ GetKernelWorkGroupSize {
+ result_type_id: Id,
+ result_id: Id,
+ invoke: Id,
+ param: Id,
+ param_size: Id,
+ param_align: Id,
+ },
+ GetKernelPreferredWorkGroupSizeMultiple {
+ result_type_id: Id,
+ result_id: Id,
+ invoke: Id,
+ param: Id,
+ param_size: Id,
+ param_align: Id,
+ },
+ RetainEvent {
+ event: Id,
+ },
+ ReleaseEvent {
+ event: Id,
+ },
+ CreateUserEvent {
+ result_type_id: Id,
+ result_id: Id,
+ },
+ IsValidEvent {
+ result_type_id: Id,
+ result_id: Id,
+ event: Id,
+ },
+ SetUserEventStatus {
+ event: Id,
+ status: Id,
+ },
+ CaptureEventProfilingInfo {
+ event: Id,
+ profiling_info: Id,
+ value: Id,
+ },
+ GetDefaultQueue {
+ result_type_id: Id,
+ result_id: Id,
+ },
+ BuildNDRange {
+ result_type_id: Id,
+ result_id: Id,
+ global_work_size: Id,
+ local_work_size: Id,
+ global_work_offset: Id,
+ },
+ ImageSparseSampleImplicitLod {
+ result_type_id: Id,
+ result_id: Id,
+ sampled_image: Id,
+ coordinate: Id,
+ image_operands: Option<ImageOperands>,
+ },
+ ImageSparseSampleExplicitLod {
+ result_type_id: Id,
+ result_id: Id,
+ sampled_image: Id,
+ coordinate: Id,
+ image_operands: ImageOperands,
+ },
+ ImageSparseSampleDrefImplicitLod {
+ result_type_id: Id,
+ result_id: Id,
+ sampled_image: Id,
+ coordinate: Id,
+ dref: Id,
+ image_operands: Option<ImageOperands>,
+ },
+ ImageSparseSampleDrefExplicitLod {
+ result_type_id: Id,
+ result_id: Id,
+ sampled_image: Id,
+ coordinate: Id,
+ dref: Id,
+ image_operands: ImageOperands,
+ },
+ ImageSparseSampleProjImplicitLod {
+ result_type_id: Id,
+ result_id: Id,
+ sampled_image: Id,
+ coordinate: Id,
+ image_operands: Option<ImageOperands>,
+ },
+ ImageSparseSampleProjExplicitLod {
+ result_type_id: Id,
+ result_id: Id,
+ sampled_image: Id,
+ coordinate: Id,
+ image_operands: ImageOperands,
+ },
+ ImageSparseSampleProjDrefImplicitLod {
+ result_type_id: Id,
+ result_id: Id,
+ sampled_image: Id,
+ coordinate: Id,
+ dref: Id,
+ image_operands: Option<ImageOperands>,
+ },
+ ImageSparseSampleProjDrefExplicitLod {
+ result_type_id: Id,
+ result_id: Id,
+ sampled_image: Id,
+ coordinate: Id,
+ dref: Id,
+ image_operands: ImageOperands,
+ },
+ ImageSparseFetch {
+ result_type_id: Id,
+ result_id: Id,
+ image: Id,
+ coordinate: Id,
+ image_operands: Option<ImageOperands>,
+ },
+ ImageSparseGather {
+ result_type_id: Id,
+ result_id: Id,
+ sampled_image: Id,
+ coordinate: Id,
+ component: Id,
+ image_operands: Option<ImageOperands>,
+ },
+ ImageSparseDrefGather {
+ result_type_id: Id,
+ result_id: Id,
+ sampled_image: Id,
+ coordinate: Id,
+ dref: Id,
+ image_operands: Option<ImageOperands>,
+ },
+ ImageSparseTexelsResident {
+ result_type_id: Id,
+ result_id: Id,
+ resident_code: Id,
+ },
+ NoLine,
+ AtomicFlagTestAndSet {
+ result_type_id: Id,
+ result_id: Id,
+ pointer: Id,
+ memory: Id,
+ semantics: Id,
+ },
+ AtomicFlagClear {
+ pointer: Id,
+ memory: Id,
+ semantics: Id,
+ },
+ ImageSparseRead {
+ result_type_id: Id,
+ result_id: Id,
+ image: Id,
+ coordinate: Id,
+ image_operands: Option<ImageOperands>,
+ },
+ SizeOf {
+ result_type_id: Id,
+ result_id: Id,
+ pointer: Id,
+ },
+ TypePipeStorage {
+ result_id: Id,
+ },
+ ConstantPipeStorage {
+ result_type_id: Id,
+ result_id: Id,
+ packet_size: u32,
+ packet_alignment: u32,
+ capacity: u32,
+ },
+ CreatePipeFromPipeStorage {
+ result_type_id: Id,
+ result_id: Id,
+ pipe_storage: Id,
+ },
+ GetKernelLocalSizeForSubgroupCount {
+ result_type_id: Id,
+ result_id: Id,
+ subgroup_count: Id,
+ invoke: Id,
+ param: Id,
+ param_size: Id,
+ param_align: Id,
+ },
+ GetKernelMaxNumSubgroups {
+ result_type_id: Id,
+ result_id: Id,
+ invoke: Id,
+ param: Id,
+ param_size: Id,
+ param_align: Id,
+ },
+ TypeNamedBarrier {
+ result_id: Id,
+ },
+ NamedBarrierInitialize {
+ result_type_id: Id,
+ result_id: Id,
+ subgroup_count: Id,
+ },
+ MemoryNamedBarrier {
+ named_barrier: Id,
+ memory: Id,
+ semantics: Id,
+ },
+ ModuleProcessed {
+ process: String,
+ },
+ ExecutionModeId {
+ entry_point: Id,
+ mode: ExecutionMode,
+ },
+ DecorateId {
+ target: Id,
+ decoration: Decoration,
+ },
+ GroupNonUniformElect {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ },
+ GroupNonUniformAll {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ predicate: Id,
+ },
+ GroupNonUniformAny {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ predicate: Id,
+ },
+ GroupNonUniformAllEqual {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ value: Id,
+ },
+ GroupNonUniformBroadcast {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ value: Id,
+ id: Id,
+ },
+ GroupNonUniformBroadcastFirst {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ value: Id,
+ },
+ GroupNonUniformBallot {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ predicate: Id,
+ },
+ GroupNonUniformInverseBallot {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ value: Id,
+ },
+ GroupNonUniformBallotBitExtract {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ value: Id,
+ index: Id,
+ },
+ GroupNonUniformBallotBitCount {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ value: Id,
+ },
+ GroupNonUniformBallotFindLSB {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ value: Id,
+ },
+ GroupNonUniformBallotFindMSB {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ value: Id,
+ },
+ GroupNonUniformShuffle {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ value: Id,
+ id: Id,
+ },
+ GroupNonUniformShuffleXor {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ value: Id,
+ mask: Id,
+ },
+ GroupNonUniformShuffleUp {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ value: Id,
+ delta: Id,
+ },
+ GroupNonUniformShuffleDown {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ value: Id,
+ delta: Id,
+ },
+ GroupNonUniformIAdd {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ value: Id,
+ cluster_size: Option<Id>,
+ },
+ GroupNonUniformFAdd {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ value: Id,
+ cluster_size: Option<Id>,
+ },
+ GroupNonUniformIMul {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ value: Id,
+ cluster_size: Option<Id>,
+ },
+ GroupNonUniformFMul {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ value: Id,
+ cluster_size: Option<Id>,
+ },
+ GroupNonUniformSMin {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ value: Id,
+ cluster_size: Option<Id>,
+ },
+ GroupNonUniformUMin {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ value: Id,
+ cluster_size: Option<Id>,
+ },
+ GroupNonUniformFMin {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ value: Id,
+ cluster_size: Option<Id>,
+ },
+ GroupNonUniformSMax {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ value: Id,
+ cluster_size: Option<Id>,
+ },
+ GroupNonUniformUMax {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ value: Id,
+ cluster_size: Option<Id>,
+ },
+ GroupNonUniformFMax {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ value: Id,
+ cluster_size: Option<Id>,
+ },
+ GroupNonUniformBitwiseAnd {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ value: Id,
+ cluster_size: Option<Id>,
+ },
+ GroupNonUniformBitwiseOr {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ value: Id,
+ cluster_size: Option<Id>,
+ },
+ GroupNonUniformBitwiseXor {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ value: Id,
+ cluster_size: Option<Id>,
+ },
+ GroupNonUniformLogicalAnd {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ value: Id,
+ cluster_size: Option<Id>,
+ },
+ GroupNonUniformLogicalOr {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ value: Id,
+ cluster_size: Option<Id>,
+ },
+ GroupNonUniformLogicalXor {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ value: Id,
+ cluster_size: Option<Id>,
+ },
+ GroupNonUniformQuadBroadcast {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ value: Id,
+ index: Id,
+ },
+ GroupNonUniformQuadSwap {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ value: Id,
+ direction: Id,
+ },
+ CopyLogical {
+ result_type_id: Id,
+ result_id: Id,
+ operand: Id,
+ },
+ PtrEqual {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ PtrNotEqual {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ PtrDiff {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ TerminateInvocation,
+ SubgroupBallotKHR {
+ result_type_id: Id,
+ result_id: Id,
+ predicate: Id,
+ },
+ SubgroupFirstInvocationKHR {
+ result_type_id: Id,
+ result_id: Id,
+ value: Id,
+ },
+ SubgroupAllKHR {
+ result_type_id: Id,
+ result_id: Id,
+ predicate: Id,
+ },
+ SubgroupAnyKHR {
+ result_type_id: Id,
+ result_id: Id,
+ predicate: Id,
+ },
+ SubgroupAllEqualKHR {
+ result_type_id: Id,
+ result_id: Id,
+ predicate: Id,
+ },
+ SubgroupReadInvocationKHR {
+ result_type_id: Id,
+ result_id: Id,
+ value: Id,
+ index: Id,
+ },
+ TraceRayKHR {
+ accel: Id,
+ ray_flags: Id,
+ cull_mask: Id,
+ sbt_offset: Id,
+ sbt_stride: Id,
+ miss_index: Id,
+ ray_origin: Id,
+ ray_tmin: Id,
+ ray_direction: Id,
+ ray_tmax: Id,
+ payload: Id,
+ },
+ ExecuteCallableKHR {
+ sbt_index: Id,
+ callable_data: Id,
+ },
+ ConvertUToAccelerationStructureKHR {
+ result_type_id: Id,
+ result_id: Id,
+ accel: Id,
+ },
+ IgnoreIntersectionKHR,
+ TerminateRayKHR,
+ SDot {
+ result_type_id: Id,
+ result_id: Id,
+ vector_1: Id,
+ vector_2: Id,
+ packed_vector_format: Option<PackedVectorFormat>,
+ },
+ UDot {
+ result_type_id: Id,
+ result_id: Id,
+ vector_1: Id,
+ vector_2: Id,
+ packed_vector_format: Option<PackedVectorFormat>,
+ },
+ SUDot {
+ result_type_id: Id,
+ result_id: Id,
+ vector_1: Id,
+ vector_2: Id,
+ packed_vector_format: Option<PackedVectorFormat>,
+ },
+ SDotAccSat {
+ result_type_id: Id,
+ result_id: Id,
+ vector_1: Id,
+ vector_2: Id,
+ accumulator: Id,
+ packed_vector_format: Option<PackedVectorFormat>,
+ },
+ UDotAccSat {
+ result_type_id: Id,
+ result_id: Id,
+ vector_1: Id,
+ vector_2: Id,
+ accumulator: Id,
+ packed_vector_format: Option<PackedVectorFormat>,
+ },
+ SUDotAccSat {
+ result_type_id: Id,
+ result_id: Id,
+ vector_1: Id,
+ vector_2: Id,
+ accumulator: Id,
+ packed_vector_format: Option<PackedVectorFormat>,
+ },
+ TypeRayQueryKHR {
+ result_id: Id,
+ },
+ RayQueryInitializeKHR {
+ ray_query: Id,
+ accel: Id,
+ ray_flags: Id,
+ cull_mask: Id,
+ ray_origin: Id,
+ ray_t_min: Id,
+ ray_direction: Id,
+ ray_t_max: Id,
+ },
+ RayQueryTerminateKHR {
+ ray_query: Id,
+ },
+ RayQueryGenerateIntersectionKHR {
+ ray_query: Id,
+ hit_t: Id,
+ },
+ RayQueryConfirmIntersectionKHR {
+ ray_query: Id,
+ },
+ RayQueryProceedKHR {
+ result_type_id: Id,
+ result_id: Id,
+ ray_query: Id,
+ },
+ RayQueryGetIntersectionTypeKHR {
+ result_type_id: Id,
+ result_id: Id,
+ ray_query: Id,
+ intersection: Id,
+ },
+ GroupIAddNonUniformAMD {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ x: Id,
+ },
+ GroupFAddNonUniformAMD {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ x: Id,
+ },
+ GroupFMinNonUniformAMD {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ x: Id,
+ },
+ GroupUMinNonUniformAMD {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ x: Id,
+ },
+ GroupSMinNonUniformAMD {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ x: Id,
+ },
+ GroupFMaxNonUniformAMD {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ x: Id,
+ },
+ GroupUMaxNonUniformAMD {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ x: Id,
+ },
+ GroupSMaxNonUniformAMD {
+ result_type_id: Id,
+ result_id: Id,
+ execution: Id,
+ operation: GroupOperation,
+ x: Id,
+ },
+ FragmentMaskFetchAMD {
+ result_type_id: Id,
+ result_id: Id,
+ image: Id,
+ coordinate: Id,
+ },
+ FragmentFetchAMD {
+ result_type_id: Id,
+ result_id: Id,
+ image: Id,
+ coordinate: Id,
+ fragment_index: Id,
+ },
+ ReadClockKHR {
+ result_type_id: Id,
+ result_id: Id,
+ scope: Id,
+ },
+ ImageSampleFootprintNV {
+ result_type_id: Id,
+ result_id: Id,
+ sampled_image: Id,
+ coordinate: Id,
+ granularity: Id,
+ coarse: Id,
+ image_operands: Option<ImageOperands>,
+ },
+ GroupNonUniformPartitionNV {
+ result_type_id: Id,
+ result_id: Id,
+ value: Id,
+ },
+ WritePackedPrimitiveIndices4x8NV {
+ index_offset: Id,
+ packed_indices: Id,
+ },
+ ReportIntersectionKHR {
+ result_type_id: Id,
+ result_id: Id,
+ hit: Id,
+ hit_kind: Id,
+ },
+ IgnoreIntersectionNV,
+ TerminateRayNV,
+ TraceNV {
+ accel: Id,
+ ray_flags: Id,
+ cull_mask: Id,
+ sbt_offset: Id,
+ sbt_stride: Id,
+ miss_index: Id,
+ ray_origin: Id,
+ ray_tmin: Id,
+ ray_direction: Id,
+ ray_tmax: Id,
+ payload_id: Id,
+ },
+ TraceMotionNV {
+ accel: Id,
+ ray_flags: Id,
+ cull_mask: Id,
+ sbt_offset: Id,
+ sbt_stride: Id,
+ miss_index: Id,
+ ray_origin: Id,
+ ray_tmin: Id,
+ ray_direction: Id,
+ ray_tmax: Id,
+ time: Id,
+ payload_id: Id,
+ },
+ TraceRayMotionNV {
+ accel: Id,
+ ray_flags: Id,
+ cull_mask: Id,
+ sbt_offset: Id,
+ sbt_stride: Id,
+ miss_index: Id,
+ ray_origin: Id,
+ ray_tmin: Id,
+ ray_direction: Id,
+ ray_tmax: Id,
+ time: Id,
+ payload: Id,
+ },
+ TypeAccelerationStructureKHR {
+ result_id: Id,
+ },
+ ExecuteCallableNV {
+ sbt_index: Id,
+ callable_data_id: Id,
+ },
+ TypeCooperativeMatrixNV {
+ result_id: Id,
+ component_type: Id,
+ execution: Id,
+ rows: Id,
+ columns: Id,
+ },
+ CooperativeMatrixLoadNV {
+ result_type_id: Id,
+ result_id: Id,
+ pointer: Id,
+ stride: Id,
+ column_major: Id,
+ memory_access: Option<MemoryAccess>,
+ },
+ CooperativeMatrixStoreNV {
+ pointer: Id,
+ object: Id,
+ stride: Id,
+ column_major: Id,
+ memory_access: Option<MemoryAccess>,
+ },
+ CooperativeMatrixMulAddNV {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ b: Id,
+ c: Id,
+ },
+ CooperativeMatrixLengthNV {
+ result_type_id: Id,
+ result_id: Id,
+ ty: Id,
+ },
+ BeginInvocationInterlockEXT,
+ EndInvocationInterlockEXT,
+ DemoteToHelperInvocation,
+ IsHelperInvocationEXT {
+ result_type_id: Id,
+ result_id: Id,
+ },
+ ConvertUToImageNV {
+ result_type_id: Id,
+ result_id: Id,
+ operand: Id,
+ },
+ ConvertUToSamplerNV {
+ result_type_id: Id,
+ result_id: Id,
+ operand: Id,
+ },
+ ConvertImageToUNV {
+ result_type_id: Id,
+ result_id: Id,
+ operand: Id,
+ },
+ ConvertSamplerToUNV {
+ result_type_id: Id,
+ result_id: Id,
+ operand: Id,
+ },
+ ConvertUToSampledImageNV {
+ result_type_id: Id,
+ result_id: Id,
+ operand: Id,
+ },
+ ConvertSampledImageToUNV {
+ result_type_id: Id,
+ result_id: Id,
+ operand: Id,
+ },
+ SamplerImageAddressingModeNV {
+ bit_width: u32,
+ },
+ SubgroupShuffleINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ data: Id,
+ invocation_id: Id,
+ },
+ SubgroupShuffleDownINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ current: Id,
+ next: Id,
+ delta: Id,
+ },
+ SubgroupShuffleUpINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ previous: Id,
+ current: Id,
+ delta: Id,
+ },
+ SubgroupShuffleXorINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ data: Id,
+ value: Id,
+ },
+ SubgroupBlockReadINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ ptr: Id,
+ },
+ SubgroupBlockWriteINTEL {
+ ptr: Id,
+ data: Id,
+ },
+ SubgroupImageBlockReadINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ image: Id,
+ coordinate: Id,
+ },
+ SubgroupImageBlockWriteINTEL {
+ image: Id,
+ coordinate: Id,
+ data: Id,
+ },
+ SubgroupImageMediaBlockReadINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ image: Id,
+ coordinate: Id,
+ width: Id,
+ height: Id,
+ },
+ SubgroupImageMediaBlockWriteINTEL {
+ image: Id,
+ coordinate: Id,
+ width: Id,
+ height: Id,
+ data: Id,
+ },
+ UCountLeadingZerosINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ operand: Id,
+ },
+ UCountTrailingZerosINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ operand: Id,
+ },
+ AbsISubINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ AbsUSubINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ IAddSatINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ UAddSatINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ IAverageINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ UAverageINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ IAverageRoundedINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ UAverageRoundedINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ ISubSatINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ USubSatINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ IMul32x16INTEL {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ UMul32x16INTEL {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Id,
+ operand2: Id,
+ },
+ ConstantFunctionPointerINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ function: Id,
+ },
+ FunctionPointerCallINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ operand1: Vec<Id>,
+ },
+ AsmTargetINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ asm_target: String,
+ },
+ AsmINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ asm_type: Id,
+ target: Id,
+ asm_instructions: String,
+ constraints: String,
+ },
+ AsmCallINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ asm: Id,
+ argument_0: Vec<Id>,
+ },
+ AtomicFMinEXT {
+ result_type_id: Id,
+ result_id: Id,
+ pointer: Id,
+ memory: Id,
+ semantics: Id,
+ value: Id,
+ },
+ AtomicFMaxEXT {
+ result_type_id: Id,
+ result_id: Id,
+ pointer: Id,
+ memory: Id,
+ semantics: Id,
+ value: Id,
+ },
+ AssumeTrueKHR {
+ condition: Id,
+ },
+ ExpectKHR {
+ result_type_id: Id,
+ result_id: Id,
+ value: Id,
+ expected_value: Id,
+ },
+ DecorateString {
+ target: Id,
+ decoration: Decoration,
+ },
+ MemberDecorateString {
+ struct_type: Id,
+ member: u32,
+ decoration: Decoration,
+ },
+ VmeImageINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ image_type: Id,
+ sampler: Id,
+ },
+ TypeVmeImageINTEL {
+ result_id: Id,
+ image_type: Id,
+ },
+ TypeAvcImePayloadINTEL {
+ result_id: Id,
+ },
+ TypeAvcRefPayloadINTEL {
+ result_id: Id,
+ },
+ TypeAvcSicPayloadINTEL {
+ result_id: Id,
+ },
+ TypeAvcMcePayloadINTEL {
+ result_id: Id,
+ },
+ TypeAvcMceResultINTEL {
+ result_id: Id,
+ },
+ TypeAvcImeResultINTEL {
+ result_id: Id,
+ },
+ TypeAvcImeResultSingleReferenceStreamoutINTEL {
+ result_id: Id,
+ },
+ TypeAvcImeResultDualReferenceStreamoutINTEL {
+ result_id: Id,
+ },
+ TypeAvcImeSingleReferenceStreaminINTEL {
+ result_id: Id,
+ },
+ TypeAvcImeDualReferenceStreaminINTEL {
+ result_id: Id,
+ },
+ TypeAvcRefResultINTEL {
+ result_id: Id,
+ },
+ TypeAvcSicResultINTEL {
+ result_id: Id,
+ },
+ SubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ slice_type: Id,
+ qp: Id,
+ },
+ SubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ reference_base_penalty: Id,
+ payload: Id,
+ },
+ SubgroupAvcMceGetDefaultInterShapePenaltyINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ slice_type: Id,
+ qp: Id,
+ },
+ SubgroupAvcMceSetInterShapePenaltyINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ packed_shape_penalty: Id,
+ payload: Id,
+ },
+ SubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ slice_type: Id,
+ qp: Id,
+ },
+ SubgroupAvcMceSetInterDirectionPenaltyINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ direction_cost: Id,
+ payload: Id,
+ },
+ SubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ slice_type: Id,
+ qp: Id,
+ },
+ SubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ slice_type: Id,
+ qp: Id,
+ },
+ SubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ },
+ SubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ },
+ SubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ },
+ SubgroupAvcMceSetMotionVectorCostFunctionINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ packed_cost_center_delta: Id,
+ packed_cost_table: Id,
+ cost_precision: Id,
+ payload: Id,
+ },
+ SubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ slice_type: Id,
+ qp: Id,
+ },
+ SubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ },
+ SubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ },
+ SubgroupAvcMceSetAcOnlyHaarINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ source_field_polarity: Id,
+ payload: Id,
+ },
+ SubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ reference_field_polarity: Id,
+ payload: Id,
+ },
+ SubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ forward_reference_field_polarity: Id,
+ backward_reference_field_polarity: Id,
+ payload: Id,
+ },
+ SubgroupAvcMceConvertToImePayloadINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcMceConvertToImeResultINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcMceConvertToRefPayloadINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcMceConvertToRefResultINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcMceConvertToSicPayloadINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcMceConvertToSicResultINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcMceGetMotionVectorsINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcMceGetInterDistortionsINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcMceGetBestInterDistortionsINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcMceGetInterMajorShapeINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcMceGetInterMinorShapeINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcMceGetInterDirectionsINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcMceGetInterMotionVectorCountINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcMceGetInterReferenceIdsINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ packed_reference_ids: Id,
+ packed_reference_parameter_field_polarities: Id,
+ payload: Id,
+ },
+ SubgroupAvcImeInitializeINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ src_coord: Id,
+ partition_mask: Id,
+ sad_adjustment: Id,
+ },
+ SubgroupAvcImeSetSingleReferenceINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ ref_offset: Id,
+ search_window_config: Id,
+ payload: Id,
+ },
+ SubgroupAvcImeSetDualReferenceINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ fwd_ref_offset: Id,
+ bwd_ref_offset: Id,
+ id_search_window_config: Id,
+ payload: Id,
+ },
+ SubgroupAvcImeRefWindowSizeINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ search_window_config: Id,
+ dual_ref: Id,
+ },
+ SubgroupAvcImeAdjustRefOffsetINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ ref_offset: Id,
+ src_coord: Id,
+ ref_window_size: Id,
+ image_size: Id,
+ },
+ SubgroupAvcImeConvertToMcePayloadINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcImeSetMaxMotionVectorCountINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ max_motion_vector_count: Id,
+ payload: Id,
+ },
+ SubgroupAvcImeSetUnidirectionalMixDisableINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcImeSetEarlySearchTerminationThresholdINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ threshold: Id,
+ payload: Id,
+ },
+ SubgroupAvcImeSetWeightedSadINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ packed_sad_weights: Id,
+ payload: Id,
+ },
+ SubgroupAvcImeEvaluateWithSingleReferenceINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ src_image: Id,
+ ref_image: Id,
+ payload: Id,
+ },
+ SubgroupAvcImeEvaluateWithDualReferenceINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ src_image: Id,
+ fwd_ref_image: Id,
+ bwd_ref_image: Id,
+ payload: Id,
+ },
+ SubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ src_image: Id,
+ ref_image: Id,
+ payload: Id,
+ streamin_components: Id,
+ },
+ SubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ src_image: Id,
+ fwd_ref_image: Id,
+ bwd_ref_image: Id,
+ payload: Id,
+ streamin_components: Id,
+ },
+ SubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ src_image: Id,
+ ref_image: Id,
+ payload: Id,
+ },
+ SubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ src_image: Id,
+ fwd_ref_image: Id,
+ bwd_ref_image: Id,
+ payload: Id,
+ },
+ SubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ src_image: Id,
+ ref_image: Id,
+ payload: Id,
+ streamin_components: Id,
+ },
+ SubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ src_image: Id,
+ fwd_ref_image: Id,
+ bwd_ref_image: Id,
+ payload: Id,
+ streamin_components: Id,
+ },
+ SubgroupAvcImeConvertToMceResultINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcImeGetSingleReferenceStreaminINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcImeGetDualReferenceStreaminINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcImeStripSingleReferenceStreamoutINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcImeStripDualReferenceStreamoutINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ major_shape: Id,
+ },
+ SubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ major_shape: Id,
+ },
+ SubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ major_shape: Id,
+ },
+ SubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ major_shape: Id,
+ direction: Id,
+ },
+ SubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ major_shape: Id,
+ direction: Id,
+ },
+ SubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ major_shape: Id,
+ direction: Id,
+ },
+ SubgroupAvcImeGetBorderReachedINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ image_select: Id,
+ payload: Id,
+ },
+ SubgroupAvcImeGetTruncatedSearchIndicationINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcFmeInitializeINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ src_coord: Id,
+ motion_vectors: Id,
+ major_shapes: Id,
+ minor_shapes: Id,
+ direction: Id,
+ pixel_resolution: Id,
+ sad_adjustment: Id,
+ },
+ SubgroupAvcBmeInitializeINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ src_coord: Id,
+ motion_vectors: Id,
+ major_shapes: Id,
+ minor_shapes: Id,
+ direction: Id,
+ pixel_resolution: Id,
+ bidirectional_weight: Id,
+ sad_adjustment: Id,
+ },
+ SubgroupAvcRefConvertToMcePayloadINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcRefSetBidirectionalMixDisableINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcRefSetBilinearFilterEnableINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcRefEvaluateWithSingleReferenceINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ src_image: Id,
+ ref_image: Id,
+ payload: Id,
+ },
+ SubgroupAvcRefEvaluateWithDualReferenceINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ src_image: Id,
+ fwd_ref_image: Id,
+ bwd_ref_image: Id,
+ payload: Id,
+ },
+ SubgroupAvcRefEvaluateWithMultiReferenceINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ src_image: Id,
+ packed_reference_ids: Id,
+ payload: Id,
+ },
+ SubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ src_image: Id,
+ packed_reference_ids: Id,
+ packed_reference_field_polarities: Id,
+ payload: Id,
+ },
+ SubgroupAvcRefConvertToMceResultINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcSicInitializeINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ src_coord: Id,
+ },
+ SubgroupAvcSicConfigureSkcINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ skip_block_partition_type: Id,
+ skip_motion_vector_mask: Id,
+ motion_vectors: Id,
+ bidirectional_weight: Id,
+ sad_adjustment: Id,
+ payload: Id,
+ },
+ SubgroupAvcSicConfigureIpeLumaINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ luma_intra_partition_mask: Id,
+ intra_neighbour_availabilty: Id,
+ left_edge_luma_pixels: Id,
+ upper_left_corner_luma_pixel: Id,
+ upper_edge_luma_pixels: Id,
+ upper_right_edge_luma_pixels: Id,
+ sad_adjustment: Id,
+ payload: Id,
+ },
+ SubgroupAvcSicConfigureIpeLumaChromaINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ luma_intra_partition_mask: Id,
+ intra_neighbour_availabilty: Id,
+ left_edge_luma_pixels: Id,
+ upper_left_corner_luma_pixel: Id,
+ upper_edge_luma_pixels: Id,
+ upper_right_edge_luma_pixels: Id,
+ left_edge_chroma_pixels: Id,
+ upper_left_corner_chroma_pixel: Id,
+ upper_edge_chroma_pixels: Id,
+ sad_adjustment: Id,
+ payload: Id,
+ },
+ SubgroupAvcSicGetMotionVectorMaskINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ skip_block_partition_type: Id,
+ direction: Id,
+ },
+ SubgroupAvcSicConvertToMcePayloadINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcSicSetIntraLumaShapePenaltyINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ packed_shape_penalty: Id,
+ payload: Id,
+ },
+ SubgroupAvcSicSetIntraLumaModeCostFunctionINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ luma_mode_penalty: Id,
+ luma_packed_neighbor_modes: Id,
+ luma_packed_non_dc_penalty: Id,
+ payload: Id,
+ },
+ SubgroupAvcSicSetIntraChromaModeCostFunctionINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ chroma_mode_base_penalty: Id,
+ payload: Id,
+ },
+ SubgroupAvcSicSetBilinearFilterEnableINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcSicSetSkcForwardTransformEnableINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ packed_sad_coefficients: Id,
+ payload: Id,
+ },
+ SubgroupAvcSicSetBlockBasedRawSkipSadINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ block_based_skip_type: Id,
+ payload: Id,
+ },
+ SubgroupAvcSicEvaluateIpeINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ src_image: Id,
+ payload: Id,
+ },
+ SubgroupAvcSicEvaluateWithSingleReferenceINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ src_image: Id,
+ ref_image: Id,
+ payload: Id,
+ },
+ SubgroupAvcSicEvaluateWithDualReferenceINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ src_image: Id,
+ fwd_ref_image: Id,
+ bwd_ref_image: Id,
+ payload: Id,
+ },
+ SubgroupAvcSicEvaluateWithMultiReferenceINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ src_image: Id,
+ packed_reference_ids: Id,
+ payload: Id,
+ },
+ SubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ src_image: Id,
+ packed_reference_ids: Id,
+ packed_reference_field_polarities: Id,
+ payload: Id,
+ },
+ SubgroupAvcSicConvertToMceResultINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcSicGetIpeLumaShapeINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcSicGetBestIpeLumaDistortionINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcSicGetBestIpeChromaDistortionINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcSicGetPackedIpeLumaModesINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcSicGetIpeChromaModeINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ SubgroupAvcSicGetInterRawSadsINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ payload: Id,
+ },
+ VariableLengthArrayINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ lenght: Id,
+ },
+ SaveMemoryINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ },
+ RestoreMemoryINTEL {
+ ptr: Id,
+ },
+ ArbitraryFloatSinCosPiINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ mout: u32,
+ from_sign: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatCastINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatCastFromIntINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ mout: u32,
+ from_sign: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatCastToIntINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatAddINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ b: Id,
+ m2: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatSubINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ b: Id,
+ m2: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatMulINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ b: Id,
+ m2: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatDivINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ b: Id,
+ m2: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatGTINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ b: Id,
+ m2: u32,
+ },
+ ArbitraryFloatGEINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ b: Id,
+ m2: u32,
+ },
+ ArbitraryFloatLTINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ b: Id,
+ m2: u32,
+ },
+ ArbitraryFloatLEINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ b: Id,
+ m2: u32,
+ },
+ ArbitraryFloatEQINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ b: Id,
+ m2: u32,
+ },
+ ArbitraryFloatRecipINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatRSqrtINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatCbrtINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatHypotINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ b: Id,
+ m2: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatSqrtINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatLogINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatLog2INTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatLog10INTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatLog1pINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatExpINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatExp2INTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatExp10INTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatExpm1INTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatSinINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatCosINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatSinCosINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatSinPiINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatCosPiINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatASinINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatASinPiINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatACosINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatACosPiINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatATanINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatATanPiINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatATan2INTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ b: Id,
+ m2: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatPowINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ b: Id,
+ m2: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatPowRINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ b: Id,
+ m2: u32,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ ArbitraryFloatPowNINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ a: Id,
+ m1: u32,
+ b: Id,
+ mout: u32,
+ enable_subnormals: u32,
+ rounding_mode: u32,
+ rounding_accuracy: u32,
+ },
+ LoopControlINTEL {
+ loop_control_parameters: Vec<u32>,
+ },
+ FixedSqrtINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ input_type: Id,
+ input: Id,
+ s: u32,
+ i: u32,
+ r_i: u32,
+ q: u32,
+ o: u32,
+ },
+ FixedRecipINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ input_type: Id,
+ input: Id,
+ s: u32,
+ i: u32,
+ r_i: u32,
+ q: u32,
+ o: u32,
+ },
+ FixedRsqrtINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ input_type: Id,
+ input: Id,
+ s: u32,
+ i: u32,
+ r_i: u32,
+ q: u32,
+ o: u32,
+ },
+ FixedSinINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ input_type: Id,
+ input: Id,
+ s: u32,
+ i: u32,
+ r_i: u32,
+ q: u32,
+ o: u32,
+ },
+ FixedCosINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ input_type: Id,
+ input: Id,
+ s: u32,
+ i: u32,
+ r_i: u32,
+ q: u32,
+ o: u32,
+ },
+ FixedSinCosINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ input_type: Id,
+ input: Id,
+ s: u32,
+ i: u32,
+ r_i: u32,
+ q: u32,
+ o: u32,
+ },
+ FixedSinPiINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ input_type: Id,
+ input: Id,
+ s: u32,
+ i: u32,
+ r_i: u32,
+ q: u32,
+ o: u32,
+ },
+ FixedCosPiINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ input_type: Id,
+ input: Id,
+ s: u32,
+ i: u32,
+ r_i: u32,
+ q: u32,
+ o: u32,
+ },
+ FixedSinCosPiINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ input_type: Id,
+ input: Id,
+ s: u32,
+ i: u32,
+ r_i: u32,
+ q: u32,
+ o: u32,
+ },
+ FixedLogINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ input_type: Id,
+ input: Id,
+ s: u32,
+ i: u32,
+ r_i: u32,
+ q: u32,
+ o: u32,
+ },
+ FixedExpINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ input_type: Id,
+ input: Id,
+ s: u32,
+ i: u32,
+ r_i: u32,
+ q: u32,
+ o: u32,
+ },
+ PtrCastToCrossWorkgroupINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ pointer: Id,
+ },
+ CrossWorkgroupCastToPtrINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ pointer: Id,
+ },
+ ReadPipeBlockingINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ packet_size: Id,
+ packet_alignment: Id,
+ },
+ WritePipeBlockingINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ packet_size: Id,
+ packet_alignment: Id,
+ },
+ FPGARegINTEL {
+ result_type_id: Id,
+ result_id: Id,
+ result: Id,
+ input: Id,
+ },
+ RayQueryGetRayTMinKHR {
+ result_type_id: Id,
+ result_id: Id,
+ ray_query: Id,
+ },
+ RayQueryGetRayFlagsKHR {
+ result_type_id: Id,
+ result_id: Id,
+ ray_query: Id,
+ },
+ RayQueryGetIntersectionTKHR {
+ result_type_id: Id,
+ result_id: Id,
+ ray_query: Id,
+ intersection: Id,
+ },
+ RayQueryGetIntersectionInstanceCustomIndexKHR {
+ result_type_id: Id,
+ result_id: Id,
+ ray_query: Id,
+ intersection: Id,
+ },
+ RayQueryGetIntersectionInstanceIdKHR {
+ result_type_id: Id,
+ result_id: Id,
+ ray_query: Id,
+ intersection: Id,
+ },
+ RayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR {
+ result_type_id: Id,
+ result_id: Id,
+ ray_query: Id,
+ intersection: Id,
+ },
+ RayQueryGetIntersectionGeometryIndexKHR {
+ result_type_id: Id,
+ result_id: Id,
+ ray_query: Id,
+ intersection: Id,
+ },
+ RayQueryGetIntersectionPrimitiveIndexKHR {
+ result_type_id: Id,
+ result_id: Id,
+ ray_query: Id,
+ intersection: Id,
+ },
+ RayQueryGetIntersectionBarycentricsKHR {
+ result_type_id: Id,
+ result_id: Id,
+ ray_query: Id,
+ intersection: Id,
+ },
+ RayQueryGetIntersectionFrontFaceKHR {
+ result_type_id: Id,
+ result_id: Id,
+ ray_query: Id,
+ intersection: Id,
+ },
+ RayQueryGetIntersectionCandidateAABBOpaqueKHR {
+ result_type_id: Id,
+ result_id: Id,
+ ray_query: Id,
+ },
+ RayQueryGetIntersectionObjectRayDirectionKHR {
+ result_type_id: Id,
+ result_id: Id,
+ ray_query: Id,
+ intersection: Id,
+ },
+ RayQueryGetIntersectionObjectRayOriginKHR {
+ result_type_id: Id,
+ result_id: Id,
+ ray_query: Id,
+ intersection: Id,
+ },
+ RayQueryGetWorldRayDirectionKHR {
+ result_type_id: Id,
+ result_id: Id,
+ ray_query: Id,
+ },
+ RayQueryGetWorldRayOriginKHR {
+ result_type_id: Id,
+ result_id: Id,
+ ray_query: Id,
+ },
+ RayQueryGetIntersectionObjectToWorldKHR {
+ result_type_id: Id,
+ result_id: Id,
+ ray_query: Id,
+ intersection: Id,
+ },
+ RayQueryGetIntersectionWorldToObjectKHR {
+ result_type_id: Id,
+ result_id: Id,
+ ray_query: Id,
+ intersection: Id,
+ },
+ AtomicFAddEXT {
+ result_type_id: Id,
+ result_id: Id,
+ pointer: Id,
+ memory: Id,
+ semantics: Id,
+ value: Id,
+ },
+ TypeBufferSurfaceINTEL {
+ result_id: Id,
+ access_qualifier: AccessQualifier,
+ },
+ TypeStructContinuedINTEL {
+ member_types: Vec<Id>,
+ },
+ ConstantCompositeContinuedINTEL {
+ constituents: Vec<Id>,
+ },
+ SpecConstantCompositeContinuedINTEL {
+ constituents: Vec<Id>,
+ },
+}
+impl Instruction {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<Self, ParseError> {
+ let opcode = (reader.next_u32()? & 0xffff) as u16;
+ Ok(match opcode {
+ 0u16 => Self::Nop,
+ 1u16 => Self::Undef {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ },
+ 2u16 => Self::SourceContinued {
+ continued_source: reader.next_string()?,
+ },
+ 3u16 => Self::Source {
+ source_language: SourceLanguage::parse(reader)?,
+ version: reader.next_u32()?,
+ file: if !reader.is_empty() {
+ Some(Id(reader.next_u32()?))
+ } else {
+ None
+ },
+ source: if !reader.is_empty() {
+ Some(reader.next_string()?)
+ } else {
+ None
+ },
+ },
+ 4u16 => Self::SourceExtension {
+ extension: reader.next_string()?,
+ },
+ 5u16 => Self::Name {
+ target: Id(reader.next_u32()?),
+ name: reader.next_string()?,
+ },
+ 6u16 => Self::MemberName {
+ ty: Id(reader.next_u32()?),
+ member: reader.next_u32()?,
+ name: reader.next_string()?,
+ },
+ 7u16 => Self::String {
+ result_id: Id(reader.next_u32()?),
+ string: reader.next_string()?,
+ },
+ 8u16 => Self::Line {
+ file: Id(reader.next_u32()?),
+ line: reader.next_u32()?,
+ column: reader.next_u32()?,
+ },
+ 10u16 => Self::Extension {
+ name: reader.next_string()?,
+ },
+ 11u16 => Self::ExtInstImport {
+ result_id: Id(reader.next_u32()?),
+ name: reader.next_string()?,
+ },
+ 12u16 => Self::ExtInst {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ set: Id(reader.next_u32()?),
+ instruction: reader.next_u32()?,
+ operands: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(Id(reader.next_u32()?));
+ }
+ vec
+ },
+ },
+ 14u16 => Self::MemoryModel {
+ addressing_model: AddressingModel::parse(reader)?,
+ memory_model: MemoryModel::parse(reader)?,
+ },
+ 15u16 => Self::EntryPoint {
+ execution_model: ExecutionModel::parse(reader)?,
+ entry_point: Id(reader.next_u32()?),
+ name: reader.next_string()?,
+ interface: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(Id(reader.next_u32()?));
+ }
+ vec
+ },
+ },
+ 16u16 => Self::ExecutionMode {
+ entry_point: Id(reader.next_u32()?),
+ mode: ExecutionMode::parse(reader)?,
+ },
+ 17u16 => Self::Capability {
+ capability: Capability::parse(reader)?,
+ },
+ 19u16 => Self::TypeVoid {
+ result_id: Id(reader.next_u32()?),
+ },
+ 20u16 => Self::TypeBool {
+ result_id: Id(reader.next_u32()?),
+ },
+ 21u16 => Self::TypeInt {
+ result_id: Id(reader.next_u32()?),
+ width: reader.next_u32()?,
+ signedness: reader.next_u32()?,
+ },
+ 22u16 => Self::TypeFloat {
+ result_id: Id(reader.next_u32()?),
+ width: reader.next_u32()?,
+ },
+ 23u16 => Self::TypeVector {
+ result_id: Id(reader.next_u32()?),
+ component_type: Id(reader.next_u32()?),
+ component_count: reader.next_u32()?,
+ },
+ 24u16 => Self::TypeMatrix {
+ result_id: Id(reader.next_u32()?),
+ column_type: Id(reader.next_u32()?),
+ column_count: reader.next_u32()?,
+ },
+ 25u16 => Self::TypeImage {
+ result_id: Id(reader.next_u32()?),
+ sampled_type: Id(reader.next_u32()?),
+ dim: Dim::parse(reader)?,
+ depth: reader.next_u32()?,
+ arrayed: reader.next_u32()?,
+ ms: reader.next_u32()?,
+ sampled: reader.next_u32()?,
+ image_format: ImageFormat::parse(reader)?,
+ access_qualifier: if !reader.is_empty() {
+ Some(AccessQualifier::parse(reader)?)
+ } else {
+ None
+ },
+ },
+ 26u16 => Self::TypeSampler {
+ result_id: Id(reader.next_u32()?),
+ },
+ 27u16 => Self::TypeSampledImage {
+ result_id: Id(reader.next_u32()?),
+ image_type: Id(reader.next_u32()?),
+ },
+ 28u16 => Self::TypeArray {
+ result_id: Id(reader.next_u32()?),
+ element_type: Id(reader.next_u32()?),
+ length: Id(reader.next_u32()?),
+ },
+ 29u16 => Self::TypeRuntimeArray {
+ result_id: Id(reader.next_u32()?),
+ element_type: Id(reader.next_u32()?),
+ },
+ 30u16 => Self::TypeStruct {
+ result_id: Id(reader.next_u32()?),
+ member_types: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(Id(reader.next_u32()?));
+ }
+ vec
+ },
+ },
+ 31u16 => Self::TypeOpaque {
+ result_id: Id(reader.next_u32()?),
+ name: reader.next_string()?,
+ },
+ 32u16 => Self::TypePointer {
+ result_id: Id(reader.next_u32()?),
+ storage_class: StorageClass::parse(reader)?,
+ ty: Id(reader.next_u32()?),
+ },
+ 33u16 => Self::TypeFunction {
+ result_id: Id(reader.next_u32()?),
+ return_type: Id(reader.next_u32()?),
+ parameter_types: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(Id(reader.next_u32()?));
+ }
+ vec
+ },
+ },
+ 34u16 => Self::TypeEvent {
+ result_id: Id(reader.next_u32()?),
+ },
+ 35u16 => Self::TypeDeviceEvent {
+ result_id: Id(reader.next_u32()?),
+ },
+ 36u16 => Self::TypeReserveId {
+ result_id: Id(reader.next_u32()?),
+ },
+ 37u16 => Self::TypeQueue {
+ result_id: Id(reader.next_u32()?),
+ },
+ 38u16 => Self::TypePipe {
+ result_id: Id(reader.next_u32()?),
+ qualifier: AccessQualifier::parse(reader)?,
+ },
+ 39u16 => Self::TypeForwardPointer {
+ pointer_type: Id(reader.next_u32()?),
+ storage_class: StorageClass::parse(reader)?,
+ },
+ 41u16 => Self::ConstantTrue {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ },
+ 42u16 => Self::ConstantFalse {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ },
+ 43u16 => Self::Constant {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ value: reader.remainder(),
+ },
+ 44u16 => Self::ConstantComposite {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ constituents: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(Id(reader.next_u32()?));
+ }
+ vec
+ },
+ },
+ 45u16 => Self::ConstantSampler {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ sampler_addressing_mode: SamplerAddressingMode::parse(reader)?,
+ param: reader.next_u32()?,
+ sampler_filter_mode: SamplerFilterMode::parse(reader)?,
+ },
+ 46u16 => Self::ConstantNull {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ },
+ 48u16 => Self::SpecConstantTrue {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ },
+ 49u16 => Self::SpecConstantFalse {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ },
+ 50u16 => Self::SpecConstant {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ value: reader.remainder(),
+ },
+ 51u16 => Self::SpecConstantComposite {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ constituents: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(Id(reader.next_u32()?));
+ }
+ vec
+ },
+ },
+ 52u16 => Self::SpecConstantOp {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ opcode: SpecConstantInstruction::parse(reader)?,
+ },
+ 54u16 => Self::Function {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ function_control: FunctionControl::parse(reader)?,
+ function_type: Id(reader.next_u32()?),
+ },
+ 55u16 => Self::FunctionParameter {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ },
+ 56u16 => Self::FunctionEnd,
+ 57u16 => Self::FunctionCall {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ function: Id(reader.next_u32()?),
+ arguments: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(Id(reader.next_u32()?));
+ }
+ vec
+ },
+ },
+ 59u16 => Self::Variable {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ storage_class: StorageClass::parse(reader)?,
+ initializer: if !reader.is_empty() {
+ Some(Id(reader.next_u32()?))
+ } else {
+ None
+ },
+ },
+ 60u16 => Self::ImageTexelPointer {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ sample: Id(reader.next_u32()?),
+ },
+ 61u16 => Self::Load {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ memory_access: if !reader.is_empty() {
+ Some(MemoryAccess::parse(reader)?)
+ } else {
+ None
+ },
+ },
+ 62u16 => Self::Store {
+ pointer: Id(reader.next_u32()?),
+ object: Id(reader.next_u32()?),
+ memory_access: if !reader.is_empty() {
+ Some(MemoryAccess::parse(reader)?)
+ } else {
+ None
+ },
+ },
+ 63u16 => Self::CopyMemory {
+ target: Id(reader.next_u32()?),
+ source: Id(reader.next_u32()?),
+ memory_access1: if !reader.is_empty() {
+ Some(MemoryAccess::parse(reader)?)
+ } else {
+ None
+ },
+ memory_access2: if !reader.is_empty() {
+ Some(MemoryAccess::parse(reader)?)
+ } else {
+ None
+ },
+ },
+ 64u16 => Self::CopyMemorySized {
+ target: Id(reader.next_u32()?),
+ source: Id(reader.next_u32()?),
+ size: Id(reader.next_u32()?),
+ memory_access1: if !reader.is_empty() {
+ Some(MemoryAccess::parse(reader)?)
+ } else {
+ None
+ },
+ memory_access2: if !reader.is_empty() {
+ Some(MemoryAccess::parse(reader)?)
+ } else {
+ None
+ },
+ },
+ 65u16 => Self::AccessChain {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ base: Id(reader.next_u32()?),
+ indexes: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(Id(reader.next_u32()?));
+ }
+ vec
+ },
+ },
+ 66u16 => Self::InBoundsAccessChain {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ base: Id(reader.next_u32()?),
+ indexes: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(Id(reader.next_u32()?));
+ }
+ vec
+ },
+ },
+ 67u16 => Self::PtrAccessChain {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ base: Id(reader.next_u32()?),
+ element: Id(reader.next_u32()?),
+ indexes: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(Id(reader.next_u32()?));
+ }
+ vec
+ },
+ },
+ 68u16 => Self::ArrayLength {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ structure: Id(reader.next_u32()?),
+ array_member: reader.next_u32()?,
+ },
+ 69u16 => Self::GenericPtrMemSemantics {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ },
+ 70u16 => Self::InBoundsPtrAccessChain {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ base: Id(reader.next_u32()?),
+ element: Id(reader.next_u32()?),
+ indexes: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(Id(reader.next_u32()?));
+ }
+ vec
+ },
+ },
+ 71u16 => Self::Decorate {
+ target: Id(reader.next_u32()?),
+ decoration: Decoration::parse(reader)?,
+ },
+ 72u16 => Self::MemberDecorate {
+ structure_type: Id(reader.next_u32()?),
+ member: reader.next_u32()?,
+ decoration: Decoration::parse(reader)?,
+ },
+ 73u16 => Self::DecorationGroup {
+ result_id: Id(reader.next_u32()?),
+ },
+ 74u16 => Self::GroupDecorate {
+ decoration_group: Id(reader.next_u32()?),
+ targets: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(Id(reader.next_u32()?));
+ }
+ vec
+ },
+ },
+ 75u16 => Self::GroupMemberDecorate {
+ decoration_group: Id(reader.next_u32()?),
+ targets: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push((Id(reader.next_u32()?), reader.next_u32()?));
+ }
+ vec
+ },
+ },
+ 77u16 => Self::VectorExtractDynamic {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ vector: Id(reader.next_u32()?),
+ index: Id(reader.next_u32()?),
+ },
+ 78u16 => Self::VectorInsertDynamic {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ vector: Id(reader.next_u32()?),
+ component: Id(reader.next_u32()?),
+ index: Id(reader.next_u32()?),
+ },
+ 79u16 => Self::VectorShuffle {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ vector_1: Id(reader.next_u32()?),
+ vector_2: Id(reader.next_u32()?),
+ components: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(reader.next_u32()?);
+ }
+ vec
+ },
+ },
+ 80u16 => Self::CompositeConstruct {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ constituents: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(Id(reader.next_u32()?));
+ }
+ vec
+ },
+ },
+ 81u16 => Self::CompositeExtract {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ composite: Id(reader.next_u32()?),
+ indexes: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(reader.next_u32()?);
+ }
+ vec
+ },
+ },
+ 82u16 => Self::CompositeInsert {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ object: Id(reader.next_u32()?),
+ composite: Id(reader.next_u32()?),
+ indexes: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(reader.next_u32()?);
+ }
+ vec
+ },
+ },
+ 83u16 => Self::CopyObject {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand: Id(reader.next_u32()?),
+ },
+ 84u16 => Self::Transpose {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ matrix: Id(reader.next_u32()?),
+ },
+ 86u16 => Self::SampledImage {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ image: Id(reader.next_u32()?),
+ sampler: Id(reader.next_u32()?),
+ },
+ 87u16 => Self::ImageSampleImplicitLod {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ sampled_image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ image_operands: if !reader.is_empty() {
+ Some(ImageOperands::parse(reader)?)
+ } else {
+ None
+ },
+ },
+ 88u16 => Self::ImageSampleExplicitLod {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ sampled_image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ image_operands: ImageOperands::parse(reader)?,
+ },
+ 89u16 => Self::ImageSampleDrefImplicitLod {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ sampled_image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ dref: Id(reader.next_u32()?),
+ image_operands: if !reader.is_empty() {
+ Some(ImageOperands::parse(reader)?)
+ } else {
+ None
+ },
+ },
+ 90u16 => Self::ImageSampleDrefExplicitLod {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ sampled_image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ dref: Id(reader.next_u32()?),
+ image_operands: ImageOperands::parse(reader)?,
+ },
+ 91u16 => Self::ImageSampleProjImplicitLod {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ sampled_image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ image_operands: if !reader.is_empty() {
+ Some(ImageOperands::parse(reader)?)
+ } else {
+ None
+ },
+ },
+ 92u16 => Self::ImageSampleProjExplicitLod {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ sampled_image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ image_operands: ImageOperands::parse(reader)?,
+ },
+ 93u16 => Self::ImageSampleProjDrefImplicitLod {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ sampled_image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ dref: Id(reader.next_u32()?),
+ image_operands: if !reader.is_empty() {
+ Some(ImageOperands::parse(reader)?)
+ } else {
+ None
+ },
+ },
+ 94u16 => Self::ImageSampleProjDrefExplicitLod {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ sampled_image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ dref: Id(reader.next_u32()?),
+ image_operands: ImageOperands::parse(reader)?,
+ },
+ 95u16 => Self::ImageFetch {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ image_operands: if !reader.is_empty() {
+ Some(ImageOperands::parse(reader)?)
+ } else {
+ None
+ },
+ },
+ 96u16 => Self::ImageGather {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ sampled_image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ component: Id(reader.next_u32()?),
+ image_operands: if !reader.is_empty() {
+ Some(ImageOperands::parse(reader)?)
+ } else {
+ None
+ },
+ },
+ 97u16 => Self::ImageDrefGather {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ sampled_image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ dref: Id(reader.next_u32()?),
+ image_operands: if !reader.is_empty() {
+ Some(ImageOperands::parse(reader)?)
+ } else {
+ None
+ },
+ },
+ 98u16 => Self::ImageRead {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ image_operands: if !reader.is_empty() {
+ Some(ImageOperands::parse(reader)?)
+ } else {
+ None
+ },
+ },
+ 99u16 => Self::ImageWrite {
+ image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ texel: Id(reader.next_u32()?),
+ image_operands: if !reader.is_empty() {
+ Some(ImageOperands::parse(reader)?)
+ } else {
+ None
+ },
+ },
+ 100u16 => Self::Image {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ sampled_image: Id(reader.next_u32()?),
+ },
+ 101u16 => Self::ImageQueryFormat {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ image: Id(reader.next_u32()?),
+ },
+ 102u16 => Self::ImageQueryOrder {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ image: Id(reader.next_u32()?),
+ },
+ 103u16 => Self::ImageQuerySizeLod {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ image: Id(reader.next_u32()?),
+ level_of_detail: Id(reader.next_u32()?),
+ },
+ 104u16 => Self::ImageQuerySize {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ image: Id(reader.next_u32()?),
+ },
+ 105u16 => Self::ImageQueryLod {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ sampled_image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ },
+ 106u16 => Self::ImageQueryLevels {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ image: Id(reader.next_u32()?),
+ },
+ 107u16 => Self::ImageQuerySamples {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ image: Id(reader.next_u32()?),
+ },
+ 109u16 => Self::ConvertFToU {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ float_value: Id(reader.next_u32()?),
+ },
+ 110u16 => Self::ConvertFToS {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ float_value: Id(reader.next_u32()?),
+ },
+ 111u16 => Self::ConvertSToF {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ signed_value: Id(reader.next_u32()?),
+ },
+ 112u16 => Self::ConvertUToF {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ unsigned_value: Id(reader.next_u32()?),
+ },
+ 113u16 => Self::UConvert {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ unsigned_value: Id(reader.next_u32()?),
+ },
+ 114u16 => Self::SConvert {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ signed_value: Id(reader.next_u32()?),
+ },
+ 115u16 => Self::FConvert {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ float_value: Id(reader.next_u32()?),
+ },
+ 116u16 => Self::QuantizeToF16 {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ },
+ 117u16 => Self::ConvertPtrToU {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ },
+ 118u16 => Self::SatConvertSToU {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ signed_value: Id(reader.next_u32()?),
+ },
+ 119u16 => Self::SatConvertUToS {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ unsigned_value: Id(reader.next_u32()?),
+ },
+ 120u16 => Self::ConvertUToPtr {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ integer_value: Id(reader.next_u32()?),
+ },
+ 121u16 => Self::PtrCastToGeneric {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ },
+ 122u16 => Self::GenericCastToPtr {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ },
+ 123u16 => Self::GenericCastToPtrExplicit {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ storage: StorageClass::parse(reader)?,
+ },
+ 124u16 => Self::Bitcast {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand: Id(reader.next_u32()?),
+ },
+ 126u16 => Self::SNegate {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand: Id(reader.next_u32()?),
+ },
+ 127u16 => Self::FNegate {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand: Id(reader.next_u32()?),
+ },
+ 128u16 => Self::IAdd {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 129u16 => Self::FAdd {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 130u16 => Self::ISub {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 131u16 => Self::FSub {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 132u16 => Self::IMul {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 133u16 => Self::FMul {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 134u16 => Self::UDiv {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 135u16 => Self::SDiv {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 136u16 => Self::FDiv {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 137u16 => Self::UMod {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 138u16 => Self::SRem {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 139u16 => Self::SMod {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 140u16 => Self::FRem {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 141u16 => Self::FMod {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 142u16 => Self::VectorTimesScalar {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ vector: Id(reader.next_u32()?),
+ scalar: Id(reader.next_u32()?),
+ },
+ 143u16 => Self::MatrixTimesScalar {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ matrix: Id(reader.next_u32()?),
+ scalar: Id(reader.next_u32()?),
+ },
+ 144u16 => Self::VectorTimesMatrix {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ vector: Id(reader.next_u32()?),
+ matrix: Id(reader.next_u32()?),
+ },
+ 145u16 => Self::MatrixTimesVector {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ matrix: Id(reader.next_u32()?),
+ vector: Id(reader.next_u32()?),
+ },
+ 146u16 => Self::MatrixTimesMatrix {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ left_matrix: Id(reader.next_u32()?),
+ right_matrix: Id(reader.next_u32()?),
+ },
+ 147u16 => Self::OuterProduct {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ vector_1: Id(reader.next_u32()?),
+ vector_2: Id(reader.next_u32()?),
+ },
+ 148u16 => Self::Dot {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ vector_1: Id(reader.next_u32()?),
+ vector_2: Id(reader.next_u32()?),
+ },
+ 149u16 => Self::IAddCarry {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 150u16 => Self::ISubBorrow {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 151u16 => Self::UMulExtended {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 152u16 => Self::SMulExtended {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 154u16 => Self::Any {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ vector: Id(reader.next_u32()?),
+ },
+ 155u16 => Self::All {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ vector: Id(reader.next_u32()?),
+ },
+ 156u16 => Self::IsNan {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ x: Id(reader.next_u32()?),
+ },
+ 157u16 => Self::IsInf {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ x: Id(reader.next_u32()?),
+ },
+ 158u16 => Self::IsFinite {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ x: Id(reader.next_u32()?),
+ },
+ 159u16 => Self::IsNormal {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ x: Id(reader.next_u32()?),
+ },
+ 160u16 => Self::SignBitSet {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ x: Id(reader.next_u32()?),
+ },
+ 161u16 => Self::LessOrGreater {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ x: Id(reader.next_u32()?),
+ y: Id(reader.next_u32()?),
+ },
+ 162u16 => Self::Ordered {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ x: Id(reader.next_u32()?),
+ y: Id(reader.next_u32()?),
+ },
+ 163u16 => Self::Unordered {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ x: Id(reader.next_u32()?),
+ y: Id(reader.next_u32()?),
+ },
+ 164u16 => Self::LogicalEqual {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 165u16 => Self::LogicalNotEqual {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 166u16 => Self::LogicalOr {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 167u16 => Self::LogicalAnd {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 168u16 => Self::LogicalNot {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand: Id(reader.next_u32()?),
+ },
+ 169u16 => Self::Select {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ condition: Id(reader.next_u32()?),
+ object_1: Id(reader.next_u32()?),
+ object_2: Id(reader.next_u32()?),
+ },
+ 170u16 => Self::IEqual {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 171u16 => Self::INotEqual {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 172u16 => Self::UGreaterThan {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 173u16 => Self::SGreaterThan {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 174u16 => Self::UGreaterThanEqual {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 175u16 => Self::SGreaterThanEqual {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 176u16 => Self::ULessThan {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 177u16 => Self::SLessThan {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 178u16 => Self::ULessThanEqual {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 179u16 => Self::SLessThanEqual {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 180u16 => Self::FOrdEqual {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 181u16 => Self::FUnordEqual {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 182u16 => Self::FOrdNotEqual {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 183u16 => Self::FUnordNotEqual {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 184u16 => Self::FOrdLessThan {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 185u16 => Self::FUnordLessThan {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 186u16 => Self::FOrdGreaterThan {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 187u16 => Self::FUnordGreaterThan {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 188u16 => Self::FOrdLessThanEqual {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 189u16 => Self::FUnordLessThanEqual {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 190u16 => Self::FOrdGreaterThanEqual {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 191u16 => Self::FUnordGreaterThanEqual {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 194u16 => Self::ShiftRightLogical {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ base: Id(reader.next_u32()?),
+ shift: Id(reader.next_u32()?),
+ },
+ 195u16 => Self::ShiftRightArithmetic {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ base: Id(reader.next_u32()?),
+ shift: Id(reader.next_u32()?),
+ },
+ 196u16 => Self::ShiftLeftLogical {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ base: Id(reader.next_u32()?),
+ shift: Id(reader.next_u32()?),
+ },
+ 197u16 => Self::BitwiseOr {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 198u16 => Self::BitwiseXor {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 199u16 => Self::BitwiseAnd {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 200u16 => Self::Not {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand: Id(reader.next_u32()?),
+ },
+ 201u16 => Self::BitFieldInsert {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ base: Id(reader.next_u32()?),
+ insert: Id(reader.next_u32()?),
+ offset: Id(reader.next_u32()?),
+ count: Id(reader.next_u32()?),
+ },
+ 202u16 => Self::BitFieldSExtract {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ base: Id(reader.next_u32()?),
+ offset: Id(reader.next_u32()?),
+ count: Id(reader.next_u32()?),
+ },
+ 203u16 => Self::BitFieldUExtract {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ base: Id(reader.next_u32()?),
+ offset: Id(reader.next_u32()?),
+ count: Id(reader.next_u32()?),
+ },
+ 204u16 => Self::BitReverse {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ base: Id(reader.next_u32()?),
+ },
+ 205u16 => Self::BitCount {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ base: Id(reader.next_u32()?),
+ },
+ 207u16 => Self::DPdx {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ p: Id(reader.next_u32()?),
+ },
+ 208u16 => Self::DPdy {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ p: Id(reader.next_u32()?),
+ },
+ 209u16 => Self::Fwidth {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ p: Id(reader.next_u32()?),
+ },
+ 210u16 => Self::DPdxFine {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ p: Id(reader.next_u32()?),
+ },
+ 211u16 => Self::DPdyFine {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ p: Id(reader.next_u32()?),
+ },
+ 212u16 => Self::FwidthFine {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ p: Id(reader.next_u32()?),
+ },
+ 213u16 => Self::DPdxCoarse {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ p: Id(reader.next_u32()?),
+ },
+ 214u16 => Self::DPdyCoarse {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ p: Id(reader.next_u32()?),
+ },
+ 215u16 => Self::FwidthCoarse {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ p: Id(reader.next_u32()?),
+ },
+ 218u16 => Self::EmitVertex,
+ 219u16 => Self::EndPrimitive,
+ 220u16 => Self::EmitStreamVertex {
+ stream: Id(reader.next_u32()?),
+ },
+ 221u16 => Self::EndStreamPrimitive {
+ stream: Id(reader.next_u32()?),
+ },
+ 224u16 => Self::ControlBarrier {
+ execution: Id(reader.next_u32()?),
+ memory: Id(reader.next_u32()?),
+ semantics: Id(reader.next_u32()?),
+ },
+ 225u16 => Self::MemoryBarrier {
+ memory: Id(reader.next_u32()?),
+ semantics: Id(reader.next_u32()?),
+ },
+ 227u16 => Self::AtomicLoad {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ memory: Id(reader.next_u32()?),
+ semantics: Id(reader.next_u32()?),
+ },
+ 228u16 => Self::AtomicStore {
+ pointer: Id(reader.next_u32()?),
+ memory: Id(reader.next_u32()?),
+ semantics: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ },
+ 229u16 => Self::AtomicExchange {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ memory: Id(reader.next_u32()?),
+ semantics: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ },
+ 230u16 => Self::AtomicCompareExchange {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ memory: Id(reader.next_u32()?),
+ equal: Id(reader.next_u32()?),
+ unequal: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ comparator: Id(reader.next_u32()?),
+ },
+ 231u16 => Self::AtomicCompareExchangeWeak {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ memory: Id(reader.next_u32()?),
+ equal: Id(reader.next_u32()?),
+ unequal: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ comparator: Id(reader.next_u32()?),
+ },
+ 232u16 => Self::AtomicIIncrement {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ memory: Id(reader.next_u32()?),
+ semantics: Id(reader.next_u32()?),
+ },
+ 233u16 => Self::AtomicIDecrement {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ memory: Id(reader.next_u32()?),
+ semantics: Id(reader.next_u32()?),
+ },
+ 234u16 => Self::AtomicIAdd {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ memory: Id(reader.next_u32()?),
+ semantics: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ },
+ 235u16 => Self::AtomicISub {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ memory: Id(reader.next_u32()?),
+ semantics: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ },
+ 236u16 => Self::AtomicSMin {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ memory: Id(reader.next_u32()?),
+ semantics: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ },
+ 237u16 => Self::AtomicUMin {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ memory: Id(reader.next_u32()?),
+ semantics: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ },
+ 238u16 => Self::AtomicSMax {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ memory: Id(reader.next_u32()?),
+ semantics: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ },
+ 239u16 => Self::AtomicUMax {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ memory: Id(reader.next_u32()?),
+ semantics: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ },
+ 240u16 => Self::AtomicAnd {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ memory: Id(reader.next_u32()?),
+ semantics: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ },
+ 241u16 => Self::AtomicOr {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ memory: Id(reader.next_u32()?),
+ semantics: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ },
+ 242u16 => Self::AtomicXor {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ memory: Id(reader.next_u32()?),
+ semantics: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ },
+ 245u16 => Self::Phi {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ variable_parent: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push((Id(reader.next_u32()?), Id(reader.next_u32()?)));
+ }
+ vec
+ },
+ },
+ 246u16 => Self::LoopMerge {
+ merge_block: Id(reader.next_u32()?),
+ continue_target: Id(reader.next_u32()?),
+ loop_control: LoopControl::parse(reader)?,
+ },
+ 247u16 => Self::SelectionMerge {
+ merge_block: Id(reader.next_u32()?),
+ selection_control: SelectionControl::parse(reader)?,
+ },
+ 248u16 => Self::Label {
+ result_id: Id(reader.next_u32()?),
+ },
+ 249u16 => Self::Branch {
+ target_label: Id(reader.next_u32()?),
+ },
+ 250u16 => Self::BranchConditional {
+ condition: Id(reader.next_u32()?),
+ true_label: Id(reader.next_u32()?),
+ false_label: Id(reader.next_u32()?),
+ branch_weights: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(reader.next_u32()?);
+ }
+ vec
+ },
+ },
+ 251u16 => Self::Switch {
+ selector: Id(reader.next_u32()?),
+ default: Id(reader.next_u32()?),
+ target: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push((reader.next_u32()?, Id(reader.next_u32()?)));
+ }
+ vec
+ },
+ },
+ 252u16 => Self::Kill,
+ 253u16 => Self::Return,
+ 254u16 => Self::ReturnValue {
+ value: Id(reader.next_u32()?),
+ },
+ 255u16 => Self::Unreachable,
+ 256u16 => Self::LifetimeStart {
+ pointer: Id(reader.next_u32()?),
+ size: reader.next_u32()?,
+ },
+ 257u16 => Self::LifetimeStop {
+ pointer: Id(reader.next_u32()?),
+ size: reader.next_u32()?,
+ },
+ 259u16 => Self::GroupAsyncCopy {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ destination: Id(reader.next_u32()?),
+ source: Id(reader.next_u32()?),
+ num_elements: Id(reader.next_u32()?),
+ stride: Id(reader.next_u32()?),
+ event: Id(reader.next_u32()?),
+ },
+ 260u16 => Self::GroupWaitEvents {
+ execution: Id(reader.next_u32()?),
+ num_events: Id(reader.next_u32()?),
+ events_list: Id(reader.next_u32()?),
+ },
+ 261u16 => Self::GroupAll {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ predicate: Id(reader.next_u32()?),
+ },
+ 262u16 => Self::GroupAny {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ predicate: Id(reader.next_u32()?),
+ },
+ 263u16 => Self::GroupBroadcast {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ local_id: Id(reader.next_u32()?),
+ },
+ 264u16 => Self::GroupIAdd {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ x: Id(reader.next_u32()?),
+ },
+ 265u16 => Self::GroupFAdd {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ x: Id(reader.next_u32()?),
+ },
+ 266u16 => Self::GroupFMin {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ x: Id(reader.next_u32()?),
+ },
+ 267u16 => Self::GroupUMin {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ x: Id(reader.next_u32()?),
+ },
+ 268u16 => Self::GroupSMin {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ x: Id(reader.next_u32()?),
+ },
+ 269u16 => Self::GroupFMax {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ x: Id(reader.next_u32()?),
+ },
+ 270u16 => Self::GroupUMax {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ x: Id(reader.next_u32()?),
+ },
+ 271u16 => Self::GroupSMax {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ x: Id(reader.next_u32()?),
+ },
+ 274u16 => Self::ReadPipe {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pipe: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ packet_size: Id(reader.next_u32()?),
+ packet_alignment: Id(reader.next_u32()?),
+ },
+ 275u16 => Self::WritePipe {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pipe: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ packet_size: Id(reader.next_u32()?),
+ packet_alignment: Id(reader.next_u32()?),
+ },
+ 276u16 => Self::ReservedReadPipe {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pipe: Id(reader.next_u32()?),
+ reserve_id: Id(reader.next_u32()?),
+ index: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ packet_size: Id(reader.next_u32()?),
+ packet_alignment: Id(reader.next_u32()?),
+ },
+ 277u16 => Self::ReservedWritePipe {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pipe: Id(reader.next_u32()?),
+ reserve_id: Id(reader.next_u32()?),
+ index: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ packet_size: Id(reader.next_u32()?),
+ packet_alignment: Id(reader.next_u32()?),
+ },
+ 278u16 => Self::ReserveReadPipePackets {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pipe: Id(reader.next_u32()?),
+ num_packets: Id(reader.next_u32()?),
+ packet_size: Id(reader.next_u32()?),
+ packet_alignment: Id(reader.next_u32()?),
+ },
+ 279u16 => Self::ReserveWritePipePackets {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pipe: Id(reader.next_u32()?),
+ num_packets: Id(reader.next_u32()?),
+ packet_size: Id(reader.next_u32()?),
+ packet_alignment: Id(reader.next_u32()?),
+ },
+ 280u16 => Self::CommitReadPipe {
+ pipe: Id(reader.next_u32()?),
+ reserve_id: Id(reader.next_u32()?),
+ packet_size: Id(reader.next_u32()?),
+ packet_alignment: Id(reader.next_u32()?),
+ },
+ 281u16 => Self::CommitWritePipe {
+ pipe: Id(reader.next_u32()?),
+ reserve_id: Id(reader.next_u32()?),
+ packet_size: Id(reader.next_u32()?),
+ packet_alignment: Id(reader.next_u32()?),
+ },
+ 282u16 => Self::IsValidReserveId {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ reserve_id: Id(reader.next_u32()?),
+ },
+ 283u16 => Self::GetNumPipePackets {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pipe: Id(reader.next_u32()?),
+ packet_size: Id(reader.next_u32()?),
+ packet_alignment: Id(reader.next_u32()?),
+ },
+ 284u16 => Self::GetMaxPipePackets {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pipe: Id(reader.next_u32()?),
+ packet_size: Id(reader.next_u32()?),
+ packet_alignment: Id(reader.next_u32()?),
+ },
+ 285u16 => Self::GroupReserveReadPipePackets {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ pipe: Id(reader.next_u32()?),
+ num_packets: Id(reader.next_u32()?),
+ packet_size: Id(reader.next_u32()?),
+ packet_alignment: Id(reader.next_u32()?),
+ },
+ 286u16 => Self::GroupReserveWritePipePackets {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ pipe: Id(reader.next_u32()?),
+ num_packets: Id(reader.next_u32()?),
+ packet_size: Id(reader.next_u32()?),
+ packet_alignment: Id(reader.next_u32()?),
+ },
+ 287u16 => Self::GroupCommitReadPipe {
+ execution: Id(reader.next_u32()?),
+ pipe: Id(reader.next_u32()?),
+ reserve_id: Id(reader.next_u32()?),
+ packet_size: Id(reader.next_u32()?),
+ packet_alignment: Id(reader.next_u32()?),
+ },
+ 288u16 => Self::GroupCommitWritePipe {
+ execution: Id(reader.next_u32()?),
+ pipe: Id(reader.next_u32()?),
+ reserve_id: Id(reader.next_u32()?),
+ packet_size: Id(reader.next_u32()?),
+ packet_alignment: Id(reader.next_u32()?),
+ },
+ 291u16 => Self::EnqueueMarker {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ queue: Id(reader.next_u32()?),
+ num_events: Id(reader.next_u32()?),
+ wait_events: Id(reader.next_u32()?),
+ ret_event: Id(reader.next_u32()?),
+ },
+ 292u16 => Self::EnqueueKernel {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ queue: Id(reader.next_u32()?),
+ flags: Id(reader.next_u32()?),
+ nd_range: Id(reader.next_u32()?),
+ num_events: Id(reader.next_u32()?),
+ wait_events: Id(reader.next_u32()?),
+ ret_event: Id(reader.next_u32()?),
+ invoke: Id(reader.next_u32()?),
+ param: Id(reader.next_u32()?),
+ param_size: Id(reader.next_u32()?),
+ param_align: Id(reader.next_u32()?),
+ local_size: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(Id(reader.next_u32()?));
+ }
+ vec
+ },
+ },
+ 293u16 => Self::GetKernelNDrangeSubGroupCount {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ nd_range: Id(reader.next_u32()?),
+ invoke: Id(reader.next_u32()?),
+ param: Id(reader.next_u32()?),
+ param_size: Id(reader.next_u32()?),
+ param_align: Id(reader.next_u32()?),
+ },
+ 294u16 => Self::GetKernelNDrangeMaxSubGroupSize {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ nd_range: Id(reader.next_u32()?),
+ invoke: Id(reader.next_u32()?),
+ param: Id(reader.next_u32()?),
+ param_size: Id(reader.next_u32()?),
+ param_align: Id(reader.next_u32()?),
+ },
+ 295u16 => Self::GetKernelWorkGroupSize {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ invoke: Id(reader.next_u32()?),
+ param: Id(reader.next_u32()?),
+ param_size: Id(reader.next_u32()?),
+ param_align: Id(reader.next_u32()?),
+ },
+ 296u16 => Self::GetKernelPreferredWorkGroupSizeMultiple {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ invoke: Id(reader.next_u32()?),
+ param: Id(reader.next_u32()?),
+ param_size: Id(reader.next_u32()?),
+ param_align: Id(reader.next_u32()?),
+ },
+ 297u16 => Self::RetainEvent {
+ event: Id(reader.next_u32()?),
+ },
+ 298u16 => Self::ReleaseEvent {
+ event: Id(reader.next_u32()?),
+ },
+ 299u16 => Self::CreateUserEvent {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ },
+ 300u16 => Self::IsValidEvent {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ event: Id(reader.next_u32()?),
+ },
+ 301u16 => Self::SetUserEventStatus {
+ event: Id(reader.next_u32()?),
+ status: Id(reader.next_u32()?),
+ },
+ 302u16 => Self::CaptureEventProfilingInfo {
+ event: Id(reader.next_u32()?),
+ profiling_info: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ },
+ 303u16 => Self::GetDefaultQueue {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ },
+ 304u16 => Self::BuildNDRange {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ global_work_size: Id(reader.next_u32()?),
+ local_work_size: Id(reader.next_u32()?),
+ global_work_offset: Id(reader.next_u32()?),
+ },
+ 305u16 => Self::ImageSparseSampleImplicitLod {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ sampled_image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ image_operands: if !reader.is_empty() {
+ Some(ImageOperands::parse(reader)?)
+ } else {
+ None
+ },
+ },
+ 306u16 => Self::ImageSparseSampleExplicitLod {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ sampled_image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ image_operands: ImageOperands::parse(reader)?,
+ },
+ 307u16 => Self::ImageSparseSampleDrefImplicitLod {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ sampled_image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ dref: Id(reader.next_u32()?),
+ image_operands: if !reader.is_empty() {
+ Some(ImageOperands::parse(reader)?)
+ } else {
+ None
+ },
+ },
+ 308u16 => Self::ImageSparseSampleDrefExplicitLod {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ sampled_image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ dref: Id(reader.next_u32()?),
+ image_operands: ImageOperands::parse(reader)?,
+ },
+ 309u16 => Self::ImageSparseSampleProjImplicitLod {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ sampled_image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ image_operands: if !reader.is_empty() {
+ Some(ImageOperands::parse(reader)?)
+ } else {
+ None
+ },
+ },
+ 310u16 => Self::ImageSparseSampleProjExplicitLod {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ sampled_image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ image_operands: ImageOperands::parse(reader)?,
+ },
+ 311u16 => Self::ImageSparseSampleProjDrefImplicitLod {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ sampled_image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ dref: Id(reader.next_u32()?),
+ image_operands: if !reader.is_empty() {
+ Some(ImageOperands::parse(reader)?)
+ } else {
+ None
+ },
+ },
+ 312u16 => Self::ImageSparseSampleProjDrefExplicitLod {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ sampled_image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ dref: Id(reader.next_u32()?),
+ image_operands: ImageOperands::parse(reader)?,
+ },
+ 313u16 => Self::ImageSparseFetch {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ image_operands: if !reader.is_empty() {
+ Some(ImageOperands::parse(reader)?)
+ } else {
+ None
+ },
+ },
+ 314u16 => Self::ImageSparseGather {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ sampled_image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ component: Id(reader.next_u32()?),
+ image_operands: if !reader.is_empty() {
+ Some(ImageOperands::parse(reader)?)
+ } else {
+ None
+ },
+ },
+ 315u16 => Self::ImageSparseDrefGather {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ sampled_image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ dref: Id(reader.next_u32()?),
+ image_operands: if !reader.is_empty() {
+ Some(ImageOperands::parse(reader)?)
+ } else {
+ None
+ },
+ },
+ 316u16 => Self::ImageSparseTexelsResident {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ resident_code: Id(reader.next_u32()?),
+ },
+ 317u16 => Self::NoLine,
+ 318u16 => Self::AtomicFlagTestAndSet {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ memory: Id(reader.next_u32()?),
+ semantics: Id(reader.next_u32()?),
+ },
+ 319u16 => Self::AtomicFlagClear {
+ pointer: Id(reader.next_u32()?),
+ memory: Id(reader.next_u32()?),
+ semantics: Id(reader.next_u32()?),
+ },
+ 320u16 => Self::ImageSparseRead {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ image_operands: if !reader.is_empty() {
+ Some(ImageOperands::parse(reader)?)
+ } else {
+ None
+ },
+ },
+ 321u16 => Self::SizeOf {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ },
+ 322u16 => Self::TypePipeStorage {
+ result_id: Id(reader.next_u32()?),
+ },
+ 323u16 => Self::ConstantPipeStorage {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ packet_size: reader.next_u32()?,
+ packet_alignment: reader.next_u32()?,
+ capacity: reader.next_u32()?,
+ },
+ 324u16 => Self::CreatePipeFromPipeStorage {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pipe_storage: Id(reader.next_u32()?),
+ },
+ 325u16 => Self::GetKernelLocalSizeForSubgroupCount {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ subgroup_count: Id(reader.next_u32()?),
+ invoke: Id(reader.next_u32()?),
+ param: Id(reader.next_u32()?),
+ param_size: Id(reader.next_u32()?),
+ param_align: Id(reader.next_u32()?),
+ },
+ 326u16 => Self::GetKernelMaxNumSubgroups {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ invoke: Id(reader.next_u32()?),
+ param: Id(reader.next_u32()?),
+ param_size: Id(reader.next_u32()?),
+ param_align: Id(reader.next_u32()?),
+ },
+ 327u16 => Self::TypeNamedBarrier {
+ result_id: Id(reader.next_u32()?),
+ },
+ 328u16 => Self::NamedBarrierInitialize {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ subgroup_count: Id(reader.next_u32()?),
+ },
+ 329u16 => Self::MemoryNamedBarrier {
+ named_barrier: Id(reader.next_u32()?),
+ memory: Id(reader.next_u32()?),
+ semantics: Id(reader.next_u32()?),
+ },
+ 330u16 => Self::ModuleProcessed {
+ process: reader.next_string()?,
+ },
+ 331u16 => Self::ExecutionModeId {
+ entry_point: Id(reader.next_u32()?),
+ mode: ExecutionMode::parse(reader)?,
+ },
+ 332u16 => Self::DecorateId {
+ target: Id(reader.next_u32()?),
+ decoration: Decoration::parse(reader)?,
+ },
+ 333u16 => Self::GroupNonUniformElect {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ },
+ 334u16 => Self::GroupNonUniformAll {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ predicate: Id(reader.next_u32()?),
+ },
+ 335u16 => Self::GroupNonUniformAny {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ predicate: Id(reader.next_u32()?),
+ },
+ 336u16 => Self::GroupNonUniformAllEqual {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ },
+ 337u16 => Self::GroupNonUniformBroadcast {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ id: Id(reader.next_u32()?),
+ },
+ 338u16 => Self::GroupNonUniformBroadcastFirst {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ },
+ 339u16 => Self::GroupNonUniformBallot {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ predicate: Id(reader.next_u32()?),
+ },
+ 340u16 => Self::GroupNonUniformInverseBallot {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ },
+ 341u16 => Self::GroupNonUniformBallotBitExtract {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ index: Id(reader.next_u32()?),
+ },
+ 342u16 => Self::GroupNonUniformBallotBitCount {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ value: Id(reader.next_u32()?),
+ },
+ 343u16 => Self::GroupNonUniformBallotFindLSB {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ },
+ 344u16 => Self::GroupNonUniformBallotFindMSB {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ },
+ 345u16 => Self::GroupNonUniformShuffle {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ id: Id(reader.next_u32()?),
+ },
+ 346u16 => Self::GroupNonUniformShuffleXor {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ mask: Id(reader.next_u32()?),
+ },
+ 347u16 => Self::GroupNonUniformShuffleUp {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ delta: Id(reader.next_u32()?),
+ },
+ 348u16 => Self::GroupNonUniformShuffleDown {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ delta: Id(reader.next_u32()?),
+ },
+ 349u16 => Self::GroupNonUniformIAdd {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ value: Id(reader.next_u32()?),
+ cluster_size: if !reader.is_empty() {
+ Some(Id(reader.next_u32()?))
+ } else {
+ None
+ },
+ },
+ 350u16 => Self::GroupNonUniformFAdd {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ value: Id(reader.next_u32()?),
+ cluster_size: if !reader.is_empty() {
+ Some(Id(reader.next_u32()?))
+ } else {
+ None
+ },
+ },
+ 351u16 => Self::GroupNonUniformIMul {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ value: Id(reader.next_u32()?),
+ cluster_size: if !reader.is_empty() {
+ Some(Id(reader.next_u32()?))
+ } else {
+ None
+ },
+ },
+ 352u16 => Self::GroupNonUniformFMul {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ value: Id(reader.next_u32()?),
+ cluster_size: if !reader.is_empty() {
+ Some(Id(reader.next_u32()?))
+ } else {
+ None
+ },
+ },
+ 353u16 => Self::GroupNonUniformSMin {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ value: Id(reader.next_u32()?),
+ cluster_size: if !reader.is_empty() {
+ Some(Id(reader.next_u32()?))
+ } else {
+ None
+ },
+ },
+ 354u16 => Self::GroupNonUniformUMin {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ value: Id(reader.next_u32()?),
+ cluster_size: if !reader.is_empty() {
+ Some(Id(reader.next_u32()?))
+ } else {
+ None
+ },
+ },
+ 355u16 => Self::GroupNonUniformFMin {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ value: Id(reader.next_u32()?),
+ cluster_size: if !reader.is_empty() {
+ Some(Id(reader.next_u32()?))
+ } else {
+ None
+ },
+ },
+ 356u16 => Self::GroupNonUniformSMax {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ value: Id(reader.next_u32()?),
+ cluster_size: if !reader.is_empty() {
+ Some(Id(reader.next_u32()?))
+ } else {
+ None
+ },
+ },
+ 357u16 => Self::GroupNonUniformUMax {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ value: Id(reader.next_u32()?),
+ cluster_size: if !reader.is_empty() {
+ Some(Id(reader.next_u32()?))
+ } else {
+ None
+ },
+ },
+ 358u16 => Self::GroupNonUniformFMax {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ value: Id(reader.next_u32()?),
+ cluster_size: if !reader.is_empty() {
+ Some(Id(reader.next_u32()?))
+ } else {
+ None
+ },
+ },
+ 359u16 => Self::GroupNonUniformBitwiseAnd {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ value: Id(reader.next_u32()?),
+ cluster_size: if !reader.is_empty() {
+ Some(Id(reader.next_u32()?))
+ } else {
+ None
+ },
+ },
+ 360u16 => Self::GroupNonUniformBitwiseOr {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ value: Id(reader.next_u32()?),
+ cluster_size: if !reader.is_empty() {
+ Some(Id(reader.next_u32()?))
+ } else {
+ None
+ },
+ },
+ 361u16 => Self::GroupNonUniformBitwiseXor {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ value: Id(reader.next_u32()?),
+ cluster_size: if !reader.is_empty() {
+ Some(Id(reader.next_u32()?))
+ } else {
+ None
+ },
+ },
+ 362u16 => Self::GroupNonUniformLogicalAnd {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ value: Id(reader.next_u32()?),
+ cluster_size: if !reader.is_empty() {
+ Some(Id(reader.next_u32()?))
+ } else {
+ None
+ },
+ },
+ 363u16 => Self::GroupNonUniformLogicalOr {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ value: Id(reader.next_u32()?),
+ cluster_size: if !reader.is_empty() {
+ Some(Id(reader.next_u32()?))
+ } else {
+ None
+ },
+ },
+ 364u16 => Self::GroupNonUniformLogicalXor {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ value: Id(reader.next_u32()?),
+ cluster_size: if !reader.is_empty() {
+ Some(Id(reader.next_u32()?))
+ } else {
+ None
+ },
+ },
+ 365u16 => Self::GroupNonUniformQuadBroadcast {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ index: Id(reader.next_u32()?),
+ },
+ 366u16 => Self::GroupNonUniformQuadSwap {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ direction: Id(reader.next_u32()?),
+ },
+ 400u16 => Self::CopyLogical {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand: Id(reader.next_u32()?),
+ },
+ 401u16 => Self::PtrEqual {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 402u16 => Self::PtrNotEqual {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 403u16 => Self::PtrDiff {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 4416u16 => Self::TerminateInvocation,
+ 4421u16 => Self::SubgroupBallotKHR {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ predicate: Id(reader.next_u32()?),
+ },
+ 4422u16 => Self::SubgroupFirstInvocationKHR {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ },
+ 4428u16 => Self::SubgroupAllKHR {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ predicate: Id(reader.next_u32()?),
+ },
+ 4429u16 => Self::SubgroupAnyKHR {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ predicate: Id(reader.next_u32()?),
+ },
+ 4430u16 => Self::SubgroupAllEqualKHR {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ predicate: Id(reader.next_u32()?),
+ },
+ 4432u16 => Self::SubgroupReadInvocationKHR {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ index: Id(reader.next_u32()?),
+ },
+ 4445u16 => Self::TraceRayKHR {
+ accel: Id(reader.next_u32()?),
+ ray_flags: Id(reader.next_u32()?),
+ cull_mask: Id(reader.next_u32()?),
+ sbt_offset: Id(reader.next_u32()?),
+ sbt_stride: Id(reader.next_u32()?),
+ miss_index: Id(reader.next_u32()?),
+ ray_origin: Id(reader.next_u32()?),
+ ray_tmin: Id(reader.next_u32()?),
+ ray_direction: Id(reader.next_u32()?),
+ ray_tmax: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 4446u16 => Self::ExecuteCallableKHR {
+ sbt_index: Id(reader.next_u32()?),
+ callable_data: Id(reader.next_u32()?),
+ },
+ 4447u16 => Self::ConvertUToAccelerationStructureKHR {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ accel: Id(reader.next_u32()?),
+ },
+ 4448u16 => Self::IgnoreIntersectionKHR,
+ 4449u16 => Self::TerminateRayKHR,
+ 4450u16 => Self::SDot {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ vector_1: Id(reader.next_u32()?),
+ vector_2: Id(reader.next_u32()?),
+ packed_vector_format: if !reader.is_empty() {
+ Some(PackedVectorFormat::parse(reader)?)
+ } else {
+ None
+ },
+ },
+ 4451u16 => Self::UDot {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ vector_1: Id(reader.next_u32()?),
+ vector_2: Id(reader.next_u32()?),
+ packed_vector_format: if !reader.is_empty() {
+ Some(PackedVectorFormat::parse(reader)?)
+ } else {
+ None
+ },
+ },
+ 4452u16 => Self::SUDot {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ vector_1: Id(reader.next_u32()?),
+ vector_2: Id(reader.next_u32()?),
+ packed_vector_format: if !reader.is_empty() {
+ Some(PackedVectorFormat::parse(reader)?)
+ } else {
+ None
+ },
+ },
+ 4453u16 => Self::SDotAccSat {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ vector_1: Id(reader.next_u32()?),
+ vector_2: Id(reader.next_u32()?),
+ accumulator: Id(reader.next_u32()?),
+ packed_vector_format: if !reader.is_empty() {
+ Some(PackedVectorFormat::parse(reader)?)
+ } else {
+ None
+ },
+ },
+ 4454u16 => Self::UDotAccSat {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ vector_1: Id(reader.next_u32()?),
+ vector_2: Id(reader.next_u32()?),
+ accumulator: Id(reader.next_u32()?),
+ packed_vector_format: if !reader.is_empty() {
+ Some(PackedVectorFormat::parse(reader)?)
+ } else {
+ None
+ },
+ },
+ 4455u16 => Self::SUDotAccSat {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ vector_1: Id(reader.next_u32()?),
+ vector_2: Id(reader.next_u32()?),
+ accumulator: Id(reader.next_u32()?),
+ packed_vector_format: if !reader.is_empty() {
+ Some(PackedVectorFormat::parse(reader)?)
+ } else {
+ None
+ },
+ },
+ 4472u16 => Self::TypeRayQueryKHR {
+ result_id: Id(reader.next_u32()?),
+ },
+ 4473u16 => Self::RayQueryInitializeKHR {
+ ray_query: Id(reader.next_u32()?),
+ accel: Id(reader.next_u32()?),
+ ray_flags: Id(reader.next_u32()?),
+ cull_mask: Id(reader.next_u32()?),
+ ray_origin: Id(reader.next_u32()?),
+ ray_t_min: Id(reader.next_u32()?),
+ ray_direction: Id(reader.next_u32()?),
+ ray_t_max: Id(reader.next_u32()?),
+ },
+ 4474u16 => Self::RayQueryTerminateKHR {
+ ray_query: Id(reader.next_u32()?),
+ },
+ 4475u16 => Self::RayQueryGenerateIntersectionKHR {
+ ray_query: Id(reader.next_u32()?),
+ hit_t: Id(reader.next_u32()?),
+ },
+ 4476u16 => Self::RayQueryConfirmIntersectionKHR {
+ ray_query: Id(reader.next_u32()?),
+ },
+ 4477u16 => Self::RayQueryProceedKHR {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ ray_query: Id(reader.next_u32()?),
+ },
+ 4479u16 => Self::RayQueryGetIntersectionTypeKHR {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ ray_query: Id(reader.next_u32()?),
+ intersection: Id(reader.next_u32()?),
+ },
+ 5000u16 => Self::GroupIAddNonUniformAMD {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ x: Id(reader.next_u32()?),
+ },
+ 5001u16 => Self::GroupFAddNonUniformAMD {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ x: Id(reader.next_u32()?),
+ },
+ 5002u16 => Self::GroupFMinNonUniformAMD {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ x: Id(reader.next_u32()?),
+ },
+ 5003u16 => Self::GroupUMinNonUniformAMD {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ x: Id(reader.next_u32()?),
+ },
+ 5004u16 => Self::GroupSMinNonUniformAMD {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ x: Id(reader.next_u32()?),
+ },
+ 5005u16 => Self::GroupFMaxNonUniformAMD {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ x: Id(reader.next_u32()?),
+ },
+ 5006u16 => Self::GroupUMaxNonUniformAMD {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ x: Id(reader.next_u32()?),
+ },
+ 5007u16 => Self::GroupSMaxNonUniformAMD {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ operation: GroupOperation::parse(reader)?,
+ x: Id(reader.next_u32()?),
+ },
+ 5011u16 => Self::FragmentMaskFetchAMD {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ },
+ 5012u16 => Self::FragmentFetchAMD {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ fragment_index: Id(reader.next_u32()?),
+ },
+ 5056u16 => Self::ReadClockKHR {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ scope: Id(reader.next_u32()?),
+ },
+ 5283u16 => Self::ImageSampleFootprintNV {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ sampled_image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ granularity: Id(reader.next_u32()?),
+ coarse: Id(reader.next_u32()?),
+ image_operands: if !reader.is_empty() {
+ Some(ImageOperands::parse(reader)?)
+ } else {
+ None
+ },
+ },
+ 5296u16 => Self::GroupNonUniformPartitionNV {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ },
+ 5299u16 => Self::WritePackedPrimitiveIndices4x8NV {
+ index_offset: Id(reader.next_u32()?),
+ packed_indices: Id(reader.next_u32()?),
+ },
+ 5334u16 => Self::ReportIntersectionKHR {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ hit: Id(reader.next_u32()?),
+ hit_kind: Id(reader.next_u32()?),
+ },
+ 5335u16 => Self::IgnoreIntersectionNV,
+ 5336u16 => Self::TerminateRayNV,
+ 5337u16 => Self::TraceNV {
+ accel: Id(reader.next_u32()?),
+ ray_flags: Id(reader.next_u32()?),
+ cull_mask: Id(reader.next_u32()?),
+ sbt_offset: Id(reader.next_u32()?),
+ sbt_stride: Id(reader.next_u32()?),
+ miss_index: Id(reader.next_u32()?),
+ ray_origin: Id(reader.next_u32()?),
+ ray_tmin: Id(reader.next_u32()?),
+ ray_direction: Id(reader.next_u32()?),
+ ray_tmax: Id(reader.next_u32()?),
+ payload_id: Id(reader.next_u32()?),
+ },
+ 5338u16 => Self::TraceMotionNV {
+ accel: Id(reader.next_u32()?),
+ ray_flags: Id(reader.next_u32()?),
+ cull_mask: Id(reader.next_u32()?),
+ sbt_offset: Id(reader.next_u32()?),
+ sbt_stride: Id(reader.next_u32()?),
+ miss_index: Id(reader.next_u32()?),
+ ray_origin: Id(reader.next_u32()?),
+ ray_tmin: Id(reader.next_u32()?),
+ ray_direction: Id(reader.next_u32()?),
+ ray_tmax: Id(reader.next_u32()?),
+ time: Id(reader.next_u32()?),
+ payload_id: Id(reader.next_u32()?),
+ },
+ 5339u16 => Self::TraceRayMotionNV {
+ accel: Id(reader.next_u32()?),
+ ray_flags: Id(reader.next_u32()?),
+ cull_mask: Id(reader.next_u32()?),
+ sbt_offset: Id(reader.next_u32()?),
+ sbt_stride: Id(reader.next_u32()?),
+ miss_index: Id(reader.next_u32()?),
+ ray_origin: Id(reader.next_u32()?),
+ ray_tmin: Id(reader.next_u32()?),
+ ray_direction: Id(reader.next_u32()?),
+ ray_tmax: Id(reader.next_u32()?),
+ time: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5341u16 => Self::TypeAccelerationStructureKHR {
+ result_id: Id(reader.next_u32()?),
+ },
+ 5344u16 => Self::ExecuteCallableNV {
+ sbt_index: Id(reader.next_u32()?),
+ callable_data_id: Id(reader.next_u32()?),
+ },
+ 5358u16 => Self::TypeCooperativeMatrixNV {
+ result_id: Id(reader.next_u32()?),
+ component_type: Id(reader.next_u32()?),
+ execution: Id(reader.next_u32()?),
+ rows: Id(reader.next_u32()?),
+ columns: Id(reader.next_u32()?),
+ },
+ 5359u16 => Self::CooperativeMatrixLoadNV {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ stride: Id(reader.next_u32()?),
+ column_major: Id(reader.next_u32()?),
+ memory_access: if !reader.is_empty() {
+ Some(MemoryAccess::parse(reader)?)
+ } else {
+ None
+ },
+ },
+ 5360u16 => Self::CooperativeMatrixStoreNV {
+ pointer: Id(reader.next_u32()?),
+ object: Id(reader.next_u32()?),
+ stride: Id(reader.next_u32()?),
+ column_major: Id(reader.next_u32()?),
+ memory_access: if !reader.is_empty() {
+ Some(MemoryAccess::parse(reader)?)
+ } else {
+ None
+ },
+ },
+ 5361u16 => Self::CooperativeMatrixMulAddNV {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ b: Id(reader.next_u32()?),
+ c: Id(reader.next_u32()?),
+ },
+ 5362u16 => Self::CooperativeMatrixLengthNV {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ ty: Id(reader.next_u32()?),
+ },
+ 5364u16 => Self::BeginInvocationInterlockEXT,
+ 5365u16 => Self::EndInvocationInterlockEXT,
+ 5380u16 => Self::DemoteToHelperInvocation,
+ 5381u16 => Self::IsHelperInvocationEXT {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ },
+ 5391u16 => Self::ConvertUToImageNV {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand: Id(reader.next_u32()?),
+ },
+ 5392u16 => Self::ConvertUToSamplerNV {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand: Id(reader.next_u32()?),
+ },
+ 5393u16 => Self::ConvertImageToUNV {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand: Id(reader.next_u32()?),
+ },
+ 5394u16 => Self::ConvertSamplerToUNV {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand: Id(reader.next_u32()?),
+ },
+ 5395u16 => Self::ConvertUToSampledImageNV {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand: Id(reader.next_u32()?),
+ },
+ 5396u16 => Self::ConvertSampledImageToUNV {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand: Id(reader.next_u32()?),
+ },
+ 5397u16 => Self::SamplerImageAddressingModeNV {
+ bit_width: reader.next_u32()?,
+ },
+ 5571u16 => Self::SubgroupShuffleINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ data: Id(reader.next_u32()?),
+ invocation_id: Id(reader.next_u32()?),
+ },
+ 5572u16 => Self::SubgroupShuffleDownINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ current: Id(reader.next_u32()?),
+ next: Id(reader.next_u32()?),
+ delta: Id(reader.next_u32()?),
+ },
+ 5573u16 => Self::SubgroupShuffleUpINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ previous: Id(reader.next_u32()?),
+ current: Id(reader.next_u32()?),
+ delta: Id(reader.next_u32()?),
+ },
+ 5574u16 => Self::SubgroupShuffleXorINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ data: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ },
+ 5575u16 => Self::SubgroupBlockReadINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ ptr: Id(reader.next_u32()?),
+ },
+ 5576u16 => Self::SubgroupBlockWriteINTEL {
+ ptr: Id(reader.next_u32()?),
+ data: Id(reader.next_u32()?),
+ },
+ 5577u16 => Self::SubgroupImageBlockReadINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ },
+ 5578u16 => Self::SubgroupImageBlockWriteINTEL {
+ image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ data: Id(reader.next_u32()?),
+ },
+ 5580u16 => Self::SubgroupImageMediaBlockReadINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ width: Id(reader.next_u32()?),
+ height: Id(reader.next_u32()?),
+ },
+ 5581u16 => Self::SubgroupImageMediaBlockWriteINTEL {
+ image: Id(reader.next_u32()?),
+ coordinate: Id(reader.next_u32()?),
+ width: Id(reader.next_u32()?),
+ height: Id(reader.next_u32()?),
+ data: Id(reader.next_u32()?),
+ },
+ 5585u16 => Self::UCountLeadingZerosINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand: Id(reader.next_u32()?),
+ },
+ 5586u16 => Self::UCountTrailingZerosINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand: Id(reader.next_u32()?),
+ },
+ 5587u16 => Self::AbsISubINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 5588u16 => Self::AbsUSubINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 5589u16 => Self::IAddSatINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 5590u16 => Self::UAddSatINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 5591u16 => Self::IAverageINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 5592u16 => Self::UAverageINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 5593u16 => Self::IAverageRoundedINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 5594u16 => Self::UAverageRoundedINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 5595u16 => Self::ISubSatINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 5596u16 => Self::USubSatINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 5597u16 => Self::IMul32x16INTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 5598u16 => Self::UMul32x16INTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 5600u16 => Self::ConstantFunctionPointerINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ function: Id(reader.next_u32()?),
+ },
+ 5601u16 => Self::FunctionPointerCallINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ operand1: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(Id(reader.next_u32()?));
+ }
+ vec
+ },
+ },
+ 5609u16 => Self::AsmTargetINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ asm_target: reader.next_string()?,
+ },
+ 5610u16 => Self::AsmINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ asm_type: Id(reader.next_u32()?),
+ target: Id(reader.next_u32()?),
+ asm_instructions: reader.next_string()?,
+ constraints: reader.next_string()?,
+ },
+ 5611u16 => Self::AsmCallINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ asm: Id(reader.next_u32()?),
+ argument_0: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(Id(reader.next_u32()?));
+ }
+ vec
+ },
+ },
+ 5614u16 => Self::AtomicFMinEXT {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ memory: Id(reader.next_u32()?),
+ semantics: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ },
+ 5615u16 => Self::AtomicFMaxEXT {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ memory: Id(reader.next_u32()?),
+ semantics: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ },
+ 5630u16 => Self::AssumeTrueKHR {
+ condition: Id(reader.next_u32()?),
+ },
+ 5631u16 => Self::ExpectKHR {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ expected_value: Id(reader.next_u32()?),
+ },
+ 5632u16 => Self::DecorateString {
+ target: Id(reader.next_u32()?),
+ decoration: Decoration::parse(reader)?,
+ },
+ 5633u16 => Self::MemberDecorateString {
+ struct_type: Id(reader.next_u32()?),
+ member: reader.next_u32()?,
+ decoration: Decoration::parse(reader)?,
+ },
+ 5699u16 => Self::VmeImageINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ image_type: Id(reader.next_u32()?),
+ sampler: Id(reader.next_u32()?),
+ },
+ 5700u16 => Self::TypeVmeImageINTEL {
+ result_id: Id(reader.next_u32()?),
+ image_type: Id(reader.next_u32()?),
+ },
+ 5701u16 => Self::TypeAvcImePayloadINTEL {
+ result_id: Id(reader.next_u32()?),
+ },
+ 5702u16 => Self::TypeAvcRefPayloadINTEL {
+ result_id: Id(reader.next_u32()?),
+ },
+ 5703u16 => Self::TypeAvcSicPayloadINTEL {
+ result_id: Id(reader.next_u32()?),
+ },
+ 5704u16 => Self::TypeAvcMcePayloadINTEL {
+ result_id: Id(reader.next_u32()?),
+ },
+ 5705u16 => Self::TypeAvcMceResultINTEL {
+ result_id: Id(reader.next_u32()?),
+ },
+ 5706u16 => Self::TypeAvcImeResultINTEL {
+ result_id: Id(reader.next_u32()?),
+ },
+ 5707u16 => Self::TypeAvcImeResultSingleReferenceStreamoutINTEL {
+ result_id: Id(reader.next_u32()?),
+ },
+ 5708u16 => Self::TypeAvcImeResultDualReferenceStreamoutINTEL {
+ result_id: Id(reader.next_u32()?),
+ },
+ 5709u16 => Self::TypeAvcImeSingleReferenceStreaminINTEL {
+ result_id: Id(reader.next_u32()?),
+ },
+ 5710u16 => Self::TypeAvcImeDualReferenceStreaminINTEL {
+ result_id: Id(reader.next_u32()?),
+ },
+ 5711u16 => Self::TypeAvcRefResultINTEL {
+ result_id: Id(reader.next_u32()?),
+ },
+ 5712u16 => Self::TypeAvcSicResultINTEL {
+ result_id: Id(reader.next_u32()?),
+ },
+ 5713u16 => Self::SubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ slice_type: Id(reader.next_u32()?),
+ qp: Id(reader.next_u32()?),
+ },
+ 5714u16 => Self::SubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ reference_base_penalty: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5715u16 => Self::SubgroupAvcMceGetDefaultInterShapePenaltyINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ slice_type: Id(reader.next_u32()?),
+ qp: Id(reader.next_u32()?),
+ },
+ 5716u16 => Self::SubgroupAvcMceSetInterShapePenaltyINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ packed_shape_penalty: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5717u16 => Self::SubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ slice_type: Id(reader.next_u32()?),
+ qp: Id(reader.next_u32()?),
+ },
+ 5718u16 => Self::SubgroupAvcMceSetInterDirectionPenaltyINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ direction_cost: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5719u16 => Self::SubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ slice_type: Id(reader.next_u32()?),
+ qp: Id(reader.next_u32()?),
+ },
+ 5720u16 => Self::SubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ slice_type: Id(reader.next_u32()?),
+ qp: Id(reader.next_u32()?),
+ },
+ 5721u16 => Self::SubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ },
+ 5722u16 => Self::SubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ },
+ 5723u16 => Self::SubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ },
+ 5724u16 => Self::SubgroupAvcMceSetMotionVectorCostFunctionINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ packed_cost_center_delta: Id(reader.next_u32()?),
+ packed_cost_table: Id(reader.next_u32()?),
+ cost_precision: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5725u16 => Self::SubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ slice_type: Id(reader.next_u32()?),
+ qp: Id(reader.next_u32()?),
+ },
+ 5726u16 => Self::SubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ },
+ 5727u16 => Self::SubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ },
+ 5728u16 => Self::SubgroupAvcMceSetAcOnlyHaarINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5729u16 => Self::SubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ source_field_polarity: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5730u16 => Self::SubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ reference_field_polarity: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5731u16 => Self::SubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ forward_reference_field_polarity: Id(reader.next_u32()?),
+ backward_reference_field_polarity: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5732u16 => Self::SubgroupAvcMceConvertToImePayloadINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5733u16 => Self::SubgroupAvcMceConvertToImeResultINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5734u16 => Self::SubgroupAvcMceConvertToRefPayloadINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5735u16 => Self::SubgroupAvcMceConvertToRefResultINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5736u16 => Self::SubgroupAvcMceConvertToSicPayloadINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5737u16 => Self::SubgroupAvcMceConvertToSicResultINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5738u16 => Self::SubgroupAvcMceGetMotionVectorsINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5739u16 => Self::SubgroupAvcMceGetInterDistortionsINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5740u16 => Self::SubgroupAvcMceGetBestInterDistortionsINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5741u16 => Self::SubgroupAvcMceGetInterMajorShapeINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5742u16 => Self::SubgroupAvcMceGetInterMinorShapeINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5743u16 => Self::SubgroupAvcMceGetInterDirectionsINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5744u16 => Self::SubgroupAvcMceGetInterMotionVectorCountINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5745u16 => Self::SubgroupAvcMceGetInterReferenceIdsINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5746u16 => Self::SubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ packed_reference_ids: Id(reader.next_u32()?),
+ packed_reference_parameter_field_polarities: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5747u16 => Self::SubgroupAvcImeInitializeINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ src_coord: Id(reader.next_u32()?),
+ partition_mask: Id(reader.next_u32()?),
+ sad_adjustment: Id(reader.next_u32()?),
+ },
+ 5748u16 => Self::SubgroupAvcImeSetSingleReferenceINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ ref_offset: Id(reader.next_u32()?),
+ search_window_config: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5749u16 => Self::SubgroupAvcImeSetDualReferenceINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ fwd_ref_offset: Id(reader.next_u32()?),
+ bwd_ref_offset: Id(reader.next_u32()?),
+ id_search_window_config: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5750u16 => Self::SubgroupAvcImeRefWindowSizeINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ search_window_config: Id(reader.next_u32()?),
+ dual_ref: Id(reader.next_u32()?),
+ },
+ 5751u16 => Self::SubgroupAvcImeAdjustRefOffsetINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ ref_offset: Id(reader.next_u32()?),
+ src_coord: Id(reader.next_u32()?),
+ ref_window_size: Id(reader.next_u32()?),
+ image_size: Id(reader.next_u32()?),
+ },
+ 5752u16 => Self::SubgroupAvcImeConvertToMcePayloadINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5753u16 => Self::SubgroupAvcImeSetMaxMotionVectorCountINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ max_motion_vector_count: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5754u16 => Self::SubgroupAvcImeSetUnidirectionalMixDisableINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5755u16 => Self::SubgroupAvcImeSetEarlySearchTerminationThresholdINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ threshold: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5756u16 => Self::SubgroupAvcImeSetWeightedSadINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ packed_sad_weights: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5757u16 => Self::SubgroupAvcImeEvaluateWithSingleReferenceINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ src_image: Id(reader.next_u32()?),
+ ref_image: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5758u16 => Self::SubgroupAvcImeEvaluateWithDualReferenceINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ src_image: Id(reader.next_u32()?),
+ fwd_ref_image: Id(reader.next_u32()?),
+ bwd_ref_image: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5759u16 => Self::SubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ src_image: Id(reader.next_u32()?),
+ ref_image: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ streamin_components: Id(reader.next_u32()?),
+ },
+ 5760u16 => Self::SubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ src_image: Id(reader.next_u32()?),
+ fwd_ref_image: Id(reader.next_u32()?),
+ bwd_ref_image: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ streamin_components: Id(reader.next_u32()?),
+ },
+ 5761u16 => Self::SubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ src_image: Id(reader.next_u32()?),
+ ref_image: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5762u16 => Self::SubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ src_image: Id(reader.next_u32()?),
+ fwd_ref_image: Id(reader.next_u32()?),
+ bwd_ref_image: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5763u16 => Self::SubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ src_image: Id(reader.next_u32()?),
+ ref_image: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ streamin_components: Id(reader.next_u32()?),
+ },
+ 5764u16 => Self::SubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ src_image: Id(reader.next_u32()?),
+ fwd_ref_image: Id(reader.next_u32()?),
+ bwd_ref_image: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ streamin_components: Id(reader.next_u32()?),
+ },
+ 5765u16 => Self::SubgroupAvcImeConvertToMceResultINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5766u16 => Self::SubgroupAvcImeGetSingleReferenceStreaminINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5767u16 => Self::SubgroupAvcImeGetDualReferenceStreaminINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5768u16 => Self::SubgroupAvcImeStripSingleReferenceStreamoutINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5769u16 => Self::SubgroupAvcImeStripDualReferenceStreamoutINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5770u16 => {
+ Self::SubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ major_shape: Id(reader.next_u32()?),
+ }
+ }
+ 5771u16 => Self::SubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ major_shape: Id(reader.next_u32()?),
+ },
+ 5772u16 => Self::SubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ major_shape: Id(reader.next_u32()?),
+ },
+ 5773u16 => Self::SubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ major_shape: Id(reader.next_u32()?),
+ direction: Id(reader.next_u32()?),
+ },
+ 5774u16 => Self::SubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ major_shape: Id(reader.next_u32()?),
+ direction: Id(reader.next_u32()?),
+ },
+ 5775u16 => Self::SubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ major_shape: Id(reader.next_u32()?),
+ direction: Id(reader.next_u32()?),
+ },
+ 5776u16 => Self::SubgroupAvcImeGetBorderReachedINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ image_select: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5777u16 => Self::SubgroupAvcImeGetTruncatedSearchIndicationINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5778u16 => Self::SubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5779u16 => Self::SubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5780u16 => Self::SubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5781u16 => Self::SubgroupAvcFmeInitializeINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ src_coord: Id(reader.next_u32()?),
+ motion_vectors: Id(reader.next_u32()?),
+ major_shapes: Id(reader.next_u32()?),
+ minor_shapes: Id(reader.next_u32()?),
+ direction: Id(reader.next_u32()?),
+ pixel_resolution: Id(reader.next_u32()?),
+ sad_adjustment: Id(reader.next_u32()?),
+ },
+ 5782u16 => Self::SubgroupAvcBmeInitializeINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ src_coord: Id(reader.next_u32()?),
+ motion_vectors: Id(reader.next_u32()?),
+ major_shapes: Id(reader.next_u32()?),
+ minor_shapes: Id(reader.next_u32()?),
+ direction: Id(reader.next_u32()?),
+ pixel_resolution: Id(reader.next_u32()?),
+ bidirectional_weight: Id(reader.next_u32()?),
+ sad_adjustment: Id(reader.next_u32()?),
+ },
+ 5783u16 => Self::SubgroupAvcRefConvertToMcePayloadINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5784u16 => Self::SubgroupAvcRefSetBidirectionalMixDisableINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5785u16 => Self::SubgroupAvcRefSetBilinearFilterEnableINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5786u16 => Self::SubgroupAvcRefEvaluateWithSingleReferenceINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ src_image: Id(reader.next_u32()?),
+ ref_image: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5787u16 => Self::SubgroupAvcRefEvaluateWithDualReferenceINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ src_image: Id(reader.next_u32()?),
+ fwd_ref_image: Id(reader.next_u32()?),
+ bwd_ref_image: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5788u16 => Self::SubgroupAvcRefEvaluateWithMultiReferenceINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ src_image: Id(reader.next_u32()?),
+ packed_reference_ids: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5789u16 => Self::SubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ src_image: Id(reader.next_u32()?),
+ packed_reference_ids: Id(reader.next_u32()?),
+ packed_reference_field_polarities: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5790u16 => Self::SubgroupAvcRefConvertToMceResultINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5791u16 => Self::SubgroupAvcSicInitializeINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ src_coord: Id(reader.next_u32()?),
+ },
+ 5792u16 => Self::SubgroupAvcSicConfigureSkcINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ skip_block_partition_type: Id(reader.next_u32()?),
+ skip_motion_vector_mask: Id(reader.next_u32()?),
+ motion_vectors: Id(reader.next_u32()?),
+ bidirectional_weight: Id(reader.next_u32()?),
+ sad_adjustment: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5793u16 => Self::SubgroupAvcSicConfigureIpeLumaINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ luma_intra_partition_mask: Id(reader.next_u32()?),
+ intra_neighbour_availabilty: Id(reader.next_u32()?),
+ left_edge_luma_pixels: Id(reader.next_u32()?),
+ upper_left_corner_luma_pixel: Id(reader.next_u32()?),
+ upper_edge_luma_pixels: Id(reader.next_u32()?),
+ upper_right_edge_luma_pixels: Id(reader.next_u32()?),
+ sad_adjustment: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5794u16 => Self::SubgroupAvcSicConfigureIpeLumaChromaINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ luma_intra_partition_mask: Id(reader.next_u32()?),
+ intra_neighbour_availabilty: Id(reader.next_u32()?),
+ left_edge_luma_pixels: Id(reader.next_u32()?),
+ upper_left_corner_luma_pixel: Id(reader.next_u32()?),
+ upper_edge_luma_pixels: Id(reader.next_u32()?),
+ upper_right_edge_luma_pixels: Id(reader.next_u32()?),
+ left_edge_chroma_pixels: Id(reader.next_u32()?),
+ upper_left_corner_chroma_pixel: Id(reader.next_u32()?),
+ upper_edge_chroma_pixels: Id(reader.next_u32()?),
+ sad_adjustment: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5795u16 => Self::SubgroupAvcSicGetMotionVectorMaskINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ skip_block_partition_type: Id(reader.next_u32()?),
+ direction: Id(reader.next_u32()?),
+ },
+ 5796u16 => Self::SubgroupAvcSicConvertToMcePayloadINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5797u16 => Self::SubgroupAvcSicSetIntraLumaShapePenaltyINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ packed_shape_penalty: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5798u16 => Self::SubgroupAvcSicSetIntraLumaModeCostFunctionINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ luma_mode_penalty: Id(reader.next_u32()?),
+ luma_packed_neighbor_modes: Id(reader.next_u32()?),
+ luma_packed_non_dc_penalty: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5799u16 => Self::SubgroupAvcSicSetIntraChromaModeCostFunctionINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ chroma_mode_base_penalty: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5800u16 => Self::SubgroupAvcSicSetBilinearFilterEnableINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5801u16 => Self::SubgroupAvcSicSetSkcForwardTransformEnableINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ packed_sad_coefficients: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5802u16 => Self::SubgroupAvcSicSetBlockBasedRawSkipSadINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ block_based_skip_type: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5803u16 => Self::SubgroupAvcSicEvaluateIpeINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ src_image: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5804u16 => Self::SubgroupAvcSicEvaluateWithSingleReferenceINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ src_image: Id(reader.next_u32()?),
+ ref_image: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5805u16 => Self::SubgroupAvcSicEvaluateWithDualReferenceINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ src_image: Id(reader.next_u32()?),
+ fwd_ref_image: Id(reader.next_u32()?),
+ bwd_ref_image: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5806u16 => Self::SubgroupAvcSicEvaluateWithMultiReferenceINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ src_image: Id(reader.next_u32()?),
+ packed_reference_ids: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5807u16 => Self::SubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ src_image: Id(reader.next_u32()?),
+ packed_reference_ids: Id(reader.next_u32()?),
+ packed_reference_field_polarities: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5808u16 => Self::SubgroupAvcSicConvertToMceResultINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5809u16 => Self::SubgroupAvcSicGetIpeLumaShapeINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5810u16 => Self::SubgroupAvcSicGetBestIpeLumaDistortionINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5811u16 => Self::SubgroupAvcSicGetBestIpeChromaDistortionINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5812u16 => Self::SubgroupAvcSicGetPackedIpeLumaModesINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5813u16 => Self::SubgroupAvcSicGetIpeChromaModeINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5814u16 => Self::SubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5815u16 => Self::SubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5816u16 => Self::SubgroupAvcSicGetInterRawSadsINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ payload: Id(reader.next_u32()?),
+ },
+ 5818u16 => Self::VariableLengthArrayINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ lenght: Id(reader.next_u32()?),
+ },
+ 5819u16 => Self::SaveMemoryINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ },
+ 5820u16 => Self::RestoreMemoryINTEL {
+ ptr: Id(reader.next_u32()?),
+ },
+ 5840u16 => Self::ArbitraryFloatSinCosPiINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ from_sign: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5841u16 => Self::ArbitraryFloatCastINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5842u16 => Self::ArbitraryFloatCastFromIntINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ mout: reader.next_u32()?,
+ from_sign: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5843u16 => Self::ArbitraryFloatCastToIntINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5846u16 => Self::ArbitraryFloatAddINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ b: Id(reader.next_u32()?),
+ m2: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5847u16 => Self::ArbitraryFloatSubINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ b: Id(reader.next_u32()?),
+ m2: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5848u16 => Self::ArbitraryFloatMulINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ b: Id(reader.next_u32()?),
+ m2: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5849u16 => Self::ArbitraryFloatDivINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ b: Id(reader.next_u32()?),
+ m2: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5850u16 => Self::ArbitraryFloatGTINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ b: Id(reader.next_u32()?),
+ m2: reader.next_u32()?,
+ },
+ 5851u16 => Self::ArbitraryFloatGEINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ b: Id(reader.next_u32()?),
+ m2: reader.next_u32()?,
+ },
+ 5852u16 => Self::ArbitraryFloatLTINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ b: Id(reader.next_u32()?),
+ m2: reader.next_u32()?,
+ },
+ 5853u16 => Self::ArbitraryFloatLEINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ b: Id(reader.next_u32()?),
+ m2: reader.next_u32()?,
+ },
+ 5854u16 => Self::ArbitraryFloatEQINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ b: Id(reader.next_u32()?),
+ m2: reader.next_u32()?,
+ },
+ 5855u16 => Self::ArbitraryFloatRecipINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5856u16 => Self::ArbitraryFloatRSqrtINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5857u16 => Self::ArbitraryFloatCbrtINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5858u16 => Self::ArbitraryFloatHypotINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ b: Id(reader.next_u32()?),
+ m2: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5859u16 => Self::ArbitraryFloatSqrtINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5860u16 => Self::ArbitraryFloatLogINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5861u16 => Self::ArbitraryFloatLog2INTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5862u16 => Self::ArbitraryFloatLog10INTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5863u16 => Self::ArbitraryFloatLog1pINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5864u16 => Self::ArbitraryFloatExpINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5865u16 => Self::ArbitraryFloatExp2INTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5866u16 => Self::ArbitraryFloatExp10INTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5867u16 => Self::ArbitraryFloatExpm1INTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5868u16 => Self::ArbitraryFloatSinINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5869u16 => Self::ArbitraryFloatCosINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5870u16 => Self::ArbitraryFloatSinCosINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5871u16 => Self::ArbitraryFloatSinPiINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5872u16 => Self::ArbitraryFloatCosPiINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5873u16 => Self::ArbitraryFloatASinINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5874u16 => Self::ArbitraryFloatASinPiINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5875u16 => Self::ArbitraryFloatACosINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5876u16 => Self::ArbitraryFloatACosPiINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5877u16 => Self::ArbitraryFloatATanINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5878u16 => Self::ArbitraryFloatATanPiINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5879u16 => Self::ArbitraryFloatATan2INTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ b: Id(reader.next_u32()?),
+ m2: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5880u16 => Self::ArbitraryFloatPowINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ b: Id(reader.next_u32()?),
+ m2: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5881u16 => Self::ArbitraryFloatPowRINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ b: Id(reader.next_u32()?),
+ m2: reader.next_u32()?,
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5882u16 => Self::ArbitraryFloatPowNINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ a: Id(reader.next_u32()?),
+ m1: reader.next_u32()?,
+ b: Id(reader.next_u32()?),
+ mout: reader.next_u32()?,
+ enable_subnormals: reader.next_u32()?,
+ rounding_mode: reader.next_u32()?,
+ rounding_accuracy: reader.next_u32()?,
+ },
+ 5887u16 => Self::LoopControlINTEL {
+ loop_control_parameters: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(reader.next_u32()?);
+ }
+ vec
+ },
+ },
+ 5923u16 => Self::FixedSqrtINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ input_type: Id(reader.next_u32()?),
+ input: Id(reader.next_u32()?),
+ s: reader.next_u32()?,
+ i: reader.next_u32()?,
+ r_i: reader.next_u32()?,
+ q: reader.next_u32()?,
+ o: reader.next_u32()?,
+ },
+ 5924u16 => Self::FixedRecipINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ input_type: Id(reader.next_u32()?),
+ input: Id(reader.next_u32()?),
+ s: reader.next_u32()?,
+ i: reader.next_u32()?,
+ r_i: reader.next_u32()?,
+ q: reader.next_u32()?,
+ o: reader.next_u32()?,
+ },
+ 5925u16 => Self::FixedRsqrtINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ input_type: Id(reader.next_u32()?),
+ input: Id(reader.next_u32()?),
+ s: reader.next_u32()?,
+ i: reader.next_u32()?,
+ r_i: reader.next_u32()?,
+ q: reader.next_u32()?,
+ o: reader.next_u32()?,
+ },
+ 5926u16 => Self::FixedSinINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ input_type: Id(reader.next_u32()?),
+ input: Id(reader.next_u32()?),
+ s: reader.next_u32()?,
+ i: reader.next_u32()?,
+ r_i: reader.next_u32()?,
+ q: reader.next_u32()?,
+ o: reader.next_u32()?,
+ },
+ 5927u16 => Self::FixedCosINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ input_type: Id(reader.next_u32()?),
+ input: Id(reader.next_u32()?),
+ s: reader.next_u32()?,
+ i: reader.next_u32()?,
+ r_i: reader.next_u32()?,
+ q: reader.next_u32()?,
+ o: reader.next_u32()?,
+ },
+ 5928u16 => Self::FixedSinCosINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ input_type: Id(reader.next_u32()?),
+ input: Id(reader.next_u32()?),
+ s: reader.next_u32()?,
+ i: reader.next_u32()?,
+ r_i: reader.next_u32()?,
+ q: reader.next_u32()?,
+ o: reader.next_u32()?,
+ },
+ 5929u16 => Self::FixedSinPiINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ input_type: Id(reader.next_u32()?),
+ input: Id(reader.next_u32()?),
+ s: reader.next_u32()?,
+ i: reader.next_u32()?,
+ r_i: reader.next_u32()?,
+ q: reader.next_u32()?,
+ o: reader.next_u32()?,
+ },
+ 5930u16 => Self::FixedCosPiINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ input_type: Id(reader.next_u32()?),
+ input: Id(reader.next_u32()?),
+ s: reader.next_u32()?,
+ i: reader.next_u32()?,
+ r_i: reader.next_u32()?,
+ q: reader.next_u32()?,
+ o: reader.next_u32()?,
+ },
+ 5931u16 => Self::FixedSinCosPiINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ input_type: Id(reader.next_u32()?),
+ input: Id(reader.next_u32()?),
+ s: reader.next_u32()?,
+ i: reader.next_u32()?,
+ r_i: reader.next_u32()?,
+ q: reader.next_u32()?,
+ o: reader.next_u32()?,
+ },
+ 5932u16 => Self::FixedLogINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ input_type: Id(reader.next_u32()?),
+ input: Id(reader.next_u32()?),
+ s: reader.next_u32()?,
+ i: reader.next_u32()?,
+ r_i: reader.next_u32()?,
+ q: reader.next_u32()?,
+ o: reader.next_u32()?,
+ },
+ 5933u16 => Self::FixedExpINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ input_type: Id(reader.next_u32()?),
+ input: Id(reader.next_u32()?),
+ s: reader.next_u32()?,
+ i: reader.next_u32()?,
+ r_i: reader.next_u32()?,
+ q: reader.next_u32()?,
+ o: reader.next_u32()?,
+ },
+ 5934u16 => Self::PtrCastToCrossWorkgroupINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ },
+ 5938u16 => Self::CrossWorkgroupCastToPtrINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ },
+ 5946u16 => Self::ReadPipeBlockingINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ packet_size: Id(reader.next_u32()?),
+ packet_alignment: Id(reader.next_u32()?),
+ },
+ 5947u16 => Self::WritePipeBlockingINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ packet_size: Id(reader.next_u32()?),
+ packet_alignment: Id(reader.next_u32()?),
+ },
+ 5949u16 => Self::FPGARegINTEL {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ result: Id(reader.next_u32()?),
+ input: Id(reader.next_u32()?),
+ },
+ 6016u16 => Self::RayQueryGetRayTMinKHR {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ ray_query: Id(reader.next_u32()?),
+ },
+ 6017u16 => Self::RayQueryGetRayFlagsKHR {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ ray_query: Id(reader.next_u32()?),
+ },
+ 6018u16 => Self::RayQueryGetIntersectionTKHR {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ ray_query: Id(reader.next_u32()?),
+ intersection: Id(reader.next_u32()?),
+ },
+ 6019u16 => Self::RayQueryGetIntersectionInstanceCustomIndexKHR {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ ray_query: Id(reader.next_u32()?),
+ intersection: Id(reader.next_u32()?),
+ },
+ 6020u16 => Self::RayQueryGetIntersectionInstanceIdKHR {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ ray_query: Id(reader.next_u32()?),
+ intersection: Id(reader.next_u32()?),
+ },
+ 6021u16 => Self::RayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ ray_query: Id(reader.next_u32()?),
+ intersection: Id(reader.next_u32()?),
+ },
+ 6022u16 => Self::RayQueryGetIntersectionGeometryIndexKHR {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ ray_query: Id(reader.next_u32()?),
+ intersection: Id(reader.next_u32()?),
+ },
+ 6023u16 => Self::RayQueryGetIntersectionPrimitiveIndexKHR {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ ray_query: Id(reader.next_u32()?),
+ intersection: Id(reader.next_u32()?),
+ },
+ 6024u16 => Self::RayQueryGetIntersectionBarycentricsKHR {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ ray_query: Id(reader.next_u32()?),
+ intersection: Id(reader.next_u32()?),
+ },
+ 6025u16 => Self::RayQueryGetIntersectionFrontFaceKHR {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ ray_query: Id(reader.next_u32()?),
+ intersection: Id(reader.next_u32()?),
+ },
+ 6026u16 => Self::RayQueryGetIntersectionCandidateAABBOpaqueKHR {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ ray_query: Id(reader.next_u32()?),
+ },
+ 6027u16 => Self::RayQueryGetIntersectionObjectRayDirectionKHR {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ ray_query: Id(reader.next_u32()?),
+ intersection: Id(reader.next_u32()?),
+ },
+ 6028u16 => Self::RayQueryGetIntersectionObjectRayOriginKHR {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ ray_query: Id(reader.next_u32()?),
+ intersection: Id(reader.next_u32()?),
+ },
+ 6029u16 => Self::RayQueryGetWorldRayDirectionKHR {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ ray_query: Id(reader.next_u32()?),
+ },
+ 6030u16 => Self::RayQueryGetWorldRayOriginKHR {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ ray_query: Id(reader.next_u32()?),
+ },
+ 6031u16 => Self::RayQueryGetIntersectionObjectToWorldKHR {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ ray_query: Id(reader.next_u32()?),
+ intersection: Id(reader.next_u32()?),
+ },
+ 6032u16 => Self::RayQueryGetIntersectionWorldToObjectKHR {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ ray_query: Id(reader.next_u32()?),
+ intersection: Id(reader.next_u32()?),
+ },
+ 6035u16 => Self::AtomicFAddEXT {
+ result_type_id: Id(reader.next_u32()?),
+ result_id: Id(reader.next_u32()?),
+ pointer: Id(reader.next_u32()?),
+ memory: Id(reader.next_u32()?),
+ semantics: Id(reader.next_u32()?),
+ value: Id(reader.next_u32()?),
+ },
+ 6086u16 => Self::TypeBufferSurfaceINTEL {
+ result_id: Id(reader.next_u32()?),
+ access_qualifier: AccessQualifier::parse(reader)?,
+ },
+ 6090u16 => Self::TypeStructContinuedINTEL {
+ member_types: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(Id(reader.next_u32()?));
+ }
+ vec
+ },
+ },
+ 6091u16 => Self::ConstantCompositeContinuedINTEL {
+ constituents: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(Id(reader.next_u32()?));
+ }
+ vec
+ },
+ },
+ 6092u16 => Self::SpecConstantCompositeContinuedINTEL {
+ constituents: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(Id(reader.next_u32()?));
+ }
+ vec
+ },
+ },
+ opcode => return Err(reader.map_err(ParseErrors::UnknownOpcode(opcode))),
+ })
+ }
+ #[doc = r" Returns the `Id` that is assigned by this instruction, if any."]
+ pub fn result_id(&self) -> Option<Id> {
+ match self {
+ Self::Undef { result_id, .. }
+ | Self::String { result_id, .. }
+ | Self::ExtInstImport { result_id, .. }
+ | Self::ExtInst { result_id, .. }
+ | Self::TypeVoid { result_id, .. }
+ | Self::TypeBool { result_id, .. }
+ | Self::TypeInt { result_id, .. }
+ | Self::TypeFloat { result_id, .. }
+ | Self::TypeVector { result_id, .. }
+ | Self::TypeMatrix { result_id, .. }
+ | Self::TypeImage { result_id, .. }
+ | Self::TypeSampler { result_id, .. }
+ | Self::TypeSampledImage { result_id, .. }
+ | Self::TypeArray { result_id, .. }
+ | Self::TypeRuntimeArray { result_id, .. }
+ | Self::TypeStruct { result_id, .. }
+ | Self::TypeOpaque { result_id, .. }
+ | Self::TypePointer { result_id, .. }
+ | Self::TypeFunction { result_id, .. }
+ | Self::TypeEvent { result_id, .. }
+ | Self::TypeDeviceEvent { result_id, .. }
+ | Self::TypeReserveId { result_id, .. }
+ | Self::TypeQueue { result_id, .. }
+ | Self::TypePipe { result_id, .. }
+ | Self::ConstantTrue { result_id, .. }
+ | Self::ConstantFalse { result_id, .. }
+ | Self::Constant { result_id, .. }
+ | Self::ConstantComposite { result_id, .. }
+ | Self::ConstantSampler { result_id, .. }
+ | Self::ConstantNull { result_id, .. }
+ | Self::SpecConstantTrue { result_id, .. }
+ | Self::SpecConstantFalse { result_id, .. }
+ | Self::SpecConstant { result_id, .. }
+ | Self::SpecConstantComposite { result_id, .. }
+ | Self::SpecConstantOp { result_id, .. }
+ | Self::Function { result_id, .. }
+ | Self::FunctionParameter { result_id, .. }
+ | Self::FunctionCall { result_id, .. }
+ | Self::Variable { result_id, .. }
+ | Self::ImageTexelPointer { result_id, .. }
+ | Self::Load { result_id, .. }
+ | Self::AccessChain { result_id, .. }
+ | Self::InBoundsAccessChain { result_id, .. }
+ | Self::PtrAccessChain { result_id, .. }
+ | Self::ArrayLength { result_id, .. }
+ | Self::GenericPtrMemSemantics { result_id, .. }
+ | Self::InBoundsPtrAccessChain { result_id, .. }
+ | Self::DecorationGroup { result_id, .. }
+ | Self::VectorExtractDynamic { result_id, .. }
+ | Self::VectorInsertDynamic { result_id, .. }
+ | Self::VectorShuffle { result_id, .. }
+ | Self::CompositeConstruct { result_id, .. }
+ | Self::CompositeExtract { result_id, .. }
+ | Self::CompositeInsert { result_id, .. }
+ | Self::CopyObject { result_id, .. }
+ | Self::Transpose { result_id, .. }
+ | Self::SampledImage { result_id, .. }
+ | Self::ImageSampleImplicitLod { result_id, .. }
+ | Self::ImageSampleExplicitLod { result_id, .. }
+ | Self::ImageSampleDrefImplicitLod { result_id, .. }
+ | Self::ImageSampleDrefExplicitLod { result_id, .. }
+ | Self::ImageSampleProjImplicitLod { result_id, .. }
+ | Self::ImageSampleProjExplicitLod { result_id, .. }
+ | Self::ImageSampleProjDrefImplicitLod { result_id, .. }
+ | Self::ImageSampleProjDrefExplicitLod { result_id, .. }
+ | Self::ImageFetch { result_id, .. }
+ | Self::ImageGather { result_id, .. }
+ | Self::ImageDrefGather { result_id, .. }
+ | Self::ImageRead { result_id, .. }
+ | Self::Image { result_id, .. }
+ | Self::ImageQueryFormat { result_id, .. }
+ | Self::ImageQueryOrder { result_id, .. }
+ | Self::ImageQuerySizeLod { result_id, .. }
+ | Self::ImageQuerySize { result_id, .. }
+ | Self::ImageQueryLod { result_id, .. }
+ | Self::ImageQueryLevels { result_id, .. }
+ | Self::ImageQuerySamples { result_id, .. }
+ | Self::ConvertFToU { result_id, .. }
+ | Self::ConvertFToS { result_id, .. }
+ | Self::ConvertSToF { result_id, .. }
+ | Self::ConvertUToF { result_id, .. }
+ | Self::UConvert { result_id, .. }
+ | Self::SConvert { result_id, .. }
+ | Self::FConvert { result_id, .. }
+ | Self::QuantizeToF16 { result_id, .. }
+ | Self::ConvertPtrToU { result_id, .. }
+ | Self::SatConvertSToU { result_id, .. }
+ | Self::SatConvertUToS { result_id, .. }
+ | Self::ConvertUToPtr { result_id, .. }
+ | Self::PtrCastToGeneric { result_id, .. }
+ | Self::GenericCastToPtr { result_id, .. }
+ | Self::GenericCastToPtrExplicit { result_id, .. }
+ | Self::Bitcast { result_id, .. }
+ | Self::SNegate { result_id, .. }
+ | Self::FNegate { result_id, .. }
+ | Self::IAdd { result_id, .. }
+ | Self::FAdd { result_id, .. }
+ | Self::ISub { result_id, .. }
+ | Self::FSub { result_id, .. }
+ | Self::IMul { result_id, .. }
+ | Self::FMul { result_id, .. }
+ | Self::UDiv { result_id, .. }
+ | Self::SDiv { result_id, .. }
+ | Self::FDiv { result_id, .. }
+ | Self::UMod { result_id, .. }
+ | Self::SRem { result_id, .. }
+ | Self::SMod { result_id, .. }
+ | Self::FRem { result_id, .. }
+ | Self::FMod { result_id, .. }
+ | Self::VectorTimesScalar { result_id, .. }
+ | Self::MatrixTimesScalar { result_id, .. }
+ | Self::VectorTimesMatrix { result_id, .. }
+ | Self::MatrixTimesVector { result_id, .. }
+ | Self::MatrixTimesMatrix { result_id, .. }
+ | Self::OuterProduct { result_id, .. }
+ | Self::Dot { result_id, .. }
+ | Self::IAddCarry { result_id, .. }
+ | Self::ISubBorrow { result_id, .. }
+ | Self::UMulExtended { result_id, .. }
+ | Self::SMulExtended { result_id, .. }
+ | Self::Any { result_id, .. }
+ | Self::All { result_id, .. }
+ | Self::IsNan { result_id, .. }
+ | Self::IsInf { result_id, .. }
+ | Self::IsFinite { result_id, .. }
+ | Self::IsNormal { result_id, .. }
+ | Self::SignBitSet { result_id, .. }
+ | Self::LessOrGreater { result_id, .. }
+ | Self::Ordered { result_id, .. }
+ | Self::Unordered { result_id, .. }
+ | Self::LogicalEqual { result_id, .. }
+ | Self::LogicalNotEqual { result_id, .. }
+ | Self::LogicalOr { result_id, .. }
+ | Self::LogicalAnd { result_id, .. }
+ | Self::LogicalNot { result_id, .. }
+ | Self::Select { result_id, .. }
+ | Self::IEqual { result_id, .. }
+ | Self::INotEqual { result_id, .. }
+ | Self::UGreaterThan { result_id, .. }
+ | Self::SGreaterThan { result_id, .. }
+ | Self::UGreaterThanEqual { result_id, .. }
+ | Self::SGreaterThanEqual { result_id, .. }
+ | Self::ULessThan { result_id, .. }
+ | Self::SLessThan { result_id, .. }
+ | Self::ULessThanEqual { result_id, .. }
+ | Self::SLessThanEqual { result_id, .. }
+ | Self::FOrdEqual { result_id, .. }
+ | Self::FUnordEqual { result_id, .. }
+ | Self::FOrdNotEqual { result_id, .. }
+ | Self::FUnordNotEqual { result_id, .. }
+ | Self::FOrdLessThan { result_id, .. }
+ | Self::FUnordLessThan { result_id, .. }
+ | Self::FOrdGreaterThan { result_id, .. }
+ | Self::FUnordGreaterThan { result_id, .. }
+ | Self::FOrdLessThanEqual { result_id, .. }
+ | Self::FUnordLessThanEqual { result_id, .. }
+ | Self::FOrdGreaterThanEqual { result_id, .. }
+ | Self::FUnordGreaterThanEqual { result_id, .. }
+ | Self::ShiftRightLogical { result_id, .. }
+ | Self::ShiftRightArithmetic { result_id, .. }
+ | Self::ShiftLeftLogical { result_id, .. }
+ | Self::BitwiseOr { result_id, .. }
+ | Self::BitwiseXor { result_id, .. }
+ | Self::BitwiseAnd { result_id, .. }
+ | Self::Not { result_id, .. }
+ | Self::BitFieldInsert { result_id, .. }
+ | Self::BitFieldSExtract { result_id, .. }
+ | Self::BitFieldUExtract { result_id, .. }
+ | Self::BitReverse { result_id, .. }
+ | Self::BitCount { result_id, .. }
+ | Self::DPdx { result_id, .. }
+ | Self::DPdy { result_id, .. }
+ | Self::Fwidth { result_id, .. }
+ | Self::DPdxFine { result_id, .. }
+ | Self::DPdyFine { result_id, .. }
+ | Self::FwidthFine { result_id, .. }
+ | Self::DPdxCoarse { result_id, .. }
+ | Self::DPdyCoarse { result_id, .. }
+ | Self::FwidthCoarse { result_id, .. }
+ | Self::AtomicLoad { result_id, .. }
+ | Self::AtomicExchange { result_id, .. }
+ | Self::AtomicCompareExchange { result_id, .. }
+ | Self::AtomicCompareExchangeWeak { result_id, .. }
+ | Self::AtomicIIncrement { result_id, .. }
+ | Self::AtomicIDecrement { result_id, .. }
+ | Self::AtomicIAdd { result_id, .. }
+ | Self::AtomicISub { result_id, .. }
+ | Self::AtomicSMin { result_id, .. }
+ | Self::AtomicUMin { result_id, .. }
+ | Self::AtomicSMax { result_id, .. }
+ | Self::AtomicUMax { result_id, .. }
+ | Self::AtomicAnd { result_id, .. }
+ | Self::AtomicOr { result_id, .. }
+ | Self::AtomicXor { result_id, .. }
+ | Self::Phi { result_id, .. }
+ | Self::Label { result_id, .. }
+ | Self::GroupAsyncCopy { result_id, .. }
+ | Self::GroupAll { result_id, .. }
+ | Self::GroupAny { result_id, .. }
+ | Self::GroupBroadcast { result_id, .. }
+ | Self::GroupIAdd { result_id, .. }
+ | Self::GroupFAdd { result_id, .. }
+ | Self::GroupFMin { result_id, .. }
+ | Self::GroupUMin { result_id, .. }
+ | Self::GroupSMin { result_id, .. }
+ | Self::GroupFMax { result_id, .. }
+ | Self::GroupUMax { result_id, .. }
+ | Self::GroupSMax { result_id, .. }
+ | Self::ReadPipe { result_id, .. }
+ | Self::WritePipe { result_id, .. }
+ | Self::ReservedReadPipe { result_id, .. }
+ | Self::ReservedWritePipe { result_id, .. }
+ | Self::ReserveReadPipePackets { result_id, .. }
+ | Self::ReserveWritePipePackets { result_id, .. }
+ | Self::IsValidReserveId { result_id, .. }
+ | Self::GetNumPipePackets { result_id, .. }
+ | Self::GetMaxPipePackets { result_id, .. }
+ | Self::GroupReserveReadPipePackets { result_id, .. }
+ | Self::GroupReserveWritePipePackets { result_id, .. }
+ | Self::EnqueueMarker { result_id, .. }
+ | Self::EnqueueKernel { result_id, .. }
+ | Self::GetKernelNDrangeSubGroupCount { result_id, .. }
+ | Self::GetKernelNDrangeMaxSubGroupSize { result_id, .. }
+ | Self::GetKernelWorkGroupSize { result_id, .. }
+ | Self::GetKernelPreferredWorkGroupSizeMultiple { result_id, .. }
+ | Self::CreateUserEvent { result_id, .. }
+ | Self::IsValidEvent { result_id, .. }
+ | Self::GetDefaultQueue { result_id, .. }
+ | Self::BuildNDRange { result_id, .. }
+ | Self::ImageSparseSampleImplicitLod { result_id, .. }
+ | Self::ImageSparseSampleExplicitLod { result_id, .. }
+ | Self::ImageSparseSampleDrefImplicitLod { result_id, .. }
+ | Self::ImageSparseSampleDrefExplicitLod { result_id, .. }
+ | Self::ImageSparseSampleProjImplicitLod { result_id, .. }
+ | Self::ImageSparseSampleProjExplicitLod { result_id, .. }
+ | Self::ImageSparseSampleProjDrefImplicitLod { result_id, .. }
+ | Self::ImageSparseSampleProjDrefExplicitLod { result_id, .. }
+ | Self::ImageSparseFetch { result_id, .. }
+ | Self::ImageSparseGather { result_id, .. }
+ | Self::ImageSparseDrefGather { result_id, .. }
+ | Self::ImageSparseTexelsResident { result_id, .. }
+ | Self::AtomicFlagTestAndSet { result_id, .. }
+ | Self::ImageSparseRead { result_id, .. }
+ | Self::SizeOf { result_id, .. }
+ | Self::TypePipeStorage { result_id, .. }
+ | Self::ConstantPipeStorage { result_id, .. }
+ | Self::CreatePipeFromPipeStorage { result_id, .. }
+ | Self::GetKernelLocalSizeForSubgroupCount { result_id, .. }
+ | Self::GetKernelMaxNumSubgroups { result_id, .. }
+ | Self::TypeNamedBarrier { result_id, .. }
+ | Self::NamedBarrierInitialize { result_id, .. }
+ | Self::GroupNonUniformElect { result_id, .. }
+ | Self::GroupNonUniformAll { result_id, .. }
+ | Self::GroupNonUniformAny { result_id, .. }
+ | Self::GroupNonUniformAllEqual { result_id, .. }
+ | Self::GroupNonUniformBroadcast { result_id, .. }
+ | Self::GroupNonUniformBroadcastFirst { result_id, .. }
+ | Self::GroupNonUniformBallot { result_id, .. }
+ | Self::GroupNonUniformInverseBallot { result_id, .. }
+ | Self::GroupNonUniformBallotBitExtract { result_id, .. }
+ | Self::GroupNonUniformBallotBitCount { result_id, .. }
+ | Self::GroupNonUniformBallotFindLSB { result_id, .. }
+ | Self::GroupNonUniformBallotFindMSB { result_id, .. }
+ | Self::GroupNonUniformShuffle { result_id, .. }
+ | Self::GroupNonUniformShuffleXor { result_id, .. }
+ | Self::GroupNonUniformShuffleUp { result_id, .. }
+ | Self::GroupNonUniformShuffleDown { result_id, .. }
+ | Self::GroupNonUniformIAdd { result_id, .. }
+ | Self::GroupNonUniformFAdd { result_id, .. }
+ | Self::GroupNonUniformIMul { result_id, .. }
+ | Self::GroupNonUniformFMul { result_id, .. }
+ | Self::GroupNonUniformSMin { result_id, .. }
+ | Self::GroupNonUniformUMin { result_id, .. }
+ | Self::GroupNonUniformFMin { result_id, .. }
+ | Self::GroupNonUniformSMax { result_id, .. }
+ | Self::GroupNonUniformUMax { result_id, .. }
+ | Self::GroupNonUniformFMax { result_id, .. }
+ | Self::GroupNonUniformBitwiseAnd { result_id, .. }
+ | Self::GroupNonUniformBitwiseOr { result_id, .. }
+ | Self::GroupNonUniformBitwiseXor { result_id, .. }
+ | Self::GroupNonUniformLogicalAnd { result_id, .. }
+ | Self::GroupNonUniformLogicalOr { result_id, .. }
+ | Self::GroupNonUniformLogicalXor { result_id, .. }
+ | Self::GroupNonUniformQuadBroadcast { result_id, .. }
+ | Self::GroupNonUniformQuadSwap { result_id, .. }
+ | Self::CopyLogical { result_id, .. }
+ | Self::PtrEqual { result_id, .. }
+ | Self::PtrNotEqual { result_id, .. }
+ | Self::PtrDiff { result_id, .. }
+ | Self::SubgroupBallotKHR { result_id, .. }
+ | Self::SubgroupFirstInvocationKHR { result_id, .. }
+ | Self::SubgroupAllKHR { result_id, .. }
+ | Self::SubgroupAnyKHR { result_id, .. }
+ | Self::SubgroupAllEqualKHR { result_id, .. }
+ | Self::SubgroupReadInvocationKHR { result_id, .. }
+ | Self::ConvertUToAccelerationStructureKHR { result_id, .. }
+ | Self::SDot { result_id, .. }
+ | Self::UDot { result_id, .. }
+ | Self::SUDot { result_id, .. }
+ | Self::SDotAccSat { result_id, .. }
+ | Self::UDotAccSat { result_id, .. }
+ | Self::SUDotAccSat { result_id, .. }
+ | Self::TypeRayQueryKHR { result_id, .. }
+ | Self::RayQueryProceedKHR { result_id, .. }
+ | Self::RayQueryGetIntersectionTypeKHR { result_id, .. }
+ | Self::GroupIAddNonUniformAMD { result_id, .. }
+ | Self::GroupFAddNonUniformAMD { result_id, .. }
+ | Self::GroupFMinNonUniformAMD { result_id, .. }
+ | Self::GroupUMinNonUniformAMD { result_id, .. }
+ | Self::GroupSMinNonUniformAMD { result_id, .. }
+ | Self::GroupFMaxNonUniformAMD { result_id, .. }
+ | Self::GroupUMaxNonUniformAMD { result_id, .. }
+ | Self::GroupSMaxNonUniformAMD { result_id, .. }
+ | Self::FragmentMaskFetchAMD { result_id, .. }
+ | Self::FragmentFetchAMD { result_id, .. }
+ | Self::ReadClockKHR { result_id, .. }
+ | Self::ImageSampleFootprintNV { result_id, .. }
+ | Self::GroupNonUniformPartitionNV { result_id, .. }
+ | Self::ReportIntersectionKHR { result_id, .. }
+ | Self::TypeAccelerationStructureKHR { result_id, .. }
+ | Self::TypeCooperativeMatrixNV { result_id, .. }
+ | Self::CooperativeMatrixLoadNV { result_id, .. }
+ | Self::CooperativeMatrixMulAddNV { result_id, .. }
+ | Self::CooperativeMatrixLengthNV { result_id, .. }
+ | Self::IsHelperInvocationEXT { result_id, .. }
+ | Self::ConvertUToImageNV { result_id, .. }
+ | Self::ConvertUToSamplerNV { result_id, .. }
+ | Self::ConvertImageToUNV { result_id, .. }
+ | Self::ConvertSamplerToUNV { result_id, .. }
+ | Self::ConvertUToSampledImageNV { result_id, .. }
+ | Self::ConvertSampledImageToUNV { result_id, .. }
+ | Self::SubgroupShuffleINTEL { result_id, .. }
+ | Self::SubgroupShuffleDownINTEL { result_id, .. }
+ | Self::SubgroupShuffleUpINTEL { result_id, .. }
+ | Self::SubgroupShuffleXorINTEL { result_id, .. }
+ | Self::SubgroupBlockReadINTEL { result_id, .. }
+ | Self::SubgroupImageBlockReadINTEL { result_id, .. }
+ | Self::SubgroupImageMediaBlockReadINTEL { result_id, .. }
+ | Self::UCountLeadingZerosINTEL { result_id, .. }
+ | Self::UCountTrailingZerosINTEL { result_id, .. }
+ | Self::AbsISubINTEL { result_id, .. }
+ | Self::AbsUSubINTEL { result_id, .. }
+ | Self::IAddSatINTEL { result_id, .. }
+ | Self::UAddSatINTEL { result_id, .. }
+ | Self::IAverageINTEL { result_id, .. }
+ | Self::UAverageINTEL { result_id, .. }
+ | Self::IAverageRoundedINTEL { result_id, .. }
+ | Self::UAverageRoundedINTEL { result_id, .. }
+ | Self::ISubSatINTEL { result_id, .. }
+ | Self::USubSatINTEL { result_id, .. }
+ | Self::IMul32x16INTEL { result_id, .. }
+ | Self::UMul32x16INTEL { result_id, .. }
+ | Self::ConstantFunctionPointerINTEL { result_id, .. }
+ | Self::FunctionPointerCallINTEL { result_id, .. }
+ | Self::AsmTargetINTEL { result_id, .. }
+ | Self::AsmINTEL { result_id, .. }
+ | Self::AsmCallINTEL { result_id, .. }
+ | Self::AtomicFMinEXT { result_id, .. }
+ | Self::AtomicFMaxEXT { result_id, .. }
+ | Self::ExpectKHR { result_id, .. }
+ | Self::VmeImageINTEL { result_id, .. }
+ | Self::TypeVmeImageINTEL { result_id, .. }
+ | Self::TypeAvcImePayloadINTEL { result_id, .. }
+ | Self::TypeAvcRefPayloadINTEL { result_id, .. }
+ | Self::TypeAvcSicPayloadINTEL { result_id, .. }
+ | Self::TypeAvcMcePayloadINTEL { result_id, .. }
+ | Self::TypeAvcMceResultINTEL { result_id, .. }
+ | Self::TypeAvcImeResultINTEL { result_id, .. }
+ | Self::TypeAvcImeResultSingleReferenceStreamoutINTEL { result_id, .. }
+ | Self::TypeAvcImeResultDualReferenceStreamoutINTEL { result_id, .. }
+ | Self::TypeAvcImeSingleReferenceStreaminINTEL { result_id, .. }
+ | Self::TypeAvcImeDualReferenceStreaminINTEL { result_id, .. }
+ | Self::TypeAvcRefResultINTEL { result_id, .. }
+ | Self::TypeAvcSicResultINTEL { result_id, .. }
+ | Self::SubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL {
+ result_id, ..
+ }
+ | Self::SubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL { result_id, .. }
+ | Self::SubgroupAvcMceGetDefaultInterShapePenaltyINTEL { result_id, .. }
+ | Self::SubgroupAvcMceSetInterShapePenaltyINTEL { result_id, .. }
+ | Self::SubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL { result_id, .. }
+ | Self::SubgroupAvcMceSetInterDirectionPenaltyINTEL { result_id, .. }
+ | Self::SubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL { result_id, .. }
+ | Self::SubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL { result_id, .. }
+ | Self::SubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL { result_id, .. }
+ | Self::SubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL { result_id, .. }
+ | Self::SubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL { result_id, .. }
+ | Self::SubgroupAvcMceSetMotionVectorCostFunctionINTEL { result_id, .. }
+ | Self::SubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL { result_id, .. }
+ | Self::SubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL { result_id, .. }
+ | Self::SubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL { result_id, .. }
+ | Self::SubgroupAvcMceSetAcOnlyHaarINTEL { result_id, .. }
+ | Self::SubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL { result_id, .. }
+ | Self::SubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL {
+ result_id,
+ ..
+ }
+ | Self::SubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL {
+ result_id,
+ ..
+ }
+ | Self::SubgroupAvcMceConvertToImePayloadINTEL { result_id, .. }
+ | Self::SubgroupAvcMceConvertToImeResultINTEL { result_id, .. }
+ | Self::SubgroupAvcMceConvertToRefPayloadINTEL { result_id, .. }
+ | Self::SubgroupAvcMceConvertToRefResultINTEL { result_id, .. }
+ | Self::SubgroupAvcMceConvertToSicPayloadINTEL { result_id, .. }
+ | Self::SubgroupAvcMceConvertToSicResultINTEL { result_id, .. }
+ | Self::SubgroupAvcMceGetMotionVectorsINTEL { result_id, .. }
+ | Self::SubgroupAvcMceGetInterDistortionsINTEL { result_id, .. }
+ | Self::SubgroupAvcMceGetBestInterDistortionsINTEL { result_id, .. }
+ | Self::SubgroupAvcMceGetInterMajorShapeINTEL { result_id, .. }
+ | Self::SubgroupAvcMceGetInterMinorShapeINTEL { result_id, .. }
+ | Self::SubgroupAvcMceGetInterDirectionsINTEL { result_id, .. }
+ | Self::SubgroupAvcMceGetInterMotionVectorCountINTEL { result_id, .. }
+ | Self::SubgroupAvcMceGetInterReferenceIdsINTEL { result_id, .. }
+ | Self::SubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL {
+ result_id,
+ ..
+ }
+ | Self::SubgroupAvcImeInitializeINTEL { result_id, .. }
+ | Self::SubgroupAvcImeSetSingleReferenceINTEL { result_id, .. }
+ | Self::SubgroupAvcImeSetDualReferenceINTEL { result_id, .. }
+ | Self::SubgroupAvcImeRefWindowSizeINTEL { result_id, .. }
+ | Self::SubgroupAvcImeAdjustRefOffsetINTEL { result_id, .. }
+ | Self::SubgroupAvcImeConvertToMcePayloadINTEL { result_id, .. }
+ | Self::SubgroupAvcImeSetMaxMotionVectorCountINTEL { result_id, .. }
+ | Self::SubgroupAvcImeSetUnidirectionalMixDisableINTEL { result_id, .. }
+ | Self::SubgroupAvcImeSetEarlySearchTerminationThresholdINTEL { result_id, .. }
+ | Self::SubgroupAvcImeSetWeightedSadINTEL { result_id, .. }
+ | Self::SubgroupAvcImeEvaluateWithSingleReferenceINTEL { result_id, .. }
+ | Self::SubgroupAvcImeEvaluateWithDualReferenceINTEL { result_id, .. }
+ | Self::SubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL { result_id, .. }
+ | Self::SubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL { result_id, .. }
+ | Self::SubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL { result_id, .. }
+ | Self::SubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL { result_id, .. }
+ | Self::SubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL {
+ result_id, ..
+ }
+ | Self::SubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL { result_id, .. }
+ | Self::SubgroupAvcImeConvertToMceResultINTEL { result_id, .. }
+ | Self::SubgroupAvcImeGetSingleReferenceStreaminINTEL { result_id, .. }
+ | Self::SubgroupAvcImeGetDualReferenceStreaminINTEL { result_id, .. }
+ | Self::SubgroupAvcImeStripSingleReferenceStreamoutINTEL { result_id, .. }
+ | Self::SubgroupAvcImeStripDualReferenceStreamoutINTEL { result_id, .. }
+ | Self::SubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL {
+ result_id,
+ ..
+ }
+ | Self::SubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL {
+ result_id,
+ ..
+ }
+ | Self::SubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL {
+ result_id,
+ ..
+ }
+ | Self::SubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL {
+ result_id,
+ ..
+ }
+ | Self::SubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL {
+ result_id,
+ ..
+ }
+ | Self::SubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL {
+ result_id,
+ ..
+ }
+ | Self::SubgroupAvcImeGetBorderReachedINTEL { result_id, .. }
+ | Self::SubgroupAvcImeGetTruncatedSearchIndicationINTEL { result_id, .. }
+ | Self::SubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL {
+ result_id, ..
+ }
+ | Self::SubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL {
+ result_id, ..
+ }
+ | Self::SubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL { result_id, .. }
+ | Self::SubgroupAvcFmeInitializeINTEL { result_id, .. }
+ | Self::SubgroupAvcBmeInitializeINTEL { result_id, .. }
+ | Self::SubgroupAvcRefConvertToMcePayloadINTEL { result_id, .. }
+ | Self::SubgroupAvcRefSetBidirectionalMixDisableINTEL { result_id, .. }
+ | Self::SubgroupAvcRefSetBilinearFilterEnableINTEL { result_id, .. }
+ | Self::SubgroupAvcRefEvaluateWithSingleReferenceINTEL { result_id, .. }
+ | Self::SubgroupAvcRefEvaluateWithDualReferenceINTEL { result_id, .. }
+ | Self::SubgroupAvcRefEvaluateWithMultiReferenceINTEL { result_id, .. }
+ | Self::SubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL { result_id, .. }
+ | Self::SubgroupAvcRefConvertToMceResultINTEL { result_id, .. }
+ | Self::SubgroupAvcSicInitializeINTEL { result_id, .. }
+ | Self::SubgroupAvcSicConfigureSkcINTEL { result_id, .. }
+ | Self::SubgroupAvcSicConfigureIpeLumaINTEL { result_id, .. }
+ | Self::SubgroupAvcSicConfigureIpeLumaChromaINTEL { result_id, .. }
+ | Self::SubgroupAvcSicGetMotionVectorMaskINTEL { result_id, .. }
+ | Self::SubgroupAvcSicConvertToMcePayloadINTEL { result_id, .. }
+ | Self::SubgroupAvcSicSetIntraLumaShapePenaltyINTEL { result_id, .. }
+ | Self::SubgroupAvcSicSetIntraLumaModeCostFunctionINTEL { result_id, .. }
+ | Self::SubgroupAvcSicSetIntraChromaModeCostFunctionINTEL { result_id, .. }
+ | Self::SubgroupAvcSicSetBilinearFilterEnableINTEL { result_id, .. }
+ | Self::SubgroupAvcSicSetSkcForwardTransformEnableINTEL { result_id, .. }
+ | Self::SubgroupAvcSicSetBlockBasedRawSkipSadINTEL { result_id, .. }
+ | Self::SubgroupAvcSicEvaluateIpeINTEL { result_id, .. }
+ | Self::SubgroupAvcSicEvaluateWithSingleReferenceINTEL { result_id, .. }
+ | Self::SubgroupAvcSicEvaluateWithDualReferenceINTEL { result_id, .. }
+ | Self::SubgroupAvcSicEvaluateWithMultiReferenceINTEL { result_id, .. }
+ | Self::SubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL { result_id, .. }
+ | Self::SubgroupAvcSicConvertToMceResultINTEL { result_id, .. }
+ | Self::SubgroupAvcSicGetIpeLumaShapeINTEL { result_id, .. }
+ | Self::SubgroupAvcSicGetBestIpeLumaDistortionINTEL { result_id, .. }
+ | Self::SubgroupAvcSicGetBestIpeChromaDistortionINTEL { result_id, .. }
+ | Self::SubgroupAvcSicGetPackedIpeLumaModesINTEL { result_id, .. }
+ | Self::SubgroupAvcSicGetIpeChromaModeINTEL { result_id, .. }
+ | Self::SubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL { result_id, .. }
+ | Self::SubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL { result_id, .. }
+ | Self::SubgroupAvcSicGetInterRawSadsINTEL { result_id, .. }
+ | Self::VariableLengthArrayINTEL { result_id, .. }
+ | Self::SaveMemoryINTEL { result_id, .. }
+ | Self::ArbitraryFloatSinCosPiINTEL { result_id, .. }
+ | Self::ArbitraryFloatCastINTEL { result_id, .. }
+ | Self::ArbitraryFloatCastFromIntINTEL { result_id, .. }
+ | Self::ArbitraryFloatCastToIntINTEL { result_id, .. }
+ | Self::ArbitraryFloatAddINTEL { result_id, .. }
+ | Self::ArbitraryFloatSubINTEL { result_id, .. }
+ | Self::ArbitraryFloatMulINTEL { result_id, .. }
+ | Self::ArbitraryFloatDivINTEL { result_id, .. }
+ | Self::ArbitraryFloatGTINTEL { result_id, .. }
+ | Self::ArbitraryFloatGEINTEL { result_id, .. }
+ | Self::ArbitraryFloatLTINTEL { result_id, .. }
+ | Self::ArbitraryFloatLEINTEL { result_id, .. }
+ | Self::ArbitraryFloatEQINTEL { result_id, .. }
+ | Self::ArbitraryFloatRecipINTEL { result_id, .. }
+ | Self::ArbitraryFloatRSqrtINTEL { result_id, .. }
+ | Self::ArbitraryFloatCbrtINTEL { result_id, .. }
+ | Self::ArbitraryFloatHypotINTEL { result_id, .. }
+ | Self::ArbitraryFloatSqrtINTEL { result_id, .. }
+ | Self::ArbitraryFloatLogINTEL { result_id, .. }
+ | Self::ArbitraryFloatLog2INTEL { result_id, .. }
+ | Self::ArbitraryFloatLog10INTEL { result_id, .. }
+ | Self::ArbitraryFloatLog1pINTEL { result_id, .. }
+ | Self::ArbitraryFloatExpINTEL { result_id, .. }
+ | Self::ArbitraryFloatExp2INTEL { result_id, .. }
+ | Self::ArbitraryFloatExp10INTEL { result_id, .. }
+ | Self::ArbitraryFloatExpm1INTEL { result_id, .. }
+ | Self::ArbitraryFloatSinINTEL { result_id, .. }
+ | Self::ArbitraryFloatCosINTEL { result_id, .. }
+ | Self::ArbitraryFloatSinCosINTEL { result_id, .. }
+ | Self::ArbitraryFloatSinPiINTEL { result_id, .. }
+ | Self::ArbitraryFloatCosPiINTEL { result_id, .. }
+ | Self::ArbitraryFloatASinINTEL { result_id, .. }
+ | Self::ArbitraryFloatASinPiINTEL { result_id, .. }
+ | Self::ArbitraryFloatACosINTEL { result_id, .. }
+ | Self::ArbitraryFloatACosPiINTEL { result_id, .. }
+ | Self::ArbitraryFloatATanINTEL { result_id, .. }
+ | Self::ArbitraryFloatATanPiINTEL { result_id, .. }
+ | Self::ArbitraryFloatATan2INTEL { result_id, .. }
+ | Self::ArbitraryFloatPowINTEL { result_id, .. }
+ | Self::ArbitraryFloatPowRINTEL { result_id, .. }
+ | Self::ArbitraryFloatPowNINTEL { result_id, .. }
+ | Self::FixedSqrtINTEL { result_id, .. }
+ | Self::FixedRecipINTEL { result_id, .. }
+ | Self::FixedRsqrtINTEL { result_id, .. }
+ | Self::FixedSinINTEL { result_id, .. }
+ | Self::FixedCosINTEL { result_id, .. }
+ | Self::FixedSinCosINTEL { result_id, .. }
+ | Self::FixedSinPiINTEL { result_id, .. }
+ | Self::FixedCosPiINTEL { result_id, .. }
+ | Self::FixedSinCosPiINTEL { result_id, .. }
+ | Self::FixedLogINTEL { result_id, .. }
+ | Self::FixedExpINTEL { result_id, .. }
+ | Self::PtrCastToCrossWorkgroupINTEL { result_id, .. }
+ | Self::CrossWorkgroupCastToPtrINTEL { result_id, .. }
+ | Self::ReadPipeBlockingINTEL { result_id, .. }
+ | Self::WritePipeBlockingINTEL { result_id, .. }
+ | Self::FPGARegINTEL { result_id, .. }
+ | Self::RayQueryGetRayTMinKHR { result_id, .. }
+ | Self::RayQueryGetRayFlagsKHR { result_id, .. }
+ | Self::RayQueryGetIntersectionTKHR { result_id, .. }
+ | Self::RayQueryGetIntersectionInstanceCustomIndexKHR { result_id, .. }
+ | Self::RayQueryGetIntersectionInstanceIdKHR { result_id, .. }
+ | Self::RayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR {
+ result_id,
+ ..
+ }
+ | Self::RayQueryGetIntersectionGeometryIndexKHR { result_id, .. }
+ | Self::RayQueryGetIntersectionPrimitiveIndexKHR { result_id, .. }
+ | Self::RayQueryGetIntersectionBarycentricsKHR { result_id, .. }
+ | Self::RayQueryGetIntersectionFrontFaceKHR { result_id, .. }
+ | Self::RayQueryGetIntersectionCandidateAABBOpaqueKHR { result_id, .. }
+ | Self::RayQueryGetIntersectionObjectRayDirectionKHR { result_id, .. }
+ | Self::RayQueryGetIntersectionObjectRayOriginKHR { result_id, .. }
+ | Self::RayQueryGetWorldRayDirectionKHR { result_id, .. }
+ | Self::RayQueryGetWorldRayOriginKHR { result_id, .. }
+ | Self::RayQueryGetIntersectionObjectToWorldKHR { result_id, .. }
+ | Self::RayQueryGetIntersectionWorldToObjectKHR { result_id, .. }
+ | Self::AtomicFAddEXT { result_id, .. }
+ | Self::TypeBufferSurfaceINTEL { result_id, .. } => Some(*result_id),
+ _ => None,
+ }
+ }
+}
+#[derive(Clone, Debug, PartialEq, Eq)]
+#[doc = "An instruction that is used as the operand of the `SpecConstantOp` instruction."]
+pub enum SpecConstantInstruction {
+ AccessChain {
+ base: Id,
+ indexes: Vec<Id>,
+ },
+ InBoundsAccessChain {
+ base: Id,
+ indexes: Vec<Id>,
+ },
+ PtrAccessChain {
+ base: Id,
+ element: Id,
+ indexes: Vec<Id>,
+ },
+ InBoundsPtrAccessChain {
+ base: Id,
+ element: Id,
+ indexes: Vec<Id>,
+ },
+ VectorShuffle {
+ vector_1: Id,
+ vector_2: Id,
+ components: Vec<u32>,
+ },
+ CompositeExtract {
+ composite: Id,
+ indexes: Vec<u32>,
+ },
+ CompositeInsert {
+ object: Id,
+ composite: Id,
+ indexes: Vec<u32>,
+ },
+ ConvertFToU {
+ float_value: Id,
+ },
+ ConvertFToS {
+ float_value: Id,
+ },
+ ConvertSToF {
+ signed_value: Id,
+ },
+ ConvertUToF {
+ unsigned_value: Id,
+ },
+ UConvert {
+ unsigned_value: Id,
+ },
+ SConvert {
+ signed_value: Id,
+ },
+ FConvert {
+ float_value: Id,
+ },
+ QuantizeToF16 {
+ value: Id,
+ },
+ ConvertPtrToU {
+ pointer: Id,
+ },
+ ConvertUToPtr {
+ integer_value: Id,
+ },
+ PtrCastToGeneric {
+ pointer: Id,
+ },
+ GenericCastToPtr {
+ pointer: Id,
+ },
+ Bitcast {
+ operand: Id,
+ },
+ SNegate {
+ operand: Id,
+ },
+ FNegate {
+ operand: Id,
+ },
+ IAdd {
+ operand1: Id,
+ operand2: Id,
+ },
+ FAdd {
+ operand1: Id,
+ operand2: Id,
+ },
+ ISub {
+ operand1: Id,
+ operand2: Id,
+ },
+ FSub {
+ operand1: Id,
+ operand2: Id,
+ },
+ IMul {
+ operand1: Id,
+ operand2: Id,
+ },
+ FMul {
+ operand1: Id,
+ operand2: Id,
+ },
+ UDiv {
+ operand1: Id,
+ operand2: Id,
+ },
+ SDiv {
+ operand1: Id,
+ operand2: Id,
+ },
+ FDiv {
+ operand1: Id,
+ operand2: Id,
+ },
+ UMod {
+ operand1: Id,
+ operand2: Id,
+ },
+ SRem {
+ operand1: Id,
+ operand2: Id,
+ },
+ SMod {
+ operand1: Id,
+ operand2: Id,
+ },
+ FRem {
+ operand1: Id,
+ operand2: Id,
+ },
+ FMod {
+ operand1: Id,
+ operand2: Id,
+ },
+ LogicalEqual {
+ operand1: Id,
+ operand2: Id,
+ },
+ LogicalNotEqual {
+ operand1: Id,
+ operand2: Id,
+ },
+ LogicalOr {
+ operand1: Id,
+ operand2: Id,
+ },
+ LogicalAnd {
+ operand1: Id,
+ operand2: Id,
+ },
+ LogicalNot {
+ operand: Id,
+ },
+ Select {
+ condition: Id,
+ object_1: Id,
+ object_2: Id,
+ },
+ IEqual {
+ operand1: Id,
+ operand2: Id,
+ },
+ INotEqual {
+ operand1: Id,
+ operand2: Id,
+ },
+ UGreaterThan {
+ operand1: Id,
+ operand2: Id,
+ },
+ SGreaterThan {
+ operand1: Id,
+ operand2: Id,
+ },
+ UGreaterThanEqual {
+ operand1: Id,
+ operand2: Id,
+ },
+ SGreaterThanEqual {
+ operand1: Id,
+ operand2: Id,
+ },
+ ULessThan {
+ operand1: Id,
+ operand2: Id,
+ },
+ SLessThan {
+ operand1: Id,
+ operand2: Id,
+ },
+ ULessThanEqual {
+ operand1: Id,
+ operand2: Id,
+ },
+ SLessThanEqual {
+ operand1: Id,
+ operand2: Id,
+ },
+ ShiftRightLogical {
+ base: Id,
+ shift: Id,
+ },
+ ShiftRightArithmetic {
+ base: Id,
+ shift: Id,
+ },
+ ShiftLeftLogical {
+ base: Id,
+ shift: Id,
+ },
+ BitwiseOr {
+ operand1: Id,
+ operand2: Id,
+ },
+ BitwiseXor {
+ operand1: Id,
+ operand2: Id,
+ },
+ BitwiseAnd {
+ operand1: Id,
+ operand2: Id,
+ },
+ Not {
+ operand: Id,
+ },
+}
+impl SpecConstantInstruction {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<Self, ParseError> {
+ let opcode = (reader.next_u32()? & 0xffff) as u16;
+ Ok(match opcode {
+ 65u16 => Self::AccessChain {
+ base: Id(reader.next_u32()?),
+ indexes: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(Id(reader.next_u32()?));
+ }
+ vec
+ },
+ },
+ 66u16 => Self::InBoundsAccessChain {
+ base: Id(reader.next_u32()?),
+ indexes: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(Id(reader.next_u32()?));
+ }
+ vec
+ },
+ },
+ 67u16 => Self::PtrAccessChain {
+ base: Id(reader.next_u32()?),
+ element: Id(reader.next_u32()?),
+ indexes: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(Id(reader.next_u32()?));
+ }
+ vec
+ },
+ },
+ 70u16 => Self::InBoundsPtrAccessChain {
+ base: Id(reader.next_u32()?),
+ element: Id(reader.next_u32()?),
+ indexes: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(Id(reader.next_u32()?));
+ }
+ vec
+ },
+ },
+ 79u16 => Self::VectorShuffle {
+ vector_1: Id(reader.next_u32()?),
+ vector_2: Id(reader.next_u32()?),
+ components: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(reader.next_u32()?);
+ }
+ vec
+ },
+ },
+ 81u16 => Self::CompositeExtract {
+ composite: Id(reader.next_u32()?),
+ indexes: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(reader.next_u32()?);
+ }
+ vec
+ },
+ },
+ 82u16 => Self::CompositeInsert {
+ object: Id(reader.next_u32()?),
+ composite: Id(reader.next_u32()?),
+ indexes: {
+ let mut vec = Vec::new();
+ while !reader.is_empty() {
+ vec.push(reader.next_u32()?);
+ }
+ vec
+ },
+ },
+ 109u16 => Self::ConvertFToU {
+ float_value: Id(reader.next_u32()?),
+ },
+ 110u16 => Self::ConvertFToS {
+ float_value: Id(reader.next_u32()?),
+ },
+ 111u16 => Self::ConvertSToF {
+ signed_value: Id(reader.next_u32()?),
+ },
+ 112u16 => Self::ConvertUToF {
+ unsigned_value: Id(reader.next_u32()?),
+ },
+ 113u16 => Self::UConvert {
+ unsigned_value: Id(reader.next_u32()?),
+ },
+ 114u16 => Self::SConvert {
+ signed_value: Id(reader.next_u32()?),
+ },
+ 115u16 => Self::FConvert {
+ float_value: Id(reader.next_u32()?),
+ },
+ 116u16 => Self::QuantizeToF16 {
+ value: Id(reader.next_u32()?),
+ },
+ 117u16 => Self::ConvertPtrToU {
+ pointer: Id(reader.next_u32()?),
+ },
+ 120u16 => Self::ConvertUToPtr {
+ integer_value: Id(reader.next_u32()?),
+ },
+ 121u16 => Self::PtrCastToGeneric {
+ pointer: Id(reader.next_u32()?),
+ },
+ 122u16 => Self::GenericCastToPtr {
+ pointer: Id(reader.next_u32()?),
+ },
+ 124u16 => Self::Bitcast {
+ operand: Id(reader.next_u32()?),
+ },
+ 126u16 => Self::SNegate {
+ operand: Id(reader.next_u32()?),
+ },
+ 127u16 => Self::FNegate {
+ operand: Id(reader.next_u32()?),
+ },
+ 128u16 => Self::IAdd {
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 129u16 => Self::FAdd {
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 130u16 => Self::ISub {
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 131u16 => Self::FSub {
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 132u16 => Self::IMul {
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 133u16 => Self::FMul {
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 134u16 => Self::UDiv {
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 135u16 => Self::SDiv {
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 136u16 => Self::FDiv {
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 137u16 => Self::UMod {
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 138u16 => Self::SRem {
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 139u16 => Self::SMod {
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 140u16 => Self::FRem {
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 141u16 => Self::FMod {
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 164u16 => Self::LogicalEqual {
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 165u16 => Self::LogicalNotEqual {
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 166u16 => Self::LogicalOr {
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 167u16 => Self::LogicalAnd {
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 168u16 => Self::LogicalNot {
+ operand: Id(reader.next_u32()?),
+ },
+ 169u16 => Self::Select {
+ condition: Id(reader.next_u32()?),
+ object_1: Id(reader.next_u32()?),
+ object_2: Id(reader.next_u32()?),
+ },
+ 170u16 => Self::IEqual {
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 171u16 => Self::INotEqual {
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 172u16 => Self::UGreaterThan {
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 173u16 => Self::SGreaterThan {
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 174u16 => Self::UGreaterThanEqual {
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 175u16 => Self::SGreaterThanEqual {
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 176u16 => Self::ULessThan {
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 177u16 => Self::SLessThan {
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 178u16 => Self::ULessThanEqual {
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 179u16 => Self::SLessThanEqual {
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 194u16 => Self::ShiftRightLogical {
+ base: Id(reader.next_u32()?),
+ shift: Id(reader.next_u32()?),
+ },
+ 195u16 => Self::ShiftRightArithmetic {
+ base: Id(reader.next_u32()?),
+ shift: Id(reader.next_u32()?),
+ },
+ 196u16 => Self::ShiftLeftLogical {
+ base: Id(reader.next_u32()?),
+ shift: Id(reader.next_u32()?),
+ },
+ 197u16 => Self::BitwiseOr {
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 198u16 => Self::BitwiseXor {
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 199u16 => Self::BitwiseAnd {
+ operand1: Id(reader.next_u32()?),
+ operand2: Id(reader.next_u32()?),
+ },
+ 200u16 => Self::Not {
+ operand: Id(reader.next_u32()?),
+ },
+ opcode => return Err(reader.map_err(ParseErrors::UnknownSpecConstantOpcode(opcode))),
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub struct ImageOperands {
+ pub bias: Option<Id>,
+ pub lod: Option<Id>,
+ pub grad: Option<(Id, Id)>,
+ pub const_offset: Option<Id>,
+ pub offset: Option<Id>,
+ pub const_offsets: Option<Id>,
+ pub sample: Option<Id>,
+ pub min_lod: Option<Id>,
+ pub make_texel_available: Option<Id>,
+ pub make_texel_visible: Option<Id>,
+ pub non_private_texel: bool,
+ pub volatile_texel: bool,
+ pub sign_extend: bool,
+ pub zero_extend: bool,
+ pub nontemporal: bool,
+ pub offsets: Option<Id>,
+}
+impl ImageOperands {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<ImageOperands, ParseError> {
+ let value = reader.next_u32()?;
+ Ok(Self {
+ bias: if value & 1u32 != 0 {
+ Some(Id(reader.next_u32()?))
+ } else {
+ None
+ },
+ lod: if value & 2u32 != 0 {
+ Some(Id(reader.next_u32()?))
+ } else {
+ None
+ },
+ grad: if value & 4u32 != 0 {
+ Some((Id(reader.next_u32()?), Id(reader.next_u32()?)))
+ } else {
+ None
+ },
+ const_offset: if value & 8u32 != 0 {
+ Some(Id(reader.next_u32()?))
+ } else {
+ None
+ },
+ offset: if value & 16u32 != 0 {
+ Some(Id(reader.next_u32()?))
+ } else {
+ None
+ },
+ const_offsets: if value & 32u32 != 0 {
+ Some(Id(reader.next_u32()?))
+ } else {
+ None
+ },
+ sample: if value & 64u32 != 0 {
+ Some(Id(reader.next_u32()?))
+ } else {
+ None
+ },
+ min_lod: if value & 128u32 != 0 {
+ Some(Id(reader.next_u32()?))
+ } else {
+ None
+ },
+ make_texel_available: if value & 256u32 != 0 {
+ Some(Id(reader.next_u32()?))
+ } else {
+ None
+ },
+ make_texel_visible: if value & 512u32 != 0 {
+ Some(Id(reader.next_u32()?))
+ } else {
+ None
+ },
+ non_private_texel: value & 1024u32 != 0,
+ volatile_texel: value & 2048u32 != 0,
+ sign_extend: value & 4096u32 != 0,
+ zero_extend: value & 8192u32 != 0,
+ nontemporal: value & 16384u32 != 0,
+ offsets: if value & 65536u32 != 0 {
+ Some(Id(reader.next_u32()?))
+ } else {
+ None
+ },
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub struct FPFastMathMode {
+ pub not_nan: bool,
+ pub not_inf: bool,
+ pub nsz: bool,
+ pub allow_recip: bool,
+ pub fast: bool,
+ pub allow_contract_fast_intel: bool,
+ pub allow_reassoc_intel: bool,
+}
+impl FPFastMathMode {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<FPFastMathMode, ParseError> {
+ let value = reader.next_u32()?;
+ Ok(Self {
+ not_nan: value & 1u32 != 0,
+ not_inf: value & 2u32 != 0,
+ nsz: value & 4u32 != 0,
+ allow_recip: value & 8u32 != 0,
+ fast: value & 16u32 != 0,
+ allow_contract_fast_intel: value & 65536u32 != 0,
+ allow_reassoc_intel: value & 131072u32 != 0,
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub struct SelectionControl {
+ pub flatten: bool,
+ pub dont_flatten: bool,
+}
+impl SelectionControl {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<SelectionControl, ParseError> {
+ let value = reader.next_u32()?;
+ Ok(Self {
+ flatten: value & 1u32 != 0,
+ dont_flatten: value & 2u32 != 0,
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub struct LoopControl {
+ pub unroll: bool,
+ pub dont_unroll: bool,
+ pub dependency_infinite: bool,
+ pub dependency_length: Option<u32>,
+ pub min_iterations: Option<u32>,
+ pub max_iterations: Option<u32>,
+ pub iteration_multiple: Option<u32>,
+ pub peel_count: Option<u32>,
+ pub partial_count: Option<u32>,
+ pub initiation_interval_intel: Option<u32>,
+ pub max_concurrency_intel: Option<u32>,
+ pub dependency_array_intel: Option<u32>,
+ pub pipeline_enable_intel: Option<u32>,
+ pub loop_coalesce_intel: Option<u32>,
+ pub max_interleaving_intel: Option<u32>,
+ pub speculated_iterations_intel: Option<u32>,
+ pub no_fusion_intel: Option<u32>,
+}
+impl LoopControl {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<LoopControl, ParseError> {
+ let value = reader.next_u32()?;
+ Ok(Self {
+ unroll: value & 1u32 != 0,
+ dont_unroll: value & 2u32 != 0,
+ dependency_infinite: value & 4u32 != 0,
+ dependency_length: if value & 8u32 != 0 {
+ Some(reader.next_u32()?)
+ } else {
+ None
+ },
+ min_iterations: if value & 16u32 != 0 {
+ Some(reader.next_u32()?)
+ } else {
+ None
+ },
+ max_iterations: if value & 32u32 != 0 {
+ Some(reader.next_u32()?)
+ } else {
+ None
+ },
+ iteration_multiple: if value & 64u32 != 0 {
+ Some(reader.next_u32()?)
+ } else {
+ None
+ },
+ peel_count: if value & 128u32 != 0 {
+ Some(reader.next_u32()?)
+ } else {
+ None
+ },
+ partial_count: if value & 256u32 != 0 {
+ Some(reader.next_u32()?)
+ } else {
+ None
+ },
+ initiation_interval_intel: if value & 65536u32 != 0 {
+ Some(reader.next_u32()?)
+ } else {
+ None
+ },
+ max_concurrency_intel: if value & 131072u32 != 0 {
+ Some(reader.next_u32()?)
+ } else {
+ None
+ },
+ dependency_array_intel: if value & 262144u32 != 0 {
+ Some(reader.next_u32()?)
+ } else {
+ None
+ },
+ pipeline_enable_intel: if value & 524288u32 != 0 {
+ Some(reader.next_u32()?)
+ } else {
+ None
+ },
+ loop_coalesce_intel: if value & 1048576u32 != 0 {
+ Some(reader.next_u32()?)
+ } else {
+ None
+ },
+ max_interleaving_intel: if value & 2097152u32 != 0 {
+ Some(reader.next_u32()?)
+ } else {
+ None
+ },
+ speculated_iterations_intel: if value & 4194304u32 != 0 {
+ Some(reader.next_u32()?)
+ } else {
+ None
+ },
+ no_fusion_intel: if value & 8388608u32 != 0 {
+ Some(reader.next_u32()?)
+ } else {
+ None
+ },
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub struct FunctionControl {
+ pub inline: bool,
+ pub dont_inline: bool,
+ pub pure: bool,
+ pub constant: bool,
+ pub opt_none_intel: bool,
+}
+impl FunctionControl {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<FunctionControl, ParseError> {
+ let value = reader.next_u32()?;
+ Ok(Self {
+ inline: value & 1u32 != 0,
+ dont_inline: value & 2u32 != 0,
+ pure: value & 4u32 != 0,
+ constant: value & 8u32 != 0,
+ opt_none_intel: value & 65536u32 != 0,
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub struct MemorySemantics {
+ pub acquire: bool,
+ pub release: bool,
+ pub acquire_release: bool,
+ pub sequentially_consistent: bool,
+ pub uniform_memory: bool,
+ pub subgroup_memory: bool,
+ pub workgroup_memory: bool,
+ pub cross_workgroup_memory: bool,
+ pub atomic_counter_memory: bool,
+ pub image_memory: bool,
+ pub output_memory: bool,
+ pub make_available: bool,
+ pub make_visible: bool,
+ pub volatile: bool,
+}
+impl MemorySemantics {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<MemorySemantics, ParseError> {
+ let value = reader.next_u32()?;
+ Ok(Self {
+ acquire: value & 2u32 != 0,
+ release: value & 4u32 != 0,
+ acquire_release: value & 8u32 != 0,
+ sequentially_consistent: value & 16u32 != 0,
+ uniform_memory: value & 64u32 != 0,
+ subgroup_memory: value & 128u32 != 0,
+ workgroup_memory: value & 256u32 != 0,
+ cross_workgroup_memory: value & 512u32 != 0,
+ atomic_counter_memory: value & 1024u32 != 0,
+ image_memory: value & 2048u32 != 0,
+ output_memory: value & 4096u32 != 0,
+ make_available: value & 8192u32 != 0,
+ make_visible: value & 16384u32 != 0,
+ volatile: value & 32768u32 != 0,
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub struct MemoryAccess {
+ pub volatile: bool,
+ pub aligned: Option<u32>,
+ pub nontemporal: bool,
+ pub make_pointer_available: Option<Id>,
+ pub make_pointer_visible: Option<Id>,
+ pub non_private_pointer: bool,
+}
+impl MemoryAccess {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<MemoryAccess, ParseError> {
+ let value = reader.next_u32()?;
+ Ok(Self {
+ volatile: value & 1u32 != 0,
+ aligned: if value & 2u32 != 0 {
+ Some(reader.next_u32()?)
+ } else {
+ None
+ },
+ nontemporal: value & 4u32 != 0,
+ make_pointer_available: if value & 8u32 != 0 {
+ Some(Id(reader.next_u32()?))
+ } else {
+ None
+ },
+ make_pointer_visible: if value & 16u32 != 0 {
+ Some(Id(reader.next_u32()?))
+ } else {
+ None
+ },
+ non_private_pointer: value & 32u32 != 0,
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub struct KernelProfilingInfo {
+ pub cmd_exec_time: bool,
+}
+impl KernelProfilingInfo {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<KernelProfilingInfo, ParseError> {
+ let value = reader.next_u32()?;
+ Ok(Self {
+ cmd_exec_time: value & 1u32 != 0,
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub struct RayFlags {
+ pub opaque_khr: bool,
+ pub no_opaque_khr: bool,
+ pub terminate_on_first_hit_khr: bool,
+ pub skip_closest_hit_shader_khr: bool,
+ pub cull_back_facing_triangles_khr: bool,
+ pub cull_front_facing_triangles_khr: bool,
+ pub cull_opaque_khr: bool,
+ pub cull_no_opaque_khr: bool,
+ pub skip_triangles_khr: bool,
+ pub skip_aab_bs_khr: bool,
+}
+impl RayFlags {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<RayFlags, ParseError> {
+ let value = reader.next_u32()?;
+ Ok(Self {
+ opaque_khr: value & 1u32 != 0,
+ no_opaque_khr: value & 2u32 != 0,
+ terminate_on_first_hit_khr: value & 4u32 != 0,
+ skip_closest_hit_shader_khr: value & 8u32 != 0,
+ cull_back_facing_triangles_khr: value & 16u32 != 0,
+ cull_front_facing_triangles_khr: value & 32u32 != 0,
+ cull_opaque_khr: value & 64u32 != 0,
+ cull_no_opaque_khr: value & 128u32 != 0,
+ skip_triangles_khr: value & 256u32 != 0,
+ skip_aab_bs_khr: value & 512u32 != 0,
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub struct FragmentShadingRate {
+ pub vertical2_pixels: bool,
+ pub vertical4_pixels: bool,
+ pub horizontal2_pixels: bool,
+ pub horizontal4_pixels: bool,
+}
+impl FragmentShadingRate {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<FragmentShadingRate, ParseError> {
+ let value = reader.next_u32()?;
+ Ok(Self {
+ vertical2_pixels: value & 1u32 != 0,
+ vertical4_pixels: value & 2u32 != 0,
+ horizontal2_pixels: value & 4u32 != 0,
+ horizontal4_pixels: value & 8u32 != 0,
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub enum SourceLanguage {
+ Unknown,
+ ESSL,
+ GLSL,
+ OpenCL_C,
+ OpenCL_CPP,
+ HLSL,
+ CPP_for_OpenCL,
+}
+impl SourceLanguage {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<SourceLanguage, ParseError> {
+ Ok(match reader.next_u32()? {
+ 0u32 => Self::Unknown,
+ 1u32 => Self::ESSL,
+ 2u32 => Self::GLSL,
+ 3u32 => Self::OpenCL_C,
+ 4u32 => Self::OpenCL_CPP,
+ 5u32 => Self::HLSL,
+ 6u32 => Self::CPP_for_OpenCL,
+ value => {
+ return Err(reader.map_err(ParseErrors::UnknownEnumerant("SourceLanguage", value)))
+ }
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub enum ExecutionModel {
+ Vertex,
+ TessellationControl,
+ TessellationEvaluation,
+ Geometry,
+ Fragment,
+ GLCompute,
+ Kernel,
+ TaskNV,
+ MeshNV,
+ RayGenerationKHR,
+ IntersectionKHR,
+ AnyHitKHR,
+ ClosestHitKHR,
+ MissKHR,
+ CallableKHR,
+}
+impl ExecutionModel {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<ExecutionModel, ParseError> {
+ Ok(match reader.next_u32()? {
+ 0u32 => Self::Vertex,
+ 1u32 => Self::TessellationControl,
+ 2u32 => Self::TessellationEvaluation,
+ 3u32 => Self::Geometry,
+ 4u32 => Self::Fragment,
+ 5u32 => Self::GLCompute,
+ 6u32 => Self::Kernel,
+ 5267u32 => Self::TaskNV,
+ 5268u32 => Self::MeshNV,
+ 5313u32 => Self::RayGenerationKHR,
+ 5314u32 => Self::IntersectionKHR,
+ 5315u32 => Self::AnyHitKHR,
+ 5316u32 => Self::ClosestHitKHR,
+ 5317u32 => Self::MissKHR,
+ 5318u32 => Self::CallableKHR,
+ value => {
+ return Err(reader.map_err(ParseErrors::UnknownEnumerant("ExecutionModel", value)))
+ }
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub enum AddressingModel {
+ Logical,
+ Physical32,
+ Physical64,
+ PhysicalStorageBuffer64,
+}
+impl AddressingModel {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<AddressingModel, ParseError> {
+ Ok(match reader.next_u32()? {
+ 0u32 => Self::Logical,
+ 1u32 => Self::Physical32,
+ 2u32 => Self::Physical64,
+ 5348u32 => Self::PhysicalStorageBuffer64,
+ value => {
+ return Err(reader.map_err(ParseErrors::UnknownEnumerant("AddressingModel", value)))
+ }
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub enum MemoryModel {
+ Simple,
+ GLSL450,
+ OpenCL,
+ Vulkan,
+}
+impl MemoryModel {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<MemoryModel, ParseError> {
+ Ok(match reader.next_u32()? {
+ 0u32 => Self::Simple,
+ 1u32 => Self::GLSL450,
+ 2u32 => Self::OpenCL,
+ 3u32 => Self::Vulkan,
+ value => {
+ return Err(reader.map_err(ParseErrors::UnknownEnumerant("MemoryModel", value)))
+ }
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub enum ExecutionMode {
+ Invocations {
+ number_of_invocation_invocations: u32,
+ },
+ SpacingEqual,
+ SpacingFractionalEven,
+ SpacingFractionalOdd,
+ VertexOrderCw,
+ VertexOrderCcw,
+ PixelCenterInteger,
+ OriginUpperLeft,
+ OriginLowerLeft,
+ EarlyFragmentTests,
+ PointMode,
+ Xfb,
+ DepthReplacing,
+ DepthGreater,
+ DepthLess,
+ DepthUnchanged,
+ LocalSize {
+ x_size: u32,
+ y_size: u32,
+ z_size: u32,
+ },
+ LocalSizeHint {
+ x_size: u32,
+ y_size: u32,
+ z_size: u32,
+ },
+ InputPoints,
+ InputLines,
+ InputLinesAdjacency,
+ Triangles,
+ InputTrianglesAdjacency,
+ Quads,
+ Isolines,
+ OutputVertices {
+ vertex_count: u32,
+ },
+ OutputPoints,
+ OutputLineStrip,
+ OutputTriangleStrip,
+ VecTypeHint {
+ vector_type: u32,
+ },
+ ContractionOff,
+ Initializer,
+ Finalizer,
+ SubgroupSize {
+ subgroup_size: u32,
+ },
+ SubgroupsPerWorkgroup {
+ subgroups_per_workgroup: u32,
+ },
+ SubgroupsPerWorkgroupId {
+ subgroups_per_workgroup: Id,
+ },
+ LocalSizeId {
+ x_size: Id,
+ y_size: Id,
+ z_size: Id,
+ },
+ LocalSizeHintId {
+ x_size_hint: Id,
+ y_size_hint: Id,
+ z_size_hint: Id,
+ },
+ SubgroupUniformControlFlowKHR,
+ PostDepthCoverage,
+ DenormPreserve {
+ target_width: u32,
+ },
+ DenormFlushToZero {
+ target_width: u32,
+ },
+ SignedZeroInfNanPreserve {
+ target_width: u32,
+ },
+ RoundingModeRTE {
+ target_width: u32,
+ },
+ RoundingModeRTZ {
+ target_width: u32,
+ },
+ StencilRefReplacingEXT,
+ OutputLinesNV,
+ OutputPrimitivesNV {
+ primitive_count: u32,
+ },
+ DerivativeGroupQuadsNV,
+ DerivativeGroupLinearNV,
+ OutputTrianglesNV,
+ PixelInterlockOrderedEXT,
+ PixelInterlockUnorderedEXT,
+ SampleInterlockOrderedEXT,
+ SampleInterlockUnorderedEXT,
+ ShadingRateInterlockOrderedEXT,
+ ShadingRateInterlockUnorderedEXT,
+ SharedLocalMemorySizeINTEL {
+ size: u32,
+ },
+ RoundingModeRTPINTEL {
+ target_width: u32,
+ },
+ RoundingModeRTNINTEL {
+ target_width: u32,
+ },
+ FloatingPointModeALTINTEL {
+ target_width: u32,
+ },
+ FloatingPointModeIEEEINTEL {
+ target_width: u32,
+ },
+ MaxWorkgroupSizeINTEL {
+ max_x_size: u32,
+ max_y_size: u32,
+ max_z_size: u32,
+ },
+ MaxWorkDimINTEL {
+ max_dimensions: u32,
+ },
+ NoGlobalOffsetINTEL,
+ NumSIMDWorkitemsINTEL {
+ vector_width: u32,
+ },
+ SchedulerTargetFmaxMhzINTEL {
+ target_fmax: u32,
+ },
+}
+impl ExecutionMode {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<ExecutionMode, ParseError> {
+ Ok(match reader.next_u32()? {
+ 0u32 => Self::Invocations {
+ number_of_invocation_invocations: reader.next_u32()?,
+ },
+ 1u32 => Self::SpacingEqual,
+ 2u32 => Self::SpacingFractionalEven,
+ 3u32 => Self::SpacingFractionalOdd,
+ 4u32 => Self::VertexOrderCw,
+ 5u32 => Self::VertexOrderCcw,
+ 6u32 => Self::PixelCenterInteger,
+ 7u32 => Self::OriginUpperLeft,
+ 8u32 => Self::OriginLowerLeft,
+ 9u32 => Self::EarlyFragmentTests,
+ 10u32 => Self::PointMode,
+ 11u32 => Self::Xfb,
+ 12u32 => Self::DepthReplacing,
+ 14u32 => Self::DepthGreater,
+ 15u32 => Self::DepthLess,
+ 16u32 => Self::DepthUnchanged,
+ 17u32 => Self::LocalSize {
+ x_size: reader.next_u32()?,
+ y_size: reader.next_u32()?,
+ z_size: reader.next_u32()?,
+ },
+ 18u32 => Self::LocalSizeHint {
+ x_size: reader.next_u32()?,
+ y_size: reader.next_u32()?,
+ z_size: reader.next_u32()?,
+ },
+ 19u32 => Self::InputPoints,
+ 20u32 => Self::InputLines,
+ 21u32 => Self::InputLinesAdjacency,
+ 22u32 => Self::Triangles,
+ 23u32 => Self::InputTrianglesAdjacency,
+ 24u32 => Self::Quads,
+ 25u32 => Self::Isolines,
+ 26u32 => Self::OutputVertices {
+ vertex_count: reader.next_u32()?,
+ },
+ 27u32 => Self::OutputPoints,
+ 28u32 => Self::OutputLineStrip,
+ 29u32 => Self::OutputTriangleStrip,
+ 30u32 => Self::VecTypeHint {
+ vector_type: reader.next_u32()?,
+ },
+ 31u32 => Self::ContractionOff,
+ 33u32 => Self::Initializer,
+ 34u32 => Self::Finalizer,
+ 35u32 => Self::SubgroupSize {
+ subgroup_size: reader.next_u32()?,
+ },
+ 36u32 => Self::SubgroupsPerWorkgroup {
+ subgroups_per_workgroup: reader.next_u32()?,
+ },
+ 37u32 => Self::SubgroupsPerWorkgroupId {
+ subgroups_per_workgroup: Id(reader.next_u32()?),
+ },
+ 38u32 => Self::LocalSizeId {
+ x_size: Id(reader.next_u32()?),
+ y_size: Id(reader.next_u32()?),
+ z_size: Id(reader.next_u32()?),
+ },
+ 39u32 => Self::LocalSizeHintId {
+ x_size_hint: Id(reader.next_u32()?),
+ y_size_hint: Id(reader.next_u32()?),
+ z_size_hint: Id(reader.next_u32()?),
+ },
+ 4421u32 => Self::SubgroupUniformControlFlowKHR,
+ 4446u32 => Self::PostDepthCoverage,
+ 4459u32 => Self::DenormPreserve {
+ target_width: reader.next_u32()?,
+ },
+ 4460u32 => Self::DenormFlushToZero {
+ target_width: reader.next_u32()?,
+ },
+ 4461u32 => Self::SignedZeroInfNanPreserve {
+ target_width: reader.next_u32()?,
+ },
+ 4462u32 => Self::RoundingModeRTE {
+ target_width: reader.next_u32()?,
+ },
+ 4463u32 => Self::RoundingModeRTZ {
+ target_width: reader.next_u32()?,
+ },
+ 5027u32 => Self::StencilRefReplacingEXT,
+ 5269u32 => Self::OutputLinesNV,
+ 5270u32 => Self::OutputPrimitivesNV {
+ primitive_count: reader.next_u32()?,
+ },
+ 5289u32 => Self::DerivativeGroupQuadsNV,
+ 5290u32 => Self::DerivativeGroupLinearNV,
+ 5298u32 => Self::OutputTrianglesNV,
+ 5366u32 => Self::PixelInterlockOrderedEXT,
+ 5367u32 => Self::PixelInterlockUnorderedEXT,
+ 5368u32 => Self::SampleInterlockOrderedEXT,
+ 5369u32 => Self::SampleInterlockUnorderedEXT,
+ 5370u32 => Self::ShadingRateInterlockOrderedEXT,
+ 5371u32 => Self::ShadingRateInterlockUnorderedEXT,
+ 5618u32 => Self::SharedLocalMemorySizeINTEL {
+ size: reader.next_u32()?,
+ },
+ 5620u32 => Self::RoundingModeRTPINTEL {
+ target_width: reader.next_u32()?,
+ },
+ 5621u32 => Self::RoundingModeRTNINTEL {
+ target_width: reader.next_u32()?,
+ },
+ 5622u32 => Self::FloatingPointModeALTINTEL {
+ target_width: reader.next_u32()?,
+ },
+ 5623u32 => Self::FloatingPointModeIEEEINTEL {
+ target_width: reader.next_u32()?,
+ },
+ 5893u32 => Self::MaxWorkgroupSizeINTEL {
+ max_x_size: reader.next_u32()?,
+ max_y_size: reader.next_u32()?,
+ max_z_size: reader.next_u32()?,
+ },
+ 5894u32 => Self::MaxWorkDimINTEL {
+ max_dimensions: reader.next_u32()?,
+ },
+ 5895u32 => Self::NoGlobalOffsetINTEL,
+ 5896u32 => Self::NumSIMDWorkitemsINTEL {
+ vector_width: reader.next_u32()?,
+ },
+ 5903u32 => Self::SchedulerTargetFmaxMhzINTEL {
+ target_fmax: reader.next_u32()?,
+ },
+ value => {
+ return Err(reader.map_err(ParseErrors::UnknownEnumerant("ExecutionMode", value)))
+ }
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub enum StorageClass {
+ UniformConstant,
+ Input,
+ Uniform,
+ Output,
+ Workgroup,
+ CrossWorkgroup,
+ Private,
+ Function,
+ Generic,
+ PushConstant,
+ AtomicCounter,
+ Image,
+ StorageBuffer,
+ CallableDataKHR,
+ IncomingCallableDataKHR,
+ RayPayloadKHR,
+ HitAttributeKHR,
+ IncomingRayPayloadKHR,
+ ShaderRecordBufferKHR,
+ PhysicalStorageBuffer,
+ CodeSectionINTEL,
+ DeviceOnlyINTEL,
+ HostOnlyINTEL,
+}
+impl StorageClass {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<StorageClass, ParseError> {
+ Ok(match reader.next_u32()? {
+ 0u32 => Self::UniformConstant,
+ 1u32 => Self::Input,
+ 2u32 => Self::Uniform,
+ 3u32 => Self::Output,
+ 4u32 => Self::Workgroup,
+ 5u32 => Self::CrossWorkgroup,
+ 6u32 => Self::Private,
+ 7u32 => Self::Function,
+ 8u32 => Self::Generic,
+ 9u32 => Self::PushConstant,
+ 10u32 => Self::AtomicCounter,
+ 11u32 => Self::Image,
+ 12u32 => Self::StorageBuffer,
+ 5328u32 => Self::CallableDataKHR,
+ 5329u32 => Self::IncomingCallableDataKHR,
+ 5338u32 => Self::RayPayloadKHR,
+ 5339u32 => Self::HitAttributeKHR,
+ 5342u32 => Self::IncomingRayPayloadKHR,
+ 5343u32 => Self::ShaderRecordBufferKHR,
+ 5349u32 => Self::PhysicalStorageBuffer,
+ 5605u32 => Self::CodeSectionINTEL,
+ 5936u32 => Self::DeviceOnlyINTEL,
+ 5937u32 => Self::HostOnlyINTEL,
+ value => {
+ return Err(reader.map_err(ParseErrors::UnknownEnumerant("StorageClass", value)))
+ }
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub enum Dim {
+ Dim1D,
+ Dim2D,
+ Dim3D,
+ Cube,
+ Rect,
+ Buffer,
+ SubpassData,
+}
+impl Dim {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<Dim, ParseError> {
+ Ok(match reader.next_u32()? {
+ 0u32 => Self::Dim1D,
+ 1u32 => Self::Dim2D,
+ 2u32 => Self::Dim3D,
+ 3u32 => Self::Cube,
+ 4u32 => Self::Rect,
+ 5u32 => Self::Buffer,
+ 6u32 => Self::SubpassData,
+ value => return Err(reader.map_err(ParseErrors::UnknownEnumerant("Dim", value))),
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub enum SamplerAddressingMode {
+ None,
+ ClampToEdge,
+ Clamp,
+ Repeat,
+ RepeatMirrored,
+}
+impl SamplerAddressingMode {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<SamplerAddressingMode, ParseError> {
+ Ok(match reader.next_u32()? {
+ 0u32 => Self::None,
+ 1u32 => Self::ClampToEdge,
+ 2u32 => Self::Clamp,
+ 3u32 => Self::Repeat,
+ 4u32 => Self::RepeatMirrored,
+ value => {
+ return Err(reader.map_err(ParseErrors::UnknownEnumerant(
+ "SamplerAddressingMode",
+ value,
+ )))
+ }
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub enum SamplerFilterMode {
+ Nearest,
+ Linear,
+}
+impl SamplerFilterMode {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<SamplerFilterMode, ParseError> {
+ Ok(match reader.next_u32()? {
+ 0u32 => Self::Nearest,
+ 1u32 => Self::Linear,
+ value => {
+ return Err(
+ reader.map_err(ParseErrors::UnknownEnumerant("SamplerFilterMode", value))
+ )
+ }
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub enum ImageFormat {
+ Unknown,
+ Rgba32f,
+ Rgba16f,
+ R32f,
+ Rgba8,
+ Rgba8Snorm,
+ Rg32f,
+ Rg16f,
+ R11fG11fB10f,
+ R16f,
+ Rgba16,
+ Rgb10A2,
+ Rg16,
+ Rg8,
+ R16,
+ R8,
+ Rgba16Snorm,
+ Rg16Snorm,
+ Rg8Snorm,
+ R16Snorm,
+ R8Snorm,
+ Rgba32i,
+ Rgba16i,
+ Rgba8i,
+ R32i,
+ Rg32i,
+ Rg16i,
+ Rg8i,
+ R16i,
+ R8i,
+ Rgba32ui,
+ Rgba16ui,
+ Rgba8ui,
+ R32ui,
+ Rgb10a2ui,
+ Rg32ui,
+ Rg16ui,
+ Rg8ui,
+ R16ui,
+ R8ui,
+ R64ui,
+ R64i,
+}
+impl ImageFormat {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<ImageFormat, ParseError> {
+ Ok(match reader.next_u32()? {
+ 0u32 => Self::Unknown,
+ 1u32 => Self::Rgba32f,
+ 2u32 => Self::Rgba16f,
+ 3u32 => Self::R32f,
+ 4u32 => Self::Rgba8,
+ 5u32 => Self::Rgba8Snorm,
+ 6u32 => Self::Rg32f,
+ 7u32 => Self::Rg16f,
+ 8u32 => Self::R11fG11fB10f,
+ 9u32 => Self::R16f,
+ 10u32 => Self::Rgba16,
+ 11u32 => Self::Rgb10A2,
+ 12u32 => Self::Rg16,
+ 13u32 => Self::Rg8,
+ 14u32 => Self::R16,
+ 15u32 => Self::R8,
+ 16u32 => Self::Rgba16Snorm,
+ 17u32 => Self::Rg16Snorm,
+ 18u32 => Self::Rg8Snorm,
+ 19u32 => Self::R16Snorm,
+ 20u32 => Self::R8Snorm,
+ 21u32 => Self::Rgba32i,
+ 22u32 => Self::Rgba16i,
+ 23u32 => Self::Rgba8i,
+ 24u32 => Self::R32i,
+ 25u32 => Self::Rg32i,
+ 26u32 => Self::Rg16i,
+ 27u32 => Self::Rg8i,
+ 28u32 => Self::R16i,
+ 29u32 => Self::R8i,
+ 30u32 => Self::Rgba32ui,
+ 31u32 => Self::Rgba16ui,
+ 32u32 => Self::Rgba8ui,
+ 33u32 => Self::R32ui,
+ 34u32 => Self::Rgb10a2ui,
+ 35u32 => Self::Rg32ui,
+ 36u32 => Self::Rg16ui,
+ 37u32 => Self::Rg8ui,
+ 38u32 => Self::R16ui,
+ 39u32 => Self::R8ui,
+ 40u32 => Self::R64ui,
+ 41u32 => Self::R64i,
+ value => {
+ return Err(reader.map_err(ParseErrors::UnknownEnumerant("ImageFormat", value)))
+ }
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub enum ImageChannelOrder {
+ R,
+ A,
+ RG,
+ RA,
+ RGB,
+ RGBA,
+ BGRA,
+ ARGB,
+ Intensity,
+ Luminance,
+ Rx,
+ RGx,
+ RGBx,
+ Depth,
+ DepthStencil,
+ sRGB,
+ sRGBx,
+ sRGBA,
+ sBGRA,
+ ABGR,
+}
+impl ImageChannelOrder {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<ImageChannelOrder, ParseError> {
+ Ok(match reader.next_u32()? {
+ 0u32 => Self::R,
+ 1u32 => Self::A,
+ 2u32 => Self::RG,
+ 3u32 => Self::RA,
+ 4u32 => Self::RGB,
+ 5u32 => Self::RGBA,
+ 6u32 => Self::BGRA,
+ 7u32 => Self::ARGB,
+ 8u32 => Self::Intensity,
+ 9u32 => Self::Luminance,
+ 10u32 => Self::Rx,
+ 11u32 => Self::RGx,
+ 12u32 => Self::RGBx,
+ 13u32 => Self::Depth,
+ 14u32 => Self::DepthStencil,
+ 15u32 => Self::sRGB,
+ 16u32 => Self::sRGBx,
+ 17u32 => Self::sRGBA,
+ 18u32 => Self::sBGRA,
+ 19u32 => Self::ABGR,
+ value => {
+ return Err(
+ reader.map_err(ParseErrors::UnknownEnumerant("ImageChannelOrder", value))
+ )
+ }
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub enum ImageChannelDataType {
+ SnormInt8,
+ SnormInt16,
+ UnormInt8,
+ UnormInt16,
+ UnormShort565,
+ UnormShort555,
+ UnormInt101010,
+ SignedInt8,
+ SignedInt16,
+ SignedInt32,
+ UnsignedInt8,
+ UnsignedInt16,
+ UnsignedInt32,
+ HalfFloat,
+ Float,
+ UnormInt24,
+ UnormInt101010_2,
+}
+impl ImageChannelDataType {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<ImageChannelDataType, ParseError> {
+ Ok(match reader.next_u32()? {
+ 0u32 => Self::SnormInt8,
+ 1u32 => Self::SnormInt16,
+ 2u32 => Self::UnormInt8,
+ 3u32 => Self::UnormInt16,
+ 4u32 => Self::UnormShort565,
+ 5u32 => Self::UnormShort555,
+ 6u32 => Self::UnormInt101010,
+ 7u32 => Self::SignedInt8,
+ 8u32 => Self::SignedInt16,
+ 9u32 => Self::SignedInt32,
+ 10u32 => Self::UnsignedInt8,
+ 11u32 => Self::UnsignedInt16,
+ 12u32 => Self::UnsignedInt32,
+ 13u32 => Self::HalfFloat,
+ 14u32 => Self::Float,
+ 15u32 => Self::UnormInt24,
+ 16u32 => Self::UnormInt101010_2,
+ value => {
+ return Err(
+ reader.map_err(ParseErrors::UnknownEnumerant("ImageChannelDataType", value))
+ )
+ }
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub enum FPRoundingMode {
+ RTE,
+ RTZ,
+ RTP,
+ RTN,
+}
+impl FPRoundingMode {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<FPRoundingMode, ParseError> {
+ Ok(match reader.next_u32()? {
+ 0u32 => Self::RTE,
+ 1u32 => Self::RTZ,
+ 2u32 => Self::RTP,
+ 3u32 => Self::RTN,
+ value => {
+ return Err(reader.map_err(ParseErrors::UnknownEnumerant("FPRoundingMode", value)))
+ }
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub enum FPDenormMode {
+ Preserve,
+ FlushToZero,
+}
+impl FPDenormMode {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<FPDenormMode, ParseError> {
+ Ok(match reader.next_u32()? {
+ 0u32 => Self::Preserve,
+ 1u32 => Self::FlushToZero,
+ value => {
+ return Err(reader.map_err(ParseErrors::UnknownEnumerant("FPDenormMode", value)))
+ }
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub enum QuantizationModes {
+ TRN,
+ TRN_ZERO,
+ RND,
+ RND_ZERO,
+ RND_INF,
+ RND_MIN_INF,
+ RND_CONV,
+ RND_CONV_ODD,
+}
+impl QuantizationModes {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<QuantizationModes, ParseError> {
+ Ok(match reader.next_u32()? {
+ 0u32 => Self::TRN,
+ 1u32 => Self::TRN_ZERO,
+ 2u32 => Self::RND,
+ 3u32 => Self::RND_ZERO,
+ 4u32 => Self::RND_INF,
+ 5u32 => Self::RND_MIN_INF,
+ 6u32 => Self::RND_CONV,
+ 7u32 => Self::RND_CONV_ODD,
+ value => {
+ return Err(
+ reader.map_err(ParseErrors::UnknownEnumerant("QuantizationModes", value))
+ )
+ }
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub enum FPOperationMode {
+ IEEE,
+ ALT,
+}
+impl FPOperationMode {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<FPOperationMode, ParseError> {
+ Ok(match reader.next_u32()? {
+ 0u32 => Self::IEEE,
+ 1u32 => Self::ALT,
+ value => {
+ return Err(reader.map_err(ParseErrors::UnknownEnumerant("FPOperationMode", value)))
+ }
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub enum OverflowModes {
+ WRAP,
+ SAT,
+ SAT_ZERO,
+ SAT_SYM,
+}
+impl OverflowModes {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<OverflowModes, ParseError> {
+ Ok(match reader.next_u32()? {
+ 0u32 => Self::WRAP,
+ 1u32 => Self::SAT,
+ 2u32 => Self::SAT_ZERO,
+ 3u32 => Self::SAT_SYM,
+ value => {
+ return Err(reader.map_err(ParseErrors::UnknownEnumerant("OverflowModes", value)))
+ }
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub enum LinkageType {
+ Export,
+ Import,
+ LinkOnceODR,
+}
+impl LinkageType {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<LinkageType, ParseError> {
+ Ok(match reader.next_u32()? {
+ 0u32 => Self::Export,
+ 1u32 => Self::Import,
+ 2u32 => Self::LinkOnceODR,
+ value => {
+ return Err(reader.map_err(ParseErrors::UnknownEnumerant("LinkageType", value)))
+ }
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub enum AccessQualifier {
+ ReadOnly,
+ WriteOnly,
+ ReadWrite,
+}
+impl AccessQualifier {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<AccessQualifier, ParseError> {
+ Ok(match reader.next_u32()? {
+ 0u32 => Self::ReadOnly,
+ 1u32 => Self::WriteOnly,
+ 2u32 => Self::ReadWrite,
+ value => {
+ return Err(reader.map_err(ParseErrors::UnknownEnumerant("AccessQualifier", value)))
+ }
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub enum FunctionParameterAttribute {
+ Zext,
+ Sext,
+ ByVal,
+ Sret,
+ NoAlias,
+ NoCapture,
+ NoWrite,
+ NoReadWrite,
+}
+impl FunctionParameterAttribute {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<FunctionParameterAttribute, ParseError> {
+ Ok(match reader.next_u32()? {
+ 0u32 => Self::Zext,
+ 1u32 => Self::Sext,
+ 2u32 => Self::ByVal,
+ 3u32 => Self::Sret,
+ 4u32 => Self::NoAlias,
+ 5u32 => Self::NoCapture,
+ 6u32 => Self::NoWrite,
+ 7u32 => Self::NoReadWrite,
+ value => {
+ return Err(reader.map_err(ParseErrors::UnknownEnumerant(
+ "FunctionParameterAttribute",
+ value,
+ )))
+ }
+ })
+ }
+}
+#[derive(Clone, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub enum Decoration {
+ RelaxedPrecision,
+ SpecId {
+ specialization_constant_id: u32,
+ },
+ Block,
+ BufferBlock,
+ RowMajor,
+ ColMajor,
+ ArrayStride {
+ array_stride: u32,
+ },
+ MatrixStride {
+ matrix_stride: u32,
+ },
+ GLSLShared,
+ GLSLPacked,
+ CPacked,
+ BuiltIn {
+ built_in: BuiltIn,
+ },
+ NoPerspective,
+ Flat,
+ Patch,
+ Centroid,
+ Sample,
+ Invariant,
+ Restrict,
+ Aliased,
+ Volatile,
+ Constant,
+ Coherent,
+ NonWritable,
+ NonReadable,
+ Uniform,
+ UniformId {
+ execution: Id,
+ },
+ SaturatedConversion,
+ Stream {
+ stream_number: u32,
+ },
+ Location {
+ location: u32,
+ },
+ Component {
+ component: u32,
+ },
+ Index {
+ index: u32,
+ },
+ Binding {
+ binding_point: u32,
+ },
+ DescriptorSet {
+ descriptor_set: u32,
+ },
+ Offset {
+ byte_offset: u32,
+ },
+ XfbBuffer {
+ xfb_buffer_number: u32,
+ },
+ XfbStride {
+ xfb_stride: u32,
+ },
+ FuncParamAttr {
+ function_parameter_attribute: FunctionParameterAttribute,
+ },
+ FPRoundingMode {
+ floating_point_rounding_mode: FPRoundingMode,
+ },
+ FPFastMathMode {
+ fast_math_mode: FPFastMathMode,
+ },
+ LinkageAttributes {
+ name: String,
+ linkage_type: LinkageType,
+ },
+ NoContraction,
+ InputAttachmentIndex {
+ attachment_index: u32,
+ },
+ Alignment {
+ alignment: u32,
+ },
+ MaxByteOffset {
+ max_byte_offset: u32,
+ },
+ AlignmentId {
+ alignment: Id,
+ },
+ MaxByteOffsetId {
+ max_byte_offset: Id,
+ },
+ NoSignedWrap,
+ NoUnsignedWrap,
+ ExplicitInterpAMD,
+ OverrideCoverageNV,
+ PassthroughNV,
+ ViewportRelativeNV,
+ SecondaryViewportRelativeNV {
+ offset: u32,
+ },
+ PerPrimitiveNV,
+ PerViewNV,
+ PerTaskNV,
+ PerVertexKHR,
+ NonUniform,
+ RestrictPointer,
+ AliasedPointer,
+ BindlessSamplerNV,
+ BindlessImageNV,
+ BoundSamplerNV,
+ BoundImageNV,
+ SIMTCallINTEL {
+ n: u32,
+ },
+ ReferencedIndirectlyINTEL,
+ ClobberINTEL {
+ register: String,
+ },
+ SideEffectsINTEL,
+ VectorComputeVariableINTEL,
+ FuncParamIOKindINTEL {
+ kind: u32,
+ },
+ VectorComputeFunctionINTEL,
+ StackCallINTEL,
+ GlobalVariableOffsetINTEL {
+ offset: u32,
+ },
+ CounterBuffer {
+ counter_buffer: Id,
+ },
+ UserSemantic {
+ semantic: String,
+ },
+ UserTypeGOOGLE {
+ user_type: String,
+ },
+ FunctionRoundingModeINTEL {
+ target_width: u32,
+ fp_rounding_mode: FPRoundingMode,
+ },
+ FunctionDenormModeINTEL {
+ target_width: u32,
+ fp_denorm_mode: FPDenormMode,
+ },
+ RegisterINTEL,
+ MemoryINTEL {
+ memory_type: String,
+ },
+ NumbanksINTEL {
+ banks: u32,
+ },
+ BankwidthINTEL {
+ bank_width: u32,
+ },
+ MaxPrivateCopiesINTEL {
+ maximum_copies: u32,
+ },
+ SinglepumpINTEL,
+ DoublepumpINTEL,
+ MaxReplicatesINTEL {
+ maximum_replicates: u32,
+ },
+ SimpleDualPortINTEL,
+ MergeINTEL {
+ merge_key: String,
+ merge_type: String,
+ },
+ BankBitsINTEL {
+ bank_bits: u32,
+ },
+ ForcePow2DepthINTEL {
+ force_key: u32,
+ },
+ BurstCoalesceINTEL,
+ CacheSizeINTEL {
+ cache_size_in_bytes: u32,
+ },
+ DontStaticallyCoalesceINTEL,
+ PrefetchINTEL {
+ prefetcher_size_in_bytes: u32,
+ },
+ StallEnableINTEL,
+ FuseLoopsInFunctionINTEL,
+ BufferLocationINTEL {
+ buffer_location_id: u32,
+ },
+ IOPipeStorageINTEL {
+ io_pipe_id: u32,
+ },
+ FunctionFloatingPointModeINTEL {
+ target_width: u32,
+ fp_operation_mode: FPOperationMode,
+ },
+ SingleElementVectorINTEL,
+ VectorComputeCallableFunctionINTEL,
+ MediaBlockIOINTEL,
+}
+impl Decoration {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<Decoration, ParseError> {
+ Ok(match reader.next_u32()? {
+ 0u32 => Self::RelaxedPrecision,
+ 1u32 => Self::SpecId {
+ specialization_constant_id: reader.next_u32()?,
+ },
+ 2u32 => Self::Block,
+ 3u32 => Self::BufferBlock,
+ 4u32 => Self::RowMajor,
+ 5u32 => Self::ColMajor,
+ 6u32 => Self::ArrayStride {
+ array_stride: reader.next_u32()?,
+ },
+ 7u32 => Self::MatrixStride {
+ matrix_stride: reader.next_u32()?,
+ },
+ 8u32 => Self::GLSLShared,
+ 9u32 => Self::GLSLPacked,
+ 10u32 => Self::CPacked,
+ 11u32 => Self::BuiltIn {
+ built_in: BuiltIn::parse(reader)?,
+ },
+ 13u32 => Self::NoPerspective,
+ 14u32 => Self::Flat,
+ 15u32 => Self::Patch,
+ 16u32 => Self::Centroid,
+ 17u32 => Self::Sample,
+ 18u32 => Self::Invariant,
+ 19u32 => Self::Restrict,
+ 20u32 => Self::Aliased,
+ 21u32 => Self::Volatile,
+ 22u32 => Self::Constant,
+ 23u32 => Self::Coherent,
+ 24u32 => Self::NonWritable,
+ 25u32 => Self::NonReadable,
+ 26u32 => Self::Uniform,
+ 27u32 => Self::UniformId {
+ execution: Id(reader.next_u32()?),
+ },
+ 28u32 => Self::SaturatedConversion,
+ 29u32 => Self::Stream {
+ stream_number: reader.next_u32()?,
+ },
+ 30u32 => Self::Location {
+ location: reader.next_u32()?,
+ },
+ 31u32 => Self::Component {
+ component: reader.next_u32()?,
+ },
+ 32u32 => Self::Index {
+ index: reader.next_u32()?,
+ },
+ 33u32 => Self::Binding {
+ binding_point: reader.next_u32()?,
+ },
+ 34u32 => Self::DescriptorSet {
+ descriptor_set: reader.next_u32()?,
+ },
+ 35u32 => Self::Offset {
+ byte_offset: reader.next_u32()?,
+ },
+ 36u32 => Self::XfbBuffer {
+ xfb_buffer_number: reader.next_u32()?,
+ },
+ 37u32 => Self::XfbStride {
+ xfb_stride: reader.next_u32()?,
+ },
+ 38u32 => Self::FuncParamAttr {
+ function_parameter_attribute: FunctionParameterAttribute::parse(reader)?,
+ },
+ 39u32 => Self::FPRoundingMode {
+ floating_point_rounding_mode: FPRoundingMode::parse(reader)?,
+ },
+ 40u32 => Self::FPFastMathMode {
+ fast_math_mode: FPFastMathMode::parse(reader)?,
+ },
+ 41u32 => Self::LinkageAttributes {
+ name: reader.next_string()?,
+ linkage_type: LinkageType::parse(reader)?,
+ },
+ 42u32 => Self::NoContraction,
+ 43u32 => Self::InputAttachmentIndex {
+ attachment_index: reader.next_u32()?,
+ },
+ 44u32 => Self::Alignment {
+ alignment: reader.next_u32()?,
+ },
+ 45u32 => Self::MaxByteOffset {
+ max_byte_offset: reader.next_u32()?,
+ },
+ 46u32 => Self::AlignmentId {
+ alignment: Id(reader.next_u32()?),
+ },
+ 47u32 => Self::MaxByteOffsetId {
+ max_byte_offset: Id(reader.next_u32()?),
+ },
+ 4469u32 => Self::NoSignedWrap,
+ 4470u32 => Self::NoUnsignedWrap,
+ 4999u32 => Self::ExplicitInterpAMD,
+ 5248u32 => Self::OverrideCoverageNV,
+ 5250u32 => Self::PassthroughNV,
+ 5252u32 => Self::ViewportRelativeNV,
+ 5256u32 => Self::SecondaryViewportRelativeNV {
+ offset: reader.next_u32()?,
+ },
+ 5271u32 => Self::PerPrimitiveNV,
+ 5272u32 => Self::PerViewNV,
+ 5273u32 => Self::PerTaskNV,
+ 5285u32 => Self::PerVertexKHR,
+ 5300u32 => Self::NonUniform,
+ 5355u32 => Self::RestrictPointer,
+ 5356u32 => Self::AliasedPointer,
+ 5398u32 => Self::BindlessSamplerNV,
+ 5399u32 => Self::BindlessImageNV,
+ 5400u32 => Self::BoundSamplerNV,
+ 5401u32 => Self::BoundImageNV,
+ 5599u32 => Self::SIMTCallINTEL {
+ n: reader.next_u32()?,
+ },
+ 5602u32 => Self::ReferencedIndirectlyINTEL,
+ 5607u32 => Self::ClobberINTEL {
+ register: reader.next_string()?,
+ },
+ 5608u32 => Self::SideEffectsINTEL,
+ 5624u32 => Self::VectorComputeVariableINTEL,
+ 5625u32 => Self::FuncParamIOKindINTEL {
+ kind: reader.next_u32()?,
+ },
+ 5626u32 => Self::VectorComputeFunctionINTEL,
+ 5627u32 => Self::StackCallINTEL,
+ 5628u32 => Self::GlobalVariableOffsetINTEL {
+ offset: reader.next_u32()?,
+ },
+ 5634u32 => Self::CounterBuffer {
+ counter_buffer: Id(reader.next_u32()?),
+ },
+ 5635u32 => Self::UserSemantic {
+ semantic: reader.next_string()?,
+ },
+ 5636u32 => Self::UserTypeGOOGLE {
+ user_type: reader.next_string()?,
+ },
+ 5822u32 => Self::FunctionRoundingModeINTEL {
+ target_width: reader.next_u32()?,
+ fp_rounding_mode: FPRoundingMode::parse(reader)?,
+ },
+ 5823u32 => Self::FunctionDenormModeINTEL {
+ target_width: reader.next_u32()?,
+ fp_denorm_mode: FPDenormMode::parse(reader)?,
+ },
+ 5825u32 => Self::RegisterINTEL,
+ 5826u32 => Self::MemoryINTEL {
+ memory_type: reader.next_string()?,
+ },
+ 5827u32 => Self::NumbanksINTEL {
+ banks: reader.next_u32()?,
+ },
+ 5828u32 => Self::BankwidthINTEL {
+ bank_width: reader.next_u32()?,
+ },
+ 5829u32 => Self::MaxPrivateCopiesINTEL {
+ maximum_copies: reader.next_u32()?,
+ },
+ 5830u32 => Self::SinglepumpINTEL,
+ 5831u32 => Self::DoublepumpINTEL,
+ 5832u32 => Self::MaxReplicatesINTEL {
+ maximum_replicates: reader.next_u32()?,
+ },
+ 5833u32 => Self::SimpleDualPortINTEL,
+ 5834u32 => Self::MergeINTEL {
+ merge_key: reader.next_string()?,
+ merge_type: reader.next_string()?,
+ },
+ 5835u32 => Self::BankBitsINTEL {
+ bank_bits: reader.next_u32()?,
+ },
+ 5836u32 => Self::ForcePow2DepthINTEL {
+ force_key: reader.next_u32()?,
+ },
+ 5899u32 => Self::BurstCoalesceINTEL,
+ 5900u32 => Self::CacheSizeINTEL {
+ cache_size_in_bytes: reader.next_u32()?,
+ },
+ 5901u32 => Self::DontStaticallyCoalesceINTEL,
+ 5902u32 => Self::PrefetchINTEL {
+ prefetcher_size_in_bytes: reader.next_u32()?,
+ },
+ 5905u32 => Self::StallEnableINTEL,
+ 5907u32 => Self::FuseLoopsInFunctionINTEL,
+ 5921u32 => Self::BufferLocationINTEL {
+ buffer_location_id: reader.next_u32()?,
+ },
+ 5944u32 => Self::IOPipeStorageINTEL {
+ io_pipe_id: reader.next_u32()?,
+ },
+ 6080u32 => Self::FunctionFloatingPointModeINTEL {
+ target_width: reader.next_u32()?,
+ fp_operation_mode: FPOperationMode::parse(reader)?,
+ },
+ 6085u32 => Self::SingleElementVectorINTEL,
+ 6087u32 => Self::VectorComputeCallableFunctionINTEL,
+ 6140u32 => Self::MediaBlockIOINTEL,
+ value => return Err(reader.map_err(ParseErrors::UnknownEnumerant("Decoration", value))),
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub enum BuiltIn {
+ Position,
+ PointSize,
+ ClipDistance,
+ CullDistance,
+ VertexId,
+ InstanceId,
+ PrimitiveId,
+ InvocationId,
+ Layer,
+ ViewportIndex,
+ TessLevelOuter,
+ TessLevelInner,
+ TessCoord,
+ PatchVertices,
+ FragCoord,
+ PointCoord,
+ FrontFacing,
+ SampleId,
+ SamplePosition,
+ SampleMask,
+ FragDepth,
+ HelperInvocation,
+ NumWorkgroups,
+ WorkgroupSize,
+ WorkgroupId,
+ LocalInvocationId,
+ GlobalInvocationId,
+ LocalInvocationIndex,
+ WorkDim,
+ GlobalSize,
+ EnqueuedWorkgroupSize,
+ GlobalOffset,
+ GlobalLinearId,
+ SubgroupSize,
+ SubgroupMaxSize,
+ NumSubgroups,
+ NumEnqueuedSubgroups,
+ SubgroupId,
+ SubgroupLocalInvocationId,
+ VertexIndex,
+ InstanceIndex,
+ SubgroupEqMask,
+ SubgroupGeMask,
+ SubgroupGtMask,
+ SubgroupLeMask,
+ SubgroupLtMask,
+ BaseVertex,
+ BaseInstance,
+ DrawIndex,
+ PrimitiveShadingRateKHR,
+ DeviceIndex,
+ ViewIndex,
+ ShadingRateKHR,
+ BaryCoordNoPerspAMD,
+ BaryCoordNoPerspCentroidAMD,
+ BaryCoordNoPerspSampleAMD,
+ BaryCoordSmoothAMD,
+ BaryCoordSmoothCentroidAMD,
+ BaryCoordSmoothSampleAMD,
+ BaryCoordPullModelAMD,
+ FragStencilRefEXT,
+ ViewportMaskNV,
+ SecondaryPositionNV,
+ SecondaryViewportMaskNV,
+ PositionPerViewNV,
+ ViewportMaskPerViewNV,
+ FullyCoveredEXT,
+ TaskCountNV,
+ PrimitiveCountNV,
+ PrimitiveIndicesNV,
+ ClipDistancePerViewNV,
+ CullDistancePerViewNV,
+ LayerPerViewNV,
+ MeshViewCountNV,
+ MeshViewIndicesNV,
+ BaryCoordKHR,
+ BaryCoordNoPerspKHR,
+ FragSizeEXT,
+ FragInvocationCountEXT,
+ LaunchIdKHR,
+ LaunchSizeKHR,
+ WorldRayOriginKHR,
+ WorldRayDirectionKHR,
+ ObjectRayOriginKHR,
+ ObjectRayDirectionKHR,
+ RayTminKHR,
+ RayTmaxKHR,
+ InstanceCustomIndexKHR,
+ ObjectToWorldKHR,
+ WorldToObjectKHR,
+ HitTNV,
+ HitKindKHR,
+ CurrentRayTimeNV,
+ IncomingRayFlagsKHR,
+ RayGeometryIndexKHR,
+ WarpsPerSMNV,
+ SMCountNV,
+ WarpIDNV,
+ SMIDNV,
+}
+impl BuiltIn {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<BuiltIn, ParseError> {
+ Ok(match reader.next_u32()? {
+ 0u32 => Self::Position,
+ 1u32 => Self::PointSize,
+ 3u32 => Self::ClipDistance,
+ 4u32 => Self::CullDistance,
+ 5u32 => Self::VertexId,
+ 6u32 => Self::InstanceId,
+ 7u32 => Self::PrimitiveId,
+ 8u32 => Self::InvocationId,
+ 9u32 => Self::Layer,
+ 10u32 => Self::ViewportIndex,
+ 11u32 => Self::TessLevelOuter,
+ 12u32 => Self::TessLevelInner,
+ 13u32 => Self::TessCoord,
+ 14u32 => Self::PatchVertices,
+ 15u32 => Self::FragCoord,
+ 16u32 => Self::PointCoord,
+ 17u32 => Self::FrontFacing,
+ 18u32 => Self::SampleId,
+ 19u32 => Self::SamplePosition,
+ 20u32 => Self::SampleMask,
+ 22u32 => Self::FragDepth,
+ 23u32 => Self::HelperInvocation,
+ 24u32 => Self::NumWorkgroups,
+ 25u32 => Self::WorkgroupSize,
+ 26u32 => Self::WorkgroupId,
+ 27u32 => Self::LocalInvocationId,
+ 28u32 => Self::GlobalInvocationId,
+ 29u32 => Self::LocalInvocationIndex,
+ 30u32 => Self::WorkDim,
+ 31u32 => Self::GlobalSize,
+ 32u32 => Self::EnqueuedWorkgroupSize,
+ 33u32 => Self::GlobalOffset,
+ 34u32 => Self::GlobalLinearId,
+ 36u32 => Self::SubgroupSize,
+ 37u32 => Self::SubgroupMaxSize,
+ 38u32 => Self::NumSubgroups,
+ 39u32 => Self::NumEnqueuedSubgroups,
+ 40u32 => Self::SubgroupId,
+ 41u32 => Self::SubgroupLocalInvocationId,
+ 42u32 => Self::VertexIndex,
+ 43u32 => Self::InstanceIndex,
+ 4416u32 => Self::SubgroupEqMask,
+ 4417u32 => Self::SubgroupGeMask,
+ 4418u32 => Self::SubgroupGtMask,
+ 4419u32 => Self::SubgroupLeMask,
+ 4420u32 => Self::SubgroupLtMask,
+ 4424u32 => Self::BaseVertex,
+ 4425u32 => Self::BaseInstance,
+ 4426u32 => Self::DrawIndex,
+ 4432u32 => Self::PrimitiveShadingRateKHR,
+ 4438u32 => Self::DeviceIndex,
+ 4440u32 => Self::ViewIndex,
+ 4444u32 => Self::ShadingRateKHR,
+ 4992u32 => Self::BaryCoordNoPerspAMD,
+ 4993u32 => Self::BaryCoordNoPerspCentroidAMD,
+ 4994u32 => Self::BaryCoordNoPerspSampleAMD,
+ 4995u32 => Self::BaryCoordSmoothAMD,
+ 4996u32 => Self::BaryCoordSmoothCentroidAMD,
+ 4997u32 => Self::BaryCoordSmoothSampleAMD,
+ 4998u32 => Self::BaryCoordPullModelAMD,
+ 5014u32 => Self::FragStencilRefEXT,
+ 5253u32 => Self::ViewportMaskNV,
+ 5257u32 => Self::SecondaryPositionNV,
+ 5258u32 => Self::SecondaryViewportMaskNV,
+ 5261u32 => Self::PositionPerViewNV,
+ 5262u32 => Self::ViewportMaskPerViewNV,
+ 5264u32 => Self::FullyCoveredEXT,
+ 5274u32 => Self::TaskCountNV,
+ 5275u32 => Self::PrimitiveCountNV,
+ 5276u32 => Self::PrimitiveIndicesNV,
+ 5277u32 => Self::ClipDistancePerViewNV,
+ 5278u32 => Self::CullDistancePerViewNV,
+ 5279u32 => Self::LayerPerViewNV,
+ 5280u32 => Self::MeshViewCountNV,
+ 5281u32 => Self::MeshViewIndicesNV,
+ 5286u32 => Self::BaryCoordKHR,
+ 5287u32 => Self::BaryCoordNoPerspKHR,
+ 5292u32 => Self::FragSizeEXT,
+ 5293u32 => Self::FragInvocationCountEXT,
+ 5319u32 => Self::LaunchIdKHR,
+ 5320u32 => Self::LaunchSizeKHR,
+ 5321u32 => Self::WorldRayOriginKHR,
+ 5322u32 => Self::WorldRayDirectionKHR,
+ 5323u32 => Self::ObjectRayOriginKHR,
+ 5324u32 => Self::ObjectRayDirectionKHR,
+ 5325u32 => Self::RayTminKHR,
+ 5326u32 => Self::RayTmaxKHR,
+ 5327u32 => Self::InstanceCustomIndexKHR,
+ 5330u32 => Self::ObjectToWorldKHR,
+ 5331u32 => Self::WorldToObjectKHR,
+ 5332u32 => Self::HitTNV,
+ 5333u32 => Self::HitKindKHR,
+ 5334u32 => Self::CurrentRayTimeNV,
+ 5351u32 => Self::IncomingRayFlagsKHR,
+ 5352u32 => Self::RayGeometryIndexKHR,
+ 5374u32 => Self::WarpsPerSMNV,
+ 5375u32 => Self::SMCountNV,
+ 5376u32 => Self::WarpIDNV,
+ 5377u32 => Self::SMIDNV,
+ value => return Err(reader.map_err(ParseErrors::UnknownEnumerant("BuiltIn", value))),
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub enum Scope {
+ CrossDevice,
+ Device,
+ Workgroup,
+ Subgroup,
+ Invocation,
+ QueueFamily,
+ ShaderCallKHR,
+}
+impl Scope {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<Scope, ParseError> {
+ Ok(match reader.next_u32()? {
+ 0u32 => Self::CrossDevice,
+ 1u32 => Self::Device,
+ 2u32 => Self::Workgroup,
+ 3u32 => Self::Subgroup,
+ 4u32 => Self::Invocation,
+ 5u32 => Self::QueueFamily,
+ 6u32 => Self::ShaderCallKHR,
+ value => return Err(reader.map_err(ParseErrors::UnknownEnumerant("Scope", value))),
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub enum GroupOperation {
+ Reduce,
+ InclusiveScan,
+ ExclusiveScan,
+ ClusteredReduce,
+ PartitionedReduceNV,
+ PartitionedInclusiveScanNV,
+ PartitionedExclusiveScanNV,
+}
+impl GroupOperation {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<GroupOperation, ParseError> {
+ Ok(match reader.next_u32()? {
+ 0u32 => Self::Reduce,
+ 1u32 => Self::InclusiveScan,
+ 2u32 => Self::ExclusiveScan,
+ 3u32 => Self::ClusteredReduce,
+ 6u32 => Self::PartitionedReduceNV,
+ 7u32 => Self::PartitionedInclusiveScanNV,
+ 8u32 => Self::PartitionedExclusiveScanNV,
+ value => {
+ return Err(reader.map_err(ParseErrors::UnknownEnumerant("GroupOperation", value)))
+ }
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub enum KernelEnqueueFlags {
+ NoWait,
+ WaitKernel,
+ WaitWorkGroup,
+}
+impl KernelEnqueueFlags {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<KernelEnqueueFlags, ParseError> {
+ Ok(match reader.next_u32()? {
+ 0u32 => Self::NoWait,
+ 1u32 => Self::WaitKernel,
+ 2u32 => Self::WaitWorkGroup,
+ value => {
+ return Err(
+ reader.map_err(ParseErrors::UnknownEnumerant("KernelEnqueueFlags", value))
+ )
+ }
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub enum Capability {
+ Matrix,
+ Shader,
+ Geometry,
+ Tessellation,
+ Addresses,
+ Linkage,
+ Kernel,
+ Vector16,
+ Float16Buffer,
+ Float16,
+ Float64,
+ Int64,
+ Int64Atomics,
+ ImageBasic,
+ ImageReadWrite,
+ ImageMipmap,
+ Pipes,
+ Groups,
+ DeviceEnqueue,
+ LiteralSampler,
+ AtomicStorage,
+ Int16,
+ TessellationPointSize,
+ GeometryPointSize,
+ ImageGatherExtended,
+ StorageImageMultisample,
+ UniformBufferArrayDynamicIndexing,
+ SampledImageArrayDynamicIndexing,
+ StorageBufferArrayDynamicIndexing,
+ StorageImageArrayDynamicIndexing,
+ ClipDistance,
+ CullDistance,
+ ImageCubeArray,
+ SampleRateShading,
+ ImageRect,
+ SampledRect,
+ GenericPointer,
+ Int8,
+ InputAttachment,
+ SparseResidency,
+ MinLod,
+ Sampled1D,
+ Image1D,
+ SampledCubeArray,
+ SampledBuffer,
+ ImageBuffer,
+ ImageMSArray,
+ StorageImageExtendedFormats,
+ ImageQuery,
+ DerivativeControl,
+ InterpolationFunction,
+ TransformFeedback,
+ GeometryStreams,
+ StorageImageReadWithoutFormat,
+ StorageImageWriteWithoutFormat,
+ MultiViewport,
+ SubgroupDispatch,
+ NamedBarrier,
+ PipeStorage,
+ GroupNonUniform,
+ GroupNonUniformVote,
+ GroupNonUniformArithmetic,
+ GroupNonUniformBallot,
+ GroupNonUniformShuffle,
+ GroupNonUniformShuffleRelative,
+ GroupNonUniformClustered,
+ GroupNonUniformQuad,
+ ShaderLayer,
+ ShaderViewportIndex,
+ UniformDecoration,
+ FragmentShadingRateKHR,
+ SubgroupBallotKHR,
+ DrawParameters,
+ WorkgroupMemoryExplicitLayoutKHR,
+ WorkgroupMemoryExplicitLayout8BitAccessKHR,
+ WorkgroupMemoryExplicitLayout16BitAccessKHR,
+ SubgroupVoteKHR,
+ StorageBuffer16BitAccess,
+ UniformAndStorageBuffer16BitAccess,
+ StoragePushConstant16,
+ StorageInputOutput16,
+ DeviceGroup,
+ MultiView,
+ VariablePointersStorageBuffer,
+ VariablePointers,
+ AtomicStorageOps,
+ SampleMaskPostDepthCoverage,
+ StorageBuffer8BitAccess,
+ UniformAndStorageBuffer8BitAccess,
+ StoragePushConstant8,
+ DenormPreserve,
+ DenormFlushToZero,
+ SignedZeroInfNanPreserve,
+ RoundingModeRTE,
+ RoundingModeRTZ,
+ RayQueryProvisionalKHR,
+ RayQueryKHR,
+ RayTraversalPrimitiveCullingKHR,
+ RayTracingKHR,
+ Float16ImageAMD,
+ ImageGatherBiasLodAMD,
+ FragmentMaskAMD,
+ StencilExportEXT,
+ ImageReadWriteLodAMD,
+ Int64ImageEXT,
+ ShaderClockKHR,
+ SampleMaskOverrideCoverageNV,
+ GeometryShaderPassthroughNV,
+ ShaderViewportIndexLayerEXT,
+ ShaderViewportMaskNV,
+ ShaderStereoViewNV,
+ PerViewAttributesNV,
+ FragmentFullyCoveredEXT,
+ MeshShadingNV,
+ ImageFootprintNV,
+ FragmentBarycentricKHR,
+ ComputeDerivativeGroupQuadsNV,
+ FragmentDensityEXT,
+ GroupNonUniformPartitionedNV,
+ ShaderNonUniform,
+ RuntimeDescriptorArray,
+ InputAttachmentArrayDynamicIndexing,
+ UniformTexelBufferArrayDynamicIndexing,
+ StorageTexelBufferArrayDynamicIndexing,
+ UniformBufferArrayNonUniformIndexing,
+ SampledImageArrayNonUniformIndexing,
+ StorageBufferArrayNonUniformIndexing,
+ StorageImageArrayNonUniformIndexing,
+ InputAttachmentArrayNonUniformIndexing,
+ UniformTexelBufferArrayNonUniformIndexing,
+ StorageTexelBufferArrayNonUniformIndexing,
+ RayTracingNV,
+ RayTracingMotionBlurNV,
+ VulkanMemoryModel,
+ VulkanMemoryModelDeviceScope,
+ PhysicalStorageBufferAddresses,
+ ComputeDerivativeGroupLinearNV,
+ RayTracingProvisionalKHR,
+ CooperativeMatrixNV,
+ FragmentShaderSampleInterlockEXT,
+ FragmentShaderShadingRateInterlockEXT,
+ ShaderSMBuiltinsNV,
+ FragmentShaderPixelInterlockEXT,
+ DemoteToHelperInvocation,
+ BindlessTextureNV,
+ SubgroupShuffleINTEL,
+ SubgroupBufferBlockIOINTEL,
+ SubgroupImageBlockIOINTEL,
+ SubgroupImageMediaBlockIOINTEL,
+ RoundToInfinityINTEL,
+ FloatingPointModeINTEL,
+ IntegerFunctions2INTEL,
+ FunctionPointersINTEL,
+ IndirectReferencesINTEL,
+ AsmINTEL,
+ AtomicFloat32MinMaxEXT,
+ AtomicFloat64MinMaxEXT,
+ AtomicFloat16MinMaxEXT,
+ VectorComputeINTEL,
+ VectorAnyINTEL,
+ ExpectAssumeKHR,
+ SubgroupAvcMotionEstimationINTEL,
+ SubgroupAvcMotionEstimationIntraINTEL,
+ SubgroupAvcMotionEstimationChromaINTEL,
+ VariableLengthArrayINTEL,
+ FunctionFloatControlINTEL,
+ FPGAMemoryAttributesINTEL,
+ FPFastMathModeINTEL,
+ ArbitraryPrecisionIntegersINTEL,
+ ArbitraryPrecisionFloatingPointINTEL,
+ UnstructuredLoopControlsINTEL,
+ FPGALoopControlsINTEL,
+ KernelAttributesINTEL,
+ FPGAKernelAttributesINTEL,
+ FPGAMemoryAccessesINTEL,
+ FPGAClusterAttributesINTEL,
+ LoopFuseINTEL,
+ FPGABufferLocationINTEL,
+ ArbitraryPrecisionFixedPointINTEL,
+ USMStorageClassesINTEL,
+ IOPipesINTEL,
+ BlockingPipesINTEL,
+ FPGARegINTEL,
+ DotProductInputAll,
+ DotProductInput4x8Bit,
+ DotProductInput4x8BitPacked,
+ DotProduct,
+ BitInstructions,
+ AtomicFloat32AddEXT,
+ AtomicFloat64AddEXT,
+ LongConstantCompositeINTEL,
+ OptNoneINTEL,
+ AtomicFloat16AddEXT,
+ DebugInfoModuleINTEL,
+}
+impl Capability {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<Capability, ParseError> {
+ Ok(match reader.next_u32()? {
+ 0u32 => Self::Matrix,
+ 1u32 => Self::Shader,
+ 2u32 => Self::Geometry,
+ 3u32 => Self::Tessellation,
+ 4u32 => Self::Addresses,
+ 5u32 => Self::Linkage,
+ 6u32 => Self::Kernel,
+ 7u32 => Self::Vector16,
+ 8u32 => Self::Float16Buffer,
+ 9u32 => Self::Float16,
+ 10u32 => Self::Float64,
+ 11u32 => Self::Int64,
+ 12u32 => Self::Int64Atomics,
+ 13u32 => Self::ImageBasic,
+ 14u32 => Self::ImageReadWrite,
+ 15u32 => Self::ImageMipmap,
+ 17u32 => Self::Pipes,
+ 18u32 => Self::Groups,
+ 19u32 => Self::DeviceEnqueue,
+ 20u32 => Self::LiteralSampler,
+ 21u32 => Self::AtomicStorage,
+ 22u32 => Self::Int16,
+ 23u32 => Self::TessellationPointSize,
+ 24u32 => Self::GeometryPointSize,
+ 25u32 => Self::ImageGatherExtended,
+ 27u32 => Self::StorageImageMultisample,
+ 28u32 => Self::UniformBufferArrayDynamicIndexing,
+ 29u32 => Self::SampledImageArrayDynamicIndexing,
+ 30u32 => Self::StorageBufferArrayDynamicIndexing,
+ 31u32 => Self::StorageImageArrayDynamicIndexing,
+ 32u32 => Self::ClipDistance,
+ 33u32 => Self::CullDistance,
+ 34u32 => Self::ImageCubeArray,
+ 35u32 => Self::SampleRateShading,
+ 36u32 => Self::ImageRect,
+ 37u32 => Self::SampledRect,
+ 38u32 => Self::GenericPointer,
+ 39u32 => Self::Int8,
+ 40u32 => Self::InputAttachment,
+ 41u32 => Self::SparseResidency,
+ 42u32 => Self::MinLod,
+ 43u32 => Self::Sampled1D,
+ 44u32 => Self::Image1D,
+ 45u32 => Self::SampledCubeArray,
+ 46u32 => Self::SampledBuffer,
+ 47u32 => Self::ImageBuffer,
+ 48u32 => Self::ImageMSArray,
+ 49u32 => Self::StorageImageExtendedFormats,
+ 50u32 => Self::ImageQuery,
+ 51u32 => Self::DerivativeControl,
+ 52u32 => Self::InterpolationFunction,
+ 53u32 => Self::TransformFeedback,
+ 54u32 => Self::GeometryStreams,
+ 55u32 => Self::StorageImageReadWithoutFormat,
+ 56u32 => Self::StorageImageWriteWithoutFormat,
+ 57u32 => Self::MultiViewport,
+ 58u32 => Self::SubgroupDispatch,
+ 59u32 => Self::NamedBarrier,
+ 60u32 => Self::PipeStorage,
+ 61u32 => Self::GroupNonUniform,
+ 62u32 => Self::GroupNonUniformVote,
+ 63u32 => Self::GroupNonUniformArithmetic,
+ 64u32 => Self::GroupNonUniformBallot,
+ 65u32 => Self::GroupNonUniformShuffle,
+ 66u32 => Self::GroupNonUniformShuffleRelative,
+ 67u32 => Self::GroupNonUniformClustered,
+ 68u32 => Self::GroupNonUniformQuad,
+ 69u32 => Self::ShaderLayer,
+ 70u32 => Self::ShaderViewportIndex,
+ 71u32 => Self::UniformDecoration,
+ 4422u32 => Self::FragmentShadingRateKHR,
+ 4423u32 => Self::SubgroupBallotKHR,
+ 4427u32 => Self::DrawParameters,
+ 4428u32 => Self::WorkgroupMemoryExplicitLayoutKHR,
+ 4429u32 => Self::WorkgroupMemoryExplicitLayout8BitAccessKHR,
+ 4430u32 => Self::WorkgroupMemoryExplicitLayout16BitAccessKHR,
+ 4431u32 => Self::SubgroupVoteKHR,
+ 4433u32 => Self::StorageBuffer16BitAccess,
+ 4434u32 => Self::UniformAndStorageBuffer16BitAccess,
+ 4435u32 => Self::StoragePushConstant16,
+ 4436u32 => Self::StorageInputOutput16,
+ 4437u32 => Self::DeviceGroup,
+ 4439u32 => Self::MultiView,
+ 4441u32 => Self::VariablePointersStorageBuffer,
+ 4442u32 => Self::VariablePointers,
+ 4445u32 => Self::AtomicStorageOps,
+ 4447u32 => Self::SampleMaskPostDepthCoverage,
+ 4448u32 => Self::StorageBuffer8BitAccess,
+ 4449u32 => Self::UniformAndStorageBuffer8BitAccess,
+ 4450u32 => Self::StoragePushConstant8,
+ 4464u32 => Self::DenormPreserve,
+ 4465u32 => Self::DenormFlushToZero,
+ 4466u32 => Self::SignedZeroInfNanPreserve,
+ 4467u32 => Self::RoundingModeRTE,
+ 4468u32 => Self::RoundingModeRTZ,
+ 4471u32 => Self::RayQueryProvisionalKHR,
+ 4472u32 => Self::RayQueryKHR,
+ 4478u32 => Self::RayTraversalPrimitiveCullingKHR,
+ 4479u32 => Self::RayTracingKHR,
+ 5008u32 => Self::Float16ImageAMD,
+ 5009u32 => Self::ImageGatherBiasLodAMD,
+ 5010u32 => Self::FragmentMaskAMD,
+ 5013u32 => Self::StencilExportEXT,
+ 5015u32 => Self::ImageReadWriteLodAMD,
+ 5016u32 => Self::Int64ImageEXT,
+ 5055u32 => Self::ShaderClockKHR,
+ 5249u32 => Self::SampleMaskOverrideCoverageNV,
+ 5251u32 => Self::GeometryShaderPassthroughNV,
+ 5254u32 => Self::ShaderViewportIndexLayerEXT,
+ 5255u32 => Self::ShaderViewportMaskNV,
+ 5259u32 => Self::ShaderStereoViewNV,
+ 5260u32 => Self::PerViewAttributesNV,
+ 5265u32 => Self::FragmentFullyCoveredEXT,
+ 5266u32 => Self::MeshShadingNV,
+ 5282u32 => Self::ImageFootprintNV,
+ 5284u32 => Self::FragmentBarycentricKHR,
+ 5288u32 => Self::ComputeDerivativeGroupQuadsNV,
+ 5291u32 => Self::FragmentDensityEXT,
+ 5297u32 => Self::GroupNonUniformPartitionedNV,
+ 5301u32 => Self::ShaderNonUniform,
+ 5302u32 => Self::RuntimeDescriptorArray,
+ 5303u32 => Self::InputAttachmentArrayDynamicIndexing,
+ 5304u32 => Self::UniformTexelBufferArrayDynamicIndexing,
+ 5305u32 => Self::StorageTexelBufferArrayDynamicIndexing,
+ 5306u32 => Self::UniformBufferArrayNonUniformIndexing,
+ 5307u32 => Self::SampledImageArrayNonUniformIndexing,
+ 5308u32 => Self::StorageBufferArrayNonUniformIndexing,
+ 5309u32 => Self::StorageImageArrayNonUniformIndexing,
+ 5310u32 => Self::InputAttachmentArrayNonUniformIndexing,
+ 5311u32 => Self::UniformTexelBufferArrayNonUniformIndexing,
+ 5312u32 => Self::StorageTexelBufferArrayNonUniformIndexing,
+ 5340u32 => Self::RayTracingNV,
+ 5341u32 => Self::RayTracingMotionBlurNV,
+ 5345u32 => Self::VulkanMemoryModel,
+ 5346u32 => Self::VulkanMemoryModelDeviceScope,
+ 5347u32 => Self::PhysicalStorageBufferAddresses,
+ 5350u32 => Self::ComputeDerivativeGroupLinearNV,
+ 5353u32 => Self::RayTracingProvisionalKHR,
+ 5357u32 => Self::CooperativeMatrixNV,
+ 5363u32 => Self::FragmentShaderSampleInterlockEXT,
+ 5372u32 => Self::FragmentShaderShadingRateInterlockEXT,
+ 5373u32 => Self::ShaderSMBuiltinsNV,
+ 5378u32 => Self::FragmentShaderPixelInterlockEXT,
+ 5379u32 => Self::DemoteToHelperInvocation,
+ 5390u32 => Self::BindlessTextureNV,
+ 5568u32 => Self::SubgroupShuffleINTEL,
+ 5569u32 => Self::SubgroupBufferBlockIOINTEL,
+ 5570u32 => Self::SubgroupImageBlockIOINTEL,
+ 5579u32 => Self::SubgroupImageMediaBlockIOINTEL,
+ 5582u32 => Self::RoundToInfinityINTEL,
+ 5583u32 => Self::FloatingPointModeINTEL,
+ 5584u32 => Self::IntegerFunctions2INTEL,
+ 5603u32 => Self::FunctionPointersINTEL,
+ 5604u32 => Self::IndirectReferencesINTEL,
+ 5606u32 => Self::AsmINTEL,
+ 5612u32 => Self::AtomicFloat32MinMaxEXT,
+ 5613u32 => Self::AtomicFloat64MinMaxEXT,
+ 5616u32 => Self::AtomicFloat16MinMaxEXT,
+ 5617u32 => Self::VectorComputeINTEL,
+ 5619u32 => Self::VectorAnyINTEL,
+ 5629u32 => Self::ExpectAssumeKHR,
+ 5696u32 => Self::SubgroupAvcMotionEstimationINTEL,
+ 5697u32 => Self::SubgroupAvcMotionEstimationIntraINTEL,
+ 5698u32 => Self::SubgroupAvcMotionEstimationChromaINTEL,
+ 5817u32 => Self::VariableLengthArrayINTEL,
+ 5821u32 => Self::FunctionFloatControlINTEL,
+ 5824u32 => Self::FPGAMemoryAttributesINTEL,
+ 5837u32 => Self::FPFastMathModeINTEL,
+ 5844u32 => Self::ArbitraryPrecisionIntegersINTEL,
+ 5845u32 => Self::ArbitraryPrecisionFloatingPointINTEL,
+ 5886u32 => Self::UnstructuredLoopControlsINTEL,
+ 5888u32 => Self::FPGALoopControlsINTEL,
+ 5892u32 => Self::KernelAttributesINTEL,
+ 5897u32 => Self::FPGAKernelAttributesINTEL,
+ 5898u32 => Self::FPGAMemoryAccessesINTEL,
+ 5904u32 => Self::FPGAClusterAttributesINTEL,
+ 5906u32 => Self::LoopFuseINTEL,
+ 5920u32 => Self::FPGABufferLocationINTEL,
+ 5922u32 => Self::ArbitraryPrecisionFixedPointINTEL,
+ 5935u32 => Self::USMStorageClassesINTEL,
+ 5943u32 => Self::IOPipesINTEL,
+ 5945u32 => Self::BlockingPipesINTEL,
+ 5948u32 => Self::FPGARegINTEL,
+ 6016u32 => Self::DotProductInputAll,
+ 6017u32 => Self::DotProductInput4x8Bit,
+ 6018u32 => Self::DotProductInput4x8BitPacked,
+ 6019u32 => Self::DotProduct,
+ 6025u32 => Self::BitInstructions,
+ 6033u32 => Self::AtomicFloat32AddEXT,
+ 6034u32 => Self::AtomicFloat64AddEXT,
+ 6089u32 => Self::LongConstantCompositeINTEL,
+ 6094u32 => Self::OptNoneINTEL,
+ 6095u32 => Self::AtomicFloat16AddEXT,
+ 6114u32 => Self::DebugInfoModuleINTEL,
+ value => return Err(reader.map_err(ParseErrors::UnknownEnumerant("Capability", value))),
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub enum RayQueryIntersection {
+ RayQueryCandidateIntersectionKHR,
+ RayQueryCommittedIntersectionKHR,
+}
+impl RayQueryIntersection {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<RayQueryIntersection, ParseError> {
+ Ok(match reader.next_u32()? {
+ 0u32 => Self::RayQueryCandidateIntersectionKHR,
+ 1u32 => Self::RayQueryCommittedIntersectionKHR,
+ value => {
+ return Err(
+ reader.map_err(ParseErrors::UnknownEnumerant("RayQueryIntersection", value))
+ )
+ }
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub enum RayQueryCommittedIntersectionType {
+ RayQueryCommittedIntersectionNoneKHR,
+ RayQueryCommittedIntersectionTriangleKHR,
+ RayQueryCommittedIntersectionGeneratedKHR,
+}
+impl RayQueryCommittedIntersectionType {
+ #[allow(dead_code)]
+ fn parse(
+ reader: &mut InstructionReader<'_>,
+ ) -> Result<RayQueryCommittedIntersectionType, ParseError> {
+ Ok(match reader.next_u32()? {
+ 0u32 => Self::RayQueryCommittedIntersectionNoneKHR,
+ 1u32 => Self::RayQueryCommittedIntersectionTriangleKHR,
+ 2u32 => Self::RayQueryCommittedIntersectionGeneratedKHR,
+ value => {
+ return Err(reader.map_err(ParseErrors::UnknownEnumerant(
+ "RayQueryCommittedIntersectionType",
+ value,
+ )))
+ }
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub enum RayQueryCandidateIntersectionType {
+ RayQueryCandidateIntersectionTriangleKHR,
+ RayQueryCandidateIntersectionAABBKHR,
+}
+impl RayQueryCandidateIntersectionType {
+ #[allow(dead_code)]
+ fn parse(
+ reader: &mut InstructionReader<'_>,
+ ) -> Result<RayQueryCandidateIntersectionType, ParseError> {
+ Ok(match reader.next_u32()? {
+ 0u32 => Self::RayQueryCandidateIntersectionTriangleKHR,
+ 1u32 => Self::RayQueryCandidateIntersectionAABBKHR,
+ value => {
+ return Err(reader.map_err(ParseErrors::UnknownEnumerant(
+ "RayQueryCandidateIntersectionType",
+ value,
+ )))
+ }
+ })
+ }
+}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[allow(non_camel_case_types)]
+pub enum PackedVectorFormat {
+ PackedVectorFormat4x8Bit,
+}
+impl PackedVectorFormat {
+ #[allow(dead_code)]
+ fn parse(reader: &mut InstructionReader<'_>) -> Result<PackedVectorFormat, ParseError> {
+ Ok(match reader.next_u32()? {
+ 0u32 => Self::PackedVectorFormat4x8Bit,
+ value => {
+ return Err(
+ reader.map_err(ParseErrors::UnknownEnumerant("PackedVectorFormat", value))
+ )
+ }
+ })
+ }
+}
diff --git a/out/spirv_reqs.rs b/out/spirv_reqs.rs
new file mode 100644
index 0000000..f46bc27
--- /dev/null
+++ b/out/spirv_reqs.rs
@@ -0,0 +1,1683 @@
+// This file is auto-generated by vulkano autogen from vk.xml header version 1.3.238.
+// It should not be edited manually. Changes should be made by editing autogen.
+
+fn check_spirv_capability(
+ device: &Device,
+ capability: Capability,
+) -> Result<(), ShaderSupportError> {
+ match capability {
+ Capability::Matrix => (),
+ Capability::Shader => (),
+ Capability::InputAttachment => (),
+ Capability::Sampled1D => (),
+ Capability::Image1D => (),
+ Capability::SampledBuffer => (),
+ Capability::ImageBuffer => (),
+ Capability::ImageQuery => (),
+ Capability::DerivativeControl => (),
+ Capability::Geometry => {
+ if !(device.enabled_features().geometry_shader) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `geometry_shader`",
+ ]));
+ }
+ }
+ Capability::Tessellation => {
+ if !(device.enabled_features().tessellation_shader) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `tessellation_shader`",
+ ]));
+ }
+ }
+ Capability::Float64 => {
+ if !(device.enabled_features().shader_float64) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_float64`",
+ ]));
+ }
+ }
+ Capability::Int64 => {
+ if !(device.enabled_features().shader_int64) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_int64`",
+ ]));
+ }
+ }
+ Capability::Int64Atomics => {
+ if !(device.enabled_features().shader_buffer_int64_atomics
+ || device.enabled_features().shader_shared_int64_atomics
+ || device.enabled_features().shader_image_int64_atomics)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_buffer_int64_atomics`",
+ "feature `shader_shared_int64_atomics`",
+ "feature `shader_image_int64_atomics`",
+ ]));
+ }
+ }
+ Capability::AtomicFloat16AddEXT => {
+ if !(device.enabled_features().shader_buffer_float16_atomic_add
+ || device.enabled_features().shader_shared_float16_atomic_add)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_buffer_float16_atomic_add`",
+ "feature `shader_shared_float16_atomic_add`",
+ ]));
+ }
+ }
+ Capability::AtomicFloat32AddEXT => {
+ if !(device.enabled_features().shader_buffer_float32_atomic_add
+ || device.enabled_features().shader_shared_float32_atomic_add
+ || device.enabled_features().shader_image_float32_atomic_add)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_buffer_float32_atomic_add`",
+ "feature `shader_shared_float32_atomic_add`",
+ "feature `shader_image_float32_atomic_add`",
+ ]));
+ }
+ }
+ Capability::AtomicFloat64AddEXT => {
+ if !(device.enabled_features().shader_buffer_float64_atomic_add
+ || device.enabled_features().shader_shared_float64_atomic_add)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_buffer_float64_atomic_add`",
+ "feature `shader_shared_float64_atomic_add`",
+ ]));
+ }
+ }
+ Capability::AtomicFloat16MinMaxEXT => {
+ if !(device
+ .enabled_features()
+ .shader_buffer_float16_atomic_min_max
+ || device
+ .enabled_features()
+ .shader_shared_float16_atomic_min_max)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_buffer_float16_atomic_min_max`",
+ "feature `shader_shared_float16_atomic_min_max`",
+ ]));
+ }
+ }
+ Capability::AtomicFloat32MinMaxEXT => {
+ if !(device
+ .enabled_features()
+ .shader_buffer_float32_atomic_min_max
+ || device
+ .enabled_features()
+ .shader_shared_float32_atomic_min_max
+ || device
+ .enabled_features()
+ .shader_image_float32_atomic_min_max)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_buffer_float32_atomic_min_max`",
+ "feature `shader_shared_float32_atomic_min_max`",
+ "feature `shader_image_float32_atomic_min_max`",
+ ]));
+ }
+ }
+ Capability::AtomicFloat64MinMaxEXT => {
+ if !(device
+ .enabled_features()
+ .shader_buffer_float64_atomic_min_max
+ || device
+ .enabled_features()
+ .shader_shared_float64_atomic_min_max)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_buffer_float64_atomic_min_max`",
+ "feature `shader_shared_float64_atomic_min_max`",
+ ]));
+ }
+ }
+ Capability::Int64ImageEXT => {
+ if !(device.enabled_features().shader_image_int64_atomics) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_image_int64_atomics`",
+ ]));
+ }
+ }
+ Capability::Int16 => {
+ if !(device.enabled_features().shader_int16) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_int16`",
+ ]));
+ }
+ }
+ Capability::TessellationPointSize => {
+ if !(device
+ .enabled_features()
+ .shader_tessellation_and_geometry_point_size)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_tessellation_and_geometry_point_size`",
+ ]));
+ }
+ }
+ Capability::GeometryPointSize => {
+ if !(device
+ .enabled_features()
+ .shader_tessellation_and_geometry_point_size)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_tessellation_and_geometry_point_size`",
+ ]));
+ }
+ }
+ Capability::ImageGatherExtended => {
+ if !(device.enabled_features().shader_image_gather_extended) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_image_gather_extended`",
+ ]));
+ }
+ }
+ Capability::StorageImageMultisample => {
+ if !(device.enabled_features().shader_storage_image_multisample) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_storage_image_multisample`",
+ ]));
+ }
+ }
+ Capability::UniformBufferArrayDynamicIndexing => {
+ if !(device
+ .enabled_features()
+ .shader_uniform_buffer_array_dynamic_indexing)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_uniform_buffer_array_dynamic_indexing`",
+ ]));
+ }
+ }
+ Capability::SampledImageArrayDynamicIndexing => {
+ if !(device
+ .enabled_features()
+ .shader_sampled_image_array_dynamic_indexing)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_sampled_image_array_dynamic_indexing`",
+ ]));
+ }
+ }
+ Capability::StorageBufferArrayDynamicIndexing => {
+ if !(device
+ .enabled_features()
+ .shader_storage_buffer_array_dynamic_indexing)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_storage_buffer_array_dynamic_indexing`",
+ ]));
+ }
+ }
+ Capability::StorageImageArrayDynamicIndexing => {
+ if !(device
+ .enabled_features()
+ .shader_storage_image_array_dynamic_indexing)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_storage_image_array_dynamic_indexing`",
+ ]));
+ }
+ }
+ Capability::ClipDistance => {
+ if !(device.enabled_features().shader_clip_distance) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_clip_distance`",
+ ]));
+ }
+ }
+ Capability::CullDistance => {
+ if !(device.enabled_features().shader_cull_distance) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_cull_distance`",
+ ]));
+ }
+ }
+ Capability::ImageCubeArray => {
+ if !(device.enabled_features().image_cube_array) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `image_cube_array`",
+ ]));
+ }
+ }
+ Capability::SampleRateShading => {
+ if !(device.enabled_features().sample_rate_shading) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `sample_rate_shading`",
+ ]));
+ }
+ }
+ Capability::SparseResidency => {
+ if !(device.enabled_features().shader_resource_residency) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_resource_residency`",
+ ]));
+ }
+ }
+ Capability::MinLod => {
+ if !(device.enabled_features().shader_resource_min_lod) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_resource_min_lod`",
+ ]));
+ }
+ }
+ Capability::SampledCubeArray => {
+ if !(device.enabled_features().image_cube_array) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `image_cube_array`",
+ ]));
+ }
+ }
+ Capability::ImageMSArray => {
+ if !(device.enabled_features().shader_storage_image_multisample) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_storage_image_multisample`",
+ ]));
+ }
+ }
+ Capability::StorageImageExtendedFormats => (),
+ Capability::InterpolationFunction => {
+ if !(device.enabled_features().sample_rate_shading) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `sample_rate_shading`",
+ ]));
+ }
+ }
+ Capability::StorageImageReadWithoutFormat => {
+ if !(device
+ .enabled_features()
+ .shader_storage_image_read_without_format
+ || device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_format_feature_flags2)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_storage_image_read_without_format`",
+ "Vulkan API version 1.1",
+ "device extension `khr_format_feature_flags2`",
+ ]));
+ }
+ }
+ Capability::StorageImageWriteWithoutFormat => {
+ if !(device
+ .enabled_features()
+ .shader_storage_image_write_without_format
+ || device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_format_feature_flags2)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_storage_image_write_without_format`",
+ "Vulkan API version 1.1",
+ "device extension `khr_format_feature_flags2`",
+ ]));
+ }
+ }
+ Capability::MultiViewport => {
+ if !(device.enabled_features().multi_viewport) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `multi_viewport`",
+ ]));
+ }
+ }
+ Capability::DrawParameters => {
+ if !(device.enabled_features().shader_draw_parameters
+ || device.enabled_extensions().khr_shader_draw_parameters)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_draw_parameters`",
+ "device extension `khr_shader_draw_parameters`",
+ ]));
+ }
+ }
+ Capability::MultiView => {
+ if !(device.enabled_features().multiview) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `multiview`",
+ ]));
+ }
+ }
+ Capability::DeviceGroup => {
+ if !(device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_device_group)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "Vulkan API version 1.1",
+ "device extension `khr_device_group`",
+ ]));
+ }
+ }
+ Capability::VariablePointersStorageBuffer => {
+ if !(device.enabled_features().variable_pointers_storage_buffer) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `variable_pointers_storage_buffer`",
+ ]));
+ }
+ }
+ Capability::VariablePointers => {
+ if !(device.enabled_features().variable_pointers) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `variable_pointers`",
+ ]));
+ }
+ }
+ Capability::ShaderClockKHR => {
+ if !(device.enabled_extensions().khr_shader_clock) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `khr_shader_clock`",
+ ]));
+ }
+ }
+ Capability::StencilExportEXT => {
+ if !(device.enabled_extensions().ext_shader_stencil_export) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `ext_shader_stencil_export`",
+ ]));
+ }
+ }
+ Capability::SubgroupBallotKHR => {
+ if !(device.enabled_extensions().ext_shader_subgroup_ballot) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `ext_shader_subgroup_ballot`",
+ ]));
+ }
+ }
+ Capability::SubgroupVoteKHR => {
+ if !(device.enabled_extensions().ext_shader_subgroup_vote) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `ext_shader_subgroup_vote`",
+ ]));
+ }
+ }
+ Capability::ImageReadWriteLodAMD => {
+ if !(device.enabled_extensions().amd_shader_image_load_store_lod) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `amd_shader_image_load_store_lod`",
+ ]));
+ }
+ }
+ Capability::ImageGatherBiasLodAMD => {
+ if !(device.enabled_extensions().amd_texture_gather_bias_lod) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `amd_texture_gather_bias_lod`",
+ ]));
+ }
+ }
+ Capability::FragmentMaskAMD => {
+ if !(device.enabled_extensions().amd_shader_fragment_mask) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `amd_shader_fragment_mask`",
+ ]));
+ }
+ }
+ Capability::SampleMaskOverrideCoverageNV => {
+ if !(device.enabled_extensions().nv_sample_mask_override_coverage) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `nv_sample_mask_override_coverage`",
+ ]));
+ }
+ }
+ Capability::GeometryShaderPassthroughNV => {
+ if !(device.enabled_extensions().nv_geometry_shader_passthrough) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `nv_geometry_shader_passthrough`",
+ ]));
+ }
+ }
+ Capability::ShaderViewportIndex => {
+ if !(device.enabled_features().shader_output_viewport_index) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_output_viewport_index`",
+ ]));
+ }
+ }
+ Capability::ShaderLayer => {
+ if !(device.enabled_features().shader_output_layer) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_output_layer`",
+ ]));
+ }
+ }
+ Capability::ShaderViewportIndexLayerEXT => {
+ if !(device.enabled_extensions().ext_shader_viewport_index_layer
+ || device.enabled_extensions().nv_viewport_array2)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `ext_shader_viewport_index_layer`",
+ "device extension `nv_viewport_array2`",
+ ]));
+ }
+ }
+ Capability::ShaderViewportMaskNV => {
+ if !(device.enabled_extensions().nv_viewport_array2) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `nv_viewport_array2`",
+ ]));
+ }
+ }
+ Capability::PerViewAttributesNV => {
+ if !(device
+ .enabled_extensions()
+ .nvx_multiview_per_view_attributes)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `nvx_multiview_per_view_attributes`",
+ ]));
+ }
+ }
+ Capability::StorageBuffer16BitAccess => {
+ if !(device.enabled_features().storage_buffer16_bit_access) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `storage_buffer16_bit_access`",
+ ]));
+ }
+ }
+ Capability::UniformAndStorageBuffer16BitAccess => {
+ if !(device
+ .enabled_features()
+ .uniform_and_storage_buffer16_bit_access)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `uniform_and_storage_buffer16_bit_access`",
+ ]));
+ }
+ }
+ Capability::StoragePushConstant16 => {
+ if !(device.enabled_features().storage_push_constant16) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `storage_push_constant16`",
+ ]));
+ }
+ }
+ Capability::StorageInputOutput16 => {
+ if !(device.enabled_features().storage_input_output16) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `storage_input_output16`",
+ ]));
+ }
+ }
+ Capability::GroupNonUniform => {
+ if !(device
+ .physical_device()
+ .properties()
+ .subgroup_supported_operations
+ .map(|x| x.intersects(crate::device::physical::SubgroupFeatures::BASIC))
+ .unwrap_or(false))
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "property `subgroup_supported_operations.BASIC`",
+ ]));
+ }
+ }
+ Capability::GroupNonUniformVote => {
+ if !(device
+ .physical_device()
+ .properties()
+ .subgroup_supported_operations
+ .map(|x| x.intersects(crate::device::physical::SubgroupFeatures::VOTE))
+ .unwrap_or(false))
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "property `subgroup_supported_operations.VOTE`",
+ ]));
+ }
+ }
+ Capability::GroupNonUniformArithmetic => {
+ if !(device
+ .physical_device()
+ .properties()
+ .subgroup_supported_operations
+ .map(|x| x.intersects(crate::device::physical::SubgroupFeatures::ARITHMETIC))
+ .unwrap_or(false))
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "property `subgroup_supported_operations.ARITHMETIC`",
+ ]));
+ }
+ }
+ Capability::GroupNonUniformBallot => {
+ if !(device
+ .physical_device()
+ .properties()
+ .subgroup_supported_operations
+ .map(|x| x.intersects(crate::device::physical::SubgroupFeatures::BALLOT))
+ .unwrap_or(false))
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "property `subgroup_supported_operations.BALLOT`",
+ ]));
+ }
+ }
+ Capability::GroupNonUniformShuffle => {
+ if !(device
+ .physical_device()
+ .properties()
+ .subgroup_supported_operations
+ .map(|x| x.intersects(crate::device::physical::SubgroupFeatures::SHUFFLE))
+ .unwrap_or(false))
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "property `subgroup_supported_operations.SHUFFLE`",
+ ]));
+ }
+ }
+ Capability::GroupNonUniformShuffleRelative => {
+ if !(device
+ .physical_device()
+ .properties()
+ .subgroup_supported_operations
+ .map(|x| x.intersects(crate::device::physical::SubgroupFeatures::SHUFFLE_RELATIVE))
+ .unwrap_or(false))
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "property `subgroup_supported_operations.SHUFFLE_RELATIVE`",
+ ]));
+ }
+ }
+ Capability::GroupNonUniformClustered => {
+ if !(device
+ .physical_device()
+ .properties()
+ .subgroup_supported_operations
+ .map(|x| x.intersects(crate::device::physical::SubgroupFeatures::CLUSTERED))
+ .unwrap_or(false))
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "property `subgroup_supported_operations.CLUSTERED`",
+ ]));
+ }
+ }
+ Capability::GroupNonUniformQuad => {
+ if !(device
+ .physical_device()
+ .properties()
+ .subgroup_supported_operations
+ .map(|x| x.intersects(crate::device::physical::SubgroupFeatures::QUAD))
+ .unwrap_or(false))
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "property `subgroup_supported_operations.QUAD`",
+ ]));
+ }
+ }
+ Capability::GroupNonUniformPartitionedNV => {
+ if !(device
+ .physical_device()
+ .properties()
+ .subgroup_supported_operations
+ .map(|x| x.intersects(crate::device::physical::SubgroupFeatures::PARTITIONED))
+ .unwrap_or(false))
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "property `subgroup_supported_operations.PARTITIONED`",
+ ]));
+ }
+ }
+ Capability::SampleMaskPostDepthCoverage => {
+ if !(device.enabled_extensions().ext_post_depth_coverage) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `ext_post_depth_coverage`",
+ ]));
+ }
+ }
+ Capability::ShaderNonUniform => {
+ if !(device.api_version() >= Version::V1_1
+ || device.enabled_extensions().ext_descriptor_indexing)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "Vulkan API version 1.1",
+ "device extension `ext_descriptor_indexing`",
+ ]));
+ }
+ }
+ Capability::RuntimeDescriptorArray => {
+ if !(device.enabled_features().runtime_descriptor_array) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `runtime_descriptor_array`",
+ ]));
+ }
+ }
+ Capability::InputAttachmentArrayDynamicIndexing => {
+ if !(device
+ .enabled_features()
+ .shader_input_attachment_array_dynamic_indexing)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_input_attachment_array_dynamic_indexing`",
+ ]));
+ }
+ }
+ Capability::UniformTexelBufferArrayDynamicIndexing => {
+ if !(device
+ .enabled_features()
+ .shader_uniform_texel_buffer_array_dynamic_indexing)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_uniform_texel_buffer_array_dynamic_indexing`",
+ ]));
+ }
+ }
+ Capability::StorageTexelBufferArrayDynamicIndexing => {
+ if !(device
+ .enabled_features()
+ .shader_storage_texel_buffer_array_dynamic_indexing)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_storage_texel_buffer_array_dynamic_indexing`",
+ ]));
+ }
+ }
+ Capability::UniformBufferArrayNonUniformIndexing => {
+ if !(device
+ .enabled_features()
+ .shader_uniform_buffer_array_non_uniform_indexing)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_uniform_buffer_array_non_uniform_indexing`",
+ ]));
+ }
+ }
+ Capability::SampledImageArrayNonUniformIndexing => {
+ if !(device
+ .enabled_features()
+ .shader_sampled_image_array_non_uniform_indexing)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_sampled_image_array_non_uniform_indexing`",
+ ]));
+ }
+ }
+ Capability::StorageBufferArrayNonUniformIndexing => {
+ if !(device
+ .enabled_features()
+ .shader_storage_buffer_array_non_uniform_indexing)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_storage_buffer_array_non_uniform_indexing`",
+ ]));
+ }
+ }
+ Capability::StorageImageArrayNonUniformIndexing => {
+ if !(device
+ .enabled_features()
+ .shader_storage_image_array_non_uniform_indexing)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_storage_image_array_non_uniform_indexing`",
+ ]));
+ }
+ }
+ Capability::InputAttachmentArrayNonUniformIndexing => {
+ if !(device
+ .enabled_features()
+ .shader_input_attachment_array_non_uniform_indexing)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_input_attachment_array_non_uniform_indexing`",
+ ]));
+ }
+ }
+ Capability::UniformTexelBufferArrayNonUniformIndexing => {
+ if !(device
+ .enabled_features()
+ .shader_uniform_texel_buffer_array_non_uniform_indexing)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_uniform_texel_buffer_array_non_uniform_indexing`",
+ ]));
+ }
+ }
+ Capability::StorageTexelBufferArrayNonUniformIndexing => {
+ if !(device
+ .enabled_features()
+ .shader_storage_texel_buffer_array_non_uniform_indexing)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_storage_texel_buffer_array_non_uniform_indexing`",
+ ]));
+ }
+ }
+ Capability::FragmentFullyCoveredEXT => {
+ if !(device.enabled_extensions().ext_conservative_rasterization) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `ext_conservative_rasterization`",
+ ]));
+ }
+ }
+ Capability::Float16 => {
+ if !(device.enabled_features().shader_float16
+ || device.enabled_extensions().amd_gpu_shader_half_float)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_float16`",
+ "device extension `amd_gpu_shader_half_float`",
+ ]));
+ }
+ }
+ Capability::Int8 => {
+ if !(device.enabled_features().shader_int8) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_int8`",
+ ]));
+ }
+ }
+ Capability::StorageBuffer8BitAccess => {
+ if !(device.enabled_features().storage_buffer8_bit_access) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `storage_buffer8_bit_access`",
+ ]));
+ }
+ }
+ Capability::UniformAndStorageBuffer8BitAccess => {
+ if !(device
+ .enabled_features()
+ .uniform_and_storage_buffer8_bit_access)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `uniform_and_storage_buffer8_bit_access`",
+ ]));
+ }
+ }
+ Capability::StoragePushConstant8 => {
+ if !(device.enabled_features().storage_push_constant8) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `storage_push_constant8`",
+ ]));
+ }
+ }
+ Capability::VulkanMemoryModel => {
+ if !(device.enabled_features().vulkan_memory_model) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `vulkan_memory_model`",
+ ]));
+ }
+ }
+ Capability::VulkanMemoryModelDeviceScope => {
+ if !(device.enabled_features().vulkan_memory_model_device_scope) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `vulkan_memory_model_device_scope`",
+ ]));
+ }
+ }
+ Capability::DenormPreserve => {
+ if !(device
+ .physical_device()
+ .properties()
+ .shader_denorm_preserve_float16
+ .unwrap_or(false)
+ || device
+ .physical_device()
+ .properties()
+ .shader_denorm_preserve_float32
+ .unwrap_or(false)
+ || device
+ .physical_device()
+ .properties()
+ .shader_denorm_preserve_float64
+ .unwrap_or(false))
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "property `shader_denorm_preserve_float16`",
+ "property `shader_denorm_preserve_float32`",
+ "property `shader_denorm_preserve_float64`",
+ ]));
+ }
+ }
+ Capability::DenormFlushToZero => {
+ if !(device
+ .physical_device()
+ .properties()
+ .shader_denorm_flush_to_zero_float16
+ .unwrap_or(false)
+ || device
+ .physical_device()
+ .properties()
+ .shader_denorm_flush_to_zero_float32
+ .unwrap_or(false)
+ || device
+ .physical_device()
+ .properties()
+ .shader_denorm_flush_to_zero_float64
+ .unwrap_or(false))
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "property `shader_denorm_flush_to_zero_float16`",
+ "property `shader_denorm_flush_to_zero_float32`",
+ "property `shader_denorm_flush_to_zero_float64`",
+ ]));
+ }
+ }
+ Capability::SignedZeroInfNanPreserve => {
+ if !(device
+ .physical_device()
+ .properties()
+ .shader_signed_zero_inf_nan_preserve_float16
+ .unwrap_or(false)
+ || device
+ .physical_device()
+ .properties()
+ .shader_signed_zero_inf_nan_preserve_float32
+ .unwrap_or(false)
+ || device
+ .physical_device()
+ .properties()
+ .shader_signed_zero_inf_nan_preserve_float64
+ .unwrap_or(false))
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "property `shader_signed_zero_inf_nan_preserve_float16`",
+ "property `shader_signed_zero_inf_nan_preserve_float32`",
+ "property `shader_signed_zero_inf_nan_preserve_float64`",
+ ]));
+ }
+ }
+ Capability::RoundingModeRTE => {
+ if !(device
+ .physical_device()
+ .properties()
+ .shader_rounding_mode_rte_float16
+ .unwrap_or(false)
+ || device
+ .physical_device()
+ .properties()
+ .shader_rounding_mode_rte_float32
+ .unwrap_or(false)
+ || device
+ .physical_device()
+ .properties()
+ .shader_rounding_mode_rte_float64
+ .unwrap_or(false))
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "property `shader_rounding_mode_rte_float16`",
+ "property `shader_rounding_mode_rte_float32`",
+ "property `shader_rounding_mode_rte_float64`",
+ ]));
+ }
+ }
+ Capability::RoundingModeRTZ => {
+ if !(device
+ .physical_device()
+ .properties()
+ .shader_rounding_mode_rtz_float16
+ .unwrap_or(false)
+ || device
+ .physical_device()
+ .properties()
+ .shader_rounding_mode_rtz_float32
+ .unwrap_or(false)
+ || device
+ .physical_device()
+ .properties()
+ .shader_rounding_mode_rtz_float64
+ .unwrap_or(false))
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "property `shader_rounding_mode_rtz_float16`",
+ "property `shader_rounding_mode_rtz_float32`",
+ "property `shader_rounding_mode_rtz_float64`",
+ ]));
+ }
+ }
+ Capability::ComputeDerivativeGroupQuadsNV => {
+ if !(device.enabled_features().compute_derivative_group_quads) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `compute_derivative_group_quads`",
+ ]));
+ }
+ }
+ Capability::ComputeDerivativeGroupLinearNV => {
+ if !(device.enabled_features().compute_derivative_group_linear) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `compute_derivative_group_linear`",
+ ]));
+ }
+ }
+ Capability::FragmentBarycentricKHR => {
+ if !(device.enabled_features().fragment_shader_barycentric
+ || device.enabled_features().fragment_shader_barycentric)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `fragment_shader_barycentric`",
+ "feature `fragment_shader_barycentric`",
+ ]));
+ }
+ }
+ Capability::ImageFootprintNV => {
+ if !(device.enabled_features().image_footprint) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `image_footprint`",
+ ]));
+ }
+ }
+ Capability::FragmentDensityEXT => {
+ if !(device.enabled_features().shading_rate_image
+ || device.enabled_features().fragment_density_map)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shading_rate_image`",
+ "feature `fragment_density_map`",
+ ]));
+ }
+ }
+ Capability::MeshShadingNV => {
+ if !(device.enabled_extensions().nv_mesh_shader) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `nv_mesh_shader`",
+ ]));
+ }
+ }
+ Capability::RayTracingKHR => {
+ if !(device.enabled_features().ray_tracing_pipeline) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `ray_tracing_pipeline`",
+ ]));
+ }
+ }
+ Capability::RayQueryKHR => {
+ if !(device.enabled_features().ray_query) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `ray_query`",
+ ]));
+ }
+ }
+ Capability::RayTraversalPrimitiveCullingKHR => {
+ if !(device.enabled_features().ray_traversal_primitive_culling
+ || device.enabled_features().ray_query)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `ray_traversal_primitive_culling`",
+ "feature `ray_query`",
+ ]));
+ }
+ }
+ Capability::RayTracingNV => {
+ if !(device.enabled_extensions().nv_ray_tracing) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `nv_ray_tracing`",
+ ]));
+ }
+ }
+ Capability::RayTracingMotionBlurNV => {
+ if !(device.enabled_features().ray_tracing_motion_blur) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `ray_tracing_motion_blur`",
+ ]));
+ }
+ }
+ Capability::TransformFeedback => {
+ if !(device.enabled_features().transform_feedback) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `transform_feedback`",
+ ]));
+ }
+ }
+ Capability::GeometryStreams => {
+ if !(device.enabled_features().geometry_streams) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `geometry_streams`",
+ ]));
+ }
+ }
+ Capability::PhysicalStorageBufferAddresses => {
+ if !(device.enabled_features().buffer_device_address) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `buffer_device_address`",
+ ]));
+ }
+ }
+ Capability::CooperativeMatrixNV => {
+ if !(device.enabled_features().cooperative_matrix) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `cooperative_matrix`",
+ ]));
+ }
+ }
+ Capability::IntegerFunctions2INTEL => {
+ if !(device.enabled_features().shader_integer_functions2) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_integer_functions2`",
+ ]));
+ }
+ }
+ Capability::ShaderSMBuiltinsNV => {
+ if !(device.enabled_features().shader_sm_builtins) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_sm_builtins`",
+ ]));
+ }
+ }
+ Capability::FragmentShaderSampleInterlockEXT => {
+ if !(device.enabled_features().fragment_shader_sample_interlock) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `fragment_shader_sample_interlock`",
+ ]));
+ }
+ }
+ Capability::FragmentShaderPixelInterlockEXT => {
+ if !(device.enabled_features().fragment_shader_pixel_interlock) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `fragment_shader_pixel_interlock`",
+ ]));
+ }
+ }
+ Capability::FragmentShaderShadingRateInterlockEXT => {
+ if !(device
+ .enabled_features()
+ .fragment_shader_shading_rate_interlock
+ || device.enabled_features().shading_rate_image)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `fragment_shader_shading_rate_interlock`",
+ "feature `shading_rate_image`",
+ ]));
+ }
+ }
+ Capability::DemoteToHelperInvocation => {
+ if !(device.enabled_features().shader_demote_to_helper_invocation) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_demote_to_helper_invocation`",
+ ]));
+ }
+ }
+ Capability::FragmentShadingRateKHR => {
+ if !(device.enabled_features().pipeline_fragment_shading_rate
+ || device.enabled_features().primitive_fragment_shading_rate
+ || device.enabled_features().attachment_fragment_shading_rate)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `pipeline_fragment_shading_rate`",
+ "feature `primitive_fragment_shading_rate`",
+ "feature `attachment_fragment_shading_rate`",
+ ]));
+ }
+ }
+ Capability::WorkgroupMemoryExplicitLayoutKHR => {
+ if !(device.enabled_features().workgroup_memory_explicit_layout) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `workgroup_memory_explicit_layout`",
+ ]));
+ }
+ }
+ Capability::WorkgroupMemoryExplicitLayout8BitAccessKHR => {
+ if !(device
+ .enabled_features()
+ .workgroup_memory_explicit_layout8_bit_access)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `workgroup_memory_explicit_layout8_bit_access`",
+ ]));
+ }
+ }
+ Capability::WorkgroupMemoryExplicitLayout16BitAccessKHR => {
+ if !(device
+ .enabled_features()
+ .workgroup_memory_explicit_layout16_bit_access)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `workgroup_memory_explicit_layout16_bit_access`",
+ ]));
+ }
+ }
+ Capability::DotProductInputAll => {
+ if !(device.enabled_features().shader_integer_dot_product) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_integer_dot_product`",
+ ]));
+ }
+ }
+ Capability::DotProductInput4x8Bit => {
+ if !(device.enabled_features().shader_integer_dot_product) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_integer_dot_product`",
+ ]));
+ }
+ }
+ Capability::DotProductInput4x8BitPacked => {
+ if !(device.enabled_features().shader_integer_dot_product) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_integer_dot_product`",
+ ]));
+ }
+ }
+ Capability::DotProduct => {
+ if !(device.enabled_features().shader_integer_dot_product) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "feature `shader_integer_dot_product`",
+ ]));
+ }
+ }
+ _ => return Err(ShaderSupportError::NotSupportedByVulkan),
+ }
+ Ok(())
+}
+fn check_spirv_extension(device: &Device, extension: &str) -> Result<(), ShaderSupportError> {
+ match extension {
+ "SPV_KHR_variable_pointers" => {
+ if !(device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_variable_pointers)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "Vulkan API version 1.1",
+ "device extension `khr_variable_pointers`",
+ ]));
+ }
+ }
+ "SPV_AMD_shader_explicit_vertex_parameter" => {
+ if !(device
+ .enabled_extensions()
+ .amd_shader_explicit_vertex_parameter)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `amd_shader_explicit_vertex_parameter`",
+ ]));
+ }
+ }
+ "SPV_AMD_gcn_shader" => {
+ if !(device.enabled_extensions().amd_gcn_shader) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `amd_gcn_shader`",
+ ]));
+ }
+ }
+ "SPV_AMD_gpu_shader_half_float" => {
+ if !(device.enabled_extensions().amd_gpu_shader_half_float) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `amd_gpu_shader_half_float`",
+ ]));
+ }
+ }
+ "SPV_AMD_gpu_shader_int16" => {
+ if !(device.enabled_extensions().amd_gpu_shader_int16) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `amd_gpu_shader_int16`",
+ ]));
+ }
+ }
+ "SPV_AMD_shader_ballot" => {
+ if !(device.enabled_extensions().amd_shader_ballot) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `amd_shader_ballot`",
+ ]));
+ }
+ }
+ "SPV_AMD_shader_fragment_mask" => {
+ if !(device.enabled_extensions().amd_shader_fragment_mask) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `amd_shader_fragment_mask`",
+ ]));
+ }
+ }
+ "SPV_AMD_shader_image_load_store_lod" => {
+ if !(device.enabled_extensions().amd_shader_image_load_store_lod) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `amd_shader_image_load_store_lod`",
+ ]));
+ }
+ }
+ "SPV_AMD_shader_trinary_minmax" => {
+ if !(device.enabled_extensions().amd_shader_trinary_minmax) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `amd_shader_trinary_minmax`",
+ ]));
+ }
+ }
+ "SPV_AMD_texture_gather_bias_lod" => {
+ if !(device.enabled_extensions().amd_texture_gather_bias_lod) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `amd_texture_gather_bias_lod`",
+ ]));
+ }
+ }
+ "SPV_AMD_shader_early_and_late_fragment_tests" => {
+ if !(device
+ .enabled_extensions()
+ .amd_shader_early_and_late_fragment_tests)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `amd_shader_early_and_late_fragment_tests`",
+ ]));
+ }
+ }
+ "SPV_KHR_shader_draw_parameters" => {
+ if !(device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_shader_draw_parameters)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "Vulkan API version 1.1",
+ "device extension `khr_shader_draw_parameters`",
+ ]));
+ }
+ }
+ "SPV_KHR_8bit_storage" => {
+ if !(device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_8bit_storage)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "Vulkan API version 1.1",
+ "device extension `khr_8bit_storage`",
+ ]));
+ }
+ }
+ "SPV_KHR_16bit_storage" => {
+ if !(device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_16bit_storage)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "Vulkan API version 1.1",
+ "device extension `khr_16bit_storage`",
+ ]));
+ }
+ }
+ "SPV_KHR_shader_clock" => {
+ if !(device.enabled_extensions().khr_shader_clock) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `khr_shader_clock`",
+ ]));
+ }
+ }
+ "SPV_KHR_float_controls" => {
+ if !(device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_shader_float_controls)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "Vulkan API version 1.1",
+ "device extension `khr_shader_float_controls`",
+ ]));
+ }
+ }
+ "SPV_KHR_storage_buffer_storage_class" => {
+ if !(device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_storage_buffer_storage_class)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "Vulkan API version 1.1",
+ "device extension `khr_storage_buffer_storage_class`",
+ ]));
+ }
+ }
+ "SPV_KHR_post_depth_coverage" => {
+ if !(device.enabled_extensions().ext_post_depth_coverage) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `ext_post_depth_coverage`",
+ ]));
+ }
+ }
+ "SPV_EXT_shader_stencil_export" => {
+ if !(device.enabled_extensions().ext_shader_stencil_export) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `ext_shader_stencil_export`",
+ ]));
+ }
+ }
+ "SPV_KHR_shader_ballot" => {
+ if !(device.enabled_extensions().ext_shader_subgroup_ballot) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `ext_shader_subgroup_ballot`",
+ ]));
+ }
+ }
+ "SPV_KHR_subgroup_vote" => {
+ if !(device.enabled_extensions().ext_shader_subgroup_vote) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `ext_shader_subgroup_vote`",
+ ]));
+ }
+ }
+ "SPV_NV_sample_mask_override_coverage" => {
+ if !(device.enabled_extensions().nv_sample_mask_override_coverage) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `nv_sample_mask_override_coverage`",
+ ]));
+ }
+ }
+ "SPV_NV_geometry_shader_passthrough" => {
+ if !(device.enabled_extensions().nv_geometry_shader_passthrough) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `nv_geometry_shader_passthrough`",
+ ]));
+ }
+ }
+ "SPV_NV_mesh_shader" => {
+ if !(device.enabled_extensions().nv_mesh_shader) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `nv_mesh_shader`",
+ ]));
+ }
+ }
+ "SPV_NV_viewport_array2" => {
+ if !(device.enabled_extensions().nv_viewport_array2) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `nv_viewport_array2`",
+ ]));
+ }
+ }
+ "SPV_NV_shader_subgroup_partitioned" => {
+ if !(device.enabled_extensions().nv_shader_subgroup_partitioned) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `nv_shader_subgroup_partitioned`",
+ ]));
+ }
+ }
+ "SPV_NV_shader_invocation_reorder" => {
+ if !(device
+ .enabled_extensions()
+ .nv_ray_tracing_invocation_reorder)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `nv_ray_tracing_invocation_reorder`",
+ ]));
+ }
+ }
+ "SPV_EXT_shader_viewport_index_layer" => {
+ if !(device.api_version() >= Version::V1_1
+ || device.enabled_extensions().ext_shader_viewport_index_layer)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "Vulkan API version 1.1",
+ "device extension `ext_shader_viewport_index_layer`",
+ ]));
+ }
+ }
+ "SPV_NVX_multiview_per_view_attributes" => {
+ if !(device
+ .enabled_extensions()
+ .nvx_multiview_per_view_attributes)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `nvx_multiview_per_view_attributes`",
+ ]));
+ }
+ }
+ "SPV_EXT_descriptor_indexing" => {
+ if !(device.api_version() >= Version::V1_1
+ || device.enabled_extensions().ext_descriptor_indexing)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "Vulkan API version 1.1",
+ "device extension `ext_descriptor_indexing`",
+ ]));
+ }
+ }
+ "SPV_KHR_vulkan_memory_model" => {
+ if !(device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_vulkan_memory_model)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "Vulkan API version 1.1",
+ "device extension `khr_vulkan_memory_model`",
+ ]));
+ }
+ }
+ "SPV_NV_compute_shader_derivatives" => {
+ if !(device.enabled_extensions().nv_compute_shader_derivatives) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `nv_compute_shader_derivatives`",
+ ]));
+ }
+ }
+ "SPV_NV_fragment_shader_barycentric" => {
+ if !(device.enabled_extensions().nv_fragment_shader_barycentric) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `nv_fragment_shader_barycentric`",
+ ]));
+ }
+ }
+ "SPV_NV_shader_image_footprint" => {
+ if !(device.enabled_extensions().nv_shader_image_footprint) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `nv_shader_image_footprint`",
+ ]));
+ }
+ }
+ "SPV_NV_shading_rate" => {
+ if !(device.enabled_extensions().nv_shading_rate_image) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `nv_shading_rate_image`",
+ ]));
+ }
+ }
+ "SPV_NV_ray_tracing" => {
+ if !(device.enabled_extensions().nv_ray_tracing) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `nv_ray_tracing`",
+ ]));
+ }
+ }
+ "SPV_KHR_ray_tracing" => {
+ if !(device.enabled_extensions().khr_ray_tracing_pipeline) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `khr_ray_tracing_pipeline`",
+ ]));
+ }
+ }
+ "SPV_KHR_ray_query" => {
+ if !(device.enabled_extensions().khr_ray_query) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `khr_ray_query`",
+ ]));
+ }
+ }
+ "SPV_KHR_ray_cull_mask" => {
+ if !(device.enabled_extensions().khr_ray_tracing_maintenance1) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `khr_ray_tracing_maintenance1`",
+ ]));
+ }
+ }
+ "SPV_GOOGLE_hlsl_functionality1" => {
+ if !(device.enabled_extensions().google_hlsl_functionality1) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `google_hlsl_functionality1`",
+ ]));
+ }
+ }
+ "SPV_GOOGLE_user_type" => {
+ if !(device.enabled_extensions().google_user_type) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `google_user_type`",
+ ]));
+ }
+ }
+ "SPV_GOOGLE_decorate_string" => {
+ if !(device.enabled_extensions().google_decorate_string) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `google_decorate_string`",
+ ]));
+ }
+ }
+ "SPV_EXT_fragment_invocation_density" => {
+ if !(device.enabled_extensions().ext_fragment_density_map) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `ext_fragment_density_map`",
+ ]));
+ }
+ }
+ "SPV_KHR_physical_storage_buffer" => {
+ if !(device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_buffer_device_address)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "Vulkan API version 1.1",
+ "device extension `khr_buffer_device_address`",
+ ]));
+ }
+ }
+ "SPV_EXT_physical_storage_buffer" => {
+ if !(device.enabled_extensions().ext_buffer_device_address) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `ext_buffer_device_address`",
+ ]));
+ }
+ }
+ "SPV_NV_cooperative_matrix" => {
+ if !(device.enabled_extensions().nv_cooperative_matrix) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `nv_cooperative_matrix`",
+ ]));
+ }
+ }
+ "SPV_NV_shader_sm_builtins" => {
+ if !(device.enabled_extensions().nv_shader_sm_builtins) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `nv_shader_sm_builtins`",
+ ]));
+ }
+ }
+ "SPV_EXT_fragment_shader_interlock" => {
+ if !(device.enabled_extensions().ext_fragment_shader_interlock) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `ext_fragment_shader_interlock`",
+ ]));
+ }
+ }
+ "SPV_EXT_demote_to_helper_invocation" => {
+ if !(device.api_version() >= Version::V1_1
+ || device
+ .enabled_extensions()
+ .ext_shader_demote_to_helper_invocation)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "Vulkan API version 1.1",
+ "device extension `ext_shader_demote_to_helper_invocation`",
+ ]));
+ }
+ }
+ "SPV_KHR_fragment_shading_rate" => {
+ if !(device.enabled_extensions().khr_fragment_shading_rate) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `khr_fragment_shading_rate`",
+ ]));
+ }
+ }
+ "SPV_KHR_non_semantic_info" => {
+ if !(device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_shader_non_semantic_info)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "Vulkan API version 1.1",
+ "device extension `khr_shader_non_semantic_info`",
+ ]));
+ }
+ }
+ "SPV_EXT_shader_image_int64" => {
+ if !(device.enabled_extensions().ext_shader_image_atomic_int64) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `ext_shader_image_atomic_int64`",
+ ]));
+ }
+ }
+ "SPV_KHR_terminate_invocation" => {
+ if !(device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_shader_terminate_invocation)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "Vulkan API version 1.1",
+ "device extension `khr_shader_terminate_invocation`",
+ ]));
+ }
+ }
+ "SPV_KHR_multiview" => {
+ if !(device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_multiview)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "Vulkan API version 1.1",
+ "device extension `khr_multiview`",
+ ]));
+ }
+ }
+ "SPV_KHR_workgroup_memory_explicit_layout" => {
+ if !(device
+ .enabled_extensions()
+ .khr_workgroup_memory_explicit_layout)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `khr_workgroup_memory_explicit_layout`",
+ ]));
+ }
+ }
+ "SPV_EXT_shader_atomic_float_add" => {
+ if !(device.enabled_extensions().ext_shader_atomic_float) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `ext_shader_atomic_float`",
+ ]));
+ }
+ }
+ "SPV_KHR_fragment_shader_barycentric" => {
+ if !(device.enabled_extensions().khr_fragment_shader_barycentric) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `khr_fragment_shader_barycentric`",
+ ]));
+ }
+ }
+ "SPV_KHR_subgroup_uniform_control_flow" => {
+ if !(device.api_version() >= Version::V1_1
+ || device
+ .enabled_extensions()
+ .khr_shader_subgroup_uniform_control_flow)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "Vulkan API version 1.1",
+ "device extension `khr_shader_subgroup_uniform_control_flow`",
+ ]));
+ }
+ }
+ "SPV_EXT_shader_atomic_float_min_max" => {
+ if !(device.enabled_extensions().ext_shader_atomic_float2) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `ext_shader_atomic_float2`",
+ ]));
+ }
+ }
+ "SPV_EXT_shader_atomic_float16_add" => {
+ if !(device.enabled_extensions().ext_shader_atomic_float2) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `ext_shader_atomic_float2`",
+ ]));
+ }
+ }
+ "SPV_KHR_integer_dot_product" => {
+ if !(device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_shader_integer_dot_product)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "Vulkan API version 1.1",
+ "device extension `khr_shader_integer_dot_product`",
+ ]));
+ }
+ }
+ "SPV_INTEL_shader_integer_functions" => {
+ if !(device.enabled_extensions().intel_shader_integer_functions2) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `intel_shader_integer_functions2`",
+ ]));
+ }
+ }
+ "SPV_KHR_device_group" => {
+ if !(device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_device_group)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "Vulkan API version 1.1",
+ "device extension `khr_device_group`",
+ ]));
+ }
+ }
+ "SPV_QCOM_image_processing" => {
+ if !(device.enabled_extensions().qcom_image_processing) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `qcom_image_processing`",
+ ]));
+ }
+ }
+ "SPV_EXT_mesh_shader" => {
+ if !(device.enabled_extensions().ext_mesh_shader) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "device extension `ext_mesh_shader`",
+ ]));
+ }
+ }
+ _ => return Err(ShaderSupportError::NotSupportedByVulkan),
+ }
+ Ok(())
+}
diff --git a/out/version.rs b/out/version.rs
new file mode 100644
index 0000000..a579a9b
--- /dev/null
+++ b/out/version.rs
@@ -0,0 +1,20 @@
+// This file is auto-generated by vulkano autogen from vk.xml header version 1.3.238.
+// It should not be edited manually. Changes should be made by editing autogen.
+
+impl Version {
+ #[doc = r" The highest Vulkan API version currently supported by Vulkano."]
+ #[doc = r""]
+ #[doc = r" It is allowed for applications that use Vulkano to make use of features from higher"]
+ #[doc = r" versions than this. However, Vulkano itself will not make use of those features and"]
+ #[doc = r" will not expose their APIs, so they must be accessed by other means."]
+ #[doc = r""]
+ #[doc = r" The `max_api_version` of an [`Instance`](crate::instance::Instance) equals"]
+ #[doc = r" `HEADER_VERSION` by default, which locks out features from newer versions. In order"]
+ #[doc = r" to enable the use of higher versions, the `max_api_version` must be overridden when"]
+ #[doc = r" creating an instance."]
+ pub const HEADER_VERSION: Version = Version {
+ major: 1,
+ minor: 3,
+ patch: 238,
+ };
+}
diff --git a/spirv.core.grammar.json b/spirv.core.grammar.json
new file mode 100644
index 0000000..bea21bd
--- /dev/null
+++ b/spirv.core.grammar.json
@@ -0,0 +1,24586 @@
+{
+ "copyright": [
+ "Copyright (c) 2014-2020 The Khronos Group Inc.",
+ "",
+ "Permission is hereby granted, free of charge, to any person obtaining a copy",
+ "of this software and/or associated documentation files (the \"Materials\"),",
+ "to deal in the Materials without restriction, including without limitation",
+ "the rights to use, copy, modify, merge, publish, distribute, sublicense,",
+ "and/or sell copies of the Materials, and to permit persons to whom the",
+ "Materials are furnished to do so, subject to the following conditions:",
+ "",
+ "The above copyright notice and this permission notice shall be included in",
+ "all copies or substantial portions of the Materials.",
+ "",
+ "MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS",
+ "STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND",
+ "HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ ",
+ "",
+ "THE MATERIALS ARE PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS",
+ "OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,",
+ "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL",
+ "THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER",
+ "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING",
+ "FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS",
+ "IN THE MATERIALS."
+ ],
+ "magic_number": "0x07230203",
+ "major_version": 1,
+ "minor_version": 6,
+ "revision": 1,
+ "instruction_printing_class": [
+ {
+ "tag": "@exclude"
+ },
+ {
+ "tag": "Miscellaneous",
+ "heading": "Miscellaneous Instructions"
+ },
+ {
+ "tag": "Debug",
+ "heading": "Debug Instructions"
+ },
+ {
+ "tag": "Annotation",
+ "heading": "Annotation Instructions"
+ },
+ {
+ "tag": "Extension",
+ "heading": "Extension Instructions"
+ },
+ {
+ "tag": "Mode-Setting",
+ "heading": "Mode-Setting Instructions"
+ },
+ {
+ "tag": "Type-Declaration",
+ "heading": "Type-Declaration Instructions"
+ },
+ {
+ "tag": "Constant-Creation",
+ "heading": "Constant-Creation Instructions"
+ },
+ {
+ "tag": "Memory",
+ "heading": "Memory Instructions"
+ },
+ {
+ "tag": "Function",
+ "heading": "Function Instructions"
+ },
+ {
+ "tag": "Image",
+ "heading": "Image Instructions"
+ },
+ {
+ "tag": "Conversion",
+ "heading": "Conversion Instructions"
+ },
+ {
+ "tag": "Composite",
+ "heading": "Composite Instructions"
+ },
+ {
+ "tag": "Arithmetic",
+ "heading": "Arithmetic Instructions"
+ },
+ {
+ "tag": "Bit",
+ "heading": "Bit Instructions"
+ },
+ {
+ "tag": "Relational_and_Logical",
+ "heading": "Relational and Logical Instructions"
+ },
+ {
+ "tag": "Derivative",
+ "heading": "Derivative Instructions"
+ },
+ {
+ "tag": "Control-Flow",
+ "heading": "Control-Flow Instructions"
+ },
+ {
+ "tag": "Atomic",
+ "heading": "Atomic Instructions"
+ },
+ {
+ "tag": "Primitive",
+ "heading": "Primitive Instructions"
+ },
+ {
+ "tag": "Barrier",
+ "heading": "Barrier Instructions"
+ },
+ {
+ "tag": "Group",
+ "heading": "Group and Subgroup Instructions"
+ },
+ {
+ "tag": "Device-Side_Enqueue",
+ "heading": "Device-Side Enqueue Instructions"
+ },
+ {
+ "tag": "Pipe",
+ "heading": "Pipe Instructions"
+ },
+ {
+ "tag": "Non-Uniform",
+ "heading": "Non-Uniform Instructions"
+ },
+ {
+ "tag": "Reserved",
+ "heading": "Reserved Instructions"
+ }
+ ],
+ "instructions": [
+ {
+ "opname": "OpNop",
+ "class": "Miscellaneous",
+ "opcode": 0
+ },
+ {
+ "opname": "OpUndef",
+ "class": "Miscellaneous",
+ "opcode": 1,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ }
+ ]
+ },
+ {
+ "opname": "OpSourceContinued",
+ "class": "Debug",
+ "opcode": 2,
+ "operands": [
+ {
+ "kind": "LiteralString",
+ "name": "'Continued Source'"
+ }
+ ]
+ },
+ {
+ "opname": "OpSource",
+ "class": "Debug",
+ "opcode": 3,
+ "operands": [
+ {
+ "kind": "SourceLanguage"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Version'"
+ },
+ {
+ "kind": "IdRef",
+ "quantifier": "?",
+ "name": "'File'"
+ },
+ {
+ "kind": "LiteralString",
+ "quantifier": "?",
+ "name": "'Source'"
+ }
+ ]
+ },
+ {
+ "opname": "OpSourceExtension",
+ "class": "Debug",
+ "opcode": 4,
+ "operands": [
+ {
+ "kind": "LiteralString",
+ "name": "'Extension'"
+ }
+ ]
+ },
+ {
+ "opname": "OpName",
+ "class": "Debug",
+ "opcode": 5,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Target'"
+ },
+ {
+ "kind": "LiteralString",
+ "name": "'Name'"
+ }
+ ]
+ },
+ {
+ "opname": "OpMemberName",
+ "class": "Debug",
+ "opcode": 6,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Type'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Member'"
+ },
+ {
+ "kind": "LiteralString",
+ "name": "'Name'"
+ }
+ ]
+ },
+ {
+ "opname": "OpString",
+ "class": "Debug",
+ "opcode": 7,
+ "operands": [
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "LiteralString",
+ "name": "'String'"
+ }
+ ]
+ },
+ {
+ "opname": "OpLine",
+ "class": "Debug",
+ "opcode": 8,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'File'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Line'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Column'"
+ }
+ ]
+ },
+ {
+ "opname": "OpExtension",
+ "class": "Extension",
+ "opcode": 10,
+ "operands": [
+ {
+ "kind": "LiteralString",
+ "name": "'Name'"
+ }
+ ]
+ },
+ {
+ "opname": "OpExtInstImport",
+ "class": "Extension",
+ "opcode": 11,
+ "operands": [
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "LiteralString",
+ "name": "'Name'"
+ }
+ ]
+ },
+ {
+ "opname": "OpExtInst",
+ "class": "Extension",
+ "opcode": 12,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Set'"
+ },
+ {
+ "kind": "LiteralExtInstInteger",
+ "name": "'Instruction'"
+ },
+ {
+ "kind": "IdRef",
+ "quantifier": "*",
+ "name": "'Operand 1', +\n'Operand 2', +\n..."
+ }
+ ]
+ },
+ {
+ "opname": "OpMemoryModel",
+ "class": "Mode-Setting",
+ "opcode": 14,
+ "operands": [
+ {
+ "kind": "AddressingModel"
+ },
+ {
+ "kind": "MemoryModel"
+ }
+ ]
+ },
+ {
+ "opname": "OpEntryPoint",
+ "class": "Mode-Setting",
+ "opcode": 15,
+ "operands": [
+ {
+ "kind": "ExecutionModel"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Entry Point'"
+ },
+ {
+ "kind": "LiteralString",
+ "name": "'Name'"
+ },
+ {
+ "kind": "IdRef",
+ "quantifier": "*",
+ "name": "'Interface'"
+ }
+ ]
+ },
+ {
+ "opname": "OpExecutionMode",
+ "class": "Mode-Setting",
+ "opcode": 16,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Entry Point'"
+ },
+ {
+ "kind": "ExecutionMode",
+ "name": "'Mode'"
+ }
+ ]
+ },
+ {
+ "opname": "OpCapability",
+ "class": "Mode-Setting",
+ "opcode": 17,
+ "operands": [
+ {
+ "kind": "Capability",
+ "name": "'Capability'"
+ }
+ ]
+ },
+ {
+ "opname": "OpTypeVoid",
+ "class": "Type-Declaration",
+ "opcode": 19,
+ "operands": [
+ {
+ "kind": "IdResult"
+ }
+ ]
+ },
+ {
+ "opname": "OpTypeBool",
+ "class": "Type-Declaration",
+ "opcode": 20,
+ "operands": [
+ {
+ "kind": "IdResult"
+ }
+ ]
+ },
+ {
+ "opname": "OpTypeInt",
+ "class": "Type-Declaration",
+ "opcode": 21,
+ "operands": [
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Width'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Signedness'"
+ }
+ ]
+ },
+ {
+ "opname": "OpTypeFloat",
+ "class": "Type-Declaration",
+ "opcode": 22,
+ "operands": [
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Width'"
+ }
+ ]
+ },
+ {
+ "opname": "OpTypeVector",
+ "class": "Type-Declaration",
+ "opcode": 23,
+ "operands": [
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Component Type'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Component Count'"
+ }
+ ]
+ },
+ {
+ "opname": "OpTypeMatrix",
+ "class": "Type-Declaration",
+ "opcode": 24,
+ "operands": [
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Column Type'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Column Count'"
+ }
+ ],
+ "capabilities": [
+ "Matrix"
+ ]
+ },
+ {
+ "opname": "OpTypeImage",
+ "class": "Type-Declaration",
+ "opcode": 25,
+ "operands": [
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sampled Type'"
+ },
+ {
+ "kind": "Dim"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Depth'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Arrayed'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'MS'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Sampled'"
+ },
+ {
+ "kind": "ImageFormat"
+ },
+ {
+ "kind": "AccessQualifier",
+ "quantifier": "?"
+ }
+ ]
+ },
+ {
+ "opname": "OpTypeSampler",
+ "class": "Type-Declaration",
+ "opcode": 26,
+ "operands": [
+ {
+ "kind": "IdResult"
+ }
+ ]
+ },
+ {
+ "opname": "OpTypeSampledImage",
+ "class": "Type-Declaration",
+ "opcode": 27,
+ "operands": [
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Image Type'"
+ }
+ ]
+ },
+ {
+ "opname": "OpTypeArray",
+ "class": "Type-Declaration",
+ "opcode": 28,
+ "operands": [
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Element Type'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Length'"
+ }
+ ]
+ },
+ {
+ "opname": "OpTypeRuntimeArray",
+ "class": "Type-Declaration",
+ "opcode": 29,
+ "operands": [
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Element Type'"
+ }
+ ],
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "opname": "OpTypeStruct",
+ "class": "Type-Declaration",
+ "opcode": 30,
+ "operands": [
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "quantifier": "*",
+ "name": "'Member 0 type', +\n'member 1 type', +\n..."
+ }
+ ]
+ },
+ {
+ "opname": "OpTypeOpaque",
+ "class": "Type-Declaration",
+ "opcode": 31,
+ "operands": [
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "LiteralString",
+ "name": "The name of the opaque type."
+ }
+ ],
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "opname": "OpTypePointer",
+ "class": "Type-Declaration",
+ "opcode": 32,
+ "operands": [
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "StorageClass"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Type'"
+ }
+ ]
+ },
+ {
+ "opname": "OpTypeFunction",
+ "class": "Type-Declaration",
+ "opcode": 33,
+ "operands": [
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Return Type'"
+ },
+ {
+ "kind": "IdRef",
+ "quantifier": "*",
+ "name": "'Parameter 0 Type', +\n'Parameter 1 Type', +\n..."
+ }
+ ]
+ },
+ {
+ "opname": "OpTypeEvent",
+ "class": "Type-Declaration",
+ "opcode": 34,
+ "operands": [
+ {
+ "kind": "IdResult"
+ }
+ ],
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "opname": "OpTypeDeviceEvent",
+ "class": "Type-Declaration",
+ "opcode": 35,
+ "operands": [
+ {
+ "kind": "IdResult"
+ }
+ ],
+ "capabilities": [
+ "DeviceEnqueue"
+ ]
+ },
+ {
+ "opname": "OpTypeReserveId",
+ "class": "Type-Declaration",
+ "opcode": 36,
+ "operands": [
+ {
+ "kind": "IdResult"
+ }
+ ],
+ "capabilities": [
+ "Pipes"
+ ]
+ },
+ {
+ "opname": "OpTypeQueue",
+ "class": "Type-Declaration",
+ "opcode": 37,
+ "operands": [
+ {
+ "kind": "IdResult"
+ }
+ ],
+ "capabilities": [
+ "DeviceEnqueue"
+ ]
+ },
+ {
+ "opname": "OpTypePipe",
+ "class": "Type-Declaration",
+ "opcode": 38,
+ "operands": [
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "AccessQualifier",
+ "name": "'Qualifier'"
+ }
+ ],
+ "capabilities": [
+ "Pipes"
+ ]
+ },
+ {
+ "opname": "OpTypeForwardPointer",
+ "class": "Type-Declaration",
+ "opcode": 39,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Pointer Type'"
+ },
+ {
+ "kind": "StorageClass"
+ }
+ ],
+ "capabilities": [
+ "Addresses",
+ "PhysicalStorageBufferAddresses"
+ ]
+ },
+ {
+ "opname": "OpConstantTrue",
+ "class": "Constant-Creation",
+ "opcode": 41,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ }
+ ]
+ },
+ {
+ "opname": "OpConstantFalse",
+ "class": "Constant-Creation",
+ "opcode": 42,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ }
+ ]
+ },
+ {
+ "opname": "OpConstant",
+ "class": "Constant-Creation",
+ "opcode": 43,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "LiteralContextDependentNumber",
+ "name": "'Value'"
+ }
+ ]
+ },
+ {
+ "opname": "OpConstantComposite",
+ "class": "Constant-Creation",
+ "opcode": 44,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "quantifier": "*",
+ "name": "'Constituents'"
+ }
+ ]
+ },
+ {
+ "opname": "OpConstantSampler",
+ "class": "Constant-Creation",
+ "opcode": 45,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "SamplerAddressingMode"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Param'"
+ },
+ {
+ "kind": "SamplerFilterMode"
+ }
+ ],
+ "capabilities": [
+ "LiteralSampler"
+ ]
+ },
+ {
+ "opname": "OpConstantNull",
+ "class": "Constant-Creation",
+ "opcode": 46,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ }
+ ]
+ },
+ {
+ "opname": "OpSpecConstantTrue",
+ "class": "Constant-Creation",
+ "opcode": 48,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ }
+ ]
+ },
+ {
+ "opname": "OpSpecConstantFalse",
+ "class": "Constant-Creation",
+ "opcode": 49,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ }
+ ]
+ },
+ {
+ "opname": "OpSpecConstant",
+ "class": "Constant-Creation",
+ "opcode": 50,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "LiteralContextDependentNumber",
+ "name": "'Value'"
+ }
+ ]
+ },
+ {
+ "opname": "OpSpecConstantComposite",
+ "class": "Constant-Creation",
+ "opcode": 51,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "quantifier": "*",
+ "name": "'Constituents'"
+ }
+ ]
+ },
+ {
+ "opname": "OpSpecConstantOp",
+ "class": "Constant-Creation",
+ "opcode": 52,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "LiteralSpecConstantOpInteger",
+ "name": "'Opcode'"
+ }
+ ]
+ },
+ {
+ "opname": "OpFunction",
+ "class": "Function",
+ "opcode": 54,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "FunctionControl"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Function Type'"
+ }
+ ]
+ },
+ {
+ "opname": "OpFunctionParameter",
+ "class": "Function",
+ "opcode": 55,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ }
+ ]
+ },
+ {
+ "opname": "OpFunctionEnd",
+ "class": "Function",
+ "opcode": 56
+ },
+ {
+ "opname": "OpFunctionCall",
+ "class": "Function",
+ "opcode": 57,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Function'"
+ },
+ {
+ "kind": "IdRef",
+ "quantifier": "*",
+ "name": "'Argument 0', +\n'Argument 1', +\n..."
+ }
+ ]
+ },
+ {
+ "opname": "OpVariable",
+ "class": "Memory",
+ "opcode": 59,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "StorageClass"
+ },
+ {
+ "kind": "IdRef",
+ "quantifier": "?",
+ "name": "'Initializer'"
+ }
+ ]
+ },
+ {
+ "opname": "OpImageTexelPointer",
+ "class": "Memory",
+ "opcode": 60,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sample'"
+ }
+ ]
+ },
+ {
+ "opname": "OpLoad",
+ "class": "Memory",
+ "opcode": 61,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "MemoryAccess",
+ "quantifier": "?"
+ }
+ ]
+ },
+ {
+ "opname": "OpStore",
+ "class": "Memory",
+ "opcode": 62,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Object'"
+ },
+ {
+ "kind": "MemoryAccess",
+ "quantifier": "?"
+ }
+ ]
+ },
+ {
+ "opname": "OpCopyMemory",
+ "class": "Memory",
+ "opcode": 63,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Target'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Source'"
+ },
+ {
+ "kind": "MemoryAccess",
+ "quantifier": "?"
+ },
+ {
+ "kind": "MemoryAccess",
+ "quantifier": "?"
+ }
+ ]
+ },
+ {
+ "opname": "OpCopyMemorySized",
+ "class": "Memory",
+ "opcode": 64,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Target'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Source'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Size'"
+ },
+ {
+ "kind": "MemoryAccess",
+ "quantifier": "?"
+ },
+ {
+ "kind": "MemoryAccess",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "Addresses"
+ ]
+ },
+ {
+ "opname": "OpAccessChain",
+ "class": "Memory",
+ "opcode": 65,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Base'"
+ },
+ {
+ "kind": "IdRef",
+ "quantifier": "*",
+ "name": "'Indexes'"
+ }
+ ]
+ },
+ {
+ "opname": "OpInBoundsAccessChain",
+ "class": "Memory",
+ "opcode": 66,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Base'"
+ },
+ {
+ "kind": "IdRef",
+ "quantifier": "*",
+ "name": "'Indexes'"
+ }
+ ]
+ },
+ {
+ "opname": "OpPtrAccessChain",
+ "class": "Memory",
+ "opcode": 67,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Base'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Element'"
+ },
+ {
+ "kind": "IdRef",
+ "quantifier": "*",
+ "name": "'Indexes'"
+ }
+ ],
+ "capabilities": [
+ "Addresses",
+ "VariablePointers",
+ "VariablePointersStorageBuffer",
+ "PhysicalStorageBufferAddresses"
+ ]
+ },
+ {
+ "opname": "OpArrayLength",
+ "class": "Memory",
+ "opcode": 68,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Structure'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Array member'"
+ }
+ ],
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "opname": "OpGenericPtrMemSemantics",
+ "class": "Memory",
+ "opcode": 69,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ }
+ ],
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "opname": "OpInBoundsPtrAccessChain",
+ "class": "Memory",
+ "opcode": 70,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Base'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Element'"
+ },
+ {
+ "kind": "IdRef",
+ "quantifier": "*",
+ "name": "'Indexes'"
+ }
+ ],
+ "capabilities": [
+ "Addresses"
+ ]
+ },
+ {
+ "opname": "OpDecorate",
+ "class": "Annotation",
+ "opcode": 71,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Target'"
+ },
+ {
+ "kind": "Decoration"
+ }
+ ]
+ },
+ {
+ "opname": "OpMemberDecorate",
+ "class": "Annotation",
+ "opcode": 72,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Structure Type'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Member'"
+ },
+ {
+ "kind": "Decoration"
+ }
+ ]
+ },
+ {
+ "opname": "OpDecorationGroup",
+ "class": "Annotation",
+ "opcode": 73,
+ "operands": [
+ {
+ "kind": "IdResult"
+ }
+ ]
+ },
+ {
+ "opname": "OpGroupDecorate",
+ "class": "Annotation",
+ "opcode": 74,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Decoration Group'"
+ },
+ {
+ "kind": "IdRef",
+ "quantifier": "*",
+ "name": "'Targets'"
+ }
+ ]
+ },
+ {
+ "opname": "OpGroupMemberDecorate",
+ "class": "Annotation",
+ "opcode": 75,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Decoration Group'"
+ },
+ {
+ "kind": "PairIdRefLiteralInteger",
+ "quantifier": "*",
+ "name": "'Targets'"
+ }
+ ]
+ },
+ {
+ "opname": "OpVectorExtractDynamic",
+ "class": "Composite",
+ "opcode": 77,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Index'"
+ }
+ ]
+ },
+ {
+ "opname": "OpVectorInsertDynamic",
+ "class": "Composite",
+ "opcode": 78,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Component'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Index'"
+ }
+ ]
+ },
+ {
+ "opname": "OpVectorShuffle",
+ "class": "Composite",
+ "opcode": 79,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector 2'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "quantifier": "*",
+ "name": "'Components'"
+ }
+ ]
+ },
+ {
+ "opname": "OpCompositeConstruct",
+ "class": "Composite",
+ "opcode": 80,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "quantifier": "*",
+ "name": "'Constituents'"
+ }
+ ]
+ },
+ {
+ "opname": "OpCompositeExtract",
+ "class": "Composite",
+ "opcode": 81,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Composite'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "quantifier": "*",
+ "name": "'Indexes'"
+ }
+ ]
+ },
+ {
+ "opname": "OpCompositeInsert",
+ "class": "Composite",
+ "opcode": 82,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Object'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Composite'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "quantifier": "*",
+ "name": "'Indexes'"
+ }
+ ]
+ },
+ {
+ "opname": "OpCopyObject",
+ "class": "Composite",
+ "opcode": 83,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand'"
+ }
+ ]
+ },
+ {
+ "opname": "OpTranspose",
+ "class": "Composite",
+ "opcode": 84,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Matrix'"
+ }
+ ],
+ "capabilities": [
+ "Matrix"
+ ]
+ },
+ {
+ "opname": "OpSampledImage",
+ "class": "Image",
+ "opcode": 86,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sampler'"
+ }
+ ]
+ },
+ {
+ "opname": "OpImageSampleImplicitLod",
+ "class": "Image",
+ "opcode": 87,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sampled Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ },
+ {
+ "kind": "ImageOperands",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "opname": "OpImageSampleExplicitLod",
+ "class": "Image",
+ "opcode": 88,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sampled Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ },
+ {
+ "kind": "ImageOperands"
+ }
+ ]
+ },
+ {
+ "opname": "OpImageSampleDrefImplicitLod",
+ "class": "Image",
+ "opcode": 89,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sampled Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'D~ref~'"
+ },
+ {
+ "kind": "ImageOperands",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "opname": "OpImageSampleDrefExplicitLod",
+ "class": "Image",
+ "opcode": 90,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sampled Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'D~ref~'"
+ },
+ {
+ "kind": "ImageOperands"
+ }
+ ],
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "opname": "OpImageSampleProjImplicitLod",
+ "class": "Image",
+ "opcode": 91,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sampled Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ },
+ {
+ "kind": "ImageOperands",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "opname": "OpImageSampleProjExplicitLod",
+ "class": "Image",
+ "opcode": 92,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sampled Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ },
+ {
+ "kind": "ImageOperands"
+ }
+ ],
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "opname": "OpImageSampleProjDrefImplicitLod",
+ "class": "Image",
+ "opcode": 93,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sampled Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'D~ref~'"
+ },
+ {
+ "kind": "ImageOperands",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "opname": "OpImageSampleProjDrefExplicitLod",
+ "class": "Image",
+ "opcode": 94,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sampled Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'D~ref~'"
+ },
+ {
+ "kind": "ImageOperands"
+ }
+ ],
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "opname": "OpImageFetch",
+ "class": "Image",
+ "opcode": 95,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ },
+ {
+ "kind": "ImageOperands",
+ "quantifier": "?"
+ }
+ ]
+ },
+ {
+ "opname": "OpImageGather",
+ "class": "Image",
+ "opcode": 96,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sampled Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Component'"
+ },
+ {
+ "kind": "ImageOperands",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "opname": "OpImageDrefGather",
+ "class": "Image",
+ "opcode": 97,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sampled Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'D~ref~'"
+ },
+ {
+ "kind": "ImageOperands",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "opname": "OpImageRead",
+ "class": "Image",
+ "opcode": 98,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ },
+ {
+ "kind": "ImageOperands",
+ "quantifier": "?"
+ }
+ ]
+ },
+ {
+ "opname": "OpImageWrite",
+ "class": "Image",
+ "opcode": 99,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Texel'"
+ },
+ {
+ "kind": "ImageOperands",
+ "quantifier": "?"
+ }
+ ]
+ },
+ {
+ "opname": "OpImage",
+ "class": "Image",
+ "opcode": 100,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sampled Image'"
+ }
+ ]
+ },
+ {
+ "opname": "OpImageQueryFormat",
+ "class": "Image",
+ "opcode": 101,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Image'"
+ }
+ ],
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "opname": "OpImageQueryOrder",
+ "class": "Image",
+ "opcode": 102,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Image'"
+ }
+ ],
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "opname": "OpImageQuerySizeLod",
+ "class": "Image",
+ "opcode": 103,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Level of Detail'"
+ }
+ ],
+ "capabilities": [
+ "Kernel",
+ "ImageQuery"
+ ]
+ },
+ {
+ "opname": "OpImageQuerySize",
+ "class": "Image",
+ "opcode": 104,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Image'"
+ }
+ ],
+ "capabilities": [
+ "Kernel",
+ "ImageQuery"
+ ]
+ },
+ {
+ "opname": "OpImageQueryLod",
+ "class": "Image",
+ "opcode": 105,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sampled Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ }
+ ],
+ "capabilities": [
+ "ImageQuery"
+ ]
+ },
+ {
+ "opname": "OpImageQueryLevels",
+ "class": "Image",
+ "opcode": 106,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Image'"
+ }
+ ],
+ "capabilities": [
+ "Kernel",
+ "ImageQuery"
+ ]
+ },
+ {
+ "opname": "OpImageQuerySamples",
+ "class": "Image",
+ "opcode": 107,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Image'"
+ }
+ ],
+ "capabilities": [
+ "Kernel",
+ "ImageQuery"
+ ]
+ },
+ {
+ "opname": "OpConvertFToU",
+ "class": "Conversion",
+ "opcode": 109,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Float Value'"
+ }
+ ]
+ },
+ {
+ "opname": "OpConvertFToS",
+ "class": "Conversion",
+ "opcode": 110,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Float Value'"
+ }
+ ]
+ },
+ {
+ "opname": "OpConvertSToF",
+ "class": "Conversion",
+ "opcode": 111,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Signed Value'"
+ }
+ ]
+ },
+ {
+ "opname": "OpConvertUToF",
+ "class": "Conversion",
+ "opcode": 112,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Unsigned Value'"
+ }
+ ]
+ },
+ {
+ "opname": "OpUConvert",
+ "class": "Conversion",
+ "opcode": 113,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Unsigned Value'"
+ }
+ ]
+ },
+ {
+ "opname": "OpSConvert",
+ "class": "Conversion",
+ "opcode": 114,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Signed Value'"
+ }
+ ]
+ },
+ {
+ "opname": "OpFConvert",
+ "class": "Conversion",
+ "opcode": 115,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Float Value'"
+ }
+ ]
+ },
+ {
+ "opname": "OpQuantizeToF16",
+ "class": "Conversion",
+ "opcode": 116,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ }
+ ]
+ },
+ {
+ "opname": "OpConvertPtrToU",
+ "class": "Conversion",
+ "opcode": 117,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ }
+ ],
+ "capabilities": [
+ "Addresses",
+ "PhysicalStorageBufferAddresses"
+ ]
+ },
+ {
+ "opname": "OpSatConvertSToU",
+ "class": "Conversion",
+ "opcode": 118,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Signed Value'"
+ }
+ ],
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "opname": "OpSatConvertUToS",
+ "class": "Conversion",
+ "opcode": 119,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Unsigned Value'"
+ }
+ ],
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "opname": "OpConvertUToPtr",
+ "class": "Conversion",
+ "opcode": 120,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Integer Value'"
+ }
+ ],
+ "capabilities": [
+ "Addresses",
+ "PhysicalStorageBufferAddresses"
+ ]
+ },
+ {
+ "opname": "OpPtrCastToGeneric",
+ "class": "Conversion",
+ "opcode": 121,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ }
+ ],
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "opname": "OpGenericCastToPtr",
+ "class": "Conversion",
+ "opcode": 122,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ }
+ ],
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "opname": "OpGenericCastToPtrExplicit",
+ "class": "Conversion",
+ "opcode": 123,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "StorageClass",
+ "name": "'Storage'"
+ }
+ ],
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "opname": "OpBitcast",
+ "class": "Conversion",
+ "opcode": 124,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand'"
+ }
+ ]
+ },
+ {
+ "opname": "OpSNegate",
+ "class": "Arithmetic",
+ "opcode": 126,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand'"
+ }
+ ]
+ },
+ {
+ "opname": "OpFNegate",
+ "class": "Arithmetic",
+ "opcode": 127,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand'"
+ }
+ ]
+ },
+ {
+ "opname": "OpIAdd",
+ "class": "Arithmetic",
+ "opcode": 128,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpFAdd",
+ "class": "Arithmetic",
+ "opcode": 129,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpISub",
+ "class": "Arithmetic",
+ "opcode": 130,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpFSub",
+ "class": "Arithmetic",
+ "opcode": 131,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpIMul",
+ "class": "Arithmetic",
+ "opcode": 132,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpFMul",
+ "class": "Arithmetic",
+ "opcode": 133,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpUDiv",
+ "class": "Arithmetic",
+ "opcode": 134,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpSDiv",
+ "class": "Arithmetic",
+ "opcode": 135,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpFDiv",
+ "class": "Arithmetic",
+ "opcode": 136,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpUMod",
+ "class": "Arithmetic",
+ "opcode": 137,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpSRem",
+ "class": "Arithmetic",
+ "opcode": 138,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpSMod",
+ "class": "Arithmetic",
+ "opcode": 139,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpFRem",
+ "class": "Arithmetic",
+ "opcode": 140,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpFMod",
+ "class": "Arithmetic",
+ "opcode": 141,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpVectorTimesScalar",
+ "class": "Arithmetic",
+ "opcode": 142,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Scalar'"
+ }
+ ]
+ },
+ {
+ "opname": "OpMatrixTimesScalar",
+ "class": "Arithmetic",
+ "opcode": 143,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Matrix'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Scalar'"
+ }
+ ],
+ "capabilities": [
+ "Matrix"
+ ]
+ },
+ {
+ "opname": "OpVectorTimesMatrix",
+ "class": "Arithmetic",
+ "opcode": 144,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Matrix'"
+ }
+ ],
+ "capabilities": [
+ "Matrix"
+ ]
+ },
+ {
+ "opname": "OpMatrixTimesVector",
+ "class": "Arithmetic",
+ "opcode": 145,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Matrix'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector'"
+ }
+ ],
+ "capabilities": [
+ "Matrix"
+ ]
+ },
+ {
+ "opname": "OpMatrixTimesMatrix",
+ "class": "Arithmetic",
+ "opcode": 146,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'LeftMatrix'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'RightMatrix'"
+ }
+ ],
+ "capabilities": [
+ "Matrix"
+ ]
+ },
+ {
+ "opname": "OpOuterProduct",
+ "class": "Arithmetic",
+ "opcode": 147,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector 2'"
+ }
+ ],
+ "capabilities": [
+ "Matrix"
+ ]
+ },
+ {
+ "opname": "OpDot",
+ "class": "Arithmetic",
+ "opcode": 148,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpIAddCarry",
+ "class": "Arithmetic",
+ "opcode": 149,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpISubBorrow",
+ "class": "Arithmetic",
+ "opcode": 150,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpUMulExtended",
+ "class": "Arithmetic",
+ "opcode": 151,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpSMulExtended",
+ "class": "Arithmetic",
+ "opcode": 152,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpAny",
+ "class": "Relational_and_Logical",
+ "opcode": 154,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector'"
+ }
+ ]
+ },
+ {
+ "opname": "OpAll",
+ "class": "Relational_and_Logical",
+ "opcode": 155,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector'"
+ }
+ ]
+ },
+ {
+ "opname": "OpIsNan",
+ "class": "Relational_and_Logical",
+ "opcode": 156,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'x'"
+ }
+ ]
+ },
+ {
+ "opname": "OpIsInf",
+ "class": "Relational_and_Logical",
+ "opcode": 157,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'x'"
+ }
+ ]
+ },
+ {
+ "opname": "OpIsFinite",
+ "class": "Relational_and_Logical",
+ "opcode": 158,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'x'"
+ }
+ ],
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "opname": "OpIsNormal",
+ "class": "Relational_and_Logical",
+ "opcode": 159,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'x'"
+ }
+ ],
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "opname": "OpSignBitSet",
+ "class": "Relational_and_Logical",
+ "opcode": 160,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'x'"
+ }
+ ],
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "opname": "OpLessOrGreater",
+ "class": "Relational_and_Logical",
+ "opcode": 161,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'x'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'y'"
+ }
+ ],
+ "capabilities": [
+ "Kernel"
+ ],
+ "lastVersion": "1.5"
+ },
+ {
+ "opname": "OpOrdered",
+ "class": "Relational_and_Logical",
+ "opcode": 162,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'x'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'y'"
+ }
+ ],
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "opname": "OpUnordered",
+ "class": "Relational_and_Logical",
+ "opcode": 163,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'x'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'y'"
+ }
+ ],
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "opname": "OpLogicalEqual",
+ "class": "Relational_and_Logical",
+ "opcode": 164,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpLogicalNotEqual",
+ "class": "Relational_and_Logical",
+ "opcode": 165,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpLogicalOr",
+ "class": "Relational_and_Logical",
+ "opcode": 166,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpLogicalAnd",
+ "class": "Relational_and_Logical",
+ "opcode": 167,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpLogicalNot",
+ "class": "Relational_and_Logical",
+ "opcode": 168,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand'"
+ }
+ ]
+ },
+ {
+ "opname": "OpSelect",
+ "class": "Relational_and_Logical",
+ "opcode": 169,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Condition'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Object 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Object 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpIEqual",
+ "class": "Relational_and_Logical",
+ "opcode": 170,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpINotEqual",
+ "class": "Relational_and_Logical",
+ "opcode": 171,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpUGreaterThan",
+ "class": "Relational_and_Logical",
+ "opcode": 172,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpSGreaterThan",
+ "class": "Relational_and_Logical",
+ "opcode": 173,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpUGreaterThanEqual",
+ "class": "Relational_and_Logical",
+ "opcode": 174,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpSGreaterThanEqual",
+ "class": "Relational_and_Logical",
+ "opcode": 175,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpULessThan",
+ "class": "Relational_and_Logical",
+ "opcode": 176,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpSLessThan",
+ "class": "Relational_and_Logical",
+ "opcode": 177,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpULessThanEqual",
+ "class": "Relational_and_Logical",
+ "opcode": 178,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpSLessThanEqual",
+ "class": "Relational_and_Logical",
+ "opcode": 179,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpFOrdEqual",
+ "class": "Relational_and_Logical",
+ "opcode": 180,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpFUnordEqual",
+ "class": "Relational_and_Logical",
+ "opcode": 181,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpFOrdNotEqual",
+ "class": "Relational_and_Logical",
+ "opcode": 182,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpFUnordNotEqual",
+ "class": "Relational_and_Logical",
+ "opcode": 183,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpFOrdLessThan",
+ "class": "Relational_and_Logical",
+ "opcode": 184,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpFUnordLessThan",
+ "class": "Relational_and_Logical",
+ "opcode": 185,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpFOrdGreaterThan",
+ "class": "Relational_and_Logical",
+ "opcode": 186,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpFUnordGreaterThan",
+ "class": "Relational_and_Logical",
+ "opcode": 187,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpFOrdLessThanEqual",
+ "class": "Relational_and_Logical",
+ "opcode": 188,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpFUnordLessThanEqual",
+ "class": "Relational_and_Logical",
+ "opcode": 189,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpFOrdGreaterThanEqual",
+ "class": "Relational_and_Logical",
+ "opcode": 190,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpFUnordGreaterThanEqual",
+ "class": "Relational_and_Logical",
+ "opcode": 191,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpShiftRightLogical",
+ "class": "Bit",
+ "opcode": 194,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Base'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Shift'"
+ }
+ ]
+ },
+ {
+ "opname": "OpShiftRightArithmetic",
+ "class": "Bit",
+ "opcode": 195,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Base'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Shift'"
+ }
+ ]
+ },
+ {
+ "opname": "OpShiftLeftLogical",
+ "class": "Bit",
+ "opcode": 196,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Base'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Shift'"
+ }
+ ]
+ },
+ {
+ "opname": "OpBitwiseOr",
+ "class": "Bit",
+ "opcode": 197,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpBitwiseXor",
+ "class": "Bit",
+ "opcode": 198,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpBitwiseAnd",
+ "class": "Bit",
+ "opcode": 199,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ]
+ },
+ {
+ "opname": "OpNot",
+ "class": "Bit",
+ "opcode": 200,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand'"
+ }
+ ]
+ },
+ {
+ "opname": "OpBitFieldInsert",
+ "class": "Bit",
+ "opcode": 201,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Base'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Insert'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Offset'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Count'"
+ }
+ ],
+ "capabilities": [
+ "Shader",
+ "BitInstructions"
+ ]
+ },
+ {
+ "opname": "OpBitFieldSExtract",
+ "class": "Bit",
+ "opcode": 202,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Base'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Offset'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Count'"
+ }
+ ],
+ "capabilities": [
+ "Shader",
+ "BitInstructions"
+ ]
+ },
+ {
+ "opname": "OpBitFieldUExtract",
+ "class": "Bit",
+ "opcode": 203,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Base'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Offset'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Count'"
+ }
+ ],
+ "capabilities": [
+ "Shader",
+ "BitInstructions"
+ ]
+ },
+ {
+ "opname": "OpBitReverse",
+ "class": "Bit",
+ "opcode": 204,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Base'"
+ }
+ ],
+ "capabilities": [
+ "Shader",
+ "BitInstructions"
+ ]
+ },
+ {
+ "opname": "OpBitCount",
+ "class": "Bit",
+ "opcode": 205,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Base'"
+ }
+ ]
+ },
+ {
+ "opname": "OpDPdx",
+ "class": "Derivative",
+ "opcode": 207,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'P'"
+ }
+ ],
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "opname": "OpDPdy",
+ "class": "Derivative",
+ "opcode": 208,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'P'"
+ }
+ ],
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "opname": "OpFwidth",
+ "class": "Derivative",
+ "opcode": 209,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'P'"
+ }
+ ],
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "opname": "OpDPdxFine",
+ "class": "Derivative",
+ "opcode": 210,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'P'"
+ }
+ ],
+ "capabilities": [
+ "DerivativeControl"
+ ]
+ },
+ {
+ "opname": "OpDPdyFine",
+ "class": "Derivative",
+ "opcode": 211,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'P'"
+ }
+ ],
+ "capabilities": [
+ "DerivativeControl"
+ ]
+ },
+ {
+ "opname": "OpFwidthFine",
+ "class": "Derivative",
+ "opcode": 212,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'P'"
+ }
+ ],
+ "capabilities": [
+ "DerivativeControl"
+ ]
+ },
+ {
+ "opname": "OpDPdxCoarse",
+ "class": "Derivative",
+ "opcode": 213,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'P'"
+ }
+ ],
+ "capabilities": [
+ "DerivativeControl"
+ ]
+ },
+ {
+ "opname": "OpDPdyCoarse",
+ "class": "Derivative",
+ "opcode": 214,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'P'"
+ }
+ ],
+ "capabilities": [
+ "DerivativeControl"
+ ]
+ },
+ {
+ "opname": "OpFwidthCoarse",
+ "class": "Derivative",
+ "opcode": 215,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'P'"
+ }
+ ],
+ "capabilities": [
+ "DerivativeControl"
+ ]
+ },
+ {
+ "opname": "OpEmitVertex",
+ "class": "Primitive",
+ "opcode": 218,
+ "capabilities": [
+ "Geometry"
+ ]
+ },
+ {
+ "opname": "OpEndPrimitive",
+ "class": "Primitive",
+ "opcode": 219,
+ "capabilities": [
+ "Geometry"
+ ]
+ },
+ {
+ "opname": "OpEmitStreamVertex",
+ "class": "Primitive",
+ "opcode": 220,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Stream'"
+ }
+ ],
+ "capabilities": [
+ "GeometryStreams"
+ ]
+ },
+ {
+ "opname": "OpEndStreamPrimitive",
+ "class": "Primitive",
+ "opcode": 221,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Stream'"
+ }
+ ],
+ "capabilities": [
+ "GeometryStreams"
+ ]
+ },
+ {
+ "opname": "OpControlBarrier",
+ "class": "Barrier",
+ "opcode": 224,
+ "operands": [
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Memory'"
+ },
+ {
+ "kind": "IdMemorySemantics",
+ "name": "'Semantics'"
+ }
+ ]
+ },
+ {
+ "opname": "OpMemoryBarrier",
+ "class": "Barrier",
+ "opcode": 225,
+ "operands": [
+ {
+ "kind": "IdScope",
+ "name": "'Memory'"
+ },
+ {
+ "kind": "IdMemorySemantics",
+ "name": "'Semantics'"
+ }
+ ]
+ },
+ {
+ "opname": "OpAtomicLoad",
+ "class": "Atomic",
+ "opcode": 227,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Memory'"
+ },
+ {
+ "kind": "IdMemorySemantics",
+ "name": "'Semantics'"
+ }
+ ]
+ },
+ {
+ "opname": "OpAtomicStore",
+ "class": "Atomic",
+ "opcode": 228,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Memory'"
+ },
+ {
+ "kind": "IdMemorySemantics",
+ "name": "'Semantics'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ }
+ ]
+ },
+ {
+ "opname": "OpAtomicExchange",
+ "class": "Atomic",
+ "opcode": 229,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Memory'"
+ },
+ {
+ "kind": "IdMemorySemantics",
+ "name": "'Semantics'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ }
+ ]
+ },
+ {
+ "opname": "OpAtomicCompareExchange",
+ "class": "Atomic",
+ "opcode": 230,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Memory'"
+ },
+ {
+ "kind": "IdMemorySemantics",
+ "name": "'Equal'"
+ },
+ {
+ "kind": "IdMemorySemantics",
+ "name": "'Unequal'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Comparator'"
+ }
+ ]
+ },
+ {
+ "opname": "OpAtomicCompareExchangeWeak",
+ "class": "Atomic",
+ "opcode": 231,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Memory'"
+ },
+ {
+ "kind": "IdMemorySemantics",
+ "name": "'Equal'"
+ },
+ {
+ "kind": "IdMemorySemantics",
+ "name": "'Unequal'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Comparator'"
+ }
+ ],
+ "capabilities": [
+ "Kernel"
+ ],
+ "lastVersion": "1.3"
+ },
+ {
+ "opname": "OpAtomicIIncrement",
+ "class": "Atomic",
+ "opcode": 232,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Memory'"
+ },
+ {
+ "kind": "IdMemorySemantics",
+ "name": "'Semantics'"
+ }
+ ]
+ },
+ {
+ "opname": "OpAtomicIDecrement",
+ "class": "Atomic",
+ "opcode": 233,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Memory'"
+ },
+ {
+ "kind": "IdMemorySemantics",
+ "name": "'Semantics'"
+ }
+ ]
+ },
+ {
+ "opname": "OpAtomicIAdd",
+ "class": "Atomic",
+ "opcode": 234,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Memory'"
+ },
+ {
+ "kind": "IdMemorySemantics",
+ "name": "'Semantics'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ }
+ ]
+ },
+ {
+ "opname": "OpAtomicISub",
+ "class": "Atomic",
+ "opcode": 235,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Memory'"
+ },
+ {
+ "kind": "IdMemorySemantics",
+ "name": "'Semantics'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ }
+ ]
+ },
+ {
+ "opname": "OpAtomicSMin",
+ "class": "Atomic",
+ "opcode": 236,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Memory'"
+ },
+ {
+ "kind": "IdMemorySemantics",
+ "name": "'Semantics'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ }
+ ]
+ },
+ {
+ "opname": "OpAtomicUMin",
+ "class": "Atomic",
+ "opcode": 237,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Memory'"
+ },
+ {
+ "kind": "IdMemorySemantics",
+ "name": "'Semantics'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ }
+ ]
+ },
+ {
+ "opname": "OpAtomicSMax",
+ "class": "Atomic",
+ "opcode": 238,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Memory'"
+ },
+ {
+ "kind": "IdMemorySemantics",
+ "name": "'Semantics'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ }
+ ]
+ },
+ {
+ "opname": "OpAtomicUMax",
+ "class": "Atomic",
+ "opcode": 239,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Memory'"
+ },
+ {
+ "kind": "IdMemorySemantics",
+ "name": "'Semantics'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ }
+ ]
+ },
+ {
+ "opname": "OpAtomicAnd",
+ "class": "Atomic",
+ "opcode": 240,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Memory'"
+ },
+ {
+ "kind": "IdMemorySemantics",
+ "name": "'Semantics'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ }
+ ]
+ },
+ {
+ "opname": "OpAtomicOr",
+ "class": "Atomic",
+ "opcode": 241,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Memory'"
+ },
+ {
+ "kind": "IdMemorySemantics",
+ "name": "'Semantics'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ }
+ ]
+ },
+ {
+ "opname": "OpAtomicXor",
+ "class": "Atomic",
+ "opcode": 242,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Memory'"
+ },
+ {
+ "kind": "IdMemorySemantics",
+ "name": "'Semantics'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ }
+ ]
+ },
+ {
+ "opname": "OpPhi",
+ "class": "Control-Flow",
+ "opcode": 245,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "PairIdRefIdRef",
+ "quantifier": "*",
+ "name": "'Variable, Parent, ...'"
+ }
+ ]
+ },
+ {
+ "opname": "OpLoopMerge",
+ "class": "Control-Flow",
+ "opcode": 246,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Merge Block'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Continue Target'"
+ },
+ {
+ "kind": "LoopControl"
+ }
+ ]
+ },
+ {
+ "opname": "OpSelectionMerge",
+ "class": "Control-Flow",
+ "opcode": 247,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Merge Block'"
+ },
+ {
+ "kind": "SelectionControl"
+ }
+ ]
+ },
+ {
+ "opname": "OpLabel",
+ "class": "Control-Flow",
+ "opcode": 248,
+ "operands": [
+ {
+ "kind": "IdResult"
+ }
+ ]
+ },
+ {
+ "opname": "OpBranch",
+ "class": "Control-Flow",
+ "opcode": 249,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Target Label'"
+ }
+ ]
+ },
+ {
+ "opname": "OpBranchConditional",
+ "class": "Control-Flow",
+ "opcode": 250,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Condition'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'True Label'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'False Label'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "quantifier": "*",
+ "name": "'Branch weights'"
+ }
+ ]
+ },
+ {
+ "opname": "OpSwitch",
+ "class": "Control-Flow",
+ "opcode": 251,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Selector'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Default'"
+ },
+ {
+ "kind": "PairLiteralIntegerIdRef",
+ "quantifier": "*",
+ "name": "'Target'"
+ }
+ ]
+ },
+ {
+ "opname": "OpKill",
+ "class": "Control-Flow",
+ "opcode": 252,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "opname": "OpReturn",
+ "class": "Control-Flow",
+ "opcode": 253
+ },
+ {
+ "opname": "OpReturnValue",
+ "class": "Control-Flow",
+ "opcode": 254,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ }
+ ]
+ },
+ {
+ "opname": "OpUnreachable",
+ "class": "Control-Flow",
+ "opcode": 255
+ },
+ {
+ "opname": "OpLifetimeStart",
+ "class": "Control-Flow",
+ "opcode": 256,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Size'"
+ }
+ ],
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "opname": "OpLifetimeStop",
+ "class": "Control-Flow",
+ "opcode": 257,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Size'"
+ }
+ ],
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "opname": "OpGroupAsyncCopy",
+ "class": "Group",
+ "opcode": 259,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Destination'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Source'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Num Elements'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Stride'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Event'"
+ }
+ ],
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "opname": "OpGroupWaitEvents",
+ "class": "Group",
+ "opcode": 260,
+ "operands": [
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Num Events'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Events List'"
+ }
+ ],
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "opname": "OpGroupAll",
+ "class": "Group",
+ "opcode": 261,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Predicate'"
+ }
+ ],
+ "capabilities": [
+ "Groups"
+ ]
+ },
+ {
+ "opname": "OpGroupAny",
+ "class": "Group",
+ "opcode": 262,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Predicate'"
+ }
+ ],
+ "capabilities": [
+ "Groups"
+ ]
+ },
+ {
+ "opname": "OpGroupBroadcast",
+ "class": "Group",
+ "opcode": 263,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'LocalId'"
+ }
+ ],
+ "capabilities": [
+ "Groups"
+ ]
+ },
+ {
+ "opname": "OpGroupIAdd",
+ "class": "Group",
+ "opcode": 264,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'X'"
+ }
+ ],
+ "capabilities": [
+ "Groups"
+ ]
+ },
+ {
+ "opname": "OpGroupFAdd",
+ "class": "Group",
+ "opcode": 265,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'X'"
+ }
+ ],
+ "capabilities": [
+ "Groups"
+ ]
+ },
+ {
+ "opname": "OpGroupFMin",
+ "class": "Group",
+ "opcode": 266,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'X'"
+ }
+ ],
+ "capabilities": [
+ "Groups"
+ ]
+ },
+ {
+ "opname": "OpGroupUMin",
+ "class": "Group",
+ "opcode": 267,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'X'"
+ }
+ ],
+ "capabilities": [
+ "Groups"
+ ]
+ },
+ {
+ "opname": "OpGroupSMin",
+ "class": "Group",
+ "opcode": 268,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'X'"
+ }
+ ],
+ "capabilities": [
+ "Groups"
+ ]
+ },
+ {
+ "opname": "OpGroupFMax",
+ "class": "Group",
+ "opcode": 269,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'X'"
+ }
+ ],
+ "capabilities": [
+ "Groups"
+ ]
+ },
+ {
+ "opname": "OpGroupUMax",
+ "class": "Group",
+ "opcode": 270,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'X'"
+ }
+ ],
+ "capabilities": [
+ "Groups"
+ ]
+ },
+ {
+ "opname": "OpGroupSMax",
+ "class": "Group",
+ "opcode": 271,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'X'"
+ }
+ ],
+ "capabilities": [
+ "Groups"
+ ]
+ },
+ {
+ "opname": "OpReadPipe",
+ "class": "Pipe",
+ "opcode": 274,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pipe'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Size'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Alignment'"
+ }
+ ],
+ "capabilities": [
+ "Pipes"
+ ]
+ },
+ {
+ "opname": "OpWritePipe",
+ "class": "Pipe",
+ "opcode": 275,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pipe'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Size'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Alignment'"
+ }
+ ],
+ "capabilities": [
+ "Pipes"
+ ]
+ },
+ {
+ "opname": "OpReservedReadPipe",
+ "class": "Pipe",
+ "opcode": 276,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pipe'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Reserve Id'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Index'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Size'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Alignment'"
+ }
+ ],
+ "capabilities": [
+ "Pipes"
+ ]
+ },
+ {
+ "opname": "OpReservedWritePipe",
+ "class": "Pipe",
+ "opcode": 277,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pipe'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Reserve Id'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Index'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Size'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Alignment'"
+ }
+ ],
+ "capabilities": [
+ "Pipes"
+ ]
+ },
+ {
+ "opname": "OpReserveReadPipePackets",
+ "class": "Pipe",
+ "opcode": 278,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pipe'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Num Packets'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Size'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Alignment'"
+ }
+ ],
+ "capabilities": [
+ "Pipes"
+ ]
+ },
+ {
+ "opname": "OpReserveWritePipePackets",
+ "class": "Pipe",
+ "opcode": 279,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pipe'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Num Packets'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Size'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Alignment'"
+ }
+ ],
+ "capabilities": [
+ "Pipes"
+ ]
+ },
+ {
+ "opname": "OpCommitReadPipe",
+ "class": "Pipe",
+ "opcode": 280,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Pipe'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Reserve Id'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Size'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Alignment'"
+ }
+ ],
+ "capabilities": [
+ "Pipes"
+ ]
+ },
+ {
+ "opname": "OpCommitWritePipe",
+ "class": "Pipe",
+ "opcode": 281,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Pipe'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Reserve Id'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Size'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Alignment'"
+ }
+ ],
+ "capabilities": [
+ "Pipes"
+ ]
+ },
+ {
+ "opname": "OpIsValidReserveId",
+ "class": "Pipe",
+ "opcode": 282,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Reserve Id'"
+ }
+ ],
+ "capabilities": [
+ "Pipes"
+ ]
+ },
+ {
+ "opname": "OpGetNumPipePackets",
+ "class": "Pipe",
+ "opcode": 283,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pipe'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Size'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Alignment'"
+ }
+ ],
+ "capabilities": [
+ "Pipes"
+ ]
+ },
+ {
+ "opname": "OpGetMaxPipePackets",
+ "class": "Pipe",
+ "opcode": 284,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pipe'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Size'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Alignment'"
+ }
+ ],
+ "capabilities": [
+ "Pipes"
+ ]
+ },
+ {
+ "opname": "OpGroupReserveReadPipePackets",
+ "class": "Pipe",
+ "opcode": 285,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pipe'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Num Packets'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Size'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Alignment'"
+ }
+ ],
+ "capabilities": [
+ "Pipes"
+ ]
+ },
+ {
+ "opname": "OpGroupReserveWritePipePackets",
+ "class": "Pipe",
+ "opcode": 286,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pipe'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Num Packets'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Size'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Alignment'"
+ }
+ ],
+ "capabilities": [
+ "Pipes"
+ ]
+ },
+ {
+ "opname": "OpGroupCommitReadPipe",
+ "class": "Pipe",
+ "opcode": 287,
+ "operands": [
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pipe'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Reserve Id'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Size'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Alignment'"
+ }
+ ],
+ "capabilities": [
+ "Pipes"
+ ]
+ },
+ {
+ "opname": "OpGroupCommitWritePipe",
+ "class": "Pipe",
+ "opcode": 288,
+ "operands": [
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pipe'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Reserve Id'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Size'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Alignment'"
+ }
+ ],
+ "capabilities": [
+ "Pipes"
+ ]
+ },
+ {
+ "opname": "OpEnqueueMarker",
+ "class": "Device-Side_Enqueue",
+ "opcode": 291,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Queue'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Num Events'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Wait Events'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ret Event'"
+ }
+ ],
+ "capabilities": [
+ "DeviceEnqueue"
+ ]
+ },
+ {
+ "opname": "OpEnqueueKernel",
+ "class": "Device-Side_Enqueue",
+ "opcode": 292,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Queue'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Flags'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'ND Range'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Num Events'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Wait Events'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ret Event'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Invoke'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Param'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Param Size'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Param Align'"
+ },
+ {
+ "kind": "IdRef",
+ "quantifier": "*",
+ "name": "'Local Size'"
+ }
+ ],
+ "capabilities": [
+ "DeviceEnqueue"
+ ]
+ },
+ {
+ "opname": "OpGetKernelNDrangeSubGroupCount",
+ "class": "Device-Side_Enqueue",
+ "opcode": 293,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'ND Range'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Invoke'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Param'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Param Size'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Param Align'"
+ }
+ ],
+ "capabilities": [
+ "DeviceEnqueue"
+ ]
+ },
+ {
+ "opname": "OpGetKernelNDrangeMaxSubGroupSize",
+ "class": "Device-Side_Enqueue",
+ "opcode": 294,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'ND Range'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Invoke'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Param'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Param Size'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Param Align'"
+ }
+ ],
+ "capabilities": [
+ "DeviceEnqueue"
+ ]
+ },
+ {
+ "opname": "OpGetKernelWorkGroupSize",
+ "class": "Device-Side_Enqueue",
+ "opcode": 295,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Invoke'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Param'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Param Size'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Param Align'"
+ }
+ ],
+ "capabilities": [
+ "DeviceEnqueue"
+ ]
+ },
+ {
+ "opname": "OpGetKernelPreferredWorkGroupSizeMultiple",
+ "class": "Device-Side_Enqueue",
+ "opcode": 296,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Invoke'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Param'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Param Size'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Param Align'"
+ }
+ ],
+ "capabilities": [
+ "DeviceEnqueue"
+ ]
+ },
+ {
+ "opname": "OpRetainEvent",
+ "class": "Device-Side_Enqueue",
+ "opcode": 297,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Event'"
+ }
+ ],
+ "capabilities": [
+ "DeviceEnqueue"
+ ]
+ },
+ {
+ "opname": "OpReleaseEvent",
+ "class": "Device-Side_Enqueue",
+ "opcode": 298,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Event'"
+ }
+ ],
+ "capabilities": [
+ "DeviceEnqueue"
+ ]
+ },
+ {
+ "opname": "OpCreateUserEvent",
+ "class": "Device-Side_Enqueue",
+ "opcode": 299,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ }
+ ],
+ "capabilities": [
+ "DeviceEnqueue"
+ ]
+ },
+ {
+ "opname": "OpIsValidEvent",
+ "class": "Device-Side_Enqueue",
+ "opcode": 300,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Event'"
+ }
+ ],
+ "capabilities": [
+ "DeviceEnqueue"
+ ]
+ },
+ {
+ "opname": "OpSetUserEventStatus",
+ "class": "Device-Side_Enqueue",
+ "opcode": 301,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Event'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Status'"
+ }
+ ],
+ "capabilities": [
+ "DeviceEnqueue"
+ ]
+ },
+ {
+ "opname": "OpCaptureEventProfilingInfo",
+ "class": "Device-Side_Enqueue",
+ "opcode": 302,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Event'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Profiling Info'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ }
+ ],
+ "capabilities": [
+ "DeviceEnqueue"
+ ]
+ },
+ {
+ "opname": "OpGetDefaultQueue",
+ "class": "Device-Side_Enqueue",
+ "opcode": 303,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ }
+ ],
+ "capabilities": [
+ "DeviceEnqueue"
+ ]
+ },
+ {
+ "opname": "OpBuildNDRange",
+ "class": "Device-Side_Enqueue",
+ "opcode": 304,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'GlobalWorkSize'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'LocalWorkSize'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'GlobalWorkOffset'"
+ }
+ ],
+ "capabilities": [
+ "DeviceEnqueue"
+ ]
+ },
+ {
+ "opname": "OpImageSparseSampleImplicitLod",
+ "class": "Image",
+ "opcode": 305,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sampled Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ },
+ {
+ "kind": "ImageOperands",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "SparseResidency"
+ ]
+ },
+ {
+ "opname": "OpImageSparseSampleExplicitLod",
+ "class": "Image",
+ "opcode": 306,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sampled Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ },
+ {
+ "kind": "ImageOperands"
+ }
+ ],
+ "capabilities": [
+ "SparseResidency"
+ ]
+ },
+ {
+ "opname": "OpImageSparseSampleDrefImplicitLod",
+ "class": "Image",
+ "opcode": 307,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sampled Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'D~ref~'"
+ },
+ {
+ "kind": "ImageOperands",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "SparseResidency"
+ ]
+ },
+ {
+ "opname": "OpImageSparseSampleDrefExplicitLod",
+ "class": "Image",
+ "opcode": 308,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sampled Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'D~ref~'"
+ },
+ {
+ "kind": "ImageOperands"
+ }
+ ],
+ "capabilities": [
+ "SparseResidency"
+ ]
+ },
+ {
+ "opname": "OpImageSparseSampleProjImplicitLod",
+ "class": "Image",
+ "opcode": 309,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sampled Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ },
+ {
+ "kind": "ImageOperands",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "SparseResidency"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpImageSparseSampleProjExplicitLod",
+ "class": "Image",
+ "opcode": 310,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sampled Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ },
+ {
+ "kind": "ImageOperands"
+ }
+ ],
+ "capabilities": [
+ "SparseResidency"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpImageSparseSampleProjDrefImplicitLod",
+ "class": "Image",
+ "opcode": 311,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sampled Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'D~ref~'"
+ },
+ {
+ "kind": "ImageOperands",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "SparseResidency"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpImageSparseSampleProjDrefExplicitLod",
+ "class": "Image",
+ "opcode": 312,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sampled Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'D~ref~'"
+ },
+ {
+ "kind": "ImageOperands"
+ }
+ ],
+ "capabilities": [
+ "SparseResidency"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpImageSparseFetch",
+ "class": "Image",
+ "opcode": 313,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ },
+ {
+ "kind": "ImageOperands",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "SparseResidency"
+ ]
+ },
+ {
+ "opname": "OpImageSparseGather",
+ "class": "Image",
+ "opcode": 314,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sampled Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Component'"
+ },
+ {
+ "kind": "ImageOperands",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "SparseResidency"
+ ]
+ },
+ {
+ "opname": "OpImageSparseDrefGather",
+ "class": "Image",
+ "opcode": 315,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sampled Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'D~ref~'"
+ },
+ {
+ "kind": "ImageOperands",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "SparseResidency"
+ ]
+ },
+ {
+ "opname": "OpImageSparseTexelsResident",
+ "class": "Image",
+ "opcode": 316,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Resident Code'"
+ }
+ ],
+ "capabilities": [
+ "SparseResidency"
+ ]
+ },
+ {
+ "opname": "OpNoLine",
+ "class": "Debug",
+ "opcode": 317
+ },
+ {
+ "opname": "OpAtomicFlagTestAndSet",
+ "class": "Atomic",
+ "opcode": 318,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Memory'"
+ },
+ {
+ "kind": "IdMemorySemantics",
+ "name": "'Semantics'"
+ }
+ ],
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "opname": "OpAtomicFlagClear",
+ "class": "Atomic",
+ "opcode": 319,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Memory'"
+ },
+ {
+ "kind": "IdMemorySemantics",
+ "name": "'Semantics'"
+ }
+ ],
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "opname": "OpImageSparseRead",
+ "class": "Image",
+ "opcode": 320,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ },
+ {
+ "kind": "ImageOperands",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "SparseResidency"
+ ]
+ },
+ {
+ "opname": "OpSizeOf",
+ "class": "Miscellaneous",
+ "opcode": 321,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ }
+ ],
+ "capabilities": [
+ "Addresses"
+ ],
+ "version": "1.1"
+ },
+ {
+ "opname": "OpTypePipeStorage",
+ "class": "Type-Declaration",
+ "opcode": 322,
+ "operands": [
+ {
+ "kind": "IdResult"
+ }
+ ],
+ "capabilities": [
+ "PipeStorage"
+ ],
+ "version": "1.1"
+ },
+ {
+ "opname": "OpConstantPipeStorage",
+ "class": "Pipe",
+ "opcode": 323,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Packet Size'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Packet Alignment'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Capacity'"
+ }
+ ],
+ "capabilities": [
+ "PipeStorage"
+ ],
+ "version": "1.1"
+ },
+ {
+ "opname": "OpCreatePipeFromPipeStorage",
+ "class": "Pipe",
+ "opcode": 324,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pipe Storage'"
+ }
+ ],
+ "capabilities": [
+ "PipeStorage"
+ ],
+ "version": "1.1"
+ },
+ {
+ "opname": "OpGetKernelLocalSizeForSubgroupCount",
+ "class": "Device-Side_Enqueue",
+ "opcode": 325,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Subgroup Count'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Invoke'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Param'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Param Size'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Param Align'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupDispatch"
+ ],
+ "version": "1.1"
+ },
+ {
+ "opname": "OpGetKernelMaxNumSubgroups",
+ "class": "Device-Side_Enqueue",
+ "opcode": 326,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Invoke'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Param'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Param Size'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Param Align'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupDispatch"
+ ],
+ "version": "1.1"
+ },
+ {
+ "opname": "OpTypeNamedBarrier",
+ "class": "Type-Declaration",
+ "opcode": 327,
+ "operands": [
+ {
+ "kind": "IdResult"
+ }
+ ],
+ "capabilities": [
+ "NamedBarrier"
+ ],
+ "version": "1.1"
+ },
+ {
+ "opname": "OpNamedBarrierInitialize",
+ "class": "Barrier",
+ "opcode": 328,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Subgroup Count'"
+ }
+ ],
+ "capabilities": [
+ "NamedBarrier"
+ ],
+ "version": "1.1"
+ },
+ {
+ "opname": "OpMemoryNamedBarrier",
+ "class": "Barrier",
+ "opcode": 329,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Named Barrier'"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Memory'"
+ },
+ {
+ "kind": "IdMemorySemantics",
+ "name": "'Semantics'"
+ }
+ ],
+ "capabilities": [
+ "NamedBarrier"
+ ],
+ "version": "1.1"
+ },
+ {
+ "opname": "OpModuleProcessed",
+ "class": "Debug",
+ "opcode": 330,
+ "operands": [
+ {
+ "kind": "LiteralString",
+ "name": "'Process'"
+ }
+ ],
+ "version": "1.1"
+ },
+ {
+ "opname": "OpExecutionModeId",
+ "class": "Mode-Setting",
+ "opcode": 331,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Entry Point'"
+ },
+ {
+ "kind": "ExecutionMode",
+ "name": "'Mode'"
+ }
+ ],
+ "version": "1.2"
+ },
+ {
+ "opname": "OpDecorateId",
+ "class": "Annotation",
+ "opcode": 332,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Target'"
+ },
+ {
+ "kind": "Decoration"
+ }
+ ],
+ "extensions": [
+ "SPV_GOOGLE_hlsl_functionality1"
+ ],
+ "version": "1.2"
+ },
+ {
+ "opname": "OpGroupNonUniformElect",
+ "class": "Non-Uniform",
+ "opcode": 333,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniform"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformAll",
+ "class": "Non-Uniform",
+ "opcode": 334,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Predicate'"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformVote"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformAny",
+ "class": "Non-Uniform",
+ "opcode": 335,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Predicate'"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformVote"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformAllEqual",
+ "class": "Non-Uniform",
+ "opcode": 336,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformVote"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformBroadcast",
+ "class": "Non-Uniform",
+ "opcode": 337,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Id'"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformBallot"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformBroadcastFirst",
+ "class": "Non-Uniform",
+ "opcode": 338,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformBallot"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformBallot",
+ "class": "Non-Uniform",
+ "opcode": 339,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Predicate'"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformBallot"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformInverseBallot",
+ "class": "Non-Uniform",
+ "opcode": 340,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformBallot"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformBallotBitExtract",
+ "class": "Non-Uniform",
+ "opcode": 341,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Index'"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformBallot"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformBallotBitCount",
+ "class": "Non-Uniform",
+ "opcode": 342,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformBallot"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformBallotFindLSB",
+ "class": "Non-Uniform",
+ "opcode": 343,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformBallot"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformBallotFindMSB",
+ "class": "Non-Uniform",
+ "opcode": 344,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformBallot"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformShuffle",
+ "class": "Non-Uniform",
+ "opcode": 345,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Id'"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformShuffle"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformShuffleXor",
+ "class": "Non-Uniform",
+ "opcode": 346,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Mask'"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformShuffle"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformShuffleUp",
+ "class": "Non-Uniform",
+ "opcode": 347,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Delta'"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformShuffleRelative"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformShuffleDown",
+ "class": "Non-Uniform",
+ "opcode": 348,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Delta'"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformShuffleRelative"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformIAdd",
+ "class": "Non-Uniform",
+ "opcode": 349,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'ClusterSize'",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformArithmetic",
+ "GroupNonUniformClustered",
+ "GroupNonUniformPartitionedNV"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformFAdd",
+ "class": "Non-Uniform",
+ "opcode": 350,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'ClusterSize'",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformArithmetic",
+ "GroupNonUniformClustered",
+ "GroupNonUniformPartitionedNV"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformIMul",
+ "class": "Non-Uniform",
+ "opcode": 351,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'ClusterSize'",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformArithmetic",
+ "GroupNonUniformClustered",
+ "GroupNonUniformPartitionedNV"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformFMul",
+ "class": "Non-Uniform",
+ "opcode": 352,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'ClusterSize'",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformArithmetic",
+ "GroupNonUniformClustered",
+ "GroupNonUniformPartitionedNV"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformSMin",
+ "class": "Non-Uniform",
+ "opcode": 353,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'ClusterSize'",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformArithmetic",
+ "GroupNonUniformClustered",
+ "GroupNonUniformPartitionedNV"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformUMin",
+ "class": "Non-Uniform",
+ "opcode": 354,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'ClusterSize'",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformArithmetic",
+ "GroupNonUniformClustered",
+ "GroupNonUniformPartitionedNV"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformFMin",
+ "class": "Non-Uniform",
+ "opcode": 355,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'ClusterSize'",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformArithmetic",
+ "GroupNonUniformClustered",
+ "GroupNonUniformPartitionedNV"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformSMax",
+ "class": "Non-Uniform",
+ "opcode": 356,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'ClusterSize'",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformArithmetic",
+ "GroupNonUniformClustered",
+ "GroupNonUniformPartitionedNV"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformUMax",
+ "class": "Non-Uniform",
+ "opcode": 357,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'ClusterSize'",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformArithmetic",
+ "GroupNonUniformClustered",
+ "GroupNonUniformPartitionedNV"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformFMax",
+ "class": "Non-Uniform",
+ "opcode": 358,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'ClusterSize'",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformArithmetic",
+ "GroupNonUniformClustered",
+ "GroupNonUniformPartitionedNV"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformBitwiseAnd",
+ "class": "Non-Uniform",
+ "opcode": 359,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'ClusterSize'",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformArithmetic",
+ "GroupNonUniformClustered",
+ "GroupNonUniformPartitionedNV"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformBitwiseOr",
+ "class": "Non-Uniform",
+ "opcode": 360,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'ClusterSize'",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformArithmetic",
+ "GroupNonUniformClustered",
+ "GroupNonUniformPartitionedNV"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformBitwiseXor",
+ "class": "Non-Uniform",
+ "opcode": 361,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'ClusterSize'",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformArithmetic",
+ "GroupNonUniformClustered",
+ "GroupNonUniformPartitionedNV"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformLogicalAnd",
+ "class": "Non-Uniform",
+ "opcode": 362,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'ClusterSize'",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformArithmetic",
+ "GroupNonUniformClustered",
+ "GroupNonUniformPartitionedNV"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformLogicalOr",
+ "class": "Non-Uniform",
+ "opcode": 363,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'ClusterSize'",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformArithmetic",
+ "GroupNonUniformClustered",
+ "GroupNonUniformPartitionedNV"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformLogicalXor",
+ "class": "Non-Uniform",
+ "opcode": 364,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'ClusterSize'",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformArithmetic",
+ "GroupNonUniformClustered",
+ "GroupNonUniformPartitionedNV"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformQuadBroadcast",
+ "class": "Non-Uniform",
+ "opcode": 365,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Index'"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformQuad"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpGroupNonUniformQuadSwap",
+ "class": "Non-Uniform",
+ "opcode": 366,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Direction'"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformQuad"
+ ],
+ "version": "1.3"
+ },
+ {
+ "opname": "OpCopyLogical",
+ "class": "Composite",
+ "opcode": 400,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand'"
+ }
+ ],
+ "version": "1.4"
+ },
+ {
+ "opname": "OpPtrEqual",
+ "class": "Memory",
+ "opcode": 401,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ],
+ "version": "1.4"
+ },
+ {
+ "opname": "OpPtrNotEqual",
+ "class": "Memory",
+ "opcode": 402,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ],
+ "version": "1.4"
+ },
+ {
+ "opname": "OpPtrDiff",
+ "class": "Memory",
+ "opcode": 403,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ],
+ "capabilities": [
+ "Addresses",
+ "VariablePointers",
+ "VariablePointersStorageBuffer"
+ ],
+ "version": "1.4"
+ },
+ {
+ "opname": "OpTerminateInvocation",
+ "class": "Control-Flow",
+ "opcode": 4416,
+ "extensions": [
+ "SPV_KHR_terminate_invocation"
+ ],
+ "capabilities": [
+ "Shader"
+ ],
+ "version": "1.6"
+ },
+ {
+ "opname": "OpSubgroupBallotKHR",
+ "class": "Group",
+ "opcode": 4421,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Predicate'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupBallotKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_shader_ballot"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupFirstInvocationKHR",
+ "class": "Group",
+ "opcode": 4422,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupBallotKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_shader_ballot"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAllKHR",
+ "class": "Group",
+ "opcode": 4428,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Predicate'"
+ }
+ ],
+ "extensions": [
+ "SPV_KHR_subgroup_vote"
+ ],
+ "capabilities": [
+ "SubgroupVoteKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAnyKHR",
+ "class": "Group",
+ "opcode": 4429,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Predicate'"
+ }
+ ],
+ "extensions": [
+ "SPV_KHR_subgroup_vote"
+ ],
+ "capabilities": [
+ "SubgroupVoteKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAllEqualKHR",
+ "class": "Group",
+ "opcode": 4430,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Predicate'"
+ }
+ ],
+ "extensions": [
+ "SPV_KHR_subgroup_vote"
+ ],
+ "capabilities": [
+ "SubgroupVoteKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupReadInvocationKHR",
+ "class": "Group",
+ "opcode": 4432,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Index'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupBallotKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_shader_ballot"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpTraceRayKHR",
+ "class": "Reserved",
+ "opcode": 4445,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Accel'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ray Flags'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Cull Mask'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'SBT Offset'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'SBT Stride'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Miss Index'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ray Origin'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ray Tmin'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ray Direction'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ray Tmax'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpExecuteCallableKHR",
+ "class": "Reserved",
+ "opcode": 4446,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'SBT Index'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Callable Data'"
+ }
+ ],
+ "capabilities": [
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpConvertUToAccelerationStructureKHR",
+ "class": "Reserved",
+ "opcode": 4447,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Accel'"
+ }
+ ],
+ "capabilities": [
+ "RayTracingKHR",
+ "RayQueryKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_tracing",
+ "SPV_KHR_ray_query"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpIgnoreIntersectionKHR",
+ "class": "Reserved",
+ "opcode": 4448,
+ "capabilities": [
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpTerminateRayKHR",
+ "class": "Reserved",
+ "opcode": 4449,
+ "capabilities": [
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSDot",
+ "class": "Arithmetic",
+ "opcode": 4450,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector 2'"
+ },
+ {
+ "kind": "PackedVectorFormat",
+ "name": "'Packed Vector Format'",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "DotProduct"
+ ],
+ "version": "1.6"
+ },
+ {
+ "opname": "OpSDotKHR",
+ "class": "Arithmetic",
+ "opcode": 4450,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector 2'"
+ },
+ {
+ "kind": "PackedVectorFormat",
+ "name": "'Packed Vector Format'",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "DotProductKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_integer_dot_product"
+ ],
+ "version": "1.6"
+ },
+ {
+ "opname": "OpUDot",
+ "class": "Arithmetic",
+ "opcode": 4451,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector 2'"
+ },
+ {
+ "kind": "PackedVectorFormat",
+ "name": "'Packed Vector Format'",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "DotProduct"
+ ],
+ "version": "1.6"
+ },
+ {
+ "opname": "OpUDotKHR",
+ "class": "Arithmetic",
+ "opcode": 4451,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector 2'"
+ },
+ {
+ "kind": "PackedVectorFormat",
+ "name": "'Packed Vector Format'",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "DotProductKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_integer_dot_product"
+ ],
+ "version": "1.6"
+ },
+ {
+ "opname": "OpSUDot",
+ "class": "Arithmetic",
+ "opcode": 4452,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector 2'"
+ },
+ {
+ "kind": "PackedVectorFormat",
+ "name": "'Packed Vector Format'",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "DotProduct"
+ ],
+ "version": "1.6"
+ },
+ {
+ "opname": "OpSUDotKHR",
+ "class": "Arithmetic",
+ "opcode": 4452,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector 2'"
+ },
+ {
+ "kind": "PackedVectorFormat",
+ "name": "'Packed Vector Format'",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "DotProductKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_integer_dot_product"
+ ],
+ "version": "1.6"
+ },
+ {
+ "opname": "OpSDotAccSat",
+ "class": "Arithmetic",
+ "opcode": 4453,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector 2'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Accumulator'"
+ },
+ {
+ "kind": "PackedVectorFormat",
+ "name": "'Packed Vector Format'",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "DotProduct"
+ ],
+ "version": "1.6"
+ },
+ {
+ "opname": "OpSDotAccSatKHR",
+ "class": "Arithmetic",
+ "opcode": 4453,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector 2'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Accumulator'"
+ },
+ {
+ "kind": "PackedVectorFormat",
+ "name": "'Packed Vector Format'",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "DotProductKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_integer_dot_product"
+ ],
+ "version": "1.6"
+ },
+ {
+ "opname": "OpUDotAccSat",
+ "class": "Arithmetic",
+ "opcode": 4454,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector 2'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Accumulator'"
+ },
+ {
+ "kind": "PackedVectorFormat",
+ "name": "'Packed Vector Format'",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "DotProduct"
+ ],
+ "version": "1.6"
+ },
+ {
+ "opname": "OpUDotAccSatKHR",
+ "class": "Arithmetic",
+ "opcode": 4454,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector 2'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Accumulator'"
+ },
+ {
+ "kind": "PackedVectorFormat",
+ "name": "'Packed Vector Format'",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "DotProductKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_integer_dot_product"
+ ],
+ "version": "1.6"
+ },
+ {
+ "opname": "OpSUDotAccSat",
+ "class": "Arithmetic",
+ "opcode": 4455,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector 2'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Accumulator'"
+ },
+ {
+ "kind": "PackedVectorFormat",
+ "name": "'Packed Vector Format'",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "DotProduct"
+ ],
+ "version": "1.6"
+ },
+ {
+ "opname": "OpSUDotAccSatKHR",
+ "class": "Arithmetic",
+ "opcode": 4455,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Vector 2'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Accumulator'"
+ },
+ {
+ "kind": "PackedVectorFormat",
+ "name": "'Packed Vector Format'",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "DotProductKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_integer_dot_product"
+ ],
+ "version": "1.6"
+ },
+ {
+ "opname": "OpTypeRayQueryKHR",
+ "class": "Reserved",
+ "opcode": 4472,
+ "operands": [
+ {
+ "kind": "IdResult"
+ }
+ ],
+ "capabilities": [
+ "RayQueryKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_query"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpRayQueryInitializeKHR",
+ "class": "Reserved",
+ "opcode": 4473,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'RayQuery'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Accel'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'RayFlags'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'CullMask'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'RayOrigin'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'RayTMin'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'RayDirection'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'RayTMax'"
+ }
+ ],
+ "capabilities": [
+ "RayQueryKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_query"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpRayQueryTerminateKHR",
+ "class": "Reserved",
+ "opcode": 4474,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'RayQuery'"
+ }
+ ],
+ "capabilities": [
+ "RayQueryKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_query"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpRayQueryGenerateIntersectionKHR",
+ "class": "Reserved",
+ "opcode": 4475,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'RayQuery'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'HitT'"
+ }
+ ],
+ "capabilities": [
+ "RayQueryKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_query"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpRayQueryConfirmIntersectionKHR",
+ "class": "Reserved",
+ "opcode": 4476,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'RayQuery'"
+ }
+ ],
+ "capabilities": [
+ "RayQueryKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_query"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpRayQueryProceedKHR",
+ "class": "Reserved",
+ "opcode": 4477,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'RayQuery'"
+ }
+ ],
+ "capabilities": [
+ "RayQueryKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_query"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpRayQueryGetIntersectionTypeKHR",
+ "class": "Reserved",
+ "opcode": 4479,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'RayQuery'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Intersection'"
+ }
+ ],
+ "capabilities": [
+ "RayQueryKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_query"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpGroupIAddNonUniformAMD",
+ "class": "Group",
+ "opcode": 5000,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'X'"
+ }
+ ],
+ "capabilities": [
+ "Groups"
+ ],
+ "extensions": [
+ "SPV_AMD_shader_ballot"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpGroupFAddNonUniformAMD",
+ "class": "Group",
+ "opcode": 5001,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'X'"
+ }
+ ],
+ "capabilities": [
+ "Groups"
+ ],
+ "extensions": [
+ "SPV_AMD_shader_ballot"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpGroupFMinNonUniformAMD",
+ "class": "Group",
+ "opcode": 5002,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'X'"
+ }
+ ],
+ "capabilities": [
+ "Groups"
+ ],
+ "extensions": [
+ "SPV_AMD_shader_ballot"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpGroupUMinNonUniformAMD",
+ "class": "Group",
+ "opcode": 5003,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'X'"
+ }
+ ],
+ "capabilities": [
+ "Groups"
+ ],
+ "extensions": [
+ "SPV_AMD_shader_ballot"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpGroupSMinNonUniformAMD",
+ "class": "Group",
+ "opcode": 5004,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'X'"
+ }
+ ],
+ "capabilities": [
+ "Groups"
+ ],
+ "extensions": [
+ "SPV_AMD_shader_ballot"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpGroupFMaxNonUniformAMD",
+ "class": "Group",
+ "opcode": 5005,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'X'"
+ }
+ ],
+ "capabilities": [
+ "Groups"
+ ],
+ "extensions": [
+ "SPV_AMD_shader_ballot"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpGroupUMaxNonUniformAMD",
+ "class": "Group",
+ "opcode": 5006,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'X'"
+ }
+ ],
+ "capabilities": [
+ "Groups"
+ ],
+ "extensions": [
+ "SPV_AMD_shader_ballot"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpGroupSMaxNonUniformAMD",
+ "class": "Group",
+ "opcode": 5007,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "GroupOperation",
+ "name": "'Operation'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'X'"
+ }
+ ],
+ "capabilities": [
+ "Groups"
+ ],
+ "extensions": [
+ "SPV_AMD_shader_ballot"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpFragmentMaskFetchAMD",
+ "class": "Reserved",
+ "opcode": 5011,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ }
+ ],
+ "capabilities": [
+ "FragmentMaskAMD"
+ ],
+ "extensions": [
+ "SPV_AMD_shader_fragment_mask"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpFragmentFetchAMD",
+ "class": "Reserved",
+ "opcode": 5012,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Fragment Index'"
+ }
+ ],
+ "capabilities": [
+ "FragmentMaskAMD"
+ ],
+ "extensions": [
+ "SPV_AMD_shader_fragment_mask"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpReadClockKHR",
+ "class": "Reserved",
+ "opcode": 5056,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Scope'"
+ }
+ ],
+ "capabilities": [
+ "ShaderClockKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_shader_clock"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpImageSampleFootprintNV",
+ "class": "Image",
+ "opcode": 5283,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sampled Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Granularity'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coarse'"
+ },
+ {
+ "kind": "ImageOperands",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "ImageFootprintNV"
+ ],
+ "extensions": [
+ "SPV_NV_shader_image_footprint"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpGroupNonUniformPartitionNV",
+ "class": "Non-Uniform",
+ "opcode": 5296,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ }
+ ],
+ "capabilities": [
+ "GroupNonUniformPartitionedNV"
+ ],
+ "extensions": [
+ "SPV_NV_shader_subgroup_partitioned"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpWritePackedPrimitiveIndices4x8NV",
+ "class": "Reserved",
+ "opcode": 5299,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Index Offset'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packed Indices'"
+ }
+ ],
+ "capabilities": [
+ "MeshShadingNV"
+ ],
+ "extensions": [
+ "SPV_NV_mesh_shader"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpReportIntersectionNV",
+ "class": "Reserved",
+ "opcode": 5334,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Hit'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'HitKind'"
+ }
+ ],
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpReportIntersectionKHR",
+ "class": "Reserved",
+ "opcode": 5334,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Hit'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'HitKind'"
+ }
+ ],
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpIgnoreIntersectionNV",
+ "class": "Reserved",
+ "opcode": 5335,
+ "capabilities": [
+ "RayTracingNV"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpTerminateRayNV",
+ "class": "Reserved",
+ "opcode": 5336,
+ "capabilities": [
+ "RayTracingNV"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpTraceNV",
+ "class": "Reserved",
+ "opcode": 5337,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Accel'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ray Flags'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Cull Mask'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'SBT Offset'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'SBT Stride'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Miss Index'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ray Origin'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ray Tmin'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ray Direction'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ray Tmax'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'PayloadId'"
+ }
+ ],
+ "capabilities": [
+ "RayTracingNV"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpTraceMotionNV",
+ "class": "Reserved",
+ "opcode": 5338,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Accel'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ray Flags'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Cull Mask'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'SBT Offset'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'SBT Stride'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Miss Index'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ray Origin'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ray Tmin'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ray Direction'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ray Tmax'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Time'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'PayloadId'"
+ }
+ ],
+ "capabilities": [
+ "RayTracingMotionBlurNV"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing_motion_blur"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpTraceRayMotionNV",
+ "class": "Reserved",
+ "opcode": 5339,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Accel'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ray Flags'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Cull Mask'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'SBT Offset'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'SBT Stride'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Miss Index'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ray Origin'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ray Tmin'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ray Direction'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ray Tmax'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Time'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "RayTracingMotionBlurNV"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing_motion_blur"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpTypeAccelerationStructureNV",
+ "class": "Reserved",
+ "opcode": 5341,
+ "operands": [
+ {
+ "kind": "IdResult"
+ }
+ ],
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR",
+ "RayQueryKHR"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing",
+ "SPV_KHR_ray_query"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpTypeAccelerationStructureKHR",
+ "class": "Reserved",
+ "opcode": 5341,
+ "operands": [
+ {
+ "kind": "IdResult"
+ }
+ ],
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR",
+ "RayQueryKHR"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing",
+ "SPV_KHR_ray_query"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpExecuteCallableNV",
+ "class": "Reserved",
+ "opcode": 5344,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'SBT Index'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Callable DataId'"
+ }
+ ],
+ "capabilities": [
+ "RayTracingNV"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpTypeCooperativeMatrixNV",
+ "class": "Reserved",
+ "opcode": 5358,
+ "operands": [
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Component Type'"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Rows'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Columns'"
+ }
+ ],
+ "capabilities": [
+ "CooperativeMatrixNV"
+ ],
+ "extensions": [
+ "SPV_NV_cooperative_matrix"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpCooperativeMatrixLoadNV",
+ "class": "Reserved",
+ "opcode": 5359,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Stride'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Column Major'"
+ },
+ {
+ "kind": "MemoryAccess",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "CooperativeMatrixNV"
+ ],
+ "extensions": [
+ "SPV_NV_cooperative_matrix"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpCooperativeMatrixStoreNV",
+ "class": "Reserved",
+ "opcode": 5360,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Object'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Stride'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Column Major'"
+ },
+ {
+ "kind": "MemoryAccess",
+ "quantifier": "?"
+ }
+ ],
+ "capabilities": [
+ "CooperativeMatrixNV"
+ ],
+ "extensions": [
+ "SPV_NV_cooperative_matrix"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpCooperativeMatrixMulAddNV",
+ "class": "Reserved",
+ "opcode": 5361,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'B'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'C'"
+ }
+ ],
+ "capabilities": [
+ "CooperativeMatrixNV"
+ ],
+ "extensions": [
+ "SPV_NV_cooperative_matrix"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpCooperativeMatrixLengthNV",
+ "class": "Reserved",
+ "opcode": 5362,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Type'"
+ }
+ ],
+ "capabilities": [
+ "CooperativeMatrixNV"
+ ],
+ "extensions": [
+ "SPV_NV_cooperative_matrix"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpBeginInvocationInterlockEXT",
+ "class": "Reserved",
+ "opcode": 5364,
+ "capabilities": [
+ "FragmentShaderSampleInterlockEXT",
+ "FragmentShaderPixelInterlockEXT",
+ "FragmentShaderShadingRateInterlockEXT"
+ ],
+ "extensions": [
+ "SPV_EXT_fragment_shader_interlock"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpEndInvocationInterlockEXT",
+ "class": "Reserved",
+ "opcode": 5365,
+ "capabilities": [
+ "FragmentShaderSampleInterlockEXT",
+ "FragmentShaderPixelInterlockEXT",
+ "FragmentShaderShadingRateInterlockEXT"
+ ],
+ "extensions": [
+ "SPV_EXT_fragment_shader_interlock"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpDemoteToHelperInvocation",
+ "class": "Control-Flow",
+ "opcode": 5380,
+ "capabilities": [
+ "DemoteToHelperInvocation"
+ ],
+ "version": "1.6"
+ },
+ {
+ "opname": "OpDemoteToHelperInvocationEXT",
+ "class": "Control-Flow",
+ "opcode": 5380,
+ "capabilities": [
+ "DemoteToHelperInvocation"
+ ],
+ "version": "1.6"
+ },
+ {
+ "opname": "OpIsHelperInvocationEXT",
+ "class": "Reserved",
+ "opcode": 5381,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ }
+ ],
+ "capabilities": [
+ "DemoteToHelperInvocationEXT"
+ ],
+ "extensions": [
+ "SPV_EXT_demote_to_helper_invocation"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpConvertUToImageNV",
+ "class": "Reserved",
+ "opcode": 5391,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand'"
+ }
+ ],
+ "capabilities": [
+ "BindlessTextureNV"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpConvertUToSamplerNV",
+ "class": "Reserved",
+ "opcode": 5392,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand'"
+ }
+ ],
+ "capabilities": [
+ "BindlessTextureNV"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpConvertImageToUNV",
+ "class": "Reserved",
+ "opcode": 5393,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand'"
+ }
+ ],
+ "capabilities": [
+ "BindlessTextureNV"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpConvertSamplerToUNV",
+ "class": "Reserved",
+ "opcode": 5394,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand'"
+ }
+ ],
+ "capabilities": [
+ "BindlessTextureNV"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpConvertUToSampledImageNV",
+ "class": "Reserved",
+ "opcode": 5395,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand'"
+ }
+ ],
+ "capabilities": [
+ "BindlessTextureNV"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpConvertSampledImageToUNV",
+ "class": "Reserved",
+ "opcode": 5396,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand'"
+ }
+ ],
+ "capabilities": [
+ "BindlessTextureNV"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSamplerImageAddressingModeNV",
+ "class": "Reserved",
+ "opcode": 5397,
+ "operands": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Bit Width'"
+ }
+ ],
+ "capabilities": [
+ "BindlessTextureNV"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupShuffleINTEL",
+ "class": "Group",
+ "opcode": 5571,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Data'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'InvocationId'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupShuffleINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupShuffleDownINTEL",
+ "class": "Group",
+ "opcode": 5572,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Current'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Next'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Delta'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupShuffleINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupShuffleUpINTEL",
+ "class": "Group",
+ "opcode": 5573,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Previous'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Current'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Delta'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupShuffleINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupShuffleXorINTEL",
+ "class": "Group",
+ "opcode": 5574,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Data'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupShuffleINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupBlockReadINTEL",
+ "class": "Group",
+ "opcode": 5575,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ptr'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupBufferBlockIOINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupBlockWriteINTEL",
+ "class": "Group",
+ "opcode": 5576,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Ptr'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Data'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupBufferBlockIOINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupImageBlockReadINTEL",
+ "class": "Group",
+ "opcode": 5577,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupImageBlockIOINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupImageBlockWriteINTEL",
+ "class": "Group",
+ "opcode": 5578,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Data'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupImageBlockIOINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupImageMediaBlockReadINTEL",
+ "class": "Group",
+ "opcode": 5580,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Width'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Height'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupImageMediaBlockIOINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupImageMediaBlockWriteINTEL",
+ "class": "Group",
+ "opcode": 5581,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Coordinate'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Width'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Height'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Data'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupImageMediaBlockIOINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpUCountLeadingZerosINTEL",
+ "class": "Reserved",
+ "opcode": 5585,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand'"
+ }
+ ],
+ "capabilities": [
+ "IntegerFunctions2INTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpUCountTrailingZerosINTEL",
+ "class": "Reserved",
+ "opcode": 5586,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand'"
+ }
+ ],
+ "capabilities": [
+ "IntegerFunctions2INTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpAbsISubINTEL",
+ "class": "Reserved",
+ "opcode": 5587,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ],
+ "capabilities": [
+ "IntegerFunctions2INTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpAbsUSubINTEL",
+ "class": "Reserved",
+ "opcode": 5588,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ],
+ "capabilities": [
+ "IntegerFunctions2INTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpIAddSatINTEL",
+ "class": "Reserved",
+ "opcode": 5589,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ],
+ "capabilities": [
+ "IntegerFunctions2INTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpUAddSatINTEL",
+ "class": "Reserved",
+ "opcode": 5590,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ],
+ "capabilities": [
+ "IntegerFunctions2INTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpIAverageINTEL",
+ "class": "Reserved",
+ "opcode": 5591,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ],
+ "capabilities": [
+ "IntegerFunctions2INTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpUAverageINTEL",
+ "class": "Reserved",
+ "opcode": 5592,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ],
+ "capabilities": [
+ "IntegerFunctions2INTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpIAverageRoundedINTEL",
+ "class": "Reserved",
+ "opcode": 5593,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ],
+ "capabilities": [
+ "IntegerFunctions2INTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpUAverageRoundedINTEL",
+ "class": "Reserved",
+ "opcode": 5594,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ],
+ "capabilities": [
+ "IntegerFunctions2INTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpISubSatINTEL",
+ "class": "Reserved",
+ "opcode": 5595,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ],
+ "capabilities": [
+ "IntegerFunctions2INTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpUSubSatINTEL",
+ "class": "Reserved",
+ "opcode": 5596,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ],
+ "capabilities": [
+ "IntegerFunctions2INTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpIMul32x16INTEL",
+ "class": "Reserved",
+ "opcode": 5597,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ],
+ "capabilities": [
+ "IntegerFunctions2INTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpUMul32x16INTEL",
+ "class": "Reserved",
+ "opcode": 5598,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Operand 2'"
+ }
+ ],
+ "capabilities": [
+ "IntegerFunctions2INTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpConstantFunctionPointerINTEL",
+ "class": "@exclude",
+ "opcode": 5600,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Function'"
+ }
+ ],
+ "capabilities": [
+ "FunctionPointersINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_function_pointers"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpFunctionPointerCallINTEL",
+ "class": "@exclude",
+ "opcode": 5601,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "quantifier": "*",
+ "name": "'Operand 1'"
+ }
+ ],
+ "capabilities": [
+ "FunctionPointersINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_function_pointers"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpAsmTargetINTEL",
+ "class": "@exclude",
+ "opcode": 5609,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "LiteralString",
+ "name": "'Asm target'"
+ }
+ ],
+ "capabilities": [
+ "AsmINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpAsmINTEL",
+ "class": "@exclude",
+ "opcode": 5610,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Asm type'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Target'"
+ },
+ {
+ "kind": "LiteralString",
+ "name": "'Asm instructions'"
+ },
+ {
+ "kind": "LiteralString",
+ "name": "'Constraints'"
+ }
+ ],
+ "capabilities": [
+ "AsmINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpAsmCallINTEL",
+ "class": "@exclude",
+ "opcode": 5611,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Asm'"
+ },
+ {
+ "kind": "IdRef",
+ "quantifier": "*",
+ "name": "'Argument 0'"
+ }
+ ],
+ "capabilities": [
+ "AsmINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpAtomicFMinEXT",
+ "class": "Atomic",
+ "opcode": 5614,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Memory'"
+ },
+ {
+ "kind": "IdMemorySemantics",
+ "name": "'Semantics'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ }
+ ],
+ "capabilities": [
+ "AtomicFloat16MinMaxEXT",
+ "AtomicFloat32MinMaxEXT",
+ "AtomicFloat64MinMaxEXT"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpAtomicFMaxEXT",
+ "class": "Atomic",
+ "opcode": 5615,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Memory'"
+ },
+ {
+ "kind": "IdMemorySemantics",
+ "name": "'Semantics'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ }
+ ],
+ "capabilities": [
+ "AtomicFloat16MinMaxEXT",
+ "AtomicFloat32MinMaxEXT",
+ "AtomicFloat64MinMaxEXT"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpAssumeTrueKHR",
+ "class": "Miscellaneous",
+ "opcode": 5630,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Condition'"
+ }
+ ],
+ "capabilities": [
+ "ExpectAssumeKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_expect_assume"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpExpectKHR",
+ "class": "Miscellaneous",
+ "opcode": 5631,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'ExpectedValue'"
+ }
+ ],
+ "capabilities": [
+ "ExpectAssumeKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_expect_assume"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpDecorateString",
+ "class": "Annotation",
+ "opcode": 5632,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Target'"
+ },
+ {
+ "kind": "Decoration"
+ }
+ ],
+ "extensions": [
+ "SPV_GOOGLE_decorate_string",
+ "SPV_GOOGLE_hlsl_functionality1"
+ ],
+ "version": "1.4"
+ },
+ {
+ "opname": "OpDecorateStringGOOGLE",
+ "class": "Annotation",
+ "opcode": 5632,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Target'"
+ },
+ {
+ "kind": "Decoration"
+ }
+ ],
+ "extensions": [
+ "SPV_GOOGLE_decorate_string",
+ "SPV_GOOGLE_hlsl_functionality1"
+ ],
+ "version": "1.4"
+ },
+ {
+ "opname": "OpMemberDecorateString",
+ "class": "Annotation",
+ "opcode": 5633,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Struct Type'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Member'"
+ },
+ {
+ "kind": "Decoration"
+ }
+ ],
+ "extensions": [
+ "SPV_GOOGLE_decorate_string",
+ "SPV_GOOGLE_hlsl_functionality1"
+ ],
+ "version": "1.4"
+ },
+ {
+ "opname": "OpMemberDecorateStringGOOGLE",
+ "class": "Annotation",
+ "opcode": 5633,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Struct Type'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Member'"
+ },
+ {
+ "kind": "Decoration"
+ }
+ ],
+ "extensions": [
+ "SPV_GOOGLE_decorate_string",
+ "SPV_GOOGLE_hlsl_functionality1"
+ ],
+ "version": "1.4"
+ },
+ {
+ "opname": "OpVmeImageINTEL",
+ "class": "@exclude",
+ "opcode": 5699,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Image Type'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sampler'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpTypeVmeImageINTEL",
+ "class": "@exclude",
+ "opcode": 5700,
+ "operands": [
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Image Type'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpTypeAvcImePayloadINTEL",
+ "class": "@exclude",
+ "opcode": 5701,
+ "operands": [
+ {
+ "kind": "IdResult"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpTypeAvcRefPayloadINTEL",
+ "class": "@exclude",
+ "opcode": 5702,
+ "operands": [
+ {
+ "kind": "IdResult"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpTypeAvcSicPayloadINTEL",
+ "class": "@exclude",
+ "opcode": 5703,
+ "operands": [
+ {
+ "kind": "IdResult"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpTypeAvcMcePayloadINTEL",
+ "class": "@exclude",
+ "opcode": 5704,
+ "operands": [
+ {
+ "kind": "IdResult"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpTypeAvcMceResultINTEL",
+ "class": "@exclude",
+ "opcode": 5705,
+ "operands": [
+ {
+ "kind": "IdResult"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpTypeAvcImeResultINTEL",
+ "class": "@exclude",
+ "opcode": 5706,
+ "operands": [
+ {
+ "kind": "IdResult"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpTypeAvcImeResultSingleReferenceStreamoutINTEL",
+ "class": "@exclude",
+ "opcode": 5707,
+ "operands": [
+ {
+ "kind": "IdResult"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpTypeAvcImeResultDualReferenceStreamoutINTEL",
+ "class": "@exclude",
+ "opcode": 5708,
+ "operands": [
+ {
+ "kind": "IdResult"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpTypeAvcImeSingleReferenceStreaminINTEL",
+ "class": "@exclude",
+ "opcode": 5709,
+ "operands": [
+ {
+ "kind": "IdResult"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpTypeAvcImeDualReferenceStreaminINTEL",
+ "class": "@exclude",
+ "opcode": 5710,
+ "operands": [
+ {
+ "kind": "IdResult"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpTypeAvcRefResultINTEL",
+ "class": "@exclude",
+ "opcode": 5711,
+ "operands": [
+ {
+ "kind": "IdResult"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpTypeAvcSicResultINTEL",
+ "class": "@exclude",
+ "opcode": 5712,
+ "operands": [
+ {
+ "kind": "IdResult"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL",
+ "class": "@exclude",
+ "opcode": 5713,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Slice Type'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Qp'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL",
+ "class": "@exclude",
+ "opcode": 5714,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Reference Base Penalty'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL",
+ "class": "@exclude",
+ "opcode": 5715,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Slice Type'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Qp'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceSetInterShapePenaltyINTEL",
+ "class": "@exclude",
+ "opcode": 5716,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packed Shape Penalty'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL",
+ "class": "@exclude",
+ "opcode": 5717,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Slice Type'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Qp'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceSetInterDirectionPenaltyINTEL",
+ "class": "@exclude",
+ "opcode": 5718,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Direction Cost'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL",
+ "class": "@exclude",
+ "opcode": 5719,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Slice Type'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Qp'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL",
+ "SubgroupAvcMotionEstimationIntraINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL",
+ "class": "@exclude",
+ "opcode": 5720,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Slice Type'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Qp'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL",
+ "class": "@exclude",
+ "opcode": 5721,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL",
+ "class": "@exclude",
+ "opcode": 5722,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL",
+ "class": "@exclude",
+ "opcode": 5723,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceSetMotionVectorCostFunctionINTEL",
+ "class": "@exclude",
+ "opcode": 5724,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packed Cost Center Delta'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packed Cost Table'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Cost Precision'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL",
+ "class": "@exclude",
+ "opcode": 5725,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Slice Type'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Qp'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL",
+ "SubgroupAvcMotionEstimationIntraINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL",
+ "class": "@exclude",
+ "opcode": 5726,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL",
+ "SubgroupAvcMotionEstimationIntraINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL",
+ "class": "@exclude",
+ "opcode": 5727,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL",
+ "SubgroupAvcMotionEstimationChromaINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceSetAcOnlyHaarINTEL",
+ "class": "@exclude",
+ "opcode": 5728,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL",
+ "class": "@exclude",
+ "opcode": 5729,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Source Field Polarity'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL",
+ "class": "@exclude",
+ "opcode": 5730,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Reference Field Polarity'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL",
+ "class": "@exclude",
+ "opcode": 5731,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Forward Reference Field Polarity'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Backward Reference Field Polarity'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceConvertToImePayloadINTEL",
+ "class": "@exclude",
+ "opcode": 5732,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceConvertToImeResultINTEL",
+ "class": "@exclude",
+ "opcode": 5733,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceConvertToRefPayloadINTEL",
+ "class": "@exclude",
+ "opcode": 5734,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceConvertToRefResultINTEL",
+ "class": "@exclude",
+ "opcode": 5735,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceConvertToSicPayloadINTEL",
+ "class": "@exclude",
+ "opcode": 5736,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceConvertToSicResultINTEL",
+ "class": "@exclude",
+ "opcode": 5737,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceGetMotionVectorsINTEL",
+ "class": "@exclude",
+ "opcode": 5738,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceGetInterDistortionsINTEL",
+ "class": "@exclude",
+ "opcode": 5739,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceGetBestInterDistortionsINTEL",
+ "class": "@exclude",
+ "opcode": 5740,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceGetInterMajorShapeINTEL",
+ "class": "@exclude",
+ "opcode": 5741,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceGetInterMinorShapeINTEL",
+ "class": "@exclude",
+ "opcode": 5742,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceGetInterDirectionsINTEL",
+ "class": "@exclude",
+ "opcode": 5743,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceGetInterMotionVectorCountINTEL",
+ "class": "@exclude",
+ "opcode": 5744,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceGetInterReferenceIdsINTEL",
+ "class": "@exclude",
+ "opcode": 5745,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL",
+ "class": "@exclude",
+ "opcode": 5746,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packed Reference Ids'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packed Reference Parameter Field Polarities'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeInitializeINTEL",
+ "class": "@exclude",
+ "opcode": 5747,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Src Coord'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Partition Mask'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'SAD Adjustment'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeSetSingleReferenceINTEL",
+ "class": "@exclude",
+ "opcode": 5748,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ref Offset'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Search Window Config'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeSetDualReferenceINTEL",
+ "class": "@exclude",
+ "opcode": 5749,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Fwd Ref Offset'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Bwd Ref Offset'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'id> Search Window Config'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeRefWindowSizeINTEL",
+ "class": "@exclude",
+ "opcode": 5750,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Search Window Config'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Dual Ref'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeAdjustRefOffsetINTEL",
+ "class": "@exclude",
+ "opcode": 5751,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ref Offset'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Src Coord'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ref Window Size'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Image Size'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeConvertToMcePayloadINTEL",
+ "class": "@exclude",
+ "opcode": 5752,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeSetMaxMotionVectorCountINTEL",
+ "class": "@exclude",
+ "opcode": 5753,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Max Motion Vector Count'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeSetUnidirectionalMixDisableINTEL",
+ "class": "@exclude",
+ "opcode": 5754,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL",
+ "class": "@exclude",
+ "opcode": 5755,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Threshold'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeSetWeightedSadINTEL",
+ "class": "@exclude",
+ "opcode": 5756,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packed Sad Weights'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeEvaluateWithSingleReferenceINTEL",
+ "class": "@exclude",
+ "opcode": 5757,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Src Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ref Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeEvaluateWithDualReferenceINTEL",
+ "class": "@exclude",
+ "opcode": 5758,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Src Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Fwd Ref Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Bwd Ref Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL",
+ "class": "@exclude",
+ "opcode": 5759,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Src Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ref Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Streamin Components'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL",
+ "class": "@exclude",
+ "opcode": 5760,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Src Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Fwd Ref Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Bwd Ref Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Streamin Components'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL",
+ "class": "@exclude",
+ "opcode": 5761,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Src Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ref Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL",
+ "class": "@exclude",
+ "opcode": 5762,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Src Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Fwd Ref Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Bwd Ref Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL",
+ "class": "@exclude",
+ "opcode": 5763,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Src Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ref Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Streamin Components'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL",
+ "class": "@exclude",
+ "opcode": 5764,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Src Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Fwd Ref Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Bwd Ref Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Streamin Components'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeConvertToMceResultINTEL",
+ "class": "@exclude",
+ "opcode": 5765,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeGetSingleReferenceStreaminINTEL",
+ "class": "@exclude",
+ "opcode": 5766,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeGetDualReferenceStreaminINTEL",
+ "class": "@exclude",
+ "opcode": 5767,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeStripSingleReferenceStreamoutINTEL",
+ "class": "@exclude",
+ "opcode": 5768,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeStripDualReferenceStreamoutINTEL",
+ "class": "@exclude",
+ "opcode": 5769,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL",
+ "class": "@exclude",
+ "opcode": 5770,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Major Shape'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL",
+ "class": "@exclude",
+ "opcode": 5771,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Major Shape'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL",
+ "class": "@exclude",
+ "opcode": 5772,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Major Shape'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL",
+ "class": "@exclude",
+ "opcode": 5773,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Major Shape'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Direction'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL",
+ "class": "@exclude",
+ "opcode": 5774,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Major Shape'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Direction'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL",
+ "class": "@exclude",
+ "opcode": 5775,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Major Shape'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Direction'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeGetBorderReachedINTEL",
+ "class": "@exclude",
+ "opcode": 5776,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Image Select'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeGetTruncatedSearchIndicationINTEL",
+ "class": "@exclude",
+ "opcode": 5777,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL",
+ "class": "@exclude",
+ "opcode": 5778,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL",
+ "class": "@exclude",
+ "opcode": 5779,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL",
+ "class": "@exclude",
+ "opcode": 5780,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcFmeInitializeINTEL",
+ "class": "@exclude",
+ "opcode": 5781,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Src Coord'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Motion Vectors'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Major Shapes'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Minor Shapes'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Direction'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pixel Resolution'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sad Adjustment'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcBmeInitializeINTEL",
+ "class": "@exclude",
+ "opcode": 5782,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Src Coord'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Motion Vectors'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Major Shapes'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Minor Shapes'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Direction'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pixel Resolution'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Bidirectional Weight'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sad Adjustment'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcRefConvertToMcePayloadINTEL",
+ "class": "@exclude",
+ "opcode": 5783,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcRefSetBidirectionalMixDisableINTEL",
+ "class": "@exclude",
+ "opcode": 5784,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcRefSetBilinearFilterEnableINTEL",
+ "class": "@exclude",
+ "opcode": 5785,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcRefEvaluateWithSingleReferenceINTEL",
+ "class": "@exclude",
+ "opcode": 5786,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Src Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ref Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcRefEvaluateWithDualReferenceINTEL",
+ "class": "@exclude",
+ "opcode": 5787,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Src Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Fwd Ref Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Bwd Ref Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcRefEvaluateWithMultiReferenceINTEL",
+ "class": "@exclude",
+ "opcode": 5788,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Src Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packed Reference Ids'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL",
+ "class": "@exclude",
+ "opcode": 5789,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Src Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packed Reference Ids'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packed Reference Field Polarities'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcRefConvertToMceResultINTEL",
+ "class": "@exclude",
+ "opcode": 5790,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcSicInitializeINTEL",
+ "class": "@exclude",
+ "opcode": 5791,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Src Coord'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcSicConfigureSkcINTEL",
+ "class": "@exclude",
+ "opcode": 5792,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Skip Block Partition Type'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Skip Motion Vector Mask'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Motion Vectors'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Bidirectional Weight'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sad Adjustment'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcSicConfigureIpeLumaINTEL",
+ "class": "@exclude",
+ "opcode": 5793,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Luma Intra Partition Mask'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Intra Neighbour Availabilty'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Left Edge Luma Pixels'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Upper Left Corner Luma Pixel'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Upper Edge Luma Pixels'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Upper Right Edge Luma Pixels'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sad Adjustment'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL",
+ "SubgroupAvcMotionEstimationIntraINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcSicConfigureIpeLumaChromaINTEL",
+ "class": "@exclude",
+ "opcode": 5794,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Luma Intra Partition Mask'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Intra Neighbour Availabilty'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Left Edge Luma Pixels'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Upper Left Corner Luma Pixel'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Upper Edge Luma Pixels'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Upper Right Edge Luma Pixels'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Left Edge Chroma Pixels'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Upper Left Corner Chroma Pixel'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Upper Edge Chroma Pixels'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Sad Adjustment'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL",
+ "SubgroupAvcMotionEstimationChromaINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcSicGetMotionVectorMaskINTEL",
+ "class": "@exclude",
+ "opcode": 5795,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Skip Block Partition Type'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Direction'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcSicConvertToMcePayloadINTEL",
+ "class": "@exclude",
+ "opcode": 5796,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL",
+ "class": "@exclude",
+ "opcode": 5797,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packed Shape Penalty'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL",
+ "class": "@exclude",
+ "opcode": 5798,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Luma Mode Penalty'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Luma Packed Neighbor Modes'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Luma Packed Non Dc Penalty'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL",
+ "SubgroupAvcMotionEstimationIntraINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL",
+ "class": "@exclude",
+ "opcode": 5799,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Chroma Mode Base Penalty'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL",
+ "SubgroupAvcMotionEstimationChromaINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcSicSetBilinearFilterEnableINTEL",
+ "class": "@exclude",
+ "opcode": 5800,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcSicSetSkcForwardTransformEnableINTEL",
+ "class": "@exclude",
+ "opcode": 5801,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packed Sad Coefficients'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL",
+ "class": "@exclude",
+ "opcode": 5802,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Block Based Skip Type'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcSicEvaluateIpeINTEL",
+ "class": "@exclude",
+ "opcode": 5803,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Src Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL",
+ "SubgroupAvcMotionEstimationIntraINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcSicEvaluateWithSingleReferenceINTEL",
+ "class": "@exclude",
+ "opcode": 5804,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Src Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Ref Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcSicEvaluateWithDualReferenceINTEL",
+ "class": "@exclude",
+ "opcode": 5805,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Src Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Fwd Ref Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Bwd Ref Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcSicEvaluateWithMultiReferenceINTEL",
+ "class": "@exclude",
+ "opcode": 5806,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Src Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packed Reference Ids'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL",
+ "class": "@exclude",
+ "opcode": 5807,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Src Image'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packed Reference Ids'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packed Reference Field Polarities'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcSicConvertToMceResultINTEL",
+ "class": "@exclude",
+ "opcode": 5808,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcSicGetIpeLumaShapeINTEL",
+ "class": "@exclude",
+ "opcode": 5809,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL",
+ "SubgroupAvcMotionEstimationIntraINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcSicGetBestIpeLumaDistortionINTEL",
+ "class": "@exclude",
+ "opcode": 5810,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL",
+ "SubgroupAvcMotionEstimationIntraINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcSicGetBestIpeChromaDistortionINTEL",
+ "class": "@exclude",
+ "opcode": 5811,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcSicGetPackedIpeLumaModesINTEL",
+ "class": "@exclude",
+ "opcode": 5812,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL",
+ "SubgroupAvcMotionEstimationIntraINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcSicGetIpeChromaModeINTEL",
+ "class": "@exclude",
+ "opcode": 5813,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL",
+ "SubgroupAvcMotionEstimationChromaINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL",
+ "class": "@exclude",
+ "opcode": 5814,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL",
+ "SubgroupAvcMotionEstimationIntraINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL",
+ "class": "@exclude",
+ "opcode": 5815,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL",
+ "SubgroupAvcMotionEstimationIntraINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSubgroupAvcSicGetInterRawSadsINTEL",
+ "class": "@exclude",
+ "opcode": 5816,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Payload'"
+ }
+ ],
+ "capabilities": [
+ "SubgroupAvcMotionEstimationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpVariableLengthArrayINTEL",
+ "class": "@exclude",
+ "opcode": 5818,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Lenght'"
+ }
+ ],
+ "capabilities": [
+ "VariableLengthArrayINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSaveMemoryINTEL",
+ "class": "@exclude",
+ "opcode": 5819,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ }
+ ],
+ "capabilities": [
+ "VariableLengthArrayINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpRestoreMemoryINTEL",
+ "class": "@exclude",
+ "opcode": 5820,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "name": "'Ptr'"
+ }
+ ],
+ "capabilities": [
+ "VariableLengthArrayINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatSinCosPiINTEL",
+ "class": "@exclude",
+ "opcode": 5840,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'FromSign'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatCastINTEL",
+ "class": "@exclude",
+ "opcode": 5841,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatCastFromIntINTEL",
+ "class": "@exclude",
+ "opcode": 5842,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'FromSign'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatCastToIntINTEL",
+ "class": "@exclude",
+ "opcode": 5843,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatAddINTEL",
+ "class": "@exclude",
+ "opcode": 5846,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'B'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M2'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatSubINTEL",
+ "class": "@exclude",
+ "opcode": 5847,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'B'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M2'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatMulINTEL",
+ "class": "@exclude",
+ "opcode": 5848,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'B'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M2'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatDivINTEL",
+ "class": "@exclude",
+ "opcode": 5849,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'B'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M2'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatGTINTEL",
+ "class": "@exclude",
+ "opcode": 5850,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'B'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M2'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatGEINTEL",
+ "class": "@exclude",
+ "opcode": 5851,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'B'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M2'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatLTINTEL",
+ "class": "@exclude",
+ "opcode": 5852,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'B'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M2'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatLEINTEL",
+ "class": "@exclude",
+ "opcode": 5853,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'B'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M2'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatEQINTEL",
+ "class": "@exclude",
+ "opcode": 5854,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'B'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M2'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatRecipINTEL",
+ "class": "@exclude",
+ "opcode": 5855,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatRSqrtINTEL",
+ "class": "@exclude",
+ "opcode": 5856,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatCbrtINTEL",
+ "class": "@exclude",
+ "opcode": 5857,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatHypotINTEL",
+ "class": "@exclude",
+ "opcode": 5858,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'B'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M2'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatSqrtINTEL",
+ "class": "@exclude",
+ "opcode": 5859,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatLogINTEL",
+ "class": "@exclude",
+ "opcode": 5860,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatLog2INTEL",
+ "class": "@exclude",
+ "opcode": 5861,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatLog10INTEL",
+ "class": "@exclude",
+ "opcode": 5862,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatLog1pINTEL",
+ "class": "@exclude",
+ "opcode": 5863,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatExpINTEL",
+ "class": "@exclude",
+ "opcode": 5864,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatExp2INTEL",
+ "class": "@exclude",
+ "opcode": 5865,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatExp10INTEL",
+ "class": "@exclude",
+ "opcode": 5866,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatExpm1INTEL",
+ "class": "@exclude",
+ "opcode": 5867,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatSinINTEL",
+ "class": "@exclude",
+ "opcode": 5868,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatCosINTEL",
+ "class": "@exclude",
+ "opcode": 5869,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatSinCosINTEL",
+ "class": "@exclude",
+ "opcode": 5870,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatSinPiINTEL",
+ "class": "@exclude",
+ "opcode": 5871,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatCosPiINTEL",
+ "class": "@exclude",
+ "opcode": 5872,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatASinINTEL",
+ "class": "@exclude",
+ "opcode": 5873,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatASinPiINTEL",
+ "class": "@exclude",
+ "opcode": 5874,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatACosINTEL",
+ "class": "@exclude",
+ "opcode": 5875,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatACosPiINTEL",
+ "class": "@exclude",
+ "opcode": 5876,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatATanINTEL",
+ "class": "@exclude",
+ "opcode": 5877,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatATanPiINTEL",
+ "class": "@exclude",
+ "opcode": 5878,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatATan2INTEL",
+ "class": "@exclude",
+ "opcode": 5879,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'B'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M2'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatPowINTEL",
+ "class": "@exclude",
+ "opcode": 5880,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'B'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M2'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatPowRINTEL",
+ "class": "@exclude",
+ "opcode": 5881,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'B'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M2'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpArbitraryFloatPowNINTEL",
+ "class": "@exclude",
+ "opcode": 5882,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'A'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'M1'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'B'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Mout'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'EnableSubnormals'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingMode'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'RoundingAccuracy'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFloatingPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpLoopControlINTEL",
+ "class": "Reserved",
+ "opcode": 5887,
+ "operands": [
+ {
+ "kind": "LiteralInteger",
+ "quantifier": "*",
+ "name": "'Loop Control Parameters'"
+ }
+ ],
+ "capabilities": [
+ "UnstructuredLoopControlsINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_unstructured_loop_controls"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpFixedSqrtINTEL",
+ "class": "@exclude",
+ "opcode": 5923,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Input Type'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Input'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'S'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'I'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'rI'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Q'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'O'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFixedPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpFixedRecipINTEL",
+ "class": "@exclude",
+ "opcode": 5924,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Input Type'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Input'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'S'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'I'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'rI'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Q'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'O'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFixedPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpFixedRsqrtINTEL",
+ "class": "@exclude",
+ "opcode": 5925,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Input Type'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Input'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'S'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'I'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'rI'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Q'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'O'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFixedPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpFixedSinINTEL",
+ "class": "@exclude",
+ "opcode": 5926,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Input Type'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Input'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'S'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'I'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'rI'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Q'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'O'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFixedPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpFixedCosINTEL",
+ "class": "@exclude",
+ "opcode": 5927,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Input Type'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Input'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'S'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'I'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'rI'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Q'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'O'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFixedPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpFixedSinCosINTEL",
+ "class": "@exclude",
+ "opcode": 5928,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Input Type'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Input'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'S'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'I'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'rI'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Q'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'O'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFixedPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpFixedSinPiINTEL",
+ "class": "@exclude",
+ "opcode": 5929,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Input Type'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Input'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'S'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'I'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'rI'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Q'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'O'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFixedPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpFixedCosPiINTEL",
+ "class": "@exclude",
+ "opcode": 5930,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Input Type'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Input'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'S'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'I'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'rI'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Q'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'O'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFixedPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpFixedSinCosPiINTEL",
+ "class": "@exclude",
+ "opcode": 5931,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Input Type'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Input'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'S'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'I'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'rI'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Q'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'O'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFixedPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpFixedLogINTEL",
+ "class": "@exclude",
+ "opcode": 5932,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Input Type'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Input'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'S'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'I'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'rI'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Q'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'O'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFixedPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpFixedExpINTEL",
+ "class": "@exclude",
+ "opcode": 5933,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Input Type'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Input'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'S'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'I'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'rI'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'Q'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'O'"
+ }
+ ],
+ "capabilities": [
+ "ArbitraryPrecisionFixedPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpPtrCastToCrossWorkgroupINTEL",
+ "class": "@exclude",
+ "opcode": 5934,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ }
+ ],
+ "capabilities": [
+ "USMStorageClassesINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpCrossWorkgroupCastToPtrINTEL",
+ "class": "@exclude",
+ "opcode": 5938,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ }
+ ],
+ "capabilities": [
+ "USMStorageClassesINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpReadPipeBlockingINTEL",
+ "class": "Pipe",
+ "opcode": 5946,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Size'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Alignment'"
+ }
+ ],
+ "capabilities": [
+ "BlockingPipesINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_blocking_pipes"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpWritePipeBlockingINTEL",
+ "class": "Pipe",
+ "opcode": 5947,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Size'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Packet Alignment'"
+ }
+ ],
+ "capabilities": [
+ "BlockingPipesINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_blocking_pipes"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpFPGARegINTEL",
+ "class": "Reserved",
+ "opcode": 5949,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Result'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Input'"
+ }
+ ],
+ "capabilities": [
+ "FPGARegINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_fpga_reg"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpRayQueryGetRayTMinKHR",
+ "class": "Reserved",
+ "opcode": 6016,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'RayQuery'"
+ }
+ ],
+ "capabilities": [
+ "RayQueryKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_query"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpRayQueryGetRayFlagsKHR",
+ "class": "Reserved",
+ "opcode": 6017,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'RayQuery'"
+ }
+ ],
+ "capabilities": [
+ "RayQueryKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_query"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpRayQueryGetIntersectionTKHR",
+ "class": "Reserved",
+ "opcode": 6018,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'RayQuery'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Intersection'"
+ }
+ ],
+ "capabilities": [
+ "RayQueryKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_query"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpRayQueryGetIntersectionInstanceCustomIndexKHR",
+ "class": "Reserved",
+ "opcode": 6019,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'RayQuery'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Intersection'"
+ }
+ ],
+ "capabilities": [
+ "RayQueryKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_query"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpRayQueryGetIntersectionInstanceIdKHR",
+ "class": "Reserved",
+ "opcode": 6020,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'RayQuery'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Intersection'"
+ }
+ ],
+ "capabilities": [
+ "RayQueryKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_query"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR",
+ "class": "Reserved",
+ "opcode": 6021,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'RayQuery'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Intersection'"
+ }
+ ],
+ "capabilities": [
+ "RayQueryKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_query"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpRayQueryGetIntersectionGeometryIndexKHR",
+ "class": "Reserved",
+ "opcode": 6022,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'RayQuery'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Intersection'"
+ }
+ ],
+ "capabilities": [
+ "RayQueryKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_query"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpRayQueryGetIntersectionPrimitiveIndexKHR",
+ "class": "Reserved",
+ "opcode": 6023,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'RayQuery'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Intersection'"
+ }
+ ],
+ "capabilities": [
+ "RayQueryKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_query"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpRayQueryGetIntersectionBarycentricsKHR",
+ "class": "Reserved",
+ "opcode": 6024,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'RayQuery'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Intersection'"
+ }
+ ],
+ "capabilities": [
+ "RayQueryKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_query"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpRayQueryGetIntersectionFrontFaceKHR",
+ "class": "Reserved",
+ "opcode": 6025,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'RayQuery'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Intersection'"
+ }
+ ],
+ "capabilities": [
+ "RayQueryKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_query"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpRayQueryGetIntersectionCandidateAABBOpaqueKHR",
+ "class": "Reserved",
+ "opcode": 6026,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'RayQuery'"
+ }
+ ],
+ "capabilities": [
+ "RayQueryKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_query"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpRayQueryGetIntersectionObjectRayDirectionKHR",
+ "class": "Reserved",
+ "opcode": 6027,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'RayQuery'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Intersection'"
+ }
+ ],
+ "capabilities": [
+ "RayQueryKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_query"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpRayQueryGetIntersectionObjectRayOriginKHR",
+ "class": "Reserved",
+ "opcode": 6028,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'RayQuery'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Intersection'"
+ }
+ ],
+ "capabilities": [
+ "RayQueryKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_query"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpRayQueryGetWorldRayDirectionKHR",
+ "class": "Reserved",
+ "opcode": 6029,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'RayQuery'"
+ }
+ ],
+ "capabilities": [
+ "RayQueryKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_query"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpRayQueryGetWorldRayOriginKHR",
+ "class": "Reserved",
+ "opcode": 6030,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'RayQuery'"
+ }
+ ],
+ "capabilities": [
+ "RayQueryKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_query"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpRayQueryGetIntersectionObjectToWorldKHR",
+ "class": "Reserved",
+ "opcode": 6031,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'RayQuery'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Intersection'"
+ }
+ ],
+ "capabilities": [
+ "RayQueryKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_query"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpRayQueryGetIntersectionWorldToObjectKHR",
+ "class": "Reserved",
+ "opcode": 6032,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'RayQuery'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Intersection'"
+ }
+ ],
+ "capabilities": [
+ "RayQueryKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_query"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpAtomicFAddEXT",
+ "class": "Atomic",
+ "opcode": 6035,
+ "operands": [
+ {
+ "kind": "IdResultType"
+ },
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Pointer'"
+ },
+ {
+ "kind": "IdScope",
+ "name": "'Memory'"
+ },
+ {
+ "kind": "IdMemorySemantics",
+ "name": "'Semantics'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'Value'"
+ }
+ ],
+ "capabilities": [
+ "AtomicFloat16AddEXT",
+ "AtomicFloat32AddEXT",
+ "AtomicFloat64AddEXT"
+ ],
+ "extensions": [
+ "SPV_EXT_shader_atomic_float_add"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpTypeBufferSurfaceINTEL",
+ "class": "Type-Declaration",
+ "opcode": 6086,
+ "operands": [
+ {
+ "kind": "IdResult"
+ },
+ {
+ "kind": "AccessQualifier",
+ "name": "'AccessQualifier'"
+ }
+ ],
+ "capabilities": [
+ "VectorComputeINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpTypeStructContinuedINTEL",
+ "class": "Type-Declaration",
+ "opcode": 6090,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "quantifier": "*",
+ "name": "'Member 0 type', +\n'member 1 type', +\n..."
+ }
+ ],
+ "capabilities": [
+ "LongConstantCompositeINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpConstantCompositeContinuedINTEL",
+ "class": "Constant-Creation",
+ "opcode": 6091,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "quantifier": "*",
+ "name": "'Constituents'"
+ }
+ ],
+ "capabilities": [
+ "LongConstantCompositeINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "opname": "OpSpecConstantCompositeContinuedINTEL",
+ "class": "Constant-Creation",
+ "opcode": 6092,
+ "operands": [
+ {
+ "kind": "IdRef",
+ "quantifier": "*",
+ "name": "'Constituents'"
+ }
+ ],
+ "capabilities": [
+ "LongConstantCompositeINTEL"
+ ],
+ "version": "None"
+ }
+ ],
+ "operand_kinds": [
+ {
+ "category": "BitEnum",
+ "kind": "ImageOperands",
+ "enumerants": [
+ {
+ "enumerant": "None",
+ "value": "0x0000"
+ },
+ {
+ "enumerant": "Bias",
+ "value": "0x0001",
+ "capabilities": [
+ "Shader"
+ ],
+ "parameters": [
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ {
+ "enumerant": "Lod",
+ "value": "0x0002",
+ "parameters": [
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ {
+ "enumerant": "Grad",
+ "value": "0x0004",
+ "parameters": [
+ {
+ "kind": "IdRef"
+ },
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ {
+ "enumerant": "ConstOffset",
+ "value": "0x0008",
+ "parameters": [
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ {
+ "enumerant": "Offset",
+ "value": "0x0010",
+ "capabilities": [
+ "ImageGatherExtended"
+ ],
+ "parameters": [
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ {
+ "enumerant": "ConstOffsets",
+ "value": "0x0020",
+ "capabilities": [
+ "ImageGatherExtended"
+ ],
+ "parameters": [
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ {
+ "enumerant": "Sample",
+ "value": "0x0040",
+ "parameters": [
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ {
+ "enumerant": "MinLod",
+ "value": "0x0080",
+ "capabilities": [
+ "MinLod"
+ ],
+ "parameters": [
+ {
+ "kind": "IdRef"
+ }
+ ]
+ },
+ {
+ "enumerant": "MakeTexelAvailable",
+ "value": "0x0100",
+ "capabilities": [
+ "VulkanMemoryModel"
+ ],
+ "parameters": [
+ {
+ "kind": "IdScope"
+ }
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "MakeTexelAvailableKHR",
+ "value": "0x0100",
+ "capabilities": [
+ "VulkanMemoryModel"
+ ],
+ "parameters": [
+ {
+ "kind": "IdScope"
+ }
+ ],
+ "extensions": [
+ "SPV_KHR_vulkan_memory_model"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "MakeTexelVisible",
+ "value": "0x0200",
+ "capabilities": [
+ "VulkanMemoryModel"
+ ],
+ "parameters": [
+ {
+ "kind": "IdScope"
+ }
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "MakeTexelVisibleKHR",
+ "value": "0x0200",
+ "capabilities": [
+ "VulkanMemoryModel"
+ ],
+ "parameters": [
+ {
+ "kind": "IdScope"
+ }
+ ],
+ "extensions": [
+ "SPV_KHR_vulkan_memory_model"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "NonPrivateTexel",
+ "value": "0x0400",
+ "capabilities": [
+ "VulkanMemoryModel"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "NonPrivateTexelKHR",
+ "value": "0x0400",
+ "capabilities": [
+ "VulkanMemoryModel"
+ ],
+ "extensions": [
+ "SPV_KHR_vulkan_memory_model"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "VolatileTexel",
+ "value": "0x0800",
+ "capabilities": [
+ "VulkanMemoryModel"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "VolatileTexelKHR",
+ "value": "0x0800",
+ "capabilities": [
+ "VulkanMemoryModel"
+ ],
+ "extensions": [
+ "SPV_KHR_vulkan_memory_model"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "SignExtend",
+ "value": "0x1000",
+ "version": "1.4"
+ },
+ {
+ "enumerant": "ZeroExtend",
+ "value": "0x2000",
+ "version": "1.4"
+ },
+ {
+ "enumerant": "Nontemporal",
+ "value": "0x4000",
+ "version": "1.6"
+ },
+ {
+ "enumerant": "Offsets",
+ "value": "0x10000",
+ "parameters": [
+ {
+ "kind": "IdRef"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "category": "BitEnum",
+ "kind": "FPFastMathMode",
+ "enumerants": [
+ {
+ "enumerant": "None",
+ "value": "0x0000"
+ },
+ {
+ "enumerant": "NotNaN",
+ "value": "0x0001"
+ },
+ {
+ "enumerant": "NotInf",
+ "value": "0x0002"
+ },
+ {
+ "enumerant": "NSZ",
+ "value": "0x0004"
+ },
+ {
+ "enumerant": "AllowRecip",
+ "value": "0x0008"
+ },
+ {
+ "enumerant": "Fast",
+ "value": "0x0010"
+ },
+ {
+ "enumerant": "AllowContractFastINTEL",
+ "value": "0x10000",
+ "capabilities": [
+ "FPFastMathModeINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "AllowReassocINTEL",
+ "value": "0x20000",
+ "capabilities": [
+ "FPFastMathModeINTEL"
+ ],
+ "version": "None"
+ }
+ ]
+ },
+ {
+ "category": "BitEnum",
+ "kind": "SelectionControl",
+ "enumerants": [
+ {
+ "enumerant": "None",
+ "value": "0x0000"
+ },
+ {
+ "enumerant": "Flatten",
+ "value": "0x0001"
+ },
+ {
+ "enumerant": "DontFlatten",
+ "value": "0x0002"
+ }
+ ]
+ },
+ {
+ "category": "BitEnum",
+ "kind": "LoopControl",
+ "enumerants": [
+ {
+ "enumerant": "None",
+ "value": "0x0000"
+ },
+ {
+ "enumerant": "Unroll",
+ "value": "0x0001"
+ },
+ {
+ "enumerant": "DontUnroll",
+ "value": "0x0002"
+ },
+ {
+ "enumerant": "DependencyInfinite",
+ "value": "0x0004",
+ "version": "1.1"
+ },
+ {
+ "enumerant": "DependencyLength",
+ "value": "0x0008",
+ "parameters": [
+ {
+ "kind": "LiteralInteger"
+ }
+ ],
+ "version": "1.1"
+ },
+ {
+ "enumerant": "MinIterations",
+ "value": "0x0010",
+ "parameters": [
+ {
+ "kind": "LiteralInteger"
+ }
+ ],
+ "version": "1.4"
+ },
+ {
+ "enumerant": "MaxIterations",
+ "value": "0x0020",
+ "parameters": [
+ {
+ "kind": "LiteralInteger"
+ }
+ ],
+ "version": "1.4"
+ },
+ {
+ "enumerant": "IterationMultiple",
+ "value": "0x0040",
+ "parameters": [
+ {
+ "kind": "LiteralInteger"
+ }
+ ],
+ "version": "1.4"
+ },
+ {
+ "enumerant": "PeelCount",
+ "value": "0x0080",
+ "parameters": [
+ {
+ "kind": "LiteralInteger"
+ }
+ ],
+ "version": "1.4"
+ },
+ {
+ "enumerant": "PartialCount",
+ "value": "0x0100",
+ "parameters": [
+ {
+ "kind": "LiteralInteger"
+ }
+ ],
+ "version": "1.4"
+ },
+ {
+ "enumerant": "InitiationIntervalINTEL",
+ "value": "0x10000",
+ "parameters": [
+ {
+ "kind": "LiteralInteger"
+ }
+ ],
+ "capabilities": [
+ "FPGALoopControlsINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_fpga_loop_controls"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "MaxConcurrencyINTEL",
+ "value": "0x20000",
+ "parameters": [
+ {
+ "kind": "LiteralInteger"
+ }
+ ],
+ "capabilities": [
+ "FPGALoopControlsINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_fpga_loop_controls"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "DependencyArrayINTEL",
+ "value": "0x40000",
+ "parameters": [
+ {
+ "kind": "LiteralInteger"
+ }
+ ],
+ "capabilities": [
+ "FPGALoopControlsINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_fpga_loop_controls"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "PipelineEnableINTEL",
+ "value": "0x80000",
+ "parameters": [
+ {
+ "kind": "LiteralInteger"
+ }
+ ],
+ "capabilities": [
+ "FPGALoopControlsINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_fpga_loop_controls"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "LoopCoalesceINTEL",
+ "value": "0x100000",
+ "parameters": [
+ {
+ "kind": "LiteralInteger"
+ }
+ ],
+ "capabilities": [
+ "FPGALoopControlsINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_fpga_loop_controls"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "MaxInterleavingINTEL",
+ "value": "0x200000",
+ "parameters": [
+ {
+ "kind": "LiteralInteger"
+ }
+ ],
+ "capabilities": [
+ "FPGALoopControlsINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_fpga_loop_controls"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SpeculatedIterationsINTEL",
+ "value": "0x400000",
+ "parameters": [
+ {
+ "kind": "LiteralInteger"
+ }
+ ],
+ "capabilities": [
+ "FPGALoopControlsINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_fpga_loop_controls"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "NoFusionINTEL",
+ "value": "0x800000",
+ "parameters": [
+ {
+ "kind": "LiteralInteger"
+ }
+ ],
+ "capabilities": [
+ "FPGALoopControlsINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_fpga_loop_controls"
+ ],
+ "version": "None"
+ }
+ ]
+ },
+ {
+ "category": "BitEnum",
+ "kind": "FunctionControl",
+ "enumerants": [
+ {
+ "enumerant": "None",
+ "value": "0x0000"
+ },
+ {
+ "enumerant": "Inline",
+ "value": "0x0001"
+ },
+ {
+ "enumerant": "DontInline",
+ "value": "0x0002"
+ },
+ {
+ "enumerant": "Pure",
+ "value": "0x0004"
+ },
+ {
+ "enumerant": "Const",
+ "value": "0x0008"
+ },
+ {
+ "enumerant": "OptNoneINTEL",
+ "value": "0x10000",
+ "capabilities": [
+ "OptNoneINTEL"
+ ],
+ "version": "None"
+ }
+ ]
+ },
+ {
+ "category": "BitEnum",
+ "kind": "MemorySemantics",
+ "enumerants": [
+ {
+ "enumerant": "Relaxed",
+ "value": "0x0000"
+ },
+ {
+ "enumerant": "None",
+ "value": "0x0000"
+ },
+ {
+ "enumerant": "Acquire",
+ "value": "0x0002"
+ },
+ {
+ "enumerant": "Release",
+ "value": "0x0004"
+ },
+ {
+ "enumerant": "AcquireRelease",
+ "value": "0x0008"
+ },
+ {
+ "enumerant": "SequentiallyConsistent",
+ "value": "0x0010"
+ },
+ {
+ "enumerant": "UniformMemory",
+ "value": "0x0040",
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "SubgroupMemory",
+ "value": "0x0080"
+ },
+ {
+ "enumerant": "WorkgroupMemory",
+ "value": "0x0100"
+ },
+ {
+ "enumerant": "CrossWorkgroupMemory",
+ "value": "0x0200"
+ },
+ {
+ "enumerant": "AtomicCounterMemory",
+ "value": "0x0400",
+ "capabilities": [
+ "AtomicStorage"
+ ]
+ },
+ {
+ "enumerant": "ImageMemory",
+ "value": "0x0800"
+ },
+ {
+ "enumerant": "OutputMemory",
+ "value": "0x1000",
+ "capabilities": [
+ "VulkanMemoryModel"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "OutputMemoryKHR",
+ "value": "0x1000",
+ "capabilities": [
+ "VulkanMemoryModel"
+ ],
+ "extensions": [
+ "SPV_KHR_vulkan_memory_model"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "MakeAvailable",
+ "value": "0x2000",
+ "capabilities": [
+ "VulkanMemoryModel"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "MakeAvailableKHR",
+ "value": "0x2000",
+ "capabilities": [
+ "VulkanMemoryModel"
+ ],
+ "extensions": [
+ "SPV_KHR_vulkan_memory_model"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "MakeVisible",
+ "value": "0x4000",
+ "capabilities": [
+ "VulkanMemoryModel"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "MakeVisibleKHR",
+ "value": "0x4000",
+ "capabilities": [
+ "VulkanMemoryModel"
+ ],
+ "extensions": [
+ "SPV_KHR_vulkan_memory_model"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "Volatile",
+ "value": "0x8000",
+ "capabilities": [
+ "VulkanMemoryModel"
+ ],
+ "extensions": [
+ "SPV_KHR_vulkan_memory_model"
+ ],
+ "version": "1.5"
+ }
+ ]
+ },
+ {
+ "category": "BitEnum",
+ "kind": "MemoryAccess",
+ "enumerants": [
+ {
+ "enumerant": "None",
+ "value": "0x0000"
+ },
+ {
+ "enumerant": "Volatile",
+ "value": "0x0001"
+ },
+ {
+ "enumerant": "Aligned",
+ "value": "0x0002",
+ "parameters": [
+ {
+ "kind": "LiteralInteger"
+ }
+ ]
+ },
+ {
+ "enumerant": "Nontemporal",
+ "value": "0x0004"
+ },
+ {
+ "enumerant": "MakePointerAvailable",
+ "value": "0x0008",
+ "parameters": [
+ {
+ "kind": "IdScope"
+ }
+ ],
+ "capabilities": [
+ "VulkanMemoryModel"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "MakePointerAvailableKHR",
+ "value": "0x0008",
+ "parameters": [
+ {
+ "kind": "IdScope"
+ }
+ ],
+ "capabilities": [
+ "VulkanMemoryModel"
+ ],
+ "extensions": [
+ "SPV_KHR_vulkan_memory_model"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "MakePointerVisible",
+ "value": "0x0010",
+ "parameters": [
+ {
+ "kind": "IdScope"
+ }
+ ],
+ "capabilities": [
+ "VulkanMemoryModel"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "MakePointerVisibleKHR",
+ "value": "0x0010",
+ "parameters": [
+ {
+ "kind": "IdScope"
+ }
+ ],
+ "capabilities": [
+ "VulkanMemoryModel"
+ ],
+ "extensions": [
+ "SPV_KHR_vulkan_memory_model"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "NonPrivatePointer",
+ "value": "0x0020",
+ "capabilities": [
+ "VulkanMemoryModel"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "NonPrivatePointerKHR",
+ "value": "0x0020",
+ "capabilities": [
+ "VulkanMemoryModel"
+ ],
+ "extensions": [
+ "SPV_KHR_vulkan_memory_model"
+ ],
+ "version": "1.5"
+ }
+ ]
+ },
+ {
+ "category": "BitEnum",
+ "kind": "KernelProfilingInfo",
+ "enumerants": [
+ {
+ "enumerant": "None",
+ "value": "0x0000"
+ },
+ {
+ "enumerant": "CmdExecTime",
+ "value": "0x0001",
+ "capabilities": [
+ "Kernel"
+ ]
+ }
+ ]
+ },
+ {
+ "category": "BitEnum",
+ "kind": "RayFlags",
+ "enumerants": [
+ {
+ "enumerant": "NoneKHR",
+ "value": "0x0000",
+ "capabilities": [
+ "RayQueryKHR",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "OpaqueKHR",
+ "value": "0x0001",
+ "capabilities": [
+ "RayQueryKHR",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "NoOpaqueKHR",
+ "value": "0x0002",
+ "capabilities": [
+ "RayQueryKHR",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "TerminateOnFirstHitKHR",
+ "value": "0x0004",
+ "capabilities": [
+ "RayQueryKHR",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SkipClosestHitShaderKHR",
+ "value": "0x0008",
+ "capabilities": [
+ "RayQueryKHR",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "CullBackFacingTrianglesKHR",
+ "value": "0x0010",
+ "capabilities": [
+ "RayQueryKHR",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "CullFrontFacingTrianglesKHR",
+ "value": "0x0020",
+ "capabilities": [
+ "RayQueryKHR",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "CullOpaqueKHR",
+ "value": "0x0040",
+ "capabilities": [
+ "RayQueryKHR",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "CullNoOpaqueKHR",
+ "value": "0x0080",
+ "capabilities": [
+ "RayQueryKHR",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SkipTrianglesKHR",
+ "value": "0x0100",
+ "capabilities": [
+ "RayTraversalPrimitiveCullingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SkipAABBsKHR",
+ "value": "0x0200",
+ "capabilities": [
+ "RayTraversalPrimitiveCullingKHR"
+ ],
+ "version": "None"
+ }
+ ]
+ },
+ {
+ "category": "BitEnum",
+ "kind": "FragmentShadingRate",
+ "enumerants": [
+ {
+ "enumerant": "Vertical2Pixels",
+ "value": "0x0001",
+ "capabilities": [
+ "FragmentShadingRateKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "Vertical4Pixels",
+ "value": "0x0002",
+ "capabilities": [
+ "FragmentShadingRateKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "Horizontal2Pixels",
+ "value": "0x0004",
+ "capabilities": [
+ "FragmentShadingRateKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "Horizontal4Pixels",
+ "value": "0x0008",
+ "capabilities": [
+ "FragmentShadingRateKHR"
+ ],
+ "version": "None"
+ }
+ ]
+ },
+ {
+ "category": "ValueEnum",
+ "kind": "SourceLanguage",
+ "enumerants": [
+ {
+ "enumerant": "Unknown",
+ "value": 0
+ },
+ {
+ "enumerant": "ESSL",
+ "value": 1
+ },
+ {
+ "enumerant": "GLSL",
+ "value": 2
+ },
+ {
+ "enumerant": "OpenCL_C",
+ "value": 3
+ },
+ {
+ "enumerant": "OpenCL_CPP",
+ "value": 4
+ },
+ {
+ "enumerant": "HLSL",
+ "value": 5
+ },
+ {
+ "enumerant": "CPP_for_OpenCL",
+ "value": 6
+ }
+ ]
+ },
+ {
+ "category": "ValueEnum",
+ "kind": "ExecutionModel",
+ "enumerants": [
+ {
+ "enumerant": "Vertex",
+ "value": 0,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "TessellationControl",
+ "value": 1,
+ "capabilities": [
+ "Tessellation"
+ ]
+ },
+ {
+ "enumerant": "TessellationEvaluation",
+ "value": 2,
+ "capabilities": [
+ "Tessellation"
+ ]
+ },
+ {
+ "enumerant": "Geometry",
+ "value": 3,
+ "capabilities": [
+ "Geometry"
+ ]
+ },
+ {
+ "enumerant": "Fragment",
+ "value": 4,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "GLCompute",
+ "value": 5,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "Kernel",
+ "value": 6,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "TaskNV",
+ "value": 5267,
+ "capabilities": [
+ "MeshShadingNV"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "MeshNV",
+ "value": 5268,
+ "capabilities": [
+ "MeshShadingNV"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "RayGenerationNV",
+ "value": 5313,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "RayGenerationKHR",
+ "value": 5313,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "IntersectionNV",
+ "value": 5314,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "IntersectionKHR",
+ "value": 5314,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "AnyHitNV",
+ "value": 5315,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "AnyHitKHR",
+ "value": 5315,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ClosestHitNV",
+ "value": 5316,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ClosestHitKHR",
+ "value": 5316,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "MissNV",
+ "value": 5317,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "MissKHR",
+ "value": 5317,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "CallableNV",
+ "value": 5318,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "CallableKHR",
+ "value": 5318,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ }
+ ]
+ },
+ {
+ "category": "ValueEnum",
+ "kind": "AddressingModel",
+ "enumerants": [
+ {
+ "enumerant": "Logical",
+ "value": 0
+ },
+ {
+ "enumerant": "Physical32",
+ "value": 1,
+ "capabilities": [
+ "Addresses"
+ ]
+ },
+ {
+ "enumerant": "Physical64",
+ "value": 2,
+ "capabilities": [
+ "Addresses"
+ ]
+ },
+ {
+ "enumerant": "PhysicalStorageBuffer64",
+ "value": 5348,
+ "extensions": [
+ "SPV_EXT_physical_storage_buffer",
+ "SPV_KHR_physical_storage_buffer"
+ ],
+ "capabilities": [
+ "PhysicalStorageBufferAddresses"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "PhysicalStorageBuffer64EXT",
+ "value": 5348,
+ "extensions": [
+ "SPV_EXT_physical_storage_buffer"
+ ],
+ "capabilities": [
+ "PhysicalStorageBufferAddresses"
+ ],
+ "version": "1.5"
+ }
+ ]
+ },
+ {
+ "category": "ValueEnum",
+ "kind": "MemoryModel",
+ "enumerants": [
+ {
+ "enumerant": "Simple",
+ "value": 0,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "GLSL450",
+ "value": 1,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "OpenCL",
+ "value": 2,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "Vulkan",
+ "value": 3,
+ "capabilities": [
+ "VulkanMemoryModel"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "VulkanKHR",
+ "value": 3,
+ "capabilities": [
+ "VulkanMemoryModel"
+ ],
+ "extensions": [
+ "SPV_KHR_vulkan_memory_model"
+ ],
+ "version": "1.5"
+ }
+ ]
+ },
+ {
+ "category": "ValueEnum",
+ "kind": "ExecutionMode",
+ "enumerants": [
+ {
+ "enumerant": "Invocations",
+ "value": 0,
+ "capabilities": [
+ "Geometry"
+ ],
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Number of <<Invocation,invocations>>'"
+ }
+ ]
+ },
+ {
+ "enumerant": "SpacingEqual",
+ "value": 1,
+ "capabilities": [
+ "Tessellation"
+ ]
+ },
+ {
+ "enumerant": "SpacingFractionalEven",
+ "value": 2,
+ "capabilities": [
+ "Tessellation"
+ ]
+ },
+ {
+ "enumerant": "SpacingFractionalOdd",
+ "value": 3,
+ "capabilities": [
+ "Tessellation"
+ ]
+ },
+ {
+ "enumerant": "VertexOrderCw",
+ "value": 4,
+ "capabilities": [
+ "Tessellation"
+ ]
+ },
+ {
+ "enumerant": "VertexOrderCcw",
+ "value": 5,
+ "capabilities": [
+ "Tessellation"
+ ]
+ },
+ {
+ "enumerant": "PixelCenterInteger",
+ "value": 6,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "OriginUpperLeft",
+ "value": 7,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "OriginLowerLeft",
+ "value": 8,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "EarlyFragmentTests",
+ "value": 9,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "PointMode",
+ "value": 10,
+ "capabilities": [
+ "Tessellation"
+ ]
+ },
+ {
+ "enumerant": "Xfb",
+ "value": 11,
+ "capabilities": [
+ "TransformFeedback"
+ ]
+ },
+ {
+ "enumerant": "DepthReplacing",
+ "value": 12,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "DepthGreater",
+ "value": 14,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "DepthLess",
+ "value": 15,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "DepthUnchanged",
+ "value": 16,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "LocalSize",
+ "value": 17,
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'x size'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'y size'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'z size'"
+ }
+ ]
+ },
+ {
+ "enumerant": "LocalSizeHint",
+ "value": 18,
+ "capabilities": [
+ "Kernel"
+ ],
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'x size'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'y size'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'z size'"
+ }
+ ]
+ },
+ {
+ "enumerant": "InputPoints",
+ "value": 19,
+ "capabilities": [
+ "Geometry"
+ ]
+ },
+ {
+ "enumerant": "InputLines",
+ "value": 20,
+ "capabilities": [
+ "Geometry"
+ ]
+ },
+ {
+ "enumerant": "InputLinesAdjacency",
+ "value": 21,
+ "capabilities": [
+ "Geometry"
+ ]
+ },
+ {
+ "enumerant": "Triangles",
+ "value": 22,
+ "capabilities": [
+ "Geometry",
+ "Tessellation"
+ ]
+ },
+ {
+ "enumerant": "InputTrianglesAdjacency",
+ "value": 23,
+ "capabilities": [
+ "Geometry"
+ ]
+ },
+ {
+ "enumerant": "Quads",
+ "value": 24,
+ "capabilities": [
+ "Tessellation"
+ ]
+ },
+ {
+ "enumerant": "Isolines",
+ "value": 25,
+ "capabilities": [
+ "Tessellation"
+ ]
+ },
+ {
+ "enumerant": "OutputVertices",
+ "value": 26,
+ "capabilities": [
+ "Geometry",
+ "Tessellation",
+ "MeshShadingNV"
+ ],
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Vertex count'"
+ }
+ ]
+ },
+ {
+ "enumerant": "OutputPoints",
+ "value": 27,
+ "capabilities": [
+ "Geometry",
+ "MeshShadingNV"
+ ]
+ },
+ {
+ "enumerant": "OutputLineStrip",
+ "value": 28,
+ "capabilities": [
+ "Geometry"
+ ]
+ },
+ {
+ "enumerant": "OutputTriangleStrip",
+ "value": 29,
+ "capabilities": [
+ "Geometry"
+ ]
+ },
+ {
+ "enumerant": "VecTypeHint",
+ "value": 30,
+ "capabilities": [
+ "Kernel"
+ ],
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Vector type'"
+ }
+ ]
+ },
+ {
+ "enumerant": "ContractionOff",
+ "value": 31,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "Initializer",
+ "value": 33,
+ "capabilities": [
+ "Kernel"
+ ],
+ "version": "1.1"
+ },
+ {
+ "enumerant": "Finalizer",
+ "value": 34,
+ "capabilities": [
+ "Kernel"
+ ],
+ "version": "1.1"
+ },
+ {
+ "enumerant": "SubgroupSize",
+ "value": 35,
+ "capabilities": [
+ "SubgroupDispatch"
+ ],
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Subgroup Size'"
+ }
+ ],
+ "version": "1.1"
+ },
+ {
+ "enumerant": "SubgroupsPerWorkgroup",
+ "value": 36,
+ "capabilities": [
+ "SubgroupDispatch"
+ ],
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Subgroups Per Workgroup'"
+ }
+ ],
+ "version": "1.1"
+ },
+ {
+ "enumerant": "SubgroupsPerWorkgroupId",
+ "value": 37,
+ "capabilities": [
+ "SubgroupDispatch"
+ ],
+ "parameters": [
+ {
+ "kind": "IdRef",
+ "name": "'Subgroups Per Workgroup'"
+ }
+ ],
+ "version": "1.2"
+ },
+ {
+ "enumerant": "LocalSizeId",
+ "value": 38,
+ "parameters": [
+ {
+ "kind": "IdRef",
+ "name": "'x size'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'y size'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'z size'"
+ }
+ ],
+ "version": "1.2"
+ },
+ {
+ "enumerant": "LocalSizeHintId",
+ "value": 39,
+ "capabilities": [
+ "Kernel"
+ ],
+ "parameters": [
+ {
+ "kind": "IdRef",
+ "name": "'x size hint'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'y size hint'"
+ },
+ {
+ "kind": "IdRef",
+ "name": "'z size hint'"
+ }
+ ],
+ "version": "1.2"
+ },
+ {
+ "enumerant": "SubgroupUniformControlFlowKHR",
+ "value": 4421,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_KHR_subgroup_uniform_control_flow"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "PostDepthCoverage",
+ "value": 4446,
+ "capabilities": [
+ "SampleMaskPostDepthCoverage"
+ ],
+ "extensions": [
+ "SPV_KHR_post_depth_coverage"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "DenormPreserve",
+ "value": 4459,
+ "capabilities": [
+ "DenormPreserve"
+ ],
+ "extensions": [
+ "SPV_KHR_float_controls"
+ ],
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Target Width'"
+ }
+ ],
+ "version": "1.4"
+ },
+ {
+ "enumerant": "DenormFlushToZero",
+ "value": 4460,
+ "capabilities": [
+ "DenormFlushToZero"
+ ],
+ "extensions": [
+ "SPV_KHR_float_controls"
+ ],
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Target Width'"
+ }
+ ],
+ "version": "1.4"
+ },
+ {
+ "enumerant": "SignedZeroInfNanPreserve",
+ "value": 4461,
+ "capabilities": [
+ "SignedZeroInfNanPreserve"
+ ],
+ "extensions": [
+ "SPV_KHR_float_controls"
+ ],
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Target Width'"
+ }
+ ],
+ "version": "1.4"
+ },
+ {
+ "enumerant": "RoundingModeRTE",
+ "value": 4462,
+ "capabilities": [
+ "RoundingModeRTE"
+ ],
+ "extensions": [
+ "SPV_KHR_float_controls"
+ ],
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Target Width'"
+ }
+ ],
+ "version": "1.4"
+ },
+ {
+ "enumerant": "RoundingModeRTZ",
+ "value": 4463,
+ "capabilities": [
+ "RoundingModeRTZ"
+ ],
+ "extensions": [
+ "SPV_KHR_float_controls"
+ ],
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Target Width'"
+ }
+ ],
+ "version": "1.4"
+ },
+ {
+ "enumerant": "StencilRefReplacingEXT",
+ "value": 5027,
+ "capabilities": [
+ "StencilExportEXT"
+ ],
+ "extensions": [
+ "SPV_EXT_shader_stencil_export"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "OutputLinesNV",
+ "value": 5269,
+ "capabilities": [
+ "MeshShadingNV"
+ ],
+ "extensions": [
+ "SPV_NV_mesh_shader"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "OutputPrimitivesNV",
+ "value": 5270,
+ "capabilities": [
+ "MeshShadingNV"
+ ],
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Primitive count'"
+ }
+ ],
+ "extensions": [
+ "SPV_NV_mesh_shader"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "DerivativeGroupQuadsNV",
+ "value": 5289,
+ "capabilities": [
+ "ComputeDerivativeGroupQuadsNV"
+ ],
+ "extensions": [
+ "SPV_NV_compute_shader_derivatives"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "DerivativeGroupLinearNV",
+ "value": 5290,
+ "capabilities": [
+ "ComputeDerivativeGroupLinearNV"
+ ],
+ "extensions": [
+ "SPV_NV_compute_shader_derivatives"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "OutputTrianglesNV",
+ "value": 5298,
+ "capabilities": [
+ "MeshShadingNV"
+ ],
+ "extensions": [
+ "SPV_NV_mesh_shader"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "PixelInterlockOrderedEXT",
+ "value": 5366,
+ "capabilities": [
+ "FragmentShaderPixelInterlockEXT"
+ ],
+ "extensions": [
+ "SPV_EXT_fragment_shader_interlock"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "PixelInterlockUnorderedEXT",
+ "value": 5367,
+ "capabilities": [
+ "FragmentShaderPixelInterlockEXT"
+ ],
+ "extensions": [
+ "SPV_EXT_fragment_shader_interlock"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SampleInterlockOrderedEXT",
+ "value": 5368,
+ "capabilities": [
+ "FragmentShaderSampleInterlockEXT"
+ ],
+ "extensions": [
+ "SPV_EXT_fragment_shader_interlock"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SampleInterlockUnorderedEXT",
+ "value": 5369,
+ "capabilities": [
+ "FragmentShaderSampleInterlockEXT"
+ ],
+ "extensions": [
+ "SPV_EXT_fragment_shader_interlock"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ShadingRateInterlockOrderedEXT",
+ "value": 5370,
+ "capabilities": [
+ "FragmentShaderShadingRateInterlockEXT"
+ ],
+ "extensions": [
+ "SPV_EXT_fragment_shader_interlock"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ShadingRateInterlockUnorderedEXT",
+ "value": 5371,
+ "capabilities": [
+ "FragmentShaderShadingRateInterlockEXT"
+ ],
+ "extensions": [
+ "SPV_EXT_fragment_shader_interlock"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SharedLocalMemorySizeINTEL",
+ "value": 5618,
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Size'"
+ }
+ ],
+ "capabilities": [
+ "VectorComputeINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "RoundingModeRTPINTEL",
+ "value": 5620,
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Target Width'"
+ }
+ ],
+ "capabilities": [
+ "RoundToInfinityINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "RoundingModeRTNINTEL",
+ "value": 5621,
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Target Width'"
+ }
+ ],
+ "capabilities": [
+ "RoundToInfinityINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FloatingPointModeALTINTEL",
+ "value": 5622,
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Target Width'"
+ }
+ ],
+ "capabilities": [
+ "RoundToInfinityINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FloatingPointModeIEEEINTEL",
+ "value": 5623,
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Target Width'"
+ }
+ ],
+ "capabilities": [
+ "RoundToInfinityINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "MaxWorkgroupSizeINTEL",
+ "value": 5893,
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'max_x_size'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'max_y_size'"
+ },
+ {
+ "kind": "LiteralInteger",
+ "name": "'max_z_size'"
+ }
+ ],
+ "capabilities": [
+ "KernelAttributesINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_kernel_attributes"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "MaxWorkDimINTEL",
+ "value": 5894,
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'max_dimensions'"
+ }
+ ],
+ "capabilities": [
+ "KernelAttributesINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_kernel_attributes"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "NoGlobalOffsetINTEL",
+ "value": 5895,
+ "capabilities": [
+ "KernelAttributesINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_kernel_attributes"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "NumSIMDWorkitemsINTEL",
+ "value": 5896,
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'vector_width'"
+ }
+ ],
+ "capabilities": [
+ "FPGAKernelAttributesINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_kernel_attributes"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SchedulerTargetFmaxMhzINTEL",
+ "value": 5903,
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'target_fmax'"
+ }
+ ],
+ "capabilities": [
+ "FPGAKernelAttributesINTEL"
+ ],
+ "version": "None"
+ }
+ ]
+ },
+ {
+ "category": "ValueEnum",
+ "kind": "StorageClass",
+ "enumerants": [
+ {
+ "enumerant": "UniformConstant",
+ "value": 0
+ },
+ {
+ "enumerant": "Input",
+ "value": 1
+ },
+ {
+ "enumerant": "Uniform",
+ "value": 2,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "Output",
+ "value": 3,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "Workgroup",
+ "value": 4
+ },
+ {
+ "enumerant": "CrossWorkgroup",
+ "value": 5
+ },
+ {
+ "enumerant": "Private",
+ "value": 6,
+ "capabilities": [
+ "Shader",
+ "VectorComputeINTEL"
+ ]
+ },
+ {
+ "enumerant": "Function",
+ "value": 7
+ },
+ {
+ "enumerant": "Generic",
+ "value": 8,
+ "capabilities": [
+ "GenericPointer"
+ ]
+ },
+ {
+ "enumerant": "PushConstant",
+ "value": 9,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "AtomicCounter",
+ "value": 10,
+ "capabilities": [
+ "AtomicStorage"
+ ]
+ },
+ {
+ "enumerant": "Image",
+ "value": 11
+ },
+ {
+ "enumerant": "StorageBuffer",
+ "value": 12,
+ "extensions": [
+ "SPV_KHR_storage_buffer_storage_class",
+ "SPV_KHR_variable_pointers"
+ ],
+ "capabilities": [
+ "Shader"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "CallableDataNV",
+ "value": 5328,
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "CallableDataKHR",
+ "value": 5328,
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "IncomingCallableDataNV",
+ "value": 5329,
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "IncomingCallableDataKHR",
+ "value": 5329,
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "RayPayloadNV",
+ "value": 5338,
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "RayPayloadKHR",
+ "value": 5338,
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "HitAttributeNV",
+ "value": 5339,
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "HitAttributeKHR",
+ "value": 5339,
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "IncomingRayPayloadNV",
+ "value": 5342,
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "IncomingRayPayloadKHR",
+ "value": 5342,
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ShaderRecordBufferNV",
+ "value": 5343,
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ShaderRecordBufferKHR",
+ "value": 5343,
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "PhysicalStorageBuffer",
+ "value": 5349,
+ "extensions": [
+ "SPV_EXT_physical_storage_buffer",
+ "SPV_KHR_physical_storage_buffer"
+ ],
+ "capabilities": [
+ "PhysicalStorageBufferAddresses"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "PhysicalStorageBufferEXT",
+ "value": 5349,
+ "extensions": [
+ "SPV_EXT_physical_storage_buffer"
+ ],
+ "capabilities": [
+ "PhysicalStorageBufferAddresses"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "CodeSectionINTEL",
+ "value": 5605,
+ "extensions": [
+ "SPV_INTEL_function_pointers"
+ ],
+ "capabilities": [
+ "FunctionPointersINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "DeviceOnlyINTEL",
+ "value": 5936,
+ "extensions": [
+ "SPV_INTEL_usm_storage_classes"
+ ],
+ "capabilities": [
+ "USMStorageClassesINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "HostOnlyINTEL",
+ "value": 5937,
+ "extensions": [
+ "SPV_INTEL_usm_storage_classes"
+ ],
+ "capabilities": [
+ "USMStorageClassesINTEL"
+ ],
+ "version": "None"
+ }
+ ]
+ },
+ {
+ "category": "ValueEnum",
+ "kind": "Dim",
+ "enumerants": [
+ {
+ "enumerant": "1D",
+ "value": 0,
+ "capabilities": [
+ "Sampled1D",
+ "Image1D"
+ ]
+ },
+ {
+ "enumerant": "2D",
+ "value": 1,
+ "capabilities": [
+ "Shader",
+ "Kernel",
+ "ImageMSArray"
+ ]
+ },
+ {
+ "enumerant": "3D",
+ "value": 2
+ },
+ {
+ "enumerant": "Cube",
+ "value": 3,
+ "capabilities": [
+ "Shader",
+ "ImageCubeArray"
+ ]
+ },
+ {
+ "enumerant": "Rect",
+ "value": 4,
+ "capabilities": [
+ "SampledRect",
+ "ImageRect"
+ ]
+ },
+ {
+ "enumerant": "Buffer",
+ "value": 5,
+ "capabilities": [
+ "SampledBuffer",
+ "ImageBuffer"
+ ]
+ },
+ {
+ "enumerant": "SubpassData",
+ "value": 6,
+ "capabilities": [
+ "InputAttachment"
+ ]
+ }
+ ]
+ },
+ {
+ "category": "ValueEnum",
+ "kind": "SamplerAddressingMode",
+ "enumerants": [
+ {
+ "enumerant": "None",
+ "value": 0,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "ClampToEdge",
+ "value": 1,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "Clamp",
+ "value": 2,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "Repeat",
+ "value": 3,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "RepeatMirrored",
+ "value": 4,
+ "capabilities": [
+ "Kernel"
+ ]
+ }
+ ]
+ },
+ {
+ "category": "ValueEnum",
+ "kind": "SamplerFilterMode",
+ "enumerants": [
+ {
+ "enumerant": "Nearest",
+ "value": 0,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "Linear",
+ "value": 1,
+ "capabilities": [
+ "Kernel"
+ ]
+ }
+ ]
+ },
+ {
+ "category": "ValueEnum",
+ "kind": "ImageFormat",
+ "enumerants": [
+ {
+ "enumerant": "Unknown",
+ "value": 0
+ },
+ {
+ "enumerant": "Rgba32f",
+ "value": 1,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "Rgba16f",
+ "value": 2,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "R32f",
+ "value": 3,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "Rgba8",
+ "value": 4,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "Rgba8Snorm",
+ "value": 5,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "Rg32f",
+ "value": 6,
+ "capabilities": [
+ "StorageImageExtendedFormats"
+ ]
+ },
+ {
+ "enumerant": "Rg16f",
+ "value": 7,
+ "capabilities": [
+ "StorageImageExtendedFormats"
+ ]
+ },
+ {
+ "enumerant": "R11fG11fB10f",
+ "value": 8,
+ "capabilities": [
+ "StorageImageExtendedFormats"
+ ]
+ },
+ {
+ "enumerant": "R16f",
+ "value": 9,
+ "capabilities": [
+ "StorageImageExtendedFormats"
+ ]
+ },
+ {
+ "enumerant": "Rgba16",
+ "value": 10,
+ "capabilities": [
+ "StorageImageExtendedFormats"
+ ]
+ },
+ {
+ "enumerant": "Rgb10A2",
+ "value": 11,
+ "capabilities": [
+ "StorageImageExtendedFormats"
+ ]
+ },
+ {
+ "enumerant": "Rg16",
+ "value": 12,
+ "capabilities": [
+ "StorageImageExtendedFormats"
+ ]
+ },
+ {
+ "enumerant": "Rg8",
+ "value": 13,
+ "capabilities": [
+ "StorageImageExtendedFormats"
+ ]
+ },
+ {
+ "enumerant": "R16",
+ "value": 14,
+ "capabilities": [
+ "StorageImageExtendedFormats"
+ ]
+ },
+ {
+ "enumerant": "R8",
+ "value": 15,
+ "capabilities": [
+ "StorageImageExtendedFormats"
+ ]
+ },
+ {
+ "enumerant": "Rgba16Snorm",
+ "value": 16,
+ "capabilities": [
+ "StorageImageExtendedFormats"
+ ]
+ },
+ {
+ "enumerant": "Rg16Snorm",
+ "value": 17,
+ "capabilities": [
+ "StorageImageExtendedFormats"
+ ]
+ },
+ {
+ "enumerant": "Rg8Snorm",
+ "value": 18,
+ "capabilities": [
+ "StorageImageExtendedFormats"
+ ]
+ },
+ {
+ "enumerant": "R16Snorm",
+ "value": 19,
+ "capabilities": [
+ "StorageImageExtendedFormats"
+ ]
+ },
+ {
+ "enumerant": "R8Snorm",
+ "value": 20,
+ "capabilities": [
+ "StorageImageExtendedFormats"
+ ]
+ },
+ {
+ "enumerant": "Rgba32i",
+ "value": 21,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "Rgba16i",
+ "value": 22,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "Rgba8i",
+ "value": 23,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "R32i",
+ "value": 24,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "Rg32i",
+ "value": 25,
+ "capabilities": [
+ "StorageImageExtendedFormats"
+ ]
+ },
+ {
+ "enumerant": "Rg16i",
+ "value": 26,
+ "capabilities": [
+ "StorageImageExtendedFormats"
+ ]
+ },
+ {
+ "enumerant": "Rg8i",
+ "value": 27,
+ "capabilities": [
+ "StorageImageExtendedFormats"
+ ]
+ },
+ {
+ "enumerant": "R16i",
+ "value": 28,
+ "capabilities": [
+ "StorageImageExtendedFormats"
+ ]
+ },
+ {
+ "enumerant": "R8i",
+ "value": 29,
+ "capabilities": [
+ "StorageImageExtendedFormats"
+ ]
+ },
+ {
+ "enumerant": "Rgba32ui",
+ "value": 30,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "Rgba16ui",
+ "value": 31,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "Rgba8ui",
+ "value": 32,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "R32ui",
+ "value": 33,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "Rgb10a2ui",
+ "value": 34,
+ "capabilities": [
+ "StorageImageExtendedFormats"
+ ]
+ },
+ {
+ "enumerant": "Rg32ui",
+ "value": 35,
+ "capabilities": [
+ "StorageImageExtendedFormats"
+ ]
+ },
+ {
+ "enumerant": "Rg16ui",
+ "value": 36,
+ "capabilities": [
+ "StorageImageExtendedFormats"
+ ]
+ },
+ {
+ "enumerant": "Rg8ui",
+ "value": 37,
+ "capabilities": [
+ "StorageImageExtendedFormats"
+ ]
+ },
+ {
+ "enumerant": "R16ui",
+ "value": 38,
+ "capabilities": [
+ "StorageImageExtendedFormats"
+ ]
+ },
+ {
+ "enumerant": "R8ui",
+ "value": 39,
+ "capabilities": [
+ "StorageImageExtendedFormats"
+ ]
+ },
+ {
+ "enumerant": "R64ui",
+ "value": 40,
+ "capabilities": [
+ "Int64ImageEXT"
+ ]
+ },
+ {
+ "enumerant": "R64i",
+ "value": 41,
+ "capabilities": [
+ "Int64ImageEXT"
+ ]
+ }
+ ]
+ },
+ {
+ "category": "ValueEnum",
+ "kind": "ImageChannelOrder",
+ "enumerants": [
+ {
+ "enumerant": "R",
+ "value": 0,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "A",
+ "value": 1,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "RG",
+ "value": 2,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "RA",
+ "value": 3,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "RGB",
+ "value": 4,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "RGBA",
+ "value": 5,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "BGRA",
+ "value": 6,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "ARGB",
+ "value": 7,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "Intensity",
+ "value": 8,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "Luminance",
+ "value": 9,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "Rx",
+ "value": 10,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "RGx",
+ "value": 11,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "RGBx",
+ "value": 12,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "Depth",
+ "value": 13,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "DepthStencil",
+ "value": 14,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "sRGB",
+ "value": 15,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "sRGBx",
+ "value": 16,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "sRGBA",
+ "value": 17,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "sBGRA",
+ "value": 18,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "ABGR",
+ "value": 19,
+ "capabilities": [
+ "Kernel"
+ ]
+ }
+ ]
+ },
+ {
+ "category": "ValueEnum",
+ "kind": "ImageChannelDataType",
+ "enumerants": [
+ {
+ "enumerant": "SnormInt8",
+ "value": 0,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "SnormInt16",
+ "value": 1,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "UnormInt8",
+ "value": 2,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "UnormInt16",
+ "value": 3,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "UnormShort565",
+ "value": 4,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "UnormShort555",
+ "value": 5,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "UnormInt101010",
+ "value": 6,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "SignedInt8",
+ "value": 7,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "SignedInt16",
+ "value": 8,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "SignedInt32",
+ "value": 9,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "UnsignedInt8",
+ "value": 10,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "UnsignedInt16",
+ "value": 11,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "UnsignedInt32",
+ "value": 12,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "HalfFloat",
+ "value": 13,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "Float",
+ "value": 14,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "UnormInt24",
+ "value": 15,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "UnormInt101010_2",
+ "value": 16,
+ "capabilities": [
+ "Kernel"
+ ]
+ }
+ ]
+ },
+ {
+ "category": "ValueEnum",
+ "kind": "FPRoundingMode",
+ "enumerants": [
+ {
+ "enumerant": "RTE",
+ "value": 0
+ },
+ {
+ "enumerant": "RTZ",
+ "value": 1
+ },
+ {
+ "enumerant": "RTP",
+ "value": 2
+ },
+ {
+ "enumerant": "RTN",
+ "value": 3
+ }
+ ]
+ },
+ {
+ "category": "ValueEnum",
+ "kind": "FPDenormMode",
+ "enumerants": [
+ {
+ "enumerant": "Preserve",
+ "value": 0,
+ "capabilities": [
+ "FunctionFloatControlINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FlushToZero",
+ "value": 1,
+ "capabilities": [
+ "FunctionFloatControlINTEL"
+ ],
+ "version": "None"
+ }
+ ]
+ },
+ {
+ "category": "ValueEnum",
+ "kind": "QuantizationModes",
+ "enumerants": [
+ {
+ "enumerant": "TRN",
+ "value": 0,
+ "capabilities": [
+ "ArbitraryPrecisionFixedPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "TRN_ZERO",
+ "value": 1,
+ "capabilities": [
+ "ArbitraryPrecisionFixedPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "RND",
+ "value": 2,
+ "capabilities": [
+ "ArbitraryPrecisionFixedPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "RND_ZERO",
+ "value": 3,
+ "capabilities": [
+ "ArbitraryPrecisionFixedPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "RND_INF",
+ "value": 4,
+ "capabilities": [
+ "ArbitraryPrecisionFixedPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "RND_MIN_INF",
+ "value": 5,
+ "capabilities": [
+ "ArbitraryPrecisionFixedPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "RND_CONV",
+ "value": 6,
+ "capabilities": [
+ "ArbitraryPrecisionFixedPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "RND_CONV_ODD",
+ "value": 7,
+ "capabilities": [
+ "ArbitraryPrecisionFixedPointINTEL"
+ ],
+ "version": "None"
+ }
+ ]
+ },
+ {
+ "category": "ValueEnum",
+ "kind": "FPOperationMode",
+ "enumerants": [
+ {
+ "enumerant": "IEEE",
+ "value": 0,
+ "capabilities": [
+ "FunctionFloatControlINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ALT",
+ "value": 1,
+ "capabilities": [
+ "FunctionFloatControlINTEL"
+ ],
+ "version": "None"
+ }
+ ]
+ },
+ {
+ "category": "ValueEnum",
+ "kind": "OverflowModes",
+ "enumerants": [
+ {
+ "enumerant": "WRAP",
+ "value": 0,
+ "capabilities": [
+ "ArbitraryPrecisionFixedPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SAT",
+ "value": 1,
+ "capabilities": [
+ "ArbitraryPrecisionFixedPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SAT_ZERO",
+ "value": 2,
+ "capabilities": [
+ "ArbitraryPrecisionFixedPointINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SAT_SYM",
+ "value": 3,
+ "capabilities": [
+ "ArbitraryPrecisionFixedPointINTEL"
+ ],
+ "version": "None"
+ }
+ ]
+ },
+ {
+ "category": "ValueEnum",
+ "kind": "LinkageType",
+ "enumerants": [
+ {
+ "enumerant": "Export",
+ "value": 0,
+ "capabilities": [
+ "Linkage"
+ ]
+ },
+ {
+ "enumerant": "Import",
+ "value": 1,
+ "capabilities": [
+ "Linkage"
+ ]
+ },
+ {
+ "enumerant": "LinkOnceODR",
+ "value": 2,
+ "capabilities": [
+ "Linkage"
+ ],
+ "extensions": [
+ "SPV_KHR_linkonce_odr"
+ ],
+ "version": "None"
+ }
+ ]
+ },
+ {
+ "category": "ValueEnum",
+ "kind": "AccessQualifier",
+ "enumerants": [
+ {
+ "enumerant": "ReadOnly",
+ "value": 0,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "WriteOnly",
+ "value": 1,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "ReadWrite",
+ "value": 2,
+ "capabilities": [
+ "Kernel"
+ ]
+ }
+ ]
+ },
+ {
+ "category": "ValueEnum",
+ "kind": "FunctionParameterAttribute",
+ "enumerants": [
+ {
+ "enumerant": "Zext",
+ "value": 0,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "Sext",
+ "value": 1,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "ByVal",
+ "value": 2,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "Sret",
+ "value": 3,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "NoAlias",
+ "value": 4,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "NoCapture",
+ "value": 5,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "NoWrite",
+ "value": 6,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "NoReadWrite",
+ "value": 7,
+ "capabilities": [
+ "Kernel"
+ ]
+ }
+ ]
+ },
+ {
+ "category": "ValueEnum",
+ "kind": "Decoration",
+ "enumerants": [
+ {
+ "enumerant": "RelaxedPrecision",
+ "value": 0,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "SpecId",
+ "value": 1,
+ "capabilities": [
+ "Shader",
+ "Kernel"
+ ],
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Specialization Constant ID'"
+ }
+ ]
+ },
+ {
+ "enumerant": "Block",
+ "value": 2,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "BufferBlock",
+ "value": 3,
+ "capabilities": [
+ "Shader"
+ ],
+ "lastVersion": "1.3"
+ },
+ {
+ "enumerant": "RowMajor",
+ "value": 4,
+ "capabilities": [
+ "Matrix"
+ ]
+ },
+ {
+ "enumerant": "ColMajor",
+ "value": 5,
+ "capabilities": [
+ "Matrix"
+ ]
+ },
+ {
+ "enumerant": "ArrayStride",
+ "value": 6,
+ "capabilities": [
+ "Shader"
+ ],
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Array Stride'"
+ }
+ ]
+ },
+ {
+ "enumerant": "MatrixStride",
+ "value": 7,
+ "capabilities": [
+ "Matrix"
+ ],
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Matrix Stride'"
+ }
+ ]
+ },
+ {
+ "enumerant": "GLSLShared",
+ "value": 8,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "GLSLPacked",
+ "value": 9,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "CPacked",
+ "value": 10,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "BuiltIn",
+ "value": 11,
+ "parameters": [
+ {
+ "kind": "BuiltIn"
+ }
+ ]
+ },
+ {
+ "enumerant": "NoPerspective",
+ "value": 13,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "Flat",
+ "value": 14,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "Patch",
+ "value": 15,
+ "capabilities": [
+ "Tessellation"
+ ]
+ },
+ {
+ "enumerant": "Centroid",
+ "value": 16,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "Sample",
+ "value": 17,
+ "capabilities": [
+ "SampleRateShading"
+ ]
+ },
+ {
+ "enumerant": "Invariant",
+ "value": 18,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "Restrict",
+ "value": 19
+ },
+ {
+ "enumerant": "Aliased",
+ "value": 20
+ },
+ {
+ "enumerant": "Volatile",
+ "value": 21
+ },
+ {
+ "enumerant": "Constant",
+ "value": 22,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "Coherent",
+ "value": 23
+ },
+ {
+ "enumerant": "NonWritable",
+ "value": 24
+ },
+ {
+ "enumerant": "NonReadable",
+ "value": 25
+ },
+ {
+ "enumerant": "Uniform",
+ "value": 26,
+ "capabilities": [
+ "Shader",
+ "UniformDecoration"
+ ]
+ },
+ {
+ "enumerant": "UniformId",
+ "value": 27,
+ "capabilities": [
+ "Shader",
+ "UniformDecoration"
+ ],
+ "parameters": [
+ {
+ "kind": "IdScope",
+ "name": "'Execution'"
+ }
+ ],
+ "version": "1.4"
+ },
+ {
+ "enumerant": "SaturatedConversion",
+ "value": 28,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "Stream",
+ "value": 29,
+ "capabilities": [
+ "GeometryStreams"
+ ],
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Stream Number'"
+ }
+ ]
+ },
+ {
+ "enumerant": "Location",
+ "value": 30,
+ "capabilities": [
+ "Shader"
+ ],
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Location'"
+ }
+ ]
+ },
+ {
+ "enumerant": "Component",
+ "value": 31,
+ "capabilities": [
+ "Shader"
+ ],
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Component'"
+ }
+ ]
+ },
+ {
+ "enumerant": "Index",
+ "value": 32,
+ "capabilities": [
+ "Shader"
+ ],
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Index'"
+ }
+ ]
+ },
+ {
+ "enumerant": "Binding",
+ "value": 33,
+ "capabilities": [
+ "Shader"
+ ],
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Binding Point'"
+ }
+ ]
+ },
+ {
+ "enumerant": "DescriptorSet",
+ "value": 34,
+ "capabilities": [
+ "Shader"
+ ],
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Descriptor Set'"
+ }
+ ]
+ },
+ {
+ "enumerant": "Offset",
+ "value": 35,
+ "capabilities": [
+ "Shader"
+ ],
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Byte Offset'"
+ }
+ ]
+ },
+ {
+ "enumerant": "XfbBuffer",
+ "value": 36,
+ "capabilities": [
+ "TransformFeedback"
+ ],
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'XFB Buffer Number'"
+ }
+ ]
+ },
+ {
+ "enumerant": "XfbStride",
+ "value": 37,
+ "capabilities": [
+ "TransformFeedback"
+ ],
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'XFB Stride'"
+ }
+ ]
+ },
+ {
+ "enumerant": "FuncParamAttr",
+ "value": 38,
+ "capabilities": [
+ "Kernel"
+ ],
+ "parameters": [
+ {
+ "kind": "FunctionParameterAttribute",
+ "name": "'Function Parameter Attribute'"
+ }
+ ]
+ },
+ {
+ "enumerant": "FPRoundingMode",
+ "value": 39,
+ "parameters": [
+ {
+ "kind": "FPRoundingMode",
+ "name": "'Floating-Point Rounding Mode'"
+ }
+ ]
+ },
+ {
+ "enumerant": "FPFastMathMode",
+ "value": 40,
+ "capabilities": [
+ "Kernel"
+ ],
+ "parameters": [
+ {
+ "kind": "FPFastMathMode",
+ "name": "'Fast-Math Mode'"
+ }
+ ]
+ },
+ {
+ "enumerant": "LinkageAttributes",
+ "value": 41,
+ "capabilities": [
+ "Linkage"
+ ],
+ "parameters": [
+ {
+ "kind": "LiteralString",
+ "name": "'Name'"
+ },
+ {
+ "kind": "LinkageType",
+ "name": "'Linkage Type'"
+ }
+ ]
+ },
+ {
+ "enumerant": "NoContraction",
+ "value": 42,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "InputAttachmentIndex",
+ "value": 43,
+ "capabilities": [
+ "InputAttachment"
+ ],
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Attachment Index'"
+ }
+ ]
+ },
+ {
+ "enumerant": "Alignment",
+ "value": 44,
+ "capabilities": [
+ "Kernel"
+ ],
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Alignment'"
+ }
+ ]
+ },
+ {
+ "enumerant": "MaxByteOffset",
+ "value": 45,
+ "capabilities": [
+ "Addresses"
+ ],
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Max Byte Offset'"
+ }
+ ],
+ "version": "1.1"
+ },
+ {
+ "enumerant": "AlignmentId",
+ "value": 46,
+ "capabilities": [
+ "Kernel"
+ ],
+ "parameters": [
+ {
+ "kind": "IdRef",
+ "name": "'Alignment'"
+ }
+ ],
+ "version": "1.2"
+ },
+ {
+ "enumerant": "MaxByteOffsetId",
+ "value": 47,
+ "capabilities": [
+ "Addresses"
+ ],
+ "parameters": [
+ {
+ "kind": "IdRef",
+ "name": "'Max Byte Offset'"
+ }
+ ],
+ "version": "1.2"
+ },
+ {
+ "enumerant": "NoSignedWrap",
+ "value": 4469,
+ "extensions": [
+ "SPV_KHR_no_integer_wrap_decoration"
+ ],
+ "version": "1.4"
+ },
+ {
+ "enumerant": "NoUnsignedWrap",
+ "value": 4470,
+ "extensions": [
+ "SPV_KHR_no_integer_wrap_decoration"
+ ],
+ "version": "1.4"
+ },
+ {
+ "enumerant": "ExplicitInterpAMD",
+ "value": 4999,
+ "extensions": [
+ "SPV_AMD_shader_explicit_vertex_parameter"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "OverrideCoverageNV",
+ "value": 5248,
+ "capabilities": [
+ "SampleMaskOverrideCoverageNV"
+ ],
+ "extensions": [
+ "SPV_NV_sample_mask_override_coverage"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "PassthroughNV",
+ "value": 5250,
+ "capabilities": [
+ "GeometryShaderPassthroughNV"
+ ],
+ "extensions": [
+ "SPV_NV_geometry_shader_passthrough"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ViewportRelativeNV",
+ "value": 5252,
+ "capabilities": [
+ "ShaderViewportMaskNV"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SecondaryViewportRelativeNV",
+ "value": 5256,
+ "capabilities": [
+ "ShaderStereoViewNV"
+ ],
+ "extensions": [
+ "SPV_NV_stereo_view_rendering"
+ ],
+ "version": "None",
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Offset'"
+ }
+ ]
+ },
+ {
+ "enumerant": "PerPrimitiveNV",
+ "value": 5271,
+ "capabilities": [
+ "MeshShadingNV"
+ ],
+ "extensions": [
+ "SPV_NV_mesh_shader"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "PerViewNV",
+ "value": 5272,
+ "capabilities": [
+ "MeshShadingNV"
+ ],
+ "extensions": [
+ "SPV_NV_mesh_shader"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "PerTaskNV",
+ "value": 5273,
+ "capabilities": [
+ "MeshShadingNV"
+ ],
+ "extensions": [
+ "SPV_NV_mesh_shader"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "PerVertexKHR",
+ "value": 5285,
+ "capabilities": [
+ "FragmentBarycentricNV",
+ "FragmentBarycentricKHR"
+ ],
+ "extensions": [
+ "SPV_NV_fragment_shader_barycentric",
+ "SPV_KHR_fragment_shader_barycentric"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "PerVertexNV",
+ "value": 5285,
+ "capabilities": [
+ "FragmentBarycentricNV",
+ "FragmentBarycentricKHR"
+ ],
+ "extensions": [
+ "SPV_NV_fragment_shader_barycentric",
+ "SPV_KHR_fragment_shader_barycentric"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "NonUniform",
+ "value": 5300,
+ "capabilities": [
+ "ShaderNonUniform"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "NonUniformEXT",
+ "value": 5300,
+ "capabilities": [
+ "ShaderNonUniform"
+ ],
+ "extensions": [
+ "SPV_EXT_descriptor_indexing"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "RestrictPointer",
+ "value": 5355,
+ "capabilities": [
+ "PhysicalStorageBufferAddresses"
+ ],
+ "extensions": [
+ "SPV_EXT_physical_storage_buffer",
+ "SPV_KHR_physical_storage_buffer"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "RestrictPointerEXT",
+ "value": 5355,
+ "capabilities": [
+ "PhysicalStorageBufferAddresses"
+ ],
+ "extensions": [
+ "SPV_EXT_physical_storage_buffer"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "AliasedPointer",
+ "value": 5356,
+ "capabilities": [
+ "PhysicalStorageBufferAddresses"
+ ],
+ "extensions": [
+ "SPV_EXT_physical_storage_buffer",
+ "SPV_KHR_physical_storage_buffer"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "AliasedPointerEXT",
+ "value": 5356,
+ "capabilities": [
+ "PhysicalStorageBufferAddresses"
+ ],
+ "extensions": [
+ "SPV_EXT_physical_storage_buffer"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "BindlessSamplerNV",
+ "value": 5398,
+ "capabilities": [
+ "BindlessTextureNV"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "BindlessImageNV",
+ "value": 5399,
+ "capabilities": [
+ "BindlessTextureNV"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "BoundSamplerNV",
+ "value": 5400,
+ "capabilities": [
+ "BindlessTextureNV"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "BoundImageNV",
+ "value": 5401,
+ "capabilities": [
+ "BindlessTextureNV"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SIMTCallINTEL",
+ "value": 5599,
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'N'"
+ }
+ ],
+ "capabilities": [
+ "VectorComputeINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ReferencedIndirectlyINTEL",
+ "value": 5602,
+ "capabilities": [
+ "IndirectReferencesINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_function_pointers"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ClobberINTEL",
+ "value": 5607,
+ "parameters": [
+ {
+ "kind": "LiteralString",
+ "name": "'Register'"
+ }
+ ],
+ "capabilities": [
+ "AsmINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SideEffectsINTEL",
+ "value": 5608,
+ "capabilities": [
+ "AsmINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "VectorComputeVariableINTEL",
+ "value": 5624,
+ "capabilities": [
+ "VectorComputeINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FuncParamIOKindINTEL",
+ "value": 5625,
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Kind'"
+ }
+ ],
+ "capabilities": [
+ "VectorComputeINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "VectorComputeFunctionINTEL",
+ "value": 5626,
+ "capabilities": [
+ "VectorComputeINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "StackCallINTEL",
+ "value": 5627,
+ "capabilities": [
+ "VectorComputeINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "GlobalVariableOffsetINTEL",
+ "value": 5628,
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Offset'"
+ }
+ ],
+ "capabilities": [
+ "VectorComputeINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "CounterBuffer",
+ "value": 5634,
+ "parameters": [
+ {
+ "kind": "IdRef",
+ "name": "'Counter Buffer'"
+ }
+ ],
+ "version": "1.4"
+ },
+ {
+ "enumerant": "HlslCounterBufferGOOGLE",
+ "value": 5634,
+ "parameters": [
+ {
+ "kind": "IdRef",
+ "name": "'Counter Buffer'"
+ }
+ ],
+ "extensions": [
+ "SPV_GOOGLE_hlsl_functionality1"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "UserSemantic",
+ "value": 5635,
+ "parameters": [
+ {
+ "kind": "LiteralString",
+ "name": "'Semantic'"
+ }
+ ],
+ "version": "1.4"
+ },
+ {
+ "enumerant": "HlslSemanticGOOGLE",
+ "value": 5635,
+ "parameters": [
+ {
+ "kind": "LiteralString",
+ "name": "'Semantic'"
+ }
+ ],
+ "extensions": [
+ "SPV_GOOGLE_hlsl_functionality1"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "UserTypeGOOGLE",
+ "value": 5636,
+ "parameters": [
+ {
+ "kind": "LiteralString",
+ "name": "'User Type'"
+ }
+ ],
+ "extensions": [
+ "SPV_GOOGLE_user_type"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FunctionRoundingModeINTEL",
+ "value": 5822,
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Target Width'"
+ },
+ {
+ "kind": "FPRoundingMode",
+ "name": "'FP Rounding Mode'"
+ }
+ ],
+ "capabilities": [
+ "FunctionFloatControlINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FunctionDenormModeINTEL",
+ "value": 5823,
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Target Width'"
+ },
+ {
+ "kind": "FPDenormMode",
+ "name": "'FP Denorm Mode'"
+ }
+ ],
+ "capabilities": [
+ "FunctionFloatControlINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "RegisterINTEL",
+ "value": 5825,
+ "capabilities": [
+ "FPGAMemoryAttributesINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_fpga_memory_attributes"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "MemoryINTEL",
+ "value": 5826,
+ "parameters": [
+ {
+ "kind": "LiteralString",
+ "name": "'Memory Type'"
+ }
+ ],
+ "capabilities": [
+ "FPGAMemoryAttributesINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_fpga_memory_attributes"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "NumbanksINTEL",
+ "value": 5827,
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Banks'"
+ }
+ ],
+ "capabilities": [
+ "FPGAMemoryAttributesINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_fpga_memory_attributes"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "BankwidthINTEL",
+ "value": 5828,
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Bank Width'"
+ }
+ ],
+ "capabilities": [
+ "FPGAMemoryAttributesINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_fpga_memory_attributes"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "MaxPrivateCopiesINTEL",
+ "value": 5829,
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Maximum Copies'"
+ }
+ ],
+ "capabilities": [
+ "FPGAMemoryAttributesINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_fpga_memory_attributes"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SinglepumpINTEL",
+ "value": 5830,
+ "capabilities": [
+ "FPGAMemoryAttributesINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_fpga_memory_attributes"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "DoublepumpINTEL",
+ "value": 5831,
+ "capabilities": [
+ "FPGAMemoryAttributesINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_fpga_memory_attributes"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "MaxReplicatesINTEL",
+ "value": 5832,
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Maximum Replicates'"
+ }
+ ],
+ "capabilities": [
+ "FPGAMemoryAttributesINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_fpga_memory_attributes"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SimpleDualPortINTEL",
+ "value": 5833,
+ "capabilities": [
+ "FPGAMemoryAttributesINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_fpga_memory_attributes"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "MergeINTEL",
+ "value": 5834,
+ "parameters": [
+ {
+ "kind": "LiteralString",
+ "name": "'Merge Key'"
+ },
+ {
+ "kind": "LiteralString",
+ "name": "'Merge Type'"
+ }
+ ],
+ "capabilities": [
+ "FPGAMemoryAttributesINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_fpga_memory_attributes"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "BankBitsINTEL",
+ "value": 5835,
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "quantifier": "*",
+ "name": "'Bank Bits'"
+ }
+ ],
+ "capabilities": [
+ "FPGAMemoryAttributesINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_fpga_memory_attributes"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ForcePow2DepthINTEL",
+ "value": 5836,
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Force Key'"
+ }
+ ],
+ "capabilities": [
+ "FPGAMemoryAttributesINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_fpga_memory_attributes"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "BurstCoalesceINTEL",
+ "value": 5899,
+ "capabilities": [
+ "FPGAMemoryAccessesINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "CacheSizeINTEL",
+ "value": 5900,
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Cache Size in bytes'"
+ }
+ ],
+ "capabilities": [
+ "FPGAMemoryAccessesINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "DontStaticallyCoalesceINTEL",
+ "value": 5901,
+ "capabilities": [
+ "FPGAMemoryAccessesINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "PrefetchINTEL",
+ "value": 5902,
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Prefetcher Size in bytes'"
+ }
+ ],
+ "capabilities": [
+ "FPGAMemoryAccessesINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "StallEnableINTEL",
+ "value": 5905,
+ "capabilities": [
+ "FPGAClusterAttributesINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FuseLoopsInFunctionINTEL",
+ "value": 5907,
+ "capabilities": [
+ "LoopFuseINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "BufferLocationINTEL",
+ "value": 5921,
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Buffer Location ID'"
+ }
+ ],
+ "capabilities": [
+ "FPGABufferLocationINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "IOPipeStorageINTEL",
+ "value": 5944,
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'IO Pipe ID'"
+ }
+ ],
+ "capabilities": [
+ "IOPipesINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FunctionFloatingPointModeINTEL",
+ "value": 6080,
+ "parameters": [
+ {
+ "kind": "LiteralInteger",
+ "name": "'Target Width'"
+ },
+ {
+ "kind": "FPOperationMode",
+ "name": "'FP Operation Mode'"
+ }
+ ],
+ "capabilities": [
+ "FunctionFloatControlINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SingleElementVectorINTEL",
+ "value": 6085,
+ "capabilities": [
+ "VectorComputeINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "VectorComputeCallableFunctionINTEL",
+ "value": 6087,
+ "capabilities": [
+ "VectorComputeINTEL"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "MediaBlockIOINTEL",
+ "value": 6140,
+ "capabilities": [
+ "VectorComputeINTEL"
+ ],
+ "version": "None"
+ }
+ ]
+ },
+ {
+ "category": "ValueEnum",
+ "kind": "BuiltIn",
+ "enumerants": [
+ {
+ "enumerant": "Position",
+ "value": 0,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "PointSize",
+ "value": 1,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "ClipDistance",
+ "value": 3,
+ "capabilities": [
+ "ClipDistance"
+ ]
+ },
+ {
+ "enumerant": "CullDistance",
+ "value": 4,
+ "capabilities": [
+ "CullDistance"
+ ]
+ },
+ {
+ "enumerant": "VertexId",
+ "value": 5,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "InstanceId",
+ "value": 6,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "PrimitiveId",
+ "value": 7,
+ "capabilities": [
+ "Geometry",
+ "Tessellation",
+ "RayTracingNV",
+ "RayTracingKHR",
+ "MeshShadingNV"
+ ]
+ },
+ {
+ "enumerant": "InvocationId",
+ "value": 8,
+ "capabilities": [
+ "Geometry",
+ "Tessellation"
+ ]
+ },
+ {
+ "enumerant": "Layer",
+ "value": 9,
+ "capabilities": [
+ "Geometry",
+ "ShaderLayer",
+ "ShaderViewportIndexLayerEXT",
+ "MeshShadingNV"
+ ]
+ },
+ {
+ "enumerant": "ViewportIndex",
+ "value": 10,
+ "capabilities": [
+ "MultiViewport",
+ "ShaderViewportIndex",
+ "ShaderViewportIndexLayerEXT",
+ "MeshShadingNV"
+ ]
+ },
+ {
+ "enumerant": "TessLevelOuter",
+ "value": 11,
+ "capabilities": [
+ "Tessellation"
+ ]
+ },
+ {
+ "enumerant": "TessLevelInner",
+ "value": 12,
+ "capabilities": [
+ "Tessellation"
+ ]
+ },
+ {
+ "enumerant": "TessCoord",
+ "value": 13,
+ "capabilities": [
+ "Tessellation"
+ ]
+ },
+ {
+ "enumerant": "PatchVertices",
+ "value": 14,
+ "capabilities": [
+ "Tessellation"
+ ]
+ },
+ {
+ "enumerant": "FragCoord",
+ "value": 15,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "PointCoord",
+ "value": 16,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "FrontFacing",
+ "value": 17,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "SampleId",
+ "value": 18,
+ "capabilities": [
+ "SampleRateShading"
+ ]
+ },
+ {
+ "enumerant": "SamplePosition",
+ "value": 19,
+ "capabilities": [
+ "SampleRateShading"
+ ]
+ },
+ {
+ "enumerant": "SampleMask",
+ "value": 20,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "FragDepth",
+ "value": 22,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "HelperInvocation",
+ "value": 23,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "NumWorkgroups",
+ "value": 24
+ },
+ {
+ "enumerant": "WorkgroupSize",
+ "value": 25
+ },
+ {
+ "enumerant": "WorkgroupId",
+ "value": 26
+ },
+ {
+ "enumerant": "LocalInvocationId",
+ "value": 27
+ },
+ {
+ "enumerant": "GlobalInvocationId",
+ "value": 28
+ },
+ {
+ "enumerant": "LocalInvocationIndex",
+ "value": 29
+ },
+ {
+ "enumerant": "WorkDim",
+ "value": 30,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "GlobalSize",
+ "value": 31,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "EnqueuedWorkgroupSize",
+ "value": 32,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "GlobalOffset",
+ "value": 33,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "GlobalLinearId",
+ "value": 34,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "SubgroupSize",
+ "value": 36,
+ "capabilities": [
+ "Kernel",
+ "GroupNonUniform",
+ "SubgroupBallotKHR"
+ ]
+ },
+ {
+ "enumerant": "SubgroupMaxSize",
+ "value": 37,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "NumSubgroups",
+ "value": 38,
+ "capabilities": [
+ "Kernel",
+ "GroupNonUniform"
+ ]
+ },
+ {
+ "enumerant": "NumEnqueuedSubgroups",
+ "value": 39,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "SubgroupId",
+ "value": 40,
+ "capabilities": [
+ "Kernel",
+ "GroupNonUniform"
+ ]
+ },
+ {
+ "enumerant": "SubgroupLocalInvocationId",
+ "value": 41,
+ "capabilities": [
+ "Kernel",
+ "GroupNonUniform",
+ "SubgroupBallotKHR"
+ ]
+ },
+ {
+ "enumerant": "VertexIndex",
+ "value": 42,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "InstanceIndex",
+ "value": 43,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "SubgroupEqMask",
+ "value": 4416,
+ "capabilities": [
+ "SubgroupBallotKHR",
+ "GroupNonUniformBallot"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "SubgroupEqMaskKHR",
+ "value": 4416,
+ "capabilities": [
+ "SubgroupBallotKHR",
+ "GroupNonUniformBallot"
+ ],
+ "extensions": [
+ "SPV_KHR_shader_ballot"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "SubgroupGeMask",
+ "value": 4417,
+ "capabilities": [
+ "SubgroupBallotKHR",
+ "GroupNonUniformBallot"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "SubgroupGeMaskKHR",
+ "value": 4417,
+ "capabilities": [
+ "SubgroupBallotKHR",
+ "GroupNonUniformBallot"
+ ],
+ "extensions": [
+ "SPV_KHR_shader_ballot"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "SubgroupGtMask",
+ "value": 4418,
+ "capabilities": [
+ "SubgroupBallotKHR",
+ "GroupNonUniformBallot"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "SubgroupGtMaskKHR",
+ "value": 4418,
+ "capabilities": [
+ "SubgroupBallotKHR",
+ "GroupNonUniformBallot"
+ ],
+ "extensions": [
+ "SPV_KHR_shader_ballot"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "SubgroupLeMask",
+ "value": 4419,
+ "capabilities": [
+ "SubgroupBallotKHR",
+ "GroupNonUniformBallot"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "SubgroupLeMaskKHR",
+ "value": 4419,
+ "capabilities": [
+ "SubgroupBallotKHR",
+ "GroupNonUniformBallot"
+ ],
+ "extensions": [
+ "SPV_KHR_shader_ballot"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "SubgroupLtMask",
+ "value": 4420,
+ "capabilities": [
+ "SubgroupBallotKHR",
+ "GroupNonUniformBallot"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "SubgroupLtMaskKHR",
+ "value": 4420,
+ "capabilities": [
+ "SubgroupBallotKHR",
+ "GroupNonUniformBallot"
+ ],
+ "extensions": [
+ "SPV_KHR_shader_ballot"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "BaseVertex",
+ "value": 4424,
+ "capabilities": [
+ "DrawParameters"
+ ],
+ "extensions": [
+ "SPV_KHR_shader_draw_parameters"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "BaseInstance",
+ "value": 4425,
+ "capabilities": [
+ "DrawParameters"
+ ],
+ "extensions": [
+ "SPV_KHR_shader_draw_parameters"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "DrawIndex",
+ "value": 4426,
+ "capabilities": [
+ "DrawParameters",
+ "MeshShadingNV"
+ ],
+ "extensions": [
+ "SPV_KHR_shader_draw_parameters",
+ "SPV_NV_mesh_shader"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "PrimitiveShadingRateKHR",
+ "value": 4432,
+ "capabilities": [
+ "FragmentShadingRateKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_fragment_shading_rate"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "DeviceIndex",
+ "value": 4438,
+ "capabilities": [
+ "DeviceGroup"
+ ],
+ "extensions": [
+ "SPV_KHR_device_group"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "ViewIndex",
+ "value": 4440,
+ "capabilities": [
+ "MultiView"
+ ],
+ "extensions": [
+ "SPV_KHR_multiview"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "ShadingRateKHR",
+ "value": 4444,
+ "capabilities": [
+ "FragmentShadingRateKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_fragment_shading_rate"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "BaryCoordNoPerspAMD",
+ "value": 4992,
+ "extensions": [
+ "SPV_AMD_shader_explicit_vertex_parameter"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "BaryCoordNoPerspCentroidAMD",
+ "value": 4993,
+ "extensions": [
+ "SPV_AMD_shader_explicit_vertex_parameter"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "BaryCoordNoPerspSampleAMD",
+ "value": 4994,
+ "extensions": [
+ "SPV_AMD_shader_explicit_vertex_parameter"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "BaryCoordSmoothAMD",
+ "value": 4995,
+ "extensions": [
+ "SPV_AMD_shader_explicit_vertex_parameter"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "BaryCoordSmoothCentroidAMD",
+ "value": 4996,
+ "extensions": [
+ "SPV_AMD_shader_explicit_vertex_parameter"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "BaryCoordSmoothSampleAMD",
+ "value": 4997,
+ "extensions": [
+ "SPV_AMD_shader_explicit_vertex_parameter"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "BaryCoordPullModelAMD",
+ "value": 4998,
+ "extensions": [
+ "SPV_AMD_shader_explicit_vertex_parameter"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FragStencilRefEXT",
+ "value": 5014,
+ "capabilities": [
+ "StencilExportEXT"
+ ],
+ "extensions": [
+ "SPV_EXT_shader_stencil_export"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ViewportMaskNV",
+ "value": 5253,
+ "capabilities": [
+ "ShaderViewportMaskNV",
+ "MeshShadingNV"
+ ],
+ "extensions": [
+ "SPV_NV_viewport_array2",
+ "SPV_NV_mesh_shader"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SecondaryPositionNV",
+ "value": 5257,
+ "capabilities": [
+ "ShaderStereoViewNV"
+ ],
+ "extensions": [
+ "SPV_NV_stereo_view_rendering"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SecondaryViewportMaskNV",
+ "value": 5258,
+ "capabilities": [
+ "ShaderStereoViewNV"
+ ],
+ "extensions": [
+ "SPV_NV_stereo_view_rendering"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "PositionPerViewNV",
+ "value": 5261,
+ "capabilities": [
+ "PerViewAttributesNV",
+ "MeshShadingNV"
+ ],
+ "extensions": [
+ "SPV_NVX_multiview_per_view_attributes",
+ "SPV_NV_mesh_shader"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ViewportMaskPerViewNV",
+ "value": 5262,
+ "capabilities": [
+ "PerViewAttributesNV",
+ "MeshShadingNV"
+ ],
+ "extensions": [
+ "SPV_NVX_multiview_per_view_attributes",
+ "SPV_NV_mesh_shader"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FullyCoveredEXT",
+ "value": 5264,
+ "capabilities": [
+ "FragmentFullyCoveredEXT"
+ ],
+ "extensions": [
+ "SPV_EXT_fragment_fully_covered"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "TaskCountNV",
+ "value": 5274,
+ "capabilities": [
+ "MeshShadingNV"
+ ],
+ "extensions": [
+ "SPV_NV_mesh_shader"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "PrimitiveCountNV",
+ "value": 5275,
+ "capabilities": [
+ "MeshShadingNV"
+ ],
+ "extensions": [
+ "SPV_NV_mesh_shader"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "PrimitiveIndicesNV",
+ "value": 5276,
+ "capabilities": [
+ "MeshShadingNV"
+ ],
+ "extensions": [
+ "SPV_NV_mesh_shader"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ClipDistancePerViewNV",
+ "value": 5277,
+ "capabilities": [
+ "MeshShadingNV"
+ ],
+ "extensions": [
+ "SPV_NV_mesh_shader"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "CullDistancePerViewNV",
+ "value": 5278,
+ "capabilities": [
+ "MeshShadingNV"
+ ],
+ "extensions": [
+ "SPV_NV_mesh_shader"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "LayerPerViewNV",
+ "value": 5279,
+ "capabilities": [
+ "MeshShadingNV"
+ ],
+ "extensions": [
+ "SPV_NV_mesh_shader"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "MeshViewCountNV",
+ "value": 5280,
+ "capabilities": [
+ "MeshShadingNV"
+ ],
+ "extensions": [
+ "SPV_NV_mesh_shader"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "MeshViewIndicesNV",
+ "value": 5281,
+ "capabilities": [
+ "MeshShadingNV"
+ ],
+ "extensions": [
+ "SPV_NV_mesh_shader"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "BaryCoordKHR",
+ "value": 5286,
+ "capabilities": [
+ "FragmentBarycentricNV",
+ "FragmentBarycentricKHR"
+ ],
+ "extensions": [
+ "SPV_NV_fragment_shader_barycentric",
+ "SPV_KHR_fragment_shader_barycentric"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "BaryCoordNV",
+ "value": 5286,
+ "capabilities": [
+ "FragmentBarycentricNV",
+ "FragmentBarycentricKHR"
+ ],
+ "extensions": [
+ "SPV_NV_fragment_shader_barycentric",
+ "SPV_KHR_fragment_shader_barycentric"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "BaryCoordNoPerspKHR",
+ "value": 5287,
+ "capabilities": [
+ "FragmentBarycentricNV",
+ "FragmentBarycentricKHR"
+ ],
+ "extensions": [
+ "SPV_NV_fragment_shader_barycentric",
+ "SPV_KHR_fragment_shader_barycentric"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "BaryCoordNoPerspNV",
+ "value": 5287,
+ "capabilities": [
+ "FragmentBarycentricNV",
+ "FragmentBarycentricKHR"
+ ],
+ "extensions": [
+ "SPV_NV_fragment_shader_barycentric",
+ "SPV_KHR_fragment_shader_barycentric"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FragSizeEXT",
+ "value": 5292,
+ "capabilities": [
+ "FragmentDensityEXT",
+ "ShadingRateNV"
+ ],
+ "extensions": [
+ "SPV_EXT_fragment_invocation_density",
+ "SPV_NV_shading_rate"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FragmentSizeNV",
+ "value": 5292,
+ "capabilities": [
+ "ShadingRateNV",
+ "FragmentDensityEXT"
+ ],
+ "extensions": [
+ "SPV_NV_shading_rate",
+ "SPV_EXT_fragment_invocation_density"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FragInvocationCountEXT",
+ "value": 5293,
+ "capabilities": [
+ "FragmentDensityEXT",
+ "ShadingRateNV"
+ ],
+ "extensions": [
+ "SPV_EXT_fragment_invocation_density",
+ "SPV_NV_shading_rate"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "InvocationsPerPixelNV",
+ "value": 5293,
+ "capabilities": [
+ "ShadingRateNV",
+ "FragmentDensityEXT"
+ ],
+ "extensions": [
+ "SPV_NV_shading_rate",
+ "SPV_EXT_fragment_invocation_density"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "LaunchIdNV",
+ "value": 5319,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "LaunchIdKHR",
+ "value": 5319,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "LaunchSizeNV",
+ "value": 5320,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "LaunchSizeKHR",
+ "value": 5320,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "WorldRayOriginNV",
+ "value": 5321,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "WorldRayOriginKHR",
+ "value": 5321,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "WorldRayDirectionNV",
+ "value": 5322,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "WorldRayDirectionKHR",
+ "value": 5322,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ObjectRayOriginNV",
+ "value": 5323,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ObjectRayOriginKHR",
+ "value": 5323,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ObjectRayDirectionNV",
+ "value": 5324,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ObjectRayDirectionKHR",
+ "value": 5324,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "RayTminNV",
+ "value": 5325,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "RayTminKHR",
+ "value": 5325,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "RayTmaxNV",
+ "value": 5326,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "RayTmaxKHR",
+ "value": 5326,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "InstanceCustomIndexNV",
+ "value": 5327,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "InstanceCustomIndexKHR",
+ "value": 5327,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ObjectToWorldNV",
+ "value": 5330,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ObjectToWorldKHR",
+ "value": 5330,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "WorldToObjectNV",
+ "value": 5331,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "WorldToObjectKHR",
+ "value": 5331,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "HitTNV",
+ "value": 5332,
+ "capabilities": [
+ "RayTracingNV"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "HitKindNV",
+ "value": 5333,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "HitKindKHR",
+ "value": 5333,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "CurrentRayTimeNV",
+ "value": 5334,
+ "capabilities": [
+ "RayTracingMotionBlurNV"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing_motion_blur"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "IncomingRayFlagsNV",
+ "value": 5351,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "IncomingRayFlagsKHR",
+ "value": 5351,
+ "capabilities": [
+ "RayTracingNV",
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing",
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "RayGeometryIndexKHR",
+ "value": 5352,
+ "capabilities": [
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "WarpsPerSMNV",
+ "value": 5374,
+ "capabilities": [
+ "ShaderSMBuiltinsNV"
+ ],
+ "extensions": [
+ "SPV_NV_shader_sm_builtins"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SMCountNV",
+ "value": 5375,
+ "capabilities": [
+ "ShaderSMBuiltinsNV"
+ ],
+ "extensions": [
+ "SPV_NV_shader_sm_builtins"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "WarpIDNV",
+ "value": 5376,
+ "capabilities": [
+ "ShaderSMBuiltinsNV"
+ ],
+ "extensions": [
+ "SPV_NV_shader_sm_builtins"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SMIDNV",
+ "value": 5377,
+ "capabilities": [
+ "ShaderSMBuiltinsNV"
+ ],
+ "extensions": [
+ "SPV_NV_shader_sm_builtins"
+ ],
+ "version": "None"
+ }
+ ]
+ },
+ {
+ "category": "ValueEnum",
+ "kind": "Scope",
+ "enumerants": [
+ {
+ "enumerant": "CrossDevice",
+ "value": 0
+ },
+ {
+ "enumerant": "Device",
+ "value": 1
+ },
+ {
+ "enumerant": "Workgroup",
+ "value": 2
+ },
+ {
+ "enumerant": "Subgroup",
+ "value": 3
+ },
+ {
+ "enumerant": "Invocation",
+ "value": 4
+ },
+ {
+ "enumerant": "QueueFamily",
+ "value": 5,
+ "capabilities": [
+ "VulkanMemoryModel"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "QueueFamilyKHR",
+ "value": 5,
+ "capabilities": [
+ "VulkanMemoryModel"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "ShaderCallKHR",
+ "value": 6,
+ "capabilities": [
+ "RayTracingKHR"
+ ],
+ "version": "None"
+ }
+ ]
+ },
+ {
+ "category": "ValueEnum",
+ "kind": "GroupOperation",
+ "enumerants": [
+ {
+ "enumerant": "Reduce",
+ "value": 0,
+ "capabilities": [
+ "Kernel",
+ "GroupNonUniformArithmetic",
+ "GroupNonUniformBallot"
+ ]
+ },
+ {
+ "enumerant": "InclusiveScan",
+ "value": 1,
+ "capabilities": [
+ "Kernel",
+ "GroupNonUniformArithmetic",
+ "GroupNonUniformBallot"
+ ]
+ },
+ {
+ "enumerant": "ExclusiveScan",
+ "value": 2,
+ "capabilities": [
+ "Kernel",
+ "GroupNonUniformArithmetic",
+ "GroupNonUniformBallot"
+ ]
+ },
+ {
+ "enumerant": "ClusteredReduce",
+ "value": 3,
+ "capabilities": [
+ "GroupNonUniformClustered"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "PartitionedReduceNV",
+ "value": 6,
+ "capabilities": [
+ "GroupNonUniformPartitionedNV"
+ ],
+ "extensions": [
+ "SPV_NV_shader_subgroup_partitioned"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "PartitionedInclusiveScanNV",
+ "value": 7,
+ "capabilities": [
+ "GroupNonUniformPartitionedNV"
+ ],
+ "extensions": [
+ "SPV_NV_shader_subgroup_partitioned"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "PartitionedExclusiveScanNV",
+ "value": 8,
+ "capabilities": [
+ "GroupNonUniformPartitionedNV"
+ ],
+ "extensions": [
+ "SPV_NV_shader_subgroup_partitioned"
+ ],
+ "version": "None"
+ }
+ ]
+ },
+ {
+ "category": "ValueEnum",
+ "kind": "KernelEnqueueFlags",
+ "enumerants": [
+ {
+ "enumerant": "NoWait",
+ "value": 0,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "WaitKernel",
+ "value": 1,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "WaitWorkGroup",
+ "value": 2,
+ "capabilities": [
+ "Kernel"
+ ]
+ }
+ ]
+ },
+ {
+ "category": "ValueEnum",
+ "kind": "Capability",
+ "enumerants": [
+ {
+ "enumerant": "Matrix",
+ "value": 0
+ },
+ {
+ "enumerant": "Shader",
+ "value": 1,
+ "capabilities": [
+ "Matrix"
+ ]
+ },
+ {
+ "enumerant": "Geometry",
+ "value": 2,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "Tessellation",
+ "value": 3,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "Addresses",
+ "value": 4
+ },
+ {
+ "enumerant": "Linkage",
+ "value": 5
+ },
+ {
+ "enumerant": "Kernel",
+ "value": 6
+ },
+ {
+ "enumerant": "Vector16",
+ "value": 7,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "Float16Buffer",
+ "value": 8,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "Float16",
+ "value": 9
+ },
+ {
+ "enumerant": "Float64",
+ "value": 10
+ },
+ {
+ "enumerant": "Int64",
+ "value": 11
+ },
+ {
+ "enumerant": "Int64Atomics",
+ "value": 12,
+ "capabilities": [
+ "Int64"
+ ]
+ },
+ {
+ "enumerant": "ImageBasic",
+ "value": 13,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "ImageReadWrite",
+ "value": 14,
+ "capabilities": [
+ "ImageBasic"
+ ]
+ },
+ {
+ "enumerant": "ImageMipmap",
+ "value": 15,
+ "capabilities": [
+ "ImageBasic"
+ ]
+ },
+ {
+ "enumerant": "Pipes",
+ "value": 17,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "Groups",
+ "value": 18,
+ "extensions": [
+ "SPV_AMD_shader_ballot"
+ ]
+ },
+ {
+ "enumerant": "DeviceEnqueue",
+ "value": 19,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "LiteralSampler",
+ "value": 20,
+ "capabilities": [
+ "Kernel"
+ ]
+ },
+ {
+ "enumerant": "AtomicStorage",
+ "value": 21,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "Int16",
+ "value": 22
+ },
+ {
+ "enumerant": "TessellationPointSize",
+ "value": 23,
+ "capabilities": [
+ "Tessellation"
+ ]
+ },
+ {
+ "enumerant": "GeometryPointSize",
+ "value": 24,
+ "capabilities": [
+ "Geometry"
+ ]
+ },
+ {
+ "enumerant": "ImageGatherExtended",
+ "value": 25,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "StorageImageMultisample",
+ "value": 27,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "UniformBufferArrayDynamicIndexing",
+ "value": 28,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "SampledImageArrayDynamicIndexing",
+ "value": 29,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "StorageBufferArrayDynamicIndexing",
+ "value": 30,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "StorageImageArrayDynamicIndexing",
+ "value": 31,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "ClipDistance",
+ "value": 32,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "CullDistance",
+ "value": 33,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "ImageCubeArray",
+ "value": 34,
+ "capabilities": [
+ "SampledCubeArray"
+ ]
+ },
+ {
+ "enumerant": "SampleRateShading",
+ "value": 35,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "ImageRect",
+ "value": 36,
+ "capabilities": [
+ "SampledRect"
+ ]
+ },
+ {
+ "enumerant": "SampledRect",
+ "value": 37,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "GenericPointer",
+ "value": 38,
+ "capabilities": [
+ "Addresses"
+ ]
+ },
+ {
+ "enumerant": "Int8",
+ "value": 39
+ },
+ {
+ "enumerant": "InputAttachment",
+ "value": 40,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "SparseResidency",
+ "value": 41,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "MinLod",
+ "value": 42,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "Sampled1D",
+ "value": 43
+ },
+ {
+ "enumerant": "Image1D",
+ "value": 44,
+ "capabilities": [
+ "Sampled1D"
+ ]
+ },
+ {
+ "enumerant": "SampledCubeArray",
+ "value": 45,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "SampledBuffer",
+ "value": 46
+ },
+ {
+ "enumerant": "ImageBuffer",
+ "value": 47,
+ "capabilities": [
+ "SampledBuffer"
+ ]
+ },
+ {
+ "enumerant": "ImageMSArray",
+ "value": 48,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "StorageImageExtendedFormats",
+ "value": 49,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "ImageQuery",
+ "value": 50,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "DerivativeControl",
+ "value": 51,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "InterpolationFunction",
+ "value": 52,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "TransformFeedback",
+ "value": 53,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "GeometryStreams",
+ "value": 54,
+ "capabilities": [
+ "Geometry"
+ ]
+ },
+ {
+ "enumerant": "StorageImageReadWithoutFormat",
+ "value": 55,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "StorageImageWriteWithoutFormat",
+ "value": 56,
+ "capabilities": [
+ "Shader"
+ ]
+ },
+ {
+ "enumerant": "MultiViewport",
+ "value": 57,
+ "capabilities": [
+ "Geometry"
+ ]
+ },
+ {
+ "enumerant": "SubgroupDispatch",
+ "value": 58,
+ "capabilities": [
+ "DeviceEnqueue"
+ ],
+ "version": "1.1"
+ },
+ {
+ "enumerant": "NamedBarrier",
+ "value": 59,
+ "capabilities": [
+ "Kernel"
+ ],
+ "version": "1.1"
+ },
+ {
+ "enumerant": "PipeStorage",
+ "value": 60,
+ "capabilities": [
+ "Pipes"
+ ],
+ "version": "1.1"
+ },
+ {
+ "enumerant": "GroupNonUniform",
+ "value": 61,
+ "version": "1.3"
+ },
+ {
+ "enumerant": "GroupNonUniformVote",
+ "value": 62,
+ "capabilities": [
+ "GroupNonUniform"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "GroupNonUniformArithmetic",
+ "value": 63,
+ "capabilities": [
+ "GroupNonUniform"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "GroupNonUniformBallot",
+ "value": 64,
+ "capabilities": [
+ "GroupNonUniform"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "GroupNonUniformShuffle",
+ "value": 65,
+ "capabilities": [
+ "GroupNonUniform"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "GroupNonUniformShuffleRelative",
+ "value": 66,
+ "capabilities": [
+ "GroupNonUniform"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "GroupNonUniformClustered",
+ "value": 67,
+ "capabilities": [
+ "GroupNonUniform"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "GroupNonUniformQuad",
+ "value": 68,
+ "capabilities": [
+ "GroupNonUniform"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "ShaderLayer",
+ "value": 69,
+ "version": "1.5"
+ },
+ {
+ "enumerant": "ShaderViewportIndex",
+ "value": 70,
+ "version": "1.5"
+ },
+ {
+ "enumerant": "UniformDecoration",
+ "value": 71,
+ "version": "1.6"
+ },
+ {
+ "enumerant": "FragmentShadingRateKHR",
+ "value": 4422,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_KHR_fragment_shading_rate"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SubgroupBallotKHR",
+ "value": 4423,
+ "extensions": [
+ "SPV_KHR_shader_ballot"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "DrawParameters",
+ "value": 4427,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_KHR_shader_draw_parameters"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "WorkgroupMemoryExplicitLayoutKHR",
+ "value": 4428,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_KHR_workgroup_memory_explicit_layout"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "WorkgroupMemoryExplicitLayout8BitAccessKHR",
+ "value": 4429,
+ "capabilities": [
+ "WorkgroupMemoryExplicitLayoutKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_workgroup_memory_explicit_layout"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "WorkgroupMemoryExplicitLayout16BitAccessKHR",
+ "value": 4430,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_KHR_workgroup_memory_explicit_layout"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SubgroupVoteKHR",
+ "value": 4431,
+ "extensions": [
+ "SPV_KHR_subgroup_vote"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "StorageBuffer16BitAccess",
+ "value": 4433,
+ "extensions": [
+ "SPV_KHR_16bit_storage"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "StorageUniformBufferBlock16",
+ "value": 4433,
+ "extensions": [
+ "SPV_KHR_16bit_storage"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "UniformAndStorageBuffer16BitAccess",
+ "value": 4434,
+ "capabilities": [
+ "StorageBuffer16BitAccess",
+ "StorageUniformBufferBlock16"
+ ],
+ "extensions": [
+ "SPV_KHR_16bit_storage"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "StorageUniform16",
+ "value": 4434,
+ "capabilities": [
+ "StorageBuffer16BitAccess",
+ "StorageUniformBufferBlock16"
+ ],
+ "extensions": [
+ "SPV_KHR_16bit_storage"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "StoragePushConstant16",
+ "value": 4435,
+ "extensions": [
+ "SPV_KHR_16bit_storage"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "StorageInputOutput16",
+ "value": 4436,
+ "extensions": [
+ "SPV_KHR_16bit_storage"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "DeviceGroup",
+ "value": 4437,
+ "extensions": [
+ "SPV_KHR_device_group"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "MultiView",
+ "value": 4439,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_KHR_multiview"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "VariablePointersStorageBuffer",
+ "value": 4441,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_KHR_variable_pointers"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "VariablePointers",
+ "value": 4442,
+ "capabilities": [
+ "VariablePointersStorageBuffer"
+ ],
+ "extensions": [
+ "SPV_KHR_variable_pointers"
+ ],
+ "version": "1.3"
+ },
+ {
+ "enumerant": "AtomicStorageOps",
+ "value": 4445,
+ "extensions": [
+ "SPV_KHR_shader_atomic_counter_ops"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SampleMaskPostDepthCoverage",
+ "value": 4447,
+ "extensions": [
+ "SPV_KHR_post_depth_coverage"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "StorageBuffer8BitAccess",
+ "value": 4448,
+ "extensions": [
+ "SPV_KHR_8bit_storage"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "UniformAndStorageBuffer8BitAccess",
+ "value": 4449,
+ "capabilities": [
+ "StorageBuffer8BitAccess"
+ ],
+ "extensions": [
+ "SPV_KHR_8bit_storage"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "StoragePushConstant8",
+ "value": 4450,
+ "extensions": [
+ "SPV_KHR_8bit_storage"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "DenormPreserve",
+ "value": 4464,
+ "extensions": [
+ "SPV_KHR_float_controls"
+ ],
+ "version": "1.4"
+ },
+ {
+ "enumerant": "DenormFlushToZero",
+ "value": 4465,
+ "extensions": [
+ "SPV_KHR_float_controls"
+ ],
+ "version": "1.4"
+ },
+ {
+ "enumerant": "SignedZeroInfNanPreserve",
+ "value": 4466,
+ "extensions": [
+ "SPV_KHR_float_controls"
+ ],
+ "version": "1.4"
+ },
+ {
+ "enumerant": "RoundingModeRTE",
+ "value": 4467,
+ "extensions": [
+ "SPV_KHR_float_controls"
+ ],
+ "version": "1.4"
+ },
+ {
+ "enumerant": "RoundingModeRTZ",
+ "value": 4468,
+ "extensions": [
+ "SPV_KHR_float_controls"
+ ],
+ "version": "1.4"
+ },
+ {
+ "enumerant": "RayQueryProvisionalKHR",
+ "value": 4471,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_query"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "RayQueryKHR",
+ "value": 4472,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_query"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "RayTraversalPrimitiveCullingKHR",
+ "value": 4478,
+ "capabilities": [
+ "RayQueryKHR",
+ "RayTracingKHR"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_query",
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "RayTracingKHR",
+ "value": 4479,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "Float16ImageAMD",
+ "value": 5008,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_AMD_gpu_shader_half_float_fetch"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ImageGatherBiasLodAMD",
+ "value": 5009,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_AMD_texture_gather_bias_lod"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FragmentMaskAMD",
+ "value": 5010,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_AMD_shader_fragment_mask"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "StencilExportEXT",
+ "value": 5013,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_EXT_shader_stencil_export"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ImageReadWriteLodAMD",
+ "value": 5015,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_AMD_shader_image_load_store_lod"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "Int64ImageEXT",
+ "value": 5016,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_EXT_shader_image_int64"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ShaderClockKHR",
+ "value": 5055,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_KHR_shader_clock"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SampleMaskOverrideCoverageNV",
+ "value": 5249,
+ "capabilities": [
+ "SampleRateShading"
+ ],
+ "extensions": [
+ "SPV_NV_sample_mask_override_coverage"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "GeometryShaderPassthroughNV",
+ "value": 5251,
+ "capabilities": [
+ "Geometry"
+ ],
+ "extensions": [
+ "SPV_NV_geometry_shader_passthrough"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ShaderViewportIndexLayerEXT",
+ "value": 5254,
+ "capabilities": [
+ "MultiViewport"
+ ],
+ "extensions": [
+ "SPV_EXT_shader_viewport_index_layer"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ShaderViewportIndexLayerNV",
+ "value": 5254,
+ "capabilities": [
+ "MultiViewport"
+ ],
+ "extensions": [
+ "SPV_NV_viewport_array2"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ShaderViewportMaskNV",
+ "value": 5255,
+ "capabilities": [
+ "ShaderViewportIndexLayerNV"
+ ],
+ "extensions": [
+ "SPV_NV_viewport_array2"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ShaderStereoViewNV",
+ "value": 5259,
+ "capabilities": [
+ "ShaderViewportMaskNV"
+ ],
+ "extensions": [
+ "SPV_NV_stereo_view_rendering"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "PerViewAttributesNV",
+ "value": 5260,
+ "capabilities": [
+ "MultiView"
+ ],
+ "extensions": [
+ "SPV_NVX_multiview_per_view_attributes"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FragmentFullyCoveredEXT",
+ "value": 5265,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_EXT_fragment_fully_covered"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "MeshShadingNV",
+ "value": 5266,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_NV_mesh_shader"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ImageFootprintNV",
+ "value": 5282,
+ "extensions": [
+ "SPV_NV_shader_image_footprint"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FragmentBarycentricKHR",
+ "value": 5284,
+ "extensions": [
+ "SPV_NV_fragment_shader_barycentric",
+ "SPV_KHR_fragment_shader_barycentric"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FragmentBarycentricNV",
+ "value": 5284,
+ "extensions": [
+ "SPV_NV_fragment_shader_barycentric",
+ "SPV_KHR_fragment_shader_barycentric"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ComputeDerivativeGroupQuadsNV",
+ "value": 5288,
+ "extensions": [
+ "SPV_NV_compute_shader_derivatives"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FragmentDensityEXT",
+ "value": 5291,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_EXT_fragment_invocation_density",
+ "SPV_NV_shading_rate"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ShadingRateNV",
+ "value": 5291,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_NV_shading_rate",
+ "SPV_EXT_fragment_invocation_density"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "GroupNonUniformPartitionedNV",
+ "value": 5297,
+ "extensions": [
+ "SPV_NV_shader_subgroup_partitioned"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ShaderNonUniform",
+ "value": 5301,
+ "capabilities": [
+ "Shader"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "ShaderNonUniformEXT",
+ "value": 5301,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_EXT_descriptor_indexing"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "RuntimeDescriptorArray",
+ "value": 5302,
+ "capabilities": [
+ "Shader"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "RuntimeDescriptorArrayEXT",
+ "value": 5302,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_EXT_descriptor_indexing"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "InputAttachmentArrayDynamicIndexing",
+ "value": 5303,
+ "capabilities": [
+ "InputAttachment"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "InputAttachmentArrayDynamicIndexingEXT",
+ "value": 5303,
+ "capabilities": [
+ "InputAttachment"
+ ],
+ "extensions": [
+ "SPV_EXT_descriptor_indexing"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "UniformTexelBufferArrayDynamicIndexing",
+ "value": 5304,
+ "capabilities": [
+ "SampledBuffer"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "UniformTexelBufferArrayDynamicIndexingEXT",
+ "value": 5304,
+ "capabilities": [
+ "SampledBuffer"
+ ],
+ "extensions": [
+ "SPV_EXT_descriptor_indexing"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "StorageTexelBufferArrayDynamicIndexing",
+ "value": 5305,
+ "capabilities": [
+ "ImageBuffer"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "StorageTexelBufferArrayDynamicIndexingEXT",
+ "value": 5305,
+ "capabilities": [
+ "ImageBuffer"
+ ],
+ "extensions": [
+ "SPV_EXT_descriptor_indexing"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "UniformBufferArrayNonUniformIndexing",
+ "value": 5306,
+ "capabilities": [
+ "ShaderNonUniform"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "UniformBufferArrayNonUniformIndexingEXT",
+ "value": 5306,
+ "capabilities": [
+ "ShaderNonUniform"
+ ],
+ "extensions": [
+ "SPV_EXT_descriptor_indexing"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "SampledImageArrayNonUniformIndexing",
+ "value": 5307,
+ "capabilities": [
+ "ShaderNonUniform"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "SampledImageArrayNonUniformIndexingEXT",
+ "value": 5307,
+ "capabilities": [
+ "ShaderNonUniform"
+ ],
+ "extensions": [
+ "SPV_EXT_descriptor_indexing"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "StorageBufferArrayNonUniformIndexing",
+ "value": 5308,
+ "capabilities": [
+ "ShaderNonUniform"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "StorageBufferArrayNonUniformIndexingEXT",
+ "value": 5308,
+ "capabilities": [
+ "ShaderNonUniform"
+ ],
+ "extensions": [
+ "SPV_EXT_descriptor_indexing"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "StorageImageArrayNonUniformIndexing",
+ "value": 5309,
+ "capabilities": [
+ "ShaderNonUniform"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "StorageImageArrayNonUniformIndexingEXT",
+ "value": 5309,
+ "capabilities": [
+ "ShaderNonUniform"
+ ],
+ "extensions": [
+ "SPV_EXT_descriptor_indexing"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "InputAttachmentArrayNonUniformIndexing",
+ "value": 5310,
+ "capabilities": [
+ "InputAttachment",
+ "ShaderNonUniform"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "InputAttachmentArrayNonUniformIndexingEXT",
+ "value": 5310,
+ "capabilities": [
+ "InputAttachment",
+ "ShaderNonUniform"
+ ],
+ "extensions": [
+ "SPV_EXT_descriptor_indexing"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "UniformTexelBufferArrayNonUniformIndexing",
+ "value": 5311,
+ "capabilities": [
+ "SampledBuffer",
+ "ShaderNonUniform"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "UniformTexelBufferArrayNonUniformIndexingEXT",
+ "value": 5311,
+ "capabilities": [
+ "SampledBuffer",
+ "ShaderNonUniform"
+ ],
+ "extensions": [
+ "SPV_EXT_descriptor_indexing"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "StorageTexelBufferArrayNonUniformIndexing",
+ "value": 5312,
+ "capabilities": [
+ "ImageBuffer",
+ "ShaderNonUniform"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "StorageTexelBufferArrayNonUniformIndexingEXT",
+ "value": 5312,
+ "capabilities": [
+ "ImageBuffer",
+ "ShaderNonUniform"
+ ],
+ "extensions": [
+ "SPV_EXT_descriptor_indexing"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "RayTracingNV",
+ "value": 5340,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "RayTracingMotionBlurNV",
+ "value": 5341,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_NV_ray_tracing_motion_blur"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "VulkanMemoryModel",
+ "value": 5345,
+ "version": "1.5"
+ },
+ {
+ "enumerant": "VulkanMemoryModelKHR",
+ "value": 5345,
+ "extensions": [
+ "SPV_KHR_vulkan_memory_model"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "VulkanMemoryModelDeviceScope",
+ "value": 5346,
+ "version": "1.5"
+ },
+ {
+ "enumerant": "VulkanMemoryModelDeviceScopeKHR",
+ "value": 5346,
+ "extensions": [
+ "SPV_KHR_vulkan_memory_model"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "PhysicalStorageBufferAddresses",
+ "value": 5347,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_EXT_physical_storage_buffer",
+ "SPV_KHR_physical_storage_buffer"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "PhysicalStorageBufferAddressesEXT",
+ "value": 5347,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_EXT_physical_storage_buffer"
+ ],
+ "version": "1.5"
+ },
+ {
+ "enumerant": "ComputeDerivativeGroupLinearNV",
+ "value": 5350,
+ "extensions": [
+ "SPV_NV_compute_shader_derivatives"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "RayTracingProvisionalKHR",
+ "value": 5353,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_KHR_ray_tracing"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "CooperativeMatrixNV",
+ "value": 5357,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_NV_cooperative_matrix"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FragmentShaderSampleInterlockEXT",
+ "value": 5363,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_EXT_fragment_shader_interlock"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FragmentShaderShadingRateInterlockEXT",
+ "value": 5372,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_EXT_fragment_shader_interlock"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ShaderSMBuiltinsNV",
+ "value": 5373,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_NV_shader_sm_builtins"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FragmentShaderPixelInterlockEXT",
+ "value": 5378,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_EXT_fragment_shader_interlock"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "DemoteToHelperInvocation",
+ "value": 5379,
+ "capabilities": [
+ "Shader"
+ ],
+ "version": "1.6"
+ },
+ {
+ "enumerant": "DemoteToHelperInvocationEXT",
+ "value": 5379,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_EXT_demote_to_helper_invocation"
+ ],
+ "version": "1.6"
+ },
+ {
+ "enumerant": "BindlessTextureNV",
+ "value": 5390,
+ "extensions": [
+ "SPV_NV_bindless_texture"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SubgroupShuffleINTEL",
+ "value": 5568,
+ "extensions": [
+ "SPV_INTEL_subgroups"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SubgroupBufferBlockIOINTEL",
+ "value": 5569,
+ "extensions": [
+ "SPV_INTEL_subgroups"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SubgroupImageBlockIOINTEL",
+ "value": 5570,
+ "extensions": [
+ "SPV_INTEL_subgroups"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SubgroupImageMediaBlockIOINTEL",
+ "value": 5579,
+ "extensions": [
+ "SPV_INTEL_media_block_io"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "RoundToInfinityINTEL",
+ "value": 5582,
+ "extensions": [
+ "SPV_INTEL_float_controls2"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FloatingPointModeINTEL",
+ "value": 5583,
+ "extensions": [
+ "SPV_INTEL_float_controls2"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "IntegerFunctions2INTEL",
+ "value": 5584,
+ "capabilities": [
+ "Shader"
+ ],
+ "extensions": [
+ "SPV_INTEL_shader_integer_functions2"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FunctionPointersINTEL",
+ "value": 5603,
+ "extensions": [
+ "SPV_INTEL_function_pointers"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "IndirectReferencesINTEL",
+ "value": 5604,
+ "extensions": [
+ "SPV_INTEL_function_pointers"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "AsmINTEL",
+ "value": 5606,
+ "extensions": [
+ "SPV_INTEL_inline_assembly"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "AtomicFloat32MinMaxEXT",
+ "value": 5612,
+ "extensions": [
+ "SPV_EXT_shader_atomic_float_min_max"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "AtomicFloat64MinMaxEXT",
+ "value": 5613,
+ "extensions": [
+ "SPV_EXT_shader_atomic_float_min_max"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "AtomicFloat16MinMaxEXT",
+ "value": 5616,
+ "extensions": [
+ "SPV_EXT_shader_atomic_float_min_max"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "VectorComputeINTEL",
+ "value": 5617,
+ "capabilities": [
+ "VectorAnyINTEL"
+ ],
+ "extensions": [
+ "SPV_INTEL_vector_compute"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "VectorAnyINTEL",
+ "value": 5619,
+ "extensions": [
+ "SPV_INTEL_vector_compute"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ExpectAssumeKHR",
+ "value": 5629,
+ "extensions": [
+ "SPV_KHR_expect_assume"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SubgroupAvcMotionEstimationINTEL",
+ "value": 5696,
+ "extensions": [
+ "SPV_INTEL_device_side_avc_motion_estimation"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SubgroupAvcMotionEstimationIntraINTEL",
+ "value": 5697,
+ "extensions": [
+ "SPV_INTEL_device_side_avc_motion_estimation"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "SubgroupAvcMotionEstimationChromaINTEL",
+ "value": 5698,
+ "extensions": [
+ "SPV_INTEL_device_side_avc_motion_estimation"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "VariableLengthArrayINTEL",
+ "value": 5817,
+ "extensions": [
+ "SPV_INTEL_variable_length_array"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FunctionFloatControlINTEL",
+ "value": 5821,
+ "extensions": [
+ "SPV_INTEL_float_controls2"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FPGAMemoryAttributesINTEL",
+ "value": 5824,
+ "extensions": [
+ "SPV_INTEL_fpga_memory_attributes"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FPFastMathModeINTEL",
+ "value": 5837,
+ "capabilities": [
+ "Kernel"
+ ],
+ "extensions": [
+ "SPV_INTEL_fp_fast_math_mode"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ArbitraryPrecisionIntegersINTEL",
+ "value": 5844,
+ "extensions": [
+ "SPV_INTEL_arbitrary_precision_integers"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ArbitraryPrecisionFloatingPointINTEL",
+ "value": 5845,
+ "extensions": [
+ "SPV_INTEL_arbitrary_precision_floating_point"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "UnstructuredLoopControlsINTEL",
+ "value": 5886,
+ "extensions": [
+ "SPV_INTEL_unstructured_loop_controls"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FPGALoopControlsINTEL",
+ "value": 5888,
+ "extensions": [
+ "SPV_INTEL_fpga_loop_controls"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "KernelAttributesINTEL",
+ "value": 5892,
+ "extensions": [
+ "SPV_INTEL_kernel_attributes"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FPGAKernelAttributesINTEL",
+ "value": 5897,
+ "extensions": [
+ "SPV_INTEL_kernel_attributes"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FPGAMemoryAccessesINTEL",
+ "value": 5898,
+ "extensions": [
+ "SPV_INTEL_fpga_memory_accesses"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FPGAClusterAttributesINTEL",
+ "value": 5904,
+ "extensions": [
+ "SPV_INTEL_fpga_cluster_attributes"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "LoopFuseINTEL",
+ "value": 5906,
+ "extensions": [
+ "SPV_INTEL_loop_fuse"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FPGABufferLocationINTEL",
+ "value": 5920,
+ "extensions": [
+ "SPV_INTEL_fpga_buffer_location"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "ArbitraryPrecisionFixedPointINTEL",
+ "value": 5922,
+ "extensions": [
+ "SPV_INTEL_arbitrary_precision_fixed_point"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "USMStorageClassesINTEL",
+ "value": 5935,
+ "extensions": [
+ "SPV_INTEL_usm_storage_classes"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "IOPipesINTEL",
+ "value": 5943,
+ "extensions": [
+ "SPV_INTEL_io_pipes"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "BlockingPipesINTEL",
+ "value": 5945,
+ "extensions": [
+ "SPV_INTEL_blocking_pipes"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "FPGARegINTEL",
+ "value": 5948,
+ "extensions": [
+ "SPV_INTEL_fpga_reg"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "DotProductInputAll",
+ "value": 6016,
+ "version": "1.6"
+ },
+ {
+ "enumerant": "DotProductInputAllKHR",
+ "value": 6016,
+ "extensions": [
+ "SPV_KHR_integer_dot_product"
+ ],
+ "version": "1.6"
+ },
+ {
+ "enumerant": "DotProductInput4x8Bit",
+ "value": 6017,
+ "capabilities": [
+ "Int8"
+ ],
+ "version": "1.6"
+ },
+ {
+ "enumerant": "DotProductInput4x8BitKHR",
+ "value": 6017,
+ "capabilities": [
+ "Int8"
+ ],
+ "extensions": [
+ "SPV_KHR_integer_dot_product"
+ ],
+ "version": "1.6"
+ },
+ {
+ "enumerant": "DotProductInput4x8BitPacked",
+ "value": 6018,
+ "version": "1.6"
+ },
+ {
+ "enumerant": "DotProductInput4x8BitPackedKHR",
+ "value": 6018,
+ "extensions": [
+ "SPV_KHR_integer_dot_product"
+ ],
+ "version": "1.6"
+ },
+ {
+ "enumerant": "DotProduct",
+ "value": 6019,
+ "version": "1.6"
+ },
+ {
+ "enumerant": "DotProductKHR",
+ "value": 6019,
+ "extensions": [
+ "SPV_KHR_integer_dot_product"
+ ],
+ "version": "1.6"
+ },
+ {
+ "enumerant": "BitInstructions",
+ "value": 6025,
+ "extensions": [
+ "SPV_KHR_bit_instructions"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "AtomicFloat32AddEXT",
+ "value": 6033,
+ "extensions": [
+ "SPV_EXT_shader_atomic_float_add"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "AtomicFloat64AddEXT",
+ "value": 6034,
+ "extensions": [
+ "SPV_EXT_shader_atomic_float_add"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "LongConstantCompositeINTEL",
+ "value": 6089,
+ "extensions": [
+ "SPV_INTEL_long_constant_composite"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "OptNoneINTEL",
+ "value": 6094,
+ "extensions": [
+ "SPV_INTEL_optnone"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "AtomicFloat16AddEXT",
+ "value": 6095,
+ "extensions": [
+ "SPV_EXT_shader_atomic_float16_add"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "DebugInfoModuleINTEL",
+ "value": 6114,
+ "extensions": [
+ "SPV_INTEL_debug_module"
+ ],
+ "version": "None"
+ }
+ ]
+ },
+ {
+ "category": "ValueEnum",
+ "kind": "RayQueryIntersection",
+ "enumerants": [
+ {
+ "enumerant": "RayQueryCandidateIntersectionKHR",
+ "value": 0,
+ "capabilities": [
+ "RayQueryKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "RayQueryCommittedIntersectionKHR",
+ "value": 1,
+ "capabilities": [
+ "RayQueryKHR"
+ ],
+ "version": "None"
+ }
+ ]
+ },
+ {
+ "category": "ValueEnum",
+ "kind": "RayQueryCommittedIntersectionType",
+ "enumerants": [
+ {
+ "enumerant": "RayQueryCommittedIntersectionNoneKHR",
+ "value": 0,
+ "capabilities": [
+ "RayQueryKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "RayQueryCommittedIntersectionTriangleKHR",
+ "value": 1,
+ "capabilities": [
+ "RayQueryKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "RayQueryCommittedIntersectionGeneratedKHR",
+ "value": 2,
+ "capabilities": [
+ "RayQueryKHR"
+ ],
+ "version": "None"
+ }
+ ]
+ },
+ {
+ "category": "ValueEnum",
+ "kind": "RayQueryCandidateIntersectionType",
+ "enumerants": [
+ {
+ "enumerant": "RayQueryCandidateIntersectionTriangleKHR",
+ "value": 0,
+ "capabilities": [
+ "RayQueryKHR"
+ ],
+ "version": "None"
+ },
+ {
+ "enumerant": "RayQueryCandidateIntersectionAABBKHR",
+ "value": 1,
+ "capabilities": [
+ "RayQueryKHR"
+ ],
+ "version": "None"
+ }
+ ]
+ },
+ {
+ "category": "ValueEnum",
+ "kind": "PackedVectorFormat",
+ "enumerants": [
+ {
+ "enumerant": "PackedVectorFormat4x8Bit",
+ "value": 0,
+ "version": "1.6"
+ },
+ {
+ "enumerant": "PackedVectorFormat4x8BitKHR",
+ "value": 0,
+ "extensions": [
+ "SPV_KHR_integer_dot_product"
+ ],
+ "version": "1.6"
+ }
+ ]
+ },
+ {
+ "category": "Id",
+ "kind": "IdResultType",
+ "doc": "Reference to an <id> representing the result's type of the enclosing instruction"
+ },
+ {
+ "category": "Id",
+ "kind": "IdResult",
+ "doc": "Definition of an <id> representing the result of the enclosing instruction"
+ },
+ {
+ "category": "Id",
+ "kind": "IdMemorySemantics",
+ "doc": "Reference to an <id> representing a 32-bit integer that is a mask from the MemorySemantics operand kind"
+ },
+ {
+ "category": "Id",
+ "kind": "IdScope",
+ "doc": "Reference to an <id> representing a 32-bit integer that is a mask from the Scope operand kind"
+ },
+ {
+ "category": "Id",
+ "kind": "IdRef",
+ "doc": "Reference to an <id>"
+ },
+ {
+ "category": "Literal",
+ "kind": "LiteralInteger",
+ "doc": "An integer consuming one or more words"
+ },
+ {
+ "category": "Literal",
+ "kind": "LiteralString",
+ "doc": "A null-terminated stream of characters consuming an integral number of words"
+ },
+ {
+ "category": "Literal",
+ "kind": "LiteralContextDependentNumber",
+ "doc": "A literal number whose size and format are determined by a previous operand in the enclosing instruction"
+ },
+ {
+ "category": "Literal",
+ "kind": "LiteralExtInstInteger",
+ "doc": "A 32-bit unsigned integer indicating which instruction to use and determining the layout of following operands (for OpExtInst)"
+ },
+ {
+ "category": "Literal",
+ "kind": "LiteralSpecConstantOpInteger",
+ "doc": "An opcode indicating the operation to be performed and determining the layout of following operands (for OpSpecConstantOp)"
+ },
+ {
+ "category": "Composite",
+ "kind": "PairLiteralIntegerIdRef",
+ "bases": [
+ "LiteralInteger",
+ "IdRef"
+ ]
+ },
+ {
+ "category": "Composite",
+ "kind": "PairIdRefLiteralInteger",
+ "bases": [
+ "IdRef",
+ "LiteralInteger"
+ ]
+ },
+ {
+ "category": "Composite",
+ "kind": "PairIdRefIdRef",
+ "bases": [
+ "IdRef",
+ "IdRef"
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/src/buffer/allocator.rs b/src/buffer/allocator.rs
new file mode 100644
index 0000000..8d591c4
--- /dev/null
+++ b/src/buffer/allocator.rs
@@ -0,0 +1,474 @@
+// Copyright (c) 2017 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+//! Efficiently suballocates buffers into smaller subbuffers.
+
+use super::{
+ sys::BufferCreateInfo, Buffer, BufferContents, BufferError, BufferMemory, BufferUsage,
+ Subbuffer,
+};
+use crate::{
+ device::{Device, DeviceOwned},
+ memory::{
+ allocator::{
+ align_up, AllocationCreateInfo, AllocationCreationError, DeviceLayout, MemoryAllocator,
+ MemoryUsage, StandardMemoryAllocator,
+ },
+ DeviceAlignment,
+ },
+ DeviceSize, NonZeroDeviceSize,
+};
+use crossbeam_queue::ArrayQueue;
+use std::{
+ cell::UnsafeCell,
+ cmp,
+ hash::{Hash, Hasher},
+ mem::ManuallyDrop,
+ sync::Arc,
+};
+
+const MAX_ARENAS: usize = 32;
+
+/// Efficiently suballocates buffers into smaller subbuffers.
+///
+/// This allocator is especially suitable when you want to upload or download some data regularly
+/// (for example, at each frame for a video game).
+///
+/// # Algorithm
+///
+/// The allocator keeps a pool of *arenas*. An arena is simply a buffer in which *arena allocation*
+/// takes place, also known as *bump allocation* or *linear allocation*. Every time you allocate,
+/// one of these arenas is suballocated. If there is no arena that is currently available, one will
+/// be allocated. After all subbuffers allocated from an arena are dropped, the arena is
+/// automatically returned to the arena pool. If you try to allocate a subbuffer larger than the
+/// current size of an arena, the arenas are automatically resized.
+///
+/// No memory is allocated when the allocator is created, be it on the Vulkan or Rust side. That
+/// only happens once you allocate a subbuffer.
+///
+/// # Usage
+///
+/// Ideally, one arena should be able to fit all data you need to update per frame, so that each
+/// arena is submitted and freed once per frame. This way, the arena pool would also contain as
+/// many arenas as there are frames in flight on the thread. Otherwise, if your arenas are not able
+/// to fit everything each frame, what will likely happen is that each subbuffer will be
+/// allocated from an individual arena. This can impact efficiency both in terms of memory usage
+/// (because each arena has the same size, even if some of the subbuffers are way smaller) as well
+/// as performance, because the data could end up more physically separated in memory, which means
+/// the GPU would need to hop from place to place a lot more during a frame.
+///
+/// Ideally the result is something roughly like this:
+///
+/// ```plain
+/// +---------------------------------------------------------------------------------------------+
+/// | Memory Block |
+/// |-----+------+-----------------------+---------+-----------------------+------+---------+-----|
+/// | | | Frame 1 Arena | | Frame 2 Arena | | | |
+/// | ••• | Tex. |-------+-------+-------| Attach. |-------+-------+-------| Tex. | Attach. | ••• |
+/// | | | Vert. | Indx. | Unif. | | Vert. | Indx. | Unif. | | | |
+/// +-----+------+-------+-------+-------+---------+-------+-------+-------+------+---------+-----+
+/// ```
+///
+/// Download or device-only usage is much the same. Try to make the arenas fit all the data you
+/// need to store at once.
+///
+/// # Examples
+///
+/// ```
+/// use vulkano::buffer::allocator::SubbufferAllocator;
+/// use vulkano::command_buffer::{
+/// AutoCommandBufferBuilder, CommandBufferUsage, PrimaryCommandBufferAbstract,
+/// };
+/// use vulkano::sync::GpuFuture;
+/// # let queue: std::sync::Arc<vulkano::device::Queue> = return;
+/// # let memory_allocator: std::sync::Arc<vulkano::memory::allocator::StandardMemoryAllocator> = return;
+/// # let command_buffer_allocator: vulkano::command_buffer::allocator::StandardCommandBufferAllocator = return;
+///
+/// // Create the buffer allocator.
+/// let buffer_allocator = SubbufferAllocator::new(memory_allocator.clone(), Default::default());
+///
+/// for n in 0..25u32 {
+/// // Each loop allocates a new subbuffer and stores `data` in it.
+/// let data: [f32; 4] = [1.0, 0.5, n as f32 / 24.0, 0.0];
+/// let subbuffer = buffer_allocator.allocate_sized().unwrap();
+/// *subbuffer.write().unwrap() = data;
+///
+/// // You can then use `subbuffer` as if it was an entirely separate buffer.
+/// AutoCommandBufferBuilder::primary(
+/// &command_buffer_allocator,
+/// queue.queue_family_index(),
+/// CommandBufferUsage::OneTimeSubmit,
+/// )
+/// .unwrap()
+/// // For the sake of the example we just call `update_buffer` on the buffer, even though
+/// // it is pointless to do that.
+/// .update_buffer(subbuffer.clone(), &[0.2, 0.3, 0.4, 0.5])
+/// .unwrap()
+/// .build().unwrap()
+/// .execute(queue.clone())
+/// .unwrap()
+/// .then_signal_fence_and_flush()
+/// .unwrap();
+/// }
+/// ```
+#[derive(Debug)]
+pub struct SubbufferAllocator<A = Arc<StandardMemoryAllocator>> {
+ state: UnsafeCell<SubbufferAllocatorState<A>>,
+}
+
+impl<A> SubbufferAllocator<A>
+where
+ A: MemoryAllocator,
+{
+ /// Creates a new `SubbufferAllocator`.
+ pub fn new(memory_allocator: A, create_info: SubbufferAllocatorCreateInfo) -> Self {
+ let SubbufferAllocatorCreateInfo {
+ arena_size,
+ buffer_usage,
+ memory_usage,
+ _ne: _,
+ } = create_info;
+
+ let properties = memory_allocator.device().physical_device().properties();
+ let buffer_alignment = [
+ buffer_usage
+ .intersects(BufferUsage::UNIFORM_TEXEL_BUFFER | BufferUsage::STORAGE_TEXEL_BUFFER)
+ .then_some(properties.min_texel_buffer_offset_alignment),
+ buffer_usage
+ .contains(BufferUsage::UNIFORM_BUFFER)
+ .then_some(properties.min_uniform_buffer_offset_alignment),
+ buffer_usage
+ .contains(BufferUsage::STORAGE_BUFFER)
+ .then_some(properties.min_storage_buffer_offset_alignment),
+ ]
+ .into_iter()
+ .flatten()
+ .max()
+ .unwrap_or(DeviceAlignment::MIN);
+
+ SubbufferAllocator {
+ state: UnsafeCell::new(SubbufferAllocatorState {
+ memory_allocator,
+ buffer_usage,
+ memory_usage,
+ buffer_alignment,
+ arena_size,
+ arena: None,
+ free_start: 0,
+ reserve: None,
+ }),
+ }
+ }
+
+ /// Returns the current size of the arenas.
+ pub fn arena_size(&self) -> DeviceSize {
+ unsafe { &*self.state.get() }.arena_size
+ }
+
+ /// Sets the arena size to the provided `size`.
+ ///
+ /// The next time you allocate a subbuffer, a new arena will be allocated with the new size,
+ /// and all subsequently allocated arenas will also share the new size.
+ pub fn set_arena_size(&self, size: DeviceSize) {
+ let state = unsafe { &mut *self.state.get() };
+ state.arena_size = size;
+ state.arena = None;
+ state.reserve = None;
+ }
+
+ /// Ensures that the size of the current arena is at least `size`.
+ ///
+ /// If `size` is greater than the current arena size, then a new arena will be allocated with
+ /// the new size, and all subsequently allocated arenas will also share the new size. Otherwise
+ /// this has no effect.
+ pub fn reserve(&self, size: DeviceSize) -> Result<(), AllocationCreationError> {
+ if size > self.arena_size() {
+ let state = unsafe { &mut *self.state.get() };
+ state.arena_size = size;
+ state.reserve = None;
+ state.arena = Some(state.next_arena()?);
+ }
+
+ Ok(())
+ }
+
+ /// Allocates a subbuffer for sized data.
+ pub fn allocate_sized<T>(&self) -> Result<Subbuffer<T>, AllocationCreationError>
+ where
+ T: BufferContents,
+ {
+ let layout = T::LAYOUT.unwrap_sized();
+
+ unsafe { &mut *self.state.get() }
+ .allocate(layout)
+ .map(|subbuffer| unsafe { subbuffer.reinterpret_unchecked() })
+ }
+
+ /// Allocates a subbuffer for a slice.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `len` is zero.
+ pub fn allocate_slice<T>(
+ &self,
+ len: DeviceSize,
+ ) -> Result<Subbuffer<[T]>, AllocationCreationError>
+ where
+ T: BufferContents,
+ {
+ self.allocate_unsized(len)
+ }
+
+ /// Allocates a subbuffer for unsized data.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `len` is zero.
+ pub fn allocate_unsized<T>(
+ &self,
+ len: DeviceSize,
+ ) -> Result<Subbuffer<T>, AllocationCreationError>
+ where
+ T: BufferContents + ?Sized,
+ {
+ let len = NonZeroDeviceSize::new(len).expect("empty slices are not valid buffer contents");
+ let layout = T::LAYOUT.layout_for_len(len).unwrap();
+
+ unsafe { &mut *self.state.get() }
+ .allocate(layout)
+ .map(|subbuffer| unsafe { subbuffer.reinterpret_unchecked() })
+ }
+
+ /// Allocates a subbuffer with the given `layout`.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `layout.alignment()` exceeds `64`.
+ pub fn allocate(
+ &self,
+ layout: DeviceLayout,
+ ) -> Result<Subbuffer<[u8]>, AllocationCreationError> {
+ assert!(layout.alignment().as_devicesize() <= 64);
+
+ unsafe { &mut *self.state.get() }.allocate(layout)
+ }
+}
+
+unsafe impl<A> DeviceOwned for SubbufferAllocator<A>
+where
+ A: MemoryAllocator,
+{
+ fn device(&self) -> &Arc<Device> {
+ unsafe { &*self.state.get() }.memory_allocator.device()
+ }
+}
+
+#[derive(Debug)]
+struct SubbufferAllocatorState<A> {
+ memory_allocator: A,
+ buffer_usage: BufferUsage,
+ memory_usage: MemoryUsage,
+ // The alignment required for the subbuffers.
+ buffer_alignment: DeviceAlignment,
+ // The current size of the arenas.
+ arena_size: DeviceSize,
+ // Contains the buffer that is currently being suballocated.
+ arena: Option<Arc<Arena>>,
+ // Offset pointing to the start of free memory within the arena.
+ free_start: DeviceSize,
+ // When an `Arena` is dropped, it returns itself here for reuse.
+ reserve: Option<Arc<ArrayQueue<Arc<Buffer>>>>,
+}
+
+impl<A> SubbufferAllocatorState<A>
+where
+ A: MemoryAllocator,
+{
+ fn allocate(
+ &mut self,
+ layout: DeviceLayout,
+ ) -> Result<Subbuffer<[u8]>, AllocationCreationError> {
+ let size = layout.size();
+ let alignment = cmp::max(layout.alignment(), self.buffer_alignment);
+
+ loop {
+ if self.arena.is_none() {
+ // If the requested size is larger than the arenas, we need to resize them.
+ if self.arena_size < size {
+ self.arena_size = size * 2;
+ // We need to drop our reference to the old pool to make sure the arenas are
+ // dropped once no longer in use, and replace it with a new pool that will not
+ // be polluted with the outdates arenas.
+ self.reserve = None;
+ }
+ self.arena = Some(self.next_arena()?);
+ self.free_start = 0;
+ }
+
+ let arena = self.arena.as_ref().unwrap();
+ let allocation = match arena.buffer.memory() {
+ BufferMemory::Normal(a) => a,
+ BufferMemory::Sparse => unreachable!(),
+ };
+ let arena_offset = allocation.offset();
+ let atom_size = allocation.atom_size().unwrap_or(DeviceAlignment::MIN);
+
+ let alignment = cmp::max(alignment, atom_size);
+ let offset = align_up(arena_offset + self.free_start, alignment);
+
+ if offset + size <= arena_offset + self.arena_size {
+ let offset = offset - arena_offset;
+ self.free_start = offset + size;
+
+ return Ok(Subbuffer::from_arena(arena.clone(), offset, layout.size()));
+ }
+
+ // We reached the end of the arena, grab the next one.
+ self.arena = None;
+ }
+ }
+
+ fn next_arena(&mut self) -> Result<Arc<Arena>, AllocationCreationError> {
+ if self.reserve.is_none() {
+ self.reserve = Some(Arc::new(ArrayQueue::new(MAX_ARENAS)));
+ }
+ let reserve = self.reserve.as_ref().unwrap();
+
+ reserve
+ .pop()
+ .map(Ok)
+ .unwrap_or_else(|| self.create_arena())
+ .map(|buffer| {
+ Arc::new(Arena {
+ buffer: ManuallyDrop::new(buffer),
+ reserve: reserve.clone(),
+ })
+ })
+ }
+
+ fn create_arena(&self) -> Result<Arc<Buffer>, AllocationCreationError> {
+ Buffer::new(
+ &self.memory_allocator,
+ BufferCreateInfo {
+ usage: self.buffer_usage,
+ ..Default::default()
+ },
+ AllocationCreateInfo {
+ usage: self.memory_usage,
+ ..Default::default()
+ },
+ DeviceLayout::from_size_alignment(self.arena_size, 1).unwrap(),
+ )
+ .map_err(|err| match err {
+ BufferError::AllocError(err) => err,
+ // We don't use sparse-binding, concurrent sharing or external memory, therefore the
+ // other errors can't happen.
+ _ => unreachable!(),
+ })
+ }
+}
+
+#[derive(Debug)]
+pub(super) struct Arena {
+ buffer: ManuallyDrop<Arc<Buffer>>,
+ // Where we return the arena in our `Drop` impl.
+ reserve: Arc<ArrayQueue<Arc<Buffer>>>,
+}
+
+impl Arena {
+ pub(super) fn buffer(&self) -> &Arc<Buffer> {
+ &self.buffer
+ }
+}
+
+impl Drop for Arena {
+ fn drop(&mut self) {
+ let buffer = unsafe { ManuallyDrop::take(&mut self.buffer) };
+ let _ = self.reserve.push(buffer);
+ }
+}
+
+impl PartialEq for Arena {
+ fn eq(&self, other: &Self) -> bool {
+ self.buffer == other.buffer
+ }
+}
+
+impl Eq for Arena {}
+
+impl Hash for Arena {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.buffer.hash(state);
+ }
+}
+
+/// Parameters to create a new [`SubbufferAllocator`].
+pub struct SubbufferAllocatorCreateInfo {
+ /// Initial size of an arena in bytes.
+ ///
+ /// Ideally this should fit all the data you need to update per frame. So for example, if you
+ /// need to allocate buffers of size 1K, 2K and 5K each frame, then this should be 8K. If your
+ /// data is dynamically-sized then try to make an educated guess or simply leave the default.
+ ///
+ /// The default value is `0`.
+ pub arena_size: DeviceSize,
+
+ /// The buffer usage that all allocated buffers should have.
+ ///
+ /// The default value is [`BufferUsage::TRANSFER_SRC`].
+ pub buffer_usage: BufferUsage,
+
+ /// The memory usage that all buffers should be allocated with.
+ ///
+ /// The default value is [`MemoryUsage::Upload`].
+ pub memory_usage: MemoryUsage,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for SubbufferAllocatorCreateInfo {
+ #[inline]
+ fn default() -> Self {
+ SubbufferAllocatorCreateInfo {
+ arena_size: 0,
+ buffer_usage: BufferUsage::TRANSFER_SRC,
+ memory_usage: MemoryUsage::Upload,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn reserve() {
+ let (device, _) = gfx_dev_and_queue!();
+ let memory_allocator = StandardMemoryAllocator::new_default(device);
+
+ let buffer_allocator = SubbufferAllocator::new(memory_allocator, Default::default());
+ assert_eq!(buffer_allocator.arena_size(), 0);
+
+ buffer_allocator.reserve(83).unwrap();
+ assert_eq!(buffer_allocator.arena_size(), 83);
+ }
+
+ #[test]
+ fn capacity_increase() {
+ let (device, _) = gfx_dev_and_queue!();
+ let memory_allocator = StandardMemoryAllocator::new_default(device);
+
+ let buffer_allocator = SubbufferAllocator::new(memory_allocator, Default::default());
+ assert_eq!(buffer_allocator.arena_size(), 0);
+
+ buffer_allocator.allocate_sized::<u32>().unwrap();
+ assert_eq!(buffer_allocator.arena_size(), 8);
+ }
+}
diff --git a/src/buffer/cpu_access.rs b/src/buffer/cpu_access.rs
deleted file mode 100644
index 5c9bc19..0000000
--- a/src/buffer/cpu_access.rs
+++ /dev/null
@@ -1,659 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-//! Buffer whose content is accessible to the CPU.
-//!
-//! The `CpuAccessibleBuffer` is a basic general-purpose buffer. It can be used in any situation
-//! but may not perform as well as other buffer types.
-//!
-//! Each access from the CPU or from the GPU locks the whole buffer for either reading or writing.
-//! You can read the buffer multiple times simultaneously. Trying to read and write simultaneously,
-//! or write and write simultaneously will block.
-
-use crate::buffer::sys::BufferCreationError;
-use crate::buffer::sys::UnsafeBuffer;
-use crate::buffer::traits::BufferAccess;
-use crate::buffer::traits::BufferInner;
-use crate::buffer::traits::TypedBufferAccess;
-use crate::buffer::BufferUsage;
-use crate::device::physical::QueueFamily;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::device::Queue;
-use crate::memory::pool::AllocFromRequirementsFilter;
-use crate::memory::pool::AllocLayout;
-use crate::memory::pool::MappingRequirement;
-use crate::memory::pool::MemoryPool;
-use crate::memory::pool::MemoryPoolAlloc;
-use crate::memory::pool::PotentialDedicatedAllocation;
-use crate::memory::pool::StdMemoryPoolAlloc;
-use crate::memory::Content;
-use crate::memory::CpuAccess as MemCpuAccess;
-use crate::memory::DedicatedAlloc;
-use crate::memory::DeviceMemoryAllocError;
-use crate::sync::AccessError;
-use crate::sync::Sharing;
-use crate::DeviceSize;
-use parking_lot::RwLock;
-use parking_lot::RwLockReadGuard;
-use parking_lot::RwLockWriteGuard;
-use smallvec::SmallVec;
-use std::error;
-use std::fmt;
-use std::hash::Hash;
-use std::hash::Hasher;
-use std::iter;
-use std::marker::PhantomData;
-use std::mem;
-use std::ops::Deref;
-use std::ops::DerefMut;
-use std::ptr;
-use std::sync::atomic::AtomicUsize;
-use std::sync::atomic::Ordering;
-use std::sync::Arc;
-
-/// Buffer whose content is accessible by the CPU.
-///
-/// Setting the `host_cached` field on the various initializers to `true` will make it so
-/// the `CpuAccessibleBuffer` prefers to allocate from host_cached memory. Host cached
-/// memory caches GPU data on the CPU side. This can be more performant in cases where
-/// the cpu needs to read data coming off the GPU.
-#[derive(Debug)]
-pub struct CpuAccessibleBuffer<T: ?Sized, A = PotentialDedicatedAllocation<StdMemoryPoolAlloc>> {
- // Inner content.
- inner: UnsafeBuffer,
-
- // The memory held by the buffer.
- memory: A,
-
- // Access pattern of the buffer.
- // Every time the user tries to read or write the buffer from the CPU, this `RwLock` is kept
- // locked and its content is checked to verify that we are allowed access. Every time the user
- // tries to submit this buffer for the GPU, this `RwLock` is briefly locked and modified.
- access: RwLock<CurrentGpuAccess>,
-
- // Queue families allowed to access this buffer.
- queue_families: SmallVec<[u32; 4]>,
-
- // Necessary to make it compile.
- marker: PhantomData<Box<T>>,
-}
-
-#[derive(Debug)]
-enum CurrentGpuAccess {
- NonExclusive {
- // Number of non-exclusive GPU accesses. Can be 0.
- num: AtomicUsize,
- },
- Exclusive {
- // Number of exclusive locks. Cannot be 0. If 0 is reached, we must jump to `NonExclusive`.
- num: usize,
- },
-}
-
-impl<T> CpuAccessibleBuffer<T> {
- /// Builds a new buffer with some data in it. Only allowed for sized data.
- pub fn from_data(
- device: Arc<Device>,
- usage: BufferUsage,
- host_cached: bool,
- data: T,
- ) -> Result<Arc<CpuAccessibleBuffer<T>>, DeviceMemoryAllocError>
- where
- T: Content + Copy + 'static,
- {
- unsafe {
- let uninitialized = CpuAccessibleBuffer::raw(
- device,
- mem::size_of::<T>() as DeviceSize,
- usage,
- host_cached,
- iter::empty(),
- )?;
-
- // Note that we are in panic-unsafety land here. However a panic should never ever
- // happen here, so in theory we are safe.
- // TODO: check whether that's true ^
-
- {
- let mut mapping = uninitialized.write().unwrap();
- ptr::write::<T>(&mut *mapping, data)
- }
-
- Ok(uninitialized)
- }
- }
-
- /// Builds a new uninitialized buffer. Only allowed for sized data.
- #[inline]
- pub unsafe fn uninitialized(
- device: Arc<Device>,
- usage: BufferUsage,
- host_cached: bool,
- ) -> Result<Arc<CpuAccessibleBuffer<T>>, DeviceMemoryAllocError> {
- CpuAccessibleBuffer::raw(
- device,
- mem::size_of::<T>() as DeviceSize,
- usage,
- host_cached,
- iter::empty(),
- )
- }
-}
-
-impl<T> CpuAccessibleBuffer<[T]> {
- /// Builds a new buffer that contains an array `T`. The initial data comes from an iterator
- /// that produces that list of Ts.
- pub fn from_iter<I>(
- device: Arc<Device>,
- usage: BufferUsage,
- host_cached: bool,
- data: I,
- ) -> Result<Arc<CpuAccessibleBuffer<[T]>>, DeviceMemoryAllocError>
- where
- I: ExactSizeIterator<Item = T>,
- T: Content + 'static,
- {
- unsafe {
- let uninitialized = CpuAccessibleBuffer::uninitialized_array(
- device,
- data.len() as DeviceSize,
- usage,
- host_cached,
- )?;
-
- // Note that we are in panic-unsafety land here. However a panic should never ever
- // happen here, so in theory we are safe.
- // TODO: check whether that's true ^
-
- {
- let mut mapping = uninitialized.write().unwrap();
-
- for (i, o) in data.zip(mapping.iter_mut()) {
- ptr::write(o, i);
- }
- }
-
- Ok(uninitialized)
- }
- }
-
- /// Builds a new buffer. Can be used for arrays.
- #[inline]
- pub unsafe fn uninitialized_array(
- device: Arc<Device>,
- len: DeviceSize,
- usage: BufferUsage,
- host_cached: bool,
- ) -> Result<Arc<CpuAccessibleBuffer<[T]>>, DeviceMemoryAllocError> {
- CpuAccessibleBuffer::raw(
- device,
- len * mem::size_of::<T>() as DeviceSize,
- usage,
- host_cached,
- iter::empty(),
- )
- }
-}
-
-impl<T: ?Sized> CpuAccessibleBuffer<T> {
- /// Builds a new buffer without checking the size.
- ///
- /// # Safety
- ///
- /// You must ensure that the size that you pass is correct for `T`.
- ///
- pub unsafe fn raw<'a, I>(
- device: Arc<Device>,
- size: DeviceSize,
- usage: BufferUsage,
- host_cached: bool,
- queue_families: I,
- ) -> Result<Arc<CpuAccessibleBuffer<T>>, DeviceMemoryAllocError>
- where
- I: IntoIterator<Item = QueueFamily<'a>>,
- {
- let queue_families = queue_families
- .into_iter()
- .map(|f| f.id())
- .collect::<SmallVec<[u32; 4]>>();
-
- let (buffer, mem_reqs) = {
- let sharing = if queue_families.len() >= 2 {
- Sharing::Concurrent(queue_families.iter().cloned())
- } else {
- Sharing::Exclusive
- };
-
- match UnsafeBuffer::new(device.clone(), size, usage, sharing, None) {
- Ok(b) => b,
- Err(BufferCreationError::AllocError(err)) => return Err(err),
- Err(_) => unreachable!(), // We don't use sparse binding, therefore the other
- // errors can't happen
- }
- };
-
- let mem = MemoryPool::alloc_from_requirements(
- &Device::standard_pool(&device),
- &mem_reqs,
- AllocLayout::Linear,
- MappingRequirement::Map,
- DedicatedAlloc::Buffer(&buffer),
- |m| {
- if m.is_host_cached() {
- if host_cached {
- AllocFromRequirementsFilter::Preferred
- } else {
- AllocFromRequirementsFilter::Allowed
- }
- } else {
- if host_cached {
- AllocFromRequirementsFilter::Allowed
- } else {
- AllocFromRequirementsFilter::Preferred
- }
- }
- },
- )?;
- debug_assert!((mem.offset() % mem_reqs.alignment) == 0);
- debug_assert!(mem.mapped_memory().is_some());
- buffer.bind_memory(mem.memory(), mem.offset())?;
-
- Ok(Arc::new(CpuAccessibleBuffer {
- inner: buffer,
- memory: mem,
- access: RwLock::new(CurrentGpuAccess::NonExclusive {
- num: AtomicUsize::new(0),
- }),
- queue_families: queue_families,
- marker: PhantomData,
- }))
- }
-}
-
-impl<T: ?Sized, A> CpuAccessibleBuffer<T, A> {
- /// Returns the queue families this buffer can be used on.
- // TODO: use a custom iterator
- #[inline]
- pub fn queue_families(&self) -> Vec<QueueFamily> {
- self.queue_families
- .iter()
- .map(|&num| {
- self.device()
- .physical_device()
- .queue_family_by_id(num)
- .unwrap()
- })
- .collect()
- }
-}
-
-impl<T: ?Sized, A> CpuAccessibleBuffer<T, A>
-where
- T: Content + 'static,
- A: MemoryPoolAlloc,
-{
- /// Locks the buffer in order to read its content from the CPU.
- ///
- /// If the buffer is currently used in exclusive mode by the GPU, this function will return
- /// an error. Similarly if you called `write()` on the buffer and haven't dropped the lock,
- /// this function will return an error as well.
- ///
- /// After this function successfully locks the buffer, any attempt to submit a command buffer
- /// that uses it in exclusive mode will fail. You can still submit this buffer for non-exclusive
- /// accesses (ie. reads).
- #[inline]
- pub fn read(&self) -> Result<ReadLock<T>, ReadLockError> {
- let lock = match self.access.try_read() {
- Some(l) => l,
- // TODO: if a user simultaneously calls .write(), and write() is currently finding out
- // that the buffer is in fact GPU locked, then we will return a CpuWriteLocked
- // error instead of a GpuWriteLocked ; is this a problem? how do we fix this?
- None => return Err(ReadLockError::CpuWriteLocked),
- };
-
- if let CurrentGpuAccess::Exclusive { .. } = *lock {
- return Err(ReadLockError::GpuWriteLocked);
- }
-
- let offset = self.memory.offset();
- let range = offset..offset + self.inner.size();
-
- Ok(ReadLock {
- inner: unsafe { self.memory.mapped_memory().unwrap().read_write(range) },
- lock: lock,
- })
- }
-
- /// Locks the buffer in order to write its content from the CPU.
- ///
- /// If the buffer is currently in use by the GPU, this function will return an error. Similarly
- /// if you called `read()` on the buffer and haven't dropped the lock, this function will
- /// return an error as well.
- ///
- /// After this function successfully locks the buffer, any attempt to submit a command buffer
- /// that uses it and any attempt to call `read()` will return an error.
- #[inline]
- pub fn write(&self) -> Result<WriteLock<T>, WriteLockError> {
- let lock = match self.access.try_write() {
- Some(l) => l,
- // TODO: if a user simultaneously calls .read() or .write(), and the function is
- // currently finding out that the buffer is in fact GPU locked, then we will
- // return a CpuLocked error instead of a GpuLocked ; is this a problem?
- // how do we fix this?
- None => return Err(WriteLockError::CpuLocked),
- };
-
- match *lock {
- CurrentGpuAccess::NonExclusive { ref num } if num.load(Ordering::SeqCst) == 0 => (),
- _ => return Err(WriteLockError::GpuLocked),
- }
-
- let offset = self.memory.offset();
- let range = offset..offset + self.inner.size();
-
- Ok(WriteLock {
- inner: unsafe { self.memory.mapped_memory().unwrap().read_write(range) },
- lock: lock,
- })
- }
-}
-
-unsafe impl<T: ?Sized, A> BufferAccess for CpuAccessibleBuffer<T, A>
-where
- T: 'static + Send + Sync,
-{
- #[inline]
- fn inner(&self) -> BufferInner {
- BufferInner {
- buffer: &self.inner,
- offset: 0,
- }
- }
-
- #[inline]
- fn size(&self) -> DeviceSize {
- self.inner.size()
- }
-
- #[inline]
- fn conflict_key(&self) -> (u64, u64) {
- (self.inner.key(), 0)
- }
-
- #[inline]
- fn try_gpu_lock(&self, exclusive_access: bool, _: &Queue) -> Result<(), AccessError> {
- if exclusive_access {
- let mut lock = match self.access.try_write() {
- Some(lock) => lock,
- None => return Err(AccessError::AlreadyInUse),
- };
-
- match *lock {
- CurrentGpuAccess::NonExclusive { ref num } if num.load(Ordering::SeqCst) == 0 => (),
- _ => return Err(AccessError::AlreadyInUse),
- };
-
- *lock = CurrentGpuAccess::Exclusive { num: 1 };
- Ok(())
- } else {
- let lock = match self.access.try_read() {
- Some(lock) => lock,
- None => return Err(AccessError::AlreadyInUse),
- };
-
- match *lock {
- CurrentGpuAccess::Exclusive { .. } => return Err(AccessError::AlreadyInUse),
- CurrentGpuAccess::NonExclusive { ref num } => num.fetch_add(1, Ordering::SeqCst),
- };
-
- Ok(())
- }
- }
-
- #[inline]
- unsafe fn increase_gpu_lock(&self) {
- // First, handle if we have a non-exclusive access.
- {
- // Since the buffer is in use by the GPU, it is invalid to hold a write-lock to
- // the buffer. The buffer can still be briefly in a write-locked state for the duration
- // of the check though.
- let read_lock = self.access.read();
- if let CurrentGpuAccess::NonExclusive { ref num } = *read_lock {
- let prev = num.fetch_add(1, Ordering::SeqCst);
- debug_assert!(prev >= 1);
- return;
- }
- }
-
- // If we reach here, this means that `access` contains `CurrentGpuAccess::Exclusive`.
- {
- // Same remark as above, but for writing.
- let mut write_lock = self.access.write();
- if let CurrentGpuAccess::Exclusive { ref mut num } = *write_lock {
- *num += 1;
- } else {
- unreachable!()
- }
- }
- }
-
- #[inline]
- unsafe fn unlock(&self) {
- // First, handle if we had a non-exclusive access.
- {
- // Since the buffer is in use by the GPU, it is invalid to hold a write-lock to
- // the buffer. The buffer can still be briefly in a write-locked state for the duration
- // of the check though.
- let read_lock = self.access.read();
- if let CurrentGpuAccess::NonExclusive { ref num } = *read_lock {
- let prev = num.fetch_sub(1, Ordering::SeqCst);
- debug_assert!(prev >= 1);
- return;
- }
- }
-
- // If we reach here, this means that `access` contains `CurrentGpuAccess::Exclusive`.
- {
- // Same remark as above, but for writing.
- let mut write_lock = self.access.write();
- if let CurrentGpuAccess::Exclusive { ref mut num } = *write_lock {
- if *num != 1 {
- *num -= 1;
- return;
- }
- } else {
- // Can happen if we lock in exclusive mode N times, and unlock N+1 times with the
- // last two unlocks happen simultaneously.
- panic!()
- }
-
- *write_lock = CurrentGpuAccess::NonExclusive {
- num: AtomicUsize::new(0),
- };
- }
- }
-}
-
-unsafe impl<T: ?Sized, A> TypedBufferAccess for CpuAccessibleBuffer<T, A>
-where
- T: 'static + Send + Sync,
-{
- type Content = T;
-}
-
-unsafe impl<T: ?Sized, A> DeviceOwned for CpuAccessibleBuffer<T, A> {
- #[inline]
- fn device(&self) -> &Arc<Device> {
- self.inner.device()
- }
-}
-
-impl<T: ?Sized, A> PartialEq for CpuAccessibleBuffer<T, A>
-where
- T: 'static + Send + Sync,
-{
- #[inline]
- fn eq(&self, other: &Self) -> bool {
- self.inner() == other.inner() && self.size() == other.size()
- }
-}
-
-impl<T: ?Sized, A> Eq for CpuAccessibleBuffer<T, A> where T: 'static + Send + Sync {}
-
-impl<T: ?Sized, A> Hash for CpuAccessibleBuffer<T, A>
-where
- T: 'static + Send + Sync,
-{
- #[inline]
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.inner().hash(state);
- self.size().hash(state);
- }
-}
-
-/// Object that can be used to read or write the content of a `CpuAccessibleBuffer`.
-///
-/// Note that this object holds a rwlock read guard on the chunk. If another thread tries to access
-/// this buffer's content or tries to submit a GPU command that uses this buffer, it will block.
-pub struct ReadLock<'a, T: ?Sized + 'a> {
- inner: MemCpuAccess<'a, T>,
- lock: RwLockReadGuard<'a, CurrentGpuAccess>,
-}
-
-impl<'a, T: ?Sized + 'a> ReadLock<'a, T> {
- /// Makes a new `ReadLock` to access a sub-part of the current `ReadLock`.
- #[inline]
- pub fn map<U: ?Sized + 'a, F>(self, f: F) -> ReadLock<'a, U>
- where
- F: FnOnce(&mut T) -> &mut U,
- {
- ReadLock {
- inner: self.inner.map(|ptr| unsafe { f(&mut *ptr) as *mut _ }),
- lock: self.lock,
- }
- }
-}
-
-impl<'a, T: ?Sized + 'a> Deref for ReadLock<'a, T> {
- type Target = T;
-
- #[inline]
- fn deref(&self) -> &T {
- self.inner.deref()
- }
-}
-
-/// Error when attempting to CPU-read a buffer.
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum ReadLockError {
- /// The buffer is already locked for write mode by the CPU.
- CpuWriteLocked,
- /// The buffer is already locked for write mode by the GPU.
- GpuWriteLocked,
-}
-
-impl error::Error for ReadLockError {}
-
-impl fmt::Display for ReadLockError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- ReadLockError::CpuWriteLocked => {
- "the buffer is already locked for write mode by the CPU"
- }
- ReadLockError::GpuWriteLocked => {
- "the buffer is already locked for write mode by the GPU"
- }
- }
- )
- }
-}
-
-/// Object that can be used to read or write the content of a `CpuAccessibleBuffer`.
-///
-/// Note that this object holds a rwlock write guard on the chunk. If another thread tries to access
-/// this buffer's content or tries to submit a GPU command that uses this buffer, it will block.
-pub struct WriteLock<'a, T: ?Sized + 'a> {
- inner: MemCpuAccess<'a, T>,
- lock: RwLockWriteGuard<'a, CurrentGpuAccess>,
-}
-
-impl<'a, T: ?Sized + 'a> WriteLock<'a, T> {
- /// Makes a new `WriteLock` to access a sub-part of the current `WriteLock`.
- #[inline]
- pub fn map<U: ?Sized + 'a, F>(self, f: F) -> WriteLock<'a, U>
- where
- F: FnOnce(&mut T) -> &mut U,
- {
- WriteLock {
- inner: self.inner.map(|ptr| unsafe { f(&mut *ptr) as *mut _ }),
- lock: self.lock,
- }
- }
-}
-
-impl<'a, T: ?Sized + 'a> Deref for WriteLock<'a, T> {
- type Target = T;
-
- #[inline]
- fn deref(&self) -> &T {
- self.inner.deref()
- }
-}
-
-impl<'a, T: ?Sized + 'a> DerefMut for WriteLock<'a, T> {
- #[inline]
- fn deref_mut(&mut self) -> &mut T {
- self.inner.deref_mut()
- }
-}
-
-/// Error when attempting to CPU-write a buffer.
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum WriteLockError {
- /// The buffer is already locked by the CPU.
- CpuLocked,
- /// The buffer is already locked by the GPU.
- GpuLocked,
-}
-
-impl error::Error for WriteLockError {}
-
-impl fmt::Display for WriteLockError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- WriteLockError::CpuLocked => "the buffer is already locked by the CPU",
- WriteLockError::GpuLocked => "the buffer is already locked by the GPU",
- }
- )
- }
-}
-
-#[cfg(test)]
-mod tests {
- use crate::buffer::{BufferUsage, CpuAccessibleBuffer};
-
- #[test]
- fn create_empty_buffer() {
- let (device, queue) = gfx_dev_and_queue!();
-
- const EMPTY: [i32; 0] = [];
-
- let _ = CpuAccessibleBuffer::from_data(device.clone(), BufferUsage::all(), false, EMPTY);
- let _ = CpuAccessibleBuffer::from_iter(device, BufferUsage::all(), false, EMPTY.iter());
- }
-}
diff --git a/src/buffer/cpu_pool.rs b/src/buffer/cpu_pool.rs
deleted file mode 100644
index 2475961..0000000
--- a/src/buffer/cpu_pool.rs
+++ /dev/null
@@ -1,945 +0,0 @@
-// Copyright (c) 2017 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::buffer::sys::BufferCreationError;
-use crate::buffer::sys::UnsafeBuffer;
-use crate::buffer::traits::BufferAccess;
-use crate::buffer::traits::BufferInner;
-use crate::buffer::traits::TypedBufferAccess;
-use crate::buffer::BufferUsage;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::device::Queue;
-use crate::memory::pool::AllocFromRequirementsFilter;
-use crate::memory::pool::AllocLayout;
-use crate::memory::pool::MappingRequirement;
-use crate::memory::pool::MemoryPool;
-use crate::memory::pool::MemoryPoolAlloc;
-use crate::memory::pool::PotentialDedicatedAllocation;
-use crate::memory::pool::StdMemoryPool;
-use crate::memory::DedicatedAlloc;
-use crate::memory::DeviceMemoryAllocError;
-use crate::sync::AccessError;
-use crate::sync::Sharing;
-use crate::DeviceSize;
-use crate::OomError;
-use std::cmp;
-use std::hash::Hash;
-use std::hash::Hasher;
-use std::iter;
-use std::marker::PhantomData;
-use std::mem;
-use std::ptr;
-use std::sync::atomic::AtomicU64;
-use std::sync::atomic::Ordering;
-use std::sync::Arc;
-use std::sync::Mutex;
-use std::sync::MutexGuard;
-
-// TODO: Add `CpuBufferPoolSubbuffer::read` to read the content of a subbuffer.
-// But that's hard to do because we must prevent `increase_gpu_lock` from working while a
-// a buffer is locked.
-
-/// Ring buffer from which "sub-buffers" can be individually allocated.
-///
-/// This buffer is especially suitable when you want to upload or download some data regularly
-/// (for example, at each frame for a video game).
-///
-/// # Usage
-///
-/// A `CpuBufferPool` is similar to a ring buffer. You start by creating an empty pool, then you
-/// grab elements from the pool and use them, and if the pool is full it will automatically grow
-/// in size.
-///
-/// Contrary to a `Vec`, elements automatically free themselves when they are dropped (ie. usually
-/// when you call `cleanup_finished()` on a future, or when you drop that future).
-///
-/// # Arc-like
-///
-/// The `CpuBufferPool` struct internally contains an `Arc`. You can clone the `CpuBufferPool` for
-/// a cheap cost, and all the clones will share the same underlying buffer.
-///
-/// # Example
-///
-/// ```
-/// use vulkano::buffer::CpuBufferPool;
-/// use vulkano::command_buffer::AutoCommandBufferBuilder;
-/// use vulkano::command_buffer::CommandBufferUsage;
-/// use vulkano::command_buffer::PrimaryCommandBuffer;
-/// use vulkano::sync::GpuFuture;
-/// # let device: std::sync::Arc<vulkano::device::Device> = return;
-/// # let queue: std::sync::Arc<vulkano::device::Queue> = return;
-///
-/// // Create the ring buffer.
-/// let buffer = CpuBufferPool::upload(device.clone());
-///
-/// for n in 0 .. 25u32 {
-/// // Each loop grabs a new entry from that ring buffer and stores ` data` in it.
-/// let data: [f32; 4] = [1.0, 0.5, n as f32 / 24.0, 0.0];
-/// let sub_buffer = buffer.next(data).unwrap();
-///
-/// // You can then use `sub_buffer` as if it was an entirely separate buffer.
-/// AutoCommandBufferBuilder::primary(device.clone(), queue.family(), CommandBufferUsage::OneTimeSubmit)
-/// .unwrap()
-/// // For the sake of the example we just call `update_buffer` on the buffer, even though
-/// // it is pointless to do that.
-/// .update_buffer(sub_buffer.clone(), &[0.2, 0.3, 0.4, 0.5])
-/// .unwrap()
-/// .build().unwrap()
-/// .execute(queue.clone())
-/// .unwrap()
-/// .then_signal_fence_and_flush()
-/// .unwrap();
-/// }
-/// ```
-///
-pub struct CpuBufferPool<T, A = Arc<StdMemoryPool>>
-where
- A: MemoryPool,
-{
- // The device of the pool.
- device: Arc<Device>,
-
- // The memory pool to use for allocations.
- pool: A,
-
- // Current buffer from which elements are grabbed.
- current_buffer: Mutex<Option<Arc<ActualBuffer<A>>>>,
-
- // Buffer usage.
- usage: BufferUsage,
-
- // Necessary to make it compile.
- marker: PhantomData<Box<T>>,
-}
-
-// One buffer of the pool.
-struct ActualBuffer<A>
-where
- A: MemoryPool,
-{
- // Inner content.
- inner: UnsafeBuffer,
-
- // The memory held by the buffer.
- memory: PotentialDedicatedAllocation<A::Alloc>,
-
- // List of the chunks that are reserved.
- chunks_in_use: Mutex<Vec<ActualBufferChunk>>,
-
- // The index of the chunk that should be available next for the ring buffer.
- next_index: AtomicU64,
-
- // Number of elements in the buffer.
- capacity: DeviceSize,
-}
-
-// Access pattern of one subbuffer.
-#[derive(Debug)]
-struct ActualBufferChunk {
- // First element number within the actual buffer.
- index: DeviceSize,
-
- // Number of occupied elements within the actual buffer.
- len: DeviceSize,
-
- // Number of `CpuBufferPoolSubbuffer` objects that point to this subbuffer.
- num_cpu_accesses: usize,
-
- // Number of `CpuBufferPoolSubbuffer` objects that point to this subbuffer and that have been
- // GPU-locked.
- num_gpu_accesses: usize,
-}
-
-/// A subbuffer allocated from a `CpuBufferPool`.
-///
-/// When this object is destroyed, the subbuffer is automatically reclaimed by the pool.
-pub struct CpuBufferPoolChunk<T, A>
-where
- A: MemoryPool,
-{
- buffer: Arc<ActualBuffer<A>>,
-
- // Index of the subbuffer within `buffer`. In number of elements.
- index: DeviceSize,
-
- // Number of bytes to add to `index * mem::size_of::<T>()` to obtain the start of the data in
- // the buffer. Necessary for alignment purposes.
- align_offset: DeviceSize,
-
- // Size of the subbuffer in number of elements, as requested by the user.
- // If this is 0, then no entry was added to `chunks_in_use`.
- requested_len: DeviceSize,
-
- // Necessary to make it compile.
- marker: PhantomData<Box<T>>,
-}
-
-/// A subbuffer allocated from a `CpuBufferPool`.
-///
-/// When this object is destroyed, the subbuffer is automatically reclaimed by the pool.
-pub struct CpuBufferPoolSubbuffer<T, A>
-where
- A: MemoryPool,
-{
- // This struct is just a wrapper around `CpuBufferPoolChunk`.
- chunk: CpuBufferPoolChunk<T, A>,
-}
-
-impl<T> CpuBufferPool<T> {
- /// Builds a `CpuBufferPool`.
- #[inline]
- pub fn new(device: Arc<Device>, usage: BufferUsage) -> CpuBufferPool<T> {
- let pool = Device::standard_pool(&device);
-
- CpuBufferPool {
- device: device,
- pool: pool,
- current_buffer: Mutex::new(None),
- usage: usage.clone(),
- marker: PhantomData,
- }
- }
-
- /// Builds a `CpuBufferPool` meant for simple uploads.
- ///
- /// Shortcut for a pool that can only be used as transfer source and with exclusive queue
- /// family accesses.
- #[inline]
- pub fn upload(device: Arc<Device>) -> CpuBufferPool<T> {
- CpuBufferPool::new(device, BufferUsage::transfer_source())
- }
-
- /// Builds a `CpuBufferPool` meant for simple downloads.
- ///
- /// Shortcut for a pool that can only be used as transfer destination and with exclusive queue
- /// family accesses.
- #[inline]
- pub fn download(device: Arc<Device>) -> CpuBufferPool<T> {
- CpuBufferPool::new(device, BufferUsage::transfer_destination())
- }
-
- /// Builds a `CpuBufferPool` meant for usage as a uniform buffer.
- ///
- /// Shortcut for a pool that can only be used as uniform buffer and with exclusive queue
- /// family accesses.
- #[inline]
- pub fn uniform_buffer(device: Arc<Device>) -> CpuBufferPool<T> {
- CpuBufferPool::new(device, BufferUsage::uniform_buffer())
- }
-
- /// Builds a `CpuBufferPool` meant for usage as a vertex buffer.
- ///
- /// Shortcut for a pool that can only be used as vertex buffer and with exclusive queue
- /// family accesses.
- #[inline]
- pub fn vertex_buffer(device: Arc<Device>) -> CpuBufferPool<T> {
- CpuBufferPool::new(device, BufferUsage::vertex_buffer())
- }
-
- /// Builds a `CpuBufferPool` meant for usage as a indirect buffer.
- ///
- /// Shortcut for a pool that can only be used as indirect buffer and with exclusive queue
- /// family accesses.
- #[inline]
- pub fn indirect_buffer(device: Arc<Device>) -> CpuBufferPool<T> {
- CpuBufferPool::new(device, BufferUsage::indirect_buffer())
- }
-}
-
-impl<T, A> CpuBufferPool<T, A>
-where
- A: MemoryPool,
-{
- /// Returns the current capacity of the pool, in number of elements.
- pub fn capacity(&self) -> DeviceSize {
- match *self.current_buffer.lock().unwrap() {
- None => 0,
- Some(ref buf) => buf.capacity,
- }
- }
-
- /// Makes sure that the capacity is at least `capacity`. Allocates memory if it is not the
- /// case.
- ///
- /// Since this can involve a memory allocation, an `OomError` can happen.
- pub fn reserve(&self, capacity: DeviceSize) -> Result<(), DeviceMemoryAllocError> {
- let mut cur_buf = self.current_buffer.lock().unwrap();
-
- // Check current capacity.
- match *cur_buf {
- Some(ref buf) if buf.capacity >= capacity => {
- return Ok(());
- }
- _ => (),
- };
-
- self.reset_buf(&mut cur_buf, capacity)
- }
-
- /// Grants access to a new subbuffer and puts `data` in it.
- ///
- /// If no subbuffer is available (because they are still in use by the GPU), a new buffer will
- /// automatically be allocated.
- ///
- /// > **Note**: You can think of it like a `Vec`. If you insert an element and the `Vec` is not
- /// > large enough, a new chunk of memory is automatically allocated.
- #[inline]
- pub fn next(&self, data: T) -> Result<CpuBufferPoolSubbuffer<T, A>, DeviceMemoryAllocError> {
- Ok(CpuBufferPoolSubbuffer {
- chunk: self.chunk(iter::once(data))?,
- })
- }
-
- /// Grants access to a new subbuffer and puts `data` in it.
- ///
- /// If no subbuffer is available (because they are still in use by the GPU), a new buffer will
- /// automatically be allocated.
- ///
- /// > **Note**: You can think of it like a `Vec`. If you insert elements and the `Vec` is not
- /// > large enough, a new chunk of memory is automatically allocated.
- ///
- /// # Panic
- ///
- /// Panics if the length of the iterator didn't match the actual number of element.
- ///
- pub fn chunk<I>(&self, data: I) -> Result<CpuBufferPoolChunk<T, A>, DeviceMemoryAllocError>
- where
- I: IntoIterator<Item = T>,
- I::IntoIter: ExactSizeIterator,
- {
- let data = data.into_iter();
-
- let mut mutex = self.current_buffer.lock().unwrap();
-
- let data = match self.try_next_impl(&mut mutex, data) {
- Ok(n) => return Ok(n),
- Err(d) => d,
- };
-
- let next_capacity = match *mutex {
- Some(ref b) if (data.len() as DeviceSize) < b.capacity => 2 * b.capacity,
- _ => 2 * data.len() as DeviceSize,
- };
-
- self.reset_buf(&mut mutex, next_capacity)?;
-
- match self.try_next_impl(&mut mutex, data) {
- Ok(n) => Ok(n),
- Err(_) => unreachable!(),
- }
- }
-
- /// Grants access to a new subbuffer and puts `data` in it.
- ///
- /// Returns `None` if no subbuffer is available.
- ///
- /// A `CpuBufferPool` is always empty the first time you use it, so you shouldn't use
- /// `try_next` the first time you use it.
- #[inline]
- pub fn try_next(&self, data: T) -> Option<CpuBufferPoolSubbuffer<T, A>> {
- let mut mutex = self.current_buffer.lock().unwrap();
- self.try_next_impl(&mut mutex, iter::once(data))
- .map(|c| CpuBufferPoolSubbuffer { chunk: c })
- .ok()
- }
-
- // Creates a new buffer and sets it as current. The capacity is in number of elements.
- //
- // `cur_buf_mutex` must be an active lock of `self.current_buffer`.
- fn reset_buf(
- &self,
- cur_buf_mutex: &mut MutexGuard<Option<Arc<ActualBuffer<A>>>>,
- capacity: DeviceSize,
- ) -> Result<(), DeviceMemoryAllocError> {
- unsafe {
- let (buffer, mem_reqs) = {
- let size_bytes = match (mem::size_of::<T>() as DeviceSize).checked_mul(capacity) {
- Some(s) => s,
- None => {
- return Err(DeviceMemoryAllocError::OomError(
- OomError::OutOfDeviceMemory,
- ))
- }
- };
-
- match UnsafeBuffer::new(
- self.device.clone(),
- size_bytes as DeviceSize,
- self.usage,
- Sharing::Exclusive::<iter::Empty<_>>,
- None,
- ) {
- Ok(b) => b,
- Err(BufferCreationError::AllocError(err)) => return Err(err),
- Err(_) => unreachable!(), // We don't use sparse binding, therefore the other
- // errors can't happen
- }
- };
-
- let mem = MemoryPool::alloc_from_requirements(
- &self.pool,
- &mem_reqs,
- AllocLayout::Linear,
- MappingRequirement::Map,
- DedicatedAlloc::Buffer(&buffer),
- |_| AllocFromRequirementsFilter::Allowed,
- )?;
- debug_assert!((mem.offset() % mem_reqs.alignment) == 0);
- debug_assert!(mem.mapped_memory().is_some());
- buffer.bind_memory(mem.memory(), mem.offset())?;
-
- **cur_buf_mutex = Some(Arc::new(ActualBuffer {
- inner: buffer,
- memory: mem,
- chunks_in_use: Mutex::new(vec![]),
- next_index: AtomicU64::new(0),
- capacity: capacity,
- }));
-
- Ok(())
- }
- }
-
- // Tries to lock a subbuffer from the current buffer.
- //
- // `cur_buf_mutex` must be an active lock of `self.current_buffer`.
- //
- // Returns `data` wrapped inside an `Err` if there is no slot available in the current buffer.
- //
- // # Panic
- //
- // Panics if the length of the iterator didn't match the actual number of element.
- //
- fn try_next_impl<I>(
- &self,
- cur_buf_mutex: &mut MutexGuard<Option<Arc<ActualBuffer<A>>>>,
- mut data: I,
- ) -> Result<CpuBufferPoolChunk<T, A>, I>
- where
- I: ExactSizeIterator<Item = T>,
- {
- // Grab the current buffer. Return `Err` if the pool wasn't "initialized" yet.
- let current_buffer = match cur_buf_mutex.clone() {
- Some(b) => b,
- None => return Err(data),
- };
-
- let mut chunks_in_use = current_buffer.chunks_in_use.lock().unwrap();
- debug_assert!(!chunks_in_use.iter().any(|c| c.len == 0));
-
- // Number of elements requested by the user.
- let requested_len = data.len() as DeviceSize;
-
- // We special case when 0 elements are requested. Polluting the list of allocated chunks
- // with chunks of length 0 means that we will have troubles deallocating.
- if requested_len == 0 {
- assert!(
- data.next().is_none(),
- "Expected iterator passed to CpuBufferPool::chunk to be empty"
- );
- return Ok(CpuBufferPoolChunk {
- // TODO: remove .clone() once non-lexical borrows land
- buffer: current_buffer.clone(),
- index: 0,
- align_offset: 0,
- requested_len: 0,
- marker: PhantomData,
- });
- }
-
- // Find a suitable offset and len, or returns if none available.
- let (index, occupied_len, align_offset) = {
- let (tentative_index, tentative_len, tentative_align_offset) = {
- // Since the only place that touches `next_index` is this code, and since we
- // own a mutex lock to the buffer, it means that `next_index` can't be accessed
- // concurrently.
- // TODO: ^ eventually should be put inside the mutex
- let idx = current_buffer.next_index.load(Ordering::SeqCst);
-
- // Find the required alignment in bytes.
- let align_bytes = cmp::max(
- if self.usage.uniform_buffer {
- self.device()
- .physical_device()
- .properties()
- .min_uniform_buffer_offset_alignment
- } else {
- 1
- },
- if self.usage.storage_buffer {
- self.device()
- .physical_device()
- .properties()
- .min_storage_buffer_offset_alignment
- } else {
- 1
- },
- );
-
- let tentative_align_offset = (align_bytes
- - ((idx * mem::size_of::<T>() as DeviceSize) % align_bytes))
- % align_bytes;
- let additional_len = if tentative_align_offset == 0 {
- 0
- } else {
- 1 + (tentative_align_offset - 1) / mem::size_of::<T>() as DeviceSize
- };
-
- (idx, requested_len + additional_len, tentative_align_offset)
- };
-
- // Find out whether any chunk in use overlaps this range.
- if tentative_index + tentative_len <= current_buffer.capacity
- && !chunks_in_use.iter().any(|c| {
- (c.index >= tentative_index && c.index < tentative_index + tentative_len)
- || (c.index <= tentative_index && c.index + c.len > tentative_index)
- })
- {
- (tentative_index, tentative_len, tentative_align_offset)
- } else {
- // Impossible to allocate at `tentative_index`. Let's try 0 instead.
- if requested_len <= current_buffer.capacity
- && !chunks_in_use.iter().any(|c| c.index < requested_len)
- {
- (0, requested_len, 0)
- } else {
- // Buffer is full. Return.
- return Err(data);
- }
- }
- };
-
- // Write `data` in the memory.
- unsafe {
- let mem_off = current_buffer.memory.offset();
- let range_start = index * mem::size_of::<T>() as DeviceSize + align_offset + mem_off;
- let range_end = (index + requested_len) * mem::size_of::<T>() as DeviceSize
- + align_offset
- + mem_off;
- let mut mapping = current_buffer
- .memory
- .mapped_memory()
- .unwrap()
- .read_write::<[T]>(range_start..range_end);
-
- let mut written = 0;
- for (o, i) in mapping.iter_mut().zip(data) {
- ptr::write(o, i);
- written += 1;
- }
- assert_eq!(
- written, requested_len,
- "Iterator passed to CpuBufferPool::chunk has a mismatch between reported \
- length and actual number of elements"
- );
- }
-
- // Mark the chunk as in use.
- current_buffer
- .next_index
- .store(index + occupied_len, Ordering::SeqCst);
- chunks_in_use.push(ActualBufferChunk {
- index,
- len: occupied_len,
- num_cpu_accesses: 1,
- num_gpu_accesses: 0,
- });
-
- Ok(CpuBufferPoolChunk {
- // TODO: remove .clone() once non-lexical borrows land
- buffer: current_buffer.clone(),
- index: index,
- align_offset,
- requested_len,
- marker: PhantomData,
- })
- }
-}
-
-// Can't automatically derive `Clone`, otherwise the compiler adds a `T: Clone` requirement.
-impl<T, A> Clone for CpuBufferPool<T, A>
-where
- A: MemoryPool + Clone,
-{
- fn clone(&self) -> Self {
- let buf = self.current_buffer.lock().unwrap();
-
- CpuBufferPool {
- device: self.device.clone(),
- pool: self.pool.clone(),
- current_buffer: Mutex::new(buf.clone()),
- usage: self.usage.clone(),
- marker: PhantomData,
- }
- }
-}
-
-unsafe impl<T, A> DeviceOwned for CpuBufferPool<T, A>
-where
- A: MemoryPool,
-{
- #[inline]
- fn device(&self) -> &Arc<Device> {
- &self.device
- }
-}
-
-impl<T, A> Clone for CpuBufferPoolChunk<T, A>
-where
- A: MemoryPool,
-{
- fn clone(&self) -> CpuBufferPoolChunk<T, A> {
- let mut chunks_in_use_lock = self.buffer.chunks_in_use.lock().unwrap();
- let chunk = chunks_in_use_lock
- .iter_mut()
- .find(|c| c.index == self.index)
- .unwrap();
-
- debug_assert!(chunk.num_cpu_accesses >= 1);
- chunk.num_cpu_accesses = chunk
- .num_cpu_accesses
- .checked_add(1)
- .expect("Overflow in CPU accesses");
-
- CpuBufferPoolChunk {
- buffer: self.buffer.clone(),
- index: self.index,
- align_offset: self.align_offset,
- requested_len: self.requested_len,
- marker: PhantomData,
- }
- }
-}
-
-unsafe impl<T, A> BufferAccess for CpuBufferPoolChunk<T, A>
-where
- A: MemoryPool,
-{
- #[inline]
- fn inner(&self) -> BufferInner {
- BufferInner {
- buffer: &self.buffer.inner,
- offset: self.index * mem::size_of::<T>() as DeviceSize + self.align_offset,
- }
- }
-
- #[inline]
- fn size(&self) -> DeviceSize {
- self.requested_len * mem::size_of::<T>() as DeviceSize
- }
-
- #[inline]
- fn conflict_key(&self) -> (u64, u64) {
- (
- self.buffer.inner.key(),
- // ensure the special cased empty buffers don't collide with a regular buffer starting at 0
- if self.requested_len == 0 {
- u64::MAX
- } else {
- self.index
- },
- )
- }
-
- #[inline]
- fn try_gpu_lock(&self, _: bool, _: &Queue) -> Result<(), AccessError> {
- if self.requested_len == 0 {
- return Ok(());
- }
-
- let mut chunks_in_use_lock = self.buffer.chunks_in_use.lock().unwrap();
- let chunk = chunks_in_use_lock
- .iter_mut()
- .find(|c| c.index == self.index)
- .unwrap();
-
- if chunk.num_gpu_accesses != 0 {
- return Err(AccessError::AlreadyInUse);
- }
-
- chunk.num_gpu_accesses = 1;
- Ok(())
- }
-
- #[inline]
- unsafe fn increase_gpu_lock(&self) {
- if self.requested_len == 0 {
- return;
- }
-
- let mut chunks_in_use_lock = self.buffer.chunks_in_use.lock().unwrap();
- let chunk = chunks_in_use_lock
- .iter_mut()
- .find(|c| c.index == self.index)
- .unwrap();
-
- debug_assert!(chunk.num_gpu_accesses >= 1);
- chunk.num_gpu_accesses = chunk
- .num_gpu_accesses
- .checked_add(1)
- .expect("Overflow in GPU usages");
- }
-
- #[inline]
- unsafe fn unlock(&self) {
- if self.requested_len == 0 {
- return;
- }
-
- let mut chunks_in_use_lock = self.buffer.chunks_in_use.lock().unwrap();
- let chunk = chunks_in_use_lock
- .iter_mut()
- .find(|c| c.index == self.index)
- .unwrap();
-
- debug_assert!(chunk.num_gpu_accesses >= 1);
- chunk.num_gpu_accesses -= 1;
- }
-}
-
-impl<T, A> Drop for CpuBufferPoolChunk<T, A>
-where
- A: MemoryPool,
-{
- fn drop(&mut self) {
- // If `requested_len` is 0, then no entry was added in the chunks.
- if self.requested_len == 0 {
- return;
- }
-
- let mut chunks_in_use_lock = self.buffer.chunks_in_use.lock().unwrap();
- let chunk_num = chunks_in_use_lock
- .iter_mut()
- .position(|c| c.index == self.index)
- .unwrap();
-
- if chunks_in_use_lock[chunk_num].num_cpu_accesses >= 2 {
- chunks_in_use_lock[chunk_num].num_cpu_accesses -= 1;
- } else {
- debug_assert_eq!(chunks_in_use_lock[chunk_num].num_gpu_accesses, 0);
- chunks_in_use_lock.remove(chunk_num);
- }
- }
-}
-
-unsafe impl<T, A> TypedBufferAccess for CpuBufferPoolChunk<T, A>
-where
- A: MemoryPool,
-{
- type Content = [T];
-}
-
-unsafe impl<T, A> DeviceOwned for CpuBufferPoolChunk<T, A>
-where
- A: MemoryPool,
-{
- #[inline]
- fn device(&self) -> &Arc<Device> {
- self.buffer.inner.device()
- }
-}
-
-impl<T, A> PartialEq for CpuBufferPoolChunk<T, A>
-where
- A: MemoryPool,
-{
- #[inline]
- fn eq(&self, other: &Self) -> bool {
- self.inner() == other.inner() && self.size() == other.size()
- }
-}
-
-impl<T, A> Eq for CpuBufferPoolChunk<T, A> where A: MemoryPool {}
-
-impl<T, A> Hash for CpuBufferPoolChunk<T, A>
-where
- A: MemoryPool,
-{
- #[inline]
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.inner().hash(state);
- self.size().hash(state);
- }
-}
-
-impl<T, A> Clone for CpuBufferPoolSubbuffer<T, A>
-where
- A: MemoryPool,
-{
- fn clone(&self) -> CpuBufferPoolSubbuffer<T, A> {
- CpuBufferPoolSubbuffer {
- chunk: self.chunk.clone(),
- }
- }
-}
-
-unsafe impl<T, A> BufferAccess for CpuBufferPoolSubbuffer<T, A>
-where
- A: MemoryPool,
-{
- #[inline]
- fn inner(&self) -> BufferInner {
- self.chunk.inner()
- }
-
- #[inline]
- fn size(&self) -> DeviceSize {
- self.chunk.size()
- }
-
- #[inline]
- fn conflict_key(&self) -> (u64, u64) {
- self.chunk.conflict_key()
- }
-
- #[inline]
- fn try_gpu_lock(&self, e: bool, q: &Queue) -> Result<(), AccessError> {
- self.chunk.try_gpu_lock(e, q)
- }
-
- #[inline]
- unsafe fn increase_gpu_lock(&self) {
- self.chunk.increase_gpu_lock()
- }
-
- #[inline]
- unsafe fn unlock(&self) {
- self.chunk.unlock()
- }
-}
-
-unsafe impl<T, A> TypedBufferAccess for CpuBufferPoolSubbuffer<T, A>
-where
- A: MemoryPool,
-{
- type Content = T;
-}
-
-unsafe impl<T, A> DeviceOwned for CpuBufferPoolSubbuffer<T, A>
-where
- A: MemoryPool,
-{
- #[inline]
- fn device(&self) -> &Arc<Device> {
- self.chunk.buffer.inner.device()
- }
-}
-
-impl<T, A> PartialEq for CpuBufferPoolSubbuffer<T, A>
-where
- A: MemoryPool,
-{
- #[inline]
- fn eq(&self, other: &Self) -> bool {
- self.inner() == other.inner() && self.size() == other.size()
- }
-}
-
-impl<T, A> Eq for CpuBufferPoolSubbuffer<T, A> where A: MemoryPool {}
-
-impl<T, A> Hash for CpuBufferPoolSubbuffer<T, A>
-where
- A: MemoryPool,
-{
- #[inline]
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.inner().hash(state);
- self.size().hash(state);
- }
-}
-
-#[cfg(test)]
-mod tests {
- use crate::buffer::CpuBufferPool;
- use std::mem;
-
- #[test]
- fn basic_create() {
- let (device, _) = gfx_dev_and_queue!();
- let _ = CpuBufferPool::<u8>::upload(device);
- }
-
- #[test]
- fn reserve() {
- let (device, _) = gfx_dev_and_queue!();
-
- let pool = CpuBufferPool::<u8>::upload(device);
- assert_eq!(pool.capacity(), 0);
-
- pool.reserve(83).unwrap();
- assert_eq!(pool.capacity(), 83);
- }
-
- #[test]
- fn capacity_increase() {
- let (device, _) = gfx_dev_and_queue!();
-
- let pool = CpuBufferPool::upload(device);
- assert_eq!(pool.capacity(), 0);
-
- pool.next(12).unwrap();
- let first_cap = pool.capacity();
- assert!(first_cap >= 1);
-
- for _ in 0..first_cap + 5 {
- mem::forget(pool.next(12).unwrap());
- }
-
- assert!(pool.capacity() > first_cap);
- }
-
- #[test]
- fn reuse_subbuffers() {
- let (device, _) = gfx_dev_and_queue!();
-
- let pool = CpuBufferPool::upload(device);
- assert_eq!(pool.capacity(), 0);
-
- let mut capacity = None;
- for _ in 0..64 {
- pool.next(12).unwrap();
-
- let new_cap = pool.capacity();
- assert!(new_cap >= 1);
- match capacity {
- None => capacity = Some(new_cap),
- Some(c) => assert_eq!(c, new_cap),
- }
- }
- }
-
- #[test]
- fn chunk_loopback() {
- let (device, _) = gfx_dev_and_queue!();
-
- let pool = CpuBufferPool::<u8>::upload(device);
- pool.reserve(5).unwrap();
-
- let a = pool.chunk(vec![0, 0]).unwrap();
- let b = pool.chunk(vec![0, 0]).unwrap();
- assert_eq!(b.index, 2);
- drop(a);
-
- let c = pool.chunk(vec![0, 0]).unwrap();
- assert_eq!(c.index, 0);
-
- assert_eq!(pool.capacity(), 5);
- }
-
- #[test]
- fn chunk_0_elems_doesnt_pollute() {
- let (device, _) = gfx_dev_and_queue!();
-
- let pool = CpuBufferPool::<u8>::upload(device);
-
- let _ = pool.chunk(vec![]).unwrap();
- let _ = pool.chunk(vec![0, 0]).unwrap();
- }
-}
diff --git a/src/buffer/device_local.rs b/src/buffer/device_local.rs
deleted file mode 100644
index 51eaf31..0000000
--- a/src/buffer/device_local.rs
+++ /dev/null
@@ -1,398 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-//! Buffer whose content is read-written by the GPU only.
-//!
-//! Each access from the CPU or from the GPU locks the whole buffer for either reading or writing.
-//! You can read the buffer multiple times simultaneously from multiple queues. Trying to read and
-//! write simultaneously, or write and write simultaneously will block with a semaphore.
-
-use crate::buffer::sys::BufferCreationError;
-use crate::buffer::sys::UnsafeBuffer;
-use crate::buffer::traits::BufferAccess;
-use crate::buffer::traits::BufferInner;
-use crate::buffer::traits::TypedBufferAccess;
-use crate::buffer::BufferUsage;
-use crate::device::physical::QueueFamily;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::device::Queue;
-use crate::memory::pool::AllocFromRequirementsFilter;
-use crate::memory::pool::AllocLayout;
-use crate::memory::pool::MappingRequirement;
-use crate::memory::pool::MemoryPool;
-use crate::memory::pool::MemoryPoolAlloc;
-use crate::memory::pool::PotentialDedicatedAllocation;
-use crate::memory::pool::StdMemoryPoolAlloc;
-use crate::memory::{DedicatedAlloc, MemoryRequirements};
-use crate::memory::{DeviceMemoryAllocError, ExternalMemoryHandleType};
-use crate::sync::AccessError;
-use crate::sync::Sharing;
-use crate::DeviceSize;
-use smallvec::SmallVec;
-use std::fs::File;
-use std::hash::Hash;
-use std::hash::Hasher;
-use std::marker::PhantomData;
-use std::mem;
-use std::sync::Arc;
-use std::sync::Mutex;
-
-/// Buffer whose content is in device-local memory.
-///
-/// This buffer type is useful in order to store intermediary data. For example you execute a
-/// compute shader that writes to this buffer, then read the content of the buffer in a following
-/// compute or graphics pipeline.
-///
-/// The `DeviceLocalBuffer` will be in device-local memory, unless the device doesn't provide any
-/// device-local memory.
-#[derive(Debug)]
-pub struct DeviceLocalBuffer<T: ?Sized, A = PotentialDedicatedAllocation<StdMemoryPoolAlloc>> {
- // Inner content.
- inner: UnsafeBuffer,
-
- // The memory held by the buffer.
- memory: A,
-
- // Queue families allowed to access this buffer.
- queue_families: SmallVec<[u32; 4]>,
-
- // Number of times this buffer is locked on the GPU side.
- gpu_lock: Mutex<GpuAccess>,
-
- // Necessary to make it compile.
- marker: PhantomData<Box<T>>,
-}
-
-#[derive(Debug, Copy, Clone)]
-enum GpuAccess {
- None,
- NonExclusive { num: u32 },
- Exclusive { num: u32 },
-}
-
-impl<T> DeviceLocalBuffer<T> {
- /// Builds a new buffer. Only allowed for sized data.
- // TODO: unsafe because uninitialized data
- #[inline]
- pub fn new<'a, I>(
- device: Arc<Device>,
- usage: BufferUsage,
- queue_families: I,
- ) -> Result<Arc<DeviceLocalBuffer<T>>, DeviceMemoryAllocError>
- where
- I: IntoIterator<Item = QueueFamily<'a>>,
- {
- unsafe {
- DeviceLocalBuffer::raw(
- device,
- mem::size_of::<T>() as DeviceSize,
- usage,
- queue_families,
- )
- }
- }
-}
-
-impl<T> DeviceLocalBuffer<[T]> {
- /// Builds a new buffer. Can be used for arrays.
- // TODO: unsafe because uninitialized data
- #[inline]
- pub fn array<'a, I>(
- device: Arc<Device>,
- len: DeviceSize,
- usage: BufferUsage,
- queue_families: I,
- ) -> Result<Arc<DeviceLocalBuffer<[T]>>, DeviceMemoryAllocError>
- where
- I: IntoIterator<Item = QueueFamily<'a>>,
- {
- unsafe {
- DeviceLocalBuffer::raw(
- device,
- len * mem::size_of::<T>() as DeviceSize,
- usage,
- queue_families,
- )
- }
- }
-}
-
-impl<T: ?Sized> DeviceLocalBuffer<T> {
- /// Builds a new buffer without checking the size.
- ///
- /// # Safety
- ///
- /// You must ensure that the size that you pass is correct for `T`.
- ///
- pub unsafe fn raw<'a, I>(
- device: Arc<Device>,
- size: DeviceSize,
- usage: BufferUsage,
- queue_families: I,
- ) -> Result<Arc<DeviceLocalBuffer<T>>, DeviceMemoryAllocError>
- where
- I: IntoIterator<Item = QueueFamily<'a>>,
- {
- let queue_families = queue_families
- .into_iter()
- .map(|f| f.id())
- .collect::<SmallVec<[u32; 4]>>();
-
- let (buffer, mem_reqs) = Self::build_buffer(&device, size, usage, &queue_families)?;
-
- let mem = MemoryPool::alloc_from_requirements(
- &Device::standard_pool(&device),
- &mem_reqs,
- AllocLayout::Linear,
- MappingRequirement::DoNotMap,
- DedicatedAlloc::Buffer(&buffer),
- |t| {
- if t.is_device_local() {
- AllocFromRequirementsFilter::Preferred
- } else {
- AllocFromRequirementsFilter::Allowed
- }
- },
- )?;
- debug_assert!((mem.offset() % mem_reqs.alignment) == 0);
- buffer.bind_memory(mem.memory(), mem.offset())?;
-
- Ok(Arc::new(DeviceLocalBuffer {
- inner: buffer,
- memory: mem,
- queue_families: queue_families,
- gpu_lock: Mutex::new(GpuAccess::None),
- marker: PhantomData,
- }))
- }
-
- /// Same as `raw` but with exportable fd option for the allocated memory on Linux
- #[cfg(target_os = "linux")]
- pub unsafe fn raw_with_exportable_fd<'a, I>(
- device: Arc<Device>,
- size: DeviceSize,
- usage: BufferUsage,
- queue_families: I,
- ) -> Result<Arc<DeviceLocalBuffer<T>>, DeviceMemoryAllocError>
- where
- I: IntoIterator<Item = QueueFamily<'a>>,
- {
- assert!(device.enabled_extensions().khr_external_memory_fd);
- assert!(device.enabled_extensions().khr_external_memory);
-
- let queue_families = queue_families
- .into_iter()
- .map(|f| f.id())
- .collect::<SmallVec<[u32; 4]>>();
-
- let (buffer, mem_reqs) = Self::build_buffer(&device, size, usage, &queue_families)?;
-
- let mem = MemoryPool::alloc_from_requirements_with_exportable_fd(
- &Device::standard_pool(&device),
- &mem_reqs,
- AllocLayout::Linear,
- MappingRequirement::DoNotMap,
- DedicatedAlloc::Buffer(&buffer),
- |t| {
- if t.is_device_local() {
- AllocFromRequirementsFilter::Preferred
- } else {
- AllocFromRequirementsFilter::Allowed
- }
- },
- )?;
- debug_assert!((mem.offset() % mem_reqs.alignment) == 0);
- buffer.bind_memory(mem.memory(), mem.offset())?;
-
- Ok(Arc::new(DeviceLocalBuffer {
- inner: buffer,
- memory: mem,
- queue_families: queue_families,
- gpu_lock: Mutex::new(GpuAccess::None),
- marker: PhantomData,
- }))
- }
-
- unsafe fn build_buffer(
- device: &Arc<Device>,
- size: DeviceSize,
- usage: BufferUsage,
- queue_families: &SmallVec<[u32; 4]>,
- ) -> Result<(UnsafeBuffer, MemoryRequirements), DeviceMemoryAllocError> {
- let (buffer, mem_reqs) = {
- let sharing = if queue_families.len() >= 2 {
- Sharing::Concurrent(queue_families.iter().cloned())
- } else {
- Sharing::Exclusive
- };
-
- match UnsafeBuffer::new(device.clone(), size, usage, sharing, None) {
- Ok(b) => b,
- Err(BufferCreationError::AllocError(err)) => return Err(err),
- Err(_) => unreachable!(), // We don't use sparse binding, therefore the other
- // errors can't happen
- }
- };
- Ok((buffer, mem_reqs))
- }
-
- /// Exports posix file descriptor for the allocated memory
- /// requires `khr_external_memory_fd` and `khr_external_memory` extensions to be loaded.
- /// Only works on Linux.
- #[cfg(target_os = "linux")]
- pub fn export_posix_fd(&self) -> Result<File, DeviceMemoryAllocError> {
- self.memory
- .memory()
- .export_fd(ExternalMemoryHandleType::posix())
- }
-}
-
-impl<T: ?Sized, A> DeviceLocalBuffer<T, A> {
- /// Returns the queue families this buffer can be used on.
- // TODO: use a custom iterator
- #[inline]
- pub fn queue_families(&self) -> Vec<QueueFamily> {
- self.queue_families
- .iter()
- .map(|&num| {
- self.device()
- .physical_device()
- .queue_family_by_id(num)
- .unwrap()
- })
- .collect()
- }
-}
-
-unsafe impl<T: ?Sized, A> DeviceOwned for DeviceLocalBuffer<T, A> {
- #[inline]
- fn device(&self) -> &Arc<Device> {
- self.inner.device()
- }
-}
-
-unsafe impl<T: ?Sized, A> BufferAccess for DeviceLocalBuffer<T, A>
-where
- T: 'static + Send + Sync,
-{
- #[inline]
- fn inner(&self) -> BufferInner {
- BufferInner {
- buffer: &self.inner,
- offset: 0,
- }
- }
-
- #[inline]
- fn size(&self) -> DeviceSize {
- self.inner.size()
- }
-
- #[inline]
- fn conflict_key(&self) -> (u64, u64) {
- (self.inner.key(), 0)
- }
-
- #[inline]
- fn try_gpu_lock(&self, exclusive: bool, _: &Queue) -> Result<(), AccessError> {
- let mut lock = self.gpu_lock.lock().unwrap();
- match &mut *lock {
- a @ &mut GpuAccess::None => {
- if exclusive {
- *a = GpuAccess::Exclusive { num: 1 };
- } else {
- *a = GpuAccess::NonExclusive { num: 1 };
- }
-
- Ok(())
- }
- &mut GpuAccess::NonExclusive { ref mut num } => {
- if exclusive {
- Err(AccessError::AlreadyInUse)
- } else {
- *num += 1;
- Ok(())
- }
- }
- &mut GpuAccess::Exclusive { .. } => Err(AccessError::AlreadyInUse),
- }
- }
-
- #[inline]
- unsafe fn increase_gpu_lock(&self) {
- let mut lock = self.gpu_lock.lock().unwrap();
- match *lock {
- GpuAccess::None => panic!(),
- GpuAccess::NonExclusive { ref mut num } => {
- debug_assert!(*num >= 1);
- *num += 1;
- }
- GpuAccess::Exclusive { ref mut num } => {
- debug_assert!(*num >= 1);
- *num += 1;
- }
- }
- }
-
- #[inline]
- unsafe fn unlock(&self) {
- let mut lock = self.gpu_lock.lock().unwrap();
-
- match *lock {
- GpuAccess::None => panic!("Tried to unlock a buffer that isn't locked"),
- GpuAccess::NonExclusive { ref mut num } => {
- assert!(*num >= 1);
- *num -= 1;
- if *num >= 1 {
- return;
- }
- }
- GpuAccess::Exclusive { ref mut num } => {
- assert!(*num >= 1);
- *num -= 1;
- if *num >= 1 {
- return;
- }
- }
- };
-
- *lock = GpuAccess::None;
- }
-}
-
-unsafe impl<T: ?Sized, A> TypedBufferAccess for DeviceLocalBuffer<T, A>
-where
- T: 'static + Send + Sync,
-{
- type Content = T;
-}
-
-impl<T: ?Sized, A> PartialEq for DeviceLocalBuffer<T, A>
-where
- T: 'static + Send + Sync,
-{
- #[inline]
- fn eq(&self, other: &Self) -> bool {
- self.inner() == other.inner() && self.size() == other.size()
- }
-}
-
-impl<T: ?Sized, A> Eq for DeviceLocalBuffer<T, A> where T: 'static + Send + Sync {}
-
-impl<T: ?Sized, A> Hash for DeviceLocalBuffer<T, A>
-where
- T: 'static + Send + Sync,
-{
- #[inline]
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.inner().hash(state);
- self.size().hash(state);
- }
-}
diff --git a/src/buffer/immutable.rs b/src/buffer/immutable.rs
deleted file mode 100644
index bb9c8e5..0000000
--- a/src/buffer/immutable.rs
+++ /dev/null
@@ -1,728 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-//! Buffer that is written once then read for as long as it is alive.
-//!
-//! Use this buffer when you have data that you never modify.
-//!
-//! Only the first ever command buffer that uses this buffer can write to it (for example by
-//! copying from another buffer). Any subsequent command buffer **must** only read from the buffer,
-//! or a panic will happen.
-//!
-//! The buffer will be stored in device-local memory if possible
-//!
-
-use crate::buffer::sys::BufferCreationError;
-use crate::buffer::sys::UnsafeBuffer;
-use crate::buffer::traits::BufferAccess;
-use crate::buffer::traits::BufferInner;
-use crate::buffer::traits::TypedBufferAccess;
-use crate::buffer::BufferUsage;
-use crate::buffer::CpuAccessibleBuffer;
-use crate::command_buffer::AutoCommandBufferBuilder;
-use crate::command_buffer::CommandBufferExecFuture;
-use crate::command_buffer::CommandBufferUsage;
-use crate::command_buffer::PrimaryAutoCommandBuffer;
-use crate::command_buffer::PrimaryCommandBuffer;
-use crate::device::physical::QueueFamily;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::device::Queue;
-use crate::memory::pool::AllocFromRequirementsFilter;
-use crate::memory::pool::AllocLayout;
-use crate::memory::pool::MappingRequirement;
-use crate::memory::pool::MemoryPool;
-use crate::memory::pool::MemoryPoolAlloc;
-use crate::memory::pool::PotentialDedicatedAllocation;
-use crate::memory::pool::StdMemoryPoolAlloc;
-use crate::memory::DedicatedAlloc;
-use crate::memory::DeviceMemoryAllocError;
-use crate::sync::AccessError;
-use crate::sync::NowFuture;
-use crate::sync::Sharing;
-use crate::DeviceSize;
-use smallvec::SmallVec;
-use std::hash::Hash;
-use std::hash::Hasher;
-use std::marker::PhantomData;
-use std::mem;
-use std::sync::atomic::AtomicBool;
-use std::sync::atomic::Ordering;
-use std::sync::Arc;
-
-/// Buffer that is written once then read for as long as it is alive.
-// TODO: implement Debug
-pub struct ImmutableBuffer<T: ?Sized, A = PotentialDedicatedAllocation<StdMemoryPoolAlloc>> {
- // Inner content.
- inner: UnsafeBuffer,
-
- // Memory allocated for the buffer.
- memory: A,
-
- // True if the `ImmutableBufferInitialization` object was used by the GPU then dropped.
- // This means that the `ImmutableBuffer` can be used as much as we want without any restriction.
- initialized: AtomicBool,
-
- // Queue families allowed to access this buffer.
- queue_families: SmallVec<[u32; 4]>,
-
- // Necessary to have the appropriate template parameter.
- marker: PhantomData<Box<T>>,
-}
-
-// TODO: make this prettier
-type ImmutableBufferFromBufferFuture = CommandBufferExecFuture<NowFuture, PrimaryAutoCommandBuffer>;
-
-impl<T: ?Sized> ImmutableBuffer<T> {
- /// Builds an `ImmutableBuffer` from some data.
- ///
- /// This function builds a memory-mapped intermediate buffer, writes the data to it, builds a
- /// command buffer that copies from this intermediate buffer to the final buffer, and finally
- /// submits the command buffer as a future.
- ///
- /// This function returns two objects: the newly-created buffer, and a future representing
- /// the initial upload operation. In order to be allowed to use the `ImmutableBuffer`, you must
- /// either submit your operation after this future, or execute this future and wait for it to
- /// be finished before submitting your own operation.
- pub fn from_data(
- data: T,
- usage: BufferUsage,
- queue: Arc<Queue>,
- ) -> Result<(Arc<ImmutableBuffer<T>>, ImmutableBufferFromBufferFuture), DeviceMemoryAllocError>
- where
- T: 'static + Copy + Send + Sync + Sized,
- {
- let source = CpuAccessibleBuffer::from_data(
- queue.device().clone(),
- BufferUsage::transfer_source(),
- false,
- data,
- )?;
- ImmutableBuffer::from_buffer(source, usage, queue)
- }
-
- /// Builds an `ImmutableBuffer` that copies its data from another buffer.
- ///
- /// This function returns two objects: the newly-created buffer, and a future representing
- /// the initial upload operation. In order to be allowed to use the `ImmutableBuffer`, you must
- /// either submit your operation after this future, or execute this future and wait for it to
- /// be finished before submitting your own operation.
- pub fn from_buffer<B>(
- source: B,
- usage: BufferUsage,
- queue: Arc<Queue>,
- ) -> Result<(Arc<ImmutableBuffer<T>>, ImmutableBufferFromBufferFuture), DeviceMemoryAllocError>
- where
- B: BufferAccess + TypedBufferAccess<Content = T> + 'static + Clone + Send + Sync,
- T: 'static + Send + Sync,
- {
- unsafe {
- // We automatically set `transfer_destination` to true in order to avoid annoying errors.
- let actual_usage = BufferUsage {
- transfer_destination: true,
- ..usage
- };
-
- let (buffer, init) = ImmutableBuffer::raw(
- source.device().clone(),
- source.size(),
- actual_usage,
- source.device().active_queue_families(),
- )?;
-
- let mut cbb = AutoCommandBufferBuilder::primary(
- source.device().clone(),
- queue.family(),
- CommandBufferUsage::MultipleSubmit,
- )?;
- cbb.copy_buffer(source, init).unwrap(); // TODO: return error?
- let cb = cbb.build().unwrap(); // TODO: return OomError
-
- let future = match cb.execute(queue) {
- Ok(f) => f,
- Err(_) => unreachable!(),
- };
-
- Ok((buffer, future))
- }
- }
-}
-
-impl<T> ImmutableBuffer<T> {
- /// Builds a new buffer with uninitialized data. Only allowed for sized data.
- ///
- /// Returns two things: the buffer, and a special access that should be used for the initial
- /// upload to the buffer.
- ///
- /// You will get an error if you try to use the buffer before using the initial upload access.
- /// However this function doesn't check whether you actually used this initial upload to fill
- /// the buffer like you're supposed to do.
- ///
- /// You will also get an error if you try to get exclusive access to the final buffer.
- ///
- /// # Safety
- ///
- /// - The `ImmutableBufferInitialization` should be used to fill the buffer with some initial
- /// data, otherwise the content is undefined.
- ///
- #[inline]
- pub unsafe fn uninitialized(
- device: Arc<Device>,
- usage: BufferUsage,
- ) -> Result<(Arc<ImmutableBuffer<T>>, ImmutableBufferInitialization<T>), DeviceMemoryAllocError>
- {
- ImmutableBuffer::raw(
- device.clone(),
- mem::size_of::<T>() as DeviceSize,
- usage,
- device.active_queue_families(),
- )
- }
-}
-
-impl<T> ImmutableBuffer<[T]> {
- pub fn from_iter<D>(
- data: D,
- usage: BufferUsage,
- queue: Arc<Queue>,
- ) -> Result<(Arc<ImmutableBuffer<[T]>>, ImmutableBufferFromBufferFuture), DeviceMemoryAllocError>
- where
- D: ExactSizeIterator<Item = T>,
- T: 'static + Send + Sync + Sized,
- {
- let source = CpuAccessibleBuffer::from_iter(
- queue.device().clone(),
- BufferUsage::transfer_source(),
- false,
- data,
- )?;
- ImmutableBuffer::from_buffer(source, usage, queue)
- }
-
- /// Builds a new buffer with uninitialized data. Can be used for arrays.
- ///
- /// Returns two things: the buffer, and a special access that should be used for the initial
- /// upload to the buffer.
- ///
- /// You will get an error if you try to use the buffer before using the initial upload access.
- /// However this function doesn't check whether you actually used this initial upload to fill
- /// the buffer like you're supposed to do.
- ///
- /// You will also get an error if you try to get exclusive access to the final buffer.
- ///
- /// # Safety
- ///
- /// - The `ImmutableBufferInitialization` should be used to fill the buffer with some initial
- /// data, otherwise the content is undefined.
- ///
- #[inline]
- pub unsafe fn uninitialized_array(
- device: Arc<Device>,
- len: DeviceSize,
- usage: BufferUsage,
- ) -> Result<
- (
- Arc<ImmutableBuffer<[T]>>,
- ImmutableBufferInitialization<[T]>,
- ),
- DeviceMemoryAllocError,
- > {
- ImmutableBuffer::raw(
- device.clone(),
- len * mem::size_of::<T>() as DeviceSize,
- usage,
- device.active_queue_families(),
- )
- }
-}
-
-impl<T: ?Sized> ImmutableBuffer<T> {
- /// Builds a new buffer without checking the size and granting free access for the initial
- /// upload.
- ///
- /// Returns two things: the buffer, and a special access that should be used for the initial
- /// upload to the buffer.
- /// You will get an error if you try to use the buffer before using the initial upload access.
- /// However this function doesn't check whether you used this initial upload to fill the buffer.
- /// You will also get an error if you try to get exclusive access to the final buffer.
- ///
- /// # Safety
- ///
- /// - You must ensure that the size that you pass is correct for `T`.
- /// - The `ImmutableBufferInitialization` should be used to fill the buffer with some initial
- /// data.
- ///
- #[inline]
- pub unsafe fn raw<'a, I>(
- device: Arc<Device>,
- size: DeviceSize,
- usage: BufferUsage,
- queue_families: I,
- ) -> Result<(Arc<ImmutableBuffer<T>>, ImmutableBufferInitialization<T>), DeviceMemoryAllocError>
- where
- I: IntoIterator<Item = QueueFamily<'a>>,
- {
- let queue_families = queue_families.into_iter().map(|f| f.id()).collect();
- ImmutableBuffer::raw_impl(device, size, usage, queue_families)
- }
-
- // Internal implementation of `raw`. This is separated from `raw` so that it doesn't need to be
- // inlined.
- unsafe fn raw_impl(
- device: Arc<Device>,
- size: DeviceSize,
- usage: BufferUsage,
- queue_families: SmallVec<[u32; 4]>,
- ) -> Result<(Arc<ImmutableBuffer<T>>, ImmutableBufferInitialization<T>), DeviceMemoryAllocError>
- {
- let (buffer, mem_reqs) = {
- let sharing = if queue_families.len() >= 2 {
- Sharing::Concurrent(queue_families.iter().cloned())
- } else {
- Sharing::Exclusive
- };
-
- match UnsafeBuffer::new(device.clone(), size, usage, sharing, None) {
- Ok(b) => b,
- Err(BufferCreationError::AllocError(err)) => return Err(err),
- Err(_) => unreachable!(), // We don't use sparse binding, therefore the other
- // errors can't happen
- }
- };
-
- let mem = MemoryPool::alloc_from_requirements(
- &Device::standard_pool(&device),
- &mem_reqs,
- AllocLayout::Linear,
- MappingRequirement::DoNotMap,
- DedicatedAlloc::Buffer(&buffer),
- |t| {
- if t.is_device_local() {
- AllocFromRequirementsFilter::Preferred
- } else {
- AllocFromRequirementsFilter::Allowed
- }
- },
- )?;
- debug_assert!((mem.offset() % mem_reqs.alignment) == 0);
- buffer.bind_memory(mem.memory(), mem.offset())?;
-
- let final_buf = Arc::new(ImmutableBuffer {
- inner: buffer,
- memory: mem,
- queue_families: queue_families,
- initialized: AtomicBool::new(false),
- marker: PhantomData,
- });
-
- let initialization = ImmutableBufferInitialization {
- buffer: final_buf.clone(),
- used: Arc::new(AtomicBool::new(false)),
- };
-
- Ok((final_buf, initialization))
- }
-}
-
-impl<T: ?Sized, A> ImmutableBuffer<T, A> {
- /// Returns the device used to create this buffer.
- #[inline]
- pub fn device(&self) -> &Arc<Device> {
- self.inner.device()
- }
-
- /// Returns the queue families this buffer can be used on.
- // TODO: use a custom iterator
- #[inline]
- pub fn queue_families(&self) -> Vec<QueueFamily> {
- self.queue_families
- .iter()
- .map(|&num| {
- self.device()
- .physical_device()
- .queue_family_by_id(num)
- .unwrap()
- })
- .collect()
- }
-}
-
-unsafe impl<T: ?Sized, A> BufferAccess for ImmutableBuffer<T, A> {
- #[inline]
- fn inner(&self) -> BufferInner {
- BufferInner {
- buffer: &self.inner,
- offset: 0,
- }
- }
-
- #[inline]
- fn size(&self) -> DeviceSize {
- self.inner.size()
- }
-
- #[inline]
- fn conflict_key(&self) -> (u64, u64) {
- (self.inner.key(), 0)
- }
-
- #[inline]
- fn try_gpu_lock(&self, exclusive_access: bool, _: &Queue) -> Result<(), AccessError> {
- if exclusive_access {
- return Err(AccessError::ExclusiveDenied);
- }
-
- if !self.initialized.load(Ordering::Relaxed) {
- return Err(AccessError::BufferNotInitialized);
- }
-
- Ok(())
- }
-
- #[inline]
- unsafe fn increase_gpu_lock(&self) {}
-
- #[inline]
- unsafe fn unlock(&self) {}
-}
-
-unsafe impl<T: ?Sized, A> TypedBufferAccess for ImmutableBuffer<T, A> {
- type Content = T;
-}
-
-unsafe impl<T: ?Sized, A> DeviceOwned for ImmutableBuffer<T, A> {
- #[inline]
- fn device(&self) -> &Arc<Device> {
- self.inner.device()
- }
-}
-
-impl<T: ?Sized, A> PartialEq for ImmutableBuffer<T, A> {
- #[inline]
- fn eq(&self, other: &Self) -> bool {
- self.inner() == other.inner() && self.size() == other.size()
- }
-}
-
-impl<T: ?Sized, A> Eq for ImmutableBuffer<T, A> {}
-
-impl<T: ?Sized, A> Hash for ImmutableBuffer<T, A> {
- #[inline]
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.inner().hash(state);
- self.size().hash(state);
- }
-}
-
-/// Access to the immutable buffer that can be used for the initial upload.
-//#[derive(Debug)] // TODO:
-pub struct ImmutableBufferInitialization<
- T: ?Sized,
- A = PotentialDedicatedAllocation<StdMemoryPoolAlloc>,
-> {
- buffer: Arc<ImmutableBuffer<T, A>>,
- used: Arc<AtomicBool>,
-}
-
-unsafe impl<T: ?Sized, A> BufferAccess for ImmutableBufferInitialization<T, A> {
- #[inline]
- fn inner(&self) -> BufferInner {
- self.buffer.inner()
- }
-
- #[inline]
- fn size(&self) -> DeviceSize {
- self.buffer.size()
- }
-
- #[inline]
- fn conflict_key(&self) -> (u64, u64) {
- (self.buffer.inner.key(), 0)
- }
-
- #[inline]
- fn try_gpu_lock(&self, _: bool, _: &Queue) -> Result<(), AccessError> {
- if self.buffer.initialized.load(Ordering::Relaxed) {
- return Err(AccessError::AlreadyInUse);
- }
-
- if !self
- .used
- .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
- .unwrap_or_else(|e| e)
- {
- Ok(())
- } else {
- Err(AccessError::AlreadyInUse)
- }
- }
-
- #[inline]
- unsafe fn increase_gpu_lock(&self) {
- debug_assert!(self.used.load(Ordering::Relaxed));
- }
-
- #[inline]
- unsafe fn unlock(&self) {
- self.buffer.initialized.store(true, Ordering::Relaxed);
- }
-}
-
-unsafe impl<T: ?Sized, A> TypedBufferAccess for ImmutableBufferInitialization<T, A> {
- type Content = T;
-}
-
-unsafe impl<T: ?Sized, A> DeviceOwned for ImmutableBufferInitialization<T, A> {
- #[inline]
- fn device(&self) -> &Arc<Device> {
- self.buffer.inner.device()
- }
-}
-
-impl<T: ?Sized, A> Clone for ImmutableBufferInitialization<T, A> {
- #[inline]
- fn clone(&self) -> ImmutableBufferInitialization<T, A> {
- ImmutableBufferInitialization {
- buffer: self.buffer.clone(),
- used: self.used.clone(),
- }
- }
-}
-
-impl<T: ?Sized, A> PartialEq for ImmutableBufferInitialization<T, A> {
- #[inline]
- fn eq(&self, other: &Self) -> bool {
- self.inner() == other.inner() && self.size() == other.size()
- }
-}
-
-impl<T: ?Sized, A> Eq for ImmutableBufferInitialization<T, A> {}
-
-impl<T: ?Sized, A> Hash for ImmutableBufferInitialization<T, A> {
- #[inline]
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.inner().hash(state);
- self.size().hash(state);
- }
-}
-
-#[cfg(test)]
-mod tests {
- use crate::buffer::cpu_access::CpuAccessibleBuffer;
- use crate::buffer::immutable::ImmutableBuffer;
- use crate::buffer::BufferUsage;
- use crate::command_buffer::AutoCommandBufferBuilder;
- use crate::command_buffer::CommandBufferUsage;
- use crate::command_buffer::PrimaryCommandBuffer;
- use crate::sync::GpuFuture;
-
- #[test]
- fn from_data_working() {
- let (device, queue) = gfx_dev_and_queue!();
-
- let (buffer, _) =
- ImmutableBuffer::from_data(12u32, BufferUsage::all(), queue.clone()).unwrap();
-
- let destination =
- CpuAccessibleBuffer::from_data(device.clone(), BufferUsage::all(), false, 0).unwrap();
-
- let mut cbb = AutoCommandBufferBuilder::primary(
- device.clone(),
- queue.family(),
- CommandBufferUsage::MultipleSubmit,
- )
- .unwrap();
- cbb.copy_buffer(buffer, destination.clone()).unwrap();
- let _ = cbb
- .build()
- .unwrap()
- .execute(queue.clone())
- .unwrap()
- .then_signal_fence_and_flush()
- .unwrap();
-
- let destination_content = destination.read().unwrap();
- assert_eq!(*destination_content, 12);
- }
-
- #[test]
- fn from_iter_working() {
- let (device, queue) = gfx_dev_and_queue!();
-
- let (buffer, _) = ImmutableBuffer::from_iter(
- (0..512u32).map(|n| n * 2),
- BufferUsage::all(),
- queue.clone(),
- )
- .unwrap();
-
- let destination = CpuAccessibleBuffer::from_iter(
- device.clone(),
- BufferUsage::all(),
- false,
- (0..512).map(|_| 0u32),
- )
- .unwrap();
-
- let mut cbb = AutoCommandBufferBuilder::primary(
- device.clone(),
- queue.family(),
- CommandBufferUsage::MultipleSubmit,
- )
- .unwrap();
- cbb.copy_buffer(buffer, destination.clone()).unwrap();
- let _ = cbb
- .build()
- .unwrap()
- .execute(queue.clone())
- .unwrap()
- .then_signal_fence_and_flush()
- .unwrap();
-
- let destination_content = destination.read().unwrap();
- for (n, &v) in destination_content.iter().enumerate() {
- assert_eq!(n * 2, v as usize);
- }
- }
-
- #[test]
- fn writing_forbidden() {
- let (device, queue) = gfx_dev_and_queue!();
-
- let (buffer, _) =
- ImmutableBuffer::from_data(12u32, BufferUsage::all(), queue.clone()).unwrap();
-
- assert_should_panic!({
- // TODO: check Result error instead of panicking
- let mut cbb = AutoCommandBufferBuilder::primary(
- device.clone(),
- queue.family(),
- CommandBufferUsage::MultipleSubmit,
- )
- .unwrap();
- cbb.fill_buffer(buffer, 50).unwrap();
- let _ = cbb
- .build()
- .unwrap()
- .execute(queue.clone())
- .unwrap()
- .then_signal_fence_and_flush()
- .unwrap();
- });
- }
-
- #[test]
- fn read_uninitialized_forbidden() {
- let (device, queue) = gfx_dev_and_queue!();
-
- let (buffer, _) = unsafe {
- ImmutableBuffer::<u32>::uninitialized(device.clone(), BufferUsage::all()).unwrap()
- };
-
- let source =
- CpuAccessibleBuffer::from_data(device.clone(), BufferUsage::all(), false, 0).unwrap();
-
- assert_should_panic!({
- // TODO: check Result error instead of panicking
- let mut cbb = AutoCommandBufferBuilder::primary(
- device.clone(),
- queue.family(),
- CommandBufferUsage::MultipleSubmit,
- )
- .unwrap();
- cbb.copy_buffer(source, buffer).unwrap();
- let _ = cbb
- .build()
- .unwrap()
- .execute(queue.clone())
- .unwrap()
- .then_signal_fence_and_flush()
- .unwrap();
- });
- }
-
- #[test]
- fn init_then_read_same_cb() {
- let (device, queue) = gfx_dev_and_queue!();
-
- let (buffer, init) = unsafe {
- ImmutableBuffer::<u32>::uninitialized(device.clone(), BufferUsage::all()).unwrap()
- };
-
- let source =
- CpuAccessibleBuffer::from_data(device.clone(), BufferUsage::all(), false, 0).unwrap();
-
- let mut cbb = AutoCommandBufferBuilder::primary(
- device.clone(),
- queue.family(),
- CommandBufferUsage::MultipleSubmit,
- )
- .unwrap();
- cbb.copy_buffer(source.clone(), init)
- .unwrap()
- .copy_buffer(buffer, source.clone())
- .unwrap();
- let _ = cbb
- .build()
- .unwrap()
- .execute(queue.clone())
- .unwrap()
- .then_signal_fence_and_flush()
- .unwrap();
- }
-
- #[test]
- #[ignore] // TODO: doesn't work because the submit sync layer isn't properly implemented
- fn init_then_read_same_future() {
- let (device, queue) = gfx_dev_and_queue!();
-
- let (buffer, init) = unsafe {
- ImmutableBuffer::<u32>::uninitialized(device.clone(), BufferUsage::all()).unwrap()
- };
-
- let source =
- CpuAccessibleBuffer::from_data(device.clone(), BufferUsage::all(), false, 0).unwrap();
-
- let mut cbb = AutoCommandBufferBuilder::primary(
- device.clone(),
- queue.family(),
- CommandBufferUsage::MultipleSubmit,
- )
- .unwrap();
- cbb.copy_buffer(source.clone(), init).unwrap();
- let cb1 = cbb.build().unwrap();
-
- let mut cbb = AutoCommandBufferBuilder::primary(
- device.clone(),
- queue.family(),
- CommandBufferUsage::MultipleSubmit,
- )
- .unwrap();
- cbb.copy_buffer(buffer, source.clone()).unwrap();
- let cb2 = cbb.build().unwrap();
-
- let _ = cb1
- .execute(queue.clone())
- .unwrap()
- .then_execute(queue.clone(), cb2)
- .unwrap()
- .then_signal_fence_and_flush()
- .unwrap();
- }
-
- #[test]
- fn create_buffer_zero_size_data() {
- let (device, queue) = gfx_dev_and_queue!();
-
- let _ = ImmutableBuffer::from_data((), BufferUsage::all(), queue.clone());
- }
-
- // TODO: write tons of tests that try to exploit loopholes
- // this isn't possible yet because checks aren't correctly implemented yet
-}
diff --git a/src/buffer/mod.rs b/src/buffer/mod.rs
index 1f203a9..1099b68 100644
--- a/src/buffer/mod.rs
+++ b/src/buffer/mod.rs
@@ -14,46 +14,60 @@
//! between a Vulkan buffer and a regular buffer is that the content of a Vulkan buffer is
//! accessible from the GPU.
//!
-//! # Various kinds of buffers
-//!
-//! The low level implementation of a buffer is [`UnsafeBuffer`](sys/struct.UnsafeBuffer.html).
-//! This type makes it possible to use all the features that Vulkan is capable of, but as its name
-//! tells it is unsafe to use.
-//!
-//! Instead you are encouraged to use one of the high-level wrappers that vulkano provides. Which
-//! wrapper to use depends on the way you are going to use the buffer:
-//!
-//! - A [`DeviceLocalBuffer`](device_local/struct.DeviceLocalBuffer.html) designates a buffer
-//! usually located in video memory and whose content can't be directly accessed by your
-//! application. Accessing this buffer from the GPU is generally faster compared to accessing a
-//! CPU-accessible buffer.
-//! - An [`ImmutableBuffer`](immutable/struct.ImmutableBuffer.html) designates a buffer in video
-//! memory and whose content can only be written at creation. Compared to `DeviceLocalBuffer`,
-//! this buffer requires less CPU processing because we don't need to keep track of the reads
-//! and writes.
-//! - A [`CpuBufferPool`](cpu_pool/struct.CpuBufferPool.html) is a ring buffer that can be used to
-//! transfer data between the CPU and the GPU at a high rate.
-//! - A [`CpuAccessibleBuffer`](cpu_access/struct.CpuAccessibleBuffer.html) is a simple buffer that
-//! can be used to prototype. It may be removed from vulkano in the far future.
-//!
-//! Here is a quick way to choose which buffer to use. Do you often need to read or write
-//! the content of the buffer? If so, use a `CpuBufferPool`. Otherwise, do you need to be able to
-//! modify the content of the buffer after its initialization? If so, use a `DeviceLocalBuffer`.
-//! If no to both questions, use an `ImmutableBuffer`.
-//!
-//! When deciding how your buffer is going to be used, don't forget that sometimes the best
-//! solution is to manipulate multiple buffers instead. For example if you need to update a buffer's
-//! content only from time to time, it may be a good idea to simply recreate a new `ImmutableBuffer`
-//! every time.
-//! Another example: if a buffer is under constant access by the GPU but you need to
-//! read its content on the CPU from time to time, it may be a good idea to use a
-//! `DeviceLocalBuffer` as the main buffer and a `CpuBufferPool` for when you need to read it.
-//! Then whenever you need to read the main buffer, ask the GPU to copy from the device-local
-//! buffer to the CPU buffer pool, and read the CPU buffer pool instead.
-//!
-//! # Buffers usage
-//!
-//! When you create a buffer object, you have to specify its *usage*. In other words, you have to
+//! Vulkano does not perform any specific marshalling of buffer data. The representation of the
+//! buffer in memory is identical between the CPU and GPU. Because the Rust compiler is allowed to
+//! reorder struct fields at will by default when using `#[repr(Rust)]`, it is advised to mark each
+//! struct requiring imput assembly as `#[repr(C)]`. This forces Rust to follow the standard C
+//! procedure. Each element is laid out in memory in the order of declaration and aligned to a
+//! multiple of their alignment.
+//!
+//! # Multiple levels of abstraction
+//!
+//! - The low-level implementation of a buffer is [`RawBuffer`], which corresponds directly to a
+//! `VkBuffer`, and as such doesn't hold onto any memory.
+//! - [`Buffer`] is a `RawBuffer` with memory bound to it, and with state tracking.
+//! - [`Subbuffer`] is what you will use most of the time, as it is what all the APIs expect. It is
+//! a reference to a portion of a `Buffer`. `Subbuffer` also has a type parameter, which is a
+//! hint for how the data in the portion of the buffer is going to be interpreted.
+//!
+//! # `Subbuffer` allocation
+//!
+//! There are two ways to get a `Subbuffer`:
+//!
+//! - By using the functions on `Buffer`, which create a new buffer and memory allocation each
+//! time, and give you a `Subbuffer` that has an entire `Buffer` dedicated to it.
+//! - By using the [`SubbufferAllocator`], which creates `Subbuffer`s by suballocating existing
+//! `Buffer`s such that the `Buffer`s can keep being reused.
+//!
+//! Which of these you should choose depends on the use case. For example, if you need to upload
+//! data to the device each frame, then you should use `SubbufferAllocator`. Same goes for if you
+//! need to download data very frequently, or if you need to allocate a lot of intermediary buffers
+//! that are only accessed by the device. On the other hand, if you need to upload some data just
+//! once, or you can keep reusing the same buffer (because its size is unchanging) it's best to
+//! use a dedicated `Buffer` for that.
+//!
+//! # Memory usage
+//!
+//! When allocating memory for a buffer, you have to specify a *memory usage*. This tells the
+//! memory allocator what memory type it should pick for the allocation.
+//!
+//! - [`MemoryUsage::DeviceOnly`] will allocate a buffer that's usually located in device-local
+//! memory and whose content can't be directly accessed by your application. Accessing this
+//! buffer from the device is generally faster compared to accessing a buffer that's located in
+//! host-visible memory.
+//! - [`MemoryUsage::Upload`] and [`MemoryUsage::Download`] both allocate from a host-visible
+//! memory type, which means the buffer can be accessed directly from the host. Buffers allocated
+//! with these memory usages are needed to get data to and from the device.
+//!
+//! Take for example a buffer that is under constant access by the device but you need to read its
+//! content on the host from time to time, it may be a good idea to use a device-local buffer as
+//! the main buffer and a host-visible buffer for when you need to read it. Then whenever you need
+//! to read the main buffer, ask the device to copy from the device-local buffer to the
+//! host-visible buffer, and read the host-visible buffer instead.
+//!
+//! # Buffer usage
+//!
+//! When you create a buffer, you have to specify its *usage*. In other words, you have to
//! specify the way it is going to be used. Trying to use a buffer in a way that wasn't specified
//! when you created it will result in a runtime error.
//!
@@ -68,35 +82,1054 @@
//!
//! - As a uniform buffer. Uniform buffers are read-only.
//! - As a storage buffer. Storage buffers can be read and written.
-//! - As a uniform texel buffer. Contrary to a uniform buffer, the data is interpreted by the
-//! GPU and can be for example normalized.
+//! - As a uniform texel buffer. Contrary to a uniform buffer, the data is interpreted by the GPU
+//! and can be for example normalized.
//! - As a storage texel buffer. Additionally, some data formats can be modified with atomic
//! operations.
//!
-//! Using uniform/storage texel buffers requires creating a *buffer view*. See the `view` module
+//! Using uniform/storage texel buffers requires creating a *buffer view*. See [the `view` module]
//! for how to create a buffer view.
//!
+//! See also [the `shader` module documentation] for information about how buffer contents need to
+//! be laid out in accordance with the shader interface.
+//!
+//! [`RawBuffer`]: self::sys::RawBuffer
+//! [`SubbufferAllocator`]: self::allocator::SubbufferAllocator
+//! [`MemoryUsage::DeviceOnly`]: crate::memory::allocator::MemoryUsage::DeviceOnly
+//! [`MemoryUsage::Upload`]: crate::memory::allocator::MemoryUsage::Upload
+//! [`MemoryUsage::Download`]: crate::memory::allocator::MemoryUsage::Download
+//! [the `view` module]: self::view
+//! [the `shader` module documentation]: crate::shader
+
+pub use self::{
+ subbuffer::{BufferContents, BufferContentsLayout, Subbuffer},
+ sys::BufferCreateInfo,
+ usage::BufferUsage,
+};
+use self::{
+ subbuffer::{ReadLockError, WriteLockError},
+ sys::RawBuffer,
+};
+use crate::{
+ device::{Device, DeviceOwned},
+ macros::vulkan_bitflags,
+ memory::{
+ allocator::{
+ AllocationCreateInfo, AllocationCreationError, AllocationType, DeviceLayout,
+ MemoryAlloc, MemoryAllocator,
+ },
+ is_aligned, DedicatedAllocation, DeviceAlignment, ExternalMemoryHandleType,
+ ExternalMemoryHandleTypes, ExternalMemoryProperties, MemoryRequirements,
+ },
+ range_map::RangeMap,
+ sync::{future::AccessError, CurrentAccess, Sharing},
+ DeviceSize, NonZeroDeviceSize, RequirementNotMet, RequiresOneOf, Version, VulkanError,
+ VulkanObject,
+};
+use parking_lot::{Mutex, MutexGuard};
+use smallvec::SmallVec;
+use std::{
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+ hash::{Hash, Hasher},
+ mem::size_of_val,
+ ops::Range,
+ ptr,
+ sync::Arc,
+};
-pub use self::cpu_access::CpuAccessibleBuffer;
-pub use self::cpu_pool::CpuBufferPool;
-pub use self::device_local::DeviceLocalBuffer;
-pub use self::immutable::ImmutableBuffer;
-pub use self::slice::BufferSlice;
-pub use self::sys::BufferCreationError;
-pub use self::traits::BufferAccess;
-pub use self::traits::BufferInner;
-pub use self::traits::TypedBufferAccess;
-pub use self::usage::BufferUsage;
-pub use self::view::BufferView;
-pub use self::view::BufferViewRef;
-
-pub mod cpu_access;
-pub mod cpu_pool;
-pub mod device_local;
-pub mod immutable;
+pub mod allocator;
+pub mod subbuffer;
pub mod sys;
+mod usage;
pub mod view;
-mod slice;
-mod traits;
-mod usage;
+/// A storage for raw bytes.
+///
+/// Unlike [`RawBuffer`], a `Buffer` has memory backing it, and can be used normally.
+///
+/// See [the module-level documentation] for more information about buffers.
+///
+/// # Examples
+///
+/// Sometimes, you need a buffer that is rarely accessed by the host. To get the best performance
+/// in this case, one should use a buffer in device-local memory, that is inaccessible from the
+/// host. As such, to initialize or otherwise access such a buffer, we need a *staging buffer*.
+///
+/// The following example outlines the general strategy one may take when initializing a
+/// device-local buffer.
+///
+/// ```
+/// use vulkano::{
+/// buffer::{BufferUsage, Buffer, BufferCreateInfo},
+/// command_buffer::{
+/// AutoCommandBufferBuilder, CommandBufferUsage, CopyBufferInfo,
+/// PrimaryCommandBufferAbstract,
+/// },
+/// memory::allocator::{AllocationCreateInfo, MemoryUsage},
+/// sync::GpuFuture,
+/// DeviceSize,
+/// };
+///
+/// # let device: std::sync::Arc<vulkano::device::Device> = return;
+/// # let queue: std::sync::Arc<vulkano::device::Queue> = return;
+/// # let memory_allocator: vulkano::memory::allocator::StandardMemoryAllocator = return;
+/// # let command_buffer_allocator: vulkano::command_buffer::allocator::StandardCommandBufferAllocator = return;
+/// // Simple iterator to construct test data.
+/// let data = (0..10_000).map(|i| i as f32);
+///
+/// // Create a host-accessible buffer initialized with the data.
+/// let temporary_accessible_buffer = Buffer::from_iter(
+/// &memory_allocator,
+/// BufferCreateInfo {
+/// // Specify that this buffer will be used as a transfer source.
+/// usage: BufferUsage::TRANSFER_SRC,
+/// ..Default::default()
+/// },
+/// AllocationCreateInfo {
+/// // Specify use for upload to the device.
+/// usage: MemoryUsage::Upload,
+/// ..Default::default()
+/// },
+/// data,
+/// )
+/// .unwrap();
+///
+/// // Create a buffer in device-local with enough space for a slice of `10_000` floats.
+/// let device_local_buffer = Buffer::new_slice::<f32>(
+/// &memory_allocator,
+/// BufferCreateInfo {
+/// // Specify use as a storage buffer and transfer destination.
+/// usage: BufferUsage::STORAGE_BUFFER | BufferUsage::TRANSFER_DST,
+/// ..Default::default()
+/// },
+/// AllocationCreateInfo {
+/// // Specify use by the device only.
+/// usage: MemoryUsage::DeviceOnly,
+/// ..Default::default()
+/// },
+/// 10_000 as DeviceSize,
+/// )
+/// .unwrap();
+///
+/// // Create a one-time command to copy between the buffers.
+/// let mut cbb = AutoCommandBufferBuilder::primary(
+/// &command_buffer_allocator,
+/// queue.queue_family_index(),
+/// CommandBufferUsage::OneTimeSubmit,
+/// )
+/// .unwrap();
+/// cbb.copy_buffer(CopyBufferInfo::buffers(
+/// temporary_accessible_buffer,
+/// device_local_buffer.clone(),
+/// ))
+/// .unwrap();
+/// let cb = cbb.build().unwrap();
+///
+/// // Execute the copy command and wait for completion before proceeding.
+/// cb.execute(queue.clone())
+/// .unwrap()
+/// .then_signal_fence_and_flush()
+/// .unwrap()
+/// .wait(None /* timeout */)
+/// .unwrap()
+/// ```
+///
+/// [the module-level documentation]: self
+#[derive(Debug)]
+pub struct Buffer {
+ inner: RawBuffer,
+ memory: BufferMemory,
+ state: Mutex<BufferState>,
+}
+
+/// The type of backing memory that a buffer can have.
+#[derive(Debug)]
+pub enum BufferMemory {
+ /// The buffer is backed by normal memory, bound with [`bind_memory`].
+ ///
+ /// [`bind_memory`]: RawBuffer::bind_memory
+ Normal(MemoryAlloc),
+
+ /// The buffer is backed by sparse memory, bound with [`bind_sparse`].
+ ///
+ /// [`bind_sparse`]: crate::device::QueueGuard::bind_sparse
+ Sparse,
+}
+
+impl Buffer {
+ /// Creates a new `Buffer` and writes `data` in it. Returns a [`Subbuffer`] spanning the whole
+ /// buffer.
+ ///
+ /// This only works with memory types that are host-visible. If you want to upload data to a
+ /// buffer allocated in device-local memory, you will need to create a staging buffer and copy
+ /// the contents over.
+ ///
+ /// > **Note**: You should **not** set the `buffer_info.size` field. The function does that
+ /// > itself.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `T` has zero size.
+ /// - Panics if `T` has an alignment greater than `64`.
+ pub fn from_data<T>(
+ allocator: &(impl MemoryAllocator + ?Sized),
+ buffer_info: BufferCreateInfo,
+ allocation_info: AllocationCreateInfo,
+ data: T,
+ ) -> Result<Subbuffer<T>, BufferError>
+ where
+ T: BufferContents,
+ {
+ let buffer = Buffer::new_sized(allocator, buffer_info, allocation_info)?;
+
+ unsafe { ptr::write(&mut *buffer.write()?, data) };
+
+ Ok(buffer)
+ }
+
+ /// Creates a new `Buffer` and writes all elements of `iter` in it. Returns a [`Subbuffer`]
+ /// spanning the whole buffer.
+ ///
+ /// This only works with memory types that are host-visible. If you want to upload data to a
+ /// buffer allocated in device-local memory, you will need to create a staging buffer and copy
+ /// the contents over.
+ ///
+ /// > **Note**: You should **not** set the `buffer_info.size` field. The function does that
+ /// > itself.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `iter` is empty.
+ pub fn from_iter<T, I>(
+ allocator: &(impl MemoryAllocator + ?Sized),
+ buffer_info: BufferCreateInfo,
+ allocation_info: AllocationCreateInfo,
+ iter: I,
+ ) -> Result<Subbuffer<[T]>, BufferError>
+ where
+ T: BufferContents,
+ I: IntoIterator<Item = T>,
+ I::IntoIter: ExactSizeIterator,
+ {
+ let iter = iter.into_iter();
+ let buffer = Buffer::new_slice(
+ allocator,
+ buffer_info,
+ allocation_info,
+ iter.len().try_into().unwrap(),
+ )?;
+
+ for (o, i) in buffer.write()?.iter_mut().zip(iter) {
+ unsafe { ptr::write(o, i) };
+ }
+
+ Ok(buffer)
+ }
+
+ /// Creates a new uninitialized `Buffer` for sized data. Returns a [`Subbuffer`] spanning the
+ /// whole buffer.
+ ///
+ /// > **Note**: You should **not** set the `buffer_info.size` field. The function does that
+ /// > itself.
+ pub fn new_sized<T>(
+ allocator: &(impl MemoryAllocator + ?Sized),
+ buffer_info: BufferCreateInfo,
+ allocation_info: AllocationCreateInfo,
+ ) -> Result<Subbuffer<T>, BufferError>
+ where
+ T: BufferContents,
+ {
+ let layout = T::LAYOUT.unwrap_sized();
+ let buffer = Subbuffer::new(Buffer::new(
+ allocator,
+ buffer_info,
+ allocation_info,
+ layout,
+ )?);
+
+ Ok(unsafe { buffer.reinterpret_unchecked() })
+ }
+
+ /// Creates a new uninitialized `Buffer` for a slice. Returns a [`Subbuffer`] spanning the
+ /// whole buffer.
+ ///
+ /// > **Note**: You should **not** set the `buffer_info.size` field. The function does that
+ /// > itself.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `len` is zero.
+ pub fn new_slice<T>(
+ allocator: &(impl MemoryAllocator + ?Sized),
+ buffer_info: BufferCreateInfo,
+ allocation_info: AllocationCreateInfo,
+ len: DeviceSize,
+ ) -> Result<Subbuffer<[T]>, BufferError>
+ where
+ T: BufferContents,
+ {
+ Buffer::new_unsized(allocator, buffer_info, allocation_info, len)
+ }
+
+ /// Creates a new uninitialized `Buffer` for unsized data. Returns a [`Subbuffer`] spanning the
+ /// whole buffer.
+ ///
+ /// > **Note**: You should **not** set the `buffer_info.size` field. The function does that
+ /// > itself.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `len` is zero.
+ pub fn new_unsized<T>(
+ allocator: &(impl MemoryAllocator + ?Sized),
+ buffer_info: BufferCreateInfo,
+ allocation_info: AllocationCreateInfo,
+ len: DeviceSize,
+ ) -> Result<Subbuffer<T>, BufferError>
+ where
+ T: BufferContents + ?Sized,
+ {
+ let len = NonZeroDeviceSize::new(len).expect("empty slices are not valid buffer contents");
+ let layout = T::LAYOUT.layout_for_len(len).unwrap();
+ let buffer = Subbuffer::new(Buffer::new(
+ allocator,
+ buffer_info,
+ allocation_info,
+ layout,
+ )?);
+
+ Ok(unsafe { buffer.reinterpret_unchecked() })
+ }
+
+ /// Creates a new uninitialized `Buffer` with the given `layout`.
+ ///
+ /// > **Note**: You should **not** set the `buffer_info.size` field. The function does that
+ /// > itself.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `layout.alignment()` is greater than 64.
+ pub fn new(
+ allocator: &(impl MemoryAllocator + ?Sized),
+ mut buffer_info: BufferCreateInfo,
+ allocation_info: AllocationCreateInfo,
+ layout: DeviceLayout,
+ ) -> Result<Arc<Self>, BufferError> {
+ assert!(layout.alignment().as_devicesize() <= 64);
+ // TODO: Enable once sparse binding materializes
+ // assert!(!allocate_info.flags.contains(BufferCreateFlags::SPARSE_BINDING));
+
+ assert!(
+ buffer_info.size == 0,
+ "`Buffer::new*` functions set the `buffer_info.size` field themselves, you should not \
+ set it yourself",
+ );
+
+ buffer_info.size = layout.size();
+
+ let raw_buffer = RawBuffer::new(allocator.device().clone(), buffer_info)?;
+ let mut requirements = *raw_buffer.memory_requirements();
+ requirements.layout = requirements.layout.align_to(layout.alignment()).unwrap();
+
+ let mut allocation = unsafe {
+ allocator.allocate_unchecked(
+ requirements,
+ AllocationType::Linear,
+ allocation_info,
+ Some(DedicatedAllocation::Buffer(&raw_buffer)),
+ )
+ }?;
+ debug_assert!(is_aligned(
+ allocation.offset(),
+ requirements.layout.alignment(),
+ ));
+ debug_assert!(allocation.size() == requirements.layout.size());
+
+ // The implementation might require a larger size than we wanted. With this it is easier to
+ // invalidate and flush the whole buffer. It does not affect the allocation in any way.
+ allocation.shrink(layout.size());
+
+ unsafe { raw_buffer.bind_memory_unchecked(allocation) }
+ .map(Arc::new)
+ .map_err(|(err, _, _)| err.into())
+ }
+
+ fn from_raw(inner: RawBuffer, memory: BufferMemory) -> Self {
+ let state = Mutex::new(BufferState::new(inner.size()));
+
+ Buffer {
+ inner,
+ memory,
+ state,
+ }
+ }
+
+ /// Returns the type of memory that is backing this buffer.
+ #[inline]
+ pub fn memory(&self) -> &BufferMemory {
+ &self.memory
+ }
+
+ /// Returns the memory requirements for this buffer.
+ #[inline]
+ pub fn memory_requirements(&self) -> &MemoryRequirements {
+ self.inner.memory_requirements()
+ }
+
+ /// Returns the flags the buffer was created with.
+ #[inline]
+ pub fn flags(&self) -> BufferCreateFlags {
+ self.inner.flags()
+ }
+
+ /// Returns the size of the buffer in bytes.
+ #[inline]
+ pub fn size(&self) -> DeviceSize {
+ self.inner.size()
+ }
+
+ /// Returns the usage the buffer was created with.
+ #[inline]
+ pub fn usage(&self) -> BufferUsage {
+ self.inner.usage()
+ }
+
+ /// Returns the sharing the buffer was created with.
+ #[inline]
+ pub fn sharing(&self) -> &Sharing<SmallVec<[u32; 4]>> {
+ self.inner.sharing()
+ }
+
+ /// Returns the external memory handle types that are supported with this buffer.
+ #[inline]
+ pub fn external_memory_handle_types(&self) -> ExternalMemoryHandleTypes {
+ self.inner.external_memory_handle_types()
+ }
+
+ /// Returns the device address for this buffer.
+ // TODO: Caching?
+ pub fn device_address(&self) -> Result<NonZeroDeviceSize, BufferError> {
+ let device = self.device();
+
+ // VUID-vkGetBufferDeviceAddress-bufferDeviceAddress-03324
+ if !device.enabled_features().buffer_device_address {
+ return Err(BufferError::RequirementNotMet {
+ required_for: "`Buffer::device_address`",
+ requires_one_of: RequiresOneOf {
+ features: &["buffer_device_address"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkBufferDeviceAddressInfo-buffer-02601
+ if !self.usage().intersects(BufferUsage::SHADER_DEVICE_ADDRESS) {
+ return Err(BufferError::BufferMissingUsage);
+ }
+
+ let info = ash::vk::BufferDeviceAddressInfo {
+ buffer: self.handle(),
+ ..Default::default()
+ };
+ let fns = device.fns();
+ let f = if device.api_version() >= Version::V1_2 {
+ fns.v1_2.get_buffer_device_address
+ } else if device.enabled_extensions().khr_buffer_device_address {
+ fns.khr_buffer_device_address.get_buffer_device_address_khr
+ } else {
+ fns.ext_buffer_device_address.get_buffer_device_address_ext
+ };
+ let ptr = unsafe { f(device.handle(), &info) };
+
+ Ok(NonZeroDeviceSize::new(ptr).unwrap())
+ }
+
+ pub(crate) fn state(&self) -> MutexGuard<'_, BufferState> {
+ self.state.lock()
+ }
+}
+
+unsafe impl VulkanObject for Buffer {
+ type Handle = ash::vk::Buffer;
+
+ #[inline]
+ fn handle(&self) -> Self::Handle {
+ self.inner.handle()
+ }
+}
+
+unsafe impl DeviceOwned for Buffer {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ self.inner.device()
+ }
+}
+
+impl PartialEq for Buffer {
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ self.inner == other.inner
+ }
+}
+
+impl Eq for Buffer {}
+
+impl Hash for Buffer {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.inner.hash(state);
+ }
+}
+
+/// The current state of a buffer.
+#[derive(Debug)]
+pub(crate) struct BufferState {
+ ranges: RangeMap<DeviceSize, BufferRangeState>,
+}
+
+impl BufferState {
+ fn new(size: DeviceSize) -> Self {
+ BufferState {
+ ranges: [(
+ 0..size,
+ BufferRangeState {
+ current_access: CurrentAccess::Shared {
+ cpu_reads: 0,
+ gpu_reads: 0,
+ },
+ },
+ )]
+ .into_iter()
+ .collect(),
+ }
+ }
+
+ pub(crate) fn check_cpu_read(&self, range: Range<DeviceSize>) -> Result<(), ReadLockError> {
+ for (_range, state) in self.ranges.range(&range) {
+ match &state.current_access {
+ CurrentAccess::CpuExclusive { .. } => return Err(ReadLockError::CpuWriteLocked),
+ CurrentAccess::GpuExclusive { .. } => return Err(ReadLockError::GpuWriteLocked),
+ CurrentAccess::Shared { .. } => (),
+ }
+ }
+
+ Ok(())
+ }
+
+ pub(crate) unsafe fn cpu_read_lock(&mut self, range: Range<DeviceSize>) {
+ self.ranges.split_at(&range.start);
+ self.ranges.split_at(&range.end);
+
+ for (_range, state) in self.ranges.range_mut(&range) {
+ match &mut state.current_access {
+ CurrentAccess::Shared { cpu_reads, .. } => {
+ *cpu_reads += 1;
+ }
+ _ => unreachable!("Buffer is being written by the CPU or GPU"),
+ }
+ }
+ }
+
+ pub(crate) unsafe fn cpu_read_unlock(&mut self, range: Range<DeviceSize>) {
+ self.ranges.split_at(&range.start);
+ self.ranges.split_at(&range.end);
+
+ for (_range, state) in self.ranges.range_mut(&range) {
+ match &mut state.current_access {
+ CurrentAccess::Shared { cpu_reads, .. } => *cpu_reads -= 1,
+ _ => unreachable!("Buffer was not locked for CPU read"),
+ }
+ }
+ }
+
+ pub(crate) fn check_cpu_write(&self, range: Range<DeviceSize>) -> Result<(), WriteLockError> {
+ for (_range, state) in self.ranges.range(&range) {
+ match &state.current_access {
+ CurrentAccess::CpuExclusive => return Err(WriteLockError::CpuLocked),
+ CurrentAccess::GpuExclusive { .. } => return Err(WriteLockError::GpuLocked),
+ CurrentAccess::Shared {
+ cpu_reads: 0,
+ gpu_reads: 0,
+ } => (),
+ CurrentAccess::Shared { cpu_reads, .. } if *cpu_reads > 0 => {
+ return Err(WriteLockError::CpuLocked)
+ }
+ CurrentAccess::Shared { .. } => return Err(WriteLockError::GpuLocked),
+ }
+ }
+
+ Ok(())
+ }
+
+ pub(crate) unsafe fn cpu_write_lock(&mut self, range: Range<DeviceSize>) {
+ self.ranges.split_at(&range.start);
+ self.ranges.split_at(&range.end);
+
+ for (_range, state) in self.ranges.range_mut(&range) {
+ state.current_access = CurrentAccess::CpuExclusive;
+ }
+ }
+
+ pub(crate) unsafe fn cpu_write_unlock(&mut self, range: Range<DeviceSize>) {
+ self.ranges.split_at(&range.start);
+ self.ranges.split_at(&range.end);
+
+ for (_range, state) in self.ranges.range_mut(&range) {
+ match &mut state.current_access {
+ CurrentAccess::CpuExclusive => {
+ state.current_access = CurrentAccess::Shared {
+ cpu_reads: 0,
+ gpu_reads: 0,
+ }
+ }
+ _ => unreachable!("Buffer was not locked for CPU write"),
+ }
+ }
+ }
+
+ pub(crate) fn check_gpu_read(&self, range: Range<DeviceSize>) -> Result<(), AccessError> {
+ for (_range, state) in self.ranges.range(&range) {
+ match &state.current_access {
+ CurrentAccess::Shared { .. } => (),
+ _ => return Err(AccessError::AlreadyInUse),
+ }
+ }
+
+ Ok(())
+ }
+
+ pub(crate) unsafe fn gpu_read_lock(&mut self, range: Range<DeviceSize>) {
+ self.ranges.split_at(&range.start);
+ self.ranges.split_at(&range.end);
+
+ for (_range, state) in self.ranges.range_mut(&range) {
+ match &mut state.current_access {
+ CurrentAccess::GpuExclusive { gpu_reads, .. }
+ | CurrentAccess::Shared { gpu_reads, .. } => *gpu_reads += 1,
+ _ => unreachable!("Buffer is being written by the CPU"),
+ }
+ }
+ }
+
+ pub(crate) unsafe fn gpu_read_unlock(&mut self, range: Range<DeviceSize>) {
+ self.ranges.split_at(&range.start);
+ self.ranges.split_at(&range.end);
+
+ for (_range, state) in self.ranges.range_mut(&range) {
+ match &mut state.current_access {
+ CurrentAccess::GpuExclusive { gpu_reads, .. } => *gpu_reads -= 1,
+ CurrentAccess::Shared { gpu_reads, .. } => *gpu_reads -= 1,
+ _ => unreachable!("Buffer was not locked for GPU read"),
+ }
+ }
+ }
+
+ pub(crate) fn check_gpu_write(&self, range: Range<DeviceSize>) -> Result<(), AccessError> {
+ for (_range, state) in self.ranges.range(&range) {
+ match &state.current_access {
+ CurrentAccess::Shared {
+ cpu_reads: 0,
+ gpu_reads: 0,
+ } => (),
+ _ => return Err(AccessError::AlreadyInUse),
+ }
+ }
+
+ Ok(())
+ }
+
+ pub(crate) unsafe fn gpu_write_lock(&mut self, range: Range<DeviceSize>) {
+ self.ranges.split_at(&range.start);
+ self.ranges.split_at(&range.end);
+
+ for (_range, state) in self.ranges.range_mut(&range) {
+ match &mut state.current_access {
+ CurrentAccess::GpuExclusive { gpu_writes, .. } => *gpu_writes += 1,
+ &mut CurrentAccess::Shared {
+ cpu_reads: 0,
+ gpu_reads,
+ } => {
+ state.current_access = CurrentAccess::GpuExclusive {
+ gpu_reads,
+ gpu_writes: 1,
+ }
+ }
+ _ => unreachable!("Buffer is being accessed by the CPU"),
+ }
+ }
+ }
+
+ pub(crate) unsafe fn gpu_write_unlock(&mut self, range: Range<DeviceSize>) {
+ self.ranges.split_at(&range.start);
+ self.ranges.split_at(&range.end);
+
+ for (_range, state) in self.ranges.range_mut(&range) {
+ match &mut state.current_access {
+ &mut CurrentAccess::GpuExclusive {
+ gpu_reads,
+ gpu_writes: 1,
+ } => {
+ state.current_access = CurrentAccess::Shared {
+ cpu_reads: 0,
+ gpu_reads,
+ }
+ }
+ CurrentAccess::GpuExclusive { gpu_writes, .. } => *gpu_writes -= 1,
+ _ => unreachable!("Buffer was not locked for GPU write"),
+ }
+ }
+ }
+}
+
+/// The current state of a specific range of bytes in a buffer.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+struct BufferRangeState {
+ current_access: CurrentAccess,
+}
+
+/// Error that can happen in buffer functions.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum BufferError {
+ VulkanError(VulkanError),
+
+ /// Allocating memory failed.
+ AllocError(AllocationCreationError),
+
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+
+ /// The buffer is missing the `SHADER_DEVICE_ADDRESS` usage.
+ BufferMissingUsage,
+
+ /// The memory was created dedicated to a resource, but not to this buffer.
+ DedicatedAllocationMismatch,
+
+ /// A dedicated allocation is required for this buffer, but one was not provided.
+ DedicatedAllocationRequired,
+
+ /// The host is already using this buffer in a way that is incompatible with the
+ /// requested access.
+ InUseByHost,
+
+ /// The device is already using this buffer in a way that is incompatible with the
+ /// requested access.
+ InUseByDevice,
+
+ /// The specified size exceeded the value of the `max_buffer_size` limit.
+ MaxBufferSizeExceeded {
+ size: DeviceSize,
+ max: DeviceSize,
+ },
+
+ /// The offset of the allocation does not have the required alignment.
+ MemoryAllocationNotAligned {
+ allocation_offset: DeviceSize,
+ required_alignment: DeviceAlignment,
+ },
+
+ /// The size of the allocation is smaller than what is required.
+ MemoryAllocationTooSmall {
+ allocation_size: DeviceSize,
+ required_size: DeviceSize,
+ },
+
+ /// The buffer was created with the `SHADER_DEVICE_ADDRESS` usage, but the memory does not
+ /// support this usage.
+ MemoryBufferDeviceAddressNotSupported,
+
+ /// The memory was created with export handle types, but none of these handle types were
+ /// enabled on the buffer.
+ MemoryExternalHandleTypesDisjoint {
+ buffer_handle_types: ExternalMemoryHandleTypes,
+ memory_export_handle_types: ExternalMemoryHandleTypes,
+ },
+
+ /// The memory was created with an import, but the import's handle type was not enabled on
+ /// the buffer.
+ MemoryImportedHandleTypeNotEnabled {
+ buffer_handle_types: ExternalMemoryHandleTypes,
+ memory_imported_handle_type: ExternalMemoryHandleType,
+ },
+
+ /// The memory backing this buffer is not visible to the host.
+ MemoryNotHostVisible,
+
+ /// The protection of buffer and memory are not equal.
+ MemoryProtectedMismatch {
+ buffer_protected: bool,
+ memory_protected: bool,
+ },
+
+ /// The provided memory type is not one of the allowed memory types that can be bound to this
+ /// buffer.
+ MemoryTypeNotAllowed {
+ provided_memory_type_index: u32,
+ allowed_memory_type_bits: u32,
+ },
+
+ /// The sharing mode was set to `Concurrent`, but one of the specified queue family indices was
+ /// out of range.
+ SharingQueueFamilyIndexOutOfRange {
+ queue_family_index: u32,
+ queue_family_count: u32,
+ },
+}
+
+impl Error for BufferError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::VulkanError(err) => Some(err),
+ Self::AllocError(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+impl Display for BufferError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::VulkanError(_) => write!(f, "a runtime error occurred"),
+ Self::AllocError(_) => write!(f, "allocating memory failed"),
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ Self::BufferMissingUsage => {
+ write!(f, "the buffer is missing the `SHADER_DEVICE_ADDRESS` usage")
+ }
+ Self::DedicatedAllocationMismatch => write!(
+ f,
+ "the memory was created dedicated to a resource, but not to this buffer",
+ ),
+ Self::DedicatedAllocationRequired => write!(
+ f,
+ "a dedicated allocation is required for this buffer, but one was not provided"
+ ),
+ Self::InUseByHost => write!(
+ f,
+ "the host is already using this buffer in a way that is incompatible with the \
+ requested access",
+ ),
+ Self::InUseByDevice => write!(
+ f,
+ "the device is already using this buffer in a way that is incompatible with the \
+ requested access"
+ ),
+ Self::MaxBufferSizeExceeded { .. } => write!(
+ f,
+ "the specified size exceeded the value of the `max_buffer_size` limit",
+ ),
+ Self::MemoryAllocationNotAligned {
+ allocation_offset,
+ required_alignment,
+ } => write!(
+ f,
+ "the offset of the allocation ({}) does not have the required alignment ({:?})",
+ allocation_offset, required_alignment,
+ ),
+ Self::MemoryAllocationTooSmall {
+ allocation_size,
+ required_size,
+ } => write!(
+ f,
+ "the size of the allocation ({}) is smaller than what is required ({})",
+ allocation_size, required_size,
+ ),
+ Self::MemoryBufferDeviceAddressNotSupported => write!(
+ f,
+ "the buffer was created with the `SHADER_DEVICE_ADDRESS` usage, but the memory \
+ does not support this usage",
+ ),
+ Self::MemoryExternalHandleTypesDisjoint { .. } => write!(
+ f,
+ "the memory was created with export handle types, but none of these handle types \
+ were enabled on the buffer",
+ ),
+ Self::MemoryImportedHandleTypeNotEnabled { .. } => write!(
+ f,
+ "the memory was created with an import, but the import's handle type was not \
+ enabled on the buffer",
+ ),
+ Self::MemoryNotHostVisible => write!(
+ f,
+ "the memory backing this buffer is not visible to the host",
+ ),
+ Self::MemoryProtectedMismatch {
+ buffer_protected,
+ memory_protected,
+ } => write!(
+ f,
+ "the protection of buffer ({}) and memory ({}) are not equal",
+ buffer_protected, memory_protected,
+ ),
+ Self::MemoryTypeNotAllowed {
+ provided_memory_type_index,
+ allowed_memory_type_bits,
+ } => write!(
+ f,
+ "the provided memory type ({}) is not one of the allowed memory types (",
+ provided_memory_type_index,
+ )
+ .and_then(|_| {
+ let mut first = true;
+
+ for i in (0..size_of_val(allowed_memory_type_bits))
+ .filter(|i| allowed_memory_type_bits & (1 << i) != 0)
+ {
+ if first {
+ write!(f, "{}", i)?;
+ first = false;
+ } else {
+ write!(f, ", {}", i)?;
+ }
+ }
+
+ Ok(())
+ })
+ .and_then(|_| write!(f, ") that can be bound to this buffer")),
+ Self::SharingQueueFamilyIndexOutOfRange { .. } => write!(
+ f,
+ "the sharing mode was set to `Concurrent`, but one of the specified queue family \
+ indices was out of range",
+ ),
+ }
+ }
+}
+
+impl From<VulkanError> for BufferError {
+ fn from(err: VulkanError) -> Self {
+ Self::VulkanError(err)
+ }
+}
+
+impl From<AllocationCreationError> for BufferError {
+ fn from(err: AllocationCreationError) -> Self {
+ Self::AllocError(err)
+ }
+}
+
+impl From<RequirementNotMet> for BufferError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
+ }
+ }
+}
+
+impl From<ReadLockError> for BufferError {
+ fn from(err: ReadLockError) -> Self {
+ match err {
+ ReadLockError::CpuWriteLocked => Self::InUseByHost,
+ ReadLockError::GpuWriteLocked => Self::InUseByDevice,
+ }
+ }
+}
+
+impl From<WriteLockError> for BufferError {
+ fn from(err: WriteLockError) -> Self {
+ match err {
+ WriteLockError::CpuLocked => Self::InUseByHost,
+ WriteLockError::GpuLocked => Self::InUseByDevice,
+ }
+ }
+}
+
+vulkan_bitflags! {
+ #[non_exhaustive]
+
+ /// Flags to be set when creating a buffer.
+ BufferCreateFlags = BufferCreateFlags(u32);
+
+ /* TODO: enable
+ /// The buffer will be backed by sparse memory binding (through queue commands) instead of
+ /// regular binding (through [`bind_memory`]).
+ ///
+ /// The [`sparse_binding`] feature must be enabled on the device.
+ ///
+ /// [`bind_memory`]: sys::RawBuffer::bind_memory
+ /// [`sparse_binding`]: crate::device::Features::sparse_binding
+ SPARSE_BINDING = SPARSE_BINDING,*/
+
+ /* TODO: enable
+ /// The buffer can be used without being fully resident in memory at the time of use.
+ ///
+ /// This requires the `sparse_binding` flag as well.
+ ///
+ /// The [`sparse_residency_buffer`] feature must be enabled on the device.
+ ///
+ /// [`sparse_residency_buffer`]: crate::device::Features::sparse_residency_buffer
+ SPARSE_RESIDENCY = SPARSE_RESIDENCY,*/
+
+ /* TODO: enable
+ /// The buffer's memory can alias with another buffer or a different part of the same buffer.
+ ///
+ /// This requires the `sparse_binding` flag as well.
+ ///
+ /// The [`sparse_residency_aliased`] feature must be enabled on the device.
+ ///
+ /// [`sparse_residency_aliased`]: crate::device::Features::sparse_residency_aliased
+ SPARSE_ALIASED = SPARSE_ALIASED,*/
+
+ /* TODO: enable
+ /// The buffer is protected, and can only be used in combination with protected memory and other
+ /// protected objects.
+ ///
+ /// The device API version must be at least 1.1.
+ PROTECTED = PROTECTED {
+ api_version: V1_1,
+ },*/
+
+ /* TODO: enable
+ /// The buffer's device address can be saved and reused on a subsequent run.
+ ///
+ /// The device API version must be at least 1.2, or either the [`khr_buffer_device_address`] or
+ /// [`ext_buffer_device_address`] extension must be enabled on the device.
+ DEVICE_ADDRESS_CAPTURE_REPLAY = DEVICE_ADDRESS_CAPTURE_REPLAY {
+ api_version: V1_2,
+ device_extensions: [khr_buffer_device_address, ext_buffer_device_address],
+ },*/
+}
+
+/// The buffer configuration to query in
+/// [`PhysicalDevice::external_buffer_properties`](crate::device::physical::PhysicalDevice::external_buffer_properties).
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct ExternalBufferInfo {
+ /// The external handle type that will be used with the buffer.
+ pub handle_type: ExternalMemoryHandleType,
+
+ /// The usage that the buffer will have.
+ pub usage: BufferUsage,
+
+ /// The sparse binding parameters that will be used.
+ pub sparse: Option<BufferCreateFlags>,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl ExternalBufferInfo {
+ /// Returns an `ExternalBufferInfo` with the specified `handle_type`.
+ #[inline]
+ pub fn handle_type(handle_type: ExternalMemoryHandleType) -> Self {
+ Self {
+ handle_type,
+ usage: BufferUsage::empty(),
+ sparse: None,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// The external memory properties supported for buffers with a given configuration.
+#[derive(Clone, Debug)]
+#[non_exhaustive]
+pub struct ExternalBufferProperties {
+ /// The properties for external memory.
+ pub external_memory_properties: ExternalMemoryProperties,
+}
diff --git a/src/buffer/slice.rs b/src/buffer/slice.rs
deleted file mode 100644
index 03995d5..0000000
--- a/src/buffer/slice.rs
+++ /dev/null
@@ -1,315 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::buffer::traits::BufferAccess;
-use crate::buffer::traits::BufferInner;
-use crate::buffer::traits::TypedBufferAccess;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::device::Queue;
-use crate::sync::AccessError;
-use crate::DeviceSize;
-use std::hash::Hash;
-use std::hash::Hasher;
-use std::marker::PhantomData;
-use std::mem;
-use std::mem::MaybeUninit;
-use std::ops::Range;
-use std::sync::Arc;
-
-/// A subpart of a buffer.
-///
-/// This object doesn't correspond to any Vulkan object. It exists for API convenience.
-///
-/// # Example
-///
-/// Creating a slice:
-///
-/// ```ignore // FIXME: unignore
-/// use vulkano::buffer::BufferSlice;
-/// # let buffer: std::sync::Arc<vulkano::buffer::DeviceLocalBuffer<[u8]>> = return;
-/// let _slice = BufferSlice::from(&buffer);
-/// ```
-///
-/// Selecting a slice of a buffer that contains `[T]`:
-///
-/// ```ignore // FIXME: unignore
-/// use vulkano::buffer::BufferSlice;
-/// # let buffer: std::sync::Arc<vulkano::buffer::DeviceLocalBuffer<[u8]>> = return;
-/// let _slice = BufferSlice::from(&buffer).slice(12 .. 14).unwrap();
-/// ```
-///
-pub struct BufferSlice<T: ?Sized, B> {
- marker: PhantomData<T>,
- resource: B,
- offset: DeviceSize,
- size: DeviceSize,
-}
-
-// We need to implement `Clone` manually, otherwise the derive adds a `T: Clone` requirement.
-impl<T: ?Sized, B> Clone for BufferSlice<T, B>
-where
- B: Clone,
-{
- #[inline]
- fn clone(&self) -> Self {
- BufferSlice {
- marker: PhantomData,
- resource: self.resource.clone(),
- offset: self.offset,
- size: self.size,
- }
- }
-}
-
-impl<T: ?Sized, B> BufferSlice<T, B> {
- #[inline]
- pub fn from_typed_buffer_access(r: B) -> BufferSlice<T, B>
- where
- B: TypedBufferAccess<Content = T>,
- {
- let size = r.size();
-
- BufferSlice {
- marker: PhantomData,
- resource: r,
- offset: 0,
- size: size,
- }
- }
-
- /// Returns the buffer that this slice belongs to.
- pub fn buffer(&self) -> &B {
- &self.resource
- }
-
- /// Returns the offset of that slice within the buffer.
- #[inline]
- pub fn offset(&self) -> DeviceSize {
- self.offset
- }
-
- /// Returns the size of that slice in bytes.
- #[inline]
- pub fn size(&self) -> DeviceSize {
- self.size
- }
-
- /// Builds a slice that contains an element from inside the buffer.
- ///
- /// This method builds an object that represents a slice of the buffer. No actual operation
- /// is performed.
- ///
- /// # Example
- ///
- /// TODO
- ///
- /// # Safety
- ///
- /// The object whose reference is passed to the closure is uninitialized. Therefore you
- /// **must not** access the content of the object.
- ///
- /// You **must** return a reference to an element from the parameter. The closure **must not**
- /// panic.
- #[inline]
- pub unsafe fn slice_custom<F, R: ?Sized>(self, f: F) -> BufferSlice<R, B>
- where
- F: for<'r> FnOnce(&'r T) -> &'r R, // TODO: bounds on R
- {
- let data: MaybeUninit<&T> = MaybeUninit::zeroed();
- let result = f(data.assume_init());
- let size = mem::size_of_val(result) as DeviceSize;
- let result = result as *const R as *const () as DeviceSize;
-
- assert!(result <= self.size());
- assert!(result + size <= self.size());
-
- BufferSlice {
- marker: PhantomData,
- resource: self.resource,
- offset: self.offset + result,
- size,
- }
- }
-
- /// Changes the `T` generic parameter of the `BufferSlice` to the desired type. This can be
- /// useful when you have a buffer with various types of data and want to create a typed slice
- /// of a region that contains a single type of data.
- ///
- /// # Example
- ///
- /// ```
- /// # use std::sync::Arc;
- /// # use vulkano::buffer::BufferSlice;
- /// # use vulkano::buffer::immutable::ImmutableBuffer;
- /// # struct VertexImpl;
- /// let blob_slice: BufferSlice<[u8], Arc<ImmutableBuffer<[u8]>>> = return;
- /// let vertex_slice: BufferSlice<[VertexImpl], Arc<ImmutableBuffer<[u8]>>> = unsafe {
- /// blob_slice.reinterpret::<[VertexImpl]>()
- /// };
- /// ```
- ///
- /// # Safety
- ///
- /// Correct `offset` and `size` must be ensured before using this `BufferSlice` on the device.
- /// See `BufferSlice::slice` for adjusting these properties.
- #[inline]
- pub unsafe fn reinterpret<R: ?Sized>(self) -> BufferSlice<R, B> {
- BufferSlice {
- marker: PhantomData,
- resource: self.resource,
- offset: self.offset,
- size: self.size,
- }
- }
-}
-
-impl<T, B> BufferSlice<[T], B> {
- /// Returns the number of elements in this slice.
- #[inline]
- pub fn len(&self) -> DeviceSize {
- debug_assert_eq!(self.size() % mem::size_of::<T>() as DeviceSize, 0);
- self.size() / mem::size_of::<T>() as DeviceSize
- }
-
- /// Reduces the slice to just one element of the array.
- ///
- /// Returns `None` if out of range.
- #[inline]
- pub fn index(self, index: DeviceSize) -> Option<BufferSlice<T, B>> {
- if index >= self.len() {
- return None;
- }
-
- Some(BufferSlice {
- marker: PhantomData,
- resource: self.resource,
- offset: self.offset + index * mem::size_of::<T>() as DeviceSize,
- size: mem::size_of::<T>() as DeviceSize,
- })
- }
-
- /// Reduces the slice to just a range of the array.
- ///
- /// Returns `None` if out of range.
- #[inline]
- pub fn slice(self, range: Range<DeviceSize>) -> Option<BufferSlice<[T], B>> {
- if range.end > self.len() {
- return None;
- }
-
- Some(BufferSlice {
- marker: PhantomData,
- resource: self.resource,
- offset: self.offset + range.start * mem::size_of::<T>() as DeviceSize,
- size: (range.end - range.start) * mem::size_of::<T>() as DeviceSize,
- })
- }
-}
-
-unsafe impl<T: ?Sized, B> BufferAccess for BufferSlice<T, B>
-where
- B: BufferAccess,
-{
- #[inline]
- fn inner(&self) -> BufferInner {
- let inner = self.resource.inner();
- BufferInner {
- buffer: inner.buffer,
- offset: inner.offset + self.offset,
- }
- }
-
- #[inline]
- fn size(&self) -> DeviceSize {
- self.size
- }
-
- #[inline]
- fn conflict_key(&self) -> (u64, u64) {
- self.resource.conflict_key()
- }
-
- #[inline]
- fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> Result<(), AccessError> {
- self.resource.try_gpu_lock(exclusive_access, queue)
- }
-
- #[inline]
- unsafe fn increase_gpu_lock(&self) {
- self.resource.increase_gpu_lock()
- }
-
- #[inline]
- unsafe fn unlock(&self) {
- self.resource.unlock()
- }
-}
-
-unsafe impl<T: ?Sized, B> TypedBufferAccess for BufferSlice<T, B>
-where
- B: BufferAccess,
-{
- type Content = T;
-}
-
-unsafe impl<T: ?Sized, B> DeviceOwned for BufferSlice<T, B>
-where
- B: DeviceOwned,
-{
- #[inline]
- fn device(&self) -> &Arc<Device> {
- self.resource.device()
- }
-}
-
-impl<T, B> From<BufferSlice<T, B>> for BufferSlice<[T], B> {
- #[inline]
- fn from(r: BufferSlice<T, B>) -> BufferSlice<[T], B> {
- BufferSlice {
- marker: PhantomData,
- resource: r.resource,
- offset: r.offset,
- size: r.size,
- }
- }
-}
-
-impl<T: ?Sized, B> PartialEq for BufferSlice<T, B>
-where
- B: BufferAccess,
-{
- #[inline]
- fn eq(&self, other: &Self) -> bool {
- self.inner() == other.inner() && self.size() == other.size()
- }
-}
-
-impl<T: ?Sized, B> Eq for BufferSlice<T, B> where B: BufferAccess {}
-
-impl<T: ?Sized, B> Hash for BufferSlice<T, B>
-where
- B: BufferAccess,
-{
- #[inline]
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.inner().hash(state);
- self.size().hash(state);
- }
-}
-
-/// Takes a `BufferSlice` that points to a struct, and returns a `BufferSlice` that points to
-/// a specific field of that struct.
-#[macro_export]
-macro_rules! buffer_slice_field {
- ($slice:expr, $field:ident) => {
- // TODO: add #[allow(unsafe_code)] when that's allowed
- unsafe { $slice.slice_custom(|s| &s.$field) }
- };
-}
diff --git a/src/buffer/subbuffer.rs b/src/buffer/subbuffer.rs
new file mode 100644
index 0000000..84d1218
--- /dev/null
+++ b/src/buffer/subbuffer.rs
@@ -0,0 +1,1331 @@
+// Copyright (c) 2016 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+//! A subpart of a buffer.
+
+use super::{allocator::Arena, Buffer, BufferError, BufferMemory};
+use crate::{
+ device::{Device, DeviceOwned},
+ macros::try_opt,
+ memory::{
+ self,
+ allocator::{align_down, align_up, DeviceLayout},
+ is_aligned, DeviceAlignment,
+ },
+ DeviceSize, NonZeroDeviceSize,
+};
+use bytemuck::{AnyBitPattern, PodCastError};
+use std::{
+ alloc::Layout,
+ cmp,
+ error::Error,
+ ffi::c_void,
+ fmt::{Display, Error as FmtError, Formatter},
+ hash::{Hash, Hasher},
+ marker::PhantomData,
+ mem::{self, align_of, size_of},
+ ops::{Deref, DerefMut, Range, RangeBounds},
+ ptr::{self, NonNull},
+ sync::Arc,
+ thread,
+};
+
+#[cfg(feature = "macros")]
+pub use vulkano_macros::BufferContents;
+
+/// A subpart of a buffer.
+///
+/// This type doesn't correspond to any Vulkan object, it exists for API convenience. Most Vulkan
+/// functions that work with buffers take the buffer as argument as well as an offset and size
+/// within the buffer, which we can represent with a single subbuffer instead.
+///
+/// `Subbuffer` also has a type parameter, which is a hint for how the data is going to be
+/// interpreted by the host or device (or both). This is useful so that we can allocate
+/// (sub)buffers that are correctly aligned and have the correct size for their content, and for
+/// type-safety. For example, when reading/writing a subbuffer from the host, you can use
+/// [`Subbuffer::read`]/[`Subbuffer::write`] without worrying about the alignment and size being
+/// correct and about converting your data from/to raw bytes.
+///
+/// There are two ways to get a `Subbuffer`:
+///
+/// - By using the functions on [`Buffer`], which create a new buffer and memory allocation each
+/// time, and give you a `Subbuffer` that has an entire `Buffer` dedicated to it.
+/// - By using the [`SubbufferAllocator`], which creates `Subbuffer`s by suballocating existing
+/// `Buffer`s such that the `Buffer`s can keep being reused.
+///
+/// Alternatively, you can also create a `Buffer` manually and convert it to a `Subbuffer<[u8]>`.
+///
+/// [`SubbufferAllocator`]: super::allocator::SubbufferAllocator
+#[derive(Debug)]
+#[repr(C)]
+pub struct Subbuffer<T: ?Sized> {
+ offset: DeviceSize,
+ size: DeviceSize,
+ parent: SubbufferParent,
+ marker: PhantomData<Arc<T>>,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+enum SubbufferParent {
+ Arena(Arc<Arena>),
+ Buffer(Arc<Buffer>),
+}
+
+impl<T: ?Sized> Subbuffer<T> {
+ pub(super) fn from_arena(arena: Arc<Arena>, offset: DeviceSize, size: DeviceSize) -> Self {
+ Subbuffer {
+ offset,
+ size,
+ parent: SubbufferParent::Arena(arena),
+ marker: PhantomData,
+ }
+ }
+
+ /// Returns the offset of the subbuffer, in bytes, relative to the buffer.
+ pub fn offset(&self) -> DeviceSize {
+ self.offset
+ }
+
+ /// Returns the offset of the subbuffer, in bytes, relative to the [`DeviceMemory`] block.
+ fn memory_offset(&self) -> DeviceSize {
+ let allocation = match self.buffer().memory() {
+ BufferMemory::Normal(a) => a,
+ BufferMemory::Sparse => unreachable!(),
+ };
+
+ allocation.offset() + self.offset
+ }
+
+ /// Returns the size of the subbuffer in bytes.
+ pub fn size(&self) -> DeviceSize {
+ self.size
+ }
+
+ /// Returns the range the subbuffer occupies, in bytes, relative to the buffer.
+ pub(crate) fn range(&self) -> Range<DeviceSize> {
+ self.offset..self.offset + self.size
+ }
+
+ /// Returns the buffer that this subbuffer is a part of.
+ pub fn buffer(&self) -> &Arc<Buffer> {
+ match &self.parent {
+ SubbufferParent::Arena(arena) => arena.buffer(),
+ SubbufferParent::Buffer(buffer) => buffer,
+ }
+ }
+
+ /// Returns the mapped pointer to the start of the subbuffer if the memory is host-visible,
+ /// otherwise returns [`None`].
+ pub fn mapped_ptr(&self) -> Option<NonNull<c_void>> {
+ match self.buffer().memory() {
+ BufferMemory::Normal(a) => a.mapped_ptr().map(|ptr| {
+ // SAFETY: The original address came from the Vulkan implementation, and allocation
+ // sizes are guaranteed to not exceed `isize::MAX` when there's a mapped pointer,
+ // so the offset better be in range.
+ unsafe { NonNull::new_unchecked(ptr.as_ptr().add(self.offset as usize)) }
+ }),
+ BufferMemory::Sparse => unreachable!(),
+ }
+ }
+
+ /// Returns the device address for this subbuffer.
+ pub fn device_address(&self) -> Result<NonZeroDeviceSize, BufferError> {
+ self.buffer().device_address().map(|ptr| {
+ // SAFETY: The original address came from the Vulkan implementation, and allocation
+ // sizes are guaranteed to not exceed `DeviceLayout::MAX_SIZE`, so the offset better be
+ // in range.
+ unsafe { NonZeroDeviceSize::new_unchecked(ptr.get() + self.offset) }
+ })
+ }
+
+ /// Casts the subbuffer to a slice of raw bytes.
+ pub fn into_bytes(self) -> Subbuffer<[u8]> {
+ unsafe { self.reinterpret_unchecked_inner() }
+ }
+
+ /// Same as [`into_bytes`], except it works with a reference to the subbuffer.
+ ///
+ /// [`into_bytes`]: Self::into_bytes
+ pub fn as_bytes(&self) -> &Subbuffer<[u8]> {
+ unsafe { self.reinterpret_ref_unchecked_inner() }
+ }
+
+ #[inline(always)]
+ unsafe fn reinterpret_unchecked_inner<U: ?Sized>(self) -> Subbuffer<U> {
+ // SAFETY: All `Subbuffer`s share the same layout.
+ mem::transmute::<Subbuffer<T>, Subbuffer<U>>(self)
+ }
+
+ #[inline(always)]
+ unsafe fn reinterpret_ref_unchecked_inner<U: ?Sized>(&self) -> &Subbuffer<U> {
+ assert!(size_of::<Subbuffer<T>>() == size_of::<Subbuffer<U>>());
+ assert!(align_of::<Subbuffer<T>>() == align_of::<Subbuffer<U>>());
+
+ // SAFETY: All `Subbuffer`s share the same layout.
+ mem::transmute::<&Subbuffer<T>, &Subbuffer<U>>(self)
+ }
+}
+
+impl<T> Subbuffer<T>
+where
+ T: BufferContents + ?Sized,
+{
+ /// Changes the `T` generic parameter of the subbffer to the desired type without checking if
+ /// the contents are correctly aligned and sized.
+ ///
+ /// **NEVER use this function** unless you absolutely have to, and even then, open an issue on
+ /// GitHub instead. **An unaligned / incorrectly sized subbuffer is undefined behavior _both on
+ /// the Rust and the Vulkan side!_**
+ ///
+ /// # Safety
+ ///
+ /// - `self.memory_offset()` must be properly aligned for `U`.
+ /// - `self.size()` must be valid for `U`, which means:
+ /// - If `U` is sized, the size must match exactly.
+ /// - If `U` is unsized, then the subbuffer size minus the size of the head (sized part) of
+ /// the DST must be evenly divisible by the size of the element type.
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn reinterpret_unchecked<U>(self) -> Subbuffer<U>
+ where
+ U: BufferContents + ?Sized,
+ {
+ let element_size = U::LAYOUT.element_size().unwrap_or(1);
+ debug_assert!(is_aligned(self.memory_offset(), U::LAYOUT.alignment()));
+ debug_assert!(self.size >= U::LAYOUT.head_size());
+ debug_assert!((self.size - U::LAYOUT.head_size()) % element_size == 0);
+
+ self.reinterpret_unchecked_inner()
+ }
+
+ /// Same as [`reinterpret_unchecked`], except it works with a reference to the subbuffer.
+ ///
+ /// # Safety
+ ///
+ /// Please read the safety docs on [`reinterpret_unchecked`] carefully.
+ ///
+ /// [`reinterpret_unchecked`]: Self::reinterpret_unchecked
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn reinterpret_ref_unchecked<U>(&self) -> &Subbuffer<U>
+ where
+ U: BufferContents + ?Sized,
+ {
+ let element_size = U::LAYOUT.element_size().unwrap_or(1);
+ debug_assert!(is_aligned(self.memory_offset(), U::LAYOUT.alignment()));
+ debug_assert!(self.size >= U::LAYOUT.head_size());
+ debug_assert!((self.size - U::LAYOUT.head_size()) % element_size == 0);
+
+ self.reinterpret_ref_unchecked_inner()
+ }
+
+ /// Locks the subbuffer in order to read its content from the host.
+ ///
+ /// If the subbuffer is currently used in exclusive mode by the device, this function will
+ /// return an error. Similarly if you called [`write`] on the buffer and haven't dropped the
+ /// lock, this function will return an error as well.
+ ///
+ /// After this function successfully locks the subbuffer, any attempt to submit a command buffer
+ /// that uses it in exclusive mode will fail. You can still submit this subbuffer for
+ /// non-exclusive accesses (ie. reads).
+ ///
+ /// If the memory backing the buffer is not [host-coherent], then this function will lock a
+ /// range that is potentially larger than the subbuffer, because the range given to
+ /// [`invalidate_range`] must be aligned to the [`non_coherent_atom_size`]. This means that for
+ /// example if your Vulkan implementation reports an atom size of 64, and you tried to put 2
+ /// subbuffers of size 32 in the same buffer, one at offset 0 and one at offset 32, while the
+ /// buffer is backed by non-coherent memory, then invalidating one subbuffer would also
+ /// invalidate the other subbuffer. This can lead to data races and is therefore not allowed.
+ /// What you should do in that case is ensure that each subbuffer is aligned to the
+ /// non-coherent atom size, so in this case one would be at offset 0 and the other at offset
+ /// 64. [`SubbufferAllocator`] does this automatically.
+ ///
+ /// [host-coherent]: crate::memory::MemoryPropertyFlags::HOST_COHERENT
+ /// [`invalidate_range`]: crate::memory::allocator::MemoryAlloc::invalidate_range
+ /// [`non_coherent_atom_size`]: crate::device::Properties::non_coherent_atom_size
+ /// [`write`]: Self::write
+ /// [`SubbufferAllocator`]: super::allocator::SubbufferAllocator
+ pub fn read(&self) -> Result<BufferReadGuard<'_, T>, BufferError> {
+ let allocation = match self.buffer().memory() {
+ BufferMemory::Normal(a) => a,
+ BufferMemory::Sparse => todo!("`Subbuffer::read` doesn't support sparse binding yet"),
+ };
+
+ let range = if let Some(atom_size) = allocation.atom_size() {
+ // This works because the suballocators align allocations to the non-coherent atom size
+ // when the memory is host-visible but not host-coherent.
+ let start = align_down(self.offset, atom_size);
+ let end = cmp::min(
+ align_up(self.offset + self.size, atom_size),
+ allocation.size(),
+ );
+
+ Range { start, end }
+ } else {
+ self.range()
+ };
+
+ let mut state = self.buffer().state();
+ state.check_cpu_read(range.clone())?;
+ unsafe { state.cpu_read_lock(range.clone()) };
+
+ if allocation.atom_size().is_some() {
+ // If there are other read locks being held at this point, they also called
+ // `invalidate_range` when locking. The GPU can't write data while the CPU holds a read
+ // lock, so there will be no new data and this call will do nothing.
+ // TODO: probably still more efficient to call it only if we're the first to acquire a
+ // read lock, but the number of CPU locks isn't currently tracked anywhere.
+ unsafe { allocation.invalidate_range(range.clone()) }?;
+ }
+
+ let mapped_ptr = self.mapped_ptr().ok_or(BufferError::MemoryNotHostVisible)?;
+ // SAFETY: `Subbuffer` guarantees that its contents are laid out correctly for `T`.
+ let data = unsafe { &*T::from_ffi(mapped_ptr.as_ptr(), self.size as usize) };
+
+ Ok(BufferReadGuard {
+ subbuffer: self,
+ data,
+ range,
+ })
+ }
+
+ /// Locks the subbuffer in order to write its content from the host.
+ ///
+ /// If the subbuffer is currently in use by the device, this function will return an error.
+ /// Similarly if you called [`read`] on the subbuffer and haven't dropped the lock, this
+ /// function will return an error as well.
+ ///
+ /// After this function successfully locks the buffer, any attempt to submit a command buffer
+ /// that uses it and any attempt to call `read` will return an error.
+ ///
+ /// If the memory backing the buffer is not [host-coherent], then this function will lock a
+ /// range that is potentially larger than the subbuffer, because the range given to
+ /// [`flush_range`] must be aligned to the [`non_coherent_atom_size`]. This means that for
+ /// example if your Vulkan implementation reports an atom size of 64, and you tried to put 2
+ /// subbuffers of size 32 in the same buffer, one at offset 0 and one at offset 32, while the
+ /// buffer is backed by non-coherent memory, then flushing one subbuffer would also flush the
+ /// other subbuffer. This can lead to data races and is therefore not allowed. What you should
+ /// do in that case is ensure that each subbuffer is aligned to the non-coherent atom size, so
+ /// in this case one would be at offset 0 and the other at offset 64. [`SubbufferAllocator`]
+ /// does this automatically.
+ ///
+ /// [host-coherent]: crate::memory::MemoryPropertyFlags::HOST_COHERENT
+ /// [`flush_range`]: crate::memory::allocator::MemoryAlloc::flush_range
+ /// [`non_coherent_atom_size`]: crate::device::Properties::non_coherent_atom_size
+ /// [`read`]: Self::read
+ /// [`SubbufferAllocator`]: super::allocator::SubbufferAllocator
+ pub fn write(&self) -> Result<BufferWriteGuard<'_, T>, BufferError> {
+ let allocation = match self.buffer().memory() {
+ BufferMemory::Normal(a) => a,
+ BufferMemory::Sparse => todo!("`Subbuffer::write` doesn't support sparse binding yet"),
+ };
+
+ let range = if let Some(atom_size) = allocation.atom_size() {
+ // This works because the suballocators align allocations to the non-coherent atom size
+ // when the memory is host-visible but not host-coherent.
+ let start = align_down(self.offset, atom_size);
+ let end = cmp::min(
+ align_up(self.offset + self.size, atom_size),
+ allocation.size(),
+ );
+
+ Range { start, end }
+ } else {
+ self.range()
+ };
+
+ let mut state = self.buffer().state();
+ state.check_cpu_write(range.clone())?;
+ unsafe { state.cpu_write_lock(range.clone()) };
+
+ if allocation.atom_size().is_some() {
+ unsafe { allocation.invalidate_range(range.clone()) }?;
+ }
+
+ let mapped_ptr = self.mapped_ptr().ok_or(BufferError::MemoryNotHostVisible)?;
+ // SAFETY: `Subbuffer` guarantees that its contents are laid out correctly for `T`.
+ let data = unsafe { &mut *T::from_ffi(mapped_ptr.as_ptr(), self.size as usize) };
+
+ Ok(BufferWriteGuard {
+ subbuffer: self,
+ data,
+ range,
+ })
+ }
+}
+
+impl<T> Subbuffer<T> {
+ /// Converts the subbuffer to a slice of one element.
+ pub fn into_slice(self) -> Subbuffer<[T]> {
+ unsafe { self.reinterpret_unchecked_inner() }
+ }
+
+ /// Same as [`into_slice`], except it works with a reference to the subbuffer.
+ ///
+ /// [`into_slice`]: Self::into_slice
+ pub fn as_slice(&self) -> &Subbuffer<[T]> {
+ unsafe { self.reinterpret_ref_unchecked_inner() }
+ }
+}
+
+impl<T> Subbuffer<T>
+where
+ T: BufferContents,
+{
+ /// Tries to cast a subbuffer of raw bytes to a `Subbuffer<T>`.
+ pub fn try_from_bytes(subbuffer: Subbuffer<[u8]>) -> Result<Self, PodCastError> {
+ if subbuffer.size() != size_of::<T>() as DeviceSize {
+ Err(PodCastError::SizeMismatch)
+ } else if !is_aligned(subbuffer.memory_offset(), DeviceAlignment::of::<T>()) {
+ Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned)
+ } else {
+ Ok(unsafe { subbuffer.reinterpret_unchecked() })
+ }
+ }
+
+ /// Tries to cast the subbuffer to a different type.
+ pub fn try_cast<U>(self) -> Result<Subbuffer<U>, PodCastError>
+ where
+ U: BufferContents,
+ {
+ if size_of::<U>() != size_of::<T>() {
+ Err(PodCastError::SizeMismatch)
+ } else if align_of::<U>() > align_of::<T>()
+ && !is_aligned(self.memory_offset(), DeviceAlignment::of::<U>())
+ {
+ Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned)
+ } else {
+ Ok(unsafe { self.reinterpret_unchecked() })
+ }
+ }
+}
+
+impl<T> Subbuffer<[T]> {
+ /// Returns the number of elements in the slice.
+ pub fn len(&self) -> DeviceSize {
+ debug_assert!(self.size % size_of::<T>() as DeviceSize == 0);
+
+ self.size / size_of::<T>() as DeviceSize
+ }
+
+ /// Reduces the subbuffer to just one element of the slice.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `index` is out of bounds.
+ pub fn index(self, index: DeviceSize) -> Subbuffer<T> {
+ assert!(index <= self.len());
+
+ unsafe { self.index_unchecked(index) }
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn index_unchecked(self, index: DeviceSize) -> Subbuffer<T> {
+ Subbuffer {
+ offset: self.offset + index * size_of::<T>() as DeviceSize,
+ size: size_of::<T>() as DeviceSize,
+ parent: self.parent,
+ marker: PhantomData,
+ }
+ }
+
+ /// Reduces the subbuffer to just a range of the slice.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `range` is out of bounds.
+ /// - Panics if `range` is empty.
+ pub fn slice(mut self, range: impl RangeBounds<DeviceSize>) -> Subbuffer<[T]> {
+ let Range { start, end } = memory::range(range, ..self.len()).unwrap();
+
+ self.offset += start * size_of::<T>() as DeviceSize;
+ self.size = (end - start) * size_of::<T>() as DeviceSize;
+ assert!(self.size != 0);
+
+ self
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn slice_unchecked(mut self, range: impl RangeBounds<DeviceSize>) -> Subbuffer<[T]> {
+ let Range { start, end } = memory::range(range, ..self.len()).unwrap_unchecked();
+
+ self.offset += start * size_of::<T>() as DeviceSize;
+ self.size = (end - start) * size_of::<T>() as DeviceSize;
+ debug_assert!(self.size != 0);
+
+ self
+ }
+
+ /// Splits the subbuffer into two at an index.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `mid` is not greater than `0`.
+ /// - Panics if `mid` is not less than `self.len()`.
+ pub fn split_at(self, mid: DeviceSize) -> (Subbuffer<[T]>, Subbuffer<[T]>) {
+ assert!(0 < mid && mid < self.len());
+
+ unsafe { self.split_at_unchecked(mid) }
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn split_at_unchecked(self, mid: DeviceSize) -> (Subbuffer<[T]>, Subbuffer<[T]>) {
+ (
+ self.clone().slice_unchecked(..mid),
+ self.slice_unchecked(mid..),
+ )
+ }
+}
+
+impl Subbuffer<[u8]> {
+ /// Creates a new `Subbuffer<[u8]>` spanning the whole buffer.
+ #[inline]
+ pub fn new(buffer: Arc<Buffer>) -> Self {
+ Subbuffer {
+ offset: 0,
+ size: buffer.size(),
+ parent: SubbufferParent::Buffer(buffer),
+ marker: PhantomData,
+ }
+ }
+
+ /// Casts the slice to a different element type while ensuring correct alignment for the type.
+ ///
+ /// The offset of the subbuffer is rounded up to the alignment of `T` and the size abjusted for
+ /// the padding, then the size is rounded down to the nearest multiple of `T`'s size.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the aligned offset would be out of bounds.
+ pub fn cast_aligned<T>(self) -> Subbuffer<[T]>
+ where
+ T: BufferContents,
+ {
+ let layout = DeviceLayout::from_layout(Layout::new::<T>()).unwrap();
+ let aligned = self.align_to(layout);
+
+ unsafe { aligned.reinterpret_unchecked() }
+ }
+
+ /// Aligns the subbuffer to the given `layout` by rounding the offset up to
+ /// `layout.alignment()` and adjusting the size for the padding, and then rounding the size
+ /// down to the nearest multiple of `layout.size()`.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the aligned offset would be out of bounds.
+ /// - Panics if `layout.alignment()` exceeds `64`.
+ #[inline]
+ pub fn align_to(mut self, layout: DeviceLayout) -> Subbuffer<[u8]> {
+ assert!(layout.alignment().as_devicesize() <= 64);
+
+ let offset = self.memory_offset();
+ let padding_front = align_up(offset, layout.alignment()) - offset;
+
+ self.offset += padding_front;
+ self.size = self.size.checked_sub(padding_front).unwrap();
+ self.size -= self.size % layout.size();
+
+ self
+ }
+}
+
+impl<T> Subbuffer<[T]>
+where
+ T: BufferContents,
+{
+ /// Tries to cast the slice to a different element type.
+ pub fn try_cast_slice<U>(self) -> Result<Subbuffer<[U]>, PodCastError>
+ where
+ U: BufferContents,
+ {
+ if size_of::<U>() != size_of::<T>() && self.size() % size_of::<U>() as DeviceSize != 0 {
+ Err(PodCastError::OutputSliceWouldHaveSlop)
+ } else if align_of::<U>() > align_of::<T>()
+ && !is_aligned(self.memory_offset(), DeviceAlignment::of::<U>())
+ {
+ Err(PodCastError::TargetAlignmentGreaterAndInputNotAligned)
+ } else {
+ Ok(unsafe { self.reinterpret_unchecked() })
+ }
+ }
+}
+
+impl From<Arc<Buffer>> for Subbuffer<[u8]> {
+ #[inline]
+ fn from(buffer: Arc<Buffer>) -> Self {
+ Self::new(buffer)
+ }
+}
+
+impl<T: ?Sized> Clone for Subbuffer<T> {
+ fn clone(&self) -> Self {
+ Subbuffer {
+ parent: self.parent.clone(),
+ ..*self
+ }
+ }
+}
+
+unsafe impl<T: ?Sized> DeviceOwned for Subbuffer<T> {
+ fn device(&self) -> &Arc<Device> {
+ self.buffer().device()
+ }
+}
+
+impl<T: ?Sized> PartialEq for Subbuffer<T> {
+ fn eq(&self, other: &Self) -> bool {
+ self.parent == other.parent && self.offset == other.offset && self.size == other.size
+ }
+}
+
+impl<T: ?Sized> Eq for Subbuffer<T> {}
+
+impl<T: ?Sized> Hash for Subbuffer<T> {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.parent.hash(state);
+ self.offset.hash(state);
+ self.size.hash(state);
+ }
+}
+
+/// RAII structure used to release the CPU access of a subbuffer when dropped.
+///
+/// This structure is created by the [`read`] method on [`Subbuffer`].
+///
+/// [`read`]: Subbuffer::read
+#[derive(Debug)]
+pub struct BufferReadGuard<'a, T: ?Sized> {
+ subbuffer: &'a Subbuffer<T>,
+ data: &'a T,
+ range: Range<DeviceSize>,
+}
+
+impl<T: ?Sized> Drop for BufferReadGuard<'_, T> {
+ fn drop(&mut self) {
+ let mut state = self.subbuffer.buffer().state();
+ unsafe { state.cpu_read_unlock(self.range.clone()) };
+ }
+}
+
+impl<T: ?Sized> Deref for BufferReadGuard<'_, T> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ self.data
+ }
+}
+
+/// RAII structure used to release the CPU write access of a subbuffer when dropped.
+///
+/// This structure is created by the [`write`] method on [`Subbuffer`].
+///
+/// [`write`]: Subbuffer::write
+#[derive(Debug)]
+pub struct BufferWriteGuard<'a, T: ?Sized> {
+ subbuffer: &'a Subbuffer<T>,
+ data: &'a mut T,
+ range: Range<DeviceSize>,
+}
+
+impl<T: ?Sized> Drop for BufferWriteGuard<'_, T> {
+ fn drop(&mut self) {
+ let allocation = match self.subbuffer.buffer().memory() {
+ BufferMemory::Normal(a) => a,
+ BufferMemory::Sparse => unreachable!(),
+ };
+
+ if allocation.atom_size().is_some() && !thread::panicking() {
+ unsafe { allocation.flush_range(self.range.clone()).unwrap() };
+ }
+
+ let mut state = self.subbuffer.buffer().state();
+ unsafe { state.cpu_write_unlock(self.range.clone()) };
+ }
+}
+
+impl<T: ?Sized> Deref for BufferWriteGuard<'_, T> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ self.data
+ }
+}
+
+impl<T: ?Sized> DerefMut for BufferWriteGuard<'_, T> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ self.data
+ }
+}
+
+/// Error when attempting to CPU-read a buffer.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum ReadLockError {
+ /// The buffer is already locked for write mode by the CPU.
+ CpuWriteLocked,
+ /// The buffer is already locked for write mode by the GPU.
+ GpuWriteLocked,
+}
+
+impl Error for ReadLockError {}
+
+impl Display for ReadLockError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ write!(
+ f,
+ "{}",
+ match self {
+ ReadLockError::CpuWriteLocked => {
+ "the buffer is already locked for write mode by the CPU"
+ }
+ ReadLockError::GpuWriteLocked => {
+ "the buffer is already locked for write mode by the GPU"
+ }
+ }
+ )
+ }
+}
+
+/// Error when attempting to CPU-write a buffer.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum WriteLockError {
+ /// The buffer is already locked by the CPU.
+ CpuLocked,
+ /// The buffer is already locked by the GPU.
+ GpuLocked,
+}
+
+impl Error for WriteLockError {}
+
+impl Display for WriteLockError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ write!(
+ f,
+ "{}",
+ match self {
+ WriteLockError::CpuLocked => "the buffer is already locked by the CPU",
+ WriteLockError::GpuLocked => "the buffer is already locked by the GPU",
+ }
+ )
+ }
+}
+
+/// Trait for types of data that can be put in a buffer.
+///
+/// This trait is not intended to be implemented manually (ever) and attempting so will make you
+/// one sad individual very quickly. Rather you should use [the derive macro]. Note also that there
+/// are blanket implementations of this trait: you don't need to implement it if the type in
+/// question already implements bytemuck's [`AnyBitPattern`]. Most if not all linear algebra crates
+/// have a feature flag that you can enable for bytemuck support. The trait is also already
+/// implemented for all slices where the element type implements `BufferContents`.
+///
+/// # Examples
+///
+/// Deriving the trait for sized types:
+///
+/// ```
+/// # use vulkano::buffer::BufferContents;
+/// #[derive(BufferContents)]
+/// #[repr(C)]
+/// struct MyData {
+/// x: f32,
+/// y: f32,
+/// array: [i32; 12],
+/// }
+/// ```
+///
+/// Deriving the trait for unsized types works the same:
+///
+/// ```
+/// # use vulkano::buffer::BufferContents;
+/// #[derive(BufferContents)]
+/// #[repr(C)]
+/// struct MyData {
+/// x: f32,
+/// y: f32,
+/// slice: [i32],
+/// }
+/// ```
+///
+/// This even works if the last field is a user-defined DST too:
+///
+/// ```
+/// # use vulkano::buffer::BufferContents;
+/// #[derive(BufferContents)]
+/// #[repr(C)]
+/// struct MyData {
+/// x: f32,
+/// y: f32,
+/// other: OtherData,
+/// }
+///
+/// #[derive(BufferContents)]
+/// #[repr(C)]
+/// struct OtherData {
+/// slice: [i32],
+/// }
+/// ```
+///
+/// You can also use generics if you please:
+///
+/// ```
+/// # use vulkano::buffer::BufferContents;
+/// #[derive(BufferContents)]
+/// #[repr(C)]
+/// struct MyData<T, U> {
+/// x: T,
+/// y: T,
+/// slice: [U],
+/// }
+/// ```
+///
+/// This even works with dependently-sized types:
+///
+/// ```
+/// # use vulkano::buffer::BufferContents;
+/// #[derive(BufferContents)]
+/// #[repr(C)]
+/// struct MyData<T>
+/// where
+/// T: ?Sized,
+/// {
+/// x: f32,
+/// y: f32,
+/// z: T,
+/// }
+/// ```
+///
+/// [the derive macro]: vulkano_macros::BufferContents
+//
+// If you absolutely *must* implement this trait by hand, here are the safety requirements (but
+// please open an issue on GitHub instead):
+//
+// - The type must be a struct and all fields must implement `BufferContents`.
+// - `LAYOUT` must be the correct layout for the type, which also means the type must either be
+// sized or if it's unsized then its metadata must be the same as that of a slice. Implementing
+// `BufferContents` for any other kind of DST is instantaneous horrifically undefined behavior.
+// - `from_ffi` must create a pointer with the same address as the `data` parameter that is passed
+// in. The pointer is expected to be aligned properly already.
+// - `from_ffi` must create a pointer that is expected to be valid for reads (and potentially
+// writes) for exactly `range` bytes. The `data` and `range` are expected to be valid for the
+// `LAYOUT`.
+pub unsafe trait BufferContents: Send + Sync + 'static {
+ /// The layout of the contents.
+ const LAYOUT: BufferContentsLayout;
+
+ /// Creates a pointer to `Self` from a pointer to the start of the data and a range in bytes.
+ ///
+ /// # Safety
+ ///
+ /// - If `Self` is sized, then `range` must match the size exactly.
+ /// - If `Self` is unsized, then the `range` minus the size of the head (sized part) of the DST
+ /// must be evenly divisible by the size of the element type.
+ #[doc(hidden)]
+ unsafe fn from_ffi(data: *mut c_void, range: usize) -> *mut Self;
+}
+
+unsafe impl<T> BufferContents for T
+where
+ T: AnyBitPattern + Send + Sync,
+{
+ const LAYOUT: BufferContentsLayout =
+ if let Some(layout) = BufferContentsLayout::from_sized(Layout::new::<T>()) {
+ layout
+ } else {
+ panic!("zero-sized types are not valid buffer contents");
+ };
+
+ #[inline(always)]
+ unsafe fn from_ffi(data: *mut c_void, range: usize) -> *mut Self {
+ debug_assert!(range == size_of::<T>());
+ debug_assert!(data as usize % align_of::<T>() == 0);
+
+ data.cast()
+ }
+}
+
+unsafe impl<T> BufferContents for [T]
+where
+ T: BufferContents,
+{
+ const LAYOUT: BufferContentsLayout = BufferContentsLayout(BufferContentsLayoutInner::Unsized {
+ head_layout: None,
+ element_layout: T::LAYOUT.unwrap_sized(),
+ });
+
+ #[inline(always)]
+ unsafe fn from_ffi(data: *mut c_void, range: usize) -> *mut Self {
+ debug_assert!(range % size_of::<T>() == 0);
+ debug_assert!(data as usize % align_of::<T>() == 0);
+ let len = range / size_of::<T>();
+
+ ptr::slice_from_raw_parts_mut(data.cast(), len)
+ }
+}
+
+/// Describes the layout required for a type so that it can be read from/written to a buffer. This
+/// is used to allocate (sub)buffers generically.
+///
+/// This is similar to [`DeviceLayout`] except that this exists for the sole purpose of describing
+/// the layout of buffer contents specifically. Which means for example that the sizedness of the
+/// type is captured, as well as the layout of the head and tail if the layout is for unsized data,
+/// in order to be able to represent everything that Vulkan can stuff in a buffer.
+///
+/// `BufferContentsLayout` also has an additional invariant compared to `DeviceLayout`: the
+/// alignment of the data must not exceed `64`. This is because that's the guaranteed alignment
+/// that all `DeviceMemory` blocks must be aligned to at minimum, and hence any greater alignment
+/// can't be guaranteed. Other than that, the invariant that sizes must be non-zero applies here as
+/// well, for both sized data and the element type of unsized data.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct BufferContentsLayout(BufferContentsLayoutInner);
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+enum BufferContentsLayoutInner {
+ Sized(DeviceLayout),
+ Unsized {
+ head_layout: Option<DeviceLayout>,
+ element_layout: DeviceLayout,
+ },
+}
+
+impl BufferContentsLayout {
+ /// Returns the size of the head (sized part). If the data has no sized part, then this will
+ /// return 0.
+ #[inline]
+ pub const fn head_size(&self) -> DeviceSize {
+ match &self.0 {
+ BufferContentsLayoutInner::Sized(sized) => sized.size(),
+ BufferContentsLayoutInner::Unsized {
+ head_layout: None, ..
+ } => 0,
+ BufferContentsLayoutInner::Unsized {
+ head_layout: Some(head_layout),
+ ..
+ } => head_layout.size(),
+ }
+ }
+
+ /// Returns the size of the element type if the data is unsized, or returns [`None`].
+ /// Guaranteed to be non-zero.
+ #[inline]
+ pub const fn element_size(&self) -> Option<DeviceSize> {
+ match &self.0 {
+ BufferContentsLayoutInner::Sized(_) => None,
+ BufferContentsLayoutInner::Unsized { element_layout, .. } => {
+ Some(element_layout.size())
+ }
+ }
+ }
+
+ /// Returns the alignment required for the data. Guaranteed to not exceed `64`.
+ #[inline]
+ pub const fn alignment(&self) -> DeviceAlignment {
+ match &self.0 {
+ BufferContentsLayoutInner::Sized(sized) => sized.alignment(),
+ BufferContentsLayoutInner::Unsized {
+ head_layout: None,
+ element_layout,
+ } => element_layout.alignment(),
+ BufferContentsLayoutInner::Unsized {
+ head_layout: Some(head_layout),
+ ..
+ } => head_layout.alignment(),
+ }
+ }
+
+ /// Returns the [`DeviceLayout`] for the data for the given `len`, or returns [`None`] on
+ /// arithmetic overflow or if the total size would exceed [`DeviceLayout::MAX_SIZE`].
+ #[inline]
+ pub const fn layout_for_len(&self, len: NonZeroDeviceSize) -> Option<DeviceLayout> {
+ match &self.0 {
+ BufferContentsLayoutInner::Sized(sized) => Some(*sized),
+ BufferContentsLayoutInner::Unsized {
+ head_layout,
+ element_layout,
+ } => {
+ let (tail_layout, _) = try_opt!(element_layout.repeat(len));
+
+ if let Some(head_layout) = head_layout {
+ let (layout, _) = try_opt!(head_layout.extend(tail_layout));
+
+ Some(layout.pad_to_alignment())
+ } else {
+ Some(tail_layout)
+ }
+ }
+ }
+ }
+
+ /// Creates a new `BufferContentsLayout` from a sized layout. This is inteded for use by the
+ /// derive macro only.
+ #[doc(hidden)]
+ #[inline]
+ pub const fn from_sized(sized: Layout) -> Option<Self> {
+ assert!(
+ sized.align() <= 64,
+ "types with alignments above 64 are not valid buffer contents",
+ );
+
+ if let Ok(sized) = DeviceLayout::from_layout(sized) {
+ Some(Self(BufferContentsLayoutInner::Sized(sized)))
+ } else {
+ None
+ }
+ }
+
+ /// Creates a new `BufferContentsLayout` from a head and element layout. This is inteded for
+ /// use by the derive macro only.
+ #[doc(hidden)]
+ #[inline]
+ pub const fn from_head_element_layout(
+ head_layout: Layout,
+ element_layout: Layout,
+ ) -> Option<Self> {
+ if head_layout.align() > 64 || element_layout.align() > 64 {
+ panic!("types with alignments above 64 are not valid buffer contents");
+ }
+
+ // The head of a `BufferContentsLayout` can be zero-sized.
+ // TODO: Replace with `Result::ok` once its constness is stabilized.
+ let head_layout = if let Ok(head_layout) = DeviceLayout::from_layout(head_layout) {
+ Some(head_layout)
+ } else {
+ None
+ };
+
+ if let Ok(element_layout) = DeviceLayout::from_layout(element_layout) {
+ Some(Self(BufferContentsLayoutInner::Unsized {
+ head_layout,
+ element_layout,
+ }))
+ } else {
+ None
+ }
+ }
+
+ /// Extends the given `previous` [`Layout`] by `self`. This is intended for use by the derive
+ /// macro only.
+ #[doc(hidden)]
+ #[inline]
+ pub const fn extend_from_layout(self, previous: &Layout) -> Option<Self> {
+ assert!(
+ previous.align() <= 64,
+ "types with alignments above 64 are not valid buffer contents",
+ );
+
+ match self.0 {
+ BufferContentsLayoutInner::Sized(sized) => {
+ let (sized, _) = try_opt!(sized.extend_from_layout(previous));
+
+ Some(Self(BufferContentsLayoutInner::Sized(sized)))
+ }
+ BufferContentsLayoutInner::Unsized {
+ head_layout: None,
+ element_layout,
+ } => {
+ // The head of a `BufferContentsLayout` can be zero-sized.
+ // TODO: Replace with `Result::ok` once its constness is stabilized.
+ let head_layout = if let Ok(head_layout) = DeviceLayout::from_layout(*previous) {
+ Some(head_layout)
+ } else {
+ None
+ };
+
+ Some(Self(BufferContentsLayoutInner::Unsized {
+ head_layout,
+ element_layout,
+ }))
+ }
+ BufferContentsLayoutInner::Unsized {
+ head_layout: Some(head_layout),
+ element_layout,
+ } => {
+ let (head_layout, _) = try_opt!(head_layout.extend_from_layout(previous));
+
+ Some(Self(BufferContentsLayoutInner::Unsized {
+ head_layout: Some(head_layout),
+ element_layout,
+ }))
+ }
+ }
+ }
+
+ /// Creates a new `BufferContentsLayout` by rounding up the size of the head to the nearest
+ /// multiple of its alignment if the layout is sized, or by rounding up the size of the head to
+ /// the nearest multiple of the alignment of the element type and aligning the head to the
+ /// alignment of the element type if there is a sized part. Doesn't do anything if there is no
+ /// sized part. Returns [`None`] if the new head size would exceed [`DeviceLayout::MAX_SIZE`].
+ /// This is inteded for use by the derive macro only.
+ #[doc(hidden)]
+ #[inline]
+ pub const fn pad_to_alignment(&self) -> Option<Self> {
+ match &self.0 {
+ BufferContentsLayoutInner::Sized(sized) => Some(Self(
+ BufferContentsLayoutInner::Sized(sized.pad_to_alignment()),
+ )),
+ BufferContentsLayoutInner::Unsized {
+ head_layout: None,
+ element_layout,
+ } => Some(Self(BufferContentsLayoutInner::Unsized {
+ head_layout: None,
+ element_layout: *element_layout,
+ })),
+ BufferContentsLayoutInner::Unsized {
+ head_layout: Some(head_layout),
+ element_layout,
+ } => {
+ // We must pad the head to the alignment of the element type, *not* the alignment
+ // of the head.
+ //
+ // Consider a head layout of `(u8, u8, u8)` and an element layout of `u32`. If we
+ // padded the head to its own alignment, like is the case for sized layouts, it
+ // wouldn't change the size. Yet there is padding between the head and the first
+ // element of the slice.
+ //
+ // The reverse is true: consider a head layout of `(u16, u8)` and an element layout
+ // of `u8`. If we padded the head to its own alignment, it would be too large.
+ let padded_head_size =
+ head_layout.size() + head_layout.padding_needed_for(element_layout.alignment());
+
+ // SAFETY: `BufferContentsLayout`'s invariant guarantees that the alignment of the
+ // element type doesn't exceed 64, which together with the overflow invariant of
+ // `DeviceLayout` means that this can't overflow.
+ let padded_head_size =
+ unsafe { NonZeroDeviceSize::new_unchecked(padded_head_size) };
+
+ // We have to align the head to the alignment of the element type, so that the
+ // struct as a whole is aligned correctly when a different struct is extended with
+ // this one.
+ //
+ // Note that this is *not* the same as aligning the head to the alignment of the
+ // element type and then padding the layout to its alignment. Consider the same
+ // layout from above, with a head layout of `(u16, u8)` and an element layout of
+ // `u8`. If we aligned the head to the element type and then padded it to its own
+ // alignment, we would get the same wrong result as above. This instead ensures the
+ // head is padded to the element and aligned to it, without the alignment of the
+ // head interfering.
+ let alignment =
+ DeviceAlignment::max(head_layout.alignment(), element_layout.alignment());
+
+ if let Some(head_layout) = DeviceLayout::new(padded_head_size, alignment) {
+ Some(Self(BufferContentsLayoutInner::Unsized {
+ head_layout: Some(head_layout),
+ element_layout: *element_layout,
+ }))
+ } else {
+ None
+ }
+ }
+ }
+ }
+
+ pub(super) const fn unwrap_sized(self) -> DeviceLayout {
+ match self.0 {
+ BufferContentsLayoutInner::Sized(sized) => sized,
+ BufferContentsLayoutInner::Unsized { .. } => {
+ panic!("called `BufferContentsLayout::unwrap_sized` on an unsized layout");
+ }
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::{
+ buffer::{
+ sys::{BufferCreateInfo, RawBuffer},
+ BufferUsage,
+ },
+ memory::{
+ allocator::{
+ AllocationCreateInfo, AllocationType, DeviceLayout, MemoryAllocator, MemoryUsage,
+ StandardMemoryAllocator,
+ },
+ MemoryRequirements,
+ },
+ };
+
+ #[test]
+ fn derive_buffer_contents() {
+ #[derive(BufferContents)]
+ #[repr(C)]
+ struct Test1(u32, u64, u8);
+
+ assert_eq!(Test1::LAYOUT.head_size() as usize, size_of::<Test1>());
+ assert_eq!(Test1::LAYOUT.element_size(), None);
+ assert_eq!(
+ Test1::LAYOUT.alignment().as_devicesize() as usize,
+ align_of::<Test1>(),
+ );
+
+ #[derive(BufferContents)]
+ #[repr(C)]
+ struct Composite1(Test1, [f32; 10], Test1);
+
+ assert_eq!(
+ Composite1::LAYOUT.head_size() as usize,
+ size_of::<Composite1>(),
+ );
+ assert_eq!(Composite1::LAYOUT.element_size(), None);
+ assert_eq!(
+ Composite1::LAYOUT.alignment().as_devicesize() as usize,
+ align_of::<Composite1>(),
+ );
+
+ #[derive(BufferContents)]
+ #[repr(C)]
+ struct Test2(u64, u8, [u32]);
+
+ assert_eq!(
+ Test2::LAYOUT.head_size() as usize,
+ size_of::<u64>() + size_of::<u32>(),
+ );
+ assert_eq!(
+ Test2::LAYOUT.element_size().unwrap() as usize,
+ size_of::<u32>(),
+ );
+ assert_eq!(
+ Test2::LAYOUT.alignment().as_devicesize() as usize,
+ align_of::<u64>(),
+ );
+
+ #[derive(BufferContents)]
+ #[repr(C)]
+ struct Composite2(Test1, [f32; 10], Test2);
+
+ assert_eq!(
+ Composite2::LAYOUT.head_size() as usize,
+ size_of::<Test1>() + size_of::<[f32; 10]>() + size_of::<u64>() + size_of::<u32>(),
+ );
+ assert_eq!(
+ Composite2::LAYOUT.element_size().unwrap() as usize,
+ size_of::<u32>(),
+ );
+ assert_eq!(
+ Composite2::LAYOUT.alignment().as_devicesize() as usize,
+ align_of::<u64>(),
+ );
+ }
+
+ #[test]
+ fn split_at() {
+ let (device, _) = gfx_dev_and_queue!();
+ let allocator = StandardMemoryAllocator::new_default(device);
+
+ let buffer = Buffer::new_slice::<u32>(
+ &allocator,
+ BufferCreateInfo {
+ usage: BufferUsage::TRANSFER_SRC,
+ ..Default::default()
+ },
+ AllocationCreateInfo {
+ usage: MemoryUsage::Upload,
+ ..Default::default()
+ },
+ 6,
+ )
+ .unwrap();
+
+ {
+ let (left, right) = buffer.clone().split_at(2);
+ assert!(left.len() == 2);
+ assert!(right.len() == 4);
+ }
+
+ {
+ let (left, right) = buffer.clone().split_at(5);
+ assert!(left.len() == 5);
+ assert!(right.len() == 1);
+ }
+
+ {
+ assert_should_panic!({ buffer.clone().split_at(0) });
+ }
+
+ {
+ assert_should_panic!({ buffer.split_at(6) });
+ }
+ }
+
+ #[test]
+ fn cast_aligned() {
+ let (device, _) = gfx_dev_and_queue!();
+ let allocator = StandardMemoryAllocator::new_default(device.clone());
+
+ let raw_buffer = RawBuffer::new(
+ device,
+ BufferCreateInfo {
+ size: 32,
+ usage: BufferUsage::TRANSFER_SRC,
+ ..Default::default()
+ },
+ )
+ .unwrap();
+
+ let requirements = MemoryRequirements {
+ layout: DeviceLayout::from_size_alignment(32, 1).unwrap(),
+ memory_type_bits: 1,
+ prefers_dedicated_allocation: false,
+ requires_dedicated_allocation: false,
+ };
+
+ // Allocate some junk in the same block as the buffer.
+ let _junk = allocator
+ .allocate(
+ MemoryRequirements {
+ layout: DeviceLayout::from_size_alignment(17, 1).unwrap(),
+ ..requirements
+ },
+ AllocationType::Linear,
+ AllocationCreateInfo::default(),
+ None,
+ )
+ .unwrap();
+
+ let allocation = allocator
+ .allocate(
+ requirements,
+ AllocationType::Linear,
+ AllocationCreateInfo::default(),
+ None,
+ )
+ .unwrap();
+
+ let buffer = Buffer::from_raw(raw_buffer, BufferMemory::Normal(allocation));
+ let buffer = Subbuffer::from(Arc::new(buffer));
+
+ assert!(buffer.memory_offset() >= 17);
+
+ {
+ #[derive(Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
+ #[repr(C, align(16))]
+ struct Test([u8; 16]);
+
+ let aligned = buffer.clone().cast_aligned::<Test>();
+ assert_eq!(aligned.memory_offset() % 16, 0);
+ assert_eq!(aligned.size(), 16);
+ }
+
+ {
+ let aligned = buffer.clone().cast_aligned::<[u8; 16]>();
+ assert_eq!(aligned.size() % 16, 0);
+ }
+
+ {
+ let layout = DeviceLayout::from_size_alignment(32, 16).unwrap();
+ let aligned = buffer.clone().align_to(layout);
+ assert!(is_aligned(aligned.memory_offset(), layout.alignment()));
+ assert_eq!(aligned.size(), 0);
+ }
+
+ {
+ let layout = DeviceLayout::from_size_alignment(1, 64).unwrap();
+ assert_should_panic!({ buffer.align_to(layout) });
+ }
+ }
+}
diff --git a/src/buffer/sys.rs b/src/buffer/sys.rs
index f462e00..93fb6d0 100644
--- a/src/buffer/sys.rs
+++ b/src/buffer/sys.rs
@@ -9,583 +9,785 @@
//! Low level implementation of buffers.
//!
-//! Wraps directly around Vulkan buffers, with the exceptions of a few safety checks.
-//!
-//! The `UnsafeBuffer` type is the lowest-level buffer object provided by this library. It is used
-//! internally by the higher-level buffer types. You are strongly encouraged to have excellent
-//! knowledge of the Vulkan specs if you want to use an `UnsafeBuffer`.
-//!
-//! Here is what you must take care of when you use an `UnsafeBuffer`:
-//!
-//! - Synchronization, ie. avoid reading and writing simultaneously to the same buffer.
-//! - Memory aliasing considerations. If you use the same memory to back multiple resources, you
-//! must ensure that they are not used together and must enable some additional flags.
-//! - Binding memory correctly and only once. If you use sparse binding, respect the rules of
-//! sparse binding.
-//! - Type safety.
-
-use crate::check_errors;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::memory::DeviceMemory;
-use crate::memory::DeviceMemoryAllocError;
-use crate::memory::MemoryRequirements;
-use crate::sync::Sharing;
-use crate::DeviceSize;
-use crate::Error;
-use crate::OomError;
-use crate::VulkanObject;
-use crate::{buffer::BufferUsage, Version};
-use ash::vk::Handle;
+//! This module contains low-level wrappers around the Vulkan buffer types. All
+//! other buffer types of this library, and all custom buffer types
+//! that you create must wrap around the types in this module.
+
+use super::{Buffer, BufferCreateFlags, BufferError, BufferMemory, BufferUsage};
+use crate::{
+ device::{Device, DeviceOwned},
+ macros::impl_id_counter,
+ memory::{
+ allocator::{AllocationType, DeviceLayout, MemoryAlloc},
+ is_aligned, DedicatedTo, ExternalMemoryHandleTypes, MemoryAllocateFlags,
+ MemoryPropertyFlags, MemoryRequirements,
+ },
+ sync::Sharing,
+ DeviceSize, RequiresOneOf, Version, VulkanError, VulkanObject,
+};
use smallvec::SmallVec;
-use std::error;
-use std::fmt;
-use std::hash::Hash;
-use std::hash::Hasher;
-use std::mem::MaybeUninit;
-use std::ptr;
-use std::sync::Arc;
-
-/// Data storage in a GPU-accessible location.
-pub struct UnsafeBuffer {
- buffer: ash::vk::Buffer,
+use std::{mem::MaybeUninit, num::NonZeroU64, ptr, sync::Arc};
+
+/// A raw buffer, with no memory backing it.
+///
+/// This is the basic buffer type, a direct translation of a `VkBuffer` object, but it is mostly
+/// useless in this form. After creating a raw buffer, you must call `bind_memory` to make a
+/// complete buffer object.
+#[derive(Debug)]
+pub struct RawBuffer {
+ handle: ash::vk::Buffer,
device: Arc<Device>,
+ id: NonZeroU64,
+
+ flags: BufferCreateFlags,
size: DeviceSize,
usage: BufferUsage,
+ sharing: Sharing<SmallVec<[u32; 4]>>,
+ external_memory_handle_types: ExternalMemoryHandleTypes,
+
+ memory_requirements: MemoryRequirements,
}
-impl UnsafeBuffer {
- /// Creates a new buffer of the given size.
- ///
- /// See the module's documentation for information about safety.
+impl RawBuffer {
+ /// Creates a new `RawBuffer`.
///
- /// # Panic
+ /// # Panics
///
- /// - Panics if `sparse.sparse` is false and `sparse.sparse_residency` or `sparse.sparse_aliased` is true.
- /// - Panics if `usage` is empty.
- ///
- pub unsafe fn new<'a, I>(
+ /// - Panics if `create_info.sharing` is [`Concurrent`](Sharing::Concurrent) with less than 2
+ /// items.
+ /// - Panics if `create_info.size` is zero.
+ /// - Panics if `create_info.usage` is empty.
+ #[inline]
+ pub fn new(
device: Arc<Device>,
- size: DeviceSize,
- mut usage: BufferUsage,
- sharing: Sharing<I>,
- sparse: Option<SparseLevel>,
- ) -> Result<(UnsafeBuffer, MemoryRequirements), BufferCreationError>
- where
- I: Iterator<Item = u32>,
- {
- let fns = device.fns();
-
- // Ensure we're not trying to create an empty buffer.
- let size = if size == 0 {
- // To avoid panicking when allocating 0 bytes, use a 1-byte buffer.
- 1
- } else {
- size
- };
+ mut create_info: BufferCreateInfo,
+ ) -> Result<Self, BufferError> {
+ match &mut create_info.sharing {
+ Sharing::Exclusive => (),
+ Sharing::Concurrent(queue_family_indices) => {
+ // VUID-VkBufferCreateInfo-sharingMode-01419
+ queue_family_indices.sort_unstable();
+ queue_family_indices.dedup();
+ }
+ }
+
+ Self::validate_new(&device, &create_info)?;
+
+ unsafe { Ok(Self::new_unchecked(device, create_info)?) }
+ }
- // Checking sparse features.
- let flags = if let Some(sparse_level) = sparse {
+ fn validate_new(device: &Device, create_info: &BufferCreateInfo) -> Result<(), BufferError> {
+ let &BufferCreateInfo {
+ flags,
+ ref sharing,
+ size,
+ usage,
+ external_memory_handle_types,
+ _ne: _,
+ } = create_info;
+
+ // VUID-VkBufferCreateInfo-flags-parameter
+ flags.validate_device(device)?;
+
+ // VUID-VkBufferCreateInfo-usage-parameter
+ usage.validate_device(device)?;
+
+ // VUID-VkBufferCreateInfo-usage-requiredbitmask
+ assert!(!usage.is_empty());
+
+ // VUID-VkBufferCreateInfo-size-00912
+ assert!(size != 0);
+
+ /* Enable when sparse binding is properly handled
+ if let Some(sparse_level) = sparse {
+ // VUID-VkBufferCreateInfo-flags-00915
if !device.enabled_features().sparse_binding {
- return Err(BufferCreationError::SparseBindingFeatureNotEnabled);
+ return Err(BufferError::RequirementNotMet {
+ required_for: "`create_info.sparse` is `Some`",
+ requires_one_of: RequiresOneOf {
+ features: &["sparse_binding"],
+ ..Default::default()
+ },
+ });
}
+ // VUID-VkBufferCreateInfo-flags-00916
if sparse_level.sparse_residency && !device.enabled_features().sparse_residency_buffer {
- return Err(BufferCreationError::SparseResidencyBufferFeatureNotEnabled);
+ return Err(BufferError::RequirementNotMet {
+ required_for: "`create_info.sparse` is `Some(sparse_level)`, where \
+ `sparse_level` contains `BufferCreateFlags::SPARSE_RESIDENCY`",
+ requires_one_of: RequiresOneOf {
+ features: &["sparse_residency_buffer"],
+ ..Default::default()
+ },
+ });
}
+ // VUID-VkBufferCreateInfo-flags-00917
if sparse_level.sparse_aliased && !device.enabled_features().sparse_residency_aliased {
- return Err(BufferCreationError::SparseResidencyAliasedFeatureNotEnabled);
+ return Err(BufferError::RequirementNotMet {
+ required_for: "`create_info.sparse` is `Some(sparse_level)`, where \
+ `sparse_level` contains `BufferCreateFlags::SPARSE_ALIASED`",
+ requires_one_of: RequiresOneOf {
+ features: &["sparse_residency_aliased"],
+ ..Default::default()
+ },
+ });
}
- sparse_level.into()
- } else {
- ash::vk::BufferCreateFlags::empty()
- };
+ // VUID-VkBufferCreateInfo-flags-00918
+ }
+ */
+
+ match sharing {
+ Sharing::Exclusive => (),
+ Sharing::Concurrent(queue_family_indices) => {
+ // VUID-VkBufferCreateInfo-sharingMode-00914
+ assert!(queue_family_indices.len() >= 2);
+
+ for &queue_family_index in queue_family_indices.iter() {
+ // VUID-VkBufferCreateInfo-sharingMode-01419
+ if queue_family_index
+ >= device.physical_device().queue_family_properties().len() as u32
+ {
+ return Err(BufferError::SharingQueueFamilyIndexOutOfRange {
+ queue_family_index,
+ queue_family_count: device
+ .physical_device()
+ .queue_family_properties()
+ .len() as u32,
+ });
+ }
+ }
+ }
+ }
- if usage.device_address && !device.enabled_features().buffer_device_address {
- usage.device_address = false;
- if ash::vk::BufferUsageFlags::from(usage).is_empty() {
- // return an error iff device_address was the only requested usage and the
- // feature isn't enabled. Otherwise we'll hit that assert below.
- // TODO: This is weird, why not just return an error always if the feature is not enabled?
- // You can't use BufferUsage::all() anymore, but is that a good idea anyway?
- return Err(BufferCreationError::DeviceAddressFeatureNotEnabled);
+ if let Some(max_buffer_size) = device.physical_device().properties().max_buffer_size {
+ // VUID-VkBufferCreateInfo-size-06409
+ if size > max_buffer_size {
+ return Err(BufferError::MaxBufferSizeExceeded {
+ size,
+ max: max_buffer_size,
+ });
}
}
- let usage_bits = ash::vk::BufferUsageFlags::from(usage);
- // Checking for empty BufferUsage.
- assert!(
- !usage_bits.is_empty(),
- "Can't create buffer with empty BufferUsage"
- );
-
- let buffer = {
- let (sh_mode, sh_indices) = match sharing {
- Sharing::Exclusive => {
- (ash::vk::SharingMode::EXCLUSIVE, SmallVec::<[u32; 8]>::new())
- }
- Sharing::Concurrent(ids) => (ash::vk::SharingMode::CONCURRENT, ids.collect()),
- };
-
- let infos = ash::vk::BufferCreateInfo {
- flags,
- size,
- usage: usage_bits,
- sharing_mode: sh_mode,
- queue_family_index_count: sh_indices.len() as u32,
- p_queue_family_indices: sh_indices.as_ptr(),
+ if !external_memory_handle_types.is_empty() {
+ if !(device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_external_memory)
+ {
+ return Err(BufferError::RequirementNotMet {
+ required_for: "`create_info.external_memory_handle_types` is not empty",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_1),
+ device_extensions: &["khr_external_memory"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkExternalMemoryBufferCreateInfo-handleTypes-parameter
+ external_memory_handle_types.validate_device(device)?;
+
+ // VUID-VkBufferCreateInfo-pNext-00920
+ // TODO:
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn new_unchecked(
+ device: Arc<Device>,
+ create_info: BufferCreateInfo,
+ ) -> Result<Self, VulkanError> {
+ let &BufferCreateInfo {
+ flags,
+ ref sharing,
+ size,
+ usage,
+ external_memory_handle_types,
+ _ne: _,
+ } = &create_info;
+
+ let (sharing_mode, queue_family_index_count, p_queue_family_indices) = match sharing {
+ Sharing::Exclusive => (ash::vk::SharingMode::EXCLUSIVE, 0, &[] as _),
+ Sharing::Concurrent(queue_family_indices) => (
+ ash::vk::SharingMode::CONCURRENT,
+ queue_family_indices.len() as u32,
+ queue_family_indices.as_ptr(),
+ ),
+ };
+
+ let mut create_info_vk = ash::vk::BufferCreateInfo {
+ flags: flags.into(),
+ size,
+ usage: usage.into(),
+ sharing_mode,
+ queue_family_index_count,
+ p_queue_family_indices,
+ ..Default::default()
+ };
+ let mut external_memory_info_vk = None;
+
+ if !external_memory_handle_types.is_empty() {
+ let _ = external_memory_info_vk.insert(ash::vk::ExternalMemoryBufferCreateInfo {
+ handle_types: external_memory_handle_types.into(),
..Default::default()
- };
+ });
+ }
+
+ if let Some(next) = external_memory_info_vk.as_mut() {
+ next.p_next = create_info_vk.p_next;
+ create_info_vk.p_next = next as *const _ as *const _;
+ }
+ let handle = {
+ let fns = device.fns();
let mut output = MaybeUninit::uninit();
- check_errors(fns.v1_0.create_buffer(
- device.internal_object(),
- &infos,
+ (fns.v1_0.create_buffer)(
+ device.handle(),
+ &create_info_vk,
ptr::null(),
output.as_mut_ptr(),
- ))?;
+ )
+ .result()
+ .map_err(VulkanError::from)?;
output.assume_init()
};
- let mem_reqs = {
- #[inline]
- fn align(val: DeviceSize, al: DeviceSize) -> DeviceSize {
- al * (1 + (val - 1) / al)
- }
+ Ok(Self::from_handle(device, handle, create_info))
+ }
- let mut output = if device.api_version() >= Version::V1_1
- || device.enabled_extensions().khr_get_memory_requirements2
- {
- let infos = ash::vk::BufferMemoryRequirementsInfo2 {
- buffer: buffer,
- ..Default::default()
- };
+ /// Creates a new `RawBuffer` from a raw object handle.
+ ///
+ /// # Safety
+ ///
+ /// - `handle` must be a valid Vulkan object handle created from `device`.
+ /// - `handle` must refer to a buffer that has not yet had memory bound to it.
+ /// - `create_info` must match the info used to create the object.
+ #[inline]
+ pub unsafe fn from_handle(
+ device: Arc<Device>,
+ handle: ash::vk::Buffer,
+ create_info: BufferCreateInfo,
+ ) -> Self {
+ let BufferCreateInfo {
+ flags,
+ size,
+ usage,
+ sharing,
+ external_memory_handle_types,
+ _ne: _,
+ } = create_info;
+
+ let mut memory_requirements = Self::get_memory_requirements(&device, handle);
+
+ debug_assert!(memory_requirements.layout.size() >= size);
+ debug_assert!(memory_requirements.memory_type_bits != 0);
+
+ // We have to manually enforce some additional requirements for some buffer types.
+ let properties = device.physical_device().properties();
+ if usage.intersects(BufferUsage::UNIFORM_TEXEL_BUFFER | BufferUsage::STORAGE_TEXEL_BUFFER) {
+ memory_requirements.layout = memory_requirements
+ .layout
+ .align_to(properties.min_texel_buffer_offset_alignment)
+ .unwrap();
+ }
- let mut output2 = if device.api_version() >= Version::V1_1
- || device.enabled_extensions().khr_dedicated_allocation
- {
- Some(ash::vk::MemoryDedicatedRequirementsKHR::default())
- } else {
- None
- };
-
- let mut output = ash::vk::MemoryRequirements2 {
- p_next: output2
- .as_mut()
- .map(|o| o as *mut ash::vk::MemoryDedicatedRequirementsKHR)
- .unwrap_or(ptr::null_mut()) as *mut _,
- ..Default::default()
- };
+ if usage.intersects(BufferUsage::STORAGE_BUFFER) {
+ memory_requirements.layout = memory_requirements
+ .layout
+ .align_to(properties.min_storage_buffer_offset_alignment)
+ .unwrap();
+ }
+
+ if usage.intersects(BufferUsage::UNIFORM_BUFFER) {
+ memory_requirements.layout = memory_requirements
+ .layout
+ .align_to(properties.min_uniform_buffer_offset_alignment)
+ .unwrap();
+ }
+
+ RawBuffer {
+ handle,
+ device,
+ id: Self::next_id(),
+ flags,
+ size,
+ usage,
+ sharing,
+ external_memory_handle_types,
+ memory_requirements,
+ }
+ }
+
+ fn get_memory_requirements(device: &Device, handle: ash::vk::Buffer) -> MemoryRequirements {
+ let info_vk = ash::vk::BufferMemoryRequirementsInfo2 {
+ buffer: handle,
+ ..Default::default()
+ };
+ let mut memory_requirements2_vk = ash::vk::MemoryRequirements2::default();
+ let mut memory_dedicated_requirements_vk = None;
+
+ if device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_dedicated_allocation
+ {
+ debug_assert!(
+ device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_get_memory_requirements2
+ );
+
+ let next = memory_dedicated_requirements_vk
+ .insert(ash::vk::MemoryDedicatedRequirements::default());
+
+ next.p_next = memory_requirements2_vk.p_next;
+ memory_requirements2_vk.p_next = next as *mut _ as *mut _;
+ }
+
+ unsafe {
+ let fns = device.fns();
+
+ if device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_get_memory_requirements2
+ {
if device.api_version() >= Version::V1_1 {
- fns.v1_1.get_buffer_memory_requirements2(
- device.internal_object(),
- &infos,
- &mut output,
+ (fns.v1_1.get_buffer_memory_requirements2)(
+ device.handle(),
+ &info_vk,
+ &mut memory_requirements2_vk,
);
} else {
- fns.khr_get_memory_requirements2
- .get_buffer_memory_requirements2_khr(
- device.internal_object(),
- &infos,
- &mut output,
- );
- }
-
- debug_assert!(output.memory_requirements.size >= size);
- debug_assert!(output.memory_requirements.memory_type_bits != 0);
-
- let mut out = MemoryRequirements::from(output.memory_requirements);
- if let Some(output2) = output2 {
- debug_assert_eq!(output2.requires_dedicated_allocation, 0);
- out.prefer_dedicated = output2.prefers_dedicated_allocation != 0;
+ (fns.khr_get_memory_requirements2
+ .get_buffer_memory_requirements2_khr)(
+ device.handle(),
+ &info_vk,
+ &mut memory_requirements2_vk,
+ );
}
- out
} else {
- let mut output: MaybeUninit<ash::vk::MemoryRequirements> = MaybeUninit::uninit();
- fns.v1_0.get_buffer_memory_requirements(
- device.internal_object(),
- buffer,
- output.as_mut_ptr(),
- );
- let output = output.assume_init();
- debug_assert!(output.size >= size);
- debug_assert!(output.memory_type_bits != 0);
- MemoryRequirements::from(output)
- };
-
- // We have to manually enforce some additional requirements for some buffer types.
- let properties = device.physical_device().properties();
- if usage.uniform_texel_buffer || usage.storage_texel_buffer {
- output.alignment = align(
- output.alignment,
- properties.min_texel_buffer_offset_alignment,
- );
- }
-
- if usage.storage_buffer {
- output.alignment = align(
- output.alignment,
- properties.min_storage_buffer_offset_alignment,
+ (fns.v1_0.get_buffer_memory_requirements)(
+ device.handle(),
+ handle,
+ &mut memory_requirements2_vk.memory_requirements,
);
}
+ }
- if usage.uniform_buffer {
- output.alignment = align(
- output.alignment,
- properties.min_uniform_buffer_offset_alignment,
- );
- }
+ MemoryRequirements {
+ layout: DeviceLayout::from_size_alignment(
+ memory_requirements2_vk.memory_requirements.size,
+ memory_requirements2_vk.memory_requirements.alignment,
+ )
+ .unwrap(),
+ memory_type_bits: memory_requirements2_vk.memory_requirements.memory_type_bits,
+ prefers_dedicated_allocation: memory_dedicated_requirements_vk
+ .map_or(false, |dreqs| dreqs.prefers_dedicated_allocation != 0),
+ requires_dedicated_allocation: memory_dedicated_requirements_vk
+ .map_or(false, |dreqs| dreqs.requires_dedicated_allocation != 0),
+ }
+ }
- output
- };
+ pub(crate) fn id(&self) -> NonZeroU64 {
+ self.id
+ }
- let obj = UnsafeBuffer {
- buffer,
- device: device.clone(),
- size,
- usage,
- };
+ /// Binds device memory to this buffer.
+ pub fn bind_memory(
+ self,
+ allocation: MemoryAlloc,
+ ) -> Result<Buffer, (BufferError, RawBuffer, MemoryAlloc)> {
+ if let Err(err) = self.validate_bind_memory(&allocation) {
+ return Err((err, self, allocation));
+ }
- Ok((obj, mem_reqs))
+ unsafe { self.bind_memory_unchecked(allocation) }
+ .map_err(|(err, buffer, allocation)| (err.into(), buffer, allocation))
}
- /// Binds device memory to this buffer.
- pub unsafe fn bind_memory(
- &self,
- memory: &DeviceMemory,
- offset: DeviceSize,
- ) -> Result<(), OomError> {
- let fns = self.device.fns();
+ fn validate_bind_memory(&self, allocation: &MemoryAlloc) -> Result<(), BufferError> {
+ assert_ne!(allocation.allocation_type(), AllocationType::NonLinear);
+
+ let memory_requirements = &self.memory_requirements;
+ let memory = allocation.device_memory();
+ let memory_offset = allocation.offset();
+ let memory_type = &self
+ .device
+ .physical_device()
+ .memory_properties()
+ .memory_types[memory.memory_type_index() as usize];
+
+ // VUID-VkBindBufferMemoryInfo-commonparent
+ assert_eq!(self.device(), memory.device());
+
+ // VUID-VkBindBufferMemoryInfo-buffer-07459
+ // Ensured by taking ownership of `RawBuffer`.
+
+ // VUID-VkBindBufferMemoryInfo-buffer-01030
+ // Currently ensured by not having sparse binding flags, but this needs to be checked once
+ // those are enabled.
+
+ // VUID-VkBindBufferMemoryInfo-memoryOffset-01031
+ // Assume that `allocation` was created correctly.
+
+ // VUID-VkBindBufferMemoryInfo-memory-01035
+ if memory_requirements.memory_type_bits & (1 << memory.memory_type_index()) == 0 {
+ return Err(BufferError::MemoryTypeNotAllowed {
+ provided_memory_type_index: memory.memory_type_index(),
+ allowed_memory_type_bits: memory_requirements.memory_type_bits,
+ });
+ }
- // We check for correctness in debug mode.
- debug_assert!({
- let mut mem_reqs = MaybeUninit::uninit();
- fns.v1_0.get_buffer_memory_requirements(
- self.device.internal_object(),
- self.buffer,
- mem_reqs.as_mut_ptr(),
- );
+ // VUID-VkBindBufferMemoryInfo-memoryOffset-01036
+ if !is_aligned(memory_offset, memory_requirements.layout.alignment()) {
+ return Err(BufferError::MemoryAllocationNotAligned {
+ allocation_offset: memory_offset,
+ required_alignment: memory_requirements.layout.alignment(),
+ });
+ }
- let mem_reqs = mem_reqs.assume_init();
- mem_reqs.size <= (memory.size() - offset)
- && (offset % mem_reqs.alignment) == 0
- && mem_reqs.memory_type_bits & (1 << memory.memory_type().id()) != 0
- });
+ // VUID-VkBindBufferMemoryInfo-size-01037
+ if allocation.size() < memory_requirements.layout.size() {
+ return Err(BufferError::MemoryAllocationTooSmall {
+ allocation_size: allocation.size(),
+ required_size: memory_requirements.layout.size(),
+ });
+ }
- // Check for alignment correctness.
- {
- let properties = self.device().physical_device().properties();
- if self.usage().uniform_texel_buffer || self.usage().storage_texel_buffer {
- debug_assert!(offset % properties.min_texel_buffer_offset_alignment == 0);
+ if let Some(dedicated_to) = memory.dedicated_to() {
+ // VUID-VkBindBufferMemoryInfo-memory-01508
+ match dedicated_to {
+ DedicatedTo::Buffer(id) if id == self.id => {}
+ _ => return Err(BufferError::DedicatedAllocationMismatch),
}
- if self.usage().storage_buffer {
- debug_assert!(offset % properties.min_storage_buffer_offset_alignment == 0);
+ debug_assert!(memory_offset == 0); // This should be ensured by the allocator
+ } else {
+ // VUID-VkBindBufferMemoryInfo-buffer-01444
+ if memory_requirements.requires_dedicated_allocation {
+ return Err(BufferError::DedicatedAllocationRequired);
}
- if self.usage().uniform_buffer {
- debug_assert!(offset % properties.min_uniform_buffer_offset_alignment == 0);
+ }
+
+ // VUID-VkBindBufferMemoryInfo-None-01899
+ if memory_type
+ .property_flags
+ .intersects(MemoryPropertyFlags::PROTECTED)
+ {
+ return Err(BufferError::MemoryProtectedMismatch {
+ buffer_protected: false,
+ memory_protected: true,
+ });
+ }
+
+ // VUID-VkBindBufferMemoryInfo-memory-02726
+ if !memory.export_handle_types().is_empty()
+ && !memory
+ .export_handle_types()
+ .intersects(self.external_memory_handle_types)
+ {
+ return Err(BufferError::MemoryExternalHandleTypesDisjoint {
+ buffer_handle_types: self.external_memory_handle_types,
+ memory_export_handle_types: memory.export_handle_types(),
+ });
+ }
+
+ if let Some(handle_type) = memory.imported_handle_type() {
+ // VUID-VkBindBufferMemoryInfo-memory-02985
+ if !ExternalMemoryHandleTypes::from(handle_type)
+ .intersects(self.external_memory_handle_types)
+ {
+ return Err(BufferError::MemoryImportedHandleTypeNotEnabled {
+ buffer_handle_types: self.external_memory_handle_types,
+ memory_imported_handle_type: handle_type,
+ });
}
}
- check_errors(fns.v1_0.bind_buffer_memory(
- self.device.internal_object(),
- self.buffer,
- memory.internal_object(),
- offset,
- ))?;
+ // VUID-VkBindBufferMemoryInfo-bufferDeviceAddress-03339
+ if !self.device.enabled_extensions().ext_buffer_device_address
+ && self.usage.intersects(BufferUsage::SHADER_DEVICE_ADDRESS)
+ && !memory
+ .flags()
+ .intersects(MemoryAllocateFlags::DEVICE_ADDRESS)
+ {
+ return Err(BufferError::MemoryBufferDeviceAddressNotSupported);
+ }
+
Ok(())
}
- /// Returns the size of the buffer in bytes.
- #[inline]
- pub fn size(&self) -> DeviceSize {
- self.size
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn bind_memory_unchecked(
+ self,
+ allocation: MemoryAlloc,
+ ) -> Result<Buffer, (VulkanError, RawBuffer, MemoryAlloc)> {
+ let memory = allocation.device_memory();
+ let memory_offset = allocation.offset();
+
+ let fns = self.device.fns();
+
+ let result = if self.device.api_version() >= Version::V1_1
+ || self.device.enabled_extensions().khr_bind_memory2
+ {
+ let bind_infos_vk = [ash::vk::BindBufferMemoryInfo {
+ buffer: self.handle,
+ memory: memory.handle(),
+ memory_offset,
+ ..Default::default()
+ }];
+
+ if self.device.api_version() >= Version::V1_1 {
+ (fns.v1_1.bind_buffer_memory2)(
+ self.device.handle(),
+ bind_infos_vk.len() as u32,
+ bind_infos_vk.as_ptr(),
+ )
+ } else {
+ (fns.khr_bind_memory2.bind_buffer_memory2_khr)(
+ self.device.handle(),
+ bind_infos_vk.len() as u32,
+ bind_infos_vk.as_ptr(),
+ )
+ }
+ } else {
+ (fns.v1_0.bind_buffer_memory)(
+ self.device.handle(),
+ self.handle,
+ memory.handle(),
+ memory_offset,
+ )
+ }
+ .result();
+
+ if let Err(err) = result {
+ return Err((VulkanError::from(err), self, allocation));
+ }
+
+ Ok(Buffer::from_raw(self, BufferMemory::Normal(allocation)))
}
- /// Returns the buffer the image was created with.
- #[inline]
- pub fn usage(&self) -> BufferUsage {
- self.usage
+ /// Returns the memory requirements for this buffer.
+ pub fn memory_requirements(&self) -> &MemoryRequirements {
+ &self.memory_requirements
}
- /// Returns a key unique to each `UnsafeBuffer`. Can be used for the `conflicts_key` method.
+ /// Returns the flags the buffer was created with.
#[inline]
- pub fn key(&self) -> u64 {
- self.buffer.as_raw()
+ pub fn flags(&self) -> BufferCreateFlags {
+ self.flags
}
-}
-unsafe impl VulkanObject for UnsafeBuffer {
- type Object = ash::vk::Buffer;
+ /// Returns the size of the buffer in bytes.
+ #[inline]
+ pub fn size(&self) -> DeviceSize {
+ self.size
+ }
+ /// Returns the usage the buffer was created with.
#[inline]
- fn internal_object(&self) -> ash::vk::Buffer {
- self.buffer
+ pub fn usage(&self) -> BufferUsage {
+ self.usage
}
-}
-unsafe impl DeviceOwned for UnsafeBuffer {
+ /// Returns the sharing the buffer was created with.
#[inline]
- fn device(&self) -> &Arc<Device> {
- &self.device
+ pub fn sharing(&self) -> &Sharing<SmallVec<[u32; 4]>> {
+ &self.sharing
}
-}
-impl fmt::Debug for UnsafeBuffer {
+ /// Returns the external memory handle types that are supported with this buffer.
#[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(fmt, "<Vulkan buffer {:?}>", self.buffer)
+ pub fn external_memory_handle_types(&self) -> ExternalMemoryHandleTypes {
+ self.external_memory_handle_types
}
}
-impl Drop for UnsafeBuffer {
+impl Drop for RawBuffer {
#[inline]
fn drop(&mut self) {
unsafe {
let fns = self.device.fns();
- fns.v1_0
- .destroy_buffer(self.device.internal_object(), self.buffer, ptr::null());
+ (fns.v1_0.destroy_buffer)(self.device.handle(), self.handle, ptr::null());
}
}
}
-impl PartialEq for UnsafeBuffer {
- #[inline]
- fn eq(&self, other: &Self) -> bool {
- self.buffer == other.buffer && self.device == other.device
- }
-}
-
-impl Eq for UnsafeBuffer {}
+unsafe impl VulkanObject for RawBuffer {
+ type Handle = ash::vk::Buffer;
-impl Hash for UnsafeBuffer {
#[inline]
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.buffer.hash(state);
- self.device.hash(state);
+ fn handle(&self) -> Self::Handle {
+ self.handle
}
}
-/// The level of sparse binding that a buffer should be created with.
-#[derive(Debug, Copy, Clone)]
-pub struct SparseLevel {
- pub sparse_residency: bool,
- pub sparse_aliased: bool,
-}
-
-impl SparseLevel {
+unsafe impl DeviceOwned for RawBuffer {
#[inline]
- pub fn none() -> SparseLevel {
- SparseLevel {
- sparse_residency: false,
- sparse_aliased: false,
- }
+ fn device(&self) -> &Arc<Device> {
+ &self.device
}
}
-impl From<SparseLevel> for ash::vk::BufferCreateFlags {
- #[inline]
- fn from(val: SparseLevel) -> Self {
- let mut result = ash::vk::BufferCreateFlags::SPARSE_BINDING;
- if val.sparse_residency {
- result |= ash::vk::BufferCreateFlags::SPARSE_RESIDENCY;
- }
- if val.sparse_aliased {
- result |= ash::vk::BufferCreateFlags::SPARSE_ALIASED;
- }
- result
- }
-}
+impl_id_counter!(RawBuffer);
-/// The device address usage flag was not set.
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub struct DeviceAddressUsageNotEnabledError;
-impl error::Error for DeviceAddressUsageNotEnabledError {}
-impl fmt::Display for DeviceAddressUsageNotEnabledError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- fmt.write_str("the device address usage flag was not set on this buffer")
- }
-}
+/// Parameters to create a new [`Buffer`].
+#[derive(Clone, Debug)]
+pub struct BufferCreateInfo {
+ /// Flags to enable.
+ ///
+ /// The default value is [`BufferCreateFlags::empty()`].
+ pub flags: BufferCreateFlags,
-/// Error that can happen when creating a buffer.
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum BufferCreationError {
- /// Allocating memory failed.
- AllocError(DeviceMemoryAllocError),
- /// Sparse binding was requested but the corresponding feature wasn't enabled.
- SparseBindingFeatureNotEnabled,
- /// Sparse residency was requested but the corresponding feature wasn't enabled.
- SparseResidencyBufferFeatureNotEnabled,
- /// Sparse aliasing was requested but the corresponding feature wasn't enabled.
- SparseResidencyAliasedFeatureNotEnabled,
- /// Device address was requested but the corresponding feature wasn't enabled.
- DeviceAddressFeatureNotEnabled,
-}
+ /// Whether the buffer can be shared across multiple queues, or is limited to a single queue.
+ ///
+ /// The default value is [`Sharing::Exclusive`].
+ pub sharing: Sharing<SmallVec<[u32; 4]>>,
-impl error::Error for BufferCreationError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- BufferCreationError::AllocError(ref err) => Some(err),
- _ => None,
- }
- }
-}
+ /// The size in bytes of the buffer.
+ ///
+ /// The default value is `0`, which must be overridden.
+ pub size: DeviceSize,
-impl fmt::Display for BufferCreationError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- BufferCreationError::AllocError(_) => "allocating memory failed",
- BufferCreationError::SparseBindingFeatureNotEnabled => {
- "sparse binding was requested but the corresponding feature wasn't enabled"
- }
- BufferCreationError::SparseResidencyBufferFeatureNotEnabled => {
- "sparse residency was requested but the corresponding feature wasn't enabled"
- }
- BufferCreationError::SparseResidencyAliasedFeatureNotEnabled => {
- "sparse aliasing was requested but the corresponding feature wasn't enabled"
- }
- BufferCreationError::DeviceAddressFeatureNotEnabled => {
- "device address was requested but the corresponding feature wasn't enabled"
- }
- }
- )
- }
-}
+ /// How the buffer is going to be used.
+ ///
+ /// The default value is [`BufferUsage::empty()`], which must be overridden.
+ pub usage: BufferUsage,
-impl From<OomError> for BufferCreationError {
- #[inline]
- fn from(err: OomError) -> BufferCreationError {
- BufferCreationError::AllocError(err.into())
- }
+ /// The external memory handle types that are going to be used with the buffer.
+ ///
+ /// If this value is not empty, then the device API version must be at least 1.1, or the
+ /// [`khr_external_memory`] extension must be enabled on the device.
+ ///
+ /// The default value is [`ExternalMemoryHandleTypes::empty()`].
+ ///
+ /// [`khr_external_memory`]: crate::device::DeviceExtensions::khr_external_memory
+ pub external_memory_handle_types: ExternalMemoryHandleTypes,
+
+ pub _ne: crate::NonExhaustive,
}
-impl From<Error> for BufferCreationError {
+impl Default for BufferCreateInfo {
#[inline]
- fn from(err: Error) -> BufferCreationError {
- match err {
- err @ Error::OutOfHostMemory => {
- BufferCreationError::AllocError(DeviceMemoryAllocError::from(err))
- }
- err @ Error::OutOfDeviceMemory => {
- BufferCreationError::AllocError(DeviceMemoryAllocError::from(err))
- }
- _ => panic!("unexpected error: {:?}", err),
+ fn default() -> Self {
+ Self {
+ flags: BufferCreateFlags::empty(),
+ sharing: Sharing::Exclusive,
+ size: 0,
+ usage: BufferUsage::empty(),
+ external_memory_handle_types: ExternalMemoryHandleTypes::empty(),
+ _ne: crate::NonExhaustive(()),
}
}
}
#[cfg(test)]
mod tests {
- use std::iter::Empty;
-
- use super::BufferCreationError;
- use super::BufferUsage;
- use super::SparseLevel;
- use super::UnsafeBuffer;
-
- use crate::device::Device;
- use crate::device::DeviceOwned;
- use crate::sync::Sharing;
+ use super::{BufferCreateInfo, BufferUsage, RawBuffer};
+ use crate::device::{Device, DeviceOwned};
#[test]
fn create() {
let (device, _) = gfx_dev_and_queue!();
- let (buf, reqs) = unsafe {
- UnsafeBuffer::new(
- device.clone(),
- 128,
- BufferUsage::all(),
- Sharing::Exclusive::<Empty<_>>,
- None,
- )
- }
+ let buf = RawBuffer::new(
+ device.clone(),
+ BufferCreateInfo {
+ size: 128,
+ usage: BufferUsage::TRANSFER_DST,
+ ..Default::default()
+ },
+ )
.unwrap();
+ let reqs = buf.memory_requirements();
- assert!(reqs.size >= 128);
+ assert!(reqs.layout.size() >= 128);
assert_eq!(buf.size(), 128);
assert_eq!(&**buf.device() as *const Device, &*device as *const Device);
}
+ /* Re-enable when sparse binding is properly implemented
#[test]
fn missing_feature_sparse_binding() {
let (device, _) = gfx_dev_and_queue!();
- let sparse = Some(SparseLevel::none());
- unsafe {
- match UnsafeBuffer::new(
- device,
- 128,
- BufferUsage::all(),
- Sharing::Exclusive::<Empty<_>>,
- sparse,
- ) {
- Err(BufferCreationError::SparseBindingFeatureNotEnabled) => (),
- _ => panic!(),
- }
- };
+ match RawBuffer::new(
+ device,
+ BufferCreateInfo {
+ size: 128,
+ sparse: Some(BufferCreateFlags::empty()),
+ usage: BufferUsage::transfer_dst,
+ ..Default::default()
+ },
+ ) {
+ Err(BufferError::RequirementNotMet {
+ requires_one_of: RequiresOneOf { features, .. },
+ ..
+ }) if features.contains(&"sparse_binding") => (),
+ _ => panic!(),
+ }
}
#[test]
fn missing_feature_sparse_residency() {
let (device, _) = gfx_dev_and_queue!(sparse_binding);
- let sparse = Some(SparseLevel {
- sparse_residency: true,
- sparse_aliased: false,
- });
- unsafe {
- match UnsafeBuffer::new(
- device,
- 128,
- BufferUsage::all(),
- Sharing::Exclusive::<Empty<_>>,
- sparse,
- ) {
- Err(BufferCreationError::SparseResidencyBufferFeatureNotEnabled) => (),
- _ => panic!(),
- }
- };
+ match RawBuffer::new(
+ device,
+ BufferCreateInfo {
+ size: 128,
+ sparse: Some(BufferCreateFlags {
+ sparse_residency: true,
+ sparse_aliased: false,
+ ..Default::default()
+ }),
+ usage: BufferUsage::transfer_dst,
+ ..Default::default()
+ },
+ ) {
+ Err(BufferError::RequirementNotMet {
+ requires_one_of: RequiresOneOf { features, .. },
+ ..
+ }) if features.contains(&"sparse_residency_buffer") => (),
+ _ => panic!(),
+ }
}
#[test]
fn missing_feature_sparse_aliased() {
let (device, _) = gfx_dev_and_queue!(sparse_binding);
- let sparse = Some(SparseLevel {
- sparse_residency: false,
- sparse_aliased: true,
- });
- unsafe {
- match UnsafeBuffer::new(
- device,
- 128,
- BufferUsage::all(),
- Sharing::Exclusive::<Empty<_>>,
- sparse,
- ) {
- Err(BufferCreationError::SparseResidencyAliasedFeatureNotEnabled) => (),
- _ => panic!(),
- }
- };
+ match RawBuffer::new(
+ device,
+ BufferCreateInfo {
+ size: 128,
+ sparse: Some(BufferCreateFlags {
+ sparse_residency: false,
+ sparse_aliased: true,
+ ..Default::default()
+ }),
+ usage: BufferUsage::transfer_dst,
+ ..Default::default()
+ },
+ ) {
+ Err(BufferError::RequirementNotMet {
+ requires_one_of: RequiresOneOf { features, .. },
+ ..
+ }) if features.contains(&"sparse_residency_aliased") => (),
+ _ => panic!(),
+ }
}
+ */
#[test]
fn create_empty_buffer() {
let (device, _) = gfx_dev_and_queue!();
- unsafe {
- let _ = UnsafeBuffer::new(
+ assert_should_panic!({
+ RawBuffer::new(
device,
- 0,
- BufferUsage::all(),
- Sharing::Exclusive::<Empty<_>>,
- None,
- );
- };
+ BufferCreateInfo {
+ size: 0,
+ usage: BufferUsage::TRANSFER_DST,
+ ..Default::default()
+ },
+ )
+ });
}
}
diff --git a/src/buffer/traits.rs b/src/buffer/traits.rs
deleted file mode 100644
index 9b76b21..0000000
--- a/src/buffer/traits.rs
+++ /dev/null
@@ -1,243 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::buffer::sys::{DeviceAddressUsageNotEnabledError, UnsafeBuffer};
-use crate::buffer::BufferSlice;
-use crate::device::DeviceOwned;
-use crate::device::Queue;
-use crate::memory::Content;
-use crate::sync::AccessError;
-use crate::DeviceSize;
-use crate::{SafeDeref, VulkanObject};
-use std::hash::Hash;
-use std::hash::Hasher;
-use std::num::NonZeroU64;
-use std::ops::Range;
-
-/// Trait for objects that represent a way for the GPU to have access to a buffer or a slice of a
-/// buffer.
-///
-/// See also `TypedBufferAccess`.
-pub unsafe trait BufferAccess: DeviceOwned {
- /// Returns the inner information about this buffer.
- fn inner(&self) -> BufferInner;
-
- /// Returns the size of the buffer in bytes.
- fn size(&self) -> DeviceSize;
-
- /// Builds a `BufferSlice` object holding the buffer by reference.
- #[inline]
- fn as_buffer_slice(&self) -> BufferSlice<Self::Content, &Self>
- where
- Self: Sized + TypedBufferAccess,
- {
- BufferSlice::from_typed_buffer_access(self)
- }
-
- /// Builds a `BufferSlice` object holding part of the buffer by reference.
- ///
- /// This method can only be called for buffers whose type is known to be an array.
- ///
- /// This method can be used when you want to perform an operation on some part of the buffer
- /// and not on the whole buffer.
- ///
- /// Returns `None` if out of range.
- #[inline]
- fn slice<T>(&self, range: Range<DeviceSize>) -> Option<BufferSlice<[T], &Self>>
- where
- Self: Sized + TypedBufferAccess<Content = [T]>,
- {
- BufferSlice::slice(self.as_buffer_slice(), range)
- }
-
- /// Builds a `BufferSlice` object holding the buffer by value.
- #[inline]
- fn into_buffer_slice(self) -> BufferSlice<Self::Content, Self>
- where
- Self: Sized + TypedBufferAccess,
- {
- BufferSlice::from_typed_buffer_access(self)
- }
-
- /// Builds a `BufferSlice` object holding part of the buffer by reference.
- ///
- /// This method can only be called for buffers whose type is known to be an array.
- ///
- /// This method can be used when you want to perform an operation on a specific element of the
- /// buffer and not on the whole buffer.
- ///
- /// Returns `None` if out of range.
- #[inline]
- fn index<T>(&self, index: DeviceSize) -> Option<BufferSlice<[T], &Self>>
- where
- Self: Sized + TypedBufferAccess<Content = [T]>,
- {
- self.slice(index..(index + 1))
- }
-
- /// Returns a key that uniquely identifies the buffer. Two buffers or images that potentially
- /// overlap in memory must return the same key.
- ///
- /// The key is shared amongst all buffers and images, which means that you can make several
- /// different buffer objects share the same memory, or make some buffer objects share memory
- /// with images, as long as they return the same key.
- ///
- /// Since it is possible to accidentally return the same key for memory ranges that don't
- /// overlap, the `conflicts_buffer` or `conflicts_image` function should always be called to
- /// verify whether they actually overlap.
- fn conflict_key(&self) -> (u64, u64);
-
- /// Locks the resource for usage on the GPU. Returns an error if the lock can't be acquired.
- ///
- /// This function exists to prevent the user from causing a data race by reading and writing
- /// to the same resource at the same time.
- ///
- /// If you call this function, you should call `unlock()` once the resource is no longer in use
- /// by the GPU. The implementation is not expected to automatically perform any unlocking and
- /// can rely on the fact that `unlock()` is going to be called.
- fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> Result<(), AccessError>;
-
- /// Locks the resource for usage on the GPU. Supposes that the resource is already locked, and
- /// simply increases the lock by one.
- ///
- /// Must only be called after `try_gpu_lock()` succeeded.
- ///
- /// If you call this function, you should call `unlock()` once the resource is no longer in use
- /// by the GPU. The implementation is not expected to automatically perform any unlocking and
- /// can rely on the fact that `unlock()` is going to be called.
- unsafe fn increase_gpu_lock(&self);
-
- /// Unlocks the resource previously acquired with `try_gpu_lock` or `increase_gpu_lock`.
- ///
- /// # Safety
- ///
- /// Must only be called once per previous lock.
- unsafe fn unlock(&self);
-
- /// Gets the device address for this buffer.
- ///
- /// # Safety
- ///
- /// No lock checking or waiting is performed. This is nevertheless still safe because the
- /// returned value isn't directly dereferencable. Unsafe code is required to dereference the
- /// value in a shader.
- fn raw_device_address(&self) -> Result<NonZeroU64, DeviceAddressUsageNotEnabledError> {
- let inner = self.inner();
-
- if !inner.buffer.usage().device_address {
- return Err(DeviceAddressUsageNotEnabledError);
- }
-
- let dev = self.device();
- unsafe {
- let info = ash::vk::BufferDeviceAddressInfo {
- buffer: inner.buffer.internal_object(),
- ..Default::default()
- };
- let ptr = dev
- .fns()
- .ext_buffer_device_address
- .get_buffer_device_address_ext(dev.internal_object(), &info);
-
- if ptr == 0 {
- panic!("got null ptr from a valid GetBufferDeviceAddressEXT call");
- }
-
- Ok(NonZeroU64::new_unchecked(ptr + inner.offset))
- }
- }
-}
-
-/// Inner information about a buffer.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
-pub struct BufferInner<'a> {
- /// The underlying buffer object.
- pub buffer: &'a UnsafeBuffer,
- /// The offset in bytes from the start of the underlying buffer object to the start of the
- /// buffer we're describing.
- pub offset: DeviceSize,
-}
-
-unsafe impl<T> BufferAccess for T
-where
- T: SafeDeref,
- T::Target: BufferAccess,
-{
- #[inline]
- fn inner(&self) -> BufferInner {
- (**self).inner()
- }
-
- #[inline]
- fn size(&self) -> DeviceSize {
- (**self).size()
- }
-
- #[inline]
- fn conflict_key(&self) -> (u64, u64) {
- (**self).conflict_key()
- }
-
- #[inline]
- fn try_gpu_lock(&self, exclusive_access: bool, queue: &Queue) -> Result<(), AccessError> {
- (**self).try_gpu_lock(exclusive_access, queue)
- }
-
- #[inline]
- unsafe fn increase_gpu_lock(&self) {
- (**self).increase_gpu_lock()
- }
-
- #[inline]
- unsafe fn unlock(&self) {
- (**self).unlock()
- }
-}
-
-/// Extension trait for `BufferAccess`. Indicates the type of the content of the buffer.
-pub unsafe trait TypedBufferAccess: BufferAccess {
- /// The type of the content.
- type Content: ?Sized;
-
- /// Returns the length of the buffer in number of elements.
- ///
- /// This method can only be called for buffers whose type is known to be an array.
- #[inline]
- fn len(&self) -> DeviceSize
- where
- Self::Content: Content,
- {
- self.size() / <Self::Content as Content>::indiv_size()
- }
-}
-
-unsafe impl<T> TypedBufferAccess for T
-where
- T: SafeDeref,
- T::Target: TypedBufferAccess,
-{
- type Content = <T::Target as TypedBufferAccess>::Content;
-}
-
-impl PartialEq for dyn BufferAccess + Send + Sync {
- #[inline]
- fn eq(&self, other: &Self) -> bool {
- self.inner() == other.inner() && self.size() == other.size()
- }
-}
-
-impl Eq for dyn BufferAccess + Send + Sync {}
-
-impl Hash for dyn BufferAccess + Send + Sync {
- #[inline]
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.inner().hash(state);
- self.size().hash(state);
- }
-}
diff --git a/src/buffer/usage.rs b/src/buffer/usage.rs
index 7566012..fc7fa1d 100644
--- a/src/buffer/usage.rs
+++ b/src/buffer/usage.rs
@@ -7,225 +7,143 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use std::ops::BitOr;
-
-/// Describes how a buffer is going to be used. This is **not** just an optimization.
-///
-/// If you try to use a buffer in a way that you didn't declare, a panic will happen.
-///
-/// Some methods are provided to build `BufferUsage` structs for some common situations. However
-/// there is no restriction in the combination of BufferUsages that can be enabled.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct BufferUsage {
- pub transfer_source: bool,
- pub transfer_destination: bool,
- pub uniform_texel_buffer: bool,
- pub storage_texel_buffer: bool,
- pub uniform_buffer: bool,
- pub storage_buffer: bool,
- pub index_buffer: bool,
- pub vertex_buffer: bool,
- pub indirect_buffer: bool,
- /// Requires the `buffer_device_address` feature. If that feature is not enabled, this will
- /// be silently ignored.
- pub device_address: bool,
-}
-
-impl BufferUsage {
- /// Builds a `BufferUsage` with all values set to false.
- #[inline]
- pub const fn none() -> BufferUsage {
- BufferUsage {
- transfer_source: false,
- transfer_destination: false,
- uniform_texel_buffer: false,
- storage_texel_buffer: false,
- uniform_buffer: false,
- storage_buffer: false,
- index_buffer: false,
- vertex_buffer: false,
- indirect_buffer: false,
- device_address: false,
- }
- }
-
- /// Builds a `BufferUsage` with all values set to true. Can be used for quick prototyping.
- #[inline]
- pub const fn all() -> BufferUsage {
- BufferUsage {
- transfer_source: true,
- transfer_destination: true,
- uniform_texel_buffer: true,
- storage_texel_buffer: true,
- uniform_buffer: true,
- storage_buffer: true,
- index_buffer: true,
- vertex_buffer: true,
- indirect_buffer: true,
- device_address: true,
- }
- }
-
- /// Builds a `BufferUsage` with `transfer_source` set to true and the rest to false.
- #[inline]
- pub const fn transfer_source() -> BufferUsage {
- BufferUsage {
- transfer_source: true,
- ..BufferUsage::none()
- }
- }
-
- /// Builds a `BufferUsage` with `transfer_destination` set to true and the rest to false.
- #[inline]
- pub const fn transfer_destination() -> BufferUsage {
- BufferUsage {
- transfer_destination: true,
- ..BufferUsage::none()
- }
- }
-
- /// Builds a `BufferUsage` with `vertex_buffer` set to true and the rest to false.
- #[inline]
- pub const fn vertex_buffer() -> BufferUsage {
- BufferUsage {
- vertex_buffer: true,
- ..BufferUsage::none()
- }
- }
-
- /// Builds a `BufferUsage` with `vertex_buffer` and `transfer_destination` set to true and the rest
- /// to false.
- #[inline]
- pub const fn vertex_buffer_transfer_destination() -> BufferUsage {
- BufferUsage {
- vertex_buffer: true,
- transfer_destination: true,
- ..BufferUsage::none()
- }
- }
-
- /// Builds a `BufferUsage` with `index_buffer` set to true and the rest to false.
- #[inline]
- pub const fn index_buffer() -> BufferUsage {
- BufferUsage {
- index_buffer: true,
- ..BufferUsage::none()
- }
- }
-
- /// Builds a `BufferUsage` with `index_buffer` and `transfer_destination` set to true and the rest to false.
- #[inline]
- pub const fn index_buffer_transfer_destination() -> BufferUsage {
- BufferUsage {
- index_buffer: true,
- transfer_destination: true,
- ..BufferUsage::none()
- }
- }
-
- /// Builds a `BufferUsage` with `uniform_buffer` set to true and the rest to false.
- #[inline]
- pub const fn uniform_buffer() -> BufferUsage {
- BufferUsage {
- uniform_buffer: true,
- ..BufferUsage::none()
- }
- }
-
- /// Builds a `BufferUsage` with `uniform_buffer` and `transfer_destination` set to true and the rest
- /// to false.
- #[inline]
- pub const fn uniform_buffer_transfer_destination() -> BufferUsage {
- BufferUsage {
- uniform_buffer: true,
- transfer_destination: true,
- ..BufferUsage::none()
- }
- }
-
- /// Builds a `BufferUsage` with `indirect_buffer` set to true and the rest to false.
- #[inline]
- pub const fn indirect_buffer() -> BufferUsage {
- BufferUsage {
- indirect_buffer: true,
- ..BufferUsage::none()
- }
- }
-
- /// Builds a `BufferUsage` with `indirect_buffer` and `transfer_destination` set to true and the rest
- /// to false.
- #[inline]
- pub const fn indirect_buffer_transfer_destination() -> BufferUsage {
- BufferUsage {
- indirect_buffer: true,
- transfer_destination: true,
- ..BufferUsage::none()
- }
- }
-
- /// Builds a `BufferUsage` with `device_address` set to true and the rest to false.
- #[inline]
- pub const fn device_address() -> BufferUsage {
- BufferUsage {
- device_address: true,
- ..BufferUsage::none()
- }
- }
-}
-
-impl From<BufferUsage> for ash::vk::BufferUsageFlags {
- fn from(val: BufferUsage) -> Self {
- let mut result = ash::vk::BufferUsageFlags::empty();
- if val.transfer_source {
- result |= ash::vk::BufferUsageFlags::TRANSFER_SRC;
- }
- if val.transfer_destination {
- result |= ash::vk::BufferUsageFlags::TRANSFER_DST;
- }
- if val.uniform_texel_buffer {
- result |= ash::vk::BufferUsageFlags::UNIFORM_TEXEL_BUFFER;
- }
- if val.storage_texel_buffer {
- result |= ash::vk::BufferUsageFlags::STORAGE_TEXEL_BUFFER;
- }
- if val.uniform_buffer {
- result |= ash::vk::BufferUsageFlags::UNIFORM_BUFFER;
- }
- if val.storage_buffer {
- result |= ash::vk::BufferUsageFlags::STORAGE_BUFFER;
- }
- if val.index_buffer {
- result |= ash::vk::BufferUsageFlags::INDEX_BUFFER;
- }
- if val.vertex_buffer {
- result |= ash::vk::BufferUsageFlags::VERTEX_BUFFER;
- }
- if val.indirect_buffer {
- result |= ash::vk::BufferUsageFlags::INDIRECT_BUFFER;
- }
- if val.device_address {
- result |= ash::vk::BufferUsageFlags::SHADER_DEVICE_ADDRESS;
- }
- result
- }
-}
-
-impl BitOr for BufferUsage {
- type Output = Self;
-
- #[inline]
- fn bitor(self, rhs: Self) -> Self {
- BufferUsage {
- transfer_source: self.transfer_source || rhs.transfer_source,
- transfer_destination: self.transfer_destination || rhs.transfer_destination,
- uniform_texel_buffer: self.uniform_texel_buffer || rhs.uniform_texel_buffer,
- storage_texel_buffer: self.storage_texel_buffer || rhs.storage_texel_buffer,
- uniform_buffer: self.uniform_buffer || rhs.uniform_buffer,
- storage_buffer: self.storage_buffer || rhs.storage_buffer,
- index_buffer: self.index_buffer || rhs.index_buffer,
- vertex_buffer: self.vertex_buffer || rhs.vertex_buffer,
- indirect_buffer: self.indirect_buffer || rhs.indirect_buffer,
- device_address: self.device_address || rhs.device_address,
- }
- }
+use crate::macros::vulkan_bitflags;
+
+vulkan_bitflags! {
+ #[non_exhaustive]
+
+ /// Describes how a buffer is going to be used. This is **not** just an optimization.
+ ///
+ /// If you try to use a buffer in a way that you didn't declare, an error will be returned.
+ BufferUsage = BufferUsageFlags(u32);
+
+ /// The buffer can be used as a source for transfer, blit, resolve and clear commands.
+ TRANSFER_SRC = TRANSFER_SRC,
+
+ /// The buffer can be used as a destination for transfer, blit, resolve and clear commands.
+ TRANSFER_DST = TRANSFER_DST,
+
+ /// The buffer can be used as a uniform texel buffer in a descriptor set.
+ UNIFORM_TEXEL_BUFFER = UNIFORM_TEXEL_BUFFER,
+
+ /// The buffer can be used as a storage texel buffer in a descriptor set.
+ STORAGE_TEXEL_BUFFER = STORAGE_TEXEL_BUFFER,
+
+ /// The buffer can be used as a uniform buffer in a descriptor set.
+ UNIFORM_BUFFER = UNIFORM_BUFFER,
+
+ /// The buffer can be used as a storage buffer in a descriptor set.
+ STORAGE_BUFFER = STORAGE_BUFFER,
+
+ /// The buffer can be used as an index buffer.
+ INDEX_BUFFER = INDEX_BUFFER,
+
+ /// The buffer can be used as a vertex or instance buffer.
+ VERTEX_BUFFER = VERTEX_BUFFER,
+
+ /// The buffer can be used as an indirect buffer.
+ INDIRECT_BUFFER = INDIRECT_BUFFER,
+
+ /// The buffer's device address can be retrieved.
+ ///
+ /// A buffer created with this usage can only be bound to device memory allocated with the
+ /// [`MemoryAllocateFlags::DEVICE_ADDRESS`] flag, unless the [`ext_buffer_device_address`]
+ /// extension is enabled on the device.
+ ///
+ /// [`MemoryAllocateFlags::DEVICE_ADDRESS`]: crate::memory::MemoryAllocateFlags::DEVICE_ADDRESS
+ /// [`ext_buffer_device_address`]: crate::device::DeviceExtensions::ext_buffer_device_address
+ SHADER_DEVICE_ADDRESS = SHADER_DEVICE_ADDRESS {
+ api_version: V1_2,
+ device_extensions: [khr_buffer_device_address, ext_buffer_device_address],
+ },
+
+ /* TODO: enable
+ // TODO: document
+ VIDEO_DECODE_SRC = VIDEO_DECODE_SRC_KHR {
+ device_extensions: [khr_video_decode_queue],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ VIDEO_DECODE_DST = VIDEO_DECODE_DST_KHR {
+ device_extensions: [khr_video_decode_queue],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ TRANSFORM_FEEDBACK_BUFFER = TRANSFORM_FEEDBACK_BUFFER_EXT {
+ device_extensions: [ext_transform_feedback],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ TRANSFORM_FEEDBACK_COUNTER_BUFFER = TRANSFORM_FEEDBACK_COUNTER_BUFFER_EXT {
+ device_extensions: [ext_transform_feedback],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ CONDITIONAL_RENDERING = CONDITIONAL_RENDERING_EXT {
+ device_extensions: [ext_conditional_rendering],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_KHR = ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_KHR {
+ device_extensions: [khr_acceleration_structure],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ ACCELERATION_STRUCTURE_STORAGE = ACCELERATION_STRUCTURE_STORAGE_KHR {
+ device_extensions: [khr_acceleration_structure],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ SHADER_BINDING_TABLE = SHADER_BINDING_TABLE_KHR {
+ device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ VIDEO_ENCODE_DST = VIDEO_ENCODE_DST_KHR {
+ device_extensions: [khr_video_encode_queue],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ VIDEO_ENCODE_SRC = VIDEO_ENCODE_SRC_KHR {
+ device_extensions: [khr_video_encode_queue],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ SAMPLER_DESCRIPTOR_BUFFER = SAMPLER_DESCRIPTOR_BUFFER_EXT {
+ device_extensions: [ext_descriptor_buffer],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ RESOURCE_DESCRIPTOR_BUFFER = RESOURCE_DESCRIPTOR_BUFFER_EXT {
+ device_extensions: [ext_descriptor_buffer],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ PUSH_DESCRIPTORS_DESCRIPTOR_BUFFER = PUSH_DESCRIPTORS_DESCRIPTOR_BUFFER_EXT {
+ device_extensions: [ext_descriptor_buffer],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ MICROMAP_BUILD_INPUT_READ_ONLY = MICROMAP_BUILD_INPUT_READ_ONLY_EXT {
+ device_extensions: [ext_opacity_micromap],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ MICROMAP_STORAGE = MICROMAP_STORAGE_EXT {
+ device_extensions: [ext_opacity_micromap],
+ },*/
}
diff --git a/src/buffer/view.rs b/src/buffer/view.rs
index bf885c2..3b1f4f4 100644
--- a/src/buffer/view.rs
+++ b/src/buffer/view.rs
@@ -15,269 +15,315 @@
//! In order to create a view from a buffer, the buffer must have been created with either the
//! `uniform_texel_buffer` or the `storage_texel_buffer` usage.
//!
-//! # Example
+//! # Examples
//!
//! ```
//! # use std::sync::Arc;
-//! use vulkano::buffer::immutable::ImmutableBuffer;
-//! use vulkano::buffer::BufferUsage;
-//! use vulkano::buffer::BufferView;
+//! use vulkano::buffer::{Buffer, BufferCreateInfo, BufferUsage};
+//! use vulkano::buffer::view::{BufferView, BufferViewCreateInfo};
//! use vulkano::format::Format;
+//! use vulkano::memory::allocator::AllocationCreateInfo;
//!
-//! # let device: Arc<vulkano::device::Device> = return;
//! # let queue: Arc<vulkano::device::Queue> = return;
-//! let usage = BufferUsage {
-//! storage_texel_buffer: true,
-//! .. BufferUsage::none()
-//! };
+//! # let memory_allocator: vulkano::memory::allocator::StandardMemoryAllocator = return;
+//! let buffer = Buffer::new_slice::<u32>(
+//! &memory_allocator,
+//! BufferCreateInfo {
+//! usage: BufferUsage::STORAGE_TEXEL_BUFFER,
+//! ..Default::default()
+//! },
+//! AllocationCreateInfo::default(),
+//! 128,
+//! )
+//! .unwrap();
//!
-//! let (buffer, _future) = ImmutableBuffer::<[u32]>::from_iter((0..128).map(|n| n), usage,
-//! queue.clone()).unwrap();
-//! let _view = BufferView::new(buffer, Format::R32Uint).unwrap();
+//! let view = BufferView::new(
+//! buffer,
+//! BufferViewCreateInfo {
+//! format: Some(Format::R32_UINT),
+//! ..Default::default()
+//! },
+//! )
+//! .unwrap();
//! ```
-use crate::buffer::BufferAccess;
-use crate::buffer::BufferInner;
-use crate::buffer::TypedBufferAccess;
-use crate::check_errors;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::format::Format;
-use crate::format::Pixel;
-use crate::Error;
-use crate::OomError;
-use crate::SafeDeref;
-use crate::VulkanObject;
-use std::error;
-use std::fmt;
-use std::mem::MaybeUninit;
-use std::ptr;
-use std::sync::Arc;
+use super::{BufferUsage, Subbuffer};
+use crate::{
+ device::{Device, DeviceOwned},
+ format::{Format, FormatFeatures},
+ macros::impl_id_counter,
+ memory::{is_aligned, DeviceAlignment},
+ DeviceSize, OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject,
+};
+use std::{
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+ mem::MaybeUninit,
+ num::NonZeroU64,
+ ops::Range,
+ ptr,
+ sync::Arc,
+};
/// Represents a way for the GPU to interpret buffer data. See the documentation of the
/// `view` module.
-pub struct BufferView<B>
-where
- B: BufferAccess,
-{
- view: ash::vk::BufferView,
- buffer: B,
- atomic_accesses: bool,
+#[derive(Debug)]
+pub struct BufferView {
+ handle: ash::vk::BufferView,
+ subbuffer: Subbuffer<[u8]>,
+ id: NonZeroU64,
+
+ format: Option<Format>,
+ format_features: FormatFeatures,
+ range: Range<DeviceSize>,
}
-impl<B> BufferView<B>
-where
- B: BufferAccess,
-{
- /// Builds a new buffer view.
+impl BufferView {
+ /// Creates a new `BufferView`.
#[inline]
- pub fn new<Px>(buffer: B, format: Format) -> Result<BufferView<B>, BufferViewCreationError>
- where
- B: TypedBufferAccess<Content = [Px]>,
- Px: Pixel,
- {
- unsafe { BufferView::unchecked(buffer, format) }
+ pub fn new(
+ subbuffer: Subbuffer<impl ?Sized>,
+ create_info: BufferViewCreateInfo,
+ ) -> Result<Arc<BufferView>, BufferViewCreationError> {
+ Self::new_inner(subbuffer.into_bytes(), create_info)
}
- /// Builds a new buffer view without checking that the format is correct.
- pub unsafe fn unchecked(
- org_buffer: B,
- format: Format,
- ) -> Result<BufferView<B>, BufferViewCreationError>
- where
- B: BufferAccess,
- {
- let (view, format_props) = {
- let size = org_buffer.size();
- let BufferInner { buffer, offset } = org_buffer.inner();
-
- let device = buffer.device();
-
- if (offset
- % device
- .physical_device()
- .properties()
- .min_texel_buffer_offset_alignment)
- != 0
- {
- return Err(BufferViewCreationError::WrongBufferAlignment);
- }
+ fn new_inner(
+ subbuffer: Subbuffer<[u8]>,
+ create_info: BufferViewCreateInfo,
+ ) -> Result<Arc<BufferView>, BufferViewCreationError> {
+ let BufferViewCreateInfo { format, _ne: _ } = create_info;
+
+ let buffer = subbuffer.buffer();
+ let device = buffer.device();
+ let properties = device.physical_device().properties();
+ let size = subbuffer.size();
+ let offset = subbuffer.offset();
+
+ // No VUID, but seems sensible?
+ let format = format.unwrap();
+
+ // VUID-VkBufferViewCreateInfo-format-parameter
+ format.validate_device(device)?;
+
+ // VUID-VkBufferViewCreateInfo-buffer-00932
+ if !buffer
+ .usage()
+ .intersects(BufferUsage::UNIFORM_TEXEL_BUFFER | BufferUsage::STORAGE_TEXEL_BUFFER)
+ {
+ return Err(BufferViewCreationError::BufferMissingUsage);
+ }
- if !buffer.usage().uniform_texel_buffer && !buffer.usage().storage_texel_buffer {
- return Err(BufferViewCreationError::WrongBufferUsage);
- }
+ // Use unchecked, because all validation has been done above.
+ let format_features = unsafe {
+ device
+ .physical_device()
+ .format_properties_unchecked(format)
+ .buffer_features
+ };
+
+ // VUID-VkBufferViewCreateInfo-buffer-00933
+ if buffer.usage().intersects(BufferUsage::UNIFORM_TEXEL_BUFFER)
+ && !format_features.intersects(FormatFeatures::UNIFORM_TEXEL_BUFFER)
+ {
+ return Err(BufferViewCreationError::UnsupportedFormat);
+ }
+
+ // VUID-VkBufferViewCreateInfo-buffer-00934
+ if buffer.usage().intersects(BufferUsage::STORAGE_TEXEL_BUFFER)
+ && !format_features.intersects(FormatFeatures::STORAGE_TEXEL_BUFFER)
+ {
+ return Err(BufferViewCreationError::UnsupportedFormat);
+ }
+
+ let block_size = format.block_size().unwrap();
+ let texels_per_block = format.texels_per_block();
+
+ // VUID-VkBufferViewCreateInfo-range-00929
+ if size % block_size != 0 {
+ return Err(BufferViewCreationError::RangeNotAligned {
+ range: size,
+ required_alignment: block_size,
+ });
+ }
- {
- let nb = size
- / format
- .size()
- .expect("Can't use a compressed format for buffer views");
- let l = device
- .physical_device()
- .properties()
- .max_texel_buffer_elements;
-
- if nb as u32 > l {
- return Err(BufferViewCreationError::MaxTexelBufferElementsExceeded);
+ // VUID-VkBufferViewCreateInfo-range-00930
+ if ((size / block_size) * texels_per_block as DeviceSize) as u32
+ > properties.max_texel_buffer_elements
+ {
+ return Err(BufferViewCreationError::MaxTexelBufferElementsExceeded);
+ }
+
+ if device.api_version() >= Version::V1_3 || device.enabled_features().texel_buffer_alignment
+ {
+ let element_size = DeviceAlignment::new(if block_size % 3 == 0 {
+ block_size / 3
+ } else {
+ block_size
+ })
+ .unwrap();
+
+ if buffer.usage().intersects(BufferUsage::STORAGE_TEXEL_BUFFER) {
+ let mut required_alignment = properties
+ .storage_texel_buffer_offset_alignment_bytes
+ .unwrap();
+
+ if properties
+ .storage_texel_buffer_offset_single_texel_alignment
+ .unwrap()
+ {
+ required_alignment = required_alignment.min(element_size);
}
- }
- let format_props = {
- let fns_i = device.instance().fns();
- let mut output = MaybeUninit::uninit();
- fns_i.v1_0.get_physical_device_format_properties(
- device.physical_device().internal_object(),
- format.into(),
- output.as_mut_ptr(),
- );
- output.assume_init().buffer_features
- };
-
- if buffer.usage().uniform_texel_buffer {
- if (format_props & ash::vk::FormatFeatureFlags::UNIFORM_TEXEL_BUFFER).is_empty() {
- return Err(BufferViewCreationError::UnsupportedFormat);
+ // VUID-VkBufferViewCreateInfo-buffer-02750
+ if !is_aligned(offset, required_alignment) {
+ return Err(BufferViewCreationError::OffsetNotAligned {
+ offset,
+ required_alignment,
+ });
}
}
- if buffer.usage().storage_texel_buffer {
- if (format_props & ash::vk::FormatFeatureFlags::STORAGE_TEXEL_BUFFER).is_empty() {
- return Err(BufferViewCreationError::UnsupportedFormat);
+ if buffer.usage().intersects(BufferUsage::UNIFORM_TEXEL_BUFFER) {
+ let mut required_alignment = properties
+ .uniform_texel_buffer_offset_alignment_bytes
+ .unwrap();
+
+ if properties
+ .uniform_texel_buffer_offset_single_texel_alignment
+ .unwrap()
+ {
+ required_alignment = required_alignment.min(element_size);
+ }
+
+ // VUID-VkBufferViewCreateInfo-buffer-02751
+ if !is_aligned(offset, required_alignment) {
+ return Err(BufferViewCreationError::OffsetNotAligned {
+ offset,
+ required_alignment,
+ });
}
}
+ } else {
+ let required_alignment = properties.min_texel_buffer_offset_alignment;
+
+ // VUID-VkBufferViewCreateInfo-offset-02749
+ if !is_aligned(offset, required_alignment) {
+ return Err(BufferViewCreationError::OffsetNotAligned {
+ offset,
+ required_alignment,
+ });
+ }
+ }
- let infos = ash::vk::BufferViewCreateInfo {
- flags: ash::vk::BufferViewCreateFlags::empty(),
- buffer: buffer.internal_object(),
- format: format.into(),
- offset,
- range: size,
- ..Default::default()
- };
+ let create_info = ash::vk::BufferViewCreateInfo {
+ flags: ash::vk::BufferViewCreateFlags::empty(),
+ buffer: buffer.handle(),
+ format: format.into(),
+ offset,
+ range: size,
+ ..Default::default()
+ };
+ let handle = unsafe {
let fns = device.fns();
let mut output = MaybeUninit::uninit();
- check_errors(fns.v1_0.create_buffer_view(
- device.internal_object(),
- &infos,
+ (fns.v1_0.create_buffer_view)(
+ device.handle(),
+ &create_info,
ptr::null(),
output.as_mut_ptr(),
- ))?;
- (output.assume_init(), format_props)
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+ output.assume_init()
};
- Ok(BufferView {
- view,
- buffer: org_buffer,
- atomic_accesses: !(format_props
- & ash::vk::FormatFeatureFlags::STORAGE_TEXEL_BUFFER_ATOMIC)
- .is_empty(),
- })
+ Ok(Arc::new(BufferView {
+ handle,
+ subbuffer,
+ id: Self::next_id(),
+ format: Some(format),
+ format_features,
+ range: 0..size,
+ }))
}
/// Returns the buffer associated to this view.
#[inline]
- pub fn buffer(&self) -> &B {
- &self.buffer
- }
-
- /// Returns true if the buffer view can be used as a uniform texel buffer.
- #[inline]
- pub fn uniform_texel_buffer(&self) -> bool {
- self.buffer.inner().buffer.usage().uniform_texel_buffer
- }
-
- /// Returns true if the buffer view can be used as a storage texel buffer.
- #[inline]
- pub fn storage_texel_buffer(&self) -> bool {
- self.buffer.inner().buffer.usage().storage_texel_buffer
+ pub fn buffer(&self) -> &Subbuffer<[u8]> {
+ &self.subbuffer
}
- /// Returns true if the buffer view can be used as a storage texel buffer with atomic accesses.
+ /// Returns the format of this view.
#[inline]
- pub fn storage_texel_buffer_atomic(&self) -> bool {
- self.atomic_accesses && self.storage_texel_buffer()
+ pub fn format(&self) -> Option<Format> {
+ self.format
}
-}
-
-unsafe impl<B> VulkanObject for BufferView<B>
-where
- B: BufferAccess,
-{
- type Object = ash::vk::BufferView;
+ /// Returns the features supported by this view’s format.
#[inline]
- fn internal_object(&self) -> ash::vk::BufferView {
- self.view
+ pub fn format_features(&self) -> FormatFeatures {
+ self.format_features
}
-}
-unsafe impl<B> DeviceOwned for BufferView<B>
-where
- B: BufferAccess,
-{
+ /// Returns the byte range of the wrapped buffer that this view exposes.
#[inline]
- fn device(&self) -> &Arc<Device> {
- self.buffer.device()
- }
-}
-
-impl<B> fmt::Debug for BufferView<B>
-where
- B: BufferAccess + fmt::Debug,
-{
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- fmt.debug_struct("BufferView")
- .field("raw", &self.view)
- .field("buffer", &self.buffer)
- .finish()
+ pub fn range(&self) -> Range<DeviceSize> {
+ self.range.clone()
}
}
-impl<B> Drop for BufferView<B>
-where
- B: BufferAccess,
-{
+impl Drop for BufferView {
#[inline]
fn drop(&mut self) {
unsafe {
- let fns = self.buffer.inner().buffer.device().fns();
- fns.v1_0.destroy_buffer_view(
- self.buffer.inner().buffer.device().internal_object(),
- self.view,
+ let fns = self.subbuffer.device().fns();
+ (fns.v1_0.destroy_buffer_view)(
+ self.subbuffer.device().handle(),
+ self.handle,
ptr::null(),
);
}
}
}
-pub unsafe trait BufferViewRef {
- type BufferAccess: BufferAccess;
+unsafe impl VulkanObject for BufferView {
+ type Handle = ash::vk::BufferView;
- fn view(&self) -> &BufferView<Self::BufferAccess>;
+ #[inline]
+ fn handle(&self) -> Self::Handle {
+ self.handle
+ }
}
-unsafe impl<B> BufferViewRef for BufferView<B>
-where
- B: BufferAccess,
-{
- type BufferAccess = B;
-
+unsafe impl DeviceOwned for BufferView {
#[inline]
- fn view(&self) -> &BufferView<B> {
- self
+ fn device(&self) -> &Arc<Device> {
+ self.subbuffer.device()
}
}
-unsafe impl<T, B> BufferViewRef for T
-where
- T: SafeDeref<Target = BufferView<B>>,
- B: BufferAccess,
-{
- type BufferAccess = B;
+impl_id_counter!(BufferView);
+
+/// Parameters to create a new `BufferView`.
+#[derive(Clone, Debug)]
+pub struct BufferViewCreateInfo {
+ /// The format of the buffer view.
+ ///
+ /// The default value is `None`, which must be overridden.
+ pub format: Option<Format>,
+
+ pub _ne: crate::NonExhaustive,
+}
+impl Default for BufferViewCreateInfo {
#[inline]
- fn view(&self) -> &BufferView<B> {
- &**self
+ fn default() -> Self {
+ Self {
+ format: None,
+ _ne: crate::NonExhaustive(()),
+ }
}
}
@@ -287,170 +333,242 @@ pub enum BufferViewCreationError {
/// Out of memory.
OomError(OomError),
- /// The buffer was not creating with one of the `storage_texel_buffer` or
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+
+ /// The buffer was not created with one of the `storage_texel_buffer` or
/// `uniform_texel_buffer` usages.
- WrongBufferUsage,
+ BufferMissingUsage,
- /// The offset within the buffer is not a multiple of the `min_texel_buffer_offset_alignment`
- /// limit.
- WrongBufferAlignment,
+ /// The offset within the buffer is not a multiple of the required alignment.
+ OffsetNotAligned {
+ offset: DeviceSize,
+ required_alignment: DeviceAlignment,
+ },
+
+ /// The range within the buffer is not a multiple of the required alignment.
+ RangeNotAligned {
+ range: DeviceSize,
+ required_alignment: DeviceSize,
+ },
/// The requested format is not supported for this usage.
UnsupportedFormat,
- /// The maximum number of elements in the buffer view has been exceeded.
+ /// The `max_texel_buffer_elements` limit has been exceeded.
MaxTexelBufferElementsExceeded,
}
-impl error::Error for BufferViewCreationError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- BufferViewCreationError::OomError(ref err) => Some(err),
+impl Error for BufferViewCreationError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ BufferViewCreationError::OomError(err) => Some(err),
_ => None,
}
}
}
-impl fmt::Display for BufferViewCreationError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- BufferViewCreationError::OomError(_) => "out of memory when creating buffer view",
- BufferViewCreationError::WrongBufferUsage => {
- "the buffer is missing correct usage flags"
- }
- BufferViewCreationError::WrongBufferAlignment => {
- "the offset within the buffer is not a multiple of the
- `min_texel_buffer_offset_alignment` limit"
- }
- BufferViewCreationError::UnsupportedFormat => {
- "the requested format is not supported for this usage"
- }
- BufferViewCreationError::MaxTexelBufferElementsExceeded => {
- "the maximum number of texel elements is exceeded"
- }
+impl Display for BufferViewCreationError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::OomError(_) => write!(f, "out of memory when creating buffer view"),
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ Self::BufferMissingUsage => write!(
+ f,
+ "the buffer was not created with one of the `storage_texel_buffer` or \
+ `uniform_texel_buffer` usages",
+ ),
+ Self::OffsetNotAligned { .. } => write!(
+ f,
+ "the offset within the buffer is not a multiple of the required alignment",
+ ),
+ Self::RangeNotAligned { .. } => write!(
+ f,
+ "the range within the buffer is not a multiple of the required alignment",
+ ),
+ Self::UnsupportedFormat => {
+ write!(f, "the requested format is not supported for this usage")
}
- )
+ Self::MaxTexelBufferElementsExceeded => {
+ write!(f, "the `max_texel_buffer_elements` limit has been exceeded")
+ }
+ }
}
}
impl From<OomError> for BufferViewCreationError {
- #[inline]
- fn from(err: OomError) -> BufferViewCreationError {
- BufferViewCreationError::OomError(err)
+ fn from(err: OomError) -> Self {
+ Self::OomError(err)
}
}
-impl From<Error> for BufferViewCreationError {
- #[inline]
- fn from(err: Error) -> BufferViewCreationError {
+impl From<VulkanError> for BufferViewCreationError {
+ fn from(err: VulkanError) -> Self {
OomError::from(err).into()
}
}
+impl From<RequirementNotMet> for BufferViewCreationError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
+ }
+ }
+}
+
#[cfg(test)]
mod tests {
- use crate::buffer::immutable::ImmutableBuffer;
- use crate::buffer::view::BufferViewCreationError;
- use crate::buffer::BufferUsage;
- use crate::buffer::BufferView;
- use crate::format::Format;
+ use super::{BufferView, BufferViewCreateInfo, BufferViewCreationError};
+ use crate::{
+ buffer::{Buffer, BufferCreateInfo, BufferUsage},
+ format::Format,
+ memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
+ };
#[test]
fn create_uniform() {
// `VK_FORMAT_R8G8B8A8_UNORM` guaranteed to be a supported format
- let (device, queue) = gfx_dev_and_queue!();
-
- let usage = BufferUsage {
- uniform_texel_buffer: true,
- ..BufferUsage::none()
- };
+ let (device, _) = gfx_dev_and_queue!();
+ let memory_allocator = StandardMemoryAllocator::new_default(device);
- let (buffer, _) =
- ImmutableBuffer::<[[u8; 4]]>::from_iter((0..128).map(|_| [0; 4]), usage, queue.clone())
- .unwrap();
- let view = BufferView::new(buffer, Format::R8G8B8A8Unorm).unwrap();
-
- assert!(view.uniform_texel_buffer());
+ let buffer = Buffer::new_slice::<[u8; 4]>(
+ &memory_allocator,
+ BufferCreateInfo {
+ usage: BufferUsage::UNIFORM_TEXEL_BUFFER,
+ ..Default::default()
+ },
+ AllocationCreateInfo {
+ usage: MemoryUsage::Upload,
+ ..Default::default()
+ },
+ 128,
+ )
+ .unwrap();
+ BufferView::new(
+ buffer,
+ BufferViewCreateInfo {
+ format: Some(Format::R8G8B8A8_UNORM),
+ ..Default::default()
+ },
+ )
+ .unwrap();
}
#[test]
fn create_storage() {
// `VK_FORMAT_R8G8B8A8_UNORM` guaranteed to be a supported format
- let (device, queue) = gfx_dev_and_queue!();
+ let (device, _) = gfx_dev_and_queue!();
+ let memory_allocator = StandardMemoryAllocator::new_default(device);
- let usage = BufferUsage {
- storage_texel_buffer: true,
- ..BufferUsage::none()
- };
-
- let (buffer, _) =
- ImmutableBuffer::<[[u8; 4]]>::from_iter((0..128).map(|_| [0; 4]), usage, queue.clone())
- .unwrap();
- let view = BufferView::new(buffer, Format::R8G8B8A8Unorm).unwrap();
-
- assert!(view.storage_texel_buffer());
+ let buffer = Buffer::new_slice::<[u8; 4]>(
+ &memory_allocator,
+ BufferCreateInfo {
+ usage: BufferUsage::STORAGE_TEXEL_BUFFER,
+ ..Default::default()
+ },
+ AllocationCreateInfo::default(),
+ 128,
+ )
+ .unwrap();
+ BufferView::new(
+ buffer,
+ BufferViewCreateInfo {
+ format: Some(Format::R8G8B8A8_UNORM),
+ ..Default::default()
+ },
+ )
+ .unwrap();
}
#[test]
fn create_storage_atomic() {
// `VK_FORMAT_R32_UINT` guaranteed to be a supported format for atomics
- let (device, queue) = gfx_dev_and_queue!();
-
- let usage = BufferUsage {
- storage_texel_buffer: true,
- ..BufferUsage::none()
- };
-
- let (buffer, _) =
- ImmutableBuffer::<[u32]>::from_iter((0..128).map(|_| 0), usage, queue.clone()).unwrap();
- let view = BufferView::new(buffer, Format::R32Uint).unwrap();
+ let (device, _) = gfx_dev_and_queue!();
+ let memory_allocator = StandardMemoryAllocator::new_default(device);
- assert!(view.storage_texel_buffer());
- assert!(view.storage_texel_buffer_atomic());
+ let buffer = Buffer::new_slice::<u32>(
+ &memory_allocator,
+ BufferCreateInfo {
+ usage: BufferUsage::STORAGE_TEXEL_BUFFER,
+ ..Default::default()
+ },
+ AllocationCreateInfo::default(),
+ 128,
+ )
+ .unwrap();
+ BufferView::new(
+ buffer,
+ BufferViewCreateInfo {
+ format: Some(Format::R32_UINT),
+ ..Default::default()
+ },
+ )
+ .unwrap();
}
#[test]
fn wrong_usage() {
// `VK_FORMAT_R8G8B8A8_UNORM` guaranteed to be a supported format
- let (device, queue) = gfx_dev_and_queue!();
+ let (device, _) = gfx_dev_and_queue!();
+ let memory_allocator = StandardMemoryAllocator::new_default(device);
- let (buffer, _) = ImmutableBuffer::<[[u8; 4]]>::from_iter(
- (0..128).map(|_| [0; 4]),
- BufferUsage::none(),
- queue.clone(),
+ let buffer = Buffer::new_slice::<[u8; 4]>(
+ &memory_allocator,
+ BufferCreateInfo {
+ usage: BufferUsage::TRANSFER_DST, // Dummy value
+ ..Default::default()
+ },
+ AllocationCreateInfo::default(),
+ 128,
)
.unwrap();
- match BufferView::new(buffer, Format::R8G8B8A8Unorm) {
- Err(BufferViewCreationError::WrongBufferUsage) => (),
+ match BufferView::new(
+ buffer,
+ BufferViewCreateInfo {
+ format: Some(Format::R8G8B8A8_UNORM),
+ ..Default::default()
+ },
+ ) {
+ Err(BufferViewCreationError::BufferMissingUsage) => (),
_ => panic!(),
}
}
#[test]
fn unsupported_format() {
- let (device, queue) = gfx_dev_and_queue!();
-
- let usage = BufferUsage {
- uniform_texel_buffer: true,
- storage_texel_buffer: true,
- ..BufferUsage::none()
- };
+ let (device, _) = gfx_dev_and_queue!();
+ let memory_allocator = StandardMemoryAllocator::new_default(device);
- let (buffer, _) = ImmutableBuffer::<[[f64; 4]]>::from_iter(
- (0..128).map(|_| [0.0; 4]),
- usage,
- queue.clone(),
+ let buffer = Buffer::new_slice::<[f64; 4]>(
+ &memory_allocator,
+ BufferCreateInfo {
+ usage: BufferUsage::UNIFORM_TEXEL_BUFFER | BufferUsage::STORAGE_TEXEL_BUFFER,
+ ..Default::default()
+ },
+ AllocationCreateInfo::default(),
+ 128,
)
.unwrap();
- // TODO: what if R64G64B64A64Sfloat is supported?
- match BufferView::new(buffer, Format::R64G64B64A64Sfloat) {
+ // TODO: what if R64G64B64A64_SFLOAT is supported?
+ match BufferView::new(
+ buffer,
+ BufferViewCreateInfo {
+ format: Some(Format::R64G64B64A64_SFLOAT),
+ ..Default::default()
+ },
+ ) {
Err(BufferViewCreationError::UnsupportedFormat) => (),
_ => panic!(),
}
diff --git a/src/cache.rs b/src/cache.rs
new file mode 100644
index 0000000..0bf3a76
--- /dev/null
+++ b/src/cache.rs
@@ -0,0 +1,87 @@
+// Copyright (c) 2016 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use ahash::HashMap;
+use parking_lot::RwLock;
+use std::{collections::hash_map::Entry, hash::Hash};
+
+/// A map specialized to caching properties that are specific to a Vulkan implementation.
+///
+/// Readers never block each other, except when an entry is vacant. In that case it gets written to
+/// once and then never again, entries are immutable after insertion.
+#[derive(Debug)]
+pub(crate) struct OnceCache<K, V> {
+ inner: RwLock<HashMap<K, V>>,
+}
+
+impl<K, V> Default for OnceCache<K, V> {
+ fn default() -> Self {
+ OnceCache {
+ inner: RwLock::new(HashMap::default()),
+ }
+ }
+}
+
+impl<K, V> OnceCache<K, V> {
+ /// Creates a new `OnceCache`.
+ pub fn new() -> Self {
+ Self::default()
+ }
+}
+
+impl<K, V> OnceCache<K, V>
+where
+ K: Eq + Hash,
+ V: Clone,
+{
+ /// Returns the value for the specified `key`. The entry gets written to with the value
+ /// returned by `f` if it doesn't exist.
+ pub fn get_or_insert(&self, key: K, f: impl FnOnce(&K) -> V) -> V {
+ if let Some(value) = self.inner.read().get(&key) {
+ return value.clone();
+ }
+
+ match self.inner.write().entry(key) {
+ Entry::Occupied(entry) => {
+ // This can happen if someone else inserted an entry between when we released
+ // the read lock and acquired the write lock.
+ entry.get().clone()
+ }
+ Entry::Vacant(entry) => {
+ let value = f(entry.key());
+ entry.insert(value.clone());
+
+ value
+ }
+ }
+ }
+
+ /// Returns the value for the specified `key`. The entry gets written to with the value
+ /// returned by `f` if it doesn't exist. If `f` returns [`Err`], the error is propagated and
+ /// the entry isn't written to.
+ pub fn get_or_try_insert<E>(&self, key: K, f: impl FnOnce(&K) -> Result<V, E>) -> Result<V, E> {
+ if let Some(value) = self.inner.read().get(&key) {
+ return Ok(value.clone());
+ }
+
+ match self.inner.write().entry(key) {
+ Entry::Occupied(entry) => {
+ // This can happen if someone else inserted an entry between when we released
+ // the read lock and acquired the write lock.
+ Ok(entry.get().clone())
+ }
+ Entry::Vacant(entry) => {
+ let value = f(entry.key())?;
+ entry.insert(value.clone());
+
+ Ok(value)
+ }
+ }
+ }
+}
diff --git a/src/command_buffer/allocator.rs b/src/command_buffer/allocator.rs
new file mode 100644
index 0000000..a2ca514
--- /dev/null
+++ b/src/command_buffer/allocator.rs
@@ -0,0 +1,698 @@
+// Copyright (c) 2016 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+//! Traits and types for managing the allocation of command buffers and command pools.
+//!
+//! In Vulkano, creating a command buffer requires passing an implementation of the
+//! [`CommandBufferAllocator`] trait. You can implement this trait yourself, or use the
+//! Vulkano-provided [`StandardCommandBufferAllocator`].
+
+use super::{
+ pool::{
+ CommandBufferAllocateInfo, CommandPool, CommandPoolAlloc, CommandPoolCreateInfo,
+ CommandPoolCreationError,
+ },
+ CommandBufferLevel,
+};
+use crate::{
+ device::{Device, DeviceOwned},
+ OomError,
+};
+use crossbeam_queue::ArrayQueue;
+use smallvec::{IntoIter, SmallVec};
+use std::{
+ cell::{Cell, UnsafeCell},
+ error::Error,
+ fmt::Display,
+ marker::PhantomData,
+ mem::ManuallyDrop,
+ sync::Arc,
+ thread,
+};
+use thread_local::ThreadLocal;
+
+const MAX_POOLS: usize = 32;
+
+/// Types that manage the memory of command buffers.
+///
+/// # Safety
+///
+/// A Vulkan command pool must be externally synchronized as if it owned the command buffers that
+/// were allocated from it. This includes allocating from the pool, freeing from the pool, resetting
+/// the pool or individual command buffers, and most importantly recording commands to command
+/// buffers. The implementation of `CommandBufferAllocator` is expected to manage this.
+///
+/// The destructors of the [`CommandBufferBuilderAlloc`] and the [`CommandBufferAlloc`] are expected
+/// to free the command buffer, reset the command buffer, or add it to a pool so that it gets
+/// reused. If the implementation frees or resets the command buffer, it must not forget that this
+/// operation must be externally synchronized.
+pub unsafe trait CommandBufferAllocator: DeviceOwned {
+ /// See [`allocate`](Self::allocate).
+ type Iter: Iterator<Item = Self::Builder>;
+
+ /// Represents a command buffer that has been allocated and that is currently being built.
+ type Builder: CommandBufferBuilderAlloc<Alloc = Self::Alloc>;
+
+ /// Represents a command buffer that has been allocated and that is pending execution or is
+ /// being executed.
+ type Alloc: CommandBufferAlloc;
+
+ /// Allocates command buffers.
+ ///
+ /// Returns an iterator that contains the requested amount of allocated command buffers.
+ fn allocate(
+ &self,
+ queue_family_index: u32,
+ level: CommandBufferLevel,
+ command_buffer_count: u32,
+ ) -> Result<Self::Iter, OomError>;
+}
+
+/// A command buffer allocated from a pool and that can be recorded.
+///
+/// # Safety
+///
+/// See [`CommandBufferAllocator`] for information about safety.
+pub unsafe trait CommandBufferBuilderAlloc: DeviceOwned {
+ /// Return type of `into_alloc`.
+ type Alloc: CommandBufferAlloc;
+
+ /// Returns the internal object that contains the command buffer.
+ fn inner(&self) -> &CommandPoolAlloc;
+
+ /// Turns this builder into a command buffer that is pending execution.
+ fn into_alloc(self) -> Self::Alloc;
+
+ /// Returns the index of the queue family that the pool targets.
+ fn queue_family_index(&self) -> u32;
+}
+
+/// A command buffer allocated from a pool that has finished being recorded.
+///
+/// # Safety
+///
+/// See [`CommandBufferAllocator`] for information about safety.
+pub unsafe trait CommandBufferAlloc: DeviceOwned + Send + Sync + 'static {
+ /// Returns the internal object that contains the command buffer.
+ fn inner(&self) -> &CommandPoolAlloc;
+
+ /// Returns the index of the queue family that the pool targets.
+ fn queue_family_index(&self) -> u32;
+}
+
+/// Standard implementation of a command buffer allocator.
+///
+/// The intended way to use this allocator is to have one that is used globally for the duration of
+/// the program, in order to avoid creating and destroying [`CommandPool`]s, as that is expensive.
+/// Alternatively, you can have one locally on a thread for the duration of the thread.
+///
+/// Internally, this allocator keeps one or more `CommandPool`s per queue family index per thread,
+/// using Thread-Local Storage. When a thread first allocates, an entry is reserved for the thread
+/// and queue family combination. After a thread exits and the allocator wasn't dropped yet, its
+/// entries are freed, but the pools it used are not dropped. The next time a new thread allocates
+/// for the first time, the entries are reused along with the pools. If all threads drop their
+/// reference to the allocator, all entries along with the allocator are dropped, even if the
+/// threads didn't exit yet, which is why you should keep the allocator alive for as long as you
+/// need to allocate so that the pools can keep being reused.
+///
+/// This allocator only needs to lock when a thread first allocates or when a thread that
+/// previously allocated exits. In all other cases, allocation is lock-free.
+///
+/// Command buffers can't be moved between threads during the building process, but finished command
+/// buffers can. When a command buffer is dropped, it is returned back to the pool for reuse.
+#[derive(Debug)]
+pub struct StandardCommandBufferAllocator {
+ device: Arc<Device>,
+ // Each queue family index points directly to its entry.
+ pools: ThreadLocal<SmallVec<[UnsafeCell<Option<Entry>>; 8]>>,
+ create_info: StandardCommandBufferAllocatorCreateInfo,
+}
+
+impl StandardCommandBufferAllocator {
+ /// Creates a new `StandardCommandBufferAllocator`.
+ #[inline]
+ pub fn new(device: Arc<Device>, create_info: StandardCommandBufferAllocatorCreateInfo) -> Self {
+ StandardCommandBufferAllocator {
+ device,
+ pools: ThreadLocal::new(),
+ create_info,
+ }
+ }
+
+ /// Tries to reset the [`CommandPool`] that's currently in use for the given queue family index
+ /// on the current thread.
+ ///
+ /// If successful, the memory of the pool can be reused again along with all command buffers
+ /// allocated from it. This is only possible if all command buffers allocated from the pool
+ /// have been dropped.
+ ///
+ /// This has no effect if the entry wasn't initialized yet or if the entry was [cleared].
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `queue_family_index` is not less than the number of queue families.
+ ///
+ /// [cleared]: Self::clear
+ #[inline]
+ pub fn try_reset_pool(
+ &self,
+ queue_family_index: u32,
+ release_resources: bool,
+ ) -> Result<(), CommandPoolResetError> {
+ if let Some(entry) = unsafe { &mut *self.entry(queue_family_index) }.as_mut() {
+ entry.try_reset_pool(release_resources)
+ } else {
+ Ok(())
+ }
+ }
+
+ /// Clears the entry for the given queue family index and the current thread. This does not
+ /// mean that the pools are dropped immediately. A pool is kept alive for as long as command
+ /// buffers allocated from it exist.
+ ///
+ /// This has no effect if the entry was not initialized yet.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `queue_family_index` is not less than the number of queue families.
+ #[inline]
+ pub fn clear(&self, queue_family_index: u32) {
+ unsafe { *self.entry(queue_family_index) = None };
+ }
+
+ fn entry(&self, queue_family_index: u32) -> *mut Option<Entry> {
+ let pools = self.pools.get_or(|| {
+ self.device
+ .physical_device()
+ .queue_family_properties()
+ .iter()
+ .map(|_| UnsafeCell::new(None))
+ .collect()
+ });
+
+ pools[queue_family_index as usize].get()
+ }
+}
+
+unsafe impl CommandBufferAllocator for StandardCommandBufferAllocator {
+ type Iter = IntoIter<[StandardCommandBufferBuilderAlloc; 1]>;
+
+ type Builder = StandardCommandBufferBuilderAlloc;
+
+ type Alloc = StandardCommandBufferAlloc;
+
+ /// Allocates command buffers.
+ ///
+ /// Returns an iterator that contains the requested amount of allocated command buffers.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family index is not active on the device.
+ /// - Panics if `command_buffer_count` exceeds the count configured for the pool corresponding
+ /// to `level`.
+ #[inline]
+ fn allocate(
+ &self,
+ queue_family_index: u32,
+ level: CommandBufferLevel,
+ command_buffer_count: u32,
+ ) -> Result<Self::Iter, OomError> {
+ // VUID-vkCreateCommandPool-queueFamilyIndex-01937
+ assert!(self
+ .device
+ .active_queue_family_indices()
+ .contains(&queue_family_index));
+
+ let entry = unsafe { &mut *self.entry(queue_family_index) };
+ if entry.is_none() {
+ let reserve = Arc::new(ArrayQueue::new(MAX_POOLS));
+ *entry = Some(Entry {
+ pool: Pool::new(
+ self.device.clone(),
+ queue_family_index,
+ reserve.clone(),
+ &self.create_info,
+ )?,
+ reserve,
+ });
+ }
+ let entry = entry.as_mut().unwrap();
+
+ // First try to allocate from existing command buffers.
+ if let Some(allocs) = entry.pool.allocate(level, command_buffer_count) {
+ return Ok(allocs);
+ }
+
+ // Else try to reset the pool.
+ if entry.try_reset_pool(false).is_err() {
+ // If that fails too try to grab a pool from the reserve.
+ entry.pool = if let Some(inner) = entry.reserve.pop() {
+ Arc::new(Pool {
+ inner: ManuallyDrop::new(inner),
+ reserve: entry.reserve.clone(),
+ })
+ } else {
+ // Else we are unfortunately forced to create a new pool.
+ Pool::new(
+ self.device.clone(),
+ queue_family_index,
+ entry.reserve.clone(),
+ &self.create_info,
+ )?
+ };
+ }
+
+ Ok(entry.pool.allocate(level, command_buffer_count).unwrap())
+ }
+}
+
+unsafe impl CommandBufferAllocator for Arc<StandardCommandBufferAllocator> {
+ type Iter = IntoIter<[StandardCommandBufferBuilderAlloc; 1]>;
+
+ type Builder = StandardCommandBufferBuilderAlloc;
+
+ type Alloc = StandardCommandBufferAlloc;
+
+ #[inline]
+ fn allocate(
+ &self,
+ queue_family_index: u32,
+ level: CommandBufferLevel,
+ command_buffer_count: u32,
+ ) -> Result<Self::Iter, OomError> {
+ (**self).allocate(queue_family_index, level, command_buffer_count)
+ }
+}
+
+unsafe impl DeviceOwned for StandardCommandBufferAllocator {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+}
+
+#[derive(Debug)]
+struct Entry {
+ // Contains the actual Vulkan command pool that is currently in use.
+ pool: Arc<Pool>,
+ // When a `Pool` is dropped, it returns itself here for reuse.
+ reserve: Arc<ArrayQueue<PoolInner>>,
+}
+
+// This is needed because of the blanket impl of `Send` on `Arc<T>`, which requires that `T` is
+// `Send + Sync`. `Pool` is `Send + !Sync` because `CommandPool` is `!Sync`. That's fine however
+// because we never access the Vulkan command pool concurrently. Same goes for the `Cell`s.
+unsafe impl Send for Entry {}
+
+impl Entry {
+ fn try_reset_pool(&mut self, release_resources: bool) -> Result<(), CommandPoolResetError> {
+ if let Some(pool) = Arc::get_mut(&mut self.pool) {
+ unsafe { pool.inner.inner.reset(release_resources) }
+ .map_err(|_| CommandPoolResetError::OutOfDeviceMemory)?;
+ *pool.inner.primary_allocations.get_mut() = 0;
+ *pool.inner.secondary_allocations.get_mut() = 0;
+
+ Ok(())
+ } else {
+ Err(CommandPoolResetError::InUse)
+ }
+ }
+}
+
+#[derive(Debug)]
+struct Pool {
+ inner: ManuallyDrop<PoolInner>,
+ // Where we return the `PoolInner` in our `Drop` impl.
+ reserve: Arc<ArrayQueue<PoolInner>>,
+}
+
+#[derive(Debug)]
+struct PoolInner {
+ // The Vulkan pool specific to a device's queue family.
+ inner: CommandPool,
+ // List of existing primary command buffers that are available for reuse.
+ primary_pool: Option<ArrayQueue<CommandPoolAlloc>>,
+ // List of existing secondary command buffers that are available for reuse.
+ secondary_pool: Option<ArrayQueue<CommandPoolAlloc>>,
+ // How many command buffers have been allocated from `self.primary_pool`.
+ primary_allocations: Cell<usize>,
+ // How many command buffers have been allocated from `self.secondary_pool`.
+ secondary_allocations: Cell<usize>,
+}
+
+impl Pool {
+ fn new(
+ device: Arc<Device>,
+ queue_family_index: u32,
+ reserve: Arc<ArrayQueue<PoolInner>>,
+ create_info: &StandardCommandBufferAllocatorCreateInfo,
+ ) -> Result<Arc<Self>, OomError> {
+ let inner = CommandPool::new(
+ device,
+ CommandPoolCreateInfo {
+ queue_family_index,
+ ..Default::default()
+ },
+ )
+ .map_err(|err| match err {
+ CommandPoolCreationError::OomError(err) => err,
+ // We check that the provided queue family index is active on the device, so it can't
+ // be out of range.
+ CommandPoolCreationError::QueueFamilyIndexOutOfRange { .. } => unreachable!(),
+ })?;
+
+ let primary_pool = if create_info.primary_buffer_count > 0 {
+ let pool = ArrayQueue::new(create_info.primary_buffer_count);
+
+ for alloc in inner.allocate_command_buffers(CommandBufferAllocateInfo {
+ level: CommandBufferLevel::Primary,
+ command_buffer_count: create_info.primary_buffer_count as u32,
+ ..Default::default()
+ })? {
+ let _ = pool.push(alloc);
+ }
+
+ Some(pool)
+ } else {
+ None
+ };
+
+ let secondary_pool = if create_info.secondary_buffer_count > 0 {
+ let pool = ArrayQueue::new(create_info.secondary_buffer_count);
+
+ for alloc in inner.allocate_command_buffers(CommandBufferAllocateInfo {
+ level: CommandBufferLevel::Secondary,
+ command_buffer_count: create_info.secondary_buffer_count as u32,
+ ..Default::default()
+ })? {
+ let _ = pool.push(alloc);
+ }
+
+ Some(pool)
+ } else {
+ None
+ };
+
+ Ok(Arc::new(Pool {
+ inner: ManuallyDrop::new(PoolInner {
+ inner,
+ primary_pool,
+ secondary_pool,
+ primary_allocations: Cell::new(0),
+ secondary_allocations: Cell::new(0),
+ }),
+ reserve,
+ }))
+ }
+
+ fn allocate(
+ self: &Arc<Self>,
+ level: CommandBufferLevel,
+ command_buffer_count: u32,
+ ) -> Option<IntoIter<[StandardCommandBufferBuilderAlloc; 1]>> {
+ let command_buffer_count = command_buffer_count as usize;
+
+ match level {
+ CommandBufferLevel::Primary => {
+ if let Some(pool) = &self.inner.primary_pool {
+ let count = self.inner.primary_allocations.get();
+ if count + command_buffer_count <= pool.capacity() {
+ let mut output = SmallVec::<[_; 1]>::with_capacity(command_buffer_count);
+ for _ in 0..command_buffer_count {
+ output.push(StandardCommandBufferBuilderAlloc {
+ inner: StandardCommandBufferAlloc {
+ inner: ManuallyDrop::new(pool.pop().unwrap()),
+ pool: self.clone(),
+ },
+ _marker: PhantomData,
+ });
+ }
+
+ self.inner
+ .primary_allocations
+ .set(count + command_buffer_count);
+
+ Some(output.into_iter())
+ } else if command_buffer_count > pool.capacity() {
+ panic!(
+ "command buffer count ({}) exceeds the capacity of the primary command \
+ buffer pool ({})",
+ command_buffer_count, pool.capacity(),
+ );
+ } else {
+ None
+ }
+ } else {
+ panic!(
+ "attempted to allocate a primary command buffer when the primary command \
+ buffer pool was configured to be empty",
+ );
+ }
+ }
+ CommandBufferLevel::Secondary => {
+ if let Some(pool) = &self.inner.secondary_pool {
+ let count = self.inner.secondary_allocations.get();
+ if count + command_buffer_count <= pool.capacity() {
+ let mut output = SmallVec::<[_; 1]>::with_capacity(command_buffer_count);
+ for _ in 0..command_buffer_count {
+ output.push(StandardCommandBufferBuilderAlloc {
+ inner: StandardCommandBufferAlloc {
+ inner: ManuallyDrop::new(pool.pop().unwrap()),
+ pool: self.clone(),
+ },
+ _marker: PhantomData,
+ });
+ }
+
+ self.inner
+ .secondary_allocations
+ .set(count + command_buffer_count);
+
+ Some(output.into_iter())
+ } else if command_buffer_count > pool.capacity() {
+ panic!(
+ "command buffer count ({}) exceeds the capacity of the secondary \
+ command buffer pool ({})",
+ command_buffer_count,
+ pool.capacity(),
+ );
+ } else {
+ None
+ }
+ } else {
+ panic!(
+ "attempted to allocate a secondary command buffer when the secondary \
+ command buffer pool was configured to be empty",
+ );
+ }
+ }
+ }
+ }
+}
+
+impl Drop for Pool {
+ fn drop(&mut self) {
+ let inner = unsafe { ManuallyDrop::take(&mut self.inner) };
+
+ if thread::panicking() {
+ return;
+ }
+
+ unsafe { inner.inner.reset(false) }.unwrap();
+ inner.primary_allocations.set(0);
+ inner.secondary_allocations.set(0);
+
+ // If there is not enough space in the reserve, we destroy the pool. The only way this can
+ // happen is if something is resource hogging, forcing new pools to be created such that
+ // the number exceeds `MAX_POOLS`, and then drops them all at once.
+ let _ = self.reserve.push(inner);
+ }
+}
+
+/// Parameters to create a new [`StandardCommandBufferAllocator`].
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct StandardCommandBufferAllocatorCreateInfo {
+ /// How many primary command buffers should be allocated per pool.
+ ///
+ /// Each time a thread allocates using some queue family index, and either no pools were
+ /// initialized yet or all pools are full, a new pool is created for that thread and queue
+ /// family combination. This option tells the allocator how many primary command buffers should
+ /// be allocated for that pool. It always allocates exactly this many command buffers at once
+ /// for the pool, as that is more performant than allocating them one-by-one. What this means
+ /// is that you should make sure that this is not too large, so that you don't end up wasting
+ /// too much memory. You also don't want this to be too low, because that on the other hand
+ /// would mean that the pool would have to be reset more often, or that more pools would need
+ /// to be created, depending on the lifetime of the command buffers.
+ ///
+ /// The default value is `256`.
+ pub primary_buffer_count: usize,
+
+ /// Same as `primary_buffer_count` except for secondary command buffers.
+ ///
+ /// The default value is `256`.
+ pub secondary_buffer_count: usize,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for StandardCommandBufferAllocatorCreateInfo {
+ #[inline]
+ fn default() -> Self {
+ StandardCommandBufferAllocatorCreateInfo {
+ primary_buffer_count: 256,
+ secondary_buffer_count: 256,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// Command buffer allocated from a [`StandardCommandBufferAllocator`] that is currently being
+/// built.
+pub struct StandardCommandBufferBuilderAlloc {
+ // The only difference between a `StandardCommandBufferBuilder` and a
+ // `StandardCommandBufferAlloc` is that the former must not implement `Send` and `Sync`.
+ // Therefore we just share the structs.
+ inner: StandardCommandBufferAlloc,
+ // Unimplemented `Send` and `Sync` from the builder.
+ _marker: PhantomData<*const ()>,
+}
+
+unsafe impl CommandBufferBuilderAlloc for StandardCommandBufferBuilderAlloc {
+ type Alloc = StandardCommandBufferAlloc;
+
+ #[inline]
+ fn inner(&self) -> &CommandPoolAlloc {
+ self.inner.inner()
+ }
+
+ #[inline]
+ fn into_alloc(self) -> Self::Alloc {
+ self.inner
+ }
+
+ #[inline]
+ fn queue_family_index(&self) -> u32 {
+ self.inner.queue_family_index()
+ }
+}
+
+unsafe impl DeviceOwned for StandardCommandBufferBuilderAlloc {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ self.inner.device()
+ }
+}
+
+/// Command buffer allocated from a [`StandardCommandBufferAllocator`].
+pub struct StandardCommandBufferAlloc {
+ // The actual command buffer. Extracted in the `Drop` implementation.
+ inner: ManuallyDrop<CommandPoolAlloc>,
+ // We hold a reference to the pool for our destructor.
+ pool: Arc<Pool>,
+}
+
+// It's fine to share `Pool` between threads because we never access the Vulkan command pool
+// concurrently. Same goes for the `Cell`s.
+unsafe impl Send for StandardCommandBufferAlloc {}
+unsafe impl Sync for StandardCommandBufferAlloc {}
+
+unsafe impl CommandBufferAlloc for StandardCommandBufferAlloc {
+ #[inline]
+ fn inner(&self) -> &CommandPoolAlloc {
+ &self.inner
+ }
+
+ #[inline]
+ fn queue_family_index(&self) -> u32 {
+ self.pool.inner.inner.queue_family_index()
+ }
+}
+
+unsafe impl DeviceOwned for StandardCommandBufferAlloc {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ self.pool.inner.inner.device()
+ }
+}
+
+impl Drop for StandardCommandBufferAlloc {
+ #[inline]
+ fn drop(&mut self) {
+ let inner = unsafe { ManuallyDrop::take(&mut self.inner) };
+ let pool = match inner.level() {
+ CommandBufferLevel::Primary => &self.pool.inner.primary_pool,
+ CommandBufferLevel::Secondary => &self.pool.inner.secondary_pool,
+ };
+ // This can't panic, because if an allocation from a particular kind of pool was made, then
+ // the pool must exist.
+ let _ = pool.as_ref().unwrap().push(inner);
+ }
+}
+
+/// Error that can be returned when resetting a [`CommandPool`].
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum CommandPoolResetError {
+ /// The `CommandPool` is still in use.
+ InUse,
+
+ /// Out of device memory.
+ OutOfDeviceMemory,
+}
+
+impl Error for CommandPoolResetError {}
+
+impl Display for CommandPoolResetError {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ Self::InUse => write!(f, "the `CommandPool` is still in use"),
+ Self::OutOfDeviceMemory => write!(f, "out of device memory"),
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::VulkanObject;
+ use std::thread;
+
+ #[test]
+ fn threads_use_different_pools() {
+ let (device, queue) = gfx_dev_and_queue!();
+
+ let allocator = StandardCommandBufferAllocator::new(device, Default::default());
+
+ let pool1 = allocator
+ .allocate(queue.queue_family_index(), CommandBufferLevel::Primary, 1)
+ .unwrap()
+ .next()
+ .unwrap()
+ .into_alloc()
+ .pool
+ .inner
+ .inner
+ .handle();
+
+ thread::spawn(move || {
+ let pool2 = allocator
+ .allocate(queue.queue_family_index(), CommandBufferLevel::Primary, 1)
+ .unwrap()
+ .next()
+ .unwrap()
+ .into_alloc()
+ .pool
+ .inner
+ .inner
+ .handle();
+ assert_ne!(pool1, pool2);
+ })
+ .join()
+ .unwrap();
+ }
+}
diff --git a/src/command_buffer/auto.rs b/src/command_buffer/auto.rs
index 64d0d2d..b143b35 100644
--- a/src/command_buffer/auto.rs
+++ b/src/command_buffer/auto.rs
@@ -7,2330 +7,795 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use crate::buffer::BufferAccess;
-use crate::buffer::TypedBufferAccess;
-use crate::command_buffer::pool::standard::StandardCommandPoolAlloc;
-use crate::command_buffer::pool::standard::StandardCommandPoolBuilder;
-use crate::command_buffer::pool::CommandPool;
-use crate::command_buffer::pool::CommandPoolBuilderAlloc;
-use crate::command_buffer::synced::SyncCommandBuffer;
-use crate::command_buffer::synced::SyncCommandBufferBuilder;
-use crate::command_buffer::synced::SyncCommandBufferBuilderError;
-use crate::command_buffer::sys::UnsafeCommandBuffer;
-use crate::command_buffer::sys::UnsafeCommandBufferBuilderBufferImageCopy;
-use crate::command_buffer::sys::UnsafeCommandBufferBuilderColorImageClear;
-use crate::command_buffer::sys::UnsafeCommandBufferBuilderImageBlit;
-use crate::command_buffer::sys::UnsafeCommandBufferBuilderImageCopy;
-use crate::command_buffer::validity::*;
-use crate::command_buffer::CommandBufferExecError;
-use crate::command_buffer::CommandBufferInheritance;
-use crate::command_buffer::CommandBufferInheritanceRenderPass;
-use crate::command_buffer::CommandBufferLevel;
-use crate::command_buffer::CommandBufferUsage;
-use crate::command_buffer::DispatchIndirectCommand;
-use crate::command_buffer::DrawIndexedIndirectCommand;
-use crate::command_buffer::DrawIndirectCommand;
-use crate::command_buffer::DynamicState;
-use crate::command_buffer::ImageUninitializedSafe;
-use crate::command_buffer::PrimaryCommandBuffer;
-use crate::command_buffer::SecondaryCommandBuffer;
-use crate::command_buffer::StateCacher;
-use crate::command_buffer::StateCacherOutcome;
-use crate::command_buffer::SubpassContents;
-use crate::descriptor_set::DescriptorSetWithOffsets;
-use crate::descriptor_set::DescriptorSetsCollection;
-use crate::device::physical::QueueFamily;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::device::Queue;
-use crate::format::ClearValue;
-use crate::format::FormatTy;
-use crate::format::Pixel;
-use crate::image::ImageAccess;
-use crate::image::ImageAspect;
-use crate::image::ImageAspects;
-use crate::image::ImageLayout;
-use crate::pipeline::depth_stencil::StencilFaces;
-use crate::pipeline::input_assembly::Index;
-use crate::pipeline::layout::PipelineLayout;
-use crate::pipeline::vertex::VertexSource;
-use crate::pipeline::ComputePipelineAbstract;
-use crate::pipeline::GraphicsPipelineAbstract;
-use crate::pipeline::PipelineBindPoint;
-use crate::query::QueryControlFlags;
-use crate::query::QueryPipelineStatisticFlags;
-use crate::query::QueryPool;
-use crate::query::QueryResultElement;
-use crate::query::QueryResultFlags;
-use crate::query::QueryType;
-use crate::render_pass::Framebuffer;
-use crate::render_pass::FramebufferAbstract;
-use crate::render_pass::LoadOp;
-use crate::render_pass::RenderPass;
-use crate::render_pass::Subpass;
-use crate::sampler::Filter;
-use crate::sync::AccessCheckError;
-use crate::sync::AccessFlags;
-use crate::sync::GpuFuture;
-use crate::sync::PipelineMemoryAccess;
-use crate::sync::PipelineStage;
-use crate::sync::PipelineStages;
-use crate::DeviceSize;
-use crate::VulkanObject;
-use crate::{OomError, SafeDeref};
-use fnv::FnvHashMap;
-use std::error;
-use std::ffi::CStr;
-use std::fmt;
-use std::iter;
-use std::marker::PhantomData;
-use std::mem;
-use std::ops::Range;
-use std::slice;
-use std::sync::atomic::AtomicBool;
-use std::sync::atomic::Ordering;
-use std::sync::Arc;
-
-/// Note that command buffers allocated from the default command pool (`Arc<StandardCommandPool>`)
-/// don't implement the `Send` and `Sync` traits. If you use this pool, then the
-/// `AutoCommandBufferBuilder` will not implement `Send` and `Sync` either. Once a command buffer
-/// is built, however, it *does* implement `Send` and `Sync`.
-pub struct AutoCommandBufferBuilder<L, P = StandardCommandPoolBuilder> {
- inner: SyncCommandBufferBuilder,
- pool_builder_alloc: P, // Safety: must be dropped after `inner`
- state_cacher: StateCacher,
-
- // The queue family that this command buffer is being created for.
- queue_family_id: u32,
+use super::{
+ allocator::{
+ CommandBufferAlloc, CommandBufferAllocator, CommandBufferBuilderAlloc,
+ StandardCommandBufferAlloc, StandardCommandBufferAllocator,
+ },
+ synced::{CommandBufferBuilderState, SyncCommandBuffer, SyncCommandBufferBuilder},
+ sys::CommandBufferBeginInfo,
+ CommandBufferExecError, CommandBufferInheritanceInfo, CommandBufferInheritanceRenderPassInfo,
+ CommandBufferInheritanceRenderPassType, CommandBufferLevel, CommandBufferResourcesUsage,
+ CommandBufferState, CommandBufferUsage, PrimaryCommandBufferAbstract, RenderingAttachmentInfo,
+ SecondaryCommandBufferAbstract, SecondaryCommandBufferResourcesUsage, SubpassContents,
+};
+use crate::{
+ command_buffer::CommandBufferInheritanceRenderingInfo,
+ device::{Device, DeviceOwned, QueueFamilyProperties},
+ format::{Format, FormatFeatures},
+ image::ImageAspects,
+ query::{QueryControlFlags, QueryType},
+ render_pass::{Framebuffer, Subpass},
+ OomError, RequirementNotMet, RequiresOneOf, VulkanObject,
+};
+use ahash::HashMap;
+use parking_lot::{Mutex, MutexGuard};
+use std::{
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+ marker::PhantomData,
+ sync::{
+ atomic::{AtomicBool, Ordering},
+ Arc,
+ },
+};
+
+/// Note that command buffers allocated from `StandardCommandBufferAllocator` don't implement
+/// the `Send` and `Sync` traits. If you use this allocator, then the `AutoCommandBufferBuilder`
+/// will not implement `Send` and `Sync` either. Once a command buffer is built, however, it *does*
+/// implement `Send` and `Sync`.
+pub struct AutoCommandBufferBuilder<L, A = StandardCommandBufferAllocator>
+where
+ A: CommandBufferAllocator,
+{
+ pub(super) inner: SyncCommandBufferBuilder,
+ builder_alloc: A::Builder, // Safety: must be dropped after `inner`
+
+ // The index of the queue family that this command buffer is being created for.
+ queue_family_index: u32,
// The inheritance for secondary command buffers.
- inheritance: Option<CommandBufferInheritance<Box<dyn FramebufferAbstract + Send + Sync>>>,
+ // Must be `None` in a primary command buffer and `Some` in a secondary command buffer.
+ pub(super) inheritance_info: Option<CommandBufferInheritanceInfo>,
// Usage flags passed when creating the command buffer.
- usage: CommandBufferUsage,
+ pub(super) usage: CommandBufferUsage,
// If we're inside a render pass, contains the render pass state.
- render_pass_state: Option<RenderPassState>,
+ pub(super) render_pass_state: Option<RenderPassState>,
// If any queries are active, this hashmap contains their state.
- query_state: FnvHashMap<ash::vk::QueryType, QueryState>,
+ pub(super) query_state: HashMap<ash::vk::QueryType, QueryState>,
_data: PhantomData<L>,
}
-// The state of the current render pass, specifying the pass, subpass index and its intended contents.
-struct RenderPassState {
- subpass: (Arc<RenderPass>, u32),
- contents: SubpassContents,
- framebuffer: ash::vk::Framebuffer, // Always null for secondary command buffers
+// The state of the current render pass.
+pub(super) struct RenderPassState {
+ pub(super) contents: SubpassContents,
+ pub(super) render_area_offset: [u32; 2],
+ pub(super) render_area_extent: [u32; 2],
+ pub(super) render_pass: RenderPassStateType,
+ pub(super) view_mask: u32,
}
-// The state of an active query.
-struct QueryState {
- query_pool: ash::vk::QueryPool,
- query: u32,
- ty: QueryType,
- flags: QueryControlFlags,
- in_subpass: bool,
+pub(super) enum RenderPassStateType {
+ BeginRenderPass(BeginRenderPassState),
+ BeginRendering(BeginRenderingState),
}
-impl AutoCommandBufferBuilder<PrimaryAutoCommandBuffer, StandardCommandPoolBuilder> {
- /// Starts building a primary command buffer.
- #[inline]
- pub fn primary(
- device: Arc<Device>,
- queue_family: QueueFamily,
- usage: CommandBufferUsage,
- ) -> Result<
- AutoCommandBufferBuilder<PrimaryAutoCommandBuffer, StandardCommandPoolBuilder>,
- OomError,
- > {
- AutoCommandBufferBuilder::with_level(
- device,
- queue_family,
- usage,
- CommandBufferLevel::primary(),
- )
- }
-}
-
-impl AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, StandardCommandPoolBuilder> {
- /// Starts building a secondary compute command buffer.
- #[inline]
- pub fn secondary_compute(
- device: Arc<Device>,
- queue_family: QueueFamily,
- usage: CommandBufferUsage,
- ) -> Result<
- AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, StandardCommandPoolBuilder>,
- OomError,
- > {
- let level = CommandBufferLevel::secondary(None, QueryPipelineStatisticFlags::none());
- AutoCommandBufferBuilder::with_level(device, queue_family, usage, level)
- }
-
- /// Same as `secondary_compute`, but allows specifying how queries are being inherited.
- #[inline]
- pub fn secondary_compute_inherit_queries(
- device: Arc<Device>,
- queue_family: QueueFamily,
- usage: CommandBufferUsage,
- occlusion_query: Option<QueryControlFlags>,
- query_statistics_flags: QueryPipelineStatisticFlags,
- ) -> Result<
- AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, StandardCommandPoolBuilder>,
- BeginError,
- > {
- if occlusion_query.is_some() && !device.enabled_features().inherited_queries {
- return Err(BeginError::InheritedQueriesFeatureNotEnabled);
- }
-
- if query_statistics_flags.count() > 0
- && !device.enabled_features().pipeline_statistics_query
- {
- return Err(BeginError::PipelineStatisticsQueryFeatureNotEnabled);
- }
-
- let level = CommandBufferLevel::secondary(occlusion_query, query_statistics_flags);
- Ok(AutoCommandBufferBuilder::with_level(
- device,
- queue_family,
- usage,
- level,
- )?)
- }
-
- /// Starts building a secondary graphics command buffer.
- #[inline]
- pub fn secondary_graphics(
- device: Arc<Device>,
- queue_family: QueueFamily,
- usage: CommandBufferUsage,
- subpass: Subpass,
- ) -> Result<
- AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, StandardCommandPoolBuilder>,
- OomError,
- > {
- let level = CommandBufferLevel::Secondary(CommandBufferInheritance {
- render_pass: Some(CommandBufferInheritanceRenderPass {
- subpass,
- framebuffer: None::<Arc<Framebuffer<()>>>,
- }),
- occlusion_query: None,
- query_statistics_flags: QueryPipelineStatisticFlags::none(),
- });
-
- AutoCommandBufferBuilder::with_level(device, queue_family, usage, level)
- }
-
- /// Same as `secondary_graphics`, but allows specifying how queries are being inherited.
- #[inline]
- pub fn secondary_graphics_inherit_queries(
- device: Arc<Device>,
- queue_family: QueueFamily,
- usage: CommandBufferUsage,
- subpass: Subpass,
- occlusion_query: Option<QueryControlFlags>,
- query_statistics_flags: QueryPipelineStatisticFlags,
- ) -> Result<
- AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, StandardCommandPoolBuilder>,
- BeginError,
- > {
- if occlusion_query.is_some() && !device.enabled_features().inherited_queries {
- return Err(BeginError::InheritedQueriesFeatureNotEnabled);
- }
-
- if query_statistics_flags.count() > 0
- && !device.enabled_features().pipeline_statistics_query
- {
- return Err(BeginError::PipelineStatisticsQueryFeatureNotEnabled);
- }
-
- let level = CommandBufferLevel::Secondary(CommandBufferInheritance {
- render_pass: Some(CommandBufferInheritanceRenderPass {
- subpass,
- framebuffer: None::<Arc<Framebuffer<()>>>,
- }),
- occlusion_query,
- query_statistics_flags,
- });
-
- Ok(AutoCommandBufferBuilder::with_level(
- device,
- queue_family,
- usage,
- level,
- )?)
+impl From<BeginRenderPassState> for RenderPassStateType {
+ fn from(val: BeginRenderPassState) -> Self {
+ Self::BeginRenderPass(val)
}
}
-impl<L> AutoCommandBufferBuilder<L, StandardCommandPoolBuilder> {
- // Actual constructor. Private.
- fn with_level<F>(
- device: Arc<Device>,
- queue_family: QueueFamily,
- usage: CommandBufferUsage,
- level: CommandBufferLevel<F>,
- ) -> Result<AutoCommandBufferBuilder<L, StandardCommandPoolBuilder>, OomError>
- where
- F: FramebufferAbstract + Clone + Send + Sync + 'static,
- {
- let (inheritance, render_pass_state) = match &level {
- CommandBufferLevel::Primary => (None, None),
- CommandBufferLevel::Secondary(inheritance) => {
- let (render_pass, render_pass_state) = match inheritance.render_pass.as_ref() {
- Some(CommandBufferInheritanceRenderPass {
- subpass,
- framebuffer,
- }) => {
- let render_pass = CommandBufferInheritanceRenderPass {
- subpass: Subpass::from(subpass.render_pass().clone(), subpass.index())
- .unwrap(),
- framebuffer: framebuffer
- .as_ref()
- .map(|f| Box::new(f.clone()) as Box<_>),
- };
- let render_pass_state = RenderPassState {
- subpass: (subpass.render_pass().clone(), subpass.index()),
- contents: SubpassContents::Inline,
- framebuffer: ash::vk::Framebuffer::null(), // Only needed for primary command buffers
- };
- (Some(render_pass), Some(render_pass_state))
- }
- None => (None, None),
- };
-
- (
- Some(CommandBufferInheritance {
- render_pass,
- occlusion_query: inheritance.occlusion_query,
- query_statistics_flags: inheritance.query_statistics_flags,
- }),
- render_pass_state,
- )
- }
- };
-
- unsafe {
- let pool = Device::standard_command_pool(&device, queue_family);
- let pool_builder_alloc = pool
- .alloc(!matches!(level, CommandBufferLevel::Primary), 1)?
- .next()
- .expect("Requested one command buffer from the command pool, but got zero.");
- let inner = SyncCommandBufferBuilder::new(pool_builder_alloc.inner(), level, usage)?;
-
- Ok(AutoCommandBufferBuilder {
- inner,
- pool_builder_alloc,
- state_cacher: StateCacher::new(),
- queue_family_id: queue_family.id(),
- render_pass_state,
- query_state: FnvHashMap::default(),
- inheritance,
- usage,
- _data: PhantomData,
- })
- }
+impl From<BeginRenderingState> for RenderPassStateType {
+ fn from(val: BeginRenderingState) -> Self {
+ Self::BeginRendering(val)
}
}
-#[derive(Clone, Copy, Debug)]
-pub enum BeginError {
- /// Occlusion query inheritance was requested, but the `inherited_queries` feature was not enabled.
- InheritedQueriesFeatureNotEnabled,
- /// Not enough memory.
- OomError(OomError),
- /// Pipeline statistics query inheritance was requested, but the `pipeline_statistics_query` feature was not enabled.
- PipelineStatisticsQueryFeatureNotEnabled,
+pub(super) struct BeginRenderPassState {
+ pub(super) subpass: Subpass,
+ pub(super) framebuffer: Option<Arc<Framebuffer>>,
}
-impl error::Error for BeginError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- Self::OomError(ref err) => Some(err),
- _ => None,
- }
- }
+pub(super) struct BeginRenderingState {
+ pub(super) attachments: Option<BeginRenderingAttachments>,
+ pub(super) color_attachment_formats: Vec<Option<Format>>,
+ pub(super) depth_attachment_format: Option<Format>,
+ pub(super) stencil_attachment_format: Option<Format>,
+ pub(super) pipeline_used: bool,
}
-impl fmt::Display for BeginError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- Self::InheritedQueriesFeatureNotEnabled => {
- "occlusion query inheritance was requested but the corresponding feature \
- wasn't enabled"
- }
- Self::OomError(_) => "not enough memory available",
- Self::PipelineStatisticsQueryFeatureNotEnabled => {
- "pipeline statistics query inheritance was requested but the corresponding \
- feature wasn't enabled"
- }
- }
- )
- }
+pub(super) struct BeginRenderingAttachments {
+ pub(super) color_attachments: Vec<Option<RenderingAttachmentInfo>>,
+ pub(super) depth_attachment: Option<RenderingAttachmentInfo>,
+ pub(super) stencil_attachment: Option<RenderingAttachmentInfo>,
}
-impl From<OomError> for BeginError {
- #[inline]
- fn from(err: OomError) -> Self {
- Self::OomError(err)
- }
+// The state of an active query.
+pub(super) struct QueryState {
+ pub(super) query_pool: ash::vk::QueryPool,
+ pub(super) query: u32,
+ pub(super) ty: QueryType,
+ pub(super) flags: QueryControlFlags,
+ pub(super) in_subpass: bool,
}
-impl<P> AutoCommandBufferBuilder<PrimaryAutoCommandBuffer<P::Alloc>, P>
+impl<A> AutoCommandBufferBuilder<PrimaryAutoCommandBuffer, A>
where
- P: CommandPoolBuilderAlloc,
+ A: CommandBufferAllocator,
{
- /// Builds the command buffer.
+ /// Starts recording a primary command buffer.
#[inline]
- pub fn build(self) -> Result<PrimaryAutoCommandBuffer<P::Alloc>, BuildError> {
- if self.render_pass_state.is_some() {
- return Err(AutoCommandBufferBuilderContextError::ForbiddenInsideRenderPass.into());
- }
-
- if !self.query_state.is_empty() {
- return Err(AutoCommandBufferBuilderContextError::QueryIsActive.into());
+ pub fn primary(
+ allocator: &A,
+ queue_family_index: u32,
+ usage: CommandBufferUsage,
+ ) -> Result<
+ AutoCommandBufferBuilder<PrimaryAutoCommandBuffer<A::Alloc>, A>,
+ CommandBufferBeginError,
+ > {
+ unsafe {
+ AutoCommandBufferBuilder::begin(
+ allocator,
+ queue_family_index,
+ CommandBufferLevel::Primary,
+ CommandBufferBeginInfo {
+ usage,
+ inheritance_info: None,
+ _ne: crate::NonExhaustive(()),
+ },
+ )
}
-
- let submit_state = match self.usage {
- CommandBufferUsage::MultipleSubmit => SubmitState::ExclusiveUse {
- in_use: AtomicBool::new(false),
- },
- CommandBufferUsage::SimultaneousUse => SubmitState::Concurrent,
- CommandBufferUsage::OneTimeSubmit => SubmitState::OneTime {
- already_submitted: AtomicBool::new(false),
- },
- };
-
- Ok(PrimaryAutoCommandBuffer {
- inner: self.inner.build()?,
- pool_alloc: self.pool_builder_alloc.into_alloc(),
- submit_state,
- })
}
}
-impl<P> AutoCommandBufferBuilder<SecondaryAutoCommandBuffer<P::Alloc>, P>
+impl<A> AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, A>
where
- P: CommandPoolBuilderAlloc,
+ A: CommandBufferAllocator,
{
- /// Builds the command buffer.
- #[inline]
- pub fn build(self) -> Result<SecondaryAutoCommandBuffer<P::Alloc>, BuildError> {
- if !self.query_state.is_empty() {
- return Err(AutoCommandBufferBuilderContextError::QueryIsActive.into());
- }
-
- let submit_state = match self.usage {
- CommandBufferUsage::MultipleSubmit => SubmitState::ExclusiveUse {
- in_use: AtomicBool::new(false),
- },
- CommandBufferUsage::SimultaneousUse => SubmitState::Concurrent,
- CommandBufferUsage::OneTimeSubmit => SubmitState::OneTime {
- already_submitted: AtomicBool::new(false),
- },
- };
-
- Ok(SecondaryAutoCommandBuffer {
- inner: self.inner.build()?,
- pool_alloc: self.pool_builder_alloc.into_alloc(),
- inheritance: self.inheritance.unwrap(),
- submit_state,
- })
- }
-}
-
-impl<L, P> AutoCommandBufferBuilder<L, P> {
- #[inline]
- fn ensure_outside_render_pass(&self) -> Result<(), AutoCommandBufferBuilderContextError> {
- if self.render_pass_state.is_some() {
- return Err(AutoCommandBufferBuilderContextError::ForbiddenInsideRenderPass);
- }
-
- Ok(())
- }
-
- #[inline]
- fn ensure_inside_render_pass_inline<Gp>(
- &self,
- pipeline: &Gp,
- ) -> Result<(), AutoCommandBufferBuilderContextError>
- where
- Gp: ?Sized + GraphicsPipelineAbstract,
- {
- let render_pass_state = self
- .render_pass_state
- .as_ref()
- .ok_or(AutoCommandBufferBuilderContextError::ForbiddenOutsideRenderPass)?;
-
- // Subpass must be for inline commands
- if render_pass_state.contents != SubpassContents::Inline {
- return Err(AutoCommandBufferBuilderContextError::WrongSubpassType);
- }
-
- // Subpasses must be the same.
- if pipeline.subpass().index() != render_pass_state.subpass.1 {
- return Err(AutoCommandBufferBuilderContextError::WrongSubpassIndex);
- }
-
- // Render passes must be compatible.
- if !pipeline
- .subpass()
- .render_pass()
- .desc()
- .is_compatible_with_desc(&render_pass_state.subpass.0.desc())
- {
- return Err(AutoCommandBufferBuilderContextError::IncompatibleRenderPass);
- }
-
- Ok(())
- }
-
+ /// Starts recording a secondary command buffer.
#[inline]
- fn queue_family(&self) -> QueueFamily {
- self.device()
- .physical_device()
- .queue_family_by_id(self.queue_family_id)
- .unwrap()
- }
-
- /// Adds a command that copies an image to another.
- ///
- /// Copy operations have several restrictions:
- ///
- /// - Copy operations are only allowed on queue families that support transfer, graphics, or
- /// compute operations.
- /// - The number of samples in the source and destination images must be equal.
- /// - The size of the uncompressed element format of the source image must be equal to the
- /// compressed element format of the destination.
- /// - If you copy between depth, stencil or depth-stencil images, the format of both images
- /// must match exactly.
- /// - For two-dimensional images, the Z coordinate must be 0 for the image offsets and 1 for
- /// the extent. Same for the Y coordinate for one-dimensional images.
- /// - For non-array images, the base array layer must be 0 and the number of layers must be 1.
- ///
- /// If `layer_count` is greater than 1, the copy will happen between each individual layer as
- /// if they were separate images.
- ///
- /// # Panic
- ///
- /// - Panics if the source or the destination was not created with `device`.
- ///
- pub fn copy_image<S, D>(
- &mut self,
- source: S,
- source_offset: [i32; 3],
- source_base_array_layer: u32,
- source_mip_level: u32,
- destination: D,
- destination_offset: [i32; 3],
- destination_base_array_layer: u32,
- destination_mip_level: u32,
- extent: [u32; 3],
- layer_count: u32,
- ) -> Result<&mut Self, CopyImageError>
- where
- S: ImageAccess + Send + Sync + 'static,
- D: ImageAccess + Send + Sync + 'static,
- {
+ pub fn secondary(
+ allocator: &A,
+ queue_family_index: u32,
+ usage: CommandBufferUsage,
+ inheritance_info: CommandBufferInheritanceInfo,
+ ) -> Result<
+ AutoCommandBufferBuilder<SecondaryAutoCommandBuffer<A::Alloc>, A>,
+ CommandBufferBeginError,
+ > {
unsafe {
- self.ensure_outside_render_pass()?;
-
- check_copy_image(
- self.device(),
- &source,
- source_offset,
- source_base_array_layer,
- source_mip_level,
- &destination,
- destination_offset,
- destination_base_array_layer,
- destination_mip_level,
- extent,
- layer_count,
- )?;
-
- let copy = UnsafeCommandBufferBuilderImageCopy {
- // TODO: Allowing choosing a subset of the image aspects, but note that if color
- // is included, neither depth nor stencil may.
- aspects: ImageAspects {
- color: source.has_color(),
- depth: !source.has_color() && source.has_depth() && destination.has_depth(),
- stencil: !source.has_color()
- && source.has_stencil()
- && destination.has_stencil(),
- ..ImageAspects::none()
+ AutoCommandBufferBuilder::begin(
+ allocator,
+ queue_family_index,
+ CommandBufferLevel::Secondary,
+ CommandBufferBeginInfo {
+ usage,
+ inheritance_info: Some(inheritance_info),
+ _ne: crate::NonExhaustive(()),
},
- source_mip_level,
- destination_mip_level,
- source_base_array_layer,
- destination_base_array_layer,
- layer_count,
- source_offset,
- destination_offset,
- extent,
- };
-
- // TODO: Allow choosing layouts, but note that only Transfer*Optimal and General are
- // valid.
- self.inner.copy_image(
- source,
- ImageLayout::TransferSrcOptimal,
- destination,
- ImageLayout::TransferDstOptimal,
- iter::once(copy),
- )?;
- Ok(self)
+ )
}
}
+}
- /// Adds a command that blits an image to another.
- ///
- /// A *blit* is similar to an image copy operation, except that the portion of the image that
- /// is transferred can be resized. You choose an area of the source and an area of the
- /// destination, and the implementation will resize the area of the source so that it matches
- /// the size of the area of the destination before writing it.
- ///
- /// Blit operations have several restrictions:
- ///
- /// - Blit operations are only allowed on queue families that support graphics operations.
- /// - The format of the source and destination images must support blit operations, which
- /// depends on the Vulkan implementation. Vulkan guarantees that some specific formats must
- /// always be supported. See tables 52 to 61 of the specifications.
- /// - Only single-sampled images are allowed.
- /// - You can only blit between two images whose formats belong to the same type. The types
- /// are: floating-point, signed integers, unsigned integers, depth-stencil.
- /// - If you blit between depth, stencil or depth-stencil images, the format of both images
- /// must match exactly.
- /// - If you blit between depth, stencil or depth-stencil images, only the `Nearest` filter is
- /// allowed.
- /// - For two-dimensional images, the Z coordinate must be 0 for the top-left offset and 1 for
- /// the bottom-right offset. Same for the Y coordinate for one-dimensional images.
- /// - For non-array images, the base array layer must be 0 and the number of layers must be 1.
- ///
- /// If `layer_count` is greater than 1, the blit will happen between each individual layer as
- /// if they were separate images.
- ///
- /// # Panic
- ///
- /// - Panics if the source or the destination was not created with `device`.
- ///
- pub fn blit_image<S, D>(
- &mut self,
- source: S,
- source_top_left: [i32; 3],
- source_bottom_right: [i32; 3],
- source_base_array_layer: u32,
- source_mip_level: u32,
- destination: D,
- destination_top_left: [i32; 3],
- destination_bottom_right: [i32; 3],
- destination_base_array_layer: u32,
- destination_mip_level: u32,
- layer_count: u32,
- filter: Filter,
- ) -> Result<&mut Self, BlitImageError>
- where
- S: ImageAccess + Send + Sync + 'static,
- D: ImageAccess + Send + Sync + 'static,
- {
- unsafe {
- if !self.queue_family().supports_graphics() {
- return Err(AutoCommandBufferBuilderContextError::NotSupportedByQueueFamily.into());
- }
+impl<L, A> AutoCommandBufferBuilder<L, A>
+where
+ A: CommandBufferAllocator,
+{
+ // Actual constructor. Private.
+ //
+ // `begin_info.inheritance_info` must match `level`.
+ unsafe fn begin(
+ allocator: &A,
+ queue_family_index: u32,
+ level: CommandBufferLevel,
+ begin_info: CommandBufferBeginInfo,
+ ) -> Result<AutoCommandBufferBuilder<L, A>, CommandBufferBeginError> {
+ Self::validate_begin(allocator.device(), queue_family_index, level, &begin_info)?;
+
+ let &CommandBufferBeginInfo {
+ usage,
+ ref inheritance_info,
+ _ne: _,
+ } = &begin_info;
+
+ let inheritance_info = inheritance_info.clone();
+ let mut render_pass_state = None;
+
+ if let Some(inheritance_info) = &inheritance_info {
+ let &CommandBufferInheritanceInfo {
+ ref render_pass,
+ occlusion_query: _,
+ query_statistics_flags: _,
+ _ne: _,
+ } = inheritance_info;
+
+ if let Some(render_pass) = render_pass {
+ // In a secondary command buffer, we don't know the render area yet, so use a
+ // dummy value.
+ let render_area_offset = [0, 0];
+ let mut render_area_extent = [u32::MAX, u32::MAX];
+
+ match render_pass {
+ CommandBufferInheritanceRenderPassType::BeginRenderPass(info) => {
+ if let Some(framebuffer) = &info.framebuffer {
+ // Still not exact, but it's a better upper bound.
+ render_area_extent = framebuffer.extent();
+ }
- self.ensure_outside_render_pass()?;
-
- check_blit_image(
- self.device(),
- &source,
- source_top_left,
- source_bottom_right,
- source_base_array_layer,
- source_mip_level,
- &destination,
- destination_top_left,
- destination_bottom_right,
- destination_base_array_layer,
- destination_mip_level,
- layer_count,
- filter,
- )?;
-
- let blit = UnsafeCommandBufferBuilderImageBlit {
- // TODO:
- aspects: if source.has_color() {
- ImageAspects {
- color: true,
- ..ImageAspects::none()
+ render_pass_state = Some(RenderPassState {
+ contents: SubpassContents::Inline,
+ render_area_offset,
+ render_area_extent,
+ render_pass: BeginRenderPassState {
+ subpass: info.subpass.clone(),
+ framebuffer: info.framebuffer.clone(),
+ }
+ .into(),
+ view_mask: info.subpass.subpass_desc().view_mask,
+ });
}
- } else {
- unimplemented!()
- },
- source_mip_level,
- destination_mip_level,
- source_base_array_layer,
- destination_base_array_layer,
- layer_count,
- source_top_left,
- source_bottom_right,
- destination_top_left,
- destination_bottom_right,
- };
-
- self.inner.blit_image(
- source,
- ImageLayout::TransferSrcOptimal,
- destination, // TODO: let choose layout
- ImageLayout::TransferDstOptimal,
- iter::once(blit),
- filter,
- )?;
- Ok(self)
- }
- }
-
- /// Adds a command that clears all the layers and mipmap levels of a color image with a
- /// specific value.
- ///
- /// # Panic
- ///
- /// Panics if `color` is not a color value.
- ///
- pub fn clear_color_image<I>(
- &mut self,
- image: I,
- color: ClearValue,
- ) -> Result<&mut Self, ClearColorImageError>
- where
- I: ImageAccess + Send + Sync + 'static,
- {
- let layers = image.dimensions().array_layers();
- let levels = image.mipmap_levels();
-
- self.clear_color_image_dimensions(image, 0, layers, 0, levels, color)
- }
-
- /// Adds a command that clears a color image with a specific value.
- ///
- /// # Panic
- ///
- /// - Panics if `color` is not a color value.
- ///
- pub fn clear_color_image_dimensions<I>(
- &mut self,
- image: I,
- first_layer: u32,
- num_layers: u32,
- first_mipmap: u32,
- num_mipmaps: u32,
- color: ClearValue,
- ) -> Result<&mut Self, ClearColorImageError>
- where
- I: ImageAccess + Send + Sync + 'static,
- {
- unsafe {
- if !self.queue_family().supports_graphics() && !self.queue_family().supports_compute() {
- return Err(AutoCommandBufferBuilderContextError::NotSupportedByQueueFamily.into());
+ CommandBufferInheritanceRenderPassType::BeginRendering(info) => {
+ render_pass_state = Some(RenderPassState {
+ contents: SubpassContents::Inline,
+ render_area_offset,
+ render_area_extent,
+ render_pass: BeginRenderingState {
+ attachments: None,
+ color_attachment_formats: info.color_attachment_formats.clone(),
+ depth_attachment_format: info.depth_attachment_format,
+ stencil_attachment_format: info.stencil_attachment_format,
+ pipeline_used: false,
+ }
+ .into(),
+ view_mask: info.view_mask,
+ });
+ }
+ }
}
-
- self.ensure_outside_render_pass()?;
- check_clear_color_image(
- self.device(),
- &image,
- first_layer,
- num_layers,
- first_mipmap,
- num_mipmaps,
- )?;
-
- match color {
- ClearValue::Float(_) | ClearValue::Int(_) | ClearValue::Uint(_) => {}
- _ => panic!("The clear color is not a color value"),
- };
-
- let region = UnsafeCommandBufferBuilderColorImageClear {
- base_mip_level: first_mipmap,
- level_count: num_mipmaps,
- base_array_layer: first_layer,
- layer_count: num_layers,
- };
-
- // TODO: let choose layout
- self.inner.clear_color_image(
- image,
- ImageLayout::TransferDstOptimal,
- color,
- iter::once(region),
- )?;
- Ok(self)
- }
- }
-
- /// Adds a command that copies from a buffer to another.
- ///
- /// This command will copy from the source to the destination. If their size is not equal, then
- /// the amount of data copied is equal to the smallest of the two.
- #[inline]
- pub fn copy_buffer<S, D, T>(
- &mut self,
- source: S,
- destination: D,
- ) -> Result<&mut Self, CopyBufferError>
- where
- S: TypedBufferAccess<Content = T> + Send + Sync + 'static,
- D: TypedBufferAccess<Content = T> + Send + Sync + 'static,
- T: ?Sized,
- {
- unsafe {
- self.ensure_outside_render_pass()?;
- let infos = check_copy_buffer(self.device(), &source, &destination)?;
- self.inner
- .copy_buffer(source, destination, iter::once((0, 0, infos.copy_size)))?;
- Ok(self)
- }
- }
-
- /// Adds a command that copies a range from the source to the destination buffer.
- /// Panics if out of bounds.
- #[inline]
- pub fn copy_buffer_dimensions<S, D, T>(
- &mut self,
- source: S,
- source_offset: DeviceSize,
- destination: D,
- destination_offset: DeviceSize,
- count: DeviceSize,
- ) -> Result<&mut Self, CopyBufferError>
- where
- S: TypedBufferAccess<Content = [T]> + Send + Sync + 'static,
- D: TypedBufferAccess<Content = [T]> + Send + Sync + 'static,
- {
- self.ensure_outside_render_pass()?;
-
- let _infos = check_copy_buffer(self.device(), &source, &destination)?;
- debug_assert!(source_offset + count <= source.len());
- debug_assert!(destination_offset + count <= destination.len());
-
- let size = std::mem::size_of::<T>() as DeviceSize;
- unsafe {
- self.inner.copy_buffer(
- source,
- destination,
- iter::once((
- source_offset * size,
- destination_offset * size,
- count * size,
- )),
- )?;
}
- Ok(self)
- }
- /// Adds a command that copies from a buffer to an image.
- pub fn copy_buffer_to_image<S, D, Px>(
- &mut self,
- source: S,
- destination: D,
- ) -> Result<&mut Self, CopyBufferImageError>
- where
- S: TypedBufferAccess<Content = [Px]> + Send + Sync + 'static,
- D: ImageAccess + Send + Sync + 'static,
- Px: Pixel,
- {
- self.ensure_outside_render_pass()?;
-
- let dims = destination.dimensions().width_height_depth();
- self.copy_buffer_to_image_dimensions(source, destination, [0, 0, 0], dims, 0, 1, 0)
- }
+ let builder_alloc = allocator
+ .allocate(queue_family_index, level, 1)?
+ .next()
+ .expect("requested one command buffer from the command pool, but got zero");
- /// Adds a command that copies from a buffer to an image.
- pub fn copy_buffer_to_image_dimensions<S, D, Px>(
- &mut self,
- source: S,
- destination: D,
- offset: [u32; 3],
- size: [u32; 3],
- first_layer: u32,
- num_layers: u32,
- mipmap: u32,
- ) -> Result<&mut Self, CopyBufferImageError>
- where
- S: TypedBufferAccess<Content = [Px]> + Send + Sync + 'static,
- D: ImageAccess + Send + Sync + 'static,
- Px: Pixel,
- {
- unsafe {
- self.ensure_outside_render_pass()?;
-
- check_copy_buffer_image(
- self.device(),
- &source,
- &destination,
- CheckCopyBufferImageTy::BufferToImage,
- offset,
- size,
- first_layer,
- num_layers,
- mipmap,
- )?;
-
- let copy = UnsafeCommandBufferBuilderBufferImageCopy {
- buffer_offset: 0,
- buffer_row_length: 0,
- buffer_image_height: 0,
- image_aspect: if destination.has_color() {
- ImageAspect::Color
- } else {
- unimplemented!()
- },
- image_mip_level: mipmap,
- image_base_array_layer: first_layer,
- image_layer_count: num_layers,
- image_offset: [offset[0] as i32, offset[1] as i32, offset[2] as i32],
- image_extent: size,
- };
-
- self.inner.copy_buffer_to_image(
- source,
- destination,
- ImageLayout::TransferDstOptimal, // TODO: let choose layout
- iter::once(copy),
- )?;
- Ok(self)
- }
- }
-
- /// Adds a command that copies from an image to a buffer.
- // The data layout of the image on the gpu is opaque, as in, it is non of our business how the gpu stores the image.
- // This does not matter since the act of copying the image into a buffer converts it to linear form.
- pub fn copy_image_to_buffer<S, D, Px>(
- &mut self,
- source: S,
- destination: D,
- ) -> Result<&mut Self, CopyBufferImageError>
- where
- S: ImageAccess + Send + Sync + 'static,
- D: TypedBufferAccess<Content = [Px]> + Send + Sync + 'static,
- Px: Pixel,
- {
- self.ensure_outside_render_pass()?;
-
- let dims = source.dimensions().width_height_depth();
- self.copy_image_to_buffer_dimensions(source, destination, [0, 0, 0], dims, 0, 1, 0)
- }
-
- /// Adds a command that copies from an image to a buffer.
- pub fn copy_image_to_buffer_dimensions<S, D, Px>(
- &mut self,
- source: S,
- destination: D,
- offset: [u32; 3],
- size: [u32; 3],
- first_layer: u32,
- num_layers: u32,
- mipmap: u32,
- ) -> Result<&mut Self, CopyBufferImageError>
- where
- S: ImageAccess + Send + Sync + 'static,
- D: TypedBufferAccess<Content = [Px]> + Send + Sync + 'static,
- Px: Pixel,
- {
- unsafe {
- self.ensure_outside_render_pass()?;
-
- check_copy_buffer_image(
- self.device(),
- &destination,
- &source,
- CheckCopyBufferImageTy::ImageToBuffer,
- offset,
- size,
- first_layer,
- num_layers,
- mipmap,
- )?;
-
- let copy = UnsafeCommandBufferBuilderBufferImageCopy {
- buffer_offset: 0,
- buffer_row_length: 0,
- buffer_image_height: 0,
- // TODO: Allow the user to choose aspect
- image_aspect: if source.has_color() {
- ImageAspect::Color
- } else if source.has_depth() {
- ImageAspect::Depth
- } else if source.has_stencil() {
- ImageAspect::Stencil
- } else {
- unimplemented!()
- },
- image_mip_level: mipmap,
- image_base_array_layer: first_layer,
- image_layer_count: num_layers,
- image_offset: [offset[0] as i32, offset[1] as i32, offset[2] as i32],
- image_extent: size,
- };
-
- self.inner.copy_image_to_buffer(
- source,
- ImageLayout::TransferSrcOptimal,
- destination, // TODO: let choose layout
- iter::once(copy),
- )?;
- Ok(self)
- }
- }
-
- /// Open a command buffer debug label region.
- ///
- /// Note: you need to enable `VK_EXT_debug_utils` extension when creating an instance.
- #[inline]
- pub fn debug_marker_begin(
- &mut self,
- name: &'static CStr,
- color: [f32; 4],
- ) -> Result<&mut Self, DebugMarkerError> {
- if !self.queue_family().supports_graphics() && self.queue_family().supports_compute() {
- return Err(AutoCommandBufferBuilderContextError::NotSupportedByQueueFamily.into());
- }
-
- check_debug_marker_color(color)?;
-
- unsafe {
- self.inner.debug_marker_begin(name.into(), color);
- }
+ let inner = SyncCommandBufferBuilder::new(builder_alloc.inner(), begin_info)?;
- Ok(self)
+ Ok(AutoCommandBufferBuilder {
+ inner,
+ builder_alloc,
+ queue_family_index,
+ render_pass_state,
+ query_state: HashMap::default(),
+ inheritance_info,
+ usage,
+ _data: PhantomData,
+ })
}
- /// Close a command buffer label region.
- ///
- /// Note: you need to open a command buffer label region first with `debug_marker_begin`.
- /// Note: you need to enable `VK_EXT_debug_utils` extension when creating an instance.
- #[inline]
- pub fn debug_marker_end(&mut self) -> Result<&mut Self, DebugMarkerError> {
- if !self.queue_family().supports_graphics() && self.queue_family().supports_compute() {
- return Err(AutoCommandBufferBuilderContextError::NotSupportedByQueueFamily.into());
- }
-
- // TODO: validate that debug_marker_begin with same name was sent earlier
-
- unsafe {
- self.inner.debug_marker_end();
- }
-
- Ok(self)
- }
+ fn validate_begin(
+ device: &Device,
+ _queue_family_index: u32,
+ level: CommandBufferLevel,
+ begin_info: &CommandBufferBeginInfo,
+ ) -> Result<(), CommandBufferBeginError> {
+ let physical_device = device.physical_device();
+ let properties = physical_device.properties();
+
+ let &CommandBufferBeginInfo {
+ usage: _,
+ ref inheritance_info,
+ _ne: _,
+ } = &begin_info;
+
+ if let Some(inheritance_info) = &inheritance_info {
+ debug_assert!(level == CommandBufferLevel::Secondary);
+
+ let &CommandBufferInheritanceInfo {
+ ref render_pass,
+ occlusion_query,
+ query_statistics_flags,
+ _ne: _,
+ } = inheritance_info;
+
+ if let Some(render_pass) = render_pass {
+ // VUID-VkCommandBufferBeginInfo-flags-06000
+ // VUID-VkCommandBufferBeginInfo-flags-06002
+ // Ensured by the definition of the `CommandBufferInheritanceRenderPassType` enum.
+
+ match render_pass {
+ CommandBufferInheritanceRenderPassType::BeginRenderPass(render_pass_info) => {
+ let &CommandBufferInheritanceRenderPassInfo {
+ ref subpass,
+ ref framebuffer,
+ } = render_pass_info;
+
+ // VUID-VkCommandBufferInheritanceInfo-commonparent
+ assert_eq!(device, subpass.render_pass().device().as_ref());
+
+ // VUID-VkCommandBufferBeginInfo-flags-06001
+ // Ensured by how the `Subpass` type is constructed.
+
+ if let Some(framebuffer) = framebuffer {
+ // VUID-VkCommandBufferInheritanceInfo-commonparent
+ assert_eq!(device, framebuffer.device().as_ref());
+
+ // VUID-VkCommandBufferBeginInfo-flags-00055
+ if !framebuffer
+ .render_pass()
+ .is_compatible_with(subpass.render_pass())
+ {
+ return Err(CommandBufferBeginError::FramebufferNotCompatible);
+ }
+ }
+ }
+ CommandBufferInheritanceRenderPassType::BeginRendering(rendering_info) => {
+ let &CommandBufferInheritanceRenderingInfo {
+ view_mask,
+ ref color_attachment_formats,
+ depth_attachment_format,
+ stencil_attachment_format,
+ rasterization_samples,
+ } = rendering_info;
+
+ // VUID-VkCommandBufferInheritanceRenderingInfo-multiview-06008
+ if view_mask != 0 && !device.enabled_features().multiview {
+ return Err(CommandBufferBeginError::RequirementNotMet {
+ required_for: "`inheritance_info.render_pass` is \
+ `CommandBufferInheritanceRenderPassType::BeginRendering`, \
+ where `view_mask` is not `0`",
+ requires_one_of: RequiresOneOf {
+ features: &["multiview"],
+ ..Default::default()
+ },
+ });
+ }
- /// Insert a label into a command buffer.
- ///
- /// Note: you need to enable `VK_EXT_debug_utils` extension when creating an instance.
- #[inline]
- pub fn debug_marker_insert(
- &mut self,
- name: &'static CStr,
- color: [f32; 4],
- ) -> Result<&mut Self, DebugMarkerError> {
- if !self.queue_family().supports_graphics() && self.queue_family().supports_compute() {
- return Err(AutoCommandBufferBuilderContextError::NotSupportedByQueueFamily.into());
- }
+ let view_count = u32::BITS - view_mask.leading_zeros();
- check_debug_marker_color(color)?;
+ // VUID-VkCommandBufferInheritanceRenderingInfo-viewMask-06009
+ if view_count > properties.max_multiview_view_count.unwrap_or(0) {
+ return Err(CommandBufferBeginError::MaxMultiviewViewCountExceeded {
+ view_count,
+ max: properties.max_multiview_view_count.unwrap_or(0),
+ });
+ }
- unsafe {
- self.inner.debug_marker_insert(name.into(), color);
- }
+ for (attachment_index, format) in color_attachment_formats
+ .iter()
+ .enumerate()
+ .flat_map(|(i, f)| f.map(|f| (i, f)))
+ {
+ let attachment_index = attachment_index as u32;
+
+ // VUID-VkCommandBufferInheritanceRenderingInfo-pColorAttachmentFormats-parameter
+ format.validate_device(device)?;
+
+ // VUID-VkCommandBufferInheritanceRenderingInfo-pColorAttachmentFormats-06006
+ // Use unchecked, because all validation has been done above.
+ if !unsafe { physical_device.format_properties_unchecked(format) }
+ .potential_format_features()
+ .intersects(FormatFeatures::COLOR_ATTACHMENT)
+ {
+ return Err(
+ CommandBufferBeginError::ColorAttachmentFormatUsageNotSupported {
+ attachment_index,
+ },
+ );
+ }
+ }
- Ok(self)
- }
+ if let Some(format) = depth_attachment_format {
+ // VUID-VkCommandBufferInheritanceRenderingInfo-depthAttachmentFormat-parameter
+ format.validate_device(device)?;
- /// Perform a single compute operation using a compute pipeline.
- #[inline]
- pub fn dispatch<Cp, S, Pc>(
- &mut self,
- group_counts: [u32; 3],
- pipeline: Cp,
- descriptor_sets: S,
- push_constants: Pc,
- ) -> Result<&mut Self, DispatchError>
- where
- Cp: ComputePipelineAbstract + Send + Sync + 'static + Clone, // TODO: meh for Clone
- S: DescriptorSetsCollection,
- {
- let descriptor_sets = descriptor_sets.into_vec();
+ // VUID-VkCommandBufferInheritanceRenderingInfo-depthAttachmentFormat-06540
+ if !format.aspects().intersects(ImageAspects::DEPTH) {
+ return Err(
+ CommandBufferBeginError::DepthAttachmentFormatUsageNotSupported,
+ );
+ }
- unsafe {
- if !self.queue_family().supports_compute() {
- return Err(AutoCommandBufferBuilderContextError::NotSupportedByQueueFamily.into());
- }
+ // VUID-VkCommandBufferInheritanceRenderingInfo-depthAttachmentFormat-06007
+ // Use unchecked, because all validation has been done above.
+ if !unsafe { physical_device.format_properties_unchecked(format) }
+ .potential_format_features()
+ .intersects(FormatFeatures::DEPTH_STENCIL_ATTACHMENT)
+ {
+ return Err(
+ CommandBufferBeginError::DepthAttachmentFormatUsageNotSupported,
+ );
+ }
+ }
- self.ensure_outside_render_pass()?;
- check_push_constants_validity(pipeline.layout(), &push_constants)?;
- check_descriptor_sets_validity(pipeline.layout(), &descriptor_sets)?;
- check_dispatch(pipeline.device(), group_counts)?;
+ if let Some(format) = stencil_attachment_format {
+ // VUID-VkCommandBufferInheritanceRenderingInfo-stencilAttachmentFormat-parameter
+ format.validate_device(device)?;
- if let StateCacherOutcome::NeedChange =
- self.state_cacher.bind_compute_pipeline(&pipeline)
- {
- self.inner.bind_pipeline_compute(pipeline.clone());
- }
+ // VUID-VkCommandBufferInheritanceRenderingInfo-stencilAttachmentFormat-06541
+ if !format.aspects().intersects(ImageAspects::STENCIL) {
+ return Err(
+ CommandBufferBeginError::StencilAttachmentFormatUsageNotSupported,
+ );
+ }
- set_push_constants(&mut self.inner, pipeline.layout(), push_constants);
- bind_descriptor_sets(
- &mut self.inner,
- &mut self.state_cacher,
- PipelineBindPoint::Compute,
- pipeline.layout(),
- descriptor_sets,
- )?;
-
- self.inner.dispatch(group_counts);
- Ok(self)
- }
- }
+ // VUID-VkCommandBufferInheritanceRenderingInfo-stencilAttachmentFormat-06199
+ // Use unchecked, because all validation has been done above.
+ if !unsafe { physical_device.format_properties_unchecked(format) }
+ .potential_format_features()
+ .intersects(FormatFeatures::DEPTH_STENCIL_ATTACHMENT)
+ {
+ return Err(
+ CommandBufferBeginError::StencilAttachmentFormatUsageNotSupported,
+ );
+ }
+ }
- /// Perform multiple compute operations using a compute pipeline. One dispatch is performed for
- /// each `vulkano::command_buffer::DispatchIndirectCommand` struct in `indirect_buffer`.
- #[inline]
- pub fn dispatch_indirect<Inb, Cp, S, Pc>(
- &mut self,
- indirect_buffer: Inb,
- pipeline: Cp,
- descriptor_sets: S,
- push_constants: Pc,
- ) -> Result<&mut Self, DispatchIndirectError>
- where
- Inb: BufferAccess
- + TypedBufferAccess<Content = [DispatchIndirectCommand]>
- + Send
- + Sync
- + 'static,
- Cp: ComputePipelineAbstract + Send + Sync + 'static + Clone, // TODO: meh for Clone
- S: DescriptorSetsCollection,
- {
- let descriptor_sets = descriptor_sets.into_vec();
+ if let (Some(depth_format), Some(stencil_format)) =
+ (depth_attachment_format, stencil_attachment_format)
+ {
+ // VUID-VkCommandBufferInheritanceRenderingInfo-depthAttachmentFormat-06200
+ if depth_format != stencil_format {
+ return Err(
+ CommandBufferBeginError::DepthStencilAttachmentFormatMismatch,
+ );
+ }
+ }
- unsafe {
- if !self.queue_family().supports_compute() {
- return Err(AutoCommandBufferBuilderContextError::NotSupportedByQueueFamily.into());
+ // VUID-VkCommandBufferInheritanceRenderingInfo-rasterizationSamples-parameter
+ rasterization_samples.validate_device(device)?;
+ }
+ }
}
- self.ensure_outside_render_pass()?;
- check_indirect_buffer(self.device(), &indirect_buffer)?;
- check_push_constants_validity(pipeline.layout(), &push_constants)?;
- check_descriptor_sets_validity(pipeline.layout(), &descriptor_sets)?;
+ if let Some(control_flags) = occlusion_query {
+ // VUID-VkCommandBufferInheritanceInfo-queryFlags-00057
+ control_flags.validate_device(device)?;
+
+ // VUID-VkCommandBufferInheritanceInfo-occlusionQueryEnable-00056
+ // VUID-VkCommandBufferInheritanceInfo-queryFlags-02788
+ if !device.enabled_features().inherited_queries {
+ return Err(CommandBufferBeginError::RequirementNotMet {
+ required_for: "`inheritance_info.occlusion_query` is `Some`",
+ requires_one_of: RequiresOneOf {
+ features: &["inherited_queries"],
+ ..Default::default()
+ },
+ });
+ }
- if let StateCacherOutcome::NeedChange =
- self.state_cacher.bind_compute_pipeline(&pipeline)
- {
- self.inner.bind_pipeline_compute(pipeline.clone());
+ // VUID-vkBeginCommandBuffer-commandBuffer-00052
+ if control_flags.intersects(QueryControlFlags::PRECISE)
+ && !device.enabled_features().occlusion_query_precise
+ {
+ return Err(CommandBufferBeginError::RequirementNotMet {
+ required_for: "`inheritance_info.occlusion_query` is \
+ `Some(control_flags)`, where `control_flags` contains \
+ `QueryControlFlags::PRECISE`",
+ requires_one_of: RequiresOneOf {
+ features: &["occlusion_query_precise"],
+ ..Default::default()
+ },
+ });
+ }
}
- set_push_constants(&mut self.inner, pipeline.layout(), push_constants);
- bind_descriptor_sets(
- &mut self.inner,
- &mut self.state_cacher,
- PipelineBindPoint::Compute,
- pipeline.layout(),
- descriptor_sets,
- )?;
-
- self.inner.dispatch_indirect(indirect_buffer)?;
- Ok(self)
- }
- }
-
- /// Perform a single draw operation using a graphics pipeline.
- ///
- /// `vertex_buffer` is a set of vertex and/or instance buffers used to provide input.
- ///
- /// All data in `vertex_buffer` is used for the draw operation. To use only some data in the
- /// buffer, wrap it in a `vulkano::buffer::BufferSlice`.
- #[inline]
- pub fn draw<V, Gp, S, Pc>(
- &mut self,
- pipeline: Gp,
- dynamic: &DynamicState,
- vertex_buffers: V,
- descriptor_sets: S,
- push_constants: Pc,
- ) -> Result<&mut Self, DrawError>
- where
- Gp: GraphicsPipelineAbstract + VertexSource<V> + Send + Sync + 'static + Clone, // TODO: meh for Clone
- S: DescriptorSetsCollection,
- {
- let descriptor_sets = descriptor_sets.into_vec();
-
- unsafe {
- // TODO: must check that pipeline is compatible with render pass
+ // VUID-VkCommandBufferInheritanceInfo-pipelineStatistics-02789
+ query_statistics_flags.validate_device(device)?;
- self.ensure_inside_render_pass_inline(&pipeline)?;
- check_dynamic_state_validity(&pipeline, dynamic)?;
- check_push_constants_validity(pipeline.layout(), &push_constants)?;
- check_descriptor_sets_validity(pipeline.layout(), &descriptor_sets)?;
- let vb_infos = check_vertex_buffers(&pipeline, vertex_buffers)?;
-
- if let StateCacherOutcome::NeedChange =
- self.state_cacher.bind_graphics_pipeline(&pipeline)
+ // VUID-VkCommandBufferInheritanceInfo-pipelineStatistics-00058
+ if query_statistics_flags.count() > 0
+ && !device.enabled_features().pipeline_statistics_query
{
- self.inner.bind_pipeline_graphics(pipeline.clone());
+ return Err(CommandBufferBeginError::RequirementNotMet {
+ required_for: "`inheritance_info.query_statistics_flags` is not empty",
+ requires_one_of: RequiresOneOf {
+ features: &["pipeline_statistics_query"],
+ ..Default::default()
+ },
+ });
}
+ } else {
+ debug_assert!(level == CommandBufferLevel::Primary);
- let dynamic = self.state_cacher.dynamic_state(dynamic);
-
- set_push_constants(&mut self.inner, pipeline.layout(), push_constants);
- set_state(&mut self.inner, &dynamic);
- bind_descriptor_sets(
- &mut self.inner,
- &mut self.state_cacher,
- PipelineBindPoint::Graphics,
- pipeline.layout(),
- descriptor_sets,
- )?;
- bind_vertex_buffers(
- &mut self.inner,
- &mut self.state_cacher,
- vb_infos.vertex_buffers,
- )?;
-
- debug_assert!(self.queue_family().supports_graphics());
-
- self.inner.draw(
- vb_infos.vertex_count as u32,
- vb_infos.instance_count as u32,
- 0,
- 0,
- );
- Ok(self)
+ // VUID-vkBeginCommandBuffer-commandBuffer-02840
+ // Ensured by the definition of the `CommandBufferUsage` enum.
}
- }
-
- /// Perform multiple draw operations using a graphics pipeline.
- ///
- /// One draw is performed for each [`DrawIndirectCommand`] struct in `indirect_buffer`.
- /// The maximum number of draw commands in the buffer is limited by the
- /// [`max_draw_indirect_count`](crate::device::Properties::max_draw_indirect_count) limit.
- /// This limit is 1 unless the
- /// [`multi_draw_indirect`](crate::device::Features::multi_draw_indirect) feature has been
- /// enabled.
- ///
- /// `vertex_buffer` is a set of vertex and/or instance buffers used to provide input. It is
- /// used for every draw operation.
- ///
- /// All data in `vertex_buffer` is used for every draw operation. To use only some data in the
- /// buffer, wrap it in a `vulkano::buffer::BufferSlice`.
- #[inline]
- pub fn draw_indirect<V, Gp, S, Pc, Inb>(
- &mut self,
- pipeline: Gp,
- dynamic: &DynamicState,
- vertex_buffers: V,
- indirect_buffer: Inb,
- descriptor_sets: S,
- push_constants: Pc,
- ) -> Result<&mut Self, DrawIndirectError>
- where
- Gp: GraphicsPipelineAbstract + VertexSource<V> + Send + Sync + 'static + Clone, // TODO: meh for Clone
- S: DescriptorSetsCollection,
- Inb: BufferAccess
- + TypedBufferAccess<Content = [DrawIndirectCommand]>
- + Send
- + Sync
- + 'static,
- {
- let descriptor_sets = descriptor_sets.into_vec();
-
- unsafe {
- // TODO: must check that pipeline is compatible with render pass
-
- self.ensure_inside_render_pass_inline(&pipeline)?;
- check_indirect_buffer(self.device(), &indirect_buffer)?;
- check_dynamic_state_validity(&pipeline, dynamic)?;
- check_push_constants_validity(pipeline.layout(), &push_constants)?;
- check_descriptor_sets_validity(pipeline.layout(), &descriptor_sets)?;
- let vb_infos = check_vertex_buffers(&pipeline, vertex_buffers)?;
-
- let requested = indirect_buffer.len() as u32;
- let limit = self
- .device()
- .physical_device()
- .properties()
- .max_draw_indirect_count;
-
- if requested > limit {
- return Err(
- CheckIndirectBufferError::MaxDrawIndirectCountLimitExceeded {
- limit,
- requested,
- }
- .into(),
- );
- }
-
- if let StateCacherOutcome::NeedChange =
- self.state_cacher.bind_graphics_pipeline(&pipeline)
- {
- self.inner.bind_pipeline_graphics(pipeline.clone());
- }
- let dynamic = self.state_cacher.dynamic_state(dynamic);
-
- set_push_constants(&mut self.inner, pipeline.layout(), push_constants);
- set_state(&mut self.inner, &dynamic);
- bind_descriptor_sets(
- &mut self.inner,
- &mut self.state_cacher,
- PipelineBindPoint::Graphics,
- pipeline.layout(),
- descriptor_sets,
- )?;
- bind_vertex_buffers(
- &mut self.inner,
- &mut self.state_cacher,
- vb_infos.vertex_buffers,
- )?;
-
- debug_assert!(self.queue_family().supports_graphics());
-
- self.inner.draw_indirect(
- indirect_buffer,
- requested,
- mem::size_of::<DrawIndirectCommand>() as u32,
- )?;
- Ok(self)
- }
+ Ok(())
}
+}
- /// Perform a single draw operation using a graphics pipeline, using an index buffer.
- ///
- /// `vertex_buffer` is a set of vertex and/or instance buffers used to provide input.
- /// `index_buffer` is a buffer containing indices into the vertex buffer that should be
- /// processed in order.
- ///
- /// All data in `vertex_buffer` and `index_buffer` is used for the draw operation. To use
- /// only some data in the buffer, wrap it in a `vulkano::buffer::BufferSlice`.
- #[inline]
- pub fn draw_indexed<V, Gp, S, Pc, Ib, I>(
- &mut self,
- pipeline: Gp,
- dynamic: &DynamicState,
- vertex_buffers: V,
- index_buffer: Ib,
- descriptor_sets: S,
- push_constants: Pc,
- ) -> Result<&mut Self, DrawIndexedError>
- where
- Gp: GraphicsPipelineAbstract + VertexSource<V> + Send + Sync + 'static + Clone, // TODO: meh for Clone
- S: DescriptorSetsCollection,
- Ib: BufferAccess + TypedBufferAccess<Content = [I]> + Send + Sync + 'static,
- I: Index + 'static,
- {
- let descriptor_sets = descriptor_sets.into_vec();
-
- unsafe {
- // TODO: must check that pipeline is compatible with render pass
-
- self.ensure_inside_render_pass_inline(&pipeline)?;
- let ib_infos = check_index_buffer(self.device(), &index_buffer)?;
- check_dynamic_state_validity(&pipeline, dynamic)?;
- check_push_constants_validity(pipeline.layout(), &push_constants)?;
- check_descriptor_sets_validity(pipeline.layout(), &descriptor_sets)?;
- let vb_infos = check_vertex_buffers(&pipeline, vertex_buffers)?;
-
- if let StateCacherOutcome::NeedChange =
- self.state_cacher.bind_graphics_pipeline(&pipeline)
- {
- self.inner.bind_pipeline_graphics(pipeline.clone());
- }
-
- if let StateCacherOutcome::NeedChange =
- self.state_cacher.bind_index_buffer(&index_buffer, I::ty())
- {
- self.inner.bind_index_buffer(index_buffer, I::ty())?;
- }
-
- let dynamic = self.state_cacher.dynamic_state(dynamic);
-
- set_push_constants(&mut self.inner, pipeline.layout(), push_constants);
- set_state(&mut self.inner, &dynamic);
- bind_descriptor_sets(
- &mut self.inner,
- &mut self.state_cacher,
- PipelineBindPoint::Graphics,
- pipeline.layout(),
- descriptor_sets,
- )?;
- bind_vertex_buffers(
- &mut self.inner,
- &mut self.state_cacher,
- vb_infos.vertex_buffers,
- )?;
- // TODO: how to handle an index out of range of the vertex buffers?
-
- debug_assert!(self.queue_family().supports_graphics());
-
- self.inner.draw_indexed(
- ib_infos.num_indices as u32,
- vb_infos.instance_count as u32,
- 0,
- 0,
- 0,
- );
- Ok(self)
- }
- }
+/// Error that can happen when beginning recording of a command buffer.
+#[derive(Clone, Copy, Debug)]
+pub enum CommandBufferBeginError {
+ /// Not enough memory.
+ OomError(OomError),
- /// Perform multiple draw operations using a graphics pipeline, using an index buffer.
- ///
- /// One draw is performed for each [`DrawIndirectCommand`] struct in `indirect_buffer`.
- /// The maximum number of draw commands in the buffer is limited by the
- /// [`max_draw_indirect_count`](crate::device::Properties::max_draw_indirect_count) limit.
- /// This limit is 1 unless the
- /// [`multi_draw_indirect`](crate::device::Features::multi_draw_indirect) feature has been
- /// enabled.
- ///
- /// `vertex_buffer` is a set of vertex and/or instance buffers used to provide input.
- /// `index_buffer` is a buffer containing indices into the vertex buffer that should be
- /// processed in order.
- ///
- /// All data in `vertex_buffer` and `index_buffer` is used for every draw operation. To use
- /// only some data in the buffer, wrap it in a `vulkano::buffer::BufferSlice`.
- #[inline]
- pub fn draw_indexed_indirect<V, Gp, S, Pc, Ib, Inb, I>(
- &mut self,
- pipeline: Gp,
- dynamic: &DynamicState,
- vertex_buffers: V,
- index_buffer: Ib,
- indirect_buffer: Inb,
- descriptor_sets: S,
- push_constants: Pc,
- ) -> Result<&mut Self, DrawIndexedIndirectError>
- where
- Gp: GraphicsPipelineAbstract + VertexSource<V> + Send + Sync + 'static + Clone, // TODO: meh for Clone
- S: DescriptorSetsCollection,
- Ib: BufferAccess + TypedBufferAccess<Content = [I]> + Send + Sync + 'static,
- Inb: BufferAccess
- + TypedBufferAccess<Content = [DrawIndexedIndirectCommand]>
- + Send
- + Sync
- + 'static,
- I: Index + 'static,
- {
- let descriptor_sets = descriptor_sets.into_vec();
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
- unsafe {
- // TODO: must check that pipeline is compatible with render pass
-
- self.ensure_inside_render_pass_inline(&pipeline)?;
- let ib_infos = check_index_buffer(self.device(), &index_buffer)?;
- check_indirect_buffer(self.device(), &indirect_buffer)?;
- check_dynamic_state_validity(&pipeline, dynamic)?;
- check_push_constants_validity(pipeline.layout(), &push_constants)?;
- check_descriptor_sets_validity(pipeline.layout(), &descriptor_sets)?;
- let vb_infos = check_vertex_buffers(&pipeline, vertex_buffers)?;
-
- let requested = indirect_buffer.len() as u32;
- let limit = self
- .device()
- .physical_device()
- .properties()
- .max_draw_indirect_count;
-
- if requested > limit {
- return Err(
- CheckIndirectBufferError::MaxDrawIndirectCountLimitExceeded {
- limit,
- requested,
- }
- .into(),
- );
- }
+ /// A color attachment has a format that does not support that usage.
+ ColorAttachmentFormatUsageNotSupported { attachment_index: u32 },
- if let StateCacherOutcome::NeedChange =
- self.state_cacher.bind_graphics_pipeline(&pipeline)
- {
- self.inner.bind_pipeline_graphics(pipeline.clone());
- }
+ /// The depth attachment has a format that does not support that usage.
+ DepthAttachmentFormatUsageNotSupported,
- if let StateCacherOutcome::NeedChange =
- self.state_cacher.bind_index_buffer(&index_buffer, I::ty())
- {
- self.inner.bind_index_buffer(index_buffer, I::ty())?;
- }
+ /// The depth and stencil attachments have different formats.
+ DepthStencilAttachmentFormatMismatch,
- let dynamic = self.state_cacher.dynamic_state(dynamic);
-
- set_push_constants(&mut self.inner, pipeline.layout(), push_constants);
- set_state(&mut self.inner, &dynamic);
- bind_descriptor_sets(
- &mut self.inner,
- &mut self.state_cacher,
- PipelineBindPoint::Graphics,
- pipeline.layout(),
- descriptor_sets,
- )?;
- bind_vertex_buffers(
- &mut self.inner,
- &mut self.state_cacher,
- vb_infos.vertex_buffers,
- )?;
-
- debug_assert!(self.queue_family().supports_graphics());
-
- self.inner.draw_indexed_indirect(
- indirect_buffer,
- requested,
- mem::size_of::<DrawIndexedIndirectCommand>() as u32,
- )?;
- Ok(self)
- }
- }
+ /// The framebuffer is not compatible with the render pass.
+ FramebufferNotCompatible,
- /// Adds a command that writes the content of a buffer.
- ///
- /// This function is similar to the `memset` function in C. The `data` parameter is a number
- /// that will be repeatedly written through the entire buffer.
- ///
- /// > **Note**: This function is technically safe because buffers can only contain integers or
- /// > floating point numbers, which are always valid whatever their memory representation is.
- /// > But unless your buffer actually contains only 32-bits integers, you are encouraged to use
- /// > this function only for zeroing the content of a buffer by passing `0` for the data.
- // TODO: not safe because of signalling NaNs
- #[inline]
- pub fn fill_buffer<B>(&mut self, buffer: B, data: u32) -> Result<&mut Self, FillBufferError>
- where
- B: BufferAccess + Send + Sync + 'static,
- {
- unsafe {
- self.ensure_outside_render_pass()?;
- check_fill_buffer(self.device(), &buffer)?;
- self.inner.fill_buffer(buffer, data);
- Ok(self)
- }
- }
+ /// The `max_multiview_view_count` limit has been exceeded.
+ MaxMultiviewViewCountExceeded { view_count: u32, max: u32 },
- /// Adds a command that writes data to a buffer.
- ///
- /// If `data` is larger than the buffer, only the part of `data` that fits is written. If the
- /// buffer is larger than `data`, only the start of the buffer is written.
- #[inline]
- pub fn update_buffer<B, D, Dd>(
- &mut self,
- buffer: B,
- data: Dd,
- ) -> Result<&mut Self, UpdateBufferError>
- where
- B: TypedBufferAccess<Content = D> + Send + Sync + 'static,
- D: ?Sized,
- Dd: SafeDeref<Target = D> + Send + Sync + 'static,
- {
- unsafe {
- self.ensure_outside_render_pass()?;
- check_update_buffer(self.device(), &buffer, data.deref())?;
-
- let size_of_data = mem::size_of_val(data.deref()) as DeviceSize;
- if buffer.size() >= size_of_data {
- self.inner.update_buffer(buffer, data);
- } else {
- unimplemented!() // TODO:
- //self.inner.update_buffer(buffer.slice(0 .. size_of_data), data);
- }
+ /// The stencil attachment has a format that does not support that usage.
+ StencilAttachmentFormatUsageNotSupported,
+}
- Ok(self)
+impl Error for CommandBufferBeginError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::OomError(err) => Some(err),
+ _ => None,
}
}
+}
- /// Adds a command that begins a query.
- ///
- /// The query will be active until [`end_query`](Self::end_query) is called for the same query.
- ///
- /// # Safety
- /// The query must be unavailable, ensured by calling [`reset_query_pool`](Self::reset_query_pool).
- pub unsafe fn begin_query(
- &mut self,
- query_pool: Arc<QueryPool>,
- query: u32,
- flags: QueryControlFlags,
- ) -> Result<&mut Self, BeginQueryError> {
- check_begin_query(self.device(), &query_pool, query, flags)?;
-
- match query_pool.ty() {
- QueryType::Occlusion => {
- if !self.queue_family().supports_graphics() {
- return Err(
- AutoCommandBufferBuilderContextError::NotSupportedByQueueFamily.into(),
- );
- }
- }
- QueryType::PipelineStatistics(flags) => {
- if flags.is_compute() && !self.queue_family().supports_compute()
- || flags.is_graphics() && !self.queue_family().supports_graphics()
- {
- return Err(
- AutoCommandBufferBuilderContextError::NotSupportedByQueueFamily.into(),
- );
- }
+impl Display for CommandBufferBeginError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::OomError(_) => write!(f, "not enough memory available"),
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ Self::ColorAttachmentFormatUsageNotSupported { attachment_index } => write!(
+ f,
+ "color attachment {} has a format that does not support that usage",
+ attachment_index,
+ ),
+ Self::DepthAttachmentFormatUsageNotSupported => write!(
+ f,
+ "the depth attachment has a format that does not support that usage",
+ ),
+ Self::DepthStencilAttachmentFormatMismatch => write!(
+ f,
+ "the depth and stencil attachments have different formats",
+ ),
+ Self::FramebufferNotCompatible => {
+ write!(f, "the framebuffer is not compatible with the render pass")
}
- QueryType::Timestamp => unreachable!(),
- }
-
- let ty = query_pool.ty();
- let raw_ty = ty.into();
- let raw_query_pool = query_pool.internal_object();
- if self.query_state.contains_key(&raw_ty) {
- return Err(AutoCommandBufferBuilderContextError::QueryIsActive.into());
- }
-
- // TODO: validity checks
- self.inner.begin_query(query_pool, query, flags);
- self.query_state.insert(
- raw_ty,
- QueryState {
- query_pool: raw_query_pool,
- query,
- ty,
- flags,
- in_subpass: self.render_pass_state.is_some(),
- },
- );
-
- Ok(self)
- }
-
- /// Adds a command that ends an active query.
- pub fn end_query(
- &mut self,
- query_pool: Arc<QueryPool>,
- query: u32,
- ) -> Result<&mut Self, EndQueryError> {
- unsafe {
- check_end_query(self.device(), &query_pool, query)?;
-
- let raw_ty = query_pool.ty().into();
- let raw_query_pool = query_pool.internal_object();
- if !self.query_state.get(&raw_ty).map_or(false, |state| {
- state.query_pool == raw_query_pool && state.query == query
- }) {
- return Err(AutoCommandBufferBuilderContextError::QueryNotActive.into());
+ Self::MaxMultiviewViewCountExceeded { .. } => {
+ write!(f, "the `max_multiview_view_count` limit has been exceeded")
}
-
- self.inner.end_query(query_pool, query);
- self.query_state.remove(&raw_ty);
- }
-
- Ok(self)
- }
-
- /// Adds a command that writes a timestamp to a timestamp query.
- ///
- /// # Safety
- /// The query must be unavailable, ensured by calling [`reset_query_pool`](Self::reset_query_pool).
- pub unsafe fn write_timestamp(
- &mut self,
- query_pool: Arc<QueryPool>,
- query: u32,
- stage: PipelineStage,
- ) -> Result<&mut Self, WriteTimestampError> {
- check_write_timestamp(
- self.device(),
- self.queue_family(),
- &query_pool,
- query,
- stage,
- )?;
-
- if !(self.queue_family().supports_graphics()
- || self.queue_family().supports_compute()
- || self.queue_family().explicitly_supports_transfers())
- {
- return Err(AutoCommandBufferBuilderContextError::NotSupportedByQueueFamily.into());
+ Self::StencilAttachmentFormatUsageNotSupported => write!(
+ f,
+ "the stencil attachment has a format that does not support that usage",
+ ),
}
-
- // TODO: validity checks
- self.inner.write_timestamp(query_pool, query, stage);
-
- Ok(self)
}
+}
- /// Adds a command that copies the results of a range of queries to a buffer on the GPU.
- ///
- /// [`query_pool.ty().result_size()`](crate::query::QueryType::result_size) elements
- /// will be written for each query in the range, plus 1 extra element per query if
- /// [`QueryResultFlags::with_availability`] is enabled.
- /// The provided buffer must be large enough to hold the data.
- ///
- /// See also [`get_results`](crate::query::QueriesRange::get_results).
- pub fn copy_query_pool_results<D, T>(
- &mut self,
- query_pool: Arc<QueryPool>,
- queries: Range<u32>,
- destination: D,
- flags: QueryResultFlags,
- ) -> Result<&mut Self, CopyQueryPoolResultsError>
- where
- D: BufferAccess + TypedBufferAccess<Content = [T]> + Send + Sync + 'static,
- T: QueryResultElement,
- {
- unsafe {
- self.ensure_outside_render_pass()?;
- let stride = check_copy_query_pool_results(
- self.device(),
- &query_pool,
- queries.clone(),
- &destination,
- flags,
- )?;
- self.inner
- .copy_query_pool_results(query_pool, queries, destination, stride, flags)?;
- }
-
- Ok(self)
+impl From<OomError> for CommandBufferBeginError {
+ fn from(err: OomError) -> Self {
+ Self::OomError(err)
}
+}
- /// Adds a command to reset a range of queries on a query pool.
- ///
- /// The affected queries will be marked as "unavailable" after this command runs, and will no
- /// longer return any results. They will be ready to have new results recorded for them.
- ///
- /// # Safety
- /// The queries in the specified range must not be active in another command buffer.
- pub unsafe fn reset_query_pool(
- &mut self,
- query_pool: Arc<QueryPool>,
- queries: Range<u32>,
- ) -> Result<&mut Self, ResetQueryPoolError> {
- self.ensure_outside_render_pass()?;
- check_reset_query_pool(self.device(), &query_pool, queries.clone())?;
-
- let raw_query_pool = query_pool.internal_object();
- if self
- .query_state
- .values()
- .any(|state| state.query_pool == raw_query_pool && queries.contains(&state.query))
- {
- return Err(AutoCommandBufferBuilderContextError::QueryIsActive.into());
+impl From<RequirementNotMet> for CommandBufferBeginError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
}
-
- // TODO: validity checks
- // Do other command buffers actually matter here? Not sure on the Vulkan spec.
- self.inner.reset_query_pool(query_pool, queries);
-
- Ok(self)
}
}
-/// Commands that can only be executed on primary command buffers
-impl<P> AutoCommandBufferBuilder<PrimaryAutoCommandBuffer<P::Alloc>, P>
+impl<A> AutoCommandBufferBuilder<PrimaryAutoCommandBuffer<A::Alloc>, A>
where
- P: CommandPoolBuilderAlloc,
+ A: CommandBufferAllocator,
{
- /// Adds a command that enters a render pass.
- ///
- /// If `contents` is `SubpassContents::SecondaryCommandBuffers`, then you will only be able to
- /// add secondary command buffers while you're inside the first subpass of the render pass.
- /// If it is `SubpassContents::Inline`, you will only be able to add inline draw commands and
- /// not secondary command buffers.
- ///
- /// C must contain exactly one clear value for each attachment in the framebuffer.
- ///
- /// You must call this before you can add draw commands.
- #[inline]
- pub fn begin_render_pass<F, I>(
- &mut self,
- framebuffer: F,
- contents: SubpassContents,
- clear_values: I,
- ) -> Result<&mut Self, BeginRenderPassError>
- where
- F: FramebufferAbstract + Clone + Send + Sync + 'static,
- I: IntoIterator<Item = ClearValue>,
- {
- unsafe {
- if !self.queue_family().supports_graphics() {
- return Err(AutoCommandBufferBuilderContextError::NotSupportedByQueueFamily.into());
- }
-
- self.ensure_outside_render_pass()?;
-
- let clear_values = framebuffer
- .render_pass()
- .desc()
- .convert_clear_values(clear_values);
- let clear_values = clear_values.collect::<Vec<_>>().into_iter(); // TODO: necessary for Send + Sync ; needs an API rework of convert_clear_values
- let mut clear_values_copy = clear_values.clone().enumerate(); // TODO: Proper errors for clear value errors instead of panics
-
- for (atch_i, atch_desc) in framebuffer
- .render_pass()
- .desc()
- .attachments()
- .into_iter()
- .enumerate()
- {
- match clear_values_copy.next() {
- Some((clear_i, clear_value)) => {
- if atch_desc.load == LoadOp::Clear {
- match clear_value {
- ClearValue::None => panic!("Bad ClearValue! index: {}, attachment index: {}, expected: {:?}, got: None",
- clear_i, atch_i, atch_desc.format.ty()),
- ClearValue::Float(_) => if atch_desc.format.ty() != FormatTy::Float {
- panic!("Bad ClearValue! index: {}, attachment index: {}, expected: {:?}, got: Float",
- clear_i, atch_i, atch_desc.format.ty());
- }
- ClearValue::Int(_) => if atch_desc.format.ty() != FormatTy::Sint {
- panic!("Bad ClearValue! index: {}, attachment index: {}, expected: {:?}, got: Int",
- clear_i, atch_i, atch_desc.format.ty());
- }
- ClearValue::Uint(_) => if atch_desc.format.ty() != FormatTy::Uint {
- panic!("Bad ClearValue! index: {}, attachment index: {}, expected: {:?}, got: Uint",
- clear_i, atch_i, atch_desc.format.ty());
- }
- ClearValue::Depth(_) => if atch_desc.format.ty() != FormatTy::Depth {
- panic!("Bad ClearValue! index: {}, attachment index: {}, expected: {:?}, got: Depth",
- clear_i, atch_i, atch_desc.format.ty());
- }
- ClearValue::Stencil(_) => if atch_desc.format.ty() != FormatTy::Stencil {
- panic!("Bad ClearValue! index: {}, attachment index: {}, expected: {:?}, got: Stencil",
- clear_i, atch_i, atch_desc.format.ty());
- }
- ClearValue::DepthStencil(_) => if atch_desc.format.ty() != FormatTy::DepthStencil {
- panic!("Bad ClearValue! index: {}, attachment index: {}, expected: {:?}, got: DepthStencil",
- clear_i, atch_i, atch_desc.format.ty());
- }
- }
- } else {
- if clear_value != ClearValue::None {
- panic!("Bad ClearValue! index: {}, attachment index: {}, expected: None, got: {:?}",
- clear_i, atch_i, clear_value);
- }
- }
- }
- None => panic!("Not enough clear values"),
- }
- }
-
- if clear_values_copy.count() != 0 {
- panic!("Too many clear values")
- }
-
- if let Some(multiview_desc) = framebuffer.render_pass().desc().multiview() {
- // When multiview is enabled, at the beginning of each subpass all non-render pass state is undefined
- self.state_cacher.invalidate();
-
- // ensure that the framebuffer is compatible with the render pass multiview configuration
- if multiview_desc
- .view_masks
- .iter()
- .chain(multiview_desc.correlation_masks.iter())
- .map(|&mask| 32 - mask.leading_zeros()) // calculates the highest used layer index of the mask
- .any(|highest_used_layer| highest_used_layer > framebuffer.layers())
- {
- panic!("A multiview mask references more layers than exist in the framebuffer");
- }
- }
-
- let framebuffer_object = FramebufferAbstract::inner(&framebuffer).internal_object();
- self.inner
- .begin_render_pass(framebuffer.clone(), contents, clear_values)?;
- self.render_pass_state = Some(RenderPassState {
- subpass: (framebuffer.render_pass().clone(), 0),
- contents,
- framebuffer: framebuffer_object,
- });
- Ok(self)
- }
- }
-
- /// Adds a command that ends the current render pass.
- ///
- /// This must be called after you went through all the subpasses and before you can build
- /// the command buffer or add further commands.
- #[inline]
- pub fn end_render_pass(&mut self) -> Result<&mut Self, AutoCommandBufferBuilderContextError> {
- unsafe {
- if let Some(render_pass_state) = self.render_pass_state.as_ref() {
- let (ref rp, index) = render_pass_state.subpass;
-
- if rp.desc().subpasses().len() as u32 != index + 1 {
- return Err(AutoCommandBufferBuilderContextError::NumSubpassesMismatch {
- actual: rp.desc().subpasses().len() as u32,
- current: index,
- });
- }
- } else {
- return Err(AutoCommandBufferBuilderContextError::ForbiddenOutsideRenderPass);
- }
-
- if self.query_state.values().any(|state| state.in_subpass) {
- return Err(AutoCommandBufferBuilderContextError::QueryIsActive);
- }
-
- debug_assert!(self.queue_family().supports_graphics());
-
- self.inner.end_render_pass();
- self.render_pass_state = None;
- Ok(self)
- }
- }
-
- /// Adds a command that executes a secondary command buffer.
- ///
- /// If the `flags` that `command_buffer` was created with are more restrictive than those of
- /// `self`, then `self` will be restricted to match. E.g. executing a secondary command buffer
- /// with `Flags::OneTimeSubmit` will set `self`'s flags to `Flags::OneTimeSubmit` also.
- pub fn execute_commands<C>(
- &mut self,
- command_buffer: C,
- ) -> Result<&mut Self, ExecuteCommandsError>
- where
- C: SecondaryCommandBuffer + Send + Sync + 'static,
- {
- self.check_command_buffer(&command_buffer)?;
- let secondary_usage = command_buffer.inner().usage();
-
- unsafe {
- let mut builder = self.inner.execute_commands();
- builder.add(command_buffer);
- builder.submit()?;
- }
-
- // Secondary command buffer could leave the primary in any state.
- self.state_cacher.invalidate();
-
- // If the secondary is non-concurrent or one-time use, that restricts the primary as well.
- self.usage = std::cmp::min(self.usage, secondary_usage);
-
- Ok(self)
- }
-
- /// Adds a command that multiple secondary command buffers in a vector.
- ///
- /// This requires that the secondary command buffers do not have resource conflicts; an error
- /// will be returned if there are any. Use `execute_commands` if you want to ensure that
- /// resource conflicts are automatically resolved.
- // TODO ^ would be nice if this just worked without errors
- pub fn execute_commands_from_vec<C>(
- &mut self,
- command_buffers: Vec<C>,
- ) -> Result<&mut Self, ExecuteCommandsError>
- where
- C: SecondaryCommandBuffer + Send + Sync + 'static,
- {
- for command_buffer in &command_buffers {
- self.check_command_buffer(command_buffer)?;
+ /// Builds the command buffer.
+ pub fn build(self) -> Result<PrimaryAutoCommandBuffer<A::Alloc>, BuildError> {
+ if self.render_pass_state.is_some() {
+ return Err(BuildError::RenderPassActive);
}
- let mut secondary_usage = CommandBufferUsage::SimultaneousUse; // Most permissive usage
- unsafe {
- let mut builder = self.inner.execute_commands();
- for command_buffer in command_buffers {
- secondary_usage = std::cmp::min(secondary_usage, command_buffer.inner().usage());
- builder.add(command_buffer);
- }
- builder.submit()?;
+ if !self.query_state.is_empty() {
+ return Err(BuildError::QueryActive);
}
- // Secondary command buffer could leave the primary in any state.
- self.state_cacher.invalidate();
-
- // If the secondary is non-concurrent or one-time use, that restricts the primary as well.
- self.usage = std::cmp::min(self.usage, secondary_usage);
+ Ok(PrimaryAutoCommandBuffer {
+ inner: self.inner.build()?,
+ _alloc: self.builder_alloc.into_alloc(),
+ usage: self.usage,
- Ok(self)
+ state: Mutex::new(Default::default()),
+ })
}
+}
- // Helper function for execute_commands
- fn check_command_buffer<C>(
- &self,
- command_buffer: &C,
- ) -> Result<(), AutoCommandBufferBuilderContextError>
- where
- C: SecondaryCommandBuffer + Send + Sync + 'static,
- {
- if let Some(render_pass) = command_buffer.inheritance().render_pass {
- self.ensure_inside_render_pass_secondary(&render_pass)?;
- } else {
- self.ensure_outside_render_pass()?;
+impl<A> AutoCommandBufferBuilder<SecondaryAutoCommandBuffer<A::Alloc>, A>
+where
+ A: CommandBufferAllocator,
+{
+ /// Builds the command buffer.
+ pub fn build(self) -> Result<SecondaryAutoCommandBuffer<A::Alloc>, BuildError> {
+ if !self.query_state.is_empty() {
+ return Err(BuildError::QueryActive);
}
- for state in self.query_state.values() {
- match state.ty {
- QueryType::Occlusion => match command_buffer.inheritance().occlusion_query {
- Some(inherited_flags) => {
- let inherited_flags = ash::vk::QueryControlFlags::from(inherited_flags);
- let state_flags = ash::vk::QueryControlFlags::from(state.flags);
-
- if inherited_flags & state_flags != state_flags {
- return Err(AutoCommandBufferBuilderContextError::QueryNotInherited);
- }
- }
- None => return Err(AutoCommandBufferBuilderContextError::QueryNotInherited),
- },
- QueryType::PipelineStatistics(state_flags) => {
- let inherited_flags = command_buffer.inheritance().query_statistics_flags;
- let inherited_flags =
- ash::vk::QueryPipelineStatisticFlags::from(inherited_flags);
- let state_flags = ash::vk::QueryPipelineStatisticFlags::from(state_flags);
-
- if inherited_flags & state_flags != state_flags {
- return Err(AutoCommandBufferBuilderContextError::QueryNotInherited);
- }
- }
- _ => (),
- }
- }
+ let submit_state = match self.usage {
+ CommandBufferUsage::MultipleSubmit => SubmitState::ExclusiveUse {
+ in_use: AtomicBool::new(false),
+ },
+ CommandBufferUsage::SimultaneousUse => SubmitState::Concurrent,
+ CommandBufferUsage::OneTimeSubmit => SubmitState::OneTime {
+ already_submitted: AtomicBool::new(false),
+ },
+ };
- Ok(())
+ Ok(SecondaryAutoCommandBuffer {
+ inner: self.inner.build()?,
+ _alloc: self.builder_alloc.into_alloc(),
+ usage: self.usage,
+ inheritance_info: self.inheritance_info.unwrap(),
+ submit_state,
+ })
}
+}
- #[inline]
- fn ensure_inside_render_pass_secondary(
- &self,
- render_pass: &CommandBufferInheritanceRenderPass<&dyn FramebufferAbstract>,
- ) -> Result<(), AutoCommandBufferBuilderContextError> {
- let render_pass_state = self
- .render_pass_state
- .as_ref()
- .ok_or(AutoCommandBufferBuilderContextError::ForbiddenOutsideRenderPass)?;
-
- if render_pass_state.contents != SubpassContents::SecondaryCommandBuffers {
- return Err(AutoCommandBufferBuilderContextError::WrongSubpassType);
- }
+/// Error that can happen when building a command buffer.
+#[derive(Clone, Debug)]
+pub enum BuildError {
+ OomError(OomError),
- // Subpasses must be the same.
- if render_pass.subpass.index() != render_pass_state.subpass.1 {
- return Err(AutoCommandBufferBuilderContextError::WrongSubpassIndex);
- }
+ /// A render pass is still active on the command buffer.
+ RenderPassActive,
- // Render passes must be compatible.
- if !render_pass
- .subpass
- .render_pass()
- .desc()
- .is_compatible_with_desc(render_pass_state.subpass.0.desc())
- {
- return Err(AutoCommandBufferBuilderContextError::IncompatibleRenderPass);
- }
+ /// A query is still active on the command buffer.
+ QueryActive,
+}
- // Framebuffer, if present on the secondary command buffer, must be the
- // same as the one in the current render pass.
- if let Some(framebuffer) = render_pass.framebuffer {
- if FramebufferAbstract::inner(framebuffer).internal_object()
- != render_pass_state.framebuffer
- {
- return Err(AutoCommandBufferBuilderContextError::IncompatibleFramebuffer);
- }
+impl Error for BuildError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::OomError(err) => Some(err),
+ _ => None,
}
-
- Ok(())
}
+}
- /// Adds a command that jumps to the next subpass of the current render pass.
- #[inline]
- pub fn next_subpass(
- &mut self,
- contents: SubpassContents,
- ) -> Result<&mut Self, AutoCommandBufferBuilderContextError> {
- unsafe {
- if let Some(render_pass_state) = self.render_pass_state.as_mut() {
- let (ref rp, ref mut index) = render_pass_state.subpass;
-
- if *index + 1 >= rp.desc().subpasses().len() as u32 {
- return Err(AutoCommandBufferBuilderContextError::NumSubpassesMismatch {
- actual: rp.desc().subpasses().len() as u32,
- current: *index,
- });
- } else {
- *index += 1;
- render_pass_state.contents = contents;
- }
-
- if let Some(multiview) = rp.desc().multiview() {
- // When multiview is enabled, at the beginning of each subpass all non-render pass state is undefined
- self.state_cacher.invalidate();
- }
- } else {
- return Err(AutoCommandBufferBuilderContextError::ForbiddenOutsideRenderPass);
- }
-
- if self.query_state.values().any(|state| state.in_subpass) {
- return Err(AutoCommandBufferBuilderContextError::QueryIsActive);
+impl Display for BuildError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::OomError(_) => write!(f, "out of memory"),
+ Self::RenderPassActive => {
+ write!(f, "a render pass is still active on the command buffer")
}
-
- debug_assert!(self.queue_family().supports_graphics());
-
- self.inner.next_subpass(contents);
- Ok(self)
+ Self::QueryActive => write!(f, "a query is still active on the command buffer"),
}
}
}
-impl<P> AutoCommandBufferBuilder<SecondaryAutoCommandBuffer<P::Alloc>, P> where
- P: CommandPoolBuilderAlloc
-{
-}
-
-unsafe impl<L, P> DeviceOwned for AutoCommandBufferBuilder<L, P> {
- #[inline]
- fn device(&self) -> &Arc<Device> {
- self.inner.device()
- }
-}
-
-// Shortcut function to set the push constants.
-unsafe fn set_push_constants<Pc>(
- destination: &mut SyncCommandBufferBuilder,
- pipeline_layout: &Arc<PipelineLayout>,
- push_constants: Pc,
-) {
- for range in pipeline_layout.push_constant_ranges() {
- debug_assert_eq!(range.offset % 4, 0);
- debug_assert_eq!(range.size % 4, 0);
-
- let data = slice::from_raw_parts(
- (&push_constants as *const Pc as *const u8).offset(range.offset as isize),
- range.size as usize,
- );
-
- destination.push_constants::<[u8]>(
- pipeline_layout.clone(),
- range.stages,
- range.offset as u32,
- range.size as u32,
- data,
- );
+impl From<OomError> for BuildError {
+ fn from(err: OomError) -> Self {
+ Self::OomError(err)
}
}
-// Shortcut function to change the state of the pipeline.
-unsafe fn set_state(destination: &mut SyncCommandBufferBuilder, dynamic: &DynamicState) {
- if let Some(line_width) = dynamic.line_width {
- destination.set_line_width(line_width);
- }
-
- if let Some(ref viewports) = dynamic.viewports {
- destination.set_viewport(0, viewports.iter().cloned().collect::<Vec<_>>().into_iter());
- // TODO: don't collect
- }
-
- if let Some(ref scissors) = dynamic.scissors {
- destination.set_scissor(0, scissors.iter().cloned().collect::<Vec<_>>().into_iter());
- // TODO: don't collect
- }
-
- if let Some(compare_mask) = dynamic.compare_mask {
- destination.set_stencil_compare_mask(StencilFaces::Front, compare_mask.front);
- destination.set_stencil_compare_mask(StencilFaces::Back, compare_mask.back);
- }
-
- if let Some(write_mask) = dynamic.write_mask {
- destination.set_stencil_write_mask(StencilFaces::Front, write_mask.front);
- destination.set_stencil_write_mask(StencilFaces::Back, write_mask.back);
+impl<L, A> AutoCommandBufferBuilder<L, A>
+where
+ A: CommandBufferAllocator,
+{
+ pub(super) fn queue_family_properties(&self) -> &QueueFamilyProperties {
+ &self.device().physical_device().queue_family_properties()[self.queue_family_index as usize]
}
- if let Some(reference) = dynamic.reference {
- destination.set_stencil_reference(StencilFaces::Front, reference.front);
- destination.set_stencil_reference(StencilFaces::Back, reference.back);
+ /// Returns the binding/setting state.
+ pub fn state(&self) -> CommandBufferBuilderState<'_> {
+ self.inner.state()
}
}
-// Shortcut function to bind vertex buffers.
-unsafe fn bind_vertex_buffers(
- destination: &mut SyncCommandBufferBuilder,
- state_cacher: &mut StateCacher,
- vertex_buffers: Vec<Box<dyn BufferAccess + Send + Sync>>,
-) -> Result<(), SyncCommandBufferBuilderError> {
- let binding_range = {
- let mut compare = state_cacher.bind_vertex_buffers();
- for vb in vertex_buffers.iter() {
- compare.add(vb);
- }
- match compare.compare() {
- Some(r) => r,
- None => return Ok(()),
- }
- };
-
- let first_binding = binding_range.start;
- let num_bindings = binding_range.end - binding_range.start;
-
- let mut binder = destination.bind_vertex_buffers();
- for vb in vertex_buffers
- .into_iter()
- .skip(first_binding as usize)
- .take(num_bindings as usize)
- {
- binder.add(vb);
- }
- binder.submit(first_binding)?;
- Ok(())
-}
-
-unsafe fn bind_descriptor_sets(
- destination: &mut SyncCommandBufferBuilder,
- state_cacher: &mut StateCacher,
- pipeline_bind_point: PipelineBindPoint,
- pipeline_layout: &Arc<PipelineLayout>,
- descriptor_sets: Vec<DescriptorSetWithOffsets>,
-) -> Result<(), SyncCommandBufferBuilderError> {
- let first_binding = {
- let mut compare = state_cacher.bind_descriptor_sets(pipeline_bind_point);
- for descriptor_set in descriptor_sets.iter() {
- compare.add(descriptor_set);
- }
- compare.compare()
- };
-
- let first_binding = match first_binding {
- None => return Ok(()),
- Some(fb) => fb,
- };
-
- let mut sets_binder = destination.bind_descriptor_sets();
- for set in descriptor_sets.into_iter().skip(first_binding as usize) {
- sets_binder.add(set);
+unsafe impl<L, A> DeviceOwned for AutoCommandBufferBuilder<L, A>
+where
+ A: CommandBufferAllocator,
+{
+ fn device(&self) -> &Arc<Device> {
+ self.inner.device()
}
- sets_binder.submit(pipeline_bind_point, pipeline_layout.clone(), first_binding)?;
- Ok(())
}
-pub struct PrimaryAutoCommandBuffer<P = StandardCommandPoolAlloc> {
+pub struct PrimaryAutoCommandBuffer<A = StandardCommandBufferAlloc> {
inner: SyncCommandBuffer,
- pool_alloc: P, // Safety: must be dropped after `inner`
+ _alloc: A, // Safety: must be dropped after `inner`
+ usage: CommandBufferUsage,
- // Tracks usage of the command buffer on the GPU.
- submit_state: SubmitState,
+ state: Mutex<CommandBufferState>,
}
-unsafe impl<P> DeviceOwned for PrimaryAutoCommandBuffer<P> {
- #[inline]
+unsafe impl<A> DeviceOwned for PrimaryAutoCommandBuffer<A> {
fn device(&self) -> &Arc<Device> {
self.inner.device()
}
}
-unsafe impl<P> PrimaryCommandBuffer for PrimaryAutoCommandBuffer<P> {
- #[inline]
- fn inner(&self) -> &UnsafeCommandBuffer {
- self.inner.as_ref()
- }
-
- #[inline]
- fn lock_submit(
- &self,
- future: &dyn GpuFuture,
- queue: &Queue,
- ) -> Result<(), CommandBufferExecError> {
- match self.submit_state {
- SubmitState::OneTime {
- ref already_submitted,
- } => {
- let was_already_submitted = already_submitted.swap(true, Ordering::SeqCst);
- if was_already_submitted {
- return Err(CommandBufferExecError::OneTimeSubmitAlreadySubmitted);
- }
- }
- SubmitState::ExclusiveUse { ref in_use } => {
- let already_in_use = in_use.swap(true, Ordering::SeqCst);
- if already_in_use {
- return Err(CommandBufferExecError::ExclusiveAlreadyInUse);
- }
- }
- SubmitState::Concurrent => (),
- };
-
- let err = match self.inner.lock_submit(future, queue) {
- Ok(()) => return Ok(()),
- Err(err) => err,
- };
-
- // If `self.inner.lock_submit()` failed, we revert action.
- match self.submit_state {
- SubmitState::OneTime {
- ref already_submitted,
- } => {
- already_submitted.store(false, Ordering::SeqCst);
- }
- SubmitState::ExclusiveUse { ref in_use } => {
- in_use.store(false, Ordering::SeqCst);
- }
- SubmitState::Concurrent => (),
- };
+unsafe impl<A> VulkanObject for PrimaryAutoCommandBuffer<A> {
+ type Handle = ash::vk::CommandBuffer;
- Err(err)
+ fn handle(&self) -> Self::Handle {
+ self.inner.as_ref().handle()
}
+}
- #[inline]
- unsafe fn unlock(&self) {
- // Because of panic safety, we unlock the inner command buffer first.
- self.inner.unlock();
-
- match self.submit_state {
- SubmitState::OneTime {
- ref already_submitted,
- } => {
- debug_assert!(already_submitted.load(Ordering::SeqCst));
- }
- SubmitState::ExclusiveUse { ref in_use } => {
- let old_val = in_use.swap(false, Ordering::SeqCst);
- debug_assert!(old_val);
- }
- SubmitState::Concurrent => (),
- };
+unsafe impl<A> PrimaryCommandBufferAbstract for PrimaryAutoCommandBuffer<A>
+where
+ A: CommandBufferAlloc,
+{
+ fn usage(&self) -> CommandBufferUsage {
+ self.usage
}
- #[inline]
- fn check_buffer_access(
- &self,
- buffer: &dyn BufferAccess,
- exclusive: bool,
- queue: &Queue,
- ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
- self.inner.check_buffer_access(buffer, exclusive, queue)
+ fn state(&self) -> MutexGuard<'_, CommandBufferState> {
+ self.state.lock()
}
- #[inline]
- fn check_image_access(
- &self,
- image: &dyn ImageAccess,
- layout: ImageLayout,
- exclusive: bool,
- queue: &Queue,
- ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
- self.inner
- .check_image_access(image, layout, exclusive, queue)
+ fn resources_usage(&self) -> &CommandBufferResourcesUsage {
+ self.inner.resources_usage()
}
}
-pub struct SecondaryAutoCommandBuffer<P = StandardCommandPoolAlloc> {
+pub struct SecondaryAutoCommandBuffer<A = StandardCommandBufferAlloc> {
inner: SyncCommandBuffer,
- pool_alloc: P, // Safety: must be dropped after `inner`
- inheritance: CommandBufferInheritance<Box<dyn FramebufferAbstract + Send + Sync>>,
+ _alloc: A, // Safety: must be dropped after `inner`
+ usage: CommandBufferUsage,
+ inheritance_info: CommandBufferInheritanceInfo,
// Tracks usage of the command buffer on the GPU.
submit_state: SubmitState,
}
-unsafe impl<P> DeviceOwned for SecondaryAutoCommandBuffer<P> {
- #[inline]
+unsafe impl<A> VulkanObject for SecondaryAutoCommandBuffer<A> {
+ type Handle = ash::vk::CommandBuffer;
+
+ fn handle(&self) -> Self::Handle {
+ self.inner.as_ref().handle()
+ }
+}
+
+unsafe impl<A> DeviceOwned for SecondaryAutoCommandBuffer<A> {
fn device(&self) -> &Arc<Device> {
self.inner.device()
}
}
-unsafe impl<P> SecondaryCommandBuffer for SecondaryAutoCommandBuffer<P> {
- #[inline]
- fn inner(&self) -> &UnsafeCommandBuffer {
- self.inner.as_ref()
+unsafe impl<A> SecondaryCommandBufferAbstract for SecondaryAutoCommandBuffer<A>
+where
+ A: CommandBufferAlloc,
+{
+ fn usage(&self) -> CommandBufferUsage {
+ self.usage
+ }
+
+ fn inheritance_info(&self) -> &CommandBufferInheritanceInfo {
+ &self.inheritance_info
}
- #[inline]
fn lock_record(&self) -> Result<(), CommandBufferExecError> {
match self.submit_state {
SubmitState::OneTime {
@@ -2353,7 +818,6 @@ unsafe impl<P> SecondaryCommandBuffer for SecondaryAutoCommandBuffer<P> {
Ok(())
}
- #[inline]
unsafe fn unlock(&self) {
match self.submit_state {
SubmitState::OneTime {
@@ -2369,51 +833,8 @@ unsafe impl<P> SecondaryCommandBuffer for SecondaryAutoCommandBuffer<P> {
};
}
- fn inheritance(&self) -> CommandBufferInheritance<&dyn FramebufferAbstract> {
- CommandBufferInheritance {
- render_pass: self.inheritance.render_pass.as_ref().map(
- |CommandBufferInheritanceRenderPass {
- subpass,
- framebuffer,
- }| {
- CommandBufferInheritanceRenderPass {
- subpass: subpass.clone(),
- framebuffer: framebuffer.as_ref().map(|f| f.as_ref() as &_),
- }
- },
- ),
- occlusion_query: self.inheritance.occlusion_query,
- query_statistics_flags: self.inheritance.query_statistics_flags,
- }
- }
-
- #[inline]
- fn num_buffers(&self) -> usize {
- self.inner.num_buffers()
- }
-
- #[inline]
- fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, PipelineMemoryAccess)> {
- self.inner.buffer(index)
- }
-
- #[inline]
- fn num_images(&self) -> usize {
- self.inner.num_images()
- }
-
- #[inline]
- fn image(
- &self,
- index: usize,
- ) -> Option<(
- &dyn ImageAccess,
- PipelineMemoryAccess,
- ImageLayout,
- ImageLayout,
- ImageUninitializedSafe,
- )> {
- self.inner.image(index)
+ fn resources_usage(&self) -> &SecondaryCommandBufferResourcesUsage {
+ self.inner.secondary_resources_usage()
}
}
@@ -2438,352 +859,96 @@ enum SubmitState {
},
}
-macro_rules! err_gen {
- ($name:ident { $($err:ident,)+ }) => (
- #[derive(Debug, Clone)]
- pub enum $name {
- $(
- $err($err),
- )+
- }
-
- impl error::Error for $name {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- $(
- $name::$err(ref err) => Some(err),
- )+
- }
- }
- }
-
- impl fmt::Display for $name {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(fmt, "{}", match *self {
- $(
- $name::$err(_) => {
- concat!("a ", stringify!($err))
- }
- )+
- })
- }
- }
-
- $(
- impl From<$err> for $name {
- #[inline]
- fn from(err: $err) -> $name {
- $name::$err(err)
- }
- }
- )+
- );
-}
-
-err_gen!(BuildError {
- AutoCommandBufferBuilderContextError,
- OomError,
-});
-
-err_gen!(BeginRenderPassError {
- AutoCommandBufferBuilderContextError,
- SyncCommandBufferBuilderError,
-});
-
-err_gen!(CopyImageError {
- AutoCommandBufferBuilderContextError,
- CheckCopyImageError,
- SyncCommandBufferBuilderError,
-});
-
-err_gen!(BlitImageError {
- AutoCommandBufferBuilderContextError,
- CheckBlitImageError,
- SyncCommandBufferBuilderError,
-});
-
-err_gen!(ClearColorImageError {
- AutoCommandBufferBuilderContextError,
- CheckClearColorImageError,
- SyncCommandBufferBuilderError,
-});
-
-err_gen!(CopyBufferError {
- AutoCommandBufferBuilderContextError,
- CheckCopyBufferError,
- SyncCommandBufferBuilderError,
-});
-
-err_gen!(CopyBufferImageError {
- AutoCommandBufferBuilderContextError,
- CheckCopyBufferImageError,
- SyncCommandBufferBuilderError,
-});
-
-err_gen!(CopyQueryPoolResultsError {
- AutoCommandBufferBuilderContextError,
- CheckCopyQueryPoolResultsError,
- SyncCommandBufferBuilderError,
-});
-
-err_gen!(FillBufferError {
- AutoCommandBufferBuilderContextError,
- CheckFillBufferError,
-});
-
-err_gen!(DebugMarkerError {
- AutoCommandBufferBuilderContextError,
- CheckColorError,
-});
-
-err_gen!(DispatchError {
- AutoCommandBufferBuilderContextError,
- CheckPushConstantsValidityError,
- CheckDescriptorSetsValidityError,
- CheckDispatchError,
- SyncCommandBufferBuilderError,
-});
-
-err_gen!(DispatchIndirectError {
- AutoCommandBufferBuilderContextError,
- CheckPushConstantsValidityError,
- CheckDescriptorSetsValidityError,
- CheckIndirectBufferError,
- SyncCommandBufferBuilderError,
-});
-
-err_gen!(DrawError {
- AutoCommandBufferBuilderContextError,
- CheckDynamicStateValidityError,
- CheckPushConstantsValidityError,
- CheckDescriptorSetsValidityError,
- CheckVertexBufferError,
- SyncCommandBufferBuilderError,
-});
-
-err_gen!(DrawIndexedError {
- AutoCommandBufferBuilderContextError,
- CheckDynamicStateValidityError,
- CheckPushConstantsValidityError,
- CheckDescriptorSetsValidityError,
- CheckVertexBufferError,
- CheckIndexBufferError,
- SyncCommandBufferBuilderError,
-});
-
-err_gen!(DrawIndirectError {
- AutoCommandBufferBuilderContextError,
- CheckDynamicStateValidityError,
- CheckPushConstantsValidityError,
- CheckDescriptorSetsValidityError,
- CheckVertexBufferError,
- CheckIndirectBufferError,
- SyncCommandBufferBuilderError,
-});
-
-err_gen!(DrawIndexedIndirectError {
- AutoCommandBufferBuilderContextError,
- CheckDynamicStateValidityError,
- CheckPushConstantsValidityError,
- CheckDescriptorSetsValidityError,
- CheckVertexBufferError,
- CheckIndexBufferError,
- CheckIndirectBufferError,
- SyncCommandBufferBuilderError,
-});
-
-err_gen!(ExecuteCommandsError {
- AutoCommandBufferBuilderContextError,
- SyncCommandBufferBuilderError,
-});
-
-err_gen!(BeginQueryError {
- AutoCommandBufferBuilderContextError,
- CheckBeginQueryError,
-});
-
-err_gen!(EndQueryError {
- AutoCommandBufferBuilderContextError,
- CheckEndQueryError,
-});
-
-err_gen!(WriteTimestampError {
- AutoCommandBufferBuilderContextError,
- CheckWriteTimestampError,
-});
-
-err_gen!(ResetQueryPoolError {
- AutoCommandBufferBuilderContextError,
- CheckResetQueryPoolError,
-});
-
-err_gen!(UpdateBufferError {
- AutoCommandBufferBuilderContextError,
- CheckUpdateBufferError,
-});
-
-#[derive(Debug, Copy, Clone)]
-pub enum AutoCommandBufferBuilderContextError {
- /// Operation forbidden inside of a render pass.
- ForbiddenInsideRenderPass,
- /// Operation forbidden outside of a render pass.
- ForbiddenOutsideRenderPass,
- /// Tried to use a secondary command buffer with a specified framebuffer that is
- /// incompatible with the current framebuffer.
- IncompatibleFramebuffer,
- /// Tried to use a graphics pipeline or secondary command buffer whose render pass
- /// is incompatible with the current render pass.
- IncompatibleRenderPass,
- /// The queue family doesn't allow this operation.
- NotSupportedByQueueFamily,
- /// Tried to end a render pass with subpasses remaining, or tried to go to next subpass with no
- /// subpass remaining.
- NumSubpassesMismatch {
- /// Actual number of subpasses in the current render pass.
- actual: u32,
- /// Current subpass index before the failing command.
- current: u32,
- },
- /// A query is active that conflicts with the current operation.
- QueryIsActive,
- /// This query was not active.
- QueryNotActive,
- /// A query is active that is not included in the `inheritance` of the secondary command buffer.
- QueryNotInherited,
- /// Tried to use a graphics pipeline or secondary command buffer whose subpass index
- /// didn't match the current subpass index.
- WrongSubpassIndex,
- /// Tried to execute a secondary command buffer inside a subpass that only allows inline
- /// commands, or a draw command in a subpass that only allows secondary command buffers.
- WrongSubpassType,
-}
-
-impl error::Error for AutoCommandBufferBuilderContextError {}
-
-impl fmt::Display for AutoCommandBufferBuilderContextError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- AutoCommandBufferBuilderContextError::ForbiddenInsideRenderPass => {
- "operation forbidden inside of a render pass"
- }
- AutoCommandBufferBuilderContextError::ForbiddenOutsideRenderPass => {
- "operation forbidden outside of a render pass"
- }
- AutoCommandBufferBuilderContextError::IncompatibleFramebuffer => {
- "tried to use a secondary command buffer with a specified framebuffer that is \
- incompatible with the current framebuffer"
- }
- AutoCommandBufferBuilderContextError::IncompatibleRenderPass => {
- "tried to use a graphics pipeline or secondary command buffer whose render pass \
- is incompatible with the current render pass"
- }
- AutoCommandBufferBuilderContextError::NotSupportedByQueueFamily => {
- "the queue family doesn't allow this operation"
- }
- AutoCommandBufferBuilderContextError::NumSubpassesMismatch { .. } => {
- "tried to end a render pass with subpasses remaining, or tried to go to next \
- subpass with no subpass remaining"
- }
- AutoCommandBufferBuilderContextError::QueryIsActive => {
- "a query is active that conflicts with the current operation"
- }
- AutoCommandBufferBuilderContextError::QueryNotActive => {
- "this query was not active"
- }
- AutoCommandBufferBuilderContextError::QueryNotInherited => {
- "a query is active that is not included in the inheritance of the secondary command buffer"
- }
- AutoCommandBufferBuilderContextError::WrongSubpassIndex => {
- "tried to use a graphics pipeline whose subpass index didn't match the current \
- subpass index"
- }
- AutoCommandBufferBuilderContextError::WrongSubpassType => {
- "tried to execute a secondary command buffer inside a subpass that only allows \
- inline commands, or a draw command in a subpass that only allows secondary \
- command buffers"
- }
- }
- )
- }
-}
-
#[cfg(test)]
mod tests {
- use crate::buffer::BufferUsage;
- use crate::buffer::CpuAccessibleBuffer;
- use crate::command_buffer::synced::SyncCommandBufferBuilderError;
- use crate::command_buffer::AutoCommandBufferBuilder;
- use crate::command_buffer::CommandBufferExecError;
- use crate::command_buffer::CommandBufferUsage;
- use crate::command_buffer::ExecuteCommandsError;
- use crate::command_buffer::PrimaryCommandBuffer;
- use crate::device::physical::PhysicalDevice;
- use crate::device::Device;
- use crate::device::DeviceExtensions;
- use crate::device::Features;
- use crate::sync::GpuFuture;
- use std::sync::Arc;
+ use super::*;
+ use crate::{
+ buffer::{Buffer, BufferCreateInfo, BufferUsage},
+ command_buffer::{
+ synced::SyncCommandBufferBuilderError, BufferCopy, CopyBufferInfoTyped, CopyError,
+ ExecuteCommandsError,
+ },
+ device::{DeviceCreateInfo, QueueCreateInfo},
+ memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
+ sync::GpuFuture,
+ };
#[test]
fn copy_buffer_dimensions() {
let instance = instance!();
- let phys = match PhysicalDevice::enumerate(&instance).next() {
+ let physical_device = match instance.enumerate_physical_devices().unwrap().next() {
Some(p) => p,
None => return,
};
- let queue_family = match phys.queue_families().next() {
- Some(q) => q,
- None => return,
- };
-
let (device, mut queues) = Device::new(
- phys,
- &Features::none(),
- &DeviceExtensions::none(),
- std::iter::once((queue_family, 0.5)),
+ physical_device,
+ DeviceCreateInfo {
+ queue_create_infos: vec![QueueCreateInfo {
+ queue_family_index: 0,
+ ..Default::default()
+ }],
+ ..Default::default()
+ },
)
.unwrap();
let queue = queues.next().unwrap();
+ let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
- let source = CpuAccessibleBuffer::from_iter(
- device.clone(),
- BufferUsage::all(),
- true,
+ let source = Buffer::from_iter(
+ &memory_allocator,
+ BufferCreateInfo {
+ usage: BufferUsage::TRANSFER_SRC,
+ ..Default::default()
+ },
+ AllocationCreateInfo {
+ usage: MemoryUsage::Upload,
+ ..Default::default()
+ },
[1_u32, 2].iter().copied(),
)
.unwrap();
- let destination = CpuAccessibleBuffer::from_iter(
- device.clone(),
- BufferUsage::all(),
- true,
+ let destination = Buffer::from_iter(
+ &memory_allocator,
+ BufferCreateInfo {
+ usage: BufferUsage::TRANSFER_DST,
+ ..Default::default()
+ },
+ AllocationCreateInfo {
+ usage: MemoryUsage::Upload,
+ ..Default::default()
+ },
[0_u32, 10, 20, 3, 4].iter().copied(),
)
.unwrap();
+ let cb_allocator = StandardCommandBufferAllocator::new(device, Default::default());
let mut cbb = AutoCommandBufferBuilder::primary(
- device.clone(),
- queue.family(),
+ &cb_allocator,
+ queue.queue_family_index(),
CommandBufferUsage::OneTimeSubmit,
)
.unwrap();
- cbb.copy_buffer_dimensions(source.clone(), 0, destination.clone(), 1, 2)
- .unwrap();
+ cbb.copy_buffer(CopyBufferInfoTyped {
+ regions: [BufferCopy {
+ src_offset: 0,
+ dst_offset: 1,
+ size: 2,
+ ..Default::default()
+ }]
+ .into(),
+ ..CopyBufferInfoTyped::buffers(source, destination.clone())
+ })
+ .unwrap();
let cb = cbb.build().unwrap();
let future = cb
- .execute(queue.clone())
+ .execute(queue)
.unwrap()
.then_signal_fence_and_flush()
.unwrap();
@@ -2798,19 +963,22 @@ mod tests {
fn secondary_nonconcurrent_conflict() {
let (device, queue) = gfx_dev_and_queue!();
+ let cb_allocator = StandardCommandBufferAllocator::new(device, Default::default());
+
// Make a secondary CB that doesn't support simultaneous use.
- let builder = AutoCommandBufferBuilder::secondary_compute(
- device.clone(),
- queue.family(),
+ let builder = AutoCommandBufferBuilder::secondary(
+ &cb_allocator,
+ queue.queue_family_index(),
CommandBufferUsage::MultipleSubmit,
+ Default::default(),
)
.unwrap();
let secondary = Arc::new(builder.build().unwrap());
{
let mut builder = AutoCommandBufferBuilder::primary(
- device.clone(),
- queue.family(),
+ &cb_allocator,
+ queue.queue_family_index(),
CommandBufferUsage::SimultaneousUse,
)
.unwrap();
@@ -2832,8 +1000,8 @@ mod tests {
{
let mut builder = AutoCommandBufferBuilder::primary(
- device.clone(),
- queue.family(),
+ &cb_allocator,
+ queue.queue_family_index(),
CommandBufferUsage::SimultaneousUse,
)
.unwrap();
@@ -2841,8 +1009,8 @@ mod tests {
let cb1 = builder.build().unwrap();
let mut builder = AutoCommandBufferBuilder::primary(
- device.clone(),
- queue.family(),
+ &cb_allocator,
+ queue.queue_family_index(),
CommandBufferUsage::SimultaneousUse,
)
.unwrap();
@@ -2861,7 +1029,106 @@ mod tests {
std::mem::drop(cb1);
// Now that the first cb is dropped, we should be able to record.
- builder.execute_commands(secondary.clone()).unwrap();
+ builder.execute_commands(secondary).unwrap();
}
}
+
+ #[test]
+ fn buffer_self_copy_overlapping() {
+ let (device, queue) = gfx_dev_and_queue!();
+
+ let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
+ let source = Buffer::from_iter(
+ &memory_allocator,
+ BufferCreateInfo {
+ usage: BufferUsage::TRANSFER_SRC | BufferUsage::TRANSFER_DST,
+ ..Default::default()
+ },
+ AllocationCreateInfo {
+ usage: MemoryUsage::Upload,
+ ..Default::default()
+ },
+ [0_u32, 1, 2, 3].iter().copied(),
+ )
+ .unwrap();
+
+ let cb_allocator = StandardCommandBufferAllocator::new(device, Default::default());
+ let mut builder = AutoCommandBufferBuilder::primary(
+ &cb_allocator,
+ queue.queue_family_index(),
+ CommandBufferUsage::OneTimeSubmit,
+ )
+ .unwrap();
+
+ builder
+ .copy_buffer(CopyBufferInfoTyped {
+ regions: [BufferCopy {
+ src_offset: 0,
+ dst_offset: 2,
+ size: 2,
+ ..Default::default()
+ }]
+ .into(),
+ ..CopyBufferInfoTyped::buffers(source.clone(), source.clone())
+ })
+ .unwrap();
+
+ let cb = builder.build().unwrap();
+
+ let future = cb
+ .execute(queue)
+ .unwrap()
+ .then_signal_fence_and_flush()
+ .unwrap();
+ future.wait(None).unwrap();
+
+ let result = source.read().unwrap();
+
+ assert_eq!(*result, [0_u32, 1, 0, 1]);
+ }
+
+ #[test]
+ fn buffer_self_copy_not_overlapping() {
+ let (device, queue) = gfx_dev_and_queue!();
+
+ let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
+ let source = Buffer::from_iter(
+ &memory_allocator,
+ BufferCreateInfo {
+ usage: BufferUsage::TRANSFER_SRC | BufferUsage::TRANSFER_DST,
+ ..Default::default()
+ },
+ AllocationCreateInfo {
+ usage: MemoryUsage::Upload,
+ ..Default::default()
+ },
+ [0_u32, 1, 2, 3].iter().copied(),
+ )
+ .unwrap();
+
+ let cb_allocator = StandardCommandBufferAllocator::new(device, Default::default());
+ let mut builder = AutoCommandBufferBuilder::primary(
+ &cb_allocator,
+ queue.queue_family_index(),
+ CommandBufferUsage::OneTimeSubmit,
+ )
+ .unwrap();
+
+ assert!(matches!(
+ builder.copy_buffer(CopyBufferInfoTyped {
+ regions: [BufferCopy {
+ src_offset: 0,
+ dst_offset: 1,
+ size: 2,
+ ..Default::default()
+ }]
+ .into(),
+ ..CopyBufferInfoTyped::buffers(source.clone(), source)
+ }),
+ Err(CopyError::OverlappingRegions {
+ src_region_index: 0,
+ dst_region_index: 0,
+ })
+ ));
+ }
}
diff --git a/src/command_buffer/commands/bind_push.rs b/src/command_buffer/commands/bind_push.rs
new file mode 100644
index 0000000..2261096
--- /dev/null
+++ b/src/command_buffer/commands/bind_push.rs
@@ -0,0 +1,1536 @@
+// Copyright (c) 2022 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use crate::{
+ buffer::{BufferContents, BufferUsage, Subbuffer},
+ command_buffer::{
+ allocator::CommandBufferAllocator,
+ auto::RenderPassStateType,
+ synced::{Command, SetOrPush, SyncCommandBufferBuilder},
+ sys::UnsafeCommandBufferBuilder,
+ AutoCommandBufferBuilder,
+ },
+ descriptor_set::{
+ check_descriptor_write, layout::DescriptorType, sys::UnsafeDescriptorSet,
+ DescriptorBindingResources, DescriptorSetResources, DescriptorSetUpdateError,
+ DescriptorSetWithOffsets, DescriptorSetsCollection, DescriptorWriteInfo,
+ WriteDescriptorSet,
+ },
+ device::{DeviceOwned, QueueFlags},
+ memory::{is_aligned, DeviceAlignment},
+ pipeline::{
+ graphics::{
+ input_assembly::{Index, IndexType},
+ render_pass::PipelineRenderPassType,
+ vertex_input::VertexBuffersCollection,
+ },
+ ComputePipeline, GraphicsPipeline, PipelineBindPoint, PipelineLayout,
+ },
+ shader::ShaderStages,
+ DeviceSize, RequirementNotMet, RequiresOneOf, VulkanObject,
+};
+use parking_lot::Mutex;
+use smallvec::SmallVec;
+use std::{
+ cmp::min,
+ error,
+ fmt::{Display, Error as FmtError, Formatter},
+ mem::{size_of, size_of_val},
+ ptr, slice,
+ sync::Arc,
+};
+
+/// # Commands to bind or push state for pipeline execution commands.
+///
+/// These commands require a queue with a pipeline type that uses the given state.
+impl<L, A> AutoCommandBufferBuilder<L, A>
+where
+ A: CommandBufferAllocator,
+{
+ /// Binds descriptor sets for future dispatch or draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support `pipeline_bind_point`.
+ /// - Panics if the highest descriptor set slot being bound is not less than the number of sets
+ /// in `pipeline_layout`.
+ /// - Panics if `self` and any element of `descriptor_sets` do not belong to the same device.
+ pub fn bind_descriptor_sets<S>(
+ &mut self,
+ pipeline_bind_point: PipelineBindPoint,
+ pipeline_layout: Arc<PipelineLayout>,
+ first_set: u32,
+ descriptor_sets: S,
+ ) -> &mut Self
+ where
+ S: DescriptorSetsCollection,
+ {
+ let descriptor_sets = descriptor_sets.into_vec();
+ self.validate_bind_descriptor_sets(
+ pipeline_bind_point,
+ &pipeline_layout,
+ first_set,
+ &descriptor_sets,
+ )
+ .unwrap();
+
+ unsafe {
+ let mut sets_binder = self.inner.bind_descriptor_sets();
+ for set in descriptor_sets.into_iter() {
+ sets_binder.add(set);
+ }
+ sets_binder.submit(pipeline_bind_point, pipeline_layout, first_set);
+ }
+
+ self
+ }
+
+ fn validate_bind_descriptor_sets(
+ &self,
+ pipeline_bind_point: PipelineBindPoint,
+ pipeline_layout: &PipelineLayout,
+ first_set: u32,
+ descriptor_sets: &[DescriptorSetWithOffsets],
+ ) -> Result<(), BindPushError> {
+ // VUID-vkCmdBindDescriptorSets-pipelineBindPoint-parameter
+ pipeline_bind_point.validate_device(self.device())?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdBindDescriptorSets-commandBuffer-cmdpool
+ // VUID-vkCmdBindDescriptorSets-pipelineBindPoint-00361
+ match pipeline_bind_point {
+ PipelineBindPoint::Compute => {
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::COMPUTE)
+ {
+ return Err(BindPushError::NotSupportedByQueueFamily);
+ }
+ }
+ PipelineBindPoint::Graphics => {
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(BindPushError::NotSupportedByQueueFamily);
+ }
+ }
+ }
+
+ // VUID-vkCmdBindDescriptorSets-firstSet-00360
+ if first_set + descriptor_sets.len() as u32 > pipeline_layout.set_layouts().len() as u32 {
+ return Err(BindPushError::DescriptorSetOutOfRange {
+ set_num: first_set + descriptor_sets.len() as u32,
+ pipeline_layout_set_count: pipeline_layout.set_layouts().len() as u32,
+ });
+ }
+
+ let properties = self.device().physical_device().properties();
+ let uniform_alignment = properties.min_uniform_buffer_offset_alignment;
+ let storage_alignment = properties.min_storage_buffer_offset_alignment;
+
+ for (i, set) in descriptor_sets.iter().enumerate() {
+ let set_num = first_set + i as u32;
+ let (set, dynamic_offsets) = set.as_ref();
+
+ // VUID-vkCmdBindDescriptorSets-commonparent
+ assert_eq!(self.device(), set.device());
+
+ let set_layout = set.layout();
+ let pipeline_set_layout = &pipeline_layout.set_layouts()[set_num as usize];
+
+ // VUID-vkCmdBindDescriptorSets-pDescriptorSets-00358
+ if !pipeline_set_layout.is_compatible_with(set_layout) {
+ return Err(BindPushError::DescriptorSetNotCompatible { set_num });
+ }
+
+ let mut dynamic_offsets_remaining = dynamic_offsets;
+ let mut required_dynamic_offset_count = 0;
+
+ for (&binding_num, binding) in set_layout.bindings() {
+ let required_alignment = match binding.descriptor_type {
+ DescriptorType::UniformBufferDynamic => uniform_alignment,
+ DescriptorType::StorageBufferDynamic => storage_alignment,
+ _ => continue,
+ };
+
+ let count = if binding.variable_descriptor_count {
+ set.variable_descriptor_count()
+ } else {
+ binding.descriptor_count
+ } as usize;
+
+ required_dynamic_offset_count += count;
+
+ if !dynamic_offsets_remaining.is_empty() {
+ let split_index = min(count, dynamic_offsets_remaining.len());
+ let dynamic_offsets = &dynamic_offsets_remaining[..split_index];
+ dynamic_offsets_remaining = &dynamic_offsets_remaining[split_index..];
+
+ let elements = match set.resources().binding(binding_num) {
+ Some(DescriptorBindingResources::Buffer(elements)) => elements.as_slice(),
+ _ => unreachable!(),
+ };
+
+ for (index, (&offset, element)) in
+ dynamic_offsets.iter().zip(elements).enumerate()
+ {
+ // VUID-vkCmdBindDescriptorSets-pDynamicOffsets-01971
+ // VUID-vkCmdBindDescriptorSets-pDynamicOffsets-01972
+ if !is_aligned(offset as DeviceSize, required_alignment) {
+ return Err(BindPushError::DynamicOffsetNotAligned {
+ set_num,
+ binding_num,
+ index: index as u32,
+ offset,
+ required_alignment,
+ });
+ }
+
+ if let Some((buffer, range)) = element {
+ // VUID-vkCmdBindDescriptorSets-pDescriptorSets-01979
+ if offset as DeviceSize + range.end > buffer.size() {
+ return Err(BindPushError::DynamicOffsetOutOfBufferBounds {
+ set_num,
+ binding_num,
+ index: index as u32,
+ offset,
+ range_end: range.end,
+ buffer_size: buffer.size(),
+ });
+ }
+ }
+ }
+ }
+ }
+
+ // VUID-vkCmdBindDescriptorSets-dynamicOffsetCount-00359
+ if dynamic_offsets.len() != required_dynamic_offset_count {
+ return Err(BindPushError::DynamicOffsetCountMismatch {
+ set_num,
+ provided_count: dynamic_offsets.len(),
+ required_count: required_dynamic_offset_count,
+ });
+ }
+ }
+
+ Ok(())
+ }
+
+ /// Binds an index buffer for future indexed draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if `self` and `index_buffer` do not belong to the same device.
+ /// - Panics if `index_buffer` does not have the [`BufferUsage::INDEX_BUFFER`] usage enabled.
+ /// - If the index buffer contains `u8` indices, panics if the [`index_type_uint8`] feature is
+ /// not enabled on the device.
+ ///
+ /// [`BufferUsage::INDEX_BUFFER`]: crate::buffer::BufferUsage::INDEX_BUFFER
+ /// [`index_type_uint8`]: crate::device::Features::index_type_uint8
+ pub fn bind_index_buffer<I: Index>(&mut self, index_buffer: Subbuffer<[I]>) -> &mut Self {
+ self.validate_bind_index_buffer(index_buffer.as_bytes(), I::ty())
+ .unwrap();
+
+ unsafe {
+ self.inner
+ .bind_index_buffer(index_buffer.into_bytes(), I::ty());
+ }
+
+ self
+ }
+
+ fn validate_bind_index_buffer(
+ &self,
+ index_buffer: &Subbuffer<[u8]>,
+ index_type: IndexType,
+ ) -> Result<(), BindPushError> {
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdBindIndexBuffer-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(BindPushError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdBindIndexBuffer-commonparent
+ assert_eq!(self.device(), index_buffer.device());
+
+ // VUID-vkCmdBindIndexBuffer-buffer-00433
+ if !index_buffer
+ .buffer()
+ .usage()
+ .intersects(BufferUsage::INDEX_BUFFER)
+ {
+ return Err(BindPushError::IndexBufferMissingUsage);
+ }
+
+ // VUID-vkCmdBindIndexBuffer-indexType-02765
+ if index_type == IndexType::U8 && !self.device().enabled_features().index_type_uint8 {
+ return Err(BindPushError::RequirementNotMet {
+ required_for: "`index_type` is `IndexType::U8`",
+ requires_one_of: RequiresOneOf {
+ features: &["index_type_uint8"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // TODO:
+ // VUID-vkCmdBindIndexBuffer-offset-00432
+
+ Ok(())
+ }
+
+ /// Binds a compute pipeline for future dispatch calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support compute operations.
+ /// - Panics if `self` and `pipeline` do not belong to the same device.
+ pub fn bind_pipeline_compute(&mut self, pipeline: Arc<ComputePipeline>) -> &mut Self {
+ self.validate_bind_pipeline_compute(&pipeline).unwrap();
+
+ unsafe {
+ self.inner.bind_pipeline_compute(pipeline);
+ }
+
+ self
+ }
+
+ fn validate_bind_pipeline_compute(
+ &self,
+ pipeline: &ComputePipeline,
+ ) -> Result<(), BindPushError> {
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdBindPipeline-pipelineBindPoint-00777
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::COMPUTE)
+ {
+ return Err(BindPushError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdBindPipeline-commonparent
+ assert_eq!(self.device(), pipeline.device());
+
+ Ok(())
+ }
+
+ /// Binds a graphics pipeline for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if `self` and `pipeline` do not belong to the same device.
+ pub fn bind_pipeline_graphics(&mut self, pipeline: Arc<GraphicsPipeline>) -> &mut Self {
+ self.validate_bind_pipeline_graphics(&pipeline).unwrap();
+
+ unsafe {
+ self.inner.bind_pipeline_graphics(pipeline);
+ }
+
+ self
+ }
+
+ fn validate_bind_pipeline_graphics(
+ &self,
+ pipeline: &GraphicsPipeline,
+ ) -> Result<(), BindPushError> {
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdBindPipeline-pipelineBindPoint-00778
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(BindPushError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdBindPipeline-commonparent
+ assert_eq!(self.device(), pipeline.device());
+
+ if let Some(last_pipeline) = self
+ .render_pass_state
+ .as_ref()
+ .and_then(|render_pass_state| match &render_pass_state.render_pass {
+ RenderPassStateType::BeginRendering(state) if state.pipeline_used => {
+ self.state().pipeline_graphics()
+ }
+ _ => None,
+ })
+ {
+ if let (
+ PipelineRenderPassType::BeginRendering(pipeline_rendering_info),
+ PipelineRenderPassType::BeginRendering(last_pipeline_rendering_info),
+ ) = (pipeline.render_pass(), last_pipeline.render_pass())
+ {
+ // VUID-vkCmdBindPipeline-pipeline-06195
+ // VUID-vkCmdBindPipeline-pipeline-06196
+ if pipeline_rendering_info.color_attachment_formats
+ != last_pipeline_rendering_info.color_attachment_formats
+ {
+ return Err(BindPushError::PreviousPipelineColorAttachmentFormatMismatch);
+ }
+
+ // VUID-vkCmdBindPipeline-pipeline-06197
+ if pipeline_rendering_info.depth_attachment_format
+ != last_pipeline_rendering_info.depth_attachment_format
+ {
+ return Err(BindPushError::PreviousPipelineDepthAttachmentFormatMismatch);
+ }
+
+ // VUID-vkCmdBindPipeline-pipeline-06194
+ if pipeline_rendering_info.stencil_attachment_format
+ != last_pipeline_rendering_info.stencil_attachment_format
+ {
+ return Err(BindPushError::PreviousPipelineStencilAttachmentFormatMismatch);
+ }
+ }
+ }
+
+ // VUID-vkCmdBindPipeline-pipeline-00781
+ // TODO:
+
+ Ok(())
+ }
+
+ /// Binds vertex buffers for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the highest vertex buffer binding being bound is greater than the
+ /// [`max_vertex_input_bindings`] device property.
+ /// - Panics if `self` and any element of `vertex_buffers` do not belong to the same device.
+ /// - Panics if any element of `vertex_buffers` does not have the
+ /// [`BufferUsage::VERTEX_BUFFER`] usage enabled.
+ ///
+ /// [`max_vertex_input_bindings`]: crate::device::Properties::max_vertex_input_bindings
+ /// [`BufferUsage::VERTEX_BUFFER`]: crate::buffer::BufferUsage::VERTEX_BUFFER
+ pub fn bind_vertex_buffers(
+ &mut self,
+ first_binding: u32,
+ vertex_buffers: impl VertexBuffersCollection,
+ ) -> &mut Self {
+ let vertex_buffers = vertex_buffers.into_vec();
+ self.validate_bind_vertex_buffers(first_binding, &vertex_buffers)
+ .unwrap();
+
+ unsafe {
+ let mut binder = self.inner.bind_vertex_buffers();
+ for vb in vertex_buffers.into_iter() {
+ binder.add(vb);
+ }
+ binder.submit(first_binding);
+ }
+
+ self
+ }
+
+ fn validate_bind_vertex_buffers(
+ &self,
+ first_binding: u32,
+ vertex_buffers: &[Subbuffer<[u8]>],
+ ) -> Result<(), BindPushError> {
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdBindVertexBuffers-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(BindPushError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdBindVertexBuffers-firstBinding-00624
+ // VUID-vkCmdBindVertexBuffers-firstBinding-00625
+ if first_binding + vertex_buffers.len() as u32
+ > self
+ .device()
+ .physical_device()
+ .properties()
+ .max_vertex_input_bindings
+ {
+ return Err(BindPushError::MaxVertexInputBindingsExceeded {
+ _binding_count: first_binding + vertex_buffers.len() as u32,
+ _max: self
+ .device()
+ .physical_device()
+ .properties()
+ .max_vertex_input_bindings,
+ });
+ }
+
+ for buffer in vertex_buffers {
+ // VUID-vkCmdBindVertexBuffers-commonparent
+ assert_eq!(self.device(), buffer.device());
+
+ // VUID-vkCmdBindVertexBuffers-pBuffers-00627
+ if !buffer
+ .buffer()
+ .usage()
+ .intersects(BufferUsage::VERTEX_BUFFER)
+ {
+ return Err(BindPushError::VertexBufferMissingUsage);
+ }
+ }
+
+ Ok(())
+ }
+
+ /// Sets push constants for future dispatch or draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `offset` is not a multiple of 4.
+ /// - Panics if the size of `push_constants` is not a multiple of 4.
+ /// - Panics if any of the bytes in `push_constants` do not fall within any of the pipeline
+ /// layout's push constant ranges.
+ pub fn push_constants<Pc>(
+ &mut self,
+ pipeline_layout: Arc<PipelineLayout>,
+ offset: u32,
+ push_constants: Pc,
+ ) -> &mut Self
+ where
+ Pc: BufferContents,
+ {
+ let size = size_of::<Pc>() as u32;
+
+ if size == 0 {
+ return self;
+ }
+
+ // SAFETY: `&push_constants` is a valid pointer, and the size of the struct is `size`,
+ // thus, getting a slice of the whole struct is safe if its not modified.
+ let push_constants = unsafe {
+ slice::from_raw_parts(&push_constants as *const Pc as *const u8, size as usize)
+ };
+
+ self.validate_push_constants(&pipeline_layout, offset, push_constants)
+ .unwrap();
+
+ let mut current_offset = offset;
+ let mut remaining_size = size;
+ for range in pipeline_layout
+ .push_constant_ranges_disjoint()
+ .iter()
+ .skip_while(|range| range.offset + range.size <= offset)
+ {
+ // there is a gap between ranges, but the passed push_constants contains
+ // some bytes in this gap, exit the loop and report error
+ if range.offset > current_offset {
+ break;
+ }
+
+ // push the minimum of the whole remaining data, and the part until the end of this range
+ let push_size = remaining_size.min(range.offset + range.size - current_offset);
+ let data_offset = (current_offset - offset) as usize;
+ unsafe {
+ self.inner.push_constants::<[u8]>(
+ pipeline_layout.clone(),
+ range.stages,
+ current_offset,
+ push_size,
+ &push_constants[data_offset..(data_offset + push_size as usize)],
+ );
+ }
+ current_offset += push_size;
+ remaining_size -= push_size;
+
+ if remaining_size == 0 {
+ break;
+ }
+ }
+
+ debug_assert!(remaining_size == 0);
+
+ self
+ }
+
+ fn validate_push_constants(
+ &self,
+ pipeline_layout: &PipelineLayout,
+ offset: u32,
+ push_constants: &[u8],
+ ) -> Result<(), BindPushError> {
+ if offset % 4 != 0 {
+ return Err(BindPushError::PushConstantsOffsetNotAligned);
+ }
+
+ if push_constants.len() % 4 != 0 {
+ return Err(BindPushError::PushConstantsSizeNotAligned);
+ }
+
+ let mut current_offset = offset;
+ let mut remaining_size = push_constants.len() as u32;
+ for range in pipeline_layout
+ .push_constant_ranges_disjoint()
+ .iter()
+ .skip_while(|range| range.offset + range.size <= offset)
+ {
+ // there is a gap between ranges, but the passed push_constants contains
+ // some bytes in this gap, exit the loop and report error
+ if range.offset > current_offset {
+ break;
+ }
+
+ // push the minimum of the whole remaining data, and the part until the end of this range
+ let push_size = remaining_size.min(range.offset + range.size - current_offset);
+ current_offset += push_size;
+ remaining_size -= push_size;
+
+ if remaining_size == 0 {
+ break;
+ }
+ }
+
+ if remaining_size != 0 {
+ return Err(BindPushError::PushConstantsDataOutOfRange {
+ offset: current_offset,
+ });
+ }
+
+ Ok(())
+ }
+
+ /// Pushes descriptor data directly into the command buffer for future dispatch or draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support `pipeline_bind_point`.
+ /// - Panics if the
+ /// [`khr_push_descriptor`](crate::device::DeviceExtensions::khr_push_descriptor)
+ /// extension is not enabled on the device.
+ /// - Panics if `set_num` is not less than the number of sets in `pipeline_layout`.
+ /// - Panics if an element of `descriptor_writes` is not compatible with `pipeline_layout`.
+ pub fn push_descriptor_set(
+ &mut self,
+ pipeline_bind_point: PipelineBindPoint,
+ pipeline_layout: Arc<PipelineLayout>,
+ set_num: u32,
+ descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>,
+ ) -> &mut Self {
+ let descriptor_writes: SmallVec<[_; 8]> = descriptor_writes.into_iter().collect();
+ self.validate_push_descriptor_set(
+ pipeline_bind_point,
+ &pipeline_layout,
+ set_num,
+ &descriptor_writes,
+ )
+ .unwrap();
+
+ unsafe {
+ self.inner.push_descriptor_set(
+ pipeline_bind_point,
+ pipeline_layout,
+ set_num,
+ descriptor_writes,
+ );
+ }
+
+ self
+ }
+
+ fn validate_push_descriptor_set(
+ &self,
+ pipeline_bind_point: PipelineBindPoint,
+ pipeline_layout: &PipelineLayout,
+ set_num: u32,
+ descriptor_writes: &[WriteDescriptorSet],
+ ) -> Result<(), BindPushError> {
+ if !self.device().enabled_extensions().khr_push_descriptor {
+ return Err(BindPushError::RequirementNotMet {
+ required_for: "`AutoCommandBufferBuilder::push_descriptor_set`",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["khr_push_descriptor"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdPushDescriptorSetKHR-pipelineBindPoint-parameter
+ pipeline_bind_point.validate_device(self.device())?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdPushDescriptorSetKHR-commandBuffer-cmdpool
+ // VUID-vkCmdPushDescriptorSetKHR-pipelineBindPoint-00363
+ match pipeline_bind_point {
+ PipelineBindPoint::Compute => {
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::COMPUTE)
+ {
+ return Err(BindPushError::NotSupportedByQueueFamily);
+ }
+ }
+ PipelineBindPoint::Graphics => {
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(BindPushError::NotSupportedByQueueFamily);
+ }
+ }
+ }
+
+ // VUID-vkCmdPushDescriptorSetKHR-commonparent
+ assert_eq!(self.device(), pipeline_layout.device());
+
+ // VUID-vkCmdPushDescriptorSetKHR-set-00364
+ if set_num as usize > pipeline_layout.set_layouts().len() {
+ return Err(BindPushError::DescriptorSetOutOfRange {
+ set_num,
+ pipeline_layout_set_count: pipeline_layout.set_layouts().len() as u32,
+ });
+ }
+
+ let descriptor_set_layout = &pipeline_layout.set_layouts()[set_num as usize];
+
+ // VUID-vkCmdPushDescriptorSetKHR-set-00365
+ if !descriptor_set_layout.push_descriptor() {
+ return Err(BindPushError::DescriptorSetNotPush { set_num });
+ }
+
+ for write in descriptor_writes {
+ check_descriptor_write(write, descriptor_set_layout, 0)?;
+ }
+
+ Ok(())
+ }
+}
+
+impl SyncCommandBufferBuilder {
+ /// Starts the process of binding descriptor sets. Returns an intermediate struct which can be
+ /// used to add the sets.
+ #[inline]
+ pub fn bind_descriptor_sets(&mut self) -> SyncCommandBufferBuilderBindDescriptorSets<'_> {
+ SyncCommandBufferBuilderBindDescriptorSets {
+ builder: self,
+ descriptor_sets: SmallVec::new(),
+ }
+ }
+
+ /// Calls `vkCmdBindIndexBuffer` on the builder.
+ #[inline]
+ pub unsafe fn bind_index_buffer(&mut self, buffer: Subbuffer<[u8]>, index_type: IndexType) {
+ struct Cmd {
+ buffer: Subbuffer<[u8]>,
+ index_type: IndexType,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "bind_index_buffer"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.bind_index_buffer(&self.buffer, self.index_type);
+ }
+ }
+
+ self.current_state.index_buffer = Some((buffer.clone(), index_type));
+ self.commands.push(Box::new(Cmd { buffer, index_type }));
+ }
+
+ /// Calls `vkCmdBindPipeline` on the builder with a compute pipeline.
+ #[inline]
+ pub unsafe fn bind_pipeline_compute(&mut self, pipeline: Arc<ComputePipeline>) {
+ struct Cmd {
+ pipeline: Arc<ComputePipeline>,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "bind_pipeline_compute"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.bind_pipeline_compute(&self.pipeline);
+ }
+ }
+
+ self.current_state.pipeline_compute = Some(pipeline.clone());
+ self.commands.push(Box::new(Cmd { pipeline }));
+ }
+
+ /// Calls `vkCmdBindPipeline` on the builder with a graphics pipeline.
+ #[inline]
+ pub unsafe fn bind_pipeline_graphics(&mut self, pipeline: Arc<GraphicsPipeline>) {
+ struct Cmd {
+ pipeline: Arc<GraphicsPipeline>,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "bind_pipeline_graphics"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.bind_pipeline_graphics(&self.pipeline);
+ }
+ }
+
+ // Reset any states that are fixed in the new pipeline. The pipeline bind command will
+ // overwrite these states.
+ self.current_state.reset_dynamic_states(
+ pipeline
+ .dynamic_states()
+ .filter(|(_, d)| !d) // not dynamic
+ .map(|(s, _)| s),
+ );
+ self.current_state.pipeline_graphics = Some(pipeline.clone());
+ self.commands.push(Box::new(Cmd { pipeline }));
+ }
+
+ /// Starts the process of binding vertex buffers. Returns an intermediate struct which can be
+ /// used to add the buffers.
+ #[inline]
+ pub fn bind_vertex_buffers(&mut self) -> SyncCommandBufferBuilderBindVertexBuffer<'_> {
+ SyncCommandBufferBuilderBindVertexBuffer {
+ builder: self,
+ inner: UnsafeCommandBufferBuilderBindVertexBuffer::new(),
+ buffers: SmallVec::new(),
+ }
+ }
+
+ /// Calls `vkCmdPushConstants` on the builder.
+ pub unsafe fn push_constants<D>(
+ &mut self,
+ pipeline_layout: Arc<PipelineLayout>,
+ stages: ShaderStages,
+ offset: u32,
+ size: u32,
+ data: &D,
+ ) where
+ D: ?Sized + Send + Sync + 'static,
+ {
+ struct Cmd {
+ pipeline_layout: Arc<PipelineLayout>,
+ stages: ShaderStages,
+ offset: u32,
+ size: u32,
+ data: Box<[u8]>,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "push_constants"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.push_constants::<[u8]>(
+ &self.pipeline_layout,
+ self.stages,
+ self.offset,
+ self.size,
+ &self.data,
+ );
+ }
+ }
+
+ debug_assert!(size_of_val(data) >= size as usize);
+
+ let mut out = Vec::with_capacity(size as usize);
+ ptr::copy::<u8>(
+ data as *const D as *const u8,
+ out.as_mut_ptr(),
+ size as usize,
+ );
+ out.set_len(size as usize);
+
+ self.commands.push(Box::new(Cmd {
+ pipeline_layout: pipeline_layout.clone(),
+ stages,
+ offset,
+ size,
+ data: out.into(),
+ }));
+
+ // TODO: Push constant invalidations.
+ // The Vulkan spec currently is unclear about this, so Vulkano currently just marks
+ // push constants as set, and never unsets them. See:
+ // https://github.com/KhronosGroup/Vulkan-Docs/issues/1485
+ // https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/2711
+ self.current_state
+ .push_constants
+ .insert(offset..offset + size);
+ self.current_state.push_constants_pipeline_layout = Some(pipeline_layout);
+ }
+
+ /// Calls `vkCmdPushDescriptorSetKHR` on the builder.
+ pub unsafe fn push_descriptor_set(
+ &mut self,
+ pipeline_bind_point: PipelineBindPoint,
+ pipeline_layout: Arc<PipelineLayout>,
+ set_num: u32,
+ descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>,
+ ) {
+ struct Cmd {
+ pipeline_bind_point: PipelineBindPoint,
+ pipeline_layout: Arc<PipelineLayout>,
+ set_num: u32,
+ descriptor_writes: SmallVec<[WriteDescriptorSet; 8]>,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "push_descriptor_set"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.push_descriptor_set(
+ self.pipeline_bind_point,
+ &self.pipeline_layout,
+ self.set_num,
+ &self.descriptor_writes,
+ );
+ }
+ }
+
+ let descriptor_writes: SmallVec<[WriteDescriptorSet; 8]> =
+ descriptor_writes.into_iter().collect();
+
+ let state = self.current_state.invalidate_descriptor_sets(
+ pipeline_bind_point,
+ pipeline_layout.clone(),
+ set_num,
+ 1,
+ );
+ let layout = state.pipeline_layout.set_layouts()[set_num as usize].as_ref();
+ debug_assert!(layout.push_descriptor());
+
+ let set_resources = match state
+ .descriptor_sets
+ .entry(set_num)
+ .or_insert_with(|| SetOrPush::Push(DescriptorSetResources::new(layout, 0)))
+ {
+ SetOrPush::Push(set_resources) => set_resources,
+ _ => unreachable!(),
+ };
+
+ for write in &descriptor_writes {
+ set_resources.update(write);
+ }
+
+ self.commands.push(Box::new(Cmd {
+ pipeline_bind_point,
+ pipeline_layout,
+ set_num,
+ descriptor_writes,
+ }));
+ }
+}
+
+pub struct SyncCommandBufferBuilderBindDescriptorSets<'b> {
+ builder: &'b mut SyncCommandBufferBuilder,
+ descriptor_sets: SmallVec<[DescriptorSetWithOffsets; 12]>,
+}
+
+impl<'b> SyncCommandBufferBuilderBindDescriptorSets<'b> {
+ /// Adds a descriptor set to the list.
+ pub fn add(&mut self, descriptor_set: impl Into<DescriptorSetWithOffsets>) {
+ self.descriptor_sets.push(descriptor_set.into());
+ }
+
+ #[inline]
+ pub unsafe fn submit(
+ self,
+ pipeline_bind_point: PipelineBindPoint,
+ pipeline_layout: Arc<PipelineLayout>,
+ first_set: u32,
+ ) {
+ if self.descriptor_sets.is_empty() {
+ return;
+ }
+
+ struct Cmd {
+ descriptor_sets: SmallVec<[DescriptorSetWithOffsets; 12]>,
+ pipeline_bind_point: PipelineBindPoint,
+ pipeline_layout: Arc<PipelineLayout>,
+ first_set: u32,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "bind_descriptor_sets"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ let descriptor_sets = self.descriptor_sets.iter().map(|x| x.as_ref().0.inner());
+ let dynamic_offsets = self
+ .descriptor_sets
+ .iter()
+ .flat_map(|x| x.as_ref().1.iter().copied());
+
+ out.bind_descriptor_sets(
+ self.pipeline_bind_point,
+ &self.pipeline_layout,
+ self.first_set,
+ descriptor_sets,
+ dynamic_offsets,
+ );
+ }
+ }
+
+ let state = self.builder.current_state.invalidate_descriptor_sets(
+ pipeline_bind_point,
+ pipeline_layout.clone(),
+ first_set,
+ self.descriptor_sets.len() as u32,
+ );
+
+ for (set_num, set) in self.descriptor_sets.iter().enumerate() {
+ state
+ .descriptor_sets
+ .insert(first_set + set_num as u32, SetOrPush::Set(set.clone()));
+ }
+
+ self.builder.commands.push(Box::new(Cmd {
+ descriptor_sets: self.descriptor_sets,
+ pipeline_bind_point,
+ pipeline_layout,
+ first_set,
+ }));
+ }
+}
+
+/// Prototype for a `vkCmdBindVertexBuffers`.
+pub struct SyncCommandBufferBuilderBindVertexBuffer<'a> {
+ builder: &'a mut SyncCommandBufferBuilder,
+ inner: UnsafeCommandBufferBuilderBindVertexBuffer,
+ buffers: SmallVec<[Subbuffer<[u8]>; 4]>,
+}
+
+impl<'a> SyncCommandBufferBuilderBindVertexBuffer<'a> {
+ /// Adds a buffer to the list.
+ #[inline]
+ pub fn add(&mut self, buffer: Subbuffer<[u8]>) {
+ self.inner.add(&buffer);
+ self.buffers.push(buffer);
+ }
+
+ #[inline]
+ pub unsafe fn submit(self, first_set: u32) {
+ struct Cmd {
+ first_set: u32,
+ inner: Mutex<Option<UnsafeCommandBufferBuilderBindVertexBuffer>>,
+ _buffers: SmallVec<[Subbuffer<[u8]>; 4]>,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "bind_vertex_buffers"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.bind_vertex_buffers(self.first_set, self.inner.lock().take().unwrap());
+ }
+ }
+
+ for (i, buffer) in self.buffers.iter().enumerate() {
+ self.builder
+ .current_state
+ .vertex_buffers
+ .insert(first_set + i as u32, buffer.clone());
+ }
+
+ self.builder.commands.push(Box::new(Cmd {
+ first_set,
+ inner: Mutex::new(Some(self.inner)),
+ _buffers: self.buffers,
+ }));
+ }
+}
+
+impl UnsafeCommandBufferBuilder {
+ /// Calls `vkCmdBindDescriptorSets` on the builder.
+ ///
+ /// Does nothing if the list of descriptor sets is empty, as it would be a no-op and isn't a
+ /// valid usage of the command anyway.
+ #[inline]
+ pub unsafe fn bind_descriptor_sets<'s>(
+ &mut self,
+ pipeline_bind_point: PipelineBindPoint,
+ pipeline_layout: &PipelineLayout,
+ first_set: u32,
+ sets: impl IntoIterator<Item = &'s UnsafeDescriptorSet>,
+ dynamic_offsets: impl IntoIterator<Item = u32>,
+ ) {
+ let fns = self.device.fns();
+
+ let sets: SmallVec<[_; 12]> = sets.into_iter().map(|s| s.handle()).collect();
+ if sets.is_empty() {
+ return;
+ }
+ let dynamic_offsets: SmallVec<[u32; 32]> = dynamic_offsets.into_iter().collect();
+
+ let num_bindings = sets.len() as u32;
+ debug_assert!(first_set + num_bindings <= pipeline_layout.set_layouts().len() as u32);
+
+ (fns.v1_0.cmd_bind_descriptor_sets)(
+ self.handle,
+ pipeline_bind_point.into(),
+ pipeline_layout.handle(),
+ first_set,
+ num_bindings,
+ sets.as_ptr(),
+ dynamic_offsets.len() as u32,
+ dynamic_offsets.as_ptr(),
+ );
+ }
+
+ /// Calls `vkCmdBindIndexBuffer` on the builder.
+ #[inline]
+ pub unsafe fn bind_index_buffer(&mut self, buffer: &Subbuffer<[u8]>, index_type: IndexType) {
+ let fns = self.device.fns();
+
+ debug_assert!(buffer.offset() < buffer.buffer().size());
+ debug_assert!(buffer
+ .buffer()
+ .usage()
+ .intersects(BufferUsage::INDEX_BUFFER));
+
+ (fns.v1_0.cmd_bind_index_buffer)(
+ self.handle,
+ buffer.buffer().handle(),
+ buffer.offset(),
+ index_type.into(),
+ );
+ }
+
+ /// Calls `vkCmdBindPipeline` on the builder with a compute pipeline.
+ #[inline]
+ pub unsafe fn bind_pipeline_compute(&mut self, pipeline: &ComputePipeline) {
+ let fns = self.device.fns();
+ (fns.v1_0.cmd_bind_pipeline)(
+ self.handle,
+ ash::vk::PipelineBindPoint::COMPUTE,
+ pipeline.handle(),
+ );
+ }
+
+ /// Calls `vkCmdBindPipeline` on the builder with a graphics pipeline.
+ #[inline]
+ pub unsafe fn bind_pipeline_graphics(&mut self, pipeline: &GraphicsPipeline) {
+ let fns = self.device.fns();
+ (fns.v1_0.cmd_bind_pipeline)(
+ self.handle,
+ ash::vk::PipelineBindPoint::GRAPHICS,
+ pipeline.handle(),
+ );
+ }
+
+ /// Calls `vkCmdBindVertexBuffers` on the builder.
+ ///
+ /// Does nothing if the list of buffers is empty, as it would be a no-op and isn't a valid
+ /// usage of the command anyway.
+ // TODO: vkCmdBindVertexBuffers2EXT
+ #[inline]
+ pub unsafe fn bind_vertex_buffers(
+ &mut self,
+ first_binding: u32,
+ params: UnsafeCommandBufferBuilderBindVertexBuffer,
+ ) {
+ debug_assert_eq!(params.raw_buffers.len(), params.offsets.len());
+
+ if params.raw_buffers.is_empty() {
+ return;
+ }
+
+ let fns = self.device.fns();
+
+ let num_bindings = params.raw_buffers.len() as u32;
+
+ debug_assert!({
+ let max_bindings = self
+ .device
+ .physical_device()
+ .properties()
+ .max_vertex_input_bindings;
+ first_binding + num_bindings <= max_bindings
+ });
+
+ (fns.v1_0.cmd_bind_vertex_buffers)(
+ self.handle,
+ first_binding,
+ num_bindings,
+ params.raw_buffers.as_ptr(),
+ params.offsets.as_ptr(),
+ );
+ }
+
+ /// Calls `vkCmdPushConstants` on the builder.
+ pub unsafe fn push_constants<D>(
+ &mut self,
+ pipeline_layout: &PipelineLayout,
+ stages: ShaderStages,
+ offset: u32,
+ size: u32,
+ data: &D,
+ ) where
+ D: BufferContents + ?Sized,
+ {
+ let fns = self.device.fns();
+
+ debug_assert!(!stages.is_empty());
+ debug_assert!(size > 0);
+ debug_assert_eq!(size % 4, 0);
+ debug_assert_eq!(offset % 4, 0);
+ debug_assert!(size_of_val(data) >= size as usize);
+
+ (fns.v1_0.cmd_push_constants)(
+ self.handle,
+ pipeline_layout.handle(),
+ stages.into(),
+ offset,
+ size,
+ data as *const _ as *const _,
+ );
+ }
+
+ /// Calls `vkCmdPushDescriptorSetKHR` on the builder.
+ ///
+ /// If the list is empty then the command is automatically ignored.
+ pub unsafe fn push_descriptor_set<'a>(
+ &mut self,
+ pipeline_bind_point: PipelineBindPoint,
+ pipeline_layout: &PipelineLayout,
+ set_num: u32,
+ descriptor_writes: impl IntoIterator<Item = &'a WriteDescriptorSet>,
+ ) {
+ debug_assert!(self.device.enabled_extensions().khr_push_descriptor);
+
+ let (infos, mut writes): (SmallVec<[_; 8]>, SmallVec<[_; 8]>) = descriptor_writes
+ .into_iter()
+ .map(|write| {
+ let binding =
+ &pipeline_layout.set_layouts()[set_num as usize].bindings()[&write.binding()];
+
+ (
+ write.to_vulkan_info(binding.descriptor_type),
+ write.to_vulkan(ash::vk::DescriptorSet::null(), binding.descriptor_type),
+ )
+ })
+ .unzip();
+
+ if writes.is_empty() {
+ return;
+ }
+
+ // Set the info pointers separately.
+ for (info, write) in infos.iter().zip(writes.iter_mut()) {
+ match info {
+ DescriptorWriteInfo::Image(info) => {
+ write.descriptor_count = info.len() as u32;
+ write.p_image_info = info.as_ptr();
+ }
+ DescriptorWriteInfo::Buffer(info) => {
+ write.descriptor_count = info.len() as u32;
+ write.p_buffer_info = info.as_ptr();
+ }
+ DescriptorWriteInfo::BufferView(info) => {
+ write.descriptor_count = info.len() as u32;
+ write.p_texel_buffer_view = info.as_ptr();
+ }
+ }
+
+ debug_assert!(write.descriptor_count != 0);
+ }
+
+ let fns = self.device.fns();
+
+ (fns.khr_push_descriptor.cmd_push_descriptor_set_khr)(
+ self.handle,
+ pipeline_bind_point.into(),
+ pipeline_layout.handle(),
+ set_num,
+ writes.len() as u32,
+ writes.as_ptr(),
+ );
+ }
+}
+
+/// Prototype for a `vkCmdBindVertexBuffers`.
+#[derive(Debug)]
+pub struct UnsafeCommandBufferBuilderBindVertexBuffer {
+ // Raw handles of the buffers to bind.
+ pub raw_buffers: SmallVec<[ash::vk::Buffer; 4]>,
+ // Raw offsets of the buffers to bind.
+ pub offsets: SmallVec<[DeviceSize; 4]>,
+}
+
+impl UnsafeCommandBufferBuilderBindVertexBuffer {
+ /// Builds a new empty list.
+ #[inline]
+ pub fn new() -> UnsafeCommandBufferBuilderBindVertexBuffer {
+ UnsafeCommandBufferBuilderBindVertexBuffer {
+ raw_buffers: SmallVec::new(),
+ offsets: SmallVec::new(),
+ }
+ }
+
+ /// Adds a buffer to the list.
+ #[inline]
+ pub fn add(&mut self, subbuffer: &Subbuffer<[u8]>) {
+ debug_assert!(subbuffer
+ .buffer()
+ .usage()
+ .intersects(BufferUsage::VERTEX_BUFFER));
+ self.raw_buffers.push(subbuffer.buffer().handle());
+ self.offsets.push(subbuffer.offset());
+ }
+}
+
+#[derive(Clone, Debug)]
+pub(in super::super) enum BindPushError {
+ DescriptorSetUpdateError(DescriptorSetUpdateError),
+
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+
+ /// The element of `descriptor_sets` being bound to a slot is not compatible with the
+ /// corresponding slot in `pipeline_layout`.
+ DescriptorSetNotCompatible {
+ set_num: u32,
+ },
+
+ /// The descriptor set number being pushed is not defined for push descriptor sets in the
+ /// pipeline layout.
+ DescriptorSetNotPush {
+ set_num: u32,
+ },
+
+ /// The highest descriptor set slot being bound is greater than the number of sets in
+ /// `pipeline_layout`.
+ DescriptorSetOutOfRange {
+ set_num: u32,
+ pipeline_layout_set_count: u32,
+ },
+
+ /// In an element of `descriptor_sets`, the number of provided dynamic offsets does not match
+ /// the number required by the descriptor set.
+ DynamicOffsetCountMismatch {
+ set_num: u32,
+ provided_count: usize,
+ required_count: usize,
+ },
+
+ /// In an element of `descriptor_sets`, a provided dynamic offset
+ /// is not a multiple of the value of the [`min_uniform_buffer_offset_alignment`] or
+ /// [`min_storage_buffer_offset_alignment`] property.
+ ///
+ /// min_uniform_buffer_offset_alignment: crate::device::Properties::min_uniform_buffer_offset_alignment
+ /// min_storage_buffer_offset_alignment: crate::device::Properties::min_storage_buffer_offset_alignment
+ DynamicOffsetNotAligned {
+ set_num: u32,
+ binding_num: u32,
+ index: u32,
+ offset: u32,
+ required_alignment: DeviceAlignment,
+ },
+
+ /// In an element of `descriptor_sets`, a provided dynamic offset, when added to the end of the
+ /// buffer range bound to the descriptor set, is greater than the size of the buffer.
+ DynamicOffsetOutOfBufferBounds {
+ set_num: u32,
+ binding_num: u32,
+ index: u32,
+ offset: u32,
+ range_end: DeviceSize,
+ buffer_size: DeviceSize,
+ },
+
+ /// An index buffer is missing the `index_buffer` usage.
+ IndexBufferMissingUsage,
+
+ /// The `max_vertex_input_bindings` limit has been exceeded.
+ MaxVertexInputBindingsExceeded {
+ _binding_count: u32,
+ _max: u32,
+ },
+
+ /// The queue family doesn't allow this operation.
+ NotSupportedByQueueFamily,
+
+ /// The newly set pipeline has color attachment formats that do not match the
+ /// previously used pipeline.
+ PreviousPipelineColorAttachmentFormatMismatch,
+
+ /// The newly set pipeline has a depth attachment format that does not match the
+ /// previously used pipeline.
+ PreviousPipelineDepthAttachmentFormatMismatch,
+
+ /// The newly set pipeline has a stencil attachment format that does not match the
+ /// previously used pipeline.
+ PreviousPipelineStencilAttachmentFormatMismatch,
+
+ /// The push constants data to be written at an offset is not included in any push constant
+ /// range of the pipeline layout.
+ PushConstantsDataOutOfRange {
+ offset: u32,
+ },
+
+ /// The push constants offset is not a multiple of 4.
+ PushConstantsOffsetNotAligned,
+
+ /// The push constants size is not a multiple of 4.
+ PushConstantsSizeNotAligned,
+
+ /// A vertex buffer is missing the `vertex_buffer` usage.
+ VertexBufferMissingUsage,
+}
+
+impl error::Error for BindPushError {
+ fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+ match self {
+ BindPushError::DescriptorSetUpdateError(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+impl Display for BindPushError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ Self::DescriptorSetUpdateError(_) => write!(f, "a DescriptorSetUpdateError"),
+ Self::DescriptorSetNotCompatible { set_num } => write!(
+ f,
+ "the element of `descriptor_sets` being bound to slot {} is not compatible with \
+ the corresponding slot in `pipeline_layout`",
+ set_num,
+ ),
+ Self::DescriptorSetNotPush { set_num } => write!(
+ f,
+ "the descriptor set number being pushed ({}) is not defined for push descriptor \
+ sets in the pipeline layout",
+ set_num,
+ ),
+ Self::DescriptorSetOutOfRange {
+ set_num,
+ pipeline_layout_set_count,
+ } => write!(
+ f,
+ "the highest descriptor set slot being bound ({}) is greater than the number of \
+ sets in `pipeline_layout` ({})",
+ set_num, pipeline_layout_set_count,
+ ),
+ Self::DynamicOffsetCountMismatch {
+ set_num,
+ provided_count,
+ required_count,
+ } => write!(
+ f,
+ "in the element of `descriptor_sets` being bound to slot {}, the number of \
+ provided dynamic offsets ({}) does not match the number required by the \
+ descriptor set ({})",
+ set_num, provided_count, required_count,
+ ),
+ Self::DynamicOffsetNotAligned {
+ set_num,
+ binding_num,
+ index,
+ offset,
+ required_alignment,
+ } => write!(
+ f,
+ "in the element of `descriptor_sets` being bound to slot {}, the dynamic offset \
+ provided for binding {} index {} ({}) is not a multiple of the value of the \
+ `min_uniform_buffer_offset_alignment` or `min_storage_buffer_offset_alignment` \
+ property ({:?})",
+ set_num, binding_num, index, offset, required_alignment,
+ ),
+ Self::DynamicOffsetOutOfBufferBounds {
+ set_num,
+ binding_num,
+ index,
+ offset,
+ range_end,
+ buffer_size,
+ } => write!(
+ f,
+ "in the element of `descriptor_sets` being bound to slot {}, the dynamic offset \
+ provided for binding {} index {} ({}), when added to the end of the buffer range \
+ bound to the descriptor set ({}), is greater than the size of the buffer ({})",
+ set_num, binding_num, index, offset, range_end, buffer_size,
+ ),
+ Self::IndexBufferMissingUsage => {
+ write!(f, "an index buffer is missing the `index_buffer` usage")
+ }
+ Self::MaxVertexInputBindingsExceeded { .. } => {
+ write!(f, "the `max_vertex_input_bindings` limit has been exceeded")
+ }
+ Self::NotSupportedByQueueFamily => {
+ write!(f, "the queue family doesn't allow this operation")
+ }
+ Self::PreviousPipelineColorAttachmentFormatMismatch => write!(
+ f,
+ "the newly set pipeline has color attachment formats that do not match the \
+ previously used pipeline",
+ ),
+ Self::PreviousPipelineDepthAttachmentFormatMismatch => write!(
+ f,
+ "the newly set pipeline has a depth attachment format that does not match the \
+ previously used pipeline",
+ ),
+ Self::PreviousPipelineStencilAttachmentFormatMismatch => write!(
+ f,
+ "the newly set pipeline has a stencil attachment format that does not match the \
+ previously used pipeline",
+ ),
+ Self::PushConstantsDataOutOfRange { offset } => write!(
+ f,
+ "the push constants data to be written at offset {} is not included in any push \
+ constant range of the pipeline layout",
+ offset,
+ ),
+ Self::PushConstantsOffsetNotAligned => {
+ write!(f, "the push constants offset is not a multiple of 4")
+ }
+ Self::PushConstantsSizeNotAligned => {
+ write!(f, "the push constants size is not a multiple of 4")
+ }
+ Self::VertexBufferMissingUsage => {
+ write!(f, "a vertex buffer is missing the `vertex_buffer` usage")
+ }
+ }
+ }
+}
+
+impl From<DescriptorSetUpdateError> for BindPushError {
+ fn from(err: DescriptorSetUpdateError) -> Self {
+ Self::DescriptorSetUpdateError(err)
+ }
+}
+
+impl From<RequirementNotMet> for BindPushError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
+ }
+ }
+}
diff --git a/src/command_buffer/commands/clear.rs b/src/command_buffer/commands/clear.rs
new file mode 100644
index 0000000..9e68611
--- /dev/null
+++ b/src/command_buffer/commands/clear.rs
@@ -0,0 +1,1207 @@
+// Copyright (c) 2022 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use crate::{
+ buffer::{BufferContents, BufferUsage, Subbuffer},
+ command_buffer::{
+ allocator::CommandBufferAllocator,
+ synced::{Command, Resource, SyncCommandBufferBuilder, SyncCommandBufferBuilderError},
+ sys::UnsafeCommandBufferBuilder,
+ AutoCommandBufferBuilder, ResourceInCommand, ResourceUseRef,
+ },
+ device::{DeviceOwned, QueueFlags},
+ format::{ClearColorValue, ClearDepthStencilValue, Format, FormatFeatures},
+ image::{ImageAccess, ImageAspects, ImageLayout, ImageSubresourceRange, ImageUsage},
+ sync::{AccessFlags, PipelineMemoryAccess, PipelineStages},
+ DeviceSize, RequirementNotMet, RequiresOneOf, SafeDeref, Version, VulkanObject,
+};
+use smallvec::{smallvec, SmallVec};
+use std::{
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+ mem::size_of_val,
+ sync::Arc,
+};
+
+/// # Commands to fill resources with new data.
+impl<L, A> AutoCommandBufferBuilder<L, A>
+where
+ A: CommandBufferAllocator,
+{
+ /// Clears a color image with a specific value.
+ pub fn clear_color_image(
+ &mut self,
+ clear_info: ClearColorImageInfo,
+ ) -> Result<&mut Self, ClearError> {
+ self.validate_clear_color_image(&clear_info)?;
+
+ unsafe {
+ self.inner.clear_color_image(clear_info)?;
+ }
+
+ Ok(self)
+ }
+
+ fn validate_clear_color_image(
+ &self,
+ clear_info: &ClearColorImageInfo,
+ ) -> Result<(), ClearError> {
+ let device = self.device();
+
+ // VUID-vkCmdClearColorImage-renderpass
+ if self.render_pass_state.is_some() {
+ return Err(ClearError::ForbiddenInsideRenderPass);
+ }
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdClearColorImage-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(ClearError::NotSupportedByQueueFamily);
+ }
+
+ let &ClearColorImageInfo {
+ ref image,
+ image_layout,
+ clear_value: _,
+ ref regions,
+ _ne: _,
+ } = clear_info;
+
+ // VUID-vkCmdClearColorImage-imageLayout-parameter
+ image_layout.validate_device(device)?;
+
+ // VUID-vkCmdClearColorImage-commonparent
+ assert_eq!(device, image.device());
+
+ // VUID-vkCmdClearColorImage-image-00002
+ if !image.usage().intersects(ImageUsage::TRANSFER_DST) {
+ return Err(ClearError::MissingUsage {
+ usage: "transfer_dst",
+ });
+ }
+
+ if device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_maintenance1 {
+ // VUID-vkCmdClearColorImage-image-01993
+ if !image
+ .format_features()
+ .intersects(FormatFeatures::TRANSFER_DST)
+ {
+ return Err(ClearError::MissingFormatFeature {
+ format_feature: "transfer_dst",
+ });
+ }
+ }
+
+ let image_aspects = image.format().aspects();
+
+ // VUID-vkCmdClearColorImage-image-00007
+ if image_aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL) {
+ return Err(ClearError::FormatNotSupported {
+ format: image.format(),
+ });
+ }
+
+ // VUID-vkCmdClearColorImage-image-00007
+ if image.format().compression().is_some() {
+ return Err(ClearError::FormatNotSupported {
+ format: image.format(),
+ });
+ }
+
+ // VUID-vkCmdClearColorImage-image-01545
+ if image.format().ycbcr_chroma_sampling().is_some() {
+ return Err(ClearError::FormatNotSupported {
+ format: image.format(),
+ });
+ }
+
+ // VUID-vkCmdClearColorImage-imageLayout-01394
+ if !matches!(
+ image_layout,
+ ImageLayout::TransferDstOptimal | ImageLayout::General
+ ) {
+ return Err(ClearError::ImageLayoutInvalid { image_layout });
+ }
+
+ for (region_index, subresource_range) in regions.iter().enumerate() {
+ // VUID-VkImageSubresourceRange-aspectMask-parameter
+ subresource_range.aspects.validate_device(device)?;
+
+ // VUID-VkImageSubresourceRange-aspectMask-requiredbitmask
+ assert!(!subresource_range.aspects.is_empty());
+
+ // VUID-vkCmdClearColorImage-aspectMask-02498
+ if !image_aspects.contains(subresource_range.aspects) {
+ return Err(ClearError::AspectsNotAllowed {
+ region_index,
+ aspects: subresource_range.aspects,
+ allowed_aspects: image_aspects,
+ });
+ }
+
+ // VUID-VkImageSubresourceRange-levelCount-01720
+ assert!(!subresource_range.mip_levels.is_empty());
+
+ // VUID-vkCmdClearColorImage-baseMipLevel-01470
+ // VUID-vkCmdClearColorImage-pRanges-01692
+ if subresource_range.mip_levels.end > image.mip_levels() {
+ return Err(ClearError::MipLevelsOutOfRange {
+ region_index,
+ mip_levels_range_end: subresource_range.mip_levels.end,
+ image_mip_levels: image.dimensions().array_layers(),
+ });
+ }
+
+ // VUID-VkImageSubresourceRange-layerCount-01721
+ assert!(!subresource_range.array_layers.is_empty());
+
+ // VUID-vkCmdClearDepthStencilImage-baseArrayLayer-01476
+ // VUID-vkCmdClearDepthStencilImage-pRanges-01695
+ if subresource_range.array_layers.end > image.dimensions().array_layers() {
+ return Err(ClearError::ArrayLayersOutOfRange {
+ region_index,
+ array_layers_range_end: subresource_range.array_layers.end,
+ image_array_layers: image.dimensions().array_layers(),
+ });
+ }
+ }
+
+ Ok(())
+ }
+
+ /// Clears a depth/stencil image with a specific value.
+ pub fn clear_depth_stencil_image(
+ &mut self,
+ clear_info: ClearDepthStencilImageInfo,
+ ) -> Result<&mut Self, ClearError> {
+ self.validate_clear_depth_stencil_image(&clear_info)?;
+
+ unsafe {
+ self.inner.clear_depth_stencil_image(clear_info)?;
+ }
+
+ Ok(self)
+ }
+
+ fn validate_clear_depth_stencil_image(
+ &self,
+ clear_info: &ClearDepthStencilImageInfo,
+ ) -> Result<(), ClearError> {
+ let device = self.device();
+
+ // VUID-vkCmdClearDepthStencilImage-renderpass
+ if self.render_pass_state.is_some() {
+ return Err(ClearError::ForbiddenInsideRenderPass);
+ }
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdClearDepthStencilImage-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(ClearError::NotSupportedByQueueFamily);
+ }
+
+ let &ClearDepthStencilImageInfo {
+ ref image,
+ image_layout,
+ clear_value,
+ ref regions,
+ _ne: _,
+ } = clear_info;
+
+ // VUID-vkCmdClearDepthStencilImage-imageLayout-parameter
+ image_layout.validate_device(device)?;
+
+ // VUID-vkCmdClearDepthStencilImage-commonparent
+ assert_eq!(device, image.device());
+
+ if device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_maintenance1 {
+ // VUID-vkCmdClearDepthStencilImage-image-01994
+ if !image
+ .format_features()
+ .intersects(FormatFeatures::TRANSFER_DST)
+ {
+ return Err(ClearError::MissingFormatFeature {
+ format_feature: "transfer_dst",
+ });
+ }
+ }
+
+ let image_aspects = image.format().aspects();
+
+ // VUID-vkCmdClearDepthStencilImage-image-00014
+ if !image_aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL) {
+ return Err(ClearError::FormatNotSupported {
+ format: image.format(),
+ });
+ }
+
+ // VUID-vkCmdClearDepthStencilImage-imageLayout-00012
+ if !matches!(
+ image_layout,
+ ImageLayout::TransferDstOptimal | ImageLayout::General
+ ) {
+ return Err(ClearError::ImageLayoutInvalid { image_layout });
+ }
+
+ // VUID-VkClearDepthStencilValue-depth-00022
+ if !device.enabled_extensions().ext_depth_range_unrestricted
+ && !(0.0..=1.0).contains(&clear_value.depth)
+ {
+ return Err(ClearError::RequirementNotMet {
+ required_for: "`clear_info.clear_value.depth` is not between `0.0` and `1.0` \
+ inclusive",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["ext_depth_range_unrestricted"],
+ ..Default::default()
+ },
+ });
+ }
+
+ let mut image_aspects_used = ImageAspects::empty();
+
+ for (region_index, subresource_range) in regions.iter().enumerate() {
+ // VUID-VkImageSubresourceRange-aspectMask-parameter
+ subresource_range.aspects.validate_device(device)?;
+
+ // VUID-VkImageSubresourceRange-aspectMask-requiredbitmask
+ assert!(!subresource_range.aspects.is_empty());
+
+ // VUID-vkCmdClearDepthStencilImage-aspectMask-02824
+ // VUID-vkCmdClearDepthStencilImage-image-02825
+ // VUID-vkCmdClearDepthStencilImage-image-02826
+ if !image_aspects.contains(subresource_range.aspects) {
+ return Err(ClearError::AspectsNotAllowed {
+ region_index,
+ aspects: subresource_range.aspects,
+ allowed_aspects: image_aspects,
+ });
+ }
+
+ image_aspects_used |= subresource_range.aspects;
+
+ // VUID-VkImageSubresourceRange-levelCount-01720
+ assert!(!subresource_range.mip_levels.is_empty());
+
+ // VUID-vkCmdClearDepthStencilImage-baseMipLevel-01474
+ // VUID-vkCmdClearDepthStencilImage-pRanges-01694
+ if subresource_range.mip_levels.end > image.mip_levels() {
+ return Err(ClearError::MipLevelsOutOfRange {
+ region_index,
+ mip_levels_range_end: subresource_range.mip_levels.end,
+ image_mip_levels: image.dimensions().array_layers(),
+ });
+ }
+
+ // VUID-VkImageSubresourceRange-layerCount-01721
+ assert!(!subresource_range.array_layers.is_empty());
+
+ // VUID-vkCmdClearDepthStencilImage-baseArrayLayer-01476
+ // VUID-vkCmdClearDepthStencilImage-pRanges-01695
+ if subresource_range.array_layers.end > image.dimensions().array_layers() {
+ return Err(ClearError::ArrayLayersOutOfRange {
+ region_index,
+ array_layers_range_end: subresource_range.array_layers.end,
+ image_array_layers: image.dimensions().array_layers(),
+ });
+ }
+ }
+
+ // VUID-vkCmdClearDepthStencilImage-pRanges-02658
+ // VUID-vkCmdClearDepthStencilImage-pRanges-02659
+ if image_aspects_used.intersects(ImageAspects::STENCIL)
+ && !image.stencil_usage().intersects(ImageUsage::TRANSFER_DST)
+ {
+ return Err(ClearError::MissingUsage {
+ usage: "transfer_dst",
+ });
+ }
+
+ // VUID-vkCmdClearDepthStencilImage-pRanges-02660
+ if !(image_aspects_used - ImageAspects::STENCIL).is_empty()
+ && !image.usage().intersects(ImageUsage::TRANSFER_DST)
+ {
+ return Err(ClearError::MissingUsage {
+ usage: "transfer_dst",
+ });
+ }
+
+ Ok(())
+ }
+
+ /// Fills a region of a buffer with repeated copies of a value.
+ ///
+ /// This function is similar to the `memset` function in C. The `data` parameter is a number
+ /// that will be repeatedly written through the entire buffer.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `dst_buffer` was not created from the same device as `self`.
+ pub fn fill_buffer(
+ &mut self,
+ dst_buffer: Subbuffer<[u32]>,
+ data: u32,
+ ) -> Result<&mut Self, ClearError> {
+ self.validate_fill_buffer(&dst_buffer, data)?;
+
+ unsafe {
+ self.inner.fill_buffer(dst_buffer, data)?;
+ }
+
+ Ok(self)
+ }
+
+ fn validate_fill_buffer(
+ &self,
+ dst_buffer: &Subbuffer<[u32]>,
+ _data: u32,
+ ) -> Result<(), ClearError> {
+ let device = self.device();
+
+ // VUID-vkCmdFillBuffer-renderpass
+ if self.render_pass_state.is_some() {
+ return Err(ClearError::ForbiddenInsideRenderPass);
+ }
+
+ let queue_family_properties = self.queue_family_properties();
+
+ if device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_maintenance1 {
+ // VUID-vkCmdFillBuffer-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::TRANSFER | QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(ClearError::NotSupportedByQueueFamily);
+ }
+ } else {
+ // VUID-vkCmdFillBuffer-commandBuffer-00030
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(ClearError::NotSupportedByQueueFamily);
+ }
+ }
+
+ // VUID-vkCmdFillBuffer-commonparent
+ assert_eq!(device, dst_buffer.device());
+
+ // VUID-vkCmdFillBuffer-size-00026
+ // Guaranteed by `Subbuffer`
+
+ // VUID-vkCmdFillBuffer-dstBuffer-00029
+ if !dst_buffer
+ .buffer()
+ .usage()
+ .intersects(BufferUsage::TRANSFER_DST)
+ {
+ return Err(ClearError::MissingUsage {
+ usage: "transfer_dst",
+ });
+ }
+
+ // VUID-vkCmdFillBuffer-dstOffset-00024
+ // VUID-vkCmdFillBuffer-size-00027
+ // Guaranteed by `Subbuffer`
+
+ // VUID-vkCmdFillBuffer-dstOffset-00025
+ // VUID-vkCmdFillBuffer-size-00028
+ // Guaranteed because we take `Subbuffer<[u32]>`
+
+ Ok(())
+ }
+
+ /// Writes data to a region of a buffer.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `dst_buffer` was not created from the same device as `self`.
+ pub fn update_buffer<D, Dd>(
+ &mut self,
+ dst_buffer: Subbuffer<D>,
+ data: Dd,
+ ) -> Result<&mut Self, ClearError>
+ where
+ D: BufferContents + ?Sized,
+ Dd: SafeDeref<Target = D> + Send + Sync + 'static,
+ {
+ self.validate_update_buffer(
+ dst_buffer.as_bytes(),
+ size_of_val(data.deref()) as DeviceSize,
+ )?;
+
+ unsafe {
+ self.inner.update_buffer(dst_buffer, data)?;
+ }
+
+ Ok(self)
+ }
+
+ fn validate_update_buffer(
+ &self,
+ dst_buffer: &Subbuffer<[u8]>,
+ data_size: DeviceSize,
+ ) -> Result<(), ClearError> {
+ let device = self.device();
+
+ // VUID-vkCmdUpdateBuffer-renderpass
+ if self.render_pass_state.is_some() {
+ return Err(ClearError::ForbiddenInsideRenderPass);
+ }
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdUpdateBuffer-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::TRANSFER | QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(ClearError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdUpdateBuffer-commonparent
+ assert_eq!(device, dst_buffer.device());
+
+ // VUID-vkCmdUpdateBuffer-dataSize-arraylength
+ assert!(data_size != 0);
+
+ // VUID-vkCmdUpdateBuffer-dstBuffer-00034
+ if !dst_buffer
+ .buffer()
+ .usage()
+ .intersects(BufferUsage::TRANSFER_DST)
+ {
+ return Err(ClearError::MissingUsage {
+ usage: "transfer_dst",
+ });
+ }
+
+ // VUID-vkCmdUpdateBuffer-dstOffset-00032
+ // VUID-vkCmdUpdateBuffer-dataSize-00033
+ if data_size > dst_buffer.size() {
+ return Err(ClearError::RegionOutOfBufferBounds {
+ region_index: 0,
+ offset_range_end: data_size,
+ buffer_size: dst_buffer.size(),
+ });
+ }
+
+ // VUID-vkCmdUpdateBuffer-dstOffset-00036
+ if dst_buffer.offset() % 4 != 0 {
+ return Err(ClearError::OffsetNotAlignedForBuffer {
+ region_index: 0,
+ offset: dst_buffer.offset(),
+ required_alignment: 4,
+ });
+ }
+
+ // VUID-vkCmdUpdateBuffer-dataSize-00037
+ if data_size > 65536 {
+ return Err(ClearError::DataTooLarge {
+ size: data_size,
+ max: 65536,
+ });
+ }
+
+ // VUID-vkCmdUpdateBuffer-dataSize-00038
+ if data_size % 4 != 0 {
+ return Err(ClearError::SizeNotAlignedForBuffer {
+ region_index: 0,
+ size: data_size,
+ required_alignment: 4,
+ });
+ }
+
+ Ok(())
+ }
+}
+
+impl SyncCommandBufferBuilder {
+ /// Calls `vkCmdClearColorImage` on the builder.
+ ///
+ /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
+ /// usage of the command anyway.
+ #[inline]
+ pub unsafe fn clear_color_image(
+ &mut self,
+ clear_info: ClearColorImageInfo,
+ ) -> Result<(), SyncCommandBufferBuilderError> {
+ struct Cmd {
+ clear_info: ClearColorImageInfo,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "clear_color_image"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.clear_color_image(&self.clear_info);
+ }
+ }
+
+ let &ClearColorImageInfo {
+ ref image,
+ image_layout,
+ clear_value: _,
+ ref regions,
+ _ne: _,
+ } = &clear_info;
+
+ let command_index = self.commands.len();
+ let command_name = "clear_color_image";
+ let resources: SmallVec<[_; 8]> = regions
+ .iter()
+ .cloned()
+ .flat_map(|subresource_range| {
+ [(
+ ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Destination,
+ secondary_use_ref: None,
+ },
+ Resource::Image {
+ image: image.clone(),
+ subresource_range,
+ memory: PipelineMemoryAccess {
+ stages: PipelineStages::ALL_TRANSFER,
+ access: AccessFlags::TRANSFER_WRITE,
+ exclusive: true,
+ },
+ start_layout: image_layout,
+ end_layout: image_layout,
+ },
+ )]
+ })
+ .collect();
+
+ for resource in &resources {
+ self.check_resource_conflicts(resource)?;
+ }
+
+ self.commands.push(Box::new(Cmd { clear_info }));
+
+ for resource in resources {
+ self.add_resource(resource);
+ }
+
+ Ok(())
+ }
+
+ /// Calls `vkCmdClearDepthStencilImage` on the builder.
+ ///
+ /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
+ /// usage of the command anyway.
+ #[inline]
+ pub unsafe fn clear_depth_stencil_image(
+ &mut self,
+ clear_info: ClearDepthStencilImageInfo,
+ ) -> Result<(), SyncCommandBufferBuilderError> {
+ struct Cmd {
+ clear_info: ClearDepthStencilImageInfo,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "clear_depth_stencil_image"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.clear_depth_stencil_image(&self.clear_info);
+ }
+ }
+
+ let &ClearDepthStencilImageInfo {
+ ref image,
+ image_layout,
+ clear_value: _,
+ ref regions,
+ _ne: _,
+ } = &clear_info;
+
+ let command_index = self.commands.len();
+ let command_name = "clear_depth_stencil_image";
+ let resources: SmallVec<[_; 8]> = regions
+ .iter()
+ .cloned()
+ .flat_map(|subresource_range| {
+ [(
+ ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Destination,
+ secondary_use_ref: None,
+ },
+ Resource::Image {
+ image: image.clone(),
+ subresource_range,
+ memory: PipelineMemoryAccess {
+ stages: PipelineStages::ALL_TRANSFER,
+ access: AccessFlags::TRANSFER_WRITE,
+ exclusive: true,
+ },
+ start_layout: image_layout,
+ end_layout: image_layout,
+ },
+ )]
+ })
+ .collect();
+
+ for resource in &resources {
+ self.check_resource_conflicts(resource)?;
+ }
+
+ self.commands.push(Box::new(Cmd { clear_info }));
+
+ for resource in resources {
+ self.add_resource(resource);
+ }
+
+ Ok(())
+ }
+
+ /// Calls `vkCmdFillBuffer` on the builder.
+ #[inline]
+ pub unsafe fn fill_buffer(
+ &mut self,
+ dst_buffer: Subbuffer<[u32]>,
+ data: u32,
+ ) -> Result<(), SyncCommandBufferBuilderError> {
+ struct Cmd {
+ dst_buffer: Subbuffer<[u32]>,
+ data: u32,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "fill_buffer"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.fill_buffer(&self.dst_buffer, self.data);
+ }
+ }
+
+ let command_index = self.commands.len();
+ let command_name = "fill_buffer";
+ let resources = [(
+ ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Destination,
+ secondary_use_ref: None,
+ },
+ Resource::Buffer {
+ buffer: dst_buffer.as_bytes().clone(),
+ range: 0..dst_buffer.size(),
+ memory: PipelineMemoryAccess {
+ stages: PipelineStages::ALL_TRANSFER,
+ access: AccessFlags::TRANSFER_WRITE,
+ exclusive: true,
+ },
+ },
+ )];
+
+ for resource in &resources {
+ self.check_resource_conflicts(resource)?;
+ }
+
+ self.commands.push(Box::new(Cmd { dst_buffer, data }));
+
+ for resource in resources {
+ self.add_resource(resource);
+ }
+
+ Ok(())
+ }
+
+ /// Calls `vkCmdUpdateBuffer` on the builder.
+ pub unsafe fn update_buffer<D, Dd>(
+ &mut self,
+ dst_buffer: Subbuffer<D>,
+ data: Dd,
+ ) -> Result<(), SyncCommandBufferBuilderError>
+ where
+ D: BufferContents + ?Sized,
+ Dd: SafeDeref<Target = D> + Send + Sync + 'static,
+ {
+ struct Cmd<D: ?Sized, Dd> {
+ dst_buffer: Subbuffer<D>,
+ data: Dd,
+ }
+
+ impl<D, Dd> Command for Cmd<D, Dd>
+ where
+ D: BufferContents + ?Sized,
+ Dd: SafeDeref<Target = D> + Send + Sync + 'static,
+ {
+ fn name(&self) -> &'static str {
+ "update_buffer"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.update_buffer(&self.dst_buffer, self.data.deref());
+ }
+ }
+
+ let command_index = self.commands.len();
+ let command_name = "update_buffer";
+ let resources = [(
+ ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Destination,
+ secondary_use_ref: None,
+ },
+ Resource::Buffer {
+ buffer: dst_buffer.as_bytes().clone(),
+ range: 0..size_of_val(data.deref()) as DeviceSize,
+ memory: PipelineMemoryAccess {
+ stages: PipelineStages::ALL_TRANSFER,
+ access: AccessFlags::TRANSFER_WRITE,
+ exclusive: true,
+ },
+ },
+ )];
+
+ for resource in &resources {
+ self.check_resource_conflicts(resource)?;
+ }
+
+ self.commands.push(Box::new(Cmd { dst_buffer, data }));
+
+ for resource in resources {
+ self.add_resource(resource);
+ }
+
+ Ok(())
+ }
+}
+
+impl UnsafeCommandBufferBuilder {
+ /// Calls `vkCmdClearColorImage` on the builder.
+ ///
+ /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
+ /// usage of the command anyway.
+ #[inline]
+ pub unsafe fn clear_color_image(&mut self, clear_info: &ClearColorImageInfo) {
+ let &ClearColorImageInfo {
+ ref image,
+ image_layout,
+ clear_value,
+ ref regions,
+ _ne: _,
+ } = clear_info;
+
+ if regions.is_empty() {
+ return;
+ }
+
+ let clear_value = clear_value.into();
+ let ranges: SmallVec<[_; 8]> = regions
+ .iter()
+ .cloned()
+ .map(ash::vk::ImageSubresourceRange::from)
+ .collect();
+
+ let fns = self.device.fns();
+ (fns.v1_0.cmd_clear_color_image)(
+ self.handle,
+ image.inner().image.handle(),
+ image_layout.into(),
+ &clear_value,
+ ranges.len() as u32,
+ ranges.as_ptr(),
+ );
+ }
+
+ /// Calls `vkCmdClearDepthStencilImage` on the builder.
+ ///
+ /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
+ /// usage of the command anyway.
+ #[inline]
+ pub unsafe fn clear_depth_stencil_image(&mut self, clear_info: &ClearDepthStencilImageInfo) {
+ let &ClearDepthStencilImageInfo {
+ ref image,
+ image_layout,
+ clear_value,
+ ref regions,
+ _ne: _,
+ } = clear_info;
+
+ if regions.is_empty() {
+ return;
+ }
+
+ let clear_value = clear_value.into();
+ let ranges: SmallVec<[_; 8]> = regions
+ .iter()
+ .cloned()
+ .map(ash::vk::ImageSubresourceRange::from)
+ .collect();
+
+ let fns = self.device.fns();
+ (fns.v1_0.cmd_clear_depth_stencil_image)(
+ self.handle,
+ image.inner().image.handle(),
+ image_layout.into(),
+ &clear_value,
+ ranges.len() as u32,
+ ranges.as_ptr(),
+ );
+ }
+
+ /// Calls `vkCmdFillBuffer` on the builder.
+ #[inline]
+ pub unsafe fn fill_buffer(&mut self, dst_buffer: &Subbuffer<[u32]>, data: u32) {
+ let fns = self.device.fns();
+ (fns.v1_0.cmd_fill_buffer)(
+ self.handle,
+ dst_buffer.buffer().handle(),
+ dst_buffer.offset(),
+ dst_buffer.size(),
+ data,
+ );
+ }
+
+ /// Calls `vkCmdUpdateBuffer` on the builder.
+ pub unsafe fn update_buffer<D>(&mut self, dst_buffer: &Subbuffer<D>, data: &D)
+ where
+ D: BufferContents + ?Sized,
+ {
+ let fns = self.device.fns();
+ (fns.v1_0.cmd_update_buffer)(
+ self.handle,
+ dst_buffer.buffer().handle(),
+ dst_buffer.offset(),
+ size_of_val(data) as DeviceSize,
+ data as *const _ as *const _,
+ );
+ }
+}
+
+/// Parameters to clear a color image.
+#[derive(Clone, Debug)]
+pub struct ClearColorImageInfo {
+ /// The image to clear.
+ ///
+ /// There is no default value.
+ pub image: Arc<dyn ImageAccess>,
+
+ /// The layout used for `image` during the clear operation.
+ ///
+ /// The following layouts are allowed:
+ /// - [`ImageLayout::TransferDstOptimal`]
+ /// - [`ImageLayout::General`]
+ ///
+ /// The default value is [`ImageLayout::TransferDstOptimal`].
+ pub image_layout: ImageLayout,
+
+ /// The color value to clear the image to.
+ ///
+ /// The default value is `ClearColorValue::Float([0.0; 4])`.
+ pub clear_value: ClearColorValue,
+
+ /// The subresource ranges of `image` to clear.
+ ///
+ /// The default value is a single region, covering the whole image.
+ pub regions: SmallVec<[ImageSubresourceRange; 1]>,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl ClearColorImageInfo {
+ /// Returns a `ClearColorImageInfo` with the specified `image`.
+ #[inline]
+ pub fn image(image: Arc<dyn ImageAccess>) -> Self {
+ let range = image.subresource_range();
+
+ Self {
+ image,
+ image_layout: ImageLayout::TransferDstOptimal,
+ clear_value: ClearColorValue::Float([0.0; 4]),
+ regions: smallvec![range],
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// Parameters to clear a depth/stencil image.
+#[derive(Clone, Debug)]
+pub struct ClearDepthStencilImageInfo {
+ /// The image to clear.
+ ///
+ /// There is no default value.
+ pub image: Arc<dyn ImageAccess>,
+
+ /// The layout used for `image` during the clear operation.
+ ///
+ /// The following layouts are allowed:
+ /// - [`ImageLayout::TransferDstOptimal`]
+ /// - [`ImageLayout::General`]
+ ///
+ /// The default value is [`ImageLayout::TransferDstOptimal`].
+ pub image_layout: ImageLayout,
+
+ /// The depth/stencil values to clear the image to.
+ ///
+ /// The default value is zero for both.
+ pub clear_value: ClearDepthStencilValue,
+
+ /// The subresource ranges of `image` to clear.
+ ///
+ /// The default value is a single region, covering the whole image.
+ pub regions: SmallVec<[ImageSubresourceRange; 1]>,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl ClearDepthStencilImageInfo {
+ /// Returns a `ClearDepthStencilImageInfo` with the specified `image`.
+ #[inline]
+ pub fn image(image: Arc<dyn ImageAccess>) -> Self {
+ let range = image.subresource_range();
+
+ Self {
+ image,
+ image_layout: ImageLayout::TransferDstOptimal,
+ clear_value: ClearDepthStencilValue::default(),
+ regions: smallvec![range],
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// Error that can happen when recording a clear command.
+#[derive(Clone, Debug)]
+pub enum ClearError {
+ SyncCommandBufferBuilderError(SyncCommandBufferBuilderError),
+
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+
+ /// Operation forbidden inside of a render pass.
+ ForbiddenInsideRenderPass,
+
+ /// The queue family doesn't allow this operation.
+ NotSupportedByQueueFamily,
+
+ /// The end of the range of accessed array layers of the subresource range of a region is
+ /// greater than the number of array layers in the image.
+ ArrayLayersOutOfRange {
+ region_index: usize,
+ array_layers_range_end: u32,
+ image_array_layers: u32,
+ },
+
+ /// The aspects of the subresource range of a region contain aspects that are not present
+ /// in the image, or that are not allowed.
+ AspectsNotAllowed {
+ region_index: usize,
+ aspects: ImageAspects,
+ allowed_aspects: ImageAspects,
+ },
+
+ /// The provided data has a size larger than the maximum allowed.
+ DataTooLarge {
+ size: DeviceSize,
+ max: DeviceSize,
+ },
+
+ /// The format of an image is not supported for this operation.
+ FormatNotSupported {
+ format: Format,
+ },
+
+ /// A specified image layout is not valid for this operation.
+ ImageLayoutInvalid {
+ image_layout: ImageLayout,
+ },
+
+ /// The end of the range of accessed mip levels of the subresource range of a region is greater
+ /// than the number of mip levels in the image.
+ MipLevelsOutOfRange {
+ region_index: usize,
+ mip_levels_range_end: u32,
+ image_mip_levels: u32,
+ },
+
+ /// An image does not have a required format feature.
+ MissingFormatFeature {
+ format_feature: &'static str,
+ },
+
+ /// A resource did not have a required usage enabled.
+ MissingUsage {
+ usage: &'static str,
+ },
+
+ /// The buffer offset of a region is not a multiple of the required buffer alignment.
+ OffsetNotAlignedForBuffer {
+ region_index: usize,
+ offset: DeviceSize,
+ required_alignment: DeviceSize,
+ },
+
+ /// The end of the range of accessed byte offsets of a region is greater than the size of the
+ /// buffer.
+ RegionOutOfBufferBounds {
+ region_index: usize,
+ offset_range_end: DeviceSize,
+ buffer_size: DeviceSize,
+ },
+
+ /// The buffer size of a region is not a multiple of the required buffer alignment.
+ SizeNotAlignedForBuffer {
+ region_index: usize,
+ size: DeviceSize,
+ required_alignment: DeviceSize,
+ },
+}
+
+impl Error for ClearError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::SyncCommandBufferBuilderError(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+impl Display for ClearError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::SyncCommandBufferBuilderError(_) => write!(f, "a SyncCommandBufferBuilderError"),
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ Self::ForbiddenInsideRenderPass => {
+ write!(f, "operation forbidden inside of a render pass")
+ }
+ Self::NotSupportedByQueueFamily => {
+ write!(f, "the queue family doesn't allow this operation")
+ }
+ Self::ArrayLayersOutOfRange {
+ region_index,
+ array_layers_range_end,
+ image_array_layers,
+ } => write!(
+ f,
+ "the end of the range of accessed array layers ({}) of the subresource range of \
+ region {} is greater than the number of array layers in the image ({})",
+ array_layers_range_end, region_index, image_array_layers,
+ ),
+ Self::AspectsNotAllowed {
+ region_index,
+ aspects,
+ allowed_aspects,
+ } => write!(
+ f,
+ "the aspects ({:?}) of the subresource range of region {} contain aspects that \
+ are not present in the image, or that are not allowed ({:?})",
+ aspects, region_index, allowed_aspects,
+ ),
+ Self::DataTooLarge { size, max } => write!(
+ f,
+ "the provided data has a size ({}) greater than the maximum allowed ({})",
+ size, max,
+ ),
+ Self::FormatNotSupported { format } => write!(
+ f,
+ "the format of the image ({:?}) is not supported for this operation",
+ format,
+ ),
+ Self::ImageLayoutInvalid { image_layout } => write!(
+ f,
+ "the specified image layout {:?} is not valid for this operation",
+ image_layout,
+ ),
+ Self::MipLevelsOutOfRange {
+ region_index,
+ mip_levels_range_end,
+ image_mip_levels,
+ } => write!(
+ f,
+ "the end of the range of accessed mip levels ({}) of the subresource range of \
+ region {} is not less than the number of mip levels in the image ({})",
+ mip_levels_range_end, region_index, image_mip_levels,
+ ),
+ Self::MissingFormatFeature { format_feature } => write!(
+ f,
+ "the image does not have the required format feature {}",
+ format_feature,
+ ),
+ Self::MissingUsage { usage } => write!(
+ f,
+ "the resource did not have the required usage {} enabled",
+ usage,
+ ),
+ Self::OffsetNotAlignedForBuffer {
+ region_index,
+ offset,
+ required_alignment,
+ } => write!(
+ f,
+ "the buffer offset ({}) of region {} is not a multiple of the required \
+ buffer alignment ({})",
+ offset, region_index, required_alignment,
+ ),
+ Self::RegionOutOfBufferBounds {
+ region_index,
+ offset_range_end,
+ buffer_size,
+ } => write!(
+ f,
+ "the end of the range of accessed byte offsets ({}) of region {} is greater \
+ than the size of the buffer ({})",
+ offset_range_end, region_index, buffer_size,
+ ),
+ Self::SizeNotAlignedForBuffer {
+ region_index,
+ size,
+ required_alignment,
+ } => write!(
+ f,
+ "the buffer size ({}) of region {} is not a multiple of the required buffer \
+ alignment ({})",
+ size, region_index, required_alignment,
+ ),
+ }
+ }
+}
+
+impl From<SyncCommandBufferBuilderError> for ClearError {
+ fn from(err: SyncCommandBufferBuilderError) -> Self {
+ Self::SyncCommandBufferBuilderError(err)
+ }
+}
+
+impl From<RequirementNotMet> for ClearError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
+ }
+ }
+}
diff --git a/src/command_buffer/commands/copy.rs b/src/command_buffer/commands/copy.rs
new file mode 100644
index 0000000..1911713
--- /dev/null
+++ b/src/command_buffer/commands/copy.rs
@@ -0,0 +1,5404 @@
+// Copyright (c) 2022 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use crate::{
+ buffer::{BufferUsage, Subbuffer},
+ command_buffer::{
+ allocator::CommandBufferAllocator,
+ synced::{Command, Resource, SyncCommandBufferBuilder, SyncCommandBufferBuilderError},
+ sys::UnsafeCommandBufferBuilder,
+ AutoCommandBufferBuilder, ResourceInCommand, ResourceUseRef,
+ },
+ device::{DeviceOwned, QueueFlags},
+ format::{Format, FormatFeatures, NumericType},
+ image::{
+ ImageAccess, ImageAspects, ImageDimensions, ImageLayout, ImageSubresourceLayers, ImageType,
+ ImageUsage, SampleCount, SampleCounts,
+ },
+ sampler::Filter,
+ sync::{AccessFlags, PipelineMemoryAccess, PipelineStages},
+ DeviceSize, RequirementNotMet, RequiresOneOf, Version, VulkanObject,
+};
+use smallvec::{smallvec, SmallVec};
+use std::{
+ cmp::{max, min},
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+ mem::size_of,
+ sync::Arc,
+};
+
+/// # Commands to transfer data between resources.
+impl<L, A> AutoCommandBufferBuilder<L, A>
+where
+ A: CommandBufferAllocator,
+{
+ /// Copies data from a buffer to another buffer.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `src_buffer` or `dst_buffer` were not created from the same device
+ /// as `self`.
+ pub fn copy_buffer(
+ &mut self,
+ copy_buffer_info: impl Into<CopyBufferInfo>,
+ ) -> Result<&mut Self, CopyError> {
+ let copy_buffer_info = copy_buffer_info.into();
+ self.validate_copy_buffer(&copy_buffer_info)?;
+
+ unsafe {
+ self.inner.copy_buffer(copy_buffer_info)?;
+ }
+
+ Ok(self)
+ }
+
+ fn validate_copy_buffer(&self, copy_buffer_info: &CopyBufferInfo) -> Result<(), CopyError> {
+ let device = self.device();
+
+ // VUID-vkCmdCopyBuffer2-renderpass
+ if self.render_pass_state.is_some() {
+ return Err(CopyError::ForbiddenInsideRenderPass);
+ }
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdCopyBuffer2-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::TRANSFER | QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(CopyError::NotSupportedByQueueFamily);
+ }
+
+ let &CopyBufferInfo {
+ ref src_buffer,
+ ref dst_buffer,
+ ref regions,
+ _ne: _,
+ } = copy_buffer_info;
+
+ // VUID-VkCopyBufferInfo2-commonparent
+ assert_eq!(device, src_buffer.device());
+ assert_eq!(device, dst_buffer.device());
+
+ // VUID-VkCopyBufferInfo2-srcBuffer-00118
+ if !src_buffer
+ .buffer()
+ .usage()
+ .intersects(BufferUsage::TRANSFER_SRC)
+ {
+ return Err(CopyError::MissingUsage {
+ resource: CopyErrorResource::Source,
+ usage: "transfer_src",
+ });
+ }
+
+ // VUID-VkCopyBufferInfo2-dstBuffer-00120
+ if !dst_buffer
+ .buffer()
+ .usage()
+ .intersects(BufferUsage::TRANSFER_DST)
+ {
+ return Err(CopyError::MissingUsage {
+ resource: CopyErrorResource::Destination,
+ usage: "transfer_dst",
+ });
+ }
+
+ let same_buffer = src_buffer.buffer() == dst_buffer.buffer();
+ let mut overlap_indices = None;
+
+ for (region_index, region) in regions.iter().enumerate() {
+ let &BufferCopy {
+ src_offset,
+ dst_offset,
+ size,
+ _ne: _,
+ } = region;
+
+ // VUID-VkBufferCopy2-size-01988
+ assert!(size != 0);
+
+ // VUID-VkCopyBufferInfo2-srcOffset-00113
+ // VUID-VkCopyBufferInfo2-size-00115
+ if src_offset + size > src_buffer.size() {
+ return Err(CopyError::RegionOutOfBufferBounds {
+ resource: CopyErrorResource::Source,
+ region_index,
+ offset_range_end: src_offset + size,
+ buffer_size: src_buffer.size(),
+ });
+ }
+
+ // VUID-VkCopyBufferInfo2-dstOffset-00114
+ // VUID-VkCopyBufferInfo2-size-00116
+ if dst_offset + size > dst_buffer.size() {
+ return Err(CopyError::RegionOutOfBufferBounds {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ offset_range_end: dst_offset + size,
+ buffer_size: dst_buffer.size(),
+ });
+ }
+
+ // VUID-VkCopyBufferInfo2-pRegions-00117
+ if same_buffer {
+ let src_region_index = region_index;
+ let src_range =
+ src_buffer.offset() + src_offset..src_buffer.offset() + src_offset + size;
+
+ for (dst_region_index, dst_region) in regions.iter().enumerate() {
+ let &BufferCopy { dst_offset, .. } = dst_region;
+
+ let dst_range =
+ dst_buffer.offset() + dst_offset..dst_buffer.offset() + dst_offset + size;
+
+ if src_range.start >= dst_range.end || dst_range.start >= src_range.end {
+ // The regions do not overlap
+ continue;
+ }
+
+ overlap_indices = Some((src_region_index, dst_region_index));
+ }
+ }
+ }
+
+ // VUID-VkCopyBufferInfo2-pRegions-00117
+ if let Some((src_region_index, dst_region_index)) = overlap_indices {
+ return Err(CopyError::OverlappingRegions {
+ src_region_index,
+ dst_region_index,
+ });
+ }
+
+ Ok(())
+ }
+
+ /// Copies data from an image to another image.
+ ///
+ /// There are several restrictions:
+ ///
+ /// - The number of samples in the source and destination images must be equal.
+ /// - The size of the uncompressed element format of the source image must be equal to the
+ /// compressed element format of the destination.
+ /// - If you copy between depth, stencil or depth-stencil images, the format of both images
+ /// must match exactly.
+ /// - For two-dimensional images, the Z coordinate must be 0 for the image offsets and 1 for
+ /// the extent. Same for the Y coordinate for one-dimensional images.
+ /// - For non-array images, the base array layer must be 0 and the number of layers must be 1.
+ ///
+ /// If `layer_count` is greater than 1, the copy will happen between each individual layer as
+ /// if they were separate images.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `src_image` or `dst_image` were not created from the same device
+ /// as `self`.
+ pub fn copy_image(&mut self, copy_image_info: CopyImageInfo) -> Result<&mut Self, CopyError> {
+ self.validate_copy_image(&copy_image_info)?;
+
+ unsafe {
+ self.inner.copy_image(copy_image_info)?;
+ }
+
+ Ok(self)
+ }
+
+ fn validate_copy_image(&self, copy_image_info: &CopyImageInfo) -> Result<(), CopyError> {
+ let device = self.device();
+
+ // VUID-vkCmdCopyImage2-renderpass
+ if self.render_pass_state.is_some() {
+ return Err(CopyError::ForbiddenInsideRenderPass);
+ }
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdCopyImage2-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::TRANSFER | QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(CopyError::NotSupportedByQueueFamily);
+ }
+
+ let &CopyImageInfo {
+ ref src_image,
+ src_image_layout,
+ ref dst_image,
+ dst_image_layout,
+ ref regions,
+ _ne: _,
+ } = copy_image_info;
+
+ // VUID-VkCopyImageInfo2-srcImageLayout-parameter
+ src_image_layout.validate_device(device)?;
+
+ // VUID-VkCopyImageInfo2-dstImageLayout-parameter
+ dst_image_layout.validate_device(device)?;
+
+ // VUID-VkCopyImageInfo2-commonparent
+ assert_eq!(device, src_image.device());
+ assert_eq!(device, dst_image.device());
+
+ let copy_2d_3d_supported =
+ device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_maintenance1;
+ let src_image_inner = src_image.inner();
+ let dst_image_inner = dst_image.inner();
+ let mut src_image_aspects = src_image.format().aspects();
+ let mut dst_image_aspects = dst_image.format().aspects();
+
+ if device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_maintenance1 {
+ // VUID-VkCopyImageInfo2-srcImage-01995
+ if !src_image
+ .format_features()
+ .intersects(FormatFeatures::TRANSFER_SRC)
+ {
+ return Err(CopyError::MissingFormatFeature {
+ resource: CopyErrorResource::Source,
+ format_feature: "transfer_src",
+ });
+ }
+
+ // VUID-VkCopyImageInfo2-dstImage-01996
+ if !dst_image
+ .format_features()
+ .intersects(FormatFeatures::TRANSFER_DST)
+ {
+ return Err(CopyError::MissingFormatFeature {
+ resource: CopyErrorResource::Destination,
+ format_feature: "transfer_dst",
+ });
+ }
+ }
+
+ // VUID-VkCopyImageInfo2-srcImage-00136
+ if src_image.samples() != dst_image.samples() {
+ return Err(CopyError::SampleCountMismatch {
+ src_sample_count: src_image.samples(),
+ dst_sample_count: dst_image.samples(),
+ });
+ }
+
+ if !(src_image_aspects.intersects(ImageAspects::COLOR)
+ || dst_image_aspects.intersects(ImageAspects::COLOR))
+ {
+ // VUID-VkCopyImageInfo2-srcImage-01548
+ if src_image.format() != dst_image.format() {
+ return Err(CopyError::FormatsMismatch {
+ src_format: src_image.format(),
+ dst_format: dst_image.format(),
+ });
+ }
+ }
+
+ // VUID-VkCopyImageInfo2-srcImageLayout-01917
+ if !matches!(
+ src_image_layout,
+ ImageLayout::TransferSrcOptimal | ImageLayout::General
+ ) {
+ return Err(CopyError::ImageLayoutInvalid {
+ resource: CopyErrorResource::Source,
+ image_layout: src_image_layout,
+ });
+ }
+
+ // VUID-VkCopyImageInfo2-dstImageLayout-01395
+ if !matches!(
+ dst_image_layout,
+ ImageLayout::TransferDstOptimal | ImageLayout::General
+ ) {
+ return Err(CopyError::ImageLayoutInvalid {
+ resource: CopyErrorResource::Destination,
+ image_layout: dst_image_layout,
+ });
+ }
+
+ let extent_alignment = match queue_family_properties.min_image_transfer_granularity {
+ [0, 0, 0] => None,
+ min_image_transfer_granularity => {
+ let granularity = move |block_extent: [u32; 3], is_multi_plane: bool| {
+ if is_multi_plane {
+ // Assume planes always have 1x1 blocks
+ min_image_transfer_granularity
+ } else {
+ // "The value returned in minImageTransferGranularity has a unit of
+ // compressed texel blocks for images having a block-compressed format, and
+ // a unit of texels otherwise."
+ [
+ min_image_transfer_granularity[0] * block_extent[0],
+ min_image_transfer_granularity[1] * block_extent[1],
+ min_image_transfer_granularity[2] * block_extent[2],
+ ]
+ }
+ };
+
+ Some((
+ granularity(
+ src_image.format().block_extent(),
+ src_image_aspects.intersects(ImageAspects::PLANE_0),
+ ),
+ granularity(
+ dst_image.format().block_extent(),
+ dst_image_aspects.intersects(ImageAspects::PLANE_0),
+ ),
+ ))
+ }
+ };
+
+ if src_image_aspects.intersects(ImageAspects::PLANE_0) {
+ // VUID-VkCopyImageInfo2-srcImage-01552
+ // VUID-VkCopyImageInfo2-srcImage-01553
+ src_image_aspects -= ImageAspects::COLOR;
+ }
+
+ if dst_image_aspects.intersects(ImageAspects::PLANE_0) {
+ // VUID-VkCopyImageInfo2-dstImage-01554
+ // VUID-VkCopyImageInfo2-dstImage-01555
+ dst_image_aspects -= ImageAspects::COLOR;
+ }
+
+ let mut src_image_aspects_used = ImageAspects::empty();
+ let mut dst_image_aspects_used = ImageAspects::empty();
+ let same_image = src_image_inner.image == dst_image_inner.image;
+ let mut overlap_subresource_indices = None;
+ let mut overlap_extent_indices = None;
+
+ for (region_index, region) in regions.iter().enumerate() {
+ let &ImageCopy {
+ ref src_subresource,
+ src_offset,
+ ref dst_subresource,
+ dst_offset,
+ extent,
+ _ne,
+ } = region;
+
+ let check_subresource = |resource: CopyErrorResource,
+ image: &dyn ImageAccess,
+ image_aspects: ImageAspects,
+ subresource: &ImageSubresourceLayers|
+ -> Result<_, CopyError> {
+ // VUID-VkCopyImageInfo2-srcSubresource-01696
+ // VUID-VkCopyImageInfo2-dstSubresource-01697
+ if subresource.mip_level >= image.mip_levels() {
+ return Err(CopyError::MipLevelsOutOfRange {
+ resource,
+ region_index,
+ mip_levels_range_end: subresource.mip_level + 1,
+ image_mip_levels: image.mip_levels(),
+ });
+ }
+
+ // VUID-VkImageSubresourceLayers-layerCount-01700
+ assert!(!subresource.array_layers.is_empty());
+
+ // VUID-VkCopyImageInfo2-srcSubresource-01698
+ // VUID-VkCopyImageInfo2-dstSubresource-01699
+ // VUID-VkCopyImageInfo2-srcImage-04443
+ // VUID-VkCopyImageInfo2-dstImage-04444
+ if subresource.array_layers.end > image.dimensions().array_layers() {
+ return Err(CopyError::ArrayLayersOutOfRange {
+ resource,
+ region_index,
+ array_layers_range_end: subresource.array_layers.end,
+ image_array_layers: image.dimensions().array_layers(),
+ });
+ }
+
+ // VUID-VkImageSubresourceLayers-aspectMask-parameter
+ subresource.aspects.validate_device(device)?;
+
+ // VUID-VkImageSubresourceLayers-aspectMask-requiredbitmask
+ assert!(!subresource.aspects.is_empty());
+
+ // VUID-VkCopyImageInfo2-aspectMask-00142
+ // VUID-VkCopyImageInfo2-aspectMask-00143
+ if !image_aspects.contains(subresource.aspects) {
+ return Err(CopyError::AspectsNotAllowed {
+ resource,
+ region_index,
+ aspects: subresource.aspects,
+ allowed_aspects: image_aspects,
+ });
+ }
+
+ let (subresource_format, subresource_extent) =
+ if image_aspects.intersects(ImageAspects::PLANE_0) {
+ // VUID-VkCopyImageInfo2-srcImage-01552
+ // VUID-VkCopyImageInfo2-srcImage-01553
+ // VUID-VkCopyImageInfo2-dstImage-01554
+ // VUID-VkCopyImageInfo2-dstImage-01555
+ if subresource.aspects.count() != 1 {
+ return Err(CopyError::MultipleAspectsNotAllowed {
+ resource,
+ region_index,
+ aspects: subresource.aspects,
+ });
+ }
+
+ if subresource.aspects.intersects(ImageAspects::PLANE_0) {
+ (
+ image.format().planes()[0],
+ image.dimensions().width_height_depth(),
+ )
+ } else if subresource.aspects.intersects(ImageAspects::PLANE_1) {
+ (
+ image.format().planes()[1],
+ image
+ .format()
+ .ycbcr_chroma_sampling()
+ .unwrap()
+ .subsampled_extent(image.dimensions().width_height_depth()),
+ )
+ } else {
+ (
+ image.format().planes()[2],
+ image
+ .format()
+ .ycbcr_chroma_sampling()
+ .unwrap()
+ .subsampled_extent(image.dimensions().width_height_depth()),
+ )
+ }
+ } else {
+ (
+ image.format(),
+ image
+ .dimensions()
+ .mip_level_dimensions(subresource.mip_level)
+ .unwrap()
+ .width_height_depth(),
+ )
+ };
+
+ Ok((subresource_format, subresource_extent))
+ };
+
+ src_image_aspects_used |= src_subresource.aspects;
+ dst_image_aspects_used |= dst_subresource.aspects;
+
+ let (src_subresource_format, src_subresource_extent) = check_subresource(
+ CopyErrorResource::Source,
+ src_image,
+ src_image_aspects,
+ src_subresource,
+ )?;
+ let (dst_subresource_format, dst_subresource_extent) = check_subresource(
+ CopyErrorResource::Destination,
+ dst_image,
+ dst_image_aspects,
+ dst_subresource,
+ )?;
+
+ if !(src_image_aspects.intersects(ImageAspects::PLANE_0)
+ || dst_image_aspects.intersects(ImageAspects::PLANE_0))
+ {
+ // VUID-VkCopyImageInfo2-srcImage-01551
+ if src_subresource.aspects != dst_subresource.aspects {
+ return Err(CopyError::AspectsMismatch {
+ region_index,
+ src_aspects: src_subresource.aspects,
+ dst_aspects: dst_subresource.aspects,
+ });
+ }
+ }
+
+ // VUID-VkCopyImageInfo2-srcImage-01548
+ // VUID-VkCopyImageInfo2-None-01549
+ // Color formats must be size-compatible.
+ if src_subresource_format.block_size() != dst_subresource_format.block_size() {
+ return Err(CopyError::FormatsNotCompatible {
+ src_format: src_subresource_format,
+ dst_format: dst_subresource_format,
+ });
+ }
+
+ // TODO:
+ // "When copying between compressed and uncompressed formats the extent members
+ // represent the texel dimensions of the source image and not the destination."
+ let mut src_extent = extent;
+ let mut dst_extent = extent;
+ let src_layer_count =
+ src_subresource.array_layers.end - src_subresource.array_layers.start;
+ let dst_layer_count =
+ dst_subresource.array_layers.end - dst_subresource.array_layers.start;
+
+ if copy_2d_3d_supported {
+ match (
+ src_image.dimensions().image_type(),
+ dst_image.dimensions().image_type(),
+ ) {
+ (ImageType::Dim2d, ImageType::Dim3d) => {
+ src_extent[2] = 1;
+
+ // VUID-vkCmdCopyImage-srcImage-01791
+ if dst_extent[2] != src_layer_count {
+ return Err(CopyError::ArrayLayerCountMismatch {
+ region_index,
+ src_layer_count,
+ dst_layer_count: dst_extent[2],
+ });
+ }
+ }
+ (ImageType::Dim3d, ImageType::Dim2d) => {
+ dst_extent[2] = 1;
+
+ // VUID-vkCmdCopyImage-dstImage-01792
+ if src_extent[2] != dst_layer_count {
+ return Err(CopyError::ArrayLayerCountMismatch {
+ region_index,
+ src_layer_count: src_extent[2],
+ dst_layer_count,
+ });
+ }
+ }
+ _ => {
+ // VUID-VkImageCopy2-extent-00140
+ if src_layer_count != dst_layer_count {
+ return Err(CopyError::ArrayLayerCountMismatch {
+ region_index,
+ src_layer_count,
+ dst_layer_count,
+ });
+ }
+ }
+ }
+ } else {
+ // VUID-VkImageCopy2-extent-00140
+ if src_layer_count != dst_layer_count {
+ return Err(CopyError::ArrayLayerCountMismatch {
+ region_index,
+ src_layer_count,
+ dst_layer_count,
+ });
+ }
+ };
+
+ if let Some((src_extent_alignment, dst_extent_alignment)) = extent_alignment {
+ let check_offset_extent = |resource: CopyErrorResource,
+ extent_alignment: [u32; 3],
+ subresource_extent: [u32; 3],
+ offset: [u32; 3],
+ extent: [u32; 3]|
+ -> Result<_, CopyError> {
+ for i in 0..3 {
+ // VUID-VkImageCopy2-extent-06668
+ // VUID-VkImageCopy2-extent-06669
+ // VUID-VkImageCopy2-extent-06670
+ assert!(extent[i] != 0);
+
+ // VUID-VkCopyImageInfo2-srcOffset-00144
+ // VUID-VkCopyImageInfo2-srcOffset-00145
+ // VUID-VkCopyImageInfo2-srcOffset-00147
+ // VUID-VkCopyImageInfo2-dstOffset-00150
+ // VUID-VkCopyImageInfo2-dstOffset-00151
+ // VUID-VkCopyImageInfo2-dstOffset-00153
+ if offset[i] + extent[i] > subresource_extent[i] {
+ return Err(CopyError::RegionOutOfImageBounds {
+ resource,
+ region_index,
+ offset_range_end: [
+ offset[0] + extent[0],
+ offset[1] + extent[1],
+ offset[2] + extent[2],
+ ],
+ subresource_extent,
+ });
+ }
+
+ // VUID-VkCopyImageInfo2-srcImage-01727
+ // VUID-VkCopyImageInfo2-dstImage-01731
+ // VUID-VkCopyImageInfo2-srcOffset-01783
+ // VUID-VkCopyImageInfo2-dstOffset-01784
+ if offset[i] % extent_alignment[i] != 0 {
+ return Err(CopyError::OffsetNotAlignedForImage {
+ resource,
+ region_index,
+ offset,
+ required_alignment: extent_alignment,
+ });
+ }
+
+ // VUID-VkCopyImageInfo2-srcImage-01728
+ // VUID-VkCopyImageInfo2-srcImage-01729
+ // VUID-VkCopyImageInfo2-srcImage-01730
+ // VUID-VkCopyImageInfo2-dstImage-01732
+ // VUID-VkCopyImageInfo2-dstImage-01733
+ // VUID-VkCopyImageInfo2-dstImage-01734
+ if offset[i] + extent[i] != subresource_extent[i]
+ && extent[i] % extent_alignment[i] != 0
+ {
+ return Err(CopyError::ExtentNotAlignedForImage {
+ resource,
+ region_index,
+ extent,
+ required_alignment: extent_alignment,
+ });
+ }
+ }
+
+ Ok(())
+ };
+
+ check_offset_extent(
+ CopyErrorResource::Source,
+ src_extent_alignment,
+ src_subresource_extent,
+ src_offset,
+ src_extent,
+ )?;
+ check_offset_extent(
+ CopyErrorResource::Destination,
+ dst_extent_alignment,
+ dst_subresource_extent,
+ dst_offset,
+ dst_extent,
+ )?;
+
+ // VUID-VkCopyImageInfo2-pRegions-00124
+ if same_image {
+ let src_region_index = region_index;
+ let src_subresource_axes = [
+ src_image_inner.first_mipmap_level + src_subresource.mip_level
+ ..src_image_inner.first_mipmap_level + src_subresource.mip_level + 1,
+ src_image_inner.first_layer + src_subresource.array_layers.start
+ ..src_image_inner.first_layer + src_subresource.array_layers.end,
+ ];
+ let src_extent_axes = [
+ src_offset[0]..src_offset[0] + extent[0],
+ src_offset[1]..src_offset[1] + extent[1],
+ src_offset[2]..src_offset[2] + extent[2],
+ ];
+
+ for (dst_region_index, dst_region) in regions.iter().enumerate() {
+ let &ImageCopy {
+ ref dst_subresource,
+ dst_offset,
+ ..
+ } = dst_region;
+
+ // For a single-plane image, the aspects must always be identical anyway
+ if src_image_aspects.intersects(ImageAspects::PLANE_0)
+ && src_subresource.aspects != dst_subresource.aspects
+ {
+ continue;
+ }
+
+ let dst_subresource_axes = [
+ dst_image_inner.first_mipmap_level + dst_subresource.mip_level
+ ..dst_image_inner.first_mipmap_level
+ + dst_subresource.mip_level
+ + 1,
+ dst_image_inner.first_layer + src_subresource.array_layers.start
+ ..dst_image_inner.first_layer + src_subresource.array_layers.end,
+ ];
+
+ if src_subresource_axes.iter().zip(dst_subresource_axes).any(
+ |(src_range, dst_range)| {
+ src_range.start >= dst_range.end || dst_range.start >= src_range.end
+ },
+ ) {
+ continue;
+ }
+
+ // If the subresource axes all overlap, then the source and destination must
+ // have the same layout.
+ overlap_subresource_indices = Some((src_region_index, dst_region_index));
+
+ let dst_extent_axes = [
+ dst_offset[0]..dst_offset[0] + extent[0],
+ dst_offset[1]..dst_offset[1] + extent[1],
+ dst_offset[2]..dst_offset[2] + extent[2],
+ ];
+
+ // There is only overlap if all of the axes overlap.
+ if src_extent_axes.iter().zip(dst_extent_axes).any(
+ |(src_range, dst_range)| {
+ src_range.start >= dst_range.end || dst_range.start >= src_range.end
+ },
+ ) {
+ continue;
+ }
+
+ overlap_extent_indices = Some((src_region_index, dst_region_index));
+ }
+ }
+ } else {
+ // If granularity is `None`, then we can only copy whole subresources.
+ let check_offset_extent = |resource: CopyErrorResource,
+ subresource_extent: [u32; 3],
+ offset: [u32; 3],
+ extent: [u32; 3]|
+ -> Result<_, CopyError> {
+ // VUID-VkCopyImageInfo2-srcImage-01727
+ // VUID-VkCopyImageInfo2-dstImage-01731
+ // VUID-vkCmdCopyImage-srcOffset-01783
+ // VUID-vkCmdCopyImage-dstOffset-01784
+ if offset != [0, 0, 0] {
+ return Err(CopyError::OffsetNotAlignedForImage {
+ resource,
+ region_index,
+ offset,
+ required_alignment: subresource_extent,
+ });
+ }
+
+ // VUID-VkCopyImageInfo2-srcImage-01728
+ // VUID-VkCopyImageInfo2-srcImage-01729
+ // VUID-VkCopyImageInfo2-srcImage-01730
+ // VUID-VkCopyImageInfo2-dstImage-01732
+ // VUID-VkCopyImageInfo2-dstImage-01733
+ // VUID-VkCopyImageInfo2-dstImage-01734
+ if extent != subresource_extent {
+ return Err(CopyError::ExtentNotAlignedForImage {
+ resource,
+ region_index,
+ extent,
+ required_alignment: subresource_extent,
+ });
+ }
+
+ Ok(())
+ };
+
+ check_offset_extent(
+ CopyErrorResource::Source,
+ src_subresource_extent,
+ src_offset,
+ src_extent,
+ )?;
+ check_offset_extent(
+ CopyErrorResource::Destination,
+ dst_subresource_extent,
+ dst_offset,
+ dst_extent,
+ )?;
+
+ // VUID-VkCopyImageInfo2-pRegions-00124
+ // A simpler version that assumes the region covers the full extent.
+ if same_image {
+ let src_region_index = region_index;
+ let src_axes = [
+ src_image_inner.first_mipmap_level + src_subresource.mip_level
+ ..src_image_inner.first_mipmap_level + src_subresource.mip_level + 1,
+ src_image_inner.first_layer + src_subresource.array_layers.start
+ ..src_image_inner.first_layer + src_subresource.array_layers.end,
+ ];
+
+ for (dst_region_index, dst_region) in regions.iter().enumerate() {
+ let &ImageCopy {
+ ref dst_subresource,
+ dst_offset: _,
+ ..
+ } = dst_region;
+
+ if src_image_aspects.intersects(ImageAspects::PLANE_0)
+ && src_subresource.aspects != dst_subresource.aspects
+ {
+ continue;
+ }
+
+ let dst_axes = [
+ dst_image_inner.first_mipmap_level + dst_subresource.mip_level
+ ..dst_image_inner.first_mipmap_level
+ + dst_subresource.mip_level
+ + 1,
+ dst_image_inner.first_layer + src_subresource.array_layers.start
+ ..dst_image_inner.first_layer + src_subresource.array_layers.end,
+ ];
+
+ // There is only overlap if all of the axes overlap.
+ if src_axes.iter().zip(dst_axes).any(|(src_range, dst_range)| {
+ src_range.start >= dst_range.end || dst_range.start >= src_range.end
+ }) {
+ continue;
+ }
+
+ overlap_extent_indices = Some((src_region_index, dst_region_index));
+ }
+ }
+ }
+ }
+
+ // VUID-VkCopyImageInfo2-aspect-06662
+ if !(src_image_aspects_used - ImageAspects::STENCIL).is_empty()
+ && !src_image.usage().intersects(ImageUsage::TRANSFER_SRC)
+ {
+ return Err(CopyError::MissingUsage {
+ resource: CopyErrorResource::Source,
+ usage: "transfer_src",
+ });
+ }
+
+ // VUID-VkCopyImageInfo2-aspect-06663
+ if !(dst_image_aspects_used - ImageAspects::STENCIL).is_empty()
+ && !dst_image.usage().intersects(ImageUsage::TRANSFER_DST)
+ {
+ return Err(CopyError::MissingUsage {
+ resource: CopyErrorResource::Destination,
+ usage: "transfer_dst",
+ });
+ }
+
+ // VUID-VkCopyImageInfo2-aspect-06664
+ if src_image_aspects_used.intersects(ImageAspects::STENCIL)
+ && !src_image
+ .stencil_usage()
+ .intersects(ImageUsage::TRANSFER_SRC)
+ {
+ return Err(CopyError::MissingUsage {
+ resource: CopyErrorResource::Source,
+ usage: "transfer_src",
+ });
+ }
+
+ // VUID-VkCopyImageInfo2-aspect-06665
+ if dst_image_aspects_used.intersects(ImageAspects::STENCIL)
+ && !dst_image
+ .stencil_usage()
+ .intersects(ImageUsage::TRANSFER_DST)
+ {
+ return Err(CopyError::MissingUsage {
+ resource: CopyErrorResource::Destination,
+ usage: "transfer_dst",
+ });
+ }
+
+ // VUID-VkCopyImageInfo2-pRegions-00124
+ if let Some((src_region_index, dst_region_index)) = overlap_extent_indices {
+ return Err(CopyError::OverlappingRegions {
+ src_region_index,
+ dst_region_index,
+ });
+ }
+
+ // VUID-VkCopyImageInfo2-srcImageLayout-00128
+ // VUID-VkCopyImageInfo2-dstImageLayout-00133
+ if let Some((src_region_index, dst_region_index)) = overlap_subresource_indices {
+ if src_image_layout != dst_image_layout {
+ return Err(CopyError::OverlappingSubresourcesLayoutMismatch {
+ src_region_index,
+ dst_region_index,
+ src_image_layout,
+ dst_image_layout,
+ });
+ }
+ }
+
+ Ok(())
+ }
+
+ /// Copies from a buffer to an image.
+ pub fn copy_buffer_to_image(
+ &mut self,
+ copy_buffer_to_image_info: CopyBufferToImageInfo,
+ ) -> Result<&mut Self, CopyError> {
+ self.validate_copy_buffer_to_image(&copy_buffer_to_image_info)?;
+
+ unsafe {
+ self.inner.copy_buffer_to_image(copy_buffer_to_image_info)?;
+ }
+
+ Ok(self)
+ }
+
+ fn validate_copy_buffer_to_image(
+ &self,
+ copy_buffer_to_image_info: &CopyBufferToImageInfo,
+ ) -> Result<(), CopyError> {
+ let device = self.device();
+
+ // VUID-vkCmdCopyBufferToImage2-renderpass
+ if self.render_pass_state.is_some() {
+ return Err(CopyError::ForbiddenInsideRenderPass);
+ }
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdCopyBufferToImage2-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::TRANSFER | QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(CopyError::NotSupportedByQueueFamily);
+ }
+
+ let &CopyBufferToImageInfo {
+ ref src_buffer,
+ ref dst_image,
+ dst_image_layout,
+ ref regions,
+ _ne: _,
+ } = copy_buffer_to_image_info;
+
+ // VUID-VkCopyBufferToImageInfo2-dstImageLayout-parameter
+ dst_image_layout.validate_device(device)?;
+
+ // VUID-VkCopyBufferToImageInfo2-commonparent
+ assert_eq!(device, src_buffer.device());
+ assert_eq!(device, dst_image.device());
+
+ let mut image_aspects = dst_image.format().aspects();
+
+ // VUID-VkCopyBufferToImageInfo2-commandBuffer-04477
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ && !image_aspects.intersects(ImageAspects::COLOR)
+ {
+ return Err(CopyError::DepthStencilNotSupportedByQueueFamily);
+ }
+
+ // VUID-VkCopyBufferToImageInfo2-srcBuffer-00174
+ if !src_buffer
+ .buffer()
+ .usage()
+ .intersects(BufferUsage::TRANSFER_SRC)
+ {
+ return Err(CopyError::MissingUsage {
+ resource: CopyErrorResource::Source,
+ usage: "transfer_src",
+ });
+ }
+
+ // VUID-VkCopyBufferToImageInfo2-dstImage-00177
+ if !dst_image.usage().intersects(ImageUsage::TRANSFER_DST) {
+ return Err(CopyError::MissingUsage {
+ resource: CopyErrorResource::Destination,
+ usage: "transfer_dst",
+ });
+ }
+
+ if device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_maintenance1 {
+ // VUID-VkCopyBufferToImageInfo2-dstImage-01997
+ if !dst_image
+ .format_features()
+ .intersects(FormatFeatures::TRANSFER_DST)
+ {
+ return Err(CopyError::MissingFormatFeature {
+ resource: CopyErrorResource::Destination,
+ format_feature: "transfer_dst",
+ });
+ }
+ }
+
+ // VUID-VkCopyBufferToImageInfo2-dstImage-00179
+ if dst_image.samples() != SampleCount::Sample1 {
+ return Err(CopyError::SampleCountInvalid {
+ resource: CopyErrorResource::Destination,
+ sample_count: dst_image.samples(),
+ allowed_sample_counts: SampleCounts::SAMPLE_1,
+ });
+ }
+
+ // VUID-VkCopyBufferToImageInfo2-dstImageLayout-01396
+ if !matches!(
+ dst_image_layout,
+ ImageLayout::TransferDstOptimal | ImageLayout::General
+ ) {
+ return Err(CopyError::ImageLayoutInvalid {
+ resource: CopyErrorResource::Destination,
+ image_layout: dst_image_layout,
+ });
+ }
+
+ let extent_alignment = match queue_family_properties.min_image_transfer_granularity {
+ [0, 0, 0] => None,
+ min_image_transfer_granularity => {
+ let granularity = move |block_extent: [u32; 3], is_multi_plane: bool| {
+ if is_multi_plane {
+ // Assume planes always have 1x1 blocks
+ min_image_transfer_granularity
+ } else {
+ // "The value returned in minImageTransferGranularity has a unit of
+ // compressed texel blocks for images having a block-compressed format, and
+ // a unit of texels otherwise."
+ [
+ min_image_transfer_granularity[0] * block_extent[0],
+ min_image_transfer_granularity[1] * block_extent[1],
+ min_image_transfer_granularity[2] * block_extent[2],
+ ]
+ }
+ };
+
+ Some(granularity(
+ dst_image.format().block_extent(),
+ image_aspects.intersects(ImageAspects::PLANE_0),
+ ))
+ }
+ };
+
+ if image_aspects.intersects(ImageAspects::PLANE_0) {
+ // VUID-VkCopyBufferToImageInfo2-aspectMask-01560
+ image_aspects -= ImageAspects::COLOR;
+ }
+
+ for (region_index, region) in regions.iter().enumerate() {
+ let &BufferImageCopy {
+ buffer_offset,
+ buffer_row_length,
+ buffer_image_height,
+ ref image_subresource,
+ image_offset,
+ image_extent,
+ _ne: _,
+ } = region;
+
+ // VUID-VkCopyBufferToImageInfo2-imageSubresource-01701
+ if image_subresource.mip_level >= dst_image.mip_levels() {
+ return Err(CopyError::MipLevelsOutOfRange {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ mip_levels_range_end: image_subresource.mip_level + 1,
+ image_mip_levels: dst_image.mip_levels(),
+ });
+ }
+
+ // VUID-VkImageSubresourceLayers-layerCount-01700
+ // VUID-VkCopyBufferToImageInfo2-baseArrayLayer-00213
+ assert!(!image_subresource.array_layers.is_empty());
+
+ // VUID-VkCopyBufferToImageInfo2-imageSubresource-01702
+ // VUID-VkCopyBufferToImageInfo2-baseArrayLayer-00213
+ if image_subresource.array_layers.end > dst_image.dimensions().array_layers() {
+ return Err(CopyError::ArrayLayersOutOfRange {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ array_layers_range_end: image_subresource.array_layers.end,
+ image_array_layers: dst_image.dimensions().array_layers(),
+ });
+ }
+
+ // VUID-VkImageSubresourceLayers-aspectMask-requiredbitmask
+ assert!(!image_subresource.aspects.is_empty());
+
+ // VUID-VkCopyBufferToImageInfo2-aspectMask-00211
+ if !image_aspects.contains(image_subresource.aspects) {
+ return Err(CopyError::AspectsNotAllowed {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ aspects: image_subresource.aspects,
+ allowed_aspects: image_aspects,
+ });
+ }
+
+ // VUID-VkBufferImageCopy2-aspectMask-00212
+ // VUID-VkCopyBufferToImageInfo2-aspectMask-01560
+ if image_subresource.aspects.count() != 1 {
+ return Err(CopyError::MultipleAspectsNotAllowed {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ aspects: image_subresource.aspects,
+ });
+ }
+
+ let (image_subresource_format, image_subresource_extent) =
+ if image_aspects.intersects(ImageAspects::PLANE_0) {
+ if image_subresource.aspects.intersects(ImageAspects::PLANE_0) {
+ (
+ dst_image.format().planes()[0],
+ dst_image.dimensions().width_height_depth(),
+ )
+ } else if image_subresource.aspects.intersects(ImageAspects::PLANE_1) {
+ (
+ dst_image.format().planes()[1],
+ dst_image
+ .format()
+ .ycbcr_chroma_sampling()
+ .unwrap()
+ .subsampled_extent(dst_image.dimensions().width_height_depth()),
+ )
+ } else {
+ (
+ dst_image.format().planes()[2],
+ dst_image
+ .format()
+ .ycbcr_chroma_sampling()
+ .unwrap()
+ .subsampled_extent(dst_image.dimensions().width_height_depth()),
+ )
+ }
+ } else {
+ (
+ dst_image.format(),
+ dst_image
+ .dimensions()
+ .mip_level_dimensions(image_subresource.mip_level)
+ .unwrap()
+ .width_height_depth(),
+ )
+ };
+
+ if let Some(extent_alignment) = extent_alignment {
+ for i in 0..3 {
+ // VUID-VkBufferImageCopy2-imageExtent-06659
+ // VUID-VkBufferImageCopy2-imageExtent-06660
+ // VUID-VkBufferImageCopy2-imageExtent-06661
+ assert!(image_extent[i] != 0);
+
+ // VUID-VkCopyBufferToImageInfo2-pRegions-06223
+ // VUID-VkCopyBufferToImageInfo2-pRegions-06224
+ // VUID-VkCopyBufferToImageInfo2-imageOffset-00200
+ if image_offset[i] + image_extent[i] > image_subresource_extent[i] {
+ return Err(CopyError::RegionOutOfImageBounds {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ offset_range_end: [
+ image_offset[0] + image_extent[0],
+ image_offset[1] + image_extent[1],
+ image_offset[2] + image_extent[2],
+ ],
+ subresource_extent: image_subresource_extent,
+ });
+ }
+
+ // VUID-VkCopyBufferToImageInfo2-imageOffset-01793
+ // VUID-VkCopyBufferToImageInfo2-imageOffset-00205
+ if image_offset[i] % extent_alignment[i] != 0 {
+ return Err(CopyError::OffsetNotAlignedForImage {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ offset: image_offset,
+ required_alignment: extent_alignment,
+ });
+ }
+
+ // VUID-VkCopyBufferToImageInfo2-imageOffset-01793
+ // VUID-VkCopyBufferToImageInfo2-imageExtent-00207
+ // VUID-VkCopyBufferToImageInfo2-imageExtent-00208
+ // VUID-VkCopyBufferToImageInfo2-imageExtent-00209
+ if image_offset[i] + image_extent[i] != image_subresource_extent[i]
+ && image_extent[i] % extent_alignment[i] != 0
+ {
+ return Err(CopyError::ExtentNotAlignedForImage {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ extent: image_extent,
+ required_alignment: extent_alignment,
+ });
+ }
+ }
+ } else {
+ // If granularity is `None`, then we can only copy whole subresources.
+
+ // VUID-VkCopyBufferToImageInfo2-imageOffset-01793
+ if image_offset != [0, 0, 0] {
+ return Err(CopyError::OffsetNotAlignedForImage {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ offset: image_offset,
+ required_alignment: image_subresource_extent,
+ });
+ }
+
+ // VUID-VkCopyBufferToImageInfo2-imageOffset-01793
+ if image_extent != image_subresource_extent {
+ return Err(CopyError::ExtentNotAlignedForImage {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ extent: image_extent,
+ required_alignment: image_subresource_extent,
+ });
+ }
+ }
+
+ // VUID-VkBufferImageCopy2-bufferRowLength-00195
+ if !(buffer_row_length == 0 || buffer_row_length >= image_extent[0]) {
+ return Err(CopyError::BufferRowLengthTooSmall {
+ resource: CopyErrorResource::Source,
+ region_index,
+ row_length: buffer_row_length,
+ min: image_extent[0],
+ });
+ }
+
+ // VUID-VkBufferImageCopy2-bufferImageHeight-00196
+ if !(buffer_image_height == 0 || buffer_image_height >= image_extent[1]) {
+ return Err(CopyError::BufferImageHeightTooSmall {
+ resource: CopyErrorResource::Source,
+ region_index,
+ image_height: buffer_image_height,
+ min: image_extent[1],
+ });
+ }
+
+ let image_subresource_block_extent = image_subresource_format.block_extent();
+
+ // VUID-VkCopyBufferToImageInfo2-bufferRowLength-00203
+ if buffer_row_length % image_subresource_block_extent[0] != 0 {
+ return Err(CopyError::BufferRowLengthNotAligned {
+ resource: CopyErrorResource::Source,
+ region_index,
+ row_length: buffer_row_length,
+ required_alignment: image_subresource_block_extent[0],
+ });
+ }
+
+ // VUID-VkCopyBufferToImageInfo2-bufferImageHeight-00204
+ if buffer_image_height % image_subresource_block_extent[1] != 0 {
+ return Err(CopyError::BufferImageHeightNotAligned {
+ resource: CopyErrorResource::Source,
+ region_index,
+ image_height: buffer_image_height,
+ required_alignment: image_subresource_block_extent[1],
+ });
+ }
+
+ // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkBufferImageCopy.html#_description
+ let image_subresource_block_size =
+ if image_subresource.aspects.intersects(ImageAspects::STENCIL) {
+ 1
+ } else if image_subresource.aspects.intersects(ImageAspects::DEPTH) {
+ match image_subresource_format {
+ Format::D16_UNORM | Format::D16_UNORM_S8_UINT => 2,
+ Format::D32_SFLOAT
+ | Format::D32_SFLOAT_S8_UINT
+ | Format::X8_D24_UNORM_PACK32
+ | Format::D24_UNORM_S8_UINT => 4,
+ _ => unreachable!(),
+ }
+ } else {
+ image_subresource_format.block_size().unwrap()
+ };
+
+ // VUID-VkCopyBufferToImageInfo2-pRegions-04725
+ // VUID-VkCopyBufferToImageInfo2-pRegions-04726
+ if (buffer_row_length / image_subresource_block_extent[0]) as DeviceSize
+ * image_subresource_block_size
+ > 0x7FFFFFFF
+ {
+ return Err(CopyError::BufferRowLengthTooLarge {
+ resource: CopyErrorResource::Source,
+ region_index,
+ buffer_row_length,
+ });
+ }
+
+ let buffer_offset_alignment =
+ if image_aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL) {
+ 4
+ } else {
+ let mut buffer_offset_alignment = image_subresource_block_size;
+
+ // VUID-VkCopyBufferToImageInfo2-commandBuffer-04052
+ // Make the alignment a multiple of 4.
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ if buffer_offset_alignment % 2 != 0 {
+ buffer_offset_alignment *= 2;
+ }
+
+ if buffer_offset_alignment % 4 != 0 {
+ buffer_offset_alignment *= 2;
+ }
+ }
+
+ buffer_offset_alignment
+ };
+
+ // VUID-VkCopyBufferToImageInfo2-bufferOffset-00206
+ // VUID-VkCopyBufferToImageInfo2-bufferOffset-01558
+ // VUID-VkCopyBufferToImageInfo2-bufferOffset-01559
+ // VUID-VkCopyBufferToImageInfo2-srcImage-04053
+ if (src_buffer.offset() + buffer_offset) % buffer_offset_alignment != 0 {
+ return Err(CopyError::OffsetNotAlignedForBuffer {
+ resource: CopyErrorResource::Source,
+ region_index,
+ offset: src_buffer.offset() + buffer_offset,
+ required_alignment: buffer_offset_alignment,
+ });
+ }
+
+ let buffer_copy_size = region.buffer_copy_size(image_subresource_format);
+
+ // VUID-VkCopyBufferToImageInfo2-pRegions-00171
+ if buffer_offset + buffer_copy_size > src_buffer.size() {
+ return Err(CopyError::RegionOutOfBufferBounds {
+ resource: CopyErrorResource::Source,
+ region_index,
+ offset_range_end: buffer_offset + buffer_copy_size,
+ buffer_size: src_buffer.size(),
+ });
+ }
+ }
+
+ // VUID-VkCopyBufferToImageInfo2-pRegions-00173
+ // Can't occur as long as memory aliasing isn't allowed.
+
+ Ok(())
+ }
+
+ /// Copies from an image to a buffer.
+ pub fn copy_image_to_buffer(
+ &mut self,
+ copy_image_to_buffer_info: CopyImageToBufferInfo,
+ ) -> Result<&mut Self, CopyError> {
+ self.validate_copy_image_to_buffer(&copy_image_to_buffer_info)?;
+
+ unsafe {
+ self.inner.copy_image_to_buffer(copy_image_to_buffer_info)?;
+ }
+
+ Ok(self)
+ }
+
+ fn validate_copy_image_to_buffer(
+ &self,
+ copy_image_to_buffer_info: &CopyImageToBufferInfo,
+ ) -> Result<(), CopyError> {
+ let device = self.device();
+
+ // VUID-vkCmdCopyImageToBuffer2-renderpass
+ if self.render_pass_state.is_some() {
+ return Err(CopyError::ForbiddenInsideRenderPass);
+ }
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdCopyImageToBuffer2-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::TRANSFER | QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(CopyError::NotSupportedByQueueFamily);
+ }
+
+ let &CopyImageToBufferInfo {
+ ref src_image,
+ src_image_layout,
+ ref dst_buffer,
+ ref regions,
+ _ne: _,
+ } = copy_image_to_buffer_info;
+
+ // VUID-VkCopyImageToBufferInfo2-srcImageLayout-parameter
+ src_image_layout.validate_device(device)?;
+
+ // VUID-VkCopyImageToBufferInfo2-commonparent
+ assert_eq!(device, dst_buffer.device());
+ assert_eq!(device, src_image.device());
+
+ let mut image_aspects = src_image.format().aspects();
+
+ // VUID-VkCopyImageToBufferInfo2-srcImage-00186
+ if !src_image.usage().intersects(ImageUsage::TRANSFER_SRC) {
+ return Err(CopyError::MissingUsage {
+ resource: CopyErrorResource::Source,
+ usage: "transfer_src",
+ });
+ }
+
+ // VUID-VkCopyImageToBufferInfo2-dstBuffer-00191
+ if !dst_buffer
+ .buffer()
+ .usage()
+ .intersects(BufferUsage::TRANSFER_DST)
+ {
+ return Err(CopyError::MissingUsage {
+ resource: CopyErrorResource::Destination,
+ usage: "transfer_dst",
+ });
+ }
+
+ if device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_maintenance1 {
+ // VUID-VkCopyImageToBufferInfo2-srcImage-01998
+ if !src_image
+ .format_features()
+ .intersects(FormatFeatures::TRANSFER_SRC)
+ {
+ return Err(CopyError::MissingFormatFeature {
+ resource: CopyErrorResource::Source,
+ format_feature: "transfer_src",
+ });
+ }
+ }
+
+ // VUID-VkCopyImageToBufferInfo2-srcImage-00188
+ if src_image.samples() != SampleCount::Sample1 {
+ return Err(CopyError::SampleCountInvalid {
+ resource: CopyErrorResource::Source,
+ sample_count: src_image.samples(),
+ allowed_sample_counts: SampleCounts::SAMPLE_1,
+ });
+ }
+
+ // VUID-VkCopyImageToBufferInfo2-srcImageLayout-01397
+ if !matches!(
+ src_image_layout,
+ ImageLayout::TransferSrcOptimal | ImageLayout::General
+ ) {
+ return Err(CopyError::ImageLayoutInvalid {
+ resource: CopyErrorResource::Source,
+ image_layout: src_image_layout,
+ });
+ }
+
+ let extent_alignment = match queue_family_properties.min_image_transfer_granularity {
+ [0, 0, 0] => None,
+ min_image_transfer_granularity => {
+ let granularity = move |block_extent: [u32; 3], is_multi_plane: bool| {
+ if is_multi_plane {
+ // Assume planes always have 1x1 blocks
+ min_image_transfer_granularity
+ } else {
+ // "The value returned in minImageTransferGranularity has a unit of
+ // compressed texel blocks for images having a block-compressed format, and
+ // a unit of texels otherwise."
+ [
+ min_image_transfer_granularity[0] * block_extent[0],
+ min_image_transfer_granularity[1] * block_extent[1],
+ min_image_transfer_granularity[2] * block_extent[2],
+ ]
+ }
+ };
+
+ Some(granularity(
+ src_image.format().block_extent(),
+ image_aspects.intersects(ImageAspects::PLANE_0),
+ ))
+ }
+ };
+
+ if image_aspects.intersects(ImageAspects::PLANE_0) {
+ // VUID-VkCopyImageToBufferInfo2-aspectMask-01560
+ image_aspects -= ImageAspects::COLOR;
+ }
+
+ for (region_index, region) in regions.iter().enumerate() {
+ let &BufferImageCopy {
+ buffer_offset,
+ buffer_row_length,
+ buffer_image_height,
+ ref image_subresource,
+ image_offset,
+ image_extent,
+ _ne: _,
+ } = region;
+
+ // VUID-VkCopyImageToBufferInfo2-imageSubresource-01703
+ if image_subresource.mip_level >= src_image.mip_levels() {
+ return Err(CopyError::MipLevelsOutOfRange {
+ resource: CopyErrorResource::Source,
+ region_index,
+ mip_levels_range_end: image_subresource.mip_level + 1,
+ image_mip_levels: src_image.mip_levels(),
+ });
+ }
+
+ // VUID-VkImageSubresourceLayers-layerCount-01700
+ assert!(!image_subresource.array_layers.is_empty());
+
+ // VUID-VkCopyImageToBufferInfo2-imageSubresource-01704
+ // VUID-VkCopyImageToBufferInfo2-baseArrayLayer-00213
+ if image_subresource.array_layers.end > src_image.dimensions().array_layers() {
+ return Err(CopyError::ArrayLayersOutOfRange {
+ resource: CopyErrorResource::Source,
+ region_index,
+ array_layers_range_end: image_subresource.array_layers.end,
+ image_array_layers: src_image.dimensions().array_layers(),
+ });
+ }
+
+ // VUID-VkImageSubresourceLayers-aspectMask-requiredbitmask
+ assert!(!image_subresource.aspects.is_empty());
+
+ // VUID-VkCopyImageToBufferInfo2-aspectMask-00211
+ if !image_aspects.contains(image_subresource.aspects) {
+ return Err(CopyError::AspectsNotAllowed {
+ resource: CopyErrorResource::Source,
+ region_index,
+ aspects: image_subresource.aspects,
+ allowed_aspects: image_aspects,
+ });
+ }
+
+ // VUID-VkBufferImageCopy2-aspectMask-00212
+ if image_subresource.aspects.count() != 1 {
+ return Err(CopyError::MultipleAspectsNotAllowed {
+ resource: CopyErrorResource::Source,
+ region_index,
+ aspects: image_subresource.aspects,
+ });
+ }
+
+ let (image_subresource_format, image_subresource_extent) =
+ if image_aspects.intersects(ImageAspects::PLANE_0) {
+ if image_subresource.aspects.intersects(ImageAspects::PLANE_0) {
+ (
+ src_image.format().planes()[0],
+ src_image.dimensions().width_height_depth(),
+ )
+ } else if image_subresource.aspects.intersects(ImageAspects::PLANE_1) {
+ (
+ src_image.format().planes()[1],
+ src_image
+ .format()
+ .ycbcr_chroma_sampling()
+ .unwrap()
+ .subsampled_extent(src_image.dimensions().width_height_depth()),
+ )
+ } else {
+ (
+ src_image.format().planes()[2],
+ src_image
+ .format()
+ .ycbcr_chroma_sampling()
+ .unwrap()
+ .subsampled_extent(src_image.dimensions().width_height_depth()),
+ )
+ }
+ } else {
+ (
+ src_image.format(),
+ src_image
+ .dimensions()
+ .mip_level_dimensions(image_subresource.mip_level)
+ .unwrap()
+ .width_height_depth(),
+ )
+ };
+
+ if let Some(extent_alignment) = extent_alignment {
+ for i in 0..3 {
+ // VUID-VkBufferImageCopy2-imageExtent-06659
+ // VUID-VkBufferImageCopy2-imageExtent-06660
+ // VUID-VkBufferImageCopy2-imageExtent-06661
+ assert!(image_extent[i] != 0);
+
+ // VUID-VkCopyImageToBufferInfo2-imageOffset-00197
+ // VUID-VkCopyImageToBufferInfo2-imageOffset-00198
+ // VUID-VkCopyImageToBufferInfo2-imageOffset-00200
+ if image_offset[i] + image_extent[i] > image_subresource_extent[i] {
+ return Err(CopyError::RegionOutOfImageBounds {
+ resource: CopyErrorResource::Source,
+ region_index,
+ offset_range_end: [
+ image_offset[0] + image_extent[0],
+ image_offset[1] + image_extent[1],
+ image_offset[2] + image_extent[2],
+ ],
+ subresource_extent: image_subresource_extent,
+ });
+ }
+
+ // VUID-VkCopyImageToBufferInfo2-imageOffset-01794
+ // VUID-VkCopyImageToBufferInfo2-imageOffset-00205
+ if image_offset[i] % extent_alignment[i] != 0 {
+ return Err(CopyError::OffsetNotAlignedForImage {
+ resource: CopyErrorResource::Source,
+ region_index,
+ offset: image_offset,
+ required_alignment: extent_alignment,
+ });
+ }
+
+ // VUID-VkCopyImageToBufferInfo2-imageOffset-01794
+ // VUID-VkCopyImageToBufferInfo2-imageExtent-00207
+ // VUID-VkCopyImageToBufferInfo2-imageExtent-00208
+ // VUID-VkCopyImageToBufferInfo2-imageExtent-00209
+ if image_offset[i] + image_extent[i] != image_subresource_extent[i]
+ && image_extent[i] % extent_alignment[i] != 0
+ {
+ return Err(CopyError::ExtentNotAlignedForImage {
+ resource: CopyErrorResource::Source,
+ region_index,
+ extent: image_extent,
+ required_alignment: extent_alignment,
+ });
+ }
+ }
+ } else {
+ // If granularity is `None`, then we can only copy whole subresources.
+
+ // VUID-VkCopyBufferToImageInfo2-imageOffset-01793
+ if image_offset != [0, 0, 0] {
+ return Err(CopyError::OffsetNotAlignedForImage {
+ resource: CopyErrorResource::Source,
+ region_index,
+ offset: image_offset,
+ required_alignment: image_subresource_extent,
+ });
+ }
+
+ // VUID-VkCopyBufferToImageInfo2-imageOffset-01793
+ if image_extent != image_subresource_extent {
+ return Err(CopyError::ExtentNotAlignedForImage {
+ resource: CopyErrorResource::Source,
+ region_index,
+ extent: image_extent,
+ required_alignment: image_subresource_extent,
+ });
+ }
+ }
+
+ // VUID-VkBufferImageCopy2-bufferRowLength-00195
+ if !(buffer_row_length == 0 || buffer_row_length >= image_extent[0]) {
+ return Err(CopyError::BufferRowLengthTooSmall {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ row_length: buffer_row_length,
+ min: image_extent[0],
+ });
+ }
+
+ // VUID-VkBufferImageCopy2-bufferImageHeight-00196
+ if !(buffer_image_height == 0 || buffer_image_height >= image_extent[1]) {
+ return Err(CopyError::BufferImageHeightTooSmall {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ image_height: buffer_image_height,
+ min: image_extent[1],
+ });
+ }
+
+ let image_subresource_block_extent = image_subresource_format.block_extent();
+
+ // VUID-VkCopyImageToBufferInfo2-bufferRowLength-00203
+ if buffer_row_length % image_subresource_block_extent[0] != 0 {
+ return Err(CopyError::BufferRowLengthNotAligned {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ row_length: buffer_row_length,
+ required_alignment: image_subresource_block_extent[0],
+ });
+ }
+
+ // VUID-VkCopyImageToBufferInfo2-bufferImageHeight-00204
+ if buffer_image_height % image_subresource_block_extent[1] != 0 {
+ return Err(CopyError::BufferImageHeightNotAligned {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ image_height: buffer_image_height,
+ required_alignment: image_subresource_block_extent[1],
+ });
+ }
+
+ // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkBufferImageCopy.html#_description
+ let image_subresource_block_size =
+ if image_subresource.aspects.intersects(ImageAspects::STENCIL) {
+ 1
+ } else if image_subresource.aspects.intersects(ImageAspects::DEPTH) {
+ match image_subresource_format {
+ Format::D16_UNORM | Format::D16_UNORM_S8_UINT => 2,
+ Format::D32_SFLOAT
+ | Format::D32_SFLOAT_S8_UINT
+ | Format::X8_D24_UNORM_PACK32
+ | Format::D24_UNORM_S8_UINT => 4,
+ _ => unreachable!(),
+ }
+ } else {
+ image_subresource_format.block_size().unwrap()
+ };
+
+ // VUID-VkCopyImageToBufferInfo2-pRegions-04725
+ // VUID-VkCopyImageToBufferInfo2-pRegions-04726
+ if (buffer_row_length / image_subresource_block_extent[0]) as DeviceSize
+ * image_subresource_block_size
+ > 0x7FFFFFFF
+ {
+ return Err(CopyError::BufferRowLengthTooLarge {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ buffer_row_length,
+ });
+ }
+
+ let buffer_offset_alignment =
+ if image_aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL) {
+ 4
+ } else {
+ let mut buffer_offset_alignment = image_subresource_block_size;
+
+ // VUID-VkCopyImageToBufferInfo2-commandBuffer-04052
+ // Make the alignment a multiple of 4.
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ if buffer_offset_alignment % 2 != 0 {
+ buffer_offset_alignment *= 2;
+ }
+
+ if buffer_offset_alignment % 4 != 0 {
+ buffer_offset_alignment *= 2;
+ }
+ }
+
+ buffer_offset_alignment
+ };
+
+ // VUID-VkCopyImageToBufferInfo2-bufferOffset-01558
+ // VUID-VkCopyImageToBufferInfo2-bufferOffset-01559
+ // VUID-VkCopyImageToBufferInfo2-bufferOffset-00206
+ // VUID-VkCopyImageToBufferInfo2-srcImage-04053
+ if (dst_buffer.offset() + buffer_offset) % buffer_offset_alignment != 0 {
+ return Err(CopyError::OffsetNotAlignedForBuffer {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ offset: dst_buffer.offset() + buffer_offset,
+ required_alignment: buffer_offset_alignment,
+ });
+ }
+
+ let buffer_copy_size = region.buffer_copy_size(image_subresource_format);
+
+ // VUID-VkCopyImageToBufferInfo2-pRegions-00183
+ if buffer_offset + buffer_copy_size > dst_buffer.size() {
+ return Err(CopyError::RegionOutOfBufferBounds {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ offset_range_end: buffer_offset + buffer_copy_size,
+ buffer_size: dst_buffer.size(),
+ });
+ }
+ }
+
+ // VUID-VkCopyImageToBufferInfo2-pRegions-00184
+ // Can't occur as long as memory aliasing isn't allowed.
+
+ Ok(())
+ }
+
+ /// Blits an image to another.
+ ///
+ /// A *blit* is similar to an image copy operation, except that the portion of the image that
+ /// is transferred can be resized. You choose an area of the source and an area of the
+ /// destination, and the implementation will resize the area of the source so that it matches
+ /// the size of the area of the destination before writing it.
+ ///
+ /// Blit operations have several restrictions:
+ ///
+ /// - Blit operations are only allowed on queue families that support graphics operations.
+ /// - The format of the source and destination images must support blit operations, which
+ /// depends on the Vulkan implementation. Vulkan guarantees that some specific formats must
+ /// always be supported. See tables 52 to 61 of the specifications.
+ /// - Only single-sampled images are allowed.
+ /// - You can only blit between two images whose formats belong to the same type. The types
+ /// are: floating-point, signed integers, unsigned integers, depth-stencil.
+ /// - If you blit between depth, stencil or depth-stencil images, the format of both images
+ /// must match exactly.
+ /// - If you blit between depth, stencil or depth-stencil images, only the `Nearest` filter is
+ /// allowed.
+ /// - For two-dimensional images, the Z coordinate must be 0 for the top-left offset and 1 for
+ /// the bottom-right offset. Same for the Y coordinate for one-dimensional images.
+ /// - For non-array images, the base array layer must be 0 and the number of layers must be 1.
+ ///
+ /// If `layer_count` is greater than 1, the blit will happen between each individual layer as
+ /// if they were separate images.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the source or the destination was not created with `device`.
+ pub fn blit_image(&mut self, blit_image_info: BlitImageInfo) -> Result<&mut Self, CopyError> {
+ self.validate_blit_image(&blit_image_info)?;
+
+ unsafe {
+ self.inner.blit_image(blit_image_info)?;
+ }
+
+ Ok(self)
+ }
+
+ fn validate_blit_image(&self, blit_image_info: &BlitImageInfo) -> Result<(), CopyError> {
+ let device = self.device();
+
+ // VUID-vkCmdBlitImage2-renderpass
+ if self.render_pass_state.is_some() {
+ return Err(CopyError::ForbiddenInsideRenderPass);
+ }
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdBlitImage2-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(CopyError::NotSupportedByQueueFamily);
+ }
+
+ let &BlitImageInfo {
+ ref src_image,
+ src_image_layout,
+ ref dst_image,
+ dst_image_layout,
+ ref regions,
+ filter,
+ _ne: _,
+ } = blit_image_info;
+
+ // VUID-VkBlitImageInfo2-srcImageLayout-parameter
+ src_image_layout.validate_device(device)?;
+
+ // VUID-VkBlitImageInfo2-dstImageLayout-parameter
+ dst_image_layout.validate_device(device)?;
+
+ // VUID-VkBlitImageInfo2-filter-parameter
+ filter.validate_device(device)?;
+
+ let src_image_inner = src_image.inner();
+ let dst_image_inner = dst_image.inner();
+
+ // VUID-VkBlitImageInfo2-commonparent
+ assert_eq!(device, src_image.device());
+ assert_eq!(device, dst_image.device());
+
+ let src_image_aspects = src_image.format().aspects();
+ let dst_image_aspects = dst_image.format().aspects();
+ let src_image_type = src_image.dimensions().image_type();
+ let dst_image_type = dst_image.dimensions().image_type();
+
+ // VUID-VkBlitImageInfo2-srcImage-00219
+ if !src_image.usage().intersects(ImageUsage::TRANSFER_SRC) {
+ return Err(CopyError::MissingUsage {
+ resource: CopyErrorResource::Source,
+ usage: "transfer_src",
+ });
+ }
+
+ // VUID-VkBlitImageInfo2-dstImage-00224
+ if !dst_image.usage().intersects(ImageUsage::TRANSFER_DST) {
+ return Err(CopyError::MissingUsage {
+ resource: CopyErrorResource::Destination,
+ usage: "transfer_dst",
+ });
+ }
+
+ // VUID-VkBlitImageInfo2-srcImage-01999
+ if !src_image
+ .format_features()
+ .intersects(FormatFeatures::BLIT_SRC)
+ {
+ return Err(CopyError::MissingFormatFeature {
+ resource: CopyErrorResource::Source,
+ format_feature: "blit_src",
+ });
+ }
+
+ // VUID-VkBlitImageInfo2-dstImage-02000
+ if !dst_image
+ .format_features()
+ .intersects(FormatFeatures::BLIT_DST)
+ {
+ return Err(CopyError::MissingFormatFeature {
+ resource: CopyErrorResource::Destination,
+ format_feature: "blit_dst",
+ });
+ }
+
+ // VUID-VkBlitImageInfo2-srcImage-06421
+ if src_image.format().ycbcr_chroma_sampling().is_some() {
+ return Err(CopyError::FormatNotSupported {
+ resource: CopyErrorResource::Source,
+ format: src_image.format(),
+ });
+ }
+
+ // VUID-VkBlitImageInfo2-dstImage-06422
+ if dst_image.format().ycbcr_chroma_sampling().is_some() {
+ return Err(CopyError::FormatNotSupported {
+ resource: CopyErrorResource::Destination,
+ format: src_image.format(),
+ });
+ }
+
+ if !(src_image_aspects.intersects(ImageAspects::COLOR)
+ && dst_image_aspects.intersects(ImageAspects::COLOR))
+ {
+ // VUID-VkBlitImageInfo2-srcImage-00231
+ if src_image.format() != dst_image.format() {
+ return Err(CopyError::FormatsMismatch {
+ src_format: src_image.format(),
+ dst_format: dst_image.format(),
+ });
+ }
+ } else {
+ // VUID-VkBlitImageInfo2-srcImage-00229
+ // VUID-VkBlitImageInfo2-srcImage-00230
+ if !matches!(
+ (
+ src_image.format().type_color().unwrap(),
+ dst_image.format().type_color().unwrap()
+ ),
+ (
+ NumericType::SFLOAT
+ | NumericType::UFLOAT
+ | NumericType::SNORM
+ | NumericType::UNORM
+ | NumericType::SSCALED
+ | NumericType::USCALED
+ | NumericType::SRGB,
+ NumericType::SFLOAT
+ | NumericType::UFLOAT
+ | NumericType::SNORM
+ | NumericType::UNORM
+ | NumericType::SSCALED
+ | NumericType::USCALED
+ | NumericType::SRGB,
+ ) | (NumericType::SINT, NumericType::SINT)
+ | (NumericType::UINT, NumericType::UINT)
+ ) {
+ return Err(CopyError::FormatsNotCompatible {
+ src_format: src_image.format(),
+ dst_format: dst_image.format(),
+ });
+ }
+ }
+
+ // VUID-VkBlitImageInfo2-srcImage-00233
+ if src_image.samples() != SampleCount::Sample1 {
+ return Err(CopyError::SampleCountInvalid {
+ resource: CopyErrorResource::Destination,
+ sample_count: dst_image.samples(),
+ allowed_sample_counts: SampleCounts::SAMPLE_1,
+ });
+ }
+
+ // VUID-VkBlitImageInfo2-dstImage-00234
+ if dst_image.samples() != SampleCount::Sample1 {
+ return Err(CopyError::SampleCountInvalid {
+ resource: CopyErrorResource::Destination,
+ sample_count: dst_image.samples(),
+ allowed_sample_counts: SampleCounts::SAMPLE_1,
+ });
+ }
+
+ // VUID-VkBlitImageInfo2-srcImageLayout-01398
+ if !matches!(
+ src_image_layout,
+ ImageLayout::TransferSrcOptimal | ImageLayout::General
+ ) {
+ return Err(CopyError::ImageLayoutInvalid {
+ resource: CopyErrorResource::Source,
+ image_layout: src_image_layout,
+ });
+ }
+
+ // VUID-VkBlitImageInfo2-dstImageLayout-01399
+ if !matches!(
+ dst_image_layout,
+ ImageLayout::TransferDstOptimal | ImageLayout::General
+ ) {
+ return Err(CopyError::ImageLayoutInvalid {
+ resource: CopyErrorResource::Destination,
+ image_layout: dst_image_layout,
+ });
+ }
+
+ // VUID-VkBlitImageInfo2-srcImage-00232
+ if !src_image_aspects.intersects(ImageAspects::COLOR) && filter != Filter::Nearest {
+ return Err(CopyError::FilterNotSupportedByFormat);
+ }
+
+ match filter {
+ Filter::Nearest => (),
+ Filter::Linear => {
+ // VUID-VkBlitImageInfo2-filter-02001
+ if !src_image
+ .format_features()
+ .intersects(FormatFeatures::SAMPLED_IMAGE_FILTER_LINEAR)
+ {
+ return Err(CopyError::FilterNotSupportedByFormat);
+ }
+ }
+ Filter::Cubic => {
+ // VUID-VkBlitImageInfo2-filter-02002
+ if !src_image
+ .format_features()
+ .intersects(FormatFeatures::SAMPLED_IMAGE_FILTER_CUBIC)
+ {
+ return Err(CopyError::FilterNotSupportedByFormat);
+ }
+
+ // VUID-VkBlitImageInfo2-filter-00237
+ if !matches!(src_image.dimensions(), ImageDimensions::Dim2d { .. }) {
+ return Err(CopyError::FilterNotSupportedForImageType);
+ }
+ }
+ }
+
+ let same_image = src_image_inner.image == dst_image_inner.image;
+ let mut overlap_subresource_indices = None;
+ let mut overlap_extent_indices = None;
+
+ for (region_index, region) in regions.iter().enumerate() {
+ let &ImageBlit {
+ ref src_subresource,
+ src_offsets,
+ ref dst_subresource,
+ dst_offsets,
+ _ne: _,
+ } = region;
+
+ let check_subresource = |resource: CopyErrorResource,
+ image: &dyn ImageAccess,
+ image_aspects: ImageAspects,
+ subresource: &ImageSubresourceLayers|
+ -> Result<_, CopyError> {
+ // VUID-VkBlitImageInfo2-srcSubresource-01705
+ // VUID-VkBlitImageInfo2-dstSubresource-01706
+ if subresource.mip_level >= image.mip_levels() {
+ return Err(CopyError::MipLevelsOutOfRange {
+ resource,
+ region_index,
+ mip_levels_range_end: subresource.mip_level + 1,
+ image_mip_levels: image.mip_levels(),
+ });
+ }
+
+ // VUID-VkImageSubresourceLayers-layerCount-01700
+ assert!(!subresource.array_layers.is_empty());
+
+ // VUID-VkBlitImageInfo2-srcSubresource-01707
+ // VUID-VkBlitImageInfo2-dstSubresource-01708
+ // VUID-VkBlitImageInfo2-srcImage-00240
+ if subresource.array_layers.end > image.dimensions().array_layers() {
+ return Err(CopyError::ArrayLayersOutOfRange {
+ resource,
+ region_index,
+ array_layers_range_end: subresource.array_layers.end,
+ image_array_layers: image.dimensions().array_layers(),
+ });
+ }
+
+ // VUID-VkImageSubresourceLayers-aspectMask-parameter
+ subresource.aspects.validate_device(device)?;
+
+ // VUID-VkImageSubresourceLayers-aspectMask-requiredbitmask
+ assert!(!subresource.aspects.is_empty());
+
+ // VUID-VkBlitImageInfo2-aspectMask-00241
+ // VUID-VkBlitImageInfo2-aspectMask-00242
+ if !image_aspects.contains(subresource.aspects) {
+ return Err(CopyError::AspectsNotAllowed {
+ resource,
+ region_index,
+ aspects: subresource.aspects,
+ allowed_aspects: image_aspects,
+ });
+ }
+
+ Ok(image
+ .dimensions()
+ .mip_level_dimensions(subresource.mip_level)
+ .unwrap()
+ .width_height_depth())
+ };
+
+ let src_subresource_extent = check_subresource(
+ CopyErrorResource::Source,
+ src_image,
+ src_image_aspects,
+ src_subresource,
+ )?;
+ let dst_subresource_extent = check_subresource(
+ CopyErrorResource::Destination,
+ dst_image,
+ dst_image_aspects,
+ dst_subresource,
+ )?;
+
+ // VUID-VkImageBlit2-aspectMask-00238
+ if src_subresource.aspects != dst_subresource.aspects {
+ return Err(CopyError::AspectsMismatch {
+ region_index,
+ src_aspects: src_subresource.aspects,
+ dst_aspects: dst_subresource.aspects,
+ });
+ }
+
+ let src_layer_count =
+ src_subresource.array_layers.end - src_subresource.array_layers.start;
+ let dst_layer_count =
+ dst_subresource.array_layers.end - dst_subresource.array_layers.start;
+
+ // VUID-VkImageBlit2-layerCount-00239
+ // VUID-VkBlitImageInfo2-srcImage-00240
+ if src_layer_count != dst_layer_count {
+ return Err(CopyError::ArrayLayerCountMismatch {
+ region_index,
+ src_layer_count,
+ dst_layer_count,
+ });
+ }
+
+ let check_offset_extent = |resource: CopyErrorResource,
+ image_type: ImageType,
+ subresource_extent: [u32; 3],
+ offsets: [[u32; 3]; 2]|
+ -> Result<_, CopyError> {
+ match image_type {
+ ImageType::Dim1d => {
+ // VUID-VkBlitImageInfo2-srcImage-00245
+ // VUID-VkBlitImageInfo2-dstImage-00250
+ if !(offsets[0][1] == 0 && offsets[1][1] == 1) {
+ return Err(CopyError::OffsetsInvalidForImageType {
+ resource,
+ region_index,
+ offsets: [offsets[0][1], offsets[1][1]],
+ });
+ }
+
+ // VUID-VkBlitImageInfo2-srcImage-00247
+ // VUID-VkBlitImageInfo2-dstImage-00252
+ if !(offsets[0][2] == 0 && offsets[1][2] == 1) {
+ return Err(CopyError::OffsetsInvalidForImageType {
+ resource,
+ region_index,
+ offsets: [offsets[0][2], offsets[1][2]],
+ });
+ }
+ }
+ ImageType::Dim2d => {
+ // VUID-VkBlitImageInfo2-srcImage-00247
+ // VUID-VkBlitImageInfo2-dstImage-00252
+ if !(offsets[0][2] == 0 && offsets[1][2] == 1) {
+ return Err(CopyError::OffsetsInvalidForImageType {
+ resource,
+ region_index,
+ offsets: [offsets[0][2], offsets[1][2]],
+ });
+ }
+ }
+ ImageType::Dim3d => (),
+ }
+
+ let offset_range_end = [
+ max(offsets[0][0], offsets[1][0]),
+ max(offsets[0][1], offsets[1][1]),
+ max(offsets[0][2], offsets[1][2]),
+ ];
+
+ for i in 0..3 {
+ // VUID-VkBlitImageInfo2-srcOffset-00243
+ // VUID-VkBlitImageInfo2-srcOffset-00244
+ // VUID-VkBlitImageInfo2-srcOffset-00246
+ // VUID-VkBlitImageInfo2-dstOffset-00248
+ // VUID-VkBlitImageInfo2-dstOffset-00249
+ // VUID-VkBlitImageInfo2-dstOffset-00251
+ if offset_range_end[i] > subresource_extent[i] {
+ return Err(CopyError::RegionOutOfImageBounds {
+ resource,
+ region_index,
+ offset_range_end,
+ subresource_extent,
+ });
+ }
+ }
+
+ Ok(())
+ };
+
+ check_offset_extent(
+ CopyErrorResource::Source,
+ src_image_type,
+ src_subresource_extent,
+ src_offsets,
+ )?;
+ check_offset_extent(
+ CopyErrorResource::Destination,
+ dst_image_type,
+ dst_subresource_extent,
+ dst_offsets,
+ )?;
+
+ // VUID-VkBlitImageInfo2-pRegions-00217
+ if same_image {
+ let src_region_index = region_index;
+ let src_subresource_axes = [
+ src_image_inner.first_mipmap_level + src_subresource.mip_level
+ ..src_image_inner.first_mipmap_level + src_subresource.mip_level + 1,
+ src_image_inner.first_layer + src_subresource.array_layers.start
+ ..src_image_inner.first_layer + src_subresource.array_layers.end,
+ ];
+ let src_extent_axes = [
+ min(src_offsets[0][0], src_offsets[1][0])
+ ..max(src_offsets[0][0], src_offsets[1][0]),
+ min(src_offsets[0][1], src_offsets[1][1])
+ ..max(src_offsets[0][1], src_offsets[1][1]),
+ min(src_offsets[0][2], src_offsets[1][2])
+ ..max(src_offsets[0][2], src_offsets[1][2]),
+ ];
+
+ for (dst_region_index, dst_region) in regions.iter().enumerate() {
+ let &ImageBlit {
+ ref dst_subresource,
+ dst_offsets,
+ ..
+ } = dst_region;
+
+ let dst_subresource_axes = [
+ dst_image_inner.first_mipmap_level + dst_subresource.mip_level
+ ..dst_image_inner.first_mipmap_level + dst_subresource.mip_level + 1,
+ dst_image_inner.first_layer + src_subresource.array_layers.start
+ ..dst_image_inner.first_layer + src_subresource.array_layers.end,
+ ];
+
+ if src_subresource_axes.iter().zip(dst_subresource_axes).any(
+ |(src_range, dst_range)| {
+ src_range.start >= dst_range.end || dst_range.start >= src_range.end
+ },
+ ) {
+ continue;
+ }
+
+ // If the subresource axes all overlap, then the source and destination must
+ // have the same layout.
+ overlap_subresource_indices = Some((src_region_index, dst_region_index));
+
+ let dst_extent_axes = [
+ min(dst_offsets[0][0], dst_offsets[1][0])
+ ..max(dst_offsets[0][0], dst_offsets[1][0]),
+ min(dst_offsets[0][1], dst_offsets[1][1])
+ ..max(dst_offsets[0][1], dst_offsets[1][1]),
+ min(dst_offsets[0][2], dst_offsets[1][2])
+ ..max(dst_offsets[0][2], dst_offsets[1][2]),
+ ];
+
+ if src_extent_axes
+ .iter()
+ .zip(dst_extent_axes)
+ .any(|(src_range, dst_range)| {
+ src_range.start >= dst_range.end || dst_range.start >= src_range.end
+ })
+ {
+ continue;
+ }
+
+ // If the extent axes *also* overlap, then that's an error.
+ overlap_extent_indices = Some((src_region_index, dst_region_index));
+ }
+ }
+ }
+
+ // VUID-VkBlitImageInfo2-pRegions-00217
+ if let Some((src_region_index, dst_region_index)) = overlap_extent_indices {
+ return Err(CopyError::OverlappingRegions {
+ src_region_index,
+ dst_region_index,
+ });
+ }
+
+ // VUID-VkBlitImageInfo2-srcImageLayout-00221
+ // VUID-VkBlitImageInfo2-dstImageLayout-00226
+ if let Some((src_region_index, dst_region_index)) = overlap_subresource_indices {
+ if src_image_layout != dst_image_layout {
+ return Err(CopyError::OverlappingSubresourcesLayoutMismatch {
+ src_region_index,
+ dst_region_index,
+ src_image_layout,
+ dst_image_layout,
+ });
+ }
+ }
+
+ Ok(())
+ }
+
+ /// Resolves a multisampled image into a single-sampled image.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `src_image` or `dst_image` were not created from the same device
+ /// as `self`.
+ pub fn resolve_image(
+ &mut self,
+ resolve_image_info: ResolveImageInfo,
+ ) -> Result<&mut Self, CopyError> {
+ self.validate_resolve_image(&resolve_image_info)?;
+
+ unsafe {
+ self.inner.resolve_image(resolve_image_info)?;
+ }
+
+ Ok(self)
+ }
+
+ fn validate_resolve_image(
+ &self,
+ resolve_image_info: &ResolveImageInfo,
+ ) -> Result<(), CopyError> {
+ let device = self.device();
+
+ // VUID-vkCmdResolveImage2-renderpass
+ if self.render_pass_state.is_some() {
+ return Err(CopyError::ForbiddenInsideRenderPass);
+ }
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdResolveImage2-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(CopyError::NotSupportedByQueueFamily);
+ }
+
+ let &ResolveImageInfo {
+ ref src_image,
+ src_image_layout,
+ ref dst_image,
+ dst_image_layout,
+ ref regions,
+ _ne: _,
+ } = resolve_image_info;
+
+ // VUID-VkResolveImageInfo2-srcImageLayout-parameter
+ src_image_layout.validate_device(device)?;
+
+ // VUID-VkResolveImageInfo2-dstImageLayout-parameter
+ dst_image_layout.validate_device(device)?;
+
+ // VUID-VkResolveImageInfo2-commonparent
+ assert_eq!(device, src_image.device());
+ assert_eq!(device, dst_image.device());
+
+ let src_image_type = src_image.dimensions().image_type();
+ let dst_image_type = dst_image.dimensions().image_type();
+
+ // VUID-VkResolveImageInfo2-srcImage-00257
+ if src_image.samples() == SampleCount::Sample1 {
+ return Err(CopyError::SampleCountInvalid {
+ resource: CopyErrorResource::Source,
+ sample_count: dst_image.samples(),
+ allowed_sample_counts: SampleCounts::SAMPLE_2
+ | SampleCounts::SAMPLE_4
+ | SampleCounts::SAMPLE_8
+ | SampleCounts::SAMPLE_16
+ | SampleCounts::SAMPLE_32
+ | SampleCounts::SAMPLE_64,
+ });
+ }
+
+ // VUID-VkResolveImageInfo2-dstImage-00259
+ if dst_image.samples() != SampleCount::Sample1 {
+ return Err(CopyError::SampleCountInvalid {
+ resource: CopyErrorResource::Destination,
+ sample_count: dst_image.samples(),
+ allowed_sample_counts: SampleCounts::SAMPLE_1,
+ });
+ }
+
+ // VUID-VkResolveImageInfo2-dstImage-02003
+ if !dst_image
+ .format_features()
+ .intersects(FormatFeatures::COLOR_ATTACHMENT)
+ {
+ return Err(CopyError::MissingFormatFeature {
+ resource: CopyErrorResource::Destination,
+ format_feature: "color_attachment",
+ });
+ }
+
+ // VUID-VkResolveImageInfo2-srcImage-01386
+ if src_image.format() != dst_image.format() {
+ return Err(CopyError::FormatsMismatch {
+ src_format: src_image.format(),
+ dst_format: dst_image.format(),
+ });
+ }
+
+ // VUID-VkResolveImageInfo2-srcImageLayout-01400
+ if !matches!(
+ src_image_layout,
+ ImageLayout::TransferSrcOptimal | ImageLayout::General
+ ) {
+ return Err(CopyError::ImageLayoutInvalid {
+ resource: CopyErrorResource::Source,
+ image_layout: src_image_layout,
+ });
+ }
+
+ // VUID-VkResolveImageInfo2-dstImageLayout-01401
+ if !matches!(
+ dst_image_layout,
+ ImageLayout::TransferDstOptimal | ImageLayout::General
+ ) {
+ return Err(CopyError::ImageLayoutInvalid {
+ resource: CopyErrorResource::Destination,
+ image_layout: dst_image_layout,
+ });
+ }
+
+ // Should be guaranteed by the requirement that formats match, and that the destination
+ // image format features support color attachments.
+ debug_assert!(
+ src_image.format().aspects().intersects(ImageAspects::COLOR)
+ && dst_image.format().aspects().intersects(ImageAspects::COLOR)
+ );
+
+ for (region_index, region) in regions.iter().enumerate() {
+ let &ImageResolve {
+ ref src_subresource,
+ src_offset,
+ ref dst_subresource,
+ dst_offset,
+ extent,
+ _ne: _,
+ } = region;
+
+ let check_subresource = |resource: CopyErrorResource,
+ image: &dyn ImageAccess,
+ subresource: &ImageSubresourceLayers|
+ -> Result<_, CopyError> {
+ // VUID-VkResolveImageInfo2-srcSubresource-01709
+ // VUID-VkResolveImageInfo2-dstSubresource-01710
+ if subresource.mip_level >= image.mip_levels() {
+ return Err(CopyError::MipLevelsOutOfRange {
+ resource,
+ region_index,
+ mip_levels_range_end: subresource.mip_level + 1,
+ image_mip_levels: image.mip_levels(),
+ });
+ }
+
+ // VUID-VkImageSubresourceLayers-layerCount-01700
+ // VUID-VkResolveImageInfo2-srcImage-04446
+ // VUID-VkResolveImageInfo2-srcImage-04447
+ assert!(!subresource.array_layers.is_empty());
+
+ // VUID-VkResolveImageInfo2-srcSubresource-01711
+ // VUID-VkResolveImageInfo2-dstSubresource-01712
+ // VUID-VkResolveImageInfo2-srcImage-04446
+ // VUID-VkResolveImageInfo2-srcImage-04447
+ if subresource.array_layers.end > image.dimensions().array_layers() {
+ return Err(CopyError::ArrayLayersOutOfRange {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ array_layers_range_end: subresource.array_layers.end,
+ image_array_layers: image.dimensions().array_layers(),
+ });
+ }
+
+ // VUID-VkImageSubresourceLayers-aspectMask-parameter
+ subresource.aspects.validate_device(device)?;
+
+ // VUID-VkImageSubresourceLayers-aspectMask-requiredbitmask
+ // VUID-VkImageResolve2-aspectMask-00266
+ if subresource.aspects != (ImageAspects::COLOR) {
+ return Err(CopyError::AspectsNotAllowed {
+ resource,
+ region_index,
+ aspects: subresource.aspects,
+ allowed_aspects: ImageAspects::COLOR,
+ });
+ }
+
+ Ok(image
+ .dimensions()
+ .mip_level_dimensions(subresource.mip_level)
+ .unwrap()
+ .width_height_depth())
+ };
+
+ let src_subresource_extent =
+ check_subresource(CopyErrorResource::Source, src_image, src_subresource)?;
+ let dst_subresource_extent =
+ check_subresource(CopyErrorResource::Destination, dst_image, dst_subresource)?;
+
+ let src_layer_count =
+ src_subresource.array_layers.end - src_subresource.array_layers.start;
+ let dst_layer_count =
+ dst_subresource.array_layers.end - dst_subresource.array_layers.start;
+
+ // VUID-VkImageResolve2-layerCount-00267
+ // VUID-VkResolveImageInfo2-srcImage-04446
+ // VUID-VkResolveImageInfo2-srcImage-04447
+ if src_layer_count != dst_layer_count {
+ return Err(CopyError::ArrayLayerCountMismatch {
+ region_index,
+ src_layer_count,
+ dst_layer_count,
+ });
+ }
+
+ // No VUID, but it makes sense?
+ assert!(extent[0] != 0 && extent[1] != 0 && extent[2] != 0);
+
+ let check_offset_extent = |resource: CopyErrorResource,
+ _image_type: ImageType,
+ subresource_extent: [u32; 3],
+ offset: [u32; 3]|
+ -> Result<_, CopyError> {
+ for i in 0..3 {
+ // No VUID, but makes sense?
+ assert!(extent[i] != 0);
+
+ // VUID-VkResolveImageInfo2-srcOffset-00269
+ // VUID-VkResolveImageInfo2-srcOffset-00270
+ // VUID-VkResolveImageInfo2-srcOffset-00272
+ // VUID-VkResolveImageInfo2-dstOffset-00274
+ // VUID-VkResolveImageInfo2-dstOffset-00275
+ // VUID-VkResolveImageInfo2-dstOffset-00277
+ if offset[i] + extent[i] > subresource_extent[i] {
+ return Err(CopyError::RegionOutOfImageBounds {
+ resource,
+ region_index,
+ offset_range_end: [
+ offset[0] + extent[0],
+ offset[1] + extent[1],
+ offset[2] + extent[2],
+ ],
+ subresource_extent,
+ });
+ }
+ }
+
+ Ok(())
+ };
+
+ check_offset_extent(
+ CopyErrorResource::Source,
+ src_image_type,
+ src_subresource_extent,
+ src_offset,
+ )?;
+ check_offset_extent(
+ CopyErrorResource::Destination,
+ dst_image_type,
+ dst_subresource_extent,
+ dst_offset,
+ )?;
+ }
+
+ // VUID-VkResolveImageInfo2-pRegions-00255
+ // Can't occur as long as memory aliasing isn't allowed, because `src_image` and
+ // `dst_image` must have different sample counts and therefore can never be the same image.
+
+ Ok(())
+ }
+}
+
+impl SyncCommandBufferBuilder {
+ /// Calls `vkCmdCopyBuffer` on the builder.
+ ///
+ /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
+ /// usage of the command anyway.
+ #[inline]
+ pub unsafe fn copy_buffer(
+ &mut self,
+ copy_buffer_info: CopyBufferInfo,
+ ) -> Result<(), SyncCommandBufferBuilderError> {
+ struct Cmd {
+ copy_buffer_info: CopyBufferInfo,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "copy_buffer"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.copy_buffer(&self.copy_buffer_info);
+ }
+ }
+
+ let CopyBufferInfo {
+ src_buffer,
+ dst_buffer,
+ regions,
+ _ne: _,
+ } = &copy_buffer_info;
+
+ let command_index = self.commands.len();
+ let command_name = "copy_buffer";
+ let resources: SmallVec<[_; 8]> = regions
+ .iter()
+ .flat_map(|region| {
+ let &BufferCopy {
+ src_offset,
+ dst_offset,
+ size,
+ _ne: _,
+ } = region;
+
+ [
+ (
+ ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Source,
+ secondary_use_ref: None,
+ },
+ Resource::Buffer {
+ buffer: src_buffer.clone(),
+ range: src_offset..src_offset + size,
+ memory: PipelineMemoryAccess {
+ stages: PipelineStages::ALL_TRANSFER,
+ access: AccessFlags::TRANSFER_READ,
+ exclusive: false,
+ },
+ },
+ ),
+ (
+ ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Destination,
+ secondary_use_ref: None,
+ },
+ Resource::Buffer {
+ buffer: dst_buffer.clone(),
+ range: dst_offset..dst_offset + size,
+ memory: PipelineMemoryAccess {
+ stages: PipelineStages::ALL_TRANSFER,
+ access: AccessFlags::TRANSFER_WRITE,
+ exclusive: true,
+ },
+ },
+ ),
+ ]
+ })
+ .collect();
+
+ for resource in &resources {
+ self.check_resource_conflicts(resource)?;
+ }
+
+ self.commands.push(Box::new(Cmd { copy_buffer_info }));
+
+ for resource in resources {
+ self.add_resource(resource);
+ }
+
+ Ok(())
+ }
+
+ /// Calls `vkCmdCopyImage` on the builder.
+ ///
+ /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
+ /// usage of the command anyway.
+ #[inline]
+ pub unsafe fn copy_image(
+ &mut self,
+ copy_image_info: CopyImageInfo,
+ ) -> Result<(), SyncCommandBufferBuilderError> {
+ struct Cmd {
+ copy_image_info: CopyImageInfo,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "copy_buffer_to_image"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.copy_image(&self.copy_image_info);
+ }
+ }
+
+ let &CopyImageInfo {
+ ref src_image,
+ src_image_layout,
+ ref dst_image,
+ dst_image_layout,
+ ref regions,
+ _ne: _,
+ } = &copy_image_info;
+
+ let command_index = self.commands.len();
+ let command_name = "copy_image";
+ let resources: SmallVec<[_; 8]> = regions
+ .iter()
+ .flat_map(|region| {
+ let &ImageCopy {
+ ref src_subresource,
+ src_offset: _,
+ ref dst_subresource,
+ dst_offset: _,
+ extent: _,
+ _ne: _,
+ } = region;
+
+ [
+ (
+ ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Source,
+ secondary_use_ref: None,
+ },
+ Resource::Image {
+ image: src_image.clone(),
+ subresource_range: src_subresource.clone().into(),
+ memory: PipelineMemoryAccess {
+ stages: PipelineStages::ALL_TRANSFER,
+ access: AccessFlags::TRANSFER_READ,
+ exclusive: false,
+ },
+ start_layout: src_image_layout,
+ end_layout: src_image_layout,
+ },
+ ),
+ (
+ ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Destination,
+ secondary_use_ref: None,
+ },
+ Resource::Image {
+ image: dst_image.clone(),
+ subresource_range: dst_subresource.clone().into(),
+ memory: PipelineMemoryAccess {
+ stages: PipelineStages::ALL_TRANSFER,
+ access: AccessFlags::TRANSFER_WRITE,
+ exclusive: true,
+ },
+ start_layout: dst_image_layout,
+ end_layout: dst_image_layout,
+ },
+ ),
+ ]
+ })
+ .collect();
+
+ for resource in &resources {
+ self.check_resource_conflicts(resource)?;
+ }
+
+ self.commands.push(Box::new(Cmd { copy_image_info }));
+
+ for resource in resources {
+ self.add_resource(resource);
+ }
+
+ Ok(())
+ }
+
+ /// Calls `vkCmdCopyBufferToImage` on the builder.
+ ///
+ /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
+ /// usage of the command anyway.
+ #[inline]
+ pub unsafe fn copy_buffer_to_image(
+ &mut self,
+ copy_buffer_to_image_info: CopyBufferToImageInfo,
+ ) -> Result<(), SyncCommandBufferBuilderError> {
+ struct Cmd {
+ copy_buffer_to_image_info: CopyBufferToImageInfo,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "copy_buffer_to_image"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.copy_buffer_to_image(&self.copy_buffer_to_image_info);
+ }
+ }
+
+ let &CopyBufferToImageInfo {
+ ref src_buffer,
+ ref dst_image,
+ dst_image_layout,
+ ref regions,
+ _ne: _,
+ } = &copy_buffer_to_image_info;
+
+ let command_index = self.commands.len();
+ let command_name = "copy_buffer_to_image";
+ let resources: SmallVec<[_; 8]> = regions
+ .iter()
+ .flat_map(|region| {
+ let &BufferImageCopy {
+ buffer_offset,
+ buffer_row_length: _,
+ buffer_image_height: _,
+ ref image_subresource,
+ image_offset: _,
+ image_extent: _,
+ _ne: _,
+ } = region;
+
+ [
+ (
+ ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Source,
+ secondary_use_ref: None,
+ },
+ Resource::Buffer {
+ buffer: src_buffer.clone(),
+ range: buffer_offset
+ ..buffer_offset + region.buffer_copy_size(dst_image.format()),
+ memory: PipelineMemoryAccess {
+ stages: PipelineStages::ALL_TRANSFER,
+ access: AccessFlags::TRANSFER_READ,
+ exclusive: false,
+ },
+ },
+ ),
+ (
+ ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Destination,
+ secondary_use_ref: None,
+ },
+ Resource::Image {
+ image: dst_image.clone(),
+ subresource_range: image_subresource.clone().into(),
+ memory: PipelineMemoryAccess {
+ stages: PipelineStages::ALL_TRANSFER,
+ access: AccessFlags::TRANSFER_WRITE,
+ exclusive: true,
+ },
+ start_layout: dst_image_layout,
+ end_layout: dst_image_layout,
+ },
+ ),
+ ]
+ })
+ .collect();
+
+ for resource in &resources {
+ self.check_resource_conflicts(resource)?;
+ }
+
+ self.commands.push(Box::new(Cmd {
+ copy_buffer_to_image_info,
+ }));
+
+ for resource in resources {
+ self.add_resource(resource);
+ }
+
+ Ok(())
+ }
+
+ /// Calls `vkCmdCopyImageToBuffer` on the builder.
+ ///
+ /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
+ /// usage of the command anyway.
+ #[inline]
+ pub unsafe fn copy_image_to_buffer(
+ &mut self,
+ copy_image_to_buffer_info: CopyImageToBufferInfo,
+ ) -> Result<(), SyncCommandBufferBuilderError> {
+ struct Cmd {
+ copy_image_to_buffer_info: CopyImageToBufferInfo,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "copy_image_to_buffer"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.copy_image_to_buffer(&self.copy_image_to_buffer_info);
+ }
+ }
+
+ let &CopyImageToBufferInfo {
+ ref src_image,
+ src_image_layout,
+ ref dst_buffer,
+ ref regions,
+ _ne: _,
+ } = &copy_image_to_buffer_info;
+
+ let command_index = self.commands.len();
+ let command_name = "copy_image_to_buffer";
+ let resources: SmallVec<[_; 8]> = regions
+ .iter()
+ .flat_map(|region| {
+ let &BufferImageCopy {
+ buffer_offset,
+ buffer_row_length: _,
+ buffer_image_height: _,
+ ref image_subresource,
+ image_offset: _,
+ image_extent: _,
+ _ne: _,
+ } = region;
+
+ [
+ (
+ ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Source,
+ secondary_use_ref: None,
+ },
+ Resource::Image {
+ image: src_image.clone(),
+ subresource_range: image_subresource.clone().into(),
+ memory: PipelineMemoryAccess {
+ stages: PipelineStages::ALL_TRANSFER,
+ access: AccessFlags::TRANSFER_READ,
+ exclusive: false,
+ },
+ start_layout: src_image_layout,
+ end_layout: src_image_layout,
+ },
+ ),
+ (
+ ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Destination,
+ secondary_use_ref: None,
+ },
+ Resource::Buffer {
+ buffer: dst_buffer.clone(),
+ range: buffer_offset
+ ..buffer_offset + region.buffer_copy_size(src_image.format()),
+ memory: PipelineMemoryAccess {
+ stages: PipelineStages::ALL_TRANSFER,
+ access: AccessFlags::TRANSFER_WRITE,
+ exclusive: true,
+ },
+ },
+ ),
+ ]
+ })
+ .collect();
+
+ for resource in &resources {
+ self.check_resource_conflicts(resource)?;
+ }
+
+ self.commands.push(Box::new(Cmd {
+ copy_image_to_buffer_info,
+ }));
+
+ for resource in resources {
+ self.add_resource(resource);
+ }
+
+ Ok(())
+ }
+
+ /// Calls `vkCmdBlitImage` on the builder.
+ ///
+ /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
+ /// usage of the command anyway.
+ #[inline]
+ pub unsafe fn blit_image(
+ &mut self,
+ blit_image_info: BlitImageInfo,
+ ) -> Result<(), SyncCommandBufferBuilderError> {
+ struct Cmd {
+ blit_image_info: BlitImageInfo,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "blit_image"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.blit_image(&self.blit_image_info);
+ }
+ }
+
+ let &BlitImageInfo {
+ ref src_image,
+ src_image_layout,
+ ref dst_image,
+ dst_image_layout,
+ ref regions,
+ filter: _,
+ _ne: _,
+ } = &blit_image_info;
+
+ let command_index = self.commands.len();
+ let command_name = "blit_image";
+ let resources: SmallVec<[_; 8]> = regions
+ .iter()
+ .flat_map(|region| {
+ let &ImageBlit {
+ ref src_subresource,
+ src_offsets: _,
+ ref dst_subresource,
+ dst_offsets: _,
+ _ne: _,
+ } = region;
+
+ [
+ (
+ ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Source,
+ secondary_use_ref: None,
+ },
+ Resource::Image {
+ image: src_image.clone(),
+ subresource_range: src_subresource.clone().into(),
+ memory: PipelineMemoryAccess {
+ stages: PipelineStages::ALL_TRANSFER,
+ access: AccessFlags::TRANSFER_READ,
+ exclusive: false,
+ },
+ start_layout: src_image_layout,
+ end_layout: src_image_layout,
+ },
+ ),
+ (
+ ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Destination,
+ secondary_use_ref: None,
+ },
+ Resource::Image {
+ image: dst_image.clone(),
+ subresource_range: dst_subresource.clone().into(),
+ memory: PipelineMemoryAccess {
+ stages: PipelineStages::ALL_TRANSFER,
+ access: AccessFlags::TRANSFER_WRITE,
+ exclusive: true,
+ },
+ start_layout: dst_image_layout,
+ end_layout: dst_image_layout,
+ },
+ ),
+ ]
+ })
+ .collect();
+
+ for resource in &resources {
+ self.check_resource_conflicts(resource)?;
+ }
+
+ self.commands.push(Box::new(Cmd { blit_image_info }));
+
+ for resource in resources {
+ self.add_resource(resource);
+ }
+
+ Ok(())
+ }
+
+ /// Calls `vkCmdResolveImage` on the builder.
+ ///
+ /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
+ /// usage of the command anyway.
+ #[inline]
+ pub unsafe fn resolve_image(
+ &mut self,
+ resolve_image_info: ResolveImageInfo,
+ ) -> Result<(), SyncCommandBufferBuilderError> {
+ struct Cmd {
+ resolve_image_info: ResolveImageInfo,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "resolve_image"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.resolve_image(&self.resolve_image_info);
+ }
+ }
+
+ let &ResolveImageInfo {
+ ref src_image,
+ src_image_layout,
+ ref dst_image,
+ dst_image_layout,
+ ref regions,
+ _ne: _,
+ } = &resolve_image_info;
+
+ let command_index = self.commands.len();
+ let command_name = "resolve_image";
+ let resources: SmallVec<[_; 8]> = regions
+ .iter()
+ .flat_map(|region| {
+ let &ImageResolve {
+ ref src_subresource,
+ src_offset: _,
+ ref dst_subresource,
+ dst_offset: _,
+ extent: _,
+ _ne: _,
+ } = region;
+
+ [
+ (
+ ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Source,
+ secondary_use_ref: None,
+ },
+ Resource::Image {
+ image: src_image.clone(),
+ subresource_range: src_subresource.clone().into(),
+ memory: PipelineMemoryAccess {
+ stages: PipelineStages::ALL_TRANSFER,
+ access: AccessFlags::TRANSFER_READ,
+ exclusive: false,
+ },
+ start_layout: src_image_layout,
+ end_layout: src_image_layout,
+ },
+ ),
+ (
+ ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Destination,
+ secondary_use_ref: None,
+ },
+ Resource::Image {
+ image: dst_image.clone(),
+ subresource_range: dst_subresource.clone().into(),
+ memory: PipelineMemoryAccess {
+ stages: PipelineStages::ALL_TRANSFER,
+ access: AccessFlags::TRANSFER_WRITE,
+ exclusive: true,
+ },
+ start_layout: dst_image_layout,
+ end_layout: dst_image_layout,
+ },
+ ),
+ ]
+ })
+ .collect();
+
+ for resource in &resources {
+ self.check_resource_conflicts(resource)?;
+ }
+
+ self.commands.push(Box::new(Cmd { resolve_image_info }));
+
+ for resource in resources {
+ self.add_resource(resource);
+ }
+
+ Ok(())
+ }
+}
+
+impl UnsafeCommandBufferBuilder {
+ /// Calls `vkCmdCopyBuffer` on the builder.
+ ///
+ /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
+ /// usage of the command anyway.
+ #[inline]
+ pub unsafe fn copy_buffer(&mut self, copy_buffer_info: &CopyBufferInfo) {
+ let CopyBufferInfo {
+ src_buffer,
+ dst_buffer,
+ regions,
+ _ne: _,
+ } = copy_buffer_info;
+
+ if regions.is_empty() {
+ return;
+ }
+
+ let fns = self.device.fns();
+
+ if self.device.api_version() >= Version::V1_3
+ || self.device.enabled_extensions().khr_copy_commands2
+ {
+ let regions: SmallVec<[_; 8]> = regions
+ .iter()
+ .map(|region| {
+ let &BufferCopy {
+ src_offset,
+ dst_offset,
+ size,
+ _ne,
+ } = region;
+
+ ash::vk::BufferCopy2 {
+ src_offset: src_offset + src_buffer.offset(),
+ dst_offset: dst_offset + dst_buffer.offset(),
+ size,
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let copy_buffer_info = ash::vk::CopyBufferInfo2 {
+ src_buffer: src_buffer.buffer().handle(),
+ dst_buffer: dst_buffer.buffer().handle(),
+ region_count: regions.len() as u32,
+ p_regions: regions.as_ptr(),
+ ..Default::default()
+ };
+
+ if self.device.api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_copy_buffer2)(self.handle, &copy_buffer_info);
+ } else {
+ (fns.khr_copy_commands2.cmd_copy_buffer2_khr)(self.handle, &copy_buffer_info);
+ }
+ } else {
+ let regions: SmallVec<[_; 8]> = regions
+ .iter()
+ .map(|region| {
+ let &BufferCopy {
+ src_offset,
+ dst_offset,
+ size,
+ _ne,
+ } = region;
+
+ ash::vk::BufferCopy {
+ src_offset: src_offset + src_buffer.offset(),
+ dst_offset: dst_offset + dst_buffer.offset(),
+ size,
+ }
+ })
+ .collect();
+
+ (fns.v1_0.cmd_copy_buffer)(
+ self.handle,
+ src_buffer.buffer().handle(),
+ dst_buffer.buffer().handle(),
+ regions.len() as u32,
+ regions.as_ptr(),
+ );
+ }
+ }
+
+ /// Calls `vkCmdCopyImage` on the builder.
+ ///
+ /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
+ /// usage of the command anyway.
+ #[inline]
+ pub unsafe fn copy_image(&mut self, copy_image_info: &CopyImageInfo) {
+ let &CopyImageInfo {
+ ref src_image,
+ src_image_layout,
+ ref dst_image,
+ dst_image_layout,
+ ref regions,
+ _ne: _,
+ } = copy_image_info;
+
+ if regions.is_empty() {
+ return;
+ }
+
+ let src_image_inner = src_image.inner();
+ let dst_image_inner = dst_image.inner();
+
+ let fns = self.device.fns();
+
+ if self.device.api_version() >= Version::V1_3
+ || self.device.enabled_extensions().khr_copy_commands2
+ {
+ let regions: SmallVec<[_; 8]> = regions
+ .into_iter()
+ .map(|region| {
+ let &ImageCopy {
+ ref src_subresource,
+ src_offset,
+ ref dst_subresource,
+ dst_offset,
+ extent,
+ _ne: _,
+ } = region;
+
+ let mut src_subresource = src_subresource.clone();
+ src_subresource.array_layers.start += src_image_inner.first_layer;
+ src_subresource.array_layers.end += src_image_inner.first_layer;
+ src_subresource.mip_level += src_image_inner.first_mipmap_level;
+
+ let mut dst_subresource = dst_subresource.clone();
+ dst_subresource.array_layers.start += dst_image_inner.first_layer;
+ dst_subresource.array_layers.end += dst_image_inner.first_layer;
+ dst_subresource.mip_level += dst_image_inner.first_mipmap_level;
+
+ ash::vk::ImageCopy2 {
+ src_subresource: src_subresource.into(),
+ src_offset: ash::vk::Offset3D {
+ x: src_offset[0] as i32,
+ y: src_offset[1] as i32,
+ z: src_offset[2] as i32,
+ },
+ dst_subresource: dst_subresource.into(),
+ dst_offset: ash::vk::Offset3D {
+ x: dst_offset[0] as i32,
+ y: dst_offset[1] as i32,
+ z: dst_offset[2] as i32,
+ },
+ extent: ash::vk::Extent3D {
+ width: extent[0],
+ height: extent[1],
+ depth: extent[2],
+ },
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let copy_image_info = ash::vk::CopyImageInfo2 {
+ src_image: src_image_inner.image.handle(),
+ src_image_layout: src_image_layout.into(),
+ dst_image: dst_image_inner.image.handle(),
+ dst_image_layout: dst_image_layout.into(),
+ region_count: regions.len() as u32,
+ p_regions: regions.as_ptr(),
+ ..Default::default()
+ };
+
+ if self.device.api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_copy_image2)(self.handle, &copy_image_info);
+ } else {
+ (fns.khr_copy_commands2.cmd_copy_image2_khr)(self.handle, &copy_image_info);
+ }
+ } else {
+ let regions: SmallVec<[_; 8]> = regions
+ .into_iter()
+ .map(|region| {
+ let &ImageCopy {
+ ref src_subresource,
+ src_offset,
+ ref dst_subresource,
+ dst_offset,
+ extent,
+ _ne: _,
+ } = region;
+
+ let mut src_subresource = src_subresource.clone();
+ src_subresource.array_layers.start += src_image_inner.first_layer;
+ src_subresource.array_layers.end += src_image_inner.first_layer;
+ src_subresource.mip_level += src_image_inner.first_mipmap_level;
+
+ let mut dst_subresource = dst_subresource.clone();
+ dst_subresource.array_layers.start += dst_image_inner.first_layer;
+ dst_subresource.array_layers.end += dst_image_inner.first_layer;
+ dst_subresource.mip_level += dst_image_inner.first_mipmap_level;
+
+ ash::vk::ImageCopy {
+ src_subresource: src_subresource.into(),
+ src_offset: ash::vk::Offset3D {
+ x: src_offset[0] as i32,
+ y: src_offset[1] as i32,
+ z: src_offset[2] as i32,
+ },
+ dst_subresource: dst_subresource.into(),
+ dst_offset: ash::vk::Offset3D {
+ x: dst_offset[0] as i32,
+ y: dst_offset[1] as i32,
+ z: dst_offset[2] as i32,
+ },
+ extent: ash::vk::Extent3D {
+ width: extent[0],
+ height: extent[1],
+ depth: extent[2],
+ },
+ }
+ })
+ .collect();
+
+ (fns.v1_0.cmd_copy_image)(
+ self.handle,
+ src_image_inner.image.handle(),
+ src_image_layout.into(),
+ dst_image_inner.image.handle(),
+ dst_image_layout.into(),
+ regions.len() as u32,
+ regions.as_ptr(),
+ );
+ }
+ }
+
+ /// Calls `vkCmdCopyBufferToImage` on the builder.
+ ///
+ /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
+ /// usage of the command anyway.
+ #[inline]
+ pub unsafe fn copy_buffer_to_image(
+ &mut self,
+ copy_buffer_to_image_info: &CopyBufferToImageInfo,
+ ) {
+ let &CopyBufferToImageInfo {
+ ref src_buffer,
+ ref dst_image,
+ dst_image_layout,
+ ref regions,
+ _ne: _,
+ } = copy_buffer_to_image_info;
+
+ if regions.is_empty() {
+ return;
+ }
+
+ let dst_image_inner = dst_image.inner();
+
+ let fns = self.device.fns();
+
+ if self.device.api_version() >= Version::V1_3
+ || self.device.enabled_extensions().khr_copy_commands2
+ {
+ let regions: SmallVec<[_; 8]> = regions
+ .iter()
+ .map(|region| {
+ let &BufferImageCopy {
+ buffer_offset,
+ buffer_row_length,
+ buffer_image_height,
+ ref image_subresource,
+ image_offset,
+ image_extent,
+ _ne: _,
+ } = region;
+
+ let mut image_subresource = image_subresource.clone();
+ image_subresource.array_layers.start += dst_image_inner.first_layer;
+ image_subresource.array_layers.end += dst_image_inner.first_layer;
+ image_subresource.mip_level += dst_image_inner.first_mipmap_level;
+
+ ash::vk::BufferImageCopy2 {
+ buffer_offset: buffer_offset + src_buffer.offset(),
+ buffer_row_length,
+ buffer_image_height,
+ image_subresource: image_subresource.into(),
+ image_offset: ash::vk::Offset3D {
+ x: image_offset[0] as i32,
+ y: image_offset[1] as i32,
+ z: image_offset[2] as i32,
+ },
+ image_extent: ash::vk::Extent3D {
+ width: image_extent[0],
+ height: image_extent[1],
+ depth: image_extent[2],
+ },
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let copy_buffer_to_image_info = ash::vk::CopyBufferToImageInfo2 {
+ src_buffer: src_buffer.buffer().handle(),
+ dst_image: dst_image_inner.image.handle(),
+ dst_image_layout: dst_image_layout.into(),
+ region_count: regions.len() as u32,
+ p_regions: regions.as_ptr(),
+ ..Default::default()
+ };
+
+ if self.device.api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_copy_buffer_to_image2)(self.handle, &copy_buffer_to_image_info);
+ } else {
+ (fns.khr_copy_commands2.cmd_copy_buffer_to_image2_khr)(
+ self.handle,
+ &copy_buffer_to_image_info,
+ );
+ }
+ } else {
+ let regions: SmallVec<[_; 8]> = regions
+ .iter()
+ .map(|region| {
+ let &BufferImageCopy {
+ buffer_offset,
+ buffer_row_length,
+ buffer_image_height,
+ ref image_subresource,
+ image_offset,
+ image_extent,
+ _ne: _,
+ } = region;
+
+ let mut image_subresource = image_subresource.clone();
+ image_subresource.array_layers.start += dst_image_inner.first_layer;
+ image_subresource.array_layers.end += dst_image_inner.first_layer;
+ image_subresource.mip_level += dst_image_inner.first_mipmap_level;
+
+ ash::vk::BufferImageCopy {
+ buffer_offset: buffer_offset + src_buffer.offset(),
+ buffer_row_length,
+ buffer_image_height,
+ image_subresource: image_subresource.into(),
+ image_offset: ash::vk::Offset3D {
+ x: image_offset[0] as i32,
+ y: image_offset[1] as i32,
+ z: image_offset[2] as i32,
+ },
+ image_extent: ash::vk::Extent3D {
+ width: image_extent[0],
+ height: image_extent[1],
+ depth: image_extent[2],
+ },
+ }
+ })
+ .collect();
+
+ (fns.v1_0.cmd_copy_buffer_to_image)(
+ self.handle,
+ src_buffer.buffer().handle(),
+ dst_image_inner.image.handle(),
+ dst_image_layout.into(),
+ regions.len() as u32,
+ regions.as_ptr(),
+ );
+ }
+ }
+
+ /// Calls `vkCmdCopyImageToBuffer` on the builder.
+ ///
+ /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
+ /// usage of the command anyway.
+ #[inline]
+ pub unsafe fn copy_image_to_buffer(
+ &mut self,
+ copy_image_to_buffer_info: &CopyImageToBufferInfo,
+ ) {
+ let &CopyImageToBufferInfo {
+ ref src_image,
+ src_image_layout,
+ ref dst_buffer,
+ ref regions,
+ _ne: _,
+ } = copy_image_to_buffer_info;
+
+ if regions.is_empty() {
+ return;
+ }
+
+ let src_image_inner = src_image.inner();
+
+ let fns = self.device.fns();
+
+ if self.device.api_version() >= Version::V1_3
+ || self.device.enabled_extensions().khr_copy_commands2
+ {
+ let regions: SmallVec<[_; 8]> = regions
+ .iter()
+ .map(|region| {
+ let &BufferImageCopy {
+ buffer_offset,
+ buffer_row_length,
+ buffer_image_height,
+ ref image_subresource,
+ image_offset,
+ image_extent,
+ _ne: _,
+ } = region;
+
+ let mut image_subresource = image_subresource.clone();
+ image_subresource.array_layers.start += src_image_inner.first_layer;
+ image_subresource.array_layers.end += src_image_inner.first_layer;
+ image_subresource.mip_level += src_image_inner.first_mipmap_level;
+
+ ash::vk::BufferImageCopy2 {
+ buffer_offset: buffer_offset + dst_buffer.offset(),
+ buffer_row_length,
+ buffer_image_height,
+ image_subresource: image_subresource.into(),
+ image_offset: ash::vk::Offset3D {
+ x: image_offset[0] as i32,
+ y: image_offset[1] as i32,
+ z: image_offset[2] as i32,
+ },
+ image_extent: ash::vk::Extent3D {
+ width: image_extent[0],
+ height: image_extent[1],
+ depth: image_extent[2],
+ },
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let copy_image_to_buffer_info = ash::vk::CopyImageToBufferInfo2 {
+ src_image: src_image_inner.image.handle(),
+ src_image_layout: src_image_layout.into(),
+ dst_buffer: dst_buffer.buffer().handle(),
+ region_count: regions.len() as u32,
+ p_regions: regions.as_ptr(),
+ ..Default::default()
+ };
+
+ if self.device.api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_copy_image_to_buffer2)(self.handle, &copy_image_to_buffer_info);
+ } else {
+ (fns.khr_copy_commands2.cmd_copy_image_to_buffer2_khr)(
+ self.handle,
+ &copy_image_to_buffer_info,
+ );
+ }
+ } else {
+ let regions: SmallVec<[_; 8]> = regions
+ .iter()
+ .map(|region| {
+ let &BufferImageCopy {
+ buffer_offset,
+ buffer_row_length,
+ buffer_image_height,
+ ref image_subresource,
+ image_offset,
+ image_extent,
+ _ne: _,
+ } = region;
+ let mut image_subresource = image_subresource.clone();
+ image_subresource.array_layers.start += src_image_inner.first_layer;
+ image_subresource.array_layers.end += src_image_inner.first_layer;
+ image_subresource.mip_level += src_image_inner.first_mipmap_level;
+
+ ash::vk::BufferImageCopy {
+ buffer_offset: buffer_offset + dst_buffer.offset(),
+ buffer_row_length,
+ buffer_image_height,
+ image_subresource: image_subresource.into(),
+ image_offset: ash::vk::Offset3D {
+ x: image_offset[0] as i32,
+ y: image_offset[1] as i32,
+ z: image_offset[2] as i32,
+ },
+ image_extent: ash::vk::Extent3D {
+ width: image_extent[0],
+ height: image_extent[1],
+ depth: image_extent[2],
+ },
+ }
+ })
+ .collect();
+
+ (fns.v1_0.cmd_copy_image_to_buffer)(
+ self.handle,
+ src_image_inner.image.handle(),
+ src_image_layout.into(),
+ dst_buffer.buffer().handle(),
+ regions.len() as u32,
+ regions.as_ptr(),
+ );
+ }
+ }
+
+ /// Calls `vkCmdBlitImage` on the builder.
+ ///
+ /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
+ /// usage of the command anyway.
+ #[inline]
+ pub unsafe fn blit_image(&mut self, blit_image_info: &BlitImageInfo) {
+ let &BlitImageInfo {
+ ref src_image,
+ src_image_layout,
+ ref dst_image,
+ dst_image_layout,
+ ref regions,
+ filter,
+ _ne,
+ } = blit_image_info;
+
+ if regions.is_empty() {
+ return;
+ }
+
+ let src_image_inner = src_image.inner();
+ let dst_image_inner = dst_image.inner();
+
+ let fns = self.device.fns();
+
+ if self.device.api_version() >= Version::V1_3
+ || self.device.enabled_extensions().khr_copy_commands2
+ {
+ let regions: SmallVec<[_; 8]> = regions
+ .into_iter()
+ .map(|region| {
+ let &ImageBlit {
+ ref src_subresource,
+ src_offsets,
+ ref dst_subresource,
+ dst_offsets,
+ _ne: _,
+ } = region;
+
+ let mut src_subresource = src_subresource.clone();
+ src_subresource.array_layers.start += src_image_inner.first_layer;
+ src_subresource.array_layers.end += src_image_inner.first_layer;
+ src_subresource.mip_level += src_image_inner.first_mipmap_level;
+
+ let mut dst_subresource = dst_subresource.clone();
+ dst_subresource.array_layers.start += dst_image_inner.first_layer;
+ dst_subresource.array_layers.end += dst_image_inner.first_layer;
+ dst_subresource.mip_level += dst_image_inner.first_mipmap_level;
+
+ ash::vk::ImageBlit2 {
+ src_subresource: src_subresource.into(),
+ src_offsets: [
+ ash::vk::Offset3D {
+ x: src_offsets[0][0] as i32,
+ y: src_offsets[0][1] as i32,
+ z: src_offsets[0][2] as i32,
+ },
+ ash::vk::Offset3D {
+ x: src_offsets[1][0] as i32,
+ y: src_offsets[1][1] as i32,
+ z: src_offsets[1][2] as i32,
+ },
+ ],
+ dst_subresource: dst_subresource.into(),
+ dst_offsets: [
+ ash::vk::Offset3D {
+ x: dst_offsets[0][0] as i32,
+ y: dst_offsets[0][1] as i32,
+ z: dst_offsets[0][2] as i32,
+ },
+ ash::vk::Offset3D {
+ x: dst_offsets[1][0] as i32,
+ y: dst_offsets[1][1] as i32,
+ z: dst_offsets[1][2] as i32,
+ },
+ ],
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let blit_image_info = ash::vk::BlitImageInfo2 {
+ src_image: src_image_inner.image.handle(),
+ src_image_layout: src_image_layout.into(),
+ dst_image: dst_image_inner.image.handle(),
+ dst_image_layout: dst_image_layout.into(),
+ region_count: regions.len() as u32,
+ p_regions: regions.as_ptr(),
+ filter: filter.into(),
+ ..Default::default()
+ };
+
+ if self.device.api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_blit_image2)(self.handle, &blit_image_info);
+ } else {
+ (fns.khr_copy_commands2.cmd_blit_image2_khr)(self.handle, &blit_image_info);
+ }
+ } else {
+ let regions: SmallVec<[_; 8]> = regions
+ .into_iter()
+ .map(|region| {
+ let &ImageBlit {
+ ref src_subresource,
+ src_offsets,
+ ref dst_subresource,
+ dst_offsets,
+ _ne: _,
+ } = region;
+
+ let mut src_subresource = src_subresource.clone();
+ src_subresource.array_layers.start += src_image_inner.first_layer;
+ src_subresource.array_layers.end += src_image_inner.first_layer;
+ src_subresource.mip_level += src_image_inner.first_mipmap_level;
+
+ let mut dst_subresource = dst_subresource.clone();
+ dst_subresource.array_layers.start += dst_image_inner.first_layer;
+ dst_subresource.array_layers.end += dst_image_inner.first_layer;
+ dst_subresource.mip_level += dst_image_inner.first_mipmap_level;
+
+ ash::vk::ImageBlit {
+ src_subresource: src_subresource.into(),
+ src_offsets: [
+ ash::vk::Offset3D {
+ x: src_offsets[0][0] as i32,
+ y: src_offsets[0][1] as i32,
+ z: src_offsets[0][2] as i32,
+ },
+ ash::vk::Offset3D {
+ x: src_offsets[1][0] as i32,
+ y: src_offsets[1][1] as i32,
+ z: src_offsets[1][2] as i32,
+ },
+ ],
+ dst_subresource: dst_subresource.into(),
+ dst_offsets: [
+ ash::vk::Offset3D {
+ x: dst_offsets[0][0] as i32,
+ y: dst_offsets[0][1] as i32,
+ z: dst_offsets[0][2] as i32,
+ },
+ ash::vk::Offset3D {
+ x: dst_offsets[1][0] as i32,
+ y: dst_offsets[1][1] as i32,
+ z: dst_offsets[1][2] as i32,
+ },
+ ],
+ }
+ })
+ .collect();
+
+ (fns.v1_0.cmd_blit_image)(
+ self.handle,
+ src_image_inner.image.handle(),
+ src_image_layout.into(),
+ dst_image_inner.image.handle(),
+ dst_image_layout.into(),
+ regions.len() as u32,
+ regions.as_ptr(),
+ filter.into(),
+ );
+ }
+ }
+
+ /// Calls `vkCmdResolveImage` on the builder.
+ ///
+ /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
+ /// usage of the command anyway.
+ #[inline]
+ pub unsafe fn resolve_image(&mut self, resolve_image_info: &ResolveImageInfo) {
+ let &ResolveImageInfo {
+ ref src_image,
+ src_image_layout,
+ ref dst_image,
+ dst_image_layout,
+ ref regions,
+ _ne: _,
+ } = resolve_image_info;
+
+ if regions.is_empty() {
+ return;
+ }
+
+ let src_image_inner = src_image.inner();
+ let dst_image_inner = dst_image.inner();
+
+ let fns = self.device.fns();
+
+ if self.device.api_version() >= Version::V1_3
+ || self.device.enabled_extensions().khr_copy_commands2
+ {
+ let regions: SmallVec<[_; 8]> = regions
+ .into_iter()
+ .map(|region| {
+ let &ImageResolve {
+ ref src_subresource,
+ src_offset,
+ ref dst_subresource,
+ dst_offset,
+ extent,
+ _ne: _,
+ } = region;
+
+ let mut src_subresource = src_subresource.clone();
+ src_subresource.array_layers.start += src_image_inner.first_layer;
+ src_subresource.array_layers.end += src_image_inner.first_layer;
+ src_subresource.mip_level += src_image_inner.first_mipmap_level;
+
+ let mut dst_subresource = dst_subresource.clone();
+ dst_subresource.array_layers.start += dst_image_inner.first_layer;
+ dst_subresource.array_layers.end += dst_image_inner.first_layer;
+ dst_subresource.mip_level += dst_image_inner.first_mipmap_level;
+
+ ash::vk::ImageResolve2 {
+ src_subresource: src_subresource.into(),
+ src_offset: ash::vk::Offset3D {
+ x: src_offset[0] as i32,
+ y: src_offset[1] as i32,
+ z: src_offset[2] as i32,
+ },
+ dst_subresource: dst_subresource.into(),
+ dst_offset: ash::vk::Offset3D {
+ x: dst_offset[0] as i32,
+ y: dst_offset[1] as i32,
+ z: dst_offset[2] as i32,
+ },
+ extent: ash::vk::Extent3D {
+ width: extent[0],
+ height: extent[1],
+ depth: extent[2],
+ },
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let resolve_image_info = ash::vk::ResolveImageInfo2 {
+ src_image: src_image_inner.image.handle(),
+ src_image_layout: src_image_layout.into(),
+ dst_image: dst_image_inner.image.handle(),
+ dst_image_layout: dst_image_layout.into(),
+ region_count: regions.len() as u32,
+ p_regions: regions.as_ptr(),
+ ..Default::default()
+ };
+
+ if self.device.api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_resolve_image2)(self.handle, &resolve_image_info);
+ } else {
+ (fns.khr_copy_commands2.cmd_resolve_image2_khr)(self.handle, &resolve_image_info);
+ }
+ } else {
+ let regions: SmallVec<[_; 8]> = regions
+ .into_iter()
+ .map(|region| {
+ let &ImageResolve {
+ ref src_subresource,
+ src_offset,
+ ref dst_subresource,
+ dst_offset,
+ extent,
+ _ne: _,
+ } = region;
+
+ let mut src_subresource = src_subresource.clone();
+ src_subresource.array_layers.start += src_image_inner.first_layer;
+ src_subresource.array_layers.end += src_image_inner.first_layer;
+ src_subresource.mip_level += src_image_inner.first_mipmap_level;
+
+ let mut dst_subresource = dst_subresource.clone();
+ dst_subresource.array_layers.start += dst_image_inner.first_layer;
+ dst_subresource.array_layers.end += dst_image_inner.first_layer;
+ dst_subresource.mip_level += dst_image_inner.first_mipmap_level;
+
+ ash::vk::ImageResolve {
+ src_subresource: src_subresource.into(),
+ src_offset: ash::vk::Offset3D {
+ x: src_offset[0] as i32,
+ y: src_offset[1] as i32,
+ z: src_offset[2] as i32,
+ },
+ dst_subresource: dst_subresource.into(),
+ dst_offset: ash::vk::Offset3D {
+ x: dst_offset[0] as i32,
+ y: dst_offset[1] as i32,
+ z: dst_offset[2] as i32,
+ },
+ extent: ash::vk::Extent3D {
+ width: extent[0],
+ height: extent[1],
+ depth: extent[2],
+ },
+ }
+ })
+ .collect();
+
+ (fns.v1_0.cmd_resolve_image)(
+ self.handle,
+ src_image_inner.image.handle(),
+ src_image_layout.into(),
+ dst_image_inner.image.handle(),
+ dst_image_layout.into(),
+ regions.len() as u32,
+ regions.as_ptr(),
+ );
+ }
+ }
+}
+
+/// Parameters to copy data from a buffer to another buffer.
+///
+/// The fields of `regions` represent bytes.
+#[derive(Clone, Debug)]
+pub struct CopyBufferInfo {
+ /// The buffer to copy from.
+ ///
+ /// There is no default value.
+ pub src_buffer: Subbuffer<[u8]>,
+
+ /// The buffer to copy to.
+ ///
+ /// There is no default value.
+ pub dst_buffer: Subbuffer<[u8]>,
+
+ /// The regions of both buffers to copy between, specified in bytes.
+ ///
+ /// The default value is a single region, with zero offsets and a `size` equal to the smallest
+ /// of the two buffers.
+ pub regions: SmallVec<[BufferCopy; 1]>,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl CopyBufferInfo {
+ /// Returns a `CopyBufferInfo` with the specified `src_buffer` and `dst_buffer`.
+ #[inline]
+ pub fn buffers(src_buffer: Subbuffer<impl ?Sized>, dst_buffer: Subbuffer<impl ?Sized>) -> Self {
+ let region = BufferCopy {
+ src_offset: 0,
+ dst_offset: 0,
+ size: min(src_buffer.size(), dst_buffer.size()),
+ ..Default::default()
+ };
+
+ Self {
+ src_buffer: src_buffer.into_bytes(),
+ dst_buffer: dst_buffer.into_bytes(),
+ regions: smallvec![region],
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// Parameters to copy data from a buffer to another buffer, with type information.
+///
+/// The fields of `regions` represent elements of `T`.
+#[derive(Clone, Debug)]
+pub struct CopyBufferInfoTyped<T> {
+ /// The buffer to copy from.
+ ///
+ /// There is no default value.
+ pub src_buffer: Subbuffer<[T]>,
+
+ /// The buffer to copy to.
+ ///
+ /// There is no default value.
+ pub dst_buffer: Subbuffer<[T]>,
+
+ /// The regions of both buffers to copy between, specified in elements of `T`.
+ ///
+ /// The default value is a single region, with zero offsets and a `size` equal to the smallest
+ /// of the two buffers.
+ pub regions: SmallVec<[BufferCopy; 1]>,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl<T> CopyBufferInfoTyped<T> {
+ /// Returns a `CopyBufferInfoTyped` with the specified `src_buffer` and `dst_buffer`.
+ pub fn buffers(src_buffer: Subbuffer<[T]>, dst_buffer: Subbuffer<[T]>) -> Self {
+ let region = BufferCopy {
+ size: min(src_buffer.len(), dst_buffer.len()),
+ ..Default::default()
+ };
+
+ Self {
+ src_buffer,
+ dst_buffer,
+ regions: smallvec![region],
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+impl<T> From<CopyBufferInfoTyped<T>> for CopyBufferInfo {
+ fn from(typed: CopyBufferInfoTyped<T>) -> Self {
+ let CopyBufferInfoTyped {
+ src_buffer,
+ dst_buffer,
+ mut regions,
+ _ne: _,
+ } = typed;
+
+ for region in &mut regions {
+ region.src_offset *= size_of::<T>() as DeviceSize;
+ region.dst_offset *= size_of::<T>() as DeviceSize;
+ region.size *= size_of::<T>() as DeviceSize;
+ }
+
+ Self {
+ src_buffer: src_buffer.as_bytes().clone(),
+ dst_buffer: dst_buffer.as_bytes().clone(),
+ regions,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// A region of data to copy between buffers.
+#[derive(Clone, Debug)]
+pub struct BufferCopy {
+ /// The offset in bytes or elements from the start of `src_buffer` that copying will
+ /// start from.
+ ///
+ /// The default value is `0`.
+ pub src_offset: DeviceSize,
+
+ /// The offset in bytes or elements from the start of `dst_buffer` that copying will
+ /// start from.
+ ///
+ /// The default value is `0`.
+ pub dst_offset: DeviceSize,
+
+ /// The number of bytes or elements to copy.
+ ///
+ /// The default value is `0`, which must be overridden.
+ pub size: DeviceSize,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for BufferCopy {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ src_offset: 0,
+ dst_offset: 0,
+ size: 0,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// Parameters to copy data from an image to another image.
+#[derive(Clone, Debug)]
+pub struct CopyImageInfo {
+ /// The image to copy from.
+ ///
+ /// There is no default value.
+ pub src_image: Arc<dyn ImageAccess>,
+
+ /// The layout used for `src_image` during the copy operation.
+ ///
+ /// The following layouts are allowed:
+ /// - [`ImageLayout::TransferSrcOptimal`]
+ /// - [`ImageLayout::General`]
+ ///
+ /// The default value is [`ImageLayout::TransferSrcOptimal`].
+ pub src_image_layout: ImageLayout,
+
+ /// The image to copy to.
+ ///
+ /// There is no default value.
+ pub dst_image: Arc<dyn ImageAccess>,
+
+ /// The layout used for `dst_image` during the copy operation.
+ ///
+ /// The following layouts are allowed:
+ /// - [`ImageLayout::TransferDstOptimal`]
+ /// - [`ImageLayout::General`]
+ ///
+ /// The default value is [`ImageLayout::TransferDstOptimal`].
+ pub dst_image_layout: ImageLayout,
+
+ /// The regions of both images to copy between.
+ ///
+ /// The default value is a single region, covering the first mip level, and the smallest of the
+ /// array layers and extent of the two images. All aspects of each image are selected, or
+ /// `plane0` if the image is multi-planar.
+ pub regions: SmallVec<[ImageCopy; 1]>,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl CopyImageInfo {
+ /// Returns a `CopyImageInfo` with the specified `src_image` and `dst_image`.
+ #[inline]
+ pub fn images(src_image: Arc<dyn ImageAccess>, dst_image: Arc<dyn ImageAccess>) -> Self {
+ let min_array_layers = src_image
+ .dimensions()
+ .array_layers()
+ .min(dst_image.dimensions().array_layers());
+ let region = ImageCopy {
+ src_subresource: ImageSubresourceLayers {
+ array_layers: 0..min_array_layers,
+ ..src_image.subresource_layers()
+ },
+ dst_subresource: ImageSubresourceLayers {
+ array_layers: 0..min_array_layers,
+ ..dst_image.subresource_layers()
+ },
+ extent: {
+ let src_extent = src_image.dimensions().width_height_depth();
+ let dst_extent = dst_image.dimensions().width_height_depth();
+
+ [
+ src_extent[0].min(dst_extent[0]),
+ src_extent[1].min(dst_extent[1]),
+ src_extent[2].min(dst_extent[2]),
+ ]
+ },
+ ..Default::default()
+ };
+
+ Self {
+ src_image,
+ src_image_layout: ImageLayout::TransferSrcOptimal,
+ dst_image,
+ dst_image_layout: ImageLayout::TransferDstOptimal,
+ regions: smallvec![region],
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// A region of data to copy between images.
+#[derive(Clone, Debug)]
+pub struct ImageCopy {
+ /// The subresource of `src_image` to copy from.
+ ///
+ /// The default value is empty, which must be overridden.
+ pub src_subresource: ImageSubresourceLayers,
+
+ /// The offset from the zero coordinate of `src_image` that copying will start from.
+ ///
+ /// The default value is `[0; 3]`.
+ pub src_offset: [u32; 3],
+
+ /// The subresource of `dst_image` to copy to.
+ ///
+ /// The default value is empty, which must be overridden.
+ pub dst_subresource: ImageSubresourceLayers,
+
+ /// The offset from the zero coordinate of `dst_image` that copying will start from.
+ ///
+ /// The default value is `[0; 3]`.
+ pub dst_offset: [u32; 3],
+
+ /// The extent of texels to copy.
+ ///
+ /// The default value is `[0; 3]`, which must be overridden.
+ pub extent: [u32; 3],
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for ImageCopy {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ src_subresource: ImageSubresourceLayers {
+ aspects: ImageAspects::empty(),
+ mip_level: 0,
+ array_layers: 0..0,
+ },
+ src_offset: [0; 3],
+ dst_subresource: ImageSubresourceLayers {
+ aspects: ImageAspects::empty(),
+ mip_level: 0,
+ array_layers: 0..0,
+ },
+ dst_offset: [0; 3],
+ extent: [0; 3],
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// Parameters to copy data from a buffer to an image.
+#[derive(Clone, Debug)]
+pub struct CopyBufferToImageInfo {
+ /// The buffer to copy from.
+ ///
+ /// There is no default value.
+ pub src_buffer: Subbuffer<[u8]>,
+
+ /// The image to copy to.
+ ///
+ /// There is no default value.
+ pub dst_image: Arc<dyn ImageAccess>,
+
+ /// The layout used for `dst_image` during the copy operation.
+ ///
+ /// The following layouts are allowed:
+ /// - [`ImageLayout::TransferDstOptimal`]
+ /// - [`ImageLayout::General`]
+ ///
+ /// The default value is [`ImageLayout::TransferDstOptimal`].
+ pub dst_image_layout: ImageLayout,
+
+ /// The regions of the buffer and image to copy between.
+ ///
+ /// The default value is a single region, covering all of the buffer and the first mip level of
+ /// the image. All aspects of the image are selected, or `plane0` if the image is multi-planar.
+ pub regions: SmallVec<[BufferImageCopy; 1]>,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl CopyBufferToImageInfo {
+ /// Returns a `CopyBufferToImageInfo` with the specified `src_buffer` and
+ /// `dst_image`.
+ #[inline]
+ pub fn buffer_image(
+ src_buffer: Subbuffer<impl ?Sized>,
+ dst_image: Arc<dyn ImageAccess>,
+ ) -> Self {
+ let region = BufferImageCopy {
+ image_subresource: dst_image.subresource_layers(),
+ image_extent: dst_image.dimensions().width_height_depth(),
+ ..Default::default()
+ };
+
+ Self {
+ src_buffer: src_buffer.into_bytes(),
+ dst_image,
+ dst_image_layout: ImageLayout::TransferDstOptimal,
+ regions: smallvec![region],
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// Parameters to copy data from an image to a buffer.
+#[derive(Clone, Debug)]
+pub struct CopyImageToBufferInfo {
+ /// The image to copy from.
+ ///
+ /// There is no default value.
+ pub src_image: Arc<dyn ImageAccess>,
+
+ /// The layout used for `src_image` during the copy operation.
+ ///
+ /// The following layouts are allowed:
+ /// - [`ImageLayout::TransferSrcOptimal`]
+ /// - [`ImageLayout::General`]
+ ///
+ /// The default value is [`ImageLayout::TransferSrcOptimal`].
+ pub src_image_layout: ImageLayout,
+
+ /// The buffer to copy to.
+ ///
+ /// There is no default value.
+ pub dst_buffer: Subbuffer<[u8]>,
+
+ /// The regions of the image and buffer to copy between.
+ ///
+ /// The default value is a single region, covering all of the buffer and the first mip level of
+ /// the image. All aspects of the image are selected, or `plane0` if the image is multi-planar.
+ pub regions: SmallVec<[BufferImageCopy; 1]>,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl CopyImageToBufferInfo {
+ /// Returns a `CopyImageToBufferInfo` with the specified `src_image` and
+ /// `dst_buffer`.
+ #[inline]
+ pub fn image_buffer(
+ src_image: Arc<dyn ImageAccess>,
+ dst_buffer: Subbuffer<impl ?Sized>,
+ ) -> Self {
+ let region = BufferImageCopy {
+ image_subresource: src_image.subresource_layers(),
+ image_extent: src_image.dimensions().width_height_depth(),
+ ..Default::default()
+ };
+
+ Self {
+ src_image,
+ src_image_layout: ImageLayout::TransferSrcOptimal,
+ dst_buffer: dst_buffer.into_bytes(),
+ regions: smallvec![region],
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// A region of data to copy between a buffer and an image.
+#[derive(Clone, Debug)]
+pub struct BufferImageCopy {
+ /// The offset in bytes from the start of the buffer that copying will start from.
+ ///
+ /// The default value is `0`.
+ pub buffer_offset: DeviceSize,
+
+ /// The number of texels between successive rows of image data in the buffer.
+ ///
+ /// If set to `0`, the width of the image is used.
+ ///
+ /// The default value is `0`.
+ pub buffer_row_length: u32,
+
+ /// The number of rows between successive depth slices of image data in the buffer.
+ ///
+ /// If set to `0`, the height of the image is used.
+ ///
+ /// The default value is `0`.
+ pub buffer_image_height: u32,
+
+ /// The subresource of the image to copy from/to.
+ ///
+ /// The default value is empty, which must be overridden.
+ pub image_subresource: ImageSubresourceLayers,
+
+ /// The offset from the zero coordinate of the image that copying will start from.
+ ///
+ /// The default value is `[0; 3]`.
+ pub image_offset: [u32; 3],
+
+ /// The extent of texels in the image to copy.
+ ///
+ /// The default value is `[0; 3]`, which must be overridden.
+ pub image_extent: [u32; 3],
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for BufferImageCopy {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ buffer_offset: 0,
+ buffer_row_length: 0,
+ buffer_image_height: 0,
+ image_subresource: ImageSubresourceLayers {
+ aspects: ImageAspects::empty(),
+ mip_level: 0,
+ array_layers: 0..0,
+ },
+ image_offset: [0; 3],
+ image_extent: [0; 3],
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+impl BufferImageCopy {
+ // Following
+ // https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap20.html#copies-buffers-images-addressing
+ pub(crate) fn buffer_copy_size(&self, format: Format) -> DeviceSize {
+ let &BufferImageCopy {
+ buffer_offset: _,
+ mut buffer_row_length,
+ mut buffer_image_height,
+ ref image_subresource,
+ image_offset: _,
+ mut image_extent,
+ _ne: _,
+ } = self;
+
+ if buffer_row_length == 0 {
+ buffer_row_length = image_extent[0];
+ }
+
+ if buffer_image_height == 0 {
+ buffer_image_height = image_extent[1];
+ }
+
+ // Scale down from texels to texel blocks, rounding up if needed.
+ let block_extent = format.block_extent();
+ buffer_row_length = (buffer_row_length + block_extent[0] - 1) / block_extent[0];
+ buffer_image_height = (buffer_image_height + block_extent[1] - 1) / block_extent[1];
+
+ for i in 0..3 {
+ image_extent[i] = (image_extent[i] + block_extent[i] - 1) / block_extent[i];
+ }
+
+ // Only one of these is greater than 1, take the greater number.
+ image_extent[2] = max(
+ image_extent[2],
+ image_subresource.array_layers.end - image_subresource.array_layers.start,
+ );
+
+ let blocks_to_last_slice = (image_extent[2] as DeviceSize - 1)
+ * buffer_image_height as DeviceSize
+ * buffer_row_length as DeviceSize;
+ let blocks_to_last_row =
+ (image_extent[1] as DeviceSize - 1) * buffer_row_length as DeviceSize;
+ let num_blocks = blocks_to_last_slice + blocks_to_last_row + image_extent[0] as DeviceSize;
+
+ // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkBufferImageCopy.html#_description
+ let block_size = if image_subresource.aspects.intersects(ImageAspects::STENCIL) {
+ 1
+ } else if image_subresource.aspects.intersects(ImageAspects::DEPTH) {
+ match format {
+ Format::D16_UNORM | Format::D16_UNORM_S8_UINT => 2,
+ Format::D32_SFLOAT
+ | Format::D32_SFLOAT_S8_UINT
+ | Format::X8_D24_UNORM_PACK32
+ | Format::D24_UNORM_S8_UINT => 4,
+ _ => unreachable!(),
+ }
+ } else {
+ format.block_size().unwrap()
+ };
+
+ num_blocks * block_size
+ }
+}
+
+/// Parameters to blit image data.
+#[derive(Clone, Debug)]
+pub struct BlitImageInfo {
+ /// The image to blit from.
+ ///
+ /// There is no default value.
+ pub src_image: Arc<dyn ImageAccess>,
+
+ /// The layout used for `src_image` during the blit operation.
+ ///
+ /// The following layouts are allowed:
+ /// - [`ImageLayout::TransferSrcOptimal`]
+ /// - [`ImageLayout::General`]
+ ///
+ /// The default value is [`ImageLayout::TransferSrcOptimal`].
+ pub src_image_layout: ImageLayout,
+
+ /// The image to blit to.
+ ///
+ /// There is no default value.
+ pub dst_image: Arc<dyn ImageAccess>,
+
+ /// The layout used for `dst_image` during the blit operation.
+ ///
+ /// The following layouts are allowed:
+ /// - [`ImageLayout::TransferDstOptimal`]
+ /// - [`ImageLayout::General`]
+ ///
+ /// The default value is [`ImageLayout::TransferDstOptimal`].
+ pub dst_image_layout: ImageLayout,
+
+ /// The regions of both images to blit between.
+ ///
+ /// The default value is a single region, covering the first mip level, and the smallest of the
+ /// array layers of the two images. The whole extent of each image is covered, scaling if
+ /// necessary. All aspects of each image are selected, or `plane0` if the image is multi-planar.
+ pub regions: SmallVec<[ImageBlit; 1]>,
+
+ /// The filter to use for sampling `src_image` when the `src_extent` and
+ /// `dst_extent` of a region are not the same size.
+ ///
+ /// The default value is [`Filter::Nearest`].
+ pub filter: Filter,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl BlitImageInfo {
+ /// Returns a `BlitImageInfo` with the specified `src_image` and `dst_image`.
+ #[inline]
+ pub fn images(src_image: Arc<dyn ImageAccess>, dst_image: Arc<dyn ImageAccess>) -> Self {
+ let min_array_layers = src_image
+ .dimensions()
+ .array_layers()
+ .min(dst_image.dimensions().array_layers());
+ let region = ImageBlit {
+ src_subresource: ImageSubresourceLayers {
+ array_layers: 0..min_array_layers,
+ ..src_image.subresource_layers()
+ },
+ src_offsets: [[0; 3], src_image.dimensions().width_height_depth()],
+ dst_subresource: ImageSubresourceLayers {
+ array_layers: 0..min_array_layers,
+ ..dst_image.subresource_layers()
+ },
+ dst_offsets: [[0; 3], dst_image.dimensions().width_height_depth()],
+ ..Default::default()
+ };
+
+ Self {
+ src_image,
+ src_image_layout: ImageLayout::TransferSrcOptimal,
+ dst_image,
+ dst_image_layout: ImageLayout::TransferDstOptimal,
+ regions: smallvec![region],
+ filter: Filter::Nearest,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// A region of data to blit between images.
+#[derive(Clone, Debug)]
+pub struct ImageBlit {
+ /// The subresource of `src_image` to blit from.
+ ///
+ /// The default value is empty, which must be overridden.
+ pub src_subresource: ImageSubresourceLayers,
+
+ /// The offsets from the zero coordinate of `src_image`, defining two corners of the region
+ /// to blit from.
+ /// If the ordering of the two offsets differs between source and destination, the image will
+ /// be flipped.
+ ///
+ /// The default value is `[[0; 3]; 2]`, which must be overridden.
+ pub src_offsets: [[u32; 3]; 2],
+
+ /// The subresource of `dst_image` to blit to.
+ ///
+ /// The default value is empty, which must be overridden.
+ pub dst_subresource: ImageSubresourceLayers,
+
+ /// The offset from the zero coordinate of `dst_image` defining two corners of the
+ /// region to blit to.
+ /// If the ordering of the two offsets differs between source and destination, the image will
+ /// be flipped.
+ ///
+ /// The default value is `[[0; 3]; 2]`, which must be overridden.
+ pub dst_offsets: [[u32; 3]; 2],
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for ImageBlit {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ src_subresource: ImageSubresourceLayers {
+ aspects: ImageAspects::empty(),
+ mip_level: 0,
+ array_layers: 0..0,
+ },
+ src_offsets: [[0; 3]; 2],
+ dst_subresource: ImageSubresourceLayers {
+ aspects: ImageAspects::empty(),
+ mip_level: 0,
+ array_layers: 0..0,
+ },
+ dst_offsets: [[0; 3]; 2],
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// Parameters to resolve image data.
+#[derive(Clone, Debug)]
+pub struct ResolveImageInfo {
+ /// The multisampled image to resolve from.
+ ///
+ /// There is no default value.
+ pub src_image: Arc<dyn ImageAccess>,
+
+ /// The layout used for `src_image` during the resolve operation.
+ ///
+ /// The following layouts are allowed:
+ /// - [`ImageLayout::TransferSrcOptimal`]
+ /// - [`ImageLayout::General`]
+ ///
+ /// The default value is [`ImageLayout::TransferSrcOptimal`].
+ pub src_image_layout: ImageLayout,
+
+ /// The non-multisampled image to resolve into.
+ ///
+ /// There is no default value.
+ pub dst_image: Arc<dyn ImageAccess>,
+
+ /// The layout used for `dst_image` during the resolve operation.
+ ///
+ /// The following layouts are allowed:
+ /// - [`ImageLayout::TransferDstOptimal`]
+ /// - [`ImageLayout::General`]
+ ///
+ /// The default value is [`ImageLayout::TransferDstOptimal`].
+ pub dst_image_layout: ImageLayout,
+
+ /// The regions of both images to resolve between.
+ ///
+ /// The default value is a single region, covering the first mip level, and the smallest of the
+ /// array layers and extent of the two images. All aspects of each image are selected, or
+ /// `plane0` if the image is multi-planar.
+ pub regions: SmallVec<[ImageResolve; 1]>,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl ResolveImageInfo {
+ /// Returns a `ResolveImageInfo` with the specified `src_image` and `dst_image`.
+ #[inline]
+ pub fn images(src_image: Arc<dyn ImageAccess>, dst_image: Arc<dyn ImageAccess>) -> Self {
+ let min_array_layers = src_image
+ .dimensions()
+ .array_layers()
+ .min(dst_image.dimensions().array_layers());
+ let region = ImageResolve {
+ src_subresource: ImageSubresourceLayers {
+ array_layers: 0..min_array_layers,
+ ..src_image.subresource_layers()
+ },
+ dst_subresource: ImageSubresourceLayers {
+ array_layers: 0..min_array_layers,
+ ..dst_image.subresource_layers()
+ },
+ extent: {
+ let src_extent = src_image.dimensions().width_height_depth();
+ let dst_extent = dst_image.dimensions().width_height_depth();
+
+ [
+ src_extent[0].min(dst_extent[0]),
+ src_extent[1].min(dst_extent[1]),
+ src_extent[2].min(dst_extent[2]),
+ ]
+ },
+ ..Default::default()
+ };
+
+ Self {
+ src_image,
+ src_image_layout: ImageLayout::TransferSrcOptimal,
+ dst_image,
+ dst_image_layout: ImageLayout::TransferDstOptimal,
+ regions: smallvec![region],
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// A region of data to resolve between images.
+#[derive(Clone, Debug)]
+pub struct ImageResolve {
+ /// The subresource of `src_image` to resolve from.
+ ///
+ /// The default value is empty, which must be overridden.
+ pub src_subresource: ImageSubresourceLayers,
+
+ /// The offset from the zero coordinate of `src_image` that resolving will start from.
+ ///
+ /// The default value is `[0; 3]`.
+ pub src_offset: [u32; 3],
+
+ /// The subresource of `dst_image` to resolve into.
+ ///
+ /// The default value is empty, which must be overridden.
+ pub dst_subresource: ImageSubresourceLayers,
+
+ /// The offset from the zero coordinate of `dst_image` that resolving will start from.
+ ///
+ /// The default value is `[0; 3]`.
+ pub dst_offset: [u32; 3],
+
+ /// The extent of texels to resolve.
+ ///
+ /// The default value is `[0; 3]`, which must be overridden.
+ pub extent: [u32; 3],
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for ImageResolve {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ src_subresource: ImageSubresourceLayers {
+ aspects: ImageAspects::empty(),
+ mip_level: 0,
+ array_layers: 0..0,
+ },
+ src_offset: [0; 3],
+ dst_subresource: ImageSubresourceLayers {
+ aspects: ImageAspects::empty(),
+ mip_level: 0,
+ array_layers: 0..0,
+ },
+ dst_offset: [0; 3],
+ extent: [0; 3],
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// Error that can happen when recording a copy command.
+#[derive(Clone, Debug)]
+pub enum CopyError {
+ SyncCommandBufferBuilderError(SyncCommandBufferBuilderError),
+
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+
+ /// Operation forbidden inside of a render pass.
+ ForbiddenInsideRenderPass,
+
+ /// The queue family doesn't allow this operation.
+ NotSupportedByQueueFamily,
+
+ /// The array layer counts of the source and destination subresource ranges of a region do not
+ /// match.
+ ArrayLayerCountMismatch {
+ region_index: usize,
+ src_layer_count: u32,
+ dst_layer_count: u32,
+ },
+
+ /// The end of the range of accessed array layers of the subresource range of a region is
+ /// greater than the number of array layers in the image.
+ ArrayLayersOutOfRange {
+ resource: CopyErrorResource,
+ region_index: usize,
+ array_layers_range_end: u32,
+ image_array_layers: u32,
+ },
+
+ /// The aspects of the source and destination subresource ranges of a region do not match.
+ AspectsMismatch {
+ region_index: usize,
+ src_aspects: ImageAspects,
+ dst_aspects: ImageAspects,
+ },
+
+ /// The aspects of the subresource range of a region contain aspects that are not present
+ /// in the image, or that are not allowed.
+ AspectsNotAllowed {
+ resource: CopyErrorResource,
+ region_index: usize,
+ aspects: ImageAspects,
+ allowed_aspects: ImageAspects,
+ },
+
+ /// The buffer image height of a region is not a multiple of the required buffer alignment.
+ BufferImageHeightNotAligned {
+ resource: CopyErrorResource,
+ region_index: usize,
+ image_height: u32,
+ required_alignment: u32,
+ },
+
+ /// The buffer image height of a region is smaller than the image extent height.
+ BufferImageHeightTooSmall {
+ resource: CopyErrorResource,
+ region_index: usize,
+ image_height: u32,
+ min: u32,
+ },
+
+ /// The buffer row length of a region is not a multiple of the required buffer alignment.
+ BufferRowLengthNotAligned {
+ resource: CopyErrorResource,
+ region_index: usize,
+ row_length: u32,
+ required_alignment: u32,
+ },
+
+ /// The buffer row length of a region specifies a row of texels that is greater than 0x7FFFFFFF
+ /// bytes in size.
+ BufferRowLengthTooLarge {
+ resource: CopyErrorResource,
+ region_index: usize,
+ buffer_row_length: u32,
+ },
+
+ /// The buffer row length of a region is smaller than the image extent width.
+ BufferRowLengthTooSmall {
+ resource: CopyErrorResource,
+ region_index: usize,
+ row_length: u32,
+ min: u32,
+ },
+
+ /// Depth/stencil images are not supported by the queue family of this command buffer; a
+ /// graphics queue family is required.
+ DepthStencilNotSupportedByQueueFamily,
+
+ /// The image extent of a region is not a multiple of the required image alignment.
+ ExtentNotAlignedForImage {
+ resource: CopyErrorResource,
+ region_index: usize,
+ extent: [u32; 3],
+ required_alignment: [u32; 3],
+ },
+
+ /// The chosen filter type does not support the dimensionality of the source image.
+ FilterNotSupportedForImageType,
+
+ /// The chosen filter type does not support the format of the source image.
+ FilterNotSupportedByFormat,
+
+ /// The format of an image is not supported for this operation.
+ FormatNotSupported {
+ resource: CopyErrorResource,
+ format: Format,
+ },
+
+ /// The format of the source image does not match the format of the destination image.
+ FormatsMismatch {
+ src_format: Format,
+ dst_format: Format,
+ },
+
+ /// The format of the source image subresource is not compatible with the format of the
+ /// destination image subresource.
+ FormatsNotCompatible {
+ src_format: Format,
+ dst_format: Format,
+ },
+
+ /// A specified image layout is not valid for this operation.
+ ImageLayoutInvalid {
+ resource: CopyErrorResource,
+ image_layout: ImageLayout,
+ },
+
+ /// The end of the range of accessed mip levels of the subresource range of a region is greater
+ /// than the number of mip levels in the image.
+ MipLevelsOutOfRange {
+ resource: CopyErrorResource,
+ region_index: usize,
+ mip_levels_range_end: u32,
+ image_mip_levels: u32,
+ },
+
+ /// An image does not have a required format feature.
+ MissingFormatFeature {
+ resource: CopyErrorResource,
+ format_feature: &'static str,
+ },
+
+ /// A resource did not have a required usage enabled.
+ MissingUsage {
+ resource: CopyErrorResource,
+ usage: &'static str,
+ },
+
+ /// A subresource range of a region specifies multiple aspects, but only one aspect can be
+ /// selected for the image.
+ MultipleAspectsNotAllowed {
+ resource: CopyErrorResource,
+ region_index: usize,
+ aspects: ImageAspects,
+ },
+
+ /// The buffer offset of a region is not a multiple of the required buffer alignment.
+ OffsetNotAlignedForBuffer {
+ resource: CopyErrorResource,
+ region_index: usize,
+ offset: DeviceSize,
+ required_alignment: DeviceSize,
+ },
+
+ /// The image offset of a region is not a multiple of the required image alignment.
+ OffsetNotAlignedForImage {
+ resource: CopyErrorResource,
+ region_index: usize,
+ offset: [u32; 3],
+ required_alignment: [u32; 3],
+ },
+
+ /// The image offsets of a region are not the values required for that axis ([0, 1]) for the
+ /// type of the image.
+ OffsetsInvalidForImageType {
+ resource: CopyErrorResource,
+ region_index: usize,
+ offsets: [u32; 2],
+ },
+
+ /// The source bounds of a region overlap with the destination bounds of a region.
+ OverlappingRegions {
+ src_region_index: usize,
+ dst_region_index: usize,
+ },
+
+ /// The source subresources of a region overlap with the destination subresources of a region,
+ /// but the source image layout does not equal the destination image layout.
+ OverlappingSubresourcesLayoutMismatch {
+ src_region_index: usize,
+ dst_region_index: usize,
+ src_image_layout: ImageLayout,
+ dst_image_layout: ImageLayout,
+ },
+
+ /// The end of the range of accessed byte offsets of a region is greater than the size of the
+ /// buffer.
+ RegionOutOfBufferBounds {
+ resource: CopyErrorResource,
+ region_index: usize,
+ offset_range_end: DeviceSize,
+ buffer_size: DeviceSize,
+ },
+
+ /// The end of the range of accessed texel offsets of a region is greater than the extent of
+ /// the selected subresource of the image.
+ RegionOutOfImageBounds {
+ resource: CopyErrorResource,
+ region_index: usize,
+ offset_range_end: [u32; 3],
+ subresource_extent: [u32; 3],
+ },
+
+ /// An image has a sample count that is not valid for this operation.
+ SampleCountInvalid {
+ resource: CopyErrorResource,
+ sample_count: SampleCount,
+ allowed_sample_counts: SampleCounts,
+ },
+
+ /// The source image has a different sample count than the destination image.
+ SampleCountMismatch {
+ src_sample_count: SampleCount,
+ dst_sample_count: SampleCount,
+ },
+}
+
+impl Error for CopyError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::SyncCommandBufferBuilderError(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+impl Display for CopyError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::SyncCommandBufferBuilderError(_) => write!(f, "a SyncCommandBufferBuilderError"),
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ Self::ForbiddenInsideRenderPass => {
+ write!(f, "operation forbidden inside of a render pass")
+ }
+ Self::NotSupportedByQueueFamily => {
+ write!(f, "the queue family doesn't allow this operation")
+ }
+ Self::ArrayLayerCountMismatch {
+ region_index,
+ src_layer_count,
+ dst_layer_count,
+ } => write!(
+ f,
+ "the array layer counts of the source and destination subresource ranges of region \
+ {} do not match (source: {}; destination: {})",
+ region_index, src_layer_count, dst_layer_count,
+ ),
+ Self::ArrayLayersOutOfRange {
+ resource,
+ region_index,
+ array_layers_range_end,
+ image_array_layers,
+ } => write!(
+ f,
+ "the end of the range of accessed array layers ({}) of the {} subresource range of \
+ region {} is greater than the number of array layers in the {} image ({})",
+ array_layers_range_end, resource, region_index, resource, image_array_layers,
+ ),
+ Self::AspectsMismatch {
+ region_index,
+ src_aspects,
+ dst_aspects,
+ } => write!(
+ f,
+ "the aspects of the source and destination subresource ranges of region {} do not \
+ match (source: {:?}; destination: {:?})",
+ region_index, src_aspects, dst_aspects,
+ ),
+ Self::AspectsNotAllowed {
+ resource,
+ region_index,
+ aspects,
+ allowed_aspects,
+ } => write!(
+ f,
+ "the aspects ({:?}) of the {} subresource range of region {} contain aspects that \
+ are not present in the {} image, or that are not allowed ({:?})",
+ aspects, resource, region_index, resource, allowed_aspects,
+ ),
+ Self::BufferImageHeightNotAligned {
+ resource,
+ region_index,
+ image_height,
+ required_alignment,
+ } => write!(
+ f,
+ "the {} buffer image height ({}) of region {} is not a multiple of the required {} \
+ buffer alignment ({})",
+ resource, image_height, region_index, resource, required_alignment,
+ ),
+ Self::BufferRowLengthTooLarge {
+ resource,
+ region_index,
+ buffer_row_length,
+ } => write!(
+ f,
+ "the {} buffer row length ({}) of region {} specifies a row of texels that is \
+ greater than 0x7FFFFFFF bytes in size",
+ resource, buffer_row_length, region_index,
+ ),
+ Self::BufferImageHeightTooSmall {
+ resource,
+ region_index,
+ image_height,
+ min,
+ } => write!(
+ f,
+ "the {} buffer image height ({}) of region {} is smaller than the {} image extent \
+ height ({})",
+ resource, image_height, region_index, resource, min,
+ ),
+ Self::BufferRowLengthNotAligned {
+ resource,
+ region_index,
+ row_length,
+ required_alignment,
+ } => write!(
+ f,
+ "the {} buffer row length ({}) of region {} is not a multiple of the required {} \
+ buffer alignment ({})",
+ resource, row_length, region_index, resource, required_alignment,
+ ),
+ Self::BufferRowLengthTooSmall {
+ resource,
+ region_index,
+ row_length,
+ min,
+ } => write!(
+ f,
+ "the {} buffer row length length ({}) of region {} is smaller than the {} image \
+ extent width ({})",
+ resource, row_length, region_index, resource, min,
+ ),
+ Self::DepthStencilNotSupportedByQueueFamily => write!(
+ f,
+ "depth/stencil images are not supported by the queue family of this command \
+ buffer; a graphics queue family is required",
+ ),
+ Self::ExtentNotAlignedForImage {
+ resource,
+ region_index,
+ extent,
+ required_alignment,
+ } => write!(
+ f,
+ "the {} image extent ({:?}) of region {} is not a multiple of the required {} \
+ image alignment ({:?})",
+ resource, extent, region_index, resource, required_alignment,
+ ),
+ Self::FilterNotSupportedForImageType => write!(
+ f,
+ "the chosen filter is not supported for the source image type",
+ ),
+ Self::FilterNotSupportedByFormat => write!(
+ f,
+ "the chosen filter is not supported by the format of the source image",
+ ),
+ Self::FormatNotSupported { resource, format } => write!(
+ f,
+ "the format of the {} image ({:?}) is not supported for this operation",
+ resource, format,
+ ),
+ Self::FormatsMismatch {
+ src_format,
+ dst_format,
+ } => write!(
+ f,
+ "the format of the source image ({:?}) does not match the format of the \
+ destination image ({:?})",
+ src_format, dst_format,
+ ),
+ Self::FormatsNotCompatible {
+ src_format,
+ dst_format,
+ } => write!(
+ f,
+ "the format of the source image subresource ({:?}) is not compatible with the \
+ format of the destination image subresource ({:?})",
+ src_format, dst_format,
+ ),
+ Self::ImageLayoutInvalid {
+ resource,
+ image_layout,
+ } => write!(
+ f,
+ "the specified {} image layout {:?} is not valid for this operation",
+ resource, image_layout,
+ ),
+ Self::MipLevelsOutOfRange {
+ resource,
+ region_index,
+ mip_levels_range_end,
+ image_mip_levels,
+ } => write!(
+ f,
+ "the end of the range of accessed mip levels ({}) of the {} subresource range of \
+ region {} is not less than the number of mip levels in the {} image ({})",
+ mip_levels_range_end, resource, region_index, resource, image_mip_levels,
+ ),
+ Self::MissingFormatFeature {
+ resource,
+ format_feature,
+ } => write!(
+ f,
+ "the {} image does not have the required format feature {}",
+ resource, format_feature,
+ ),
+ Self::MissingUsage { resource, usage } => write!(
+ f,
+ "the {} resource did not have the required usage {} enabled",
+ resource, usage,
+ ),
+ Self::MultipleAspectsNotAllowed {
+ resource,
+ region_index,
+ aspects,
+ } => write!(
+ f,
+ "the {} subresource range of region {} specifies multiple aspects ({:?}), but only \
+ one aspect can be selected for the {} image",
+ resource, region_index, aspects, resource,
+ ),
+ Self::OffsetNotAlignedForBuffer {
+ resource,
+ region_index,
+ offset,
+ required_alignment,
+ } => write!(
+ f,
+ "the {} buffer offset ({}) of region {} is not a multiple of the required {} \
+ buffer alignment ({})",
+ resource, offset, region_index, resource, required_alignment,
+ ),
+ Self::OffsetNotAlignedForImage {
+ resource,
+ region_index,
+ offset,
+ required_alignment,
+ } => write!(
+ f,
+ "the {} image offset ({:?}) of region {} is not a multiple of the required {} \
+ image alignment ({:?})",
+ resource, offset, region_index, resource, required_alignment,
+ ),
+ Self::OffsetsInvalidForImageType {
+ resource,
+ region_index,
+ offsets,
+ } => write!(
+ f,
+ "the {} image offsets ({:?}) of region {} are not the values required for that \
+ axis ([0, 1]) for the type of the {} image",
+ resource, offsets, region_index, resource,
+ ),
+ Self::OverlappingRegions {
+ src_region_index,
+ dst_region_index,
+ } => write!(
+ f,
+ "the source bounds of region {} overlap with the destination bounds of region {}",
+ src_region_index, dst_region_index,
+ ),
+ Self::OverlappingSubresourcesLayoutMismatch {
+ src_region_index,
+ dst_region_index,
+ src_image_layout,
+ dst_image_layout,
+ } => write!(
+ f,
+ "the source subresources of region {} overlap with the destination subresources of \
+ region {}, but the source image layout ({:?}) does not equal the destination image \
+ layout ({:?})",
+ src_region_index, dst_region_index, src_image_layout, dst_image_layout,
+ ),
+ Self::RegionOutOfBufferBounds {
+ resource,
+ region_index,
+ offset_range_end,
+ buffer_size,
+ } => write!(
+ f,
+ "the end of the range of accessed {} byte offsets ({}) of region {} is greater \
+ than the size of the {} buffer ({})",
+ resource, offset_range_end, region_index, resource, buffer_size,
+ ),
+ Self::RegionOutOfImageBounds {
+ resource,
+ region_index,
+ offset_range_end,
+ subresource_extent,
+ } => write!(
+ f,
+ "the end of the range of accessed {} texel offsets ({:?}) of region {} is greater \
+ than the extent of the selected subresource of the {} image ({:?})",
+ resource, offset_range_end, region_index, resource, subresource_extent,
+ ),
+ Self::SampleCountInvalid {
+ resource,
+ sample_count,
+ allowed_sample_counts,
+ } => write!(
+ f,
+ "the {} image has a sample count ({:?}) that is not valid for this operation \
+ ({:?})",
+ resource, sample_count, allowed_sample_counts,
+ ),
+ Self::SampleCountMismatch {
+ src_sample_count,
+ dst_sample_count,
+ } => write!(
+ f,
+ "the source image has a different sample count ({:?}) than the destination image \
+ ({:?})",
+ src_sample_count, dst_sample_count,
+ ),
+ }
+ }
+}
+
+impl From<SyncCommandBufferBuilderError> for CopyError {
+ fn from(err: SyncCommandBufferBuilderError) -> Self {
+ Self::SyncCommandBufferBuilderError(err)
+ }
+}
+
+impl From<RequirementNotMet> for CopyError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
+ }
+ }
+}
+
+/// Indicates which resource a `CopyError` applies to.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum CopyErrorResource {
+ Source,
+ Destination,
+}
+
+impl Display for CopyErrorResource {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::Source => write!(f, "source"),
+ Self::Destination => write!(f, "destination"),
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::format::Format;
+
+ /// Computes the minimum required len in elements for buffer with image data in specified
+ /// format of specified size.
+ fn required_size_for_format(format: Format, extent: [u32; 3], layer_count: u32) -> DeviceSize {
+ let num_blocks = extent
+ .into_iter()
+ .zip(format.block_extent())
+ .map(|(extent, block_extent)| {
+ let extent = extent as DeviceSize;
+ let block_extent = block_extent as DeviceSize;
+ (extent + block_extent - 1) / block_extent
+ })
+ .product::<DeviceSize>()
+ * layer_count as DeviceSize;
+ let block_size = format
+ .block_size()
+ .expect("this format cannot accept pixels");
+ num_blocks * block_size
+ }
+
+ #[test]
+ fn test_required_len_for_format() {
+ // issue #1292
+ assert_eq!(
+ required_size_for_format(Format::BC1_RGB_UNORM_BLOCK, [2048, 2048, 1], 1),
+ 2097152
+ );
+ // other test cases
+ assert_eq!(
+ required_size_for_format(Format::R8G8B8A8_UNORM, [2048, 2048, 1], 1),
+ 16777216
+ );
+ assert_eq!(
+ required_size_for_format(Format::R4G4_UNORM_PACK8, [512, 512, 1], 1),
+ 262144
+ );
+ assert_eq!(
+ required_size_for_format(Format::R8G8B8_USCALED, [512, 512, 1], 1),
+ 786432
+ );
+ assert_eq!(
+ required_size_for_format(Format::R32G32_UINT, [512, 512, 1], 1),
+ 2097152
+ );
+ assert_eq!(
+ required_size_for_format(Format::R32G32_UINT, [512, 512, 1], 1),
+ 2097152
+ );
+ assert_eq!(
+ required_size_for_format(Format::ASTC_8x8_UNORM_BLOCK, [512, 512, 1], 1),
+ 65536
+ );
+ assert_eq!(
+ required_size_for_format(Format::ASTC_12x12_SRGB_BLOCK, [512, 512, 1], 1),
+ 29584
+ );
+ }
+}
diff --git a/src/command_buffer/commands/debug.rs b/src/command_buffer/commands/debug.rs
new file mode 100644
index 0000000..4d77a4e
--- /dev/null
+++ b/src/command_buffer/commands/debug.rs
@@ -0,0 +1,345 @@
+// Copyright (c) 2022 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use crate::{
+ command_buffer::{
+ allocator::CommandBufferAllocator,
+ synced::{Command, SyncCommandBufferBuilder},
+ sys::UnsafeCommandBufferBuilder,
+ AutoCommandBufferBuilder,
+ },
+ device::{DeviceOwned, QueueFlags},
+ instance::debug::DebugUtilsLabel,
+ RequiresOneOf,
+};
+use std::{
+ error::Error,
+ ffi::CString,
+ fmt::{Display, Error as FmtError, Formatter},
+};
+
+/// # Commands for debugging.
+///
+/// These commands all require the [`ext_debug_utils`] extension to be enabled on the instance.
+///
+/// [`ext_debug_utils`]: crate::instance::InstanceExtensions::ext_debug_utils
+impl<L, A> AutoCommandBufferBuilder<L, A>
+where
+ A: CommandBufferAllocator,
+{
+ /// Opens a command buffer debug label region.
+ pub fn begin_debug_utils_label(
+ &mut self,
+ mut label_info: DebugUtilsLabel,
+ ) -> Result<&mut Self, DebugUtilsError> {
+ self.validate_begin_debug_utils_label(&mut label_info)?;
+
+ unsafe {
+ self.inner.begin_debug_utils_label(label_info);
+ }
+
+ Ok(self)
+ }
+
+ fn validate_begin_debug_utils_label(
+ &self,
+ _label_info: &mut DebugUtilsLabel,
+ ) -> Result<(), DebugUtilsError> {
+ if !self
+ .device()
+ .instance()
+ .enabled_extensions()
+ .ext_debug_utils
+ {
+ return Err(DebugUtilsError::RequirementNotMet {
+ required_for: "`AutoCommandBufferBuilder::begin_debug_utils_label`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["ext_debug_utils"],
+ ..Default::default()
+ },
+ });
+ }
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdBeginDebugUtilsLabelEXT-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(DebugUtilsError::NotSupportedByQueueFamily);
+ }
+
+ Ok(())
+ }
+
+ /// Closes a command buffer debug label region.
+ ///
+ /// # Safety
+ ///
+ /// - When submitting the command buffer, there must be an outstanding command buffer label
+ /// region begun with `begin_debug_utils_label` in the queue, either within this command
+ /// buffer or a previously submitted one.
+ pub unsafe fn end_debug_utils_label(&mut self) -> Result<&mut Self, DebugUtilsError> {
+ self.validate_end_debug_utils_label()?;
+
+ self.inner.end_debug_utils_label();
+
+ Ok(self)
+ }
+
+ fn validate_end_debug_utils_label(&self) -> Result<(), DebugUtilsError> {
+ if !self
+ .device()
+ .instance()
+ .enabled_extensions()
+ .ext_debug_utils
+ {
+ return Err(DebugUtilsError::RequirementNotMet {
+ required_for: "`AutoCommandBufferBuilder::end_debug_utils_label`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["ext_debug_utils"],
+ ..Default::default()
+ },
+ });
+ }
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdEndDebugUtilsLabelEXT-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(DebugUtilsError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdEndDebugUtilsLabelEXT-commandBuffer-01912
+ // TODO: not checked, so unsafe for now
+
+ // VUID-vkCmdEndDebugUtilsLabelEXT-commandBuffer-01913
+ // TODO: not checked, so unsafe for now
+
+ Ok(())
+ }
+
+ /// Inserts a command buffer debug label.
+ pub fn insert_debug_utils_label(
+ &mut self,
+ mut label_info: DebugUtilsLabel,
+ ) -> Result<&mut Self, DebugUtilsError> {
+ self.validate_insert_debug_utils_label(&mut label_info)?;
+
+ unsafe {
+ self.inner.insert_debug_utils_label(label_info);
+ }
+
+ Ok(self)
+ }
+
+ fn validate_insert_debug_utils_label(
+ &self,
+ _label_info: &mut DebugUtilsLabel,
+ ) -> Result<(), DebugUtilsError> {
+ if !self
+ .device()
+ .instance()
+ .enabled_extensions()
+ .ext_debug_utils
+ {
+ return Err(DebugUtilsError::RequirementNotMet {
+ required_for: "`AutoCommandBufferBuilder::insert_debug_utils_label`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["ext_debug_utils"],
+ ..Default::default()
+ },
+ });
+ }
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdInsertDebugUtilsLabelEXT-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(DebugUtilsError::NotSupportedByQueueFamily);
+ }
+
+ Ok(())
+ }
+}
+
+impl SyncCommandBufferBuilder {
+ /// Calls `vkCmdBeginDebugUtilsLabelEXT` on the builder.
+ ///
+ /// # Safety
+ /// The command pool that this command buffer was allocated from must support graphics or
+ /// compute operations
+ #[inline]
+ pub unsafe fn begin_debug_utils_label(&mut self, label_info: DebugUtilsLabel) {
+ struct Cmd {
+ label_info: DebugUtilsLabel,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "begin_debug_utils_label"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.begin_debug_utils_label(&self.label_info);
+ }
+ }
+
+ self.commands.push(Box::new(Cmd { label_info }));
+ }
+
+ /// Calls `vkCmdEndDebugUtilsLabelEXT` on the builder.
+ ///
+ /// # Safety
+ ///
+ /// - The command pool that this command buffer was allocated from must support graphics or
+ /// compute operations
+ /// - There must be an outstanding `debug_marker_begin` command prior to the
+ /// `debug_marker_end` on the queue.
+ #[inline]
+ pub unsafe fn end_debug_utils_label(&mut self) {
+ struct Cmd {}
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "end_debug_utils_label"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.end_debug_utils_label();
+ }
+ }
+
+ self.commands.push(Box::new(Cmd {}));
+ }
+
+ /// Calls `vkCmdInsertDebugUtilsLabelEXT` on the builder.
+ ///
+ /// # Safety
+ /// The command pool that this command buffer was allocated from must support graphics or
+ /// compute operations
+ #[inline]
+ pub unsafe fn insert_debug_utils_label(&mut self, label_info: DebugUtilsLabel) {
+ struct Cmd {
+ label_info: DebugUtilsLabel,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "insert_debug_utils_label"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.insert_debug_utils_label(&self.label_info);
+ }
+ }
+
+ self.commands.push(Box::new(Cmd { label_info }));
+ }
+}
+
+impl UnsafeCommandBufferBuilder {
+ /// Calls `vkCmdBeginDebugUtilsLabelEXT` on the builder.
+ ///
+ /// # Safety
+ /// The command pool that this command buffer was allocated from must support graphics or
+ /// compute operations
+ #[inline]
+ pub unsafe fn begin_debug_utils_label(&mut self, label_info: &DebugUtilsLabel) {
+ let &DebugUtilsLabel {
+ ref label_name,
+ color,
+ _ne: _,
+ } = label_info;
+
+ let label_name_vk = CString::new(label_name.as_str()).unwrap();
+ let label_info = ash::vk::DebugUtilsLabelEXT {
+ p_label_name: label_name_vk.as_ptr(),
+ color,
+ ..Default::default()
+ };
+
+ let fns = self.device.instance().fns();
+ (fns.ext_debug_utils.cmd_begin_debug_utils_label_ext)(self.handle, &label_info);
+ }
+
+ /// Calls `vkCmdEndDebugUtilsLabelEXT` on the builder.
+ ///
+ /// # Safety
+ /// There must be an outstanding `vkCmdBeginDebugUtilsLabelEXT` command prior to the
+ /// `vkQueueEndDebugUtilsLabelEXT` on the queue tha `CommandBuffer` is submitted to.
+ #[inline]
+ pub unsafe fn end_debug_utils_label(&mut self) {
+ let fns = self.device.instance().fns();
+ (fns.ext_debug_utils.cmd_end_debug_utils_label_ext)(self.handle);
+ }
+
+ /// Calls `vkCmdInsertDebugUtilsLabelEXT` on the builder.
+ ///
+ /// # Safety
+ /// The command pool that this command buffer was allocated from must support graphics or
+ /// compute operations
+ #[inline]
+ pub unsafe fn insert_debug_utils_label(&mut self, label_info: &DebugUtilsLabel) {
+ let &DebugUtilsLabel {
+ ref label_name,
+ color,
+ _ne: _,
+ } = label_info;
+
+ let label_name_vk = CString::new(label_name.as_str()).unwrap();
+ let label_info = ash::vk::DebugUtilsLabelEXT {
+ p_label_name: label_name_vk.as_ptr(),
+ color,
+ ..Default::default()
+ };
+
+ let fns = self.device.instance().fns();
+ (fns.ext_debug_utils.cmd_insert_debug_utils_label_ext)(self.handle, &label_info);
+ }
+}
+
+/// Error that can happen when recording a debug utils command.
+#[derive(Clone, Debug)]
+pub enum DebugUtilsError {
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+
+ /// The queue family doesn't allow this operation.
+ NotSupportedByQueueFamily,
+}
+
+impl Error for DebugUtilsError {}
+
+impl Display for DebugUtilsError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ Self::NotSupportedByQueueFamily => {
+ write!(f, "the queue family doesn't allow this operation")
+ }
+ }
+ }
+}
diff --git a/src/command_buffer/commands/dynamic_state.rs b/src/command_buffer/commands/dynamic_state.rs
new file mode 100644
index 0000000..b56df7f
--- /dev/null
+++ b/src/command_buffer/commands/dynamic_state.rs
@@ -0,0 +1,3006 @@
+// Copyright (c) 2022 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use crate::{
+ command_buffer::{
+ allocator::CommandBufferAllocator,
+ synced::{Command, SyncCommandBufferBuilder},
+ sys::UnsafeCommandBufferBuilder,
+ AutoCommandBufferBuilder,
+ },
+ device::{DeviceOwned, QueueFlags},
+ pipeline::{
+ graphics::{
+ color_blend::LogicOp,
+ depth_stencil::{CompareOp, StencilFaces, StencilOp, StencilOps},
+ input_assembly::PrimitiveTopology,
+ rasterization::{CullMode, DepthBias, FrontFace, LineStipple},
+ viewport::{Scissor, Viewport},
+ },
+ DynamicState,
+ },
+ RequirementNotMet, RequiresOneOf, Version,
+};
+use parking_lot::Mutex;
+use smallvec::SmallVec;
+use std::{
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+ ops::RangeInclusive,
+};
+
+/// # Commands to set dynamic state for pipelines.
+///
+/// These commands require a queue with a pipeline type that uses the given state.
+impl<L, A> AutoCommandBufferBuilder<L, A>
+where
+ A: CommandBufferAllocator,
+{
+ // Helper function for dynamic state setting.
+ fn validate_pipeline_fixed_state(
+ &self,
+ state: DynamicState,
+ ) -> Result<(), SetDynamicStateError> {
+ // VUID-vkCmdDispatch-None-02859
+ if self.state().pipeline_graphics().map_or(false, |pipeline| {
+ matches!(pipeline.dynamic_state(state), Some(false))
+ }) {
+ return Err(SetDynamicStateError::PipelineHasFixedState);
+ }
+
+ Ok(())
+ }
+
+ /// Sets the dynamic blend constants for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ pub fn set_blend_constants(&mut self, constants: [f32; 4]) -> &mut Self {
+ self.validate_set_blend_constants(constants).unwrap();
+
+ unsafe {
+ self.inner.set_blend_constants(constants);
+ }
+
+ self
+ }
+
+ fn validate_set_blend_constants(
+ &self,
+ _constants: [f32; 4],
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::BlendConstants)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetBlendConstants-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ Ok(())
+ }
+
+ /// Sets whether dynamic color writes should be enabled for each attachment in the
+ /// framebuffer.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the [`color_write_enable`](crate::device::Features::color_write_enable)
+ /// feature is not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ /// - If there is a graphics pipeline with color blend state bound, `enables.len()` must equal
+ /// - [`attachments.len()`](crate::pipeline::graphics::color_blend::ColorBlendState::attachments).
+ pub fn set_color_write_enable<I>(&mut self, enables: I) -> &mut Self
+ where
+ I: IntoIterator<Item = bool>,
+ I::IntoIter: ExactSizeIterator,
+ {
+ let enables = enables.into_iter();
+
+ self.validate_set_color_write_enable(&enables).unwrap();
+
+ unsafe {
+ self.inner.set_color_write_enable(enables);
+ }
+
+ self
+ }
+
+ fn validate_set_color_write_enable(
+ &self,
+ enables: &impl ExactSizeIterator,
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::ColorWriteEnable)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetColorWriteEnableEXT-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetColorWriteEnableEXT-None-04803
+ if !self.device().enabled_features().color_write_enable {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`AutoCommandBufferBuilder::set_color_write_enable`",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["ext_color_write_enable"],
+ ..Default::default()
+ },
+ });
+ }
+
+ if let Some(color_blend_state) = self
+ .state()
+ .pipeline_graphics()
+ .and_then(|pipeline| pipeline.color_blend_state())
+ {
+ // VUID-vkCmdSetColorWriteEnableEXT-attachmentCount-06656
+ // Indirectly checked
+ if enables.len() != color_blend_state.attachments.len() {
+ return Err(
+ SetDynamicStateError::PipelineColorBlendAttachmentCountMismatch {
+ provided_count: enables.len() as u32,
+ required_count: color_blend_state.attachments.len() as u32,
+ },
+ );
+ }
+ }
+
+ Ok(())
+ }
+
+ /// Sets the dynamic cull mode for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the device API version is less than 1.3 and the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is
+ /// not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ pub fn set_cull_mode(&mut self, cull_mode: CullMode) -> &mut Self {
+ self.validate_set_cull_mode(cull_mode).unwrap();
+
+ unsafe {
+ self.inner.set_cull_mode(cull_mode);
+ }
+
+ self
+ }
+
+ fn validate_set_cull_mode(&self, cull_mode: CullMode) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::CullMode)?;
+
+ // VUID-vkCmdSetCullMode-cullMode-parameter
+ cull_mode.validate_device(self.device())?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetCullMode-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetCullMode-None-03384
+ if !(self.device().api_version() >= Version::V1_3
+ || self.device().enabled_features().extended_dynamic_state)
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`AutoCommandBufferBuilder::set_cull_mode`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ /// Sets the dynamic depth bias values for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ /// - If the [`depth_bias_clamp`](crate::device::Features::depth_bias_clamp)
+ /// feature is not enabled on the device, panics if `clamp` is not 0.0.
+ pub fn set_depth_bias(
+ &mut self,
+ constant_factor: f32,
+ clamp: f32,
+ slope_factor: f32,
+ ) -> &mut Self {
+ self.validate_set_depth_bias(constant_factor, clamp, slope_factor)
+ .unwrap();
+
+ unsafe {
+ self.inner
+ .set_depth_bias(constant_factor, clamp, slope_factor);
+ }
+
+ self
+ }
+
+ fn validate_set_depth_bias(
+ &self,
+ _constant_factor: f32,
+ clamp: f32,
+ _slope_factor: f32,
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::DepthBias)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetDepthBias-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetDepthBias-depthBiasClamp-00790
+ if clamp != 0.0 && !self.device().enabled_features().depth_bias_clamp {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`clamp` is not `0.0`",
+ requires_one_of: RequiresOneOf {
+ features: &["depth_bias_clamp"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ /// Sets whether dynamic depth bias is enabled for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the device API version is less than 1.3 and the
+ /// [`extended_dynamic_state2`](crate::device::Features::extended_dynamic_state2) feature is
+ /// not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ pub fn set_depth_bias_enable(&mut self, enable: bool) -> &mut Self {
+ self.validate_set_depth_bias_enable(enable).unwrap();
+
+ unsafe {
+ self.inner.set_depth_bias_enable(enable);
+ }
+
+ self
+ }
+
+ fn validate_set_depth_bias_enable(&self, _enable: bool) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::DepthBiasEnable)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetDepthBiasEnable-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetDepthBiasEnable-None-04872
+ if !(self.device().api_version() >= Version::V1_3
+ || self.device().enabled_features().extended_dynamic_state2)
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`AutoCommandBufferBuilder::set_depth_bias_enable`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state2"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ /// Sets the dynamic depth bounds for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ /// - If the
+ /// [`ext_depth_range_unrestricted`](crate::device::DeviceExtensions::ext_depth_range_unrestricted)
+ /// device extension is not enabled, panics if the start and end of `bounds` are not between
+ /// 0.0 and 1.0 inclusive.
+ pub fn set_depth_bounds(&mut self, bounds: RangeInclusive<f32>) -> &mut Self {
+ self.validate_set_depth_bounds(bounds.clone()).unwrap();
+
+ unsafe {
+ self.inner.set_depth_bounds(bounds);
+ }
+
+ self
+ }
+
+ fn validate_set_depth_bounds(
+ &self,
+ bounds: RangeInclusive<f32>,
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::DepthBounds)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetDepthBounds-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetDepthBounds-minDepthBounds-00600
+ // VUID-vkCmdSetDepthBounds-maxDepthBounds-00601
+ if !self
+ .device()
+ .enabled_extensions()
+ .ext_depth_range_unrestricted
+ && !((0.0..=1.0).contains(bounds.start()) && (0.0..=1.0).contains(bounds.end()))
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`bounds` is not between `0.0` and `1.0` inclusive",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["ext_depth_range_unrestricted"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ /// Sets whether dynamic depth bounds testing is enabled for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the device API version is less than 1.3 and the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is
+ /// not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ pub fn set_depth_bounds_test_enable(&mut self, enable: bool) -> &mut Self {
+ self.validate_set_depth_bounds_test_enable(enable).unwrap();
+
+ unsafe {
+ self.inner.set_depth_bounds_test_enable(enable);
+ }
+
+ self
+ }
+
+ fn validate_set_depth_bounds_test_enable(
+ &self,
+ _enable: bool,
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::DepthBoundsTestEnable)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetDepthBoundsTestEnable-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetDepthBoundsTestEnable-None-03349
+ if !(self.device().api_version() >= Version::V1_3
+ || self.device().enabled_features().extended_dynamic_state)
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`AutoCommandBufferBuilder::set_depth_bounds_test_enable`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ /// Sets the dynamic depth compare op for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the device API version is less than 1.3 and the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is
+ /// not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ pub fn set_depth_compare_op(&mut self, compare_op: CompareOp) -> &mut Self {
+ self.validate_set_depth_compare_op(compare_op).unwrap();
+
+ unsafe {
+ self.inner.set_depth_compare_op(compare_op);
+ }
+
+ self
+ }
+
+ fn validate_set_depth_compare_op(
+ &self,
+ compare_op: CompareOp,
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::DepthCompareOp)?;
+
+ // VUID-vkCmdSetDepthCompareOp-depthCompareOp-parameter
+ compare_op.validate_device(self.device())?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetDepthCompareOp-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetDepthCompareOp-None-03353
+ if !(self.device().api_version() >= Version::V1_3
+ || self.device().enabled_features().extended_dynamic_state)
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`AutoCommandBufferBuilder::set_depth_compare_op`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ /// Sets whether dynamic depth testing is enabled for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the device API version is less than 1.3 and the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is
+ /// not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ pub fn set_depth_test_enable(&mut self, enable: bool) -> &mut Self {
+ self.validate_set_depth_test_enable(enable).unwrap();
+
+ unsafe {
+ self.inner.set_depth_test_enable(enable);
+ }
+
+ self
+ }
+
+ fn validate_set_depth_test_enable(&self, _enable: bool) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::DepthTestEnable)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetDepthTestEnable-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetDepthTestEnable-None-03352
+ if !(self.device().api_version() >= Version::V1_3
+ || self.device().enabled_features().extended_dynamic_state)
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`AutoCommandBufferBuilder::set_depth_test_enable`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ /// Sets whether dynamic depth write is enabled for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the device API version is less than 1.3 and the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is
+ /// not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ pub fn set_depth_write_enable(&mut self, enable: bool) -> &mut Self {
+ self.validate_set_depth_write_enable(enable).unwrap();
+
+ unsafe {
+ self.inner.set_depth_write_enable(enable);
+ }
+
+ self
+ }
+
+ fn validate_set_depth_write_enable(&self, _enable: bool) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::DepthWriteEnable)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetDepthWriteEnable-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetDepthWriteEnable-None-03354
+ if !(self.device().api_version() >= Version::V1_3
+ || self.device().enabled_features().extended_dynamic_state)
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`AutoCommandBufferBuilder::set_depth_write_enable`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ /// Sets the dynamic discard rectangles for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the
+ /// [`ext_discard_rectangles`](crate::device::DeviceExtensions::ext_discard_rectangles)
+ /// extension is not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ /// - Panics if the highest discard rectangle slot being set is greater than the
+ /// [`max_discard_rectangles`](crate::device::Properties::max_discard_rectangles) device
+ /// property.
+ pub fn set_discard_rectangle(
+ &mut self,
+ first_rectangle: u32,
+ rectangles: impl IntoIterator<Item = Scissor>,
+ ) -> &mut Self {
+ let rectangles: SmallVec<[Scissor; 2]> = rectangles.into_iter().collect();
+ self.validate_set_discard_rectangle(first_rectangle, &rectangles)
+ .unwrap();
+
+ unsafe {
+ self.inner
+ .set_discard_rectangle(first_rectangle, rectangles);
+ }
+
+ self
+ }
+
+ fn validate_set_discard_rectangle(
+ &self,
+ first_rectangle: u32,
+ rectangles: &[Scissor],
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::DiscardRectangle)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetDiscardRectangle-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ if self.device().enabled_extensions().ext_discard_rectangles {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`AutoCommandBufferBuilder::set_discard_rectangle`",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["ext_discard_rectangles"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdSetDiscardRectangleEXT-firstDiscardRectangle-00585
+ if first_rectangle + rectangles.len() as u32
+ > self
+ .device()
+ .physical_device()
+ .properties()
+ .max_discard_rectangles
+ .unwrap()
+ {
+ return Err(SetDynamicStateError::MaxDiscardRectanglesExceeded {
+ provided: first_rectangle + rectangles.len() as u32,
+ max: self
+ .device()
+ .physical_device()
+ .properties()
+ .max_discard_rectangles
+ .unwrap(),
+ });
+ }
+
+ Ok(())
+ }
+
+ /// Sets the dynamic front face for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the device API version is less than 1.3 and the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is
+ /// not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ pub fn set_front_face(&mut self, face: FrontFace) -> &mut Self {
+ self.validate_set_front_face(face).unwrap();
+
+ unsafe {
+ self.inner.set_front_face(face);
+ }
+
+ self
+ }
+
+ fn validate_set_front_face(&self, face: FrontFace) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::FrontFace)?;
+
+ // VUID-vkCmdSetFrontFace-frontFace-parameter
+ face.validate_device(self.device())?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetFrontFace-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetFrontFace-None-03383
+ if !(self.device().api_version() >= Version::V1_3
+ || self.device().enabled_features().extended_dynamic_state)
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`AutoCommandBufferBuilder::set_front_face`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ /// Sets the dynamic line stipple values for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the [`ext_line_rasterization`](crate::device::DeviceExtensions::ext_line_rasterization)
+ /// extension is not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ /// - Panics if `factor` is not between 1 and 256 inclusive.
+ pub fn set_line_stipple(&mut self, factor: u32, pattern: u16) -> &mut Self {
+ self.validate_set_line_stipple(factor, pattern).unwrap();
+
+ unsafe {
+ self.inner.set_line_stipple(factor, pattern);
+ }
+
+ self
+ }
+
+ fn validate_set_line_stipple(
+ &self,
+ factor: u32,
+ _pattern: u16,
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::LineStipple)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetLineStippleEXT-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ if !self.device().enabled_extensions().ext_line_rasterization {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`AutoCommandBufferBuilder::set_line_stipple`",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["ext_line_rasterization"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdSetLineStippleEXT-lineStippleFactor-02776
+ if !(1..=256).contains(&factor) {
+ return Err(SetDynamicStateError::FactorOutOfRange);
+ }
+
+ Ok(())
+ }
+
+ /// Sets the dynamic line width for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ /// - If the [`wide_lines`](crate::device::Features::wide_lines) feature is not enabled, panics
+ /// if `line_width` is not 1.0.
+ pub fn set_line_width(&mut self, line_width: f32) -> &mut Self {
+ self.validate_set_line_width(line_width).unwrap();
+
+ unsafe {
+ self.inner.set_line_width(line_width);
+ }
+
+ self
+ }
+
+ fn validate_set_line_width(&self, line_width: f32) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::LineWidth)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetLineWidth-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetLineWidth-lineWidth-00788
+ if !self.device().enabled_features().wide_lines && line_width != 1.0 {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`line_width` is not `1.0`",
+ requires_one_of: RequiresOneOf {
+ features: &["wide_lines"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ /// Sets the dynamic logic op for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the
+ /// [`extended_dynamic_state2_logic_op`](crate::device::Features::extended_dynamic_state2_logic_op)
+ /// feature is not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ pub fn set_logic_op(&mut self, logic_op: LogicOp) -> &mut Self {
+ self.validate_set_logic_op(logic_op).unwrap();
+
+ unsafe {
+ self.inner.set_logic_op(logic_op);
+ }
+
+ self
+ }
+
+ fn validate_set_logic_op(&self, logic_op: LogicOp) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::LogicOp)?;
+
+ // VUID-vkCmdSetLogicOpEXT-logicOp-parameter
+ logic_op.validate_device(self.device())?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetLogicOpEXT-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetLogicOpEXT-None-04867
+ if !self
+ .device()
+ .enabled_features()
+ .extended_dynamic_state2_logic_op
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`AutoCommandBufferBuilder::set_logic_op`",
+ requires_one_of: RequiresOneOf {
+ features: &["extended_dynamic_state2_logic_op"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ /// Sets the dynamic number of patch control points for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the
+ /// [`extended_dynamic_state2_patch_control_points`](crate::device::Features::extended_dynamic_state2_patch_control_points)
+ /// feature is not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ /// - Panics if `num` is 0.
+ /// - Panics if `num` is greater than the
+ /// [`max_tessellation_patch_size`](crate::device::Properties::max_tessellation_patch_size)
+ /// property of the device.
+ pub fn set_patch_control_points(&mut self, num: u32) -> &mut Self {
+ self.validate_set_patch_control_points(num).unwrap();
+
+ unsafe {
+ self.inner.set_patch_control_points(num);
+ }
+
+ self
+ }
+
+ fn validate_set_patch_control_points(&self, num: u32) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::PatchControlPoints)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetPatchControlPointsEXT-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetPatchControlPointsEXT-None-04873
+ if !self
+ .device()
+ .enabled_features()
+ .extended_dynamic_state2_patch_control_points
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`AutoCommandBufferBuilder::set_patch_control_points`",
+ requires_one_of: RequiresOneOf {
+ features: &["extended_dynamic_state2_patch_control_points"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdSetPatchControlPointsEXT-patchControlPoints-04874
+ assert!(num > 0, "num must be greater than 0");
+
+ // VUID-vkCmdSetPatchControlPointsEXT-patchControlPoints-04874
+ if num
+ > self
+ .device()
+ .physical_device()
+ .properties()
+ .max_tessellation_patch_size
+ {
+ return Err(SetDynamicStateError::MaxTessellationPatchSizeExceeded {
+ provided: num,
+ max: self
+ .device()
+ .physical_device()
+ .properties()
+ .max_tessellation_patch_size,
+ });
+ }
+
+ Ok(())
+ }
+
+ /// Sets whether dynamic primitive restart is enabled for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the device API version is less than 1.3 and the
+ /// [`extended_dynamic_state2`](crate::device::Features::extended_dynamic_state2) feature is
+ /// not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ pub fn set_primitive_restart_enable(&mut self, enable: bool) -> &mut Self {
+ self.validate_set_primitive_restart_enable(enable).unwrap();
+
+ unsafe {
+ self.inner.set_primitive_restart_enable(enable);
+ }
+
+ self
+ }
+
+ fn validate_set_primitive_restart_enable(
+ &self,
+ _enable: bool,
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::PrimitiveRestartEnable)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetPrimitiveRestartEnable-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetPrimitiveRestartEnable-None-04866
+ if !(self.device().api_version() >= Version::V1_3
+ || self.device().enabled_features().extended_dynamic_state2)
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`AutoCommandBufferBuilder::set_primitive_restart_enable`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state2"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ /// Sets the dynamic primitive topology for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the device API version is less than 1.3 and the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is
+ /// not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ /// - If the [`geometry_shader`](crate::device::Features::geometry_shader) feature is not
+ /// enabled, panics if `topology` is a `WithAdjacency` topology.
+ /// - If the [`tessellation_shader`](crate::device::Features::tessellation_shader) feature is
+ /// not enabled, panics if `topology` is `PatchList`.
+ pub fn set_primitive_topology(&mut self, topology: PrimitiveTopology) -> &mut Self {
+ self.validate_set_primitive_topology(topology).unwrap();
+
+ unsafe {
+ self.inner.set_primitive_topology(topology);
+ }
+
+ self
+ }
+
+ fn validate_set_primitive_topology(
+ &self,
+ topology: PrimitiveTopology,
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::PrimitiveTopology)?;
+
+ // VUID-vkCmdSetPrimitiveTopology-primitiveTopology-parameter
+ topology.validate_device(self.device())?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetPrimitiveTopology-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetPrimitiveTopology-None-03347
+ if !(self.device().api_version() >= Version::V1_3
+ || self.device().enabled_features().extended_dynamic_state)
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`AutoCommandBufferBuilder::set_primitive_topology`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID?
+ // Since these requirements exist for fixed state when creating the pipeline,
+ // I assume they exist for dynamic state as well.
+ match topology {
+ PrimitiveTopology::TriangleFan => {
+ if self.device().enabled_extensions().khr_portability_subset
+ && !self.device().enabled_features().triangle_fans
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "this device is a portability subset device, and `topology` \
+ is `PrimitiveTopology::TriangleFan`",
+ requires_one_of: RequiresOneOf {
+ features: &["triangle_fans"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ PrimitiveTopology::LineListWithAdjacency
+ | PrimitiveTopology::LineStripWithAdjacency
+ | PrimitiveTopology::TriangleListWithAdjacency
+ | PrimitiveTopology::TriangleStripWithAdjacency => {
+ if !self.device().enabled_features().geometry_shader {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`topology` is `PrimitiveTopology::*WithAdjacency`",
+ requires_one_of: RequiresOneOf {
+ features: &["geometry_shader"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ PrimitiveTopology::PatchList => {
+ if !self.device().enabled_features().tessellation_shader {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`topology` is `PrimitiveTopology::PatchList`",
+ requires_one_of: RequiresOneOf {
+ features: &["tessellation_shader"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ _ => (),
+ }
+
+ Ok(())
+ }
+
+ /// Sets whether dynamic rasterizer discard is enabled for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the device API version is less than 1.3 and the
+ /// [`extended_dynamic_state2`](crate::device::Features::extended_dynamic_state2) feature is
+ /// not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ pub fn set_rasterizer_discard_enable(&mut self, enable: bool) -> &mut Self {
+ self.validate_set_rasterizer_discard_enable(enable).unwrap();
+
+ unsafe {
+ self.inner.set_rasterizer_discard_enable(enable);
+ }
+
+ self
+ }
+
+ fn validate_set_rasterizer_discard_enable(
+ &self,
+ _enable: bool,
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::RasterizerDiscardEnable)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetRasterizerDiscardEnable-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetRasterizerDiscardEnable-None-04871
+ if !(self.device().api_version() >= Version::V1_3
+ || self.device().enabled_features().extended_dynamic_state2)
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`AutoCommandBufferBuilder::set_rasterizer_discard_enable`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state2"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ /// Sets the dynamic scissors for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ /// - Panics if the highest scissor slot being set is greater than the
+ /// [`max_viewports`](crate::device::Properties::max_viewports) device property.
+ /// - If the [`multi_viewport`](crate::device::Features::multi_viewport) feature is not enabled,
+ /// panics if `first_scissor` is not 0, or if more than 1 scissor is provided.
+ pub fn set_scissor(
+ &mut self,
+ first_scissor: u32,
+ scissors: impl IntoIterator<Item = Scissor>,
+ ) -> &mut Self {
+ let scissors: SmallVec<[Scissor; 2]> = scissors.into_iter().collect();
+ self.validate_set_scissor(first_scissor, &scissors).unwrap();
+
+ unsafe {
+ self.inner.set_scissor(first_scissor, scissors);
+ }
+
+ self
+ }
+
+ fn validate_set_scissor(
+ &self,
+ first_scissor: u32,
+ scissors: &[Scissor],
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::Scissor)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetScissor-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetScissor-firstScissor-00592
+ if first_scissor + scissors.len() as u32
+ > self.device().physical_device().properties().max_viewports
+ {
+ return Err(SetDynamicStateError::MaxViewportsExceeded {
+ provided: first_scissor + scissors.len() as u32,
+ max: self.device().physical_device().properties().max_viewports,
+ });
+ }
+
+ if !self.device().enabled_features().multi_viewport {
+ // VUID-vkCmdSetScissor-firstScissor-00593
+ if first_scissor != 0 {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`first_scissor` is not `0`",
+ requires_one_of: RequiresOneOf {
+ features: &["multi_viewport"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdSetScissor-scissorCount-00594
+ if scissors.len() > 1 {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`scissors.len()` is greater than `1`",
+ requires_one_of: RequiresOneOf {
+ features: &["multi_viewport"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+
+ Ok(())
+ }
+
+ /// Sets the dynamic scissors with count for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the device API version is less than 1.3 and the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is
+ /// not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ /// - Panics if the highest scissor slot being set is greater than the
+ /// [`max_viewports`](crate::device::Properties::max_viewports) device property.
+ /// - If the [`multi_viewport`](crate::device::Features::multi_viewport) feature is not enabled,
+ /// panics if more than 1 scissor is provided.
+ pub fn set_scissor_with_count(
+ &mut self,
+ scissors: impl IntoIterator<Item = Scissor>,
+ ) -> &mut Self {
+ let scissors: SmallVec<[Scissor; 2]> = scissors.into_iter().collect();
+ self.validate_set_scissor_with_count(&scissors).unwrap();
+
+ unsafe {
+ self.inner.set_scissor_with_count(scissors);
+ }
+
+ self
+ }
+
+ fn validate_set_scissor_with_count(
+ &self,
+ scissors: &[Scissor],
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::ScissorWithCount)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetScissorWithCount-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetScissorWithCount-None-03396
+ if !(self.device().api_version() >= Version::V1_3
+ || self.device().enabled_features().extended_dynamic_state)
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`AutoCommandBufferBuilder::set_scissor_with_count`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdSetScissorWithCount-scissorCount-03397
+ if scissors.len() as u32 > self.device().physical_device().properties().max_viewports {
+ return Err(SetDynamicStateError::MaxViewportsExceeded {
+ provided: scissors.len() as u32,
+ max: self.device().physical_device().properties().max_viewports,
+ });
+ }
+
+ // VUID-vkCmdSetScissorWithCount-scissorCount-03398
+ if !self.device().enabled_features().multi_viewport && scissors.len() > 1 {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`scissors.len()` is greater than `1`",
+ requires_one_of: RequiresOneOf {
+ features: &["multi_viewport"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ /// Sets the dynamic stencil compare mask on one or both faces for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ pub fn set_stencil_compare_mask(
+ &mut self,
+ faces: StencilFaces,
+ compare_mask: u32,
+ ) -> &mut Self {
+ self.validate_set_stencil_compare_mask(faces, compare_mask)
+ .unwrap();
+
+ unsafe {
+ self.inner.set_stencil_compare_mask(faces, compare_mask);
+ }
+
+ self
+ }
+
+ fn validate_set_stencil_compare_mask(
+ &self,
+ faces: StencilFaces,
+ _compare_mask: u32,
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::StencilCompareMask)?;
+
+ // VUID-vkCmdSetStencilCompareMask-faceMask-parameter
+ faces.validate_device(self.device())?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetStencilCompareMask-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ Ok(())
+ }
+
+ /// Sets the dynamic stencil ops on one or both faces for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the device API version is less than 1.3 and the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is
+ /// not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ pub fn set_stencil_op(
+ &mut self,
+ faces: StencilFaces,
+ fail_op: StencilOp,
+ pass_op: StencilOp,
+ depth_fail_op: StencilOp,
+ compare_op: CompareOp,
+ ) -> &mut Self {
+ self.validate_set_stencil_op(faces, fail_op, pass_op, depth_fail_op, compare_op)
+ .unwrap();
+
+ unsafe {
+ self.inner
+ .set_stencil_op(faces, fail_op, pass_op, depth_fail_op, compare_op);
+ }
+
+ self
+ }
+
+ fn validate_set_stencil_op(
+ &self,
+ faces: StencilFaces,
+ fail_op: StencilOp,
+ pass_op: StencilOp,
+ depth_fail_op: StencilOp,
+ compare_op: CompareOp,
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::StencilOp)?;
+
+ // VUID-vkCmdSetStencilOp-faceMask-parameter
+ faces.validate_device(self.device())?;
+
+ // VUID-vkCmdSetStencilOp-failOp-parameter
+ fail_op.validate_device(self.device())?;
+
+ // VUID-vkCmdSetStencilOp-passOp-parameter
+ pass_op.validate_device(self.device())?;
+
+ // VUID-vkCmdSetStencilOp-depthFailOp-parameter
+ depth_fail_op.validate_device(self.device())?;
+
+ // VUID-vkCmdSetStencilOp-compareOp-parameter
+ compare_op.validate_device(self.device())?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetStencilOp-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetStencilOp-None-03351
+ if !(self.device().api_version() >= Version::V1_3
+ || self.device().enabled_features().extended_dynamic_state)
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`AutoCommandBufferBuilder::set_stencil_op`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ /// Sets the dynamic stencil reference on one or both faces for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ pub fn set_stencil_reference(&mut self, faces: StencilFaces, reference: u32) -> &mut Self {
+ self.validate_set_stencil_reference(faces, reference)
+ .unwrap();
+
+ unsafe {
+ self.inner.set_stencil_reference(faces, reference);
+ }
+
+ self
+ }
+
+ fn validate_set_stencil_reference(
+ &self,
+ faces: StencilFaces,
+ _reference: u32,
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::StencilReference)?;
+
+ // VUID-vkCmdSetStencilReference-faceMask-parameter
+ faces.validate_device(self.device())?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetStencilReference-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ Ok(())
+ }
+
+ /// Sets whether dynamic stencil testing is enabled for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the device API version is less than 1.3 and the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is
+ /// not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ pub fn set_stencil_test_enable(&mut self, enable: bool) -> &mut Self {
+ self.validate_set_stencil_test_enable(enable).unwrap();
+
+ unsafe {
+ self.inner.set_stencil_test_enable(enable);
+ }
+
+ self
+ }
+
+ fn validate_set_stencil_test_enable(&self, _enable: bool) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::StencilTestEnable)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetStencilTestEnable-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetStencilTestEnable-None-03350
+ if !(self.device().api_version() >= Version::V1_3
+ || self.device().enabled_features().extended_dynamic_state)
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`AutoCommandBufferBuilder::set_stencil_test_enable`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ /// Sets the dynamic stencil write mask on one or both faces for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ pub fn set_stencil_write_mask(&mut self, faces: StencilFaces, write_mask: u32) -> &mut Self {
+ self.validate_set_stencil_write_mask(faces, write_mask)
+ .unwrap();
+
+ unsafe {
+ self.inner.set_stencil_write_mask(faces, write_mask);
+ }
+
+ self
+ }
+
+ fn validate_set_stencil_write_mask(
+ &self,
+ faces: StencilFaces,
+ _write_mask: u32,
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::StencilWriteMask)?;
+
+ // VUID-vkCmdSetStencilWriteMask-faceMask-parameter
+ faces.validate_device(self.device())?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetStencilWriteMask-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ Ok(())
+ }
+
+ /// Sets the dynamic viewports for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ /// - Panics if the highest viewport slot being set is greater than the
+ /// [`max_viewports`](crate::device::Properties::max_viewports) device property.
+ /// - If the [`multi_viewport`](crate::device::Features::multi_viewport) feature is not enabled,
+ /// panics if `first_viewport` is not 0, or if more than 1 viewport is provided.
+ pub fn set_viewport(
+ &mut self,
+ first_viewport: u32,
+ viewports: impl IntoIterator<Item = Viewport>,
+ ) -> &mut Self {
+ let viewports: SmallVec<[Viewport; 2]> = viewports.into_iter().collect();
+ self.validate_set_viewport(first_viewport, &viewports)
+ .unwrap();
+
+ unsafe {
+ self.inner.set_viewport(first_viewport, viewports);
+ }
+
+ self
+ }
+
+ fn validate_set_viewport(
+ &self,
+ first_viewport: u32,
+ viewports: &[Viewport],
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::Viewport)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetViewport-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetViewport-firstViewport-01223
+ if first_viewport + viewports.len() as u32
+ > self.device().physical_device().properties().max_viewports
+ {
+ return Err(SetDynamicStateError::MaxViewportsExceeded {
+ provided: first_viewport + viewports.len() as u32,
+ max: self.device().physical_device().properties().max_viewports,
+ });
+ }
+
+ if !self.device().enabled_features().multi_viewport {
+ // VUID-vkCmdSetViewport-firstViewport-01224
+ if first_viewport != 0 {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`first_scissors` is not `0`",
+ requires_one_of: RequiresOneOf {
+ features: &["multi_viewport"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdSetViewport-viewportCount-01225
+ if viewports.len() > 1 {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`viewports.len()` is greater than `1`",
+ requires_one_of: RequiresOneOf {
+ features: &["multi_viewport"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+
+ Ok(())
+ }
+
+ /// Sets the dynamic viewports with count for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the device API version is less than 1.3 and the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is
+ /// not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ /// - Panics if the highest viewport slot being set is greater than the
+ /// [`max_viewports`](crate::device::Properties::max_viewports) device property.
+ /// - If the [`multi_viewport`](crate::device::Features::multi_viewport) feature is not enabled,
+ /// panics if more than 1 viewport is provided.
+ pub fn set_viewport_with_count(
+ &mut self,
+ viewports: impl IntoIterator<Item = Viewport>,
+ ) -> &mut Self {
+ let viewports: SmallVec<[Viewport; 2]> = viewports.into_iter().collect();
+ self.validate_set_viewport_with_count(&viewports).unwrap();
+
+ unsafe {
+ self.inner.set_viewport_with_count(viewports);
+ }
+
+ self
+ }
+
+ fn validate_set_viewport_with_count(
+ &self,
+ viewports: &[Viewport],
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::ViewportWithCount)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetViewportWithCount-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetViewportWithCount-None-03393
+ if !(self.device().api_version() >= Version::V1_3
+ || self.device().enabled_features().extended_dynamic_state)
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`AutoCommandBufferBuilder::set_viewport_with_count`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdSetViewportWithCount-viewportCount-03394
+ if viewports.len() as u32 > self.device().physical_device().properties().max_viewports {
+ return Err(SetDynamicStateError::MaxViewportsExceeded {
+ provided: viewports.len() as u32,
+ max: self.device().physical_device().properties().max_viewports,
+ });
+ }
+
+ // VUID-vkCmdSetViewportWithCount-viewportCount-03395
+ if !self.device().enabled_features().multi_viewport && viewports.len() > 1 {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`viewports.len()` is greater than `1`",
+ requires_one_of: RequiresOneOf {
+ features: &["multi_viewport"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+}
+
+impl SyncCommandBufferBuilder {
+ /// Calls `vkCmdSetBlendConstants` on the builder.
+ #[inline]
+ pub unsafe fn set_blend_constants(&mut self, constants: [f32; 4]) {
+ struct Cmd {
+ constants: [f32; 4],
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "set_blend_constants"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.set_blend_constants(self.constants);
+ }
+ }
+
+ self.commands.push(Box::new(Cmd { constants }));
+ self.current_state.blend_constants = Some(constants);
+ }
+
+ /// Calls `vkCmdSetColorWriteEnableEXT` on the builder.
+ ///
+ /// If the list is empty then the command is automatically ignored.
+ pub unsafe fn set_color_write_enable(&mut self, enables: impl IntoIterator<Item = bool>) {
+ struct Cmd<I> {
+ enables: Mutex<Option<I>>,
+ }
+
+ impl<I> Command for Cmd<I>
+ where
+ I: IntoIterator<Item = bool> + Send + Sync,
+ {
+ fn name(&self) -> &'static str {
+ "set_color_write_enable"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.set_color_write_enable(self.enables.lock().take().unwrap());
+ }
+ }
+
+ let enables: SmallVec<[bool; 4]> = enables.into_iter().collect();
+ self.current_state.color_write_enable = Some(enables.clone());
+ self.commands.push(Box::new(Cmd {
+ enables: Mutex::new(Some(enables)),
+ }));
+ }
+
+ /// Calls `vkCmdSetCullModeEXT` on the builder.
+ #[inline]
+ pub unsafe fn set_cull_mode(&mut self, cull_mode: CullMode) {
+ struct Cmd {
+ cull_mode: CullMode,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "set_cull_mode"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.set_cull_mode(self.cull_mode);
+ }
+ }
+
+ self.commands.push(Box::new(Cmd { cull_mode }));
+ self.current_state.cull_mode = Some(cull_mode);
+ }
+
+ /// Calls `vkCmdSetDepthBias` on the builder.
+ #[inline]
+ pub unsafe fn set_depth_bias(&mut self, constant_factor: f32, clamp: f32, slope_factor: f32) {
+ struct Cmd {
+ constant_factor: f32,
+ clamp: f32,
+ slope_factor: f32,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "set_depth_bias"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.set_depth_bias(self.constant_factor, self.clamp, self.slope_factor);
+ }
+ }
+
+ self.commands.push(Box::new(Cmd {
+ constant_factor,
+ clamp,
+ slope_factor,
+ }));
+ self.current_state.depth_bias = Some(DepthBias {
+ constant_factor,
+ clamp,
+ slope_factor,
+ });
+ }
+
+ /// Calls `vkCmdSetDepthBiasEnableEXT` on the builder.
+ #[inline]
+ pub unsafe fn set_depth_bias_enable(&mut self, enable: bool) {
+ struct Cmd {
+ enable: bool,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "set_depth_bias_enable"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.set_depth_bias_enable(self.enable);
+ }
+ }
+
+ self.commands.push(Box::new(Cmd { enable }));
+ self.current_state.depth_bias_enable = Some(enable);
+ }
+
+ /// Calls `vkCmdSetDepthBounds` on the builder.
+ #[inline]
+ pub unsafe fn set_depth_bounds(&mut self, bounds: RangeInclusive<f32>) {
+ struct Cmd {
+ bounds: RangeInclusive<f32>,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "set_depth_bounds"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.set_depth_bounds(self.bounds.clone());
+ }
+ }
+
+ self.commands.push(Box::new(Cmd {
+ bounds: bounds.clone(),
+ }));
+ self.current_state.depth_bounds = Some(bounds);
+ }
+
+ /// Calls `vkCmdSetDepthBoundsTestEnableEXT` on the builder.
+ #[inline]
+ pub unsafe fn set_depth_bounds_test_enable(&mut self, enable: bool) {
+ struct Cmd {
+ enable: bool,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "set_depth_bounds_test_enable"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.set_depth_bounds_test_enable(self.enable);
+ }
+ }
+
+ self.commands.push(Box::new(Cmd { enable }));
+ self.current_state.depth_bounds_test_enable = Some(enable);
+ }
+
+ /// Calls `vkCmdSetDepthCompareOpEXT` on the builder.
+ #[inline]
+ pub unsafe fn set_depth_compare_op(&mut self, compare_op: CompareOp) {
+ struct Cmd {
+ compare_op: CompareOp,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "set_depth_compare_op"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.set_depth_compare_op(self.compare_op);
+ }
+ }
+
+ self.commands.push(Box::new(Cmd { compare_op }));
+ self.current_state.depth_compare_op = Some(compare_op);
+ }
+
+ /// Calls `vkCmdSetDepthTestEnableEXT` on the builder.
+ #[inline]
+ pub unsafe fn set_depth_test_enable(&mut self, enable: bool) {
+ struct Cmd {
+ enable: bool,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "set_depth_test_enable"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.set_depth_test_enable(self.enable);
+ }
+ }
+
+ self.commands.push(Box::new(Cmd { enable }));
+ self.current_state.depth_test_enable = Some(enable);
+ }
+
+ /// Calls `vkCmdSetDepthWriteEnableEXT` on the builder.
+ #[inline]
+ pub unsafe fn set_depth_write_enable(&mut self, enable: bool) {
+ struct Cmd {
+ enable: bool,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "set_depth_write_enable"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.set_depth_write_enable(self.enable);
+ }
+ }
+
+ self.commands.push(Box::new(Cmd { enable }));
+ self.current_state.depth_write_enable = Some(enable);
+ }
+
+ /// Calls `vkCmdSetDiscardRectangle` on the builder.
+ ///
+ /// If the list is empty then the command is automatically ignored.
+ pub unsafe fn set_discard_rectangle(
+ &mut self,
+ first_rectangle: u32,
+ rectangles: impl IntoIterator<Item = Scissor>,
+ ) {
+ struct Cmd {
+ first_rectangle: u32,
+ rectangles: Mutex<SmallVec<[Scissor; 2]>>,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "set_discard_rectangle"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.set_discard_rectangle(self.first_rectangle, self.rectangles.lock().drain(..));
+ }
+ }
+
+ let rectangles: SmallVec<[Scissor; 2]> = rectangles.into_iter().collect();
+
+ for (num, rectangle) in rectangles.iter().enumerate() {
+ let num = num as u32 + first_rectangle;
+ self.current_state.discard_rectangle.insert(num, *rectangle);
+ }
+
+ self.commands.push(Box::new(Cmd {
+ first_rectangle,
+ rectangles: Mutex::new(rectangles),
+ }));
+ }
+
+ /// Calls `vkCmdSetFrontFaceEXT` on the builder.
+ #[inline]
+ pub unsafe fn set_front_face(&mut self, face: FrontFace) {
+ struct Cmd {
+ face: FrontFace,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "set_front_face"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.set_front_face(self.face);
+ }
+ }
+
+ self.commands.push(Box::new(Cmd { face }));
+ self.current_state.front_face = Some(face);
+ }
+
+ /// Calls `vkCmdSetLineStippleEXT` on the builder.
+ #[inline]
+ pub unsafe fn set_line_stipple(&mut self, factor: u32, pattern: u16) {
+ struct Cmd {
+ factor: u32,
+ pattern: u16,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "set_line_stipple"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.set_line_stipple(self.factor, self.pattern);
+ }
+ }
+
+ self.commands.push(Box::new(Cmd { factor, pattern }));
+ self.current_state.line_stipple = Some(LineStipple { factor, pattern });
+ }
+
+ /// Calls `vkCmdSetLineWidth` on the builder.
+ #[inline]
+ pub unsafe fn set_line_width(&mut self, line_width: f32) {
+ struct Cmd {
+ line_width: f32,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "set_line_width"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.set_line_width(self.line_width);
+ }
+ }
+
+ self.commands.push(Box::new(Cmd { line_width }));
+ self.current_state.line_width = Some(line_width);
+ }
+
+ /// Calls `vkCmdSetLogicOpEXT` on the builder.
+ #[inline]
+ pub unsafe fn set_logic_op(&mut self, logic_op: LogicOp) {
+ struct Cmd {
+ logic_op: LogicOp,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "set_logic_op"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.set_logic_op(self.logic_op);
+ }
+ }
+
+ self.commands.push(Box::new(Cmd { logic_op }));
+ self.current_state.logic_op = Some(logic_op);
+ }
+
+ /// Calls `vkCmdSetPatchControlPointsEXT` on the builder.
+ #[inline]
+ pub unsafe fn set_patch_control_points(&mut self, num: u32) {
+ struct Cmd {
+ num: u32,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "set_patch_control_points"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.set_patch_control_points(self.num);
+ }
+ }
+
+ self.commands.push(Box::new(Cmd { num }));
+ self.current_state.patch_control_points = Some(num);
+ }
+
+ /// Calls `vkCmdSetPrimitiveRestartEnableEXT` on the builder.
+ #[inline]
+ pub unsafe fn set_primitive_restart_enable(&mut self, enable: bool) {
+ struct Cmd {
+ enable: bool,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "set_primitive_restart_enable"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.set_primitive_restart_enable(self.enable);
+ }
+ }
+
+ self.commands.push(Box::new(Cmd { enable }));
+ self.current_state.primitive_restart_enable = Some(enable);
+ }
+
+ /// Calls `vkCmdSetPrimitiveTopologyEXT` on the builder.
+ #[inline]
+ pub unsafe fn set_primitive_topology(&mut self, topology: PrimitiveTopology) {
+ struct Cmd {
+ topology: PrimitiveTopology,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "set_primitive_topology"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.set_primitive_topology(self.topology);
+ }
+ }
+
+ self.commands.push(Box::new(Cmd { topology }));
+ self.current_state.primitive_topology = Some(topology);
+ }
+
+ /// Calls `vkCmdSetRasterizerDiscardEnableEXT` on the builder.
+ #[inline]
+ pub unsafe fn set_rasterizer_discard_enable(&mut self, enable: bool) {
+ struct Cmd {
+ enable: bool,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "set_rasterizer_discard_enable"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.set_rasterizer_discard_enable(self.enable);
+ }
+ }
+
+ self.commands.push(Box::new(Cmd { enable }));
+ self.current_state.rasterizer_discard_enable = Some(enable);
+ }
+
+ /// Calls `vkCmdSetStencilCompareMask` on the builder.
+ #[inline]
+ pub unsafe fn set_stencil_compare_mask(&mut self, faces: StencilFaces, compare_mask: u32) {
+ struct Cmd {
+ faces: StencilFaces,
+ compare_mask: u32,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "set_stencil_compare_mask"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.set_stencil_compare_mask(self.faces, self.compare_mask);
+ }
+ }
+
+ self.commands.push(Box::new(Cmd {
+ faces,
+ compare_mask,
+ }));
+
+ let faces = ash::vk::StencilFaceFlags::from(faces);
+
+ if faces.intersects(ash::vk::StencilFaceFlags::FRONT) {
+ self.current_state.stencil_compare_mask.front = Some(compare_mask);
+ }
+
+ if faces.intersects(ash::vk::StencilFaceFlags::BACK) {
+ self.current_state.stencil_compare_mask.back = Some(compare_mask);
+ }
+ }
+
+ /// Calls `vkCmdSetStencilOpEXT` on the builder.
+ #[inline]
+ pub unsafe fn set_stencil_op(
+ &mut self,
+ faces: StencilFaces,
+ fail_op: StencilOp,
+ pass_op: StencilOp,
+ depth_fail_op: StencilOp,
+ compare_op: CompareOp,
+ ) {
+ struct Cmd {
+ faces: StencilFaces,
+ fail_op: StencilOp,
+ pass_op: StencilOp,
+ depth_fail_op: StencilOp,
+ compare_op: CompareOp,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "set_stencil_op"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.set_stencil_op(
+ self.faces,
+ self.fail_op,
+ self.pass_op,
+ self.depth_fail_op,
+ self.compare_op,
+ );
+ }
+ }
+
+ self.commands.push(Box::new(Cmd {
+ faces,
+ fail_op,
+ pass_op,
+ depth_fail_op,
+ compare_op,
+ }));
+
+ let faces = ash::vk::StencilFaceFlags::from(faces);
+
+ if faces.intersects(ash::vk::StencilFaceFlags::FRONT) {
+ self.current_state.stencil_op.front = Some(StencilOps {
+ fail_op,
+ pass_op,
+ depth_fail_op,
+ compare_op,
+ });
+ }
+
+ if faces.intersects(ash::vk::StencilFaceFlags::BACK) {
+ self.current_state.stencil_op.back = Some(StencilOps {
+ fail_op,
+ pass_op,
+ depth_fail_op,
+ compare_op,
+ });
+ }
+ }
+
+ /// Calls `vkCmdSetStencilReference` on the builder.
+ #[inline]
+ pub unsafe fn set_stencil_reference(&mut self, faces: StencilFaces, reference: u32) {
+ struct Cmd {
+ faces: StencilFaces,
+ reference: u32,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "set_stencil_reference"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.set_stencil_reference(self.faces, self.reference);
+ }
+ }
+
+ self.commands.push(Box::new(Cmd { faces, reference }));
+
+ let faces = ash::vk::StencilFaceFlags::from(faces);
+
+ if faces.intersects(ash::vk::StencilFaceFlags::FRONT) {
+ self.current_state.stencil_reference.front = Some(reference);
+ }
+
+ if faces.intersects(ash::vk::StencilFaceFlags::BACK) {
+ self.current_state.stencil_reference.back = Some(reference);
+ }
+ }
+
+ /// Calls `vkCmdSetStencilTestEnableEXT` on the builder.
+ #[inline]
+ pub unsafe fn set_stencil_test_enable(&mut self, enable: bool) {
+ struct Cmd {
+ enable: bool,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "set_stencil_test_enable"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.set_stencil_test_enable(self.enable);
+ }
+ }
+
+ self.commands.push(Box::new(Cmd { enable }));
+ self.current_state.stencil_test_enable = Some(enable);
+ }
+
+ /// Calls `vkCmdSetStencilWriteMask` on the builder.
+ #[inline]
+ pub unsafe fn set_stencil_write_mask(&mut self, faces: StencilFaces, write_mask: u32) {
+ struct Cmd {
+ faces: StencilFaces,
+ write_mask: u32,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "set_stencil_write_mask"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.set_stencil_write_mask(self.faces, self.write_mask);
+ }
+ }
+
+ self.commands.push(Box::new(Cmd { faces, write_mask }));
+
+ let faces = ash::vk::StencilFaceFlags::from(faces);
+
+ if faces.intersects(ash::vk::StencilFaceFlags::FRONT) {
+ self.current_state.stencil_write_mask.front = Some(write_mask);
+ }
+
+ if faces.intersects(ash::vk::StencilFaceFlags::BACK) {
+ self.current_state.stencil_write_mask.back = Some(write_mask);
+ }
+ }
+
+ /// Calls `vkCmdSetScissor` on the builder.
+ ///
+ /// If the list is empty then the command is automatically ignored.
+ pub unsafe fn set_scissor(
+ &mut self,
+ first_scissor: u32,
+ scissors: impl IntoIterator<Item = Scissor>,
+ ) {
+ struct Cmd {
+ first_scissor: u32,
+ scissors: Mutex<SmallVec<[Scissor; 2]>>,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "set_scissor"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.set_scissor(self.first_scissor, self.scissors.lock().drain(..));
+ }
+ }
+
+ let scissors: SmallVec<[Scissor; 2]> = scissors.into_iter().collect();
+
+ for (num, scissor) in scissors.iter().enumerate() {
+ let num = num as u32 + first_scissor;
+ self.current_state.scissor.insert(num, *scissor);
+ }
+
+ self.commands.push(Box::new(Cmd {
+ first_scissor,
+ scissors: Mutex::new(scissors),
+ }));
+ }
+
+ /// Calls `vkCmdSetScissorWithCountEXT` on the builder.
+ ///
+ /// If the list is empty then the command is automatically ignored.
+ pub unsafe fn set_scissor_with_count(&mut self, scissors: impl IntoIterator<Item = Scissor>) {
+ struct Cmd {
+ scissors: Mutex<SmallVec<[Scissor; 2]>>,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "set_scissor_with_count"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.set_scissor_with_count(self.scissors.lock().drain(..));
+ }
+ }
+
+ let scissors: SmallVec<[Scissor; 2]> = scissors.into_iter().collect();
+ self.current_state.scissor_with_count = Some(scissors.clone());
+ self.commands.push(Box::new(Cmd {
+ scissors: Mutex::new(scissors),
+ }));
+ }
+
+ /// Calls `vkCmdSetViewport` on the builder.
+ ///
+ /// If the list is empty then the command is automatically ignored.
+ pub unsafe fn set_viewport(
+ &mut self,
+ first_viewport: u32,
+ viewports: impl IntoIterator<Item = Viewport>,
+ ) {
+ struct Cmd {
+ first_viewport: u32,
+ viewports: Mutex<SmallVec<[Viewport; 2]>>,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "set_viewport"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.set_viewport(self.first_viewport, self.viewports.lock().drain(..));
+ }
+ }
+
+ let viewports: SmallVec<[Viewport; 2]> = viewports.into_iter().collect();
+
+ for (num, viewport) in viewports.iter().enumerate() {
+ let num = num as u32 + first_viewport;
+ self.current_state.viewport.insert(num, viewport.clone());
+ }
+
+ self.commands.push(Box::new(Cmd {
+ first_viewport,
+ viewports: Mutex::new(viewports),
+ }));
+ }
+
+ /// Calls `vkCmdSetViewportWithCountEXT` on the builder.
+ ///
+ /// If the list is empty then the command is automatically ignored.
+ pub unsafe fn set_viewport_with_count(
+ &mut self,
+ viewports: impl IntoIterator<Item = Viewport>,
+ ) {
+ struct Cmd {
+ viewports: Mutex<SmallVec<[Viewport; 2]>>,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "set_viewport_with_count"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.set_viewport_with_count(self.viewports.lock().drain(..));
+ }
+ }
+
+ let viewports: SmallVec<[Viewport; 2]> = viewports.into_iter().collect();
+ self.current_state.viewport_with_count = Some(viewports.clone());
+ self.commands.push(Box::new(Cmd {
+ viewports: Mutex::new(viewports),
+ }));
+ }
+}
+
+impl UnsafeCommandBufferBuilder {
+ /// Calls `vkCmdSetBlendConstants` on the builder.
+ #[inline]
+ pub unsafe fn set_blend_constants(&mut self, constants: [f32; 4]) {
+ let fns = self.device.fns();
+ (fns.v1_0.cmd_set_blend_constants)(self.handle, &constants);
+ }
+
+ /// Calls `vkCmdSetColorWriteEnableEXT` on the builder.
+ ///
+ /// If the list is empty then the command is automatically ignored.
+ pub unsafe fn set_color_write_enable(&mut self, enables: impl IntoIterator<Item = bool>) {
+ debug_assert!(self.device.enabled_extensions().ext_color_write_enable);
+
+ let enables = enables
+ .into_iter()
+ .map(|v| v as ash::vk::Bool32)
+ .collect::<SmallVec<[_; 4]>>();
+ if enables.is_empty() {
+ return;
+ }
+
+ let fns = self.device.fns();
+ (fns.ext_color_write_enable.cmd_set_color_write_enable_ext)(
+ self.handle,
+ enables.len() as u32,
+ enables.as_ptr(),
+ );
+ }
+
+ /// Calls `vkCmdSetCullModeEXT` on the builder.
+ #[inline]
+ pub unsafe fn set_cull_mode(&mut self, cull_mode: CullMode) {
+ let fns = self.device.fns();
+
+ if self.device.api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_set_cull_mode)(self.handle, cull_mode.into());
+ } else {
+ debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state);
+ (fns.ext_extended_dynamic_state.cmd_set_cull_mode_ext)(self.handle, cull_mode.into());
+ }
+ }
+
+ /// Calls `vkCmdSetDepthBias` on the builder.
+ #[inline]
+ pub unsafe fn set_depth_bias(&mut self, constant_factor: f32, clamp: f32, slope_factor: f32) {
+ let fns = self.device.fns();
+ (fns.v1_0.cmd_set_depth_bias)(self.handle, constant_factor, clamp, slope_factor);
+ }
+
+ /// Calls `vkCmdSetDepthBiasEnableEXT` on the builder.
+ #[inline]
+ pub unsafe fn set_depth_bias_enable(&mut self, enable: bool) {
+ let fns = self.device.fns();
+
+ if self.device.api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_set_depth_bias_enable)(self.handle, enable.into());
+ } else {
+ debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state2);
+ (fns.ext_extended_dynamic_state2
+ .cmd_set_depth_bias_enable_ext)(self.handle, enable.into());
+ }
+ }
+
+ /// Calls `vkCmdSetDepthBounds` on the builder.
+ #[inline]
+ pub unsafe fn set_depth_bounds(&mut self, bounds: RangeInclusive<f32>) {
+ let fns = self.device.fns();
+ (fns.v1_0.cmd_set_depth_bounds)(self.handle, *bounds.start(), *bounds.end());
+ }
+
+ /// Calls `vkCmdSetDepthBoundsTestEnableEXT` on the builder.
+ #[inline]
+ pub unsafe fn set_depth_bounds_test_enable(&mut self, enable: bool) {
+ let fns = self.device.fns();
+
+ if self.device.api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_set_depth_bounds_test_enable)(self.handle, enable.into());
+ } else {
+ debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state);
+ (fns.ext_extended_dynamic_state
+ .cmd_set_depth_bounds_test_enable_ext)(self.handle, enable.into());
+ }
+ }
+
+ /// Calls `vkCmdSetDepthCompareOpEXT` on the builder.
+ #[inline]
+ pub unsafe fn set_depth_compare_op(&mut self, compare_op: CompareOp) {
+ let fns = self.device.fns();
+
+ if self.device.api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_set_depth_compare_op)(self.handle, compare_op.into());
+ } else {
+ debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state);
+ (fns.ext_extended_dynamic_state.cmd_set_depth_compare_op_ext)(
+ self.handle,
+ compare_op.into(),
+ );
+ }
+ }
+
+ /// Calls `vkCmdSetDepthTestEnableEXT` on the builder.
+ #[inline]
+ pub unsafe fn set_depth_test_enable(&mut self, enable: bool) {
+ let fns = self.device.fns();
+
+ if self.device.api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_set_depth_test_enable)(self.handle, enable.into());
+ } else {
+ debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state);
+ (fns.ext_extended_dynamic_state.cmd_set_depth_test_enable_ext)(
+ self.handle,
+ enable.into(),
+ );
+ }
+ }
+
+ /// Calls `vkCmdSetDepthWriteEnableEXT` on the builder.
+ #[inline]
+ pub unsafe fn set_depth_write_enable(&mut self, enable: bool) {
+ let fns = self.device.fns();
+
+ if self.device.api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_set_depth_write_enable)(self.handle, enable.into());
+ } else {
+ debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state);
+ (fns.ext_extended_dynamic_state
+ .cmd_set_depth_write_enable_ext)(self.handle, enable.into());
+ }
+ }
+
+ /// Calls `vkCmdSetDiscardRectangleEXT` on the builder.
+ ///
+ /// If the list is empty then the command is automatically ignored.
+ pub unsafe fn set_discard_rectangle(
+ &mut self,
+ first_rectangle: u32,
+ rectangles: impl IntoIterator<Item = Scissor>,
+ ) {
+ debug_assert!(self.device.enabled_extensions().ext_discard_rectangles);
+
+ let rectangles = rectangles
+ .into_iter()
+ .map(|v| v.into())
+ .collect::<SmallVec<[_; 2]>>();
+ if rectangles.is_empty() {
+ return;
+ }
+
+ debug_assert!(
+ first_rectangle + rectangles.len() as u32
+ <= self
+ .device
+ .physical_device()
+ .properties()
+ .max_discard_rectangles
+ .unwrap()
+ );
+
+ let fns = self.device.fns();
+ (fns.ext_discard_rectangles.cmd_set_discard_rectangle_ext)(
+ self.handle,
+ first_rectangle,
+ rectangles.len() as u32,
+ rectangles.as_ptr(),
+ );
+ }
+
+ /// Calls `vkCmdSetFrontFaceEXT` on the builder.
+ #[inline]
+ pub unsafe fn set_front_face(&mut self, face: FrontFace) {
+ let fns = self.device.fns();
+
+ if self.device.api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_set_front_face)(self.handle, face.into());
+ } else {
+ debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state);
+ (fns.ext_extended_dynamic_state.cmd_set_front_face_ext)(self.handle, face.into());
+ }
+ }
+
+ /// Calls `vkCmdSetLineStippleEXT` on the builder.
+ #[inline]
+ pub unsafe fn set_line_stipple(&mut self, factor: u32, pattern: u16) {
+ debug_assert!(self.device.enabled_extensions().ext_line_rasterization);
+ let fns = self.device.fns();
+ (fns.ext_line_rasterization.cmd_set_line_stipple_ext)(self.handle, factor, pattern);
+ }
+
+ /// Calls `vkCmdSetLineWidth` on the builder.
+ #[inline]
+ pub unsafe fn set_line_width(&mut self, line_width: f32) {
+ let fns = self.device.fns();
+ (fns.v1_0.cmd_set_line_width)(self.handle, line_width);
+ }
+
+ /// Calls `vkCmdSetLogicOpEXT` on the builder.
+ #[inline]
+ pub unsafe fn set_logic_op(&mut self, logic_op: LogicOp) {
+ debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state2);
+ debug_assert!(
+ self.device
+ .enabled_features()
+ .extended_dynamic_state2_logic_op
+ );
+ let fns = self.device.fns();
+
+ (fns.ext_extended_dynamic_state2.cmd_set_logic_op_ext)(self.handle, logic_op.into());
+ }
+
+ /// Calls `vkCmdSetPatchControlPointsEXT` on the builder.
+ #[inline]
+ pub unsafe fn set_patch_control_points(&mut self, num: u32) {
+ debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state2);
+ let fns = self.device.fns();
+ (fns.ext_extended_dynamic_state2
+ .cmd_set_patch_control_points_ext)(self.handle, num);
+ }
+
+ /// Calls `vkCmdSetPrimitiveRestartEnableEXT` on the builder.
+ #[inline]
+ pub unsafe fn set_primitive_restart_enable(&mut self, enable: bool) {
+ let fns = self.device.fns();
+
+ if self.device.api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_set_primitive_restart_enable)(self.handle, enable.into());
+ } else {
+ debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state2);
+ (fns.ext_extended_dynamic_state2
+ .cmd_set_primitive_restart_enable_ext)(self.handle, enable.into());
+ }
+ }
+
+ /// Calls `vkCmdSetPrimitiveTopologyEXT` on the builder.
+ #[inline]
+ pub unsafe fn set_primitive_topology(&mut self, topology: PrimitiveTopology) {
+ let fns = self.device.fns();
+
+ if self.device.api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_set_primitive_topology)(self.handle, topology.into());
+ } else {
+ debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state);
+ (fns.ext_extended_dynamic_state
+ .cmd_set_primitive_topology_ext)(self.handle, topology.into());
+ }
+ }
+
+ /// Calls `vkCmdSetRasterizerDiscardEnableEXT` on the builder.
+ #[inline]
+ pub unsafe fn set_rasterizer_discard_enable(&mut self, enable: bool) {
+ let fns = self.device.fns();
+
+ if self.device.api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_set_rasterizer_discard_enable)(self.handle, enable.into());
+ } else {
+ debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state2);
+ (fns.ext_extended_dynamic_state2
+ .cmd_set_rasterizer_discard_enable_ext)(self.handle, enable.into());
+ }
+ }
+
+ /// Calls `vkCmdSetStencilCompareMask` on the builder.
+ #[inline]
+ pub unsafe fn set_stencil_compare_mask(&mut self, face_mask: StencilFaces, compare_mask: u32) {
+ let fns = self.device.fns();
+ (fns.v1_0.cmd_set_stencil_compare_mask)(self.handle, face_mask.into(), compare_mask);
+ }
+
+ /// Calls `vkCmdSetStencilOpEXT` on the builder.
+ #[inline]
+ pub unsafe fn set_stencil_op(
+ &mut self,
+ face_mask: StencilFaces,
+ fail_op: StencilOp,
+ pass_op: StencilOp,
+ depth_fail_op: StencilOp,
+ compare_op: CompareOp,
+ ) {
+ let fns = self.device.fns();
+
+ if self.device.api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_set_stencil_op)(
+ self.handle,
+ face_mask.into(),
+ fail_op.into(),
+ pass_op.into(),
+ depth_fail_op.into(),
+ compare_op.into(),
+ );
+ } else {
+ debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state);
+ (fns.ext_extended_dynamic_state.cmd_set_stencil_op_ext)(
+ self.handle,
+ face_mask.into(),
+ fail_op.into(),
+ pass_op.into(),
+ depth_fail_op.into(),
+ compare_op.into(),
+ );
+ }
+ }
+
+ /// Calls `vkCmdSetStencilReference` on the builder.
+ #[inline]
+ pub unsafe fn set_stencil_reference(&mut self, face_mask: StencilFaces, reference: u32) {
+ let fns = self.device.fns();
+ (fns.v1_0.cmd_set_stencil_reference)(self.handle, face_mask.into(), reference);
+ }
+
+ /// Calls `vkCmdSetStencilTestEnableEXT` on the builder.
+ #[inline]
+ pub unsafe fn set_stencil_test_enable(&mut self, enable: bool) {
+ let fns = self.device.fns();
+
+ if self.device.api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_set_stencil_test_enable)(self.handle, enable.into());
+ } else {
+ debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state);
+ (fns.ext_extended_dynamic_state
+ .cmd_set_stencil_test_enable_ext)(self.handle, enable.into());
+ }
+ }
+
+ /// Calls `vkCmdSetStencilWriteMask` on the builder.
+ #[inline]
+ pub unsafe fn set_stencil_write_mask(&mut self, face_mask: StencilFaces, write_mask: u32) {
+ let fns = self.device.fns();
+ (fns.v1_0.cmd_set_stencil_write_mask)(self.handle, face_mask.into(), write_mask);
+ }
+
+ /// Calls `vkCmdSetScissor` on the builder.
+ ///
+ /// If the list is empty then the command is automatically ignored.
+ pub unsafe fn set_scissor(
+ &mut self,
+ first_scissor: u32,
+ scissors: impl IntoIterator<Item = Scissor>,
+ ) {
+ let scissors = scissors
+ .into_iter()
+ .map(ash::vk::Rect2D::from)
+ .collect::<SmallVec<[_; 2]>>();
+ if scissors.is_empty() {
+ return;
+ }
+
+ let fns = self.device.fns();
+ (fns.v1_0.cmd_set_scissor)(
+ self.handle,
+ first_scissor,
+ scissors.len() as u32,
+ scissors.as_ptr(),
+ );
+ }
+
+ /// Calls `vkCmdSetScissorWithCountEXT` on the builder.
+ ///
+ /// If the list is empty then the command is automatically ignored.
+ pub unsafe fn set_scissor_with_count(&mut self, scissors: impl IntoIterator<Item = Scissor>) {
+ let scissors = scissors
+ .into_iter()
+ .map(ash::vk::Rect2D::from)
+ .collect::<SmallVec<[_; 2]>>();
+ if scissors.is_empty() {
+ return;
+ }
+
+ let fns = self.device.fns();
+
+ if self.device.api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_set_scissor_with_count)(
+ self.handle,
+ scissors.len() as u32,
+ scissors.as_ptr(),
+ );
+ } else {
+ debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state);
+ (fns.ext_extended_dynamic_state
+ .cmd_set_scissor_with_count_ext)(
+ self.handle,
+ scissors.len() as u32,
+ scissors.as_ptr(),
+ );
+ }
+ }
+
+ /// Calls `vkCmdSetViewport` on the builder.
+ ///
+ /// If the list is empty then the command is automatically ignored.
+ pub unsafe fn set_viewport(
+ &mut self,
+ first_viewport: u32,
+ viewports: impl IntoIterator<Item = Viewport>,
+ ) {
+ let viewports = viewports
+ .into_iter()
+ .map(|v| v.into())
+ .collect::<SmallVec<[_; 2]>>();
+ if viewports.is_empty() {
+ return;
+ }
+
+ let fns = self.device.fns();
+ (fns.v1_0.cmd_set_viewport)(
+ self.handle,
+ first_viewport,
+ viewports.len() as u32,
+ viewports.as_ptr(),
+ );
+ }
+
+ /// Calls `vkCmdSetViewportWithCountEXT` on the builder.
+ ///
+ /// If the list is empty then the command is automatically ignored.
+ pub unsafe fn set_viewport_with_count(
+ &mut self,
+ viewports: impl IntoIterator<Item = Viewport>,
+ ) {
+ let viewports = viewports
+ .into_iter()
+ .map(|v| v.into())
+ .collect::<SmallVec<[_; 2]>>();
+ if viewports.is_empty() {
+ return;
+ }
+
+ let fns = self.device.fns();
+
+ if self.device.api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_set_viewport_with_count)(
+ self.handle,
+ viewports.len() as u32,
+ viewports.as_ptr(),
+ );
+ } else {
+ debug_assert!(self.device.enabled_extensions().ext_extended_dynamic_state);
+ (fns.ext_extended_dynamic_state
+ .cmd_set_viewport_with_count_ext)(
+ self.handle,
+ viewports.len() as u32,
+ viewports.as_ptr(),
+ );
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
+#[allow(dead_code)]
+pub(in super::super) enum SetDynamicStateError {
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+
+ /// The provided `factor` is not between 1 and 256 inclusive.
+ FactorOutOfRange,
+
+ /// The [`max_discard_rectangles`](crate::device::Properties::max_discard_rectangles)
+ /// limit has been exceeded.
+ MaxDiscardRectanglesExceeded { provided: u32, max: u32 },
+
+ /// The [`max_tessellation_patch_size`](crate::device::Properties::max_tessellation_patch_size)
+ /// limit has been exceeded.
+ MaxTessellationPatchSizeExceeded { provided: u32, max: u32 },
+
+ /// The [`max_viewports`](crate::device::Properties::max_viewports)
+ /// limit has been exceeded.
+ MaxViewportsExceeded { provided: u32, max: u32 },
+
+ /// The queue family doesn't allow this operation.
+ NotSupportedByQueueFamily,
+
+ /// The provided item count is different from the number of attachments in the color blend
+ /// state of the currently bound pipeline.
+ PipelineColorBlendAttachmentCountMismatch {
+ provided_count: u32,
+ required_count: u32,
+ },
+
+ /// The currently bound pipeline contains this state as internally fixed state, which cannot be
+ /// overridden with dynamic state.
+ PipelineHasFixedState,
+}
+
+impl Error for SetDynamicStateError {}
+
+impl Display for SetDynamicStateError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ Self::FactorOutOfRange => write!(
+ f,
+ "the provided `factor` is not between 1 and 256 inclusive",
+ ),
+ Self::MaxDiscardRectanglesExceeded { .. } => {
+ write!(f, "the `max_discard_rectangles` limit has been exceeded")
+ }
+ Self::MaxTessellationPatchSizeExceeded { .. } => write!(
+ f,
+ "the `max_tessellation_patch_size` limit has been exceeded",
+ ),
+ Self::MaxViewportsExceeded { .. } => {
+ write!(f, "the `max_viewports` limit has been exceeded")
+ }
+ Self::NotSupportedByQueueFamily => {
+ write!(f, "the queue family doesn't allow this operation")
+ }
+ Self::PipelineColorBlendAttachmentCountMismatch {
+ provided_count,
+ required_count,
+ } => write!(
+ f,
+ "the provided item count ({}) is different from the number of attachments in the \
+ color blend state of the currently bound pipeline ({})",
+ provided_count, required_count,
+ ),
+ Self::PipelineHasFixedState => write!(
+ f,
+ "the currently bound pipeline contains this state as internally fixed state, which \
+ cannot be overridden with dynamic state",
+ ),
+ }
+ }
+}
+
+impl From<RequirementNotMet> for SetDynamicStateError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
+ }
+ }
+}
diff --git a/src/sync/semaphore/mod.rs b/src/command_buffer/commands/mod.rs
index 6fc7688..08c8aee 100644
--- a/src/sync/semaphore/mod.rs
+++ b/src/command_buffer/commands/mod.rs
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 The vulkano developers
+// Copyright (c) 2022 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
@@ -7,9 +7,13 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-pub use self::external_semaphore_handle_type::ExternalSemaphoreHandleType;
-pub use self::semaphore::Semaphore;
-pub use self::semaphore::SemaphoreError;
-
-mod external_semaphore_handle_type;
-mod semaphore;
+pub(super) mod bind_push;
+pub(super) mod clear;
+pub(super) mod copy;
+pub(super) mod debug;
+pub(super) mod dynamic_state;
+pub(super) mod pipeline;
+pub(super) mod query;
+pub(super) mod render_pass;
+pub(super) mod secondary;
+pub(super) mod sync;
diff --git a/src/command_buffer/commands/pipeline.rs b/src/command_buffer/commands/pipeline.rs
new file mode 100644
index 0000000..27a162a
--- /dev/null
+++ b/src/command_buffer/commands/pipeline.rs
@@ -0,0 +1,2975 @@
+// Copyright (c) 2022 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use crate::{
+ buffer::{view::BufferView, BufferUsage, Subbuffer},
+ command_buffer::{
+ allocator::CommandBufferAllocator,
+ auto::{RenderPassState, RenderPassStateType},
+ synced::{Command, Resource, SyncCommandBufferBuilder, SyncCommandBufferBuilderError},
+ sys::UnsafeCommandBufferBuilder,
+ AutoCommandBufferBuilder, DispatchIndirectCommand, DrawIndexedIndirectCommand,
+ DrawIndirectCommand, ResourceInCommand, ResourceUseRef, SubpassContents,
+ },
+ descriptor_set::{layout::DescriptorType, DescriptorBindingResources},
+ device::{DeviceOwned, QueueFlags},
+ format::{Format, FormatFeatures},
+ image::{
+ view::ImageViewType, ImageAccess, ImageAspects, ImageSubresourceRange, ImageViewAbstract,
+ SampleCount,
+ },
+ pipeline::{
+ graphics::{
+ input_assembly::{PrimitiveTopology, PrimitiveTopologyClass},
+ render_pass::PipelineRenderPassType,
+ vertex_input::VertexInputRate,
+ },
+ DynamicState, GraphicsPipeline, PartialStateMode, Pipeline, PipelineLayout,
+ },
+ sampler::{Sampler, SamplerImageViewIncompatibleError},
+ shader::{DescriptorBindingRequirements, ShaderScalarType, ShaderStage},
+ sync::{AccessFlags, PipelineMemoryAccess, PipelineStages},
+ DeviceSize, RequiresOneOf, VulkanObject,
+};
+use std::{
+ cmp::min,
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+ mem::size_of,
+ ops::Range,
+ sync::Arc,
+};
+
+/// # Commands to execute a bound pipeline.
+///
+/// Dispatch commands require a compute queue, draw commands require a graphics queue.
+impl<L, A> AutoCommandBufferBuilder<L, A>
+where
+ A: CommandBufferAllocator,
+{
+ /// Perform a single compute operation using a compute pipeline.
+ ///
+ /// A compute pipeline must have been bound using
+ /// [`bind_pipeline_compute`](Self::bind_pipeline_compute). Any resources used by the compute
+ /// pipeline, such as descriptor sets, must have been set beforehand.
+ pub fn dispatch(
+ &mut self,
+ group_counts: [u32; 3],
+ ) -> Result<&mut Self, PipelineExecutionError> {
+ self.validate_dispatch(group_counts)?;
+
+ unsafe {
+ self.inner.dispatch(group_counts)?;
+ }
+
+ Ok(self)
+ }
+
+ fn validate_dispatch(&self, group_counts: [u32; 3]) -> Result<(), PipelineExecutionError> {
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdDispatch-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::COMPUTE)
+ {
+ return Err(PipelineExecutionError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdDispatch-renderpass
+ if self.render_pass_state.is_some() {
+ return Err(PipelineExecutionError::ForbiddenInsideRenderPass);
+ }
+
+ // VUID-vkCmdDispatch-None-02700
+ let pipeline = match self.state().pipeline_compute() {
+ Some(x) => x.as_ref(),
+ None => return Err(PipelineExecutionError::PipelineNotBound),
+ };
+
+ self.validate_pipeline_descriptor_sets(pipeline)?;
+ self.validate_pipeline_push_constants(pipeline.layout())?;
+
+ let max = self
+ .device()
+ .physical_device()
+ .properties()
+ .max_compute_work_group_count;
+
+ // VUID-vkCmdDispatch-groupCountX-00386
+ // VUID-vkCmdDispatch-groupCountY-00387
+ // VUID-vkCmdDispatch-groupCountZ-00388
+ if group_counts[0] > max[0] || group_counts[1] > max[1] || group_counts[2] > max[2] {
+ return Err(PipelineExecutionError::MaxComputeWorkGroupCountExceeded {
+ requested: group_counts,
+ max,
+ });
+ }
+
+ Ok(())
+ }
+
+ /// Perform multiple compute operations using a compute pipeline. One dispatch is performed for
+ /// each [`DispatchIndirectCommand`] struct in `indirect_buffer`.
+ ///
+ /// A compute pipeline must have been bound using
+ /// [`bind_pipeline_compute`](Self::bind_pipeline_compute). Any resources used by the compute
+ /// pipeline, such as descriptor sets, must have been set beforehand.
+ pub fn dispatch_indirect(
+ &mut self,
+ indirect_buffer: Subbuffer<[DispatchIndirectCommand]>,
+ ) -> Result<&mut Self, PipelineExecutionError> {
+ self.validate_dispatch_indirect(indirect_buffer.as_bytes())?;
+
+ unsafe {
+ self.inner.dispatch_indirect(indirect_buffer)?;
+ }
+
+ Ok(self)
+ }
+
+ fn validate_dispatch_indirect(
+ &self,
+ indirect_buffer: &Subbuffer<[u8]>,
+ ) -> Result<(), PipelineExecutionError> {
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdDispatchIndirect-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::COMPUTE)
+ {
+ return Err(PipelineExecutionError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdDispatchIndirect-renderpass
+ if self.render_pass_state.is_some() {
+ return Err(PipelineExecutionError::ForbiddenInsideRenderPass);
+ }
+
+ // VUID-vkCmdDispatchIndirect-None-02700
+ let pipeline = match self.state().pipeline_compute() {
+ Some(x) => x.as_ref(),
+ None => return Err(PipelineExecutionError::PipelineNotBound),
+ };
+
+ self.validate_pipeline_descriptor_sets(pipeline)?;
+ self.validate_pipeline_push_constants(pipeline.layout())?;
+ self.validate_indirect_buffer(indirect_buffer)?;
+
+ Ok(())
+ }
+
+ /// Perform a single draw operation using a graphics pipeline.
+ ///
+ /// The parameters specify the first vertex and the number of vertices to draw, and the first
+ /// instance and number of instances. For non-instanced drawing, specify `instance_count` as 1
+ /// and `first_instance` as 0.
+ ///
+ /// A graphics pipeline must have been bound using
+ /// [`bind_pipeline_graphics`](Self::bind_pipeline_graphics). Any resources used by the graphics
+ /// pipeline, such as descriptor sets, vertex buffers and dynamic state, must have been set
+ /// beforehand. If the bound graphics pipeline uses vertex buffers, then the provided vertex and
+ /// instance ranges must be in range of the bound vertex buffers.
+ pub fn draw(
+ &mut self,
+ vertex_count: u32,
+ instance_count: u32,
+ first_vertex: u32,
+ first_instance: u32,
+ ) -> Result<&mut Self, PipelineExecutionError> {
+ self.validate_draw(vertex_count, instance_count, first_vertex, first_instance)?;
+
+ unsafe {
+ self.inner
+ .draw(vertex_count, instance_count, first_vertex, first_instance)?;
+ }
+
+ if let RenderPassStateType::BeginRendering(state) =
+ &mut self.render_pass_state.as_mut().unwrap().render_pass
+ {
+ state.pipeline_used = true;
+ }
+
+ Ok(self)
+ }
+
+ fn validate_draw(
+ &self,
+ vertex_count: u32,
+ instance_count: u32,
+ first_vertex: u32,
+ first_instance: u32,
+ ) -> Result<(), PipelineExecutionError> {
+ // VUID-vkCmdDraw-renderpass
+ let render_pass_state = self
+ .render_pass_state
+ .as_ref()
+ .ok_or(PipelineExecutionError::ForbiddenOutsideRenderPass)?;
+
+ // VUID-vkCmdDraw-None-02700
+ let pipeline = match self.state().pipeline_graphics() {
+ Some(x) => x.as_ref(),
+ None => return Err(PipelineExecutionError::PipelineNotBound),
+ };
+
+ self.validate_pipeline_descriptor_sets(pipeline)?;
+ self.validate_pipeline_push_constants(pipeline.layout())?;
+ self.validate_pipeline_graphics_dynamic_state(pipeline)?;
+ self.validate_pipeline_graphics_render_pass(pipeline, render_pass_state)?;
+ self.validate_pipeline_graphics_vertex_buffers(
+ pipeline,
+ Some((first_vertex, vertex_count)),
+ Some((first_instance, instance_count)),
+ )?;
+
+ Ok(())
+ }
+
+ /// Perform multiple draw operations using a graphics pipeline.
+ ///
+ /// One draw is performed for each [`DrawIndirectCommand`] struct in `indirect_buffer`.
+ /// The maximum number of draw commands in the buffer is limited by the
+ /// [`max_draw_indirect_count`](crate::device::Properties::max_draw_indirect_count) limit.
+ /// This limit is 1 unless the
+ /// [`multi_draw_indirect`](crate::device::Features::multi_draw_indirect) feature has been
+ /// enabled.
+ ///
+ /// A graphics pipeline must have been bound using
+ /// [`bind_pipeline_graphics`](Self::bind_pipeline_graphics). Any resources used by the graphics
+ /// pipeline, such as descriptor sets, vertex buffers and dynamic state, must have been set
+ /// beforehand. If the bound graphics pipeline uses vertex buffers, then the vertex and instance
+ /// ranges of each `DrawIndirectCommand` in the indirect buffer must be in range of the bound
+ /// vertex buffers.
+ pub fn draw_indirect(
+ &mut self,
+ indirect_buffer: Subbuffer<[DrawIndirectCommand]>,
+ ) -> Result<&mut Self, PipelineExecutionError> {
+ let draw_count = indirect_buffer.len() as u32;
+ let stride = size_of::<DrawIndirectCommand>() as u32;
+ self.validate_draw_indirect(indirect_buffer.as_bytes(), draw_count, stride)?;
+
+ unsafe {
+ self.inner
+ .draw_indirect(indirect_buffer, draw_count, stride)?;
+ }
+
+ if let RenderPassStateType::BeginRendering(state) =
+ &mut self.render_pass_state.as_mut().unwrap().render_pass
+ {
+ state.pipeline_used = true;
+ }
+
+ Ok(self)
+ }
+
+ fn validate_draw_indirect(
+ &self,
+ indirect_buffer: &Subbuffer<[u8]>,
+ draw_count: u32,
+ _stride: u32,
+ ) -> Result<(), PipelineExecutionError> {
+ // VUID-vkCmdDrawIndirect-renderpass
+ let render_pass_state = self
+ .render_pass_state
+ .as_ref()
+ .ok_or(PipelineExecutionError::ForbiddenOutsideRenderPass)?;
+
+ // VUID-vkCmdDrawIndirect-None-02700
+ let pipeline = match self.state().pipeline_graphics() {
+ Some(x) => x.as_ref(),
+ None => return Err(PipelineExecutionError::PipelineNotBound),
+ };
+
+ self.validate_pipeline_descriptor_sets(pipeline)?;
+ self.validate_pipeline_push_constants(pipeline.layout())?;
+ self.validate_pipeline_graphics_dynamic_state(pipeline)?;
+ self.validate_pipeline_graphics_render_pass(pipeline, render_pass_state)?;
+ self.validate_pipeline_graphics_vertex_buffers(pipeline, None, None)?;
+
+ self.validate_indirect_buffer(indirect_buffer)?;
+
+ // VUID-vkCmdDrawIndirect-drawCount-02718
+ if draw_count > 1 && !self.device().enabled_features().multi_draw_indirect {
+ return Err(PipelineExecutionError::RequirementNotMet {
+ required_for: "`draw_count` is greater than `1`",
+ requires_one_of: RequiresOneOf {
+ features: &["multi_draw_indirect"],
+ ..Default::default()
+ },
+ });
+ }
+
+ let max = self
+ .device()
+ .physical_device()
+ .properties()
+ .max_draw_indirect_count;
+
+ // VUID-vkCmdDrawIndirect-drawCount-02719
+ if draw_count > max {
+ return Err(PipelineExecutionError::MaxDrawIndirectCountExceeded {
+ provided: draw_count,
+ max,
+ });
+ }
+
+ Ok(())
+ }
+
+ /// Perform a single draw operation using a graphics pipeline, using an index buffer.
+ ///
+ /// The parameters specify the first index and the number of indices in the index buffer that
+ /// should be used, and the first instance and number of instances. For non-instanced drawing,
+ /// specify `instance_count` as 1 and `first_instance` as 0. The `vertex_offset` is a constant
+ /// value that should be added to each index in the index buffer to produce the final vertex
+ /// number to be used.
+ ///
+ /// An index buffer must have been bound using
+ /// [`bind_index_buffer`](Self::bind_index_buffer), and the provided index range must be in
+ /// range of the bound index buffer.
+ ///
+ /// A graphics pipeline must have been bound using
+ /// [`bind_pipeline_graphics`](Self::bind_pipeline_graphics). Any resources used by the graphics
+ /// pipeline, such as descriptor sets, vertex buffers and dynamic state, must have been set
+ /// beforehand. If the bound graphics pipeline uses vertex buffers, then the provided instance
+ /// range must be in range of the bound vertex buffers. The vertex indices in the index buffer
+ /// must be in range of the bound vertex buffers.
+ pub fn draw_indexed(
+ &mut self,
+ index_count: u32,
+ instance_count: u32,
+ first_index: u32,
+ vertex_offset: i32,
+ first_instance: u32,
+ ) -> Result<&mut Self, PipelineExecutionError> {
+ self.validate_draw_indexed(
+ index_count,
+ instance_count,
+ first_index,
+ vertex_offset,
+ first_instance,
+ )?;
+
+ unsafe {
+ self.inner.draw_indexed(
+ index_count,
+ instance_count,
+ first_index,
+ vertex_offset,
+ first_instance,
+ )?;
+ }
+
+ if let RenderPassStateType::BeginRendering(state) =
+ &mut self.render_pass_state.as_mut().unwrap().render_pass
+ {
+ state.pipeline_used = true;
+ }
+
+ Ok(self)
+ }
+
+ fn validate_draw_indexed(
+ &self,
+ index_count: u32,
+ instance_count: u32,
+ first_index: u32,
+ _vertex_offset: i32,
+ first_instance: u32,
+ ) -> Result<(), PipelineExecutionError> {
+ // TODO: how to handle an index out of range of the vertex buffers?
+
+ // VUID-vkCmdDrawIndexed-renderpass
+ let render_pass_state = self
+ .render_pass_state
+ .as_ref()
+ .ok_or(PipelineExecutionError::ForbiddenOutsideRenderPass)?;
+
+ // VUID-vkCmdDrawIndexed-None-02700
+ let pipeline = match self.state().pipeline_graphics() {
+ Some(x) => x.as_ref(),
+ None => return Err(PipelineExecutionError::PipelineNotBound),
+ };
+
+ self.validate_pipeline_descriptor_sets(pipeline)?;
+ self.validate_pipeline_push_constants(pipeline.layout())?;
+ self.validate_pipeline_graphics_dynamic_state(pipeline)?;
+ self.validate_pipeline_graphics_render_pass(pipeline, render_pass_state)?;
+ self.validate_pipeline_graphics_vertex_buffers(
+ pipeline,
+ None,
+ Some((first_instance, instance_count)),
+ )?;
+
+ self.validate_index_buffer(Some((first_index, index_count)))?;
+
+ Ok(())
+ }
+
+ /// Perform multiple draw operations using a graphics pipeline, using an index buffer.
+ ///
+ /// One draw is performed for each [`DrawIndexedIndirectCommand`] struct in `indirect_buffer`.
+ /// The maximum number of draw commands in the buffer is limited by the
+ /// [`max_draw_indirect_count`](crate::device::Properties::max_draw_indirect_count) limit.
+ /// This limit is 1 unless the
+ /// [`multi_draw_indirect`](crate::device::Features::multi_draw_indirect) feature has been
+ /// enabled.
+ ///
+ /// An index buffer must have been bound using
+ /// [`bind_index_buffer`](Self::bind_index_buffer), and the index ranges of each
+ /// `DrawIndexedIndirectCommand` in the indirect buffer must be in range of the bound index
+ /// buffer.
+ ///
+ /// A graphics pipeline must have been bound using
+ /// [`bind_pipeline_graphics`](Self::bind_pipeline_graphics). Any resources used by the graphics
+ /// pipeline, such as descriptor sets, vertex buffers and dynamic state, must have been set
+ /// beforehand. If the bound graphics pipeline uses vertex buffers, then the instance ranges of
+ /// each `DrawIndexedIndirectCommand` in the indirect buffer must be in range of the bound
+ /// vertex buffers.
+ pub fn draw_indexed_indirect(
+ &mut self,
+ indirect_buffer: Subbuffer<[DrawIndexedIndirectCommand]>,
+ ) -> Result<&mut Self, PipelineExecutionError> {
+ let draw_count = indirect_buffer.len() as u32;
+ let stride = size_of::<DrawIndexedIndirectCommand>() as u32;
+ self.validate_draw_indexed_indirect(indirect_buffer.as_bytes(), draw_count, stride)?;
+
+ unsafe {
+ self.inner
+ .draw_indexed_indirect(indirect_buffer, draw_count, stride)?;
+ }
+
+ if let RenderPassStateType::BeginRendering(state) =
+ &mut self.render_pass_state.as_mut().unwrap().render_pass
+ {
+ state.pipeline_used = true;
+ }
+
+ Ok(self)
+ }
+
+ fn validate_draw_indexed_indirect(
+ &self,
+ indirect_buffer: &Subbuffer<[u8]>,
+ draw_count: u32,
+ _stride: u32,
+ ) -> Result<(), PipelineExecutionError> {
+ // VUID-vkCmdDrawIndexedIndirect-renderpass
+ let render_pass_state = self
+ .render_pass_state
+ .as_ref()
+ .ok_or(PipelineExecutionError::ForbiddenOutsideRenderPass)?;
+
+ // VUID-vkCmdDrawIndexedIndirect-None-02700
+ let pipeline = match self.state().pipeline_graphics() {
+ Some(x) => x.as_ref(),
+ None => return Err(PipelineExecutionError::PipelineNotBound),
+ };
+
+ self.validate_pipeline_descriptor_sets(pipeline)?;
+ self.validate_pipeline_push_constants(pipeline.layout())?;
+ self.validate_pipeline_graphics_dynamic_state(pipeline)?;
+ self.validate_pipeline_graphics_render_pass(pipeline, render_pass_state)?;
+ self.validate_pipeline_graphics_vertex_buffers(pipeline, None, None)?;
+
+ self.validate_index_buffer(None)?;
+ self.validate_indirect_buffer(indirect_buffer)?;
+
+ // VUID-vkCmdDrawIndexedIndirect-drawCount-02718
+ if draw_count > 1 && !self.device().enabled_features().multi_draw_indirect {
+ return Err(PipelineExecutionError::RequirementNotMet {
+ required_for: "`draw_count` is greater than `1`",
+ requires_one_of: RequiresOneOf {
+ features: &["multi_draw_indirect"],
+ ..Default::default()
+ },
+ });
+ }
+
+ let max = self
+ .device()
+ .physical_device()
+ .properties()
+ .max_draw_indirect_count;
+
+ // VUID-vkCmdDrawIndexedIndirect-drawCount-02719
+ if draw_count > max {
+ return Err(PipelineExecutionError::MaxDrawIndirectCountExceeded {
+ provided: draw_count,
+ max,
+ });
+ }
+
+ Ok(())
+ }
+
+ fn validate_index_buffer(
+ &self,
+ indices: Option<(u32, u32)>,
+ ) -> Result<(), PipelineExecutionError> {
+ let current_state = self.state();
+
+ // VUID?
+ let (index_buffer, index_type) = match current_state.index_buffer() {
+ Some(x) => x,
+ None => return Err(PipelineExecutionError::IndexBufferNotBound),
+ };
+
+ if let Some((first_index, index_count)) = indices {
+ let max_index_count = (index_buffer.size() / index_type.size()) as u32;
+
+ // // VUID-vkCmdDrawIndexed-firstIndex-04932
+ if first_index + index_count > max_index_count {
+ return Err(PipelineExecutionError::IndexBufferRangeOutOfBounds {
+ highest_index: first_index + index_count,
+ max_index_count,
+ });
+ }
+ }
+
+ Ok(())
+ }
+
+ fn validate_indirect_buffer(
+ &self,
+ buffer: &Subbuffer<[u8]>,
+ ) -> Result<(), PipelineExecutionError> {
+ // VUID-vkCmdDispatchIndirect-commonparent
+ assert_eq!(self.device(), buffer.device());
+
+ // VUID-vkCmdDispatchIndirect-buffer-02709
+ if !buffer
+ .buffer()
+ .usage()
+ .intersects(BufferUsage::INDIRECT_BUFFER)
+ {
+ return Err(PipelineExecutionError::IndirectBufferMissingUsage);
+ }
+
+ // VUID-vkCmdDispatchIndirect-offset-02710
+ // TODO:
+
+ Ok(())
+ }
+
+ fn validate_pipeline_descriptor_sets<Pl: Pipeline>(
+ &self,
+ pipeline: &Pl,
+ ) -> Result<(), PipelineExecutionError> {
+ fn validate_resources<T>(
+ set_num: u32,
+ binding_num: u32,
+ binding_reqs: &DescriptorBindingRequirements,
+ elements: &[Option<T>],
+ mut extra_check: impl FnMut(u32, &T) -> Result<(), DescriptorResourceInvalidError>,
+ ) -> Result<(), PipelineExecutionError> {
+ let elements_to_check = if let Some(descriptor_count) = binding_reqs.descriptor_count {
+ // The shader has a fixed-sized array, so it will never access more than
+ // the first `descriptor_count` elements.
+ elements.get(..descriptor_count as usize).ok_or({
+ // There are less than `descriptor_count` elements in `elements`
+ PipelineExecutionError::DescriptorResourceInvalid {
+ set_num,
+ binding_num,
+ index: elements.len() as u32,
+ error: DescriptorResourceInvalidError::Missing,
+ }
+ })?
+ } else {
+ // The shader has a runtime-sized array, so any element could potentially
+ // be accessed. We must check them all.
+ elements
+ };
+
+ for (index, element) in elements_to_check.iter().enumerate() {
+ let index = index as u32;
+
+ // VUID-vkCmdDispatch-None-02699
+ let element = match element {
+ Some(x) => x,
+ None => {
+ return Err(PipelineExecutionError::DescriptorResourceInvalid {
+ set_num,
+ binding_num,
+ index,
+ error: DescriptorResourceInvalidError::Missing,
+ })
+ }
+ };
+
+ if let Err(error) = extra_check(index, element) {
+ return Err(PipelineExecutionError::DescriptorResourceInvalid {
+ set_num,
+ binding_num,
+ index,
+ error,
+ });
+ }
+ }
+
+ Ok(())
+ }
+
+ if pipeline.num_used_descriptor_sets() == 0 {
+ return Ok(());
+ }
+
+ let current_state = self.state();
+
+ // VUID-vkCmdDispatch-None-02697
+ let bindings_pipeline_layout =
+ match current_state.descriptor_sets_pipeline_layout(pipeline.bind_point()) {
+ Some(x) => x,
+ None => return Err(PipelineExecutionError::PipelineLayoutNotCompatible),
+ };
+
+ // VUID-vkCmdDispatch-None-02697
+ if !pipeline.layout().is_compatible_with(
+ bindings_pipeline_layout,
+ pipeline.num_used_descriptor_sets(),
+ ) {
+ return Err(PipelineExecutionError::PipelineLayoutNotCompatible);
+ }
+
+ for (&(set_num, binding_num), binding_reqs) in pipeline.descriptor_binding_requirements() {
+ let layout_binding =
+ &pipeline.layout().set_layouts()[set_num as usize].bindings()[&binding_num];
+
+ let check_buffer =
+ |_index: u32, (_buffer, _range): &(Subbuffer<[u8]>, Range<DeviceSize>)| Ok(());
+
+ let check_buffer_view = |index: u32, buffer_view: &Arc<BufferView>| {
+ for desc_reqs in (binding_reqs.descriptors.get(&Some(index)).into_iter())
+ .chain(binding_reqs.descriptors.get(&None))
+ {
+ if layout_binding.descriptor_type == DescriptorType::StorageTexelBuffer {
+ // VUID-vkCmdDispatch-OpTypeImage-06423
+ if binding_reqs.image_format.is_none()
+ && !desc_reqs.memory_write.is_empty()
+ && !buffer_view
+ .format_features()
+ .intersects(FormatFeatures::STORAGE_WRITE_WITHOUT_FORMAT)
+ {
+ return Err(DescriptorResourceInvalidError::StorageWriteWithoutFormatNotSupported);
+ }
+
+ // VUID-vkCmdDispatch-OpTypeImage-06424
+ if binding_reqs.image_format.is_none()
+ && !desc_reqs.memory_read.is_empty()
+ && !buffer_view
+ .format_features()
+ .intersects(FormatFeatures::STORAGE_READ_WITHOUT_FORMAT)
+ {
+ return Err(DescriptorResourceInvalidError::StorageReadWithoutFormatNotSupported);
+ }
+ }
+ }
+
+ Ok(())
+ };
+
+ let check_image_view_common = |index: u32, image_view: &Arc<dyn ImageViewAbstract>| {
+ for desc_reqs in (binding_reqs.descriptors.get(&Some(index)).into_iter())
+ .chain(binding_reqs.descriptors.get(&None))
+ {
+ // VUID-vkCmdDispatch-None-02691
+ if desc_reqs.storage_image_atomic
+ && !image_view
+ .format_features()
+ .intersects(FormatFeatures::STORAGE_IMAGE_ATOMIC)
+ {
+ return Err(DescriptorResourceInvalidError::StorageImageAtomicNotSupported);
+ }
+
+ if layout_binding.descriptor_type == DescriptorType::StorageImage {
+ // VUID-vkCmdDispatch-OpTypeImage-06423
+ if binding_reqs.image_format.is_none()
+ && !desc_reqs.memory_write.is_empty()
+ && !image_view
+ .format_features()
+ .intersects(FormatFeatures::STORAGE_WRITE_WITHOUT_FORMAT)
+ {
+ return Err(
+ DescriptorResourceInvalidError::StorageWriteWithoutFormatNotSupported,
+ );
+ }
+
+ // VUID-vkCmdDispatch-OpTypeImage-06424
+ if binding_reqs.image_format.is_none()
+ && !desc_reqs.memory_read.is_empty()
+ && !image_view
+ .format_features()
+ .intersects(FormatFeatures::STORAGE_READ_WITHOUT_FORMAT)
+ {
+ return Err(
+ DescriptorResourceInvalidError::StorageReadWithoutFormatNotSupported,
+ );
+ }
+ }
+ }
+
+ /*
+ Instruction/Sampler/Image View Validation
+ https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap16.html#textures-input-validation
+ */
+
+ // The SPIR-V Image Format is not compatible with the image view’s format.
+ if let Some(format) = binding_reqs.image_format {
+ if image_view.format() != Some(format) {
+ return Err(DescriptorResourceInvalidError::ImageViewFormatMismatch {
+ required: format,
+ provided: image_view.format(),
+ });
+ }
+ }
+
+ // Rules for viewType
+ if let Some(image_view_type) = binding_reqs.image_view_type {
+ if image_view.view_type() != image_view_type {
+ return Err(DescriptorResourceInvalidError::ImageViewTypeMismatch {
+ required: image_view_type,
+ provided: image_view.view_type(),
+ });
+ }
+ }
+
+ // - If the image was created with VkImageCreateInfo::samples equal to
+ // VK_SAMPLE_COUNT_1_BIT, the instruction must have MS = 0.
+ // - If the image was created with VkImageCreateInfo::samples not equal to
+ // VK_SAMPLE_COUNT_1_BIT, the instruction must have MS = 1.
+ if binding_reqs.image_multisampled
+ != (image_view.image().samples() != SampleCount::Sample1)
+ {
+ return Err(
+ DescriptorResourceInvalidError::ImageViewMultisampledMismatch {
+ required: binding_reqs.image_multisampled,
+ provided: image_view.image().samples() != SampleCount::Sample1,
+ },
+ );
+ }
+
+ // - If the Sampled Type of the OpTypeImage does not match the numeric format of the
+ // image, as shown in the SPIR-V Sampled Type column of the
+ // Interpretation of Numeric Format table.
+ // - If the signedness of any read or sample operation does not match the signedness of
+ // the image’s format.
+ if let Some(scalar_type) = binding_reqs.image_scalar_type {
+ let aspects = image_view.subresource_range().aspects;
+ let view_scalar_type = ShaderScalarType::from(
+ if aspects.intersects(
+ ImageAspects::COLOR
+ | ImageAspects::PLANE_0
+ | ImageAspects::PLANE_1
+ | ImageAspects::PLANE_2,
+ ) {
+ image_view.format().unwrap().type_color().unwrap()
+ } else if aspects.intersects(ImageAspects::DEPTH) {
+ image_view.format().unwrap().type_depth().unwrap()
+ } else if aspects.intersects(ImageAspects::STENCIL) {
+ image_view.format().unwrap().type_stencil().unwrap()
+ } else {
+ // Per `ImageViewBuilder::aspects` and
+ // VUID-VkDescriptorImageInfo-imageView-01976
+ unreachable!()
+ },
+ );
+
+ if scalar_type != view_scalar_type {
+ return Err(
+ DescriptorResourceInvalidError::ImageViewScalarTypeMismatch {
+ required: scalar_type,
+ provided: view_scalar_type,
+ },
+ );
+ }
+ }
+
+ Ok(())
+ };
+
+ let check_sampler_common = |index: u32, sampler: &Arc<Sampler>| {
+ for desc_reqs in (binding_reqs.descriptors.get(&Some(index)).into_iter())
+ .chain(binding_reqs.descriptors.get(&None))
+ {
+ // VUID-vkCmdDispatch-None-02703
+ // VUID-vkCmdDispatch-None-02704
+ if desc_reqs.sampler_no_unnormalized_coordinates
+ && sampler.unnormalized_coordinates()
+ {
+ return Err(
+ DescriptorResourceInvalidError::SamplerUnnormalizedCoordinatesNotAllowed,
+ );
+ }
+
+ // - OpImageFetch, OpImageSparseFetch, OpImage*Gather, and OpImageSparse*Gather must not
+ // be used with a sampler that enables sampler Y′CBCR conversion.
+ // - The ConstOffset and Offset operands must not be used with a sampler that enables
+ // sampler Y′CBCR conversion.
+ if desc_reqs.sampler_no_ycbcr_conversion
+ && sampler.sampler_ycbcr_conversion().is_some()
+ {
+ return Err(
+ DescriptorResourceInvalidError::SamplerYcbcrConversionNotAllowed,
+ );
+ }
+
+ /*
+ Instruction/Sampler/Image View Validation
+ https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap16.html#textures-input-validation
+ */
+
+ // - The SPIR-V instruction is one of the OpImage*Dref* instructions and the sampler
+ // compareEnable is VK_FALSE
+ // - The SPIR-V instruction is not one of the OpImage*Dref* instructions and the sampler
+ // compareEnable is VK_TRUE
+ if desc_reqs.sampler_compare != sampler.compare().is_some() {
+ return Err(DescriptorResourceInvalidError::SamplerCompareMismatch {
+ required: desc_reqs.sampler_compare,
+ provided: sampler.compare().is_some(),
+ });
+ }
+ }
+
+ Ok(())
+ };
+
+ let check_image_view = |index: u32, image_view: &Arc<dyn ImageViewAbstract>| {
+ check_image_view_common(index, image_view)?;
+
+ if let Some(sampler) = layout_binding.immutable_samplers.get(index as usize) {
+ check_sampler_common(index, sampler)?;
+ }
+
+ Ok(())
+ };
+
+ let check_image_view_sampler =
+ |index: u32, (image_view, sampler): &(Arc<dyn ImageViewAbstract>, Arc<Sampler>)| {
+ check_image_view_common(index, image_view)?;
+ check_sampler_common(index, sampler)?;
+
+ Ok(())
+ };
+
+ let check_sampler = |index: u32, sampler: &Arc<Sampler>| {
+ check_sampler_common(index, sampler)?;
+
+ for desc_reqs in (binding_reqs.descriptors.get(&Some(index)).into_iter())
+ .chain(binding_reqs.descriptors.get(&None))
+ {
+ // Check sampler-image compatibility. Only done for separate samplers;
+ // combined image samplers are checked when updating the descriptor set.
+
+ // If the image view isn't actually present in the resources, then just skip it.
+ // It will be caught later by check_resources.
+ let iter = desc_reqs.sampler_with_images.iter().filter_map(|id| {
+ current_state
+ .descriptor_set(pipeline.bind_point(), id.set)
+ .and_then(|set| set.resources().binding(id.binding))
+ .and_then(|res| match res {
+ DescriptorBindingResources::ImageView(elements) => elements
+ .get(id.index as usize)
+ .and_then(|opt| opt.as_ref().map(|opt| (id, opt))),
+ _ => None,
+ })
+ });
+
+ for (id, image_view) in iter {
+ if let Err(error) = sampler.check_can_sample(image_view.as_ref()) {
+ return Err(
+ DescriptorResourceInvalidError::SamplerImageViewIncompatible {
+ image_view_set_num: id.set,
+ image_view_binding_num: id.binding,
+ image_view_index: id.index,
+ error,
+ },
+ );
+ }
+ }
+ }
+
+ Ok(())
+ };
+
+ let check_none = |index: u32, _: &()| {
+ if let Some(sampler) = layout_binding.immutable_samplers.get(index as usize) {
+ check_sampler(index, sampler)?;
+ }
+
+ Ok(())
+ };
+
+ let set_resources = match current_state.descriptor_set(pipeline.bind_point(), set_num) {
+ Some(x) => x.resources(),
+ None => return Err(PipelineExecutionError::DescriptorSetNotBound { set_num }),
+ };
+
+ let binding_resources = set_resources.binding(binding_num).unwrap();
+
+ match binding_resources {
+ DescriptorBindingResources::None(elements) => {
+ validate_resources(set_num, binding_num, binding_reqs, elements, check_none)?;
+ }
+ DescriptorBindingResources::Buffer(elements) => {
+ validate_resources(set_num, binding_num, binding_reqs, elements, check_buffer)?;
+ }
+ DescriptorBindingResources::BufferView(elements) => {
+ validate_resources(
+ set_num,
+ binding_num,
+ binding_reqs,
+ elements,
+ check_buffer_view,
+ )?;
+ }
+ DescriptorBindingResources::ImageView(elements) => {
+ validate_resources(
+ set_num,
+ binding_num,
+ binding_reqs,
+ elements,
+ check_image_view,
+ )?;
+ }
+ DescriptorBindingResources::ImageViewSampler(elements) => {
+ validate_resources(
+ set_num,
+ binding_num,
+ binding_reqs,
+ elements,
+ check_image_view_sampler,
+ )?;
+ }
+ DescriptorBindingResources::Sampler(elements) => {
+ validate_resources(
+ set_num,
+ binding_num,
+ binding_reqs,
+ elements,
+ check_sampler,
+ )?;
+ }
+ }
+ }
+
+ Ok(())
+ }
+
+ fn validate_pipeline_push_constants(
+ &self,
+ pipeline_layout: &PipelineLayout,
+ ) -> Result<(), PipelineExecutionError> {
+ if pipeline_layout.push_constant_ranges().is_empty()
+ || self.device().enabled_features().maintenance4
+ {
+ return Ok(());
+ }
+
+ let current_state = self.state();
+
+ // VUID-vkCmdDispatch-maintenance4-06425
+ let constants_pipeline_layout = match current_state.push_constants_pipeline_layout() {
+ Some(x) => x,
+ None => return Err(PipelineExecutionError::PushConstantsMissing),
+ };
+
+ // VUID-vkCmdDispatch-maintenance4-06425
+ if pipeline_layout.handle() != constants_pipeline_layout.handle()
+ && pipeline_layout.push_constant_ranges()
+ != constants_pipeline_layout.push_constant_ranges()
+ {
+ return Err(PipelineExecutionError::PushConstantsNotCompatible);
+ }
+
+ let set_bytes = current_state.push_constants();
+
+ // VUID-vkCmdDispatch-maintenance4-06425
+ if !pipeline_layout
+ .push_constant_ranges()
+ .iter()
+ .all(|pc_range| set_bytes.contains(pc_range.offset..pc_range.offset + pc_range.size))
+ {
+ return Err(PipelineExecutionError::PushConstantsMissing);
+ }
+
+ Ok(())
+ }
+
+ fn validate_pipeline_graphics_dynamic_state(
+ &self,
+ pipeline: &GraphicsPipeline,
+ ) -> Result<(), PipelineExecutionError> {
+ let device = pipeline.device();
+ let current_state = self.state();
+
+ // VUID-vkCmdDraw-commandBuffer-02701
+ for dynamic_state in pipeline
+ .dynamic_states()
+ .filter(|(_, d)| *d)
+ .map(|(s, _)| s)
+ {
+ match dynamic_state {
+ DynamicState::BlendConstants => {
+ // VUID?
+ if current_state.blend_constants().is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::ColorWriteEnable => {
+ // VUID-vkCmdDraw-attachmentCount-06667
+ let enables = if let Some(enables) = current_state.color_write_enable() {
+ enables
+ } else {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ };
+
+ // VUID-vkCmdDraw-attachmentCount-06667
+ if enables.len() < pipeline.color_blend_state().unwrap().attachments.len() {
+ return Err(
+ PipelineExecutionError::DynamicColorWriteEnableNotEnoughValues {
+ color_write_enable_count: enables.len() as u32,
+ attachment_count: pipeline
+ .color_blend_state()
+ .unwrap()
+ .attachments
+ .len() as u32,
+ },
+ );
+ }
+ }
+ DynamicState::CullMode => {
+ // VUID?
+ if current_state.cull_mode().is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::DepthBias => {
+ // VUID?
+ if current_state.depth_bias().is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::DepthBiasEnable => {
+ // VUID-vkCmdDraw-None-04877
+ if current_state.depth_bias_enable().is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::DepthBounds => {
+ // VUID?
+ if current_state.depth_bounds().is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::DepthBoundsTestEnable => {
+ // VUID?
+ if current_state.depth_bounds_test_enable().is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::DepthCompareOp => {
+ // VUID?
+ if current_state.depth_compare_op().is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::DepthTestEnable => {
+ // VUID?
+ if current_state.depth_test_enable().is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::DepthWriteEnable => {
+ // VUID?
+ if current_state.depth_write_enable().is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+
+ // TODO: Check if the depth buffer is writable
+ }
+ DynamicState::DiscardRectangle => {
+ let discard_rectangle_count =
+ match pipeline.discard_rectangle_state().unwrap().rectangles {
+ PartialStateMode::Dynamic(count) => count,
+ _ => unreachable!(),
+ };
+
+ for num in 0..discard_rectangle_count {
+ // VUID?
+ if current_state.discard_rectangle(num).is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ }
+ DynamicState::ExclusiveScissor => todo!(),
+ DynamicState::FragmentShadingRate => todo!(),
+ DynamicState::FrontFace => {
+ // VUID?
+ if current_state.front_face().is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::LineStipple => {
+ // VUID?
+ if current_state.line_stipple().is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::LineWidth => {
+ // VUID?
+ if current_state.line_width().is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::LogicOp => {
+ // VUID-vkCmdDraw-logicOp-04878
+ if current_state.logic_op().is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::PatchControlPoints => {
+ // VUID-vkCmdDraw-None-04875
+ if current_state.patch_control_points().is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::PrimitiveRestartEnable => {
+ // VUID-vkCmdDraw-None-04879
+ let primitive_restart_enable =
+ if let Some(enable) = current_state.primitive_restart_enable() {
+ enable
+ } else {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ };
+
+ if primitive_restart_enable {
+ let topology = match pipeline.input_assembly_state().topology {
+ PartialStateMode::Fixed(topology) => topology,
+ PartialStateMode::Dynamic(_) => {
+ if let Some(topology) = current_state.primitive_topology() {
+ topology
+ } else {
+ return Err(PipelineExecutionError::DynamicStateNotSet {
+ dynamic_state: DynamicState::PrimitiveTopology,
+ });
+ }
+ }
+ };
+
+ match topology {
+ PrimitiveTopology::PointList
+ | PrimitiveTopology::LineList
+ | PrimitiveTopology::TriangleList
+ | PrimitiveTopology::LineListWithAdjacency
+ | PrimitiveTopology::TriangleListWithAdjacency => {
+ // VUID?
+ if !device.enabled_features().primitive_topology_list_restart {
+ return Err(PipelineExecutionError::RequirementNotMet {
+ required_for: "The bound pipeline sets \
+ `DynamicState::PrimitiveRestartEnable` and the \
+ current primitive topology is \
+ `PrimitiveTopology::*List`",
+ requires_one_of: RequiresOneOf {
+ features: &["primitive_topology_list_restart"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ PrimitiveTopology::PatchList => {
+ // VUID?
+ if !device
+ .enabled_features()
+ .primitive_topology_patch_list_restart
+ {
+ return Err(PipelineExecutionError::RequirementNotMet {
+ required_for: "The bound pipeline sets \
+ `DynamicState::PrimitiveRestartEnable` and the \
+ current primitive topology is \
+ `PrimitiveTopology::PatchList`",
+ requires_one_of: RequiresOneOf {
+ features: &["primitive_topology_patch_list_restart"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ _ => (),
+ }
+ }
+ }
+ DynamicState::PrimitiveTopology => {
+ // VUID-vkCmdDraw-primitiveTopology-03420
+ let topology = if let Some(topology) = current_state.primitive_topology() {
+ topology
+ } else {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ };
+
+ if pipeline.shader(ShaderStage::TessellationControl).is_some() {
+ // VUID?
+ if !matches!(topology, PrimitiveTopology::PatchList) {
+ return Err(PipelineExecutionError::DynamicPrimitiveTopologyInvalid {
+ topology,
+ });
+ }
+ } else {
+ // VUID?
+ if matches!(topology, PrimitiveTopology::PatchList) {
+ return Err(PipelineExecutionError::DynamicPrimitiveTopologyInvalid {
+ topology,
+ });
+ }
+ }
+
+ let required_topology_class = match pipeline.input_assembly_state().topology {
+ PartialStateMode::Dynamic(topology_class) => topology_class,
+ _ => unreachable!(),
+ };
+
+ // VUID-vkCmdDraw-primitiveTopology-03420
+ if topology.class() != required_topology_class {
+ return Err(
+ PipelineExecutionError::DynamicPrimitiveTopologyClassMismatch {
+ provided_class: topology.class(),
+ required_class: required_topology_class,
+ },
+ );
+ }
+
+ // TODO: check that the topology matches the geometry shader
+ }
+ DynamicState::RasterizerDiscardEnable => {
+ // VUID-vkCmdDraw-None-04876
+ if current_state.rasterizer_discard_enable().is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::RayTracingPipelineStackSize => unreachable!(
+ "RayTracingPipelineStackSize dynamic state should not occur on a graphics pipeline"
+ ),
+ DynamicState::SampleLocations => todo!(),
+ DynamicState::Scissor => {
+ for num in 0..pipeline.viewport_state().unwrap().count().unwrap() {
+ // VUID?
+ if current_state.scissor(num).is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ }
+ DynamicState::ScissorWithCount => {
+ // VUID-vkCmdDraw-scissorCount-03418
+ // VUID-vkCmdDraw-viewportCount-03419
+ let scissor_count = if let Some(scissors) = current_state.scissor_with_count() {
+ scissors.len() as u32
+ } else {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ };
+
+ // Check if the counts match, but only if the viewport count is fixed.
+ // If the viewport count is also dynamic, then the
+ // DynamicState::ViewportWithCount match arm will handle it.
+ if let Some(viewport_count) = pipeline.viewport_state().unwrap().count() {
+ // VUID-vkCmdDraw-scissorCount-03418
+ if viewport_count != scissor_count {
+ return Err(
+ PipelineExecutionError::DynamicViewportScissorCountMismatch {
+ viewport_count,
+ scissor_count,
+ },
+ );
+ }
+ }
+ }
+ DynamicState::StencilCompareMask => {
+ let state = current_state.stencil_compare_mask();
+
+ // VUID?
+ if state.front.is_none() || state.back.is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::StencilOp => {
+ let state = current_state.stencil_op();
+
+ // VUID?
+ if state.front.is_none() || state.back.is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::StencilReference => {
+ let state = current_state.stencil_reference();
+
+ // VUID?
+ if state.front.is_none() || state.back.is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::StencilTestEnable => {
+ // VUID?
+ if current_state.stencil_test_enable().is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+
+ // TODO: Check if the stencil buffer is writable
+ }
+ DynamicState::StencilWriteMask => {
+ let state = current_state.stencil_write_mask();
+
+ // VUID?
+ if state.front.is_none() || state.back.is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::VertexInput => todo!(),
+ DynamicState::VertexInputBindingStride => todo!(),
+ DynamicState::Viewport => {
+ for num in 0..pipeline.viewport_state().unwrap().count().unwrap() {
+ // VUID?
+ if current_state.viewport(num).is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ }
+ DynamicState::ViewportCoarseSampleOrder => todo!(),
+ DynamicState::ViewportShadingRatePalette => todo!(),
+ DynamicState::ViewportWithCount => {
+ // VUID-vkCmdDraw-viewportCount-03417
+ let viewport_count = if let Some(viewports) = current_state.viewport_with_count() {
+ viewports.len() as u32
+ } else {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ };
+
+ let scissor_count = if let Some(scissor_count) =
+ pipeline.viewport_state().unwrap().count()
+ {
+ // The scissor count is fixed.
+ scissor_count
+ } else {
+ // VUID-vkCmdDraw-viewportCount-03419
+ // The scissor count is also dynamic.
+ if let Some(scissors) = current_state.scissor_with_count() {
+ scissors.len() as u32
+ } else {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ };
+
+ // VUID-vkCmdDraw-viewportCount-03417
+ // VUID-vkCmdDraw-viewportCount-03419
+ if viewport_count != scissor_count {
+ return Err(
+ PipelineExecutionError::DynamicViewportScissorCountMismatch {
+ viewport_count,
+ scissor_count,
+ },
+ );
+ }
+
+ // TODO: VUID-vkCmdDrawIndexed-primitiveFragmentShadingRateWithMultipleViewports-04552
+ // If the primitiveFragmentShadingRateWithMultipleViewports limit is not supported,
+ // the bound graphics pipeline was created with the
+ // VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT dynamic state enabled, and any of the
+ // shader stages of the bound graphics pipeline write to the PrimitiveShadingRateKHR
+ // built-in, then vkCmdSetViewportWithCountEXT must have been called in the current
+ // command buffer prior to this drawing command, and the viewportCount parameter of
+ // vkCmdSetViewportWithCountEXT must be 1
+ }
+ DynamicState::ViewportWScaling => todo!(),
+ DynamicState::TessellationDomainOrigin => todo!(),
+ DynamicState::DepthClampEnable => todo!(),
+ DynamicState::PolygonMode => todo!(),
+ DynamicState::RasterizationSamples => todo!(),
+ DynamicState::SampleMask => todo!(),
+ DynamicState::AlphaToCoverageEnable => todo!(),
+ DynamicState::AlphaToOneEnable => todo!(),
+ DynamicState::LogicOpEnable => todo!(),
+ DynamicState::ColorBlendEnable => todo!(),
+ DynamicState::ColorBlendEquation => todo!(),
+ DynamicState::ColorWriteMask => todo!(),
+ DynamicState::RasterizationStream => todo!(),
+ DynamicState::ConservativeRasterizationMode => todo!(),
+ DynamicState::ExtraPrimitiveOverestimationSize => todo!(),
+ DynamicState::DepthClipEnable => todo!(),
+ DynamicState::SampleLocationsEnable => todo!(),
+ DynamicState::ColorBlendAdvanced => todo!(),
+ DynamicState::ProvokingVertexMode => todo!(),
+ DynamicState::LineRasterizationMode => todo!(),
+ DynamicState::LineStippleEnable => todo!(),
+ DynamicState::DepthClipNegativeOneToOne => todo!(),
+ DynamicState::ViewportWScalingEnable => todo!(),
+ DynamicState::ViewportSwizzle => todo!(),
+ DynamicState::CoverageToColorEnable => todo!(),
+ DynamicState::CoverageToColorLocation => todo!(),
+ DynamicState::CoverageModulationMode => todo!(),
+ DynamicState::CoverageModulationTableEnable => todo!(),
+ DynamicState::CoverageModulationTable => todo!(),
+ DynamicState::ShadingRateImageEnable => todo!(),
+ DynamicState::RepresentativeFragmentTestEnable => todo!(),
+ DynamicState::CoverageReductionMode => todo!(),
+ }
+ }
+
+ Ok(())
+ }
+
+ fn validate_pipeline_graphics_render_pass(
+ &self,
+ pipeline: &GraphicsPipeline,
+ render_pass_state: &RenderPassState,
+ ) -> Result<(), PipelineExecutionError> {
+ // VUID?
+ if render_pass_state.contents != SubpassContents::Inline {
+ return Err(PipelineExecutionError::ForbiddenWithSubpassContents {
+ subpass_contents: render_pass_state.contents,
+ });
+ }
+
+ match (&render_pass_state.render_pass, pipeline.render_pass()) {
+ (
+ RenderPassStateType::BeginRenderPass(state),
+ PipelineRenderPassType::BeginRenderPass(pipeline_subpass),
+ ) => {
+ // VUID-vkCmdDraw-renderPass-02684
+ if !pipeline_subpass
+ .render_pass()
+ .is_compatible_with(state.subpass.render_pass())
+ {
+ return Err(PipelineExecutionError::PipelineRenderPassNotCompatible);
+ }
+
+ // VUID-vkCmdDraw-subpass-02685
+ if pipeline_subpass.index() != state.subpass.index() {
+ return Err(PipelineExecutionError::PipelineSubpassMismatch {
+ pipeline: pipeline_subpass.index(),
+ current: state.subpass.index(),
+ });
+ }
+ }
+ (
+ RenderPassStateType::BeginRendering(current_rendering_info),
+ PipelineRenderPassType::BeginRendering(pipeline_rendering_info),
+ ) => {
+ // VUID-vkCmdDraw-viewMask-06178
+ if pipeline_rendering_info.view_mask != render_pass_state.view_mask {
+ return Err(PipelineExecutionError::PipelineViewMaskMismatch {
+ pipeline_view_mask: pipeline_rendering_info.view_mask,
+ required_view_mask: render_pass_state.view_mask,
+ });
+ }
+
+ // VUID-vkCmdDraw-colorAttachmentCount-06179
+ if pipeline_rendering_info.color_attachment_formats.len()
+ != current_rendering_info.color_attachment_formats.len()
+ {
+ return Err(
+ PipelineExecutionError::PipelineColorAttachmentCountMismatch {
+ pipeline_count: pipeline_rendering_info.color_attachment_formats.len()
+ as u32,
+ required_count: current_rendering_info.color_attachment_formats.len()
+ as u32,
+ },
+ );
+ }
+
+ for (color_attachment_index, required_format, pipeline_format) in
+ current_rendering_info
+ .color_attachment_formats
+ .iter()
+ .zip(
+ pipeline_rendering_info
+ .color_attachment_formats
+ .iter()
+ .copied(),
+ )
+ .enumerate()
+ .filter_map(|(i, (r, p))| r.map(|r| (i as u32, r, p)))
+ {
+ // VUID-vkCmdDraw-colorAttachmentCount-06180
+ if Some(required_format) != pipeline_format {
+ return Err(
+ PipelineExecutionError::PipelineColorAttachmentFormatMismatch {
+ color_attachment_index,
+ pipeline_format,
+ required_format,
+ },
+ );
+ }
+ }
+
+ if let Some((required_format, pipeline_format)) = current_rendering_info
+ .depth_attachment_format
+ .map(|r| (r, pipeline_rendering_info.depth_attachment_format))
+ {
+ // VUID-vkCmdDraw-pDepthAttachment-06181
+ if Some(required_format) != pipeline_format {
+ return Err(
+ PipelineExecutionError::PipelineDepthAttachmentFormatMismatch {
+ pipeline_format,
+ required_format,
+ },
+ );
+ }
+ }
+
+ if let Some((required_format, pipeline_format)) = current_rendering_info
+ .stencil_attachment_format
+ .map(|r| (r, pipeline_rendering_info.stencil_attachment_format))
+ {
+ // VUID-vkCmdDraw-pStencilAttachment-06182
+ if Some(required_format) != pipeline_format {
+ return Err(
+ PipelineExecutionError::PipelineStencilAttachmentFormatMismatch {
+ pipeline_format,
+ required_format,
+ },
+ );
+ }
+ }
+
+ // VUID-vkCmdDraw-imageView-06172
+ // VUID-vkCmdDraw-imageView-06173
+ // VUID-vkCmdDraw-imageView-06174
+ // VUID-vkCmdDraw-imageView-06175
+ // VUID-vkCmdDraw-imageView-06176
+ // VUID-vkCmdDraw-imageView-06177
+ // TODO:
+ }
+ _ => return Err(PipelineExecutionError::PipelineRenderPassTypeMismatch),
+ }
+
+ // VUID-vkCmdDraw-None-02686
+ // TODO:
+
+ Ok(())
+ }
+
+ fn validate_pipeline_graphics_vertex_buffers(
+ &self,
+ pipeline: &GraphicsPipeline,
+ vertices: Option<(u32, u32)>,
+ instances: Option<(u32, u32)>,
+ ) -> Result<(), PipelineExecutionError> {
+ let vertex_input = pipeline.vertex_input_state();
+ let mut vertices_in_buffers: Option<u64> = None;
+ let mut instances_in_buffers: Option<u64> = None;
+ let current_state = self.state();
+
+ for (&binding_num, binding_desc) in &vertex_input.bindings {
+ // VUID-vkCmdDraw-None-04007
+ let vertex_buffer = match current_state.vertex_buffer(binding_num) {
+ Some(x) => x,
+ None => return Err(PipelineExecutionError::VertexBufferNotBound { binding_num }),
+ };
+
+ let mut num_elements = vertex_buffer.size() / binding_desc.stride as u64;
+
+ match binding_desc.input_rate {
+ VertexInputRate::Vertex => {
+ vertices_in_buffers = Some(if let Some(x) = vertices_in_buffers {
+ min(x, num_elements)
+ } else {
+ num_elements
+ });
+ }
+ VertexInputRate::Instance { divisor } => {
+ if divisor == 0 {
+ // A divisor of 0 means the same instance data is used for all instances,
+ // so we can draw any number of instances from a single element.
+ // The buffer must contain at least one element though.
+ if num_elements != 0 {
+ num_elements = u64::MAX;
+ }
+ } else {
+ // If divisor is e.g. 2, we use only half the amount of data from the source
+ // buffer, so the number of instances that can be drawn is twice as large.
+ num_elements = num_elements.saturating_mul(divisor as u64);
+ }
+
+ instances_in_buffers = Some(if let Some(x) = instances_in_buffers {
+ min(x, num_elements)
+ } else {
+ num_elements
+ });
+ }
+ };
+ }
+
+ if let Some((first_vertex, vertex_count)) = vertices {
+ let vertices_needed = first_vertex as u64 + vertex_count as u64;
+
+ if let Some(vertices_in_buffers) = vertices_in_buffers {
+ // VUID-vkCmdDraw-None-02721
+ if vertices_needed > vertices_in_buffers {
+ return Err(PipelineExecutionError::VertexBufferVertexRangeOutOfBounds {
+ vertices_needed,
+ vertices_in_buffers,
+ });
+ }
+ }
+ }
+
+ if let Some((first_instance, instance_count)) = instances {
+ let instances_needed = first_instance as u64 + instance_count as u64;
+
+ if let Some(instances_in_buffers) = instances_in_buffers {
+ // VUID-vkCmdDraw-None-02721
+ if instances_needed > instances_in_buffers {
+ return Err(
+ PipelineExecutionError::VertexBufferInstanceRangeOutOfBounds {
+ instances_needed,
+ instances_in_buffers,
+ },
+ );
+ }
+ }
+
+ let view_mask = match pipeline.render_pass() {
+ PipelineRenderPassType::BeginRenderPass(subpass) => {
+ subpass.render_pass().views_used()
+ }
+ PipelineRenderPassType::BeginRendering(rendering_info) => rendering_info.view_mask,
+ };
+
+ if view_mask != 0 {
+ let max = pipeline
+ .device()
+ .physical_device()
+ .properties()
+ .max_multiview_instance_index
+ .unwrap_or(0);
+
+ let highest_instance = instances_needed.saturating_sub(1);
+
+ // VUID-vkCmdDraw-maxMultiviewInstanceIndex-02688
+ if highest_instance > max as u64 {
+ return Err(PipelineExecutionError::MaxMultiviewInstanceIndexExceeded {
+ highest_instance,
+ max,
+ });
+ }
+ }
+ }
+
+ Ok(())
+ }
+}
+
+impl SyncCommandBufferBuilder {
+ /// Calls `vkCmdDispatch` on the builder.
+ #[inline]
+ pub unsafe fn dispatch(
+ &mut self,
+ group_counts: [u32; 3],
+ ) -> Result<(), SyncCommandBufferBuilderError> {
+ struct Cmd {
+ group_counts: [u32; 3],
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "dispatch"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.dispatch(self.group_counts);
+ }
+ }
+
+ let command_index = self.commands.len();
+ let command_name = "dispatch";
+ let pipeline = self
+ .current_state
+ .pipeline_compute
+ .as_ref()
+ .unwrap()
+ .as_ref();
+
+ let mut resources = Vec::new();
+ self.add_descriptor_sets(&mut resources, command_index, command_name, pipeline);
+
+ for resource in &resources {
+ self.check_resource_conflicts(resource)?;
+ }
+
+ self.commands.push(Box::new(Cmd { group_counts }));
+
+ for resource in resources {
+ self.add_resource(resource);
+ }
+
+ Ok(())
+ }
+
+ /// Calls `vkCmdDispatchIndirect` on the builder.
+ #[inline]
+ pub unsafe fn dispatch_indirect(
+ &mut self,
+ indirect_buffer: Subbuffer<[DispatchIndirectCommand]>,
+ ) -> Result<(), SyncCommandBufferBuilderError> {
+ struct Cmd {
+ indirect_buffer: Subbuffer<[DispatchIndirectCommand]>,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "dispatch_indirect"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.dispatch_indirect(&self.indirect_buffer);
+ }
+ }
+
+ let command_index = self.commands.len();
+ let command_name = "dispatch_indirect";
+ let pipeline = self
+ .current_state
+ .pipeline_compute
+ .as_ref()
+ .unwrap()
+ .as_ref();
+
+ let mut resources = Vec::new();
+ self.add_descriptor_sets(&mut resources, command_index, command_name, pipeline);
+ self.add_indirect_buffer(
+ &mut resources,
+ command_index,
+ command_name,
+ indirect_buffer.as_bytes(),
+ );
+
+ for resource in &resources {
+ self.check_resource_conflicts(resource)?;
+ }
+
+ self.commands.push(Box::new(Cmd { indirect_buffer }));
+
+ for resource in resources {
+ self.add_resource(resource);
+ }
+
+ Ok(())
+ }
+
+ /// Calls `vkCmdDraw` on the builder.
+ #[inline]
+ pub unsafe fn draw(
+ &mut self,
+ vertex_count: u32,
+ instance_count: u32,
+ first_vertex: u32,
+ first_instance: u32,
+ ) -> Result<(), SyncCommandBufferBuilderError> {
+ struct Cmd {
+ vertex_count: u32,
+ instance_count: u32,
+ first_vertex: u32,
+ first_instance: u32,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "draw"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.draw(
+ self.vertex_count,
+ self.instance_count,
+ self.first_vertex,
+ self.first_instance,
+ );
+ }
+ }
+
+ let command_index = self.commands.len();
+ let command_name = "draw";
+ let pipeline = self
+ .current_state
+ .pipeline_graphics
+ .as_ref()
+ .unwrap()
+ .as_ref();
+
+ let mut resources = Vec::new();
+ self.add_descriptor_sets(&mut resources, command_index, command_name, pipeline);
+ self.add_vertex_buffers(&mut resources, command_index, command_name, pipeline);
+
+ for resource in &resources {
+ self.check_resource_conflicts(resource)?;
+ }
+
+ self.commands.push(Box::new(Cmd {
+ vertex_count,
+ instance_count,
+ first_vertex,
+ first_instance,
+ }));
+
+ for resource in resources {
+ self.add_resource(resource);
+ }
+
+ Ok(())
+ }
+
+ /// Calls `vkCmdDrawIndexed` on the builder.
+ #[inline]
+ pub unsafe fn draw_indexed(
+ &mut self,
+ index_count: u32,
+ instance_count: u32,
+ first_index: u32,
+ vertex_offset: i32,
+ first_instance: u32,
+ ) -> Result<(), SyncCommandBufferBuilderError> {
+ struct Cmd {
+ index_count: u32,
+ instance_count: u32,
+ first_index: u32,
+ vertex_offset: i32,
+ first_instance: u32,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "draw_indexed"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.draw_indexed(
+ self.index_count,
+ self.instance_count,
+ self.first_index,
+ self.vertex_offset,
+ self.first_instance,
+ );
+ }
+ }
+
+ let command_index = self.commands.len();
+ let command_name = "draw_indexed";
+ let pipeline = self
+ .current_state
+ .pipeline_graphics
+ .as_ref()
+ .unwrap()
+ .as_ref();
+
+ let mut resources = Vec::new();
+ self.add_descriptor_sets(&mut resources, command_index, command_name, pipeline);
+ self.add_vertex_buffers(&mut resources, command_index, command_name, pipeline);
+ self.add_index_buffer(&mut resources, command_index, command_name);
+
+ for resource in &resources {
+ self.check_resource_conflicts(resource)?;
+ }
+
+ self.commands.push(Box::new(Cmd {
+ index_count,
+ instance_count,
+ first_index,
+ vertex_offset,
+ first_instance,
+ }));
+
+ for resource in resources {
+ self.add_resource(resource);
+ }
+
+ Ok(())
+ }
+
+ /// Calls `vkCmdDrawIndirect` on the builder.
+ #[inline]
+ pub unsafe fn draw_indirect(
+ &mut self,
+ indirect_buffer: Subbuffer<[DrawIndirectCommand]>,
+ draw_count: u32,
+ stride: u32,
+ ) -> Result<(), SyncCommandBufferBuilderError> {
+ struct Cmd {
+ indirect_buffer: Subbuffer<[DrawIndirectCommand]>,
+ draw_count: u32,
+ stride: u32,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "draw_indirect"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.draw_indirect(&self.indirect_buffer, self.draw_count, self.stride);
+ }
+ }
+
+ let command_index = self.commands.len();
+ let command_name = "draw_indirect";
+ let pipeline = self
+ .current_state
+ .pipeline_graphics
+ .as_ref()
+ .unwrap()
+ .as_ref();
+
+ let mut resources = Vec::new();
+ self.add_descriptor_sets(&mut resources, command_index, command_name, pipeline);
+ self.add_vertex_buffers(&mut resources, command_index, command_name, pipeline);
+ self.add_indirect_buffer(
+ &mut resources,
+ command_index,
+ command_name,
+ indirect_buffer.as_bytes(),
+ );
+
+ for resource in &resources {
+ self.check_resource_conflicts(resource)?;
+ }
+
+ self.commands.push(Box::new(Cmd {
+ indirect_buffer,
+ draw_count,
+ stride,
+ }));
+
+ for resource in resources {
+ self.add_resource(resource);
+ }
+
+ Ok(())
+ }
+
+ /// Calls `vkCmdDrawIndexedIndirect` on the builder.
+ #[inline]
+ pub unsafe fn draw_indexed_indirect(
+ &mut self,
+ indirect_buffer: Subbuffer<[DrawIndexedIndirectCommand]>,
+ draw_count: u32,
+ stride: u32,
+ ) -> Result<(), SyncCommandBufferBuilderError> {
+ struct Cmd {
+ indirect_buffer: Subbuffer<[DrawIndexedIndirectCommand]>,
+ draw_count: u32,
+ stride: u32,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "draw_indexed_indirect"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.draw_indexed_indirect(&self.indirect_buffer, self.draw_count, self.stride);
+ }
+ }
+
+ let command_index = self.commands.len();
+ let command_name = "draw_indexed_indirect";
+ let pipeline = self
+ .current_state
+ .pipeline_graphics
+ .as_ref()
+ .unwrap()
+ .as_ref();
+
+ let mut resources = Vec::new();
+ self.add_descriptor_sets(&mut resources, command_index, command_name, pipeline);
+ self.add_vertex_buffers(&mut resources, command_index, command_name, pipeline);
+ self.add_index_buffer(&mut resources, command_index, command_name);
+ self.add_indirect_buffer(
+ &mut resources,
+ command_index,
+ command_name,
+ indirect_buffer.as_bytes(),
+ );
+
+ for resource in &resources {
+ self.check_resource_conflicts(resource)?;
+ }
+
+ self.commands.push(Box::new(Cmd {
+ indirect_buffer,
+ draw_count,
+ stride,
+ }));
+
+ for resource in resources {
+ self.add_resource(resource);
+ }
+
+ Ok(())
+ }
+
+ fn add_descriptor_sets<Pl: Pipeline>(
+ &self,
+ resources: &mut Vec<(ResourceUseRef, Resource)>,
+ command_index: usize,
+ command_name: &'static str,
+ pipeline: &Pl,
+ ) {
+ let descriptor_sets_state = match self
+ .current_state
+ .descriptor_sets
+ .get(&pipeline.bind_point())
+ {
+ Some(x) => x,
+ None => return,
+ };
+
+ for (&(set, binding), binding_reqs) in pipeline.descriptor_binding_requirements() {
+ // TODO: Can things be refactored so that the pipeline layout isn't needed at all?
+ let descriptor_type = descriptor_sets_state.pipeline_layout.set_layouts()[set as usize]
+ .bindings()[&binding]
+ .descriptor_type;
+
+ let (access_read, access_write) = match descriptor_type {
+ DescriptorType::Sampler => continue,
+ DescriptorType::InputAttachment => {
+ // FIXME: This is tricky. Since we read from the input attachment
+ // and this input attachment is being written in an earlier pass,
+ // vulkano will think that it needs to put a pipeline barrier and will
+ // return a `Conflict` error. For now as a work-around we simply ignore
+ // input attachments.
+ continue;
+ }
+ DescriptorType::CombinedImageSampler
+ | DescriptorType::SampledImage
+ | DescriptorType::UniformTexelBuffer => (Some(AccessFlags::SHADER_READ), None),
+ DescriptorType::StorageImage
+ | DescriptorType::StorageTexelBuffer
+ | DescriptorType::StorageBuffer
+ | DescriptorType::StorageBufferDynamic => (
+ Some(AccessFlags::SHADER_READ),
+ Some(AccessFlags::SHADER_WRITE),
+ ),
+ DescriptorType::UniformBuffer | DescriptorType::UniformBufferDynamic => {
+ (Some(AccessFlags::UNIFORM_READ), None)
+ }
+ };
+
+ let memory_iter = move |index: u32| {
+ let mut stages_read = PipelineStages::empty();
+ let mut stages_write = PipelineStages::empty();
+
+ for desc_reqs in (binding_reqs.descriptors.get(&Some(index)).into_iter())
+ .chain(binding_reqs.descriptors.get(&None))
+ {
+ stages_read |= desc_reqs.memory_read.into();
+ stages_write |= desc_reqs.memory_write.into();
+ }
+
+ let memory_read = (!stages_read.is_empty()).then(|| PipelineMemoryAccess {
+ stages: stages_read,
+ access: access_read.unwrap(),
+ exclusive: false,
+ });
+ let memory_write = (!stages_write.is_empty()).then(|| PipelineMemoryAccess {
+ stages: stages_write,
+ access: access_write.unwrap(),
+ exclusive: true,
+ });
+
+ [memory_read, memory_write].into_iter().flatten()
+ };
+ let buffer_resource =
+ |(index, buffer, range): (u32, Subbuffer<[u8]>, Range<DeviceSize>)| {
+ memory_iter(index).map(move |memory| {
+ (
+ ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::DescriptorSet {
+ set,
+ binding,
+ index,
+ },
+ secondary_use_ref: None,
+ },
+ Resource::Buffer {
+ buffer: buffer.clone(),
+ range: range.clone(),
+ memory,
+ },
+ )
+ })
+ };
+ let image_resource = |(index, image, subresource_range): (
+ u32,
+ Arc<dyn ImageAccess>,
+ ImageSubresourceRange,
+ )| {
+ let layout = image
+ .descriptor_layouts()
+ .expect("descriptor_layouts must return Some when used in an image view")
+ .layout_for(descriptor_type);
+
+ memory_iter(index).map(move |memory| {
+ (
+ ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::DescriptorSet {
+ set,
+ binding,
+ index,
+ },
+ secondary_use_ref: None,
+ },
+ Resource::Image {
+ image: image.clone(),
+ subresource_range: subresource_range.clone(),
+ memory,
+ start_layout: layout,
+ end_layout: layout,
+ },
+ )
+ })
+ };
+
+ let descriptor_set_state = &descriptor_sets_state.descriptor_sets[&set];
+
+ match descriptor_set_state.resources().binding(binding).unwrap() {
+ DescriptorBindingResources::None(_) => continue,
+ DescriptorBindingResources::Buffer(elements) => {
+ if matches!(
+ descriptor_type,
+ DescriptorType::UniformBufferDynamic | DescriptorType::StorageBufferDynamic
+ ) {
+ let dynamic_offsets = descriptor_set_state.dynamic_offsets();
+ resources.extend(
+ (elements.iter().enumerate())
+ .filter_map(|(index, element)| {
+ element.as_ref().map(|(buffer, range)| {
+ let dynamic_offset = dynamic_offsets[index] as DeviceSize;
+
+ (
+ index as u32,
+ buffer.clone(),
+ dynamic_offset + range.start
+ ..dynamic_offset + range.end,
+ )
+ })
+ })
+ .flat_map(buffer_resource),
+ );
+ } else {
+ resources.extend(
+ (elements.iter().enumerate())
+ .filter_map(|(index, element)| {
+ element.as_ref().map(|(buffer, range)| {
+ (index as u32, buffer.clone(), range.clone())
+ })
+ })
+ .flat_map(buffer_resource),
+ );
+ }
+ }
+ DescriptorBindingResources::BufferView(elements) => {
+ resources.extend(
+ (elements.iter().enumerate())
+ .filter_map(|(index, element)| {
+ element.as_ref().map(|buffer_view| {
+ (
+ index as u32,
+ buffer_view.buffer().clone(),
+ buffer_view.range(),
+ )
+ })
+ })
+ .flat_map(buffer_resource),
+ );
+ }
+ DescriptorBindingResources::ImageView(elements) => {
+ resources.extend(
+ (elements.iter().enumerate())
+ .filter_map(|(index, element)| {
+ element.as_ref().map(|image_view| {
+ (
+ index as u32,
+ image_view.image(),
+ image_view.subresource_range().clone(),
+ )
+ })
+ })
+ .flat_map(image_resource),
+ );
+ }
+ DescriptorBindingResources::ImageViewSampler(elements) => {
+ resources.extend(
+ (elements.iter().enumerate())
+ .filter_map(|(index, element)| {
+ element.as_ref().map(|(image_view, _)| {
+ (
+ index as u32,
+ image_view.image(),
+ image_view.subresource_range().clone(),
+ )
+ })
+ })
+ .flat_map(image_resource),
+ );
+ }
+ DescriptorBindingResources::Sampler(_) => (),
+ }
+ }
+ }
+
+ fn add_vertex_buffers(
+ &self,
+ resources: &mut Vec<(ResourceUseRef, Resource)>,
+ command_index: usize,
+ command_name: &'static str,
+ pipeline: &GraphicsPipeline,
+ ) {
+ resources.extend(
+ pipeline
+ .vertex_input_state()
+ .bindings
+ .iter()
+ .map(|(&binding, _)| {
+ let vertex_buffer = &self.current_state.vertex_buffers[&binding];
+ (
+ ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::VertexBuffer { binding },
+ secondary_use_ref: None,
+ },
+ Resource::Buffer {
+ buffer: vertex_buffer.clone(),
+ range: 0..vertex_buffer.size(), // TODO:
+ memory: PipelineMemoryAccess {
+ stages: PipelineStages::VERTEX_INPUT,
+ access: AccessFlags::VERTEX_ATTRIBUTE_READ,
+ exclusive: false,
+ },
+ },
+ )
+ }),
+ );
+ }
+
+ fn add_index_buffer(
+ &self,
+ resources: &mut Vec<(ResourceUseRef, Resource)>,
+ command_index: usize,
+ command_name: &'static str,
+ ) {
+ let index_buffer = &self.current_state.index_buffer.as_ref().unwrap().0;
+ resources.push((
+ ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::IndexBuffer,
+ secondary_use_ref: None,
+ },
+ Resource::Buffer {
+ buffer: index_buffer.clone(),
+ range: 0..index_buffer.size(), // TODO:
+ memory: PipelineMemoryAccess {
+ stages: PipelineStages::VERTEX_INPUT,
+ access: AccessFlags::INDEX_READ,
+ exclusive: false,
+ },
+ },
+ ));
+ }
+
+ fn add_indirect_buffer(
+ &self,
+ resources: &mut Vec<(ResourceUseRef, Resource)>,
+ command_index: usize,
+ command_name: &'static str,
+ indirect_buffer: &Subbuffer<[u8]>,
+ ) {
+ resources.push((
+ ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::IndirectBuffer,
+ secondary_use_ref: None,
+ },
+ Resource::Buffer {
+ buffer: indirect_buffer.clone(),
+ range: 0..indirect_buffer.size(), // TODO:
+ memory: PipelineMemoryAccess {
+ stages: PipelineStages::DRAW_INDIRECT,
+ access: AccessFlags::INDIRECT_COMMAND_READ,
+ exclusive: false,
+ },
+ },
+ ));
+ }
+}
+
+impl UnsafeCommandBufferBuilder {
+ /// Calls `vkCmdDispatch` on the builder.
+ #[inline]
+ pub unsafe fn dispatch(&mut self, group_counts: [u32; 3]) {
+ debug_assert!({
+ let max_group_counts = self
+ .device
+ .physical_device()
+ .properties()
+ .max_compute_work_group_count;
+ group_counts[0] <= max_group_counts[0]
+ && group_counts[1] <= max_group_counts[1]
+ && group_counts[2] <= max_group_counts[2]
+ });
+
+ let fns = self.device.fns();
+ (fns.v1_0.cmd_dispatch)(
+ self.handle,
+ group_counts[0],
+ group_counts[1],
+ group_counts[2],
+ );
+ }
+
+ /// Calls `vkCmdDispatchIndirect` on the builder.
+ #[inline]
+ pub unsafe fn dispatch_indirect(&mut self, buffer: &Subbuffer<[DispatchIndirectCommand]>) {
+ let fns = self.device.fns();
+
+ debug_assert!(buffer.offset() < buffer.buffer().size());
+ debug_assert!(buffer
+ .buffer()
+ .usage()
+ .intersects(BufferUsage::INDIRECT_BUFFER));
+ debug_assert_eq!(buffer.offset() % 4, 0);
+
+ (fns.v1_0.cmd_dispatch_indirect)(self.handle, buffer.buffer().handle(), buffer.offset());
+ }
+
+ /// Calls `vkCmdDraw` on the builder.
+ #[inline]
+ pub unsafe fn draw(
+ &mut self,
+ vertex_count: u32,
+ instance_count: u32,
+ first_vertex: u32,
+ first_instance: u32,
+ ) {
+ let fns = self.device.fns();
+ (fns.v1_0.cmd_draw)(
+ self.handle,
+ vertex_count,
+ instance_count,
+ first_vertex,
+ first_instance,
+ );
+ }
+
+ /// Calls `vkCmdDrawIndexed` on the builder.
+ #[inline]
+ pub unsafe fn draw_indexed(
+ &mut self,
+ index_count: u32,
+ instance_count: u32,
+ first_index: u32,
+ vertex_offset: i32,
+ first_instance: u32,
+ ) {
+ let fns = self.device.fns();
+ (fns.v1_0.cmd_draw_indexed)(
+ self.handle,
+ index_count,
+ instance_count,
+ first_index,
+ vertex_offset,
+ first_instance,
+ );
+ }
+
+ /// Calls `vkCmdDrawIndirect` on the builder.
+ #[inline]
+ pub unsafe fn draw_indirect(
+ &mut self,
+ buffer: &Subbuffer<[DrawIndirectCommand]>,
+ draw_count: u32,
+ stride: u32,
+ ) {
+ let fns = self.device.fns();
+
+ debug_assert!(
+ draw_count == 0
+ || ((stride % 4) == 0)
+ && stride as usize >= size_of::<ash::vk::DrawIndirectCommand>()
+ );
+
+ debug_assert!(buffer.offset() < buffer.buffer().size());
+ debug_assert!(buffer
+ .buffer()
+ .usage()
+ .intersects(BufferUsage::INDIRECT_BUFFER));
+
+ (fns.v1_0.cmd_draw_indirect)(
+ self.handle,
+ buffer.buffer().handle(),
+ buffer.offset(),
+ draw_count,
+ stride,
+ );
+ }
+
+ /// Calls `vkCmdDrawIndexedIndirect` on the builder.
+ #[inline]
+ pub unsafe fn draw_indexed_indirect(
+ &mut self,
+ buffer: &Subbuffer<[DrawIndexedIndirectCommand]>,
+ draw_count: u32,
+ stride: u32,
+ ) {
+ let fns = self.device.fns();
+
+ debug_assert!(buffer.offset() < buffer.buffer().size());
+ debug_assert!(buffer
+ .buffer()
+ .usage()
+ .intersects(BufferUsage::INDIRECT_BUFFER));
+
+ (fns.v1_0.cmd_draw_indexed_indirect)(
+ self.handle,
+ buffer.buffer().handle(),
+ buffer.offset(),
+ draw_count,
+ stride,
+ );
+ }
+}
+
+/// Error that can happen when recording a bound pipeline execution command.
+#[derive(Debug, Clone)]
+pub enum PipelineExecutionError {
+ SyncCommandBufferBuilderError(SyncCommandBufferBuilderError),
+
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+
+ /// The resource bound to a descriptor set binding at a particular index is not compatible
+ /// with the requirements of the pipeline and shaders.
+ DescriptorResourceInvalid {
+ set_num: u32,
+ binding_num: u32,
+ index: u32,
+ error: DescriptorResourceInvalidError,
+ },
+
+ /// The pipeline layout requires a descriptor set bound to a set number, but none was bound.
+ DescriptorSetNotBound {
+ set_num: u32,
+ },
+
+ /// The bound pipeline uses a dynamic color write enable setting, but the number of provided
+ /// enable values is less than the number of attachments in the current render subpass.
+ DynamicColorWriteEnableNotEnoughValues {
+ color_write_enable_count: u32,
+ attachment_count: u32,
+ },
+
+ /// The bound pipeline uses a dynamic primitive topology, but the provided topology is of a
+ /// different topology class than what the pipeline requires.
+ DynamicPrimitiveTopologyClassMismatch {
+ provided_class: PrimitiveTopologyClass,
+ required_class: PrimitiveTopologyClass,
+ },
+
+ /// The bound pipeline uses a dynamic primitive topology, but the provided topology is not
+ /// compatible with the shader stages in the pipeline.
+ DynamicPrimitiveTopologyInvalid {
+ topology: PrimitiveTopology,
+ },
+
+ /// The pipeline requires a particular dynamic state, but this state was not set.
+ DynamicStateNotSet {
+ dynamic_state: DynamicState,
+ },
+
+ /// The bound pipeline uses a dynamic scissor and/or viewport count, but the scissor count
+ /// does not match the viewport count.
+ DynamicViewportScissorCountMismatch {
+ viewport_count: u32,
+ scissor_count: u32,
+ },
+
+ /// Operation forbidden inside a render pass.
+ ForbiddenInsideRenderPass,
+
+ /// Operation forbidden outside a render pass.
+ ForbiddenOutsideRenderPass,
+
+ /// Operation forbidden inside a render subpass with the specified contents.
+ ForbiddenWithSubpassContents {
+ subpass_contents: SubpassContents,
+ },
+
+ /// An indexed draw command was recorded, but no index buffer was bound.
+ IndexBufferNotBound,
+
+ /// The highest index to be drawn exceeds the available number of indices in the bound index
+ /// buffer.
+ IndexBufferRangeOutOfBounds {
+ highest_index: u32,
+ max_index_count: u32,
+ },
+
+ /// The `indirect_buffer` usage was not enabled on the indirect buffer.
+ IndirectBufferMissingUsage,
+
+ /// The `max_compute_work_group_count` limit has been exceeded.
+ MaxComputeWorkGroupCountExceeded {
+ requested: [u32; 3],
+ max: [u32; 3],
+ },
+
+ /// The `max_draw_indirect_count` limit has been exceeded.
+ MaxDrawIndirectCountExceeded {
+ provided: u32,
+ max: u32,
+ },
+
+ /// The `max_multiview_instance_index` limit has been exceeded.
+ MaxMultiviewInstanceIndexExceeded {
+ highest_instance: u64,
+ max: u32,
+ },
+
+ /// The queue family doesn't allow this operation.
+ NotSupportedByQueueFamily,
+
+ /// The color attachment count in the bound pipeline does not match the count of the current
+ /// render pass.
+ PipelineColorAttachmentCountMismatch {
+ pipeline_count: u32,
+ required_count: u32,
+ },
+
+ /// The format of a color attachment in the bound pipeline does not match the format of the
+ /// corresponding color attachment in the current render pass.
+ PipelineColorAttachmentFormatMismatch {
+ color_attachment_index: u32,
+ pipeline_format: Option<Format>,
+ required_format: Format,
+ },
+
+ /// The format of the depth attachment in the bound pipeline does not match the format of the
+ /// depth attachment in the current render pass.
+ PipelineDepthAttachmentFormatMismatch {
+ pipeline_format: Option<Format>,
+ required_format: Format,
+ },
+
+ /// The bound pipeline is not compatible with the layout used to bind the descriptor sets.
+ PipelineLayoutNotCompatible,
+
+ /// No pipeline was bound to the bind point used by the operation.
+ PipelineNotBound,
+
+ /// The bound graphics pipeline uses a render pass that is not compatible with the currently
+ /// active render pass.
+ PipelineRenderPassNotCompatible,
+
+ /// The bound graphics pipeline uses a render pass of a different type than the currently
+ /// active render pass.
+ PipelineRenderPassTypeMismatch,
+
+ /// The bound graphics pipeline uses a render subpass index that doesn't match the currently
+ /// active subpass index.
+ PipelineSubpassMismatch {
+ pipeline: u32,
+ current: u32,
+ },
+
+ /// The format of the stencil attachment in the bound pipeline does not match the format of the
+ /// stencil attachment in the current render pass.
+ PipelineStencilAttachmentFormatMismatch {
+ pipeline_format: Option<Format>,
+ required_format: Format,
+ },
+
+ /// The view mask of the bound pipeline does not match the view mask of the current render pass.
+ PipelineViewMaskMismatch {
+ pipeline_view_mask: u32,
+ required_view_mask: u32,
+ },
+
+ /// The push constants are not compatible with the pipeline layout.
+ PushConstantsNotCompatible,
+
+ /// Not all push constants used by the pipeline have been set.
+ PushConstantsMissing,
+
+ /// The bound graphics pipeline requires a vertex buffer bound to a binding number, but none
+ /// was bound.
+ VertexBufferNotBound {
+ binding_num: u32,
+ },
+
+ /// The number of instances to be drawn exceeds the available number of indices in the
+ /// bound vertex buffers used by the pipeline.
+ VertexBufferInstanceRangeOutOfBounds {
+ instances_needed: u64,
+ instances_in_buffers: u64,
+ },
+
+ /// The number of vertices to be drawn exceeds the lowest available number of vertices in the
+ /// bound vertex buffers used by the pipeline.
+ VertexBufferVertexRangeOutOfBounds {
+ vertices_needed: u64,
+ vertices_in_buffers: u64,
+ },
+}
+
+impl Error for PipelineExecutionError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::SyncCommandBufferBuilderError(err) => Some(err),
+ Self::DescriptorResourceInvalid { error, .. } => Some(error),
+ _ => None,
+ }
+ }
+}
+
+impl Display for PipelineExecutionError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::SyncCommandBufferBuilderError(_) => write!(f, "a SyncCommandBufferBuilderError"),
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ Self::DescriptorResourceInvalid {
+ set_num,
+ binding_num,
+ index,
+ ..
+ } => write!(
+ f,
+ "the resource bound to descriptor set {} binding {} at index {} is not compatible \
+ with the requirements of the pipeline and shaders",
+ set_num, binding_num, index,
+ ),
+ Self::DescriptorSetNotBound { set_num } => write!(
+ f,
+ "the pipeline layout requires a descriptor set bound to set number {}, but none \
+ was bound",
+ set_num,
+ ),
+ Self::DynamicColorWriteEnableNotEnoughValues {
+ color_write_enable_count,
+ attachment_count,
+ } => write!(
+ f,
+ "the bound pipeline uses a dynamic color write enable setting, but the number of \
+ provided enable values ({}) is less than the number of attachments in the current \
+ render subpass ({})",
+ color_write_enable_count, attachment_count,
+ ),
+ Self::DynamicPrimitiveTopologyClassMismatch {
+ provided_class,
+ required_class,
+ } => write!(
+ f,
+ "The bound pipeline uses a dynamic primitive topology, but the provided topology \
+ is of a different topology class ({:?}) than what the pipeline requires ({:?})",
+ provided_class, required_class,
+ ),
+ Self::DynamicPrimitiveTopologyInvalid { topology } => write!(
+ f,
+ "the bound pipeline uses a dynamic primitive topology, but the provided topology \
+ ({:?}) is not compatible with the shader stages in the pipeline",
+ topology,
+ ),
+ Self::DynamicStateNotSet { dynamic_state } => write!(
+ f,
+ "the pipeline requires the dynamic state {:?}, but this state was not set",
+ dynamic_state,
+ ),
+ Self::DynamicViewportScissorCountMismatch {
+ viewport_count,
+ scissor_count,
+ } => write!(
+ f,
+ "the bound pipeline uses a dynamic scissor and/or viewport count, but the scissor \
+ count ({}) does not match the viewport count ({})",
+ scissor_count, viewport_count,
+ ),
+ Self::ForbiddenInsideRenderPass => {
+ write!(f, "operation forbidden inside a render pass")
+ }
+ Self::ForbiddenOutsideRenderPass => {
+ write!(f, "operation forbidden outside a render pass")
+ }
+ Self::ForbiddenWithSubpassContents { subpass_contents } => write!(
+ f,
+ "operation forbidden inside a render subpass with contents {:?}",
+ subpass_contents,
+ ),
+ Self::IndexBufferNotBound => write!(
+ f,
+ "an indexed draw command was recorded, but no index buffer was bound",
+ ),
+ Self::IndexBufferRangeOutOfBounds {
+ highest_index,
+ max_index_count,
+ } => write!(
+ f,
+ "the highest index to be drawn ({}) exceeds the available number of indices in the \
+ bound index buffer ({})",
+ highest_index, max_index_count,
+ ),
+ Self::IndirectBufferMissingUsage => write!(
+ f,
+ "the `indirect_buffer` usage was not enabled on the indirect buffer",
+ ),
+ Self::MaxComputeWorkGroupCountExceeded { .. } => write!(
+ f,
+ "the `max_compute_work_group_count` limit has been exceeded",
+ ),
+ Self::MaxDrawIndirectCountExceeded { .. } => {
+ write!(f, "the `max_draw_indirect_count` limit has been exceeded")
+ }
+ Self::MaxMultiviewInstanceIndexExceeded { .. } => write!(
+ f,
+ "the `max_multiview_instance_index` limit has been exceeded",
+ ),
+ Self::NotSupportedByQueueFamily => {
+ write!(f, "the queue family doesn't allow this operation")
+ }
+ Self::PipelineColorAttachmentCountMismatch {
+ pipeline_count,
+ required_count,
+ } => write!(
+ f,
+ "the color attachment count in the bound pipeline ({}) does not match the count of \
+ the current render pass ({})",
+ pipeline_count, required_count,
+ ),
+ Self::PipelineColorAttachmentFormatMismatch {
+ color_attachment_index,
+ pipeline_format,
+ required_format,
+ } => write!(
+ f,
+ "the format of color attachment {} in the bound pipeline ({:?}) does not match the \
+ format of the corresponding color attachment in the current render pass ({:?})",
+ color_attachment_index, pipeline_format, required_format,
+ ),
+ Self::PipelineDepthAttachmentFormatMismatch {
+ pipeline_format,
+ required_format,
+ } => write!(
+ f,
+ "the format of the depth attachment in the bound pipeline ({:?}) does not match \
+ the format of the depth attachment in the current render pass ({:?})",
+ pipeline_format, required_format,
+ ),
+ Self::PipelineLayoutNotCompatible => write!(
+ f,
+ "the bound pipeline is not compatible with the layout used to bind the descriptor \
+ sets",
+ ),
+ Self::PipelineNotBound => write!(
+ f,
+ "no pipeline was bound to the bind point used by the operation",
+ ),
+ Self::PipelineRenderPassNotCompatible => write!(
+ f,
+ "the bound graphics pipeline uses a render pass that is not compatible with the \
+ currently active render pass",
+ ),
+ Self::PipelineRenderPassTypeMismatch => write!(
+ f,
+ "the bound graphics pipeline uses a render pass of a different type than the \
+ currently active render pass",
+ ),
+ Self::PipelineSubpassMismatch { pipeline, current } => write!(
+ f,
+ "the bound graphics pipeline uses a render subpass index ({}) that doesn't match \
+ the currently active subpass index ({})",
+ pipeline, current,
+ ),
+ Self::PipelineStencilAttachmentFormatMismatch {
+ pipeline_format,
+ required_format,
+ } => write!(
+ f,
+ "the format of the stencil attachment in the bound pipeline ({:?}) does not match \
+ the format of the stencil attachment in the current render pass ({:?})",
+ pipeline_format, required_format,
+ ),
+ Self::PipelineViewMaskMismatch {
+ pipeline_view_mask,
+ required_view_mask,
+ } => write!(
+ f,
+ "the view mask of the bound pipeline ({}) does not match the view mask of the \
+ current render pass ({})",
+ pipeline_view_mask, required_view_mask,
+ ),
+ Self::PushConstantsNotCompatible => write!(
+ f,
+ "the push constants are not compatible with the pipeline layout",
+ ),
+ Self::PushConstantsMissing => write!(
+ f,
+ "not all push constants used by the pipeline have been set",
+ ),
+ Self::VertexBufferNotBound { binding_num } => write!(
+ f,
+ "the bound graphics pipeline requires a vertex buffer bound to binding number {}, \
+ but none was bound",
+ binding_num,
+ ),
+ Self::VertexBufferInstanceRangeOutOfBounds {
+ instances_needed,
+ instances_in_buffers,
+ } => write!(
+ f,
+ "the number of instances to be drawn ({}) exceeds the available number of \
+ instances in the bound vertex buffers ({}) used by the pipeline",
+ instances_needed, instances_in_buffers,
+ ),
+ Self::VertexBufferVertexRangeOutOfBounds {
+ vertices_needed,
+ vertices_in_buffers,
+ } => write!(
+ f,
+ "the number of vertices to be drawn ({}) exceeds the available number of vertices \
+ in the bound vertex buffers ({}) used by the pipeline",
+ vertices_needed, vertices_in_buffers,
+ ),
+ }
+ }
+}
+
+impl From<SyncCommandBufferBuilderError> for PipelineExecutionError {
+ fn from(err: SyncCommandBufferBuilderError) -> Self {
+ Self::SyncCommandBufferBuilderError(err)
+ }
+}
+
+#[derive(Clone, Copy, Debug)]
+pub enum DescriptorResourceInvalidError {
+ ImageViewFormatMismatch {
+ required: Format,
+ provided: Option<Format>,
+ },
+ ImageViewMultisampledMismatch {
+ required: bool,
+ provided: bool,
+ },
+ ImageViewScalarTypeMismatch {
+ required: ShaderScalarType,
+ provided: ShaderScalarType,
+ },
+ ImageViewTypeMismatch {
+ required: ImageViewType,
+ provided: ImageViewType,
+ },
+ Missing,
+ SamplerCompareMismatch {
+ required: bool,
+ provided: bool,
+ },
+ SamplerImageViewIncompatible {
+ image_view_set_num: u32,
+ image_view_binding_num: u32,
+ image_view_index: u32,
+ error: SamplerImageViewIncompatibleError,
+ },
+ SamplerUnnormalizedCoordinatesNotAllowed,
+ SamplerYcbcrConversionNotAllowed,
+ StorageImageAtomicNotSupported,
+ StorageReadWithoutFormatNotSupported,
+ StorageWriteWithoutFormatNotSupported,
+}
+
+impl Error for DescriptorResourceInvalidError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::SamplerImageViewIncompatible { error, .. } => Some(error),
+ _ => None,
+ }
+ }
+}
+
+impl Display for DescriptorResourceInvalidError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::ImageViewFormatMismatch { provided, required } => write!(
+ f,
+ "the format of the bound image view ({:?}) does not match what the pipeline \
+ requires ({:?})",
+ provided, required,
+ ),
+ Self::ImageViewMultisampledMismatch { provided, required } => write!(
+ f,
+ "the multisampling of the bound image ({}) does not match what the pipeline \
+ requires ({})",
+ provided, required,
+ ),
+ Self::ImageViewScalarTypeMismatch { provided, required } => write!(
+ f,
+ "the scalar type of the format and aspect of the bound image view ({:?}) does not \
+ match what the pipeline requires ({:?})",
+ provided, required,
+ ),
+ Self::ImageViewTypeMismatch { provided, required } => write!(
+ f,
+ "the image view type of the bound image view ({:?}) does not match what the \
+ pipeline requires ({:?})",
+ provided, required,
+ ),
+ Self::Missing => write!(f, "no resource was bound"),
+ Self::SamplerImageViewIncompatible { .. } => write!(
+ f,
+ "the bound sampler samples an image view that is not compatible with that sampler",
+ ),
+ Self::SamplerCompareMismatch { provided, required } => write!(
+ f,
+ "the depth comparison state of the bound sampler ({}) does not match what the \
+ pipeline requires ({})",
+ provided, required,
+ ),
+ Self::SamplerUnnormalizedCoordinatesNotAllowed => write!(
+ f,
+ "the bound sampler is required to have unnormalized coordinates disabled",
+ ),
+ Self::SamplerYcbcrConversionNotAllowed => write!(
+ f,
+ "the bound sampler is required to have no attached sampler YCbCr conversion",
+ ),
+ Self::StorageImageAtomicNotSupported => write!(
+ f,
+ "the bound image view does not support the `storage_image_atomic` format feature",
+ ),
+ Self::StorageReadWithoutFormatNotSupported => write!(
+ f,
+ "the bound image view or buffer view does not support the \
+ `storage_read_without_format` format feature",
+ ),
+ Self::StorageWriteWithoutFormatNotSupported => write!(
+ f,
+ "the bound image view or buffer view does not support the \
+ `storage_write_without_format` format feature",
+ ),
+ }
+ }
+}
diff --git a/src/command_buffer/commands/query.rs b/src/command_buffer/commands/query.rs
new file mode 100644
index 0000000..75adb76
--- /dev/null
+++ b/src/command_buffer/commands/query.rs
@@ -0,0 +1,1024 @@
+// Copyright (c) 2022 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use crate::{
+ buffer::{BufferUsage, Subbuffer},
+ command_buffer::{
+ allocator::CommandBufferAllocator,
+ auto::QueryState,
+ synced::{Command, Resource, SyncCommandBufferBuilder, SyncCommandBufferBuilderError},
+ sys::UnsafeCommandBufferBuilder,
+ AutoCommandBufferBuilder, ResourceInCommand, ResourceUseRef,
+ },
+ device::{DeviceOwned, QueueFlags},
+ query::{
+ QueriesRange, Query, QueryControlFlags, QueryPool, QueryResultElement, QueryResultFlags,
+ QueryType,
+ },
+ sync::{AccessFlags, PipelineMemoryAccess, PipelineStage, PipelineStages},
+ DeviceSize, RequirementNotMet, RequiresOneOf, Version, VulkanObject,
+};
+use std::{
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+ mem::size_of,
+ ops::Range,
+ sync::Arc,
+};
+
+/// # Commands related to queries.
+impl<L, A> AutoCommandBufferBuilder<L, A>
+where
+ A: CommandBufferAllocator,
+{
+ /// Begins a query.
+ ///
+ /// The query will be active until [`end_query`](Self::end_query) is called for the same query.
+ ///
+ /// # Safety
+ ///
+ /// The query must be unavailable, ensured by calling
+ /// [`reset_query_pool`](Self::reset_query_pool).
+ pub unsafe fn begin_query(
+ &mut self,
+ query_pool: Arc<QueryPool>,
+ query: u32,
+ flags: QueryControlFlags,
+ ) -> Result<&mut Self, QueryError> {
+ self.validate_begin_query(&query_pool, query, flags)?;
+
+ let ty = query_pool.query_type();
+ let raw_query_pool = query_pool.handle();
+
+ self.inner.begin_query(query_pool, query, flags);
+ self.query_state.insert(
+ ty.into(),
+ QueryState {
+ query_pool: raw_query_pool,
+ query,
+ ty,
+ flags,
+ in_subpass: self.render_pass_state.is_some(),
+ },
+ );
+
+ Ok(self)
+ }
+
+ fn validate_begin_query(
+ &self,
+ query_pool: &QueryPool,
+ query: u32,
+ flags: QueryControlFlags,
+ ) -> Result<(), QueryError> {
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdBeginQuery-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(QueryError::NotSupportedByQueueFamily);
+ }
+
+ let device = self.device();
+
+ // VUID-vkCmdBeginQuery-flags-parameter
+ flags.validate_device(device)?;
+
+ // VUID-vkCmdBeginQuery-commonparent
+ assert_eq!(device, query_pool.device());
+
+ // VUID-vkCmdBeginQuery-query-00802
+ query_pool.query(query).ok_or(QueryError::OutOfRange)?;
+
+ match query_pool.query_type() {
+ QueryType::Occlusion => {
+ // VUID-vkCmdBeginQuery-commandBuffer-cmdpool
+ // // VUID-vkCmdBeginQuery-queryType-00803
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(QueryError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdBeginQuery-queryType-00800
+ if flags.intersects(QueryControlFlags::PRECISE)
+ && !device.enabled_features().occlusion_query_precise
+ {
+ return Err(QueryError::RequirementNotMet {
+ required_for: "`flags` contains `QueryControlFlags::PRECISE`",
+ requires_one_of: RequiresOneOf {
+ features: &["occlusion_query_precise"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ QueryType::PipelineStatistics(statistic_flags) => {
+ // VUID-vkCmdBeginQuery-commandBuffer-cmdpool
+ // VUID-vkCmdBeginQuery-queryType-00804
+ // VUID-vkCmdBeginQuery-queryType-00805
+ if statistic_flags.is_compute()
+ && !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::COMPUTE)
+ || statistic_flags.is_graphics()
+ && !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(QueryError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdBeginQuery-queryType-00800
+ if flags.intersects(QueryControlFlags::PRECISE) {
+ return Err(QueryError::InvalidFlags);
+ }
+ }
+ // VUID-vkCmdBeginQuery-queryType-02804
+ QueryType::Timestamp => return Err(QueryError::NotPermitted),
+ }
+
+ // VUID-vkCmdBeginQuery-queryPool-01922
+ if self
+ .query_state
+ .contains_key(&query_pool.query_type().into())
+ {
+ return Err(QueryError::QueryIsActive);
+ }
+
+ if let Some(render_pass_state) = &self.render_pass_state {
+ // VUID-vkCmdBeginQuery-query-00808
+ if query + render_pass_state.view_mask.count_ones() > query_pool.query_count() {
+ return Err(QueryError::OutOfRangeMultiview);
+ }
+ }
+
+ // VUID-vkCmdBeginQuery-None-00807
+ // Not checked, therefore unsafe.
+ // TODO: add check.
+
+ Ok(())
+ }
+
+ /// Ends an active query.
+ pub fn end_query(
+ &mut self,
+ query_pool: Arc<QueryPool>,
+ query: u32,
+ ) -> Result<&mut Self, QueryError> {
+ self.validate_end_query(&query_pool, query)?;
+
+ unsafe {
+ let raw_ty = query_pool.query_type().into();
+ self.inner.end_query(query_pool, query);
+ self.query_state.remove(&raw_ty);
+ }
+
+ Ok(self)
+ }
+
+ fn validate_end_query(&self, query_pool: &QueryPool, query: u32) -> Result<(), QueryError> {
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdEndQuery-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(QueryError::NotSupportedByQueueFamily);
+ }
+
+ let device = self.device();
+
+ // VUID-vkCmdEndQuery-commonparent
+ assert_eq!(device, query_pool.device());
+
+ // VUID-vkCmdEndQuery-None-01923
+ if !self
+ .query_state
+ .get(&query_pool.query_type().into())
+ .map_or(false, |state| {
+ state.query_pool == query_pool.handle() && state.query == query
+ })
+ {
+ return Err(QueryError::QueryNotActive);
+ }
+
+ // VUID-vkCmdEndQuery-query-00810
+ query_pool.query(query).ok_or(QueryError::OutOfRange)?;
+
+ if let Some(render_pass_state) = &self.render_pass_state {
+ // VUID-vkCmdEndQuery-query-00812
+ if query + render_pass_state.view_mask.count_ones() > query_pool.query_count() {
+ return Err(QueryError::OutOfRangeMultiview);
+ }
+ }
+
+ Ok(())
+ }
+
+ /// Writes a timestamp to a timestamp query.
+ ///
+ /// # Safety
+ ///
+ /// The query must be unavailable, ensured by calling
+ /// [`reset_query_pool`](Self::reset_query_pool).
+ pub unsafe fn write_timestamp(
+ &mut self,
+ query_pool: Arc<QueryPool>,
+ query: u32,
+ stage: PipelineStage,
+ ) -> Result<&mut Self, QueryError> {
+ self.validate_write_timestamp(&query_pool, query, stage)?;
+
+ self.inner.write_timestamp(query_pool, query, stage);
+
+ Ok(self)
+ }
+
+ fn validate_write_timestamp(
+ &self,
+ query_pool: &QueryPool,
+ query: u32,
+ stage: PipelineStage,
+ ) -> Result<(), QueryError> {
+ let device = self.device();
+
+ if !device.enabled_features().synchronization2 && PipelineStages::from(stage).is_2() {
+ return Err(QueryError::RequirementNotMet {
+ required_for: "`stage` has flags set from `VkPipelineStageFlagBits2`",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdWriteTimestamp2-stage-parameter
+ stage.validate_device(device)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdWriteTimestamp2-commandBuffer-cmdpool
+ if !queue_family_properties.queue_flags.intersects(
+ QueueFlags::TRANSFER
+ | QueueFlags::GRAPHICS
+ | QueueFlags::COMPUTE
+ | QueueFlags::VIDEO_DECODE
+ | QueueFlags::VIDEO_ENCODE,
+ ) {
+ return Err(QueryError::NotSupportedByQueueFamily);
+ }
+
+ let device = self.device();
+
+ // VUID-vkCmdWriteTimestamp2-commonparent
+ assert_eq!(device, query_pool.device());
+
+ // VUID-vkCmdWriteTimestamp2-stage-03860
+ if !PipelineStages::from(queue_family_properties.queue_flags).contains_enum(stage) {
+ return Err(QueryError::StageNotSupported);
+ }
+
+ match stage {
+ PipelineStage::GeometryShader => {
+ // VUID-vkCmdWriteTimestamp2-stage-03929
+ if !device.enabled_features().geometry_shader {
+ return Err(QueryError::RequirementNotMet {
+ required_for: "`stage` is `PipelineStage::GeometryShader`",
+ requires_one_of: RequiresOneOf {
+ features: &["geometry_shadere"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ PipelineStage::TessellationControlShader
+ | PipelineStage::TessellationEvaluationShader => {
+ // VUID-vkCmdWriteTimestamp2-stage-03930
+ if !device.enabled_features().tessellation_shader {
+ return Err(QueryError::RequirementNotMet {
+ required_for: "`stage` is `PipelineStage::TessellationControlShader` or \
+ `PipelineStage::TessellationEvaluationShader`",
+ requires_one_of: RequiresOneOf {
+ features: &["tessellation_shader"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ PipelineStage::ConditionalRendering => {
+ // VUID-vkCmdWriteTimestamp2-stage-03931
+ if !device.enabled_features().conditional_rendering {
+ return Err(QueryError::RequirementNotMet {
+ required_for: "`stage` is `PipelineStage::ConditionalRendering`",
+ requires_one_of: RequiresOneOf {
+ features: &["conditional_rendering"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ PipelineStage::FragmentDensityProcess => {
+ // VUID-vkCmdWriteTimestamp2-stage-03932
+ if !device.enabled_features().fragment_density_map {
+ return Err(QueryError::RequirementNotMet {
+ required_for: "`stage` is `PipelineStage::FragmentDensityProcess`",
+ requires_one_of: RequiresOneOf {
+ features: &["fragment_density_map"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ PipelineStage::TransformFeedback => {
+ // VUID-vkCmdWriteTimestamp2-stage-03933
+ if !device.enabled_features().transform_feedback {
+ return Err(QueryError::RequirementNotMet {
+ required_for: "`stage` is `PipelineStage::TransformFeedback`",
+ requires_one_of: RequiresOneOf {
+ features: &["transform_feedback"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ PipelineStage::MeshShader => {
+ // VUID-vkCmdWriteTimestamp2-stage-03934
+ if !device.enabled_features().mesh_shader {
+ return Err(QueryError::RequirementNotMet {
+ required_for: "`stage` is `PipelineStage::MeshShader`",
+ requires_one_of: RequiresOneOf {
+ features: &["mesh_shader"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ PipelineStage::TaskShader => {
+ // VUID-vkCmdWriteTimestamp2-stage-03935
+ if !device.enabled_features().task_shader {
+ return Err(QueryError::RequirementNotMet {
+ required_for: "`stage` is `PipelineStage::TaskShader`",
+ requires_one_of: RequiresOneOf {
+ features: &["task_shader"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ PipelineStage::FragmentShadingRateAttachment => {
+ // VUID-vkCmdWriteTimestamp2-shadingRateImage-07316
+ if !(device.enabled_features().attachment_fragment_shading_rate
+ || device.enabled_features().shading_rate_image)
+ {
+ return Err(QueryError::RequirementNotMet {
+ required_for: "`stage` is `PipelineStage::FragmentShadingRateAttachment`",
+ requires_one_of: RequiresOneOf {
+ features: &["attachment_fragment_shading_rate", "shading_rate_image"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ PipelineStage::SubpassShading => {
+ // VUID-vkCmdWriteTimestamp2-stage-04957
+ if !device.enabled_features().subpass_shading {
+ return Err(QueryError::RequirementNotMet {
+ required_for: "`stage` is `PipelineStage::SubpassShading`",
+ requires_one_of: RequiresOneOf {
+ features: &["subpass_shading"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ PipelineStage::InvocationMask => {
+ // VUID-vkCmdWriteTimestamp2-stage-04995
+ if !device.enabled_features().invocation_mask {
+ return Err(QueryError::RequirementNotMet {
+ required_for: "`stage` is `PipelineStage::InvocationMask`",
+ requires_one_of: RequiresOneOf {
+ features: &["invocation_mask"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ _ => (),
+ }
+
+ // VUID-vkCmdWriteTimestamp2-queryPool-03861
+ if !matches!(query_pool.query_type(), QueryType::Timestamp) {
+ return Err(QueryError::NotPermitted);
+ }
+
+ // VUID-vkCmdWriteTimestamp2-timestampValidBits-03863
+ if queue_family_properties.timestamp_valid_bits.is_none() {
+ return Err(QueryError::NoTimestampValidBits);
+ }
+
+ // VUID-vkCmdWriteTimestamp2-query-04903
+ query_pool.query(query).ok_or(QueryError::OutOfRange)?;
+
+ if let Some(render_pass_state) = &self.render_pass_state {
+ // VUID-vkCmdWriteTimestamp2-query-03865
+ if query + render_pass_state.view_mask.count_ones() > query_pool.query_count() {
+ return Err(QueryError::OutOfRangeMultiview);
+ }
+ }
+
+ // VUID-vkCmdWriteTimestamp2-queryPool-03862
+ // VUID-vkCmdWriteTimestamp2-None-03864
+ // Not checked, therefore unsafe.
+ // TODO: add check.
+
+ Ok(())
+ }
+
+ /// Copies the results of a range of queries to a buffer on the GPU.
+ ///
+ /// [`query_pool.ty().result_len()`] elements will be written for each query in the range, plus
+ /// 1 extra element per query if [`QueryResultFlags::WITH_AVAILABILITY`] is enabled.
+ /// The provided buffer must be large enough to hold the data.
+ ///
+ /// See also [`get_results`].
+ ///
+ /// [`query_pool.ty().result_len()`]: crate::query::QueryType::result_len
+ /// [`QueryResultFlags::WITH_AVAILABILITY`]: crate::query::QueryResultFlags::WITH_AVAILABILITY
+ /// [`get_results`]: crate::query::QueriesRange::get_results
+ pub fn copy_query_pool_results<T>(
+ &mut self,
+ query_pool: Arc<QueryPool>,
+ queries: Range<u32>,
+ destination: Subbuffer<[T]>,
+ flags: QueryResultFlags,
+ ) -> Result<&mut Self, QueryError>
+ where
+ T: QueryResultElement,
+ {
+ self.validate_copy_query_pool_results(&query_pool, queries.clone(), &destination, flags)?;
+
+ unsafe {
+ let per_query_len = query_pool.query_type().result_len()
+ + flags.intersects(QueryResultFlags::WITH_AVAILABILITY) as DeviceSize;
+ let stride = per_query_len * std::mem::size_of::<T>() as DeviceSize;
+ self.inner
+ .copy_query_pool_results(query_pool, queries, destination, stride, flags)?;
+ }
+
+ Ok(self)
+ }
+
+ fn validate_copy_query_pool_results<T>(
+ &self,
+ query_pool: &QueryPool,
+ queries: Range<u32>,
+ destination: &Subbuffer<[T]>,
+ flags: QueryResultFlags,
+ ) -> Result<(), QueryError>
+ where
+ T: QueryResultElement,
+ {
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdCopyQueryPoolResults-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(QueryError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdCopyQueryPoolResults-renderpass
+ if self.render_pass_state.is_some() {
+ return Err(QueryError::ForbiddenInsideRenderPass);
+ }
+
+ let device = self.device();
+
+ // VUID-vkCmdCopyQueryPoolResults-commonparent
+ assert_eq!(device, destination.buffer().device());
+ assert_eq!(device, query_pool.device());
+
+ assert!(destination.len() > 0);
+
+ // VUID-vkCmdCopyQueryPoolResults-flags-00822
+ // VUID-vkCmdCopyQueryPoolResults-flags-00823
+ debug_assert!(destination.offset() % std::mem::size_of::<T>() as DeviceSize == 0);
+
+ // VUID-vkCmdCopyQueryPoolResults-firstQuery-00820
+ // VUID-vkCmdCopyQueryPoolResults-firstQuery-00821
+ query_pool
+ .queries_range(queries.clone())
+ .ok_or(QueryError::OutOfRange)?;
+
+ let count = queries.end - queries.start;
+ let per_query_len = query_pool.query_type().result_len()
+ + flags.intersects(QueryResultFlags::WITH_AVAILABILITY) as DeviceSize;
+ let required_len = per_query_len * count as DeviceSize;
+
+ // VUID-vkCmdCopyQueryPoolResults-dstBuffer-00824
+ if destination.len() < required_len {
+ return Err(QueryError::BufferTooSmall {
+ required_len,
+ actual_len: destination.len(),
+ });
+ }
+
+ // VUID-vkCmdCopyQueryPoolResults-dstBuffer-00825
+ if !destination
+ .buffer()
+ .usage()
+ .intersects(BufferUsage::TRANSFER_DST)
+ {
+ return Err(QueryError::DestinationMissingUsage);
+ }
+
+ // VUID-vkCmdCopyQueryPoolResults-queryType-00827
+ if matches!(query_pool.query_type(), QueryType::Timestamp)
+ && flags.intersects(QueryResultFlags::PARTIAL)
+ {
+ return Err(QueryError::InvalidFlags);
+ }
+
+ Ok(())
+ }
+
+ /// Resets a range of queries on a query pool.
+ ///
+ /// The affected queries will be marked as "unavailable" after this command runs, and will no
+ /// longer return any results. They will be ready to have new results recorded for them.
+ ///
+ /// # Safety
+ /// The queries in the specified range must not be active in another command buffer.
+ // TODO: Do other command buffers actually matter here? Not sure on the Vulkan spec.
+ pub unsafe fn reset_query_pool(
+ &mut self,
+ query_pool: Arc<QueryPool>,
+ queries: Range<u32>,
+ ) -> Result<&mut Self, QueryError> {
+ self.validate_reset_query_pool(&query_pool, queries.clone())?;
+
+ self.inner.reset_query_pool(query_pool, queries);
+
+ Ok(self)
+ }
+
+ fn validate_reset_query_pool(
+ &self,
+ query_pool: &QueryPool,
+ queries: Range<u32>,
+ ) -> Result<(), QueryError> {
+ // VUID-vkCmdResetQueryPool-renderpass
+ if self.render_pass_state.is_some() {
+ return Err(QueryError::ForbiddenInsideRenderPass);
+ }
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdResetQueryPool-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(QueryError::NotSupportedByQueueFamily);
+ }
+
+ let device = self.device();
+
+ // VUID-vkCmdResetQueryPool-commonparent
+ assert_eq!(device, query_pool.device());
+
+ // VUID-vkCmdResetQueryPool-firstQuery-00796
+ // VUID-vkCmdResetQueryPool-firstQuery-00797
+ query_pool
+ .queries_range(queries.clone())
+ .ok_or(QueryError::OutOfRange)?;
+
+ // VUID-vkCmdResetQueryPool-None-02841
+ if self
+ .query_state
+ .values()
+ .any(|state| state.query_pool == query_pool.handle() && queries.contains(&state.query))
+ {
+ return Err(QueryError::QueryIsActive);
+ }
+
+ Ok(())
+ }
+}
+
+impl SyncCommandBufferBuilder {
+ /// Calls `vkCmdBeginQuery` on the builder.
+ #[inline]
+ pub unsafe fn begin_query(
+ &mut self,
+ query_pool: Arc<QueryPool>,
+ query: u32,
+ flags: QueryControlFlags,
+ ) {
+ struct Cmd {
+ query_pool: Arc<QueryPool>,
+ query: u32,
+ flags: QueryControlFlags,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "begin_query"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.begin_query(self.query_pool.query(self.query).unwrap(), self.flags);
+ }
+ }
+
+ self.commands.push(Box::new(Cmd {
+ query_pool,
+ query,
+ flags,
+ }));
+ }
+
+ /// Calls `vkCmdEndQuery` on the builder.
+ #[inline]
+ pub unsafe fn end_query(&mut self, query_pool: Arc<QueryPool>, query: u32) {
+ struct Cmd {
+ query_pool: Arc<QueryPool>,
+ query: u32,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "end_query"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.end_query(self.query_pool.query(self.query).unwrap());
+ }
+ }
+
+ self.commands.push(Box::new(Cmd { query_pool, query }));
+ }
+
+ /// Calls `vkCmdWriteTimestamp` on the builder.
+ #[inline]
+ pub unsafe fn write_timestamp(
+ &mut self,
+ query_pool: Arc<QueryPool>,
+ query: u32,
+ stage: PipelineStage,
+ ) {
+ struct Cmd {
+ query_pool: Arc<QueryPool>,
+ query: u32,
+ stage: PipelineStage,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "write_timestamp"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.write_timestamp(self.query_pool.query(self.query).unwrap(), self.stage);
+ }
+ }
+
+ self.commands.push(Box::new(Cmd {
+ query_pool,
+ query,
+ stage,
+ }));
+ }
+
+ /// Calls `vkCmdCopyQueryPoolResults` on the builder.
+ ///
+ /// # Safety
+ /// `stride` must be at least the number of bytes that will be written by each query.
+ pub unsafe fn copy_query_pool_results(
+ &mut self,
+ query_pool: Arc<QueryPool>,
+ queries: Range<u32>,
+ destination: Subbuffer<[impl QueryResultElement]>,
+ stride: DeviceSize,
+ flags: QueryResultFlags,
+ ) -> Result<(), SyncCommandBufferBuilderError> {
+ struct Cmd<T> {
+ query_pool: Arc<QueryPool>,
+ queries: Range<u32>,
+ destination: Subbuffer<[T]>,
+ stride: DeviceSize,
+ flags: QueryResultFlags,
+ }
+
+ impl<T> Command for Cmd<T>
+ where
+ T: QueryResultElement,
+ {
+ fn name(&self) -> &'static str {
+ "copy_query_pool_results"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.copy_query_pool_results(
+ self.query_pool.queries_range(self.queries.clone()).unwrap(),
+ &self.destination,
+ self.stride,
+ self.flags,
+ );
+ }
+ }
+
+ let command_index = self.commands.len();
+ let command_name = "copy_query_pool_results";
+ let resources = [(
+ ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Destination,
+ secondary_use_ref: None,
+ },
+ Resource::Buffer {
+ buffer: destination.as_bytes().clone(),
+ range: 0..destination.size(), // TODO:
+ memory: PipelineMemoryAccess {
+ stages: PipelineStages::ALL_TRANSFER,
+ access: AccessFlags::TRANSFER_WRITE,
+ exclusive: true,
+ },
+ },
+ )];
+
+ for resource in &resources {
+ self.check_resource_conflicts(resource)?;
+ }
+
+ self.commands.push(Box::new(Cmd {
+ query_pool,
+ queries,
+ destination,
+ stride,
+ flags,
+ }));
+
+ for resource in resources {
+ self.add_resource(resource);
+ }
+
+ Ok(())
+ }
+
+ /// Calls `vkCmdResetQueryPool` on the builder.
+ #[inline]
+ pub unsafe fn reset_query_pool(&mut self, query_pool: Arc<QueryPool>, queries: Range<u32>) {
+ struct Cmd {
+ query_pool: Arc<QueryPool>,
+ queries: Range<u32>,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "reset_query_pool"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.reset_query_pool(self.query_pool.queries_range(self.queries.clone()).unwrap());
+ }
+ }
+
+ self.commands.push(Box::new(Cmd {
+ query_pool,
+ queries,
+ }));
+ }
+}
+
+impl UnsafeCommandBufferBuilder {
+ /// Calls `vkCmdBeginQuery` on the builder.
+ #[inline]
+ pub unsafe fn begin_query(&mut self, query: Query<'_>, flags: QueryControlFlags) {
+ let fns = self.device.fns();
+ (fns.v1_0.cmd_begin_query)(
+ self.handle,
+ query.pool().handle(),
+ query.index(),
+ flags.into(),
+ );
+ }
+
+ /// Calls `vkCmdEndQuery` on the builder.
+ #[inline]
+ pub unsafe fn end_query(&mut self, query: Query<'_>) {
+ let fns = self.device.fns();
+ (fns.v1_0.cmd_end_query)(self.handle, query.pool().handle(), query.index());
+ }
+
+ /// Calls `vkCmdWriteTimestamp` on the builder.
+ #[inline]
+ pub unsafe fn write_timestamp(&mut self, query: Query<'_>, stage: PipelineStage) {
+ let fns = self.device.fns();
+
+ if self.device.enabled_features().synchronization2 {
+ if self.device.api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_write_timestamp2)(
+ self.handle,
+ stage.into(),
+ query.pool().handle(),
+ query.index(),
+ );
+ } else {
+ debug_assert!(self.device.enabled_extensions().khr_synchronization2);
+ (fns.khr_synchronization2.cmd_write_timestamp2_khr)(
+ self.handle,
+ stage.into(),
+ query.pool().handle(),
+ query.index(),
+ );
+ }
+ } else {
+ (fns.v1_0.cmd_write_timestamp)(
+ self.handle,
+ stage.into(),
+ query.pool().handle(),
+ query.index(),
+ );
+ }
+ }
+
+ /// Calls `vkCmdCopyQueryPoolResults` on the builder.
+ pub unsafe fn copy_query_pool_results<T>(
+ &mut self,
+ queries: QueriesRange<'_>,
+ destination: &Subbuffer<[T]>,
+ stride: DeviceSize,
+ flags: QueryResultFlags,
+ ) where
+ T: QueryResultElement,
+ {
+ let range = queries.range();
+ debug_assert!(destination.offset() < destination.buffer().size());
+ debug_assert!(destination
+ .buffer()
+ .usage()
+ .intersects(BufferUsage::TRANSFER_DST));
+ debug_assert!(destination.offset() % size_of::<T>() as DeviceSize == 0);
+ debug_assert!(stride % size_of::<T>() as DeviceSize == 0);
+
+ let fns = self.device.fns();
+ (fns.v1_0.cmd_copy_query_pool_results)(
+ self.handle,
+ queries.pool().handle(),
+ range.start,
+ range.end - range.start,
+ destination.buffer().handle(),
+ destination.offset(),
+ stride,
+ ash::vk::QueryResultFlags::from(flags) | T::FLAG,
+ );
+ }
+
+ /// Calls `vkCmdResetQueryPool` on the builder.
+ #[inline]
+ pub unsafe fn reset_query_pool(&mut self, queries: QueriesRange<'_>) {
+ let range = queries.range();
+ let fns = self.device.fns();
+ (fns.v1_0.cmd_reset_query_pool)(
+ self.handle,
+ queries.pool().handle(),
+ range.start,
+ range.end - range.start,
+ );
+ }
+}
+
+/// Error that can happen when recording a query command.
+#[derive(Clone, Debug)]
+pub enum QueryError {
+ SyncCommandBufferBuilderError(SyncCommandBufferBuilderError),
+
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+
+ /// The buffer is too small for the copy operation.
+ BufferTooSmall {
+ /// Required number of elements in the buffer.
+ required_len: DeviceSize,
+ /// Actual number of elements in the buffer.
+ actual_len: DeviceSize,
+ },
+
+ /// The destination buffer is missing the `transfer_dst` usage.
+ DestinationMissingUsage,
+
+ /// Operation forbidden inside of a render pass.
+ ForbiddenInsideRenderPass,
+
+ /// The provided flags are not allowed for this type of query.
+ InvalidFlags,
+
+ /// The queue family's `timestamp_valid_bits` value is `None`.
+ NoTimestampValidBits,
+
+ /// This operation is not permitted on this query type.
+ NotPermitted,
+
+ /// The queue family doesn't allow this operation.
+ NotSupportedByQueueFamily,
+
+ /// The provided query index is not valid for this pool.
+ OutOfRange,
+
+ /// The provided query index plus the number of views in the current render subpass is greater
+ /// than the number of queries in the pool.
+ OutOfRangeMultiview,
+
+ /// A query is active that conflicts with the current operation.
+ QueryIsActive,
+
+ /// This query was not active.
+ QueryNotActive,
+
+ /// The provided stage is not supported by the queue family.
+ StageNotSupported,
+}
+
+impl Error for QueryError {}
+
+impl Display for QueryError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::SyncCommandBufferBuilderError(_) => write!(f, "a SyncCommandBufferBuilderError"),
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ Self::BufferTooSmall { .. } => {
+ write!(f, "the buffer is too small for the copy operation")
+ }
+ Self::DestinationMissingUsage => write!(
+ f,
+ "the destination buffer is missing the `transfer_dst` usage",
+ ),
+ Self::ForbiddenInsideRenderPass => {
+ write!(f, "operation forbidden inside of a render pass")
+ }
+ Self::InvalidFlags => write!(
+ f,
+ "the provided flags are not allowed for this type of query",
+ ),
+ Self::NoTimestampValidBits => {
+ write!(f, "the queue family's timestamp_valid_bits value is None")
+ }
+ Self::NotPermitted => write!(f, "this operation is not permitted on this query type"),
+ Self::NotSupportedByQueueFamily => {
+ write!(f, "the queue family doesn't allow this operation")
+ }
+ Self::OutOfRange => write!(f, "the provided query index is not valid for this pool"),
+ Self::OutOfRangeMultiview => write!(
+ f,
+ "the provided query index plus the number of views in the current render subpass \
+ is greater than the number of queries in the pool",
+ ),
+ Self::QueryIsActive => write!(
+ f,
+ "a query is active that conflicts with the current operation"
+ ),
+ Self::QueryNotActive => write!(f, "this query was not active"),
+ Self::StageNotSupported => {
+ write!(f, "the provided stage is not supported by the queue family")
+ }
+ }
+ }
+}
+
+impl From<SyncCommandBufferBuilderError> for QueryError {
+ fn from(err: SyncCommandBufferBuilderError) -> Self {
+ Self::SyncCommandBufferBuilderError(err)
+ }
+}
+
+impl From<RequirementNotMet> for QueryError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
+ }
+ }
+}
diff --git a/src/command_buffer/commands/render_pass.rs b/src/command_buffer/commands/render_pass.rs
new file mode 100644
index 0000000..6096cd0
--- /dev/null
+++ b/src/command_buffer/commands/render_pass.rs
@@ -0,0 +1,3175 @@
+// Copyright (c) 2022 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use crate::{
+ command_buffer::{
+ allocator::CommandBufferAllocator,
+ auto::{
+ BeginRenderPassState, BeginRenderingAttachments, BeginRenderingState, RenderPassState,
+ RenderPassStateType,
+ },
+ synced::{Command, Resource, SyncCommandBufferBuilder, SyncCommandBufferBuilderError},
+ sys::UnsafeCommandBufferBuilder,
+ AutoCommandBufferBuilder, ResourceInCommand, ResourceUseRef, SubpassContents,
+ },
+ device::{DeviceOwned, QueueFlags},
+ format::{ClearColorValue, ClearValue, Format, NumericType},
+ image::{ImageAspects, ImageLayout, ImageUsage, ImageViewAbstract, SampleCount},
+ render_pass::{
+ AttachmentDescription, Framebuffer, LoadOp, RenderPass, ResolveMode, StoreOp,
+ SubpassDescription,
+ },
+ sync::{AccessFlags, PipelineMemoryAccess, PipelineStages},
+ RequirementNotMet, RequiresOneOf, Version, VulkanObject,
+};
+use smallvec::SmallVec;
+use std::{
+ cmp::min,
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+ ops::Range,
+ sync::Arc,
+};
+
+/// # Commands for render passes.
+///
+/// These commands require a graphics queue.
+impl<L, A> AutoCommandBufferBuilder<L, A>
+where
+ A: CommandBufferAllocator,
+{
+ /// Begins a render pass using a render pass object and framebuffer.
+ ///
+ /// You must call this or `begin_rendering` before you can record draw commands.
+ ///
+ /// `contents` specifies what kinds of commands will be recorded in the render pass, either
+ /// draw commands or executions of secondary command buffers.
+ pub fn begin_render_pass(
+ &mut self,
+ mut render_pass_begin_info: RenderPassBeginInfo,
+ contents: SubpassContents,
+ ) -> Result<&mut Self, RenderPassError> {
+ self.validate_begin_render_pass(&mut render_pass_begin_info, contents)?;
+
+ unsafe {
+ let RenderPassBeginInfo {
+ ref render_pass,
+ ref framebuffer,
+ render_area_offset,
+ render_area_extent,
+ clear_values: _,
+ _ne: _,
+ } = render_pass_begin_info;
+
+ let subpass = render_pass.clone().first_subpass();
+ let view_mask = subpass.subpass_desc().view_mask;
+
+ let render_pass_state = RenderPassState {
+ contents,
+ render_area_offset,
+ render_area_extent,
+ render_pass: BeginRenderPassState {
+ subpass,
+ framebuffer: Some(framebuffer.clone()),
+ }
+ .into(),
+ view_mask,
+ };
+
+ self.inner
+ .begin_render_pass(render_pass_begin_info, contents)?;
+ self.render_pass_state = Some(render_pass_state);
+
+ Ok(self)
+ }
+ }
+
+ fn validate_begin_render_pass(
+ &self,
+ render_pass_begin_info: &mut RenderPassBeginInfo,
+ contents: SubpassContents,
+ ) -> Result<(), RenderPassError> {
+ let device = self.device();
+
+ // VUID-VkSubpassBeginInfo-contents-parameter
+ contents.validate_device(device)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdBeginRenderPass2-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(RenderPassError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdBeginRenderPass2-renderpass
+ if self.render_pass_state.is_some() {
+ return Err(RenderPassError::ForbiddenInsideRenderPass);
+ }
+
+ let RenderPassBeginInfo {
+ render_pass,
+ framebuffer,
+ render_area_offset,
+ render_area_extent,
+ clear_values,
+ _ne: _,
+ } = render_pass_begin_info;
+
+ // VUID-VkRenderPassBeginInfo-commonparent
+ // VUID-vkCmdBeginRenderPass2-framebuffer-02779
+ assert_eq!(device, framebuffer.device());
+
+ // VUID-VkRenderPassBeginInfo-renderPass-00904
+ if !render_pass.is_compatible_with(framebuffer.render_pass()) {
+ return Err(RenderPassError::FramebufferNotCompatible);
+ }
+
+ for i in 0..2 {
+ // VUID-VkRenderPassBeginInfo-pNext-02852
+ // VUID-VkRenderPassBeginInfo-pNext-02853
+ if render_area_offset[i] + render_area_extent[i] > framebuffer.extent()[i] {
+ return Err(RenderPassError::RenderAreaOutOfBounds);
+ }
+ }
+
+ for (attachment_index, (attachment_desc, image_view)) in render_pass
+ .attachments()
+ .iter()
+ .zip(framebuffer.attachments())
+ .enumerate()
+ {
+ let attachment_index = attachment_index as u32;
+ let &AttachmentDescription {
+ initial_layout,
+ final_layout,
+ ..
+ } = attachment_desc;
+
+ for layout in [initial_layout, final_layout] {
+ match layout {
+ ImageLayout::ColorAttachmentOptimal => {
+ // VUID-vkCmdBeginRenderPass2-initialLayout-03094
+ if !image_view.usage().intersects(ImageUsage::COLOR_ATTACHMENT) {
+ return Err(RenderPassError::AttachmentImageMissingUsage {
+ attachment_index,
+ usage: "color_attachment",
+ });
+ }
+ }
+ ImageLayout::DepthReadOnlyStencilAttachmentOptimal
+ | ImageLayout::DepthAttachmentStencilReadOnlyOptimal
+ | ImageLayout::DepthStencilAttachmentOptimal
+ | ImageLayout::DepthStencilReadOnlyOptimal => {
+ // VUID-vkCmdBeginRenderPass2-initialLayout-03096
+ if !image_view
+ .usage()
+ .intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT)
+ {
+ return Err(RenderPassError::AttachmentImageMissingUsage {
+ attachment_index,
+ usage: "depth_stencil_attachment",
+ });
+ }
+ }
+ ImageLayout::ShaderReadOnlyOptimal => {
+ // VUID-vkCmdBeginRenderPass2-initialLayout-03097
+ if !image_view
+ .usage()
+ .intersects(ImageUsage::SAMPLED | ImageUsage::INPUT_ATTACHMENT)
+ {
+ return Err(RenderPassError::AttachmentImageMissingUsage {
+ attachment_index,
+ usage: "sampled or input_attachment",
+ });
+ }
+ }
+ ImageLayout::TransferSrcOptimal => {
+ // VUID-vkCmdBeginRenderPass2-initialLayout-03098
+ if !image_view.usage().intersects(ImageUsage::TRANSFER_SRC) {
+ return Err(RenderPassError::AttachmentImageMissingUsage {
+ attachment_index,
+ usage: "transfer_src",
+ });
+ }
+ }
+ ImageLayout::TransferDstOptimal => {
+ // VUID-vkCmdBeginRenderPass2-initialLayout-03099
+ if !image_view.usage().intersects(ImageUsage::TRANSFER_DST) {
+ return Err(RenderPassError::AttachmentImageMissingUsage {
+ attachment_index,
+ usage: "transfer_dst",
+ });
+ }
+ }
+ _ => (),
+ }
+ }
+ }
+
+ for subpass_desc in render_pass.subpasses() {
+ let SubpassDescription {
+ view_mask: _,
+ input_attachments,
+ color_attachments,
+ resolve_attachments,
+ depth_stencil_attachment,
+ preserve_attachments: _,
+ _ne: _,
+ } = subpass_desc;
+
+ for atch_ref in (input_attachments.iter())
+ .chain(color_attachments)
+ .chain(resolve_attachments)
+ .chain([depth_stencil_attachment])
+ .flatten()
+ {
+ let image_view = &framebuffer.attachments()[atch_ref.attachment as usize];
+
+ match atch_ref.layout {
+ ImageLayout::ColorAttachmentOptimal => {
+ // VUID-vkCmdBeginRenderPass2-initialLayout-03094
+ if !image_view.usage().intersects(ImageUsage::COLOR_ATTACHMENT) {
+ return Err(RenderPassError::AttachmentImageMissingUsage {
+ attachment_index: atch_ref.attachment,
+ usage: "color_attachment",
+ });
+ }
+ }
+ ImageLayout::DepthReadOnlyStencilAttachmentOptimal
+ | ImageLayout::DepthAttachmentStencilReadOnlyOptimal
+ | ImageLayout::DepthStencilAttachmentOptimal
+ | ImageLayout::DepthStencilReadOnlyOptimal => {
+ // VUID-vkCmdBeginRenderPass2-initialLayout-03096
+ if !image_view
+ .usage()
+ .intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT)
+ {
+ return Err(RenderPassError::AttachmentImageMissingUsage {
+ attachment_index: atch_ref.attachment,
+ usage: "depth_stencil_attachment",
+ });
+ }
+ }
+ ImageLayout::ShaderReadOnlyOptimal => {
+ // VUID-vkCmdBeginRenderPass2-initialLayout-03097
+ if !image_view
+ .usage()
+ .intersects(ImageUsage::SAMPLED | ImageUsage::INPUT_ATTACHMENT)
+ {
+ return Err(RenderPassError::AttachmentImageMissingUsage {
+ attachment_index: atch_ref.attachment,
+ usage: "sampled or input_attachment",
+ });
+ }
+ }
+ ImageLayout::TransferSrcOptimal => {
+ // VUID-vkCmdBeginRenderPass2-initialLayout-03098
+ if !image_view.usage().intersects(ImageUsage::TRANSFER_SRC) {
+ return Err(RenderPassError::AttachmentImageMissingUsage {
+ attachment_index: atch_ref.attachment,
+ usage: "transfer_src",
+ });
+ }
+ }
+ ImageLayout::TransferDstOptimal => {
+ // VUID-vkCmdBeginRenderPass2-initialLayout-03099
+ if !image_view.usage().intersects(ImageUsage::TRANSFER_DST) {
+ return Err(RenderPassError::AttachmentImageMissingUsage {
+ attachment_index: atch_ref.attachment,
+ usage: "transfer_dst",
+ });
+ }
+ }
+ _ => (),
+ }
+ }
+ }
+
+ // VUID-VkRenderPassBeginInfo-clearValueCount-00902
+ if clear_values.len() < render_pass.attachments().len() {
+ return Err(RenderPassError::ClearValueMissing {
+ attachment_index: clear_values.len() as u32,
+ });
+ }
+
+ // VUID-VkRenderPassBeginInfo-clearValueCount-04962
+ for (attachment_index, (attachment_desc, &mut clear_value)) in render_pass
+ .attachments()
+ .iter()
+ .zip(clear_values)
+ .enumerate()
+ {
+ let attachment_index = attachment_index as u32;
+ let attachment_format = attachment_desc.format.unwrap();
+
+ if attachment_desc.load_op == LoadOp::Clear
+ || attachment_desc.stencil_load_op == LoadOp::Clear
+ {
+ let clear_value = match clear_value {
+ Some(x) => x,
+ None => return Err(RenderPassError::ClearValueMissing { attachment_index }),
+ };
+
+ if let (Some(numeric_type), LoadOp::Clear) =
+ (attachment_format.type_color(), attachment_desc.load_op)
+ {
+ match numeric_type {
+ NumericType::SFLOAT
+ | NumericType::UFLOAT
+ | NumericType::SNORM
+ | NumericType::UNORM
+ | NumericType::SSCALED
+ | NumericType::USCALED
+ | NumericType::SRGB => {
+ if !matches!(clear_value, ClearValue::Float(_)) {
+ return Err(RenderPassError::ClearValueNotCompatible {
+ clear_value,
+ attachment_index,
+ attachment_format,
+ });
+ }
+ }
+ NumericType::SINT => {
+ if !matches!(clear_value, ClearValue::Int(_)) {
+ return Err(RenderPassError::ClearValueNotCompatible {
+ clear_value,
+ attachment_index,
+ attachment_format,
+ });
+ }
+ }
+ NumericType::UINT => {
+ if !matches!(clear_value, ClearValue::Uint(_)) {
+ return Err(RenderPassError::ClearValueNotCompatible {
+ clear_value,
+ attachment_index,
+ attachment_format,
+ });
+ }
+ }
+ }
+ } else {
+ let attachment_aspects = attachment_format.aspects();
+ let need_depth = attachment_aspects.intersects(ImageAspects::DEPTH)
+ && attachment_desc.load_op == LoadOp::Clear;
+ let need_stencil = attachment_aspects.intersects(ImageAspects::STENCIL)
+ && attachment_desc.stencil_load_op == LoadOp::Clear;
+
+ if need_depth && need_stencil {
+ if !matches!(clear_value, ClearValue::DepthStencil(_)) {
+ return Err(RenderPassError::ClearValueNotCompatible {
+ clear_value,
+ attachment_index,
+ attachment_format,
+ });
+ }
+ } else if need_depth {
+ if !matches!(clear_value, ClearValue::Depth(_)) {
+ return Err(RenderPassError::ClearValueNotCompatible {
+ clear_value,
+ attachment_index,
+ attachment_format,
+ });
+ }
+ } else if need_stencil {
+ if !matches!(clear_value, ClearValue::Stencil(_)) {
+ return Err(RenderPassError::ClearValueNotCompatible {
+ clear_value,
+ attachment_index,
+ attachment_format,
+ });
+ }
+ }
+ }
+ }
+ }
+
+ // VUID-vkCmdBeginRenderPass2-initialLayout-03100
+ // TODO:
+
+ // VUID-vkCmdBeginRenderPass2-srcStageMask-06453
+ // TODO:
+
+ // VUID-vkCmdBeginRenderPass2-dstStageMask-06454
+ // TODO:
+
+ // VUID-vkCmdBeginRenderPass2-framebuffer-02533
+ // For any attachment in framebuffer that is used by renderPass and is bound to memory locations that are also bound to another attachment used by renderPass, and if at least one of those uses causes either
+ // attachment to be written to, both attachments must have had the VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT set
+
+ Ok(())
+ }
+
+ /// Advances to the next subpass of the render pass previously begun with `begin_render_pass`.
+ pub fn next_subpass(
+ &mut self,
+ contents: SubpassContents,
+ ) -> Result<&mut Self, RenderPassError> {
+ self.validate_next_subpass(contents)?;
+
+ unsafe {
+ let render_pass_state = self.render_pass_state.as_mut().unwrap();
+ let begin_render_pass_state = match &mut render_pass_state.render_pass {
+ RenderPassStateType::BeginRenderPass(x) => x,
+ _ => unreachable!(),
+ };
+
+ begin_render_pass_state.subpass.next_subpass();
+ render_pass_state.contents = contents;
+ render_pass_state.view_mask = begin_render_pass_state.subpass.subpass_desc().view_mask;
+
+ if render_pass_state.view_mask != 0 {
+ // When multiview is enabled, at the beginning of each subpass, all
+ // non-render pass state is undefined.
+ self.inner.reset_state();
+ }
+
+ self.inner.next_subpass(contents);
+ }
+
+ Ok(self)
+ }
+
+ fn validate_next_subpass(&self, contents: SubpassContents) -> Result<(), RenderPassError> {
+ let device = self.device();
+
+ // VUID-VkSubpassBeginInfo-contents-parameter
+ contents.validate_device(device)?;
+
+ // VUID-vkCmdNextSubpass2-renderpass
+ let render_pass_state = self
+ .render_pass_state
+ .as_ref()
+ .ok_or(RenderPassError::ForbiddenOutsideRenderPass)?;
+
+ let begin_render_pass_state = match &render_pass_state.render_pass {
+ RenderPassStateType::BeginRenderPass(state) => state,
+ RenderPassStateType::BeginRendering(_) => {
+ return Err(RenderPassError::ForbiddenWithBeginRendering)
+ }
+ };
+
+ // VUID-vkCmdNextSubpass2-None-03102
+ if begin_render_pass_state.subpass.is_last_subpass() {
+ return Err(RenderPassError::NoSubpassesRemaining {
+ current_subpass: begin_render_pass_state.subpass.index(),
+ });
+ }
+
+ // VUID?
+ if self.query_state.values().any(|state| state.in_subpass) {
+ return Err(RenderPassError::QueryIsActive);
+ }
+
+ // VUID-vkCmdNextSubpass2-commandBuffer-cmdpool
+ debug_assert!(self
+ .queue_family_properties()
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS));
+
+ // VUID-vkCmdNextSubpass2-bufferlevel
+ // Ensured by the type of the impl block
+
+ Ok(())
+ }
+
+ /// Ends the render pass previously begun with `begin_render_pass`.
+ ///
+ /// This must be called after you went through all the subpasses.
+ pub fn end_render_pass(&mut self) -> Result<&mut Self, RenderPassError> {
+ self.validate_end_render_pass()?;
+
+ unsafe {
+ self.inner.end_render_pass();
+ self.render_pass_state = None;
+ }
+
+ Ok(self)
+ }
+
+ fn validate_end_render_pass(&self) -> Result<(), RenderPassError> {
+ // VUID-vkCmdEndRenderPass2-renderpass
+ let render_pass_state = self
+ .render_pass_state
+ .as_ref()
+ .ok_or(RenderPassError::ForbiddenOutsideRenderPass)?;
+
+ let begin_render_pass_state = match &render_pass_state.render_pass {
+ RenderPassStateType::BeginRenderPass(state) => state,
+ RenderPassStateType::BeginRendering(_) => {
+ return Err(RenderPassError::ForbiddenWithBeginRendering)
+ }
+ };
+
+ // VUID-vkCmdEndRenderPass2-None-03103
+ if !begin_render_pass_state.subpass.is_last_subpass() {
+ return Err(RenderPassError::SubpassesRemaining {
+ current_subpass: begin_render_pass_state.subpass.index(),
+ remaining_subpasses: begin_render_pass_state
+ .subpass
+ .render_pass()
+ .subpasses()
+ .len() as u32
+ - begin_render_pass_state.subpass.index(),
+ });
+ }
+
+ // VUID?
+ if self.query_state.values().any(|state| state.in_subpass) {
+ return Err(RenderPassError::QueryIsActive);
+ }
+
+ // VUID-vkCmdEndRenderPass2-commandBuffer-cmdpool
+ debug_assert!(self
+ .queue_family_properties()
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS));
+
+ // VUID-vkCmdEndRenderPass2-bufferlevel
+ // Ensured by the type of the impl block
+
+ Ok(())
+ }
+}
+
+impl<L, A> AutoCommandBufferBuilder<L, A>
+where
+ A: CommandBufferAllocator,
+{
+ /// Begins a render pass without a render pass object or framebuffer.
+ ///
+ /// You must call this or `begin_render_pass` before you can record draw commands.
+ pub fn begin_rendering(
+ &mut self,
+ mut rendering_info: RenderingInfo,
+ ) -> Result<&mut Self, RenderPassError> {
+ rendering_info.set_extent_layers()?;
+ self.validate_begin_rendering(&mut rendering_info)?;
+
+ unsafe {
+ let RenderingInfo {
+ render_area_offset,
+ render_area_extent,
+ layer_count: _,
+ view_mask,
+ ref color_attachments,
+ ref depth_attachment,
+ ref stencil_attachment,
+ contents,
+ _ne: _,
+ } = rendering_info;
+
+ let render_pass_state = RenderPassState {
+ contents,
+ render_area_offset,
+ render_area_extent,
+ render_pass: BeginRenderingState {
+ attachments: Some(BeginRenderingAttachments {
+ color_attachments: color_attachments.clone(),
+ depth_attachment: depth_attachment.clone(),
+ stencil_attachment: stencil_attachment.clone(),
+ }),
+ color_attachment_formats: color_attachments
+ .iter()
+ .map(|a| a.as_ref().map(|a| a.image_view.format().unwrap()))
+ .collect(),
+ depth_attachment_format: depth_attachment
+ .as_ref()
+ .map(|a| a.image_view.format().unwrap()),
+ stencil_attachment_format: stencil_attachment
+ .as_ref()
+ .map(|a| a.image_view.format().unwrap()),
+ pipeline_used: false,
+ }
+ .into(),
+ view_mask,
+ };
+
+ self.inner.begin_rendering(rendering_info)?;
+
+ self.render_pass_state = Some(render_pass_state);
+ }
+
+ Ok(self)
+ }
+
+ fn validate_begin_rendering(
+ &self,
+ rendering_info: &mut RenderingInfo,
+ ) -> Result<(), RenderPassError> {
+ let device = self.device();
+ let properties = device.physical_device().properties();
+
+ // VUID-vkCmdBeginRendering-dynamicRendering-06446
+ if !device.enabled_features().dynamic_rendering {
+ return Err(RenderPassError::RequirementNotMet {
+ required_for: "`AutoCommandBufferBuilder::begin_rendering`",
+ requires_one_of: RequiresOneOf {
+ features: &["dynamic_rendering"],
+ ..Default::default()
+ },
+ });
+ }
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdBeginRendering-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(RenderPassError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdBeginRendering-renderpass
+ if self.render_pass_state.is_some() {
+ return Err(RenderPassError::ForbiddenInsideRenderPass);
+ }
+
+ let &mut RenderingInfo {
+ render_area_offset,
+ render_area_extent,
+ layer_count,
+ view_mask,
+ ref color_attachments,
+ ref depth_attachment,
+ ref stencil_attachment,
+ contents,
+ _ne: _,
+ } = rendering_info;
+
+ // VUID-VkRenderingInfo-flags-parameter
+ contents.validate_device(device)?;
+
+ // VUID-vkCmdBeginRendering-commandBuffer-06068
+ if self.inheritance_info.is_some() && contents == SubpassContents::SecondaryCommandBuffers {
+ return Err(RenderPassError::ContentsForbiddenInSecondaryCommandBuffer);
+ }
+
+ // No VUID, but for sanity it makes sense to treat this the same as in framebuffers.
+ if view_mask != 0 && layer_count != 1 {
+ return Err(RenderPassError::MultiviewLayersInvalid);
+ }
+
+ // VUID-VkRenderingInfo-multiview-06127
+ if view_mask != 0 && !device.enabled_features().multiview {
+ return Err(RenderPassError::RequirementNotMet {
+ required_for: "`rendering_info.viewmask` is not `0`",
+ requires_one_of: RequiresOneOf {
+ features: &["multiview"],
+ ..Default::default()
+ },
+ });
+ }
+
+ let view_count = u32::BITS - view_mask.leading_zeros();
+
+ // VUID-VkRenderingInfo-viewMask-06128
+ if view_count > properties.max_multiview_view_count.unwrap_or(0) {
+ return Err(RenderPassError::MaxMultiviewViewCountExceeded {
+ view_count,
+ max: properties.max_multiview_view_count.unwrap_or(0),
+ });
+ }
+
+ let mut samples = None;
+
+ // VUID-VkRenderingInfo-colorAttachmentCount-06106
+ if color_attachments.len() > properties.max_color_attachments as usize {
+ return Err(RenderPassError::MaxColorAttachmentsExceeded {
+ color_attachment_count: color_attachments.len() as u32,
+ max: properties.max_color_attachments,
+ });
+ }
+
+ for (attachment_index, attachment_info) in
+ color_attachments
+ .iter()
+ .enumerate()
+ .filter_map(|(index, attachment_info)| {
+ attachment_info
+ .as_ref()
+ .map(|attachment_info| (index, attachment_info))
+ })
+ {
+ let attachment_index = attachment_index as u32;
+ let RenderingAttachmentInfo {
+ image_view,
+ image_layout,
+ resolve_info,
+ load_op,
+ store_op,
+ clear_value: _,
+ _ne: _,
+ } = attachment_info;
+
+ // VUID-VkRenderingAttachmentInfo-imageLayout-parameter
+ image_layout.validate_device(device)?;
+
+ // VUID-VkRenderingAttachmentInfo-loadOp-parameter
+ load_op.validate_device(device)?;
+
+ // VUID-VkRenderingAttachmentInfo-storeOp-parameter
+ store_op.validate_device(device)?;
+
+ // VUID-VkRenderingInfo-colorAttachmentCount-06087
+ if !image_view.usage().intersects(ImageUsage::COLOR_ATTACHMENT) {
+ return Err(RenderPassError::ColorAttachmentMissingUsage { attachment_index });
+ }
+
+ let image = image_view.image();
+ let image_extent = image.dimensions().width_height_depth();
+
+ for i in 0..2 {
+ // VUID-VkRenderingInfo-pNext-06079
+ // VUID-VkRenderingInfo-pNext-06080
+ if render_area_offset[i] + render_area_extent[i] > image_extent[i] {
+ return Err(RenderPassError::RenderAreaOutOfBounds);
+ }
+ }
+
+ // VUID-VkRenderingInfo-imageView-06070
+ match samples {
+ Some(samples) if samples == image.samples() => (),
+ Some(_) => {
+ return Err(RenderPassError::ColorAttachmentSamplesMismatch {
+ attachment_index,
+ });
+ }
+ None => samples = Some(image.samples()),
+ }
+
+ // VUID-VkRenderingAttachmentInfo-imageView-06135
+ // VUID-VkRenderingAttachmentInfo-imageView-06145
+ // VUID-VkRenderingInfo-colorAttachmentCount-06090
+ // VUID-VkRenderingInfo-colorAttachmentCount-06096
+ if matches!(
+ image_layout,
+ ImageLayout::Undefined
+ | ImageLayout::ShaderReadOnlyOptimal
+ | ImageLayout::TransferSrcOptimal
+ | ImageLayout::TransferDstOptimal
+ | ImageLayout::Preinitialized
+ | ImageLayout::PresentSrc
+ | ImageLayout::DepthStencilAttachmentOptimal
+ | ImageLayout::DepthStencilReadOnlyOptimal
+ | ImageLayout::DepthReadOnlyStencilAttachmentOptimal
+ | ImageLayout::DepthAttachmentStencilReadOnlyOptimal
+ ) {
+ return Err(RenderPassError::ColorAttachmentLayoutInvalid { attachment_index });
+ }
+
+ if let Some(resolve_info) = resolve_info {
+ let &RenderingAttachmentResolveInfo {
+ mode,
+ image_view: ref resolve_image_view,
+ image_layout: resolve_image_layout,
+ } = resolve_info;
+
+ // VUID-VkRenderingAttachmentInfo-resolveImageLayout-parameter
+ resolve_image_layout.validate_device(device)?;
+
+ // VUID-VkRenderingAttachmentInfo-resolveMode-parameter
+ mode.validate_device(device)?;
+
+ let resolve_image = resolve_image_view.image();
+
+ match image_view.format().unwrap().type_color() {
+ Some(
+ NumericType::SFLOAT
+ | NumericType::UFLOAT
+ | NumericType::SNORM
+ | NumericType::UNORM
+ | NumericType::SSCALED
+ | NumericType::USCALED
+ | NumericType::SRGB,
+ ) => {
+ // VUID-VkRenderingAttachmentInfo-imageView-06129
+ if mode != ResolveMode::Average {
+ return Err(RenderPassError::ColorAttachmentResolveModeNotSupported {
+ attachment_index,
+ });
+ }
+ }
+ Some(NumericType::SINT | NumericType::UINT) => {
+ // VUID-VkRenderingAttachmentInfo-imageView-06130
+ if mode != ResolveMode::SampleZero {
+ return Err(RenderPassError::ColorAttachmentResolveModeNotSupported {
+ attachment_index,
+ });
+ }
+ }
+ None => (),
+ }
+
+ // VUID-VkRenderingAttachmentInfo-imageView-06132
+ if image.samples() == SampleCount::Sample1 {
+ return Err(RenderPassError::ColorAttachmentWithResolveNotMultisampled {
+ attachment_index,
+ });
+ }
+
+ // VUID-VkRenderingAttachmentInfo-imageView-06133
+ if resolve_image.samples() != SampleCount::Sample1 {
+ return Err(RenderPassError::ColorAttachmentResolveMultisampled {
+ attachment_index,
+ });
+ }
+
+ // VUID-VkRenderingAttachmentInfo-imageView-06134
+ if image_view.format() != resolve_image_view.format() {
+ return Err(RenderPassError::ColorAttachmentResolveFormatMismatch {
+ attachment_index,
+ });
+ }
+
+ // VUID-VkRenderingAttachmentInfo-imageView-06136
+ // VUID-VkRenderingAttachmentInfo-imageView-06146
+ // VUID-VkRenderingInfo-colorAttachmentCount-06091
+ // VUID-VkRenderingInfo-colorAttachmentCount-06097
+ if matches!(
+ resolve_image_layout,
+ ImageLayout::Undefined
+ | ImageLayout::ShaderReadOnlyOptimal
+ | ImageLayout::TransferSrcOptimal
+ | ImageLayout::TransferDstOptimal
+ | ImageLayout::Preinitialized
+ | ImageLayout::PresentSrc
+ | ImageLayout::DepthStencilAttachmentOptimal
+ | ImageLayout::DepthStencilReadOnlyOptimal
+ | ImageLayout::DepthReadOnlyStencilAttachmentOptimal
+ | ImageLayout::DepthAttachmentStencilReadOnlyOptimal
+ ) {
+ return Err(RenderPassError::ColorAttachmentResolveLayoutInvalid {
+ attachment_index,
+ });
+ }
+ }
+ }
+
+ if let Some(attachment_info) = depth_attachment {
+ let RenderingAttachmentInfo {
+ image_view,
+ image_layout,
+ resolve_info,
+ load_op,
+ store_op,
+ clear_value: _,
+ _ne: _,
+ } = attachment_info;
+
+ // VUID-VkRenderingAttachmentInfo-imageLayout-parameter
+ image_layout.validate_device(device)?;
+
+ // VUID-VkRenderingAttachmentInfo-loadOp-parameter
+ load_op.validate_device(device)?;
+
+ // VUID-VkRenderingAttachmentInfo-storeOp-parameter
+ store_op.validate_device(device)?;
+
+ let image_aspects = image_view.format().unwrap().aspects();
+
+ // VUID-VkRenderingInfo-pDepthAttachment-06547
+ if !image_aspects.intersects(ImageAspects::DEPTH) {
+ return Err(RenderPassError::DepthAttachmentFormatUsageNotSupported);
+ }
+
+ // VUID-VkRenderingInfo-pDepthAttachment-06088
+ if !image_view
+ .usage()
+ .intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT)
+ {
+ return Err(RenderPassError::DepthAttachmentMissingUsage);
+ }
+
+ let image = image_view.image();
+ let image_extent = image.dimensions().width_height_depth();
+
+ for i in 0..2 {
+ // VUID-VkRenderingInfo-pNext-06079
+ // VUID-VkRenderingInfo-pNext-06080
+ if render_area_offset[i] + render_area_extent[i] > image_extent[i] {
+ return Err(RenderPassError::RenderAreaOutOfBounds);
+ }
+ }
+
+ // VUID-VkRenderingInfo-imageView-06070
+ match samples {
+ Some(samples) if samples == image.samples() => (),
+ Some(_) => {
+ return Err(RenderPassError::DepthAttachmentSamplesMismatch);
+ }
+ None => samples = Some(image.samples()),
+ }
+
+ // VUID-VkRenderingAttachmentInfo-imageView-06135
+ // VUID-VkRenderingAttachmentInfo-imageView-06145
+ // VUID-VkRenderingInfo-pDepthAttachment-06092
+ if matches!(
+ image_layout,
+ ImageLayout::Undefined
+ | ImageLayout::ShaderReadOnlyOptimal
+ | ImageLayout::TransferSrcOptimal
+ | ImageLayout::TransferDstOptimal
+ | ImageLayout::Preinitialized
+ | ImageLayout::PresentSrc
+ | ImageLayout::ColorAttachmentOptimal
+ ) {
+ return Err(RenderPassError::DepthAttachmentLayoutInvalid);
+ }
+
+ if let Some(resolve_info) = resolve_info {
+ let &RenderingAttachmentResolveInfo {
+ mode,
+ image_view: ref resolve_image_view,
+ image_layout: resolve_image_layout,
+ } = resolve_info;
+
+ // VUID-VkRenderingAttachmentInfo-resolveImageLayout-parameter
+ resolve_image_layout.validate_device(device)?;
+
+ // VUID-VkRenderingAttachmentInfo-resolveMode-parameter
+ mode.validate_device(device)?;
+
+ // VUID-VkRenderingInfo-pDepthAttachment-06102
+ if !properties
+ .supported_depth_resolve_modes
+ .map_or(false, |modes| modes.contains_enum(mode))
+ {
+ return Err(RenderPassError::DepthAttachmentResolveModeNotSupported);
+ }
+
+ let resolve_image = resolve_image_view.image();
+
+ // VUID-VkRenderingAttachmentInfo-imageView-06132
+ if image.samples() == SampleCount::Sample1 {
+ return Err(RenderPassError::DepthAttachmentWithResolveNotMultisampled);
+ }
+
+ // VUID-VkRenderingAttachmentInfo-imageView-06133
+ if resolve_image.samples() != SampleCount::Sample1 {
+ return Err(RenderPassError::DepthAttachmentResolveMultisampled);
+ }
+
+ // VUID-VkRenderingAttachmentInfo-imageView-06134
+ if image_view.format() != resolve_image_view.format() {
+ return Err(RenderPassError::DepthAttachmentResolveFormatMismatch);
+ }
+
+ // VUID-VkRenderingAttachmentInfo-imageView-06136
+ // VUID-VkRenderingAttachmentInfo-imageView-06146
+ // VUID-VkRenderingInfo-pDepthAttachment-06093
+ // VUID-VkRenderingInfo-pDepthAttachment-06098
+ if matches!(
+ resolve_image_layout,
+ ImageLayout::Undefined
+ | ImageLayout::DepthStencilReadOnlyOptimal
+ | ImageLayout::ShaderReadOnlyOptimal
+ | ImageLayout::TransferSrcOptimal
+ | ImageLayout::TransferDstOptimal
+ | ImageLayout::Preinitialized
+ | ImageLayout::PresentSrc
+ | ImageLayout::ColorAttachmentOptimal
+ | ImageLayout::DepthReadOnlyStencilAttachmentOptimal
+ ) {
+ return Err(RenderPassError::DepthAttachmentResolveLayoutInvalid);
+ }
+ }
+ }
+
+ if let Some(attachment_info) = stencil_attachment {
+ let RenderingAttachmentInfo {
+ image_view,
+ image_layout,
+ resolve_info,
+ load_op,
+ store_op,
+ clear_value: _,
+ _ne: _,
+ } = attachment_info;
+
+ // VUID-VkRenderingAttachmentInfo-imageLayout-parameter
+ image_layout.validate_device(device)?;
+
+ // VUID-VkRenderingAttachmentInfo-loadOp-parameter
+ load_op.validate_device(device)?;
+
+ // VUID-VkRenderingAttachmentInfo-storeOp-parameter
+ store_op.validate_device(device)?;
+
+ let image_aspects = image_view.format().unwrap().aspects();
+
+ // VUID-VkRenderingInfo-pStencilAttachment-06548
+ if !image_aspects.intersects(ImageAspects::STENCIL) {
+ return Err(RenderPassError::StencilAttachmentFormatUsageNotSupported);
+ }
+
+ // VUID-VkRenderingInfo-pStencilAttachment-06089
+ if !image_view
+ .usage()
+ .intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT)
+ {
+ return Err(RenderPassError::StencilAttachmentMissingUsage);
+ }
+
+ let image = image_view.image();
+ let image_extent = image.dimensions().width_height_depth();
+
+ for i in 0..2 {
+ // VUID-VkRenderingInfo-pNext-06079
+ // VUID-VkRenderingInfo-pNext-06080
+ if render_area_offset[i] + render_area_extent[i] > image_extent[i] {
+ return Err(RenderPassError::RenderAreaOutOfBounds);
+ }
+ }
+
+ // VUID-VkRenderingInfo-imageView-06070
+ match samples {
+ Some(samples) if samples == image.samples() => (),
+ Some(_) => {
+ return Err(RenderPassError::StencilAttachmentSamplesMismatch);
+ }
+ None => (),
+ }
+
+ // VUID-VkRenderingAttachmentInfo-imageView-06135
+ // VUID-VkRenderingAttachmentInfo-imageView-06145
+ // VUID-VkRenderingInfo-pStencilAttachment-06094
+ if matches!(
+ image_layout,
+ ImageLayout::Undefined
+ | ImageLayout::ShaderReadOnlyOptimal
+ | ImageLayout::TransferSrcOptimal
+ | ImageLayout::TransferDstOptimal
+ | ImageLayout::Preinitialized
+ | ImageLayout::PresentSrc
+ | ImageLayout::ColorAttachmentOptimal
+ ) {
+ return Err(RenderPassError::StencilAttachmentLayoutInvalid);
+ }
+
+ if let Some(resolve_info) = resolve_info {
+ let &RenderingAttachmentResolveInfo {
+ mode,
+ image_view: ref resolve_image_view,
+ image_layout: resolve_image_layout,
+ } = resolve_info;
+
+ // VUID-VkRenderingAttachmentInfo-resolveImageLayout-parameter
+ resolve_image_layout.validate_device(device)?;
+
+ // VUID-VkRenderingAttachmentInfo-resolveMode-parameter
+ mode.validate_device(device)?;
+
+ // VUID-VkRenderingInfo-pStencilAttachment-06103
+ if !properties
+ .supported_stencil_resolve_modes
+ .map_or(false, |modes| modes.contains_enum(mode))
+ {
+ return Err(RenderPassError::StencilAttachmentResolveModeNotSupported);
+ }
+
+ let resolve_image = resolve_image_view.image();
+
+ // VUID-VkRenderingAttachmentInfo-imageView-06132
+ if image.samples() == SampleCount::Sample1 {
+ return Err(RenderPassError::StencilAttachmentWithResolveNotMultisampled);
+ }
+
+ // VUID-VkRenderingAttachmentInfo-imageView-06133
+ if resolve_image.samples() != SampleCount::Sample1 {
+ return Err(RenderPassError::StencilAttachmentResolveMultisampled);
+ }
+
+ // VUID-VkRenderingAttachmentInfo-imageView-06134
+ if image_view.format() != resolve_image_view.format() {
+ return Err(RenderPassError::StencilAttachmentResolveFormatMismatch);
+ }
+
+ // VUID-VkRenderingAttachmentInfo-imageView-06136
+ // VUID-VkRenderingAttachmentInfo-imageView-06146
+ // VUID-VkRenderingInfo-pStencilAttachment-06095
+ // VUID-VkRenderingInfo-pStencilAttachment-06099
+ if matches!(
+ resolve_image_layout,
+ ImageLayout::Undefined
+ | ImageLayout::DepthStencilReadOnlyOptimal
+ | ImageLayout::ShaderReadOnlyOptimal
+ | ImageLayout::TransferSrcOptimal
+ | ImageLayout::TransferDstOptimal
+ | ImageLayout::Preinitialized
+ | ImageLayout::PresentSrc
+ | ImageLayout::ColorAttachmentOptimal
+ | ImageLayout::DepthAttachmentStencilReadOnlyOptimal
+ ) {
+ return Err(RenderPassError::StencilAttachmentResolveLayoutInvalid);
+ }
+ }
+ }
+
+ if let (Some(depth_attachment_info), Some(stencil_attachment_info)) =
+ (depth_attachment, stencil_attachment)
+ {
+ // VUID-VkRenderingInfo-pDepthAttachment-06085
+ if &depth_attachment_info.image_view != &stencil_attachment_info.image_view {
+ return Err(RenderPassError::DepthStencilAttachmentImageViewMismatch);
+ }
+
+ match (
+ &depth_attachment_info.resolve_info,
+ &stencil_attachment_info.resolve_info,
+ ) {
+ (None, None) => (),
+ (None, Some(_)) | (Some(_), None) => {
+ // VUID-VkRenderingInfo-pDepthAttachment-06104
+ if !properties.independent_resolve_none.unwrap_or(false) {
+ return Err(
+ RenderPassError::DepthStencilAttachmentResolveModesNotSupported,
+ );
+ }
+ }
+ (Some(depth_resolve_info), Some(stencil_resolve_info)) => {
+ // VUID-VkRenderingInfo-pDepthAttachment-06105
+ if !properties.independent_resolve.unwrap_or(false)
+ && depth_resolve_info.mode != stencil_resolve_info.mode
+ {
+ return Err(
+ RenderPassError::DepthStencilAttachmentResolveModesNotSupported,
+ );
+ }
+
+ // VUID-VkRenderingInfo-pDepthAttachment-06086
+ if &depth_resolve_info.image_view != &stencil_resolve_info.image_view {
+ return Err(
+ RenderPassError::DepthStencilAttachmentResolveImageViewMismatch,
+ );
+ }
+ }
+ }
+ }
+
+ Ok(())
+ }
+
+ /// Ends the render pass previously begun with `begin_rendering`.
+ pub fn end_rendering(&mut self) -> Result<&mut Self, RenderPassError> {
+ self.validate_end_rendering()?;
+
+ unsafe {
+ self.inner.end_rendering();
+ self.render_pass_state = None;
+ }
+
+ Ok(self)
+ }
+
+ fn validate_end_rendering(&self) -> Result<(), RenderPassError> {
+ // VUID-vkCmdEndRendering-renderpass
+ let render_pass_state = self
+ .render_pass_state
+ .as_ref()
+ .ok_or(RenderPassError::ForbiddenOutsideRenderPass)?;
+
+ // VUID?
+ if self.inheritance_info.is_some() {
+ return Err(RenderPassError::ForbiddenWithInheritedRenderPass);
+ }
+
+ // VUID-vkCmdEndRendering-None-06161
+ // VUID-vkCmdEndRendering-commandBuffer-06162
+ match &render_pass_state.render_pass {
+ RenderPassStateType::BeginRenderPass(_) => {
+ return Err(RenderPassError::ForbiddenWithBeginRenderPass)
+ }
+ RenderPassStateType::BeginRendering(_) => (),
+ }
+
+ // VUID-vkCmdEndRendering-commandBuffer-cmdpool
+ debug_assert!(self
+ .queue_family_properties()
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS));
+
+ Ok(())
+ }
+
+ /// Clears specific regions of specific attachments of the framebuffer.
+ ///
+ /// `attachments` specify the types of attachments and their clear values.
+ /// `rects` specify the regions to clear.
+ ///
+ /// A graphics pipeline must have been bound using
+ /// [`bind_pipeline_graphics`](Self::bind_pipeline_graphics). And the command must be inside render pass.
+ ///
+ /// If the render pass instance this is recorded in uses multiview,
+ /// then `ClearRect.base_array_layer` must be zero and `ClearRect.layer_count` must be one.
+ ///
+ /// The rectangle area must be inside the render area ranges.
+ pub fn clear_attachments(
+ &mut self,
+ attachments: impl IntoIterator<Item = ClearAttachment>,
+ rects: impl IntoIterator<Item = ClearRect>,
+ ) -> Result<&mut Self, RenderPassError> {
+ let attachments: SmallVec<[ClearAttachment; 3]> = attachments.into_iter().collect();
+ let rects: SmallVec<[ClearRect; 4]> = rects.into_iter().collect();
+
+ self.validate_clear_attachments(&attachments, &rects)?;
+
+ unsafe {
+ self.inner.clear_attachments(attachments, rects);
+ }
+
+ Ok(self)
+ }
+
+ fn validate_clear_attachments(
+ &self,
+ attachments: &[ClearAttachment],
+ rects: &[ClearRect],
+ ) -> Result<(), RenderPassError> {
+ // VUID-vkCmdClearAttachments-renderpass
+ let render_pass_state = self
+ .render_pass_state
+ .as_ref()
+ .ok_or(RenderPassError::ForbiddenOutsideRenderPass)?;
+
+ if render_pass_state.contents != SubpassContents::Inline {
+ return Err(RenderPassError::ForbiddenWithSubpassContents {
+ contents: render_pass_state.contents,
+ });
+ }
+
+ //let subpass_desc = begin_render_pass_state.subpass.subpass_desc();
+ //let render_pass = begin_render_pass_state.subpass.render_pass();
+ let is_multiview = render_pass_state.view_mask != 0;
+ let mut layer_count = u32::MAX;
+
+ for &clear_attachment in attachments {
+ match clear_attachment {
+ ClearAttachment::Color {
+ color_attachment,
+ clear_value,
+ } => {
+ let attachment_format = match &render_pass_state.render_pass {
+ RenderPassStateType::BeginRenderPass(state) => {
+ let color_attachments = &state.subpass.subpass_desc().color_attachments;
+ let atch_ref = color_attachments.get(color_attachment as usize).ok_or(
+ RenderPassError::ColorAttachmentIndexOutOfRange {
+ color_attachment_index: color_attachment,
+ num_color_attachments: color_attachments.len() as u32,
+ },
+ )?;
+
+ atch_ref.as_ref().map(|atch_ref| {
+ state.subpass.render_pass().attachments()
+ [atch_ref.attachment as usize]
+ .format
+ .unwrap()
+ })
+ }
+ RenderPassStateType::BeginRendering(state) => *state
+ .color_attachment_formats
+ .get(color_attachment as usize)
+ .ok_or(RenderPassError::ColorAttachmentIndexOutOfRange {
+ color_attachment_index: color_attachment,
+ num_color_attachments: state.color_attachment_formats.len() as u32,
+ })?,
+ };
+
+ // VUID-vkCmdClearAttachments-aspectMask-02501
+ if !attachment_format.map_or(false, |format| {
+ matches!(
+ (clear_value, format.type_color().unwrap()),
+ (
+ ClearColorValue::Float(_),
+ NumericType::SFLOAT
+ | NumericType::UFLOAT
+ | NumericType::SNORM
+ | NumericType::UNORM
+ | NumericType::SSCALED
+ | NumericType::USCALED
+ | NumericType::SRGB
+ ) | (ClearColorValue::Int(_), NumericType::SINT)
+ | (ClearColorValue::Uint(_), NumericType::UINT)
+ )
+ }) {
+ return Err(RenderPassError::ClearAttachmentNotCompatible {
+ clear_attachment,
+ attachment_format,
+ });
+ }
+
+ let image_view = match &render_pass_state.render_pass {
+ RenderPassStateType::BeginRenderPass(state) => (state.framebuffer.as_ref())
+ .zip(
+ state.subpass.subpass_desc().color_attachments
+ [color_attachment as usize]
+ .as_ref(),
+ )
+ .map(|(framebuffer, atch_ref)| {
+ &framebuffer.attachments()[atch_ref.attachment as usize]
+ }),
+ RenderPassStateType::BeginRendering(state) => state
+ .attachments
+ .as_ref()
+ .and_then(|attachments| {
+ attachments.color_attachments[color_attachment as usize].as_ref()
+ })
+ .map(|attachment_info| &attachment_info.image_view),
+ };
+
+ // We only know the layer count if we have a known attachment image.
+ if let Some(image_view) = image_view {
+ let array_layers = &image_view.subresource_range().array_layers;
+ layer_count = min(layer_count, array_layers.end - array_layers.start);
+ }
+ }
+ ClearAttachment::Depth(_)
+ | ClearAttachment::Stencil(_)
+ | ClearAttachment::DepthStencil(_) => {
+ let (depth_format, stencil_format) = match &render_pass_state.render_pass {
+ RenderPassStateType::BeginRenderPass(state) => state
+ .subpass
+ .subpass_desc()
+ .depth_stencil_attachment
+ .as_ref()
+ .map_or((None, None), |atch_ref| {
+ let format = state.subpass.render_pass().attachments()
+ [atch_ref.attachment as usize]
+ .format
+ .unwrap();
+ (Some(format), Some(format))
+ }),
+ RenderPassStateType::BeginRendering(state) => (
+ state.depth_attachment_format,
+ state.stencil_attachment_format,
+ ),
+ };
+
+ // VUID-vkCmdClearAttachments-aspectMask-02502
+ if matches!(
+ clear_attachment,
+ ClearAttachment::Depth(_) | ClearAttachment::DepthStencil(_)
+ ) && !depth_format.map_or(false, |format| {
+ format.aspects().intersects(ImageAspects::DEPTH)
+ }) {
+ return Err(RenderPassError::ClearAttachmentNotCompatible {
+ clear_attachment,
+ attachment_format: None,
+ });
+ }
+
+ // VUID-vkCmdClearAttachments-aspectMask-02503
+ if matches!(
+ clear_attachment,
+ ClearAttachment::Stencil(_) | ClearAttachment::DepthStencil(_)
+ ) && !stencil_format.map_or(false, |format| {
+ format.aspects().intersects(ImageAspects::STENCIL)
+ }) {
+ return Err(RenderPassError::ClearAttachmentNotCompatible {
+ clear_attachment,
+ attachment_format: None,
+ });
+ }
+
+ let image_view = match &render_pass_state.render_pass {
+ RenderPassStateType::BeginRenderPass(state) => (state.framebuffer.as_ref())
+ .zip(
+ state
+ .subpass
+ .subpass_desc()
+ .depth_stencil_attachment
+ .as_ref(),
+ )
+ .map(|(framebuffer, atch_ref)| {
+ &framebuffer.attachments()[atch_ref.attachment as usize]
+ }),
+ RenderPassStateType::BeginRendering(state) => state
+ .attachments
+ .as_ref()
+ .and_then(|attachments| attachments.depth_attachment.as_ref())
+ .map(|attachment_info| &attachment_info.image_view),
+ };
+
+ // We only know the layer count if we have a known attachment image.
+ if let Some(image_view) = image_view {
+ let array_layers = &image_view.subresource_range().array_layers;
+ layer_count = min(layer_count, array_layers.end - array_layers.start);
+ }
+ }
+ }
+ }
+
+ for (rect_index, rect) in rects.iter().enumerate() {
+ for i in 0..2 {
+ // VUID-vkCmdClearAttachments-rect-02682
+ // VUID-vkCmdClearAttachments-rect-02683
+ if rect.extent[i] == 0 {
+ return Err(RenderPassError::RectExtentZero { rect_index });
+ }
+
+ // VUID-vkCmdClearAttachments-pRects-00016
+ // TODO: This check will always pass in secondary command buffers because of how
+ // it's set in `with_level`.
+ // It needs to be checked during `execute_commands` instead.
+ if rect.offset[i] < render_pass_state.render_area_offset[i]
+ || rect.offset[i] + rect.extent[i]
+ > render_pass_state.render_area_offset[i]
+ + render_pass_state.render_area_extent[i]
+ {
+ return Err(RenderPassError::RectOutOfBounds { rect_index });
+ }
+ }
+
+ // VUID-vkCmdClearAttachments-layerCount-01934
+ if rect.array_layers.is_empty() {
+ return Err(RenderPassError::RectArrayLayersEmpty { rect_index });
+ }
+
+ // VUID-vkCmdClearAttachments-pRects-00017
+ if rect.array_layers.end > layer_count {
+ return Err(RenderPassError::RectArrayLayersOutOfBounds { rect_index });
+ }
+
+ // VUID-vkCmdClearAttachments-baseArrayLayer-00018
+ if is_multiview && rect.array_layers != (0..1) {
+ return Err(RenderPassError::MultiviewRectArrayLayersInvalid { rect_index });
+ }
+ }
+
+ // VUID-vkCmdClearAttachments-commandBuffer-cmdpool
+ debug_assert!(self
+ .queue_family_properties()
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS));
+
+ Ok(())
+ }
+}
+
+impl SyncCommandBufferBuilder {
+ /// Calls `vkCmdBeginRenderPass` on the builder.
+ // TODO: it shouldn't be possible to get an error if the framebuffer checked conflicts already
+ // TODO: after begin_render_pass has been called, flushing should be forbidden and an error
+ // returned if conflict
+ #[inline]
+ pub unsafe fn begin_render_pass(
+ &mut self,
+ render_pass_begin_info: RenderPassBeginInfo,
+ contents: SubpassContents,
+ ) -> Result<(), SyncCommandBufferBuilderError> {
+ struct Cmd {
+ render_pass_begin_info: RenderPassBeginInfo,
+ contents: SubpassContents,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "begin_render_pass"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.begin_render_pass(&self.render_pass_begin_info, self.contents);
+ }
+ }
+
+ let RenderPassBeginInfo {
+ render_pass,
+ framebuffer,
+ render_area_offset: _,
+ render_area_extent: _,
+ clear_values: _,
+ _ne: _,
+ } = &render_pass_begin_info;
+
+ let command_index = self.commands.len();
+ let command_name = "begin_render_pass";
+ let resources = render_pass
+ .attachments()
+ .iter()
+ .enumerate()
+ .map(|(index, desc)| {
+ let image_view = &framebuffer.attachments()[index];
+ let index = index as u32;
+
+ (
+ ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::FramebufferAttachment { index },
+ secondary_use_ref: None,
+ },
+ Resource::Image {
+ image: image_view.image(),
+ subresource_range: image_view.subresource_range().clone(),
+ memory: PipelineMemoryAccess {
+ stages: PipelineStages::ALL_COMMANDS, // TODO: wrong!
+ access: AccessFlags::INPUT_ATTACHMENT_READ
+ | AccessFlags::COLOR_ATTACHMENT_READ
+ | AccessFlags::COLOR_ATTACHMENT_WRITE
+ | AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ
+ | AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE, // TODO: suboptimal
+ exclusive: true, // TODO: suboptimal ; note: remember to always pass true if desc.initial_layout != desc.final_layout
+ },
+ start_layout: desc.initial_layout,
+ end_layout: desc.final_layout,
+ },
+ )
+ })
+ .collect::<Vec<_>>();
+
+ for resource in &resources {
+ self.check_resource_conflicts(resource)?;
+ }
+
+ self.commands.push(Box::new(Cmd {
+ render_pass_begin_info,
+ contents,
+ }));
+
+ for resource in resources {
+ self.add_resource(resource);
+ }
+
+ self.latest_render_pass_enter = Some(self.commands.len() - 1);
+
+ Ok(())
+ }
+
+ /// Calls `vkCmdNextSubpass` on the builder.
+ #[inline]
+ pub unsafe fn next_subpass(&mut self, contents: SubpassContents) {
+ struct Cmd {
+ contents: SubpassContents,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "next_subpass"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.next_subpass(self.contents);
+ }
+ }
+
+ self.commands.push(Box::new(Cmd { contents }));
+ }
+
+ /// Calls `vkCmdEndRenderPass` on the builder.
+ #[inline]
+ pub unsafe fn end_render_pass(&mut self) {
+ struct Cmd;
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "end_render_pass"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.end_render_pass();
+ }
+ }
+
+ self.commands.push(Box::new(Cmd));
+ debug_assert!(self.latest_render_pass_enter.is_some());
+ self.latest_render_pass_enter = None;
+ }
+
+ /// Calls `vkCmdBeginRendering` on the builder.
+ #[inline]
+ pub unsafe fn begin_rendering(
+ &mut self,
+ rendering_info: RenderingInfo,
+ ) -> Result<(), SyncCommandBufferBuilderError> {
+ struct Cmd {
+ rendering_info: RenderingInfo,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "begin_rendering"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.begin_rendering(&self.rendering_info);
+ }
+ }
+
+ let RenderingInfo {
+ render_area_offset: _,
+ render_area_extent: _,
+ layer_count: _,
+ view_mask: _,
+ color_attachments,
+ depth_attachment,
+ stencil_attachment,
+ contents: _,
+ _ne,
+ } = &rendering_info;
+
+ let command_index = self.commands.len();
+ let command_name = "begin_rendering";
+ let resources = (color_attachments
+ .iter()
+ .enumerate()
+ .filter_map(|(index, attachment_info)| {
+ attachment_info
+ .as_ref()
+ .map(|attachment_info| (index as u32, attachment_info))
+ })
+ .flat_map(|(index, attachment_info)| {
+ let &RenderingAttachmentInfo {
+ ref image_view,
+ image_layout,
+ ref resolve_info,
+ load_op: _,
+ store_op: _,
+ clear_value: _,
+ _ne: _,
+ } = attachment_info;
+
+ [
+ Some((
+ ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::ColorAttachment { index },
+ secondary_use_ref: None,
+ },
+ Resource::Image {
+ image: image_view.image(),
+ subresource_range: image_view.subresource_range().clone(),
+ memory: PipelineMemoryAccess {
+ stages: PipelineStages::ALL_COMMANDS, // TODO: wrong!
+ access: AccessFlags::COLOR_ATTACHMENT_READ
+ | AccessFlags::COLOR_ATTACHMENT_WRITE, // TODO: suboptimal
+ exclusive: true, // TODO: suboptimal
+ },
+ start_layout: image_layout,
+ end_layout: image_layout,
+ },
+ )),
+ resolve_info.as_ref().map(|resolve_info| {
+ let &RenderingAttachmentResolveInfo {
+ mode: _,
+ ref image_view,
+ image_layout,
+ } = resolve_info;
+
+ (
+ ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::ColorResolveAttachment {
+ index,
+ },
+ secondary_use_ref: None,
+ },
+ Resource::Image {
+ image: image_view.image(),
+ subresource_range: image_view.subresource_range().clone(),
+ memory: PipelineMemoryAccess {
+ stages: PipelineStages::ALL_COMMANDS, // TODO: wrong!
+ access: AccessFlags::COLOR_ATTACHMENT_READ
+ | AccessFlags::COLOR_ATTACHMENT_WRITE, // TODO: suboptimal
+ exclusive: true, // TODO: suboptimal
+ },
+ start_layout: image_layout,
+ end_layout: image_layout,
+ },
+ )
+ }),
+ ]
+ .into_iter()
+ .flatten()
+ }))
+ .chain(depth_attachment.iter().flat_map(|attachment_info| {
+ let &RenderingAttachmentInfo {
+ ref image_view,
+ image_layout,
+ ref resolve_info,
+ load_op: _,
+ store_op: _,
+ clear_value: _,
+ _ne: _,
+ } = attachment_info;
+
+ [
+ Some((
+ ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::DepthStencilAttachment,
+ secondary_use_ref: None,
+ },
+ Resource::Image {
+ image: image_view.image(),
+ subresource_range: image_view.subresource_range().clone(),
+ memory: PipelineMemoryAccess {
+ stages: PipelineStages::ALL_COMMANDS, // TODO: wrong!
+ access: AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ
+ | AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE, // TODO: suboptimal
+ exclusive: true, // TODO: suboptimal
+ },
+ start_layout: image_layout,
+ end_layout: image_layout,
+ },
+ )),
+ resolve_info.as_ref().map(|resolve_info| {
+ let &RenderingAttachmentResolveInfo {
+ mode: _,
+ ref image_view,
+ image_layout,
+ } = resolve_info;
+
+ (
+ ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::DepthStencilResolveAttachment,
+ secondary_use_ref: None,
+ },
+ Resource::Image {
+ image: image_view.image(),
+ subresource_range: image_view.subresource_range().clone(),
+ memory: PipelineMemoryAccess {
+ stages: PipelineStages::ALL_COMMANDS, // TODO: wrong!
+ access: AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ
+ | AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE, // TODO: suboptimal
+ exclusive: true, // TODO: suboptimal
+ },
+ start_layout: image_layout,
+ end_layout: image_layout,
+ },
+ )
+ }),
+ ]
+ .into_iter()
+ .flatten()
+ }))
+ .chain(stencil_attachment.iter().flat_map(|attachment_info| {
+ let &RenderingAttachmentInfo {
+ ref image_view,
+ image_layout,
+ ref resolve_info,
+ load_op: _,
+ store_op: _,
+ clear_value: _,
+ _ne: _,
+ } = attachment_info;
+
+ [
+ Some((
+ ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::DepthStencilAttachment,
+ secondary_use_ref: None,
+ },
+ Resource::Image {
+ image: image_view.image(),
+ subresource_range: image_view.subresource_range().clone(),
+ memory: PipelineMemoryAccess {
+ stages: PipelineStages::ALL_COMMANDS, // TODO: wrong!
+ access: AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ
+ | AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE, // TODO: suboptimal
+ exclusive: true, // TODO: suboptimal
+ },
+ start_layout: image_layout,
+ end_layout: image_layout,
+ },
+ )),
+ resolve_info.as_ref().map(|resolve_info| {
+ let &RenderingAttachmentResolveInfo {
+ mode: _,
+ ref image_view,
+ image_layout,
+ } = resolve_info;
+
+ (
+ ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::DepthStencilResolveAttachment,
+ secondary_use_ref: None,
+ },
+ Resource::Image {
+ image: image_view.image(),
+ subresource_range: image_view.subresource_range().clone(),
+ memory: PipelineMemoryAccess {
+ stages: PipelineStages::ALL_COMMANDS, // TODO: wrong!
+ access: AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ
+ | AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE, // TODO: suboptimal
+ exclusive: true, // TODO: suboptimal
+ },
+ start_layout: image_layout,
+ end_layout: image_layout,
+ },
+ )
+ }),
+ ]
+ .into_iter()
+ .flatten()
+ }))
+ .collect::<Vec<_>>();
+
+ for resource in &resources {
+ self.check_resource_conflicts(resource)?;
+ }
+
+ self.commands.push(Box::new(Cmd { rendering_info }));
+
+ for resource in resources {
+ self.add_resource(resource);
+ }
+
+ self.latest_render_pass_enter = Some(self.commands.len() - 1);
+
+ Ok(())
+ }
+
+ /// Calls `vkCmdEndRendering` on the builder.
+ #[inline]
+ pub unsafe fn end_rendering(&mut self) {
+ struct Cmd;
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "end_rendering"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.end_rendering();
+ }
+ }
+
+ self.commands.push(Box::new(Cmd));
+ debug_assert!(self.latest_render_pass_enter.is_some());
+ self.latest_render_pass_enter = None;
+ }
+
+ /// Calls `vkCmdClearAttachments` on the builder.
+ ///
+ /// Does nothing if the list of attachments or the list of rects is empty, as it would be a
+ /// no-op and isn't a valid usage of the command anyway.
+ pub unsafe fn clear_attachments(
+ &mut self,
+ attachments: impl IntoIterator<Item = ClearAttachment>,
+ rects: impl IntoIterator<Item = ClearRect>,
+ ) {
+ struct Cmd {
+ attachments: SmallVec<[ClearAttachment; 3]>,
+ rects: SmallVec<[ClearRect; 4]>,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "clear_attachments"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.clear_attachments(self.attachments.iter().copied(), self.rects.iter().cloned());
+ }
+ }
+ let attachments: SmallVec<[_; 3]> = attachments.into_iter().collect();
+ let rects: SmallVec<[_; 4]> = rects.into_iter().collect();
+
+ self.commands.push(Box::new(Cmd { attachments, rects }));
+ }
+}
+
+impl UnsafeCommandBufferBuilder {
+ /// Calls `vkCmdBeginRenderPass` on the builder.
+ #[inline]
+ pub unsafe fn begin_render_pass(
+ &mut self,
+ render_pass_begin_info: &RenderPassBeginInfo,
+ contents: SubpassContents,
+ ) {
+ let &RenderPassBeginInfo {
+ ref render_pass,
+ ref framebuffer,
+ render_area_offset,
+ render_area_extent,
+ ref clear_values,
+ _ne: _,
+ } = render_pass_begin_info;
+
+ let clear_values_vk: SmallVec<[_; 4]> = clear_values
+ .iter()
+ .copied()
+ .map(|clear_value| clear_value.map(Into::into).unwrap_or_default())
+ .collect();
+
+ let render_pass_begin_info = ash::vk::RenderPassBeginInfo {
+ render_pass: render_pass.handle(),
+ framebuffer: framebuffer.handle(),
+ render_area: ash::vk::Rect2D {
+ offset: ash::vk::Offset2D {
+ x: render_area_offset[0] as i32,
+ y: render_area_offset[1] as i32,
+ },
+ extent: ash::vk::Extent2D {
+ width: render_area_extent[0],
+ height: render_area_extent[1],
+ },
+ },
+ clear_value_count: clear_values_vk.len() as u32,
+ p_clear_values: clear_values_vk.as_ptr(),
+ ..Default::default()
+ };
+
+ let subpass_begin_info = ash::vk::SubpassBeginInfo {
+ contents: contents.into(),
+ ..Default::default()
+ };
+
+ let fns = self.device.fns();
+
+ if self.device.api_version() >= Version::V1_2
+ || self.device.enabled_extensions().khr_create_renderpass2
+ {
+ if self.device.api_version() >= Version::V1_2 {
+ (fns.v1_2.cmd_begin_render_pass2)(
+ self.handle,
+ &render_pass_begin_info,
+ &subpass_begin_info,
+ );
+ } else {
+ (fns.khr_create_renderpass2.cmd_begin_render_pass2_khr)(
+ self.handle,
+ &render_pass_begin_info,
+ &subpass_begin_info,
+ );
+ }
+ } else {
+ debug_assert!(subpass_begin_info.p_next.is_null());
+
+ (fns.v1_0.cmd_begin_render_pass)(
+ self.handle,
+ &render_pass_begin_info,
+ subpass_begin_info.contents,
+ );
+ }
+ }
+
+ /// Calls `vkCmdNextSubpass` on the builder.
+ #[inline]
+ pub unsafe fn next_subpass(&mut self, contents: SubpassContents) {
+ let fns = self.device.fns();
+
+ let subpass_begin_info = ash::vk::SubpassBeginInfo {
+ contents: contents.into(),
+ ..Default::default()
+ };
+
+ let subpass_end_info = ash::vk::SubpassEndInfo::default();
+
+ if self.device.api_version() >= Version::V1_2
+ || self.device.enabled_extensions().khr_create_renderpass2
+ {
+ if self.device.api_version() >= Version::V1_2 {
+ (fns.v1_2.cmd_next_subpass2)(self.handle, &subpass_begin_info, &subpass_end_info);
+ } else {
+ (fns.khr_create_renderpass2.cmd_next_subpass2_khr)(
+ self.handle,
+ &subpass_begin_info,
+ &subpass_end_info,
+ );
+ }
+ } else {
+ debug_assert!(subpass_begin_info.p_next.is_null());
+ debug_assert!(subpass_end_info.p_next.is_null());
+
+ (fns.v1_0.cmd_next_subpass)(self.handle, subpass_begin_info.contents);
+ }
+ }
+
+ /// Calls `vkCmdEndRenderPass` on the builder.
+ #[inline]
+ pub unsafe fn end_render_pass(&mut self) {
+ let fns = self.device.fns();
+
+ let subpass_end_info = ash::vk::SubpassEndInfo::default();
+
+ if self.device.api_version() >= Version::V1_2
+ || self.device.enabled_extensions().khr_create_renderpass2
+ {
+ if self.device.api_version() >= Version::V1_2 {
+ (fns.v1_2.cmd_end_render_pass2)(self.handle, &subpass_end_info);
+ } else {
+ (fns.khr_create_renderpass2.cmd_end_render_pass2_khr)(
+ self.handle,
+ &subpass_end_info,
+ );
+ }
+ } else {
+ debug_assert!(subpass_end_info.p_next.is_null());
+
+ (fns.v1_0.cmd_end_render_pass)(self.handle);
+ }
+ }
+
+ /// Calls `vkCmdBeginRendering` on the builder.
+ #[inline]
+ pub unsafe fn begin_rendering(&mut self, rendering_info: &RenderingInfo) {
+ let &RenderingInfo {
+ render_area_offset,
+ render_area_extent,
+ layer_count,
+ view_mask,
+ ref color_attachments,
+ ref depth_attachment,
+ ref stencil_attachment,
+ contents,
+ _ne: _,
+ } = rendering_info;
+
+ let map_attachment_info = |attachment_info: &Option<_>| {
+ if let Some(attachment_info) = attachment_info {
+ let &RenderingAttachmentInfo {
+ ref image_view,
+ image_layout,
+ resolve_info: ref resolve,
+ load_op,
+ store_op,
+ clear_value,
+ _ne: _,
+ } = attachment_info;
+
+ let (resolve_mode, resolve_image_view, resolve_image_layout) =
+ if let Some(resolve) = resolve {
+ let &RenderingAttachmentResolveInfo {
+ mode,
+ ref image_view,
+ image_layout,
+ } = resolve;
+
+ (mode.into(), image_view.handle(), image_layout.into())
+ } else {
+ (
+ ash::vk::ResolveModeFlags::NONE,
+ Default::default(),
+ Default::default(),
+ )
+ };
+
+ ash::vk::RenderingAttachmentInfo {
+ image_view: image_view.handle(),
+ image_layout: image_layout.into(),
+ resolve_mode,
+ resolve_image_view,
+ resolve_image_layout,
+ load_op: load_op.into(),
+ store_op: store_op.into(),
+ clear_value: clear_value.map_or_else(Default::default, Into::into),
+ ..Default::default()
+ }
+ } else {
+ ash::vk::RenderingAttachmentInfo {
+ image_view: ash::vk::ImageView::null(),
+ ..Default::default()
+ }
+ }
+ };
+
+ let color_attachments: SmallVec<[_; 2]> =
+ color_attachments.iter().map(map_attachment_info).collect();
+ let depth_attachment = map_attachment_info(depth_attachment);
+ let stencil_attachment = map_attachment_info(stencil_attachment);
+
+ let rendering_info = ash::vk::RenderingInfo {
+ flags: contents.into(),
+ render_area: ash::vk::Rect2D {
+ offset: ash::vk::Offset2D {
+ x: render_area_offset[0] as i32,
+ y: render_area_offset[1] as i32,
+ },
+ extent: ash::vk::Extent2D {
+ width: render_area_extent[0],
+ height: render_area_extent[1],
+ },
+ },
+ layer_count,
+ view_mask,
+ color_attachment_count: color_attachments.len() as u32,
+ p_color_attachments: color_attachments.as_ptr(),
+ p_depth_attachment: &depth_attachment,
+ p_stencil_attachment: &stencil_attachment,
+ ..Default::default()
+ };
+
+ let fns = self.device.fns();
+
+ if self.device.api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_begin_rendering)(self.handle, &rendering_info);
+ } else {
+ debug_assert!(self.device.enabled_extensions().khr_dynamic_rendering);
+ (fns.khr_dynamic_rendering.cmd_begin_rendering_khr)(self.handle, &rendering_info);
+ }
+ }
+
+ /// Calls `vkCmdEndRendering` on the builder.
+ #[inline]
+ pub unsafe fn end_rendering(&mut self) {
+ let fns = self.device.fns();
+
+ if self.device.api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_end_rendering)(self.handle);
+ } else {
+ debug_assert!(self.device.enabled_extensions().khr_dynamic_rendering);
+ (fns.khr_dynamic_rendering.cmd_end_rendering_khr)(self.handle);
+ }
+ }
+
+ /// Calls `vkCmdClearAttachments` on the builder.
+ ///
+ /// Does nothing if the list of attachments or the list of rects is empty, as it would be a
+ /// no-op and isn't a valid usage of the command anyway.
+ pub unsafe fn clear_attachments(
+ &mut self,
+ attachments: impl IntoIterator<Item = ClearAttachment>,
+ rects: impl IntoIterator<Item = ClearRect>,
+ ) {
+ let attachments: SmallVec<[_; 3]> = attachments.into_iter().map(|v| v.into()).collect();
+ let rects: SmallVec<[_; 4]> = rects
+ .into_iter()
+ .map(|rect| ash::vk::ClearRect {
+ rect: ash::vk::Rect2D {
+ offset: ash::vk::Offset2D {
+ x: rect.offset[0] as i32,
+ y: rect.offset[1] as i32,
+ },
+ extent: ash::vk::Extent2D {
+ width: rect.extent[0],
+ height: rect.extent[1],
+ },
+ },
+ base_array_layer: rect.array_layers.start,
+ layer_count: rect.array_layers.end - rect.array_layers.start,
+ })
+ .collect();
+
+ if attachments.is_empty() || rects.is_empty() {
+ return;
+ }
+
+ let fns = self.device.fns();
+ (fns.v1_0.cmd_clear_attachments)(
+ self.handle,
+ attachments.len() as u32,
+ attachments.as_ptr(),
+ rects.len() as u32,
+ rects.as_ptr(),
+ );
+ }
+}
+
+/// Parameters to begin a new render pass.
+#[derive(Clone, Debug)]
+pub struct RenderPassBeginInfo {
+ /// The render pass to begin.
+ ///
+ /// If this is not the render pass that `framebuffer` was created with, it must be compatible
+ /// with that render pass.
+ ///
+ /// The default value is the render pass of `framebuffer`.
+ pub render_pass: Arc<RenderPass>,
+
+ /// The framebuffer to use for rendering.
+ ///
+ /// There is no default value.
+ pub framebuffer: Arc<Framebuffer>,
+
+ /// The offset from the top left corner of the framebuffer that will be rendered to.
+ ///
+ /// The default value is `[0, 0]`.
+ pub render_area_offset: [u32; 2],
+
+ /// The size of the area that will be rendered to.
+ ///
+ /// `render_area_offset + render_area_extent` must not be greater than [`framebuffer.extent()`].
+ ///
+ /// The default value is [`framebuffer.extent()`].
+ pub render_area_extent: [u32; 2],
+
+ /// Provides, for each attachment in `render_pass` that has a load operation of
+ /// [`LoadOp::Clear`], the clear values that should be used for the attachments in the
+ /// framebuffer. There must be exactly [`framebuffer.attachments().len()`] elements provided,
+ /// and each one must match the attachment format.
+ ///
+ /// To skip over an attachment whose load operation is something else, provide `None`.
+ ///
+ /// The default value is empty, which must be overridden if the framebuffer has attachments.
+ pub clear_values: Vec<Option<ClearValue>>,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl RenderPassBeginInfo {
+ #[inline]
+ pub fn framebuffer(framebuffer: Arc<Framebuffer>) -> Self {
+ let render_area_extent = framebuffer.extent();
+
+ Self {
+ render_pass: framebuffer.render_pass().clone(),
+ framebuffer,
+ render_area_offset: [0, 0],
+ render_area_extent,
+ clear_values: Vec::new(),
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// Parameters to begin rendering.
+#[derive(Clone, Debug)]
+pub struct RenderingInfo {
+ /// The offset from the top left corner of the attachments that will be rendered to.
+ ///
+ /// This value must be smaller than the smallest width and height of the attachment images.
+ ///
+ /// The default value is `[0, 0]`.
+ pub render_area_offset: [u32; 2],
+
+ /// The size of the area that will be rendered to.
+ ///
+ /// This value plus `render_area_offset` must be no larger than the smallest width and height
+ /// of the attachment images.
+ /// If one of the elements is set to 0, the extent will be calculated automatically from the
+ /// extents of the attachment images to be the largest allowed. At least one attachment image
+ /// must be specified in that case.
+ ///
+ /// The default value is `[0, 0]`.
+ pub render_area_extent: [u32; 2],
+
+ /// The number of layers of the attachments that will be rendered to.
+ ///
+ /// This must be no larger than the smallest number of array layers of the attachment images.
+ /// If set to 0, the number of layers will be calculated automatically from the
+ /// layer ranges of the attachment images to be the largest allowed. At least one attachment
+ /// image must be specified in that case.
+ ///
+ /// If the render pass uses multiview (`view_mask` is not 0), then this value must be 0 or 1.
+ ///
+ /// The default value is `0`.
+ pub layer_count: u32,
+
+ /// If not `0`, enables multiview rendering, and specifies the view indices that are rendered
+ /// to. The value is a bitmask, so that that for example `0b11` will draw to the first two
+ /// views and `0b101` will draw to the first and third view.
+ ///
+ /// If set to a nonzero value, the [`multiview`](crate::device::Features::multiview) feature
+ /// must be enabled on the device.
+ ///
+ /// The default value is `0`.
+ pub view_mask: u32,
+
+ /// The color attachments to use for rendering.
+ ///
+ /// The number of color attachments must be less than the
+ /// [`max_color_attachments`](crate::device::Properties::max_color_attachments) limit of the
+ /// physical device. All color attachments must have the same `samples` value.
+ ///
+ /// The default value is empty.
+ pub color_attachments: Vec<Option<RenderingAttachmentInfo>>,
+
+ /// The depth attachment to use for rendering.
+ ///
+ /// If set to `Some`, the image view must have the same `samples` value as those in
+ /// `color_attachments`.
+ ///
+ /// The default value is `None`.
+ pub depth_attachment: Option<RenderingAttachmentInfo>,
+
+ /// The stencil attachment to use for rendering.
+ ///
+ /// If set to `Some`, the image view must have the same `samples` value as those in
+ /// `color_attachments`.
+ ///
+ /// The default value is `None`.
+ pub stencil_attachment: Option<RenderingAttachmentInfo>,
+
+ /// What kinds of commands will be recorded in the render pass: either inline draw commands, or
+ /// executions of secondary command buffers.
+ ///
+ /// If recorded in a secondary command buffer, this must be [`SubpassContents::Inline`].
+ ///
+ /// The default value is [`SubpassContents::Inline`].
+ pub contents: SubpassContents,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for RenderingInfo {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ render_area_offset: [0, 0],
+ render_area_extent: [0, 0],
+ layer_count: 0,
+ view_mask: 0,
+ color_attachments: Vec::new(),
+ depth_attachment: None,
+ stencil_attachment: None,
+ contents: SubpassContents::Inline,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+impl RenderingInfo {
+ pub(crate) fn set_extent_layers(&mut self) -> Result<(), RenderPassError> {
+ let &mut RenderingInfo {
+ render_area_offset,
+ ref mut render_area_extent,
+ ref mut layer_count,
+ view_mask,
+ ref color_attachments,
+ ref depth_attachment,
+ ref stencil_attachment,
+ contents: _,
+ _ne: _,
+ } = self;
+
+ let auto_extent = render_area_extent[0] == 0 || render_area_extent[1] == 0;
+ let auto_layers = *layer_count == 0;
+
+ // Set the values based on the attachment sizes.
+ if auto_extent || auto_layers {
+ if auto_extent {
+ *render_area_extent = [u32::MAX, u32::MAX];
+ }
+
+ if auto_layers {
+ if view_mask != 0 {
+ *layer_count = 1;
+ } else {
+ *layer_count = u32::MAX;
+ }
+ }
+
+ for image_view in (color_attachments.iter().flatten())
+ .chain(depth_attachment.iter())
+ .chain(stencil_attachment.iter())
+ .flat_map(|attachment_info| {
+ Some(&attachment_info.image_view).into_iter().chain(
+ attachment_info
+ .resolve_info
+ .as_ref()
+ .map(|resolve_info| &resolve_info.image_view),
+ )
+ })
+ {
+ if auto_extent {
+ let extent = image_view.dimensions().width_height();
+
+ for i in 0..2 {
+ render_area_extent[i] = min(render_area_extent[i], extent[i]);
+ }
+ }
+
+ if auto_layers {
+ let subresource_range = image_view.subresource_range();
+ let array_layers =
+ subresource_range.array_layers.end - subresource_range.array_layers.start;
+
+ *layer_count = min(*layer_count, array_layers);
+ }
+ }
+
+ if auto_extent {
+ if *render_area_extent == [u32::MAX, u32::MAX] {
+ return Err(RenderPassError::AutoExtentAttachmentsEmpty);
+ }
+
+ // Subtract the offset from the calculated max extent.
+ // If there is an underflow, then the offset is too large, and validation should
+ // catch that later.
+ for i in 0..2 {
+ render_area_extent[i] = render_area_extent[i]
+ .checked_sub(render_area_offset[i])
+ .unwrap_or(1);
+ }
+ }
+
+ if auto_layers {
+ if *layer_count == u32::MAX {
+ return Err(RenderPassError::AutoLayersAttachmentsEmpty);
+ }
+ }
+ }
+
+ Ok(())
+ }
+}
+
+/// Parameters to specify properties of an attachment.
+#[derive(Clone, Debug)]
+pub struct RenderingAttachmentInfo {
+ /// The image view to use as the attachment.
+ ///
+ /// There is no default value.
+ pub image_view: Arc<dyn ImageViewAbstract>,
+
+ /// The image layout that `image_view` should be in during the resolve operation.
+ ///
+ /// The default value is [`ImageLayout::ColorAttachmentOptimal`] if `image_view` has a color
+ /// format, [`ImageLayout::DepthStencilAttachmentOptimal`] if `image_view` has a depth/stencil
+ /// format.
+ pub image_layout: ImageLayout,
+
+ /// The resolve operation that should be performed at the end of rendering.
+ ///
+ /// The default value is `None`.
+ pub resolve_info: Option<RenderingAttachmentResolveInfo>,
+
+ /// What the implementation should do with the attachment at the start of rendering.
+ ///
+ /// The default value is [`LoadOp::DontCare`].
+ pub load_op: LoadOp,
+
+ /// What the implementation should do with the attachment at the end of rendering.
+ ///
+ /// The default value is [`StoreOp::DontCare`].
+ pub store_op: StoreOp,
+
+ /// If `load_op` is [`LoadOp::Clear`], specifies the clear value that should be used for the
+ /// attachment.
+ ///
+ /// If `load_op` is something else, provide `None`.
+ ///
+ /// The default value is `None`.
+ pub clear_value: Option<ClearValue>,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl RenderingAttachmentInfo {
+ /// Returns a `RenderingAttachmentInfo` with the specified `image_view`.
+ #[inline]
+ pub fn image_view(image_view: Arc<dyn ImageViewAbstract>) -> Self {
+ let aspects = image_view.format().unwrap().aspects();
+ let image_layout = if aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL) {
+ ImageLayout::DepthStencilAttachmentOptimal
+ } else {
+ ImageLayout::ColorAttachmentOptimal
+ };
+
+ Self {
+ image_view,
+ image_layout,
+ resolve_info: None,
+ load_op: LoadOp::DontCare,
+ store_op: StoreOp::DontCare,
+ clear_value: None,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// Parameters to specify the resolve behavior of an attachment.
+#[derive(Clone, Debug)]
+pub struct RenderingAttachmentResolveInfo {
+ /// How the resolve operation should be performed.
+ ///
+ /// The default value is [`ResolveMode::Average`].
+ pub mode: ResolveMode,
+
+ /// The image view that the result of the resolve operation should be written to.
+ ///
+ /// There is no default value.
+ pub image_view: Arc<dyn ImageViewAbstract>,
+
+ /// The image layout that `image_view` should be in during the resolve operation.
+ ///
+ /// The default value is [`ImageLayout::ColorAttachmentOptimal`] if `image_view` has a color
+ /// format, [`ImageLayout::DepthStencilAttachmentOptimal`] if `image_view` has a depth/stencil
+ /// format.
+ pub image_layout: ImageLayout,
+}
+
+impl RenderingAttachmentResolveInfo {
+ /// Returns a `RenderingAttachmentResolveInfo` with the specified `image_view`.
+ #[inline]
+ pub fn image_view(image_view: Arc<dyn ImageViewAbstract>) -> Self {
+ let aspects = image_view.format().unwrap().aspects();
+ let image_layout = if aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL) {
+ ImageLayout::DepthStencilAttachmentOptimal
+ } else {
+ ImageLayout::ColorAttachmentOptimal
+ };
+
+ Self {
+ mode: ResolveMode::Average,
+ image_view,
+ image_layout,
+ }
+ }
+}
+
+/// Clear attachment type, used in [`clear_attachments`] command.
+///
+/// [`clear_attachments`]: crate::command_buffer::AutoCommandBufferBuilder::clear_attachments
+#[derive(Clone, Copy, Debug)]
+pub enum ClearAttachment {
+ /// Clear the color attachment at the specified index, with the specified clear value.
+ Color {
+ color_attachment: u32,
+ clear_value: ClearColorValue,
+ },
+
+ /// Clear the depth attachment with the specified depth value.
+ Depth(f32),
+
+ /// Clear the stencil attachment with the specified stencil value.
+ Stencil(u32),
+
+ /// Clear the depth and stencil attachments with the specified depth and stencil values.
+ DepthStencil((f32, u32)),
+}
+
+impl From<ClearAttachment> for ash::vk::ClearAttachment {
+ #[inline]
+ fn from(v: ClearAttachment) -> Self {
+ match v {
+ ClearAttachment::Color {
+ color_attachment,
+ clear_value,
+ } => ash::vk::ClearAttachment {
+ aspect_mask: ash::vk::ImageAspectFlags::COLOR,
+ color_attachment,
+ clear_value: ash::vk::ClearValue {
+ color: clear_value.into(),
+ },
+ },
+ ClearAttachment::Depth(depth) => ash::vk::ClearAttachment {
+ aspect_mask: ash::vk::ImageAspectFlags::DEPTH,
+ color_attachment: 0,
+ clear_value: ash::vk::ClearValue {
+ depth_stencil: ash::vk::ClearDepthStencilValue { depth, stencil: 0 },
+ },
+ },
+ ClearAttachment::Stencil(stencil) => ash::vk::ClearAttachment {
+ aspect_mask: ash::vk::ImageAspectFlags::STENCIL,
+ color_attachment: 0,
+ clear_value: ash::vk::ClearValue {
+ depth_stencil: ash::vk::ClearDepthStencilValue {
+ depth: 0.0,
+ stencil,
+ },
+ },
+ },
+ ClearAttachment::DepthStencil((depth, stencil)) => ash::vk::ClearAttachment {
+ aspect_mask: ash::vk::ImageAspectFlags::DEPTH | ash::vk::ImageAspectFlags::STENCIL,
+ color_attachment: 0,
+ clear_value: ash::vk::ClearValue {
+ depth_stencil: ash::vk::ClearDepthStencilValue { depth, stencil },
+ },
+ },
+ }
+ }
+}
+
+/// Specifies the clear region for the [`clear_attachments`] command.
+///
+/// [`clear_attachments`]: crate::command_buffer::AutoCommandBufferBuilder::clear_attachments
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct ClearRect {
+ /// The rectangle offset.
+ pub offset: [u32; 2],
+
+ /// The width and height of the rectangle.
+ pub extent: [u32; 2],
+
+ /// The range of array layers to be cleared.
+ pub array_layers: Range<u32>,
+}
+
+/// Error that can happen when recording a render pass command.
+#[derive(Clone, Debug)]
+pub enum RenderPassError {
+ SyncCommandBufferBuilderError(SyncCommandBufferBuilderError),
+
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+
+ /// A framebuffer image did not have the required usage enabled.
+ AttachmentImageMissingUsage {
+ attachment_index: u32,
+ usage: &'static str,
+ },
+
+ /// One of the elements of `render_pass_extent` is zero, but no attachment images were given to
+ /// calculate the extent from.
+ AutoExtentAttachmentsEmpty,
+
+ /// `layer_count` is zero, but no attachment images were given to calculate the number of layers
+ /// from.
+ AutoLayersAttachmentsEmpty,
+
+ /// A clear attachment value is not compatible with the attachment's format.
+ ClearAttachmentNotCompatible {
+ clear_attachment: ClearAttachment,
+ attachment_format: Option<Format>,
+ },
+
+ /// A clear value for a render pass attachment is missing.
+ ClearValueMissing {
+ attachment_index: u32,
+ },
+
+ /// A clear value provided for a render pass attachment is not compatible with the attachment's
+ /// format.
+ ClearValueNotCompatible {
+ clear_value: ClearValue,
+ attachment_index: u32,
+ attachment_format: Format,
+ },
+
+ /// An attachment clear value specifies a `color_attachment` index that is not less than the
+ /// number of color attachments in the subpass.
+ ColorAttachmentIndexOutOfRange {
+ color_attachment_index: u32,
+ num_color_attachments: u32,
+ },
+
+ /// A color attachment has a layout that is not supported.
+ ColorAttachmentLayoutInvalid {
+ attachment_index: u32,
+ },
+
+ /// A color attachment is missing the `color_attachment` usage.
+ ColorAttachmentMissingUsage {
+ attachment_index: u32,
+ },
+
+ /// A color resolve attachment has a `format` value different from the corresponding color
+ /// attachment.
+ ColorAttachmentResolveFormatMismatch {
+ attachment_index: u32,
+ },
+
+ /// A color resolve attachment has a layout that is not supported.
+ ColorAttachmentResolveLayoutInvalid {
+ attachment_index: u32,
+ },
+
+ /// A color resolve attachment has a resolve mode that is not supported.
+ ColorAttachmentResolveModeNotSupported {
+ attachment_index: u32,
+ },
+
+ /// A color resolve attachment has a `samples` value other than [`SampleCount::Sample1`].
+ ColorAttachmentResolveMultisampled {
+ attachment_index: u32,
+ },
+
+ /// A color attachment has a `samples` value that is different from the first
+ /// color attachment.
+ ColorAttachmentSamplesMismatch {
+ attachment_index: u32,
+ },
+
+ /// A color attachment with a resolve attachment has a `samples` value of
+ /// [`SampleCount::Sample1`].
+ ColorAttachmentWithResolveNotMultisampled {
+ attachment_index: u32,
+ },
+
+ /// The contents `SubpassContents::SecondaryCommandBuffers` is not allowed inside a secondary
+ /// command buffer.
+ ContentsForbiddenInSecondaryCommandBuffer,
+
+ /// The depth attachment has a format that does not support that usage.
+ DepthAttachmentFormatUsageNotSupported,
+
+ /// The depth attachment has a layout that is not supported.
+ DepthAttachmentLayoutInvalid,
+
+ /// The depth attachment is missing the `depth_stencil_attachment` usage.
+ DepthAttachmentMissingUsage,
+
+ /// The depth resolve attachment has a `format` value different from the corresponding depth
+ /// attachment.
+ DepthAttachmentResolveFormatMismatch,
+
+ /// The depth resolve attachment has a layout that is not supported.
+ DepthAttachmentResolveLayoutInvalid,
+
+ /// The depth resolve attachment has a resolve mode that is not supported.
+ DepthAttachmentResolveModeNotSupported,
+
+ /// The depth resolve attachment has a `samples` value other than [`SampleCount::Sample1`].
+ DepthAttachmentResolveMultisampled,
+
+ /// The depth attachment has a `samples` value that is different from the first
+ /// color attachment.
+ DepthAttachmentSamplesMismatch,
+
+ /// The depth attachment has a resolve attachment and has a `samples` value of
+ /// [`SampleCount::Sample1`].
+ DepthAttachmentWithResolveNotMultisampled,
+
+ /// The depth and stencil attachments have different image views.
+ DepthStencilAttachmentImageViewMismatch,
+
+ /// The depth and stencil resolve attachments have different image views.
+ DepthStencilAttachmentResolveImageViewMismatch,
+
+ /// The combination of depth and stencil resolve modes is not supported by the device.
+ DepthStencilAttachmentResolveModesNotSupported,
+
+ /// Operation forbidden inside a render pass.
+ ForbiddenInsideRenderPass,
+
+ /// Operation forbidden outside a render pass.
+ ForbiddenOutsideRenderPass,
+
+ /// Operation forbidden inside a render pass instance that was begun with `begin_rendering`.
+ ForbiddenWithBeginRendering,
+
+ /// Operation forbidden inside a render pass instance that was begun with `begin_render_pass`.
+ ForbiddenWithBeginRenderPass,
+
+ /// Operation forbidden inside a render pass instance that is inherited by a secondary command
+ /// buffer.
+ ForbiddenWithInheritedRenderPass,
+
+ /// Operation forbidden inside a render subpass with the specified contents.
+ ForbiddenWithSubpassContents {
+ contents: SubpassContents,
+ },
+
+ /// The framebuffer is not compatible with the render pass.
+ FramebufferNotCompatible,
+
+ /// The `max_color_attachments` limit has been exceeded.
+ MaxColorAttachmentsExceeded {
+ color_attachment_count: u32,
+ max: u32,
+ },
+
+ /// The `max_multiview_view_count` limit has been exceeded.
+ MaxMultiviewViewCountExceeded {
+ view_count: u32,
+ max: u32,
+ },
+
+ /// The render pass uses multiview, but `layer_count` was not 0 or 1.
+ MultiviewLayersInvalid,
+
+ /// The render pass uses multiview, and in a clear rectangle, `array_layers` was not `0..1`.
+ MultiviewRectArrayLayersInvalid {
+ rect_index: usize,
+ },
+
+ /// Tried to advance to the next subpass, but there are no subpasses remaining in the render
+ /// pass.
+ NoSubpassesRemaining {
+ current_subpass: u32,
+ },
+
+ /// The queue family doesn't allow this operation.
+ NotSupportedByQueueFamily,
+
+ /// A query is active that conflicts with the current operation.
+ QueryIsActive,
+
+ /// A clear rectangle's `array_layers` is empty.
+ RectArrayLayersEmpty {
+ rect_index: usize,
+ },
+
+ /// A clear rectangle's `array_layers` is outside the range of layers of the attachments.
+ RectArrayLayersOutOfBounds {
+ rect_index: usize,
+ },
+
+ /// A clear rectangle's `extent` is zero.
+ RectExtentZero {
+ rect_index: usize,
+ },
+
+ /// A clear rectangle's `offset` and `extent` are outside the render area of the render pass
+ /// instance.
+ RectOutOfBounds {
+ rect_index: usize,
+ },
+
+ /// The render area's `offset` and `extent` are outside the extent of the framebuffer.
+ RenderAreaOutOfBounds,
+
+ /// The stencil attachment has a format that does not support that usage.
+ StencilAttachmentFormatUsageNotSupported,
+
+ /// The stencil attachment has a layout that is not supported.
+ StencilAttachmentLayoutInvalid,
+
+ /// The stencil attachment is missing the `depth_stencil_attachment` usage.
+ StencilAttachmentMissingUsage,
+
+ /// The stencil resolve attachment has a `format` value different from the corresponding stencil
+ /// attachment.
+ StencilAttachmentResolveFormatMismatch,
+
+ /// The stencil resolve attachment has a layout that is not supported.
+ StencilAttachmentResolveLayoutInvalid,
+
+ /// The stencil resolve attachment has a resolve mode that is not supported.
+ StencilAttachmentResolveModeNotSupported,
+
+ /// The stencil resolve attachment has a `samples` value other than [`SampleCount::Sample1`].
+ StencilAttachmentResolveMultisampled,
+
+ /// The stencil attachment has a `samples` value that is different from the first
+ /// color attachment or the depth attachment.
+ StencilAttachmentSamplesMismatch,
+
+ /// The stencil attachment has a resolve attachment and has a `samples` value of
+ /// [`SampleCount::Sample1`].
+ StencilAttachmentWithResolveNotMultisampled,
+
+ /// Tried to end a render pass with subpasses still remaining in the render pass.
+ SubpassesRemaining {
+ current_subpass: u32,
+ remaining_subpasses: u32,
+ },
+}
+
+impl Error for RenderPassError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::SyncCommandBufferBuilderError(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+impl Display for RenderPassError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::SyncCommandBufferBuilderError(_) => write!(f, "a SyncCommandBufferBuilderError"),
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ Self::AttachmentImageMissingUsage {
+ attachment_index,
+ usage,
+ } => write!(
+ f,
+ "the framebuffer image attached to attachment index {} did not have the required \
+ usage {} enabled",
+ attachment_index, usage,
+ ),
+ Self::AutoExtentAttachmentsEmpty => write!(
+ f,
+ "one of the elements of `render_pass_extent` is zero, but no attachment images \
+ were given to calculate the extent from",
+ ),
+ Self::AutoLayersAttachmentsEmpty => write!(
+ f,
+ "`layer_count` is zero, but no attachment images were given to calculate the \
+ number of layers from",
+ ),
+ Self::ClearAttachmentNotCompatible {
+ clear_attachment,
+ attachment_format,
+ } => write!(
+ f,
+ "a clear attachment value ({:?}) is not compatible with the attachment's format \
+ ({:?})",
+ clear_attachment, attachment_format,
+ ),
+ Self::ClearValueMissing { attachment_index } => write!(
+ f,
+ "a clear value for render pass attachment {} is missing",
+ attachment_index,
+ ),
+ Self::ClearValueNotCompatible {
+ clear_value,
+ attachment_index,
+ attachment_format,
+ } => write!(
+ f,
+ "a clear value ({:?}) provided for render pass attachment {} is not compatible \
+ with the attachment's format ({:?})",
+ clear_value, attachment_index, attachment_format,
+ ),
+ Self::ColorAttachmentIndexOutOfRange {
+ color_attachment_index,
+ num_color_attachments,
+ } => write!(
+ f,
+ "an attachment clear value specifies a `color_attachment` index {} that is not \
+ less than the number of color attachments in the subpass ({})",
+ color_attachment_index, num_color_attachments,
+ ),
+ Self::ColorAttachmentLayoutInvalid { attachment_index } => write!(
+ f,
+ "color attachment {} has a layout that is not supported",
+ attachment_index,
+ ),
+ Self::ColorAttachmentMissingUsage { attachment_index } => write!(
+ f,
+ "color attachment {} is missing the `color_attachment` usage",
+ attachment_index,
+ ),
+ Self::ColorAttachmentResolveFormatMismatch { attachment_index } => write!(
+ f,
+ "color attachment {} has a `format` value different from the corresponding color \
+ attachment",
+ attachment_index,
+ ),
+ Self::ColorAttachmentResolveLayoutInvalid { attachment_index } => write!(
+ f,
+ "color resolve attachment {} has a layout that is not supported",
+ attachment_index,
+ ),
+ Self::ColorAttachmentResolveModeNotSupported { attachment_index } => write!(
+ f,
+ "color resolve attachment {} has a resolve mode that is not supported",
+ attachment_index,
+ ),
+ Self::ColorAttachmentResolveMultisampled { attachment_index } => write!(
+ f,
+ "color resolve attachment {} has a `samples` value other than \
+ `SampleCount::Sample1`",
+ attachment_index,
+ ),
+ Self::ColorAttachmentSamplesMismatch { attachment_index } => write!(
+ f,
+ "color attachment {} has a `samples` value that is different from the first color \
+ attachment",
+ attachment_index,
+ ),
+ Self::ColorAttachmentWithResolveNotMultisampled { attachment_index } => write!(
+ f,
+ "color attachment {} with a resolve attachment has a `samples` value of \
+ `SampleCount::Sample1`",
+ attachment_index,
+ ),
+ Self::ContentsForbiddenInSecondaryCommandBuffer => write!(
+ f,
+ "the contents `SubpassContents::SecondaryCommandBuffers` is not allowed inside a \
+ secondary command buffer",
+ ),
+ Self::DepthAttachmentFormatUsageNotSupported => write!(
+ f,
+ "the depth attachment has a format that does not support that usage",
+ ),
+ Self::DepthAttachmentLayoutInvalid => {
+ write!(f, "the depth attachment has a layout that is not supported")
+ }
+ Self::DepthAttachmentMissingUsage => write!(
+ f,
+ "the depth attachment is missing the `depth_stencil_attachment` usage",
+ ),
+ Self::DepthAttachmentResolveFormatMismatch => write!(
+ f,
+ "the depth resolve attachment has a `format` value different from the \
+ corresponding depth attachment",
+ ),
+ Self::DepthAttachmentResolveLayoutInvalid => write!(
+ f,
+ "the depth resolve attachment has a layout that is not supported",
+ ),
+ Self::DepthAttachmentResolveModeNotSupported => write!(
+ f,
+ "the depth resolve attachment has a resolve mode that is not supported",
+ ),
+ Self::DepthAttachmentResolveMultisampled => write!(
+ f,
+ "the depth resolve attachment has a `samples` value other than \
+ `SampleCount::Sample1`",
+ ),
+ Self::DepthAttachmentSamplesMismatch => write!(
+ f,
+ "the depth attachment has a `samples` value that is different from the first color \
+ attachment",
+ ),
+ Self::DepthAttachmentWithResolveNotMultisampled => write!(
+ f,
+ "the depth attachment has a resolve attachment and has a `samples` value of \
+ `SampleCount::Sample1`",
+ ),
+ Self::DepthStencilAttachmentImageViewMismatch => write!(
+ f,
+ "the depth and stencil attachments have different image views",
+ ),
+ Self::DepthStencilAttachmentResolveImageViewMismatch => write!(
+ f,
+ "the depth and stencil resolve attachments have different image views",
+ ),
+ Self::DepthStencilAttachmentResolveModesNotSupported => write!(
+ f,
+ "the combination of depth and stencil resolve modes is not supported by the device",
+ ),
+ Self::ForbiddenInsideRenderPass => {
+ write!(f, "operation forbidden inside a render pass")
+ }
+ Self::ForbiddenOutsideRenderPass => {
+ write!(f, "operation forbidden outside a render pass")
+ }
+ Self::ForbiddenWithBeginRendering => write!(
+ f,
+ "operation forbidden inside a render pass instance that was begun with \
+ `begin_rendering`",
+ ),
+ Self::ForbiddenWithBeginRenderPass => write!(
+ f,
+ "operation forbidden inside a render pass instance that was begun with \
+ `begin_render_pass`",
+ ),
+ Self::ForbiddenWithInheritedRenderPass => write!(
+ f,
+ "operation forbidden inside a render pass instance that is inherited by a \
+ secondary command buffer",
+ ),
+ Self::ForbiddenWithSubpassContents {
+ contents: subpass_contents,
+ } => write!(
+ f,
+ "operation forbidden inside a render subpass with contents {:?}",
+ subpass_contents,
+ ),
+ Self::FramebufferNotCompatible => {
+ write!(f, "the framebuffer is not compatible with the render pass")
+ }
+ Self::MaxColorAttachmentsExceeded { .. } => {
+ write!(f, "the `max_color_attachments` limit has been exceeded")
+ }
+ Self::MaxMultiviewViewCountExceeded { .. } => {
+ write!(f, "the `max_multiview_view_count` limit has been exceeded")
+ }
+ Self::MultiviewLayersInvalid => write!(
+ f,
+ "the render pass uses multiview, but `layer_count` was not 0 or 1",
+ ),
+ Self::MultiviewRectArrayLayersInvalid { rect_index } => write!(
+ f,
+ "the render pass uses multiview, and in clear rectangle index {}, `array_layers` \
+ was not `0..1`",
+ rect_index,
+ ),
+ Self::NoSubpassesRemaining { current_subpass } => write!(
+ f,
+ "tried to advance to the next subpass after subpass {}, but there are no subpasses \
+ remaining in the render pass",
+ current_subpass,
+ ),
+ Self::NotSupportedByQueueFamily => {
+ write!(f, "the queue family doesn't allow this operation")
+ }
+ Self::QueryIsActive => write!(
+ f,
+ "a query is active that conflicts with the current operation",
+ ),
+ Self::RectArrayLayersEmpty { rect_index } => write!(
+ f,
+ "clear rectangle index {} `array_layers` is empty",
+ rect_index,
+ ),
+ Self::RectArrayLayersOutOfBounds { rect_index } => write!(
+ f,
+ "clear rectangle index {} `array_layers` is outside the range of layers of the \
+ attachments",
+ rect_index,
+ ),
+ Self::RectExtentZero { rect_index } => {
+ write!(f, "clear rectangle index {} `extent` is zero", rect_index)
+ }
+ Self::RectOutOfBounds { rect_index } => write!(
+ f,
+ "clear rectangle index {} `offset` and `extent` are outside the render area of the \
+ render pass instance",
+ rect_index,
+ ),
+ Self::RenderAreaOutOfBounds => write!(
+ f,
+ "the render area's `offset` and `extent` are outside the extent of the framebuffer",
+ ),
+ Self::StencilAttachmentFormatUsageNotSupported => write!(
+ f,
+ "the stencil attachment has a format that does not support that usage",
+ ),
+ Self::StencilAttachmentLayoutInvalid => write!(
+ f,
+ "the stencil attachment has a layout that is not supported",
+ ),
+ Self::StencilAttachmentMissingUsage => write!(
+ f,
+ "the stencil attachment is missing the `depth_stencil_attachment` usage",
+ ),
+ Self::StencilAttachmentResolveFormatMismatch => write!(
+ f,
+ "the stencil resolve attachment has a `format` value different from the \
+ corresponding stencil attachment",
+ ),
+ Self::StencilAttachmentResolveLayoutInvalid => write!(
+ f,
+ "the stencil resolve attachment has a layout that is not supported",
+ ),
+ Self::StencilAttachmentResolveModeNotSupported => write!(
+ f,
+ "the stencil resolve attachment has a resolve mode that is not supported",
+ ),
+ Self::StencilAttachmentResolveMultisampled => write!(
+ f,
+ "the stencil resolve attachment has a `samples` value other than \
+ `SampleCount::Sample1`",
+ ),
+ Self::StencilAttachmentSamplesMismatch => write!(
+ f,
+ "the stencil attachment has a `samples` value that is different from the first \
+ color attachment",
+ ),
+ Self::StencilAttachmentWithResolveNotMultisampled => write!(
+ f,
+ "the stencil attachment has a resolve attachment and has a `samples` value of \
+ `SampleCount::Sample1`",
+ ),
+ Self::SubpassesRemaining {
+ current_subpass,
+ remaining_subpasses,
+ } => write!(
+ f,
+ "tried to end a render pass at subpass {}, with {} subpasses still remaining in \
+ the render pass",
+ current_subpass, remaining_subpasses,
+ ),
+ }
+ }
+}
+
+impl From<SyncCommandBufferBuilderError> for RenderPassError {
+ fn from(err: SyncCommandBufferBuilderError) -> Self {
+ Self::SyncCommandBufferBuilderError(err)
+ }
+}
+
+impl From<RequirementNotMet> for RenderPassError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
+ }
+ }
+}
diff --git a/src/command_buffer/commands/secondary.rs b/src/command_buffer/commands/secondary.rs
new file mode 100644
index 0000000..ff70edc
--- /dev/null
+++ b/src/command_buffer/commands/secondary.rs
@@ -0,0 +1,930 @@
+// Copyright (c) 2022 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use crate::{
+ command_buffer::{
+ allocator::CommandBufferAllocator,
+ auto::RenderPassStateType,
+ synced::{Command, Resource, SyncCommandBufferBuilder, SyncCommandBufferBuilderError},
+ sys::UnsafeCommandBufferBuilder,
+ AutoCommandBufferBuilder, CommandBufferExecError, CommandBufferInheritanceRenderPassType,
+ CommandBufferUsage, ResourceInCommand, ResourceUseRef, SecondaryCommandBufferAbstract,
+ SecondaryCommandBufferBufferUsage, SecondaryCommandBufferImageUsage,
+ SecondaryCommandBufferResourcesUsage, SubpassContents,
+ },
+ device::{DeviceOwned, QueueFlags},
+ format::Format,
+ image::SampleCount,
+ query::{QueryControlFlags, QueryPipelineStatisticFlags, QueryType},
+ RequiresOneOf, SafeDeref, VulkanObject,
+};
+use smallvec::SmallVec;
+use std::{
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+};
+
+/// # Commands to execute a secondary command buffer inside a primary command buffer.
+///
+/// These commands can be called on any queue that can execute the commands recorded in the
+/// secondary command buffer.
+impl<L, A> AutoCommandBufferBuilder<L, A>
+where
+ A: CommandBufferAllocator,
+{
+ /// Executes a secondary command buffer.
+ ///
+ /// If the `flags` that `command_buffer` was created with are more restrictive than those of
+ /// `self`, then `self` will be restricted to match. E.g. executing a secondary command buffer
+ /// with `Flags::OneTimeSubmit` will set `self`'s flags to `Flags::OneTimeSubmit` also.
+ pub fn execute_commands<C>(
+ &mut self,
+ command_buffer: C,
+ ) -> Result<&mut Self, ExecuteCommandsError>
+ where
+ C: SecondaryCommandBufferAbstract + 'static,
+ {
+ self.validate_execute_commands(&command_buffer, 0)?;
+
+ unsafe {
+ let secondary_usage = command_buffer.usage();
+ let mut builder = self.inner.execute_commands();
+ builder.add(command_buffer);
+ builder.submit()?;
+
+ // Secondary command buffer could leave the primary in any state.
+ self.inner.reset_state();
+
+ // If the secondary is non-concurrent or one-time use, that restricts the primary as
+ // well.
+ self.usage = std::cmp::min(self.usage, secondary_usage);
+ }
+
+ Ok(self)
+ }
+
+ /// Executes multiple secondary command buffers in a vector.
+ ///
+ /// This requires that the secondary command buffers do not have resource conflicts; an error
+ /// will be returned if there are any. Use `execute_commands` if you want to ensure that
+ /// resource conflicts are automatically resolved.
+ // TODO ^ would be nice if this just worked without errors
+ pub fn execute_commands_from_vec<C>(
+ &mut self,
+ command_buffers: Vec<C>,
+ ) -> Result<&mut Self, ExecuteCommandsError>
+ where
+ C: SecondaryCommandBufferAbstract + 'static,
+ {
+ for (command_buffer_index, command_buffer) in command_buffers.iter().enumerate() {
+ self.validate_execute_commands(command_buffer, command_buffer_index as u32)?;
+ }
+
+ unsafe {
+ let mut secondary_usage = CommandBufferUsage::SimultaneousUse; // Most permissive usage
+
+ let mut builder = self.inner.execute_commands();
+ for command_buffer in command_buffers {
+ secondary_usage = std::cmp::min(secondary_usage, command_buffer.usage());
+ builder.add(command_buffer);
+ }
+ builder.submit()?;
+
+ // Secondary command buffer could leave the primary in any state.
+ self.inner.reset_state();
+
+ // If the secondary is non-concurrent or one-time use, that restricts the primary as
+ // well.
+ self.usage = std::cmp::min(self.usage, secondary_usage);
+ }
+
+ Ok(self)
+ }
+
+ fn validate_execute_commands<C>(
+ &self,
+ command_buffer: &C,
+ command_buffer_index: u32,
+ ) -> Result<(), ExecuteCommandsError>
+ where
+ C: SecondaryCommandBufferAbstract + 'static,
+ {
+ // VUID-vkCmdExecuteCommands-commonparent
+ assert_eq!(self.device(), command_buffer.device());
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdExecuteCommands-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::TRANSFER | QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(ExecuteCommandsError::NotSupportedByQueueFamily);
+ }
+
+ // TODO:
+ // VUID-vkCmdExecuteCommands-pCommandBuffers-00094
+
+ if let Some(render_pass_state) = &self.render_pass_state {
+ // VUID-vkCmdExecuteCommands-contents-06018
+ // VUID-vkCmdExecuteCommands-flags-06024
+ if render_pass_state.contents != SubpassContents::SecondaryCommandBuffers {
+ return Err(ExecuteCommandsError::ForbiddenWithSubpassContents {
+ contents: render_pass_state.contents,
+ });
+ }
+
+ // VUID-vkCmdExecuteCommands-pCommandBuffers-00096
+ let inheritance_render_pass = command_buffer
+ .inheritance_info()
+ .render_pass
+ .as_ref()
+ .ok_or(ExecuteCommandsError::RenderPassInheritanceRequired {
+ command_buffer_index,
+ })?;
+
+ match (&render_pass_state.render_pass, inheritance_render_pass) {
+ (
+ RenderPassStateType::BeginRenderPass(state),
+ CommandBufferInheritanceRenderPassType::BeginRenderPass(inheritance_info),
+ ) => {
+ // VUID-vkCmdExecuteCommands-pBeginInfo-06020
+ if !inheritance_info
+ .subpass
+ .render_pass()
+ .is_compatible_with(state.subpass.render_pass())
+ {
+ return Err(ExecuteCommandsError::RenderPassNotCompatible {
+ command_buffer_index,
+ });
+ }
+
+ // VUID-vkCmdExecuteCommands-pCommandBuffers-06019
+ if inheritance_info.subpass.index() != state.subpass.index() {
+ return Err(ExecuteCommandsError::RenderPassSubpassMismatch {
+ command_buffer_index,
+ required_subpass: state.subpass.index(),
+ inherited_subpass: inheritance_info.subpass.index(),
+ });
+ }
+
+ // VUID-vkCmdExecuteCommands-pCommandBuffers-00099
+ if let Some(framebuffer) = &inheritance_info.framebuffer {
+ if framebuffer != state.framebuffer.as_ref().unwrap() {
+ return Err(ExecuteCommandsError::RenderPassFramebufferMismatch {
+ command_buffer_index,
+ });
+ }
+ }
+ }
+ (
+ RenderPassStateType::BeginRendering(state),
+ CommandBufferInheritanceRenderPassType::BeginRendering(inheritance_info),
+ ) => {
+ let attachments = state.attachments.as_ref().unwrap();
+
+ // VUID-vkCmdExecuteCommands-colorAttachmentCount-06027
+ if inheritance_info.color_attachment_formats.len()
+ != attachments.color_attachments.len()
+ {
+ return Err(
+ ExecuteCommandsError::RenderPassColorAttachmentCountMismatch {
+ command_buffer_index,
+ required_count: attachments.color_attachments.len() as u32,
+ inherited_count: inheritance_info.color_attachment_formats.len()
+ as u32,
+ },
+ );
+ }
+
+ for (color_attachment_index, image_view, inherited_format) in attachments
+ .color_attachments
+ .iter()
+ .zip(inheritance_info.color_attachment_formats.iter().copied())
+ .enumerate()
+ .filter_map(|(i, (a, f))| a.as_ref().map(|a| (i as u32, &a.image_view, f)))
+ {
+ let required_format = image_view.format().unwrap();
+
+ // VUID-vkCmdExecuteCommands-imageView-06028
+ if Some(required_format) != inherited_format {
+ return Err(
+ ExecuteCommandsError::RenderPassColorAttachmentFormatMismatch {
+ command_buffer_index,
+ color_attachment_index,
+ required_format,
+ inherited_format,
+ },
+ );
+ }
+
+ // VUID-vkCmdExecuteCommands-pNext-06035
+ if image_view.image().samples() != inheritance_info.rasterization_samples {
+ return Err(
+ ExecuteCommandsError::RenderPassColorAttachmentSamplesMismatch {
+ command_buffer_index,
+ color_attachment_index,
+ required_samples: image_view.image().samples(),
+ inherited_samples: inheritance_info.rasterization_samples,
+ },
+ );
+ }
+ }
+
+ if let Some((image_view, format)) = attachments
+ .depth_attachment
+ .as_ref()
+ .map(|a| (&a.image_view, inheritance_info.depth_attachment_format))
+ {
+ // VUID-vkCmdExecuteCommands-pDepthAttachment-06029
+ if Some(image_view.format().unwrap()) != format {
+ return Err(
+ ExecuteCommandsError::RenderPassDepthAttachmentFormatMismatch {
+ command_buffer_index,
+ required_format: image_view.format().unwrap(),
+ inherited_format: format,
+ },
+ );
+ }
+
+ // VUID-vkCmdExecuteCommands-pNext-06036
+ if image_view.image().samples() != inheritance_info.rasterization_samples {
+ return Err(
+ ExecuteCommandsError::RenderPassDepthAttachmentSamplesMismatch {
+ command_buffer_index,
+ required_samples: image_view.image().samples(),
+ inherited_samples: inheritance_info.rasterization_samples,
+ },
+ );
+ }
+ }
+
+ if let Some((image_view, format)) = attachments
+ .stencil_attachment
+ .as_ref()
+ .map(|a| (&a.image_view, inheritance_info.stencil_attachment_format))
+ {
+ // VUID-vkCmdExecuteCommands-pStencilAttachment-06030
+ if Some(image_view.format().unwrap()) != format {
+ return Err(
+ ExecuteCommandsError::RenderPassStencilAttachmentFormatMismatch {
+ command_buffer_index,
+ required_format: image_view.format().unwrap(),
+ inherited_format: format,
+ },
+ );
+ }
+
+ // VUID-vkCmdExecuteCommands-pNext-06037
+ if image_view.image().samples() != inheritance_info.rasterization_samples {
+ return Err(
+ ExecuteCommandsError::RenderPassStencilAttachmentSamplesMismatch {
+ command_buffer_index,
+ required_samples: image_view.image().samples(),
+ inherited_samples: inheritance_info.rasterization_samples,
+ },
+ );
+ }
+ }
+
+ // VUID-vkCmdExecuteCommands-viewMask-06031
+ if inheritance_info.view_mask != render_pass_state.view_mask {
+ return Err(ExecuteCommandsError::RenderPassViewMaskMismatch {
+ command_buffer_index,
+ required_view_mask: render_pass_state.view_mask,
+ inherited_view_mask: inheritance_info.view_mask,
+ });
+ }
+ }
+ _ => {
+ // VUID-vkCmdExecuteCommands-pBeginInfo-06025
+ return Err(ExecuteCommandsError::RenderPassTypeMismatch {
+ command_buffer_index,
+ });
+ }
+ }
+
+ // TODO:
+ // VUID-vkCmdExecuteCommands-commandBuffer-06533
+ // VUID-vkCmdExecuteCommands-commandBuffer-06534
+ // VUID-vkCmdExecuteCommands-pCommandBuffers-06535
+ // VUID-vkCmdExecuteCommands-pCommandBuffers-06536
+ } else {
+ // VUID-vkCmdExecuteCommands-pCommandBuffers-00100
+ if command_buffer.inheritance_info().render_pass.is_some() {
+ return Err(ExecuteCommandsError::RenderPassInheritanceForbidden {
+ command_buffer_index,
+ });
+ }
+ }
+
+ // VUID-vkCmdExecuteCommands-commandBuffer-00101
+ if !self.query_state.is_empty() && !self.device().enabled_features().inherited_queries {
+ return Err(ExecuteCommandsError::RequirementNotMet {
+ required_for: "`AutoCommandBufferBuilder::execute_commands` when a query is active",
+ requires_one_of: RequiresOneOf {
+ features: &["inherited_queries"],
+ ..Default::default()
+ },
+ });
+ }
+
+ for state in self.query_state.values() {
+ match state.ty {
+ QueryType::Occlusion => {
+ // VUID-vkCmdExecuteCommands-commandBuffer-00102
+ let inherited_flags = command_buffer.inheritance_info().occlusion_query.ok_or(
+ ExecuteCommandsError::OcclusionQueryInheritanceRequired {
+ command_buffer_index,
+ },
+ )?;
+
+ let inherited_flags_vk = ash::vk::QueryControlFlags::from(inherited_flags);
+ let state_flags_vk = ash::vk::QueryControlFlags::from(state.flags);
+
+ // VUID-vkCmdExecuteCommands-commandBuffer-00103
+ if inherited_flags_vk & state_flags_vk != state_flags_vk {
+ return Err(ExecuteCommandsError::OcclusionQueryFlagsNotSuperset {
+ command_buffer_index,
+ required_flags: state.flags,
+ inherited_flags,
+ });
+ }
+ }
+ QueryType::PipelineStatistics(state_flags) => {
+ let inherited_flags = command_buffer.inheritance_info().query_statistics_flags;
+ let inherited_flags_vk =
+ ash::vk::QueryPipelineStatisticFlags::from(inherited_flags);
+ let state_flags_vk = ash::vk::QueryPipelineStatisticFlags::from(state_flags);
+
+ // VUID-vkCmdExecuteCommands-commandBuffer-00104
+ if inherited_flags_vk & state_flags_vk != state_flags_vk {
+ return Err(
+ ExecuteCommandsError::PipelineStatisticsQueryFlagsNotSuperset {
+ command_buffer_index,
+ required_flags: state_flags,
+ inherited_flags,
+ },
+ );
+ }
+ }
+ QueryType::Timestamp => (),
+ }
+ }
+
+ // TODO:
+ // VUID-vkCmdExecuteCommands-pCommandBuffers-00091
+ // VUID-vkCmdExecuteCommands-pCommandBuffers-00092
+ // VUID-vkCmdExecuteCommands-pCommandBuffers-00093
+ // VUID-vkCmdExecuteCommands-pCommandBuffers-00105
+
+ // VUID-vkCmdExecuteCommands-bufferlevel
+ // Ensured by the type of the impl block.
+
+ // VUID-vkCmdExecuteCommands-pCommandBuffers-00088
+ // VUID-vkCmdExecuteCommands-pCommandBuffers-00089
+ // Ensured by the SecondaryCommandBuffer trait.
+
+ Ok(())
+ }
+}
+
+impl SyncCommandBufferBuilder {
+ /// Starts the process of executing secondary command buffers. Returns an intermediate struct
+ /// which can be used to add the command buffers.
+ #[inline]
+ pub unsafe fn execute_commands(&mut self) -> SyncCommandBufferBuilderExecuteCommands<'_> {
+ SyncCommandBufferBuilderExecuteCommands {
+ builder: self,
+ inner: Vec::new(),
+ }
+ }
+}
+
+/// Prototype for a `vkCmdExecuteCommands`.
+pub struct SyncCommandBufferBuilderExecuteCommands<'a> {
+ builder: &'a mut SyncCommandBufferBuilder,
+ inner: Vec<Box<dyn SecondaryCommandBufferAbstract>>,
+}
+
+impl<'a> SyncCommandBufferBuilderExecuteCommands<'a> {
+ /// Adds a command buffer to the list.
+ pub fn add(&mut self, command_buffer: impl SecondaryCommandBufferAbstract + 'static) {
+ self.inner.push(Box::new(command_buffer));
+ }
+
+ #[inline]
+ pub unsafe fn submit(self) -> Result<(), SyncCommandBufferBuilderError> {
+ struct DropUnlock(Box<dyn SecondaryCommandBufferAbstract>);
+ impl std::ops::Deref for DropUnlock {
+ type Target = Box<dyn SecondaryCommandBufferAbstract>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+ }
+ unsafe impl SafeDeref for DropUnlock {}
+
+ impl Drop for DropUnlock {
+ fn drop(&mut self) {
+ unsafe {
+ self.unlock();
+ }
+ }
+ }
+
+ struct Cmd(Vec<DropUnlock>);
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "execute_commands"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ let mut execute = UnsafeCommandBufferBuilderExecuteCommands::new();
+ self.0
+ .iter()
+ .for_each(|cbuf| execute.add_raw(cbuf.handle()));
+ out.execute_commands(execute);
+ }
+ }
+
+ let command_index = self.builder.commands.len();
+ let command_name = "execute_commands";
+ let resources: Vec<_> = self
+ .inner
+ .iter()
+ .enumerate()
+ .flat_map(|(index, cbuf)| {
+ let index = index as u32;
+ let SecondaryCommandBufferResourcesUsage { buffers, images } =
+ cbuf.resources_usage();
+
+ (buffers.iter().map(move |usage| {
+ let &SecondaryCommandBufferBufferUsage {
+ use_ref,
+ ref buffer,
+ ref range,
+ memory,
+ } = usage;
+
+ (
+ ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::SecondaryCommandBuffer {
+ index,
+ },
+ secondary_use_ref: Some(use_ref.into()),
+ },
+ Resource::Buffer {
+ buffer: buffer.clone(),
+ range: range.clone(),
+ memory,
+ },
+ )
+ }))
+ .chain(images.iter().map(move |usage| {
+ let &SecondaryCommandBufferImageUsage {
+ use_ref,
+ ref image,
+ ref subresource_range,
+ memory,
+ start_layout,
+ end_layout,
+ } = usage;
+
+ (
+ ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::SecondaryCommandBuffer {
+ index,
+ },
+ secondary_use_ref: Some(use_ref.into()),
+ },
+ Resource::Image {
+ image: image.clone(),
+ subresource_range: subresource_range.clone(),
+ memory,
+ start_layout,
+ end_layout,
+ },
+ )
+ }))
+ })
+ .collect();
+
+ for resource in &resources {
+ self.builder.check_resource_conflicts(resource)?;
+ }
+
+ self.builder.commands.push(Box::new(Cmd(self
+ .inner
+ .into_iter()
+ .map(|cbuf| {
+ cbuf.lock_record()?;
+ Ok(DropUnlock(cbuf))
+ })
+ .collect::<Result<Vec<_>, CommandBufferExecError>>()?)));
+
+ for resource in resources {
+ self.builder.add_resource(resource);
+ }
+
+ Ok(())
+ }
+}
+
+impl UnsafeCommandBufferBuilder {
+ /// Calls `vkCmdExecuteCommands` on the builder.
+ ///
+ /// Does nothing if the list of command buffers is empty, as it would be a no-op and isn't a
+ /// valid usage of the command anyway.
+ #[inline]
+ pub unsafe fn execute_commands(&mut self, cbs: UnsafeCommandBufferBuilderExecuteCommands) {
+ if cbs.raw_cbs.is_empty() {
+ return;
+ }
+
+ let fns = self.device.fns();
+ (fns.v1_0.cmd_execute_commands)(
+ self.handle,
+ cbs.raw_cbs.len() as u32,
+ cbs.raw_cbs.as_ptr(),
+ );
+ }
+}
+
+/// Prototype for a `vkCmdExecuteCommands`.
+pub struct UnsafeCommandBufferBuilderExecuteCommands {
+ // Raw handles of the command buffers to execute.
+ raw_cbs: SmallVec<[ash::vk::CommandBuffer; 4]>,
+}
+
+impl UnsafeCommandBufferBuilderExecuteCommands {
+ /// Builds a new empty list.
+ #[inline]
+ pub fn new() -> UnsafeCommandBufferBuilderExecuteCommands {
+ UnsafeCommandBufferBuilderExecuteCommands {
+ raw_cbs: SmallVec::new(),
+ }
+ }
+
+ /// Adds a command buffer to the list.
+ pub fn add(&mut self, cb: &(impl SecondaryCommandBufferAbstract + ?Sized)) {
+ // TODO: debug assert that it is a secondary command buffer?
+ self.raw_cbs.push(cb.handle());
+ }
+
+ /// Adds a command buffer to the list.
+ #[inline]
+ pub unsafe fn add_raw(&mut self, cb: ash::vk::CommandBuffer) {
+ self.raw_cbs.push(cb);
+ }
+}
+
+/// Error that can happen when executing a secondary command buffer.
+#[derive(Clone, Debug)]
+pub enum ExecuteCommandsError {
+ SyncCommandBufferBuilderError(SyncCommandBufferBuilderError),
+
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+
+ /// Operation forbidden inside a render subpass with the specified contents.
+ ForbiddenWithSubpassContents {
+ contents: SubpassContents,
+ },
+
+ /// The queue family doesn't allow this operation.
+ NotSupportedByQueueFamily,
+
+ /// A render pass is active, but a command buffer does not contain occlusion query inheritance
+ /// info.
+ OcclusionQueryInheritanceRequired {
+ command_buffer_index: u32,
+ },
+
+ /// The inherited occlusion query control flags of a command buffer are not a superset of the
+ /// currently active flags.
+ OcclusionQueryFlagsNotSuperset {
+ command_buffer_index: u32,
+ required_flags: QueryControlFlags,
+ inherited_flags: QueryControlFlags,
+ },
+
+ /// The inherited pipeline statistics query flags of a command buffer are not a superset of the
+ /// currently active flags.
+ PipelineStatisticsQueryFlagsNotSuperset {
+ command_buffer_index: u32,
+ required_flags: QueryPipelineStatisticFlags,
+ inherited_flags: QueryPipelineStatisticFlags,
+ },
+
+ /// The inherited color attachment count of a command buffer does not match the current
+ /// attachment count.
+ RenderPassColorAttachmentCountMismatch {
+ command_buffer_index: u32,
+ required_count: u32,
+ inherited_count: u32,
+ },
+
+ /// The inherited format of a color attachment of a command buffer does not match the current
+ /// attachment format.
+ RenderPassColorAttachmentFormatMismatch {
+ command_buffer_index: u32,
+ color_attachment_index: u32,
+ required_format: Format,
+ inherited_format: Option<Format>,
+ },
+
+ /// The inherited sample count of a color attachment of a command buffer does not match the
+ /// current attachment sample count.
+ RenderPassColorAttachmentSamplesMismatch {
+ command_buffer_index: u32,
+ color_attachment_index: u32,
+ required_samples: SampleCount,
+ inherited_samples: SampleCount,
+ },
+
+ /// The inherited format of the depth attachment of a command buffer does not match the current
+ /// attachment format.
+ RenderPassDepthAttachmentFormatMismatch {
+ command_buffer_index: u32,
+ required_format: Format,
+ inherited_format: Option<Format>,
+ },
+
+ /// The inherited sample count of the depth attachment of a command buffer does not match the
+ /// current attachment sample count.
+ RenderPassDepthAttachmentSamplesMismatch {
+ command_buffer_index: u32,
+ required_samples: SampleCount,
+ inherited_samples: SampleCount,
+ },
+
+ /// The inherited framebuffer of a command buffer does not match the current framebuffer.
+ RenderPassFramebufferMismatch {
+ command_buffer_index: u32,
+ },
+
+ /// A render pass is active, but a command buffer does not contain render pass inheritance info.
+ RenderPassInheritanceRequired {
+ command_buffer_index: u32,
+ },
+
+ /// A render pass is not active, but a command buffer contains render pass inheritance info.
+ RenderPassInheritanceForbidden {
+ command_buffer_index: u32,
+ },
+
+ /// The inherited render pass of a command buffer is not compatible with the current render
+ /// pass.
+ RenderPassNotCompatible {
+ command_buffer_index: u32,
+ },
+
+ /// The inherited format of the stencil attachment of a command buffer does not match the
+ /// current attachment format.
+ RenderPassStencilAttachmentFormatMismatch {
+ command_buffer_index: u32,
+ required_format: Format,
+ inherited_format: Option<Format>,
+ },
+
+ /// The inherited sample count of the stencil attachment of a command buffer does not match the
+ /// current attachment sample count.
+ RenderPassStencilAttachmentSamplesMismatch {
+ command_buffer_index: u32,
+ required_samples: SampleCount,
+ inherited_samples: SampleCount,
+ },
+
+ /// The inherited subpass index of a command buffer does not match the current subpass index.
+ RenderPassSubpassMismatch {
+ command_buffer_index: u32,
+ required_subpass: u32,
+ inherited_subpass: u32,
+ },
+
+ /// The inherited render pass of a command buffer is of the wrong type.
+ RenderPassTypeMismatch {
+ command_buffer_index: u32,
+ },
+
+ /// The inherited view mask of a command buffer does not match the current view mask.
+ RenderPassViewMaskMismatch {
+ command_buffer_index: u32,
+ required_view_mask: u32,
+ inherited_view_mask: u32,
+ },
+}
+
+impl Error for ExecuteCommandsError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::SyncCommandBufferBuilderError(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+impl Display for ExecuteCommandsError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::SyncCommandBufferBuilderError(_) => write!(f, "a SyncCommandBufferBuilderError"),
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ Self::ForbiddenWithSubpassContents {
+ contents: subpass_contents,
+ } => write!(
+ f,
+ "operation forbidden inside a render subpass with contents {:?}",
+ subpass_contents,
+ ),
+ Self::NotSupportedByQueueFamily => {
+ write!(f, "the queue family doesn't allow this operation")
+ }
+ Self::OcclusionQueryInheritanceRequired {
+ command_buffer_index,
+ } => write!(
+ f,
+ "a render pass is active, but command buffer {} does not contain occlusion query \
+ inheritance info",
+ command_buffer_index,
+ ),
+ Self::OcclusionQueryFlagsNotSuperset {
+ command_buffer_index,
+ required_flags,
+ inherited_flags,
+ } => write!(
+ f,
+ "the inherited occlusion query control flags ({:?}) of command buffer {} are not a \
+ superset of the currently active flags ({:?})",
+ inherited_flags, command_buffer_index, required_flags,
+ ),
+ Self::PipelineStatisticsQueryFlagsNotSuperset {
+ command_buffer_index,
+ required_flags,
+ inherited_flags,
+ } => write!(
+ f,
+ "the inherited pipeline statistics query flags ({:?}) of command buffer {} are not \
+ a superset of the currently active flags ({:?})",
+ inherited_flags, command_buffer_index, required_flags,
+ ),
+ Self::RenderPassColorAttachmentCountMismatch {
+ command_buffer_index,
+ required_count,
+ inherited_count,
+ } => write!(
+ f,
+ "the inherited color attachment count ({}) of command buffer {} does not match the \
+ current attachment count ({})",
+ inherited_count, command_buffer_index, required_count,
+ ),
+ Self::RenderPassColorAttachmentFormatMismatch {
+ command_buffer_index,
+ color_attachment_index,
+ required_format,
+ inherited_format,
+ } => write!(
+ f,
+ "the inherited format ({:?}) of color attachment {} of command buffer {} does not \
+ match the current attachment format ({:?})",
+ inherited_format, color_attachment_index, command_buffer_index, required_format,
+ ),
+ Self::RenderPassColorAttachmentSamplesMismatch {
+ command_buffer_index,
+ color_attachment_index,
+ required_samples,
+ inherited_samples,
+ } => write!(
+ f,
+ "the inherited sample count ({:?}) of color attachment {} of command buffer {} \
+ does not match the current attachment sample count ({:?})",
+ inherited_samples, color_attachment_index, command_buffer_index, required_samples,
+ ),
+ Self::RenderPassDepthAttachmentFormatMismatch {
+ command_buffer_index,
+ required_format,
+ inherited_format,
+ } => write!(
+ f,
+ "the inherited format ({:?}) of the depth attachment of command buffer {} does not \
+ match the current attachment format ({:?})",
+ inherited_format, command_buffer_index, required_format,
+ ),
+ Self::RenderPassDepthAttachmentSamplesMismatch {
+ command_buffer_index,
+ required_samples,
+ inherited_samples,
+ } => write!(
+ f,
+ "the inherited sample count ({:?}) of the depth attachment of command buffer {} \
+ does not match the current attachment sample count ({:?})",
+ inherited_samples, command_buffer_index, required_samples,
+ ),
+ Self::RenderPassFramebufferMismatch {
+ command_buffer_index,
+ } => write!(
+ f,
+ "the inherited framebuffer of command buffer {} does not match the current \
+ framebuffer",
+ command_buffer_index,
+ ),
+ Self::RenderPassInheritanceRequired {
+ command_buffer_index,
+ } => write!(
+ f,
+ "a render pass is active, but command buffer {} does not contain render pass \
+ inheritance info",
+ command_buffer_index,
+ ),
+ Self::RenderPassInheritanceForbidden {
+ command_buffer_index,
+ } => write!(
+ f,
+ "a render pass is not active, but command buffer {} contains render pass \
+ inheritance info",
+ command_buffer_index,
+ ),
+ Self::RenderPassNotCompatible {
+ command_buffer_index,
+ } => write!(
+ f,
+ "the inherited render pass of command buffer {} is not compatible with the current \
+ render pass",
+ command_buffer_index,
+ ),
+ Self::RenderPassStencilAttachmentFormatMismatch {
+ command_buffer_index,
+ required_format,
+ inherited_format,
+ } => write!(
+ f,
+ "the inherited format ({:?}) of the stencil attachment of command buffer {} does \
+ not match the current attachment format ({:?})",
+ inherited_format, command_buffer_index, required_format,
+ ),
+ Self::RenderPassStencilAttachmentSamplesMismatch {
+ command_buffer_index,
+ required_samples,
+ inherited_samples,
+ } => write!(
+ f,
+ "the inherited sample count ({:?}) of the stencil attachment of command buffer {} \
+ does not match the current attachment sample count ({:?})",
+ inherited_samples, command_buffer_index, required_samples,
+ ),
+ Self::RenderPassSubpassMismatch {
+ command_buffer_index,
+ required_subpass,
+ inherited_subpass,
+ } => write!(
+ f,
+ "the inherited subpass index ({}) of command buffer {} does not match the current \
+ subpass index ({})",
+ inherited_subpass, command_buffer_index, required_subpass,
+ ),
+ Self::RenderPassTypeMismatch {
+ command_buffer_index,
+ } => write!(
+ f,
+ "the inherited render pass of command buffer {} is of the wrong type",
+ command_buffer_index,
+ ),
+ Self::RenderPassViewMaskMismatch {
+ command_buffer_index,
+ required_view_mask,
+ inherited_view_mask,
+ } => write!(
+ f,
+ "the inherited view mask ({}) of command buffer {} does not match the current view \
+ mask ({})",
+ inherited_view_mask, command_buffer_index, required_view_mask,
+ ),
+ }
+ }
+}
+
+impl From<SyncCommandBufferBuilderError> for ExecuteCommandsError {
+ fn from(err: SyncCommandBufferBuilderError) -> Self {
+ Self::SyncCommandBufferBuilderError(err)
+ }
+}
diff --git a/src/command_buffer/commands/sync.rs b/src/command_buffer/commands/sync.rs
new file mode 100644
index 0000000..2d4e346
--- /dev/null
+++ b/src/command_buffer/commands/sync.rs
@@ -0,0 +1,931 @@
+// Copyright (c) 2022 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use crate::{
+ command_buffer::{
+ synced::{Command, SyncCommandBufferBuilder},
+ sys::UnsafeCommandBufferBuilder,
+ },
+ image::ImageLayout,
+ sync::{
+ event::Event, AccessFlags, BufferMemoryBarrier, DependencyFlags, DependencyInfo,
+ ImageMemoryBarrier, MemoryBarrier, PipelineStages,
+ },
+ Version, VulkanObject,
+};
+use smallvec::SmallVec;
+use std::{ptr, sync::Arc};
+
+impl SyncCommandBufferBuilder {
+ /// Calls `vkCmdSetEvent` on the builder.
+ #[inline]
+ pub unsafe fn set_event(&mut self, event: Arc<Event>, dependency_info: DependencyInfo) {
+ struct Cmd {
+ event: Arc<Event>,
+ dependency_info: DependencyInfo,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "set_event"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.set_event(&self.event, &self.dependency_info);
+ }
+ }
+
+ self.commands.push(Box::new(Cmd {
+ event,
+ dependency_info,
+ }));
+ }
+
+ /// Calls `vkCmdWaitEvents` on the builder.
+ #[inline]
+ pub unsafe fn wait_events(
+ &mut self,
+ events: impl IntoIterator<Item = (Arc<Event>, DependencyInfo)>,
+ ) {
+ struct Cmd {
+ events: SmallVec<[(Arc<Event>, DependencyInfo); 4]>,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "wait_events"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.wait_events(
+ self.events
+ .iter()
+ .map(|&(ref event, ref dependency_info)| (event.as_ref(), dependency_info)),
+ );
+ }
+ }
+
+ self.commands.push(Box::new(Cmd {
+ events: events.into_iter().collect(),
+ }));
+ }
+
+ /// Calls `vkCmdResetEvent` on the builder.
+ #[inline]
+ pub unsafe fn reset_event(&mut self, event: Arc<Event>, stages: PipelineStages) {
+ struct Cmd {
+ event: Arc<Event>,
+ stages: PipelineStages,
+ }
+
+ impl Command for Cmd {
+ fn name(&self) -> &'static str {
+ "reset_event"
+ }
+
+ unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
+ out.reset_event(&self.event, self.stages);
+ }
+ }
+
+ self.commands.push(Box::new(Cmd { event, stages }));
+ }
+}
+
+impl UnsafeCommandBufferBuilder {
+ #[inline]
+ pub unsafe fn pipeline_barrier(&mut self, dependency_info: &DependencyInfo) {
+ if dependency_info.is_empty() {
+ return;
+ }
+
+ let DependencyInfo {
+ mut dependency_flags,
+ memory_barriers,
+ buffer_memory_barriers,
+ image_memory_barriers,
+ _ne: _,
+ } = dependency_info;
+
+ // TODO: Is this needed?
+ dependency_flags |= DependencyFlags::BY_REGION;
+
+ if self.device.enabled_features().synchronization2 {
+ let memory_barriers_vk: SmallVec<[_; 2]> = memory_barriers
+ .into_iter()
+ .map(|barrier| {
+ let &MemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ _ne: _,
+ } = barrier;
+
+ debug_assert!(AccessFlags::from(src_stages).contains(src_access));
+ debug_assert!(AccessFlags::from(dst_stages).contains(dst_access));
+
+ ash::vk::MemoryBarrier2 {
+ src_stage_mask: src_stages.into(),
+ src_access_mask: src_access.into(),
+ dst_stage_mask: dst_stages.into(),
+ dst_access_mask: dst_access.into(),
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let buffer_memory_barriers_vk: SmallVec<[_; 8]> = buffer_memory_barriers
+ .into_iter()
+ .map(|barrier| {
+ let &BufferMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ queue_family_ownership_transfer,
+ ref buffer,
+ ref range,
+ _ne: _,
+ } = barrier;
+
+ debug_assert!(AccessFlags::from(src_stages).contains(src_access));
+ debug_assert!(AccessFlags::from(dst_stages).contains(dst_access));
+ debug_assert!(!range.is_empty());
+ debug_assert!(range.end <= buffer.size());
+
+ let (src_queue_family_index, dst_queue_family_index) =
+ queue_family_ownership_transfer.map_or(
+ (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED),
+ Into::into,
+ );
+
+ ash::vk::BufferMemoryBarrier2 {
+ src_stage_mask: src_stages.into(),
+ src_access_mask: src_access.into(),
+ dst_stage_mask: dst_stages.into(),
+ dst_access_mask: dst_access.into(),
+ src_queue_family_index,
+ dst_queue_family_index,
+ buffer: buffer.handle(),
+ offset: range.start,
+ size: range.end - range.start,
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let image_memory_barriers_vk: SmallVec<[_; 8]> = image_memory_barriers
+ .into_iter()
+ .map(|barrier| {
+ let &ImageMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ old_layout,
+ new_layout,
+ queue_family_ownership_transfer,
+ ref image,
+ ref subresource_range,
+ _ne: _,
+ } = barrier;
+
+ debug_assert!(AccessFlags::from(src_stages).contains(src_access));
+ debug_assert!(AccessFlags::from(dst_stages).contains(dst_access));
+
+ debug_assert!(
+ old_layout == new_layout
+ || !matches!(
+ new_layout,
+ ImageLayout::Undefined | ImageLayout::Preinitialized
+ )
+ );
+ debug_assert!(image
+ .format()
+ .unwrap()
+ .aspects()
+ .contains(subresource_range.aspects));
+ debug_assert!(!subresource_range.mip_levels.is_empty());
+ debug_assert!(subresource_range.mip_levels.end <= image.mip_levels());
+ debug_assert!(!subresource_range.array_layers.is_empty());
+ debug_assert!(
+ subresource_range.array_layers.end <= image.dimensions().array_layers()
+ );
+
+ let (src_queue_family_index, dst_queue_family_index) =
+ queue_family_ownership_transfer.map_or(
+ (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED),
+ Into::into,
+ );
+
+ ash::vk::ImageMemoryBarrier2 {
+ src_stage_mask: src_stages.into(),
+ src_access_mask: src_access.into(),
+ dst_stage_mask: dst_stages.into(),
+ dst_access_mask: dst_access.into(),
+ old_layout: old_layout.into(),
+ new_layout: new_layout.into(),
+ src_queue_family_index,
+ dst_queue_family_index,
+ image: image.handle(),
+ subresource_range: subresource_range.clone().into(),
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let dependency_info_vk = ash::vk::DependencyInfo {
+ dependency_flags: dependency_flags.into(),
+ memory_barrier_count: memory_barriers_vk.len() as u32,
+ p_memory_barriers: memory_barriers_vk.as_ptr(),
+ buffer_memory_barrier_count: buffer_memory_barriers_vk.len() as u32,
+ p_buffer_memory_barriers: buffer_memory_barriers_vk.as_ptr(),
+ image_memory_barrier_count: image_memory_barriers_vk.len() as u32,
+ p_image_memory_barriers: image_memory_barriers_vk.as_ptr(),
+ ..Default::default()
+ };
+
+ let fns = self.device.fns();
+
+ if self.device.api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_pipeline_barrier2)(self.handle, &dependency_info_vk);
+ } else {
+ debug_assert!(self.device.enabled_extensions().khr_synchronization2);
+ (fns.khr_synchronization2.cmd_pipeline_barrier2_khr)(
+ self.handle,
+ &dependency_info_vk,
+ );
+ }
+ } else {
+ let mut src_stage_mask = ash::vk::PipelineStageFlags::empty();
+ let mut dst_stage_mask = ash::vk::PipelineStageFlags::empty();
+
+ let memory_barriers_vk: SmallVec<[_; 2]> = memory_barriers
+ .into_iter()
+ .map(|barrier| {
+ let &MemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ _ne: _,
+ } = barrier;
+
+ debug_assert!(AccessFlags::from(src_stages).contains(src_access));
+ debug_assert!(AccessFlags::from(dst_stages).contains(dst_access));
+
+ src_stage_mask |= src_stages.into();
+ dst_stage_mask |= dst_stages.into();
+
+ ash::vk::MemoryBarrier {
+ src_access_mask: src_access.into(),
+ dst_access_mask: dst_access.into(),
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let buffer_memory_barriers_vk: SmallVec<[_; 8]> = buffer_memory_barriers
+ .into_iter()
+ .map(|barrier| {
+ let &BufferMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ queue_family_ownership_transfer,
+ ref buffer,
+ ref range,
+ _ne: _,
+ } = barrier;
+
+ debug_assert!(AccessFlags::from(src_stages).contains(src_access));
+ debug_assert!(AccessFlags::from(dst_stages).contains(dst_access));
+ debug_assert!(!range.is_empty());
+ debug_assert!(range.end <= buffer.size());
+
+ src_stage_mask |= src_stages.into();
+ dst_stage_mask |= dst_stages.into();
+
+ let (src_queue_family_index, dst_queue_family_index) =
+ queue_family_ownership_transfer.map_or(
+ (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED),
+ Into::into,
+ );
+
+ ash::vk::BufferMemoryBarrier {
+ src_access_mask: src_access.into(),
+ dst_access_mask: dst_access.into(),
+ src_queue_family_index,
+ dst_queue_family_index,
+ buffer: buffer.handle(),
+ offset: range.start,
+ size: range.end - range.start,
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let image_memory_barriers_vk: SmallVec<[_; 8]> = image_memory_barriers
+ .into_iter()
+ .map(|barrier| {
+ let &ImageMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ old_layout,
+ new_layout,
+ queue_family_ownership_transfer,
+ ref image,
+ ref subresource_range,
+ _ne: _,
+ } = barrier;
+
+ debug_assert!(AccessFlags::from(src_stages).contains(src_access));
+ debug_assert!(AccessFlags::from(dst_stages).contains(dst_access));
+ debug_assert!(!matches!(
+ new_layout,
+ ImageLayout::Undefined | ImageLayout::Preinitialized
+ ));
+ debug_assert!(image
+ .format()
+ .unwrap()
+ .aspects()
+ .contains(subresource_range.aspects));
+ debug_assert!(!subresource_range.mip_levels.is_empty());
+ debug_assert!(subresource_range.mip_levels.end <= image.mip_levels());
+ debug_assert!(!subresource_range.array_layers.is_empty());
+ debug_assert!(
+ subresource_range.array_layers.end <= image.dimensions().array_layers()
+ );
+
+ src_stage_mask |= src_stages.into();
+ dst_stage_mask |= dst_stages.into();
+
+ let (src_queue_family_index, dst_queue_family_index) =
+ queue_family_ownership_transfer.map_or(
+ (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED),
+ Into::into,
+ );
+
+ ash::vk::ImageMemoryBarrier {
+ src_access_mask: src_access.into(),
+ dst_access_mask: dst_access.into(),
+ old_layout: old_layout.into(),
+ new_layout: new_layout.into(),
+ src_queue_family_index,
+ dst_queue_family_index,
+ image: image.handle(),
+ subresource_range: subresource_range.clone().into(),
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ if src_stage_mask.is_empty() {
+ // "VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT is [...] equivalent to
+ // VK_PIPELINE_STAGE_2_NONE in the first scope."
+ src_stage_mask |= ash::vk::PipelineStageFlags::TOP_OF_PIPE;
+ }
+
+ if dst_stage_mask.is_empty() {
+ // "VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT is [...] equivalent to
+ // VK_PIPELINE_STAGE_2_NONE in the second scope."
+ dst_stage_mask |= ash::vk::PipelineStageFlags::BOTTOM_OF_PIPE;
+ }
+
+ let fns = self.device.fns();
+ (fns.v1_0.cmd_pipeline_barrier)(
+ self.handle,
+ src_stage_mask,
+ dst_stage_mask,
+ dependency_flags.into(),
+ memory_barriers_vk.len() as u32,
+ memory_barriers_vk.as_ptr(),
+ buffer_memory_barriers_vk.len() as u32,
+ buffer_memory_barriers_vk.as_ptr(),
+ image_memory_barriers_vk.len() as u32,
+ image_memory_barriers_vk.as_ptr(),
+ );
+ }
+ }
+
+ /// Calls `vkCmdSetEvent` on the builder.
+ #[inline]
+ pub unsafe fn set_event(&mut self, event: &Event, dependency_info: &DependencyInfo) {
+ let &DependencyInfo {
+ mut dependency_flags,
+ ref memory_barriers,
+ ref buffer_memory_barriers,
+ ref image_memory_barriers,
+ _ne: _,
+ } = dependency_info;
+
+ // TODO: Is this needed?
+ dependency_flags |= DependencyFlags::BY_REGION;
+
+ let fns = self.device.fns();
+
+ if self.device.enabled_features().synchronization2 {
+ let memory_barriers_vk: SmallVec<[_; 2]> = memory_barriers
+ .into_iter()
+ .map(|barrier| {
+ let &MemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ _ne: _,
+ } = barrier;
+
+ ash::vk::MemoryBarrier2 {
+ src_stage_mask: src_stages.into(),
+ src_access_mask: src_access.into(),
+ dst_stage_mask: dst_stages.into(),
+ dst_access_mask: dst_access.into(),
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let buffer_memory_barriers_vk: SmallVec<[_; 8]> = buffer_memory_barriers
+ .into_iter()
+ .map(|barrier| {
+ let &BufferMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ queue_family_ownership_transfer,
+ ref buffer,
+ ref range,
+ _ne: _,
+ } = barrier;
+
+ let (src_queue_family_index, dst_queue_family_index) =
+ queue_family_ownership_transfer.map_or(
+ (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED),
+ Into::into,
+ );
+
+ ash::vk::BufferMemoryBarrier2 {
+ src_stage_mask: src_stages.into(),
+ src_access_mask: src_access.into(),
+ dst_stage_mask: dst_stages.into(),
+ dst_access_mask: dst_access.into(),
+ src_queue_family_index,
+ dst_queue_family_index,
+ buffer: buffer.handle(),
+ offset: range.start,
+ size: range.end - range.start,
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let image_memory_barriers_vk: SmallVec<[_; 8]> = image_memory_barriers
+ .into_iter()
+ .map(|barrier| {
+ let &ImageMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ old_layout,
+ new_layout,
+ queue_family_ownership_transfer,
+ ref image,
+ ref subresource_range,
+ _ne: _,
+ } = barrier;
+
+ let (src_queue_family_index, dst_queue_family_index) =
+ queue_family_ownership_transfer.map_or(
+ (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED),
+ Into::into,
+ );
+
+ ash::vk::ImageMemoryBarrier2 {
+ src_stage_mask: src_stages.into(),
+ src_access_mask: src_access.into(),
+ dst_stage_mask: dst_stages.into(),
+ dst_access_mask: dst_access.into(),
+ old_layout: old_layout.into(),
+ new_layout: new_layout.into(),
+ src_queue_family_index,
+ dst_queue_family_index,
+ image: image.handle(),
+ subresource_range: subresource_range.clone().into(),
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let dependency_info_vk = ash::vk::DependencyInfo {
+ dependency_flags: dependency_flags.into(),
+ memory_barrier_count: memory_barriers_vk.len() as u32,
+ p_memory_barriers: memory_barriers_vk.as_ptr(),
+ buffer_memory_barrier_count: buffer_memory_barriers_vk.len() as u32,
+ p_buffer_memory_barriers: buffer_memory_barriers_vk.as_ptr(),
+ image_memory_barrier_count: image_memory_barriers_vk.len() as u32,
+ p_image_memory_barriers: image_memory_barriers_vk.as_ptr(),
+ ..Default::default()
+ };
+
+ if self.device.api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_set_event2)(self.handle, event.handle(), &dependency_info_vk);
+ } else {
+ debug_assert!(self.device.enabled_extensions().khr_synchronization2);
+ (fns.khr_synchronization2.cmd_set_event2_khr)(
+ self.handle,
+ event.handle(),
+ &dependency_info_vk,
+ );
+ }
+ } else {
+ // The original function only takes a source stage mask; the rest of the info is
+ // provided with `wait_events` instead. Therefore, we condense the source stages
+ // here and ignore the rest.
+
+ let mut stage_mask = ash::vk::PipelineStageFlags::empty();
+
+ for barrier in memory_barriers {
+ stage_mask |= barrier.src_stages.into();
+ }
+
+ for barrier in buffer_memory_barriers {
+ stage_mask |= barrier.src_stages.into();
+ }
+
+ for barrier in image_memory_barriers {
+ stage_mask |= barrier.src_stages.into();
+ }
+
+ if stage_mask.is_empty() {
+ // "VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT is [...] equivalent to
+ // VK_PIPELINE_STAGE_2_NONE in the first scope."
+ stage_mask |= ash::vk::PipelineStageFlags::TOP_OF_PIPE;
+ }
+
+ (fns.v1_0.cmd_set_event)(self.handle, event.handle(), stage_mask);
+ }
+ }
+
+ /// Calls `vkCmdWaitEvents` on the builder.
+ pub unsafe fn wait_events<'a>(
+ &mut self,
+ events: impl IntoIterator<Item = (&'a Event, &'a DependencyInfo)>,
+ ) {
+ let fns = self.device.fns();
+
+ if self.device.enabled_features().synchronization2 {
+ struct PerDependencyInfo {
+ memory_barriers_vk: SmallVec<[ash::vk::MemoryBarrier2; 2]>,
+ buffer_memory_barriers_vk: SmallVec<[ash::vk::BufferMemoryBarrier2; 8]>,
+ image_memory_barriers_vk: SmallVec<[ash::vk::ImageMemoryBarrier2; 8]>,
+ }
+
+ let mut events_vk: SmallVec<[_; 4]> = SmallVec::new();
+ let mut dependency_infos_vk: SmallVec<[_; 4]> = SmallVec::new();
+ let mut per_dependency_info_vk: SmallVec<[_; 4]> = SmallVec::new();
+
+ for (event, dependency_info) in events {
+ let &DependencyInfo {
+ mut dependency_flags,
+ ref memory_barriers,
+ ref buffer_memory_barriers,
+ ref image_memory_barriers,
+ _ne: _,
+ } = dependency_info;
+
+ // TODO: Is this needed?
+ dependency_flags |= DependencyFlags::BY_REGION;
+
+ let memory_barriers_vk: SmallVec<[_; 2]> = memory_barriers
+ .into_iter()
+ .map(|barrier| {
+ let &MemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ _ne: _,
+ } = barrier;
+
+ ash::vk::MemoryBarrier2 {
+ src_stage_mask: src_stages.into(),
+ src_access_mask: src_access.into(),
+ dst_stage_mask: dst_stages.into(),
+ dst_access_mask: dst_access.into(),
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let buffer_memory_barriers_vk: SmallVec<[_; 8]> = buffer_memory_barriers
+ .into_iter()
+ .map(|barrier| {
+ let &BufferMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ queue_family_ownership_transfer,
+ ref buffer,
+ ref range,
+ _ne: _,
+ } = barrier;
+
+ let (src_queue_family_index, dst_queue_family_index) =
+ queue_family_ownership_transfer.map_or(
+ (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED),
+ Into::into,
+ );
+
+ ash::vk::BufferMemoryBarrier2 {
+ src_stage_mask: src_stages.into(),
+ src_access_mask: src_access.into(),
+ dst_stage_mask: dst_stages.into(),
+ dst_access_mask: dst_access.into(),
+ src_queue_family_index,
+ dst_queue_family_index,
+ buffer: buffer.handle(),
+ offset: range.start,
+ size: range.end - range.start,
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let image_memory_barriers_vk: SmallVec<[_; 8]> = image_memory_barriers
+ .into_iter()
+ .map(|barrier| {
+ let &ImageMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ old_layout,
+ new_layout,
+ queue_family_ownership_transfer,
+ ref image,
+ ref subresource_range,
+ _ne: _,
+ } = barrier;
+
+ let (src_queue_family_index, dst_queue_family_index) =
+ queue_family_ownership_transfer.map_or(
+ (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED),
+ Into::into,
+ );
+
+ ash::vk::ImageMemoryBarrier2 {
+ src_stage_mask: src_stages.into(),
+ src_access_mask: src_access.into(),
+ dst_stage_mask: dst_stages.into(),
+ dst_access_mask: dst_access.into(),
+ old_layout: old_layout.into(),
+ new_layout: new_layout.into(),
+ src_queue_family_index,
+ dst_queue_family_index,
+ image: image.handle(),
+ subresource_range: subresource_range.clone().into(),
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ events_vk.push(event.handle());
+ dependency_infos_vk.push(ash::vk::DependencyInfo {
+ dependency_flags: dependency_flags.into(),
+ memory_barrier_count: 0,
+ p_memory_barriers: ptr::null(),
+ buffer_memory_barrier_count: 0,
+ p_buffer_memory_barriers: ptr::null(),
+ image_memory_barrier_count: 0,
+ p_image_memory_barriers: ptr::null(),
+ ..Default::default()
+ });
+ per_dependency_info_vk.push(PerDependencyInfo {
+ memory_barriers_vk,
+ buffer_memory_barriers_vk,
+ image_memory_barriers_vk,
+ });
+ }
+
+ for (
+ dependency_info_vk,
+ PerDependencyInfo {
+ memory_barriers_vk,
+ buffer_memory_barriers_vk,
+ image_memory_barriers_vk,
+ },
+ ) in (dependency_infos_vk.iter_mut()).zip(per_dependency_info_vk.iter_mut())
+ {
+ *dependency_info_vk = ash::vk::DependencyInfo {
+ memory_barrier_count: memory_barriers_vk.len() as u32,
+ p_memory_barriers: memory_barriers_vk.as_ptr(),
+ buffer_memory_barrier_count: buffer_memory_barriers_vk.len() as u32,
+ p_buffer_memory_barriers: buffer_memory_barriers_vk.as_ptr(),
+ image_memory_barrier_count: image_memory_barriers_vk.len() as u32,
+ p_image_memory_barriers: image_memory_barriers_vk.as_ptr(),
+ ..*dependency_info_vk
+ }
+ }
+
+ if self.device.api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_wait_events2)(
+ self.handle,
+ events_vk.len() as u32,
+ events_vk.as_ptr(),
+ dependency_infos_vk.as_ptr(),
+ );
+ } else {
+ debug_assert!(self.device.enabled_extensions().khr_synchronization2);
+ (fns.khr_synchronization2.cmd_wait_events2_khr)(
+ self.handle,
+ events_vk.len() as u32,
+ events_vk.as_ptr(),
+ dependency_infos_vk.as_ptr(),
+ );
+ }
+ } else {
+ // With the original function, you can only specify a single dependency info for all
+ // events at once, rather than separately for each event. Therefore, to achieve the
+ // same behaviour as the "2" function, we split it up into multiple Vulkan API calls,
+ // one per event.
+
+ for (event, dependency_info) in events {
+ let events_vk = [event.handle()];
+
+ let &DependencyInfo {
+ dependency_flags: _,
+ ref memory_barriers,
+ ref buffer_memory_barriers,
+ ref image_memory_barriers,
+ _ne: _,
+ } = dependency_info;
+
+ let mut src_stage_mask = ash::vk::PipelineStageFlags::empty();
+ let mut dst_stage_mask = ash::vk::PipelineStageFlags::empty();
+
+ let memory_barriers_vk: SmallVec<[_; 2]> = memory_barriers
+ .into_iter()
+ .map(|barrier| {
+ let &MemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ _ne: _,
+ } = barrier;
+
+ src_stage_mask |= src_stages.into();
+ dst_stage_mask |= dst_stages.into();
+
+ ash::vk::MemoryBarrier {
+ src_access_mask: src_access.into(),
+ dst_access_mask: dst_access.into(),
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let buffer_memory_barriers_vk: SmallVec<[_; 8]> = buffer_memory_barriers
+ .into_iter()
+ .map(|barrier| {
+ let &BufferMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ queue_family_ownership_transfer,
+ ref buffer,
+ ref range,
+ _ne: _,
+ } = barrier;
+
+ src_stage_mask |= src_stages.into();
+ dst_stage_mask |= dst_stages.into();
+
+ let (src_queue_family_index, dst_queue_family_index) =
+ queue_family_ownership_transfer.map_or(
+ (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED),
+ Into::into,
+ );
+
+ ash::vk::BufferMemoryBarrier {
+ src_access_mask: src_access.into(),
+ dst_access_mask: dst_access.into(),
+ src_queue_family_index,
+ dst_queue_family_index,
+ buffer: buffer.handle(),
+ offset: range.start,
+ size: range.end - range.start,
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let image_memory_barriers_vk: SmallVec<[_; 8]> = image_memory_barriers
+ .into_iter()
+ .map(|barrier| {
+ let &ImageMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ old_layout,
+ new_layout,
+ queue_family_ownership_transfer,
+ ref image,
+ ref subresource_range,
+ _ne: _,
+ } = barrier;
+
+ src_stage_mask |= src_stages.into();
+ dst_stage_mask |= dst_stages.into();
+
+ let (src_queue_family_index, dst_queue_family_index) =
+ queue_family_ownership_transfer.map_or(
+ (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED),
+ Into::into,
+ );
+
+ ash::vk::ImageMemoryBarrier {
+ src_access_mask: src_access.into(),
+ dst_access_mask: dst_access.into(),
+ old_layout: old_layout.into(),
+ new_layout: new_layout.into(),
+ src_queue_family_index,
+ dst_queue_family_index,
+ image: image.handle(),
+ subresource_range: subresource_range.clone().into(),
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ if src_stage_mask.is_empty() {
+ // "VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT is [...] equivalent to
+ // VK_PIPELINE_STAGE_2_NONE in the first scope."
+ src_stage_mask |= ash::vk::PipelineStageFlags::TOP_OF_PIPE;
+ }
+
+ if dst_stage_mask.is_empty() {
+ // "VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT is [...] equivalent to
+ // VK_PIPELINE_STAGE_2_NONE in the second scope."
+ dst_stage_mask |= ash::vk::PipelineStageFlags::BOTTOM_OF_PIPE;
+ }
+
+ (fns.v1_0.cmd_wait_events)(
+ self.handle,
+ 1,
+ events_vk.as_ptr(),
+ src_stage_mask,
+ dst_stage_mask,
+ memory_barriers_vk.len() as u32,
+ memory_barriers_vk.as_ptr(),
+ buffer_memory_barriers_vk.len() as u32,
+ buffer_memory_barriers_vk.as_ptr(),
+ image_memory_barriers_vk.len() as u32,
+ image_memory_barriers_vk.as_ptr(),
+ );
+ }
+ }
+ }
+
+ /// Calls `vkCmdResetEvent` on the builder.
+ #[inline]
+ pub unsafe fn reset_event(&mut self, event: &Event, stages: PipelineStages) {
+ debug_assert!(!stages.intersects(PipelineStages::HOST));
+ debug_assert_ne!(stages, PipelineStages::empty());
+
+ let fns = self.device.fns();
+
+ if self.device.enabled_features().synchronization2 {
+ if self.device.api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_reset_event2)(self.handle, event.handle(), stages.into());
+ } else {
+ debug_assert!(self.device.enabled_extensions().khr_synchronization2);
+ (fns.khr_synchronization2.cmd_reset_event2_khr)(
+ self.handle,
+ event.handle(),
+ stages.into(),
+ );
+ }
+ } else {
+ (fns.v1_0.cmd_reset_event)(self.handle, event.handle(), stages.into());
+ }
+ }
+
+ // TODO: wait_event
+}
diff --git a/src/command_buffer/mod.rs b/src/command_buffer/mod.rs
index b439a4d..5808d51 100644
--- a/src/command_buffer/mod.rs
+++ b/src/command_buffer/mod.rs
@@ -7,141 +7,161 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-//! Commands that the GPU will execute (includes draw commands).
+//! Recording commands to execute on the device.
//!
-//! With Vulkan, before the GPU can do anything you must create a `CommandBuffer`. A command buffer
-//! is a list of commands that will executed by the GPU. Once a command buffer is created, you can
-//! execute it. A command buffer must always be created even for the most simple tasks.
+//! With Vulkan, to get the device to perform work, even relatively simple tasks, you must create a
+//! command buffer. A command buffer is a list of commands that will executed by the device.
+//! You must first record commands to a command buffer builder, then build it into an actual
+//! command buffer, and then it can be used. Depending on how a command buffer is created, it can
+//! be used only once, or reused many times.
//!
-//! # Primary and secondary command buffers.
+//! # Command pools and allocators
//!
-//! There are three types of command buffers:
+//! Command buffers are allocated from *command pools*. A command pool holds memory that is used to
+//! record the sequence of commands in a command buffer. Command pools are not thread-safe, and
+//! therefore commands cannot be recorded to a single command buffer from multiple threads at a
+//! time.
//!
-//! - **Primary command buffers**. They can contain any command. They are the only type of command
-//! buffer that can be submitted to a queue.
-//! - **Secondary "graphics" command buffers**. They can only contain draw and clear commands.
-//! They can only be called from a primary command buffer when inside a render pass.
-//! - **Secondary "compute" command buffers**. They can only contain non-render-pass-related
-//! commands (ie. everything but drawing, clearing, etc.) and cannot enter a render pass. They
-//! can only be called from a primary command buffer outside of a render pass.
+//! Raw command pools are unsafe to use, so Vulkano uses [command buffer allocators] to manage
+//! command buffers and pools, to ensure their memory is used efficiently, and to protect against
+//! invalid usage. Vulkano provides the [`StandardCommandBufferAllocator`] for this purpose, but
+//! you can also create your own by implementing the [`CommandBufferAllocator`] trait.
//!
-//! Using secondary command buffers leads to slightly lower performance on the GPU, but they have
-//! two advantages on the CPU side:
+//! # Primary and secondary command buffers
//!
-//! - Building a command buffer is a single-threaded operation, but by using secondary command
-//! buffers you can build multiple secondary command buffers in multiple threads simultaneously.
-//! - Secondary command buffers can be kept alive between frames. When you always repeat the same
-//! operations, it might be a good idea to build a secondary command buffer once at
-//! initialization and then reuse it afterwards.
+//! There are two levels of command buffers:
//!
-//! # The `AutoCommandBufferBuilder`
+//! - [`PrimaryCommandBufferAbstract`] can be executed on a queue, and is the main command buffer
+//! type. It cannot be executed within another command buffer.
+//! - [`SecondaryCommandBufferAbstract`] can only be executed within a primary command buffer,
+//! not directly on a queue.
//!
-//! The most basic (and recommended) way to create a command buffer is to create a
-//! [`AutoCommandBufferBuilder`](struct.AutoCommandBufferBuilder.html), then record commands to it.
-//! When you are done adding commands, build it to obtain either a `PrimaryAutoCommandBuffer` or
-//! `SecondAutoCommandBuffer`.
+//! Using secondary command buffers, there is slightly more overhead than using primary command
+//! buffers alone, but there are also advantages. A single command buffer cannot be recorded
+//! from multiple threads at a time, so if you want to divide the recording work among several
+//! threads, each thread must record its own command buffer. While it is possible for these to be
+//! all primary command buffers, there are limitations: a render pass or query cannot span multiple
+//! primary command buffers, while secondary command buffers can [inherit] this state from their
+//! parent primary command buffer. Therefore, to have a single render pass or query that is shared
+//! across all the command buffers, you must record secondary command buffers.
//!
-//! Once built, use [the `PrimaryCommandBuffer` trait](trait.PrimaryCommandBuffer.html) to submit the
-//! command buffer. Submitting a command buffer returns an object that implements the `GpuFuture` trait
-//! and that represents the moment when the execution will end on the GPU.
+//! # Recording a command buffer
+//!
+//! To record a new command buffer, the most direct way is to create a new
+//! [`AutoCommandBufferBuilder`]. You can then call methods on this object to record new commands to
+//! the command buffer. When you are done recording, you call [`build`] to finalise the command
+//! buffer and turn it into either a [`PrimaryCommandBufferAbstract`] or a
+//! [`SecondaryCommandBufferAbstract`].
+//!
+// //! Using the standard `CommandBufferBuilder`, you must enter synchronization commands such as
+// //! [pipeline barriers], to ensure that there are no races and memory access hazards. This can be
+// //! difficult to do manually, so Vulkano also provides an alternative builder,
+// //! [`AutoCommandBufferBuilder`]. Using this builder, you do not have to worry about managing
+// //! synchronization, but the end result may not be quite as efficient.
+//!
+//! # Submitting a primary command buffer
+//!
+//! Once primary a command buffer is recorded and built, you can use the
+//! [`PrimaryCommandBufferAbstract`] trait to submit the command buffer to a queue. Submitting a
+//! command buffer returns an object that implements the [`GpuFuture`] trait and that represents
+//! the moment when the execution will end on the GPU.
//!
//! ```
//! use vulkano::command_buffer::AutoCommandBufferBuilder;
//! use vulkano::command_buffer::CommandBufferUsage;
-//! use vulkano::command_buffer::PrimaryCommandBuffer;
+//! use vulkano::command_buffer::PrimaryCommandBufferAbstract;
+//! use vulkano::command_buffer::SubpassContents;
+//!
+//! # use vulkano::{buffer::BufferContents, pipeline::graphics::vertex_input::Vertex};
//!
+//! # #[derive(BufferContents, Vertex)]
+//! # #[repr(C)]
+//! # struct PosVertex {
+//! # #[format(R32G32B32_SFLOAT)]
+//! # position: [f32; 3]
+//! # };
//! # let device: std::sync::Arc<vulkano::device::Device> = return;
//! # let queue: std::sync::Arc<vulkano::device::Queue> = return;
+//! # let vertex_buffer: vulkano::buffer::Subbuffer<[PosVertex]> = return;
+//! # let render_pass_begin_info: vulkano::command_buffer::RenderPassBeginInfo = return;
+//! # let graphics_pipeline: std::sync::Arc<vulkano::pipeline::graphics::GraphicsPipeline> = return;
+//! # let command_buffer_allocator: vulkano::command_buffer::allocator::StandardCommandBufferAllocator = return;
//! let cb = AutoCommandBufferBuilder::primary(
-//! device.clone(),
-//! queue.family(),
+//! &command_buffer_allocator,
+//! queue.queue_family_index(),
//! CommandBufferUsage::MultipleSubmit
//! ).unwrap()
-//! // TODO: add an actual command to this example
+//! .begin_render_pass(render_pass_begin_info, SubpassContents::Inline).unwrap()
+//! .bind_pipeline_graphics(graphics_pipeline.clone())
+//! .bind_vertex_buffers(0, vertex_buffer.clone())
+//! .draw(vertex_buffer.len() as u32, 1, 0, 0).unwrap()
+//! .end_render_pass().unwrap()
//! .build().unwrap();
//!
//! let _future = cb.execute(queue.clone());
//! ```
//!
-//! # Internal architecture of vulkano
-//!
-//! The `commands_raw` and `commands_extra` modules contain structs that correspond to various
-//! commands that can be added to command buffer builders. A command can be added to a command
-//! buffer builder by using the `AddCommand<C>` trait, where `C` is the command struct.
-//!
-//! The `AutoCommandBufferBuilder` internally uses a `UnsafeCommandBufferBuilder` wrapped around
-//! multiple layers. See the `cb` module for more information.
-//!
-//! Command pools are automatically handled by default, but vulkano also allows you to use
-//! alternative command pool implementations and use them. See the `pool` module for more
-//! information.
-
-pub use self::auto::AutoCommandBufferBuilder;
-pub use self::auto::AutoCommandBufferBuilderContextError;
-pub use self::auto::BeginError;
-pub use self::auto::BeginQueryError;
-pub use self::auto::BeginRenderPassError;
-pub use self::auto::BlitImageError;
-pub use self::auto::BuildError;
-pub use self::auto::ClearColorImageError;
-pub use self::auto::CopyBufferError;
-pub use self::auto::CopyBufferImageError;
-pub use self::auto::CopyImageError;
-pub use self::auto::CopyQueryPoolResultsError;
-pub use self::auto::DebugMarkerError;
-pub use self::auto::DispatchError;
-pub use self::auto::DispatchIndirectError;
-pub use self::auto::DrawError;
-pub use self::auto::DrawIndexedError;
-pub use self::auto::DrawIndexedIndirectError;
-pub use self::auto::DrawIndirectError;
-pub use self::auto::EndQueryError;
-pub use self::auto::ExecuteCommandsError;
-pub use self::auto::FillBufferError;
-pub use self::auto::PrimaryAutoCommandBuffer;
-pub use self::auto::ResetQueryPoolError;
-pub use self::auto::SecondaryAutoCommandBuffer;
-pub use self::auto::UpdateBufferError;
-pub use self::auto::WriteTimestampError;
-pub use self::state_cacher::StateCacher;
-pub use self::state_cacher::StateCacherOutcome;
-pub use self::traits::CommandBufferExecError;
-pub use self::traits::CommandBufferExecFuture;
-pub use self::traits::PrimaryCommandBuffer;
-pub use self::traits::SecondaryCommandBuffer;
-use crate::pipeline::depth_stencil::DynamicStencilValue;
-use crate::pipeline::viewport::{Scissor, Viewport};
-use crate::query::QueryControlFlags;
-use crate::query::QueryPipelineStatisticFlags;
-use crate::render_pass::{Framebuffer, Subpass};
-use std::sync::Arc;
+//! [`StandardCommandBufferAllocator`]: self::allocator::StandardCommandBufferAllocator
+//! [`CommandBufferAllocator`]: self::allocator::CommandBufferAllocator
+//! [inherit]: CommandBufferInheritanceInfo
+//! [`build`]: CommandBufferBuilder::build
+//! [pipeline barriers]: CommandBufferBuilder::pipeline_barrier
+//! [`GpuFuture`]: crate::sync::GpuFuture
+#[doc(no_inline)]
+pub(crate) use self::standard::{PrimaryCommandBuffer, SecondaryCommandBuffer};
+pub use self::{
+ auto::{
+ AutoCommandBufferBuilder, BuildError, CommandBufferBeginError, PrimaryAutoCommandBuffer,
+ SecondaryAutoCommandBuffer,
+ },
+ commands::{
+ clear::{ClearColorImageInfo, ClearDepthStencilImageInfo, ClearError},
+ copy::{
+ BlitImageInfo, BufferCopy, BufferImageCopy, CopyBufferInfo, CopyBufferInfoTyped,
+ CopyBufferToImageInfo, CopyError, CopyErrorResource, CopyImageInfo,
+ CopyImageToBufferInfo, ImageBlit, ImageCopy, ImageResolve, ResolveImageInfo,
+ },
+ debug::DebugUtilsError,
+ pipeline::PipelineExecutionError,
+ query::QueryError,
+ render_pass::{
+ ClearAttachment, ClearRect, RenderPassBeginInfo, RenderPassError,
+ RenderingAttachmentInfo, RenderingAttachmentResolveInfo, RenderingInfo,
+ },
+ secondary::ExecuteCommandsError,
+ },
+ traits::{
+ CommandBufferExecError, CommandBufferExecFuture, PrimaryCommandBufferAbstract,
+ SecondaryCommandBufferAbstract,
+ },
+};
+use crate::{
+ buffer::{Buffer, Subbuffer},
+ format::Format,
+ image::{sys::Image, ImageAccess, ImageLayout, ImageSubresourceRange, SampleCount},
+ macros::vulkan_enum,
+ query::{QueryControlFlags, QueryPipelineStatisticFlags},
+ range_map::RangeMap,
+ render_pass::{Framebuffer, Subpass},
+ sync::{semaphore::Semaphore, PipelineMemoryAccess, PipelineStages},
+ DeviceSize,
+};
+use ahash::HashMap;
+use bytemuck::{Pod, Zeroable};
+use std::{ops::Range, sync::Arc};
+
+pub mod allocator;
mod auto;
+mod commands;
pub mod pool;
-mod state_cacher;
-pub mod submit;
+pub(crate) mod standard;
pub mod synced;
pub mod sys;
mod traits;
-pub mod validity;
-
-#[derive(Debug, Clone, Copy)]
-pub enum ImageUninitializedSafe {
- Safe,
- Unsafe,
-}
-
-impl ImageUninitializedSafe {
- pub fn is_safe(&self) -> bool {
- match self {
- Self::Safe => true,
- Self::Unsafe => false,
- }
- }
-}
#[repr(C)]
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+#[derive(Clone, Copy, Debug, Default, Zeroable, Pod, PartialEq, Eq)]
pub struct DrawIndirectCommand {
pub vertex_count: u32,
pub instance_count: u32,
@@ -150,7 +170,7 @@ pub struct DrawIndirectCommand {
}
#[repr(C)]
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+#[derive(Clone, Copy, Debug, Default, Zeroable, Pod, PartialEq, Eq)]
pub struct DrawIndexedIndirectCommand {
pub index_count: u32,
pub instance_count: u32,
@@ -160,84 +180,60 @@ pub struct DrawIndexedIndirectCommand {
}
#[repr(C)]
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+#[derive(Clone, Copy, Debug, Default, Zeroable, Pod, PartialEq, Eq)]
pub struct DispatchIndirectCommand {
pub x: u32,
pub y: u32,
pub z: u32,
}
-/// The dynamic state to use for a draw command.
-// TODO: probably not the right location
-#[derive(Debug, Clone)]
-pub struct DynamicState {
- pub line_width: Option<f32>,
- pub viewports: Option<Vec<Viewport>>,
- pub scissors: Option<Vec<Scissor>>,
- pub compare_mask: Option<DynamicStencilValue>,
- pub write_mask: Option<DynamicStencilValue>,
- pub reference: Option<DynamicStencilValue>,
-}
+vulkan_enum! {
+ #[non_exhaustive]
-impl DynamicState {
- #[inline]
- pub fn none() -> DynamicState {
- DynamicState {
- line_width: None,
- viewports: None,
- scissors: None,
- compare_mask: None,
- write_mask: None,
- reference: None,
- }
- }
-}
-
-impl Default for DynamicState {
- #[inline]
- fn default() -> DynamicState {
- DynamicState::none()
- }
-}
+ /// Describes what a subpass in a command buffer will contain.
+ SubpassContents = SubpassContents(i32);
-/// Describes what a subpass in a command buffer will contain.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-#[repr(i32)]
-pub enum SubpassContents {
/// The subpass will only directly contain commands.
- Inline = ash::vk::SubpassContents::INLINE.as_raw(),
+ Inline = INLINE,
+
/// The subpass will only contain secondary command buffers invocations.
- SecondaryCommandBuffers = ash::vk::SubpassContents::SECONDARY_COMMAND_BUFFERS.as_raw(),
+ SecondaryCommandBuffers = SECONDARY_COMMAND_BUFFERS,
}
-impl From<SubpassContents> for ash::vk::SubpassContents {
+impl From<SubpassContents> for ash::vk::RenderingFlags {
#[inline]
fn from(val: SubpassContents) -> Self {
- Self::from_raw(val as i32)
+ match val {
+ SubpassContents::Inline => Self::empty(),
+ SubpassContents::SecondaryCommandBuffers => Self::CONTENTS_SECONDARY_COMMAND_BUFFERS,
+ }
}
}
-/// Determines the kind of command buffer to create.
-#[derive(Debug, Clone)]
-pub enum CommandBufferLevel<F> {
+vulkan_enum! {
+ /// Determines the kind of command buffer to create.
+ CommandBufferLevel = CommandBufferLevel(i32);
+
/// Primary command buffers can be executed on a queue, and can call secondary command buffers.
/// Render passes must begin and end within the same primary command buffer.
- Primary,
+ Primary = PRIMARY,
/// Secondary command buffers cannot be executed on a queue, but can be executed by a primary
/// command buffer. If created for a render pass, they must fit within a single render subpass.
- Secondary(CommandBufferInheritance<F>),
+ Secondary = SECONDARY,
}
/// The context that a secondary command buffer can inherit from the primary command
/// buffer it's executed in.
-#[derive(Clone, Debug, Default)]
-pub struct CommandBufferInheritance<F> {
- /// If `Some`, the secondary command buffer is required to be executed within a specific
- /// render subpass, and can only call draw operations.
- /// If `None`, it must be executed outside a render pass, and can execute dispatch and transfer
- /// operations, but not drawing operations.
- render_pass: Option<CommandBufferInheritanceRenderPass<F>>,
+#[derive(Clone, Debug)]
+pub struct CommandBufferInheritanceInfo {
+ /// If `Some`, the secondary command buffer is required to be executed within a render pass
+ /// instance, and can only call draw operations.
+ /// If `None`, it must be executed outside a render pass instance, and can execute dispatch and
+ /// transfer operations, but not drawing operations.
+ ///
+ /// The default value is `None`.
+ pub render_pass: Option<CommandBufferInheritanceRenderPassType>,
/// If `Some`, the secondary command buffer is allowed to be executed within a primary that has
/// an occlusion query active. The inner `QueryControlFlags` specifies which flags the
@@ -246,53 +242,156 @@ pub struct CommandBufferInheritance<F> {
/// secondary command buffer is executed.
///
/// The `inherited_queries` feature must be enabled if this is `Some`.
- occlusion_query: Option<QueryControlFlags>,
+ ///
+ /// The default value is `None`.
+ pub occlusion_query: Option<QueryControlFlags>,
/// Which pipeline statistics queries are allowed to be active on the primary command buffer
/// when this secondary command buffer is executed.
///
- /// The `pipeline_statistics_query` feature must be enabled if any of the flags of this value
- /// are set.
- query_statistics_flags: QueryPipelineStatisticFlags,
+ /// If this value is not empty, the [`pipeline_statistics_query`] feature must be enabled on
+ /// the device.
+ ///
+ /// The default value is [`QueryPipelineStatisticFlags::empty()`].
+ ///
+ /// [`pipeline_statistics_query`]: crate::device::Features::pipeline_statistics_query
+ pub query_statistics_flags: QueryPipelineStatisticFlags,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for CommandBufferInheritanceInfo {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ render_pass: None,
+ occlusion_query: None,
+ query_statistics_flags: QueryPipelineStatisticFlags::empty(),
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// Selects the type of render pass for command buffer inheritance.
+#[derive(Clone, Debug)]
+pub enum CommandBufferInheritanceRenderPassType {
+ /// The secondary command buffer will be executed within a render pass begun with
+ /// `begin_render_pass`, using a `RenderPass` object and `Framebuffer`.
+ BeginRenderPass(CommandBufferInheritanceRenderPassInfo),
+
+ /// The secondary command buffer will be executed within a render pass begun with
+ /// `begin_rendering`, using dynamic rendering.
+ BeginRendering(CommandBufferInheritanceRenderingInfo),
+}
+
+impl From<Subpass> for CommandBufferInheritanceRenderPassType {
+ #[inline]
+ fn from(val: Subpass) -> Self {
+ Self::BeginRenderPass(val.into())
+ }
+}
+
+impl From<CommandBufferInheritanceRenderPassInfo> for CommandBufferInheritanceRenderPassType {
+ #[inline]
+ fn from(val: CommandBufferInheritanceRenderPassInfo) -> Self {
+ Self::BeginRenderPass(val)
+ }
+}
+
+impl From<CommandBufferInheritanceRenderingInfo> for CommandBufferInheritanceRenderPassType {
+ #[inline]
+ fn from(val: CommandBufferInheritanceRenderingInfo) -> Self {
+ Self::BeginRendering(val)
+ }
}
/// The render pass context that a secondary command buffer is created for.
-#[derive(Debug, Clone)]
-pub struct CommandBufferInheritanceRenderPass<F> {
+#[derive(Clone, Debug)]
+pub struct CommandBufferInheritanceRenderPassInfo {
/// The render subpass that this secondary command buffer must be executed within.
+ ///
+ /// There is no default value.
pub subpass: Subpass,
/// The framebuffer object that will be used when calling the command buffer.
/// This parameter is optional and is an optimization hint for the implementation.
- pub framebuffer: Option<F>,
+ ///
+ /// The default value is `None`.
+ pub framebuffer: Option<Arc<Framebuffer>>,
}
-impl CommandBufferLevel<Framebuffer<()>> {
- /// Equivalent to `Kind::Primary`.
- ///
- /// > **Note**: If you use `let kind = Kind::Primary;` in your code, you will probably get a
- /// > compilation error because the Rust compiler couldn't determine the template parameters
- /// > of `Kind`. To solve that problem in an easy way you can use this function instead.
+impl CommandBufferInheritanceRenderPassInfo {
+ /// Returns a `CommandBufferInheritanceRenderPassInfo` with the specified `subpass`.
#[inline]
- pub fn primary() -> CommandBufferLevel<Arc<Framebuffer<()>>> {
- CommandBufferLevel::Primary
+ pub fn subpass(subpass: Subpass) -> Self {
+ Self {
+ subpass,
+ framebuffer: None,
+ }
}
+}
+
+impl From<Subpass> for CommandBufferInheritanceRenderPassInfo {
+ #[inline]
+ fn from(subpass: Subpass) -> Self {
+ Self {
+ subpass,
+ framebuffer: None,
+ }
+ }
+}
+
+/// The dynamic rendering context that a secondary command buffer is created for.
+#[derive(Clone, Debug)]
+pub struct CommandBufferInheritanceRenderingInfo {
+ /// If not `0`, indicates that multiview rendering will be enabled, and specifies the view
+ /// indices that are rendered to. The value is a bitmask, so that that for example `0b11` will
+ /// draw to the first two views and `0b101` will draw to the first and third view.
+ ///
+ /// If set to a nonzero value, then the [`multiview`] feature must be enabled on the device.
+ ///
+ /// The default value is `0`.
+ ///
+ /// [`multiview`]: crate::device::Features::multiview
+ pub view_mask: u32,
+
+ /// The formats of the color attachments that will be used during rendering.
+ ///
+ /// If an element is `None`, it indicates that the attachment will not be used.
+ ///
+ /// The default value is empty.
+ pub color_attachment_formats: Vec<Option<Format>>,
+
+ /// The format of the depth attachment that will be used during rendering.
+ ///
+ /// If set to `None`, it indicates that no depth attachment will be used.
+ ///
+ /// The default value is `None`.
+ pub depth_attachment_format: Option<Format>,
- /// Equivalent to `Kind::Secondary`.
+ /// The format of the stencil attachment that will be used during rendering.
///
- /// > **Note**: If you use `let kind = Kind::Secondary;` in your code, you will probably get a
- /// > compilation error because the Rust compiler couldn't determine the template parameters
- /// > of `Kind`. To solve that problem in an easy way you can use this function instead.
+ /// If set to `None`, it indicates that no stencil attachment will be used.
+ ///
+ /// The default value is `None`.
+ pub stencil_attachment_format: Option<Format>,
+
+ /// The number of samples that the color, depth and stencil attachments will have.
+ ///
+ /// The default value is [`SampleCount::Sample1`]
+ pub rasterization_samples: SampleCount,
+}
+
+impl Default for CommandBufferInheritanceRenderingInfo {
#[inline]
- pub fn secondary(
- occlusion_query: Option<QueryControlFlags>,
- query_statistics_flags: QueryPipelineStatisticFlags,
- ) -> CommandBufferLevel<Arc<Framebuffer<()>>> {
- CommandBufferLevel::Secondary(CommandBufferInheritance {
- render_pass: None,
- occlusion_query,
- query_statistics_flags,
- })
+ fn default() -> Self {
+ Self {
+ view_mask: 0,
+ color_attachment_formats: Vec::new(),
+ depth_attachment_format: None,
+ stencil_attachment_format: None,
+ rasterization_samples: SampleCount::Sample1,
+ }
}
}
@@ -324,3 +423,213 @@ impl From<CommandBufferUsage> for ash::vk::CommandBufferUsageFlags {
Self::from_raw(val as u32)
}
}
+
+/// Parameters to submit command buffers to a queue.
+#[derive(Clone, Debug)]
+pub struct SubmitInfo {
+ /// The semaphores to wait for before beginning the execution of this batch of
+ /// command buffer operations.
+ ///
+ /// The default value is empty.
+ pub wait_semaphores: Vec<SemaphoreSubmitInfo>,
+
+ /// The command buffers to execute.
+ ///
+ /// The default value is empty.
+ pub command_buffers: Vec<Arc<dyn PrimaryCommandBufferAbstract>>,
+
+ /// The semaphores to signal after the execution of this batch of command buffer operations
+ /// has completed.
+ ///
+ /// The default value is empty.
+ pub signal_semaphores: Vec<SemaphoreSubmitInfo>,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for SubmitInfo {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ wait_semaphores: Vec::new(),
+ command_buffers: Vec::new(),
+ signal_semaphores: Vec::new(),
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// Parameters for a semaphore signal or wait operation in a command buffer submission.
+#[derive(Clone, Debug)]
+pub struct SemaphoreSubmitInfo {
+ /// The semaphore to signal or wait for.
+ pub semaphore: Arc<Semaphore>,
+
+ /// For a semaphore wait operation, specifies the pipeline stages in the second synchronization
+ /// scope: stages of queue operations following the wait operation that can start executing
+ /// after the semaphore is signalled.
+ ///
+ /// For a semaphore signal operation, specifies the pipeline stages in the first synchronization
+ /// scope: stages of queue operations preceding the signal operation that must complete before
+ /// the semaphore is signalled.
+ /// If this value does not equal [`ALL_COMMANDS`], then the [`synchronization2`] feature must
+ /// be enabled on the device.
+ ///
+ /// The default value is [`ALL_COMMANDS`].
+ ///
+ /// [`ALL_COMMANDS`]: PipelineStages::ALL_COMMANDS
+ /// [`synchronization2`]: crate::device::Features::synchronization2
+ pub stages: PipelineStages,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl SemaphoreSubmitInfo {
+ /// Returns a `SemaphoreSubmitInfo` with the specified `semaphore`.
+ #[inline]
+ pub fn semaphore(semaphore: Arc<Semaphore>) -> Self {
+ Self {
+ semaphore,
+ stages: PipelineStages::ALL_COMMANDS,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+#[derive(Debug, Default)]
+pub struct CommandBufferState {
+ has_been_submitted: bool,
+ pending_submits: u32,
+}
+
+impl CommandBufferState {
+ pub(crate) fn has_been_submitted(&self) -> bool {
+ self.has_been_submitted
+ }
+
+ pub(crate) fn is_submit_pending(&self) -> bool {
+ self.pending_submits != 0
+ }
+
+ pub(crate) unsafe fn add_queue_submit(&mut self) {
+ self.has_been_submitted = true;
+ self.pending_submits += 1;
+ }
+
+ pub(crate) unsafe fn set_submit_finished(&mut self) {
+ self.pending_submits -= 1;
+ }
+}
+
+#[doc(hidden)]
+#[derive(Debug)]
+pub struct CommandBufferResourcesUsage {
+ pub(crate) buffers: Vec<CommandBufferBufferUsage>,
+ pub(crate) images: Vec<CommandBufferImageUsage>,
+ pub(crate) buffer_indices: HashMap<Arc<Buffer>, usize>,
+ pub(crate) image_indices: HashMap<Arc<Image>, usize>,
+}
+
+#[derive(Debug)]
+pub(crate) struct CommandBufferBufferUsage {
+ pub(crate) buffer: Arc<Buffer>,
+ pub(crate) ranges: RangeMap<DeviceSize, CommandBufferBufferRangeUsage>,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub(crate) struct CommandBufferBufferRangeUsage {
+ pub(crate) first_use: Option<ResourceUseRef>,
+ pub(crate) mutable: bool,
+}
+
+#[derive(Debug)]
+pub(crate) struct CommandBufferImageUsage {
+ pub(crate) image: Arc<Image>,
+ pub(crate) ranges: RangeMap<DeviceSize, CommandBufferImageRangeUsage>,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub(crate) struct CommandBufferImageRangeUsage {
+ pub(crate) first_use: Option<ResourceUseRef>,
+ pub(crate) mutable: bool,
+ pub(crate) expected_layout: ImageLayout,
+ pub(crate) final_layout: ImageLayout,
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct ResourceUseRef {
+ pub command_index: usize,
+ pub command_name: &'static str,
+ pub resource_in_command: ResourceInCommand,
+ pub secondary_use_ref: Option<SecondaryResourceUseRef>,
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct SecondaryResourceUseRef {
+ pub command_index: usize,
+ pub command_name: &'static str,
+ pub resource_in_command: ResourceInCommand,
+}
+
+impl From<ResourceUseRef> for SecondaryResourceUseRef {
+ #[inline]
+ fn from(val: ResourceUseRef) -> Self {
+ let ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command,
+ secondary_use_ref,
+ } = val;
+
+ debug_assert!(secondary_use_ref.is_none());
+
+ SecondaryResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command,
+ }
+ }
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+pub enum ResourceInCommand {
+ ColorAttachment { index: u32 },
+ ColorResolveAttachment { index: u32 },
+ DepthStencilAttachment,
+ DepthStencilResolveAttachment,
+ DescriptorSet { set: u32, binding: u32, index: u32 },
+ Destination,
+ FramebufferAttachment { index: u32 },
+ ImageMemoryBarrier { index: u32 },
+ IndexBuffer,
+ IndirectBuffer,
+ SecondaryCommandBuffer { index: u32 },
+ Source,
+ VertexBuffer { binding: u32 },
+}
+
+#[doc(hidden)]
+#[derive(Debug, Default)]
+pub struct SecondaryCommandBufferResourcesUsage {
+ pub(crate) buffers: Vec<SecondaryCommandBufferBufferUsage>,
+ pub(crate) images: Vec<SecondaryCommandBufferImageUsage>,
+}
+
+#[derive(Debug)]
+pub(crate) struct SecondaryCommandBufferBufferUsage {
+ pub(crate) use_ref: ResourceUseRef,
+ pub(crate) buffer: Subbuffer<[u8]>,
+ pub(crate) range: Range<DeviceSize>,
+ pub(crate) memory: PipelineMemoryAccess,
+}
+
+#[derive(Debug)]
+pub(crate) struct SecondaryCommandBufferImageUsage {
+ pub(crate) use_ref: ResourceUseRef,
+ pub(crate) image: Arc<dyn ImageAccess>,
+ pub(crate) subresource_range: ImageSubresourceRange,
+ pub(crate) memory: PipelineMemoryAccess,
+ pub(crate) start_layout: ImageLayout,
+ pub(crate) end_layout: ImageLayout,
+}
diff --git a/src/command_buffer/pool.rs b/src/command_buffer/pool.rs
new file mode 100644
index 0000000..b93e645
--- /dev/null
+++ b/src/command_buffer/pool.rs
@@ -0,0 +1,645 @@
+// Copyright (c) 2016 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+//! Memory and resource pool for recording command buffers.
+//!
+//! A command pool holds and manages the memory of one or more command buffers. If you destroy a
+//! command pool, all command buffers recorded from it become invalid. This could lead to invalid
+//! usage and unsoundness, so to ensure safety you must use a [command buffer allocator].
+//!
+//! [command buffer allocator]: crate::command_buffer::allocator
+
+use crate::{
+ command_buffer::CommandBufferLevel,
+ device::{Device, DeviceOwned},
+ macros::impl_id_counter,
+ OomError, RequiresOneOf, Version, VulkanError, VulkanObject,
+};
+use smallvec::SmallVec;
+use std::{
+ cell::Cell,
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+ marker::PhantomData,
+ mem::MaybeUninit,
+ num::NonZeroU64,
+ ptr,
+ sync::Arc,
+};
+
+/// Represents a Vulkan command pool.
+///
+/// A command pool is always tied to a specific queue family. Command buffers allocated from a pool
+/// can only be executed on the corresponding queue family.
+///
+/// This struct doesn't implement the `Sync` trait because Vulkan command pools are not thread
+/// safe. In other words, you can only use a pool from one thread at a time.
+#[derive(Debug)]
+pub struct CommandPool {
+ handle: ash::vk::CommandPool,
+ device: Arc<Device>,
+ id: NonZeroU64,
+
+ queue_family_index: u32,
+ _transient: bool,
+ _reset_command_buffer: bool,
+ // Unimplement `Sync`, as Vulkan command pools are not thread-safe.
+ _marker: PhantomData<Cell<ash::vk::CommandPool>>,
+}
+
+impl CommandPool {
+ /// Creates a new `CommandPool`.
+ pub fn new(
+ device: Arc<Device>,
+ mut create_info: CommandPoolCreateInfo,
+ ) -> Result<CommandPool, CommandPoolCreationError> {
+ Self::validate(&device, &mut create_info)?;
+ let handle = unsafe { Self::create(&device, &create_info)? };
+
+ let CommandPoolCreateInfo {
+ queue_family_index,
+ transient,
+ reset_command_buffer,
+ _ne: _,
+ } = create_info;
+
+ Ok(CommandPool {
+ handle,
+ device,
+ id: Self::next_id(),
+ queue_family_index,
+ _transient: transient,
+ _reset_command_buffer: reset_command_buffer,
+ _marker: PhantomData,
+ })
+ }
+
+ /// Creates a new `UnsafeCommandPool` from a raw object handle.
+ ///
+ /// # Safety
+ ///
+ /// - `handle` must be a valid Vulkan object handle created from `device`.
+ /// - `create_info` must match the info used to create the object.
+ #[inline]
+ pub unsafe fn from_handle(
+ device: Arc<Device>,
+ handle: ash::vk::CommandPool,
+ create_info: CommandPoolCreateInfo,
+ ) -> CommandPool {
+ let CommandPoolCreateInfo {
+ queue_family_index,
+ transient,
+ reset_command_buffer,
+ _ne: _,
+ } = create_info;
+
+ CommandPool {
+ handle,
+ device,
+ id: Self::next_id(),
+ queue_family_index,
+ _transient: transient,
+ _reset_command_buffer: reset_command_buffer,
+ _marker: PhantomData,
+ }
+ }
+
+ fn validate(
+ device: &Device,
+ create_info: &mut CommandPoolCreateInfo,
+ ) -> Result<(), CommandPoolCreationError> {
+ let &mut CommandPoolCreateInfo {
+ queue_family_index,
+ transient: _,
+ reset_command_buffer: _,
+ _ne: _,
+ } = create_info;
+
+ // VUID-vkCreateCommandPool-queueFamilyIndex-01937
+ if queue_family_index >= device.physical_device().queue_family_properties().len() as u32 {
+ return Err(CommandPoolCreationError::QueueFamilyIndexOutOfRange {
+ queue_family_index,
+ queue_family_count: device.physical_device().queue_family_properties().len() as u32,
+ });
+ }
+
+ Ok(())
+ }
+
+ unsafe fn create(
+ device: &Device,
+ create_info: &CommandPoolCreateInfo,
+ ) -> Result<ash::vk::CommandPool, CommandPoolCreationError> {
+ let &CommandPoolCreateInfo {
+ queue_family_index,
+ transient,
+ reset_command_buffer,
+ _ne: _,
+ } = create_info;
+
+ let mut flags = ash::vk::CommandPoolCreateFlags::empty();
+
+ if transient {
+ flags |= ash::vk::CommandPoolCreateFlags::TRANSIENT;
+ }
+
+ if reset_command_buffer {
+ flags |= ash::vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER;
+ }
+
+ let create_info = ash::vk::CommandPoolCreateInfo {
+ flags,
+ queue_family_index,
+ ..Default::default()
+ };
+
+ let handle = {
+ let fns = device.fns();
+ let mut output = MaybeUninit::uninit();
+ (fns.v1_0.create_command_pool)(
+ device.handle(),
+ &create_info,
+ ptr::null(),
+ output.as_mut_ptr(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+ output.assume_init()
+ };
+
+ Ok(handle)
+ }
+
+ /// Resets the pool, which resets all the command buffers that were allocated from it.
+ ///
+ /// If `release_resources` is true, it is a hint to the implementation that it should free all
+ /// the memory internally allocated for this pool.
+ ///
+ /// # Safety
+ ///
+ /// - The command buffers allocated from this pool jump to the initial state.
+ #[inline]
+ pub unsafe fn reset(&self, release_resources: bool) -> Result<(), OomError> {
+ let flags = if release_resources {
+ ash::vk::CommandPoolResetFlags::RELEASE_RESOURCES
+ } else {
+ ash::vk::CommandPoolResetFlags::empty()
+ };
+
+ let fns = self.device.fns();
+ (fns.v1_0.reset_command_pool)(self.device.handle(), self.handle, flags)
+ .result()
+ .map_err(VulkanError::from)?;
+
+ Ok(())
+ }
+
+ /// Allocates command buffers.
+ #[inline]
+ pub fn allocate_command_buffers(
+ &self,
+ allocate_info: CommandBufferAllocateInfo,
+ ) -> Result<impl ExactSizeIterator<Item = CommandPoolAlloc>, OomError> {
+ let CommandBufferAllocateInfo {
+ level,
+ command_buffer_count,
+ _ne: _,
+ } = allocate_info;
+
+ // VUID-vkAllocateCommandBuffers-pAllocateInfo::commandBufferCount-arraylength
+ let out = if command_buffer_count == 0 {
+ vec![]
+ } else {
+ let allocate_info = ash::vk::CommandBufferAllocateInfo {
+ command_pool: self.handle,
+ level: level.into(),
+ command_buffer_count,
+ ..Default::default()
+ };
+
+ unsafe {
+ let fns = self.device.fns();
+ let mut out = Vec::with_capacity(command_buffer_count as usize);
+ (fns.v1_0.allocate_command_buffers)(
+ self.device.handle(),
+ &allocate_info,
+ out.as_mut_ptr(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+ out.set_len(command_buffer_count as usize);
+ out
+ }
+ };
+
+ let device = self.device.clone();
+
+ Ok(out.into_iter().map(move |command_buffer| CommandPoolAlloc {
+ handle: command_buffer,
+ device: device.clone(),
+ id: CommandPoolAlloc::next_id(),
+ level,
+ }))
+ }
+
+ /// Frees individual command buffers.
+ ///
+ /// # Safety
+ ///
+ /// - The `command_buffers` must have been allocated from this pool.
+ /// - The `command_buffers` must not be in the pending state.
+ pub unsafe fn free_command_buffers(
+ &self,
+ command_buffers: impl IntoIterator<Item = CommandPoolAlloc>,
+ ) {
+ let command_buffers: SmallVec<[_; 4]> =
+ command_buffers.into_iter().map(|cb| cb.handle).collect();
+ let fns = self.device.fns();
+ (fns.v1_0.free_command_buffers)(
+ self.device.handle(),
+ self.handle,
+ command_buffers.len() as u32,
+ command_buffers.as_ptr(),
+ )
+ }
+
+ /// Trims a command pool, which recycles unused internal memory from the command pool back to
+ /// the system.
+ ///
+ /// Command buffers allocated from the pool are not affected by trimming.
+ ///
+ /// This function is supported only if the
+ /// [`khr_maintenance1`](crate::device::DeviceExtensions::khr_maintenance1) extension is
+ /// enabled on the device. Otherwise an error is returned.
+ /// Since this operation is purely an optimization it is legitimate to call this function and
+ /// simply ignore any possible error.
+ #[inline]
+ pub fn trim(&self) -> Result<(), CommandPoolTrimError> {
+ if !(self.device.api_version() >= Version::V1_1
+ || self.device.enabled_extensions().khr_maintenance1)
+ {
+ return Err(CommandPoolTrimError::RequirementNotMet {
+ required_for: "`CommandPool::trim`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_1),
+ device_extensions: &["khr_maintenance1"],
+ ..Default::default()
+ },
+ });
+ }
+
+ unsafe {
+ let fns = self.device.fns();
+
+ if self.device.api_version() >= Version::V1_1 {
+ (fns.v1_1.trim_command_pool)(
+ self.device.handle(),
+ self.handle,
+ ash::vk::CommandPoolTrimFlags::empty(),
+ );
+ } else {
+ (fns.khr_maintenance1.trim_command_pool_khr)(
+ self.device.handle(),
+ self.handle,
+ ash::vk::CommandPoolTrimFlagsKHR::empty(),
+ );
+ }
+
+ Ok(())
+ }
+ }
+
+ /// Returns the queue family on which command buffers of this pool can be executed.
+ #[inline]
+ pub fn queue_family_index(&self) -> u32 {
+ self.queue_family_index
+ }
+}
+
+impl Drop for CommandPool {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ let fns = self.device.fns();
+ (fns.v1_0.destroy_command_pool)(self.device.handle(), self.handle, ptr::null());
+ }
+ }
+}
+
+unsafe impl VulkanObject for CommandPool {
+ type Handle = ash::vk::CommandPool;
+
+ #[inline]
+ fn handle(&self) -> Self::Handle {
+ self.handle
+ }
+}
+
+unsafe impl DeviceOwned for CommandPool {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+}
+
+impl_id_counter!(CommandPool);
+
+/// Error that can happen when creating a `CommandPool`.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum CommandPoolCreationError {
+ /// Not enough memory.
+ OomError(OomError),
+
+ /// The provided `queue_family_index` was not less than the number of queue families in the
+ /// physical device.
+ QueueFamilyIndexOutOfRange {
+ queue_family_index: u32,
+ queue_family_count: u32,
+ },
+}
+
+impl Error for CommandPoolCreationError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::OomError(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+impl Display for CommandPoolCreationError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::OomError(_) => write!(f, "not enough memory",),
+ Self::QueueFamilyIndexOutOfRange {
+ queue_family_index,
+ queue_family_count,
+ } => write!(
+ f,
+ "the provided `queue_family_index` ({}) was not less than the number of queue \
+ families in the physical device ({})",
+ queue_family_index, queue_family_count,
+ ),
+ }
+ }
+}
+
+impl From<VulkanError> for CommandPoolCreationError {
+ fn from(err: VulkanError) -> Self {
+ match err {
+ err @ VulkanError::OutOfHostMemory => Self::OomError(OomError::from(err)),
+ _ => panic!("unexpected error: {:?}", err),
+ }
+ }
+}
+
+/// Parameters to create an `CommandPool`.
+#[derive(Clone, Debug)]
+pub struct CommandPoolCreateInfo {
+ /// The index of the queue family that this pool is created for. All command buffers allocated
+ /// from this pool must be submitted on a queue belonging to that family.
+ ///
+ /// The default value is `u32::MAX`, which must be overridden.
+ pub queue_family_index: u32,
+
+ /// A hint to the implementation that the command buffers allocated from this pool will be
+ /// short-lived.
+ ///
+ /// The default value is `false`.
+ pub transient: bool,
+
+ /// Whether the command buffers allocated from this pool can be reset individually.
+ ///
+ /// The default value is `false`.
+ pub reset_command_buffer: bool,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for CommandPoolCreateInfo {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ queue_family_index: u32::MAX,
+ transient: false,
+ reset_command_buffer: false,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// Parameters to allocate an `UnsafeCommandPoolAlloc`.
+#[derive(Clone, Debug)]
+pub struct CommandBufferAllocateInfo {
+ /// The level of command buffer to allocate.
+ ///
+ /// The default value is [`CommandBufferLevel::Primary`].
+ pub level: CommandBufferLevel,
+
+ /// The number of command buffers to allocate.
+ ///
+ /// The default value is `1`.
+ pub command_buffer_count: u32,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for CommandBufferAllocateInfo {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ level: CommandBufferLevel::Primary,
+ command_buffer_count: 1,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// Opaque type that represents a command buffer allocated from a pool.
+#[derive(Debug)]
+pub struct CommandPoolAlloc {
+ handle: ash::vk::CommandBuffer,
+ device: Arc<Device>,
+ id: NonZeroU64,
+ level: CommandBufferLevel,
+}
+
+impl CommandPoolAlloc {
+ /// Returns the level of the command buffer.
+ #[inline]
+ pub fn level(&self) -> CommandBufferLevel {
+ self.level
+ }
+}
+
+unsafe impl VulkanObject for CommandPoolAlloc {
+ type Handle = ash::vk::CommandBuffer;
+
+ #[inline]
+ fn handle(&self) -> Self::Handle {
+ self.handle
+ }
+}
+
+unsafe impl DeviceOwned for CommandPoolAlloc {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+}
+
+impl_id_counter!(CommandPoolAlloc);
+
+/// Error that can happen when trimming command pools.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum CommandPoolTrimError {
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+}
+
+impl Error for CommandPoolTrimError {}
+
+impl Display for CommandPoolTrimError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ }
+ }
+}
+
+impl From<VulkanError> for CommandPoolTrimError {
+ fn from(err: VulkanError) -> CommandPoolTrimError {
+ panic!("unexpected error: {:?}", err)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::{
+ CommandPool, CommandPoolCreateInfo, CommandPoolCreationError, CommandPoolTrimError,
+ };
+ use crate::{
+ command_buffer::{pool::CommandBufferAllocateInfo, CommandBufferLevel},
+ RequiresOneOf, Version,
+ };
+
+ #[test]
+ fn basic_create() {
+ let (device, queue) = gfx_dev_and_queue!();
+ let _ = CommandPool::new(
+ device,
+ CommandPoolCreateInfo {
+ queue_family_index: queue.queue_family_index(),
+ ..Default::default()
+ },
+ )
+ .unwrap();
+ }
+
+ #[test]
+ fn queue_family_getter() {
+ let (device, queue) = gfx_dev_and_queue!();
+ let pool = CommandPool::new(
+ device,
+ CommandPoolCreateInfo {
+ queue_family_index: queue.queue_family_index(),
+ ..Default::default()
+ },
+ )
+ .unwrap();
+ assert_eq!(pool.queue_family_index(), queue.queue_family_index());
+ }
+
+ #[test]
+ fn check_queue_family_too_high() {
+ let (device, _) = gfx_dev_and_queue!();
+
+ match CommandPool::new(
+ device,
+ CommandPoolCreateInfo {
+ ..Default::default()
+ },
+ ) {
+ Err(CommandPoolCreationError::QueueFamilyIndexOutOfRange { .. }) => (),
+ _ => panic!(),
+ }
+ }
+
+ #[test]
+ fn check_maintenance_when_trim() {
+ let (device, queue) = gfx_dev_and_queue!();
+ let pool = CommandPool::new(
+ device.clone(),
+ CommandPoolCreateInfo {
+ queue_family_index: queue.queue_family_index(),
+ ..Default::default()
+ },
+ )
+ .unwrap();
+
+ if device.api_version() >= Version::V1_1 {
+ if matches!(
+ pool.trim(),
+ Err(CommandPoolTrimError::RequirementNotMet {
+ requires_one_of: RequiresOneOf {
+ device_extensions,
+ ..
+ }, ..
+ }) if device_extensions.contains(&"khr_maintenance1")
+ ) {
+ panic!()
+ }
+ } else {
+ if !matches!(
+ pool.trim(),
+ Err(CommandPoolTrimError::RequirementNotMet {
+ requires_one_of: RequiresOneOf {
+ device_extensions,
+ ..
+ }, ..
+ }) if device_extensions.contains(&"khr_maintenance1")
+ ) {
+ panic!()
+ }
+ }
+ }
+
+ // TODO: test that trim works if VK_KHR_maintenance1 if enabled ; the test macro doesn't
+ // support enabling extensions yet
+
+ #[test]
+ fn basic_alloc() {
+ let (device, queue) = gfx_dev_and_queue!();
+ let pool = CommandPool::new(
+ device,
+ CommandPoolCreateInfo {
+ queue_family_index: queue.queue_family_index(),
+ ..Default::default()
+ },
+ )
+ .unwrap();
+ let iter = pool
+ .allocate_command_buffers(CommandBufferAllocateInfo {
+ level: CommandBufferLevel::Primary,
+ command_buffer_count: 12,
+ ..Default::default()
+ })
+ .unwrap();
+ assert_eq!(iter.count(), 12);
+ }
+}
diff --git a/src/command_buffer/pool/mod.rs b/src/command_buffer/pool/mod.rs
deleted file mode 100644
index e7a6fb6..0000000
--- a/src/command_buffer/pool/mod.rs
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-//! In the Vulkan API, command buffers must be allocated from *command pools*.
-//!
-//! A command pool holds and manages the memory of one or more command buffers. If you destroy a
-//! command pool, all of its command buffers are automatically destroyed.
-//!
-//! In vulkano, creating a command buffer requires passing an implementation of the `CommandPool`
-//! trait. By default vulkano will use the `StandardCommandPool` struct, but you can implement
-//! this trait yourself by wrapping around the `UnsafeCommandPool` type.
-
-use crate::device::physical::QueueFamily;
-
-use crate::device::DeviceOwned;
-use crate::OomError;
-
-pub use self::standard::StandardCommandPool;
-pub use self::sys::CommandPoolTrimError;
-pub use self::sys::UnsafeCommandPool;
-pub use self::sys::UnsafeCommandPoolAlloc;
-pub use self::sys::UnsafeCommandPoolAllocIter;
-
-pub mod standard;
-mod sys;
-
-/// Types that manage the memory of command buffers.
-///
-/// # Safety
-///
-/// A Vulkan command pool must be externally synchronized as if it owned the command buffers that
-/// were allocated from it. This includes allocating from the pool, freeing from the pool,
-/// resetting the pool or individual command buffers, and most importantly recording commands to
-/// command buffers.
-///
-/// The implementation of `CommandPool` is expected to manage this. For as long as a `Builder`
-/// is alive, the trait implementation is expected to lock the pool that allocated the `Builder`
-/// for the current thread.
-///
-/// > **Note**: This may be modified in the future to allow different implementation strategies.
-///
-/// The destructors of the `CommandPoolBuilderAlloc` and the `CommandPoolAlloc` are expected to
-/// free the command buffer, reset the command buffer, or add it to a pool so that it gets reused.
-/// If the implementation frees or resets the command buffer, it must not forget that this
-/// operation must lock the pool.
-///
-pub unsafe trait CommandPool: DeviceOwned {
- /// See `alloc()`.
- type Iter: Iterator<Item = Self::Builder>;
- /// Represents a command buffer that has been allocated and that is currently being built.
- type Builder: CommandPoolBuilderAlloc<Alloc = Self::Alloc>;
- /// Represents a command buffer that has been allocated and that is pending execution or is
- /// being executed.
- type Alloc: CommandPoolAlloc;
-
- /// Allocates command buffers from this pool.
- ///
- /// Returns an iterator that contains an bunch of allocated command buffers.
- fn alloc(&self, secondary: bool, count: u32) -> Result<Self::Iter, OomError>;
-
- /// Returns the queue family that this pool targets.
- fn queue_family(&self) -> QueueFamily;
-}
-
-/// A command buffer allocated from a pool and that can be recorded.
-///
-/// # Safety
-///
-/// See `CommandPool` for information about safety.
-///
-pub unsafe trait CommandPoolBuilderAlloc: DeviceOwned {
- /// Return type of `into_alloc`.
- type Alloc: CommandPoolAlloc;
-
- /// Returns the internal object that contains the command buffer.
- fn inner(&self) -> &UnsafeCommandPoolAlloc;
-
- /// Turns this builder into a command buffer that is pending execution.
- fn into_alloc(self) -> Self::Alloc;
-
- /// Returns the queue family that the pool targets.
- fn queue_family(&self) -> QueueFamily;
-}
-
-/// A command buffer allocated from a pool that has finished being recorded.
-///
-/// # Safety
-///
-/// See `CommandPool` for information about safety.
-///
-pub unsafe trait CommandPoolAlloc: DeviceOwned {
- /// Returns the internal object that contains the command buffer.
- fn inner(&self) -> &UnsafeCommandPoolAlloc;
-
- /// Returns the queue family that the pool targets.
- fn queue_family(&self) -> QueueFamily;
-}
diff --git a/src/command_buffer/pool/standard.rs b/src/command_buffer/pool/standard.rs
deleted file mode 100644
index 3bf105a..0000000
--- a/src/command_buffer/pool/standard.rs
+++ /dev/null
@@ -1,313 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crossbeam_queue::SegQueue;
-use fnv::FnvHashMap;
-use std::marker::PhantomData;
-use std::mem::ManuallyDrop;
-use std::ptr;
-use std::sync::Arc;
-use std::sync::Mutex;
-use std::sync::Weak;
-use std::thread;
-use std::vec::IntoIter as VecIntoIter;
-
-use crate::command_buffer::pool::CommandPool;
-use crate::command_buffer::pool::CommandPoolAlloc;
-use crate::command_buffer::pool::CommandPoolBuilderAlloc;
-use crate::command_buffer::pool::UnsafeCommandPool;
-use crate::command_buffer::pool::UnsafeCommandPoolAlloc;
-use crate::device::physical::QueueFamily;
-
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::OomError;
-use crate::VulkanObject;
-
-/// Standard implementation of a command pool.
-///
-/// It is guaranteed that the allocated command buffers keep the `Arc<StandardCommandPool>` alive.
-/// This is desirable so that we can store a `Weak<StandardCommandPool>`.
-///
-/// Will use one Vulkan pool per thread in order to avoid locking. Will try to reuse command
-/// buffers. Command buffers can't be moved between threads during the building process, but
-/// finished command buffers can.
-pub struct StandardCommandPool {
- // The device.
- device: Arc<Device>,
-
- // Identifier of the queue family.
- queue_family: u32,
-
- // For each thread, we store thread-specific info.
- per_thread: Mutex<FnvHashMap<thread::ThreadId, Weak<StandardCommandPoolPerThread>>>,
-}
-
-unsafe impl Send for StandardCommandPool {}
-unsafe impl Sync for StandardCommandPool {}
-
-struct StandardCommandPoolPerThread {
- // The Vulkan pool of this thread.
- pool: Mutex<UnsafeCommandPool>,
- // List of existing primary command buffers that are available for reuse.
- available_primary_command_buffers: SegQueue<UnsafeCommandPoolAlloc>,
- // List of existing secondary command buffers that are available for reuse.
- available_secondary_command_buffers: SegQueue<UnsafeCommandPoolAlloc>,
-}
-
-impl StandardCommandPool {
- /// Builds a new pool.
- ///
- /// # Panic
- ///
- /// - Panics if the device and the queue family don't belong to the same physical device.
- ///
- pub fn new(device: Arc<Device>, queue_family: QueueFamily) -> StandardCommandPool {
- assert_eq!(
- device.physical_device().internal_object(),
- queue_family.physical_device().internal_object()
- );
-
- StandardCommandPool {
- device: device,
- queue_family: queue_family.id(),
- per_thread: Mutex::new(Default::default()),
- }
- }
-}
-
-unsafe impl CommandPool for Arc<StandardCommandPool> {
- type Iter = VecIntoIter<StandardCommandPoolBuilder>;
- type Builder = StandardCommandPoolBuilder;
- type Alloc = StandardCommandPoolAlloc;
-
- fn alloc(&self, secondary: bool, count: u32) -> Result<Self::Iter, OomError> {
- // Find the correct `StandardCommandPoolPerThread` structure.
- let mut hashmap = self.per_thread.lock().unwrap();
- // TODO: meh for iterating everything every time
- hashmap.retain(|_, w| w.upgrade().is_some());
-
- let this_thread = thread::current().id();
-
- // Get an appropriate `Arc<StandardCommandPoolPerThread>`.
- let per_thread = if let Some(entry) = hashmap.get(&this_thread).and_then(Weak::upgrade) {
- entry
- } else {
- let new_pool =
- UnsafeCommandPool::new(self.device.clone(), self.queue_family(), false, true)?;
- let pt = Arc::new(StandardCommandPoolPerThread {
- pool: Mutex::new(new_pool),
- available_primary_command_buffers: SegQueue::new(),
- available_secondary_command_buffers: SegQueue::new(),
- });
-
- hashmap.insert(this_thread, Arc::downgrade(&pt));
- pt
- };
-
- // The final output.
- let mut output = Vec::with_capacity(count as usize);
-
- // First, pick from already-existing command buffers.
- {
- let existing = if secondary {
- &per_thread.available_secondary_command_buffers
- } else {
- &per_thread.available_primary_command_buffers
- };
-
- for _ in 0..count as usize {
- if let Some(cmd) = existing.pop() {
- output.push(StandardCommandPoolBuilder {
- inner: StandardCommandPoolAlloc {
- cmd: ManuallyDrop::new(cmd),
- pool: per_thread.clone(),
- pool_parent: self.clone(),
- secondary: secondary,
- device: self.device.clone(),
- },
- dummy_avoid_send_sync: PhantomData,
- });
- } else {
- break;
- }
- }
- };
-
- // Then allocate the rest.
- if output.len() < count as usize {
- let pool_lock = per_thread.pool.lock().unwrap();
- let num_new = count as usize - output.len();
-
- for cmd in pool_lock.alloc_command_buffers(secondary, num_new as u32)? {
- output.push(StandardCommandPoolBuilder {
- inner: StandardCommandPoolAlloc {
- cmd: ManuallyDrop::new(cmd),
- pool: per_thread.clone(),
- pool_parent: self.clone(),
- secondary: secondary,
- device: self.device.clone(),
- },
- dummy_avoid_send_sync: PhantomData,
- });
- }
- }
-
- // Final output.
- Ok(output.into_iter())
- }
-
- #[inline]
- fn queue_family(&self) -> QueueFamily {
- self.device
- .physical_device()
- .queue_family_by_id(self.queue_family)
- .unwrap()
- }
-}
-
-unsafe impl DeviceOwned for StandardCommandPool {
- #[inline]
- fn device(&self) -> &Arc<Device> {
- &self.device
- }
-}
-
-/// Command buffer allocated from a `StandardCommandPool` and that is currently being built.
-pub struct StandardCommandPoolBuilder {
- // The only difference between a `StandardCommandPoolBuilder` and a `StandardCommandPoolAlloc`
- // is that the former must not implement `Send` and `Sync`. Therefore we just share the structs.
- inner: StandardCommandPoolAlloc,
- // Unimplemented `Send` and `Sync` from the builder.
- dummy_avoid_send_sync: PhantomData<*const u8>,
-}
-
-unsafe impl CommandPoolBuilderAlloc for StandardCommandPoolBuilder {
- type Alloc = StandardCommandPoolAlloc;
-
- #[inline]
- fn inner(&self) -> &UnsafeCommandPoolAlloc {
- self.inner.inner()
- }
-
- #[inline]
- fn into_alloc(self) -> Self::Alloc {
- self.inner
- }
-
- #[inline]
- fn queue_family(&self) -> QueueFamily {
- self.inner.queue_family()
- }
-}
-
-unsafe impl DeviceOwned for StandardCommandPoolBuilder {
- #[inline]
- fn device(&self) -> &Arc<Device> {
- self.inner.device()
- }
-}
-
-/// Command buffer allocated from a `StandardCommandPool`.
-pub struct StandardCommandPoolAlloc {
- // The actual command buffer. Extracted in the `Drop` implementation.
- cmd: ManuallyDrop<UnsafeCommandPoolAlloc>,
- // We hold a reference to the command pool for our destructor.
- pool: Arc<StandardCommandPoolPerThread>,
- // Keep alive the `StandardCommandPool`, otherwise it would be destroyed.
- pool_parent: Arc<StandardCommandPool>,
- // True if secondary command buffer.
- secondary: bool,
- // The device we belong to. Necessary because of the `DeviceOwned` trait implementation.
- device: Arc<Device>,
-}
-
-unsafe impl Send for StandardCommandPoolAlloc {}
-unsafe impl Sync for StandardCommandPoolAlloc {}
-
-unsafe impl CommandPoolAlloc for StandardCommandPoolAlloc {
- #[inline]
- fn inner(&self) -> &UnsafeCommandPoolAlloc {
- &*self.cmd
- }
-
- #[inline]
- fn queue_family(&self) -> QueueFamily {
- let queue_family_id = self.pool.pool.lock().unwrap().queue_family().id();
-
- self.device
- .physical_device()
- .queue_family_by_id(queue_family_id)
- .unwrap()
- }
-}
-
-unsafe impl DeviceOwned for StandardCommandPoolAlloc {
- #[inline]
- fn device(&self) -> &Arc<Device> {
- // Note that we could grab the device from `self.pool`. Unfortunately this requires a mutex
- // lock, so it isn't compatible with the API of `DeviceOwned`.
- &self.device
- }
-}
-
-impl Drop for StandardCommandPoolAlloc {
- fn drop(&mut self) {
- // Safe because `self.cmd` is wrapped in a `ManuallyDrop`.
- let cmd: UnsafeCommandPoolAlloc = unsafe { ptr::read(&*self.cmd) };
-
- if self.secondary {
- self.pool.available_secondary_command_buffers.push(cmd);
- } else {
- self.pool.available_primary_command_buffers.push(cmd);
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use crate::command_buffer::pool::CommandPool;
- use crate::command_buffer::pool::CommandPoolBuilderAlloc;
- use crate::command_buffer::pool::StandardCommandPool;
- use crate::device::Device;
- use crate::VulkanObject;
- use std::sync::Arc;
-
- #[test]
- fn reuse_command_buffers() {
- let (device, _) = gfx_dev_and_queue!();
- let queue_family = device.physical_device().queue_families().next().unwrap();
-
- let pool = Device::standard_command_pool(&device, queue_family);
- // Avoid the weak reference to StandardCommandPoolPerThread expiring.
- let cb_hold_weakref = pool.alloc(false, 1).unwrap().next().unwrap();
-
- let cb = pool.alloc(false, 1).unwrap().next().unwrap();
- let raw = cb.inner().internal_object();
- drop(cb);
-
- let cb2 = pool.alloc(false, 1).unwrap().next().unwrap();
- assert_eq!(raw, cb2.inner().internal_object());
- }
-
- #[test]
- fn pool_kept_alive_by_allocs() {
- let (device, queue) = gfx_dev_and_queue!();
-
- let pool = Arc::new(StandardCommandPool::new(device, queue.family()));
- let pool_weak = Arc::downgrade(&pool);
-
- let cb = pool.alloc(false, 1).unwrap().next().unwrap();
- drop(pool);
- assert!(pool_weak.upgrade().is_some());
-
- drop(cb);
- assert!(pool_weak.upgrade().is_none());
- }
-}
diff --git a/src/command_buffer/pool/sys.rs b/src/command_buffer/pool/sys.rs
deleted file mode 100644
index 8432182..0000000
--- a/src/command_buffer/pool/sys.rs
+++ /dev/null
@@ -1,421 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::check_errors;
-use crate::device::physical::QueueFamily;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::Error;
-use crate::OomError;
-use crate::Version;
-use crate::VulkanObject;
-use smallvec::SmallVec;
-use std::error;
-use std::fmt;
-use std::marker::PhantomData;
-use std::mem::MaybeUninit;
-use std::ptr;
-use std::sync::Arc;
-use std::vec::IntoIter as VecIntoIter;
-
-/// Low-level implementation of a command pool.
-///
-/// A command pool is always tied to a specific queue family. Command buffers allocated from a pool
-/// can only be executed on the corresponding queue family.
-///
-/// This struct doesn't implement the `Sync` trait because Vulkan command pools are not thread
-/// safe. In other words, you can only use a pool from one thread at a time.
-#[derive(Debug)]
-pub struct UnsafeCommandPool {
- pool: ash::vk::CommandPool,
- device: Arc<Device>,
-
- // Index of the associated queue family in the physical device.
- queue_family_index: u32,
-
- // We don't want `UnsafeCommandPool` to implement Sync.
- // This marker unimplements both Send and Sync, but we reimplement Send manually right under.
- dummy_avoid_sync: PhantomData<*const u8>,
-}
-
-unsafe impl Send for UnsafeCommandPool {}
-
-impl UnsafeCommandPool {
- /// Creates a new pool.
- ///
- /// The command buffers created with this pool can only be executed on queues of the given
- /// family.
- ///
- /// Setting `transient` to true is a hint to the implementation that the command buffers will
- /// be short-lived.
- /// Setting `reset_cb` to true means that command buffers can be reset individually.
- ///
- /// # Panic
- ///
- /// - Panics if the queue family doesn't belong to the same physical device as `device`.
- ///
- pub fn new(
- device: Arc<Device>,
- queue_family: QueueFamily,
- transient: bool,
- reset_cb: bool,
- ) -> Result<UnsafeCommandPool, OomError> {
- assert_eq!(
- device.physical_device().internal_object(),
- queue_family.physical_device().internal_object(),
- "Device doesn't match physical device when creating a command pool"
- );
-
- let fns = device.fns();
-
- let flags = {
- let flag1 = if transient {
- ash::vk::CommandPoolCreateFlags::TRANSIENT
- } else {
- ash::vk::CommandPoolCreateFlags::empty()
- };
- let flag2 = if reset_cb {
- ash::vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER
- } else {
- ash::vk::CommandPoolCreateFlags::empty()
- };
- flag1 | flag2
- };
-
- let pool = unsafe {
- let infos = ash::vk::CommandPoolCreateInfo {
- flags: flags,
- queue_family_index: queue_family.id(),
- ..Default::default()
- };
-
- let mut output = MaybeUninit::uninit();
- check_errors(fns.v1_0.create_command_pool(
- device.internal_object(),
- &infos,
- ptr::null(),
- output.as_mut_ptr(),
- ))?;
- output.assume_init()
- };
-
- Ok(UnsafeCommandPool {
- pool: pool,
- device: device.clone(),
- queue_family_index: queue_family.id(),
- dummy_avoid_sync: PhantomData,
- })
- }
-
- /// Resets the pool, which resets all the command buffers that were allocated from it.
- ///
- /// If `release_resources` is true, it is a hint to the implementation that it should free all
- /// the memory internally allocated for this pool.
- ///
- /// # Safety
- ///
- /// The command buffers allocated from this pool jump to the initial state.
- ///
- pub unsafe fn reset(&self, release_resources: bool) -> Result<(), OomError> {
- let flags = if release_resources {
- ash::vk::CommandPoolResetFlags::RELEASE_RESOURCES
- } else {
- ash::vk::CommandPoolResetFlags::empty()
- };
-
- let fns = self.device.fns();
- check_errors(
- fns.v1_0
- .reset_command_pool(self.device.internal_object(), self.pool, flags),
- )?;
- Ok(())
- }
-
- /// Trims a command pool, which recycles unused internal memory from the command pool back to
- /// the system.
- ///
- /// Command buffers allocated from the pool are not affected by trimming.
- ///
- /// This function is supported only if the `VK_KHR_maintenance1` extension was enabled at
- /// device creation. Otherwise an error is returned.
- /// Since this operation is purely an optimization it is legitimate to call this function and
- /// simply ignore any possible error.
- pub fn trim(&self) -> Result<(), CommandPoolTrimError> {
- unsafe {
- if !(self.device.api_version() >= Version::V1_1
- || self.device.enabled_extensions().khr_maintenance1)
- {
- return Err(CommandPoolTrimError::Maintenance1ExtensionNotEnabled);
- }
-
- let fns = self.device.fns();
-
- if self.device.api_version() >= Version::V1_1 {
- fns.v1_1.trim_command_pool(
- self.device.internal_object(),
- self.pool,
- ash::vk::CommandPoolTrimFlags::empty(),
- );
- } else {
- fns.khr_maintenance1.trim_command_pool_khr(
- self.device.internal_object(),
- self.pool,
- ash::vk::CommandPoolTrimFlagsKHR::empty(),
- );
- }
-
- Ok(())
- }
- }
-
- /// Allocates `count` command buffers.
- ///
- /// If `secondary` is true, allocates secondary command buffers. Otherwise, allocates primary
- /// command buffers.
- pub fn alloc_command_buffers(
- &self,
- secondary: bool,
- count: u32,
- ) -> Result<UnsafeCommandPoolAllocIter, OomError> {
- if count == 0 {
- return Ok(UnsafeCommandPoolAllocIter {
- device: self.device.clone(),
- list: vec![].into_iter(),
- });
- }
-
- let infos = ash::vk::CommandBufferAllocateInfo {
- command_pool: self.pool,
- level: if secondary {
- ash::vk::CommandBufferLevel::SECONDARY
- } else {
- ash::vk::CommandBufferLevel::PRIMARY
- },
- command_buffer_count: count,
- ..Default::default()
- };
-
- unsafe {
- let fns = self.device.fns();
- let mut out = Vec::with_capacity(count as usize);
- check_errors(fns.v1_0.allocate_command_buffers(
- self.device.internal_object(),
- &infos,
- out.as_mut_ptr(),
- ))?;
-
- out.set_len(count as usize);
-
- Ok(UnsafeCommandPoolAllocIter {
- device: self.device.clone(),
- list: out.into_iter(),
- })
- }
- }
-
- /// Frees individual command buffers.
- ///
- /// # Safety
- ///
- /// The command buffers must have been allocated from this pool. They must not be in use.
- ///
- pub unsafe fn free_command_buffers<I>(&self, command_buffers: I)
- where
- I: Iterator<Item = UnsafeCommandPoolAlloc>,
- {
- let command_buffers: SmallVec<[_; 4]> =
- command_buffers.map(|cb| cb.command_buffer).collect();
- let fns = self.device.fns();
- fns.v1_0.free_command_buffers(
- self.device.internal_object(),
- self.pool,
- command_buffers.len() as u32,
- command_buffers.as_ptr(),
- )
- }
-
- /// Returns the queue family on which command buffers of this pool can be executed.
- #[inline]
- pub fn queue_family(&self) -> QueueFamily {
- self.device
- .physical_device()
- .queue_family_by_id(self.queue_family_index)
- .unwrap()
- }
-}
-
-unsafe impl DeviceOwned for UnsafeCommandPool {
- #[inline]
- fn device(&self) -> &Arc<Device> {
- &self.device
- }
-}
-
-unsafe impl VulkanObject for UnsafeCommandPool {
- type Object = ash::vk::CommandPool;
-
- #[inline]
- fn internal_object(&self) -> ash::vk::CommandPool {
- self.pool
- }
-}
-
-impl Drop for UnsafeCommandPool {
- #[inline]
- fn drop(&mut self) {
- unsafe {
- let fns = self.device.fns();
- fns.v1_0
- .destroy_command_pool(self.device.internal_object(), self.pool, ptr::null());
- }
- }
-}
-
-/// Opaque type that represents a command buffer allocated from a pool.
-pub struct UnsafeCommandPoolAlloc {
- command_buffer: ash::vk::CommandBuffer,
- device: Arc<Device>,
-}
-
-unsafe impl DeviceOwned for UnsafeCommandPoolAlloc {
- #[inline]
- fn device(&self) -> &Arc<Device> {
- &self.device
- }
-}
-
-unsafe impl VulkanObject for UnsafeCommandPoolAlloc {
- type Object = ash::vk::CommandBuffer;
-
- #[inline]
- fn internal_object(&self) -> ash::vk::CommandBuffer {
- self.command_buffer
- }
-}
-
-/// Iterator for newly-allocated command buffers.
-#[derive(Debug)]
-pub struct UnsafeCommandPoolAllocIter {
- device: Arc<Device>,
- list: VecIntoIter<ash::vk::CommandBuffer>,
-}
-
-impl Iterator for UnsafeCommandPoolAllocIter {
- type Item = UnsafeCommandPoolAlloc;
-
- #[inline]
- fn next(&mut self) -> Option<UnsafeCommandPoolAlloc> {
- self.list
- .next()
- .map(|command_buffer| UnsafeCommandPoolAlloc {
- command_buffer,
- device: self.device.clone(),
- })
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.list.size_hint()
- }
-}
-
-impl ExactSizeIterator for UnsafeCommandPoolAllocIter {}
-
-/// Error that can happen when trimming command pools.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum CommandPoolTrimError {
- /// The `KHR_maintenance1` extension was not enabled.
- Maintenance1ExtensionNotEnabled,
-}
-
-impl error::Error for CommandPoolTrimError {}
-
-impl fmt::Display for CommandPoolTrimError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- CommandPoolTrimError::Maintenance1ExtensionNotEnabled => {
- "the `KHR_maintenance1` extension was not enabled"
- }
- }
- )
- }
-}
-
-impl From<Error> for CommandPoolTrimError {
- #[inline]
- fn from(err: Error) -> CommandPoolTrimError {
- panic!("unexpected error: {:?}", err)
- }
-}
-
-#[cfg(test)]
-mod tests {
- use crate::command_buffer::pool::CommandPoolTrimError;
- use crate::command_buffer::pool::UnsafeCommandPool;
- use crate::Version;
-
- #[test]
- fn basic_create() {
- let (device, queue) = gfx_dev_and_queue!();
- let _ = UnsafeCommandPool::new(device, queue.family(), false, false).unwrap();
- }
-
- #[test]
- fn queue_family_getter() {
- let (device, queue) = gfx_dev_and_queue!();
- let pool = UnsafeCommandPool::new(device, queue.family(), false, false).unwrap();
- assert_eq!(pool.queue_family().id(), queue.family().id());
- }
-
- #[test]
- fn panic_if_not_match_family() {
- let (device, _) = gfx_dev_and_queue!();
- let (_, queue) = gfx_dev_and_queue!();
-
- assert_should_panic!(
- "Device doesn't match physical device when creating a command pool",
- {
- let _ = UnsafeCommandPool::new(device, queue.family(), false, false);
- }
- );
- }
-
- #[test]
- fn check_maintenance_when_trim() {
- let (device, queue) = gfx_dev_and_queue!();
- let pool = UnsafeCommandPool::new(device.clone(), queue.family(), false, false).unwrap();
-
- if device.api_version() >= Version::V1_1 {
- match pool.trim() {
- Err(CommandPoolTrimError::Maintenance1ExtensionNotEnabled) => panic!(),
- _ => (),
- }
- } else {
- match pool.trim() {
- Err(CommandPoolTrimError::Maintenance1ExtensionNotEnabled) => (),
- _ => panic!(),
- }
- }
- }
-
- // TODO: test that trim works if VK_KHR_maintenance1 if enabled ; the test macro doesn't
- // support enabling extensions yet
-
- #[test]
- fn basic_alloc() {
- let (device, queue) = gfx_dev_and_queue!();
- let pool = UnsafeCommandPool::new(device, queue.family(), false, false).unwrap();
- let iter = pool.alloc_command_buffers(false, 12).unwrap();
- assert_eq!(iter.count(), 12);
- }
-}
diff --git a/src/command_buffer/standard/builder/bind_push.rs b/src/command_buffer/standard/builder/bind_push.rs
new file mode 100644
index 0000000..7fe5d7b
--- /dev/null
+++ b/src/command_buffer/standard/builder/bind_push.rs
@@ -0,0 +1,936 @@
+// Copyright (c) 2022 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use super::{CommandBufferBuilder, RenderPassStateType, SetOrPush};
+use crate::{
+ buffer::{BufferContents, BufferUsage, Subbuffer},
+ command_buffer::{allocator::CommandBufferAllocator, commands::bind_push::BindPushError},
+ descriptor_set::{
+ check_descriptor_write, layout::DescriptorType, DescriptorBindingResources,
+ DescriptorSetResources, DescriptorSetWithOffsets, DescriptorSetsCollection,
+ DescriptorWriteInfo, WriteDescriptorSet,
+ },
+ device::{DeviceOwned, QueueFlags},
+ memory::is_aligned,
+ pipeline::{
+ graphics::{
+ input_assembly::{Index, IndexType},
+ render_pass::PipelineRenderPassType,
+ vertex_input::VertexBuffersCollection,
+ },
+ ComputePipeline, GraphicsPipeline, PipelineBindPoint, PipelineLayout,
+ },
+ DeviceSize, RequiresOneOf, VulkanObject,
+};
+use smallvec::SmallVec;
+use std::{cmp::min, mem::size_of_val, os::raw::c_void, sync::Arc};
+
+impl<L, A> CommandBufferBuilder<L, A>
+where
+ A: CommandBufferAllocator,
+{
+ /// Binds descriptor sets for future dispatch or draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support `pipeline_bind_point`.
+ /// - Panics if the highest descriptor set slot being bound is not less than the number of sets
+ /// in `pipeline_layout`.
+ /// - Panics if `self` and any element of `descriptor_sets` do not belong to the same device.
+ pub fn bind_descriptor_sets(
+ &mut self,
+ pipeline_bind_point: PipelineBindPoint,
+ pipeline_layout: Arc<PipelineLayout>,
+ first_set: u32,
+ descriptor_sets: impl DescriptorSetsCollection,
+ ) -> &mut Self {
+ let descriptor_sets = descriptor_sets.into_vec();
+ self.validate_bind_descriptor_sets(
+ pipeline_bind_point,
+ &pipeline_layout,
+ first_set,
+ &descriptor_sets,
+ )
+ .unwrap();
+
+ unsafe {
+ self.bind_descriptor_sets_unchecked(
+ pipeline_bind_point,
+ pipeline_layout,
+ first_set,
+ descriptor_sets,
+ )
+ }
+ }
+
+ fn validate_bind_descriptor_sets(
+ &self,
+ pipeline_bind_point: PipelineBindPoint,
+ pipeline_layout: &PipelineLayout,
+ first_set: u32,
+ descriptor_sets: &[DescriptorSetWithOffsets],
+ ) -> Result<(), BindPushError> {
+ // VUID-vkCmdBindDescriptorSets-pipelineBindPoint-parameter
+ pipeline_bind_point.validate_device(self.device())?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdBindDescriptorSets-commandBuffer-cmdpool
+ // VUID-vkCmdBindDescriptorSets-pipelineBindPoint-00361
+ match pipeline_bind_point {
+ PipelineBindPoint::Compute => {
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::COMPUTE)
+ {
+ return Err(BindPushError::NotSupportedByQueueFamily);
+ }
+ }
+ PipelineBindPoint::Graphics => {
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(BindPushError::NotSupportedByQueueFamily);
+ }
+ }
+ }
+
+ // VUID-vkCmdBindDescriptorSets-firstSet-00360
+ if first_set + descriptor_sets.len() as u32 > pipeline_layout.set_layouts().len() as u32 {
+ return Err(BindPushError::DescriptorSetOutOfRange {
+ set_num: first_set + descriptor_sets.len() as u32,
+ pipeline_layout_set_count: pipeline_layout.set_layouts().len() as u32,
+ });
+ }
+
+ let properties = self.device().physical_device().properties();
+ let uniform_alignment = properties.min_uniform_buffer_offset_alignment;
+ let storage_alignment = properties.min_storage_buffer_offset_alignment;
+
+ for (i, set) in descriptor_sets.iter().enumerate() {
+ let set_num = first_set + i as u32;
+ let (set, dynamic_offsets) = set.as_ref();
+
+ // VUID-vkCmdBindDescriptorSets-commonparent
+ assert_eq!(self.device(), set.device());
+
+ let set_layout = set.layout();
+ let pipeline_set_layout = &pipeline_layout.set_layouts()[set_num as usize];
+
+ // VUID-vkCmdBindDescriptorSets-pDescriptorSets-00358
+ if !pipeline_set_layout.is_compatible_with(set_layout) {
+ return Err(BindPushError::DescriptorSetNotCompatible { set_num });
+ }
+
+ let mut dynamic_offsets_remaining = dynamic_offsets;
+ let mut required_dynamic_offset_count = 0;
+
+ for (&binding_num, binding) in set_layout.bindings() {
+ let required_alignment = match binding.descriptor_type {
+ DescriptorType::UniformBufferDynamic => uniform_alignment,
+ DescriptorType::StorageBufferDynamic => storage_alignment,
+ _ => continue,
+ };
+
+ let count = if binding.variable_descriptor_count {
+ set.variable_descriptor_count()
+ } else {
+ binding.descriptor_count
+ } as usize;
+
+ required_dynamic_offset_count += count;
+
+ if !dynamic_offsets_remaining.is_empty() {
+ let split_index = min(count, dynamic_offsets_remaining.len());
+ let dynamic_offsets = &dynamic_offsets_remaining[..split_index];
+ dynamic_offsets_remaining = &dynamic_offsets_remaining[split_index..];
+
+ let elements = match set.resources().binding(binding_num) {
+ Some(DescriptorBindingResources::Buffer(elements)) => elements.as_slice(),
+ _ => unreachable!(),
+ };
+
+ for (index, (&offset, element)) in
+ dynamic_offsets.iter().zip(elements).enumerate()
+ {
+ // VUID-vkCmdBindDescriptorSets-pDynamicOffsets-01971
+ // VUID-vkCmdBindDescriptorSets-pDynamicOffsets-01972
+ if !is_aligned(offset as DeviceSize, required_alignment) {
+ return Err(BindPushError::DynamicOffsetNotAligned {
+ set_num,
+ binding_num,
+ index: index as u32,
+ offset,
+ required_alignment,
+ });
+ }
+
+ if let Some((buffer, range)) = element {
+ // VUID-vkCmdBindDescriptorSets-pDescriptorSets-01979
+ if offset as DeviceSize + range.end > buffer.size() {
+ return Err(BindPushError::DynamicOffsetOutOfBufferBounds {
+ set_num,
+ binding_num,
+ index: index as u32,
+ offset,
+ range_end: range.end,
+ buffer_size: buffer.size(),
+ });
+ }
+ }
+ }
+ }
+ }
+
+ // VUID-vkCmdBindDescriptorSets-dynamicOffsetCount-00359
+ if dynamic_offsets.len() != required_dynamic_offset_count {
+ return Err(BindPushError::DynamicOffsetCountMismatch {
+ set_num,
+ provided_count: dynamic_offsets.len(),
+ required_count: required_dynamic_offset_count,
+ });
+ }
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn bind_descriptor_sets_unchecked(
+ &mut self,
+ pipeline_bind_point: PipelineBindPoint,
+ pipeline_layout: Arc<PipelineLayout>,
+ first_set: u32,
+ descriptor_sets: impl DescriptorSetsCollection,
+ ) -> &mut Self {
+ let descriptor_sets_with_offsets = descriptor_sets.into_vec();
+
+ if descriptor_sets_with_offsets.is_empty() {
+ return self;
+ }
+
+ let descriptor_sets: SmallVec<[_; 12]> = descriptor_sets_with_offsets
+ .iter()
+ .map(|x| x.as_ref().0.inner().handle())
+ .collect();
+ let dynamic_offsets: SmallVec<[_; 32]> = descriptor_sets_with_offsets
+ .iter()
+ .flat_map(|x| x.as_ref().1.iter().copied())
+ .collect();
+
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_bind_descriptor_sets)(
+ self.handle(),
+ pipeline_bind_point.into(),
+ pipeline_layout.handle(),
+ first_set,
+ descriptor_sets.len() as u32,
+ descriptor_sets.as_ptr(),
+ dynamic_offsets.len() as u32,
+ dynamic_offsets.as_ptr(),
+ );
+
+ let state = self.builder_state.invalidate_descriptor_sets(
+ pipeline_bind_point,
+ pipeline_layout.clone(),
+ first_set,
+ descriptor_sets_with_offsets.len() as u32,
+ );
+
+ self.resources
+ .reserve(descriptor_sets_with_offsets.len() + 1);
+
+ for (set_num, descriptor_set_with_offsets) in
+ descriptor_sets_with_offsets.into_iter().enumerate()
+ {
+ let descriptor_set = descriptor_set_with_offsets.as_ref().0.clone();
+ state.descriptor_sets.insert(
+ first_set + set_num as u32,
+ SetOrPush::Set(descriptor_set_with_offsets),
+ );
+ self.resources.push(Box::new(descriptor_set));
+ }
+
+ self.resources.push(Box::new(pipeline_layout));
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Binds an index buffer for future indexed draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if `self` and `index_buffer` do not belong to the same device.
+ /// - Panics if `index_buffer` does not have the [`BufferUsage::INDEX_BUFFER`] usage enabled.
+ /// - If the index buffer contains `u8` indices, panics if the [`index_type_uint8`] feature is
+ /// not enabled on the device.
+ ///
+ /// [`BufferUsage::INDEX_BUFFER`]: crate::buffer::BufferUsage::INDEX_BUFFER
+ /// [`index_type_uint8`]: crate::device::Features::index_type_uint8
+ pub fn bind_index_buffer<I: Index>(&mut self, index_buffer: Subbuffer<[I]>) -> &mut Self {
+ self.validate_bind_index_buffer(index_buffer.as_bytes(), I::ty())
+ .unwrap();
+
+ unsafe { self.bind_index_buffer_unchecked(index_buffer.into_bytes(), I::ty()) }
+ }
+
+ fn validate_bind_index_buffer(
+ &self,
+ index_buffer: &Subbuffer<[u8]>,
+ index_type: IndexType,
+ ) -> Result<(), BindPushError> {
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdBindIndexBuffer-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(BindPushError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdBindIndexBuffer-commonparent
+ assert_eq!(self.device(), index_buffer.device());
+
+ // VUID-vkCmdBindIndexBuffer-buffer-00433
+ if !index_buffer
+ .buffer()
+ .usage()
+ .intersects(BufferUsage::INDEX_BUFFER)
+ {
+ return Err(BindPushError::IndexBufferMissingUsage);
+ }
+
+ // VUID-vkCmdBindIndexBuffer-indexType-02765
+ if index_type == IndexType::U8 && !self.device().enabled_features().index_type_uint8 {
+ return Err(BindPushError::RequirementNotMet {
+ required_for: "`index_type` is `IndexType::U8`",
+ requires_one_of: RequiresOneOf {
+ features: &["index_type_uint8"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // TODO:
+ // VUID-vkCmdBindIndexBuffer-offset-00432
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn bind_index_buffer_unchecked(
+ &mut self,
+ buffer: Subbuffer<[u8]>,
+ index_type: IndexType,
+ ) -> &mut Self {
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_bind_index_buffer)(
+ self.handle(),
+ buffer.buffer().handle(),
+ buffer.offset(),
+ index_type.into(),
+ );
+
+ self.builder_state.index_buffer = Some((buffer.clone(), index_type));
+ self.resources.push(Box::new(buffer));
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Binds a compute pipeline for future dispatch calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support compute operations.
+ /// - Panics if `self` and `pipeline` do not belong to the same device.
+ pub fn bind_pipeline_compute(&mut self, pipeline: Arc<ComputePipeline>) -> &mut Self {
+ self.validate_bind_pipeline_compute(&pipeline).unwrap();
+
+ unsafe { self.bind_pipeline_compute_unchecked(pipeline) }
+ }
+
+ fn validate_bind_pipeline_compute(
+ &self,
+ pipeline: &ComputePipeline,
+ ) -> Result<(), BindPushError> {
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdBindPipeline-pipelineBindPoint-00777
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::COMPUTE)
+ {
+ return Err(BindPushError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdBindPipeline-commonparent
+ assert_eq!(self.device(), pipeline.device());
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn bind_pipeline_compute_unchecked(
+ &mut self,
+ pipeline: Arc<ComputePipeline>,
+ ) -> &mut Self {
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_bind_pipeline)(
+ self.handle(),
+ ash::vk::PipelineBindPoint::COMPUTE,
+ pipeline.handle(),
+ );
+
+ self.builder_state.pipeline_compute = Some(pipeline.clone());
+ self.resources.push(Box::new(pipeline));
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Binds a graphics pipeline for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if `self` and `pipeline` do not belong to the same device.
+ pub fn bind_pipeline_graphics(&mut self, pipeline: Arc<GraphicsPipeline>) -> &mut Self {
+ self.validate_bind_pipeline_graphics(&pipeline).unwrap();
+
+ unsafe { self.bind_pipeline_graphics_unchecked(pipeline) }
+ }
+
+ fn validate_bind_pipeline_graphics(
+ &self,
+ pipeline: &GraphicsPipeline,
+ ) -> Result<(), BindPushError> {
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdBindPipeline-pipelineBindPoint-00778
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(BindPushError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdBindPipeline-commonparent
+ assert_eq!(self.device(), pipeline.device());
+
+ if let Some(last_pipeline) =
+ self.builder_state
+ .render_pass
+ .as_ref()
+ .and_then(|render_pass_state| match &render_pass_state.render_pass {
+ RenderPassStateType::BeginRendering(state) if state.pipeline_used => {
+ self.builder_state.pipeline_graphics.as_ref()
+ }
+ _ => None,
+ })
+ {
+ if let (
+ PipelineRenderPassType::BeginRendering(pipeline_rendering_info),
+ PipelineRenderPassType::BeginRendering(last_pipeline_rendering_info),
+ ) = (pipeline.render_pass(), last_pipeline.render_pass())
+ {
+ // VUID-vkCmdBindPipeline-pipeline-06195
+ // VUID-vkCmdBindPipeline-pipeline-06196
+ if pipeline_rendering_info.color_attachment_formats
+ != last_pipeline_rendering_info.color_attachment_formats
+ {
+ return Err(BindPushError::PreviousPipelineColorAttachmentFormatMismatch);
+ }
+
+ // VUID-vkCmdBindPipeline-pipeline-06197
+ if pipeline_rendering_info.depth_attachment_format
+ != last_pipeline_rendering_info.depth_attachment_format
+ {
+ return Err(BindPushError::PreviousPipelineDepthAttachmentFormatMismatch);
+ }
+
+ // VUID-vkCmdBindPipeline-pipeline-06194
+ if pipeline_rendering_info.stencil_attachment_format
+ != last_pipeline_rendering_info.stencil_attachment_format
+ {
+ return Err(BindPushError::PreviousPipelineStencilAttachmentFormatMismatch);
+ }
+ }
+ }
+
+ // VUID-vkCmdBindPipeline-pipeline-00781
+ // TODO:
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn bind_pipeline_graphics_unchecked(
+ &mut self,
+ pipeline: Arc<GraphicsPipeline>,
+ ) -> &mut Self {
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_bind_pipeline)(
+ self.handle(),
+ ash::vk::PipelineBindPoint::GRAPHICS,
+ pipeline.handle(),
+ );
+
+ // Reset any states that are fixed in the new pipeline. The pipeline bind command will
+ // overwrite these states.
+ self.builder_state.reset_dynamic_states(
+ pipeline
+ .dynamic_states()
+ .filter(|(_, d)| !d) // not dynamic
+ .map(|(s, _)| s),
+ );
+ self.builder_state.pipeline_graphics = Some(pipeline.clone());
+ self.resources.push(Box::new(pipeline));
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Binds vertex buffers for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the highest vertex buffer binding being bound is greater than the
+ /// [`max_vertex_input_bindings`] device property.
+ /// - Panics if `self` and any element of `vertex_buffers` do not belong to the same device.
+ /// - Panics if any element of `vertex_buffers` does not have the
+ /// [`BufferUsage::VERTEX_BUFFER`] usage enabled.
+ ///
+ /// [`max_vertex_input_bindings`]: crate::device::Properties::max_vertex_input_bindings
+ /// [`BufferUsage::VERTEX_BUFFER`]: crate::buffer::BufferUsage::VERTEX_BUFFER
+ pub fn bind_vertex_buffers(
+ &mut self,
+ first_binding: u32,
+ vertex_buffers: impl VertexBuffersCollection,
+ ) -> &mut Self {
+ let vertex_buffers = vertex_buffers.into_vec();
+ self.validate_bind_vertex_buffers(first_binding, &vertex_buffers)
+ .unwrap();
+
+ unsafe { self.bind_vertex_buffers_unchecked(first_binding, vertex_buffers) }
+ }
+
+ fn validate_bind_vertex_buffers(
+ &self,
+ first_binding: u32,
+ vertex_buffers: &[Subbuffer<[u8]>],
+ ) -> Result<(), BindPushError> {
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdBindVertexBuffers-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(BindPushError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdBindVertexBuffers-firstBinding-00624
+ // VUID-vkCmdBindVertexBuffers-firstBinding-00625
+ if first_binding + vertex_buffers.len() as u32
+ > self
+ .device()
+ .physical_device()
+ .properties()
+ .max_vertex_input_bindings
+ {
+ return Err(BindPushError::MaxVertexInputBindingsExceeded {
+ _binding_count: first_binding + vertex_buffers.len() as u32,
+ _max: self
+ .device()
+ .physical_device()
+ .properties()
+ .max_vertex_input_bindings,
+ });
+ }
+
+ for buffer in vertex_buffers {
+ // VUID-vkCmdBindVertexBuffers-commonparent
+ assert_eq!(self.device(), buffer.device());
+
+ // VUID-vkCmdBindVertexBuffers-pBuffers-00627
+ if !buffer
+ .buffer()
+ .usage()
+ .intersects(BufferUsage::VERTEX_BUFFER)
+ {
+ return Err(BindPushError::VertexBufferMissingUsage);
+ }
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn bind_vertex_buffers_unchecked(
+ &mut self,
+ first_binding: u32,
+ buffers: impl VertexBuffersCollection,
+ ) -> &mut Self {
+ let buffers = buffers.into_vec();
+
+ if buffers.is_empty() {
+ return self;
+ }
+
+ let (buffers_vk, offsets_vk): (SmallVec<[_; 4]>, SmallVec<[_; 4]>) = buffers
+ .iter()
+ .map(|buffer| (buffer.buffer().handle(), buffer.offset()))
+ .unzip();
+
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_bind_vertex_buffers)(
+ self.handle(),
+ first_binding,
+ buffers_vk.len() as u32,
+ buffers_vk.as_ptr(),
+ offsets_vk.as_ptr(),
+ );
+
+ self.resources.reserve(buffers.len());
+
+ for (i, buffer) in buffers.into_iter().enumerate() {
+ self.builder_state
+ .vertex_buffers
+ .insert(first_binding + i as u32, buffer.clone());
+ self.resources.push(Box::new(buffer));
+ }
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Sets push constants for future dispatch or draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `offset` is not a multiple of 4.
+ /// - Panics if the size of `push_constants` is not a multiple of 4.
+ /// - Panics if any of the bytes in `push_constants` do not fall within any of the pipeline
+ /// layout's push constant ranges.
+ pub fn push_constants(
+ &mut self,
+ pipeline_layout: Arc<PipelineLayout>,
+ offset: u32,
+ push_constants: &(impl BufferContents + ?Sized),
+ ) -> &mut Self {
+ self.validate_push_constants(&pipeline_layout, offset, size_of_val(push_constants) as u32)
+ .unwrap();
+
+ unsafe { self.push_constants_unchecked(pipeline_layout, offset, push_constants) }
+ }
+
+ fn validate_push_constants(
+ &self,
+ pipeline_layout: &PipelineLayout,
+ offset: u32,
+ data_size: u32,
+ ) -> Result<(), BindPushError> {
+ if offset % 4 != 0 {
+ return Err(BindPushError::PushConstantsOffsetNotAligned);
+ }
+
+ if data_size % 4 != 0 {
+ return Err(BindPushError::PushConstantsSizeNotAligned);
+ }
+
+ let mut current_offset = offset;
+ let mut remaining_size = data_size;
+
+ for range in pipeline_layout
+ .push_constant_ranges_disjoint()
+ .iter()
+ .skip_while(|range| range.offset + range.size <= offset)
+ {
+ // there is a gap between ranges, but the passed push_constants contains
+ // some bytes in this gap, exit the loop and report error
+ if range.offset > current_offset {
+ break;
+ }
+
+ // push the minimum of the whole remaining data, and the part until the end of this range
+ let push_size = remaining_size.min(range.offset + range.size - current_offset);
+ current_offset += push_size;
+ remaining_size -= push_size;
+
+ if remaining_size == 0 {
+ break;
+ }
+ }
+
+ if remaining_size != 0 {
+ return Err(BindPushError::PushConstantsDataOutOfRange {
+ offset: current_offset,
+ });
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn push_constants_unchecked(
+ &mut self,
+ pipeline_layout: Arc<PipelineLayout>,
+ offset: u32,
+ push_constants: &(impl BufferContents + ?Sized),
+ ) -> &mut Self {
+ let mut current_offset = offset;
+ let mut remaining_size = size_of_val(push_constants) as u32;
+
+ let fns = self.device().fns();
+
+ for range in pipeline_layout
+ .push_constant_ranges_disjoint()
+ .iter()
+ .skip_while(|range| range.offset + range.size <= offset)
+ {
+ // there is a gap between ranges, but the passed push_constants contains
+ // some bytes in this gap, exit the loop and report error
+ if range.offset > current_offset {
+ break;
+ }
+
+ // push the minimum of the whole remaining data, and the part until the end of this range
+ let push_size = min(remaining_size, range.offset + range.size - current_offset);
+ let data_offset = (current_offset - offset) as usize;
+
+ (fns.v1_0.cmd_push_constants)(
+ self.handle(),
+ pipeline_layout.handle(),
+ range.stages.into(),
+ current_offset,
+ push_size,
+ (push_constants as *const _ as *const c_void).add(data_offset),
+ );
+
+ current_offset += push_size;
+ remaining_size -= push_size;
+
+ if remaining_size == 0 {
+ break;
+ }
+ }
+
+ debug_assert!(remaining_size == 0);
+
+ // TODO: Push constant invalidations.
+ // The Vulkan spec currently is unclear about this, so Vulkano currently just marks
+ // push constants as set, and never unsets them. See:
+ // https://github.com/KhronosGroup/Vulkan-Docs/issues/1485
+ // https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/2711
+ self.builder_state
+ .push_constants
+ .insert(offset..offset + size_of_val(push_constants) as u32);
+ self.builder_state.push_constants_pipeline_layout = Some(pipeline_layout.clone());
+ self.resources.push(Box::new(pipeline_layout));
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Pushes descriptor data directly into the command buffer for future dispatch or draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support `pipeline_bind_point`.
+ /// - Panics if the [`khr_push_descriptor`] extension is not enabled on the device.
+ /// - Panics if `set_num` is not less than the number of sets in `pipeline_layout`.
+ /// - Panics if an element of `descriptor_writes` is not compatible with `pipeline_layout`.
+ ///
+ /// [`khr_push_descriptor`]: crate::device::DeviceExtensions::khr_push_descriptor
+ pub fn push_descriptor_set(
+ &mut self,
+ pipeline_bind_point: PipelineBindPoint,
+ pipeline_layout: Arc<PipelineLayout>,
+ set_num: u32,
+ descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>,
+ ) -> &mut Self {
+ let descriptor_writes: SmallVec<[_; 8]> = descriptor_writes.into_iter().collect();
+ self.validate_push_descriptor_set(
+ pipeline_bind_point,
+ &pipeline_layout,
+ set_num,
+ &descriptor_writes,
+ )
+ .unwrap();
+
+ unsafe {
+ self.push_descriptor_set_unchecked(
+ pipeline_bind_point,
+ pipeline_layout,
+ set_num,
+ descriptor_writes,
+ )
+ }
+ }
+
+ fn validate_push_descriptor_set(
+ &self,
+ pipeline_bind_point: PipelineBindPoint,
+ pipeline_layout: &PipelineLayout,
+ set_num: u32,
+ descriptor_writes: &[WriteDescriptorSet],
+ ) -> Result<(), BindPushError> {
+ if !self.device().enabled_extensions().khr_push_descriptor {
+ return Err(BindPushError::RequirementNotMet {
+ required_for: "`CommandBufferBuilder::push_descriptor_set`",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["khr_push_descriptor"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdPushDescriptorSetKHR-pipelineBindPoint-parameter
+ pipeline_bind_point.validate_device(self.device())?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdPushDescriptorSetKHR-commandBuffer-cmdpool
+ // VUID-vkCmdPushDescriptorSetKHR-pipelineBindPoint-00363
+ match pipeline_bind_point {
+ PipelineBindPoint::Compute => {
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::COMPUTE)
+ {
+ return Err(BindPushError::NotSupportedByQueueFamily);
+ }
+ }
+ PipelineBindPoint::Graphics => {
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(BindPushError::NotSupportedByQueueFamily);
+ }
+ }
+ }
+
+ // VUID-vkCmdPushDescriptorSetKHR-commonparent
+ assert_eq!(self.device(), pipeline_layout.device());
+
+ // VUID-vkCmdPushDescriptorSetKHR-set-00364
+ if set_num as usize > pipeline_layout.set_layouts().len() {
+ return Err(BindPushError::DescriptorSetOutOfRange {
+ set_num,
+ pipeline_layout_set_count: pipeline_layout.set_layouts().len() as u32,
+ });
+ }
+
+ let descriptor_set_layout = &pipeline_layout.set_layouts()[set_num as usize];
+
+ // VUID-vkCmdPushDescriptorSetKHR-set-00365
+ if !descriptor_set_layout.push_descriptor() {
+ return Err(BindPushError::DescriptorSetNotPush { set_num });
+ }
+
+ for write in descriptor_writes {
+ check_descriptor_write(write, descriptor_set_layout, 0)?;
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn push_descriptor_set_unchecked(
+ &mut self,
+ pipeline_bind_point: PipelineBindPoint,
+ pipeline_layout: Arc<PipelineLayout>,
+ set_num: u32,
+ descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>,
+ ) -> &mut Self {
+ let descriptor_writes: SmallVec<[WriteDescriptorSet; 8]> =
+ descriptor_writes.into_iter().collect();
+
+ debug_assert!(self.device().enabled_extensions().khr_push_descriptor);
+
+ let (infos, mut writes): (SmallVec<[_; 8]>, SmallVec<[_; 8]>) = descriptor_writes
+ .iter()
+ .map(|write| {
+ let binding =
+ &pipeline_layout.set_layouts()[set_num as usize].bindings()[&write.binding()];
+
+ (
+ write.to_vulkan_info(binding.descriptor_type),
+ write.to_vulkan(ash::vk::DescriptorSet::null(), binding.descriptor_type),
+ )
+ })
+ .unzip();
+
+ if writes.is_empty() {
+ return self;
+ }
+
+ // Set the info pointers separately.
+ for (info, write) in infos.iter().zip(writes.iter_mut()) {
+ match info {
+ DescriptorWriteInfo::Image(info) => {
+ write.descriptor_count = info.len() as u32;
+ write.p_image_info = info.as_ptr();
+ }
+ DescriptorWriteInfo::Buffer(info) => {
+ write.descriptor_count = info.len() as u32;
+ write.p_buffer_info = info.as_ptr();
+ }
+ DescriptorWriteInfo::BufferView(info) => {
+ write.descriptor_count = info.len() as u32;
+ write.p_texel_buffer_view = info.as_ptr();
+ }
+ }
+
+ debug_assert!(write.descriptor_count != 0);
+ }
+
+ let fns = self.device().fns();
+ (fns.khr_push_descriptor.cmd_push_descriptor_set_khr)(
+ self.handle(),
+ pipeline_bind_point.into(),
+ pipeline_layout.handle(),
+ set_num,
+ writes.len() as u32,
+ writes.as_ptr(),
+ );
+
+ let state = self.builder_state.invalidate_descriptor_sets(
+ pipeline_bind_point,
+ pipeline_layout.clone(),
+ set_num,
+ 1,
+ );
+ let descriptor_set_layout = state.pipeline_layout.set_layouts()[set_num as usize].as_ref();
+ debug_assert!(descriptor_set_layout.push_descriptor());
+
+ let set_resources = match state.descriptor_sets.entry(set_num).or_insert_with(|| {
+ SetOrPush::Push(DescriptorSetResources::new(descriptor_set_layout, 0))
+ }) {
+ SetOrPush::Push(set_resources) => set_resources,
+ _ => unreachable!(),
+ };
+
+ for write in &descriptor_writes {
+ set_resources.update(write);
+ }
+
+ self.resources.push(Box::new(pipeline_layout));
+
+ self.next_command_index += 1;
+ self
+ }
+}
diff --git a/src/command_buffer/standard/builder/clear.rs b/src/command_buffer/standard/builder/clear.rs
new file mode 100644
index 0000000..40ba941
--- /dev/null
+++ b/src/command_buffer/standard/builder/clear.rs
@@ -0,0 +1,742 @@
+// Copyright (c) 2022 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use super::{ClearColorImageInfo, ClearDepthStencilImageInfo, ClearError, CommandBufferBuilder};
+use crate::{
+ buffer::{BufferContents, BufferUsage, Subbuffer},
+ command_buffer::{allocator::CommandBufferAllocator, ResourceInCommand, ResourceUseRef},
+ device::{DeviceOwned, QueueFlags},
+ format::FormatFeatures,
+ image::{ImageAccess, ImageAspects, ImageLayout, ImageUsage},
+ sync::PipelineStageAccess,
+ DeviceSize, RequiresOneOf, Version, VulkanObject,
+};
+use smallvec::SmallVec;
+use std::mem::size_of_val;
+
+impl<L, A> CommandBufferBuilder<L, A>
+where
+ A: CommandBufferAllocator,
+{
+ /// Clears a color image with a specific value.
+ ///
+ /// # Safety
+ ///
+ /// - Appropriate synchronization must be provided for all images
+ /// that are accessed by the command.
+ /// - All images that are accessed by the command must be in the expected image layout.
+ #[inline]
+ pub unsafe fn clear_color_image(
+ &mut self,
+ clear_info: ClearColorImageInfo,
+ ) -> Result<&mut Self, ClearError> {
+ self.validate_clear_color_image(&clear_info)?;
+
+ unsafe { Ok(self.clear_color_image_unchecked(clear_info)) }
+ }
+
+ fn validate_clear_color_image(
+ &self,
+ clear_info: &ClearColorImageInfo,
+ ) -> Result<(), ClearError> {
+ let device = self.device();
+
+ // VUID-vkCmdClearColorImage-renderpass
+ if self.builder_state.render_pass.is_some() {
+ return Err(ClearError::ForbiddenInsideRenderPass);
+ }
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdClearColorImage-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(ClearError::NotSupportedByQueueFamily);
+ }
+
+ let &ClearColorImageInfo {
+ ref image,
+ image_layout,
+ clear_value: _,
+ ref regions,
+ _ne: _,
+ } = clear_info;
+
+ // VUID-vkCmdClearColorImage-imageLayout-parameter
+ image_layout.validate_device(device)?;
+
+ // VUID-vkCmdClearColorImage-commonparent
+ assert_eq!(device, image.device());
+
+ // VUID-vkCmdClearColorImage-image-00002
+ if !image.usage().intersects(ImageUsage::TRANSFER_DST) {
+ return Err(ClearError::MissingUsage {
+ usage: "transfer_dst",
+ });
+ }
+
+ if device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_maintenance1 {
+ // VUID-vkCmdClearColorImage-image-01993
+ if !image
+ .format_features()
+ .intersects(FormatFeatures::TRANSFER_DST)
+ {
+ return Err(ClearError::MissingFormatFeature {
+ format_feature: "transfer_dst",
+ });
+ }
+ }
+
+ let image_aspects = image.format().aspects();
+
+ // VUID-vkCmdClearColorImage-image-00007
+ if image_aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL) {
+ return Err(ClearError::FormatNotSupported {
+ format: image.format(),
+ });
+ }
+
+ // VUID-vkCmdClearColorImage-image-00007
+ if image.format().compression().is_some() {
+ return Err(ClearError::FormatNotSupported {
+ format: image.format(),
+ });
+ }
+
+ // VUID-vkCmdClearColorImage-image-01545
+ if image.format().ycbcr_chroma_sampling().is_some() {
+ return Err(ClearError::FormatNotSupported {
+ format: image.format(),
+ });
+ }
+
+ // VUID-vkCmdClearColorImage-imageLayout-01394
+ if !matches!(
+ image_layout,
+ ImageLayout::TransferDstOptimal | ImageLayout::General
+ ) {
+ return Err(ClearError::ImageLayoutInvalid { image_layout });
+ }
+
+ for (region_index, subresource_range) in regions.iter().enumerate() {
+ // VUID-VkImageSubresourceRange-aspectMask-parameter
+ subresource_range.aspects.validate_device(device)?;
+
+ // VUID-VkImageSubresourceRange-aspectMask-requiredbitmask
+ assert!(!subresource_range.aspects.is_empty());
+
+ // VUID-vkCmdClearColorImage-aspectMask-02498
+ if !image_aspects.contains(subresource_range.aspects) {
+ return Err(ClearError::AspectsNotAllowed {
+ region_index,
+ aspects: subresource_range.aspects,
+ allowed_aspects: image_aspects,
+ });
+ }
+
+ // VUID-VkImageSubresourceRange-levelCount-01720
+ assert!(!subresource_range.mip_levels.is_empty());
+
+ // VUID-vkCmdClearColorImage-baseMipLevel-01470
+ // VUID-vkCmdClearColorImage-pRanges-01692
+ if subresource_range.mip_levels.end > image.mip_levels() {
+ return Err(ClearError::MipLevelsOutOfRange {
+ region_index,
+ mip_levels_range_end: subresource_range.mip_levels.end,
+ image_mip_levels: image.dimensions().array_layers(),
+ });
+ }
+
+ // VUID-VkImageSubresourceRange-layerCount-01721
+ assert!(!subresource_range.array_layers.is_empty());
+
+ // VUID-vkCmdClearDepthStencilImage-baseArrayLayer-01476
+ // VUID-vkCmdClearDepthStencilImage-pRanges-01695
+ if subresource_range.array_layers.end > image.dimensions().array_layers() {
+ return Err(ClearError::ArrayLayersOutOfRange {
+ region_index,
+ array_layers_range_end: subresource_range.array_layers.end,
+ image_array_layers: image.dimensions().array_layers(),
+ });
+ }
+ }
+
+ // TODO: sync check
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn clear_color_image_unchecked(
+ &mut self,
+ clear_info: ClearColorImageInfo,
+ ) -> &mut Self {
+ let ClearColorImageInfo {
+ image,
+ image_layout,
+ clear_value,
+ regions,
+ _ne: _,
+ } = clear_info;
+
+ if regions.is_empty() {
+ return self;
+ }
+
+ let image_inner = image.inner();
+ let clear_value = clear_value.into();
+ let ranges: SmallVec<[_; 8]> = regions
+ .iter()
+ .cloned()
+ .map(ash::vk::ImageSubresourceRange::from)
+ .collect();
+
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_clear_color_image)(
+ self.handle(),
+ image_inner.image.handle(),
+ image_layout.into(),
+ &clear_value,
+ ranges.len() as u32,
+ ranges.as_ptr(),
+ );
+
+ let command_index = self.next_command_index;
+ let command_name = "clear_color_image";
+ let use_ref = ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Destination,
+ secondary_use_ref: None,
+ };
+
+ for mut subresource_range in regions {
+ subresource_range.array_layers.start += image_inner.first_layer;
+ subresource_range.array_layers.end += image_inner.first_layer;
+ subresource_range.mip_levels.start += image_inner.first_mipmap_level;
+ subresource_range.mip_levels.end += image_inner.first_mipmap_level;
+
+ self.resources_usage_state.record_image_access(
+ &use_ref,
+ image_inner.image,
+ subresource_range,
+ PipelineStageAccess::Clear_TransferWrite,
+ image_layout,
+ );
+ }
+
+ self.resources.push(Box::new(image));
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Clears a depth/stencil image with a specific value.
+ ///
+ /// # Safety
+ ///
+ /// - Appropriate synchronization must be provided for all images
+ /// that are accessed by the command.
+ /// - All images that are accessed by the command must be in the expected image layout.
+ #[inline]
+ pub unsafe fn clear_depth_stencil_image(
+ &mut self,
+ clear_info: ClearDepthStencilImageInfo,
+ ) -> Result<&mut Self, ClearError> {
+ self.validate_clear_depth_stencil_image(&clear_info)?;
+
+ unsafe { Ok(self.clear_depth_stencil_image_unchecked(clear_info)) }
+ }
+
+ fn validate_clear_depth_stencil_image(
+ &self,
+ clear_info: &ClearDepthStencilImageInfo,
+ ) -> Result<(), ClearError> {
+ let device = self.device();
+
+ // VUID-vkCmdClearDepthStencilImage-renderpass
+ if self.builder_state.render_pass.is_some() {
+ return Err(ClearError::ForbiddenInsideRenderPass);
+ }
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdClearDepthStencilImage-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(ClearError::NotSupportedByQueueFamily);
+ }
+
+ let &ClearDepthStencilImageInfo {
+ ref image,
+ image_layout,
+ clear_value,
+ ref regions,
+ _ne: _,
+ } = clear_info;
+
+ // VUID-vkCmdClearDepthStencilImage-imageLayout-parameter
+ image_layout.validate_device(device)?;
+
+ // VUID-vkCmdClearDepthStencilImage-commonparent
+ assert_eq!(device, image.device());
+
+ if device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_maintenance1 {
+ // VUID-vkCmdClearDepthStencilImage-image-01994
+ if !image
+ .format_features()
+ .intersects(FormatFeatures::TRANSFER_DST)
+ {
+ return Err(ClearError::MissingFormatFeature {
+ format_feature: "transfer_dst",
+ });
+ }
+ }
+
+ let image_aspects = image.format().aspects();
+
+ // VUID-vkCmdClearDepthStencilImage-image-00014
+ if !image_aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL) {
+ return Err(ClearError::FormatNotSupported {
+ format: image.format(),
+ });
+ }
+
+ // VUID-vkCmdClearDepthStencilImage-imageLayout-00012
+ if !matches!(
+ image_layout,
+ ImageLayout::TransferDstOptimal | ImageLayout::General
+ ) {
+ return Err(ClearError::ImageLayoutInvalid { image_layout });
+ }
+
+ // VUID-VkClearDepthStencilValue-depth-00022
+ if !device.enabled_extensions().ext_depth_range_unrestricted
+ && !(0.0..=1.0).contains(&clear_value.depth)
+ {
+ return Err(ClearError::RequirementNotMet {
+ required_for: "`clear_info.clear_value.depth` is not between `0.0` and `1.0` \
+ inclusive",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["ext_depth_range_unrestricted"],
+ ..Default::default()
+ },
+ });
+ }
+
+ let mut image_aspects_used = ImageAspects::empty();
+
+ for (region_index, subresource_range) in regions.iter().enumerate() {
+ // VUID-VkImageSubresourceRange-aspectMask-parameter
+ subresource_range.aspects.validate_device(device)?;
+
+ // VUID-VkImageSubresourceRange-aspectMask-requiredbitmask
+ assert!(!subresource_range.aspects.is_empty());
+
+ // VUID-vkCmdClearDepthStencilImage-aspectMask-02824
+ // VUID-vkCmdClearDepthStencilImage-image-02825
+ // VUID-vkCmdClearDepthStencilImage-image-02826
+ if !image_aspects.contains(subresource_range.aspects) {
+ return Err(ClearError::AspectsNotAllowed {
+ region_index,
+ aspects: subresource_range.aspects,
+ allowed_aspects: image_aspects,
+ });
+ }
+
+ image_aspects_used |= subresource_range.aspects;
+
+ // VUID-VkImageSubresourceRange-levelCount-01720
+ assert!(!subresource_range.mip_levels.is_empty());
+
+ // VUID-vkCmdClearDepthStencilImage-baseMipLevel-01474
+ // VUID-vkCmdClearDepthStencilImage-pRanges-01694
+ if subresource_range.mip_levels.end > image.mip_levels() {
+ return Err(ClearError::MipLevelsOutOfRange {
+ region_index,
+ mip_levels_range_end: subresource_range.mip_levels.end,
+ image_mip_levels: image.dimensions().array_layers(),
+ });
+ }
+
+ // VUID-VkImageSubresourceRange-layerCount-01721
+ assert!(!subresource_range.array_layers.is_empty());
+
+ // VUID-vkCmdClearDepthStencilImage-baseArrayLayer-01476
+ // VUID-vkCmdClearDepthStencilImage-pRanges-01695
+ if subresource_range.array_layers.end > image.dimensions().array_layers() {
+ return Err(ClearError::ArrayLayersOutOfRange {
+ region_index,
+ array_layers_range_end: subresource_range.array_layers.end,
+ image_array_layers: image.dimensions().array_layers(),
+ });
+ }
+ }
+
+ // VUID-vkCmdClearDepthStencilImage-pRanges-02658
+ // VUID-vkCmdClearDepthStencilImage-pRanges-02659
+ if image_aspects_used.intersects(ImageAspects::STENCIL)
+ && !image.stencil_usage().intersects(ImageUsage::TRANSFER_DST)
+ {
+ return Err(ClearError::MissingUsage {
+ usage: "transfer_dst",
+ });
+ }
+
+ // VUID-vkCmdClearDepthStencilImage-pRanges-02660
+ if !(image_aspects_used - ImageAspects::STENCIL).is_empty()
+ && !image.usage().intersects(ImageUsage::TRANSFER_DST)
+ {
+ return Err(ClearError::MissingUsage {
+ usage: "transfer_dst",
+ });
+ }
+
+ // TODO: sync check
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn clear_depth_stencil_image_unchecked(
+ &mut self,
+ clear_info: ClearDepthStencilImageInfo,
+ ) -> &mut Self {
+ let ClearDepthStencilImageInfo {
+ image,
+ image_layout,
+ clear_value,
+ regions,
+ _ne: _,
+ } = clear_info;
+
+ if regions.is_empty() {
+ return self;
+ }
+
+ let image_inner = image.inner();
+ let clear_value = clear_value.into();
+ let ranges: SmallVec<[_; 8]> = regions
+ .iter()
+ .cloned()
+ .map(ash::vk::ImageSubresourceRange::from)
+ .collect();
+
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_clear_depth_stencil_image)(
+ self.handle(),
+ image_inner.image.handle(),
+ image_layout.into(),
+ &clear_value,
+ ranges.len() as u32,
+ ranges.as_ptr(),
+ );
+
+ let command_index = self.next_command_index;
+ let command_name = "clear_depth_stencil_image";
+ let use_ref = ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Destination,
+ secondary_use_ref: None,
+ };
+
+ for mut subresource_range in regions {
+ subresource_range.array_layers.start += image_inner.first_layer;
+ subresource_range.array_layers.end += image_inner.first_layer;
+ subresource_range.mip_levels.start += image_inner.first_mipmap_level;
+ subresource_range.mip_levels.end += image_inner.first_mipmap_level;
+
+ self.resources_usage_state.record_image_access(
+ &use_ref,
+ image_inner.image,
+ subresource_range,
+ PipelineStageAccess::Clear_TransferWrite,
+ image_layout,
+ );
+ }
+
+ self.resources.push(Box::new(image));
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Fills a region of a buffer with repeated copies of a value.
+ ///
+ /// This function is similar to the `memset` function in C. The `data` parameter is a number
+ /// that will be repeatedly written through the entire buffer.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `dst_buffer` was not created from the same device as `self`.
+ ///
+ /// # Safety
+ ///
+ /// - Appropriate synchronization must be provided for all buffers
+ /// that are accessed by the command.
+ #[inline]
+ pub unsafe fn fill_buffer(
+ &mut self,
+ dst_buffer: Subbuffer<[u32]>,
+ data: u32,
+ ) -> Result<&mut Self, ClearError> {
+ self.validate_fill_buffer(&dst_buffer, data)?;
+
+ unsafe { Ok(self.fill_buffer_unchecked(dst_buffer, data)) }
+ }
+
+ fn validate_fill_buffer(
+ &self,
+ dst_buffer: &Subbuffer<[u32]>,
+ _data: u32,
+ ) -> Result<(), ClearError> {
+ let device = self.device();
+
+ // VUID-vkCmdFillBuffer-renderpass
+ if self.builder_state.render_pass.is_some() {
+ return Err(ClearError::ForbiddenInsideRenderPass);
+ }
+
+ let queue_family_properties = self.queue_family_properties();
+
+ if device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_maintenance1 {
+ // VUID-vkCmdFillBuffer-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::TRANSFER | QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(ClearError::NotSupportedByQueueFamily);
+ }
+ } else {
+ // VUID-vkCmdFillBuffer-commandBuffer-00030
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(ClearError::NotSupportedByQueueFamily);
+ }
+ }
+
+ // VUID-vkCmdFillBuffer-commonparent
+ assert_eq!(device, dst_buffer.device());
+
+ // VUID-vkCmdFillBuffer-size-00026
+ // Guaranteed by `Subbuffer`
+
+ // VUID-vkCmdFillBuffer-dstBuffer-00029
+ if !dst_buffer
+ .buffer()
+ .usage()
+ .intersects(BufferUsage::TRANSFER_DST)
+ {
+ return Err(ClearError::MissingUsage {
+ usage: "transfer_dst",
+ });
+ }
+
+ // VUID-vkCmdFillBuffer-dstOffset-00024
+ // VUID-vkCmdFillBuffer-size-00027
+ // Guaranteed by `Subbuffer`
+
+ // VUID-vkCmdFillBuffer-dstOffset-00025
+ // VUID-vkCmdFillBuffer-size-00028
+ // Guaranteed because we take `Subbuffer<[u32]>`
+
+ // TODO: sync check
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn fill_buffer_unchecked(
+ &mut self,
+ dst_buffer: Subbuffer<[u32]>,
+ data: u32,
+ ) -> &mut Self {
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_fill_buffer)(
+ self.handle(),
+ dst_buffer.buffer().handle(),
+ dst_buffer.offset(),
+ dst_buffer.size(),
+ data,
+ );
+
+ let command_index = self.next_command_index;
+ let command_name = "fill_buffer";
+ let use_ref = ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Destination,
+ secondary_use_ref: None,
+ };
+
+ self.resources_usage_state.record_buffer_access(
+ &use_ref,
+ dst_buffer.buffer(),
+ dst_buffer.range(),
+ PipelineStageAccess::Clear_TransferWrite,
+ );
+
+ self.resources.push(Box::new(dst_buffer));
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Writes data to a region of a buffer.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `dst_buffer` was not created from the same device as `self`.
+ ///
+ /// # Safety
+ ///
+ /// - Appropriate synchronization must be provided for all buffers
+ /// that are accessed by the command.
+ #[inline]
+ pub unsafe fn update_buffer<D>(
+ &mut self,
+ dst_buffer: Subbuffer<D>,
+ data: &D,
+ ) -> Result<&mut Self, ClearError>
+ where
+ D: BufferContents + ?Sized,
+ {
+ self.validate_update_buffer(dst_buffer.as_bytes(), size_of_val(data) as DeviceSize)?;
+
+ unsafe { Ok(self.update_buffer_unchecked(dst_buffer, data)) }
+ }
+
+ fn validate_update_buffer(
+ &self,
+ dst_buffer: &Subbuffer<[u8]>,
+ data_size: DeviceSize,
+ ) -> Result<(), ClearError> {
+ let device = self.device();
+
+ // VUID-vkCmdUpdateBuffer-renderpass
+ if self.builder_state.render_pass.is_some() {
+ return Err(ClearError::ForbiddenInsideRenderPass);
+ }
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdUpdateBuffer-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::TRANSFER | QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(ClearError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdUpdateBuffer-commonparent
+ assert_eq!(device, dst_buffer.device());
+
+ // VUID-vkCmdUpdateBuffer-dataSize-arraylength
+ assert!(data_size != 0);
+
+ // VUID-vkCmdUpdateBuffer-dstBuffer-00034
+ if !dst_buffer
+ .buffer()
+ .usage()
+ .intersects(BufferUsage::TRANSFER_DST)
+ {
+ return Err(ClearError::MissingUsage {
+ usage: "transfer_dst",
+ });
+ }
+
+ // VUID-vkCmdUpdateBuffer-dstOffset-00032
+ // VUID-vkCmdUpdateBuffer-dataSize-00033
+ if data_size > dst_buffer.size() {
+ return Err(ClearError::RegionOutOfBufferBounds {
+ region_index: 0,
+ offset_range_end: data_size,
+ buffer_size: dst_buffer.size(),
+ });
+ }
+
+ // VUID-vkCmdUpdateBuffer-dstOffset-00036
+ if dst_buffer.offset() % 4 != 0 {
+ return Err(ClearError::OffsetNotAlignedForBuffer {
+ region_index: 0,
+ offset: dst_buffer.offset(),
+ required_alignment: 4,
+ });
+ }
+
+ // VUID-vkCmdUpdateBuffer-dataSize-00037
+ if data_size > 65536 {
+ return Err(ClearError::DataTooLarge {
+ size: data_size,
+ max: 65536,
+ });
+ }
+
+ // VUID-vkCmdUpdateBuffer-dataSize-00038
+ if data_size % 4 != 0 {
+ return Err(ClearError::SizeNotAlignedForBuffer {
+ region_index: 0,
+ size: data_size,
+ required_alignment: 4,
+ });
+ }
+
+ // TODO: sync check
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn update_buffer_unchecked<D>(
+ &mut self,
+ dst_buffer: Subbuffer<D>,
+ data: &D,
+ ) -> &mut Self
+ where
+ D: BufferContents + ?Sized,
+ {
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_update_buffer)(
+ self.handle(),
+ dst_buffer.buffer().handle(),
+ dst_buffer.offset(),
+ size_of_val(data) as DeviceSize,
+ data as *const _ as *const _,
+ );
+
+ let command_index = self.next_command_index;
+ let command_name = "update_buffer";
+ let use_ref = ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Destination,
+ secondary_use_ref: None,
+ };
+
+ let dst_range = dst_buffer.offset()..dst_buffer.offset() + size_of_val(data) as DeviceSize;
+ self.resources_usage_state.record_buffer_access(
+ &use_ref,
+ dst_buffer.buffer(),
+ dst_range,
+ PipelineStageAccess::Clear_TransferWrite,
+ );
+
+ self.resources.push(Box::new(dst_buffer));
+
+ self.next_command_index += 1;
+ self
+ }
+}
diff --git a/src/command_buffer/standard/builder/copy.rs b/src/command_buffer/standard/builder/copy.rs
new file mode 100644
index 0000000..4d80e2a
--- /dev/null
+++ b/src/command_buffer/standard/builder/copy.rs
@@ -0,0 +1,3729 @@
+// Copyright (c) 2022 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use super::{
+ BlitImageInfo, BufferCopy, BufferImageCopy, CommandBufferBuilder, CopyBufferInfo,
+ CopyBufferToImageInfo, CopyError, CopyErrorResource, CopyImageInfo, CopyImageToBufferInfo,
+ ImageCopy, ResolveImageInfo,
+};
+use crate::{
+ buffer::BufferUsage,
+ command_buffer::{
+ allocator::CommandBufferAllocator, ImageBlit, ImageResolve, ResourceInCommand,
+ ResourceUseRef,
+ },
+ device::{DeviceOwned, QueueFlags},
+ format::{Format, FormatFeatures, NumericType},
+ image::{
+ ImageAccess, ImageAspects, ImageDimensions, ImageLayout, ImageSubresourceLayers,
+ ImageSubresourceRange, ImageType, ImageUsage, SampleCount, SampleCounts,
+ },
+ sampler::Filter,
+ sync::PipelineStageAccess,
+ DeviceSize, Version, VulkanObject,
+};
+use smallvec::SmallVec;
+use std::cmp::{max, min};
+
+impl<L, A> CommandBufferBuilder<L, A>
+where
+ A: CommandBufferAllocator,
+{
+ /// Copies data from a buffer to another buffer.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `src_buffer` or `dst_buffer` were not created from the same device
+ /// as `self`.
+ ///
+ /// # Safety
+ ///
+ /// - Appropriate synchronization must be provided for all buffers
+ /// that are accessed by the command.
+ #[inline]
+ pub unsafe fn copy_buffer(
+ &mut self,
+ copy_buffer_info: impl Into<CopyBufferInfo>,
+ ) -> Result<&mut Self, CopyError> {
+ let copy_buffer_info = copy_buffer_info.into();
+ self.validate_copy_buffer(&copy_buffer_info)?;
+
+ unsafe { Ok(self.copy_buffer_unchecked(copy_buffer_info)) }
+ }
+
+ fn validate_copy_buffer(&self, copy_buffer_info: &CopyBufferInfo) -> Result<(), CopyError> {
+ let device = self.device();
+
+ // VUID-vkCmdCopyBuffer2-renderpass
+ if self.builder_state.render_pass.is_some() {
+ return Err(CopyError::ForbiddenInsideRenderPass);
+ }
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdCopyBuffer2-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::TRANSFER | QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(CopyError::NotSupportedByQueueFamily);
+ }
+
+ let &CopyBufferInfo {
+ ref src_buffer,
+ ref dst_buffer,
+ ref regions,
+ _ne: _,
+ } = copy_buffer_info;
+
+ // VUID-VkCopyBufferInfo2-commonparent
+ assert_eq!(device, src_buffer.device());
+ assert_eq!(device, dst_buffer.device());
+
+ // VUID-VkCopyBufferInfo2-srcBuffer-00118
+ if !src_buffer
+ .buffer()
+ .usage()
+ .intersects(BufferUsage::TRANSFER_SRC)
+ {
+ return Err(CopyError::MissingUsage {
+ resource: CopyErrorResource::Source,
+ usage: "transfer_src",
+ });
+ }
+
+ // VUID-VkCopyBufferInfo2-dstBuffer-00120
+ if !dst_buffer
+ .buffer()
+ .usage()
+ .intersects(BufferUsage::TRANSFER_DST)
+ {
+ return Err(CopyError::MissingUsage {
+ resource: CopyErrorResource::Destination,
+ usage: "transfer_dst",
+ });
+ }
+
+ let same_buffer = src_buffer.buffer() == dst_buffer.buffer();
+ let mut overlap_indices = None;
+
+ for (region_index, region) in regions.iter().enumerate() {
+ let &BufferCopy {
+ src_offset,
+ dst_offset,
+ size,
+ _ne: _,
+ } = region;
+
+ // VUID-VkBufferCopy2-size-01988
+ assert!(size != 0);
+
+ // VUID-VkCopyBufferInfo2-srcOffset-00113
+ // VUID-VkCopyBufferInfo2-size-00115
+ if src_offset + size > src_buffer.size() {
+ return Err(CopyError::RegionOutOfBufferBounds {
+ resource: CopyErrorResource::Source,
+ region_index,
+ offset_range_end: src_offset + size,
+ buffer_size: src_buffer.size(),
+ });
+ }
+
+ // VUID-VkCopyBufferInfo2-dstOffset-00114
+ // VUID-VkCopyBufferInfo2-size-00116
+ if dst_offset + size > dst_buffer.size() {
+ return Err(CopyError::RegionOutOfBufferBounds {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ offset_range_end: dst_offset + size,
+ buffer_size: dst_buffer.size(),
+ });
+ }
+
+ // VUID-VkCopyBufferInfo2-pRegions-00117
+ if same_buffer {
+ let src_region_index = region_index;
+ let src_range =
+ src_buffer.offset() + src_offset..src_buffer.offset() + src_offset + size;
+
+ for (dst_region_index, dst_region) in regions.iter().enumerate() {
+ let &BufferCopy { dst_offset, .. } = dst_region;
+
+ let dst_range =
+ dst_buffer.offset() + dst_offset..dst_buffer.offset() + dst_offset + size;
+
+ if src_range.start >= dst_range.end || dst_range.start >= src_range.end {
+ // The regions do not overlap
+ continue;
+ }
+
+ overlap_indices = Some((src_region_index, dst_region_index));
+ }
+ }
+ }
+
+ // VUID-VkCopyBufferInfo2-pRegions-00117
+ if let Some((src_region_index, dst_region_index)) = overlap_indices {
+ return Err(CopyError::OverlappingRegions {
+ src_region_index,
+ dst_region_index,
+ });
+ }
+
+ // TODO: sync check
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn copy_buffer_unchecked(
+ &mut self,
+ copy_buffer_info: impl Into<CopyBufferInfo>,
+ ) -> &mut Self {
+ let copy_buffer_info = copy_buffer_info.into();
+ let CopyBufferInfo {
+ src_buffer,
+ dst_buffer,
+ regions,
+ _ne: _,
+ } = copy_buffer_info;
+
+ if regions.is_empty() {
+ return self;
+ }
+
+ let fns = self.device().fns();
+
+ if self.device().api_version() >= Version::V1_3
+ || self.device().enabled_extensions().khr_copy_commands2
+ {
+ let regions: SmallVec<[_; 8]> = regions
+ .iter()
+ .map(|region| {
+ let &BufferCopy {
+ src_offset,
+ dst_offset,
+ size,
+ _ne,
+ } = region;
+
+ ash::vk::BufferCopy2 {
+ src_offset: src_offset + src_buffer.offset(),
+ dst_offset: dst_offset + dst_buffer.offset(),
+ size,
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let copy_buffer_info = ash::vk::CopyBufferInfo2 {
+ src_buffer: src_buffer.buffer().handle(),
+ dst_buffer: dst_buffer.buffer().handle(),
+ region_count: regions.len() as u32,
+ p_regions: regions.as_ptr(),
+ ..Default::default()
+ };
+
+ if self.device().api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_copy_buffer2)(self.handle(), &copy_buffer_info);
+ } else {
+ (fns.khr_copy_commands2.cmd_copy_buffer2_khr)(self.handle(), &copy_buffer_info);
+ }
+ } else {
+ let regions: SmallVec<[_; 8]> = regions
+ .iter()
+ .map(|region| {
+ let &BufferCopy {
+ src_offset,
+ dst_offset,
+ size,
+ _ne,
+ } = region;
+
+ ash::vk::BufferCopy {
+ src_offset: src_offset + src_buffer.offset(),
+ dst_offset: dst_offset + dst_buffer.offset(),
+ size,
+ }
+ })
+ .collect();
+
+ (fns.v1_0.cmd_copy_buffer)(
+ self.handle(),
+ src_buffer.buffer().handle(),
+ dst_buffer.buffer().handle(),
+ regions.len() as u32,
+ regions.as_ptr(),
+ );
+ }
+
+ let command_index = self.next_command_index;
+ let command_name = "copy_buffer";
+ let src_use_ref = ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Source,
+ secondary_use_ref: None,
+ };
+ let dst_use_ref = ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Destination,
+ secondary_use_ref: None,
+ };
+
+ for region in regions {
+ let BufferCopy {
+ src_offset,
+ dst_offset,
+ size,
+ _ne: _,
+ } = region;
+
+ let mut src_range = src_offset..src_offset + size;
+ src_range.start += src_buffer.offset();
+ src_range.end += src_buffer.offset();
+ self.resources_usage_state.record_buffer_access(
+ &src_use_ref,
+ src_buffer.buffer(),
+ src_range,
+ PipelineStageAccess::Copy_TransferRead,
+ );
+
+ let mut dst_range = dst_offset..dst_offset + size;
+ dst_range.start += dst_buffer.offset();
+ dst_range.end += dst_buffer.offset();
+ self.resources_usage_state.record_buffer_access(
+ &dst_use_ref,
+ dst_buffer.buffer(),
+ dst_range,
+ PipelineStageAccess::Copy_TransferWrite,
+ );
+ }
+
+ self.resources.push(Box::new(src_buffer));
+ self.resources.push(Box::new(dst_buffer));
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Copies data from an image to another image.
+ ///
+ /// There are several restrictions:
+ ///
+ /// - The number of samples in the source and destination images must be equal.
+ /// - The size of the uncompressed element format of the source image must be equal to the
+ /// compressed element format of the destination.
+ /// - If you copy between depth, stencil or depth-stencil images, the format of both images
+ /// must match exactly.
+ /// - For two-dimensional images, the Z coordinate must be 0 for the image offsets and 1 for
+ /// the extent. Same for the Y coordinate for one-dimensional images.
+ /// - For non-array images, the base array layer must be 0 and the number of layers must be 1.
+ ///
+ /// If `layer_count` is greater than 1, the copy will happen between each individual layer as
+ /// if they were separate images.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `src_image` or `dst_image` were not created from the same device
+ /// as `self`.
+ ///
+ /// # Safety
+ ///
+ /// - Appropriate synchronization must be provided for all images
+ /// that are accessed by the command.
+ /// - All images that are accessed by the command must be in the expected image layout.
+ #[inline]
+ pub unsafe fn copy_image(
+ &mut self,
+ copy_image_info: CopyImageInfo,
+ ) -> Result<&mut Self, CopyError> {
+ self.validate_copy_image(&copy_image_info)?;
+
+ unsafe { Ok(self.copy_image_unchecked(copy_image_info)) }
+ }
+
+ fn validate_copy_image(&self, copy_image_info: &CopyImageInfo) -> Result<(), CopyError> {
+ let device = self.device();
+
+ // VUID-vkCmdCopyImage2-renderpass
+ if self.builder_state.render_pass.is_some() {
+ return Err(CopyError::ForbiddenInsideRenderPass);
+ }
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdCopyImage2-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::TRANSFER | QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(CopyError::NotSupportedByQueueFamily);
+ }
+
+ let &CopyImageInfo {
+ ref src_image,
+ src_image_layout,
+ ref dst_image,
+ dst_image_layout,
+ ref regions,
+ _ne: _,
+ } = copy_image_info;
+
+ // VUID-VkCopyImageInfo2-srcImageLayout-parameter
+ src_image_layout.validate_device(device)?;
+
+ // VUID-VkCopyImageInfo2-dstImageLayout-parameter
+ dst_image_layout.validate_device(device)?;
+
+ // VUID-VkCopyImageInfo2-commonparent
+ assert_eq!(device, src_image.device());
+ assert_eq!(device, dst_image.device());
+
+ let copy_2d_3d_supported =
+ device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_maintenance1;
+ let src_image_inner = src_image.inner();
+ let dst_image_inner = dst_image.inner();
+ let mut src_image_aspects = src_image.format().aspects();
+ let mut dst_image_aspects = dst_image.format().aspects();
+
+ if device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_maintenance1 {
+ // VUID-VkCopyImageInfo2-srcImage-01995
+ if !src_image
+ .format_features()
+ .intersects(FormatFeatures::TRANSFER_SRC)
+ {
+ return Err(CopyError::MissingFormatFeature {
+ resource: CopyErrorResource::Source,
+ format_feature: "transfer_src",
+ });
+ }
+
+ // VUID-VkCopyImageInfo2-dstImage-01996
+ if !dst_image
+ .format_features()
+ .intersects(FormatFeatures::TRANSFER_DST)
+ {
+ return Err(CopyError::MissingFormatFeature {
+ resource: CopyErrorResource::Destination,
+ format_feature: "transfer_dst",
+ });
+ }
+ }
+
+ // VUID-VkCopyImageInfo2-srcImage-00136
+ if src_image.samples() != dst_image.samples() {
+ return Err(CopyError::SampleCountMismatch {
+ src_sample_count: src_image.samples(),
+ dst_sample_count: dst_image.samples(),
+ });
+ }
+
+ if !(src_image_aspects.intersects(ImageAspects::COLOR)
+ || dst_image_aspects.intersects(ImageAspects::COLOR))
+ {
+ // VUID-VkCopyImageInfo2-srcImage-01548
+ if src_image.format() != dst_image.format() {
+ return Err(CopyError::FormatsMismatch {
+ src_format: src_image.format(),
+ dst_format: dst_image.format(),
+ });
+ }
+ }
+
+ // VUID-VkCopyImageInfo2-srcImageLayout-01917
+ if !matches!(
+ src_image_layout,
+ ImageLayout::TransferSrcOptimal | ImageLayout::General
+ ) {
+ return Err(CopyError::ImageLayoutInvalid {
+ resource: CopyErrorResource::Source,
+ image_layout: src_image_layout,
+ });
+ }
+
+ // VUID-VkCopyImageInfo2-dstImageLayout-01395
+ if !matches!(
+ dst_image_layout,
+ ImageLayout::TransferDstOptimal | ImageLayout::General
+ ) {
+ return Err(CopyError::ImageLayoutInvalid {
+ resource: CopyErrorResource::Destination,
+ image_layout: dst_image_layout,
+ });
+ }
+
+ let extent_alignment = match queue_family_properties.min_image_transfer_granularity {
+ [0, 0, 0] => None,
+ min_image_transfer_granularity => {
+ let granularity = move |block_extent: [u32; 3], is_multi_plane: bool| {
+ if is_multi_plane {
+ // Assume planes always have 1x1 blocks
+ min_image_transfer_granularity
+ } else {
+ // "The value returned in minImageTransferGranularity has a unit of
+ // compressed texel blocks for images having a block-compressed format, and
+ // a unit of texels otherwise."
+ [
+ min_image_transfer_granularity[0] * block_extent[0],
+ min_image_transfer_granularity[1] * block_extent[1],
+ min_image_transfer_granularity[2] * block_extent[2],
+ ]
+ }
+ };
+
+ Some((
+ granularity(
+ src_image.format().block_extent(),
+ src_image_aspects.intersects(ImageAspects::PLANE_0),
+ ),
+ granularity(
+ dst_image.format().block_extent(),
+ dst_image_aspects.intersects(ImageAspects::PLANE_0),
+ ),
+ ))
+ }
+ };
+
+ if src_image_aspects.intersects(ImageAspects::PLANE_0) {
+ // VUID-VkCopyImageInfo2-srcImage-01552
+ // VUID-VkCopyImageInfo2-srcImage-01553
+ src_image_aspects -= ImageAspects::COLOR;
+ }
+
+ if dst_image_aspects.intersects(ImageAspects::PLANE_0) {
+ // VUID-VkCopyImageInfo2-dstImage-01554
+ // VUID-VkCopyImageInfo2-dstImage-01555
+ dst_image_aspects -= ImageAspects::COLOR;
+ }
+
+ let mut src_image_aspects_used = ImageAspects::empty();
+ let mut dst_image_aspects_used = ImageAspects::empty();
+ let same_image = src_image_inner.image == dst_image_inner.image;
+ let mut overlap_subresource_indices = None;
+ let mut overlap_extent_indices = None;
+
+ for (region_index, region) in regions.iter().enumerate() {
+ let &ImageCopy {
+ ref src_subresource,
+ src_offset,
+ ref dst_subresource,
+ dst_offset,
+ extent,
+ _ne,
+ } = region;
+
+ let check_subresource = |resource: CopyErrorResource,
+ image: &dyn ImageAccess,
+ image_aspects: ImageAspects,
+ subresource: &ImageSubresourceLayers|
+ -> Result<_, CopyError> {
+ // VUID-VkCopyImageInfo2-srcSubresource-01696
+ // VUID-VkCopyImageInfo2-dstSubresource-01697
+ if subresource.mip_level >= image.mip_levels() {
+ return Err(CopyError::MipLevelsOutOfRange {
+ resource,
+ region_index,
+ mip_levels_range_end: subresource.mip_level + 1,
+ image_mip_levels: image.mip_levels(),
+ });
+ }
+
+ // VUID-VkImageSubresourceLayers-layerCount-01700
+ assert!(!subresource.array_layers.is_empty());
+
+ // VUID-VkCopyImageInfo2-srcSubresource-01698
+ // VUID-VkCopyImageInfo2-dstSubresource-01699
+ // VUID-VkCopyImageInfo2-srcImage-04443
+ // VUID-VkCopyImageInfo2-dstImage-04444
+ if subresource.array_layers.end > image.dimensions().array_layers() {
+ return Err(CopyError::ArrayLayersOutOfRange {
+ resource,
+ region_index,
+ array_layers_range_end: subresource.array_layers.end,
+ image_array_layers: image.dimensions().array_layers(),
+ });
+ }
+
+ // VUID-VkImageSubresourceLayers-aspectMask-parameter
+ subresource.aspects.validate_device(device)?;
+
+ // VUID-VkImageSubresourceLayers-aspectMask-requiredbitmask
+ assert!(!subresource.aspects.is_empty());
+
+ // VUID-VkCopyImageInfo2-aspectMask-00142
+ // VUID-VkCopyImageInfo2-aspectMask-00143
+ if !image_aspects.contains(subresource.aspects) {
+ return Err(CopyError::AspectsNotAllowed {
+ resource,
+ region_index,
+ aspects: subresource.aspects,
+ allowed_aspects: image_aspects,
+ });
+ }
+
+ let (subresource_format, subresource_extent) =
+ if image_aspects.intersects(ImageAspects::PLANE_0) {
+ // VUID-VkCopyImageInfo2-srcImage-01552
+ // VUID-VkCopyImageInfo2-srcImage-01553
+ // VUID-VkCopyImageInfo2-dstImage-01554
+ // VUID-VkCopyImageInfo2-dstImage-01555
+ if subresource.aspects.count() != 1 {
+ return Err(CopyError::MultipleAspectsNotAllowed {
+ resource,
+ region_index,
+ aspects: subresource.aspects,
+ });
+ }
+
+ if subresource.aspects.intersects(ImageAspects::PLANE_0) {
+ (
+ image.format().planes()[0],
+ image.dimensions().width_height_depth(),
+ )
+ } else if subresource.aspects.intersects(ImageAspects::PLANE_1) {
+ (
+ image.format().planes()[1],
+ image
+ .format()
+ .ycbcr_chroma_sampling()
+ .unwrap()
+ .subsampled_extent(image.dimensions().width_height_depth()),
+ )
+ } else {
+ (
+ image.format().planes()[2],
+ image
+ .format()
+ .ycbcr_chroma_sampling()
+ .unwrap()
+ .subsampled_extent(image.dimensions().width_height_depth()),
+ )
+ }
+ } else {
+ (
+ image.format(),
+ image
+ .dimensions()
+ .mip_level_dimensions(subresource.mip_level)
+ .unwrap()
+ .width_height_depth(),
+ )
+ };
+
+ Ok((subresource_format, subresource_extent))
+ };
+
+ src_image_aspects_used |= src_subresource.aspects;
+ dst_image_aspects_used |= dst_subresource.aspects;
+
+ let (src_subresource_format, src_subresource_extent) = check_subresource(
+ CopyErrorResource::Source,
+ src_image,
+ src_image_aspects,
+ src_subresource,
+ )?;
+ let (dst_subresource_format, dst_subresource_extent) = check_subresource(
+ CopyErrorResource::Destination,
+ dst_image,
+ dst_image_aspects,
+ dst_subresource,
+ )?;
+
+ if !(src_image_aspects.intersects(ImageAspects::PLANE_0)
+ || dst_image_aspects.intersects(ImageAspects::PLANE_0))
+ {
+ // VUID-VkCopyImageInfo2-srcImage-01551
+ if src_subresource.aspects != dst_subresource.aspects {
+ return Err(CopyError::AspectsMismatch {
+ region_index,
+ src_aspects: src_subresource.aspects,
+ dst_aspects: dst_subresource.aspects,
+ });
+ }
+ }
+
+ // VUID-VkCopyImageInfo2-srcImage-01548
+ // VUID-VkCopyImageInfo2-None-01549
+ // Color formats must be size-compatible.
+ if src_subresource_format.block_size() != dst_subresource_format.block_size() {
+ return Err(CopyError::FormatsNotCompatible {
+ src_format: src_subresource_format,
+ dst_format: dst_subresource_format,
+ });
+ }
+
+ // TODO:
+ // "When copying between compressed and uncompressed formats the extent members
+ // represent the texel dimensions of the source image and not the destination."
+ let mut src_extent = extent;
+ let mut dst_extent = extent;
+ let src_layer_count =
+ src_subresource.array_layers.end - src_subresource.array_layers.start;
+ let dst_layer_count =
+ dst_subresource.array_layers.end - dst_subresource.array_layers.start;
+
+ if copy_2d_3d_supported {
+ match (
+ src_image.dimensions().image_type(),
+ dst_image.dimensions().image_type(),
+ ) {
+ (ImageType::Dim2d, ImageType::Dim3d) => {
+ src_extent[2] = 1;
+
+ // VUID-vkCmdCopyImage-srcImage-01791
+ if dst_extent[2] != src_layer_count {
+ return Err(CopyError::ArrayLayerCountMismatch {
+ region_index,
+ src_layer_count,
+ dst_layer_count: dst_extent[2],
+ });
+ }
+ }
+ (ImageType::Dim3d, ImageType::Dim2d) => {
+ dst_extent[2] = 1;
+
+ // VUID-vkCmdCopyImage-dstImage-01792
+ if src_extent[2] != dst_layer_count {
+ return Err(CopyError::ArrayLayerCountMismatch {
+ region_index,
+ src_layer_count: src_extent[2],
+ dst_layer_count,
+ });
+ }
+ }
+ _ => {
+ // VUID-VkImageCopy2-extent-00140
+ if src_layer_count != dst_layer_count {
+ return Err(CopyError::ArrayLayerCountMismatch {
+ region_index,
+ src_layer_count,
+ dst_layer_count,
+ });
+ }
+ }
+ }
+ } else {
+ // VUID-VkImageCopy2-extent-00140
+ if src_layer_count != dst_layer_count {
+ return Err(CopyError::ArrayLayerCountMismatch {
+ region_index,
+ src_layer_count,
+ dst_layer_count,
+ });
+ }
+ };
+
+ if let Some((src_extent_alignment, dst_extent_alignment)) = extent_alignment {
+ let check_offset_extent = |resource: CopyErrorResource,
+ extent_alignment: [u32; 3],
+ subresource_extent: [u32; 3],
+ offset: [u32; 3],
+ extent: [u32; 3]|
+ -> Result<_, CopyError> {
+ for i in 0..3 {
+ // VUID-VkImageCopy2-extent-06668
+ // VUID-VkImageCopy2-extent-06669
+ // VUID-VkImageCopy2-extent-06670
+ assert!(extent[i] != 0);
+
+ // VUID-VkCopyImageInfo2-srcOffset-00144
+ // VUID-VkCopyImageInfo2-srcOffset-00145
+ // VUID-VkCopyImageInfo2-srcOffset-00147
+ // VUID-VkCopyImageInfo2-dstOffset-00150
+ // VUID-VkCopyImageInfo2-dstOffset-00151
+ // VUID-VkCopyImageInfo2-dstOffset-00153
+ if offset[i] + extent[i] > subresource_extent[i] {
+ return Err(CopyError::RegionOutOfImageBounds {
+ resource,
+ region_index,
+ offset_range_end: [
+ offset[0] + extent[0],
+ offset[1] + extent[1],
+ offset[2] + extent[2],
+ ],
+ subresource_extent,
+ });
+ }
+
+ // VUID-VkCopyImageInfo2-srcImage-01727
+ // VUID-VkCopyImageInfo2-dstImage-01731
+ // VUID-VkCopyImageInfo2-srcOffset-01783
+ // VUID-VkCopyImageInfo2-dstOffset-01784
+ if offset[i] % extent_alignment[i] != 0 {
+ return Err(CopyError::OffsetNotAlignedForImage {
+ resource,
+ region_index,
+ offset,
+ required_alignment: extent_alignment,
+ });
+ }
+
+ // VUID-VkCopyImageInfo2-srcImage-01728
+ // VUID-VkCopyImageInfo2-srcImage-01729
+ // VUID-VkCopyImageInfo2-srcImage-01730
+ // VUID-VkCopyImageInfo2-dstImage-01732
+ // VUID-VkCopyImageInfo2-dstImage-01733
+ // VUID-VkCopyImageInfo2-dstImage-01734
+ if offset[i] + extent[i] != subresource_extent[i]
+ && extent[i] % extent_alignment[i] != 0
+ {
+ return Err(CopyError::ExtentNotAlignedForImage {
+ resource,
+ region_index,
+ extent,
+ required_alignment: extent_alignment,
+ });
+ }
+ }
+
+ Ok(())
+ };
+
+ check_offset_extent(
+ CopyErrorResource::Source,
+ src_extent_alignment,
+ src_subresource_extent,
+ src_offset,
+ src_extent,
+ )?;
+ check_offset_extent(
+ CopyErrorResource::Destination,
+ dst_extent_alignment,
+ dst_subresource_extent,
+ dst_offset,
+ dst_extent,
+ )?;
+
+ // VUID-VkCopyImageInfo2-pRegions-00124
+ if same_image {
+ let src_region_index = region_index;
+ let src_subresource_axes = [
+ src_image_inner.first_mipmap_level + src_subresource.mip_level
+ ..src_image_inner.first_mipmap_level + src_subresource.mip_level + 1,
+ src_image_inner.first_layer + src_subresource.array_layers.start
+ ..src_image_inner.first_layer + src_subresource.array_layers.end,
+ ];
+ let src_extent_axes = [
+ src_offset[0]..src_offset[0] + extent[0],
+ src_offset[1]..src_offset[1] + extent[1],
+ src_offset[2]..src_offset[2] + extent[2],
+ ];
+
+ for (dst_region_index, dst_region) in regions.iter().enumerate() {
+ let &ImageCopy {
+ ref dst_subresource,
+ dst_offset,
+ ..
+ } = dst_region;
+
+ // For a single-plane image, the aspects must always be identical anyway
+ if src_image_aspects.intersects(ImageAspects::PLANE_0)
+ && src_subresource.aspects != dst_subresource.aspects
+ {
+ continue;
+ }
+
+ let dst_subresource_axes = [
+ dst_image_inner.first_mipmap_level + dst_subresource.mip_level
+ ..dst_image_inner.first_mipmap_level
+ + dst_subresource.mip_level
+ + 1,
+ dst_image_inner.first_layer + src_subresource.array_layers.start
+ ..dst_image_inner.first_layer + src_subresource.array_layers.end,
+ ];
+
+ if src_subresource_axes.iter().zip(dst_subresource_axes).any(
+ |(src_range, dst_range)| {
+ src_range.start >= dst_range.end || dst_range.start >= src_range.end
+ },
+ ) {
+ continue;
+ }
+
+ // If the subresource axes all overlap, then the source and destination must
+ // have the same layout.
+ overlap_subresource_indices = Some((src_region_index, dst_region_index));
+
+ let dst_extent_axes = [
+ dst_offset[0]..dst_offset[0] + extent[0],
+ dst_offset[1]..dst_offset[1] + extent[1],
+ dst_offset[2]..dst_offset[2] + extent[2],
+ ];
+
+ // There is only overlap if all of the axes overlap.
+ if src_extent_axes.iter().zip(dst_extent_axes).any(
+ |(src_range, dst_range)| {
+ src_range.start >= dst_range.end || dst_range.start >= src_range.end
+ },
+ ) {
+ continue;
+ }
+
+ overlap_extent_indices = Some((src_region_index, dst_region_index));
+ }
+ }
+ } else {
+ // If granularity is `None`, then we can only copy whole subresources.
+ let check_offset_extent = |resource: CopyErrorResource,
+ subresource_extent: [u32; 3],
+ offset: [u32; 3],
+ extent: [u32; 3]|
+ -> Result<_, CopyError> {
+ // VUID-VkCopyImageInfo2-srcImage-01727
+ // VUID-VkCopyImageInfo2-dstImage-01731
+ // VUID-vkCmdCopyImage-srcOffset-01783
+ // VUID-vkCmdCopyImage-dstOffset-01784
+ if offset != [0, 0, 0] {
+ return Err(CopyError::OffsetNotAlignedForImage {
+ resource,
+ region_index,
+ offset,
+ required_alignment: subresource_extent,
+ });
+ }
+
+ // VUID-VkCopyImageInfo2-srcImage-01728
+ // VUID-VkCopyImageInfo2-srcImage-01729
+ // VUID-VkCopyImageInfo2-srcImage-01730
+ // VUID-VkCopyImageInfo2-dstImage-01732
+ // VUID-VkCopyImageInfo2-dstImage-01733
+ // VUID-VkCopyImageInfo2-dstImage-01734
+ if extent != subresource_extent {
+ return Err(CopyError::ExtentNotAlignedForImage {
+ resource,
+ region_index,
+ extent,
+ required_alignment: subresource_extent,
+ });
+ }
+
+ Ok(())
+ };
+
+ check_offset_extent(
+ CopyErrorResource::Source,
+ src_subresource_extent,
+ src_offset,
+ src_extent,
+ )?;
+ check_offset_extent(
+ CopyErrorResource::Destination,
+ dst_subresource_extent,
+ dst_offset,
+ dst_extent,
+ )?;
+
+ // VUID-VkCopyImageInfo2-pRegions-00124
+ // A simpler version that assumes the region covers the full extent.
+ if same_image {
+ let src_region_index = region_index;
+ let src_axes = [
+ src_image_inner.first_mipmap_level + src_subresource.mip_level
+ ..src_image_inner.first_mipmap_level + src_subresource.mip_level + 1,
+ src_image_inner.first_layer + src_subresource.array_layers.start
+ ..src_image_inner.first_layer + src_subresource.array_layers.end,
+ ];
+
+ for (dst_region_index, dst_region) in regions.iter().enumerate() {
+ let &ImageCopy {
+ ref dst_subresource,
+ dst_offset: _,
+ ..
+ } = dst_region;
+
+ if src_image_aspects.intersects(ImageAspects::PLANE_0)
+ && src_subresource.aspects != dst_subresource.aspects
+ {
+ continue;
+ }
+
+ let dst_axes = [
+ dst_image_inner.first_mipmap_level + dst_subresource.mip_level
+ ..dst_image_inner.first_mipmap_level
+ + dst_subresource.mip_level
+ + 1,
+ dst_image_inner.first_layer + src_subresource.array_layers.start
+ ..dst_image_inner.first_layer + src_subresource.array_layers.end,
+ ];
+
+ // There is only overlap if all of the axes overlap.
+ if src_axes.iter().zip(dst_axes).any(|(src_range, dst_range)| {
+ src_range.start >= dst_range.end || dst_range.start >= src_range.end
+ }) {
+ continue;
+ }
+
+ overlap_extent_indices = Some((src_region_index, dst_region_index));
+ }
+ }
+ }
+ }
+
+ // VUID-VkCopyImageInfo2-aspect-06662
+ if !(src_image_aspects_used - ImageAspects::STENCIL).is_empty()
+ && !src_image.usage().intersects(ImageUsage::TRANSFER_SRC)
+ {
+ return Err(CopyError::MissingUsage {
+ resource: CopyErrorResource::Source,
+ usage: "transfer_src",
+ });
+ }
+
+ // VUID-VkCopyImageInfo2-aspect-06663
+ if !(dst_image_aspects_used - ImageAspects::STENCIL).is_empty()
+ && !dst_image.usage().intersects(ImageUsage::TRANSFER_DST)
+ {
+ return Err(CopyError::MissingUsage {
+ resource: CopyErrorResource::Destination,
+ usage: "transfer_dst",
+ });
+ }
+
+ // VUID-VkCopyImageInfo2-aspect-06664
+ if src_image_aspects_used.intersects(ImageAspects::STENCIL)
+ && !src_image
+ .stencil_usage()
+ .intersects(ImageUsage::TRANSFER_SRC)
+ {
+ return Err(CopyError::MissingUsage {
+ resource: CopyErrorResource::Source,
+ usage: "transfer_src",
+ });
+ }
+
+ // VUID-VkCopyImageInfo2-aspect-06665
+ if dst_image_aspects_used.intersects(ImageAspects::STENCIL)
+ && !dst_image
+ .stencil_usage()
+ .intersects(ImageUsage::TRANSFER_DST)
+ {
+ return Err(CopyError::MissingUsage {
+ resource: CopyErrorResource::Destination,
+ usage: "transfer_dst",
+ });
+ }
+
+ // VUID-VkCopyImageInfo2-pRegions-00124
+ if let Some((src_region_index, dst_region_index)) = overlap_extent_indices {
+ return Err(CopyError::OverlappingRegions {
+ src_region_index,
+ dst_region_index,
+ });
+ }
+
+ // VUID-VkCopyImageInfo2-srcImageLayout-00128
+ // VUID-VkCopyImageInfo2-dstImageLayout-00133
+ if let Some((src_region_index, dst_region_index)) = overlap_subresource_indices {
+ if src_image_layout != dst_image_layout {
+ return Err(CopyError::OverlappingSubresourcesLayoutMismatch {
+ src_region_index,
+ dst_region_index,
+ src_image_layout,
+ dst_image_layout,
+ });
+ }
+ }
+
+ // TODO: sync check
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn copy_image_unchecked(&mut self, copy_image_info: CopyImageInfo) -> &mut Self {
+ let CopyImageInfo {
+ src_image,
+ src_image_layout,
+ dst_image,
+ dst_image_layout,
+ regions,
+ _ne: _,
+ } = copy_image_info;
+
+ if regions.is_empty() {
+ return self;
+ }
+
+ let src_image_inner = src_image.inner();
+ let dst_image_inner = dst_image.inner();
+
+ let fns = self.device().fns();
+
+ if self.device().api_version() >= Version::V1_3
+ || self.device().enabled_extensions().khr_copy_commands2
+ {
+ let regions: SmallVec<[_; 8]> = regions
+ .iter()
+ .map(|region| {
+ let &ImageCopy {
+ ref src_subresource,
+ src_offset,
+ ref dst_subresource,
+ dst_offset,
+ extent,
+ _ne: _,
+ } = region;
+
+ let mut src_subresource = src_subresource.clone();
+ src_subresource.array_layers.start += src_image_inner.first_layer;
+ src_subresource.array_layers.end += src_image_inner.first_layer;
+ src_subresource.mip_level += src_image_inner.first_mipmap_level;
+
+ let mut dst_subresource = dst_subresource.clone();
+ dst_subresource.array_layers.start += dst_image_inner.first_layer;
+ dst_subresource.array_layers.end += dst_image_inner.first_layer;
+ dst_subresource.mip_level += dst_image_inner.first_mipmap_level;
+
+ ash::vk::ImageCopy2 {
+ src_subresource: src_subresource.into(),
+ src_offset: ash::vk::Offset3D {
+ x: src_offset[0] as i32,
+ y: src_offset[1] as i32,
+ z: src_offset[2] as i32,
+ },
+ dst_subresource: dst_subresource.into(),
+ dst_offset: ash::vk::Offset3D {
+ x: dst_offset[0] as i32,
+ y: dst_offset[1] as i32,
+ z: dst_offset[2] as i32,
+ },
+ extent: ash::vk::Extent3D {
+ width: extent[0],
+ height: extent[1],
+ depth: extent[2],
+ },
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let copy_image_info = ash::vk::CopyImageInfo2 {
+ src_image: src_image_inner.image.handle(),
+ src_image_layout: src_image_layout.into(),
+ dst_image: dst_image_inner.image.handle(),
+ dst_image_layout: dst_image_layout.into(),
+ region_count: regions.len() as u32,
+ p_regions: regions.as_ptr(),
+ ..Default::default()
+ };
+
+ if self.device().api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_copy_image2)(self.handle(), &copy_image_info);
+ } else {
+ (fns.khr_copy_commands2.cmd_copy_image2_khr)(self.handle(), &copy_image_info);
+ }
+ } else {
+ let regions: SmallVec<[_; 8]> = regions
+ .iter()
+ .map(|region| {
+ let &ImageCopy {
+ ref src_subresource,
+ src_offset,
+ ref dst_subresource,
+ dst_offset,
+ extent,
+ _ne: _,
+ } = region;
+
+ let mut src_subresource = src_subresource.clone();
+ src_subresource.array_layers.start += src_image_inner.first_layer;
+ src_subresource.array_layers.end += src_image_inner.first_layer;
+ src_subresource.mip_level += src_image_inner.first_mipmap_level;
+
+ let mut dst_subresource = dst_subresource.clone();
+ dst_subresource.array_layers.start += dst_image_inner.first_layer;
+ dst_subresource.array_layers.end += dst_image_inner.first_layer;
+ dst_subresource.mip_level += dst_image_inner.first_mipmap_level;
+
+ ash::vk::ImageCopy {
+ src_subresource: src_subresource.into(),
+ src_offset: ash::vk::Offset3D {
+ x: src_offset[0] as i32,
+ y: src_offset[1] as i32,
+ z: src_offset[2] as i32,
+ },
+ dst_subresource: dst_subresource.into(),
+ dst_offset: ash::vk::Offset3D {
+ x: dst_offset[0] as i32,
+ y: dst_offset[1] as i32,
+ z: dst_offset[2] as i32,
+ },
+ extent: ash::vk::Extent3D {
+ width: extent[0],
+ height: extent[1],
+ depth: extent[2],
+ },
+ }
+ })
+ .collect();
+
+ (fns.v1_0.cmd_copy_image)(
+ self.handle(),
+ src_image_inner.image.handle(),
+ src_image_layout.into(),
+ dst_image_inner.image.handle(),
+ dst_image_layout.into(),
+ regions.len() as u32,
+ regions.as_ptr(),
+ );
+ }
+
+ let command_index = self.next_command_index;
+ let command_name = "copy_image";
+ let src_use_ref = ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Source,
+ secondary_use_ref: None,
+ };
+ let dst_use_ref = ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Destination,
+ secondary_use_ref: None,
+ };
+
+ for region in regions {
+ let ImageCopy {
+ src_subresource,
+ src_offset: _,
+ dst_subresource,
+ dst_offset: _,
+ extent: _,
+ _ne: _,
+ } = region;
+
+ let mut src_subresource_range = ImageSubresourceRange::from(src_subresource);
+ src_subresource_range.array_layers.start += src_image_inner.first_layer;
+ src_subresource_range.array_layers.end += src_image_inner.first_layer;
+ src_subresource_range.mip_levels.start += src_image_inner.first_mipmap_level;
+ src_subresource_range.mip_levels.end += src_image_inner.first_mipmap_level;
+ self.resources_usage_state.record_image_access(
+ &src_use_ref,
+ src_image_inner.image,
+ src_subresource_range,
+ PipelineStageAccess::Copy_TransferRead,
+ src_image_layout,
+ );
+
+ let mut dst_subresource_range = ImageSubresourceRange::from(dst_subresource);
+ dst_subresource_range.array_layers.start += dst_image_inner.first_layer;
+ dst_subresource_range.array_layers.end += dst_image_inner.first_layer;
+ dst_subresource_range.mip_levels.start += dst_image_inner.first_mipmap_level;
+ dst_subresource_range.mip_levels.end += dst_image_inner.first_mipmap_level;
+ self.resources_usage_state.record_image_access(
+ &dst_use_ref,
+ dst_image_inner.image,
+ dst_subresource_range,
+ PipelineStageAccess::Copy_TransferWrite,
+ dst_image_layout,
+ );
+ }
+
+ self.resources.push(Box::new(src_image));
+ self.resources.push(Box::new(dst_image));
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Copies from a buffer to an image.
+ ///
+ /// # Safety
+ ///
+ /// - Appropriate synchronization must be provided for all buffers and images
+ /// that are accessed by the command.
+ /// - All images that are accessed by the command must be in the expected image layout.
+ #[inline]
+ pub unsafe fn copy_buffer_to_image(
+ &mut self,
+ copy_buffer_to_image_info: CopyBufferToImageInfo,
+ ) -> Result<&mut Self, CopyError> {
+ self.validate_copy_buffer_to_image(&copy_buffer_to_image_info)?;
+
+ unsafe { Ok(self.copy_buffer_to_image_unchecked(copy_buffer_to_image_info)) }
+ }
+
+ fn validate_copy_buffer_to_image(
+ &self,
+ copy_buffer_to_image_info: &CopyBufferToImageInfo,
+ ) -> Result<(), CopyError> {
+ let device = self.device();
+
+ // VUID-vkCmdCopyBufferToImage2-renderpass
+ if self.builder_state.render_pass.is_some() {
+ return Err(CopyError::ForbiddenInsideRenderPass);
+ }
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdCopyBufferToImage2-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::TRANSFER | QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(CopyError::NotSupportedByQueueFamily);
+ }
+
+ let &CopyBufferToImageInfo {
+ ref src_buffer,
+ ref dst_image,
+ dst_image_layout,
+ ref regions,
+ _ne: _,
+ } = copy_buffer_to_image_info;
+
+ // VUID-VkCopyBufferToImageInfo2-dstImageLayout-parameter
+ dst_image_layout.validate_device(device)?;
+
+ // VUID-VkCopyBufferToImageInfo2-commonparent
+ assert_eq!(device, src_buffer.device());
+ assert_eq!(device, dst_image.device());
+
+ let mut image_aspects = dst_image.format().aspects();
+
+ // VUID-VkCopyBufferToImageInfo2-commandBuffer-04477
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ && !image_aspects.intersects(ImageAspects::COLOR)
+ {
+ return Err(CopyError::DepthStencilNotSupportedByQueueFamily);
+ }
+
+ // VUID-VkCopyBufferToImageInfo2-srcBuffer-00174
+ if !src_buffer
+ .buffer()
+ .usage()
+ .intersects(BufferUsage::TRANSFER_SRC)
+ {
+ return Err(CopyError::MissingUsage {
+ resource: CopyErrorResource::Source,
+ usage: "transfer_src",
+ });
+ }
+
+ // VUID-VkCopyBufferToImageInfo2-dstImage-00177
+ if !dst_image.usage().intersects(ImageUsage::TRANSFER_DST) {
+ return Err(CopyError::MissingUsage {
+ resource: CopyErrorResource::Destination,
+ usage: "transfer_dst",
+ });
+ }
+
+ if device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_maintenance1 {
+ // VUID-VkCopyBufferToImageInfo2-dstImage-01997
+ if !dst_image
+ .format_features()
+ .intersects(FormatFeatures::TRANSFER_DST)
+ {
+ return Err(CopyError::MissingFormatFeature {
+ resource: CopyErrorResource::Destination,
+ format_feature: "transfer_dst",
+ });
+ }
+ }
+
+ // VUID-VkCopyBufferToImageInfo2-dstImage-00179
+ if dst_image.samples() != SampleCount::Sample1 {
+ return Err(CopyError::SampleCountInvalid {
+ resource: CopyErrorResource::Destination,
+ sample_count: dst_image.samples(),
+ allowed_sample_counts: SampleCounts::SAMPLE_1,
+ });
+ }
+
+ // VUID-VkCopyBufferToImageInfo2-dstImageLayout-01396
+ if !matches!(
+ dst_image_layout,
+ ImageLayout::TransferDstOptimal | ImageLayout::General
+ ) {
+ return Err(CopyError::ImageLayoutInvalid {
+ resource: CopyErrorResource::Destination,
+ image_layout: dst_image_layout,
+ });
+ }
+
+ let extent_alignment = match queue_family_properties.min_image_transfer_granularity {
+ [0, 0, 0] => None,
+ min_image_transfer_granularity => {
+ let granularity = move |block_extent: [u32; 3], is_multi_plane: bool| {
+ if is_multi_plane {
+ // Assume planes always have 1x1 blocks
+ min_image_transfer_granularity
+ } else {
+ // "The value returned in minImageTransferGranularity has a unit of
+ // compressed texel blocks for images having a block-compressed format, and
+ // a unit of texels otherwise."
+ [
+ min_image_transfer_granularity[0] * block_extent[0],
+ min_image_transfer_granularity[1] * block_extent[1],
+ min_image_transfer_granularity[2] * block_extent[2],
+ ]
+ }
+ };
+
+ Some(granularity(
+ dst_image.format().block_extent(),
+ image_aspects.intersects(ImageAspects::PLANE_0),
+ ))
+ }
+ };
+
+ if image_aspects.intersects(ImageAspects::PLANE_0) {
+ // VUID-VkCopyBufferToImageInfo2-aspectMask-01560
+ image_aspects -= ImageAspects::COLOR;
+ }
+
+ for (region_index, region) in regions.iter().enumerate() {
+ let &BufferImageCopy {
+ buffer_offset,
+ buffer_row_length,
+ buffer_image_height,
+ ref image_subresource,
+ image_offset,
+ image_extent,
+ _ne: _,
+ } = region;
+
+ // VUID-VkCopyBufferToImageInfo2-imageSubresource-01701
+ if image_subresource.mip_level >= dst_image.mip_levels() {
+ return Err(CopyError::MipLevelsOutOfRange {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ mip_levels_range_end: image_subresource.mip_level + 1,
+ image_mip_levels: dst_image.mip_levels(),
+ });
+ }
+
+ // VUID-VkImageSubresourceLayers-layerCount-01700
+ // VUID-VkCopyBufferToImageInfo2-baseArrayLayer-00213
+ assert!(!image_subresource.array_layers.is_empty());
+
+ // VUID-VkCopyBufferToImageInfo2-imageSubresource-01702
+ // VUID-VkCopyBufferToImageInfo2-baseArrayLayer-00213
+ if image_subresource.array_layers.end > dst_image.dimensions().array_layers() {
+ return Err(CopyError::ArrayLayersOutOfRange {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ array_layers_range_end: image_subresource.array_layers.end,
+ image_array_layers: dst_image.dimensions().array_layers(),
+ });
+ }
+
+ // VUID-VkImageSubresourceLayers-aspectMask-requiredbitmask
+ assert!(!image_subresource.aspects.is_empty());
+
+ // VUID-VkCopyBufferToImageInfo2-aspectMask-00211
+ if !image_aspects.contains(image_subresource.aspects) {
+ return Err(CopyError::AspectsNotAllowed {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ aspects: image_subresource.aspects,
+ allowed_aspects: image_aspects,
+ });
+ }
+
+ // VUID-VkBufferImageCopy2-aspectMask-00212
+ // VUID-VkCopyBufferToImageInfo2-aspectMask-01560
+ if image_subresource.aspects.count() != 1 {
+ return Err(CopyError::MultipleAspectsNotAllowed {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ aspects: image_subresource.aspects,
+ });
+ }
+
+ let (image_subresource_format, image_subresource_extent) =
+ if image_aspects.intersects(ImageAspects::PLANE_0) {
+ if image_subresource.aspects.intersects(ImageAspects::PLANE_0) {
+ (
+ dst_image.format().planes()[0],
+ dst_image.dimensions().width_height_depth(),
+ )
+ } else if image_subresource.aspects.intersects(ImageAspects::PLANE_1) {
+ (
+ dst_image.format().planes()[1],
+ dst_image
+ .format()
+ .ycbcr_chroma_sampling()
+ .unwrap()
+ .subsampled_extent(dst_image.dimensions().width_height_depth()),
+ )
+ } else {
+ (
+ dst_image.format().planes()[2],
+ dst_image
+ .format()
+ .ycbcr_chroma_sampling()
+ .unwrap()
+ .subsampled_extent(dst_image.dimensions().width_height_depth()),
+ )
+ }
+ } else {
+ (
+ dst_image.format(),
+ dst_image
+ .dimensions()
+ .mip_level_dimensions(image_subresource.mip_level)
+ .unwrap()
+ .width_height_depth(),
+ )
+ };
+
+ if let Some(extent_alignment) = extent_alignment {
+ for i in 0..3 {
+ // VUID-VkBufferImageCopy2-imageExtent-06659
+ // VUID-VkBufferImageCopy2-imageExtent-06660
+ // VUID-VkBufferImageCopy2-imageExtent-06661
+ assert!(image_extent[i] != 0);
+
+ // VUID-VkCopyBufferToImageInfo2-pRegions-06223
+ // VUID-VkCopyBufferToImageInfo2-pRegions-06224
+ // VUID-VkCopyBufferToImageInfo2-imageOffset-00200
+ if image_offset[i] + image_extent[i] > image_subresource_extent[i] {
+ return Err(CopyError::RegionOutOfImageBounds {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ offset_range_end: [
+ image_offset[0] + image_extent[0],
+ image_offset[1] + image_extent[1],
+ image_offset[2] + image_extent[2],
+ ],
+ subresource_extent: image_subresource_extent,
+ });
+ }
+
+ // VUID-VkCopyBufferToImageInfo2-imageOffset-01793
+ // VUID-VkCopyBufferToImageInfo2-imageOffset-00205
+ if image_offset[i] % extent_alignment[i] != 0 {
+ return Err(CopyError::OffsetNotAlignedForImage {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ offset: image_offset,
+ required_alignment: extent_alignment,
+ });
+ }
+
+ // VUID-VkCopyBufferToImageInfo2-imageOffset-01793
+ // VUID-VkCopyBufferToImageInfo2-imageExtent-00207
+ // VUID-VkCopyBufferToImageInfo2-imageExtent-00208
+ // VUID-VkCopyBufferToImageInfo2-imageExtent-00209
+ if image_offset[i] + image_extent[i] != image_subresource_extent[i]
+ && image_extent[i] % extent_alignment[i] != 0
+ {
+ return Err(CopyError::ExtentNotAlignedForImage {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ extent: image_extent,
+ required_alignment: extent_alignment,
+ });
+ }
+ }
+ } else {
+ // If granularity is `None`, then we can only copy whole subresources.
+
+ // VUID-VkCopyBufferToImageInfo2-imageOffset-01793
+ if image_offset != [0, 0, 0] {
+ return Err(CopyError::OffsetNotAlignedForImage {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ offset: image_offset,
+ required_alignment: image_subresource_extent,
+ });
+ }
+
+ // VUID-VkCopyBufferToImageInfo2-imageOffset-01793
+ if image_extent != image_subresource_extent {
+ return Err(CopyError::ExtentNotAlignedForImage {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ extent: image_extent,
+ required_alignment: image_subresource_extent,
+ });
+ }
+ }
+
+ // VUID-VkBufferImageCopy2-bufferRowLength-00195
+ if !(buffer_row_length == 0 || buffer_row_length >= image_extent[0]) {
+ return Err(CopyError::BufferRowLengthTooSmall {
+ resource: CopyErrorResource::Source,
+ region_index,
+ row_length: buffer_row_length,
+ min: image_extent[0],
+ });
+ }
+
+ // VUID-VkBufferImageCopy2-bufferImageHeight-00196
+ if !(buffer_image_height == 0 || buffer_image_height >= image_extent[1]) {
+ return Err(CopyError::BufferImageHeightTooSmall {
+ resource: CopyErrorResource::Source,
+ region_index,
+ image_height: buffer_image_height,
+ min: image_extent[1],
+ });
+ }
+
+ let image_subresource_block_extent = image_subresource_format.block_extent();
+
+ // VUID-VkCopyBufferToImageInfo2-bufferRowLength-00203
+ if buffer_row_length % image_subresource_block_extent[0] != 0 {
+ return Err(CopyError::BufferRowLengthNotAligned {
+ resource: CopyErrorResource::Source,
+ region_index,
+ row_length: buffer_row_length,
+ required_alignment: image_subresource_block_extent[0],
+ });
+ }
+
+ // VUID-VkCopyBufferToImageInfo2-bufferImageHeight-00204
+ if buffer_image_height % image_subresource_block_extent[1] != 0 {
+ return Err(CopyError::BufferImageHeightNotAligned {
+ resource: CopyErrorResource::Source,
+ region_index,
+ image_height: buffer_image_height,
+ required_alignment: image_subresource_block_extent[1],
+ });
+ }
+
+ // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkBufferImageCopy.html#_description
+ let image_subresource_block_size =
+ if image_subresource.aspects.intersects(ImageAspects::STENCIL) {
+ 1
+ } else if image_subresource.aspects.intersects(ImageAspects::DEPTH) {
+ match image_subresource_format {
+ Format::D16_UNORM | Format::D16_UNORM_S8_UINT => 2,
+ Format::D32_SFLOAT
+ | Format::D32_SFLOAT_S8_UINT
+ | Format::X8_D24_UNORM_PACK32
+ | Format::D24_UNORM_S8_UINT => 4,
+ _ => unreachable!(),
+ }
+ } else {
+ image_subresource_format.block_size().unwrap()
+ };
+
+ // VUID-VkCopyBufferToImageInfo2-pRegions-04725
+ // VUID-VkCopyBufferToImageInfo2-pRegions-04726
+ if (buffer_row_length / image_subresource_block_extent[0]) as DeviceSize
+ * image_subresource_block_size
+ > 0x7FFFFFFF
+ {
+ return Err(CopyError::BufferRowLengthTooLarge {
+ resource: CopyErrorResource::Source,
+ region_index,
+ buffer_row_length,
+ });
+ }
+
+ let buffer_offset_alignment =
+ if image_aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL) {
+ 4
+ } else {
+ let mut buffer_offset_alignment = image_subresource_block_size;
+
+ // VUID-VkCopyBufferToImageInfo2-commandBuffer-04052
+ // Make the alignment a multiple of 4.
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ if buffer_offset_alignment % 2 != 0 {
+ buffer_offset_alignment *= 2;
+ }
+
+ if buffer_offset_alignment % 4 != 0 {
+ buffer_offset_alignment *= 2;
+ }
+ }
+
+ buffer_offset_alignment
+ };
+
+ // VUID-VkCopyBufferToImageInfo2-bufferOffset-00206
+ // VUID-VkCopyBufferToImageInfo2-bufferOffset-01558
+ // VUID-VkCopyBufferToImageInfo2-bufferOffset-01559
+ // VUID-VkCopyBufferToImageInfo2-srcImage-04053
+ if (src_buffer.offset() + buffer_offset) % buffer_offset_alignment != 0 {
+ return Err(CopyError::OffsetNotAlignedForBuffer {
+ resource: CopyErrorResource::Source,
+ region_index,
+ offset: src_buffer.offset() + buffer_offset,
+ required_alignment: buffer_offset_alignment,
+ });
+ }
+
+ let buffer_copy_size = region.buffer_copy_size(image_subresource_format);
+
+ // VUID-VkCopyBufferToImageInfo2-pRegions-00171
+ if buffer_offset + buffer_copy_size > src_buffer.size() {
+ return Err(CopyError::RegionOutOfBufferBounds {
+ resource: CopyErrorResource::Source,
+ region_index,
+ offset_range_end: buffer_offset + buffer_copy_size,
+ buffer_size: src_buffer.size(),
+ });
+ }
+ }
+
+ // VUID-VkCopyBufferToImageInfo2-pRegions-00173
+ // Can't occur as long as memory aliasing isn't allowed.
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn copy_buffer_to_image_unchecked(
+ &mut self,
+ copy_buffer_to_image_info: CopyBufferToImageInfo,
+ ) -> &mut Self {
+ let CopyBufferToImageInfo {
+ src_buffer,
+ dst_image,
+ dst_image_layout,
+ regions,
+ _ne: _,
+ } = copy_buffer_to_image_info;
+
+ if regions.is_empty() {
+ return self;
+ }
+
+ let dst_image_inner = dst_image.inner();
+
+ let fns = self.device().fns();
+
+ if self.device().api_version() >= Version::V1_3
+ || self.device().enabled_extensions().khr_copy_commands2
+ {
+ let regions: SmallVec<[_; 8]> = regions
+ .iter()
+ .map(|region| {
+ let &BufferImageCopy {
+ buffer_offset,
+ buffer_row_length,
+ buffer_image_height,
+ ref image_subresource,
+ image_offset,
+ image_extent,
+ _ne: _,
+ } = region;
+
+ let mut image_subresource = image_subresource.clone();
+ image_subresource.array_layers.start += dst_image_inner.first_layer;
+ image_subresource.array_layers.end += dst_image_inner.first_layer;
+ image_subresource.mip_level += dst_image_inner.first_mipmap_level;
+
+ ash::vk::BufferImageCopy2 {
+ buffer_offset: buffer_offset + src_buffer.offset(),
+ buffer_row_length,
+ buffer_image_height,
+ image_subresource: image_subresource.into(),
+ image_offset: ash::vk::Offset3D {
+ x: image_offset[0] as i32,
+ y: image_offset[1] as i32,
+ z: image_offset[2] as i32,
+ },
+ image_extent: ash::vk::Extent3D {
+ width: image_extent[0],
+ height: image_extent[1],
+ depth: image_extent[2],
+ },
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let copy_buffer_to_image_info = ash::vk::CopyBufferToImageInfo2 {
+ src_buffer: src_buffer.buffer().handle(),
+ dst_image: dst_image_inner.image.handle(),
+ dst_image_layout: dst_image_layout.into(),
+ region_count: regions.len() as u32,
+ p_regions: regions.as_ptr(),
+ ..Default::default()
+ };
+
+ if self.device().api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_copy_buffer_to_image2)(self.handle(), &copy_buffer_to_image_info);
+ } else {
+ (fns.khr_copy_commands2.cmd_copy_buffer_to_image2_khr)(
+ self.handle(),
+ &copy_buffer_to_image_info,
+ );
+ }
+ } else {
+ let regions: SmallVec<[_; 8]> = regions
+ .iter()
+ .map(|region| {
+ let &BufferImageCopy {
+ buffer_offset,
+ buffer_row_length,
+ buffer_image_height,
+ ref image_subresource,
+ image_offset,
+ image_extent,
+ _ne: _,
+ } = region;
+
+ let mut image_subresource = image_subresource.clone();
+ image_subresource.array_layers.start += dst_image_inner.first_layer;
+ image_subresource.array_layers.end += dst_image_inner.first_layer;
+ image_subresource.mip_level += dst_image_inner.first_mipmap_level;
+
+ ash::vk::BufferImageCopy {
+ buffer_offset: buffer_offset + src_buffer.offset(),
+ buffer_row_length,
+ buffer_image_height,
+ image_subresource: image_subresource.into(),
+ image_offset: ash::vk::Offset3D {
+ x: image_offset[0] as i32,
+ y: image_offset[1] as i32,
+ z: image_offset[2] as i32,
+ },
+ image_extent: ash::vk::Extent3D {
+ width: image_extent[0],
+ height: image_extent[1],
+ depth: image_extent[2],
+ },
+ }
+ })
+ .collect();
+
+ (fns.v1_0.cmd_copy_buffer_to_image)(
+ self.handle(),
+ src_buffer.buffer().handle(),
+ dst_image_inner.image.handle(),
+ dst_image_layout.into(),
+ regions.len() as u32,
+ regions.as_ptr(),
+ );
+ }
+
+ let command_index = self.next_command_index;
+ let command_name = "copy_buffer_to_image";
+ let src_use_ref = ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Source,
+ secondary_use_ref: None,
+ };
+ let dst_use_ref = ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Destination,
+ secondary_use_ref: None,
+ };
+
+ for region in regions {
+ let buffer_copy_size = region.buffer_copy_size(dst_image.format());
+
+ let BufferImageCopy {
+ buffer_offset,
+ buffer_row_length: _,
+ buffer_image_height: _,
+ image_subresource,
+ image_offset: _,
+ image_extent: _,
+ _ne: _,
+ } = region;
+
+ let mut src_range = buffer_offset..buffer_offset + buffer_copy_size;
+ src_range.start += src_buffer.offset();
+ src_range.end += src_buffer.offset();
+ self.resources_usage_state.record_buffer_access(
+ &src_use_ref,
+ src_buffer.buffer(),
+ src_range,
+ PipelineStageAccess::Copy_TransferRead,
+ );
+
+ let mut dst_subresource_range = ImageSubresourceRange::from(image_subresource);
+ dst_subresource_range.array_layers.start += dst_image_inner.first_layer;
+ dst_subresource_range.array_layers.end += dst_image_inner.first_layer;
+ dst_subresource_range.mip_levels.start += dst_image_inner.first_mipmap_level;
+ dst_subresource_range.mip_levels.end += dst_image_inner.first_mipmap_level;
+ self.resources_usage_state.record_image_access(
+ &dst_use_ref,
+ dst_image_inner.image,
+ dst_subresource_range,
+ PipelineStageAccess::Copy_TransferWrite,
+ dst_image_layout,
+ );
+ }
+
+ self.resources.push(Box::new(src_buffer));
+ self.resources.push(Box::new(dst_image));
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Copies from an image to a buffer.
+ ///
+ /// # Safety
+ ///
+ /// - Appropriate synchronization must be provided for all buffers and images
+ /// that are accessed by the command.
+ /// - All images that are accessed by the command must be in the expected image layout.
+ #[inline]
+ pub unsafe fn copy_image_to_buffer(
+ &mut self,
+ copy_image_to_buffer_info: CopyImageToBufferInfo,
+ ) -> Result<&mut Self, CopyError> {
+ self.validate_copy_image_to_buffer(&copy_image_to_buffer_info)?;
+
+ unsafe { Ok(self.copy_image_to_buffer_unchecked(copy_image_to_buffer_info)) }
+ }
+
+ fn validate_copy_image_to_buffer(
+ &self,
+ copy_image_to_buffer_info: &CopyImageToBufferInfo,
+ ) -> Result<(), CopyError> {
+ let device = self.device();
+
+ // VUID-vkCmdCopyImageToBuffer2-renderpass
+ if self.builder_state.render_pass.is_some() {
+ return Err(CopyError::ForbiddenInsideRenderPass);
+ }
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdCopyImageToBuffer2-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::TRANSFER | QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(CopyError::NotSupportedByQueueFamily);
+ }
+
+ let &CopyImageToBufferInfo {
+ ref src_image,
+ src_image_layout,
+ ref dst_buffer,
+ ref regions,
+ _ne: _,
+ } = copy_image_to_buffer_info;
+
+ // VUID-VkCopyImageToBufferInfo2-srcImageLayout-parameter
+ src_image_layout.validate_device(device)?;
+
+ // VUID-VkCopyImageToBufferInfo2-commonparent
+ assert_eq!(device, dst_buffer.device());
+ assert_eq!(device, src_image.device());
+
+ let mut image_aspects = src_image.format().aspects();
+
+ // VUID-VkCopyImageToBufferInfo2-srcImage-00186
+ if !src_image.usage().intersects(ImageUsage::TRANSFER_SRC) {
+ return Err(CopyError::MissingUsage {
+ resource: CopyErrorResource::Source,
+ usage: "transfer_src",
+ });
+ }
+
+ // VUID-VkCopyImageToBufferInfo2-dstBuffer-00191
+ if !dst_buffer
+ .buffer()
+ .usage()
+ .intersects(BufferUsage::TRANSFER_DST)
+ {
+ return Err(CopyError::MissingUsage {
+ resource: CopyErrorResource::Destination,
+ usage: "transfer_dst",
+ });
+ }
+
+ if device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_maintenance1 {
+ // VUID-VkCopyImageToBufferInfo2-srcImage-01998
+ if !src_image
+ .format_features()
+ .intersects(FormatFeatures::TRANSFER_SRC)
+ {
+ return Err(CopyError::MissingFormatFeature {
+ resource: CopyErrorResource::Source,
+ format_feature: "transfer_src",
+ });
+ }
+ }
+
+ // VUID-VkCopyImageToBufferInfo2-srcImage-00188
+ if src_image.samples() != SampleCount::Sample1 {
+ return Err(CopyError::SampleCountInvalid {
+ resource: CopyErrorResource::Source,
+ sample_count: src_image.samples(),
+ allowed_sample_counts: SampleCounts::SAMPLE_1,
+ });
+ }
+
+ // VUID-VkCopyImageToBufferInfo2-srcImageLayout-01397
+ if !matches!(
+ src_image_layout,
+ ImageLayout::TransferSrcOptimal | ImageLayout::General
+ ) {
+ return Err(CopyError::ImageLayoutInvalid {
+ resource: CopyErrorResource::Source,
+ image_layout: src_image_layout,
+ });
+ }
+
+ let extent_alignment = match queue_family_properties.min_image_transfer_granularity {
+ [0, 0, 0] => None,
+ min_image_transfer_granularity => {
+ let granularity = move |block_extent: [u32; 3], is_multi_plane: bool| {
+ if is_multi_plane {
+ // Assume planes always have 1x1 blocks
+ min_image_transfer_granularity
+ } else {
+ // "The value returned in minImageTransferGranularity has a unit of
+ // compressed texel blocks for images having a block-compressed format, and
+ // a unit of texels otherwise."
+ [
+ min_image_transfer_granularity[0] * block_extent[0],
+ min_image_transfer_granularity[1] * block_extent[1],
+ min_image_transfer_granularity[2] * block_extent[2],
+ ]
+ }
+ };
+
+ Some(granularity(
+ src_image.format().block_extent(),
+ image_aspects.intersects(ImageAspects::PLANE_0),
+ ))
+ }
+ };
+
+ if image_aspects.intersects(ImageAspects::PLANE_0) {
+ // VUID-VkCopyImageToBufferInfo2-aspectMask-01560
+ image_aspects -= ImageAspects::COLOR;
+ }
+
+ for (region_index, region) in regions.iter().enumerate() {
+ let &BufferImageCopy {
+ buffer_offset,
+ buffer_row_length,
+ buffer_image_height,
+ ref image_subresource,
+ image_offset,
+ image_extent,
+ _ne: _,
+ } = region;
+
+ // VUID-VkCopyImageToBufferInfo2-imageSubresource-01703
+ if image_subresource.mip_level >= src_image.mip_levels() {
+ return Err(CopyError::MipLevelsOutOfRange {
+ resource: CopyErrorResource::Source,
+ region_index,
+ mip_levels_range_end: image_subresource.mip_level + 1,
+ image_mip_levels: src_image.mip_levels(),
+ });
+ }
+
+ // VUID-VkImageSubresourceLayers-layerCount-01700
+ assert!(!image_subresource.array_layers.is_empty());
+
+ // VUID-VkCopyImageToBufferInfo2-imageSubresource-01704
+ // VUID-VkCopyImageToBufferInfo2-baseArrayLayer-00213
+ if image_subresource.array_layers.end > src_image.dimensions().array_layers() {
+ return Err(CopyError::ArrayLayersOutOfRange {
+ resource: CopyErrorResource::Source,
+ region_index,
+ array_layers_range_end: image_subresource.array_layers.end,
+ image_array_layers: src_image.dimensions().array_layers(),
+ });
+ }
+
+ // VUID-VkImageSubresourceLayers-aspectMask-requiredbitmask
+ assert!(!image_subresource.aspects.is_empty());
+
+ // VUID-VkCopyImageToBufferInfo2-aspectMask-00211
+ if !image_aspects.contains(image_subresource.aspects) {
+ return Err(CopyError::AspectsNotAllowed {
+ resource: CopyErrorResource::Source,
+ region_index,
+ aspects: image_subresource.aspects,
+ allowed_aspects: image_aspects,
+ });
+ }
+
+ // VUID-VkBufferImageCopy2-aspectMask-00212
+ if image_subresource.aspects.count() != 1 {
+ return Err(CopyError::MultipleAspectsNotAllowed {
+ resource: CopyErrorResource::Source,
+ region_index,
+ aspects: image_subresource.aspects,
+ });
+ }
+
+ let (image_subresource_format, image_subresource_extent) =
+ if image_aspects.intersects(ImageAspects::PLANE_0) {
+ if image_subresource.aspects.intersects(ImageAspects::PLANE_0) {
+ (
+ src_image.format().planes()[0],
+ src_image.dimensions().width_height_depth(),
+ )
+ } else if image_subresource.aspects.intersects(ImageAspects::PLANE_1) {
+ (
+ src_image.format().planes()[1],
+ src_image
+ .format()
+ .ycbcr_chroma_sampling()
+ .unwrap()
+ .subsampled_extent(src_image.dimensions().width_height_depth()),
+ )
+ } else {
+ (
+ src_image.format().planes()[2],
+ src_image
+ .format()
+ .ycbcr_chroma_sampling()
+ .unwrap()
+ .subsampled_extent(src_image.dimensions().width_height_depth()),
+ )
+ }
+ } else {
+ (
+ src_image.format(),
+ src_image
+ .dimensions()
+ .mip_level_dimensions(image_subresource.mip_level)
+ .unwrap()
+ .width_height_depth(),
+ )
+ };
+
+ if let Some(extent_alignment) = extent_alignment {
+ for i in 0..3 {
+ // VUID-VkBufferImageCopy2-imageExtent-06659
+ // VUID-VkBufferImageCopy2-imageExtent-06660
+ // VUID-VkBufferImageCopy2-imageExtent-06661
+ assert!(image_extent[i] != 0);
+
+ // VUID-VkCopyImageToBufferInfo2-imageOffset-00197
+ // VUID-VkCopyImageToBufferInfo2-imageOffset-00198
+ // VUID-VkCopyImageToBufferInfo2-imageOffset-00200
+ if image_offset[i] + image_extent[i] > image_subresource_extent[i] {
+ return Err(CopyError::RegionOutOfImageBounds {
+ resource: CopyErrorResource::Source,
+ region_index,
+ offset_range_end: [
+ image_offset[0] + image_extent[0],
+ image_offset[1] + image_extent[1],
+ image_offset[2] + image_extent[2],
+ ],
+ subresource_extent: image_subresource_extent,
+ });
+ }
+
+ // VUID-VkCopyImageToBufferInfo2-imageOffset-01794
+ // VUID-VkCopyImageToBufferInfo2-imageOffset-00205
+ if image_offset[i] % extent_alignment[i] != 0 {
+ return Err(CopyError::OffsetNotAlignedForImage {
+ resource: CopyErrorResource::Source,
+ region_index,
+ offset: image_offset,
+ required_alignment: extent_alignment,
+ });
+ }
+
+ // VUID-VkCopyImageToBufferInfo2-imageOffset-01794
+ // VUID-VkCopyImageToBufferInfo2-imageExtent-00207
+ // VUID-VkCopyImageToBufferInfo2-imageExtent-00208
+ // VUID-VkCopyImageToBufferInfo2-imageExtent-00209
+ if image_offset[i] + image_extent[i] != image_subresource_extent[i]
+ && image_extent[i] % extent_alignment[i] != 0
+ {
+ return Err(CopyError::ExtentNotAlignedForImage {
+ resource: CopyErrorResource::Source,
+ region_index,
+ extent: image_extent,
+ required_alignment: extent_alignment,
+ });
+ }
+ }
+ } else {
+ // If granularity is `None`, then we can only copy whole subresources.
+
+ // VUID-VkCopyBufferToImageInfo2-imageOffset-01793
+ if image_offset != [0, 0, 0] {
+ return Err(CopyError::OffsetNotAlignedForImage {
+ resource: CopyErrorResource::Source,
+ region_index,
+ offset: image_offset,
+ required_alignment: image_subresource_extent,
+ });
+ }
+
+ // VUID-VkCopyBufferToImageInfo2-imageOffset-01793
+ if image_extent != image_subresource_extent {
+ return Err(CopyError::ExtentNotAlignedForImage {
+ resource: CopyErrorResource::Source,
+ region_index,
+ extent: image_extent,
+ required_alignment: image_subresource_extent,
+ });
+ }
+ }
+
+ // VUID-VkBufferImageCopy2-bufferRowLength-00195
+ if !(buffer_row_length == 0 || buffer_row_length >= image_extent[0]) {
+ return Err(CopyError::BufferRowLengthTooSmall {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ row_length: buffer_row_length,
+ min: image_extent[0],
+ });
+ }
+
+ // VUID-VkBufferImageCopy2-bufferImageHeight-00196
+ if !(buffer_image_height == 0 || buffer_image_height >= image_extent[1]) {
+ return Err(CopyError::BufferImageHeightTooSmall {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ image_height: buffer_image_height,
+ min: image_extent[1],
+ });
+ }
+
+ let image_subresource_block_extent = image_subresource_format.block_extent();
+
+ // VUID-VkCopyImageToBufferInfo2-bufferRowLength-00203
+ if buffer_row_length % image_subresource_block_extent[0] != 0 {
+ return Err(CopyError::BufferRowLengthNotAligned {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ row_length: buffer_row_length,
+ required_alignment: image_subresource_block_extent[0],
+ });
+ }
+
+ // VUID-VkCopyImageToBufferInfo2-bufferImageHeight-00204
+ if buffer_image_height % image_subresource_block_extent[1] != 0 {
+ return Err(CopyError::BufferImageHeightNotAligned {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ image_height: buffer_image_height,
+ required_alignment: image_subresource_block_extent[1],
+ });
+ }
+
+ // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkBufferImageCopy.html#_description
+ let image_subresource_block_size =
+ if image_subresource.aspects.intersects(ImageAspects::STENCIL) {
+ 1
+ } else if image_subresource.aspects.intersects(ImageAspects::DEPTH) {
+ match image_subresource_format {
+ Format::D16_UNORM | Format::D16_UNORM_S8_UINT => 2,
+ Format::D32_SFLOAT
+ | Format::D32_SFLOAT_S8_UINT
+ | Format::X8_D24_UNORM_PACK32
+ | Format::D24_UNORM_S8_UINT => 4,
+ _ => unreachable!(),
+ }
+ } else {
+ image_subresource_format.block_size().unwrap()
+ };
+
+ // VUID-VkCopyImageToBufferInfo2-pRegions-04725
+ // VUID-VkCopyImageToBufferInfo2-pRegions-04726
+ if (buffer_row_length / image_subresource_block_extent[0]) as DeviceSize
+ * image_subresource_block_size
+ > 0x7FFFFFFF
+ {
+ return Err(CopyError::BufferRowLengthTooLarge {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ buffer_row_length,
+ });
+ }
+
+ let buffer_offset_alignment =
+ if image_aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL) {
+ 4
+ } else {
+ let mut buffer_offset_alignment = image_subresource_block_size;
+
+ // VUID-VkCopyImageToBufferInfo2-commandBuffer-04052
+ // Make the alignment a multiple of 4.
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ if buffer_offset_alignment % 2 != 0 {
+ buffer_offset_alignment *= 2;
+ }
+
+ if buffer_offset_alignment % 4 != 0 {
+ buffer_offset_alignment *= 2;
+ }
+ }
+
+ buffer_offset_alignment
+ };
+
+ // VUID-VkCopyImageToBufferInfo2-bufferOffset-01558
+ // VUID-VkCopyImageToBufferInfo2-bufferOffset-01559
+ // VUID-VkCopyImageToBufferInfo2-bufferOffset-00206
+ // VUID-VkCopyImageToBufferInfo2-srcImage-04053
+ if (dst_buffer.offset() + buffer_offset) % buffer_offset_alignment != 0 {
+ return Err(CopyError::OffsetNotAlignedForBuffer {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ offset: dst_buffer.offset() + buffer_offset,
+ required_alignment: buffer_offset_alignment,
+ });
+ }
+
+ let buffer_copy_size = region.buffer_copy_size(image_subresource_format);
+
+ // VUID-VkCopyImageToBufferInfo2-pRegions-00183
+ if buffer_offset + buffer_copy_size > dst_buffer.size() {
+ return Err(CopyError::RegionOutOfBufferBounds {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ offset_range_end: buffer_offset + buffer_copy_size,
+ buffer_size: dst_buffer.size(),
+ });
+ }
+ }
+
+ // VUID-VkCopyImageToBufferInfo2-pRegions-00184
+ // Can't occur as long as memory aliasing isn't allowed.
+
+ // TODO: sync check
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn copy_image_to_buffer_unchecked(
+ &mut self,
+ copy_image_to_buffer_info: CopyImageToBufferInfo,
+ ) -> &mut Self {
+ let CopyImageToBufferInfo {
+ src_image,
+ src_image_layout,
+ dst_buffer,
+ regions,
+ _ne: _,
+ } = copy_image_to_buffer_info;
+
+ if regions.is_empty() {
+ return self;
+ }
+
+ let src_image_inner = src_image.inner();
+
+ let fns = self.device().fns();
+
+ if self.device().api_version() >= Version::V1_3
+ || self.device().enabled_extensions().khr_copy_commands2
+ {
+ let regions: SmallVec<[_; 8]> = regions
+ .iter()
+ .map(|region| {
+ let &BufferImageCopy {
+ buffer_offset,
+ buffer_row_length,
+ buffer_image_height,
+ ref image_subresource,
+ image_offset,
+ image_extent,
+ _ne: _,
+ } = region;
+
+ let mut image_subresource = image_subresource.clone();
+ image_subresource.array_layers.start += src_image_inner.first_layer;
+ image_subresource.array_layers.end += src_image_inner.first_layer;
+ image_subresource.mip_level += src_image_inner.first_mipmap_level;
+
+ ash::vk::BufferImageCopy2 {
+ buffer_offset: buffer_offset + dst_buffer.offset(),
+ buffer_row_length,
+ buffer_image_height,
+ image_subresource: image_subresource.into(),
+ image_offset: ash::vk::Offset3D {
+ x: image_offset[0] as i32,
+ y: image_offset[1] as i32,
+ z: image_offset[2] as i32,
+ },
+ image_extent: ash::vk::Extent3D {
+ width: image_extent[0],
+ height: image_extent[1],
+ depth: image_extent[2],
+ },
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let copy_image_to_buffer_info = ash::vk::CopyImageToBufferInfo2 {
+ src_image: src_image_inner.image.handle(),
+ src_image_layout: src_image_layout.into(),
+ dst_buffer: dst_buffer.buffer().handle(),
+ region_count: regions.len() as u32,
+ p_regions: regions.as_ptr(),
+ ..Default::default()
+ };
+
+ if self.device().api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_copy_image_to_buffer2)(self.handle(), &copy_image_to_buffer_info);
+ } else {
+ (fns.khr_copy_commands2.cmd_copy_image_to_buffer2_khr)(
+ self.handle(),
+ &copy_image_to_buffer_info,
+ );
+ }
+ } else {
+ let regions: SmallVec<[_; 8]> = regions
+ .iter()
+ .map(|region| {
+ let &BufferImageCopy {
+ buffer_offset,
+ buffer_row_length,
+ buffer_image_height,
+ ref image_subresource,
+ image_offset,
+ image_extent,
+ _ne: _,
+ } = region;
+ let mut image_subresource = image_subresource.clone();
+ image_subresource.array_layers.start += src_image_inner.first_layer;
+ image_subresource.array_layers.end += src_image_inner.first_layer;
+ image_subresource.mip_level += src_image_inner.first_mipmap_level;
+
+ ash::vk::BufferImageCopy {
+ buffer_offset: buffer_offset + dst_buffer.offset(),
+ buffer_row_length,
+ buffer_image_height,
+ image_subresource: image_subresource.into(),
+ image_offset: ash::vk::Offset3D {
+ x: image_offset[0] as i32,
+ y: image_offset[1] as i32,
+ z: image_offset[2] as i32,
+ },
+ image_extent: ash::vk::Extent3D {
+ width: image_extent[0],
+ height: image_extent[1],
+ depth: image_extent[2],
+ },
+ }
+ })
+ .collect();
+
+ (fns.v1_0.cmd_copy_image_to_buffer)(
+ self.handle(),
+ src_image_inner.image.handle(),
+ src_image_layout.into(),
+ dst_buffer.buffer().handle(),
+ regions.len() as u32,
+ regions.as_ptr(),
+ );
+ }
+
+ let command_index = self.next_command_index;
+ let command_name = "copy_image_to_buffer";
+ let src_use_ref = ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Source,
+ secondary_use_ref: None,
+ };
+ let dst_use_ref = ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Destination,
+ secondary_use_ref: None,
+ };
+
+ for region in regions {
+ let buffer_copy_size = region.buffer_copy_size(src_image.format());
+
+ let BufferImageCopy {
+ buffer_offset,
+ buffer_row_length: _,
+ buffer_image_height: _,
+ image_subresource,
+ image_offset: _,
+ image_extent: _,
+ _ne: _,
+ } = region;
+
+ let mut src_subresource_range = ImageSubresourceRange::from(image_subresource);
+ src_subresource_range.array_layers.start += src_image_inner.first_layer;
+ src_subresource_range.array_layers.end += src_image_inner.first_layer;
+ src_subresource_range.mip_levels.start += src_image_inner.first_mipmap_level;
+ src_subresource_range.mip_levels.end += src_image_inner.first_mipmap_level;
+ self.resources_usage_state.record_image_access(
+ &src_use_ref,
+ src_image_inner.image,
+ src_subresource_range,
+ PipelineStageAccess::Copy_TransferRead,
+ src_image_layout,
+ );
+
+ let mut dst_range = buffer_offset..buffer_offset + buffer_copy_size;
+ dst_range.start += dst_buffer.offset();
+ dst_range.end += dst_buffer.offset();
+ self.resources_usage_state.record_buffer_access(
+ &dst_use_ref,
+ dst_buffer.buffer(),
+ dst_range,
+ PipelineStageAccess::Copy_TransferWrite,
+ );
+ }
+
+ self.resources.push(Box::new(src_image));
+ self.resources.push(Box::new(dst_buffer));
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Blits an image to another.
+ ///
+ /// A *blit* is similar to an image copy operation, except that the portion of the image that
+ /// is transferred can be resized. You choose an area of the source and an area of the
+ /// destination, and the implementation will resize the area of the source so that it matches
+ /// the size of the area of the destination before writing it.
+ ///
+ /// Blit operations have several restrictions:
+ ///
+ /// - Blit operations are only allowed on queue families that support graphics operations.
+ /// - The format of the source and destination images must support blit operations, which
+ /// depends on the Vulkan implementation. Vulkan guarantees that some specific formats must
+ /// always be supported. See tables 52 to 61 of the specifications.
+ /// - Only single-sampled images are allowed.
+ /// - You can only blit between two images whose formats belong to the same type. The types
+ /// are: floating-point, signed integers, unsigned integers, depth-stencil.
+ /// - If you blit between depth, stencil or depth-stencil images, the format of both images
+ /// must match exactly.
+ /// - If you blit between depth, stencil or depth-stencil images, only the `Nearest` filter is
+ /// allowed.
+ /// - For two-dimensional images, the Z coordinate must be 0 for the top-left offset and 1 for
+ /// the bottom-right offset. Same for the Y coordinate for one-dimensional images.
+ /// - For non-array images, the base array layer must be 0 and the number of layers must be 1.
+ ///
+ /// If `layer_count` is greater than 1, the blit will happen between each individual layer as
+ /// if they were separate images.
+ ///
+ /// # Panic
+ ///
+ /// - Panics if the source or the destination was not created with `device`.
+ ///
+ /// # Safety
+ ///
+ /// - Appropriate synchronization must be provided for all images
+ /// that are accessed by the command.
+ /// - All images that are accessed by the command must be in the expected image layout.
+ #[inline]
+ pub unsafe fn blit_image(
+ &mut self,
+ blit_image_info: BlitImageInfo,
+ ) -> Result<&mut Self, CopyError> {
+ self.validate_blit_image(&blit_image_info)?;
+
+ unsafe { Ok(self.blit_image_unchecked(blit_image_info)) }
+ }
+
+ fn validate_blit_image(&self, blit_image_info: &BlitImageInfo) -> Result<(), CopyError> {
+ let device = self.device();
+
+ // VUID-vkCmdBlitImage2-renderpass
+ if self.builder_state.render_pass.is_some() {
+ return Err(CopyError::ForbiddenInsideRenderPass);
+ }
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdBlitImage2-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(CopyError::NotSupportedByQueueFamily);
+ }
+
+ let &BlitImageInfo {
+ ref src_image,
+ src_image_layout,
+ ref dst_image,
+ dst_image_layout,
+ ref regions,
+ filter,
+ _ne: _,
+ } = blit_image_info;
+
+ // VUID-VkBlitImageInfo2-srcImageLayout-parameter
+ src_image_layout.validate_device(device)?;
+
+ // VUID-VkBlitImageInfo2-dstImageLayout-parameter
+ dst_image_layout.validate_device(device)?;
+
+ // VUID-VkBlitImageInfo2-filter-parameter
+ filter.validate_device(device)?;
+
+ let src_image_inner = src_image.inner();
+ let dst_image_inner = dst_image.inner();
+
+ // VUID-VkBlitImageInfo2-commonparent
+ assert_eq!(device, src_image.device());
+ assert_eq!(device, dst_image.device());
+
+ let src_image_aspects = src_image.format().aspects();
+ let dst_image_aspects = dst_image.format().aspects();
+ let src_image_type = src_image.dimensions().image_type();
+ let dst_image_type = dst_image.dimensions().image_type();
+
+ // VUID-VkBlitImageInfo2-srcImage-00219
+ if !src_image.usage().intersects(ImageUsage::TRANSFER_SRC) {
+ return Err(CopyError::MissingUsage {
+ resource: CopyErrorResource::Source,
+ usage: "transfer_src",
+ });
+ }
+
+ // VUID-VkBlitImageInfo2-dstImage-00224
+ if !dst_image.usage().intersects(ImageUsage::TRANSFER_DST) {
+ return Err(CopyError::MissingUsage {
+ resource: CopyErrorResource::Destination,
+ usage: "transfer_dst",
+ });
+ }
+
+ // VUID-VkBlitImageInfo2-srcImage-01999
+ if !src_image
+ .format_features()
+ .intersects(FormatFeatures::BLIT_SRC)
+ {
+ return Err(CopyError::MissingFormatFeature {
+ resource: CopyErrorResource::Source,
+ format_feature: "blit_src",
+ });
+ }
+
+ // VUID-VkBlitImageInfo2-dstImage-02000
+ if !dst_image
+ .format_features()
+ .intersects(FormatFeatures::BLIT_DST)
+ {
+ return Err(CopyError::MissingFormatFeature {
+ resource: CopyErrorResource::Destination,
+ format_feature: "blit_dst",
+ });
+ }
+
+ // VUID-VkBlitImageInfo2-srcImage-06421
+ if src_image.format().ycbcr_chroma_sampling().is_some() {
+ return Err(CopyError::FormatNotSupported {
+ resource: CopyErrorResource::Source,
+ format: src_image.format(),
+ });
+ }
+
+ // VUID-VkBlitImageInfo2-dstImage-06422
+ if dst_image.format().ycbcr_chroma_sampling().is_some() {
+ return Err(CopyError::FormatNotSupported {
+ resource: CopyErrorResource::Destination,
+ format: src_image.format(),
+ });
+ }
+
+ if !(src_image_aspects.intersects(ImageAspects::COLOR)
+ && dst_image_aspects.intersects(ImageAspects::COLOR))
+ {
+ // VUID-VkBlitImageInfo2-srcImage-00231
+ if src_image.format() != dst_image.format() {
+ return Err(CopyError::FormatsMismatch {
+ src_format: src_image.format(),
+ dst_format: dst_image.format(),
+ });
+ }
+ } else {
+ // VUID-VkBlitImageInfo2-srcImage-00229
+ // VUID-VkBlitImageInfo2-srcImage-00230
+ if !matches!(
+ (
+ src_image.format().type_color().unwrap(),
+ dst_image.format().type_color().unwrap()
+ ),
+ (
+ NumericType::SFLOAT
+ | NumericType::UFLOAT
+ | NumericType::SNORM
+ | NumericType::UNORM
+ | NumericType::SSCALED
+ | NumericType::USCALED
+ | NumericType::SRGB,
+ NumericType::SFLOAT
+ | NumericType::UFLOAT
+ | NumericType::SNORM
+ | NumericType::UNORM
+ | NumericType::SSCALED
+ | NumericType::USCALED
+ | NumericType::SRGB,
+ ) | (NumericType::SINT, NumericType::SINT)
+ | (NumericType::UINT, NumericType::UINT)
+ ) {
+ return Err(CopyError::FormatsNotCompatible {
+ src_format: src_image.format(),
+ dst_format: dst_image.format(),
+ });
+ }
+ }
+
+ // VUID-VkBlitImageInfo2-srcImage-00233
+ if src_image.samples() != SampleCount::Sample1 {
+ return Err(CopyError::SampleCountInvalid {
+ resource: CopyErrorResource::Destination,
+ sample_count: dst_image.samples(),
+ allowed_sample_counts: SampleCounts::SAMPLE_1,
+ });
+ }
+
+ // VUID-VkBlitImageInfo2-dstImage-00234
+ if dst_image.samples() != SampleCount::Sample1 {
+ return Err(CopyError::SampleCountInvalid {
+ resource: CopyErrorResource::Destination,
+ sample_count: dst_image.samples(),
+ allowed_sample_counts: SampleCounts::SAMPLE_1,
+ });
+ }
+
+ // VUID-VkBlitImageInfo2-srcImageLayout-01398
+ if !matches!(
+ src_image_layout,
+ ImageLayout::TransferSrcOptimal | ImageLayout::General
+ ) {
+ return Err(CopyError::ImageLayoutInvalid {
+ resource: CopyErrorResource::Source,
+ image_layout: src_image_layout,
+ });
+ }
+
+ // VUID-VkBlitImageInfo2-dstImageLayout-01399
+ if !matches!(
+ dst_image_layout,
+ ImageLayout::TransferDstOptimal | ImageLayout::General
+ ) {
+ return Err(CopyError::ImageLayoutInvalid {
+ resource: CopyErrorResource::Destination,
+ image_layout: dst_image_layout,
+ });
+ }
+
+ // VUID-VkBlitImageInfo2-srcImage-00232
+ if !src_image_aspects.intersects(ImageAspects::COLOR) && filter != Filter::Nearest {
+ return Err(CopyError::FilterNotSupportedByFormat);
+ }
+
+ match filter {
+ Filter::Nearest => (),
+ Filter::Linear => {
+ // VUID-VkBlitImageInfo2-filter-02001
+ if !src_image
+ .format_features()
+ .intersects(FormatFeatures::SAMPLED_IMAGE_FILTER_LINEAR)
+ {
+ return Err(CopyError::FilterNotSupportedByFormat);
+ }
+ }
+ Filter::Cubic => {
+ // VUID-VkBlitImageInfo2-filter-02002
+ if !src_image
+ .format_features()
+ .intersects(FormatFeatures::SAMPLED_IMAGE_FILTER_CUBIC)
+ {
+ return Err(CopyError::FilterNotSupportedByFormat);
+ }
+
+ // VUID-VkBlitImageInfo2-filter-00237
+ if !matches!(src_image.dimensions(), ImageDimensions::Dim2d { .. }) {
+ return Err(CopyError::FilterNotSupportedForImageType);
+ }
+ }
+ }
+
+ let same_image = src_image_inner.image == dst_image_inner.image;
+ let mut overlap_subresource_indices = None;
+ let mut overlap_extent_indices = None;
+
+ for (region_index, region) in regions.iter().enumerate() {
+ let &ImageBlit {
+ ref src_subresource,
+ src_offsets,
+ ref dst_subresource,
+ dst_offsets,
+ _ne: _,
+ } = region;
+
+ let check_subresource = |resource: CopyErrorResource,
+ image: &dyn ImageAccess,
+ image_aspects: ImageAspects,
+ subresource: &ImageSubresourceLayers|
+ -> Result<_, CopyError> {
+ // VUID-VkBlitImageInfo2-srcSubresource-01705
+ // VUID-VkBlitImageInfo2-dstSubresource-01706
+ if subresource.mip_level >= image.mip_levels() {
+ return Err(CopyError::MipLevelsOutOfRange {
+ resource,
+ region_index,
+ mip_levels_range_end: subresource.mip_level + 1,
+ image_mip_levels: image.mip_levels(),
+ });
+ }
+
+ // VUID-VkImageSubresourceLayers-layerCount-01700
+ assert!(!subresource.array_layers.is_empty());
+
+ // VUID-VkBlitImageInfo2-srcSubresource-01707
+ // VUID-VkBlitImageInfo2-dstSubresource-01708
+ // VUID-VkBlitImageInfo2-srcImage-00240
+ if subresource.array_layers.end > image.dimensions().array_layers() {
+ return Err(CopyError::ArrayLayersOutOfRange {
+ resource,
+ region_index,
+ array_layers_range_end: subresource.array_layers.end,
+ image_array_layers: image.dimensions().array_layers(),
+ });
+ }
+
+ // VUID-VkImageSubresourceLayers-aspectMask-parameter
+ subresource.aspects.validate_device(device)?;
+
+ // VUID-VkImageSubresourceLayers-aspectMask-requiredbitmask
+ assert!(!subresource.aspects.is_empty());
+
+ // VUID-VkBlitImageInfo2-aspectMask-00241
+ // VUID-VkBlitImageInfo2-aspectMask-00242
+ if !image_aspects.contains(subresource.aspects) {
+ return Err(CopyError::AspectsNotAllowed {
+ resource,
+ region_index,
+ aspects: subresource.aspects,
+ allowed_aspects: image_aspects,
+ });
+ }
+
+ Ok(image
+ .dimensions()
+ .mip_level_dimensions(subresource.mip_level)
+ .unwrap()
+ .width_height_depth())
+ };
+
+ let src_subresource_extent = check_subresource(
+ CopyErrorResource::Source,
+ src_image,
+ src_image_aspects,
+ src_subresource,
+ )?;
+ let dst_subresource_extent = check_subresource(
+ CopyErrorResource::Destination,
+ dst_image,
+ dst_image_aspects,
+ dst_subresource,
+ )?;
+
+ // VUID-VkImageBlit2-aspectMask-00238
+ if src_subresource.aspects != dst_subresource.aspects {
+ return Err(CopyError::AspectsMismatch {
+ region_index,
+ src_aspects: src_subresource.aspects,
+ dst_aspects: dst_subresource.aspects,
+ });
+ }
+
+ let src_layer_count =
+ src_subresource.array_layers.end - src_subresource.array_layers.start;
+ let dst_layer_count =
+ dst_subresource.array_layers.end - dst_subresource.array_layers.start;
+
+ // VUID-VkImageBlit2-layerCount-00239
+ // VUID-VkBlitImageInfo2-srcImage-00240
+ if src_layer_count != dst_layer_count {
+ return Err(CopyError::ArrayLayerCountMismatch {
+ region_index,
+ src_layer_count,
+ dst_layer_count,
+ });
+ }
+
+ let check_offset_extent = |resource: CopyErrorResource,
+ image_type: ImageType,
+ subresource_extent: [u32; 3],
+ offsets: [[u32; 3]; 2]|
+ -> Result<_, CopyError> {
+ match image_type {
+ ImageType::Dim1d => {
+ // VUID-VkBlitImageInfo2-srcImage-00245
+ // VUID-VkBlitImageInfo2-dstImage-00250
+ if !(offsets[0][1] == 0 && offsets[1][1] == 1) {
+ return Err(CopyError::OffsetsInvalidForImageType {
+ resource,
+ region_index,
+ offsets: [offsets[0][1], offsets[1][1]],
+ });
+ }
+
+ // VUID-VkBlitImageInfo2-srcImage-00247
+ // VUID-VkBlitImageInfo2-dstImage-00252
+ if !(offsets[0][2] == 0 && offsets[1][2] == 1) {
+ return Err(CopyError::OffsetsInvalidForImageType {
+ resource,
+ region_index,
+ offsets: [offsets[0][2], offsets[1][2]],
+ });
+ }
+ }
+ ImageType::Dim2d => {
+ // VUID-VkBlitImageInfo2-srcImage-00247
+ // VUID-VkBlitImageInfo2-dstImage-00252
+ if !(offsets[0][2] == 0 && offsets[1][2] == 1) {
+ return Err(CopyError::OffsetsInvalidForImageType {
+ resource,
+ region_index,
+ offsets: [offsets[0][2], offsets[1][2]],
+ });
+ }
+ }
+ ImageType::Dim3d => (),
+ }
+
+ let offset_range_end = [
+ max(offsets[0][0], offsets[1][0]),
+ max(offsets[0][1], offsets[1][1]),
+ max(offsets[0][2], offsets[1][2]),
+ ];
+
+ for i in 0..3 {
+ // VUID-VkBlitImageInfo2-srcOffset-00243
+ // VUID-VkBlitImageInfo2-srcOffset-00244
+ // VUID-VkBlitImageInfo2-srcOffset-00246
+ // VUID-VkBlitImageInfo2-dstOffset-00248
+ // VUID-VkBlitImageInfo2-dstOffset-00249
+ // VUID-VkBlitImageInfo2-dstOffset-00251
+ if offset_range_end[i] > subresource_extent[i] {
+ return Err(CopyError::RegionOutOfImageBounds {
+ resource,
+ region_index,
+ offset_range_end,
+ subresource_extent,
+ });
+ }
+ }
+
+ Ok(())
+ };
+
+ check_offset_extent(
+ CopyErrorResource::Source,
+ src_image_type,
+ src_subresource_extent,
+ src_offsets,
+ )?;
+ check_offset_extent(
+ CopyErrorResource::Destination,
+ dst_image_type,
+ dst_subresource_extent,
+ dst_offsets,
+ )?;
+
+ // VUID-VkBlitImageInfo2-pRegions-00217
+ if same_image {
+ let src_region_index = region_index;
+ let src_subresource_axes = [
+ src_image_inner.first_mipmap_level + src_subresource.mip_level
+ ..src_image_inner.first_mipmap_level + src_subresource.mip_level + 1,
+ src_image_inner.first_layer + src_subresource.array_layers.start
+ ..src_image_inner.first_layer + src_subresource.array_layers.end,
+ ];
+ let src_extent_axes = [
+ min(src_offsets[0][0], src_offsets[1][0])
+ ..max(src_offsets[0][0], src_offsets[1][0]),
+ min(src_offsets[0][1], src_offsets[1][1])
+ ..max(src_offsets[0][1], src_offsets[1][1]),
+ min(src_offsets[0][2], src_offsets[1][2])
+ ..max(src_offsets[0][2], src_offsets[1][2]),
+ ];
+
+ for (dst_region_index, dst_region) in regions.iter().enumerate() {
+ let &ImageBlit {
+ ref dst_subresource,
+ dst_offsets,
+ ..
+ } = dst_region;
+
+ let dst_subresource_axes = [
+ dst_image_inner.first_mipmap_level + dst_subresource.mip_level
+ ..dst_image_inner.first_mipmap_level + dst_subresource.mip_level + 1,
+ dst_image_inner.first_layer + src_subresource.array_layers.start
+ ..dst_image_inner.first_layer + src_subresource.array_layers.end,
+ ];
+
+ if src_subresource_axes.iter().zip(dst_subresource_axes).any(
+ |(src_range, dst_range)| {
+ src_range.start >= dst_range.end || dst_range.start >= src_range.end
+ },
+ ) {
+ continue;
+ }
+
+ // If the subresource axes all overlap, then the source and destination must
+ // have the same layout.
+ overlap_subresource_indices = Some((src_region_index, dst_region_index));
+
+ let dst_extent_axes = [
+ min(dst_offsets[0][0], dst_offsets[1][0])
+ ..max(dst_offsets[0][0], dst_offsets[1][0]),
+ min(dst_offsets[0][1], dst_offsets[1][1])
+ ..max(dst_offsets[0][1], dst_offsets[1][1]),
+ min(dst_offsets[0][2], dst_offsets[1][2])
+ ..max(dst_offsets[0][2], dst_offsets[1][2]),
+ ];
+
+ if src_extent_axes
+ .iter()
+ .zip(dst_extent_axes)
+ .any(|(src_range, dst_range)| {
+ src_range.start >= dst_range.end || dst_range.start >= src_range.end
+ })
+ {
+ continue;
+ }
+
+ // If the extent axes *also* overlap, then that's an error.
+ overlap_extent_indices = Some((src_region_index, dst_region_index));
+ }
+ }
+ }
+
+ // VUID-VkBlitImageInfo2-pRegions-00217
+ if let Some((src_region_index, dst_region_index)) = overlap_extent_indices {
+ return Err(CopyError::OverlappingRegions {
+ src_region_index,
+ dst_region_index,
+ });
+ }
+
+ // VUID-VkBlitImageInfo2-srcImageLayout-00221
+ // VUID-VkBlitImageInfo2-dstImageLayout-00226
+ if let Some((src_region_index, dst_region_index)) = overlap_subresource_indices {
+ if src_image_layout != dst_image_layout {
+ return Err(CopyError::OverlappingSubresourcesLayoutMismatch {
+ src_region_index,
+ dst_region_index,
+ src_image_layout,
+ dst_image_layout,
+ });
+ }
+ }
+
+ // TODO: sync check
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn blit_image_unchecked(&mut self, blit_image_info: BlitImageInfo) -> &mut Self {
+ let BlitImageInfo {
+ src_image,
+ src_image_layout,
+ dst_image,
+ dst_image_layout,
+ regions,
+ filter,
+ _ne: _,
+ } = blit_image_info;
+
+ if regions.is_empty() {
+ return self;
+ }
+
+ let src_image_inner = src_image.inner();
+ let dst_image_inner = dst_image.inner();
+
+ let fns = self.device().fns();
+
+ if self.device().api_version() >= Version::V1_3
+ || self.device().enabled_extensions().khr_copy_commands2
+ {
+ let regions: SmallVec<[_; 8]> = regions
+ .iter()
+ .map(|region| {
+ let &ImageBlit {
+ ref src_subresource,
+ src_offsets,
+ ref dst_subresource,
+ dst_offsets,
+ _ne: _,
+ } = region;
+
+ let mut src_subresource = src_subresource.clone();
+ src_subresource.array_layers.start += src_image_inner.first_layer;
+ src_subresource.array_layers.end += src_image_inner.first_layer;
+ src_subresource.mip_level += src_image_inner.first_mipmap_level;
+
+ let mut dst_subresource = dst_subresource.clone();
+ dst_subresource.array_layers.start += dst_image_inner.first_layer;
+ dst_subresource.array_layers.end += dst_image_inner.first_layer;
+ dst_subresource.mip_level += dst_image_inner.first_mipmap_level;
+
+ ash::vk::ImageBlit2 {
+ src_subresource: src_subresource.into(),
+ src_offsets: [
+ ash::vk::Offset3D {
+ x: src_offsets[0][0] as i32,
+ y: src_offsets[0][1] as i32,
+ z: src_offsets[0][2] as i32,
+ },
+ ash::vk::Offset3D {
+ x: src_offsets[1][0] as i32,
+ y: src_offsets[1][1] as i32,
+ z: src_offsets[1][2] as i32,
+ },
+ ],
+ dst_subresource: dst_subresource.into(),
+ dst_offsets: [
+ ash::vk::Offset3D {
+ x: dst_offsets[0][0] as i32,
+ y: dst_offsets[0][1] as i32,
+ z: dst_offsets[0][2] as i32,
+ },
+ ash::vk::Offset3D {
+ x: dst_offsets[1][0] as i32,
+ y: dst_offsets[1][1] as i32,
+ z: dst_offsets[1][2] as i32,
+ },
+ ],
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let blit_image_info = ash::vk::BlitImageInfo2 {
+ src_image: src_image_inner.image.handle(),
+ src_image_layout: src_image_layout.into(),
+ dst_image: dst_image_inner.image.handle(),
+ dst_image_layout: dst_image_layout.into(),
+ region_count: regions.len() as u32,
+ p_regions: regions.as_ptr(),
+ filter: filter.into(),
+ ..Default::default()
+ };
+
+ if self.device().api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_blit_image2)(self.handle(), &blit_image_info);
+ } else {
+ (fns.khr_copy_commands2.cmd_blit_image2_khr)(self.handle(), &blit_image_info);
+ }
+ } else {
+ let regions: SmallVec<[_; 8]> = regions
+ .iter()
+ .map(|region| {
+ let &ImageBlit {
+ ref src_subresource,
+ src_offsets,
+ ref dst_subresource,
+ dst_offsets,
+ _ne: _,
+ } = region;
+
+ let mut src_subresource = src_subresource.clone();
+ src_subresource.array_layers.start += src_image_inner.first_layer;
+ src_subresource.array_layers.end += src_image_inner.first_layer;
+ src_subresource.mip_level += src_image_inner.first_mipmap_level;
+
+ let mut dst_subresource = dst_subresource.clone();
+ dst_subresource.array_layers.start += dst_image_inner.first_layer;
+ dst_subresource.array_layers.end += dst_image_inner.first_layer;
+ dst_subresource.mip_level += dst_image_inner.first_mipmap_level;
+
+ ash::vk::ImageBlit {
+ src_subresource: src_subresource.into(),
+ src_offsets: [
+ ash::vk::Offset3D {
+ x: src_offsets[0][0] as i32,
+ y: src_offsets[0][1] as i32,
+ z: src_offsets[0][2] as i32,
+ },
+ ash::vk::Offset3D {
+ x: src_offsets[1][0] as i32,
+ y: src_offsets[1][1] as i32,
+ z: src_offsets[1][2] as i32,
+ },
+ ],
+ dst_subresource: dst_subresource.into(),
+ dst_offsets: [
+ ash::vk::Offset3D {
+ x: dst_offsets[0][0] as i32,
+ y: dst_offsets[0][1] as i32,
+ z: dst_offsets[0][2] as i32,
+ },
+ ash::vk::Offset3D {
+ x: dst_offsets[1][0] as i32,
+ y: dst_offsets[1][1] as i32,
+ z: dst_offsets[1][2] as i32,
+ },
+ ],
+ }
+ })
+ .collect();
+
+ (fns.v1_0.cmd_blit_image)(
+ self.handle(),
+ src_image_inner.image.handle(),
+ src_image_layout.into(),
+ dst_image_inner.image.handle(),
+ dst_image_layout.into(),
+ regions.len() as u32,
+ regions.as_ptr(),
+ filter.into(),
+ );
+ }
+
+ let command_index = self.next_command_index;
+ let command_name = "blit_image";
+ let src_use_ref = ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Source,
+ secondary_use_ref: None,
+ };
+ let dst_use_ref = ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Destination,
+ secondary_use_ref: None,
+ };
+
+ for region in regions {
+ let ImageBlit {
+ src_subresource,
+ src_offsets: _,
+ dst_subresource,
+ dst_offsets: _,
+ _ne: _,
+ } = region;
+
+ let mut src_subresource_range = ImageSubresourceRange::from(src_subresource);
+ src_subresource_range.array_layers.start += src_image_inner.first_layer;
+ src_subresource_range.array_layers.end += src_image_inner.first_layer;
+ src_subresource_range.mip_levels.start += src_image_inner.first_mipmap_level;
+ src_subresource_range.mip_levels.end += src_image_inner.first_mipmap_level;
+ self.resources_usage_state.record_image_access(
+ &src_use_ref,
+ src_image_inner.image,
+ src_subresource_range,
+ PipelineStageAccess::Blit_TransferRead,
+ src_image_layout,
+ );
+
+ let mut dst_subresource_range = ImageSubresourceRange::from(dst_subresource);
+ dst_subresource_range.array_layers.start += dst_image_inner.first_layer;
+ dst_subresource_range.array_layers.end += dst_image_inner.first_layer;
+ dst_subresource_range.mip_levels.start += dst_image_inner.first_mipmap_level;
+ dst_subresource_range.mip_levels.end += dst_image_inner.first_mipmap_level;
+ self.resources_usage_state.record_image_access(
+ &dst_use_ref,
+ dst_image_inner.image,
+ dst_subresource_range,
+ PipelineStageAccess::Blit_TransferWrite,
+ dst_image_layout,
+ );
+ }
+
+ self.resources.push(Box::new(src_image));
+ self.resources.push(Box::new(dst_image));
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Resolves a multisampled image into a single-sampled image.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `src_image` or `dst_image` were not created from the same device
+ /// as `self`.
+ ///
+ /// # Safety
+ ///
+ /// - Appropriate synchronization must be provided for all images
+ /// that are accessed by the command.
+ /// - All images that are accessed by the command must be in the expected image layout.
+ #[inline]
+ pub unsafe fn resolve_image(
+ &mut self,
+ resolve_image_info: ResolveImageInfo,
+ ) -> Result<&mut Self, CopyError> {
+ self.validate_resolve_image(&resolve_image_info)?;
+
+ unsafe { Ok(self.resolve_image_unchecked(resolve_image_info)) }
+ }
+
+ fn validate_resolve_image(
+ &self,
+ resolve_image_info: &ResolveImageInfo,
+ ) -> Result<(), CopyError> {
+ let device = self.device();
+
+ // VUID-vkCmdResolveImage2-renderpass
+ if self.builder_state.render_pass.is_some() {
+ return Err(CopyError::ForbiddenInsideRenderPass);
+ }
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdResolveImage2-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(CopyError::NotSupportedByQueueFamily);
+ }
+
+ let &ResolveImageInfo {
+ ref src_image,
+ src_image_layout,
+ ref dst_image,
+ dst_image_layout,
+ ref regions,
+ _ne: _,
+ } = resolve_image_info;
+
+ // VUID-VkResolveImageInfo2-srcImageLayout-parameter
+ src_image_layout.validate_device(device)?;
+
+ // VUID-VkResolveImageInfo2-dstImageLayout-parameter
+ dst_image_layout.validate_device(device)?;
+
+ // VUID-VkResolveImageInfo2-commonparent
+ assert_eq!(device, src_image.device());
+ assert_eq!(device, dst_image.device());
+
+ let src_image_type = src_image.dimensions().image_type();
+ let dst_image_type = dst_image.dimensions().image_type();
+
+ // VUID-VkResolveImageInfo2-srcImage-00257
+ if src_image.samples() == SampleCount::Sample1 {
+ return Err(CopyError::SampleCountInvalid {
+ resource: CopyErrorResource::Source,
+ sample_count: dst_image.samples(),
+ allowed_sample_counts: SampleCounts::SAMPLE_2
+ | SampleCounts::SAMPLE_4
+ | SampleCounts::SAMPLE_8
+ | SampleCounts::SAMPLE_16
+ | SampleCounts::SAMPLE_32
+ | SampleCounts::SAMPLE_64,
+ });
+ }
+
+ // VUID-VkResolveImageInfo2-dstImage-00259
+ if dst_image.samples() != SampleCount::Sample1 {
+ return Err(CopyError::SampleCountInvalid {
+ resource: CopyErrorResource::Destination,
+ sample_count: dst_image.samples(),
+ allowed_sample_counts: SampleCounts::SAMPLE_1,
+ });
+ }
+
+ // VUID-VkResolveImageInfo2-dstImage-02003
+ if !dst_image
+ .format_features()
+ .intersects(FormatFeatures::COLOR_ATTACHMENT)
+ {
+ return Err(CopyError::MissingFormatFeature {
+ resource: CopyErrorResource::Destination,
+ format_feature: "color_attachment",
+ });
+ }
+
+ // VUID-VkResolveImageInfo2-srcImage-01386
+ if src_image.format() != dst_image.format() {
+ return Err(CopyError::FormatsMismatch {
+ src_format: src_image.format(),
+ dst_format: dst_image.format(),
+ });
+ }
+
+ // VUID-VkResolveImageInfo2-srcImageLayout-01400
+ if !matches!(
+ src_image_layout,
+ ImageLayout::TransferSrcOptimal | ImageLayout::General
+ ) {
+ return Err(CopyError::ImageLayoutInvalid {
+ resource: CopyErrorResource::Source,
+ image_layout: src_image_layout,
+ });
+ }
+
+ // VUID-VkResolveImageInfo2-dstImageLayout-01401
+ if !matches!(
+ dst_image_layout,
+ ImageLayout::TransferDstOptimal | ImageLayout::General
+ ) {
+ return Err(CopyError::ImageLayoutInvalid {
+ resource: CopyErrorResource::Destination,
+ image_layout: dst_image_layout,
+ });
+ }
+
+ // Should be guaranteed by the requirement that formats match, and that the destination
+ // image format features support color attachments.
+ debug_assert!(
+ src_image.format().aspects().intersects(ImageAspects::COLOR)
+ && dst_image.format().aspects().intersects(ImageAspects::COLOR)
+ );
+
+ for (region_index, region) in regions.iter().enumerate() {
+ let &ImageResolve {
+ ref src_subresource,
+ src_offset,
+ ref dst_subresource,
+ dst_offset,
+ extent,
+ _ne: _,
+ } = region;
+
+ let check_subresource = |resource: CopyErrorResource,
+ image: &dyn ImageAccess,
+ subresource: &ImageSubresourceLayers|
+ -> Result<_, CopyError> {
+ // VUID-VkResolveImageInfo2-srcSubresource-01709
+ // VUID-VkResolveImageInfo2-dstSubresource-01710
+ if subresource.mip_level >= image.mip_levels() {
+ return Err(CopyError::MipLevelsOutOfRange {
+ resource,
+ region_index,
+ mip_levels_range_end: subresource.mip_level + 1,
+ image_mip_levels: image.mip_levels(),
+ });
+ }
+
+ // VUID-VkImageSubresourceLayers-layerCount-01700
+ // VUID-VkResolveImageInfo2-srcImage-04446
+ // VUID-VkResolveImageInfo2-srcImage-04447
+ assert!(!subresource.array_layers.is_empty());
+
+ // VUID-VkResolveImageInfo2-srcSubresource-01711
+ // VUID-VkResolveImageInfo2-dstSubresource-01712
+ // VUID-VkResolveImageInfo2-srcImage-04446
+ // VUID-VkResolveImageInfo2-srcImage-04447
+ if subresource.array_layers.end > image.dimensions().array_layers() {
+ return Err(CopyError::ArrayLayersOutOfRange {
+ resource: CopyErrorResource::Destination,
+ region_index,
+ array_layers_range_end: subresource.array_layers.end,
+ image_array_layers: image.dimensions().array_layers(),
+ });
+ }
+
+ // VUID-VkImageSubresourceLayers-aspectMask-parameter
+ subresource.aspects.validate_device(device)?;
+
+ // VUID-VkImageSubresourceLayers-aspectMask-requiredbitmask
+ // VUID-VkImageResolve2-aspectMask-00266
+ if subresource.aspects != (ImageAspects::COLOR) {
+ return Err(CopyError::AspectsNotAllowed {
+ resource,
+ region_index,
+ aspects: subresource.aspects,
+ allowed_aspects: ImageAspects::COLOR,
+ });
+ }
+
+ Ok(image
+ .dimensions()
+ .mip_level_dimensions(subresource.mip_level)
+ .unwrap()
+ .width_height_depth())
+ };
+
+ let src_subresource_extent =
+ check_subresource(CopyErrorResource::Source, src_image, src_subresource)?;
+ let dst_subresource_extent =
+ check_subresource(CopyErrorResource::Destination, dst_image, dst_subresource)?;
+
+ let src_layer_count =
+ src_subresource.array_layers.end - src_subresource.array_layers.start;
+ let dst_layer_count =
+ dst_subresource.array_layers.end - dst_subresource.array_layers.start;
+
+ // VUID-VkImageResolve2-layerCount-00267
+ // VUID-VkResolveImageInfo2-srcImage-04446
+ // VUID-VkResolveImageInfo2-srcImage-04447
+ if src_layer_count != dst_layer_count {
+ return Err(CopyError::ArrayLayerCountMismatch {
+ region_index,
+ src_layer_count,
+ dst_layer_count,
+ });
+ }
+
+ // No VUID, but it makes sense?
+ assert!(extent[0] != 0 && extent[1] != 0 && extent[2] != 0);
+
+ let check_offset_extent = |resource: CopyErrorResource,
+ _image_type: ImageType,
+ subresource_extent: [u32; 3],
+ offset: [u32; 3]|
+ -> Result<_, CopyError> {
+ for i in 0..3 {
+ // No VUID, but makes sense?
+ assert!(extent[i] != 0);
+
+ // VUID-VkResolveImageInfo2-srcOffset-00269
+ // VUID-VkResolveImageInfo2-srcOffset-00270
+ // VUID-VkResolveImageInfo2-srcOffset-00272
+ // VUID-VkResolveImageInfo2-dstOffset-00274
+ // VUID-VkResolveImageInfo2-dstOffset-00275
+ // VUID-VkResolveImageInfo2-dstOffset-00277
+ if offset[i] + extent[i] > subresource_extent[i] {
+ return Err(CopyError::RegionOutOfImageBounds {
+ resource,
+ region_index,
+ offset_range_end: [
+ offset[0] + extent[0],
+ offset[1] + extent[1],
+ offset[2] + extent[2],
+ ],
+ subresource_extent,
+ });
+ }
+ }
+
+ Ok(())
+ };
+
+ check_offset_extent(
+ CopyErrorResource::Source,
+ src_image_type,
+ src_subresource_extent,
+ src_offset,
+ )?;
+ check_offset_extent(
+ CopyErrorResource::Destination,
+ dst_image_type,
+ dst_subresource_extent,
+ dst_offset,
+ )?;
+ }
+
+ // VUID-VkResolveImageInfo2-pRegions-00255
+ // Can't occur as long as memory aliasing isn't allowed, because `src_image` and
+ // `dst_image` must have different sample counts and therefore can never be the same image.
+
+ // TODO: sync check
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn resolve_image_unchecked(
+ &mut self,
+ resolve_image_info: ResolveImageInfo,
+ ) -> &mut Self {
+ let ResolveImageInfo {
+ src_image,
+ src_image_layout,
+ dst_image,
+ dst_image_layout,
+ regions,
+ _ne: _,
+ } = resolve_image_info;
+
+ if regions.is_empty() {
+ return self;
+ }
+
+ let src_image_inner = src_image.inner();
+ let dst_image_inner = dst_image.inner();
+
+ let fns = self.device().fns();
+
+ if self.device().api_version() >= Version::V1_3
+ || self.device().enabled_extensions().khr_copy_commands2
+ {
+ let regions: SmallVec<[_; 8]> = regions
+ .iter()
+ .map(|region| {
+ let &ImageResolve {
+ ref src_subresource,
+ src_offset,
+ ref dst_subresource,
+ dst_offset,
+ extent,
+ _ne: _,
+ } = region;
+
+ let mut src_subresource = src_subresource.clone();
+ src_subresource.array_layers.start += src_image_inner.first_layer;
+ src_subresource.array_layers.end += src_image_inner.first_layer;
+ src_subresource.mip_level += src_image_inner.first_mipmap_level;
+
+ let mut dst_subresource = dst_subresource.clone();
+ dst_subresource.array_layers.start += dst_image_inner.first_layer;
+ dst_subresource.array_layers.end += dst_image_inner.first_layer;
+ dst_subresource.mip_level += dst_image_inner.first_mipmap_level;
+
+ ash::vk::ImageResolve2 {
+ src_subresource: src_subresource.into(),
+ src_offset: ash::vk::Offset3D {
+ x: src_offset[0] as i32,
+ y: src_offset[1] as i32,
+ z: src_offset[2] as i32,
+ },
+ dst_subresource: dst_subresource.into(),
+ dst_offset: ash::vk::Offset3D {
+ x: dst_offset[0] as i32,
+ y: dst_offset[1] as i32,
+ z: dst_offset[2] as i32,
+ },
+ extent: ash::vk::Extent3D {
+ width: extent[0],
+ height: extent[1],
+ depth: extent[2],
+ },
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let resolve_image_info = ash::vk::ResolveImageInfo2 {
+ src_image: src_image_inner.image.handle(),
+ src_image_layout: src_image_layout.into(),
+ dst_image: dst_image_inner.image.handle(),
+ dst_image_layout: dst_image_layout.into(),
+ region_count: regions.len() as u32,
+ p_regions: regions.as_ptr(),
+ ..Default::default()
+ };
+
+ if self.device().api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_resolve_image2)(self.handle(), &resolve_image_info);
+ } else {
+ (fns.khr_copy_commands2.cmd_resolve_image2_khr)(self.handle(), &resolve_image_info);
+ }
+ } else {
+ let regions: SmallVec<[_; 8]> = regions
+ .iter()
+ .map(|region| {
+ let &ImageResolve {
+ ref src_subresource,
+ src_offset,
+ ref dst_subresource,
+ dst_offset,
+ extent,
+ _ne: _,
+ } = region;
+
+ let mut src_subresource = src_subresource.clone();
+ src_subresource.array_layers.start += src_image_inner.first_layer;
+ src_subresource.array_layers.end += src_image_inner.first_layer;
+ src_subresource.mip_level += src_image_inner.first_mipmap_level;
+
+ let mut dst_subresource = dst_subresource.clone();
+ dst_subresource.array_layers.start += dst_image_inner.first_layer;
+ dst_subresource.array_layers.end += dst_image_inner.first_layer;
+ dst_subresource.mip_level += dst_image_inner.first_mipmap_level;
+
+ ash::vk::ImageResolve {
+ src_subresource: src_subresource.into(),
+ src_offset: ash::vk::Offset3D {
+ x: src_offset[0] as i32,
+ y: src_offset[1] as i32,
+ z: src_offset[2] as i32,
+ },
+ dst_subresource: dst_subresource.into(),
+ dst_offset: ash::vk::Offset3D {
+ x: dst_offset[0] as i32,
+ y: dst_offset[1] as i32,
+ z: dst_offset[2] as i32,
+ },
+ extent: ash::vk::Extent3D {
+ width: extent[0],
+ height: extent[1],
+ depth: extent[2],
+ },
+ }
+ })
+ .collect();
+
+ (fns.v1_0.cmd_resolve_image)(
+ self.handle(),
+ src_image_inner.image.handle(),
+ src_image_layout.into(),
+ dst_image_inner.image.handle(),
+ dst_image_layout.into(),
+ regions.len() as u32,
+ regions.as_ptr(),
+ );
+ }
+
+ let command_index = self.next_command_index;
+ let command_name = "resolve_image";
+ let src_use_ref = ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Source,
+ secondary_use_ref: None,
+ };
+ let dst_use_ref = ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Destination,
+ secondary_use_ref: None,
+ };
+
+ for region in regions {
+ let ImageResolve {
+ src_subresource,
+ src_offset: _,
+ dst_subresource,
+ dst_offset: _,
+ extent: _,
+ _ne: _,
+ } = region;
+
+ let mut src_subresource_range = ImageSubresourceRange::from(src_subresource);
+ src_subresource_range.array_layers.start += src_image_inner.first_layer;
+ src_subresource_range.array_layers.end += src_image_inner.first_layer;
+ src_subresource_range.mip_levels.start += src_image_inner.first_mipmap_level;
+ src_subresource_range.mip_levels.end += src_image_inner.first_mipmap_level;
+ self.resources_usage_state.record_image_access(
+ &src_use_ref,
+ src_image_inner.image,
+ src_subresource_range,
+ PipelineStageAccess::Resolve_TransferRead,
+ src_image_layout,
+ );
+
+ let mut dst_subresource_range = ImageSubresourceRange::from(dst_subresource);
+ dst_subresource_range.array_layers.start += dst_image_inner.first_layer;
+ dst_subresource_range.array_layers.end += dst_image_inner.first_layer;
+ dst_subresource_range.mip_levels.start += dst_image_inner.first_mipmap_level;
+ dst_subresource_range.mip_levels.end += dst_image_inner.first_mipmap_level;
+ self.resources_usage_state.record_image_access(
+ &dst_use_ref,
+ dst_image_inner.image,
+ dst_subresource_range,
+ PipelineStageAccess::Resolve_TransferWrite,
+ dst_image_layout,
+ );
+ }
+
+ self.resources.push(Box::new(src_image));
+ self.resources.push(Box::new(dst_image));
+
+ self.next_command_index += 1;
+ self
+ }
+}
diff --git a/src/command_buffer/standard/builder/debug.rs b/src/command_buffer/standard/builder/debug.rs
new file mode 100644
index 0000000..e0aa436
--- /dev/null
+++ b/src/command_buffer/standard/builder/debug.rs
@@ -0,0 +1,216 @@
+// Copyright (c) 2022 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use super::{CommandBufferBuilder, DebugUtilsError};
+use crate::{
+ command_buffer::allocator::CommandBufferAllocator,
+ device::{DeviceOwned, QueueFlags},
+ instance::debug::DebugUtilsLabel,
+ RequiresOneOf, VulkanObject,
+};
+use std::ffi::CString;
+
+impl<L, A> CommandBufferBuilder<L, A>
+where
+ A: CommandBufferAllocator,
+{
+ /// Opens a command buffer debug label region.
+ #[inline]
+ pub fn begin_debug_utils_label(
+ &mut self,
+ label_info: DebugUtilsLabel,
+ ) -> Result<&mut Self, DebugUtilsError> {
+ self.validate_begin_debug_utils_label(&label_info)?;
+
+ unsafe { Ok(self.begin_debug_utils_label_unchecked(label_info)) }
+ }
+
+ fn validate_begin_debug_utils_label(
+ &self,
+ _label_info: &DebugUtilsLabel,
+ ) -> Result<(), DebugUtilsError> {
+ if !self
+ .device()
+ .instance()
+ .enabled_extensions()
+ .ext_debug_utils
+ {
+ return Err(DebugUtilsError::RequirementNotMet {
+ required_for: "`CommandBufferBuilder::begin_debug_utils_label`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["ext_debug_utils"],
+ ..Default::default()
+ },
+ });
+ }
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdBeginDebugUtilsLabelEXT-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(DebugUtilsError::NotSupportedByQueueFamily);
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn begin_debug_utils_label_unchecked(
+ &mut self,
+ label_info: DebugUtilsLabel,
+ ) -> &mut Self {
+ let DebugUtilsLabel {
+ label_name,
+ color,
+ _ne: _,
+ } = label_info;
+
+ let label_name_vk = CString::new(label_name.as_str()).unwrap();
+ let label_info = ash::vk::DebugUtilsLabelEXT {
+ p_label_name: label_name_vk.as_ptr(),
+ color,
+ ..Default::default()
+ };
+
+ let fns = self.device().instance().fns();
+ (fns.ext_debug_utils.cmd_begin_debug_utils_label_ext)(self.handle(), &label_info);
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Closes a command buffer debug label region.
+ ///
+ /// # Safety
+ ///
+ /// - When submitting the command buffer, there must be an outstanding command buffer label
+ /// region begun with `begin_debug_utils_label` in the queue, either within this command
+ /// buffer or a previously submitted one.
+ #[inline]
+ pub unsafe fn end_debug_utils_label(&mut self) -> Result<&mut Self, DebugUtilsError> {
+ self.validate_end_debug_utils_label()?;
+
+ Ok(self.end_debug_utils_label_unchecked())
+ }
+
+ fn validate_end_debug_utils_label(&self) -> Result<(), DebugUtilsError> {
+ if !self
+ .device()
+ .instance()
+ .enabled_extensions()
+ .ext_debug_utils
+ {
+ return Err(DebugUtilsError::RequirementNotMet {
+ required_for: "`CommandBufferBuilder::end_debug_utils_label`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["ext_debug_utils"],
+ ..Default::default()
+ },
+ });
+ }
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdEndDebugUtilsLabelEXT-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(DebugUtilsError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdEndDebugUtilsLabelEXT-commandBuffer-01912
+ // TODO: not checked, so unsafe for now
+
+ // VUID-vkCmdEndDebugUtilsLabelEXT-commandBuffer-01913
+ // TODO: not checked, so unsafe for now
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn end_debug_utils_label_unchecked(&mut self) -> &mut Self {
+ let fns = self.device().instance().fns();
+ (fns.ext_debug_utils.cmd_end_debug_utils_label_ext)(self.handle());
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Inserts a command buffer debug label.
+ #[inline]
+ pub fn insert_debug_utils_label(
+ &mut self,
+ label_info: DebugUtilsLabel,
+ ) -> Result<&mut Self, DebugUtilsError> {
+ self.validate_insert_debug_utils_label(&label_info)?;
+
+ unsafe { Ok(self.insert_debug_utils_label_unchecked(label_info)) }
+ }
+
+ fn validate_insert_debug_utils_label(
+ &self,
+ _label_info: &DebugUtilsLabel,
+ ) -> Result<(), DebugUtilsError> {
+ if !self
+ .device()
+ .instance()
+ .enabled_extensions()
+ .ext_debug_utils
+ {
+ return Err(DebugUtilsError::RequirementNotMet {
+ required_for: "`CommandBufferBuilder::insert_debug_utils_label`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["ext_debug_utils"],
+ ..Default::default()
+ },
+ });
+ }
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdInsertDebugUtilsLabelEXT-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(DebugUtilsError::NotSupportedByQueueFamily);
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn insert_debug_utils_label_unchecked(
+ &mut self,
+ label_info: DebugUtilsLabel,
+ ) -> &mut Self {
+ let DebugUtilsLabel {
+ label_name,
+ color,
+ _ne: _,
+ } = label_info;
+
+ let label_name_vk = CString::new(label_name.as_str()).unwrap();
+ let label_info = ash::vk::DebugUtilsLabelEXT {
+ p_label_name: label_name_vk.as_ptr(),
+ color,
+ ..Default::default()
+ };
+
+ let fns = self.device().instance().fns();
+ (fns.ext_debug_utils.cmd_insert_debug_utils_label_ext)(self.handle(), &label_info);
+
+ self.next_command_index += 1;
+ self
+ }
+}
diff --git a/src/command_buffer/standard/builder/dynamic_state.rs b/src/command_buffer/standard/builder/dynamic_state.rs
new file mode 100644
index 0000000..d0f357b
--- /dev/null
+++ b/src/command_buffer/standard/builder/dynamic_state.rs
@@ -0,0 +1,2350 @@
+// Copyright (c) 2022 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use super::CommandBufferBuilder;
+use crate::{
+ command_buffer::{
+ allocator::CommandBufferAllocator, commands::dynamic_state::SetDynamicStateError,
+ },
+ device::{DeviceOwned, QueueFlags},
+ pipeline::{
+ graphics::{
+ color_blend::LogicOp,
+ depth_stencil::{CompareOp, StencilFaces, StencilOp, StencilOps},
+ input_assembly::PrimitiveTopology,
+ rasterization::{CullMode, DepthBias, FrontFace, LineStipple},
+ viewport::{Scissor, Viewport},
+ },
+ DynamicState,
+ },
+ RequiresOneOf, Version, VulkanObject,
+};
+use smallvec::SmallVec;
+use std::ops::RangeInclusive;
+
+impl<L, A> CommandBufferBuilder<L, A>
+where
+ A: CommandBufferAllocator,
+{
+ // Helper function for dynamic state setting.
+ #[inline]
+ fn validate_pipeline_fixed_state(
+ &self,
+ state: DynamicState,
+ ) -> Result<(), SetDynamicStateError> {
+ // VUID-vkCmdDispatch-None-02859
+ if self
+ .builder_state
+ .pipeline_graphics
+ .as_ref()
+ .map_or(false, |pipeline| {
+ matches!(pipeline.dynamic_state(state), Some(false))
+ })
+ {
+ return Err(SetDynamicStateError::PipelineHasFixedState);
+ }
+
+ Ok(())
+ }
+
+ /// Sets the dynamic blend constants for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ #[inline]
+ pub fn set_blend_constants(&mut self, constants: [f32; 4]) -> &mut Self {
+ self.validate_set_blend_constants(constants).unwrap();
+
+ unsafe { self.set_blend_constants_unchecked(constants) }
+ }
+
+ fn validate_set_blend_constants(
+ &self,
+ _constants: [f32; 4],
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::BlendConstants)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetBlendConstants-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn set_blend_constants_unchecked(&mut self, constants: [f32; 4]) -> &mut Self {
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_set_blend_constants)(self.handle(), &constants);
+
+ self.builder_state.blend_constants = Some(constants);
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Sets whether dynamic color writes should be enabled for each attachment in the
+ /// framebuffer.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the [`color_write_enable`] feature is not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ /// - If there is a graphics pipeline with color blend state bound, `enables.len()` must equal
+ /// [`attachments.len()`].
+ ///
+ /// [`color_write_enable`]: crate::device::Features::color_write_enable
+ /// [`attachments.len()`]: crate::pipeline::graphics::color_blend::ColorBlendState::attachments
+ #[inline]
+ pub fn set_color_write_enable<I>(&mut self, enables: I) -> &mut Self
+ where
+ I: IntoIterator<Item = bool>,
+ I::IntoIter: ExactSizeIterator,
+ {
+ let enables = enables.into_iter();
+ self.validate_set_color_write_enable(&enables).unwrap();
+
+ unsafe { self.set_color_write_enable_unchecked(enables) }
+ }
+
+ fn validate_set_color_write_enable(
+ &self,
+ enables: &impl ExactSizeIterator,
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::ColorWriteEnable)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetColorWriteEnableEXT-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetColorWriteEnableEXT-None-04803
+ if !self.device().enabled_features().color_write_enable {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`CommandBufferBuilder::set_color_write_enable`",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["ext_color_write_enable"],
+ ..Default::default()
+ },
+ });
+ }
+
+ if let Some(color_blend_state) = self
+ .builder_state
+ .pipeline_graphics
+ .as_ref()
+ .and_then(|pipeline| pipeline.color_blend_state())
+ {
+ // VUID-vkCmdSetColorWriteEnableEXT-attachmentCount-06656
+ // Indirectly checked
+ if enables.len() != color_blend_state.attachments.len() {
+ return Err(
+ SetDynamicStateError::PipelineColorBlendAttachmentCountMismatch {
+ provided_count: enables.len() as u32,
+ required_count: color_blend_state.attachments.len() as u32,
+ },
+ );
+ }
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn set_color_write_enable_unchecked(
+ &mut self,
+ enables: impl IntoIterator<Item = bool>,
+ ) -> &mut Self {
+ let enables: SmallVec<[bool; 4]> = enables.into_iter().collect();
+
+ if enables.is_empty() {
+ return self;
+ }
+
+ debug_assert!(self.device().enabled_extensions().ext_color_write_enable);
+ let enables_vk = enables
+ .iter()
+ .copied()
+ .map(ash::vk::Bool32::from)
+ .collect::<SmallVec<[_; 4]>>();
+
+ let fns = self.device().fns();
+ (fns.ext_color_write_enable.cmd_set_color_write_enable_ext)(
+ self.handle(),
+ enables_vk.len() as u32,
+ enables_vk.as_ptr(),
+ );
+
+ self.builder_state.color_write_enable = Some(enables);
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Sets the dynamic cull mode for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the device API version is less than 1.3 and the [`extended_dynamic_state`]
+ /// feature is not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ ///
+ /// [`extended_dynamic_state`]: crate::device::Features::extended_dynamic_state
+ #[inline]
+ pub fn set_cull_mode(&mut self, cull_mode: CullMode) -> &mut Self {
+ self.validate_set_cull_mode(cull_mode).unwrap();
+
+ unsafe { self.set_cull_mode_unchecked(cull_mode) }
+ }
+
+ fn validate_set_cull_mode(&self, cull_mode: CullMode) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::CullMode)?;
+
+ // VUID-vkCmdSetCullMode-cullMode-parameter
+ cull_mode.validate_device(self.device())?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetCullMode-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetCullMode-None-03384
+ if !(self.device().api_version() >= Version::V1_3
+ || self.device().enabled_features().extended_dynamic_state)
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`CommandBufferBuilder::set_cull_mode`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn set_cull_mode_unchecked(&mut self, cull_mode: CullMode) -> &mut Self {
+ let fns = self.device().fns();
+
+ if self.device().api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_set_cull_mode)(self.handle(), cull_mode.into());
+ } else {
+ debug_assert!(
+ self.device()
+ .enabled_extensions()
+ .ext_extended_dynamic_state
+ );
+ (fns.ext_extended_dynamic_state.cmd_set_cull_mode_ext)(self.handle(), cull_mode.into());
+ }
+
+ self.builder_state.cull_mode = Some(cull_mode);
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Sets the dynamic depth bias values for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ /// - If the [`depth_bias_clamp`] feature is not enabled on the device, panics if `clamp` is
+ /// not 0.0.
+ ///
+ /// [`depth_bias_clamp`]: crate::device::Features::depth_bias_clamp
+ #[inline]
+ pub fn set_depth_bias(
+ &mut self,
+ constant_factor: f32,
+ clamp: f32,
+ slope_factor: f32,
+ ) -> &mut Self {
+ self.validate_set_depth_bias(constant_factor, clamp, slope_factor)
+ .unwrap();
+
+ unsafe { self.set_depth_bias_unchecked(constant_factor, clamp, slope_factor) }
+ }
+
+ fn validate_set_depth_bias(
+ &self,
+ _constant_factor: f32,
+ clamp: f32,
+ _slope_factor: f32,
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::DepthBias)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetDepthBias-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetDepthBias-depthBiasClamp-00790
+ if clamp != 0.0 && !self.device().enabled_features().depth_bias_clamp {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`clamp` is not `0.0`",
+ requires_one_of: RequiresOneOf {
+ features: &["depth_bias_clamp"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn set_depth_bias_unchecked(
+ &mut self,
+ constant_factor: f32,
+ clamp: f32,
+ slope_factor: f32,
+ ) -> &mut Self {
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_set_depth_bias)(self.handle(), constant_factor, clamp, slope_factor);
+
+ self.builder_state.depth_bias = Some(DepthBias {
+ constant_factor,
+ clamp,
+ slope_factor,
+ });
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Sets whether dynamic depth bias is enabled for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the device API version is less than 1.3 and the [`extended_dynamic_state2`]
+ /// feature is not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ ///
+ /// [`extended_dynamic_state2`]: crate::device::Features::extended_dynamic_state2
+ #[inline]
+ pub fn set_depth_bias_enable(&mut self, enable: bool) -> &mut Self {
+ self.validate_set_depth_bias_enable(enable).unwrap();
+
+ unsafe { self.set_depth_bias_enable_unchecked(enable) }
+ }
+
+ fn validate_set_depth_bias_enable(&self, _enable: bool) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::DepthBiasEnable)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetDepthBiasEnable-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetDepthBiasEnable-None-04872
+ if !(self.device().api_version() >= Version::V1_3
+ || self.device().enabled_features().extended_dynamic_state2)
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`CommandBufferBuilder::set_depth_bias_enable`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state2"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn set_depth_bias_enable_unchecked(&mut self, enable: bool) -> &mut Self {
+ let fns = self.device().fns();
+
+ if self.device().api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_set_depth_bias_enable)(self.handle(), enable.into());
+ } else {
+ debug_assert!(
+ self.device()
+ .enabled_extensions()
+ .ext_extended_dynamic_state2
+ );
+ (fns.ext_extended_dynamic_state2
+ .cmd_set_depth_bias_enable_ext)(self.handle(), enable.into());
+ }
+
+ self.builder_state.depth_bias_enable = Some(enable);
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Sets the dynamic depth bounds for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ /// - If the [`ext_depth_range_unrestricted`] extension is not enabled on the device, panics if
+ /// the start and end of `bounds` are not between 0.0 and 1.0 inclusive.
+ ///
+ /// [`ext_depth_range_unrestricted`]: crate::device::DeviceExtensions::ext_depth_range_unrestricted
+ pub fn set_depth_bounds(&mut self, bounds: RangeInclusive<f32>) -> &mut Self {
+ self.validate_set_depth_bounds(bounds.clone()).unwrap();
+
+ unsafe { self.set_depth_bounds_unchecked(bounds) }
+ }
+
+ fn validate_set_depth_bounds(
+ &self,
+ bounds: RangeInclusive<f32>,
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::DepthBounds)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetDepthBounds-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetDepthBounds-minDepthBounds-00600
+ // VUID-vkCmdSetDepthBounds-maxDepthBounds-00601
+ if !self
+ .device()
+ .enabled_extensions()
+ .ext_depth_range_unrestricted
+ && !((0.0..=1.0).contains(bounds.start()) && (0.0..=1.0).contains(bounds.end()))
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`bounds` is not between `0.0` and `1.0` inclusive",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["ext_depth_range_unrestricted"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn set_depth_bounds_unchecked(&mut self, bounds: RangeInclusive<f32>) -> &mut Self {
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_set_depth_bounds)(self.handle(), *bounds.start(), *bounds.end());
+
+ self.builder_state.depth_bounds = Some(bounds);
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Sets whether dynamic depth bounds testing is enabled for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the device API version is less than 1.3 and the [`extended_dynamic_state`]
+ /// feature is not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ ///
+ /// [`extended_dynamic_state`]: crate::device::Features::extended_dynamic_state
+ #[inline]
+ pub fn set_depth_bounds_test_enable(&mut self, enable: bool) -> &mut Self {
+ self.validate_set_depth_bounds_test_enable(enable).unwrap();
+
+ unsafe { self.set_depth_bounds_test_enable_unchecked(enable) }
+ }
+
+ fn validate_set_depth_bounds_test_enable(
+ &self,
+ _enable: bool,
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::DepthBoundsTestEnable)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetDepthBoundsTestEnable-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetDepthBoundsTestEnable-None-03349
+ if !(self.device().api_version() >= Version::V1_3
+ || self.device().enabled_features().extended_dynamic_state)
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`CommandBufferBuilder::set_depth_bounds_test_enable`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn set_depth_bounds_test_enable_unchecked(&mut self, enable: bool) -> &mut Self {
+ let fns = self.device().fns();
+
+ if self.device().api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_set_depth_bounds_test_enable)(self.handle(), enable.into());
+ } else {
+ debug_assert!(
+ self.device()
+ .enabled_extensions()
+ .ext_extended_dynamic_state
+ );
+ (fns.ext_extended_dynamic_state
+ .cmd_set_depth_bounds_test_enable_ext)(self.handle(), enable.into());
+ }
+
+ self.builder_state.depth_bounds_test_enable = Some(enable);
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Sets the dynamic depth compare op for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the device API version is less than 1.3 and the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is
+ /// not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ #[inline]
+ pub fn set_depth_compare_op(&mut self, compare_op: CompareOp) -> &mut Self {
+ self.validate_set_depth_compare_op(compare_op).unwrap();
+
+ unsafe { self.set_depth_compare_op_unchecked(compare_op) }
+ }
+
+ fn validate_set_depth_compare_op(
+ &self,
+ compare_op: CompareOp,
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::DepthCompareOp)?;
+
+ // VUID-vkCmdSetDepthCompareOp-depthCompareOp-parameter
+ compare_op.validate_device(self.device())?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetDepthCompareOp-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetDepthCompareOp-None-03353
+ if !(self.device().api_version() >= Version::V1_3
+ || self.device().enabled_features().extended_dynamic_state)
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`CommandBufferBuilder::set_depth_compare_op`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn set_depth_compare_op_unchecked(&mut self, compare_op: CompareOp) -> &mut Self {
+ let fns = self.device().fns();
+
+ if self.device().api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_set_depth_compare_op)(self.handle(), compare_op.into());
+ } else {
+ debug_assert!(
+ self.device()
+ .enabled_extensions()
+ .ext_extended_dynamic_state
+ );
+ (fns.ext_extended_dynamic_state.cmd_set_depth_compare_op_ext)(
+ self.handle(),
+ compare_op.into(),
+ );
+ }
+
+ self.builder_state.depth_compare_op = Some(compare_op);
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Sets whether dynamic depth testing is enabled for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the device API version is less than 1.3 and the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is
+ /// not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ #[inline]
+ pub fn set_depth_test_enable(&mut self, enable: bool) -> &mut Self {
+ self.validate_set_depth_test_enable(enable).unwrap();
+
+ unsafe { self.set_depth_test_enable_unchecked(enable) }
+ }
+
+ fn validate_set_depth_test_enable(&self, _enable: bool) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::DepthTestEnable)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetDepthTestEnable-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetDepthTestEnable-None-03352
+ if !(self.device().api_version() >= Version::V1_3
+ || self.device().enabled_features().extended_dynamic_state)
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`CommandBufferBuilder::set_depth_test_enable`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn set_depth_test_enable_unchecked(&mut self, enable: bool) -> &mut Self {
+ let fns = self.device().fns();
+
+ if self.device().api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_set_depth_test_enable)(self.handle(), enable.into());
+ } else {
+ debug_assert!(
+ self.device()
+ .enabled_extensions()
+ .ext_extended_dynamic_state
+ );
+ (fns.ext_extended_dynamic_state.cmd_set_depth_test_enable_ext)(
+ self.handle(),
+ enable.into(),
+ );
+ }
+
+ self.builder_state.depth_test_enable = Some(enable);
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Sets whether dynamic depth write is enabled for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the device API version is less than 1.3 and the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is
+ /// not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ #[inline]
+ pub fn set_depth_write_enable(&mut self, enable: bool) -> &mut Self {
+ self.validate_set_depth_write_enable(enable).unwrap();
+
+ unsafe { self.set_depth_write_enable_unchecked(enable) }
+ }
+
+ fn validate_set_depth_write_enable(&self, _enable: bool) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::DepthWriteEnable)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetDepthWriteEnable-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetDepthWriteEnable-None-03354
+ if !(self.device().api_version() >= Version::V1_3
+ || self.device().enabled_features().extended_dynamic_state)
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`CommandBufferBuilder::set_depth_write_enable`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn set_depth_write_enable_unchecked(&mut self, enable: bool) -> &mut Self {
+ let fns = self.device().fns();
+
+ if self.device().api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_set_depth_write_enable)(self.handle(), enable.into());
+ } else {
+ debug_assert!(
+ self.device()
+ .enabled_extensions()
+ .ext_extended_dynamic_state
+ );
+ (fns.ext_extended_dynamic_state
+ .cmd_set_depth_write_enable_ext)(self.handle(), enable.into());
+ }
+
+ self.builder_state.depth_write_enable = Some(enable);
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Sets the dynamic discard rectangles for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the
+ /// [`ext_discard_rectangles`](crate::device::DeviceExtensions::ext_discard_rectangles)
+ /// extension is not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ /// - Panics if the highest discard rectangle slot being set is greater than the
+ /// [`max_discard_rectangles`](crate::device::Properties::max_discard_rectangles) device
+ /// property.
+ pub fn set_discard_rectangle(
+ &mut self,
+ first_rectangle: u32,
+ rectangles: impl IntoIterator<Item = Scissor>,
+ ) -> &mut Self {
+ let rectangles: SmallVec<[Scissor; 2]> = rectangles.into_iter().collect();
+ self.validate_set_discard_rectangle(first_rectangle, &rectangles)
+ .unwrap();
+
+ unsafe { self.set_discard_rectangle_unchecked(first_rectangle, rectangles) }
+ }
+
+ fn validate_set_discard_rectangle(
+ &self,
+ first_rectangle: u32,
+ rectangles: &[Scissor],
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::DiscardRectangle)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetDiscardRectangle-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ if self.device().enabled_extensions().ext_discard_rectangles {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`CommandBufferBuilder::set_discard_rectangle`",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["ext_discard_rectangles"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdSetDiscardRectangleEXT-firstDiscardRectangle-00585
+ if first_rectangle + rectangles.len() as u32
+ > self
+ .device()
+ .physical_device()
+ .properties()
+ .max_discard_rectangles
+ .unwrap()
+ {
+ return Err(SetDynamicStateError::MaxDiscardRectanglesExceeded {
+ provided: first_rectangle + rectangles.len() as u32,
+ max: self
+ .device()
+ .physical_device()
+ .properties()
+ .max_discard_rectangles
+ .unwrap(),
+ });
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn set_discard_rectangle_unchecked(
+ &mut self,
+ first_rectangle: u32,
+ rectangles: impl IntoIterator<Item = Scissor>,
+ ) -> &mut Self {
+ let rectangles: SmallVec<[Scissor; 2]> = rectangles.into_iter().collect();
+
+ if rectangles.is_empty() {
+ return self;
+ }
+
+ debug_assert!(self.device().enabled_extensions().ext_discard_rectangles);
+
+ let rectangles_vk = rectangles
+ .iter()
+ .copied()
+ .map(ash::vk::Rect2D::from)
+ .collect::<SmallVec<[_; 2]>>();
+
+ debug_assert!(
+ first_rectangle + rectangles.len() as u32
+ <= self
+ .device()
+ .physical_device()
+ .properties()
+ .max_discard_rectangles
+ .unwrap()
+ );
+
+ let fns = self.device().fns();
+ (fns.ext_discard_rectangles.cmd_set_discard_rectangle_ext)(
+ self.handle(),
+ first_rectangle,
+ rectangles_vk.len() as u32,
+ rectangles_vk.as_ptr(),
+ );
+
+ for (num, rectangle) in rectangles.iter().enumerate() {
+ let num = num as u32 + first_rectangle;
+ self.builder_state.discard_rectangle.insert(num, *rectangle);
+ }
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Sets the dynamic front face for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the device API version is less than 1.3 and the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is
+ /// not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ #[inline]
+ pub fn set_front_face(&mut self, face: FrontFace) -> &mut Self {
+ self.validate_set_front_face(face).unwrap();
+
+ unsafe { self.set_front_face_unchecked(face) }
+ }
+
+ fn validate_set_front_face(&self, face: FrontFace) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::FrontFace)?;
+
+ // VUID-vkCmdSetFrontFace-frontFace-parameter
+ face.validate_device(self.device())?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetFrontFace-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetFrontFace-None-03383
+ if !(self.device().api_version() >= Version::V1_3
+ || self.device().enabled_features().extended_dynamic_state)
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`CommandBufferBuilder::set_front_face`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn set_front_face_unchecked(&mut self, face: FrontFace) -> &mut Self {
+ let fns = self.device().fns();
+
+ if self.device().api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_set_front_face)(self.handle(), face.into());
+ } else {
+ debug_assert!(
+ self.device()
+ .enabled_extensions()
+ .ext_extended_dynamic_state
+ );
+ (fns.ext_extended_dynamic_state.cmd_set_front_face_ext)(self.handle(), face.into());
+ }
+
+ self.builder_state.front_face = Some(face);
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Sets the dynamic line stipple values for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the [`ext_line_rasterization`](crate::device::DeviceExtensions::ext_line_rasterization)
+ /// extension is not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ /// - Panics if `factor` is not between 1 and 256 inclusive.
+ #[inline]
+ pub fn set_line_stipple(&mut self, factor: u32, pattern: u16) -> &mut Self {
+ self.validate_set_line_stipple(factor, pattern).unwrap();
+
+ unsafe { self.set_line_stipple_unchecked(factor, pattern) }
+ }
+
+ fn validate_set_line_stipple(
+ &self,
+ factor: u32,
+ _pattern: u16,
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::LineStipple)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetLineStippleEXT-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ if !self.device().enabled_extensions().ext_line_rasterization {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`CommandBufferBuilder::set_line_stipple`",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["ext_line_rasterization"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdSetLineStippleEXT-lineStippleFactor-02776
+ if !(1..=256).contains(&factor) {
+ return Err(SetDynamicStateError::FactorOutOfRange);
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn set_line_stipple_unchecked(&mut self, factor: u32, pattern: u16) -> &mut Self {
+ debug_assert!(self.device().enabled_extensions().ext_line_rasterization);
+ let fns = self.device().fns();
+ (fns.ext_line_rasterization.cmd_set_line_stipple_ext)(self.handle(), factor, pattern);
+
+ self.builder_state.line_stipple = Some(LineStipple { factor, pattern });
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Sets the dynamic line width for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ /// - If the [`wide_lines`](crate::device::Features::wide_lines) feature is not enabled, panics
+ /// if `line_width` is not 1.0.
+ pub fn set_line_width(&mut self, line_width: f32) -> &mut Self {
+ self.validate_set_line_width(line_width).unwrap();
+
+ unsafe { self.set_line_width_unchecked(line_width) }
+ }
+
+ fn validate_set_line_width(&self, line_width: f32) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::LineWidth)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetLineWidth-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetLineWidth-lineWidth-00788
+ if !self.device().enabled_features().wide_lines && line_width != 1.0 {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`line_width` is not `1.0`",
+ requires_one_of: RequiresOneOf {
+ features: &["wide_lines"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn set_line_width_unchecked(&mut self, line_width: f32) -> &mut Self {
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_set_line_width)(self.handle(), line_width);
+
+ self.builder_state.line_width = Some(line_width);
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Sets the dynamic logic op for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the
+ /// [`extended_dynamic_state2_logic_op`](crate::device::Features::extended_dynamic_state2_logic_op)
+ /// feature is not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ #[inline]
+ pub fn set_logic_op(&mut self, logic_op: LogicOp) -> &mut Self {
+ self.validate_set_logic_op(logic_op).unwrap();
+
+ unsafe { self.set_logic_op_unchecked(logic_op) }
+ }
+
+ fn validate_set_logic_op(&self, logic_op: LogicOp) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::LogicOp)?;
+
+ // VUID-vkCmdSetLogicOpEXT-logicOp-parameter
+ logic_op.validate_device(self.device())?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetLogicOpEXT-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetLogicOpEXT-None-04867
+ if !self
+ .device()
+ .enabled_features()
+ .extended_dynamic_state2_logic_op
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`CommandBufferBuilder::set_logic_op`",
+ requires_one_of: RequiresOneOf {
+ features: &["extended_dynamic_state2_logic_op"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn set_logic_op_unchecked(&mut self, logic_op: LogicOp) -> &mut Self {
+ debug_assert!(
+ self.device()
+ .enabled_extensions()
+ .ext_extended_dynamic_state2
+ );
+ debug_assert!(
+ self.device()
+ .enabled_features()
+ .extended_dynamic_state2_logic_op
+ );
+ let fns = self.device().fns();
+ (fns.ext_extended_dynamic_state2.cmd_set_logic_op_ext)(self.handle(), logic_op.into());
+
+ self.builder_state.logic_op = Some(logic_op);
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Sets the dynamic number of patch control points for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the
+ /// [`extended_dynamic_state2_patch_control_points`](crate::device::Features::extended_dynamic_state2_patch_control_points)
+ /// feature is not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ /// - Panics if `num` is 0.
+ /// - Panics if `num` is greater than the
+ /// [`max_tessellation_patch_size`](crate::device::Properties::max_tessellation_patch_size)
+ /// property of the device.
+ #[inline]
+ pub fn set_patch_control_points(&mut self, num: u32) -> &mut Self {
+ self.validate_set_patch_control_points(num).unwrap();
+
+ unsafe { self.set_patch_control_points_unchecked(num) }
+ }
+
+ fn validate_set_patch_control_points(&self, num: u32) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::PatchControlPoints)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetPatchControlPointsEXT-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetPatchControlPointsEXT-None-04873
+ if !self
+ .device()
+ .enabled_features()
+ .extended_dynamic_state2_patch_control_points
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`CommandBufferBuilder::set_patch_control_points`",
+ requires_one_of: RequiresOneOf {
+ features: &["extended_dynamic_state2_patch_control_points"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdSetPatchControlPointsEXT-patchControlPoints-04874
+ assert!(num > 0, "num must be greater than 0");
+
+ // VUID-vkCmdSetPatchControlPointsEXT-patchControlPoints-04874
+ if num
+ > self
+ .device()
+ .physical_device()
+ .properties()
+ .max_tessellation_patch_size
+ {
+ return Err(SetDynamicStateError::MaxTessellationPatchSizeExceeded {
+ provided: num,
+ max: self
+ .device()
+ .physical_device()
+ .properties()
+ .max_tessellation_patch_size,
+ });
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn set_patch_control_points_unchecked(&mut self, num: u32) -> &mut Self {
+ debug_assert!(
+ self.device()
+ .enabled_extensions()
+ .ext_extended_dynamic_state2
+ );
+ let fns = self.device().fns();
+ (fns.ext_extended_dynamic_state2
+ .cmd_set_patch_control_points_ext)(self.handle(), num);
+
+ self.builder_state.patch_control_points = Some(num);
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Sets whether dynamic primitive restart is enabled for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the device API version is less than 1.3 and the
+ /// [`extended_dynamic_state2`](crate::device::Features::extended_dynamic_state2) feature is
+ /// not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ #[inline]
+ pub fn set_primitive_restart_enable(&mut self, enable: bool) -> &mut Self {
+ self.validate_set_primitive_restart_enable(enable).unwrap();
+
+ unsafe { self.set_primitive_restart_enable_unchecked(enable) }
+ }
+
+ fn validate_set_primitive_restart_enable(
+ &self,
+ _enable: bool,
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::PrimitiveRestartEnable)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetPrimitiveRestartEnable-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetPrimitiveRestartEnable-None-04866
+ if !(self.device().api_version() >= Version::V1_3
+ || self.device().enabled_features().extended_dynamic_state2)
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`CommandBufferBuilder::set_primitive_restart_enable`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state2"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn set_primitive_restart_enable_unchecked(&mut self, enable: bool) -> &mut Self {
+ let fns = self.device().fns();
+
+ if self.device().api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_set_primitive_restart_enable)(self.handle(), enable.into());
+ } else {
+ debug_assert!(
+ self.device()
+ .enabled_extensions()
+ .ext_extended_dynamic_state2
+ );
+ (fns.ext_extended_dynamic_state2
+ .cmd_set_primitive_restart_enable_ext)(self.handle(), enable.into());
+ }
+
+ self.builder_state.primitive_restart_enable = Some(enable);
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Sets the dynamic primitive topology for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the device API version is less than 1.3 and the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is
+ /// not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ /// - If the [`geometry_shader`](crate::device::Features::geometry_shader) feature is not
+ /// enabled, panics if `topology` is a `WithAdjacency` topology.
+ /// - If the [`tessellation_shader`](crate::device::Features::tessellation_shader) feature is
+ /// not enabled, panics if `topology` is `PatchList`.
+ #[inline]
+ pub fn set_primitive_topology(&mut self, topology: PrimitiveTopology) -> &mut Self {
+ self.validate_set_primitive_topology(topology).unwrap();
+
+ unsafe { self.set_primitive_topology_unchecked(topology) }
+ }
+
+ fn validate_set_primitive_topology(
+ &self,
+ topology: PrimitiveTopology,
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::PrimitiveTopology)?;
+
+ // VUID-vkCmdSetPrimitiveTopology-primitiveTopology-parameter
+ topology.validate_device(self.device())?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetPrimitiveTopology-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetPrimitiveTopology-None-03347
+ if !(self.device().api_version() >= Version::V1_3
+ || self.device().enabled_features().extended_dynamic_state)
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`CommandBufferBuilder::set_primitive_topology`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID?
+ // Since these requirements exist for fixed state when creating the pipeline,
+ // I assume they exist for dynamic state as well.
+ match topology {
+ PrimitiveTopology::TriangleFan => {
+ if self.device().enabled_extensions().khr_portability_subset
+ && !self.device().enabled_features().triangle_fans
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "this device is a portability subset device, and `topology` \
+ is `PrimitiveTopology::TriangleFan`",
+ requires_one_of: RequiresOneOf {
+ features: &["triangle_fans"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ PrimitiveTopology::LineListWithAdjacency
+ | PrimitiveTopology::LineStripWithAdjacency
+ | PrimitiveTopology::TriangleListWithAdjacency
+ | PrimitiveTopology::TriangleStripWithAdjacency => {
+ if !self.device().enabled_features().geometry_shader {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`topology` is `PrimitiveTopology::*WithAdjacency`",
+ requires_one_of: RequiresOneOf {
+ features: &["geometry_shader"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ PrimitiveTopology::PatchList => {
+ if !self.device().enabled_features().tessellation_shader {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`topology` is `PrimitiveTopology::PatchList`",
+ requires_one_of: RequiresOneOf {
+ features: &["tessellation_shader"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ _ => (),
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn set_primitive_topology_unchecked(
+ &mut self,
+ topology: PrimitiveTopology,
+ ) -> &mut Self {
+ let fns = self.device().fns();
+
+ if self.device().api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_set_primitive_topology)(self.handle(), topology.into());
+ } else {
+ debug_assert!(
+ self.device()
+ .enabled_extensions()
+ .ext_extended_dynamic_state
+ );
+ (fns.ext_extended_dynamic_state
+ .cmd_set_primitive_topology_ext)(self.handle(), topology.into());
+ }
+
+ self.builder_state.primitive_topology = Some(topology);
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Sets whether dynamic rasterizer discard is enabled for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the device API version is less than 1.3 and the
+ /// [`extended_dynamic_state2`](crate::device::Features::extended_dynamic_state2) feature is
+ /// not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ #[inline]
+ pub fn set_rasterizer_discard_enable(&mut self, enable: bool) -> &mut Self {
+ self.validate_set_rasterizer_discard_enable(enable).unwrap();
+
+ unsafe { self.set_rasterizer_discard_enable_unchecked(enable) }
+ }
+
+ fn validate_set_rasterizer_discard_enable(
+ &self,
+ _enable: bool,
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::RasterizerDiscardEnable)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetRasterizerDiscardEnable-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetRasterizerDiscardEnable-None-04871
+ if !(self.device().api_version() >= Version::V1_3
+ || self.device().enabled_features().extended_dynamic_state2)
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`CommandBufferBuilder::set_rasterizer_discard_enable`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state2"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn set_rasterizer_discard_enable_unchecked(&mut self, enable: bool) -> &mut Self {
+ let fns = self.device().fns();
+
+ if self.device().api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_set_rasterizer_discard_enable)(self.handle(), enable.into());
+ } else {
+ debug_assert!(
+ self.device()
+ .enabled_extensions()
+ .ext_extended_dynamic_state2
+ );
+ (fns.ext_extended_dynamic_state2
+ .cmd_set_rasterizer_discard_enable_ext)(self.handle(), enable.into());
+ }
+
+ self.builder_state.rasterizer_discard_enable = Some(enable);
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Sets the dynamic scissors for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ /// - Panics if the highest scissor slot being set is greater than the
+ /// [`max_viewports`](crate::device::Properties::max_viewports) device property.
+ /// - If the [`multi_viewport`](crate::device::Features::multi_viewport) feature is not enabled,
+ /// panics if `first_scissor` is not 0, or if more than 1 scissor is provided.
+ #[inline]
+ pub fn set_scissor(
+ &mut self,
+ first_scissor: u32,
+ scissors: impl IntoIterator<Item = Scissor>,
+ ) -> &mut Self {
+ let scissors: SmallVec<[Scissor; 2]> = scissors.into_iter().collect();
+ self.validate_set_scissor(first_scissor, &scissors).unwrap();
+
+ unsafe { self.set_scissor_unchecked(first_scissor, scissors) }
+ }
+
+ fn validate_set_scissor(
+ &self,
+ first_scissor: u32,
+ scissors: &[Scissor],
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::Scissor)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetScissor-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetScissor-firstScissor-00592
+ if first_scissor + scissors.len() as u32
+ > self.device().physical_device().properties().max_viewports
+ {
+ return Err(SetDynamicStateError::MaxViewportsExceeded {
+ provided: first_scissor + scissors.len() as u32,
+ max: self.device().physical_device().properties().max_viewports,
+ });
+ }
+
+ if !self.device().enabled_features().multi_viewport {
+ // VUID-vkCmdSetScissor-firstScissor-00593
+ if first_scissor != 0 {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`first_scissor` is not `0`",
+ requires_one_of: RequiresOneOf {
+ features: &["multi_viewport"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdSetScissor-scissorCount-00594
+ if scissors.len() > 1 {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`scissors.len()` is greater than `1`",
+ requires_one_of: RequiresOneOf {
+ features: &["multi_viewport"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn set_scissor_unchecked(
+ &mut self,
+ first_scissor: u32,
+ scissors: impl IntoIterator<Item = Scissor>,
+ ) -> &mut Self {
+ let scissors: SmallVec<[Scissor; 2]> = scissors.into_iter().collect();
+
+ if scissors.is_empty() {
+ return self;
+ }
+
+ let scissors_vk = scissors
+ .iter()
+ .copied()
+ .map(ash::vk::Rect2D::from)
+ .collect::<SmallVec<[_; 2]>>();
+
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_set_scissor)(
+ self.handle(),
+ first_scissor,
+ scissors_vk.len() as u32,
+ scissors_vk.as_ptr(),
+ );
+
+ for (num, scissor) in scissors.iter().enumerate() {
+ let num = num as u32 + first_scissor;
+ self.builder_state.scissor.insert(num, *scissor);
+ }
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Sets the dynamic scissors with count for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the device API version is less than 1.3 and the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is
+ /// not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ /// - Panics if the highest scissor slot being set is greater than the
+ /// [`max_viewports`](crate::device::Properties::max_viewports) device property.
+ /// - If the [`multi_viewport`](crate::device::Features::multi_viewport) feature is not enabled,
+ /// panics if more than 1 scissor is provided.
+ #[inline]
+ pub fn set_scissor_with_count(
+ &mut self,
+ scissors: impl IntoIterator<Item = Scissor>,
+ ) -> &mut Self {
+ let scissors: SmallVec<[Scissor; 2]> = scissors.into_iter().collect();
+ self.validate_set_scissor_with_count(&scissors).unwrap();
+
+ unsafe { self.set_scissor_with_count_unchecked(scissors) }
+ }
+
+ fn validate_set_scissor_with_count(
+ &self,
+ scissors: &[Scissor],
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::ScissorWithCount)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetScissorWithCount-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetScissorWithCount-None-03396
+ if !(self.device().api_version() >= Version::V1_3
+ || self.device().enabled_features().extended_dynamic_state)
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`CommandBufferBuilder::set_scissor_with_count`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdSetScissorWithCount-scissorCount-03397
+ if scissors.len() as u32 > self.device().physical_device().properties().max_viewports {
+ return Err(SetDynamicStateError::MaxViewportsExceeded {
+ provided: scissors.len() as u32,
+ max: self.device().physical_device().properties().max_viewports,
+ });
+ }
+
+ // VUID-vkCmdSetScissorWithCount-scissorCount-03398
+ if !self.device().enabled_features().multi_viewport && scissors.len() > 1 {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`scissors.len()` is greater than `1`",
+ requires_one_of: RequiresOneOf {
+ features: &["multi_viewport"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn set_scissor_with_count_unchecked(
+ &mut self,
+ scissors: impl IntoIterator<Item = Scissor>,
+ ) -> &mut Self {
+ let scissors: SmallVec<[Scissor; 2]> = scissors.into_iter().collect();
+
+ if scissors.is_empty() {
+ return self;
+ }
+
+ let scissors_vk = scissors
+ .iter()
+ .copied()
+ .map(ash::vk::Rect2D::from)
+ .collect::<SmallVec<[_; 2]>>();
+
+ let fns = self.device().fns();
+
+ if self.device().api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_set_scissor_with_count)(
+ self.handle(),
+ scissors_vk.len() as u32,
+ scissors_vk.as_ptr(),
+ );
+ } else {
+ debug_assert!(
+ self.device()
+ .enabled_extensions()
+ .ext_extended_dynamic_state
+ );
+ (fns.ext_extended_dynamic_state
+ .cmd_set_scissor_with_count_ext)(
+ self.handle(),
+ scissors_vk.len() as u32,
+ scissors_vk.as_ptr(),
+ );
+ }
+
+ self.builder_state.scissor_with_count = Some(scissors);
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Sets the dynamic stencil compare mask on one or both faces for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ pub fn set_stencil_compare_mask(
+ &mut self,
+ faces: StencilFaces,
+ compare_mask: u32,
+ ) -> &mut Self {
+ self.validate_set_stencil_compare_mask(faces, compare_mask)
+ .unwrap();
+
+ unsafe { self.set_stencil_compare_mask_unchecked(faces, compare_mask) }
+ }
+
+ fn validate_set_stencil_compare_mask(
+ &self,
+ faces: StencilFaces,
+ _compare_mask: u32,
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::StencilCompareMask)?;
+
+ // VUID-vkCmdSetStencilCompareMask-faceMask-parameter
+ faces.validate_device(self.device())?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetStencilCompareMask-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn set_stencil_compare_mask_unchecked(
+ &mut self,
+ faces: StencilFaces,
+ compare_mask: u32,
+ ) -> &mut Self {
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_set_stencil_compare_mask)(self.handle(), faces.into(), compare_mask);
+
+ let faces = ash::vk::StencilFaceFlags::from(faces);
+
+ if faces.intersects(ash::vk::StencilFaceFlags::FRONT) {
+ self.builder_state.stencil_compare_mask.front = Some(compare_mask);
+ }
+
+ if faces.intersects(ash::vk::StencilFaceFlags::BACK) {
+ self.builder_state.stencil_compare_mask.back = Some(compare_mask);
+ }
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Sets the dynamic stencil ops on one or both faces for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the device API version is less than 1.3 and the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is
+ /// not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ #[inline]
+ pub fn set_stencil_op(
+ &mut self,
+ faces: StencilFaces,
+ fail_op: StencilOp,
+ pass_op: StencilOp,
+ depth_fail_op: StencilOp,
+ compare_op: CompareOp,
+ ) -> &mut Self {
+ self.validate_set_stencil_op(faces, fail_op, pass_op, depth_fail_op, compare_op)
+ .unwrap();
+
+ unsafe { self.set_stencil_op_unchecked(faces, fail_op, pass_op, depth_fail_op, compare_op) }
+ }
+
+ fn validate_set_stencil_op(
+ &self,
+ faces: StencilFaces,
+ fail_op: StencilOp,
+ pass_op: StencilOp,
+ depth_fail_op: StencilOp,
+ compare_op: CompareOp,
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::StencilOp)?;
+
+ // VUID-vkCmdSetStencilOp-faceMask-parameter
+ faces.validate_device(self.device())?;
+
+ // VUID-vkCmdSetStencilOp-failOp-parameter
+ fail_op.validate_device(self.device())?;
+
+ // VUID-vkCmdSetStencilOp-passOp-parameter
+ pass_op.validate_device(self.device())?;
+
+ // VUID-vkCmdSetStencilOp-depthFailOp-parameter
+ depth_fail_op.validate_device(self.device())?;
+
+ // VUID-vkCmdSetStencilOp-compareOp-parameter
+ compare_op.validate_device(self.device())?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetStencilOp-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetStencilOp-None-03351
+ if !(self.device().api_version() >= Version::V1_3
+ || self.device().enabled_features().extended_dynamic_state)
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`CommandBufferBuilder::set_stencil_op`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn set_stencil_op_unchecked(
+ &mut self,
+ faces: StencilFaces,
+ fail_op: StencilOp,
+ pass_op: StencilOp,
+ depth_fail_op: StencilOp,
+ compare_op: CompareOp,
+ ) -> &mut Self {
+ let fns = self.device().fns();
+
+ if self.device().api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_set_stencil_op)(
+ self.handle(),
+ faces.into(),
+ fail_op.into(),
+ pass_op.into(),
+ depth_fail_op.into(),
+ compare_op.into(),
+ );
+ } else {
+ debug_assert!(
+ self.device()
+ .enabled_extensions()
+ .ext_extended_dynamic_state
+ );
+ (fns.ext_extended_dynamic_state.cmd_set_stencil_op_ext)(
+ self.handle(),
+ faces.into(),
+ fail_op.into(),
+ pass_op.into(),
+ depth_fail_op.into(),
+ compare_op.into(),
+ );
+ }
+
+ let faces = ash::vk::StencilFaceFlags::from(faces);
+
+ if faces.intersects(ash::vk::StencilFaceFlags::FRONT) {
+ self.builder_state.stencil_op.front = Some(StencilOps {
+ fail_op,
+ pass_op,
+ depth_fail_op,
+ compare_op,
+ });
+ }
+
+ if faces.intersects(ash::vk::StencilFaceFlags::BACK) {
+ self.builder_state.stencil_op.back = Some(StencilOps {
+ fail_op,
+ pass_op,
+ depth_fail_op,
+ compare_op,
+ });
+ }
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Sets the dynamic stencil reference on one or both faces for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ pub fn set_stencil_reference(&mut self, faces: StencilFaces, reference: u32) -> &mut Self {
+ self.validate_set_stencil_reference(faces, reference)
+ .unwrap();
+
+ unsafe { self.set_stencil_reference_unchecked(faces, reference) }
+ }
+
+ fn validate_set_stencil_reference(
+ &self,
+ faces: StencilFaces,
+ _reference: u32,
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::StencilReference)?;
+
+ // VUID-vkCmdSetStencilReference-faceMask-parameter
+ faces.validate_device(self.device())?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetStencilReference-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn set_stencil_reference_unchecked(
+ &mut self,
+ faces: StencilFaces,
+ reference: u32,
+ ) -> &mut Self {
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_set_stencil_reference)(self.handle(), faces.into(), reference);
+
+ let faces = ash::vk::StencilFaceFlags::from(faces);
+
+ if faces.intersects(ash::vk::StencilFaceFlags::FRONT) {
+ self.builder_state.stencil_reference.front = Some(reference);
+ }
+
+ if faces.intersects(ash::vk::StencilFaceFlags::BACK) {
+ self.builder_state.stencil_reference.back = Some(reference);
+ }
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Sets whether dynamic stencil testing is enabled for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the device API version is less than 1.3 and the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is
+ /// not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ #[inline]
+ pub fn set_stencil_test_enable(&mut self, enable: bool) -> &mut Self {
+ self.validate_set_stencil_test_enable(enable).unwrap();
+
+ unsafe { self.set_stencil_test_enable_unchecked(enable) }
+ }
+
+ fn validate_set_stencil_test_enable(&self, _enable: bool) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::StencilTestEnable)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetStencilTestEnable-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetStencilTestEnable-None-03350
+ if !(self.device().api_version() >= Version::V1_3
+ || self.device().enabled_features().extended_dynamic_state)
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`CommandBufferBuilder::set_stencil_test_enable`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn set_stencil_test_enable_unchecked(&mut self, enable: bool) -> &mut Self {
+ let fns = self.device().fns();
+
+ if self.device().api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_set_stencil_test_enable)(self.handle(), enable.into());
+ } else {
+ debug_assert!(
+ self.device()
+ .enabled_extensions()
+ .ext_extended_dynamic_state
+ );
+ (fns.ext_extended_dynamic_state
+ .cmd_set_stencil_test_enable_ext)(self.handle(), enable.into());
+ }
+
+ self.builder_state.stencil_test_enable = Some(enable);
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Sets the dynamic stencil write mask on one or both faces for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ pub fn set_stencil_write_mask(&mut self, faces: StencilFaces, write_mask: u32) -> &mut Self {
+ self.validate_set_stencil_write_mask(faces, write_mask)
+ .unwrap();
+
+ unsafe { self.set_stencil_write_mask_unchecked(faces, write_mask) }
+ }
+
+ fn validate_set_stencil_write_mask(
+ &self,
+ faces: StencilFaces,
+ _write_mask: u32,
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::StencilWriteMask)?;
+
+ // VUID-vkCmdSetStencilWriteMask-faceMask-parameter
+ faces.validate_device(self.device())?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetStencilWriteMask-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn set_stencil_write_mask_unchecked(
+ &mut self,
+ faces: StencilFaces,
+ write_mask: u32,
+ ) -> &mut Self {
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_set_stencil_write_mask)(self.handle(), faces.into(), write_mask);
+
+ let faces = ash::vk::StencilFaceFlags::from(faces);
+
+ if faces.intersects(ash::vk::StencilFaceFlags::FRONT) {
+ self.builder_state.stencil_write_mask.front = Some(write_mask);
+ }
+
+ if faces.intersects(ash::vk::StencilFaceFlags::BACK) {
+ self.builder_state.stencil_write_mask.back = Some(write_mask);
+ }
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Sets the dynamic viewports for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ /// - Panics if the highest viewport slot being set is greater than the
+ /// [`max_viewports`](crate::device::Properties::max_viewports) device property.
+ /// - If the [`multi_viewport`](crate::device::Features::multi_viewport) feature is not enabled,
+ /// panics if `first_viewport` is not 0, or if more than 1 viewport is provided.
+ pub fn set_viewport(
+ &mut self,
+ first_viewport: u32,
+ viewports: impl IntoIterator<Item = Viewport>,
+ ) -> &mut Self {
+ let viewports: SmallVec<[Viewport; 2]> = viewports.into_iter().collect();
+ self.validate_set_viewport(first_viewport, &viewports)
+ .unwrap();
+
+ unsafe { self.set_viewport_unchecked(first_viewport, viewports) }
+ }
+
+ fn validate_set_viewport(
+ &self,
+ first_viewport: u32,
+ viewports: &[Viewport],
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::Viewport)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetViewport-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetViewport-firstViewport-01223
+ if first_viewport + viewports.len() as u32
+ > self.device().physical_device().properties().max_viewports
+ {
+ return Err(SetDynamicStateError::MaxViewportsExceeded {
+ provided: first_viewport + viewports.len() as u32,
+ max: self.device().physical_device().properties().max_viewports,
+ });
+ }
+
+ if !self.device().enabled_features().multi_viewport {
+ // VUID-vkCmdSetViewport-firstViewport-01224
+ if first_viewport != 0 {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`first_scissors` is not `0`",
+ requires_one_of: RequiresOneOf {
+ features: &["multi_viewport"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdSetViewport-viewportCount-01225
+ if viewports.len() > 1 {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`viewports.len()` is greater than `1`",
+ requires_one_of: RequiresOneOf {
+ features: &["multi_viewport"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn set_viewport_unchecked(
+ &mut self,
+ first_viewport: u32,
+ viewports: impl IntoIterator<Item = Viewport>,
+ ) -> &mut Self {
+ let viewports: SmallVec<[Viewport; 2]> = viewports.into_iter().collect();
+
+ if viewports.is_empty() {
+ return self;
+ }
+
+ let viewports_vk = viewports
+ .iter()
+ .cloned()
+ .map(ash::vk::Viewport::from)
+ .collect::<SmallVec<[_; 2]>>();
+
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_set_viewport)(
+ self.handle(),
+ first_viewport,
+ viewports_vk.len() as u32,
+ viewports_vk.as_ptr(),
+ );
+
+ for (num, viewport) in viewports.iter().enumerate() {
+ let num = num as u32 + first_viewport;
+ self.builder_state.viewport.insert(num, viewport.clone());
+ }
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Sets the dynamic viewports with count for future draw calls.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the queue family of the command buffer does not support graphics operations.
+ /// - Panics if the device API version is less than 1.3 and the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature is
+ /// not enabled on the device.
+ /// - Panics if the currently bound graphics pipeline already contains this state internally.
+ /// - Panics if the highest viewport slot being set is greater than the
+ /// [`max_viewports`](crate::device::Properties::max_viewports) device property.
+ /// - If the [`multi_viewport`](crate::device::Features::multi_viewport) feature is not enabled,
+ /// panics if more than 1 viewport is provided.
+ #[inline]
+ pub fn set_viewport_with_count(
+ &mut self,
+ viewports: impl IntoIterator<Item = Viewport>,
+ ) -> &mut Self {
+ let viewports: SmallVec<[Viewport; 2]> = viewports.into_iter().collect();
+ self.validate_set_viewport_with_count(&viewports).unwrap();
+
+ unsafe { self.set_viewport_with_count_unchecked(viewports) }
+ }
+
+ fn validate_set_viewport_with_count(
+ &self,
+ viewports: &[Viewport],
+ ) -> Result<(), SetDynamicStateError> {
+ self.validate_pipeline_fixed_state(DynamicState::ViewportWithCount)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetViewportWithCount-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(SetDynamicStateError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetViewportWithCount-None-03393
+ if !(self.device().api_version() >= Version::V1_3
+ || self.device().enabled_features().extended_dynamic_state)
+ {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`CommandBufferBuilder::set_viewport_with_count`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdSetViewportWithCount-viewportCount-03394
+ if viewports.len() as u32 > self.device().physical_device().properties().max_viewports {
+ return Err(SetDynamicStateError::MaxViewportsExceeded {
+ provided: viewports.len() as u32,
+ max: self.device().physical_device().properties().max_viewports,
+ });
+ }
+
+ // VUID-vkCmdSetViewportWithCount-viewportCount-03395
+ if !self.device().enabled_features().multi_viewport && viewports.len() > 1 {
+ return Err(SetDynamicStateError::RequirementNotMet {
+ required_for: "`viewports.len()` is greater than `1`",
+ requires_one_of: RequiresOneOf {
+ features: &["multi_viewport"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn set_viewport_with_count_unchecked(
+ &mut self,
+ viewports: impl IntoIterator<Item = Viewport>,
+ ) -> &mut Self {
+ let viewports: SmallVec<[Viewport; 2]> = viewports.into_iter().collect();
+
+ if viewports.is_empty() {
+ return self;
+ }
+
+ let viewports_vk = viewports
+ .iter()
+ .cloned()
+ .map(ash::vk::Viewport::from)
+ .collect::<SmallVec<[_; 2]>>();
+
+ let fns = self.device().fns();
+
+ if self.device().api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_set_viewport_with_count)(
+ self.handle(),
+ viewports_vk.len() as u32,
+ viewports_vk.as_ptr(),
+ );
+ } else {
+ debug_assert!(
+ self.device()
+ .enabled_extensions()
+ .ext_extended_dynamic_state
+ );
+ (fns.ext_extended_dynamic_state
+ .cmd_set_viewport_with_count_ext)(
+ self.handle(),
+ viewports_vk.len() as u32,
+ viewports_vk.as_ptr(),
+ );
+ }
+
+ self.builder_state.viewport_with_count = Some(viewports);
+
+ self.next_command_index += 1;
+ self
+ }
+}
diff --git a/src/command_buffer/standard/builder/mod.rs b/src/command_buffer/standard/builder/mod.rs
new file mode 100644
index 0000000..d8ce6a3
--- /dev/null
+++ b/src/command_buffer/standard/builder/mod.rs
@@ -0,0 +1,1585 @@
+// Copyright (c) 2022 The Vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+pub use self::{
+ bind_push::*, clear::*, copy::*, debug::*, dynamic_state::*, pipeline::*, query::*,
+ render_pass::*, secondary::*, sync::*,
+};
+use super::{PrimaryCommandBuffer, SecondaryCommandBuffer, SubmitState};
+pub use crate::command_buffer::{
+ BlitImageInfo, BufferCopy, BufferImageCopy, ClearAttachment, ClearColorImageInfo,
+ ClearDepthStencilImageInfo, ClearError, ClearRect, CopyBufferInfo, CopyBufferInfoTyped,
+ CopyBufferToImageInfo, CopyError, CopyErrorResource, CopyImageInfo, CopyImageToBufferInfo,
+ DebugUtilsError, ExecuteCommandsError, ImageBlit, ImageCopy, ImageResolve,
+ PipelineExecutionError, QueryError, RenderPassBeginInfo, RenderPassError,
+ RenderingAttachmentInfo, RenderingAttachmentResolveInfo, RenderingInfo, ResolveImageInfo,
+};
+use crate::{
+ buffer::{Buffer, Subbuffer},
+ command_buffer::{
+ allocator::{
+ CommandBufferAllocator, CommandBufferBuilderAlloc, StandardCommandBufferAllocator,
+ },
+ sys::CommandBufferBeginInfo,
+ BuildError, CommandBufferBeginError, CommandBufferInheritanceInfo,
+ CommandBufferInheritanceRenderPassInfo, CommandBufferInheritanceRenderPassType,
+ CommandBufferInheritanceRenderingInfo, CommandBufferLevel, CommandBufferUsage,
+ ResourceInCommand, ResourceUseRef, SubpassContents,
+ },
+ descriptor_set::{DescriptorSetResources, DescriptorSetWithOffsets},
+ device::{Device, DeviceOwned, QueueFamilyProperties, QueueFlags},
+ format::FormatFeatures,
+ image::{sys::Image, ImageAspects, ImageLayout, ImageSubresourceRange, ImageViewAbstract},
+ pipeline::{
+ graphics::{
+ color_blend::LogicOp,
+ depth_stencil::{CompareOp, StencilOps},
+ input_assembly::{IndexType, PrimitiveTopology},
+ rasterization::{CullMode, DepthBias, FrontFace, LineStipple},
+ render_pass::PipelineRenderingCreateInfo,
+ viewport::{Scissor, Viewport},
+ },
+ ComputePipeline, DynamicState, GraphicsPipeline, PipelineBindPoint, PipelineLayout,
+ },
+ query::{QueryControlFlags, QueryType},
+ range_map::RangeMap,
+ range_set::RangeSet,
+ render_pass::{Framebuffer, LoadOp, StoreOp, Subpass},
+ sync::{
+ BufferMemoryBarrier, DependencyInfo, ImageMemoryBarrier, PipelineStage,
+ PipelineStageAccess, PipelineStageAccessSet, PipelineStages,
+ },
+ DeviceSize, OomError, RequiresOneOf, VulkanError, VulkanObject,
+};
+use ahash::HashMap;
+use parking_lot::Mutex;
+use smallvec::SmallVec;
+use std::{
+ any::Any,
+ collections::hash_map::Entry,
+ marker::PhantomData,
+ ops::{Range, RangeInclusive},
+ ptr,
+ sync::{atomic::AtomicBool, Arc},
+};
+
+mod bind_push;
+mod clear;
+mod copy;
+mod debug;
+mod dynamic_state;
+mod pipeline;
+mod query;
+mod render_pass;
+mod secondary;
+mod sync;
+
+/// Records commands to a command buffer.
+pub struct CommandBufferBuilder<L, A = StandardCommandBufferAllocator>
+where
+ A: CommandBufferAllocator,
+{
+ builder_alloc: A::Builder,
+ inheritance_info: Option<CommandBufferInheritanceInfo>, // Must be `None` in a primary command buffer and `Some` in a secondary command buffer.
+ queue_family_index: u32,
+ usage: CommandBufferUsage,
+
+ next_command_index: usize,
+ resources: Vec<Box<dyn Any + Send + Sync>>,
+ builder_state: CommandBufferBuilderState,
+ resources_usage_state: ResourcesState,
+
+ _data: PhantomData<L>,
+}
+
+unsafe impl<L, A> DeviceOwned for CommandBufferBuilder<L, A>
+where
+ A: CommandBufferAllocator,
+{
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ self.builder_alloc.device()
+ }
+}
+
+unsafe impl<L, A> VulkanObject for CommandBufferBuilder<L, A>
+where
+ A: CommandBufferAllocator,
+{
+ type Handle = ash::vk::CommandBuffer;
+
+ #[inline]
+ fn handle(&self) -> Self::Handle {
+ self.builder_alloc.inner().handle()
+ }
+}
+
+impl<A> CommandBufferBuilder<PrimaryCommandBuffer, A>
+where
+ A: CommandBufferAllocator,
+{
+ /// Starts recording a primary command buffer.
+ #[inline]
+ pub fn primary(
+ allocator: &A,
+ queue_family_index: u32,
+ usage: CommandBufferUsage,
+ ) -> Result<Self, CommandBufferBeginError> {
+ unsafe {
+ CommandBufferBuilder::begin(
+ allocator,
+ queue_family_index,
+ CommandBufferLevel::Primary,
+ CommandBufferBeginInfo {
+ usage,
+ inheritance_info: None,
+ _ne: crate::NonExhaustive(()),
+ },
+ )
+ }
+ }
+}
+
+impl<A> CommandBufferBuilder<SecondaryCommandBuffer, A>
+where
+ A: CommandBufferAllocator,
+{
+ /// Starts recording a secondary command buffer.
+ #[inline]
+ pub fn secondary(
+ allocator: &A,
+ queue_family_index: u32,
+ usage: CommandBufferUsage,
+ inheritance_info: CommandBufferInheritanceInfo,
+ ) -> Result<Self, CommandBufferBeginError> {
+ unsafe {
+ CommandBufferBuilder::begin(
+ allocator,
+ queue_family_index,
+ CommandBufferLevel::Secondary,
+ CommandBufferBeginInfo {
+ usage,
+ inheritance_info: Some(inheritance_info),
+ _ne: crate::NonExhaustive(()),
+ },
+ )
+ }
+ }
+}
+
+impl<L, A> CommandBufferBuilder<L, A>
+where
+ A: CommandBufferAllocator,
+{
+ // Actual constructor. Private.
+ //
+ // `begin_info.inheritance_info` must match `level`.
+ unsafe fn begin(
+ allocator: &A,
+ queue_family_index: u32,
+ level: CommandBufferLevel,
+ begin_info: CommandBufferBeginInfo,
+ ) -> Result<Self, CommandBufferBeginError> {
+ Self::validate_begin(allocator.device(), queue_family_index, level, &begin_info)?;
+ Ok(Self::begin_unchecked(
+ allocator,
+ queue_family_index,
+ level,
+ begin_info,
+ )?)
+ }
+
+ fn validate_begin(
+ device: &Device,
+ _queue_family_index: u32,
+ level: CommandBufferLevel,
+ begin_info: &CommandBufferBeginInfo,
+ ) -> Result<(), CommandBufferBeginError> {
+ let physical_device = device.physical_device();
+ let properties = physical_device.properties();
+
+ let &CommandBufferBeginInfo {
+ usage: _,
+ ref inheritance_info,
+ _ne: _,
+ } = &begin_info;
+
+ if let Some(inheritance_info) = &inheritance_info {
+ debug_assert!(level == CommandBufferLevel::Secondary);
+
+ let &CommandBufferInheritanceInfo {
+ ref render_pass,
+ occlusion_query,
+ query_statistics_flags,
+ _ne: _,
+ } = inheritance_info;
+
+ if let Some(render_pass) = render_pass {
+ // VUID-VkCommandBufferBeginInfo-flags-06000
+ // VUID-VkCommandBufferBeginInfo-flags-06002
+ // Ensured by the definition of the `CommandBufferInheritanceRenderPassType` enum.
+
+ match render_pass {
+ CommandBufferInheritanceRenderPassType::BeginRenderPass(render_pass_info) => {
+ let &CommandBufferInheritanceRenderPassInfo {
+ ref subpass,
+ ref framebuffer,
+ } = render_pass_info;
+
+ // VUID-VkCommandBufferInheritanceInfo-commonparent
+ assert_eq!(device, subpass.render_pass().device().as_ref());
+
+ // VUID-VkCommandBufferBeginInfo-flags-06001
+ // Ensured by how the `Subpass` type is constructed.
+
+ if let Some(framebuffer) = framebuffer {
+ // VUID-VkCommandBufferInheritanceInfo-commonparent
+ assert_eq!(device, framebuffer.device().as_ref());
+
+ // VUID-VkCommandBufferBeginInfo-flags-00055
+ if !framebuffer
+ .render_pass()
+ .is_compatible_with(subpass.render_pass())
+ {
+ return Err(CommandBufferBeginError::FramebufferNotCompatible);
+ }
+ }
+ }
+ CommandBufferInheritanceRenderPassType::BeginRendering(rendering_info) => {
+ let &CommandBufferInheritanceRenderingInfo {
+ view_mask,
+ ref color_attachment_formats,
+ depth_attachment_format,
+ stencil_attachment_format,
+ rasterization_samples,
+ } = rendering_info;
+
+ // VUID-VkCommandBufferInheritanceRenderingInfo-multiview-06008
+ if view_mask != 0 && !device.enabled_features().multiview {
+ return Err(CommandBufferBeginError::RequirementNotMet {
+ required_for: "`inheritance_info.render_pass` is \
+ `CommandBufferInheritanceRenderPassType::BeginRendering`, \
+ where `view_mask` is not `0`",
+ requires_one_of: RequiresOneOf {
+ features: &["multiview"],
+ ..Default::default()
+ },
+ });
+ }
+
+ let view_count = u32::BITS - view_mask.leading_zeros();
+
+ // VUID-VkCommandBufferInheritanceRenderingInfo-viewMask-06009
+ if view_count > properties.max_multiview_view_count.unwrap_or(0) {
+ return Err(CommandBufferBeginError::MaxMultiviewViewCountExceeded {
+ view_count,
+ max: properties.max_multiview_view_count.unwrap_or(0),
+ });
+ }
+
+ for (attachment_index, format) in color_attachment_formats
+ .iter()
+ .enumerate()
+ .flat_map(|(i, f)| f.map(|f| (i, f)))
+ {
+ let attachment_index = attachment_index as u32;
+
+ // VUID-VkCommandBufferInheritanceRenderingInfo-pColorAttachmentFormats-parameter
+ format.validate_device(device)?;
+
+ // VUID-VkCommandBufferInheritanceRenderingInfo-pColorAttachmentFormats-06006
+ // Use unchecked, because all validation has been done above.
+ if !unsafe { physical_device.format_properties_unchecked(format) }
+ .potential_format_features()
+ .intersects(FormatFeatures::COLOR_ATTACHMENT)
+ {
+ return Err(
+ CommandBufferBeginError::ColorAttachmentFormatUsageNotSupported {
+ attachment_index,
+ },
+ );
+ }
+ }
+
+ if let Some(format) = depth_attachment_format {
+ // VUID-VkCommandBufferInheritanceRenderingInfo-depthAttachmentFormat-parameter
+ format.validate_device(device)?;
+
+ // VUID-VkCommandBufferInheritanceRenderingInfo-depthAttachmentFormat-06540
+ if !format.aspects().intersects(ImageAspects::DEPTH) {
+ return Err(
+ CommandBufferBeginError::DepthAttachmentFormatUsageNotSupported,
+ );
+ }
+
+ // VUID-VkCommandBufferInheritanceRenderingInfo-depthAttachmentFormat-06007
+ // Use unchecked, because all validation has been done above.
+ if !unsafe { physical_device.format_properties_unchecked(format) }
+ .potential_format_features()
+ .intersects(FormatFeatures::DEPTH_STENCIL_ATTACHMENT)
+ {
+ return Err(
+ CommandBufferBeginError::DepthAttachmentFormatUsageNotSupported,
+ );
+ }
+ }
+
+ if let Some(format) = stencil_attachment_format {
+ // VUID-VkCommandBufferInheritanceRenderingInfo-stencilAttachmentFormat-parameter
+ format.validate_device(device)?;
+
+ // VUID-VkCommandBufferInheritanceRenderingInfo-stencilAttachmentFormat-06541
+ if !format.aspects().intersects(ImageAspects::STENCIL) {
+ return Err(
+ CommandBufferBeginError::StencilAttachmentFormatUsageNotSupported,
+ );
+ }
+
+ // VUID-VkCommandBufferInheritanceRenderingInfo-stencilAttachmentFormat-06199
+ // Use unchecked, because all validation has been done above.
+ if !unsafe { physical_device.format_properties_unchecked(format) }
+ .potential_format_features()
+ .intersects(FormatFeatures::DEPTH_STENCIL_ATTACHMENT)
+ {
+ return Err(
+ CommandBufferBeginError::StencilAttachmentFormatUsageNotSupported,
+ );
+ }
+ }
+
+ if let (Some(depth_format), Some(stencil_format)) =
+ (depth_attachment_format, stencil_attachment_format)
+ {
+ // VUID-VkCommandBufferInheritanceRenderingInfo-depthAttachmentFormat-06200
+ if depth_format != stencil_format {
+ return Err(
+ CommandBufferBeginError::DepthStencilAttachmentFormatMismatch,
+ );
+ }
+ }
+
+ // VUID-VkCommandBufferInheritanceRenderingInfo-rasterizationSamples-parameter
+ rasterization_samples.validate_device(device)?;
+ }
+ }
+ }
+
+ if let Some(control_flags) = occlusion_query {
+ // VUID-VkCommandBufferInheritanceInfo-queryFlags-00057
+ control_flags.validate_device(device)?;
+
+ // VUID-VkCommandBufferInheritanceInfo-occlusionQueryEnable-00056
+ // VUID-VkCommandBufferInheritanceInfo-queryFlags-02788
+ if !device.enabled_features().inherited_queries {
+ return Err(CommandBufferBeginError::RequirementNotMet {
+ required_for: "`inheritance_info.occlusion_query` is `Some`",
+ requires_one_of: RequiresOneOf {
+ features: &["inherited_queries"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkBeginCommandBuffer-commandBuffer-00052
+ if control_flags.intersects(QueryControlFlags::PRECISE)
+ && !device.enabled_features().occlusion_query_precise
+ {
+ return Err(CommandBufferBeginError::RequirementNotMet {
+ required_for: "`inheritance_info.occlusion_query` is \
+ `Some(control_flags)`, where `control_flags` contains \
+ `QueryControlFlags::PRECISE`",
+ requires_one_of: RequiresOneOf {
+ features: &["occlusion_query_precise"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+
+ // VUID-VkCommandBufferInheritanceInfo-pipelineStatistics-02789
+ query_statistics_flags.validate_device(device)?;
+
+ // VUID-VkCommandBufferInheritanceInfo-pipelineStatistics-00058
+ if query_statistics_flags.count() > 0
+ && !device.enabled_features().pipeline_statistics_query
+ {
+ return Err(CommandBufferBeginError::RequirementNotMet {
+ required_for: "`inheritance_info.query_statistics_flags` is not empty",
+ requires_one_of: RequiresOneOf {
+ features: &["pipeline_statistics_query"],
+ ..Default::default()
+ },
+ });
+ }
+ } else {
+ debug_assert!(level == CommandBufferLevel::Primary);
+
+ // VUID-vkBeginCommandBuffer-commandBuffer-02840
+ // Ensured by the definition of the `CommandBufferUsage` enum.
+ }
+
+ Ok(())
+ }
+
+ unsafe fn begin_unchecked(
+ allocator: &A,
+ queue_family_index: u32,
+ level: CommandBufferLevel,
+ begin_info: CommandBufferBeginInfo,
+ ) -> Result<Self, OomError> {
+ let CommandBufferBeginInfo {
+ usage,
+ inheritance_info,
+ _ne: _,
+ } = begin_info;
+
+ let builder_alloc = allocator
+ .allocate(queue_family_index, level, 1)?
+ .next()
+ .expect("requested one command buffer from the command pool, but got zero");
+
+ {
+ let device = builder_alloc.device();
+
+ let mut flags = ash::vk::CommandBufferUsageFlags::from(usage);
+ let mut inheritance_info_vk = None;
+ let mut inheritance_rendering_info_vk = None;
+ let mut color_attachment_formats_vk: SmallVec<[_; 4]> = SmallVec::new();
+
+ if let Some(inheritance_info) = &inheritance_info {
+ let &CommandBufferInheritanceInfo {
+ ref render_pass,
+ occlusion_query,
+ query_statistics_flags,
+ _ne: _,
+ } = inheritance_info;
+
+ let inheritance_info_vk =
+ inheritance_info_vk.insert(ash::vk::CommandBufferInheritanceInfo {
+ render_pass: ash::vk::RenderPass::null(),
+ subpass: 0,
+ framebuffer: ash::vk::Framebuffer::null(),
+ occlusion_query_enable: ash::vk::FALSE,
+ query_flags: ash::vk::QueryControlFlags::empty(),
+ pipeline_statistics: query_statistics_flags.into(),
+ ..Default::default()
+ });
+
+ if let Some(flags) = occlusion_query {
+ inheritance_info_vk.occlusion_query_enable = ash::vk::TRUE;
+
+ if flags.intersects(QueryControlFlags::PRECISE) {
+ inheritance_info_vk.query_flags = ash::vk::QueryControlFlags::PRECISE;
+ }
+ }
+
+ if let Some(render_pass) = render_pass {
+ flags |= ash::vk::CommandBufferUsageFlags::RENDER_PASS_CONTINUE;
+
+ match render_pass {
+ CommandBufferInheritanceRenderPassType::BeginRenderPass(
+ render_pass_info,
+ ) => {
+ let &CommandBufferInheritanceRenderPassInfo {
+ ref subpass,
+ ref framebuffer,
+ } = render_pass_info;
+
+ inheritance_info_vk.render_pass = subpass.render_pass().handle();
+ inheritance_info_vk.subpass = subpass.index();
+ inheritance_info_vk.framebuffer = framebuffer
+ .as_ref()
+ .map(|fb| fb.handle())
+ .unwrap_or_default();
+ }
+ CommandBufferInheritanceRenderPassType::BeginRendering(rendering_info) => {
+ let &CommandBufferInheritanceRenderingInfo {
+ view_mask,
+ ref color_attachment_formats,
+ depth_attachment_format,
+ stencil_attachment_format,
+ rasterization_samples,
+ } = rendering_info;
+
+ color_attachment_formats_vk.extend(
+ color_attachment_formats.iter().map(|format| {
+ format.map_or(ash::vk::Format::UNDEFINED, Into::into)
+ }),
+ );
+
+ let inheritance_rendering_info_vk = inheritance_rendering_info_vk
+ .insert(ash::vk::CommandBufferInheritanceRenderingInfo {
+ flags: ash::vk::RenderingFlags::empty(),
+ view_mask,
+ color_attachment_count: color_attachment_formats_vk.len()
+ as u32,
+ p_color_attachment_formats: color_attachment_formats_vk
+ .as_ptr(),
+ depth_attachment_format: depth_attachment_format
+ .map_or(ash::vk::Format::UNDEFINED, Into::into),
+ stencil_attachment_format: stencil_attachment_format
+ .map_or(ash::vk::Format::UNDEFINED, Into::into),
+ rasterization_samples: rasterization_samples.into(),
+ ..Default::default()
+ });
+
+ inheritance_info_vk.p_next =
+ inheritance_rendering_info_vk as *const _ as *const _;
+ }
+ }
+ }
+ }
+
+ let begin_info_vk = ash::vk::CommandBufferBeginInfo {
+ flags,
+ p_inheritance_info: inheritance_info_vk
+ .as_ref()
+ .map_or(ptr::null(), |info| info),
+ ..Default::default()
+ };
+
+ let fns = device.fns();
+
+ (fns.v1_0.begin_command_buffer)(builder_alloc.inner().handle(), &begin_info_vk)
+ .result()
+ .map_err(VulkanError::from)?;
+ }
+
+ let mut builder_state: CommandBufferBuilderState = Default::default();
+
+ if let Some(inheritance_info) = &inheritance_info {
+ let &CommandBufferInheritanceInfo {
+ ref render_pass,
+ occlusion_query: _,
+ query_statistics_flags: _,
+ _ne: _,
+ } = inheritance_info;
+
+ if let Some(render_pass) = render_pass {
+ builder_state.render_pass = Some(RenderPassState::from_inheritance(render_pass));
+ }
+ }
+
+ Ok(CommandBufferBuilder {
+ builder_alloc,
+ inheritance_info,
+ queue_family_index,
+ usage,
+
+ next_command_index: 0,
+ resources: Vec::new(),
+ builder_state,
+ resources_usage_state: Default::default(),
+
+ _data: PhantomData,
+ })
+ }
+
+ fn queue_family_properties(&self) -> &QueueFamilyProperties {
+ &self.device().physical_device().queue_family_properties()[self.queue_family_index as usize]
+ }
+}
+
+impl<A> CommandBufferBuilder<PrimaryCommandBuffer<A::Alloc>, A>
+where
+ A: CommandBufferAllocator,
+{
+ /// Builds the command buffer.
+ pub fn build(self) -> Result<PrimaryCommandBuffer<A::Alloc>, BuildError> {
+ if self.builder_state.render_pass.is_some() {
+ return Err(BuildError::RenderPassActive);
+ }
+
+ if !self.builder_state.queries.is_empty() {
+ return Err(BuildError::QueryActive);
+ }
+
+ Ok(unsafe { self.build_unchecked()? })
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn build_unchecked(self) -> Result<PrimaryCommandBuffer<A::Alloc>, OomError> {
+ let fns = self.device().fns();
+ (fns.v1_0.end_command_buffer)(self.builder_alloc.inner().handle())
+ .result()
+ .map_err(VulkanError::from)?;
+
+ Ok(PrimaryCommandBuffer {
+ alloc: self.builder_alloc.into_alloc(),
+ _usage: self.usage,
+ _resources: self.resources,
+
+ _state: Mutex::new(Default::default()),
+ })
+ }
+}
+
+impl<A> CommandBufferBuilder<SecondaryCommandBuffer<A::Alloc>, A>
+where
+ A: CommandBufferAllocator,
+{
+ /// Builds the command buffer.
+ pub fn build(self) -> Result<SecondaryCommandBuffer<A::Alloc>, BuildError> {
+ if !self.builder_state.queries.is_empty() {
+ return Err(BuildError::QueryActive);
+ }
+
+ Ok(unsafe { self.build_unchecked()? })
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn build_unchecked(self) -> Result<SecondaryCommandBuffer<A::Alloc>, OomError> {
+ let fns = self.device().fns();
+ (fns.v1_0.end_command_buffer)(self.builder_alloc.inner().handle())
+ .result()
+ .map_err(VulkanError::from)?;
+
+ let submit_state = match self.usage {
+ CommandBufferUsage::MultipleSubmit => SubmitState::ExclusiveUse {
+ in_use: AtomicBool::new(false),
+ },
+ CommandBufferUsage::SimultaneousUse => SubmitState::Concurrent,
+ CommandBufferUsage::OneTimeSubmit => SubmitState::OneTime {
+ already_submitted: AtomicBool::new(false),
+ },
+ };
+
+ Ok(SecondaryCommandBuffer {
+ alloc: self.builder_alloc.into_alloc(),
+ inheritance_info: self.inheritance_info.unwrap(),
+ usage: self.usage,
+
+ _resources: self.resources,
+
+ submit_state,
+ })
+ }
+}
+
+/// Holds the current binding and setting state.
+#[derive(Default)]
+struct CommandBufferBuilderState {
+ // Render pass
+ render_pass: Option<RenderPassState>,
+
+ // Bind/push
+ descriptor_sets: HashMap<PipelineBindPoint, DescriptorSetState>,
+ index_buffer: Option<(Subbuffer<[u8]>, IndexType)>,
+ pipeline_compute: Option<Arc<ComputePipeline>>,
+ pipeline_graphics: Option<Arc<GraphicsPipeline>>,
+ vertex_buffers: HashMap<u32, Subbuffer<[u8]>>,
+ push_constants: RangeSet<u32>,
+ push_constants_pipeline_layout: Option<Arc<PipelineLayout>>,
+
+ // Dynamic state
+ blend_constants: Option<[f32; 4]>,
+ color_write_enable: Option<SmallVec<[bool; 4]>>,
+ cull_mode: Option<CullMode>,
+ depth_bias: Option<DepthBias>,
+ depth_bias_enable: Option<bool>,
+ depth_bounds: Option<RangeInclusive<f32>>,
+ depth_bounds_test_enable: Option<bool>,
+ depth_compare_op: Option<CompareOp>,
+ depth_test_enable: Option<bool>,
+ depth_write_enable: Option<bool>,
+ discard_rectangle: HashMap<u32, Scissor>,
+ front_face: Option<FrontFace>,
+ line_stipple: Option<LineStipple>,
+ line_width: Option<f32>,
+ logic_op: Option<LogicOp>,
+ patch_control_points: Option<u32>,
+ primitive_restart_enable: Option<bool>,
+ primitive_topology: Option<PrimitiveTopology>,
+ rasterizer_discard_enable: Option<bool>,
+ scissor: HashMap<u32, Scissor>,
+ scissor_with_count: Option<SmallVec<[Scissor; 2]>>,
+ stencil_compare_mask: StencilStateDynamic,
+ stencil_op: StencilOpStateDynamic,
+ stencil_reference: StencilStateDynamic,
+ stencil_test_enable: Option<bool>,
+ stencil_write_mask: StencilStateDynamic,
+ viewport: HashMap<u32, Viewport>,
+ viewport_with_count: Option<SmallVec<[Viewport; 2]>>,
+
+ // Active queries
+ queries: HashMap<ash::vk::QueryType, QueryState>,
+}
+
+impl CommandBufferBuilderState {
+ fn reset_dynamic_states(&mut self, states: impl IntoIterator<Item = DynamicState>) {
+ for state in states {
+ match state {
+ DynamicState::BlendConstants => self.blend_constants = None,
+ DynamicState::ColorWriteEnable => self.color_write_enable = None,
+ DynamicState::CullMode => self.cull_mode = None,
+ DynamicState::DepthBias => self.depth_bias = None,
+ DynamicState::DepthBiasEnable => self.depth_bias_enable = None,
+ DynamicState::DepthBounds => self.depth_bounds = None,
+ DynamicState::DepthBoundsTestEnable => self.depth_bounds_test_enable = None,
+ DynamicState::DepthCompareOp => self.depth_compare_op = None,
+ DynamicState::DepthTestEnable => self.depth_test_enable = None,
+ DynamicState::DepthWriteEnable => self.depth_write_enable = None,
+ DynamicState::DiscardRectangle => self.discard_rectangle.clear(),
+ DynamicState::ExclusiveScissor => (), // TODO;
+ DynamicState::FragmentShadingRate => (), // TODO:
+ DynamicState::FrontFace => self.front_face = None,
+ DynamicState::LineStipple => self.line_stipple = None,
+ DynamicState::LineWidth => self.line_width = None,
+ DynamicState::LogicOp => self.logic_op = None,
+ DynamicState::PatchControlPoints => self.patch_control_points = None,
+ DynamicState::PrimitiveRestartEnable => self.primitive_restart_enable = None,
+ DynamicState::PrimitiveTopology => self.primitive_topology = None,
+ DynamicState::RasterizerDiscardEnable => self.rasterizer_discard_enable = None,
+ DynamicState::RayTracingPipelineStackSize => (), // TODO:
+ DynamicState::SampleLocations => (), // TODO:
+ DynamicState::Scissor => self.scissor.clear(),
+ DynamicState::ScissorWithCount => self.scissor_with_count = None,
+ DynamicState::StencilCompareMask => self.stencil_compare_mask = Default::default(),
+ DynamicState::StencilOp => self.stencil_op = Default::default(),
+ DynamicState::StencilReference => self.stencil_reference = Default::default(),
+ DynamicState::StencilTestEnable => self.stencil_test_enable = None,
+ DynamicState::StencilWriteMask => self.stencil_write_mask = Default::default(),
+ DynamicState::VertexInput => (), // TODO:
+ DynamicState::VertexInputBindingStride => (), // TODO:
+ DynamicState::Viewport => self.viewport.clear(),
+ DynamicState::ViewportCoarseSampleOrder => (), // TODO:
+ DynamicState::ViewportShadingRatePalette => (), // TODO:
+ DynamicState::ViewportWScaling => (), // TODO:
+ DynamicState::ViewportWithCount => self.viewport_with_count = None,
+ DynamicState::TessellationDomainOrigin => (), // TODO:
+ DynamicState::DepthClampEnable => (), // TODO:
+ DynamicState::PolygonMode => (), // TODO:
+ DynamicState::RasterizationSamples => (), // TODO:
+ DynamicState::SampleMask => (), // TODO:
+ DynamicState::AlphaToCoverageEnable => (), // TODO:
+ DynamicState::AlphaToOneEnable => (), // TODO:
+ DynamicState::LogicOpEnable => (), // TODO:
+ DynamicState::ColorBlendEnable => (), // TODO:
+ DynamicState::ColorBlendEquation => (), // TODO:
+ DynamicState::ColorWriteMask => (), // TODO:
+ DynamicState::RasterizationStream => (), // TODO:
+ DynamicState::ConservativeRasterizationMode => (), // TODO:
+ DynamicState::ExtraPrimitiveOverestimationSize => (), // TODO:
+ DynamicState::DepthClipEnable => (), // TODO:
+ DynamicState::SampleLocationsEnable => (), // TODO:
+ DynamicState::ColorBlendAdvanced => (), // TODO:
+ DynamicState::ProvokingVertexMode => (), // TODO:
+ DynamicState::LineRasterizationMode => (), // TODO:
+ DynamicState::LineStippleEnable => (), // TODO:
+ DynamicState::DepthClipNegativeOneToOne => (), // TODO:
+ DynamicState::ViewportWScalingEnable => (), // TODO:
+ DynamicState::ViewportSwizzle => (), // TODO:
+ DynamicState::CoverageToColorEnable => (), // TODO:
+ DynamicState::CoverageToColorLocation => (), // TODO:
+ DynamicState::CoverageModulationMode => (), // TODO:
+ DynamicState::CoverageModulationTableEnable => (), // TODO:
+ DynamicState::CoverageModulationTable => (), // TODO:
+ DynamicState::ShadingRateImageEnable => (), // TODO:
+ DynamicState::RepresentativeFragmentTestEnable => (), // TODO:
+ DynamicState::CoverageReductionMode => (), // TODO:
+ }
+ }
+ }
+
+ fn invalidate_descriptor_sets(
+ &mut self,
+ pipeline_bind_point: PipelineBindPoint,
+ pipeline_layout: Arc<PipelineLayout>,
+ first_set: u32,
+ num_descriptor_sets: u32,
+ ) -> &mut DescriptorSetState {
+ match self.descriptor_sets.entry(pipeline_bind_point) {
+ Entry::Vacant(entry) => entry.insert(DescriptorSetState {
+ descriptor_sets: Default::default(),
+ pipeline_layout,
+ }),
+ Entry::Occupied(entry) => {
+ let state = entry.into_mut();
+
+ let invalidate_from = if state.pipeline_layout == pipeline_layout {
+ // If we're still using the exact same layout, then of course it's compatible.
+ None
+ } else if state.pipeline_layout.push_constant_ranges()
+ != pipeline_layout.push_constant_ranges()
+ {
+ // If the push constant ranges don't match,
+ // all bound descriptor sets are disturbed.
+ Some(0)
+ } else {
+ // Find the first descriptor set layout in the current pipeline layout that
+ // isn't compatible with the corresponding set in the new pipeline layout.
+ // If an incompatible set was found, all bound sets from that slot onwards will
+ // be disturbed.
+ let current_layouts = state.pipeline_layout.set_layouts();
+ let new_layouts = pipeline_layout.set_layouts();
+ let max = (current_layouts.len() as u32).min(first_set + num_descriptor_sets);
+ (0..max).find(|&num| {
+ let num = num as usize;
+ !current_layouts[num].is_compatible_with(&new_layouts[num])
+ })
+ };
+
+ if let Some(invalidate_from) = invalidate_from {
+ // Remove disturbed sets and set new pipeline layout.
+ state
+ .descriptor_sets
+ .retain(|&num, _| num < invalidate_from);
+ state.pipeline_layout = pipeline_layout;
+ } else if (first_set + num_descriptor_sets) as usize
+ >= state.pipeline_layout.set_layouts().len()
+ {
+ // New layout is a superset of the old one.
+ state.pipeline_layout = pipeline_layout;
+ }
+
+ state
+ }
+ }
+ }
+}
+
+struct RenderPassState {
+ contents: SubpassContents,
+ render_area_offset: [u32; 2],
+ render_area_extent: [u32; 2],
+
+ rendering_info: PipelineRenderingCreateInfo,
+ attachments: Option<RenderPassStateAttachments>,
+
+ render_pass: RenderPassStateType,
+}
+
+impl RenderPassState {
+ fn from_inheritance(render_pass: &CommandBufferInheritanceRenderPassType) -> Self {
+ match render_pass {
+ CommandBufferInheritanceRenderPassType::BeginRenderPass(info) => {
+ RenderPassState {
+ contents: SubpassContents::Inline,
+ render_area_offset: [0, 0],
+ render_area_extent: (info.framebuffer.as_ref())
+ // Still not exact, but it's a better upper bound.
+ .map_or([u32::MAX, u32::MAX], |framebuffer| framebuffer.extent()),
+
+ rendering_info: PipelineRenderingCreateInfo::from_subpass(&info.subpass),
+ attachments: info.framebuffer.as_ref().map(|framebuffer| {
+ RenderPassStateAttachments::from_subpass(&info.subpass, framebuffer)
+ }),
+
+ render_pass: BeginRenderPassState {
+ subpass: info.subpass.clone(),
+ framebuffer: info.framebuffer.clone(),
+ }
+ .into(),
+ }
+ }
+ CommandBufferInheritanceRenderPassType::BeginRendering(info) => RenderPassState {
+ contents: SubpassContents::Inline,
+ render_area_offset: [0, 0],
+ render_area_extent: [u32::MAX, u32::MAX],
+
+ rendering_info: PipelineRenderingCreateInfo::from_inheritance_rendering_info(info),
+ attachments: None,
+
+ render_pass: BeginRenderingState {
+ pipeline_used: false,
+ }
+ .into(),
+ },
+ }
+ }
+}
+
+enum RenderPassStateType {
+ BeginRenderPass(BeginRenderPassState),
+ BeginRendering(BeginRenderingState),
+}
+
+impl From<BeginRenderPassState> for RenderPassStateType {
+ #[inline]
+ fn from(val: BeginRenderPassState) -> Self {
+ Self::BeginRenderPass(val)
+ }
+}
+
+impl From<BeginRenderingState> for RenderPassStateType {
+ #[inline]
+ fn from(val: BeginRenderingState) -> Self {
+ Self::BeginRendering(val)
+ }
+}
+
+struct BeginRenderPassState {
+ subpass: Subpass,
+ framebuffer: Option<Arc<Framebuffer>>,
+}
+
+struct BeginRenderingState {
+ pipeline_used: bool,
+}
+
+struct RenderPassStateAttachments {
+ color_attachments: Vec<Option<RenderPassStateAttachmentInfo>>,
+ depth_attachment: Option<RenderPassStateAttachmentInfo>,
+ stencil_attachment: Option<RenderPassStateAttachmentInfo>,
+}
+
+impl RenderPassStateAttachments {
+ fn from_subpass(subpass: &Subpass, framebuffer: &Framebuffer) -> Self {
+ let subpass_desc = subpass.subpass_desc();
+ let rp_attachments = subpass.render_pass().attachments();
+ let fb_attachments = framebuffer.attachments();
+
+ Self {
+ color_attachments: (subpass_desc.color_attachments.iter().enumerate())
+ .map(|(index, atch_ref)| {
+ (atch_ref.as_ref()).map(|atch_ref| RenderPassStateAttachmentInfo {
+ image_view: fb_attachments[atch_ref.attachment as usize].clone(),
+ image_layout: atch_ref.layout,
+ load_access: subpass
+ .load_op(atch_ref.attachment)
+ .and_then(color_load_access),
+ store_access: subpass
+ .store_op(atch_ref.attachment)
+ .and_then(color_store_access),
+ resolve_info: (subpass_desc.resolve_attachments.get(index))
+ .and_then(|atch_ref| atch_ref.as_ref())
+ .map(|atch_ref| RenderPassStateAttachmentResolveInfo {
+ image_view: fb_attachments[atch_ref.attachment as usize].clone(),
+ image_layout: atch_ref.layout,
+ load_access: subpass
+ .load_op(atch_ref.attachment)
+ .and_then(color_load_access),
+ store_access: subpass
+ .store_op(atch_ref.attachment)
+ .and_then(color_store_access),
+ }),
+ })
+ })
+ .collect(),
+ depth_attachment: (subpass_desc.depth_stencil_attachment.as_ref())
+ .filter(|atch_ref| {
+ (rp_attachments[atch_ref.attachment as usize].format.unwrap())
+ .aspects()
+ .intersects(ImageAspects::DEPTH)
+ })
+ .map(|atch_ref| RenderPassStateAttachmentInfo {
+ image_view: fb_attachments[atch_ref.attachment as usize].clone(),
+ image_layout: atch_ref.layout,
+ load_access: subpass
+ .load_op(atch_ref.attachment)
+ .and_then(depth_stencil_load_access),
+ store_access: subpass
+ .store_op(atch_ref.attachment)
+ .and_then(depth_stencil_store_access),
+ resolve_info: None,
+ }),
+ stencil_attachment: (subpass_desc.depth_stencil_attachment.as_ref())
+ .filter(|atch_ref| {
+ (rp_attachments[atch_ref.attachment as usize].format.unwrap())
+ .aspects()
+ .intersects(ImageAspects::STENCIL)
+ })
+ .map(|atch_ref| RenderPassStateAttachmentInfo {
+ image_view: fb_attachments[atch_ref.attachment as usize].clone(),
+ image_layout: atch_ref.layout,
+ load_access: subpass
+ .stencil_load_op(atch_ref.attachment)
+ .and_then(depth_stencil_load_access),
+ store_access: subpass
+ .stencil_store_op(atch_ref.attachment)
+ .and_then(depth_stencil_store_access),
+ resolve_info: None,
+ }),
+ }
+ }
+
+ fn from_rendering_info(info: &RenderingInfo) -> Self {
+ Self {
+ color_attachments: (info.color_attachments.iter())
+ .map(|atch_info| {
+ (atch_info.as_ref()).map(|atch_info| RenderPassStateAttachmentInfo {
+ image_view: atch_info.image_view.clone(),
+ image_layout: atch_info.image_layout,
+ load_access: color_load_access(atch_info.load_op),
+ store_access: color_store_access(atch_info.store_op),
+ resolve_info: atch_info.resolve_info.as_ref().map(|resolve_atch_info| {
+ RenderPassStateAttachmentResolveInfo {
+ image_view: resolve_atch_info.image_view.clone(),
+ image_layout: resolve_atch_info.image_layout,
+ load_access: None,
+ store_access: None,
+ }
+ }),
+ })
+ })
+ .collect(),
+ depth_attachment: (info.depth_attachment.as_ref()).map(|atch_info| {
+ RenderPassStateAttachmentInfo {
+ image_view: atch_info.image_view.clone(),
+ image_layout: atch_info.image_layout,
+ load_access: depth_stencil_load_access(atch_info.load_op),
+ store_access: depth_stencil_store_access(atch_info.store_op),
+ resolve_info: atch_info.resolve_info.as_ref().map(|resolve_atch_info| {
+ RenderPassStateAttachmentResolveInfo {
+ image_view: resolve_atch_info.image_view.clone(),
+ image_layout: resolve_atch_info.image_layout,
+ load_access: None,
+ store_access: None,
+ }
+ }),
+ }
+ }),
+ stencil_attachment: (info.stencil_attachment.as_ref()).map(|atch_info| {
+ RenderPassStateAttachmentInfo {
+ image_view: atch_info.image_view.clone(),
+ image_layout: atch_info.image_layout,
+ load_access: depth_stencil_load_access(atch_info.load_op),
+ store_access: depth_stencil_store_access(atch_info.store_op),
+ resolve_info: atch_info.resolve_info.as_ref().map(|resolve_atch_info| {
+ RenderPassStateAttachmentResolveInfo {
+ image_view: resolve_atch_info.image_view.clone(),
+ image_layout: resolve_atch_info.image_layout,
+ load_access: None,
+ store_access: None,
+ }
+ }),
+ }
+ }),
+ }
+ }
+}
+
+fn color_load_access(load_op: LoadOp) -> Option<PipelineStageAccess> {
+ match load_op {
+ LoadOp::Load => Some(PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentRead),
+ LoadOp::Clear => Some(PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentWrite),
+ LoadOp::DontCare => Some(PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentWrite),
+ //LoadOp::None => None,
+ }
+}
+
+fn depth_stencil_load_access(load_op: LoadOp) -> Option<PipelineStageAccess> {
+ match load_op {
+ LoadOp::Load => Some(PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentRead),
+ LoadOp::Clear => Some(PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentWrite),
+ LoadOp::DontCare => {
+ Some(PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentWrite)
+ } //LoadOp::None => None,
+ }
+}
+
+fn color_store_access(store_op: StoreOp) -> Option<PipelineStageAccess> {
+ match store_op {
+ StoreOp::Store => Some(PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentWrite),
+ StoreOp::DontCare => Some(PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentWrite),
+ // StoreOp::None => None,
+ }
+}
+
+fn depth_stencil_store_access(store_op: StoreOp) -> Option<PipelineStageAccess> {
+ match store_op {
+ StoreOp::Store => Some(PipelineStageAccess::LateFragmentTests_DepthStencilAttachmentWrite),
+ StoreOp::DontCare => {
+ Some(PipelineStageAccess::LateFragmentTests_DepthStencilAttachmentWrite)
+ } // StoreOp::None => None,
+ }
+}
+
+struct RenderPassStateAttachmentInfo {
+ image_view: Arc<dyn ImageViewAbstract>,
+ image_layout: ImageLayout,
+ load_access: Option<PipelineStageAccess>,
+ store_access: Option<PipelineStageAccess>,
+ resolve_info: Option<RenderPassStateAttachmentResolveInfo>,
+}
+
+struct RenderPassStateAttachmentResolveInfo {
+ image_view: Arc<dyn ImageViewAbstract>,
+ image_layout: ImageLayout,
+ load_access: Option<PipelineStageAccess>,
+ store_access: Option<PipelineStageAccess>,
+}
+
+struct DescriptorSetState {
+ descriptor_sets: HashMap<u32, SetOrPush>,
+ pipeline_layout: Arc<PipelineLayout>,
+}
+
+#[derive(Clone)]
+enum SetOrPush {
+ Set(DescriptorSetWithOffsets),
+ Push(DescriptorSetResources),
+}
+
+impl SetOrPush {
+ pub fn resources(&self) -> &DescriptorSetResources {
+ match self {
+ Self::Set(set) => set.as_ref().0.resources(),
+ Self::Push(resources) => resources,
+ }
+ }
+
+ #[inline]
+ pub fn dynamic_offsets(&self) -> &[u32] {
+ match self {
+ Self::Set(set) => set.as_ref().1,
+ Self::Push(_) => &[],
+ }
+ }
+}
+
+#[derive(Clone, Copy, Debug, Default)]
+struct StencilStateDynamic {
+ front: Option<u32>,
+ back: Option<u32>,
+}
+
+#[derive(Clone, Copy, Debug, Default)]
+struct StencilOpStateDynamic {
+ front: Option<StencilOps>,
+ back: Option<StencilOps>,
+}
+
+struct QueryState {
+ query_pool: ash::vk::QueryPool,
+ query: u32,
+ ty: QueryType,
+ flags: QueryControlFlags,
+ in_subpass: bool,
+}
+
+#[derive(Debug, Default)]
+struct ResourcesState {
+ buffers: HashMap<Arc<Buffer>, RangeMap<DeviceSize, BufferRangeState>>,
+ images: HashMap<Arc<Image>, RangeMap<DeviceSize, ImageRangeState>>,
+}
+
+#[derive(Clone, Debug, Default, PartialEq, Eq)]
+struct BufferRangeState {
+ resource_uses: Vec<ResourceUseRef>,
+ memory_access: MemoryAccessState,
+}
+
+#[derive(Clone, Debug, Default, PartialEq, Eq)]
+struct ImageRangeState {
+ resource_uses: Vec<ResourceUseRef>,
+ memory_access: MemoryAccessState,
+ expected_layout: ImageLayout,
+ current_layout: ImageLayout,
+}
+
+impl ResourcesState {
+ fn record_buffer_access(
+ &mut self,
+ use_ref: &ResourceUseRef,
+ buffer: &Arc<Buffer>,
+ range: Range<DeviceSize>,
+ stage_access: PipelineStageAccess,
+ ) {
+ let range_map = self.buffers.entry(buffer.clone()).or_insert_with(|| {
+ [(0..buffer.size(), Default::default())]
+ .into_iter()
+ .collect()
+ });
+ range_map.split_at(&range.start);
+ range_map.split_at(&range.end);
+
+ for (_range, state) in range_map.range_mut(&range) {
+ state.resource_uses.push(*use_ref);
+ state.memory_access.record_access(use_ref, stage_access);
+ }
+ }
+
+ fn record_image_access(
+ &mut self,
+ use_ref: &ResourceUseRef,
+ image: &Arc<Image>,
+ subresource_range: ImageSubresourceRange,
+ stage_access: PipelineStageAccess,
+ image_layout: ImageLayout,
+ ) {
+ let range_map = self.images.entry(image.clone()).or_insert_with(|| {
+ [(0..image.range_size(), Default::default())]
+ .into_iter()
+ .collect()
+ });
+
+ for range in image.iter_ranges(subresource_range) {
+ range_map.split_at(&range.start);
+ range_map.split_at(&range.end);
+
+ for (_range, state) in range_map.range_mut(&range) {
+ if state.resource_uses.is_empty() {
+ state.expected_layout = image_layout;
+ }
+
+ state.resource_uses.push(*use_ref);
+ state.memory_access.record_access(use_ref, stage_access);
+ }
+ }
+ }
+
+ fn record_pipeline_barrier(
+ &mut self,
+ command_index: usize,
+ command_name: &'static str,
+ dependency_info: &DependencyInfo,
+ queue_flags: QueueFlags,
+ ) {
+ for barrier in &dependency_info.buffer_memory_barriers {
+ let barrier_scopes = BarrierScopes::from_buffer_memory_barrier(barrier, queue_flags);
+ let &BufferMemoryBarrier {
+ src_stages: _,
+ src_access: _,
+ dst_stages: _,
+ dst_access: _,
+ queue_family_ownership_transfer: _,
+ ref buffer,
+ ref range,
+ _ne: _,
+ } = barrier;
+
+ let range_map = self.buffers.entry(buffer.clone()).or_insert_with(|| {
+ [(0..buffer.size(), Default::default())]
+ .into_iter()
+ .collect()
+ });
+ range_map.split_at(&range.start);
+ range_map.split_at(&range.end);
+
+ for (_range, state) in range_map.range_mut(range) {
+ state.memory_access.record_barrier(&barrier_scopes, None);
+ }
+ }
+
+ for (index, barrier) in dependency_info.image_memory_barriers.iter().enumerate() {
+ let index = index as u32;
+ let barrier_scopes = BarrierScopes::from_image_memory_barrier(barrier, queue_flags);
+ let &ImageMemoryBarrier {
+ src_stages: _,
+ src_access: _,
+ dst_stages: _,
+ dst_access: _,
+ old_layout,
+ new_layout,
+ queue_family_ownership_transfer: _,
+ ref image,
+ ref subresource_range,
+ _ne,
+ } = barrier;
+
+ // This is only used if there is a layout transition.
+ let use_ref = ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::ImageMemoryBarrier { index },
+ secondary_use_ref: None,
+ };
+ let layout_transition = (old_layout != new_layout).then_some(&use_ref);
+
+ let range_map = self.images.entry(image.clone()).or_insert_with(|| {
+ [(0..image.range_size(), Default::default())]
+ .into_iter()
+ .collect()
+ });
+
+ for range in image.iter_ranges(subresource_range.clone()) {
+ range_map.split_at(&range.start);
+ range_map.split_at(&range.end);
+
+ for (_range, state) in range_map.range_mut(&range) {
+ if old_layout != new_layout {
+ if state.resource_uses.is_empty() {
+ state.expected_layout = old_layout;
+ }
+
+ state.resource_uses.push(ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::ImageMemoryBarrier { index },
+ secondary_use_ref: None,
+ });
+ state.current_layout = new_layout;
+ }
+
+ state
+ .memory_access
+ .record_barrier(&barrier_scopes, layout_transition);
+ }
+ }
+ }
+
+ for barrier in &dependency_info.buffer_memory_barriers {
+ let &BufferMemoryBarrier {
+ ref buffer,
+ ref range,
+ ..
+ } = barrier;
+
+ let range_map = self.buffers.get_mut(buffer).unwrap();
+ for (_range, state) in range_map.range_mut(range) {
+ state.memory_access.apply_pending();
+ }
+ }
+
+ for barrier in &dependency_info.image_memory_barriers {
+ let &ImageMemoryBarrier {
+ ref image,
+ ref subresource_range,
+ ..
+ } = barrier;
+
+ let range_map = self.images.get_mut(image).unwrap();
+ for range in image.iter_ranges(subresource_range.clone()) {
+ for (_range, state) in range_map.range_mut(&range) {
+ state.memory_access.apply_pending();
+ }
+ }
+ }
+ }
+}
+
+#[derive(Clone, Debug, Default, PartialEq, Eq)]
+struct MemoryAccessState {
+ mutable: bool,
+ last_write: Option<WriteState>,
+ reads_since_last_write: HashMap<PipelineStage, ReadState>,
+
+ /// Pending changes that have not yet been applied. This is used during barrier recording.
+ pending: Option<PendingWriteState>,
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+struct WriteState {
+ use_ref: ResourceUseRef,
+ access: PipelineStageAccess,
+
+ /// The `dst_stages` and `dst_access` of all barriers that protect against this write.
+ barriers_since: PipelineStageAccessSet,
+
+ /// The `dst_stages` of all barriers that form a dependency chain with this write.
+ dependency_chain: PipelineStages,
+
+ /// The union of all `barriers_since` of all `reads_since_last_write`.
+ read_barriers_since: PipelineStages,
+}
+
+#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
+struct PendingWriteState {
+ /// If this is `Some`, then the barrier is treated as a new write,
+ /// and the previous `last_write` is discarded.
+ /// Otherwise, the values below are added to the existing `last_write`.
+ layout_transition: Option<ResourceUseRef>,
+
+ barriers_since: PipelineStageAccessSet,
+ dependency_chain: PipelineStages,
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+struct ReadState {
+ use_ref: ResourceUseRef,
+ access: PipelineStageAccess,
+
+ /// The `dst_stages` of all barriers that protect against this read.
+ /// This always includes the stage of `self`.
+ barriers_since: PipelineStages,
+
+ /// Stages of reads recorded after this read,
+ /// that were in scope of `barriers_since` at the time of recording.
+ /// This always includes the stage of `self`.
+ barriered_reads_since: PipelineStages,
+
+ /// Pending changes that have not yet been applied. This is used during barrier recording.
+ pending: Option<PendingReadState>,
+}
+
+#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
+struct PendingReadState {
+ barriers_since: PipelineStages,
+}
+
+impl MemoryAccessState {
+ fn record_access(&mut self, use_ref: &ResourceUseRef, access: PipelineStageAccess) {
+ if access.is_write() {
+ self.mutable = true;
+ self.last_write = Some(WriteState {
+ use_ref: *use_ref,
+ access,
+ barriers_since: Default::default(),
+ dependency_chain: Default::default(),
+ read_barriers_since: Default::default(),
+ });
+ self.reads_since_last_write.clear();
+ } else {
+ let pipeline_stage = PipelineStage::try_from(access).unwrap();
+ let pipeline_stages = PipelineStages::from(pipeline_stage);
+
+ for read_state in self.reads_since_last_write.values_mut() {
+ if read_state.barriers_since.intersects(pipeline_stages) {
+ read_state.barriered_reads_since |= pipeline_stages;
+ } else {
+ read_state.barriered_reads_since -= pipeline_stages;
+ }
+ }
+
+ self.reads_since_last_write.insert(
+ pipeline_stage,
+ ReadState {
+ use_ref: *use_ref,
+ access,
+ barriers_since: pipeline_stages,
+ barriered_reads_since: pipeline_stages,
+ pending: None,
+ },
+ );
+ }
+ }
+
+ fn record_barrier(
+ &mut self,
+ barrier_scopes: &BarrierScopes,
+ layout_transition: Option<&ResourceUseRef>,
+ ) {
+ let skip_reads = if let Some(use_ref) = layout_transition {
+ let pending = self.pending.get_or_insert_with(Default::default);
+ pending.layout_transition = Some(*use_ref);
+ true
+ } else {
+ self.pending
+ .map_or(false, |pending| pending.layout_transition.is_some())
+ };
+
+ // If the last write is in the src scope of the barrier, then add the dst scopes.
+ // If the barrier includes a layout transition, then that layout transition is
+ // considered the last write, and it is always in the src scope of the barrier.
+ if layout_transition.is_some()
+ || self.last_write.as_ref().map_or(false, |write_state| {
+ barrier_scopes
+ .src_access_scope
+ .contains_enum(write_state.access)
+ || barrier_scopes
+ .src_exec_scope
+ .intersects(write_state.dependency_chain)
+ })
+ {
+ let pending = self.pending.get_or_insert_with(Default::default);
+ pending.barriers_since |= barrier_scopes.dst_access_scope;
+ pending.dependency_chain |= barrier_scopes.dst_exec_scope;
+ }
+
+ // A layout transition counts as a write, which means that `reads_since_last_write` will
+ // be cleared when applying pending operations.
+ // Therefore, there is no need to update the reads.
+ if !skip_reads {
+ // Gather all reads for which `barriers_since` is in the barrier's `src_exec_scope`.
+ let reads_in_src_exec_scope = self.reads_since_last_write.iter().fold(
+ PipelineStages::empty(),
+ |total, (&stage, read_state)| {
+ if barrier_scopes
+ .src_exec_scope
+ .intersects(read_state.barriers_since)
+ {
+ total.union(stage.into())
+ } else {
+ total
+ }
+ },
+ );
+
+ for read_state in self.reads_since_last_write.values_mut() {
+ if reads_in_src_exec_scope.intersects(read_state.barriered_reads_since) {
+ let pending = read_state.pending.get_or_insert_with(Default::default);
+ pending.barriers_since |= barrier_scopes.dst_exec_scope;
+ }
+ }
+ }
+ }
+
+ fn apply_pending(&mut self) {
+ if let Some(PendingWriteState {
+ layout_transition,
+ barriers_since,
+ dependency_chain,
+ }) = self.pending.take()
+ {
+ // If there is a pending layout transition, it is treated as the new `last_write`.
+ if let Some(use_ref) = layout_transition {
+ self.mutable = true;
+ self.last_write = Some(WriteState {
+ use_ref,
+ access: PipelineStageAccess::ImageLayoutTransition,
+ barriers_since,
+ dependency_chain,
+ read_barriers_since: Default::default(),
+ });
+ self.reads_since_last_write.clear();
+ } else if let Some(write_state) = &mut self.last_write {
+ write_state.barriers_since |= barriers_since;
+ write_state.dependency_chain |= dependency_chain;
+ }
+ }
+
+ for read_state in self.reads_since_last_write.values_mut() {
+ if let Some(PendingReadState { barriers_since }) = read_state.pending.take() {
+ read_state.barriers_since |= barriers_since;
+
+ if let Some(write_state) = &mut self.last_write {
+ write_state.read_barriers_since |= read_state.barriers_since;
+ }
+ }
+ }
+ }
+}
+
+struct BarrierScopes {
+ src_exec_scope: PipelineStages,
+ src_access_scope: PipelineStageAccessSet,
+ dst_exec_scope: PipelineStages,
+ dst_access_scope: PipelineStageAccessSet,
+}
+
+impl BarrierScopes {
+ fn from_buffer_memory_barrier(barrier: &BufferMemoryBarrier, queue_flags: QueueFlags) -> Self {
+ let src_stages_expanded = barrier.src_stages.expand(queue_flags);
+ let src_exec_scope = src_stages_expanded.with_earlier();
+ let src_access_scope = PipelineStageAccessSet::from(barrier.src_access)
+ & PipelineStageAccessSet::from(src_stages_expanded);
+
+ let dst_stages_expanded = barrier.dst_stages.expand(queue_flags);
+ let dst_exec_scope = dst_stages_expanded.with_later();
+ let dst_access_scope = PipelineStageAccessSet::from(barrier.dst_access)
+ & PipelineStageAccessSet::from(dst_stages_expanded);
+
+ Self {
+ src_exec_scope,
+ src_access_scope,
+ dst_exec_scope,
+ dst_access_scope,
+ }
+ }
+
+ fn from_image_memory_barrier(barrier: &ImageMemoryBarrier, queue_flags: QueueFlags) -> Self {
+ let src_stages_expanded = barrier.src_stages.expand(queue_flags);
+ let src_exec_scope = src_stages_expanded.with_earlier();
+ let src_access_scope = PipelineStageAccessSet::from(barrier.src_access)
+ & PipelineStageAccessSet::from(src_stages_expanded);
+
+ let dst_stages_expanded = barrier.dst_stages.expand(queue_flags);
+ let dst_exec_scope = dst_stages_expanded.with_later();
+ let dst_access_scope = PipelineStageAccessSet::from(barrier.dst_access)
+ & PipelineStageAccessSet::from(dst_stages_expanded);
+
+ Self {
+ src_exec_scope,
+ src_access_scope,
+ dst_exec_scope,
+ dst_access_scope,
+ }
+ }
+}
diff --git a/src/command_buffer/standard/builder/pipeline.rs b/src/command_buffer/standard/builder/pipeline.rs
new file mode 100644
index 0000000..fec3565
--- /dev/null
+++ b/src/command_buffer/standard/builder/pipeline.rs
@@ -0,0 +1,2433 @@
+// Copyright (c) 2022 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use super::{
+ CommandBufferBuilder, CommandBufferBuilderState, DescriptorSetState, PipelineExecutionError,
+ RenderPassState, RenderPassStateAttachmentInfo, RenderPassStateType, ResourcesState,
+};
+use crate::{
+ buffer::{view::BufferView, BufferUsage, Subbuffer},
+ command_buffer::{
+ allocator::CommandBufferAllocator, commands::pipeline::DescriptorResourceInvalidError,
+ DispatchIndirectCommand, DrawIndexedIndirectCommand, DrawIndirectCommand,
+ ResourceInCommand, ResourceUseRef, SubpassContents,
+ },
+ descriptor_set::{layout::DescriptorType, DescriptorBindingResources},
+ device::{DeviceOwned, QueueFlags},
+ format::FormatFeatures,
+ image::{ImageAccess, ImageAspects, ImageSubresourceRange, ImageViewAbstract, SampleCount},
+ pipeline::{
+ graphics::{
+ input_assembly::{IndexType, PrimitiveTopology},
+ render_pass::PipelineRenderPassType,
+ vertex_input::VertexInputRate,
+ },
+ DynamicState, GraphicsPipeline, PartialStateMode, Pipeline, PipelineBindPoint,
+ PipelineLayout,
+ },
+ sampler::Sampler,
+ shader::{
+ DescriptorBindingRequirements, FragmentTestsStages, ShaderScalarType, ShaderStage,
+ ShaderStages,
+ },
+ sync::PipelineStageAccess,
+ DeviceSize, RequiresOneOf, VulkanObject,
+};
+use ahash::HashMap;
+use std::{cmp::min, mem::size_of, ops::Range, sync::Arc};
+
+impl<L, A> CommandBufferBuilder<L, A>
+where
+ A: CommandBufferAllocator,
+{
+ /// Perform a single compute operation using a compute pipeline.
+ ///
+ /// A compute pipeline must have been bound using [`bind_pipeline_compute`]. Any resources used
+ /// by the compute pipeline, such as descriptor sets, must have been set beforehand.
+ ///
+ /// # Safety
+ ///
+ /// - Appropriate synchronization must be provided for all buffers and images
+ /// that are accessed by the command.
+ /// - All images that are accessed by the command must be in the expected image layout.
+ ///
+ /// [`bind_pipeline_compute`]: Self::bind_pipeline_compute
+ #[inline]
+ pub unsafe fn dispatch(
+ &mut self,
+ group_counts: [u32; 3],
+ ) -> Result<&mut Self, PipelineExecutionError> {
+ self.validate_dispatch(group_counts)?;
+
+ unsafe { Ok(self.dispatch_unchecked(group_counts)) }
+ }
+
+ fn validate_dispatch(&self, group_counts: [u32; 3]) -> Result<(), PipelineExecutionError> {
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdDispatch-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::COMPUTE)
+ {
+ return Err(PipelineExecutionError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdDispatch-renderpass
+ if self.builder_state.render_pass.is_some() {
+ return Err(PipelineExecutionError::ForbiddenInsideRenderPass);
+ }
+
+ // VUID-vkCmdDispatch-None-02700
+ let pipeline = self
+ .builder_state
+ .pipeline_compute
+ .as_ref()
+ .ok_or(PipelineExecutionError::PipelineNotBound)?
+ .as_ref();
+
+ self.validate_pipeline_descriptor_sets(pipeline)?;
+ self.validate_pipeline_push_constants(pipeline.layout())?;
+
+ let max = self
+ .device()
+ .physical_device()
+ .properties()
+ .max_compute_work_group_count;
+
+ // VUID-vkCmdDispatch-groupCountX-00386
+ // VUID-vkCmdDispatch-groupCountY-00387
+ // VUID-vkCmdDispatch-groupCountZ-00388
+ if group_counts[0] > max[0] || group_counts[1] > max[1] || group_counts[2] > max[2] {
+ return Err(PipelineExecutionError::MaxComputeWorkGroupCountExceeded {
+ requested: group_counts,
+ max,
+ });
+ }
+
+ // TODO: sync check
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn dispatch_unchecked(&mut self, group_counts: [u32; 3]) -> &mut Self {
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_dispatch)(
+ self.handle(),
+ group_counts[0],
+ group_counts[1],
+ group_counts[2],
+ );
+
+ let command_index = self.next_command_index;
+ let command_name = "dispatch";
+ let pipeline = self
+ .builder_state
+ .pipeline_compute
+ .as_ref()
+ .unwrap()
+ .as_ref();
+ record_descriptor_sets_access(
+ &mut self.resources_usage_state,
+ command_index,
+ command_name,
+ &self.builder_state.descriptor_sets,
+ pipeline,
+ );
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Perform multiple compute operations using a compute pipeline. One dispatch is performed for
+ /// each [`DispatchIndirectCommand`] struct in `indirect_buffer`.
+ ///
+ /// A compute pipeline must have been bound using [`bind_pipeline_compute`]. Any resources used
+ /// by the compute pipeline, such as descriptor sets, must have been set beforehand.
+ ///
+ /// # Safety
+ ///
+ /// - Appropriate synchronization must be provided for all buffers and images
+ /// that are accessed by the command.
+ /// - All images that are accessed by the command must be in the expected image layout.
+ ///
+ /// [`bind_pipeline_compute`]: Self::bind_pipeline_compute
+ #[inline]
+ pub unsafe fn dispatch_indirect(
+ &mut self,
+ indirect_buffer: Subbuffer<[DispatchIndirectCommand]>,
+ ) -> Result<&mut Self, PipelineExecutionError> {
+ self.validate_dispatch_indirect(indirect_buffer.as_bytes())?;
+
+ unsafe { Ok(self.dispatch_indirect_unchecked(indirect_buffer)) }
+ }
+
+ fn validate_dispatch_indirect(
+ &self,
+ indirect_buffer: &Subbuffer<[u8]>,
+ ) -> Result<(), PipelineExecutionError> {
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdDispatchIndirect-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::COMPUTE)
+ {
+ return Err(PipelineExecutionError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdDispatchIndirect-renderpass
+ if self.builder_state.render_pass.is_some() {
+ return Err(PipelineExecutionError::ForbiddenInsideRenderPass);
+ }
+
+ // VUID-vkCmdDispatchIndirect-None-02700
+ let pipeline = self
+ .builder_state
+ .pipeline_compute
+ .as_ref()
+ .ok_or(PipelineExecutionError::PipelineNotBound)?
+ .as_ref();
+
+ self.validate_pipeline_descriptor_sets(pipeline)?;
+ self.validate_pipeline_push_constants(pipeline.layout())?;
+ self.validate_indirect_buffer(indirect_buffer)?;
+
+ // TODO: sync check
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn dispatch_indirect_unchecked(
+ &mut self,
+ indirect_buffer: Subbuffer<[DispatchIndirectCommand]>,
+ ) -> &mut Self {
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_dispatch_indirect)(
+ self.handle(),
+ indirect_buffer.buffer().handle(),
+ indirect_buffer.offset(),
+ );
+
+ let command_index = self.next_command_index;
+ let command_name = "dispatch_indirect";
+ let pipeline = self
+ .builder_state
+ .pipeline_compute
+ .as_ref()
+ .unwrap()
+ .as_ref();
+ record_descriptor_sets_access(
+ &mut self.resources_usage_state,
+ command_index,
+ command_name,
+ &self.builder_state.descriptor_sets,
+ pipeline,
+ );
+ record_indirect_buffer_access(
+ &mut self.resources_usage_state,
+ command_index,
+ command_name,
+ indirect_buffer.as_bytes(),
+ );
+
+ self.resources.push(Box::new(indirect_buffer));
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Perform a single draw operation using a graphics pipeline.
+ ///
+ /// The parameters specify the first vertex and the number of vertices to draw, and the first
+ /// instance and number of instances. For non-instanced drawing, specify `instance_count` as 1
+ /// and `first_instance` as 0.
+ ///
+ /// A graphics pipeline must have been bound using [`bind_pipeline_graphics`]. Any resources
+ /// used by the graphics pipeline, such as descriptor sets, vertex buffers and dynamic state,
+ /// must have been set beforehand. If the bound graphics pipeline uses vertex buffers, then the
+ /// provided vertex and instance ranges must be in range of the bound vertex buffers.
+ ///
+ /// # Safety
+ ///
+ /// - Appropriate synchronization must be provided for all buffers and images
+ /// that are accessed by the command.
+ /// - All images that are accessed by the command must be in the expected image layout.
+ ///
+ /// [`bind_pipeline_graphics`]: Self::bind_pipeline_graphics
+ #[inline]
+ pub unsafe fn draw(
+ &mut self,
+ vertex_count: u32,
+ instance_count: u32,
+ first_vertex: u32,
+ first_instance: u32,
+ ) -> Result<&mut Self, PipelineExecutionError> {
+ self.validate_draw(vertex_count, instance_count, first_vertex, first_instance)?;
+
+ unsafe {
+ Ok(self.draw_unchecked(vertex_count, instance_count, first_vertex, first_instance))
+ }
+ }
+
+ fn validate_draw(
+ &self,
+ vertex_count: u32,
+ instance_count: u32,
+ first_vertex: u32,
+ first_instance: u32,
+ ) -> Result<(), PipelineExecutionError> {
+ // VUID-vkCmdDraw-renderpass
+ let render_pass_state = self
+ .builder_state
+ .render_pass
+ .as_ref()
+ .ok_or(PipelineExecutionError::ForbiddenOutsideRenderPass)?;
+
+ // VUID-vkCmdDraw-None-02700
+ let pipeline = self
+ .builder_state
+ .pipeline_graphics
+ .as_ref()
+ .ok_or(PipelineExecutionError::PipelineNotBound)?
+ .as_ref();
+
+ self.validate_pipeline_descriptor_sets(pipeline)?;
+ self.validate_pipeline_push_constants(pipeline.layout())?;
+ self.validate_pipeline_graphics_dynamic_state(pipeline)?;
+ self.validate_pipeline_graphics_render_pass(pipeline, render_pass_state)?;
+ self.validate_pipeline_graphics_vertex_buffers(
+ pipeline,
+ Some((first_vertex, vertex_count)),
+ Some((first_instance, instance_count)),
+ )?;
+
+ // TODO: sync check
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn draw_unchecked(
+ &mut self,
+ vertex_count: u32,
+ instance_count: u32,
+ first_vertex: u32,
+ first_instance: u32,
+ ) -> &mut Self {
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_draw)(
+ self.handle(),
+ vertex_count,
+ instance_count,
+ first_vertex,
+ first_instance,
+ );
+
+ let command_index = self.next_command_index;
+ let command_name = "draw";
+ let pipeline = self
+ .builder_state
+ .pipeline_graphics
+ .as_ref()
+ .unwrap()
+ .as_ref();
+ record_descriptor_sets_access(
+ &mut self.resources_usage_state,
+ command_index,
+ command_name,
+ &self.builder_state.descriptor_sets,
+ pipeline,
+ );
+ record_vertex_buffers_access(
+ &mut self.resources_usage_state,
+ command_index,
+ command_name,
+ &self.builder_state.vertex_buffers,
+ pipeline,
+ );
+ record_subpass_attachments_access(
+ &mut self.resources_usage_state,
+ command_index,
+ command_name,
+ self.builder_state.render_pass.as_ref().unwrap(),
+ &self.builder_state,
+ pipeline,
+ );
+
+ if let RenderPassStateType::BeginRendering(state) =
+ &mut self.builder_state.render_pass.as_mut().unwrap().render_pass
+ {
+ state.pipeline_used = true;
+ }
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Perform multiple draw operations using a graphics pipeline.
+ ///
+ /// One draw is performed for each [`DrawIndirectCommand`] struct in `indirect_buffer`.
+ /// The maximum number of draw commands in the buffer is limited by the
+ /// [`max_draw_indirect_count`] limit.
+ /// This limit is 1 unless the [`multi_draw_indirect`] feature has been enabled on the device.
+ ///
+ /// A graphics pipeline must have been bound using [`bind_pipeline_graphics`]. Any resources
+ /// used by the graphics pipeline, such as descriptor sets, vertex buffers and dynamic state,
+ /// must have been set beforehand. If the bound graphics pipeline uses vertex buffers, then the
+ /// vertex and instance ranges of each `DrawIndirectCommand` in the indirect buffer must be in
+ /// range of the bound vertex buffers.
+ ///
+ /// # Safety
+ ///
+ /// - Appropriate synchronization must be provided for all buffers and images
+ /// that are accessed by the command.
+ /// - All images that are accessed by the command must be in the expected image layout.
+ ///
+ /// [`max_draw_indirect_count`]: crate::device::Properties::max_draw_indirect_count
+ /// [`multi_draw_indirect`]: crate::device::Features::multi_draw_indirect
+ /// [`bind_pipeline_graphics`]: Self::bind_pipeline_graphics
+ #[inline]
+ pub unsafe fn draw_indirect(
+ &mut self,
+ indirect_buffer: Subbuffer<[DrawIndirectCommand]>,
+ ) -> Result<&mut Self, PipelineExecutionError> {
+ let draw_count = indirect_buffer.len() as u32;
+ let stride = size_of::<DrawIndirectCommand>() as u32;
+ self.validate_draw_indirect(indirect_buffer.as_bytes(), draw_count, stride)?;
+
+ unsafe { Ok(self.draw_indirect_unchecked(indirect_buffer, draw_count, stride)) }
+ }
+
+ fn validate_draw_indirect(
+ &self,
+ indirect_buffer: &Subbuffer<[u8]>,
+ draw_count: u32,
+ _stride: u32,
+ ) -> Result<(), PipelineExecutionError> {
+ // VUID-vkCmdDrawIndirect-renderpass
+ let render_pass_state = self
+ .builder_state
+ .render_pass
+ .as_ref()
+ .ok_or(PipelineExecutionError::ForbiddenOutsideRenderPass)?;
+
+ // VUID-vkCmdDrawIndirect-None-02700
+ let pipeline = self
+ .builder_state
+ .pipeline_graphics
+ .as_ref()
+ .ok_or(PipelineExecutionError::PipelineNotBound)?
+ .as_ref();
+
+ self.validate_pipeline_descriptor_sets(pipeline)?;
+ self.validate_pipeline_push_constants(pipeline.layout())?;
+ self.validate_pipeline_graphics_dynamic_state(pipeline)?;
+ self.validate_pipeline_graphics_render_pass(pipeline, render_pass_state)?;
+ self.validate_pipeline_graphics_vertex_buffers(pipeline, None, None)?;
+
+ self.validate_indirect_buffer(indirect_buffer)?;
+
+ // VUID-vkCmdDrawIndirect-drawCount-02718
+ if draw_count > 1 && !self.device().enabled_features().multi_draw_indirect {
+ return Err(PipelineExecutionError::RequirementNotMet {
+ required_for: "`draw_count` is greater than `1`",
+ requires_one_of: RequiresOneOf {
+ features: &["multi_draw_indirect"],
+ ..Default::default()
+ },
+ });
+ }
+
+ let max = self
+ .device()
+ .physical_device()
+ .properties()
+ .max_draw_indirect_count;
+
+ // VUID-vkCmdDrawIndirect-drawCount-02719
+ if draw_count > max {
+ return Err(PipelineExecutionError::MaxDrawIndirectCountExceeded {
+ provided: draw_count,
+ max,
+ });
+ }
+
+ // TODO: sync check
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn draw_indirect_unchecked(
+ &mut self,
+ indirect_buffer: Subbuffer<[DrawIndirectCommand]>,
+ draw_count: u32,
+ stride: u32,
+ ) -> &mut Self {
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_draw_indirect)(
+ self.handle(),
+ indirect_buffer.buffer().handle(),
+ indirect_buffer.offset(),
+ draw_count,
+ stride,
+ );
+
+ let command_index = self.next_command_index;
+ let command_name = "draw_indirect";
+ let pipeline = self
+ .builder_state
+ .pipeline_graphics
+ .as_ref()
+ .unwrap()
+ .as_ref();
+ record_descriptor_sets_access(
+ &mut self.resources_usage_state,
+ command_index,
+ command_name,
+ &self.builder_state.descriptor_sets,
+ pipeline,
+ );
+ record_vertex_buffers_access(
+ &mut self.resources_usage_state,
+ command_index,
+ command_name,
+ &self.builder_state.vertex_buffers,
+ pipeline,
+ );
+ record_indirect_buffer_access(
+ &mut self.resources_usage_state,
+ command_index,
+ command_name,
+ indirect_buffer.as_bytes(),
+ );
+ record_subpass_attachments_access(
+ &mut self.resources_usage_state,
+ command_index,
+ command_name,
+ self.builder_state.render_pass.as_ref().unwrap(),
+ &self.builder_state,
+ pipeline,
+ );
+
+ if let RenderPassStateType::BeginRendering(state) =
+ &mut self.builder_state.render_pass.as_mut().unwrap().render_pass
+ {
+ state.pipeline_used = true;
+ }
+
+ self.resources.push(Box::new(indirect_buffer));
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Perform a single draw operation using a graphics pipeline, using an index buffer.
+ ///
+ /// The parameters specify the first index and the number of indices in the index buffer that
+ /// should be used, and the first instance and number of instances. For non-instanced drawing,
+ /// specify `instance_count` as 1 and `first_instance` as 0. The `vertex_offset` is a constant
+ /// value that should be added to each index in the index buffer to produce the final vertex
+ /// number to be used.
+ ///
+ /// An index buffer must have been bound using [`bind_index_buffer`], and the provided index
+ /// range must be in range of the bound index buffer.
+ ///
+ /// A graphics pipeline must have been bound using [`bind_pipeline_graphics`]. Any resources
+ /// used by the graphics pipeline, such as descriptor sets, vertex buffers and dynamic state,
+ /// must have been set beforehand. If the bound graphics pipeline uses vertex buffers, then the
+ /// provided instance range must be in range of the bound vertex buffers. The vertex indices in
+ /// the index buffer must be in range of the bound vertex buffers.
+ ///
+ /// # Safety
+ ///
+ /// - Appropriate synchronization must be provided for all buffers and images
+ /// that are accessed by the command.
+ /// - All images that are accessed by the command must be in the expected image layout.
+ ///
+ /// [`bind_index_buffer`]: Self::bind_index_buffer
+ /// [`bind_pipeline_graphics`]: Self::bind_pipeline_graphics
+ #[inline]
+ pub unsafe fn draw_indexed(
+ &mut self,
+ index_count: u32,
+ instance_count: u32,
+ first_index: u32,
+ vertex_offset: i32,
+ first_instance: u32,
+ ) -> Result<&mut Self, PipelineExecutionError> {
+ self.validate_draw_indexed(
+ index_count,
+ instance_count,
+ first_index,
+ vertex_offset,
+ first_instance,
+ )?;
+
+ unsafe {
+ Ok(self.draw_indexed_unchecked(
+ index_count,
+ instance_count,
+ first_index,
+ vertex_offset,
+ first_instance,
+ ))
+ }
+ }
+
+ fn validate_draw_indexed(
+ &self,
+ index_count: u32,
+ instance_count: u32,
+ first_index: u32,
+ _vertex_offset: i32,
+ first_instance: u32,
+ ) -> Result<(), PipelineExecutionError> {
+ // TODO: how to handle an index out of range of the vertex buffers?
+
+ // VUID-vkCmdDrawIndexed-renderpass
+ let render_pass_state = self
+ .builder_state
+ .render_pass
+ .as_ref()
+ .ok_or(PipelineExecutionError::ForbiddenOutsideRenderPass)?;
+
+ // VUID-vkCmdDrawIndexed-None-02700
+ let pipeline = self
+ .builder_state
+ .pipeline_graphics
+ .as_ref()
+ .ok_or(PipelineExecutionError::PipelineNotBound)?
+ .as_ref();
+
+ self.validate_pipeline_descriptor_sets(pipeline)?;
+ self.validate_pipeline_push_constants(pipeline.layout())?;
+ self.validate_pipeline_graphics_dynamic_state(pipeline)?;
+ self.validate_pipeline_graphics_render_pass(pipeline, render_pass_state)?;
+ self.validate_pipeline_graphics_vertex_buffers(
+ pipeline,
+ None,
+ Some((first_instance, instance_count)),
+ )?;
+
+ self.validate_index_buffer(Some((first_index, index_count)))?;
+
+ // TODO: sync check
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn draw_indexed_unchecked(
+ &mut self,
+ index_count: u32,
+ instance_count: u32,
+ first_index: u32,
+ vertex_offset: i32,
+ first_instance: u32,
+ ) -> &mut Self {
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_draw_indexed)(
+ self.handle(),
+ index_count,
+ instance_count,
+ first_index,
+ vertex_offset,
+ first_instance,
+ );
+
+ let command_index = self.next_command_index;
+ let command_name = "draw_indexed";
+ let pipeline = self
+ .builder_state
+ .pipeline_graphics
+ .as_ref()
+ .unwrap()
+ .as_ref();
+ record_descriptor_sets_access(
+ &mut self.resources_usage_state,
+ command_index,
+ command_name,
+ &self.builder_state.descriptor_sets,
+ pipeline,
+ );
+ record_vertex_buffers_access(
+ &mut self.resources_usage_state,
+ command_index,
+ command_name,
+ &self.builder_state.vertex_buffers,
+ pipeline,
+ );
+ record_index_buffer_access(
+ &mut self.resources_usage_state,
+ command_index,
+ command_name,
+ &self.builder_state.index_buffer,
+ );
+ record_subpass_attachments_access(
+ &mut self.resources_usage_state,
+ command_index,
+ command_name,
+ self.builder_state.render_pass.as_ref().unwrap(),
+ &self.builder_state,
+ pipeline,
+ );
+
+ if let RenderPassStateType::BeginRendering(state) =
+ &mut self.builder_state.render_pass.as_mut().unwrap().render_pass
+ {
+ state.pipeline_used = true;
+ }
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Perform multiple draw operations using a graphics pipeline, using an index buffer.
+ ///
+ /// One draw is performed for each [`DrawIndexedIndirectCommand`] struct in `indirect_buffer`.
+ /// The maximum number of draw commands in the buffer is limited by the
+ /// [`max_draw_indirect_count`] limit.
+ /// This limit is 1 unless the [`multi_draw_indirect`] feature has been enabled on the device.
+ ///
+ /// An index buffer must have been bound using [`bind_index_buffer`], and the index ranges of
+ /// each `DrawIndexedIndirectCommand` in the indirect buffer must be in range of the bound
+ /// index buffer.
+ ///
+ /// A graphics pipeline must have been bound using [`bind_pipeline_graphics`]. Any resources
+ /// used by the graphics pipeline, such as descriptor sets, vertex buffers and dynamic state,
+ /// must have been set beforehand. If the bound graphics pipeline uses vertex buffers, then the
+ /// instance ranges of each `DrawIndexedIndirectCommand` in the indirect buffer must be in
+ /// range of the bound vertex buffers.
+ ///
+ /// # Safety
+ ///
+ /// - Appropriate synchronization must be provided for all buffers and images
+ /// that are accessed by the command.
+ /// - All images that are accessed by the command must be in the expected image layout.
+ ///
+ /// [`max_draw_indirect_count`]: crate::device::Properties::max_draw_indirect_count
+ /// [`multi_draw_indirect`]: crate::device::Features::multi_draw_indirect
+ /// [`bind_index_buffer`]: Self::bind_index_buffer
+ /// [`bind_pipeline_graphics`]: Self::bind_pipeline_graphics
+ #[inline]
+ pub unsafe fn draw_indexed_indirect(
+ &mut self,
+ indirect_buffer: Subbuffer<[DrawIndexedIndirectCommand]>,
+ ) -> Result<&mut Self, PipelineExecutionError> {
+ let draw_count = indirect_buffer.len() as u32;
+ let stride = size_of::<DrawIndexedIndirectCommand>() as u32;
+ self.validate_draw_indexed_indirect(indirect_buffer.as_bytes(), draw_count, stride)?;
+
+ unsafe { Ok(self.draw_indexed_indirect_unchecked(indirect_buffer, draw_count, stride)) }
+ }
+
+ fn validate_draw_indexed_indirect(
+ &self,
+ indirect_buffer: &Subbuffer<[u8]>,
+ draw_count: u32,
+ _stride: u32,
+ ) -> Result<(), PipelineExecutionError> {
+ // VUID-vkCmdDrawIndexedIndirect-renderpass
+ let render_pass_state = self
+ .builder_state
+ .render_pass
+ .as_ref()
+ .ok_or(PipelineExecutionError::ForbiddenOutsideRenderPass)?;
+
+ // VUID-vkCmdDrawIndexedIndirect-None-02700
+ let pipeline = self
+ .builder_state
+ .pipeline_graphics
+ .as_ref()
+ .ok_or(PipelineExecutionError::PipelineNotBound)?
+ .as_ref();
+
+ self.validate_pipeline_descriptor_sets(pipeline)?;
+ self.validate_pipeline_push_constants(pipeline.layout())?;
+ self.validate_pipeline_graphics_dynamic_state(pipeline)?;
+ self.validate_pipeline_graphics_render_pass(pipeline, render_pass_state)?;
+ self.validate_pipeline_graphics_vertex_buffers(pipeline, None, None)?;
+
+ self.validate_index_buffer(None)?;
+ self.validate_indirect_buffer(indirect_buffer)?;
+
+ // VUID-vkCmdDrawIndexedIndirect-drawCount-02718
+ if draw_count > 1 && !self.device().enabled_features().multi_draw_indirect {
+ return Err(PipelineExecutionError::RequirementNotMet {
+ required_for: "`draw_count` is greater than `1`",
+ requires_one_of: RequiresOneOf {
+ features: &["multi_draw_indirect"],
+ ..Default::default()
+ },
+ });
+ }
+
+ let max = self
+ .device()
+ .physical_device()
+ .properties()
+ .max_draw_indirect_count;
+
+ // VUID-vkCmdDrawIndexedIndirect-drawCount-02719
+ if draw_count > max {
+ return Err(PipelineExecutionError::MaxDrawIndirectCountExceeded {
+ provided: draw_count,
+ max,
+ });
+ }
+
+ // TODO: sync check
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn draw_indexed_indirect_unchecked(
+ &mut self,
+ indirect_buffer: Subbuffer<[DrawIndexedIndirectCommand]>,
+ draw_count: u32,
+ stride: u32,
+ ) -> &mut Self {
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_draw_indexed_indirect)(
+ self.handle(),
+ indirect_buffer.buffer().handle(),
+ indirect_buffer.offset(),
+ draw_count,
+ stride,
+ );
+
+ let command_index = self.next_command_index;
+ let command_name = "draw_indexed_indirect";
+ let pipeline = self
+ .builder_state
+ .pipeline_graphics
+ .as_ref()
+ .unwrap()
+ .as_ref();
+ record_descriptor_sets_access(
+ &mut self.resources_usage_state,
+ command_index,
+ command_name,
+ &self.builder_state.descriptor_sets,
+ pipeline,
+ );
+ record_vertex_buffers_access(
+ &mut self.resources_usage_state,
+ command_index,
+ command_name,
+ &self.builder_state.vertex_buffers,
+ pipeline,
+ );
+ record_index_buffer_access(
+ &mut self.resources_usage_state,
+ command_index,
+ command_name,
+ &self.builder_state.index_buffer,
+ );
+ record_indirect_buffer_access(
+ &mut self.resources_usage_state,
+ command_index,
+ command_name,
+ indirect_buffer.as_bytes(),
+ );
+ record_subpass_attachments_access(
+ &mut self.resources_usage_state,
+ command_index,
+ command_name,
+ self.builder_state.render_pass.as_ref().unwrap(),
+ &self.builder_state,
+ pipeline,
+ );
+
+ if let RenderPassStateType::BeginRendering(state) =
+ &mut self.builder_state.render_pass.as_mut().unwrap().render_pass
+ {
+ state.pipeline_used = true;
+ }
+
+ self.resources.push(Box::new(indirect_buffer));
+
+ self.next_command_index += 1;
+ self
+ }
+
+ fn validate_index_buffer(
+ &self,
+ indices: Option<(u32, u32)>,
+ ) -> Result<(), PipelineExecutionError> {
+ // VUID?
+ let (index_buffer, index_type) = self
+ .builder_state
+ .index_buffer
+ .as_ref()
+ .ok_or(PipelineExecutionError::IndexBufferNotBound)?;
+
+ if let Some((first_index, index_count)) = indices {
+ let max_index_count = (index_buffer.size() / index_type.size()) as u32;
+
+ // // VUID-vkCmdDrawIndexed-firstIndex-04932
+ if first_index + index_count > max_index_count {
+ return Err(PipelineExecutionError::IndexBufferRangeOutOfBounds {
+ highest_index: first_index + index_count,
+ max_index_count,
+ });
+ }
+ }
+
+ Ok(())
+ }
+
+ fn validate_indirect_buffer(
+ &self,
+ buffer: &Subbuffer<[u8]>,
+ ) -> Result<(), PipelineExecutionError> {
+ // VUID-vkCmdDispatchIndirect-commonparent
+ assert_eq!(self.device(), buffer.device());
+
+ // VUID-vkCmdDispatchIndirect-buffer-02709
+ if !buffer
+ .buffer()
+ .usage()
+ .intersects(BufferUsage::INDIRECT_BUFFER)
+ {
+ return Err(PipelineExecutionError::IndirectBufferMissingUsage);
+ }
+
+ // VUID-vkCmdDispatchIndirect-offset-02710
+ // TODO:
+
+ Ok(())
+ }
+
+ fn validate_pipeline_descriptor_sets(
+ &self,
+ pipeline: &impl Pipeline,
+ ) -> Result<(), PipelineExecutionError> {
+ fn validate_resources<T>(
+ set_num: u32,
+ binding_num: u32,
+ binding_reqs: &DescriptorBindingRequirements,
+ elements: &[Option<T>],
+ mut extra_check: impl FnMut(u32, &T) -> Result<(), DescriptorResourceInvalidError>,
+ ) -> Result<(), PipelineExecutionError> {
+ let elements_to_check = if let Some(descriptor_count) = binding_reqs.descriptor_count {
+ // The shader has a fixed-sized array, so it will never access more than
+ // the first `descriptor_count` elements.
+ elements.get(..descriptor_count as usize).ok_or({
+ // There are less than `descriptor_count` elements in `elements`
+ PipelineExecutionError::DescriptorResourceInvalid {
+ set_num,
+ binding_num,
+ index: elements.len() as u32,
+ error: DescriptorResourceInvalidError::Missing,
+ }
+ })?
+ } else {
+ // The shader has a runtime-sized array, so any element could potentially
+ // be accessed. We must check them all.
+ elements
+ };
+
+ for (index, element) in elements_to_check.iter().enumerate() {
+ let index = index as u32;
+
+ // VUID-vkCmdDispatch-None-02699
+ let element = match element {
+ Some(x) => x,
+ None => {
+ return Err(PipelineExecutionError::DescriptorResourceInvalid {
+ set_num,
+ binding_num,
+ index,
+ error: DescriptorResourceInvalidError::Missing,
+ })
+ }
+ };
+
+ if let Err(error) = extra_check(index, element) {
+ return Err(PipelineExecutionError::DescriptorResourceInvalid {
+ set_num,
+ binding_num,
+ index,
+ error,
+ });
+ }
+ }
+
+ Ok(())
+ }
+
+ if pipeline.num_used_descriptor_sets() == 0 {
+ return Ok(());
+ }
+
+ // VUID-vkCmdDispatch-None-02697
+ let descriptor_set_state = self
+ .builder_state
+ .descriptor_sets
+ .get(&pipeline.bind_point())
+ .ok_or(PipelineExecutionError::PipelineLayoutNotCompatible)?;
+
+ // VUID-vkCmdDispatch-None-02697
+ if !pipeline.layout().is_compatible_with(
+ &descriptor_set_state.pipeline_layout,
+ pipeline.num_used_descriptor_sets(),
+ ) {
+ return Err(PipelineExecutionError::PipelineLayoutNotCompatible);
+ }
+
+ for (&(set_num, binding_num), binding_reqs) in pipeline.descriptor_binding_requirements() {
+ let layout_binding =
+ &pipeline.layout().set_layouts()[set_num as usize].bindings()[&binding_num];
+
+ let check_buffer =
+ |_index: u32, (_buffer, _range): &(Subbuffer<[u8]>, Range<DeviceSize>)| Ok(());
+
+ let check_buffer_view = |index: u32, buffer_view: &Arc<BufferView>| {
+ for desc_reqs in (binding_reqs.descriptors.get(&Some(index)).into_iter())
+ .chain(binding_reqs.descriptors.get(&None))
+ {
+ if layout_binding.descriptor_type == DescriptorType::StorageTexelBuffer {
+ // VUID-vkCmdDispatch-OpTypeImage-06423
+ if binding_reqs.image_format.is_none()
+ && !desc_reqs.memory_write.is_empty()
+ && !buffer_view
+ .format_features()
+ .intersects(FormatFeatures::STORAGE_WRITE_WITHOUT_FORMAT)
+ {
+ return Err(DescriptorResourceInvalidError::StorageWriteWithoutFormatNotSupported);
+ }
+
+ // VUID-vkCmdDispatch-OpTypeImage-06424
+ if binding_reqs.image_format.is_none()
+ && !desc_reqs.memory_read.is_empty()
+ && !buffer_view
+ .format_features()
+ .intersects(FormatFeatures::STORAGE_READ_WITHOUT_FORMAT)
+ {
+ return Err(DescriptorResourceInvalidError::StorageReadWithoutFormatNotSupported);
+ }
+ }
+ }
+
+ Ok(())
+ };
+
+ let check_image_view_common = |index: u32, image_view: &Arc<dyn ImageViewAbstract>| {
+ for desc_reqs in (binding_reqs.descriptors.get(&Some(index)).into_iter())
+ .chain(binding_reqs.descriptors.get(&None))
+ {
+ // VUID-vkCmdDispatch-None-02691
+ if desc_reqs.storage_image_atomic
+ && !image_view
+ .format_features()
+ .intersects(FormatFeatures::STORAGE_IMAGE_ATOMIC)
+ {
+ return Err(DescriptorResourceInvalidError::StorageImageAtomicNotSupported);
+ }
+
+ if layout_binding.descriptor_type == DescriptorType::StorageImage {
+ // VUID-vkCmdDispatch-OpTypeImage-06423
+ if binding_reqs.image_format.is_none()
+ && !desc_reqs.memory_write.is_empty()
+ && !image_view
+ .format_features()
+ .intersects(FormatFeatures::STORAGE_WRITE_WITHOUT_FORMAT)
+ {
+ return Err(
+ DescriptorResourceInvalidError::StorageWriteWithoutFormatNotSupported,
+ );
+ }
+
+ // VUID-vkCmdDispatch-OpTypeImage-06424
+ if binding_reqs.image_format.is_none()
+ && !desc_reqs.memory_read.is_empty()
+ && !image_view
+ .format_features()
+ .intersects(FormatFeatures::STORAGE_READ_WITHOUT_FORMAT)
+ {
+ return Err(
+ DescriptorResourceInvalidError::StorageReadWithoutFormatNotSupported,
+ );
+ }
+ }
+ }
+
+ /*
+ Instruction/Sampler/Image View Validation
+ https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap16.html#textures-input-validation
+ */
+
+ // The SPIR-V Image Format is not compatible with the image view’s format.
+ if let Some(format) = binding_reqs.image_format {
+ if image_view.format() != Some(format) {
+ return Err(DescriptorResourceInvalidError::ImageViewFormatMismatch {
+ required: format,
+ provided: image_view.format(),
+ });
+ }
+ }
+
+ // Rules for viewType
+ if let Some(image_view_type) = binding_reqs.image_view_type {
+ if image_view.view_type() != image_view_type {
+ return Err(DescriptorResourceInvalidError::ImageViewTypeMismatch {
+ required: image_view_type,
+ provided: image_view.view_type(),
+ });
+ }
+ }
+
+ // - If the image was created with VkImageCreateInfo::samples equal to
+ // VK_SAMPLE_COUNT_1_BIT, the instruction must have MS = 0.
+ // - If the image was created with VkImageCreateInfo::samples not equal to
+ // VK_SAMPLE_COUNT_1_BIT, the instruction must have MS = 1.
+ if binding_reqs.image_multisampled
+ != (image_view.image().samples() != SampleCount::Sample1)
+ {
+ return Err(
+ DescriptorResourceInvalidError::ImageViewMultisampledMismatch {
+ required: binding_reqs.image_multisampled,
+ provided: image_view.image().samples() != SampleCount::Sample1,
+ },
+ );
+ }
+
+ // - If the Sampled Type of the OpTypeImage does not match the numeric format of the
+ // image, as shown in the SPIR-V Sampled Type column of the
+ // Interpretation of Numeric Format table.
+ // - If the signedness of any read or sample operation does not match the signedness of
+ // the image’s format.
+ if let Some(scalar_type) = binding_reqs.image_scalar_type {
+ let aspects = image_view.subresource_range().aspects;
+ let view_scalar_type = ShaderScalarType::from(
+ if aspects.intersects(
+ ImageAspects::COLOR
+ | ImageAspects::PLANE_0
+ | ImageAspects::PLANE_1
+ | ImageAspects::PLANE_2,
+ ) {
+ image_view.format().unwrap().type_color().unwrap()
+ } else if aspects.intersects(ImageAspects::DEPTH) {
+ image_view.format().unwrap().type_depth().unwrap()
+ } else if aspects.intersects(ImageAspects::STENCIL) {
+ image_view.format().unwrap().type_stencil().unwrap()
+ } else {
+ // Per `ImageViewBuilder::aspects` and
+ // VUID-VkDescriptorImageInfo-imageView-01976
+ unreachable!()
+ },
+ );
+
+ if scalar_type != view_scalar_type {
+ return Err(
+ DescriptorResourceInvalidError::ImageViewScalarTypeMismatch {
+ required: scalar_type,
+ provided: view_scalar_type,
+ },
+ );
+ }
+ }
+
+ Ok(())
+ };
+
+ let check_sampler_common = |index: u32, sampler: &Arc<Sampler>| {
+ for desc_reqs in (binding_reqs.descriptors.get(&Some(index)).into_iter())
+ .chain(binding_reqs.descriptors.get(&None))
+ {
+ // VUID-vkCmdDispatch-None-02703
+ // VUID-vkCmdDispatch-None-02704
+ if desc_reqs.sampler_no_unnormalized_coordinates
+ && sampler.unnormalized_coordinates()
+ {
+ return Err(
+ DescriptorResourceInvalidError::SamplerUnnormalizedCoordinatesNotAllowed,
+ );
+ }
+
+ // - OpImageFetch, OpImageSparseFetch, OpImage*Gather, and OpImageSparse*Gather must not
+ // be used with a sampler that enables sampler Y′CBCR conversion.
+ // - The ConstOffset and Offset operands must not be used with a sampler that enables
+ // sampler Y′CBCR conversion.
+ if desc_reqs.sampler_no_ycbcr_conversion
+ && sampler.sampler_ycbcr_conversion().is_some()
+ {
+ return Err(
+ DescriptorResourceInvalidError::SamplerYcbcrConversionNotAllowed,
+ );
+ }
+
+ /*
+ Instruction/Sampler/Image View Validation
+ https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap16.html#textures-input-validation
+ */
+
+ // - The SPIR-V instruction is one of the OpImage*Dref* instructions and the sampler
+ // compareEnable is VK_FALSE
+ // - The SPIR-V instruction is not one of the OpImage*Dref* instructions and the sampler
+ // compareEnable is VK_TRUE
+ if desc_reqs.sampler_compare != sampler.compare().is_some() {
+ return Err(DescriptorResourceInvalidError::SamplerCompareMismatch {
+ required: desc_reqs.sampler_compare,
+ provided: sampler.compare().is_some(),
+ });
+ }
+ }
+
+ Ok(())
+ };
+
+ let check_image_view = |index: u32, image_view: &Arc<dyn ImageViewAbstract>| {
+ check_image_view_common(index, image_view)?;
+
+ if let Some(sampler) = layout_binding.immutable_samplers.get(index as usize) {
+ check_sampler_common(index, sampler)?;
+ }
+
+ Ok(())
+ };
+
+ let check_image_view_sampler =
+ |index: u32, (image_view, sampler): &(Arc<dyn ImageViewAbstract>, Arc<Sampler>)| {
+ check_image_view_common(index, image_view)?;
+ check_sampler_common(index, sampler)?;
+
+ Ok(())
+ };
+
+ let check_sampler = |index: u32, sampler: &Arc<Sampler>| {
+ check_sampler_common(index, sampler)?;
+
+ for desc_reqs in (binding_reqs.descriptors.get(&Some(index)).into_iter())
+ .chain(binding_reqs.descriptors.get(&None))
+ {
+ // Check sampler-image compatibility. Only done for separate samplers;
+ // combined image samplers are checked when updating the descriptor set.
+
+ // If the image view isn't actually present in the resources, then just skip it.
+ // It will be caught later by check_resources.
+ let iter = desc_reqs.sampler_with_images.iter().filter_map(|id| {
+ descriptor_set_state
+ .descriptor_sets
+ .get(&id.set)
+ .and_then(|set| set.resources().binding(id.binding))
+ .and_then(|res| match res {
+ DescriptorBindingResources::ImageView(elements) => elements
+ .get(id.index as usize)
+ .and_then(|opt| opt.as_ref().map(|opt| (id, opt))),
+ _ => None,
+ })
+ });
+
+ for (id, image_view) in iter {
+ if let Err(error) = sampler.check_can_sample(image_view.as_ref()) {
+ return Err(
+ DescriptorResourceInvalidError::SamplerImageViewIncompatible {
+ image_view_set_num: id.set,
+ image_view_binding_num: id.binding,
+ image_view_index: id.index,
+ error,
+ },
+ );
+ }
+ }
+ }
+
+ Ok(())
+ };
+
+ let check_none = |index: u32, _: &()| {
+ if let Some(sampler) = layout_binding.immutable_samplers.get(index as usize) {
+ check_sampler(index, sampler)?;
+ }
+
+ Ok(())
+ };
+
+ let set_resources = descriptor_set_state
+ .descriptor_sets
+ .get(&set_num)
+ .ok_or(PipelineExecutionError::DescriptorSetNotBound { set_num })?
+ .resources();
+
+ let binding_resources = set_resources.binding(binding_num).unwrap();
+
+ match binding_resources {
+ DescriptorBindingResources::None(elements) => {
+ validate_resources(set_num, binding_num, binding_reqs, elements, check_none)?;
+ }
+ DescriptorBindingResources::Buffer(elements) => {
+ validate_resources(set_num, binding_num, binding_reqs, elements, check_buffer)?;
+ }
+ DescriptorBindingResources::BufferView(elements) => {
+ validate_resources(
+ set_num,
+ binding_num,
+ binding_reqs,
+ elements,
+ check_buffer_view,
+ )?;
+ }
+ DescriptorBindingResources::ImageView(elements) => {
+ validate_resources(
+ set_num,
+ binding_num,
+ binding_reqs,
+ elements,
+ check_image_view,
+ )?;
+ }
+ DescriptorBindingResources::ImageViewSampler(elements) => {
+ validate_resources(
+ set_num,
+ binding_num,
+ binding_reqs,
+ elements,
+ check_image_view_sampler,
+ )?;
+ }
+ DescriptorBindingResources::Sampler(elements) => {
+ validate_resources(
+ set_num,
+ binding_num,
+ binding_reqs,
+ elements,
+ check_sampler,
+ )?;
+ }
+ }
+ }
+
+ Ok(())
+ }
+
+ fn validate_pipeline_push_constants(
+ &self,
+ pipeline_layout: &PipelineLayout,
+ ) -> Result<(), PipelineExecutionError> {
+ if pipeline_layout.push_constant_ranges().is_empty()
+ || self.device().enabled_features().maintenance4
+ {
+ return Ok(());
+ }
+
+ // VUID-vkCmdDispatch-maintenance4-06425
+ let constants_pipeline_layout = self
+ .builder_state
+ .push_constants_pipeline_layout
+ .as_ref()
+ .ok_or(PipelineExecutionError::PushConstantsMissing)?;
+
+ // VUID-vkCmdDispatch-maintenance4-06425
+ if pipeline_layout.handle() != constants_pipeline_layout.handle()
+ && pipeline_layout.push_constant_ranges()
+ != constants_pipeline_layout.push_constant_ranges()
+ {
+ return Err(PipelineExecutionError::PushConstantsNotCompatible);
+ }
+
+ let set_bytes = &self.builder_state.push_constants;
+
+ // VUID-vkCmdDispatch-maintenance4-06425
+ if !pipeline_layout
+ .push_constant_ranges()
+ .iter()
+ .all(|pc_range| set_bytes.contains(pc_range.offset..pc_range.offset + pc_range.size))
+ {
+ return Err(PipelineExecutionError::PushConstantsMissing);
+ }
+
+ Ok(())
+ }
+
+ fn validate_pipeline_graphics_dynamic_state(
+ &self,
+ pipeline: &GraphicsPipeline,
+ ) -> Result<(), PipelineExecutionError> {
+ let device = pipeline.device();
+
+ // VUID-vkCmdDraw-commandBuffer-02701
+ for dynamic_state in pipeline
+ .dynamic_states()
+ .filter(|(_, d)| *d)
+ .map(|(s, _)| s)
+ {
+ match dynamic_state {
+ DynamicState::BlendConstants => {
+ // VUID?
+ if self.builder_state.blend_constants.is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::ColorWriteEnable => {
+ // VUID-vkCmdDraw-attachmentCount-06667
+ let enables = self.builder_state.color_write_enable.as_ref().ok_or(PipelineExecutionError::DynamicStateNotSet { dynamic_state })?;
+
+ // VUID-vkCmdDraw-attachmentCount-06667
+ if enables.len() < pipeline.color_blend_state().unwrap().attachments.len() {
+ return Err(
+ PipelineExecutionError::DynamicColorWriteEnableNotEnoughValues {
+ color_write_enable_count: enables.len() as u32,
+ attachment_count: pipeline
+ .color_blend_state()
+ .unwrap()
+ .attachments
+ .len() as u32,
+ },
+ );
+ }
+ }
+ DynamicState::CullMode => {
+ // VUID?
+ if self.builder_state.cull_mode.is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::DepthBias => {
+ // VUID?
+ if self.builder_state.depth_bias.is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::DepthBiasEnable => {
+ // VUID-vkCmdDraw-None-04877
+ if self.builder_state.depth_bias_enable.is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::DepthBounds => {
+ // VUID?
+ if self.builder_state.depth_bounds.is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::DepthBoundsTestEnable => {
+ // VUID?
+ if self.builder_state.depth_bounds_test_enable.is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::DepthCompareOp => {
+ // VUID?
+ if self.builder_state.depth_compare_op.is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::DepthTestEnable => {
+ // VUID?
+ if self.builder_state.depth_test_enable.is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::DepthWriteEnable => {
+ // VUID?
+ if self.builder_state.depth_write_enable.is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+
+ // TODO: Check if the depth buffer is writable
+ }
+ DynamicState::DiscardRectangle => {
+ let discard_rectangle_count =
+ match pipeline.discard_rectangle_state().unwrap().rectangles {
+ PartialStateMode::Dynamic(count) => count,
+ _ => unreachable!(),
+ };
+
+ for num in 0..discard_rectangle_count {
+ // VUID?
+ if !self.builder_state.discard_rectangle.contains_key(&num) {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ }
+ DynamicState::ExclusiveScissor => todo!(),
+ DynamicState::FragmentShadingRate => todo!(),
+ DynamicState::FrontFace => {
+ // VUID?
+ if self.builder_state.front_face.is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::LineStipple => {
+ // VUID?
+ if self.builder_state.line_stipple.is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::LineWidth => {
+ // VUID?
+ if self.builder_state.line_width.is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::LogicOp => {
+ // VUID-vkCmdDraw-logicOp-04878
+ if self.builder_state.logic_op.is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::PatchControlPoints => {
+ // VUID-vkCmdDraw-None-04875
+ if self.builder_state.patch_control_points.is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::PrimitiveRestartEnable => {
+ // VUID-vkCmdDraw-None-04879
+ let primitive_restart_enable =
+ if let Some(enable) = self.builder_state.primitive_restart_enable {
+ enable
+ } else {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ };
+
+ if primitive_restart_enable {
+ let topology = match pipeline.input_assembly_state().topology {
+ PartialStateMode::Fixed(topology) => topology,
+ PartialStateMode::Dynamic(_) => {
+ if let Some(topology) = self.builder_state.primitive_topology {
+ topology
+ } else {
+ return Err(PipelineExecutionError::DynamicStateNotSet {
+ dynamic_state: DynamicState::PrimitiveTopology,
+ });
+ }
+ }
+ };
+
+ match topology {
+ PrimitiveTopology::PointList
+ | PrimitiveTopology::LineList
+ | PrimitiveTopology::TriangleList
+ | PrimitiveTopology::LineListWithAdjacency
+ | PrimitiveTopology::TriangleListWithAdjacency => {
+ // VUID?
+ if !device.enabled_features().primitive_topology_list_restart {
+ return Err(PipelineExecutionError::RequirementNotMet {
+ required_for: "The bound pipeline sets \
+ `DynamicState::PrimitiveRestartEnable` and the \
+ current primitive topology is \
+ `PrimitiveTopology::*List`",
+ requires_one_of: RequiresOneOf {
+ features: &["primitive_topology_list_restart"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ PrimitiveTopology::PatchList => {
+ // VUID?
+ if !device
+ .enabled_features()
+ .primitive_topology_patch_list_restart
+ {
+ return Err(PipelineExecutionError::RequirementNotMet {
+ required_for: "The bound pipeline sets \
+ `DynamicState::PrimitiveRestartEnable` and the \
+ current primitive topology is \
+ `PrimitiveTopology::PatchList`",
+ requires_one_of: RequiresOneOf {
+ features: &["primitive_topology_patch_list_restart"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ _ => (),
+ }
+ }
+ }
+ DynamicState::PrimitiveTopology => {
+ // VUID-vkCmdDraw-primitiveTopology-03420
+ let topology = if let Some(topology) = self.builder_state.primitive_topology {
+ topology
+ } else {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ };
+
+ if pipeline.shader(ShaderStage::TessellationControl).is_some() {
+ // VUID?
+ if !matches!(topology, PrimitiveTopology::PatchList) {
+ return Err(PipelineExecutionError::DynamicPrimitiveTopologyInvalid {
+ topology,
+ });
+ }
+ } else {
+ // VUID?
+ if matches!(topology, PrimitiveTopology::PatchList) {
+ return Err(PipelineExecutionError::DynamicPrimitiveTopologyInvalid {
+ topology,
+ });
+ }
+ }
+
+ let required_topology_class = match pipeline.input_assembly_state().topology {
+ PartialStateMode::Dynamic(topology_class) => topology_class,
+ _ => unreachable!(),
+ };
+
+ // VUID-vkCmdDraw-primitiveTopology-03420
+ if topology.class() != required_topology_class {
+ return Err(
+ PipelineExecutionError::DynamicPrimitiveTopologyClassMismatch {
+ provided_class: topology.class(),
+ required_class: required_topology_class,
+ },
+ );
+ }
+
+ // TODO: check that the topology matches the geometry shader
+ }
+ DynamicState::RasterizerDiscardEnable => {
+ // VUID-vkCmdDraw-None-04876
+ if self.builder_state.rasterizer_discard_enable.is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::RayTracingPipelineStackSize => unreachable!(
+ "RayTracingPipelineStackSize dynamic state should not occur on a graphics pipeline"
+ ),
+ DynamicState::SampleLocations => todo!(),
+ DynamicState::Scissor => {
+ for num in 0..pipeline.viewport_state().unwrap().count().unwrap() {
+ // VUID?
+ if !self.builder_state.scissor.contains_key(&num) {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ }
+ DynamicState::ScissorWithCount => {
+ // VUID-vkCmdDraw-scissorCount-03418
+ // VUID-vkCmdDraw-viewportCount-03419
+ let scissor_count = self.builder_state.scissor_with_count.as_ref().ok_or(PipelineExecutionError::DynamicStateNotSet { dynamic_state })?.len() as u32;
+
+ // Check if the counts match, but only if the viewport count is fixed.
+ // If the viewport count is also dynamic, then the
+ // DynamicState::ViewportWithCount match arm will handle it.
+ if let Some(viewport_count) = pipeline.viewport_state().unwrap().count() {
+ // VUID-vkCmdDraw-scissorCount-03418
+ if viewport_count != scissor_count {
+ return Err(
+ PipelineExecutionError::DynamicViewportScissorCountMismatch {
+ viewport_count,
+ scissor_count,
+ },
+ );
+ }
+ }
+ }
+ DynamicState::StencilCompareMask => {
+ let state = self.builder_state.stencil_compare_mask;
+
+ // VUID?
+ if state.front.is_none() || state.back.is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::StencilOp => {
+ let state = self.builder_state.stencil_op;
+
+ // VUID?
+ if state.front.is_none() || state.back.is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::StencilReference => {
+ let state = self.builder_state.stencil_reference;
+
+ // VUID?
+ if state.front.is_none() || state.back.is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::StencilTestEnable => {
+ // VUID?
+ if self.builder_state.stencil_test_enable.is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+
+ // TODO: Check if the stencil buffer is writable
+ }
+ DynamicState::StencilWriteMask => {
+ let state = self.builder_state.stencil_write_mask;
+
+ // VUID?
+ if state.front.is_none() || state.back.is_none() {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ DynamicState::VertexInput => todo!(),
+ DynamicState::VertexInputBindingStride => todo!(),
+ DynamicState::Viewport => {
+ for num in 0..pipeline.viewport_state().unwrap().count().unwrap() {
+ // VUID?
+ if !self.builder_state.viewport.contains_key(&num) {
+ return Err(PipelineExecutionError::DynamicStateNotSet { dynamic_state });
+ }
+ }
+ }
+ DynamicState::ViewportCoarseSampleOrder => todo!(),
+ DynamicState::ViewportShadingRatePalette => todo!(),
+ DynamicState::ViewportWithCount => {
+ // VUID-vkCmdDraw-viewportCount-03417
+ let viewport_count = self.builder_state.viewport_with_count.as_ref().ok_or(PipelineExecutionError::DynamicStateNotSet { dynamic_state })?.len() as u32;
+
+ let scissor_count = if let Some(scissor_count) =
+ pipeline.viewport_state().unwrap().count()
+ {
+ // The scissor count is fixed.
+ scissor_count
+ } else {
+ // VUID-vkCmdDraw-viewportCount-03419
+ // The scissor count is also dynamic.
+ self.builder_state.scissor_with_count.as_ref().ok_or(PipelineExecutionError::DynamicStateNotSet { dynamic_state })?.len() as u32
+ };
+
+ // VUID-vkCmdDraw-viewportCount-03417
+ // VUID-vkCmdDraw-viewportCount-03419
+ if viewport_count != scissor_count {
+ return Err(
+ PipelineExecutionError::DynamicViewportScissorCountMismatch {
+ viewport_count,
+ scissor_count,
+ },
+ );
+ }
+
+ // TODO: VUID-vkCmdDrawIndexed-primitiveFragmentShadingRateWithMultipleViewports-04552
+ // If the primitiveFragmentShadingRateWithMultipleViewports limit is not supported,
+ // the bound graphics pipeline was created with the
+ // VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT dynamic state enabled, and any of the
+ // shader stages of the bound graphics pipeline write to the PrimitiveShadingRateKHR
+ // built-in, then vkCmdSetViewportWithCountEXT must have been called in the current
+ // command buffer prior to this drawing command, and the viewportCount parameter of
+ // vkCmdSetViewportWithCountEXT must be 1
+ }
+ DynamicState::ViewportWScaling => todo!(),
+ DynamicState::TessellationDomainOrigin => todo!(),
+ DynamicState::DepthClampEnable => todo!(),
+ DynamicState::PolygonMode => todo!(),
+ DynamicState::RasterizationSamples => todo!(),
+ DynamicState::SampleMask => todo!(),
+ DynamicState::AlphaToCoverageEnable => todo!(),
+ DynamicState::AlphaToOneEnable => todo!(),
+ DynamicState::LogicOpEnable => todo!(),
+ DynamicState::ColorBlendEnable => todo!(),
+ DynamicState::ColorBlendEquation => todo!(),
+ DynamicState::ColorWriteMask => todo!(),
+ DynamicState::RasterizationStream => todo!(),
+ DynamicState::ConservativeRasterizationMode => todo!(),
+ DynamicState::ExtraPrimitiveOverestimationSize => todo!(),
+ DynamicState::DepthClipEnable => todo!(),
+ DynamicState::SampleLocationsEnable => todo!(),
+ DynamicState::ColorBlendAdvanced => todo!(),
+ DynamicState::ProvokingVertexMode => todo!(),
+ DynamicState::LineRasterizationMode => todo!(),
+ DynamicState::LineStippleEnable => todo!(),
+ DynamicState::DepthClipNegativeOneToOne => todo!(),
+ DynamicState::ViewportWScalingEnable => todo!(),
+ DynamicState::ViewportSwizzle => todo!(),
+ DynamicState::CoverageToColorEnable => todo!(),
+ DynamicState::CoverageToColorLocation => todo!(),
+ DynamicState::CoverageModulationMode => todo!(),
+ DynamicState::CoverageModulationTableEnable => todo!(),
+ DynamicState::CoverageModulationTable => todo!(),
+ DynamicState::ShadingRateImageEnable => todo!(),
+ DynamicState::RepresentativeFragmentTestEnable => todo!(),
+ DynamicState::CoverageReductionMode => todo!(),
+ }
+ }
+
+ Ok(())
+ }
+
+ fn validate_pipeline_graphics_render_pass(
+ &self,
+ pipeline: &GraphicsPipeline,
+ render_pass_state: &RenderPassState,
+ ) -> Result<(), PipelineExecutionError> {
+ // VUID?
+ if render_pass_state.contents != SubpassContents::Inline {
+ return Err(PipelineExecutionError::ForbiddenWithSubpassContents {
+ subpass_contents: render_pass_state.contents,
+ });
+ }
+
+ match (&render_pass_state.render_pass, pipeline.render_pass()) {
+ (
+ RenderPassStateType::BeginRenderPass(state),
+ PipelineRenderPassType::BeginRenderPass(pipeline_subpass),
+ ) => {
+ // VUID-vkCmdDraw-renderPass-02684
+ if !pipeline_subpass
+ .render_pass()
+ .is_compatible_with(state.subpass.render_pass())
+ {
+ return Err(PipelineExecutionError::PipelineRenderPassNotCompatible);
+ }
+
+ // VUID-vkCmdDraw-subpass-02685
+ if pipeline_subpass.index() != state.subpass.index() {
+ return Err(PipelineExecutionError::PipelineSubpassMismatch {
+ pipeline: pipeline_subpass.index(),
+ current: state.subpass.index(),
+ });
+ }
+ }
+ (
+ RenderPassStateType::BeginRendering(_),
+ PipelineRenderPassType::BeginRendering(pipeline_rendering_info),
+ ) => {
+ // VUID-vkCmdDraw-viewMask-06178
+ if pipeline_rendering_info.view_mask != render_pass_state.rendering_info.view_mask {
+ return Err(PipelineExecutionError::PipelineViewMaskMismatch {
+ pipeline_view_mask: pipeline_rendering_info.view_mask,
+ required_view_mask: render_pass_state.rendering_info.view_mask,
+ });
+ }
+
+ // VUID-vkCmdDraw-colorAttachmentCount-06179
+ if pipeline_rendering_info.color_attachment_formats.len()
+ != render_pass_state
+ .rendering_info
+ .color_attachment_formats
+ .len()
+ {
+ return Err(
+ PipelineExecutionError::PipelineColorAttachmentCountMismatch {
+ pipeline_count: pipeline_rendering_info.color_attachment_formats.len()
+ as u32,
+ required_count: render_pass_state
+ .rendering_info
+ .color_attachment_formats
+ .len() as u32,
+ },
+ );
+ }
+
+ for (color_attachment_index, required_format, pipeline_format) in render_pass_state
+ .rendering_info
+ .color_attachment_formats
+ .iter()
+ .zip(
+ pipeline_rendering_info
+ .color_attachment_formats
+ .iter()
+ .copied(),
+ )
+ .enumerate()
+ .filter_map(|(i, (r, p))| r.map(|r| (i as u32, r, p)))
+ {
+ // VUID-vkCmdDraw-colorAttachmentCount-06180
+ if Some(required_format) != pipeline_format {
+ return Err(
+ PipelineExecutionError::PipelineColorAttachmentFormatMismatch {
+ color_attachment_index,
+ pipeline_format,
+ required_format,
+ },
+ );
+ }
+ }
+
+ if let Some((required_format, pipeline_format)) = render_pass_state
+ .rendering_info
+ .depth_attachment_format
+ .map(|r| (r, pipeline_rendering_info.depth_attachment_format))
+ {
+ // VUID-vkCmdDraw-pDepthAttachment-06181
+ if Some(required_format) != pipeline_format {
+ return Err(
+ PipelineExecutionError::PipelineDepthAttachmentFormatMismatch {
+ pipeline_format,
+ required_format,
+ },
+ );
+ }
+ }
+
+ if let Some((required_format, pipeline_format)) = render_pass_state
+ .rendering_info
+ .stencil_attachment_format
+ .map(|r| (r, pipeline_rendering_info.stencil_attachment_format))
+ {
+ // VUID-vkCmdDraw-pStencilAttachment-06182
+ if Some(required_format) != pipeline_format {
+ return Err(
+ PipelineExecutionError::PipelineStencilAttachmentFormatMismatch {
+ pipeline_format,
+ required_format,
+ },
+ );
+ }
+ }
+
+ // VUID-vkCmdDraw-imageView-06172
+ // VUID-vkCmdDraw-imageView-06173
+ // VUID-vkCmdDraw-imageView-06174
+ // VUID-vkCmdDraw-imageView-06175
+ // VUID-vkCmdDraw-imageView-06176
+ // VUID-vkCmdDraw-imageView-06177
+ // TODO:
+ }
+ _ => return Err(PipelineExecutionError::PipelineRenderPassTypeMismatch),
+ }
+
+ // VUID-vkCmdDraw-None-02686
+ // TODO:
+
+ Ok(())
+ }
+
+ fn validate_pipeline_graphics_vertex_buffers(
+ &self,
+ pipeline: &GraphicsPipeline,
+ vertices: Option<(u32, u32)>,
+ instances: Option<(u32, u32)>,
+ ) -> Result<(), PipelineExecutionError> {
+ let vertex_input = pipeline.vertex_input_state();
+ let mut vertices_in_buffers: Option<u64> = None;
+ let mut instances_in_buffers: Option<u64> = None;
+
+ for (&binding_num, binding_desc) in &vertex_input.bindings {
+ // VUID-vkCmdDraw-None-04007
+ let vertex_buffer = match self.builder_state.vertex_buffers.get(&binding_num) {
+ Some(x) => x,
+ None => return Err(PipelineExecutionError::VertexBufferNotBound { binding_num }),
+ };
+
+ let mut num_elements = vertex_buffer.size() / binding_desc.stride as u64;
+
+ match binding_desc.input_rate {
+ VertexInputRate::Vertex => {
+ vertices_in_buffers = Some(if let Some(x) = vertices_in_buffers {
+ min(x, num_elements)
+ } else {
+ num_elements
+ });
+ }
+ VertexInputRate::Instance { divisor } => {
+ if divisor == 0 {
+ // A divisor of 0 means the same instance data is used for all instances,
+ // so we can draw any number of instances from a single element.
+ // The buffer must contain at least one element though.
+ if num_elements != 0 {
+ num_elements = u64::MAX;
+ }
+ } else {
+ // If divisor is e.g. 2, we use only half the amount of data from the source
+ // buffer, so the number of instances that can be drawn is twice as large.
+ num_elements = num_elements.saturating_mul(divisor as u64);
+ }
+
+ instances_in_buffers = Some(if let Some(x) = instances_in_buffers {
+ min(x, num_elements)
+ } else {
+ num_elements
+ });
+ }
+ };
+ }
+
+ if let Some((first_vertex, vertex_count)) = vertices {
+ let vertices_needed = first_vertex as u64 + vertex_count as u64;
+
+ if let Some(vertices_in_buffers) = vertices_in_buffers {
+ // VUID-vkCmdDraw-None-02721
+ if vertices_needed > vertices_in_buffers {
+ return Err(PipelineExecutionError::VertexBufferVertexRangeOutOfBounds {
+ vertices_needed,
+ vertices_in_buffers,
+ });
+ }
+ }
+ }
+
+ if let Some((first_instance, instance_count)) = instances {
+ let instances_needed = first_instance as u64 + instance_count as u64;
+
+ if let Some(instances_in_buffers) = instances_in_buffers {
+ // VUID-vkCmdDraw-None-02721
+ if instances_needed > instances_in_buffers {
+ return Err(
+ PipelineExecutionError::VertexBufferInstanceRangeOutOfBounds {
+ instances_needed,
+ instances_in_buffers,
+ },
+ );
+ }
+ }
+
+ let view_mask = match pipeline.render_pass() {
+ PipelineRenderPassType::BeginRenderPass(subpass) => {
+ subpass.render_pass().views_used()
+ }
+ PipelineRenderPassType::BeginRendering(rendering_info) => rendering_info.view_mask,
+ };
+
+ if view_mask != 0 {
+ let max = pipeline
+ .device()
+ .physical_device()
+ .properties()
+ .max_multiview_instance_index
+ .unwrap_or(0);
+
+ let highest_instance = instances_needed.saturating_sub(1);
+
+ // VUID-vkCmdDraw-maxMultiviewInstanceIndex-02688
+ if highest_instance > max as u64 {
+ return Err(PipelineExecutionError::MaxMultiviewInstanceIndexExceeded {
+ highest_instance,
+ max,
+ });
+ }
+ }
+ }
+
+ Ok(())
+ }
+}
+
+fn record_descriptor_sets_access(
+ resources_usage_state: &mut ResourcesState,
+ command_index: usize,
+ command_name: &'static str,
+ descriptor_sets_state: &HashMap<PipelineBindPoint, DescriptorSetState>,
+ pipeline: &impl Pipeline,
+) {
+ let descriptor_sets_state = match descriptor_sets_state.get(&pipeline.bind_point()) {
+ Some(x) => x,
+ None => return,
+ };
+
+ for (&(set, binding), binding_reqs) in pipeline.descriptor_binding_requirements() {
+ let descriptor_type = descriptor_sets_state.pipeline_layout.set_layouts()[set as usize]
+ .bindings()[&binding]
+ .descriptor_type;
+
+ // TODO: Should input attachments be handled here or in attachment access?
+ if descriptor_type == DescriptorType::InputAttachment {
+ continue;
+ }
+
+ let use_iter = move |index: u32| {
+ let (stages_read, stages_write) = [Some(index), None]
+ .into_iter()
+ .filter_map(|index| binding_reqs.descriptors.get(&index))
+ .fold(
+ (ShaderStages::empty(), ShaderStages::empty()),
+ |(stages_read, stages_write), desc_reqs| {
+ (
+ stages_read | desc_reqs.memory_read,
+ stages_write | desc_reqs.memory_write,
+ )
+ },
+ );
+ let use_ref = ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::DescriptorSet {
+ set,
+ binding,
+ index,
+ },
+ secondary_use_ref: None,
+ };
+ let stage_access_iter = PipelineStageAccess::iter_descriptor_stages(
+ descriptor_type,
+ stages_read,
+ stages_write,
+ );
+ (use_ref, stage_access_iter)
+ };
+
+ let descriptor_set_state = &descriptor_sets_state.descriptor_sets[&set];
+
+ match descriptor_set_state.resources().binding(binding).unwrap() {
+ DescriptorBindingResources::None(_) => continue,
+ DescriptorBindingResources::Buffer(elements) => {
+ if matches!(
+ descriptor_type,
+ DescriptorType::UniformBufferDynamic | DescriptorType::StorageBufferDynamic
+ ) {
+ let dynamic_offsets = descriptor_set_state.dynamic_offsets();
+
+ for (index, element) in elements.iter().enumerate() {
+ if let Some((buffer, range)) = element {
+ let dynamic_offset = dynamic_offsets[index] as DeviceSize;
+ let (use_ref, stage_access_iter) = use_iter(index as u32);
+
+ let mut range = range.clone();
+ range.start += buffer.offset() + dynamic_offset;
+ range.end += buffer.offset() + dynamic_offset;
+
+ for stage_access in stage_access_iter {
+ resources_usage_state.record_buffer_access(
+ &use_ref,
+ buffer.buffer(),
+ range.clone(),
+ stage_access,
+ );
+ }
+ }
+ }
+ } else {
+ for (index, element) in elements.iter().enumerate() {
+ if let Some((buffer, range)) = element {
+ let (use_ref, stage_access_iter) = use_iter(index as u32);
+
+ let mut range = range.clone();
+ range.start += buffer.offset();
+ range.end += buffer.offset();
+
+ for stage_access in stage_access_iter {
+ resources_usage_state.record_buffer_access(
+ &use_ref,
+ buffer.buffer(),
+ range.clone(),
+ stage_access,
+ );
+ }
+ }
+ }
+ }
+ }
+ DescriptorBindingResources::BufferView(elements) => {
+ for (index, element) in elements.iter().enumerate() {
+ if let Some(buffer_view) = element {
+ let buffer = buffer_view.buffer();
+ let (use_ref, stage_access_iter) = use_iter(index as u32);
+
+ let mut range = buffer_view.range();
+ range.start += buffer.offset();
+ range.end += buffer.offset();
+
+ for stage_access in stage_access_iter {
+ resources_usage_state.record_buffer_access(
+ &use_ref,
+ buffer.buffer(),
+ range.clone(),
+ stage_access,
+ );
+ }
+ }
+ }
+ }
+ DescriptorBindingResources::ImageView(elements) => {
+ for (index, element) in elements.iter().enumerate() {
+ if let Some(image_view) = element {
+ let image = image_view.image();
+ let image_inner = image.inner();
+ let layout = image
+ .descriptor_layouts()
+ .expect(
+ "descriptor_layouts must return Some when used in an image view",
+ )
+ .layout_for(descriptor_type);
+ let (use_ref, stage_access_iter) = use_iter(index as u32);
+
+ let mut subresource_range = image_view.subresource_range().clone();
+ subresource_range.array_layers.start += image_inner.first_layer;
+ subresource_range.array_layers.end += image_inner.first_layer;
+ subresource_range.mip_levels.start += image_inner.first_mipmap_level;
+ subresource_range.mip_levels.end += image_inner.first_mipmap_level;
+
+ for stage_access in stage_access_iter {
+ resources_usage_state.record_image_access(
+ &use_ref,
+ image_inner.image,
+ subresource_range.clone(),
+ stage_access,
+ layout,
+ );
+ }
+ }
+ }
+ }
+ DescriptorBindingResources::ImageViewSampler(elements) => {
+ for (index, element) in elements.iter().enumerate() {
+ if let Some((image_view, _)) = element {
+ let image = image_view.image();
+ let image_inner = image.inner();
+ let layout = image
+ .descriptor_layouts()
+ .expect(
+ "descriptor_layouts must return Some when used in an image view",
+ )
+ .layout_for(descriptor_type);
+ let (use_ref, stage_access_iter) = use_iter(index as u32);
+
+ let mut subresource_range = image_view.subresource_range().clone();
+ subresource_range.array_layers.start += image_inner.first_layer;
+ subresource_range.array_layers.end += image_inner.first_layer;
+ subresource_range.mip_levels.start += image_inner.first_mipmap_level;
+ subresource_range.mip_levels.end += image_inner.first_mipmap_level;
+
+ for stage_access in stage_access_iter {
+ resources_usage_state.record_image_access(
+ &use_ref,
+ image_inner.image,
+ subresource_range.clone(),
+ stage_access,
+ layout,
+ );
+ }
+ }
+ }
+ }
+ DescriptorBindingResources::Sampler(_) => (),
+ }
+ }
+}
+
+fn record_vertex_buffers_access(
+ resources_usage_state: &mut ResourcesState,
+ command_index: usize,
+ command_name: &'static str,
+ vertex_buffers_state: &HashMap<u32, Subbuffer<[u8]>>,
+ pipeline: &GraphicsPipeline,
+) {
+ for &binding in pipeline.vertex_input_state().bindings.keys() {
+ let buffer = &vertex_buffers_state[&binding];
+ let use_ref = ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::VertexBuffer { binding },
+ secondary_use_ref: None,
+ };
+
+ let mut range = 0..buffer.size(); // TODO: take range from draw command
+ range.start += buffer.offset();
+ range.end += buffer.offset();
+ resources_usage_state.record_buffer_access(
+ &use_ref,
+ buffer.buffer(),
+ range,
+ PipelineStageAccess::VertexAttributeInput_VertexAttributeRead,
+ );
+ }
+}
+
+fn record_index_buffer_access(
+ resources_usage_state: &mut ResourcesState,
+ command_index: usize,
+ command_name: &'static str,
+ index_buffer_state: &Option<(Subbuffer<[u8]>, IndexType)>,
+) {
+ let buffer = &index_buffer_state.as_ref().unwrap().0;
+ let use_ref = ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::IndexBuffer,
+ secondary_use_ref: None,
+ };
+
+ let mut range = 0..buffer.size(); // TODO: take range from draw command
+ range.start += buffer.offset();
+ range.end += buffer.offset();
+ resources_usage_state.record_buffer_access(
+ &use_ref,
+ buffer.buffer(),
+ range,
+ PipelineStageAccess::IndexInput_IndexRead,
+ );
+}
+
+fn record_indirect_buffer_access(
+ resources_usage_state: &mut ResourcesState,
+ command_index: usize,
+ command_name: &'static str,
+ buffer: &Subbuffer<[u8]>,
+) {
+ let use_ref = ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::IndirectBuffer,
+ secondary_use_ref: None,
+ };
+
+ let mut range = 0..buffer.size(); // TODO: take range from draw command
+ range.start += buffer.offset();
+ range.end += buffer.offset();
+ resources_usage_state.record_buffer_access(
+ &use_ref,
+ buffer.buffer(),
+ range,
+ PipelineStageAccess::DrawIndirect_IndirectCommandRead,
+ );
+}
+
+fn record_subpass_attachments_access(
+ resources_usage_state: &mut ResourcesState,
+ command_index: usize,
+ command_name: &'static str,
+ render_pass_state: &RenderPassState,
+ builder_state: &CommandBufferBuilderState,
+ pipeline: &GraphicsPipeline,
+) {
+ if Option::from(pipeline.rasterization_state().rasterizer_discard_enable)
+ .or(builder_state.rasterizer_discard_enable)
+ .unwrap()
+ {
+ return;
+ }
+
+ let attachments = match &render_pass_state.attachments {
+ Some(x) => x,
+ None => return,
+ };
+
+ if let Some(attachment_info) = attachments.depth_attachment.as_ref() {
+ let &RenderPassStateAttachmentInfo {
+ ref image_view,
+ image_layout,
+ ..
+ } = attachment_info;
+
+ // TODO: check `pipeline.depth_stencil_state` for whether the attachment is going to be
+ // read and/or written.
+ let accesses: &'static [PipelineStageAccess] =
+ match pipeline.fragment_tests_stages().unwrap() {
+ FragmentTestsStages::Early => {
+ &[PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentWrite]
+ }
+ FragmentTestsStages::Late => {
+ &[PipelineStageAccess::LateFragmentTests_DepthStencilAttachmentWrite]
+ }
+ FragmentTestsStages::EarlyAndLate => &[
+ PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentWrite,
+ PipelineStageAccess::LateFragmentTests_DepthStencilAttachmentWrite,
+ ],
+ };
+
+ let image = image_view.image();
+ let image_inner = image.inner();
+ let mut subresource_range = ImageSubresourceRange {
+ aspects: ImageAspects::DEPTH,
+ ..image_view.subresource_range().clone()
+ };
+ subresource_range.array_layers.start += image_inner.first_layer;
+ subresource_range.array_layers.end += image_inner.first_layer;
+ subresource_range.mip_levels.start += image_inner.first_mipmap_level;
+ subresource_range.mip_levels.end += image_inner.first_mipmap_level;
+
+ let use_ref = ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::DepthStencilAttachment,
+ secondary_use_ref: None,
+ };
+
+ for &access in accesses {
+ resources_usage_state.record_image_access(
+ &use_ref,
+ image_inner.image,
+ subresource_range.clone(),
+ access,
+ image_layout,
+ );
+ }
+ }
+
+ if let Some(attachment_info) = attachments.stencil_attachment.as_ref() {
+ let &RenderPassStateAttachmentInfo {
+ ref image_view,
+ image_layout,
+ ..
+ } = attachment_info;
+
+ // TODO: check `pipeline.depth_stencil_state` for whether the attachment is going to be
+ // read and/or written.
+ let accesses: &'static [PipelineStageAccess] =
+ match pipeline.fragment_tests_stages().unwrap() {
+ FragmentTestsStages::Early => {
+ &[PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentWrite]
+ }
+ FragmentTestsStages::Late => {
+ &[PipelineStageAccess::LateFragmentTests_DepthStencilAttachmentWrite]
+ }
+ FragmentTestsStages::EarlyAndLate => &[
+ PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentWrite,
+ PipelineStageAccess::LateFragmentTests_DepthStencilAttachmentWrite,
+ ],
+ };
+
+ let image = image_view.image();
+ let image_inner = image.inner();
+ let mut subresource_range = ImageSubresourceRange {
+ aspects: ImageAspects::STENCIL,
+ ..image_view.subresource_range().clone()
+ };
+ subresource_range.array_layers.start += image_inner.first_layer;
+ subresource_range.array_layers.end += image_inner.first_layer;
+ subresource_range.mip_levels.start += image_inner.first_mipmap_level;
+ subresource_range.mip_levels.end += image_inner.first_mipmap_level;
+
+ let use_ref = ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::DepthStencilAttachment,
+ secondary_use_ref: None,
+ };
+
+ for &access in accesses {
+ resources_usage_state.record_image_access(
+ &use_ref,
+ image_inner.image,
+ subresource_range.clone(),
+ access,
+ image_layout,
+ );
+ }
+ }
+
+ for (index, attachment_info) in (attachments.color_attachments.iter().enumerate())
+ .filter_map(|(i, a)| a.as_ref().map(|a| (i as u32, a)))
+ {
+ let &RenderPassStateAttachmentInfo {
+ ref image_view,
+ image_layout,
+ ..
+ } = attachment_info;
+
+ let image = image_view.image();
+ let image_inner = image.inner();
+ let mut subresource_range = image_view.subresource_range().clone();
+ subresource_range.array_layers.start += image_inner.first_layer;
+ subresource_range.array_layers.end += image_inner.first_layer;
+ subresource_range.mip_levels.start += image_inner.first_mipmap_level;
+ subresource_range.mip_levels.end += image_inner.first_mipmap_level;
+
+ let use_ref = ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::ColorAttachment { index },
+ secondary_use_ref: None,
+ };
+
+ // TODO: process only the color attachment indices that the fragment shader actually
+ // writes to.
+ // TODO: is it possible to only read a color attachment but not write it?
+ resources_usage_state.record_image_access(
+ &use_ref,
+ image_inner.image,
+ subresource_range,
+ PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentWrite,
+ image_layout,
+ );
+ }
+}
diff --git a/src/command_buffer/standard/builder/query.rs b/src/command_buffer/standard/builder/query.rs
new file mode 100644
index 0000000..608f9bb
--- /dev/null
+++ b/src/command_buffer/standard/builder/query.rs
@@ -0,0 +1,752 @@
+// Copyright (c) 2022 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use super::{CommandBufferBuilder, QueryError, QueryState};
+use crate::{
+ buffer::{BufferUsage, Subbuffer},
+ command_buffer::{allocator::CommandBufferAllocator, ResourceInCommand, ResourceUseRef},
+ device::{DeviceOwned, QueueFlags},
+ query::{QueryControlFlags, QueryPool, QueryResultElement, QueryResultFlags, QueryType},
+ sync::{PipelineStage, PipelineStageAccess, PipelineStages},
+ DeviceSize, RequiresOneOf, Version, VulkanObject,
+};
+use std::{ops::Range, sync::Arc};
+
+impl<L, A> CommandBufferBuilder<L, A>
+where
+ A: CommandBufferAllocator,
+{
+ /// Begins a query.
+ ///
+ /// The query will be active until [`end_query`] is called for the same query.
+ ///
+ /// # Safety
+ ///
+ /// - The query must be unavailable, ensured by calling [`reset_query_pool`].
+ ///
+ /// [`end_query`]: Self::end_query
+ /// [`reset_query_pool`]: Self::reset_query_pool
+ #[inline]
+ pub unsafe fn begin_query(
+ &mut self,
+ query_pool: Arc<QueryPool>,
+ query: u32,
+ flags: QueryControlFlags,
+ ) -> Result<&mut Self, QueryError> {
+ self.validate_begin_query(&query_pool, query, flags)?;
+
+ Ok(self.begin_query_unchecked(query_pool, query, flags))
+ }
+
+ fn validate_begin_query(
+ &self,
+ query_pool: &QueryPool,
+ query: u32,
+ flags: QueryControlFlags,
+ ) -> Result<(), QueryError> {
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdBeginQuery-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(QueryError::NotSupportedByQueueFamily);
+ }
+
+ let device = self.device();
+
+ // VUID-vkCmdBeginQuery-flags-parameter
+ flags.validate_device(device)?;
+
+ // VUID-vkCmdBeginQuery-commonparent
+ assert_eq!(device, query_pool.device());
+
+ // VUID-vkCmdBeginQuery-query-00802
+ query_pool.query(query).ok_or(QueryError::OutOfRange)?;
+
+ match query_pool.query_type() {
+ QueryType::Occlusion => {
+ // VUID-vkCmdBeginQuery-commandBuffer-cmdpool
+ // // VUID-vkCmdBeginQuery-queryType-00803
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(QueryError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdBeginQuery-queryType-00800
+ if flags.intersects(QueryControlFlags::PRECISE)
+ && !device.enabled_features().occlusion_query_precise
+ {
+ return Err(QueryError::RequirementNotMet {
+ required_for: "`flags` contains `QueryControlFlags::PRECISE`",
+ requires_one_of: RequiresOneOf {
+ features: &["occlusion_query_precise"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ QueryType::PipelineStatistics(statistic_flags) => {
+ // VUID-vkCmdBeginQuery-commandBuffer-cmdpool
+ // VUID-vkCmdBeginQuery-queryType-00804
+ // VUID-vkCmdBeginQuery-queryType-00805
+ if statistic_flags.is_compute()
+ && !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::COMPUTE)
+ || statistic_flags.is_graphics()
+ && !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(QueryError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdBeginQuery-queryType-00800
+ if flags.intersects(QueryControlFlags::PRECISE) {
+ return Err(QueryError::InvalidFlags);
+ }
+ }
+ // VUID-vkCmdBeginQuery-queryType-02804
+ QueryType::Timestamp => return Err(QueryError::NotPermitted),
+ }
+
+ // VUID-vkCmdBeginQuery-queryPool-01922
+ if self
+ .builder_state
+ .queries
+ .contains_key(&query_pool.query_type().into())
+ {
+ return Err(QueryError::QueryIsActive);
+ }
+
+ if let Some(render_pass_state) = &self.builder_state.render_pass {
+ // VUID-vkCmdBeginQuery-query-00808
+ if query + render_pass_state.rendering_info.view_mask.count_ones()
+ > query_pool.query_count()
+ {
+ return Err(QueryError::OutOfRangeMultiview);
+ }
+ }
+
+ // VUID-vkCmdBeginQuery-None-00807
+ // Not checked, therefore unsafe.
+ // TODO: add check.
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn begin_query_unchecked(
+ &mut self,
+ query_pool: Arc<QueryPool>,
+ query: u32,
+ flags: QueryControlFlags,
+ ) -> &mut Self {
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_begin_query)(self.handle(), query_pool.handle(), query, flags.into());
+
+ let ty = query_pool.query_type();
+ self.builder_state.queries.insert(
+ ty.into(),
+ QueryState {
+ query_pool: query_pool.handle(),
+ query,
+ ty,
+ flags,
+ in_subpass: self.builder_state.render_pass.is_some(),
+ },
+ );
+
+ self.resources.push(Box::new(query_pool));
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Ends an active query.
+ #[inline]
+ pub fn end_query(
+ &mut self,
+ query_pool: Arc<QueryPool>,
+ query: u32,
+ ) -> Result<&mut Self, QueryError> {
+ self.validate_end_query(&query_pool, query)?;
+
+ unsafe { Ok(self.end_query_unchecked(query_pool, query)) }
+ }
+
+ fn validate_end_query(&self, query_pool: &QueryPool, query: u32) -> Result<(), QueryError> {
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdEndQuery-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(QueryError::NotSupportedByQueueFamily);
+ }
+
+ let device = self.device();
+
+ // VUID-vkCmdEndQuery-commonparent
+ assert_eq!(device, query_pool.device());
+
+ // VUID-vkCmdEndQuery-None-01923
+ if !self
+ .builder_state
+ .queries
+ .get(&query_pool.query_type().into())
+ .map_or(false, |state| {
+ state.query_pool == query_pool.handle() && state.query == query
+ })
+ {
+ return Err(QueryError::QueryNotActive);
+ }
+
+ // VUID-vkCmdEndQuery-query-00810
+ query_pool.query(query).ok_or(QueryError::OutOfRange)?;
+
+ if let Some(render_pass_state) = &self.builder_state.render_pass {
+ // VUID-vkCmdEndQuery-query-00812
+ if query + render_pass_state.rendering_info.view_mask.count_ones()
+ > query_pool.query_count()
+ {
+ return Err(QueryError::OutOfRangeMultiview);
+ }
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn end_query_unchecked(
+ &mut self,
+ query_pool: Arc<QueryPool>,
+ query: u32,
+ ) -> &mut Self {
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_end_query)(self.handle(), query_pool.handle(), query);
+
+ self.builder_state
+ .queries
+ .remove(&query_pool.query_type().into());
+
+ self.resources.push(Box::new(query_pool));
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Writes a timestamp to a timestamp query.
+ ///
+ /// # Safety
+ ///
+ /// - The query must be unavailable, ensured by calling [`reset_query_pool`].
+ ///
+ /// [`reset_query_pool`]: Self::reset_query_pool
+ pub unsafe fn write_timestamp(
+ &mut self,
+ query_pool: Arc<QueryPool>,
+ query: u32,
+ stage: PipelineStage,
+ ) -> Result<&mut Self, QueryError> {
+ self.validate_write_timestamp(&query_pool, query, stage)?;
+
+ Ok(self.write_timestamp_unchecked(query_pool, query, stage))
+ }
+
+ fn validate_write_timestamp(
+ &self,
+ query_pool: &QueryPool,
+ query: u32,
+ stage: PipelineStage,
+ ) -> Result<(), QueryError> {
+ let device = self.device();
+
+ if !device.enabled_features().synchronization2 && PipelineStages::from(stage).is_2() {
+ return Err(QueryError::RequirementNotMet {
+ required_for: "`stage` has flags set from `VkPipelineStageFlagBits2`",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdWriteTimestamp2-stage-parameter
+ stage.validate_device(device)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdWriteTimestamp2-commandBuffer-cmdpool
+ if !queue_family_properties.queue_flags.intersects(
+ QueueFlags::TRANSFER
+ | QueueFlags::GRAPHICS
+ | QueueFlags::COMPUTE
+ | QueueFlags::VIDEO_DECODE
+ | QueueFlags::VIDEO_ENCODE,
+ ) {
+ return Err(QueryError::NotSupportedByQueueFamily);
+ }
+
+ let device = self.device();
+
+ // VUID-vkCmdWriteTimestamp2-commonparent
+ assert_eq!(device, query_pool.device());
+
+ // VUID-vkCmdWriteTimestamp2-stage-03860
+ if !PipelineStages::from(queue_family_properties.queue_flags).contains_enum(stage) {
+ return Err(QueryError::StageNotSupported);
+ }
+
+ match stage {
+ PipelineStage::GeometryShader => {
+ // VUID-vkCmdWriteTimestamp2-stage-03929
+ if !device.enabled_features().geometry_shader {
+ return Err(QueryError::RequirementNotMet {
+ required_for: "`stage` is `PipelineStage::GeometryShader`",
+ requires_one_of: RequiresOneOf {
+ features: &["geometry_shadere"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ PipelineStage::TessellationControlShader
+ | PipelineStage::TessellationEvaluationShader => {
+ // VUID-vkCmdWriteTimestamp2-stage-03930
+ if !device.enabled_features().tessellation_shader {
+ return Err(QueryError::RequirementNotMet {
+ required_for: "`stage` is `PipelineStage::TessellationControlShader` or \
+ `PipelineStage::TessellationEvaluationShader`",
+ requires_one_of: RequiresOneOf {
+ features: &["tessellation_shader"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ PipelineStage::ConditionalRendering => {
+ // VUID-vkCmdWriteTimestamp2-stage-03931
+ if !device.enabled_features().conditional_rendering {
+ return Err(QueryError::RequirementNotMet {
+ required_for: "`stage` is `PipelineStage::ConditionalRendering`",
+ requires_one_of: RequiresOneOf {
+ features: &["conditional_rendering"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ PipelineStage::FragmentDensityProcess => {
+ // VUID-vkCmdWriteTimestamp2-stage-03932
+ if !device.enabled_features().fragment_density_map {
+ return Err(QueryError::RequirementNotMet {
+ required_for: "`stage` is `PipelineStage::FragmentDensityProcess`",
+ requires_one_of: RequiresOneOf {
+ features: &["fragment_density_map"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ PipelineStage::TransformFeedback => {
+ // VUID-vkCmdWriteTimestamp2-stage-03933
+ if !device.enabled_features().transform_feedback {
+ return Err(QueryError::RequirementNotMet {
+ required_for: "`stage` is `PipelineStage::TransformFeedback`",
+ requires_one_of: RequiresOneOf {
+ features: &["transform_feedback"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ PipelineStage::MeshShader => {
+ // VUID-vkCmdWriteTimestamp2-stage-03934
+ if !device.enabled_features().mesh_shader {
+ return Err(QueryError::RequirementNotMet {
+ required_for: "`stage` is `PipelineStage::MeshShader`",
+ requires_one_of: RequiresOneOf {
+ features: &["mesh_shader"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ PipelineStage::TaskShader => {
+ // VUID-vkCmdWriteTimestamp2-stage-03935
+ if !device.enabled_features().task_shader {
+ return Err(QueryError::RequirementNotMet {
+ required_for: "`stage` is `PipelineStage::TaskShader`",
+ requires_one_of: RequiresOneOf {
+ features: &["task_shader"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ PipelineStage::FragmentShadingRateAttachment => {
+ // VUID-vkCmdWriteTimestamp2-shadingRateImage-07316
+ if !(device.enabled_features().attachment_fragment_shading_rate
+ || device.enabled_features().shading_rate_image)
+ {
+ return Err(QueryError::RequirementNotMet {
+ required_for: "`stage` is `PipelineStage::FragmentShadingRateAttachment`",
+ requires_one_of: RequiresOneOf {
+ features: &["attachment_fragment_shading_rate", "shading_rate_image"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ PipelineStage::SubpassShading => {
+ // VUID-vkCmdWriteTimestamp2-stage-04957
+ if !device.enabled_features().subpass_shading {
+ return Err(QueryError::RequirementNotMet {
+ required_for: "`stage` is `PipelineStage::SubpassShading`",
+ requires_one_of: RequiresOneOf {
+ features: &["subpass_shading"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ PipelineStage::InvocationMask => {
+ // VUID-vkCmdWriteTimestamp2-stage-04995
+ if !device.enabled_features().invocation_mask {
+ return Err(QueryError::RequirementNotMet {
+ required_for: "`stage` is `PipelineStage::InvocationMask`",
+ requires_one_of: RequiresOneOf {
+ features: &["invocation_mask"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ _ => (),
+ }
+
+ // VUID-vkCmdWriteTimestamp2-queryPool-03861
+ if !matches!(query_pool.query_type(), QueryType::Timestamp) {
+ return Err(QueryError::NotPermitted);
+ }
+
+ // VUID-vkCmdWriteTimestamp2-timestampValidBits-03863
+ if queue_family_properties.timestamp_valid_bits.is_none() {
+ return Err(QueryError::NoTimestampValidBits);
+ }
+
+ // VUID-vkCmdWriteTimestamp2-query-04903
+ query_pool.query(query).ok_or(QueryError::OutOfRange)?;
+
+ if let Some(render_pass_state) = &self.builder_state.render_pass {
+ // VUID-vkCmdWriteTimestamp2-query-03865
+ if query + render_pass_state.rendering_info.view_mask.count_ones()
+ > query_pool.query_count()
+ {
+ return Err(QueryError::OutOfRangeMultiview);
+ }
+ }
+
+ // VUID-vkCmdWriteTimestamp2-queryPool-03862
+ // VUID-vkCmdWriteTimestamp2-None-03864
+ // Not checked, therefore unsafe.
+ // TODO: add check.
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn write_timestamp_unchecked(
+ &mut self,
+ query_pool: Arc<QueryPool>,
+ query: u32,
+ stage: PipelineStage,
+ ) -> &mut Self {
+ let fns = self.device().fns();
+
+ if self.device().enabled_features().synchronization2 {
+ if self.device().api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_write_timestamp2)(
+ self.handle(),
+ stage.into(),
+ query_pool.handle(),
+ query,
+ );
+ } else {
+ debug_assert!(self.device().enabled_extensions().khr_synchronization2);
+ (fns.khr_synchronization2.cmd_write_timestamp2_khr)(
+ self.handle(),
+ stage.into(),
+ query_pool.handle(),
+ query,
+ );
+ }
+ } else {
+ (fns.v1_0.cmd_write_timestamp)(self.handle(), stage.into(), query_pool.handle(), query);
+ }
+
+ self.resources.push(Box::new(query_pool));
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Copies the results of a range of queries to a buffer on the GPU.
+ ///
+ /// [`query_pool.ty().result_len()`] elements will be written for each query in the range, plus
+ /// 1 extra element per query if [`QueryResultFlags::WITH_AVAILABILITY`] is enabled.
+ /// The provided buffer must be large enough to hold the data.
+ ///
+ /// See also [`get_results`].
+ ///
+ /// # Safety
+ ///
+ /// - Appropriate synchronization must be provided for all buffers
+ /// that are accessed by the command.
+ ///
+ /// [`query_pool.ty().result_len()`]: crate::query::QueryType::result_len
+ /// [`QueryResultFlags::WITH_AVAILABILITY`]: crate::query::QueryResultFlags::WITH_AVAILABILITY
+ /// [`get_results`]: crate::query::QueriesRange::get_results
+ pub unsafe fn copy_query_pool_results<T>(
+ &mut self,
+ query_pool: Arc<QueryPool>,
+ queries: Range<u32>,
+ dst_buffer: Subbuffer<[T]>,
+ flags: QueryResultFlags,
+ ) -> Result<&mut Self, QueryError>
+ where
+ T: QueryResultElement,
+ {
+ self.validate_copy_query_pool_results(
+ &query_pool,
+ queries.clone(),
+ dst_buffer.as_bytes(),
+ std::mem::size_of::<T>() as DeviceSize,
+ flags,
+ )?;
+
+ unsafe {
+ let per_query_len = query_pool.query_type().result_len()
+ + flags.intersects(QueryResultFlags::WITH_AVAILABILITY) as DeviceSize;
+ let stride = per_query_len * std::mem::size_of::<T>() as DeviceSize;
+ Ok(self
+ .copy_query_pool_results_unchecked(query_pool, queries, dst_buffer, stride, flags))
+ }
+ }
+
+ fn validate_copy_query_pool_results(
+ &self,
+ query_pool: &QueryPool,
+ queries: Range<u32>,
+ dst_buffer: &Subbuffer<[u8]>,
+ element_size: DeviceSize,
+ flags: QueryResultFlags,
+ ) -> Result<(), QueryError> {
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdCopyQueryPoolResults-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(QueryError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdCopyQueryPoolResults-renderpass
+ if self.builder_state.render_pass.is_some() {
+ return Err(QueryError::ForbiddenInsideRenderPass);
+ }
+
+ let device = self.device();
+
+ // VUID-vkCmdCopyQueryPoolResults-commonparent
+ assert_eq!(device, dst_buffer.buffer().device());
+ assert_eq!(device, query_pool.device());
+
+ assert!(dst_buffer.len() > 0);
+
+ // VUID-vkCmdCopyQueryPoolResults-flags-00822
+ // VUID-vkCmdCopyQueryPoolResults-flags-00823
+ debug_assert!(dst_buffer.offset() % element_size == 0);
+
+ // VUID-vkCmdCopyQueryPoolResults-firstQuery-00820
+ // VUID-vkCmdCopyQueryPoolResults-firstQuery-00821
+ query_pool
+ .queries_range(queries.clone())
+ .ok_or(QueryError::OutOfRange)?;
+
+ let count = queries.end - queries.start;
+ let per_query_len = query_pool.query_type().result_len()
+ + flags.intersects(QueryResultFlags::WITH_AVAILABILITY) as DeviceSize;
+ let required_len = per_query_len * count as DeviceSize;
+
+ // VUID-vkCmdCopyQueryPoolResults-dstBuffer-00824
+ if dst_buffer.len() < required_len {
+ return Err(QueryError::BufferTooSmall {
+ required_len,
+ actual_len: dst_buffer.len(),
+ });
+ }
+
+ // VUID-vkCmdCopyQueryPoolResults-dstBuffer-00825
+ if !dst_buffer
+ .buffer()
+ .usage()
+ .intersects(BufferUsage::TRANSFER_DST)
+ {
+ return Err(QueryError::DestinationMissingUsage);
+ }
+
+ // VUID-vkCmdCopyQueryPoolResults-queryType-00827
+ if matches!(query_pool.query_type(), QueryType::Timestamp)
+ && flags.intersects(QueryResultFlags::PARTIAL)
+ {
+ return Err(QueryError::InvalidFlags);
+ }
+
+ // TODO: sync check
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn copy_query_pool_results_unchecked<T>(
+ &mut self,
+ query_pool: Arc<QueryPool>,
+ queries: Range<u32>,
+ dst_buffer: Subbuffer<[T]>,
+ stride: DeviceSize,
+ flags: QueryResultFlags,
+ ) -> &mut Self
+ where
+ T: QueryResultElement,
+ {
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_copy_query_pool_results)(
+ self.handle(),
+ query_pool.handle(),
+ queries.start,
+ queries.end - queries.start,
+ dst_buffer.buffer().handle(),
+ dst_buffer.offset(),
+ stride,
+ ash::vk::QueryResultFlags::from(flags) | T::FLAG,
+ );
+
+ let command_index = self.next_command_index;
+ let command_name = "copy_query_pool_results";
+ let use_ref = ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: ResourceInCommand::Destination,
+ secondary_use_ref: None,
+ };
+
+ self.resources_usage_state.record_buffer_access(
+ &use_ref,
+ dst_buffer.buffer(),
+ dst_buffer.range(),
+ PipelineStageAccess::Copy_TransferWrite,
+ );
+
+ self.resources.push(Box::new(query_pool));
+ self.resources.push(Box::new(dst_buffer));
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Resets a range of queries on a query pool.
+ ///
+ /// The affected queries will be marked as "unavailable" after this command runs, and will no
+ /// longer return any results. They will be ready to have new results recorded for them.
+ ///
+ /// # Safety
+ /// The queries in the specified range must not be active in another command buffer.
+ // TODO: Do other command buffers actually matter here? Not sure on the Vulkan spec.
+ pub unsafe fn reset_query_pool(
+ &mut self,
+ query_pool: Arc<QueryPool>,
+ queries: Range<u32>,
+ ) -> Result<&mut Self, QueryError> {
+ self.validate_reset_query_pool(&query_pool, queries.clone())?;
+
+ Ok(self.reset_query_pool_unchecked(query_pool, queries))
+ }
+
+ fn validate_reset_query_pool(
+ &self,
+ query_pool: &QueryPool,
+ queries: Range<u32>,
+ ) -> Result<(), QueryError> {
+ // VUID-vkCmdResetQueryPool-renderpass
+ if self.builder_state.render_pass.is_some() {
+ return Err(QueryError::ForbiddenInsideRenderPass);
+ }
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdResetQueryPool-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(QueryError::NotSupportedByQueueFamily);
+ }
+
+ let device = self.device();
+
+ // VUID-vkCmdResetQueryPool-commonparent
+ assert_eq!(device, query_pool.device());
+
+ // VUID-vkCmdResetQueryPool-firstQuery-00796
+ // VUID-vkCmdResetQueryPool-firstQuery-00797
+ query_pool
+ .queries_range(queries.clone())
+ .ok_or(QueryError::OutOfRange)?;
+
+ // VUID-vkCmdResetQueryPool-None-02841
+ if self
+ .builder_state
+ .queries
+ .values()
+ .any(|state| state.query_pool == query_pool.handle() && queries.contains(&state.query))
+ {
+ return Err(QueryError::QueryIsActive);
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn reset_query_pool_unchecked(
+ &mut self,
+ query_pool: Arc<QueryPool>,
+ queries: Range<u32>,
+ ) -> &mut Self {
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_reset_query_pool)(
+ self.handle(),
+ query_pool.handle(),
+ queries.start,
+ queries.end - queries.start,
+ );
+
+ self.resources.push(Box::new(query_pool));
+
+ self.next_command_index += 1;
+ self
+ }
+}
diff --git a/src/command_buffer/standard/builder/render_pass.rs b/src/command_buffer/standard/builder/render_pass.rs
new file mode 100644
index 0000000..d3182ef
--- /dev/null
+++ b/src/command_buffer/standard/builder/render_pass.rs
@@ -0,0 +1,2248 @@
+// Copyright (c) 2022 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use super::{
+ BeginRenderPassState, BeginRenderingState, ClearAttachment, ClearRect, CommandBufferBuilder,
+ RenderPassBeginInfo, RenderPassError, RenderPassState, RenderPassStateAttachmentInfo,
+ RenderPassStateAttachmentResolveInfo, RenderPassStateAttachments, RenderPassStateType,
+ RenderingAttachmentInfo, RenderingAttachmentResolveInfo, RenderingInfo, ResourcesState,
+};
+use crate::{
+ command_buffer::{
+ allocator::CommandBufferAllocator, PrimaryCommandBuffer, ResourceInCommand, ResourceUseRef,
+ SubpassContents,
+ },
+ device::{DeviceOwned, QueueFlags},
+ format::{ClearColorValue, ClearValue, NumericType},
+ image::{ImageAspects, ImageLayout, ImageUsage, SampleCount},
+ pipeline::graphics::render_pass::PipelineRenderingCreateInfo,
+ render_pass::{AttachmentDescription, LoadOp, ResolveMode, SubpassDescription},
+ sync::PipelineStageAccess,
+ RequiresOneOf, Version, VulkanObject,
+};
+use smallvec::SmallVec;
+use std::cmp::min;
+
+impl<A> CommandBufferBuilder<PrimaryCommandBuffer<A::Alloc>, A>
+where
+ A: CommandBufferAllocator,
+{
+ /// Begins a render pass using a render pass object and framebuffer.
+ ///
+ /// You must call this or `begin_rendering` before you can record draw commands.
+ ///
+ /// `contents` specifies what kinds of commands will be recorded in the render pass, either
+ /// draw commands or executions of secondary command buffers.
+ ///
+ /// # Safety
+ ///
+ /// - Appropriate synchronization must be provided for all images
+ /// that are accessed by the command.
+ /// - All images that are accessed by the command must be in the expected image layout.
+ #[inline]
+ pub unsafe fn begin_render_pass(
+ &mut self,
+ render_pass_begin_info: RenderPassBeginInfo,
+ contents: SubpassContents,
+ ) -> Result<&mut Self, RenderPassError> {
+ self.validate_begin_render_pass(&render_pass_begin_info, contents)?;
+
+ unsafe { Ok(self.begin_render_pass_unchecked(render_pass_begin_info, contents)) }
+ }
+
+ fn validate_begin_render_pass(
+ &self,
+ render_pass_begin_info: &RenderPassBeginInfo,
+ contents: SubpassContents,
+ ) -> Result<(), RenderPassError> {
+ let device = self.device();
+
+ // VUID-VkSubpassBeginInfo-contents-parameter
+ contents.validate_device(device)?;
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdBeginRenderPass2-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(RenderPassError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdBeginRenderPass2-renderpass
+ if self.builder_state.render_pass.is_some() {
+ return Err(RenderPassError::ForbiddenInsideRenderPass);
+ }
+
+ let RenderPassBeginInfo {
+ render_pass,
+ framebuffer,
+ render_area_offset,
+ render_area_extent,
+ clear_values,
+ _ne: _,
+ } = render_pass_begin_info;
+
+ // VUID-VkRenderPassBeginInfo-commonparent
+ // VUID-vkCmdBeginRenderPass2-framebuffer-02779
+ assert_eq!(device, framebuffer.device());
+
+ // VUID-VkRenderPassBeginInfo-renderPass-00904
+ if !render_pass.is_compatible_with(framebuffer.render_pass()) {
+ return Err(RenderPassError::FramebufferNotCompatible);
+ }
+
+ for i in 0..2 {
+ // VUID-VkRenderPassBeginInfo-pNext-02852
+ // VUID-VkRenderPassBeginInfo-pNext-02853
+ if render_area_offset[i] + render_area_extent[i] > framebuffer.extent()[i] {
+ return Err(RenderPassError::RenderAreaOutOfBounds);
+ }
+ }
+
+ for (attachment_index, (attachment_desc, image_view)) in render_pass
+ .attachments()
+ .iter()
+ .zip(framebuffer.attachments())
+ .enumerate()
+ {
+ let attachment_index = attachment_index as u32;
+ let &AttachmentDescription {
+ initial_layout,
+ final_layout,
+ ..
+ } = attachment_desc;
+
+ for layout in [initial_layout, final_layout] {
+ match layout {
+ ImageLayout::ColorAttachmentOptimal => {
+ // VUID-vkCmdBeginRenderPass2-initialLayout-03094
+ if !image_view.usage().intersects(ImageUsage::COLOR_ATTACHMENT) {
+ return Err(RenderPassError::AttachmentImageMissingUsage {
+ attachment_index,
+ usage: "color_attachment",
+ });
+ }
+ }
+ ImageLayout::DepthReadOnlyStencilAttachmentOptimal
+ | ImageLayout::DepthAttachmentStencilReadOnlyOptimal
+ | ImageLayout::DepthStencilAttachmentOptimal
+ | ImageLayout::DepthStencilReadOnlyOptimal => {
+ // VUID-vkCmdBeginRenderPass2-initialLayout-03096
+ if !image_view
+ .usage()
+ .intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT)
+ {
+ return Err(RenderPassError::AttachmentImageMissingUsage {
+ attachment_index,
+ usage: "depth_stencil_attachment",
+ });
+ }
+ }
+ ImageLayout::ShaderReadOnlyOptimal => {
+ // VUID-vkCmdBeginRenderPass2-initialLayout-03097
+ if !image_view
+ .usage()
+ .intersects(ImageUsage::SAMPLED | ImageUsage::INPUT_ATTACHMENT)
+ {
+ return Err(RenderPassError::AttachmentImageMissingUsage {
+ attachment_index,
+ usage: "sampled or input_attachment",
+ });
+ }
+ }
+ ImageLayout::TransferSrcOptimal => {
+ // VUID-vkCmdBeginRenderPass2-initialLayout-03098
+ if !image_view.usage().intersects(ImageUsage::TRANSFER_SRC) {
+ return Err(RenderPassError::AttachmentImageMissingUsage {
+ attachment_index,
+ usage: "transfer_src",
+ });
+ }
+ }
+ ImageLayout::TransferDstOptimal => {
+ // VUID-vkCmdBeginRenderPass2-initialLayout-03099
+ if !image_view.usage().intersects(ImageUsage::TRANSFER_DST) {
+ return Err(RenderPassError::AttachmentImageMissingUsage {
+ attachment_index,
+ usage: "transfer_dst",
+ });
+ }
+ }
+ _ => (),
+ }
+ }
+ }
+
+ for subpass_desc in render_pass.subpasses() {
+ let SubpassDescription {
+ view_mask: _,
+ input_attachments,
+ color_attachments,
+ resolve_attachments,
+ depth_stencil_attachment,
+ preserve_attachments: _,
+ _ne: _,
+ } = subpass_desc;
+
+ for atch_ref in (input_attachments.iter())
+ .chain(color_attachments)
+ .chain(resolve_attachments)
+ .chain([depth_stencil_attachment])
+ .flatten()
+ {
+ let image_view = &framebuffer.attachments()[atch_ref.attachment as usize];
+
+ match atch_ref.layout {
+ ImageLayout::ColorAttachmentOptimal => {
+ // VUID-vkCmdBeginRenderPass2-initialLayout-03094
+ if !image_view.usage().intersects(ImageUsage::COLOR_ATTACHMENT) {
+ return Err(RenderPassError::AttachmentImageMissingUsage {
+ attachment_index: atch_ref.attachment,
+ usage: "color_attachment",
+ });
+ }
+ }
+ ImageLayout::DepthReadOnlyStencilAttachmentOptimal
+ | ImageLayout::DepthAttachmentStencilReadOnlyOptimal
+ | ImageLayout::DepthStencilAttachmentOptimal
+ | ImageLayout::DepthStencilReadOnlyOptimal => {
+ // VUID-vkCmdBeginRenderPass2-initialLayout-03096
+ if !image_view
+ .usage()
+ .intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT)
+ {
+ return Err(RenderPassError::AttachmentImageMissingUsage {
+ attachment_index: atch_ref.attachment,
+ usage: "depth_stencil_attachment",
+ });
+ }
+ }
+ ImageLayout::ShaderReadOnlyOptimal => {
+ // VUID-vkCmdBeginRenderPass2-initialLayout-03097
+ if !image_view
+ .usage()
+ .intersects(ImageUsage::SAMPLED | ImageUsage::INPUT_ATTACHMENT)
+ {
+ return Err(RenderPassError::AttachmentImageMissingUsage {
+ attachment_index: atch_ref.attachment,
+ usage: "sampled or input_attachment",
+ });
+ }
+ }
+ ImageLayout::TransferSrcOptimal => {
+ // VUID-vkCmdBeginRenderPass2-initialLayout-03098
+ if !image_view.usage().intersects(ImageUsage::TRANSFER_SRC) {
+ return Err(RenderPassError::AttachmentImageMissingUsage {
+ attachment_index: atch_ref.attachment,
+ usage: "transfer_src",
+ });
+ }
+ }
+ ImageLayout::TransferDstOptimal => {
+ // VUID-vkCmdBeginRenderPass2-initialLayout-03099
+ if !image_view.usage().intersects(ImageUsage::TRANSFER_DST) {
+ return Err(RenderPassError::AttachmentImageMissingUsage {
+ attachment_index: atch_ref.attachment,
+ usage: "transfer_dst",
+ });
+ }
+ }
+ _ => (),
+ }
+ }
+ }
+
+ // VUID-VkRenderPassBeginInfo-clearValueCount-00902
+ if clear_values.len() < render_pass.attachments().len() {
+ return Err(RenderPassError::ClearValueMissing {
+ attachment_index: clear_values.len() as u32,
+ });
+ }
+
+ // VUID-VkRenderPassBeginInfo-clearValueCount-04962
+ for (attachment_index, (attachment_desc, &clear_value)) in render_pass
+ .attachments()
+ .iter()
+ .zip(clear_values)
+ .enumerate()
+ {
+ let attachment_index = attachment_index as u32;
+ let attachment_format = attachment_desc.format.unwrap();
+
+ if attachment_desc.load_op == LoadOp::Clear
+ || attachment_desc.stencil_load_op == LoadOp::Clear
+ {
+ let clear_value = match clear_value {
+ Some(x) => x,
+ None => return Err(RenderPassError::ClearValueMissing { attachment_index }),
+ };
+
+ if let (Some(numeric_type), LoadOp::Clear) =
+ (attachment_format.type_color(), attachment_desc.load_op)
+ {
+ match numeric_type {
+ NumericType::SFLOAT
+ | NumericType::UFLOAT
+ | NumericType::SNORM
+ | NumericType::UNORM
+ | NumericType::SSCALED
+ | NumericType::USCALED
+ | NumericType::SRGB => {
+ if !matches!(clear_value, ClearValue::Float(_)) {
+ return Err(RenderPassError::ClearValueNotCompatible {
+ clear_value,
+ attachment_index,
+ attachment_format,
+ });
+ }
+ }
+ NumericType::SINT => {
+ if !matches!(clear_value, ClearValue::Int(_)) {
+ return Err(RenderPassError::ClearValueNotCompatible {
+ clear_value,
+ attachment_index,
+ attachment_format,
+ });
+ }
+ }
+ NumericType::UINT => {
+ if !matches!(clear_value, ClearValue::Uint(_)) {
+ return Err(RenderPassError::ClearValueNotCompatible {
+ clear_value,
+ attachment_index,
+ attachment_format,
+ });
+ }
+ }
+ }
+ } else {
+ let attachment_aspects = attachment_format.aspects();
+ let need_depth = attachment_aspects.intersects(ImageAspects::DEPTH)
+ && attachment_desc.load_op == LoadOp::Clear;
+ let need_stencil = attachment_aspects.intersects(ImageAspects::STENCIL)
+ && attachment_desc.stencil_load_op == LoadOp::Clear;
+
+ if need_depth && need_stencil {
+ if !matches!(clear_value, ClearValue::DepthStencil(_)) {
+ return Err(RenderPassError::ClearValueNotCompatible {
+ clear_value,
+ attachment_index,
+ attachment_format,
+ });
+ }
+ } else if need_depth {
+ if !matches!(clear_value, ClearValue::Depth(_)) {
+ return Err(RenderPassError::ClearValueNotCompatible {
+ clear_value,
+ attachment_index,
+ attachment_format,
+ });
+ }
+ } else if need_stencil {
+ if !matches!(clear_value, ClearValue::Stencil(_)) {
+ return Err(RenderPassError::ClearValueNotCompatible {
+ clear_value,
+ attachment_index,
+ attachment_format,
+ });
+ }
+ }
+ }
+ }
+ }
+
+ // VUID-vkCmdBeginRenderPass2-initialLayout-03100
+ // TODO:
+
+ // VUID-vkCmdBeginRenderPass2-srcStageMask-06453
+ // TODO:
+
+ // VUID-vkCmdBeginRenderPass2-dstStageMask-06454
+ // TODO:
+
+ // VUID-vkCmdBeginRenderPass2-framebuffer-02533
+ // For any attachment in framebuffer that is used by renderPass and is bound to memory locations that are also bound to another attachment used by renderPass, and if at least one of those uses causes either
+ // attachment to be written to, both attachments must have had the VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT set
+
+ // TODO: sync check
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn begin_render_pass_unchecked(
+ &mut self,
+ render_pass_begin_info: RenderPassBeginInfo,
+ contents: SubpassContents,
+ ) -> &mut Self {
+ let RenderPassBeginInfo {
+ render_pass,
+ framebuffer,
+ render_area_offset,
+ render_area_extent,
+ clear_values,
+ _ne: _,
+ } = render_pass_begin_info;
+
+ let clear_values_vk: SmallVec<[_; 4]> = clear_values
+ .iter()
+ .copied()
+ .map(|clear_value| clear_value.map(Into::into).unwrap_or_default())
+ .collect();
+
+ let render_pass_begin_info = ash::vk::RenderPassBeginInfo {
+ render_pass: render_pass.handle(),
+ framebuffer: framebuffer.handle(),
+ render_area: ash::vk::Rect2D {
+ offset: ash::vk::Offset2D {
+ x: render_area_offset[0] as i32,
+ y: render_area_offset[1] as i32,
+ },
+ extent: ash::vk::Extent2D {
+ width: render_area_extent[0],
+ height: render_area_extent[1],
+ },
+ },
+ clear_value_count: clear_values_vk.len() as u32,
+ p_clear_values: clear_values_vk.as_ptr(),
+ ..Default::default()
+ };
+
+ let subpass_begin_info = ash::vk::SubpassBeginInfo {
+ contents: contents.into(),
+ ..Default::default()
+ };
+
+ let fns = self.device().fns();
+
+ if self.device().api_version() >= Version::V1_2
+ || self.device().enabled_extensions().khr_create_renderpass2
+ {
+ if self.device().api_version() >= Version::V1_2 {
+ (fns.v1_2.cmd_begin_render_pass2)(
+ self.handle(),
+ &render_pass_begin_info,
+ &subpass_begin_info,
+ );
+ } else {
+ (fns.khr_create_renderpass2.cmd_begin_render_pass2_khr)(
+ self.handle(),
+ &render_pass_begin_info,
+ &subpass_begin_info,
+ );
+ }
+ } else {
+ debug_assert!(subpass_begin_info.p_next.is_null());
+
+ (fns.v1_0.cmd_begin_render_pass)(
+ self.handle(),
+ &render_pass_begin_info,
+ subpass_begin_info.contents,
+ );
+ }
+
+ let command_index = self.next_command_index;
+ let command_name = "begin_render_pass";
+
+ // Advance to first subpass
+ {
+ let subpass = render_pass.clone().first_subpass();
+ self.builder_state.render_pass = Some(RenderPassState {
+ contents,
+ render_area_offset,
+ render_area_extent,
+
+ rendering_info: PipelineRenderingCreateInfo::from_subpass(&subpass),
+ attachments: Some(RenderPassStateAttachments::from_subpass(
+ &subpass,
+ &framebuffer,
+ )),
+
+ render_pass: BeginRenderPassState {
+ subpass,
+ framebuffer: Some(framebuffer.clone()),
+ }
+ .into(),
+ });
+ }
+
+ // Start of first subpass
+ {
+ // TODO: Apply barriers and layout transitions
+
+ let render_pass_state = self.builder_state.render_pass.as_ref().unwrap();
+ record_subpass_attachments_load(
+ &mut self.resources_usage_state,
+ command_index,
+ command_name,
+ render_pass_state,
+ );
+ }
+
+ self.resources.push(Box::new(render_pass));
+ self.resources.push(Box::new(framebuffer));
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Advances to the next subpass of the render pass previously begun with `begin_render_pass`.
+ ///
+ /// # Safety
+ ///
+ /// - Appropriate synchronization must be provided for all images
+ /// that are accessed by the command.
+ /// - All images that are accessed by the command must be in the expected image layout.
+ #[inline]
+ pub unsafe fn next_subpass(
+ &mut self,
+ contents: SubpassContents,
+ ) -> Result<&mut Self, RenderPassError> {
+ self.validate_next_subpass(contents)?;
+
+ unsafe { Ok(self.next_subpass_unchecked(contents)) }
+ }
+
+ fn validate_next_subpass(&self, contents: SubpassContents) -> Result<(), RenderPassError> {
+ let device = self.device();
+
+ // VUID-VkSubpassBeginInfo-contents-parameter
+ contents.validate_device(device)?;
+
+ // VUID-vkCmdNextSubpass2-renderpass
+ let render_pass_state = self
+ .builder_state
+ .render_pass
+ .as_ref()
+ .ok_or(RenderPassError::ForbiddenOutsideRenderPass)?;
+
+ let begin_render_pass_state = match &render_pass_state.render_pass {
+ RenderPassStateType::BeginRenderPass(state) => state,
+ RenderPassStateType::BeginRendering(_) => {
+ return Err(RenderPassError::ForbiddenWithBeginRendering)
+ }
+ };
+
+ // VUID-vkCmdNextSubpass2-None-03102
+ if begin_render_pass_state.subpass.is_last_subpass() {
+ return Err(RenderPassError::NoSubpassesRemaining {
+ current_subpass: begin_render_pass_state.subpass.index(),
+ });
+ }
+
+ // VUID?
+ if self
+ .builder_state
+ .queries
+ .values()
+ .any(|state| state.in_subpass)
+ {
+ return Err(RenderPassError::QueryIsActive);
+ }
+
+ // VUID-vkCmdNextSubpass2-commandBuffer-cmdpool
+ debug_assert!(self
+ .queue_family_properties()
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS));
+
+ // VUID-vkCmdNextSubpass2-bufferlevel
+ // Ensured by the type of the impl block
+
+ // TODO: sync check
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn next_subpass_unchecked(&mut self, contents: SubpassContents) -> &mut Self {
+ let subpass_begin_info = ash::vk::SubpassBeginInfo {
+ contents: contents.into(),
+ ..Default::default()
+ };
+
+ let subpass_end_info = ash::vk::SubpassEndInfo::default();
+
+ let fns = self.device().fns();
+
+ if self.device().api_version() >= Version::V1_2
+ || self.device().enabled_extensions().khr_create_renderpass2
+ {
+ if self.device().api_version() >= Version::V1_2 {
+ (fns.v1_2.cmd_next_subpass2)(self.handle(), &subpass_begin_info, &subpass_end_info);
+ } else {
+ (fns.khr_create_renderpass2.cmd_next_subpass2_khr)(
+ self.handle(),
+ &subpass_begin_info,
+ &subpass_end_info,
+ );
+ }
+ } else {
+ (fns.v1_0.cmd_next_subpass)(self.handle(), subpass_begin_info.contents);
+ }
+
+ let command_index = self.next_command_index;
+ let command_name = "next_subpass";
+
+ // End of previous subpass
+ {
+ let render_pass_state = self.builder_state.render_pass.as_ref().unwrap();
+ record_subpass_attachments_resolve(
+ &mut self.resources_usage_state,
+ command_index,
+ command_name,
+ render_pass_state,
+ );
+ record_subpass_attachments_store(
+ &mut self.resources_usage_state,
+ command_index,
+ command_name,
+ render_pass_state,
+ );
+ }
+
+ // Advance to next subpass
+ {
+ let render_pass_state = self.builder_state.render_pass.as_mut().unwrap();
+ let begin_render_pass_state = match &mut render_pass_state.render_pass {
+ RenderPassStateType::BeginRenderPass(x) => x,
+ _ => unreachable!(),
+ };
+
+ begin_render_pass_state.subpass.next_subpass();
+ render_pass_state.contents = contents;
+ render_pass_state.rendering_info =
+ PipelineRenderingCreateInfo::from_subpass(&begin_render_pass_state.subpass);
+ render_pass_state.attachments = Some(RenderPassStateAttachments::from_subpass(
+ &begin_render_pass_state.subpass,
+ begin_render_pass_state.framebuffer.as_ref().unwrap(),
+ ));
+
+ if render_pass_state.rendering_info.view_mask != 0 {
+ // When multiview is enabled, at the beginning of each subpass, all
+ // non-render pass state is undefined.
+ self.builder_state = Default::default();
+ }
+ }
+
+ // Start of next subpass
+ {
+ // TODO: Apply barriers and layout transitions
+
+ let render_pass_state = self.builder_state.render_pass.as_ref().unwrap();
+ record_subpass_attachments_load(
+ &mut self.resources_usage_state,
+ command_index,
+ command_name,
+ render_pass_state,
+ );
+ }
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Ends the render pass previously begun with `begin_render_pass`.
+ ///
+ /// This must be called after you went through all the subpasses.
+ ///
+ /// # Safety
+ ///
+ /// - Appropriate synchronization must be provided for all images
+ /// that are accessed by the command.
+ /// - All images that are accessed by the command must be in the expected image layout.
+ #[inline]
+ pub unsafe fn end_render_pass(&mut self) -> Result<&mut Self, RenderPassError> {
+ self.validate_end_render_pass()?;
+
+ unsafe { Ok(self.end_render_pass_unchecked()) }
+ }
+
+ fn validate_end_render_pass(&self) -> Result<(), RenderPassError> {
+ // VUID-vkCmdEndRenderPass2-renderpass
+ let render_pass_state = self
+ .builder_state
+ .render_pass
+ .as_ref()
+ .ok_or(RenderPassError::ForbiddenOutsideRenderPass)?;
+
+ let begin_render_pass_state = match &render_pass_state.render_pass {
+ RenderPassStateType::BeginRenderPass(state) => state,
+ RenderPassStateType::BeginRendering(_) => {
+ return Err(RenderPassError::ForbiddenWithBeginRendering)
+ }
+ };
+
+ // VUID-vkCmdEndRenderPass2-None-03103
+ if !begin_render_pass_state.subpass.is_last_subpass() {
+ return Err(RenderPassError::SubpassesRemaining {
+ current_subpass: begin_render_pass_state.subpass.index(),
+ remaining_subpasses: begin_render_pass_state
+ .subpass
+ .render_pass()
+ .subpasses()
+ .len() as u32
+ - begin_render_pass_state.subpass.index(),
+ });
+ }
+
+ // VUID?
+ if self
+ .builder_state
+ .queries
+ .values()
+ .any(|state| state.in_subpass)
+ {
+ return Err(RenderPassError::QueryIsActive);
+ }
+
+ // VUID-vkCmdEndRenderPass2-commandBuffer-cmdpool
+ debug_assert!(self
+ .queue_family_properties()
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS));
+
+ // VUID-vkCmdEndRenderPass2-bufferlevel
+ // Ensured by the type of the impl block
+
+ // TODO: sync check
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn end_render_pass_unchecked(&mut self) -> &mut Self {
+ let subpass_end_info = ash::vk::SubpassEndInfo::default();
+
+ let fns = self.device().fns();
+
+ if self.device().api_version() >= Version::V1_2
+ || self.device().enabled_extensions().khr_create_renderpass2
+ {
+ if self.device().api_version() >= Version::V1_2 {
+ (fns.v1_2.cmd_end_render_pass2)(self.handle(), &subpass_end_info);
+ } else {
+ (fns.khr_create_renderpass2.cmd_end_render_pass2_khr)(
+ self.handle(),
+ &subpass_end_info,
+ );
+ }
+ } else {
+ (fns.v1_0.cmd_end_render_pass)(self.handle());
+ }
+
+ let command_index = self.next_command_index;
+ let command_name = "end_render_pass";
+
+ // End of last subpass
+ {
+ let render_pass_state = self.builder_state.render_pass.as_ref().unwrap();
+ record_subpass_attachments_resolve(
+ &mut self.resources_usage_state,
+ command_index,
+ command_name,
+ render_pass_state,
+ );
+ record_subpass_attachments_store(
+ &mut self.resources_usage_state,
+ command_index,
+ command_name,
+ render_pass_state,
+ );
+ }
+
+ // TODO: Apply barriers and layout transitions
+
+ self.builder_state.render_pass = None;
+
+ self.next_command_index += 1;
+ self
+ }
+}
+
+impl<L, A> CommandBufferBuilder<L, A>
+where
+ A: CommandBufferAllocator,
+{
+ /// Begins a render pass without a render pass object or framebuffer.
+ ///
+ /// You must call this or `begin_render_pass` before you can record draw commands.
+ ///
+ /// # Safety
+ ///
+ /// - Appropriate synchronization must be provided for all images
+ /// that are accessed by the command.
+ /// - All images that are accessed by the command must be in the expected image layout.
+ #[inline]
+ pub unsafe fn begin_rendering(
+ &mut self,
+ mut rendering_info: RenderingInfo,
+ ) -> Result<&mut Self, RenderPassError> {
+ rendering_info.set_extent_layers()?;
+ self.validate_begin_rendering(&rendering_info)?;
+
+ unsafe { Ok(self.begin_rendering_unchecked(rendering_info)) }
+ }
+
+ fn validate_begin_rendering(
+ &self,
+ rendering_info: &RenderingInfo,
+ ) -> Result<(), RenderPassError> {
+ let device = self.device();
+ let properties = device.physical_device().properties();
+
+ // VUID-vkCmdBeginRendering-dynamicRendering-06446
+ if !device.enabled_features().dynamic_rendering {
+ return Err(RenderPassError::RequirementNotMet {
+ required_for: "`CommandBufferBuilder::begin_rendering`",
+ requires_one_of: RequiresOneOf {
+ features: &["dynamic_rendering"],
+ ..Default::default()
+ },
+ });
+ }
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdBeginRendering-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS)
+ {
+ return Err(RenderPassError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdBeginRendering-renderpass
+ if self.builder_state.render_pass.is_some() {
+ return Err(RenderPassError::ForbiddenInsideRenderPass);
+ }
+
+ let &RenderingInfo {
+ render_area_offset,
+ render_area_extent,
+ layer_count,
+ view_mask,
+ ref color_attachments,
+ ref depth_attachment,
+ ref stencil_attachment,
+ contents,
+ _ne: _,
+ } = rendering_info;
+
+ // VUID-VkRenderingInfo-flags-parameter
+ contents.validate_device(device)?;
+
+ // VUID-vkCmdBeginRendering-commandBuffer-06068
+ if self.inheritance_info.is_some() && contents == SubpassContents::SecondaryCommandBuffers {
+ return Err(RenderPassError::ContentsForbiddenInSecondaryCommandBuffer);
+ }
+
+ // No VUID, but for sanity it makes sense to treat this the same as in framebuffers.
+ if view_mask != 0 && layer_count != 1 {
+ return Err(RenderPassError::MultiviewLayersInvalid);
+ }
+
+ // VUID-VkRenderingInfo-multiview-06127
+ if view_mask != 0 && !device.enabled_features().multiview {
+ return Err(RenderPassError::RequirementNotMet {
+ required_for: "`rendering_info.viewmask` is not `0`",
+ requires_one_of: RequiresOneOf {
+ features: &["multiview"],
+ ..Default::default()
+ },
+ });
+ }
+
+ let view_count = u32::BITS - view_mask.leading_zeros();
+
+ // VUID-VkRenderingInfo-viewMask-06128
+ if view_count > properties.max_multiview_view_count.unwrap_or(0) {
+ return Err(RenderPassError::MaxMultiviewViewCountExceeded {
+ view_count,
+ max: properties.max_multiview_view_count.unwrap_or(0),
+ });
+ }
+
+ let mut samples = None;
+
+ // VUID-VkRenderingInfo-colorAttachmentCount-06106
+ if color_attachments.len() > properties.max_color_attachments as usize {
+ return Err(RenderPassError::MaxColorAttachmentsExceeded {
+ color_attachment_count: color_attachments.len() as u32,
+ max: properties.max_color_attachments,
+ });
+ }
+
+ for (attachment_index, attachment_info) in
+ color_attachments
+ .iter()
+ .enumerate()
+ .filter_map(|(index, attachment_info)| {
+ attachment_info
+ .as_ref()
+ .map(|attachment_info| (index, attachment_info))
+ })
+ {
+ let attachment_index = attachment_index as u32;
+ let RenderingAttachmentInfo {
+ image_view,
+ image_layout,
+ resolve_info,
+ load_op,
+ store_op,
+ clear_value: _,
+ _ne: _,
+ } = attachment_info;
+
+ // VUID-VkRenderingAttachmentInfo-imageLayout-parameter
+ image_layout.validate_device(device)?;
+
+ // VUID-VkRenderingAttachmentInfo-loadOp-parameter
+ load_op.validate_device(device)?;
+
+ // VUID-VkRenderingAttachmentInfo-storeOp-parameter
+ store_op.validate_device(device)?;
+
+ // VUID-VkRenderingInfo-colorAttachmentCount-06087
+ if !image_view.usage().intersects(ImageUsage::COLOR_ATTACHMENT) {
+ return Err(RenderPassError::ColorAttachmentMissingUsage { attachment_index });
+ }
+
+ let image = image_view.image();
+ let image_extent = image.dimensions().width_height_depth();
+
+ for i in 0..2 {
+ // VUID-VkRenderingInfo-pNext-06079
+ // VUID-VkRenderingInfo-pNext-06080
+ if render_area_offset[i] + render_area_extent[i] > image_extent[i] {
+ return Err(RenderPassError::RenderAreaOutOfBounds);
+ }
+ }
+
+ // VUID-VkRenderingInfo-imageView-06070
+ match samples {
+ Some(samples) if samples == image.samples() => (),
+ Some(_) => {
+ return Err(RenderPassError::ColorAttachmentSamplesMismatch {
+ attachment_index,
+ });
+ }
+ None => samples = Some(image.samples()),
+ }
+
+ // VUID-VkRenderingAttachmentInfo-imageView-06135
+ // VUID-VkRenderingAttachmentInfo-imageView-06145
+ // VUID-VkRenderingInfo-colorAttachmentCount-06090
+ // VUID-VkRenderingInfo-colorAttachmentCount-06096
+ if matches!(
+ image_layout,
+ ImageLayout::Undefined
+ | ImageLayout::ShaderReadOnlyOptimal
+ | ImageLayout::TransferSrcOptimal
+ | ImageLayout::TransferDstOptimal
+ | ImageLayout::Preinitialized
+ | ImageLayout::PresentSrc
+ | ImageLayout::DepthStencilAttachmentOptimal
+ | ImageLayout::DepthStencilReadOnlyOptimal
+ | ImageLayout::DepthReadOnlyStencilAttachmentOptimal
+ | ImageLayout::DepthAttachmentStencilReadOnlyOptimal
+ ) {
+ return Err(RenderPassError::ColorAttachmentLayoutInvalid { attachment_index });
+ }
+
+ if let Some(resolve_info) = resolve_info {
+ let &RenderingAttachmentResolveInfo {
+ mode,
+ image_view: ref resolve_image_view,
+ image_layout: resolve_image_layout,
+ } = resolve_info;
+
+ // VUID-VkRenderingAttachmentInfo-resolveImageLayout-parameter
+ resolve_image_layout.validate_device(device)?;
+
+ // VUID-VkRenderingAttachmentInfo-resolveMode-parameter
+ mode.validate_device(device)?;
+
+ let resolve_image = resolve_image_view.image();
+
+ match image_view.format().unwrap().type_color() {
+ Some(
+ NumericType::SFLOAT
+ | NumericType::UFLOAT
+ | NumericType::SNORM
+ | NumericType::UNORM
+ | NumericType::SSCALED
+ | NumericType::USCALED
+ | NumericType::SRGB,
+ ) => {
+ // VUID-VkRenderingAttachmentInfo-imageView-06129
+ if mode != ResolveMode::Average {
+ return Err(RenderPassError::ColorAttachmentResolveModeNotSupported {
+ attachment_index,
+ });
+ }
+ }
+ Some(NumericType::SINT | NumericType::UINT) => {
+ // VUID-VkRenderingAttachmentInfo-imageView-06130
+ if mode != ResolveMode::SampleZero {
+ return Err(RenderPassError::ColorAttachmentResolveModeNotSupported {
+ attachment_index,
+ });
+ }
+ }
+ None => (),
+ }
+
+ // VUID-VkRenderingAttachmentInfo-imageView-06132
+ if image.samples() == SampleCount::Sample1 {
+ return Err(RenderPassError::ColorAttachmentWithResolveNotMultisampled {
+ attachment_index,
+ });
+ }
+
+ // VUID-VkRenderingAttachmentInfo-imageView-06133
+ if resolve_image.samples() != SampleCount::Sample1 {
+ return Err(RenderPassError::ColorAttachmentResolveMultisampled {
+ attachment_index,
+ });
+ }
+
+ // VUID-VkRenderingAttachmentInfo-imageView-06134
+ if image_view.format() != resolve_image_view.format() {
+ return Err(RenderPassError::ColorAttachmentResolveFormatMismatch {
+ attachment_index,
+ });
+ }
+
+ // VUID-VkRenderingAttachmentInfo-imageView-06136
+ // VUID-VkRenderingAttachmentInfo-imageView-06146
+ // VUID-VkRenderingInfo-colorAttachmentCount-06091
+ // VUID-VkRenderingInfo-colorAttachmentCount-06097
+ if matches!(
+ resolve_image_layout,
+ ImageLayout::Undefined
+ | ImageLayout::ShaderReadOnlyOptimal
+ | ImageLayout::TransferSrcOptimal
+ | ImageLayout::TransferDstOptimal
+ | ImageLayout::Preinitialized
+ | ImageLayout::PresentSrc
+ | ImageLayout::DepthStencilAttachmentOptimal
+ | ImageLayout::DepthStencilReadOnlyOptimal
+ | ImageLayout::DepthReadOnlyStencilAttachmentOptimal
+ | ImageLayout::DepthAttachmentStencilReadOnlyOptimal
+ ) {
+ return Err(RenderPassError::ColorAttachmentResolveLayoutInvalid {
+ attachment_index,
+ });
+ }
+ }
+ }
+
+ if let Some(attachment_info) = depth_attachment {
+ let RenderingAttachmentInfo {
+ image_view,
+ image_layout,
+ resolve_info,
+ load_op,
+ store_op,
+ clear_value: _,
+ _ne: _,
+ } = attachment_info;
+
+ // VUID-VkRenderingAttachmentInfo-imageLayout-parameter
+ image_layout.validate_device(device)?;
+
+ // VUID-VkRenderingAttachmentInfo-loadOp-parameter
+ load_op.validate_device(device)?;
+
+ // VUID-VkRenderingAttachmentInfo-storeOp-parameter
+ store_op.validate_device(device)?;
+
+ let image_aspects = image_view.format().unwrap().aspects();
+
+ // VUID-VkRenderingInfo-pDepthAttachment-06547
+ if !image_aspects.intersects(ImageAspects::DEPTH) {
+ return Err(RenderPassError::DepthAttachmentFormatUsageNotSupported);
+ }
+
+ // VUID-VkRenderingInfo-pDepthAttachment-06088
+ if !image_view
+ .usage()
+ .intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT)
+ {
+ return Err(RenderPassError::DepthAttachmentMissingUsage);
+ }
+
+ let image = image_view.image();
+ let image_extent = image.dimensions().width_height_depth();
+
+ for i in 0..2 {
+ // VUID-VkRenderingInfo-pNext-06079
+ // VUID-VkRenderingInfo-pNext-06080
+ if render_area_offset[i] + render_area_extent[i] > image_extent[i] {
+ return Err(RenderPassError::RenderAreaOutOfBounds);
+ }
+ }
+
+ // VUID-VkRenderingInfo-imageView-06070
+ match samples {
+ Some(samples) if samples == image.samples() => (),
+ Some(_) => {
+ return Err(RenderPassError::DepthAttachmentSamplesMismatch);
+ }
+ None => samples = Some(image.samples()),
+ }
+
+ // VUID-VkRenderingAttachmentInfo-imageView-06135
+ // VUID-VkRenderingAttachmentInfo-imageView-06145
+ // VUID-VkRenderingInfo-pDepthAttachment-06092
+ if matches!(
+ image_layout,
+ ImageLayout::Undefined
+ | ImageLayout::ShaderReadOnlyOptimal
+ | ImageLayout::TransferSrcOptimal
+ | ImageLayout::TransferDstOptimal
+ | ImageLayout::Preinitialized
+ | ImageLayout::PresentSrc
+ | ImageLayout::ColorAttachmentOptimal
+ ) {
+ return Err(RenderPassError::DepthAttachmentLayoutInvalid);
+ }
+
+ if let Some(resolve_info) = resolve_info {
+ let &RenderingAttachmentResolveInfo {
+ mode,
+ image_view: ref resolve_image_view,
+ image_layout: resolve_image_layout,
+ } = resolve_info;
+
+ // VUID-VkRenderingAttachmentInfo-resolveImageLayout-parameter
+ resolve_image_layout.validate_device(device)?;
+
+ // VUID-VkRenderingAttachmentInfo-resolveMode-parameter
+ mode.validate_device(device)?;
+
+ // VUID-VkRenderingInfo-pDepthAttachment-06102
+ if !properties
+ .supported_depth_resolve_modes
+ .map_or(false, |modes| modes.contains_enum(mode))
+ {
+ return Err(RenderPassError::DepthAttachmentResolveModeNotSupported);
+ }
+
+ let resolve_image = resolve_image_view.image();
+
+ // VUID-VkRenderingAttachmentInfo-imageView-06132
+ if image.samples() == SampleCount::Sample1 {
+ return Err(RenderPassError::DepthAttachmentWithResolveNotMultisampled);
+ }
+
+ // VUID-VkRenderingAttachmentInfo-imageView-06133
+ if resolve_image.samples() != SampleCount::Sample1 {
+ return Err(RenderPassError::DepthAttachmentResolveMultisampled);
+ }
+
+ // VUID-VkRenderingAttachmentInfo-imageView-06134
+ if image_view.format() != resolve_image_view.format() {
+ return Err(RenderPassError::DepthAttachmentResolveFormatMismatch);
+ }
+
+ // VUID-VkRenderingAttachmentInfo-imageView-06136
+ // VUID-VkRenderingAttachmentInfo-imageView-06146
+ // VUID-VkRenderingInfo-pDepthAttachment-06093
+ // VUID-VkRenderingInfo-pDepthAttachment-06098
+ if matches!(
+ resolve_image_layout,
+ ImageLayout::Undefined
+ | ImageLayout::DepthStencilReadOnlyOptimal
+ | ImageLayout::ShaderReadOnlyOptimal
+ | ImageLayout::TransferSrcOptimal
+ | ImageLayout::TransferDstOptimal
+ | ImageLayout::Preinitialized
+ | ImageLayout::PresentSrc
+ | ImageLayout::ColorAttachmentOptimal
+ | ImageLayout::DepthReadOnlyStencilAttachmentOptimal
+ ) {
+ return Err(RenderPassError::DepthAttachmentResolveLayoutInvalid);
+ }
+ }
+ }
+
+ if let Some(attachment_info) = stencil_attachment {
+ let RenderingAttachmentInfo {
+ image_view,
+ image_layout,
+ resolve_info,
+ load_op,
+ store_op,
+ clear_value: _,
+ _ne: _,
+ } = attachment_info;
+
+ // VUID-VkRenderingAttachmentInfo-imageLayout-parameter
+ image_layout.validate_device(device)?;
+
+ // VUID-VkRenderingAttachmentInfo-loadOp-parameter
+ load_op.validate_device(device)?;
+
+ // VUID-VkRenderingAttachmentInfo-storeOp-parameter
+ store_op.validate_device(device)?;
+
+ let image_aspects = image_view.format().unwrap().aspects();
+
+ // VUID-VkRenderingInfo-pStencilAttachment-06548
+ if !image_aspects.intersects(ImageAspects::STENCIL) {
+ return Err(RenderPassError::StencilAttachmentFormatUsageNotSupported);
+ }
+
+ // VUID-VkRenderingInfo-pStencilAttachment-06089
+ if !image_view
+ .usage()
+ .intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT)
+ {
+ return Err(RenderPassError::StencilAttachmentMissingUsage);
+ }
+
+ let image = image_view.image();
+ let image_extent = image.dimensions().width_height_depth();
+
+ for i in 0..2 {
+ // VUID-VkRenderingInfo-pNext-06079
+ // VUID-VkRenderingInfo-pNext-06080
+ if render_area_offset[i] + render_area_extent[i] > image_extent[i] {
+ return Err(RenderPassError::RenderAreaOutOfBounds);
+ }
+ }
+
+ // VUID-VkRenderingInfo-imageView-06070
+ match samples {
+ Some(samples) if samples == image.samples() => (),
+ Some(_) => {
+ return Err(RenderPassError::StencilAttachmentSamplesMismatch);
+ }
+ None => (),
+ }
+
+ // VUID-VkRenderingAttachmentInfo-imageView-06135
+ // VUID-VkRenderingAttachmentInfo-imageView-06145
+ // VUID-VkRenderingInfo-pStencilAttachment-06094
+ if matches!(
+ image_layout,
+ ImageLayout::Undefined
+ | ImageLayout::ShaderReadOnlyOptimal
+ | ImageLayout::TransferSrcOptimal
+ | ImageLayout::TransferDstOptimal
+ | ImageLayout::Preinitialized
+ | ImageLayout::PresentSrc
+ | ImageLayout::ColorAttachmentOptimal
+ ) {
+ return Err(RenderPassError::StencilAttachmentLayoutInvalid);
+ }
+
+ if let Some(resolve_info) = resolve_info {
+ let &RenderingAttachmentResolveInfo {
+ mode,
+ image_view: ref resolve_image_view,
+ image_layout: resolve_image_layout,
+ } = resolve_info;
+
+ // VUID-VkRenderingAttachmentInfo-resolveImageLayout-parameter
+ resolve_image_layout.validate_device(device)?;
+
+ // VUID-VkRenderingAttachmentInfo-resolveMode-parameter
+ mode.validate_device(device)?;
+
+ // VUID-VkRenderingInfo-pStencilAttachment-06103
+ if !properties
+ .supported_stencil_resolve_modes
+ .map_or(false, |modes| modes.contains_enum(mode))
+ {
+ return Err(RenderPassError::StencilAttachmentResolveModeNotSupported);
+ }
+
+ let resolve_image = resolve_image_view.image();
+
+ // VUID-VkRenderingAttachmentInfo-imageView-06132
+ if image.samples() == SampleCount::Sample1 {
+ return Err(RenderPassError::StencilAttachmentWithResolveNotMultisampled);
+ }
+
+ // VUID-VkRenderingAttachmentInfo-imageView-06133
+ if resolve_image.samples() != SampleCount::Sample1 {
+ return Err(RenderPassError::StencilAttachmentResolveMultisampled);
+ }
+
+ // VUID-VkRenderingAttachmentInfo-imageView-06134
+ if image_view.format() != resolve_image_view.format() {
+ return Err(RenderPassError::StencilAttachmentResolveFormatMismatch);
+ }
+
+ // VUID-VkRenderingAttachmentInfo-imageView-06136
+ // VUID-VkRenderingAttachmentInfo-imageView-06146
+ // VUID-VkRenderingInfo-pStencilAttachment-06095
+ // VUID-VkRenderingInfo-pStencilAttachment-06099
+ if matches!(
+ resolve_image_layout,
+ ImageLayout::Undefined
+ | ImageLayout::DepthStencilReadOnlyOptimal
+ | ImageLayout::ShaderReadOnlyOptimal
+ | ImageLayout::TransferSrcOptimal
+ | ImageLayout::TransferDstOptimal
+ | ImageLayout::Preinitialized
+ | ImageLayout::PresentSrc
+ | ImageLayout::ColorAttachmentOptimal
+ | ImageLayout::DepthAttachmentStencilReadOnlyOptimal
+ ) {
+ return Err(RenderPassError::StencilAttachmentResolveLayoutInvalid);
+ }
+ }
+ }
+
+ if let (Some(depth_attachment_info), Some(stencil_attachment_info)) =
+ (depth_attachment, stencil_attachment)
+ {
+ // VUID-VkRenderingInfo-pDepthAttachment-06085
+ if &depth_attachment_info.image_view != &stencil_attachment_info.image_view {
+ return Err(RenderPassError::DepthStencilAttachmentImageViewMismatch);
+ }
+
+ match (
+ &depth_attachment_info.resolve_info,
+ &stencil_attachment_info.resolve_info,
+ ) {
+ (None, None) => (),
+ (None, Some(_)) | (Some(_), None) => {
+ // VUID-VkRenderingInfo-pDepthAttachment-06104
+ if !properties.independent_resolve_none.unwrap_or(false) {
+ return Err(
+ RenderPassError::DepthStencilAttachmentResolveModesNotSupported,
+ );
+ }
+ }
+ (Some(depth_resolve_info), Some(stencil_resolve_info)) => {
+ // VUID-VkRenderingInfo-pDepthAttachment-06105
+ if !properties.independent_resolve.unwrap_or(false)
+ && depth_resolve_info.mode != stencil_resolve_info.mode
+ {
+ return Err(
+ RenderPassError::DepthStencilAttachmentResolveModesNotSupported,
+ );
+ }
+
+ // VUID-VkRenderingInfo-pDepthAttachment-06086
+ if &depth_resolve_info.image_view != &stencil_resolve_info.image_view {
+ return Err(
+ RenderPassError::DepthStencilAttachmentResolveImageViewMismatch,
+ );
+ }
+ }
+ }
+ }
+
+ // TODO: sync check
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn begin_rendering_unchecked(&mut self, rendering_info: RenderingInfo) -> &mut Self {
+ {
+ let &RenderingInfo {
+ render_area_offset,
+ render_area_extent,
+ layer_count,
+ view_mask,
+ ref color_attachments,
+ ref depth_attachment,
+ ref stencil_attachment,
+ contents,
+ _ne,
+ } = &rendering_info;
+
+ let map_attachment_info = |attachment_info: &Option<_>| {
+ if let Some(attachment_info) = attachment_info {
+ let &RenderingAttachmentInfo {
+ ref image_view,
+ image_layout,
+ resolve_info: ref resolve,
+ load_op,
+ store_op,
+ clear_value,
+ _ne: _,
+ } = attachment_info;
+
+ let (resolve_mode, resolve_image_view, resolve_image_layout) =
+ if let Some(resolve) = resolve {
+ let &RenderingAttachmentResolveInfo {
+ mode,
+ ref image_view,
+ image_layout,
+ } = resolve;
+
+ (mode.into(), image_view.handle(), image_layout.into())
+ } else {
+ (
+ ash::vk::ResolveModeFlags::NONE,
+ Default::default(),
+ Default::default(),
+ )
+ };
+
+ ash::vk::RenderingAttachmentInfo {
+ image_view: image_view.handle(),
+ image_layout: image_layout.into(),
+ resolve_mode,
+ resolve_image_view,
+ resolve_image_layout,
+ load_op: load_op.into(),
+ store_op: store_op.into(),
+ clear_value: clear_value.map_or_else(Default::default, Into::into),
+ ..Default::default()
+ }
+ } else {
+ ash::vk::RenderingAttachmentInfo {
+ image_view: ash::vk::ImageView::null(),
+ ..Default::default()
+ }
+ }
+ };
+
+ let color_attachments_vk: SmallVec<[_; 2]> =
+ color_attachments.iter().map(map_attachment_info).collect();
+ let depth_attachment_vk = map_attachment_info(depth_attachment);
+ let stencil_attachment_vk = map_attachment_info(stencil_attachment);
+
+ let rendering_info_vk = ash::vk::RenderingInfo {
+ flags: contents.into(),
+ render_area: ash::vk::Rect2D {
+ offset: ash::vk::Offset2D {
+ x: render_area_offset[0] as i32,
+ y: render_area_offset[1] as i32,
+ },
+ extent: ash::vk::Extent2D {
+ width: render_area_extent[0],
+ height: render_area_extent[1],
+ },
+ },
+ layer_count,
+ view_mask,
+ color_attachment_count: color_attachments_vk.len() as u32,
+ p_color_attachments: color_attachments_vk.as_ptr(),
+ p_depth_attachment: &depth_attachment_vk,
+ p_stencil_attachment: &stencil_attachment_vk,
+ ..Default::default()
+ };
+
+ let fns = self.device().fns();
+
+ if self.device().api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_begin_rendering)(self.handle(), &rendering_info_vk);
+ } else {
+ debug_assert!(self.device().enabled_extensions().khr_dynamic_rendering);
+ (fns.khr_dynamic_rendering.cmd_begin_rendering_khr)(
+ self.handle(),
+ &rendering_info_vk,
+ );
+ }
+
+ self.builder_state.render_pass = Some(RenderPassState {
+ contents,
+ render_area_offset,
+ render_area_extent,
+
+ rendering_info: PipelineRenderingCreateInfo::from_rendering_info(&rendering_info),
+ attachments: Some(RenderPassStateAttachments::from_rendering_info(
+ &rendering_info,
+ )),
+
+ render_pass: BeginRenderingState {
+ pipeline_used: false,
+ }
+ .into(),
+ });
+ }
+
+ let RenderingInfo {
+ color_attachments,
+ depth_attachment,
+ stencil_attachment,
+ ..
+ } = rendering_info;
+
+ for attachment_info in color_attachments.into_iter().flatten() {
+ let RenderingAttachmentInfo {
+ image_view,
+ image_layout: _,
+ resolve_info,
+ load_op: _,
+ store_op: _,
+ clear_value: _,
+ _ne: _,
+ } = attachment_info;
+
+ self.resources.push(Box::new(image_view));
+
+ if let Some(resolve_info) = resolve_info {
+ let RenderingAttachmentResolveInfo {
+ mode: _,
+ image_view,
+ image_layout: _,
+ } = resolve_info;
+
+ self.resources.push(Box::new(image_view));
+ }
+ }
+
+ if let Some(attachment_info) = depth_attachment {
+ let RenderingAttachmentInfo {
+ image_view,
+ image_layout: _,
+ resolve_info,
+ load_op: _,
+ store_op: _,
+ clear_value: _,
+ _ne: _,
+ } = attachment_info;
+
+ self.resources.push(Box::new(image_view));
+
+ if let Some(resolve_info) = resolve_info {
+ let RenderingAttachmentResolveInfo {
+ mode: _,
+ image_view,
+ image_layout: _,
+ } = resolve_info;
+
+ self.resources.push(Box::new(image_view));
+ }
+ }
+
+ if let Some(attachment_info) = stencil_attachment {
+ let RenderingAttachmentInfo {
+ image_view,
+ image_layout: _,
+ resolve_info,
+ load_op: _,
+ store_op: _,
+ clear_value: _,
+ _ne: _,
+ } = attachment_info;
+
+ self.resources.push(Box::new(image_view));
+
+ if let Some(resolve_info) = resolve_info {
+ let RenderingAttachmentResolveInfo {
+ mode: _,
+ image_view,
+ image_layout: _,
+ } = resolve_info;
+
+ self.resources.push(Box::new(image_view));
+ }
+ }
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Ends the render pass previously begun with `begin_rendering`.
+ ///
+ /// # Safety
+ ///
+ /// - Appropriate synchronization must be provided for all images
+ /// that are accessed by the command.
+ /// - All images that are accessed by the command must be in the expected image layout.
+ #[inline]
+ pub unsafe fn end_rendering(&mut self) -> Result<&mut Self, RenderPassError> {
+ self.validate_end_rendering()?;
+
+ unsafe { Ok(self.end_rendering_unchecked()) }
+ }
+
+ fn validate_end_rendering(&self) -> Result<(), RenderPassError> {
+ // VUID-vkCmdEndRendering-renderpass
+ let render_pass_state = self
+ .builder_state
+ .render_pass
+ .as_ref()
+ .ok_or(RenderPassError::ForbiddenOutsideRenderPass)?;
+
+ // VUID?
+ if self.inheritance_info.is_some() {
+ return Err(RenderPassError::ForbiddenWithInheritedRenderPass);
+ }
+
+ // VUID-vkCmdEndRendering-None-06161
+ // VUID-vkCmdEndRendering-commandBuffer-06162
+ match &render_pass_state.render_pass {
+ RenderPassStateType::BeginRenderPass(_) => {
+ return Err(RenderPassError::ForbiddenWithBeginRenderPass)
+ }
+ RenderPassStateType::BeginRendering(_) => (),
+ }
+
+ // VUID-vkCmdEndRendering-commandBuffer-cmdpool
+ debug_assert!(self
+ .queue_family_properties()
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS));
+
+ // TODO: sync check
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn end_rendering_unchecked(&mut self) -> &mut Self {
+ let fns = self.device().fns();
+
+ if self.device().api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_end_rendering)(self.handle());
+ } else {
+ debug_assert!(self.device().enabled_extensions().khr_dynamic_rendering);
+ (fns.khr_dynamic_rendering.cmd_end_rendering_khr)(self.handle());
+ }
+
+ let command_index = self.next_command_index;
+ let command_name = "end_rendering";
+ let render_pass_state = self.builder_state.render_pass.as_ref().unwrap();
+
+ record_subpass_attachments_resolve(
+ &mut self.resources_usage_state,
+ command_index,
+ command_name,
+ render_pass_state,
+ );
+ record_subpass_attachments_store(
+ &mut self.resources_usage_state,
+ command_index,
+ command_name,
+ render_pass_state,
+ );
+
+ self.builder_state.render_pass = None;
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Clears specific regions of specific attachments of the framebuffer.
+ ///
+ /// `attachments` specify the types of attachments and their clear values.
+ /// `rects` specify the regions to clear.
+ ///
+ /// A graphics pipeline must have been bound using [`bind_pipeline_graphics`].
+ /// And the command must be inside render pass.
+ ///
+ /// If the render pass instance this is recorded in uses multiview,
+ /// then `ClearRect.base_array_layer` must be zero and `ClearRect.layer_count` must be one.
+ ///
+ /// The rectangle area must be inside the render area ranges.
+ ///
+ /// # Safety
+ ///
+ /// - Appropriate synchronization must be provided for all images
+ /// that are accessed by the command.
+ /// - All images that are accessed by the command must be in the expected image layout.
+ ///
+ /// [`bind_pipeline_graphics`]: Self::bind_pipeline_graphics
+ #[inline]
+ pub unsafe fn clear_attachments(
+ &mut self,
+ attachments: impl IntoIterator<Item = ClearAttachment>,
+ rects: impl IntoIterator<Item = ClearRect>,
+ ) -> Result<&mut Self, RenderPassError> {
+ let attachments: SmallVec<[ClearAttachment; 3]> = attachments.into_iter().collect();
+ let rects: SmallVec<[ClearRect; 4]> = rects.into_iter().collect();
+
+ self.validate_clear_attachments(&attachments, &rects)?;
+
+ unsafe { Ok(self.clear_attachments_unchecked(attachments, rects)) }
+ }
+
+ fn validate_clear_attachments(
+ &self,
+ attachments: &[ClearAttachment],
+ rects: &[ClearRect],
+ ) -> Result<(), RenderPassError> {
+ // VUID-vkCmdClearAttachments-renderpass
+ let render_pass_state = self
+ .builder_state
+ .render_pass
+ .as_ref()
+ .ok_or(RenderPassError::ForbiddenOutsideRenderPass)?;
+
+ if render_pass_state.contents != SubpassContents::Inline {
+ return Err(RenderPassError::ForbiddenWithSubpassContents {
+ contents: render_pass_state.contents,
+ });
+ }
+
+ //let subpass_desc = begin_render_pass_state.subpass.subpass_desc();
+ //let render_pass = begin_render_pass_state.subpass.render_pass();
+ let is_multiview = render_pass_state.rendering_info.view_mask != 0;
+ let mut layer_count = u32::MAX;
+
+ for &clear_attachment in attachments {
+ match clear_attachment {
+ ClearAttachment::Color {
+ color_attachment,
+ clear_value,
+ } => {
+ let attachment_format = *render_pass_state
+ .rendering_info
+ .color_attachment_formats
+ .get(color_attachment as usize)
+ .ok_or(RenderPassError::ColorAttachmentIndexOutOfRange {
+ color_attachment_index: color_attachment,
+ num_color_attachments: render_pass_state
+ .rendering_info
+ .color_attachment_formats
+ .len() as u32,
+ })?;
+
+ // VUID-vkCmdClearAttachments-aspectMask-02501
+ if !attachment_format.map_or(false, |format| {
+ matches!(
+ (clear_value, format.type_color().unwrap()),
+ (
+ ClearColorValue::Float(_),
+ NumericType::SFLOAT
+ | NumericType::UFLOAT
+ | NumericType::SNORM
+ | NumericType::UNORM
+ | NumericType::SSCALED
+ | NumericType::USCALED
+ | NumericType::SRGB
+ ) | (ClearColorValue::Int(_), NumericType::SINT)
+ | (ClearColorValue::Uint(_), NumericType::UINT)
+ )
+ }) {
+ return Err(RenderPassError::ClearAttachmentNotCompatible {
+ clear_attachment,
+ attachment_format,
+ });
+ }
+
+ let image_view = render_pass_state
+ .attachments
+ .as_ref()
+ .and_then(|attachments| {
+ attachments.color_attachments[color_attachment as usize].as_ref()
+ })
+ .map(|attachment_info| &attachment_info.image_view);
+
+ // We only know the layer count if we have a known attachment image.
+ if let Some(image_view) = image_view {
+ let array_layers = &image_view.subresource_range().array_layers;
+ layer_count = min(layer_count, array_layers.end - array_layers.start);
+ }
+ }
+ ClearAttachment::Depth(_)
+ | ClearAttachment::Stencil(_)
+ | ClearAttachment::DepthStencil(_) => {
+ let depth_format = render_pass_state.rendering_info.depth_attachment_format;
+ let stencil_format = render_pass_state.rendering_info.stencil_attachment_format;
+
+ // VUID-vkCmdClearAttachments-aspectMask-02502
+ if matches!(
+ clear_attachment,
+ ClearAttachment::Depth(_) | ClearAttachment::DepthStencil(_)
+ ) && !depth_format.map_or(false, |format| {
+ format.aspects().intersects(ImageAspects::DEPTH)
+ }) {
+ return Err(RenderPassError::ClearAttachmentNotCompatible {
+ clear_attachment,
+ attachment_format: None,
+ });
+ }
+
+ // VUID-vkCmdClearAttachments-aspectMask-02503
+ if matches!(
+ clear_attachment,
+ ClearAttachment::Stencil(_) | ClearAttachment::DepthStencil(_)
+ ) && !stencil_format.map_or(false, |format| {
+ format.aspects().intersects(ImageAspects::STENCIL)
+ }) {
+ return Err(RenderPassError::ClearAttachmentNotCompatible {
+ clear_attachment,
+ attachment_format: None,
+ });
+ }
+
+ let image_view = render_pass_state
+ .attachments
+ .as_ref()
+ .and_then(|attachments| attachments.depth_attachment.as_ref())
+ .map(|attachment_info| &attachment_info.image_view);
+
+ // We only know the layer count if we have a known attachment image.
+ if let Some(image_view) = image_view {
+ let array_layers = &image_view.subresource_range().array_layers;
+ layer_count = min(layer_count, array_layers.end - array_layers.start);
+ }
+ }
+ }
+ }
+
+ for (rect_index, rect) in rects.iter().enumerate() {
+ for i in 0..2 {
+ // VUID-vkCmdClearAttachments-rect-02682
+ // VUID-vkCmdClearAttachments-rect-02683
+ if rect.extent[i] == 0 {
+ return Err(RenderPassError::RectExtentZero { rect_index });
+ }
+
+ // VUID-vkCmdClearAttachments-pRects-00016
+ // TODO: This check will always pass in secondary command buffers because of how
+ // it's set in `with_level`.
+ // It needs to be checked during `execute_commands` instead.
+ if rect.offset[i] < render_pass_state.render_area_offset[i]
+ || rect.offset[i] + rect.extent[i]
+ > render_pass_state.render_area_offset[i]
+ + render_pass_state.render_area_extent[i]
+ {
+ return Err(RenderPassError::RectOutOfBounds { rect_index });
+ }
+ }
+
+ // VUID-vkCmdClearAttachments-layerCount-01934
+ if rect.array_layers.is_empty() {
+ return Err(RenderPassError::RectArrayLayersEmpty { rect_index });
+ }
+
+ // VUID-vkCmdClearAttachments-pRects-00017
+ if rect.array_layers.end > layer_count {
+ return Err(RenderPassError::RectArrayLayersOutOfBounds { rect_index });
+ }
+
+ // VUID-vkCmdClearAttachments-baseArrayLayer-00018
+ if is_multiview && rect.array_layers != (0..1) {
+ return Err(RenderPassError::MultiviewRectArrayLayersInvalid { rect_index });
+ }
+ }
+
+ // VUID-vkCmdClearAttachments-commandBuffer-cmdpool
+ debug_assert!(self
+ .queue_family_properties()
+ .queue_flags
+ .intersects(QueueFlags::GRAPHICS));
+
+ // TODO: sync check
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn clear_attachments_unchecked(
+ &mut self,
+ attachments: impl IntoIterator<Item = ClearAttachment>,
+ rects: impl IntoIterator<Item = ClearRect>,
+ ) -> &mut Self {
+ let attachments_vk: SmallVec<[_; 3]> = attachments.into_iter().map(|v| v.into()).collect();
+ let rects_vk: SmallVec<[_; 4]> = rects
+ .into_iter()
+ .map(|rect| ash::vk::ClearRect {
+ rect: ash::vk::Rect2D {
+ offset: ash::vk::Offset2D {
+ x: rect.offset[0] as i32,
+ y: rect.offset[1] as i32,
+ },
+ extent: ash::vk::Extent2D {
+ width: rect.extent[0],
+ height: rect.extent[1],
+ },
+ },
+ base_array_layer: rect.array_layers.start,
+ layer_count: rect.array_layers.end - rect.array_layers.start,
+ })
+ .collect();
+
+ if attachments_vk.is_empty() || rects_vk.is_empty() {
+ return self;
+ }
+
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_clear_attachments)(
+ self.handle(),
+ attachments_vk.len() as u32,
+ attachments_vk.as_ptr(),
+ rects_vk.len() as u32,
+ rects_vk.as_ptr(),
+ );
+
+ // TODO: sync state update
+
+ self.next_command_index += 1;
+ self
+ }
+}
+
+fn record_subpass_attachments_resolve(
+ resources_usage_state: &mut ResourcesState,
+ command_index: usize,
+ command_name: &'static str,
+ render_pass_state: &RenderPassState,
+) {
+ let attachments = render_pass_state.attachments.as_ref().unwrap();
+
+ let record_attachment = |resources_usage_state: &mut ResourcesState,
+ attachment_info,
+ aspects_override,
+ resource_in_command,
+ resolve_resource_in_command| {
+ let &RenderPassStateAttachmentInfo {
+ ref image_view,
+ image_layout,
+ ref resolve_info,
+ ..
+ } = attachment_info;
+
+ let image = image_view.image();
+ let image_inner = image.inner();
+ let mut subresource_range = image_view.subresource_range().clone();
+ subresource_range.array_layers.start += image_inner.first_layer;
+ subresource_range.array_layers.end += image_inner.first_layer;
+ subresource_range.mip_levels.start += image_inner.first_mipmap_level;
+ subresource_range.mip_levels.end += image_inner.first_mipmap_level;
+
+ if let Some(aspects) = aspects_override {
+ subresource_range.aspects = aspects;
+ }
+
+ let use_ref = ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command,
+ secondary_use_ref: None,
+ };
+
+ if let Some(resolve_info) = resolve_info {
+ let &RenderPassStateAttachmentResolveInfo {
+ image_view: ref resolve_image_view,
+ image_layout: resolve_image_layout,
+ ..
+ } = resolve_info;
+
+ let resolve_image = resolve_image_view.image();
+ let resolve_image_inner = resolve_image.inner();
+ let mut resolve_subresource_range = resolve_image_view.subresource_range().clone();
+ resolve_subresource_range.array_layers.start += resolve_image_inner.first_layer;
+ resolve_subresource_range.array_layers.end += resolve_image_inner.first_layer;
+ resolve_subresource_range.mip_levels.start += resolve_image_inner.first_mipmap_level;
+ resolve_subresource_range.mip_levels.end += resolve_image_inner.first_mipmap_level;
+
+ if let Some(aspects) = aspects_override {
+ resolve_subresource_range.aspects = aspects;
+ }
+
+ let resolve_use_ref = ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: resolve_resource_in_command,
+ secondary_use_ref: None,
+ };
+
+ // The resolve operation uses the stages/access for color attachments,
+ // even for depth/stencil attachments.
+ resources_usage_state.record_image_access(
+ &use_ref,
+ image_inner.image,
+ subresource_range,
+ PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentRead,
+ image_layout,
+ );
+ resources_usage_state.record_image_access(
+ &resolve_use_ref,
+ resolve_image_inner.image,
+ resolve_subresource_range,
+ PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentWrite,
+ resolve_image_layout,
+ );
+ }
+ };
+
+ if let Some(attachment_info) = attachments.depth_attachment.as_ref() {
+ record_attachment(
+ resources_usage_state,
+ attachment_info,
+ Some(ImageAspects::DEPTH),
+ ResourceInCommand::DepthStencilAttachment,
+ ResourceInCommand::DepthStencilResolveAttachment,
+ );
+ }
+
+ if let Some(attachment_info) = attachments.stencil_attachment.as_ref() {
+ record_attachment(
+ resources_usage_state,
+ attachment_info,
+ Some(ImageAspects::STENCIL),
+ ResourceInCommand::DepthStencilAttachment,
+ ResourceInCommand::DepthStencilResolveAttachment,
+ );
+ }
+
+ for (index, attachment_info) in (attachments.color_attachments.iter().enumerate())
+ .filter_map(|(i, a)| a.as_ref().map(|a| (i as u32, a)))
+ {
+ record_attachment(
+ resources_usage_state,
+ attachment_info,
+ None,
+ ResourceInCommand::ColorAttachment { index },
+ ResourceInCommand::ColorResolveAttachment { index },
+ );
+ }
+}
+
+fn record_subpass_attachments_store(
+ resources_usage_state: &mut ResourcesState,
+ command_index: usize,
+ command_name: &'static str,
+ render_pass_state: &RenderPassState,
+) {
+ let attachments = render_pass_state.attachments.as_ref().unwrap();
+
+ let record_attachment = |resources_usage_state: &mut ResourcesState,
+ attachment_info,
+ aspects_override,
+ resource_in_command,
+ resolve_resource_in_command| {
+ let &RenderPassStateAttachmentInfo {
+ ref image_view,
+ image_layout,
+ store_access,
+ ref resolve_info,
+ ..
+ } = attachment_info;
+
+ if let Some(access) = store_access {
+ let image = image_view.image();
+ let image_inner = image.inner();
+ let mut subresource_range = image_view.subresource_range().clone();
+ subresource_range.array_layers.start += image_inner.first_layer;
+ subresource_range.array_layers.end += image_inner.first_layer;
+ subresource_range.mip_levels.start += image_inner.first_mipmap_level;
+ subresource_range.mip_levels.end += image_inner.first_mipmap_level;
+
+ if let Some(aspects) = aspects_override {
+ subresource_range.aspects = aspects;
+ }
+
+ let use_ref = ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command,
+ secondary_use_ref: None,
+ };
+
+ resources_usage_state.record_image_access(
+ &use_ref,
+ image_inner.image,
+ subresource_range,
+ access,
+ image_layout,
+ );
+ }
+
+ if let Some(resolve_info) = resolve_info {
+ let &RenderPassStateAttachmentResolveInfo {
+ ref image_view,
+ image_layout,
+ store_access,
+ ..
+ } = resolve_info;
+
+ if let Some(access) = store_access {
+ let image = image_view.image();
+ let image_inner = image.inner();
+ let mut subresource_range = image_view.subresource_range().clone();
+ subresource_range.array_layers.start += image_inner.first_layer;
+ subresource_range.array_layers.end += image_inner.first_layer;
+ subresource_range.mip_levels.start += image_inner.first_mipmap_level;
+ subresource_range.mip_levels.end += image_inner.first_mipmap_level;
+
+ if let Some(aspects) = aspects_override {
+ subresource_range.aspects = aspects;
+ }
+
+ let use_ref = ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: resolve_resource_in_command,
+ secondary_use_ref: None,
+ };
+
+ resources_usage_state.record_image_access(
+ &use_ref,
+ image_inner.image,
+ subresource_range,
+ access,
+ image_layout,
+ );
+ }
+ }
+ };
+
+ if let Some(attachment_info) = attachments.depth_attachment.as_ref() {
+ record_attachment(
+ resources_usage_state,
+ attachment_info,
+ Some(ImageAspects::DEPTH),
+ ResourceInCommand::DepthStencilAttachment,
+ ResourceInCommand::DepthStencilResolveAttachment,
+ );
+ }
+
+ if let Some(attachment_info) = attachments.stencil_attachment.as_ref() {
+ record_attachment(
+ resources_usage_state,
+ attachment_info,
+ Some(ImageAspects::STENCIL),
+ ResourceInCommand::DepthStencilAttachment,
+ ResourceInCommand::DepthStencilResolveAttachment,
+ );
+ }
+
+ for (index, attachment_info) in (attachments.color_attachments.iter().enumerate())
+ .filter_map(|(i, a)| a.as_ref().map(|a| (i as u32, a)))
+ {
+ record_attachment(
+ resources_usage_state,
+ attachment_info,
+ None,
+ ResourceInCommand::ColorAttachment { index },
+ ResourceInCommand::ColorResolveAttachment { index },
+ );
+ }
+}
+
+fn record_subpass_attachments_load(
+ resources_usage_state: &mut ResourcesState,
+ command_index: usize,
+ command_name: &'static str,
+ render_pass_state: &RenderPassState,
+) {
+ let attachments = render_pass_state.attachments.as_ref().unwrap();
+
+ let record_attachment = |resources_usage_state: &mut ResourcesState,
+ attachment_info,
+ aspects_override,
+ resource_in_command,
+ resolve_resource_in_command| {
+ let &RenderPassStateAttachmentInfo {
+ ref image_view,
+ image_layout,
+ load_access,
+ ref resolve_info,
+ ..
+ } = attachment_info;
+
+ if let Some(access) = load_access {
+ let image = image_view.image();
+ let image_inner = image.inner();
+ let mut subresource_range = image_view.subresource_range().clone();
+ subresource_range.array_layers.start += image_inner.first_layer;
+ subresource_range.array_layers.end += image_inner.first_layer;
+ subresource_range.mip_levels.start += image_inner.first_mipmap_level;
+ subresource_range.mip_levels.end += image_inner.first_mipmap_level;
+
+ if let Some(aspects) = aspects_override {
+ subresource_range.aspects = aspects;
+ }
+
+ let use_ref = ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command,
+ secondary_use_ref: None,
+ };
+
+ resources_usage_state.record_image_access(
+ &use_ref,
+ image_inner.image,
+ subresource_range,
+ access,
+ image_layout,
+ );
+ }
+
+ if let Some(resolve_info) = resolve_info {
+ let &RenderPassStateAttachmentResolveInfo {
+ ref image_view,
+ image_layout,
+ load_access,
+ ..
+ } = resolve_info;
+
+ if let Some(access) = load_access {
+ let image = image_view.image();
+ let image_inner = image.inner();
+ let mut subresource_range = image_view.subresource_range().clone();
+ subresource_range.array_layers.start += image_inner.first_layer;
+ subresource_range.array_layers.end += image_inner.first_layer;
+ subresource_range.mip_levels.start += image_inner.first_mipmap_level;
+ subresource_range.mip_levels.end += image_inner.first_mipmap_level;
+
+ if let Some(aspects) = aspects_override {
+ subresource_range.aspects = aspects;
+ }
+
+ let use_ref = ResourceUseRef {
+ command_index,
+ command_name,
+ resource_in_command: resolve_resource_in_command,
+ secondary_use_ref: None,
+ };
+
+ resources_usage_state.record_image_access(
+ &use_ref,
+ image_inner.image,
+ subresource_range,
+ access,
+ image_layout,
+ );
+ }
+ }
+ };
+
+ if let Some(attachment_info) = attachments.depth_attachment.as_ref() {
+ record_attachment(
+ resources_usage_state,
+ attachment_info,
+ Some(ImageAspects::DEPTH),
+ ResourceInCommand::DepthStencilAttachment,
+ ResourceInCommand::DepthStencilResolveAttachment,
+ );
+ }
+
+ if let Some(attachment_info) = attachments.stencil_attachment.as_ref() {
+ record_attachment(
+ resources_usage_state,
+ attachment_info,
+ Some(ImageAspects::STENCIL),
+ ResourceInCommand::DepthStencilAttachment,
+ ResourceInCommand::DepthStencilResolveAttachment,
+ );
+ }
+
+ for (index, attachment_info) in (attachments.color_attachments.iter().enumerate())
+ .filter_map(|(i, a)| a.as_ref().map(|a| (i as u32, a)))
+ {
+ record_attachment(
+ resources_usage_state,
+ attachment_info,
+ None,
+ ResourceInCommand::ColorAttachment { index },
+ ResourceInCommand::ColorResolveAttachment { index },
+ );
+ }
+}
diff --git a/src/command_buffer/standard/builder/secondary.rs b/src/command_buffer/standard/builder/secondary.rs
new file mode 100644
index 0000000..b7678b8
--- /dev/null
+++ b/src/command_buffer/standard/builder/secondary.rs
@@ -0,0 +1,393 @@
+// Copyright (c) 2022 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use super::{CommandBufferBuilder, ExecuteCommandsError, RenderPassStateType};
+use crate::{
+ command_buffer::{
+ allocator::{CommandBufferAlloc, CommandBufferAllocator},
+ CommandBufferInheritanceRenderPassType, PrimaryCommandBuffer, SecondaryCommandBuffer,
+ SubpassContents,
+ },
+ device::{DeviceOwned, QueueFlags},
+ query::QueryType,
+ RequiresOneOf, SafeDeref, VulkanObject,
+};
+
+impl<A> CommandBufferBuilder<PrimaryCommandBuffer<A::Alloc>, A>
+where
+ A: CommandBufferAllocator,
+{
+ /// Executes a secondary command buffer.
+ ///
+ /// If the `usage` that `command_buffer` was created with are more restrictive than those of
+ /// `self`, then `self` will be restricted to match. E.g. executing a secondary command buffer
+ /// with [`OneTimeSubmit`] will set `self`'s usage to
+ /// `OneTimeSubmit` also.
+ ///
+ /// # Safety
+ ///
+ /// - Appropriate synchronization must be provided for all buffers and images
+ /// that are accessed by the command.
+ /// - All images that are accessed by the command must be in the expected image layout.
+ ///
+ /// [`OneTimeSubmit`]: crate::command_buffer::CommandBufferUsage::OneTimeSubmit
+ pub unsafe fn execute_commands(
+ &mut self,
+ command_buffer: SecondaryCommandBuffer<impl CommandBufferAlloc + 'static>,
+ ) -> Result<&mut Self, ExecuteCommandsError> {
+ self.validate_execute_commands(&command_buffer, 0)?;
+
+ unsafe { Ok(self.execute_commands_unchecked(command_buffer)) }
+ }
+
+ fn validate_execute_commands(
+ &self,
+ command_buffer: &SecondaryCommandBuffer<impl CommandBufferAlloc + 'static>,
+ command_buffer_index: u32,
+ ) -> Result<(), ExecuteCommandsError> {
+ // VUID-vkCmdExecuteCommands-commonparent
+ assert_eq!(self.device(), command_buffer.device());
+
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdExecuteCommands-commandBuffer-cmdpool
+ if !queue_family_properties
+ .queue_flags
+ .intersects(QueueFlags::TRANSFER | QueueFlags::GRAPHICS | QueueFlags::COMPUTE)
+ {
+ return Err(ExecuteCommandsError::NotSupportedByQueueFamily);
+ }
+
+ // TODO:
+ // VUID-vkCmdExecuteCommands-pCommandBuffers-00094
+
+ if let Some(render_pass_state) = &self.builder_state.render_pass {
+ // VUID-vkCmdExecuteCommands-contents-06018
+ // VUID-vkCmdExecuteCommands-flags-06024
+ if render_pass_state.contents != SubpassContents::SecondaryCommandBuffers {
+ return Err(ExecuteCommandsError::ForbiddenWithSubpassContents {
+ contents: render_pass_state.contents,
+ });
+ }
+
+ // VUID-vkCmdExecuteCommands-pCommandBuffers-00096
+ let inheritance_render_pass = command_buffer
+ .inheritance_info()
+ .render_pass
+ .as_ref()
+ .ok_or(ExecuteCommandsError::RenderPassInheritanceRequired {
+ command_buffer_index,
+ })?;
+
+ match (&render_pass_state.render_pass, inheritance_render_pass) {
+ (
+ RenderPassStateType::BeginRenderPass(state),
+ CommandBufferInheritanceRenderPassType::BeginRenderPass(inheritance_info),
+ ) => {
+ // VUID-vkCmdExecuteCommands-pBeginInfo-06020
+ if !inheritance_info
+ .subpass
+ .render_pass()
+ .is_compatible_with(state.subpass.render_pass())
+ {
+ return Err(ExecuteCommandsError::RenderPassNotCompatible {
+ command_buffer_index,
+ });
+ }
+
+ // VUID-vkCmdExecuteCommands-pCommandBuffers-06019
+ if inheritance_info.subpass.index() != state.subpass.index() {
+ return Err(ExecuteCommandsError::RenderPassSubpassMismatch {
+ command_buffer_index,
+ required_subpass: state.subpass.index(),
+ inherited_subpass: inheritance_info.subpass.index(),
+ });
+ }
+
+ // VUID-vkCmdExecuteCommands-pCommandBuffers-00099
+ if let Some(framebuffer) = &inheritance_info.framebuffer {
+ if framebuffer != state.framebuffer.as_ref().unwrap() {
+ return Err(ExecuteCommandsError::RenderPassFramebufferMismatch {
+ command_buffer_index,
+ });
+ }
+ }
+ }
+ (
+ RenderPassStateType::BeginRendering(_),
+ CommandBufferInheritanceRenderPassType::BeginRendering(inheritance_info),
+ ) => {
+ let attachments = render_pass_state.attachments.as_ref().unwrap();
+
+ // VUID-vkCmdExecuteCommands-colorAttachmentCount-06027
+ if inheritance_info.color_attachment_formats.len()
+ != attachments.color_attachments.len()
+ {
+ return Err(
+ ExecuteCommandsError::RenderPassColorAttachmentCountMismatch {
+ command_buffer_index,
+ required_count: attachments.color_attachments.len() as u32,
+ inherited_count: inheritance_info.color_attachment_formats.len()
+ as u32,
+ },
+ );
+ }
+
+ for (color_attachment_index, image_view, inherited_format) in attachments
+ .color_attachments
+ .iter()
+ .zip(inheritance_info.color_attachment_formats.iter().copied())
+ .enumerate()
+ .filter_map(|(i, (a, f))| a.as_ref().map(|a| (i as u32, &a.image_view, f)))
+ {
+ let required_format = image_view.format().unwrap();
+
+ // VUID-vkCmdExecuteCommands-imageView-06028
+ if Some(required_format) != inherited_format {
+ return Err(
+ ExecuteCommandsError::RenderPassColorAttachmentFormatMismatch {
+ command_buffer_index,
+ color_attachment_index,
+ required_format,
+ inherited_format,
+ },
+ );
+ }
+
+ // VUID-vkCmdExecuteCommands-pNext-06035
+ if image_view.image().samples() != inheritance_info.rasterization_samples {
+ return Err(
+ ExecuteCommandsError::RenderPassColorAttachmentSamplesMismatch {
+ command_buffer_index,
+ color_attachment_index,
+ required_samples: image_view.image().samples(),
+ inherited_samples: inheritance_info.rasterization_samples,
+ },
+ );
+ }
+ }
+
+ if let Some((image_view, format)) = attachments
+ .depth_attachment
+ .as_ref()
+ .map(|a| (&a.image_view, inheritance_info.depth_attachment_format))
+ {
+ // VUID-vkCmdExecuteCommands-pDepthAttachment-06029
+ if Some(image_view.format().unwrap()) != format {
+ return Err(
+ ExecuteCommandsError::RenderPassDepthAttachmentFormatMismatch {
+ command_buffer_index,
+ required_format: image_view.format().unwrap(),
+ inherited_format: format,
+ },
+ );
+ }
+
+ // VUID-vkCmdExecuteCommands-pNext-06036
+ if image_view.image().samples() != inheritance_info.rasterization_samples {
+ return Err(
+ ExecuteCommandsError::RenderPassDepthAttachmentSamplesMismatch {
+ command_buffer_index,
+ required_samples: image_view.image().samples(),
+ inherited_samples: inheritance_info.rasterization_samples,
+ },
+ );
+ }
+ }
+
+ if let Some((image_view, format)) = attachments
+ .stencil_attachment
+ .as_ref()
+ .map(|a| (&a.image_view, inheritance_info.stencil_attachment_format))
+ {
+ // VUID-vkCmdExecuteCommands-pStencilAttachment-06030
+ if Some(image_view.format().unwrap()) != format {
+ return Err(
+ ExecuteCommandsError::RenderPassStencilAttachmentFormatMismatch {
+ command_buffer_index,
+ required_format: image_view.format().unwrap(),
+ inherited_format: format,
+ },
+ );
+ }
+
+ // VUID-vkCmdExecuteCommands-pNext-06037
+ if image_view.image().samples() != inheritance_info.rasterization_samples {
+ return Err(
+ ExecuteCommandsError::RenderPassStencilAttachmentSamplesMismatch {
+ command_buffer_index,
+ required_samples: image_view.image().samples(),
+ inherited_samples: inheritance_info.rasterization_samples,
+ },
+ );
+ }
+ }
+
+ // VUID-vkCmdExecuteCommands-viewMask-06031
+ if inheritance_info.view_mask != render_pass_state.rendering_info.view_mask {
+ return Err(ExecuteCommandsError::RenderPassViewMaskMismatch {
+ command_buffer_index,
+ required_view_mask: render_pass_state.rendering_info.view_mask,
+ inherited_view_mask: inheritance_info.view_mask,
+ });
+ }
+ }
+ _ => {
+ // VUID-vkCmdExecuteCommands-pBeginInfo-06025
+ return Err(ExecuteCommandsError::RenderPassTypeMismatch {
+ command_buffer_index,
+ });
+ }
+ }
+
+ // TODO:
+ // VUID-vkCmdExecuteCommands-commandBuffer-06533
+ // VUID-vkCmdExecuteCommands-commandBuffer-06534
+ // VUID-vkCmdExecuteCommands-pCommandBuffers-06535
+ // VUID-vkCmdExecuteCommands-pCommandBuffers-06536
+ } else {
+ // VUID-vkCmdExecuteCommands-pCommandBuffers-00100
+ if command_buffer.inheritance_info().render_pass.is_some() {
+ return Err(ExecuteCommandsError::RenderPassInheritanceForbidden {
+ command_buffer_index,
+ });
+ }
+ }
+
+ // VUID-vkCmdExecuteCommands-commandBuffer-00101
+ if !self.builder_state.queries.is_empty()
+ && !self.device().enabled_features().inherited_queries
+ {
+ return Err(ExecuteCommandsError::RequirementNotMet {
+ required_for: "`CommandBufferBuilder::execute_commands` when a query is active",
+ requires_one_of: RequiresOneOf {
+ features: &["inherited_queries"],
+ ..Default::default()
+ },
+ });
+ }
+
+ for state in self.builder_state.queries.values() {
+ match state.ty {
+ QueryType::Occlusion => {
+ // VUID-vkCmdExecuteCommands-commandBuffer-00102
+ let inherited_flags = command_buffer.inheritance_info().occlusion_query.ok_or(
+ ExecuteCommandsError::OcclusionQueryInheritanceRequired {
+ command_buffer_index,
+ },
+ )?;
+
+ let inherited_flags_vk = ash::vk::QueryControlFlags::from(inherited_flags);
+ let state_flags_vk = ash::vk::QueryControlFlags::from(state.flags);
+
+ // VUID-vkCmdExecuteCommands-commandBuffer-00103
+ if inherited_flags_vk & state_flags_vk != state_flags_vk {
+ return Err(ExecuteCommandsError::OcclusionQueryFlagsNotSuperset {
+ command_buffer_index,
+ required_flags: state.flags,
+ inherited_flags,
+ });
+ }
+ }
+ QueryType::PipelineStatistics(state_flags) => {
+ let inherited_flags = command_buffer.inheritance_info().query_statistics_flags;
+ let inherited_flags_vk =
+ ash::vk::QueryPipelineStatisticFlags::from(inherited_flags);
+ let state_flags_vk = ash::vk::QueryPipelineStatisticFlags::from(state_flags);
+
+ // VUID-vkCmdExecuteCommands-commandBuffer-00104
+ if inherited_flags_vk & state_flags_vk != state_flags_vk {
+ return Err(
+ ExecuteCommandsError::PipelineStatisticsQueryFlagsNotSuperset {
+ command_buffer_index,
+ required_flags: state_flags,
+ inherited_flags,
+ },
+ );
+ }
+ }
+ QueryType::Timestamp => (),
+ }
+ }
+
+ // TODO:
+ // VUID-vkCmdExecuteCommands-pCommandBuffers-00091
+ // VUID-vkCmdExecuteCommands-pCommandBuffers-00092
+ // VUID-vkCmdExecuteCommands-pCommandBuffers-00093
+ // VUID-vkCmdExecuteCommands-pCommandBuffers-00105
+
+ // VUID-vkCmdExecuteCommands-bufferlevel
+ // Ensured by the type of the impl block.
+
+ // VUID-vkCmdExecuteCommands-pCommandBuffers-00088
+ // VUID-vkCmdExecuteCommands-pCommandBuffers-00089
+ // Ensured by the SecondaryCommandBuffer trait.
+
+ // TODO: sync check
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn execute_commands_unchecked(
+ &mut self,
+ command_buffer: SecondaryCommandBuffer<impl CommandBufferAlloc + 'static>,
+ ) -> &mut Self {
+ struct DropUnlock<As>(SecondaryCommandBuffer<As>)
+ where
+ As: CommandBufferAlloc;
+
+ impl<As> std::ops::Deref for DropUnlock<As>
+ where
+ As: CommandBufferAlloc,
+ {
+ type Target = SecondaryCommandBuffer<As>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+ }
+ unsafe impl<As> SafeDeref for DropUnlock<As> where As: CommandBufferAlloc {}
+
+ impl<As> Drop for DropUnlock<As>
+ where
+ As: CommandBufferAlloc,
+ {
+ fn drop(&mut self) {
+ unsafe {
+ self.unlock();
+ }
+ }
+ }
+
+ let command_buffer = {
+ command_buffer.lock_record().unwrap();
+ DropUnlock(command_buffer)
+ };
+
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_execute_commands)(self.handle(), 1, &command_buffer.handle());
+
+ // The secondary command buffer could leave the primary in any state.
+ self.builder_state = Default::default();
+
+ // If the secondary is non-concurrent or one-time use, that restricts the primary as well.
+ self.usage = std::cmp::min(self.usage, command_buffer.usage);
+
+ let _command_index = self.next_command_index;
+ let _command_name = "execute_commands";
+
+ // TODO: sync state update
+
+ self.resources.push(Box::new(command_buffer));
+
+ self.next_command_index += 1;
+ self
+ }
+}
diff --git a/src/command_buffer/standard/builder/sync.rs b/src/command_buffer/standard/builder/sync.rs
new file mode 100644
index 0000000..c608194
--- /dev/null
+++ b/src/command_buffer/standard/builder/sync.rs
@@ -0,0 +1,4459 @@
+// Copyright (c) 2022 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use super::{CommandBufferBuilder, RenderPassStateType};
+use crate::{
+ command_buffer::allocator::CommandBufferAllocator,
+ device::{DeviceOwned, QueueFlags},
+ image::{ImageAspects, ImageCreateFlags, ImageLayout, ImageUsage},
+ sync::{
+ event::Event, AccessFlags, BufferMemoryBarrier, DependencyFlags, DependencyInfo,
+ ImageMemoryBarrier, MemoryBarrier, PipelineStages, QueueFamilyOwnershipTransfer, Sharing,
+ },
+ DeviceSize, RequirementNotMet, RequiresOneOf, Version, VulkanObject,
+};
+use smallvec::SmallVec;
+use std::{
+ cmp::max,
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+ ptr,
+ sync::Arc,
+};
+
+impl<L, A> CommandBufferBuilder<L, A>
+where
+ A: CommandBufferAllocator,
+{
+ /// Inserts a memory dependency into the queue.
+ ///
+ /// A pipeline barrier is the primary means of synchronizing work within a single queue.
+ /// Without a pipeline barrier, all commands in a queue could complete out of order, and there
+ /// would be no guarantee about the ordering of memory accesses. When a dependency is inserted,
+ /// a chosen subset of operations after the barrier (the destination synchronization scope)
+ /// depend on, and therefore must wait for the completion of, a chosen subset operations before
+ /// barrier (the source synchronization scope).
+ ///
+ /// When the queue has to wait, it may not be doing useful work, so barriers should be kept to
+ /// the minimum needed to ensure proper functioning. Overly broad barriers, specifying
+ /// a larger class of operations than needed (especially [`ALL_COMMANDS`]), can slow down the
+ /// queue and make it work less efficiently.
+ ///
+ /// In addition to ensuring correct operation, pipeline barriers are also used to transition
+ /// images (or parts of images) from one [image layout] to another.
+ ///
+ /// # Safety
+ ///
+ /// - All images that are accessed by the command must be in the expected image layout.
+ /// - For each element of `dependency_info.image_memory_barriers` that contains an image layout
+ /// transition, which is a write operation, the barrier must be defined appropriately to
+ /// ensure no memory access hazard occurs.
+ ///
+ /// [`ALL_COMMANDS`]: PipelineStages::ALL_COMMANDS
+ /// [image layout]: ImageLayout
+ #[inline]
+ pub unsafe fn pipeline_barrier(
+ &mut self,
+ dependency_info: DependencyInfo,
+ ) -> Result<&mut Self, SynchronizationError> {
+ self.validate_pipeline_barrier(&dependency_info)?;
+
+ unsafe { Ok(self.pipeline_barrier_unchecked(dependency_info)) }
+ }
+
+ fn validate_pipeline_barrier(
+ &self,
+ dependency_info: &DependencyInfo,
+ ) -> Result<(), SynchronizationError> {
+ let device = self.device();
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdPipelineBarrier2-commandBuffer-cmdpool
+ if !queue_family_properties.queue_flags.intersects(
+ QueueFlags::TRANSFER
+ | QueueFlags::GRAPHICS
+ | QueueFlags::COMPUTE
+ | QueueFlags::VIDEO_DECODE
+ | QueueFlags::VIDEO_ENCODE,
+ ) {
+ return Err(SynchronizationError::NotSupportedByQueueFamily);
+ }
+
+ let &DependencyInfo {
+ dependency_flags,
+ ref memory_barriers,
+ ref buffer_memory_barriers,
+ ref image_memory_barriers,
+ _ne: _,
+ } = dependency_info;
+
+ // VUID-VkDependencyInfo-dependencyFlags-parameter
+ dependency_flags.validate_device(device)?;
+
+ let check_stages_access = |ty: char,
+ barrier_index: usize,
+ src_stages: PipelineStages,
+ src_access: AccessFlags,
+ dst_stages: PipelineStages,
+ dst_access: AccessFlags|
+ -> Result<(), SynchronizationError> {
+ for (stages, access) in [(src_stages, src_access), (dst_stages, dst_access)] {
+ // VUID-vkCmdPipelineBarrier2-synchronization2-03848
+ if !device.enabled_features().synchronization2 {
+ if stages.is_2() {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where \
+ `src_stages` or `dst_stages` contains flags from \
+ `VkPipelineStageFlagBits2`",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }
+
+ if access.is_2() {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where \
+ `src_access` or `dst_access` contains flags from \
+ `VkAccessFlagBits2`",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-parameter
+ // VUID-VkMemoryBarrier2-dstStageMask-parameter
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-parameter
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-parameter
+ // VUID-VkImageMemoryBarrier2-srcStageMask-parameter
+ // VUID-VkImageMemoryBarrier2-dstStageMask-parameter
+ stages.validate_device(device)?;
+
+ // VUID-VkMemoryBarrier2-srcAccessMask-parameter
+ // VUID-VkMemoryBarrier2-dstAccessMask-parameter
+ // VUID-VkBufferMemoryBarrier2-srcAccessMask-parameter
+ // VUID-VkBufferMemoryBarrier2-dstAccessMask-parameter
+ // VUID-VkImageMemoryBarrier2-srcAccessMask-parameter
+ // VUID-VkImageMemoryBarrier2-dstAccessMask-parameter
+ access.validate_device(device)?;
+
+ // VUID-vkCmdPipelineBarrier2-srcStageMask-03849
+ // VUID-vkCmdPipelineBarrier2-dstStageMask-03850
+ if !PipelineStages::from(queue_family_properties.queue_flags).contains(stages) {
+ match ty {
+ 'm' => {
+ return Err(SynchronizationError::MemoryBarrierStageNotSupported {
+ barrier_index,
+ })
+ }
+ 'b' => {
+ return Err(
+ SynchronizationError::BufferMemoryBarrierStageNotSupported {
+ barrier_index,
+ },
+ )
+ }
+ 'i' => {
+ return Err(SynchronizationError::ImageMemoryBarrierStageNotSupported {
+ barrier_index,
+ })
+ }
+ _ => unreachable!(),
+ }
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03929
+ // VUID-VkMemoryBarrier2-dstStageMask-03929
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03929
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03929
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03930
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03930
+ if stages.intersects(PipelineStages::GEOMETRY_SHADER)
+ && !device.enabled_features().geometry_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::GEOMETRY_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["geometry_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03930
+ // VUID-VkMemoryBarrier2-dstStageMask-03930
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03930
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03930
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03930
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03930
+ if stages.intersects(
+ PipelineStages::TESSELLATION_CONTROL_SHADER
+ | PipelineStages::TESSELLATION_EVALUATION_SHADER,
+ ) && !device.enabled_features().tessellation_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::TESSELLATION_CONTROL_SHADER` or \
+ `PipelineStages::TESSELLATION_EVALUATION_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["tessellation_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03931
+ // VUID-VkMemoryBarrier2-dstStageMask-03931
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03931
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03931
+ // VUID-VImagekMemoryBarrier2-srcStageMask-03931
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03931
+ if stages.intersects(PipelineStages::CONDITIONAL_RENDERING)
+ && !device.enabled_features().conditional_rendering
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::CONDITIONAL_RENDERING`",
+ requires_one_of: RequiresOneOf {
+ features: &["conditional_rendering"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03932
+ // VUID-VkMemoryBarrier2-dstStageMask-03932
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03932
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03932
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03932
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03932
+ if stages.intersects(PipelineStages::FRAGMENT_DENSITY_PROCESS)
+ && !device.enabled_features().fragment_density_map
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::FRAGMENT_DENSITY_PROCESS`",
+ requires_one_of: RequiresOneOf {
+ features: &["fragment_density_map"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03933
+ // VUID-VkMemoryBarrier2-dstStageMask-03933
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03933
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03933
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03933
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03933
+ if stages.intersects(PipelineStages::TRANSFORM_FEEDBACK)
+ && !device.enabled_features().transform_feedback
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::TRANSFORM_FEEDBACK`",
+ requires_one_of: RequiresOneOf {
+ features: &["transform_feedback"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03934
+ // VUID-VkMemoryBarrier2-dstStageMask-03934
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03934
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03934
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03934
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03934
+ if stages.intersects(PipelineStages::MESH_SHADER)
+ && !device.enabled_features().mesh_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::MESH_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["mesh_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03935
+ // VUID-VkMemoryBarrier2-dstStageMask-03935
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03935
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03935
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03935
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03935
+ if stages.intersects(PipelineStages::TASK_SHADER)
+ && !device.enabled_features().task_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::TASK_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["task_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-shadingRateImage-07316
+ // VUID-VkMemoryBarrier2-shadingRateImage-07316
+ // VUID-VkBufferMemoryBarrier2-shadingRateImage-07316
+ // VUID-VkBufferMemoryBarrier2-shadingRateImage-07316
+ // VUID-VkImageMemoryBarrier2-shadingRateImage-07316
+ // VUID-VkImageMemoryBarrier2-shadingRateImage-07316
+ if stages.intersects(PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT)
+ && !(device.enabled_features().attachment_fragment_shading_rate
+ || device.enabled_features().shading_rate_image)
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT`",
+ requires_one_of: RequiresOneOf {
+ features: &["attachment_fragment_shading_rate", "shading_rate_image"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-04957
+ // VUID-VkMemoryBarrier2-dstStageMask-04957
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-04957
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-04957
+ // VUID-VkImageMemoryBarrier2-srcStageMask-04957
+ // VUID-VkImageMemoryBarrier2-dstStageMask-04957
+ if stages.intersects(PipelineStages::SUBPASS_SHADING)
+ && !device.enabled_features().subpass_shading
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::SUBPASS_SHADING`",
+ requires_one_of: RequiresOneOf {
+ features: &["subpass_shading"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-04995
+ // VUID-VkMemoryBarrier2-dstStageMask-04995
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-04995
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-04995
+ // VUID-VkImageMemoryBarrier2-srcStageMask-04995
+ // VUID-VkImageMemoryBarrier2-dstStageMask-04995
+ if stages.intersects(PipelineStages::INVOCATION_MASK)
+ && !device.enabled_features().invocation_mask
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::INVOCATION_MASK`",
+ requires_one_of: RequiresOneOf {
+ features: &["invocation_mask"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdPipelineBarrier-srcStageMask-03937
+ // VUID-vkCmdPipelineBarrier-dstStageMask-03937
+ if stages.is_empty() && !device.enabled_features().synchronization2 {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ is empty",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // A bit of a ridiculous number of VUIDs...
+
+ // VUID-VkMemoryBarrier2-srcAccessMask-03900
+ // ..
+ // VUID-VkMemoryBarrier2-srcAccessMask-07458
+
+ // VUID-VkMemoryBarrier2-dstAccessMask-03900
+ // ..
+ // VUID-VkMemoryBarrier2-dstAccessMask-07458
+
+ // VUID-VkBufferMemoryBarrier2-srcAccessMask-03900
+ // ..
+ // VUID-VkBufferMemoryBarrier2-srcAccessMask-07458
+
+ // VUID-VkBufferMemoryBarrier2-dstAccessMask-03900
+ // ..
+ // VUID-VkBufferMemoryBarrier2-dstAccessMask-07458
+
+ // VUID-VkImageMemoryBarrier2-srcAccessMask-03900
+ // ..
+ // VUID-VkImageMemoryBarrier2-srcAccessMask-07458
+
+ // VUID-VkImageMemoryBarrier2-dstAccessMask-03900
+ // ..
+ // VUID-VkImageMemoryBarrier2-dstAccessMask-07458
+
+ if !AccessFlags::from(stages).contains(access) {
+ match ty {
+ 'm' => {
+ return Err(
+ SynchronizationError::MemoryBarrierAccessNotSupportedByStages {
+ barrier_index,
+ },
+ )
+ }
+ 'b' => return Err(
+ SynchronizationError::BufferMemoryBarrierAccessNotSupportedByStages {
+ barrier_index,
+ },
+ ),
+ 'i' => return Err(
+ SynchronizationError::ImageMemoryBarrierAccessNotSupportedByStages {
+ barrier_index,
+ },
+ ),
+ _ => unreachable!(),
+ }
+ }
+ }
+
+ // VUID-VkMemoryBarrier2-srcAccessMask-06256
+ // VUID-VkBufferMemoryBarrier2-srcAccessMask-06256
+ // VUID-VkImageMemoryBarrier2-srcAccessMask-06256
+ if !device.enabled_features().ray_query
+ && src_access.intersects(AccessFlags::ACCELERATION_STRUCTURE_READ)
+ && src_stages.intersects(
+ PipelineStages::VERTEX_SHADER
+ | PipelineStages::TESSELLATION_CONTROL_SHADER
+ | PipelineStages::TESSELLATION_EVALUATION_SHADER
+ | PipelineStages::GEOMETRY_SHADER
+ | PipelineStages::FRAGMENT_SHADER
+ | PipelineStages::COMPUTE_SHADER
+ | PipelineStages::PRE_RASTERIZATION_SHADERS
+ | PipelineStages::TASK_SHADER
+ | PipelineStages::MESH_SHADER,
+ )
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where \
+ `src_access` contains `ACCELERATION_STRUCTURE_READ`, and \
+ `src_stages` contains a shader stage other than `RAY_TRACING_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["ray_query"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ };
+
+ let check_queue_family_ownership_transfer = |ty: char,
+ barrier_index: usize,
+ src_stages: PipelineStages,
+ dst_stages: PipelineStages,
+ queue_family_ownership_transfer: Option<
+ QueueFamilyOwnershipTransfer,
+ >,
+ sharing: &Sharing<_>|
+ -> Result<(), SynchronizationError> {
+ if let Some(transfer) = queue_family_ownership_transfer {
+ // VUID?
+ transfer.validate_device(device)?;
+
+ // VUID-VkBufferMemoryBarrier2-srcQueueFamilyIndex-04087
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-04070
+ // Ensured by the definition of `QueueFamilyOwnershipTransfer`.
+
+ // VUID-VkBufferMemoryBarrier2-buffer-04088
+ // VUID-VkImageMemoryBarrier2-image-04071
+ // Ensured by the definition of `QueueFamilyOwnershipTransfer`.
+
+ let queue_family_count =
+ device.physical_device().queue_family_properties().len() as u32;
+
+ let provided_queue_family_index = match (sharing, transfer) {
+ (
+ Sharing::Exclusive,
+ QueueFamilyOwnershipTransfer::ExclusiveBetweenLocal {
+ src_index,
+ dst_index,
+ },
+ ) => Some(max(src_index, dst_index)),
+ (
+ Sharing::Exclusive,
+ QueueFamilyOwnershipTransfer::ExclusiveToExternal { src_index }
+ | QueueFamilyOwnershipTransfer::ExclusiveToForeign { src_index },
+ ) => Some(src_index),
+ (
+ Sharing::Exclusive,
+ QueueFamilyOwnershipTransfer::ExclusiveFromExternal { dst_index }
+ | QueueFamilyOwnershipTransfer::ExclusiveFromForeign { dst_index },
+ ) => Some(dst_index),
+ (
+ Sharing::Concurrent(_),
+ QueueFamilyOwnershipTransfer::ConcurrentToExternal
+ | QueueFamilyOwnershipTransfer::ConcurrentFromExternal
+ | QueueFamilyOwnershipTransfer::ConcurrentToForeign
+ | QueueFamilyOwnershipTransfer::ConcurrentFromForeign,
+ ) => None,
+ _ => match ty {
+ 'b' => return Err(SynchronizationError::BufferMemoryBarrierOwnershipTransferSharingMismatch {
+ barrier_index,
+ }),
+ 'i' => return Err(SynchronizationError::ImageMemoryBarrierOwnershipTransferSharingMismatch {
+ barrier_index,
+ }),
+ _ => unreachable!(),
+ },
+ }.filter(|&index| index >= queue_family_count);
+
+ // VUID-VkBufferMemoryBarrier2-buffer-04089
+ // VUID-VkImageMemoryBarrier2-image-04072
+
+ if let Some(provided_queue_family_index) = provided_queue_family_index {
+ match ty {
+ 'b' => return Err(SynchronizationError::BufferMemoryBarrierOwnershipTransferIndexOutOfRange {
+ barrier_index,
+ provided_queue_family_index,
+ queue_family_count,
+ }),
+ 'i' => return Err(SynchronizationError::ImageMemoryBarrierOwnershipTransferIndexOutOfRange {
+ barrier_index,
+ provided_queue_family_index,
+ queue_family_count,
+ }),
+ _ => unreachable!(),
+ }
+ }
+
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03851
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03854
+ if src_stages.intersects(PipelineStages::HOST)
+ || dst_stages.intersects(PipelineStages::HOST)
+ {
+ match ty {
+ 'b' => return Err(SynchronizationError::BufferMemoryBarrierOwnershipTransferHostNotAllowed {
+ barrier_index,
+ }),
+ 'i' => return Err(SynchronizationError::ImageMemoryBarrierOwnershipTransferHostForbidden {
+ barrier_index,
+ }),
+ _ => unreachable!(),
+ }
+ }
+ }
+
+ Ok(())
+ };
+
+ for (barrier_index, barrier) in memory_barriers.iter().enumerate() {
+ let &MemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ _ne: _,
+ } = barrier;
+
+ /*
+ Check stages and access
+ */
+
+ check_stages_access(
+ 'm',
+ barrier_index,
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ )?;
+ }
+
+ for (barrier_index, barrier) in buffer_memory_barriers.iter().enumerate() {
+ let &BufferMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ queue_family_ownership_transfer,
+ ref buffer,
+ ref range,
+ _ne: _,
+ } = barrier;
+
+ // VUID-VkBufferMemoryBarrier2-buffer-01931
+ // Ensured by Buffer type construction.
+
+ /*
+ Check stages and access
+ */
+
+ check_stages_access(
+ 'b',
+ barrier_index,
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ )?;
+
+ /*
+ Check queue family transfer
+ */
+
+ check_queue_family_ownership_transfer(
+ 'b',
+ barrier_index,
+ src_stages,
+ dst_stages,
+ queue_family_ownership_transfer,
+ buffer.sharing(),
+ )?;
+
+ /*
+ Check range
+ */
+
+ // VUID-VkBufferMemoryBarrier2-size-01188
+ assert!(!range.is_empty());
+
+ // VUID-VkBufferMemoryBarrier2-offset-01187
+ // VUID-VkBufferMemoryBarrier2-size-01189
+ if range.end > buffer.size() {
+ return Err(SynchronizationError::BufferMemoryBarrierOutOfRange {
+ barrier_index,
+ range_end: range.end,
+ buffer_size: buffer.size(),
+ });
+ }
+ }
+
+ for (barrier_index, barrier) in image_memory_barriers.iter().enumerate() {
+ let &ImageMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ old_layout,
+ new_layout,
+ queue_family_ownership_transfer,
+ ref image,
+ ref subresource_range,
+ _ne: _,
+ } = barrier;
+
+ // VUID-VkImageMemoryBarrier2-image-01932
+ // Ensured by Image type construction.
+
+ /*
+ Check stages and access
+ */
+
+ check_stages_access(
+ 'i',
+ barrier_index,
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ )?;
+
+ /*
+ Check layouts
+ */
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-parameter
+ old_layout.validate_device(device)?;
+
+ // VUID-VkImageMemoryBarrier2-newLayout-parameter
+ new_layout.validate_device(device)?;
+
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03855
+ if src_stages.intersects(PipelineStages::HOST)
+ && !matches!(
+ old_layout,
+ ImageLayout::Preinitialized | ImageLayout::Undefined | ImageLayout::General
+ )
+ {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierOldLayoutFromHostInvalid {
+ barrier_index,
+ old_layout,
+ },
+ );
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01197
+ // Not checked yet, therefore unsafe.
+
+ // VUID-VkImageMemoryBarrier2-newLayout-01198
+ if matches!(
+ new_layout,
+ ImageLayout::Undefined | ImageLayout::Preinitialized
+ ) {
+ return Err(SynchronizationError::ImageMemoryBarrierNewLayoutInvalid {
+ barrier_index,
+ });
+ }
+
+ // VUID-VkImageMemoryBarrier2-attachmentFeedbackLoopLayout-07313
+ /*if !device.enabled_features().attachment_feedback_loop_layout
+ && matches!(new_layout, ImageLayout::AttachmentFeedbackLoopOptimal)
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`dependency_info.image_memory_barriers` has an element where \
+ `new_layout` is `AttachmentFeedbackLoopOptimal`",
+ requires_one_of: RequiresOneOf {
+ features: &["attachment_feedback_loop_layout"],
+ ..Default::default()
+ },
+ });
+ }*/
+
+ for layout in [old_layout, new_layout] {
+ // VUID-VkImageMemoryBarrier2-synchronization2-06911
+ /*if !device.enabled_features().synchronization2
+ && matches!(
+ layout,
+ ImageLayout::AttachmentOptimal | ImageLayout::ReadOnlyOptimal
+ )
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`dependency_info.image_memory_barriers` has an element \
+ where `old_layout` or `new_layout` is `AttachmentOptimal` or \
+ `ReadOnlyOptimal`",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }*/
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-07006
+ /*if layout == ImageLayout::AttachmentFeedbackLoopOptimal {
+ if !image.usage().intersects(
+ ImageUsage::COLOR_ATTACHMENT | ImageUsage::DEPTH_STENCIL_ATTACHMENT,
+ ) {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierImageMissingUsageForLayout {
+ barrier_index,
+ layout,
+ requires_one_of_usage: ImageUsage::COLOR_ATTACHMENT
+ | ImageUsage::DEPTH_STENCIL_ATTACHMENT,
+ },
+ );
+ }
+
+ if !image
+ .usage()
+ .intersects(ImageUsage::INPUT_ATTACHMENT | ImageUsage::SAMPLED)
+ {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierImageMissingUsageForLayout {
+ barrier_index,
+ layout,
+ requires_one_of_usage: ImageUsage::INPUT_ATTACHMENT
+ | ImageUsage::SAMPLED,
+ },
+ );
+ }
+
+ if !image
+ .usage()
+ .intersects(ImageUsage::ATTACHMENT_FEEDBACK_LOOP)
+ {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierImageMissingUsageForLayout {
+ barrier_index,
+ layout,
+ requires_one_of_usage: ImageUsage::ATTACHMENT_FEEDBACK_LOOP,
+ },
+ );
+ }
+ }*/
+
+ let requires_one_of_usage = match layout {
+ // VUID-VkImageMemoryBarrier2-oldLayout-01208
+ ImageLayout::ColorAttachmentOptimal => ImageUsage::COLOR_ATTACHMENT,
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01209
+ ImageLayout::DepthStencilAttachmentOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01210
+ ImageLayout::DepthStencilReadOnlyOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01211
+ ImageLayout::ShaderReadOnlyOptimal => {
+ ImageUsage::SAMPLED | ImageUsage::INPUT_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01212
+ ImageLayout::TransferSrcOptimal => ImageUsage::TRANSFER_SRC,
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01213
+ ImageLayout::TransferDstOptimal => ImageUsage::TRANSFER_DST,
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01658
+ ImageLayout::DepthReadOnlyStencilAttachmentOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01659
+ ImageLayout::DepthAttachmentStencilReadOnlyOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ }
+
+ /*
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-04065
+ ImageLayout::DepthReadOnlyOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ | ImageUsage::SAMPLED
+ | ImageUsage::INPUT_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-04066
+ ImageLayout::DepthAttachmentOptimal => ImageUsage::DEPTH_STENCIL_ATTACHMENT,
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-04067
+ ImageLayout::StencilReadOnlyOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ | ImageUsage::SAMPLED
+ | ImageUsage::INPUT_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-04068
+ ImageLayout::StencilAttachmentOptimal => ImageUsage::DEPTH_STENCIL_ATTACHMENT,
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-03938
+ ImageLayout::AttachmentOptimal => {
+ ImageUsage::COLOR_ATTACHMENT | ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-03939
+ ImageLayout::ReadOnlyOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ | ImageUsage::SAMPLED
+ | ImageUsage::INPUT_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-02088
+ ImageLayout::FragmentShadingRateAttachmentOptimal => {
+ ImageUsage::FRAGMENT_SHADING_RATE_ATTACHMENT
+ }
+ */
+ _ => continue,
+ };
+
+ if !image.usage().intersects(requires_one_of_usage) {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierImageMissingUsageForLayout {
+ barrier_index,
+ layout,
+ requires_one_of_usage,
+ },
+ );
+ }
+ }
+
+ /*
+ Check queue family tansfer
+ */
+
+ check_queue_family_ownership_transfer(
+ 'i',
+ barrier_index,
+ src_stages,
+ dst_stages,
+ queue_family_ownership_transfer,
+ image.sharing(),
+ )?;
+
+ /*
+ Check subresource range
+ */
+
+ // VUID-VkImageSubresourceRange-aspectMask-requiredbitmask
+ assert!(!subresource_range.aspects.is_empty());
+
+ // VUID-VkImageSubresourceRange-aspectMask-parameter
+ subresource_range.aspects.validate_device(device)?;
+
+ let image_aspects = image.format().unwrap().aspects();
+
+ // VUID-VkImageMemoryBarrier2-image-01673
+ // VUID-VkImageMemoryBarrier2-image-03319
+ if image_aspects.contains(subresource_range.aspects) {
+ return Err(SynchronizationError::ImageMemoryBarrierAspectsNotAllowed {
+ barrier_index,
+ aspects: subresource_range.aspects - image_aspects,
+ });
+ }
+
+ if image_aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL) {
+ // VUID-VkImageMemoryBarrier2-image-03320
+ if !device.enabled_features().separate_depth_stencil_layouts
+ && image_aspects.contains(ImageAspects::DEPTH | ImageAspects::STENCIL)
+ && !subresource_range
+ .aspects
+ .contains(ImageAspects::DEPTH | ImageAspects::STENCIL)
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`dependency_info.image_memory_barriers` has an element \
+ where `image` has both a depth and a stencil aspect, and \
+ `subresource_range.aspects` does not contain both aspects",
+ requires_one_of: RequiresOneOf {
+ features: &["separate_depth_stencil_layouts"],
+ ..Default::default()
+ },
+ });
+ }
+ } else {
+ // VUID-VkImageMemoryBarrier2-image-01671
+ if !image.flags().intersects(ImageCreateFlags::DISJOINT)
+ && subresource_range.aspects != ImageAspects::COLOR
+ {
+ return Err(SynchronizationError::ImageMemoryBarrierAspectsNotAllowed {
+ barrier_index,
+ aspects: subresource_range.aspects - ImageAspects::COLOR,
+ });
+ }
+ }
+
+ // VUID-VkImageSubresourceRange-levelCount-01720
+ assert!(!subresource_range.mip_levels.is_empty());
+
+ // VUID-VkImageMemoryBarrier2-subresourceRange-01486
+ // VUID-VkImageMemoryBarrier2-subresourceRange-01724
+ if subresource_range.mip_levels.end > image.mip_levels() {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierMipLevelsOutOfRange {
+ barrier_index,
+ mip_levels_range_end: subresource_range.mip_levels.end,
+ image_mip_levels: image.mip_levels(),
+ },
+ );
+ }
+
+ // VUID-VkImageSubresourceRange-layerCount-01721
+ assert!(!subresource_range.array_layers.is_empty());
+
+ // VUID-VkImageMemoryBarrier2-subresourceRange-01488
+ // VUID-VkImageMemoryBarrier2-subresourceRange-01725
+ if subresource_range.array_layers.end > image.dimensions().array_layers() {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierArrayLayersOutOfRange {
+ barrier_index,
+ array_layers_range_end: subresource_range.array_layers.end,
+ image_array_layers: image.dimensions().array_layers(),
+ },
+ );
+ }
+ }
+
+ /*
+ Checks for current render pass
+ */
+
+ if let Some(render_pass_state) = self.builder_state.render_pass.as_ref() {
+ // VUID-vkCmdPipelineBarrier2-None-06191
+ let begin_render_pass_state = match &render_pass_state.render_pass {
+ RenderPassStateType::BeginRenderPass(x) => x,
+ RenderPassStateType::BeginRendering(_) => {
+ return Err(SynchronizationError::ForbiddenWithBeginRendering)
+ }
+ };
+ let subpass_index = begin_render_pass_state.subpass.index();
+ let subpass_desc = begin_render_pass_state.subpass.subpass_desc();
+ let dependencies = begin_render_pass_state.subpass.render_pass().dependencies();
+
+ // VUID-vkCmdPipelineBarrier2-pDependencies-02285
+ // TODO: see https://github.com/KhronosGroup/Vulkan-Docs/issues/1982
+ if !dependencies.iter().any(|dependency| {
+ dependency.src_subpass == Some(subpass_index)
+ && dependency.dst_subpass == Some(subpass_index)
+ }) {
+ return Err(SynchronizationError::MemoryBarrierNoMatchingSubpassSelfDependency);
+ }
+
+ // VUID-vkCmdPipelineBarrier2-bufferMemoryBarrierCount-01178
+ if !buffer_memory_barriers.is_empty() {
+ return Err(SynchronizationError::BufferMemoryBarrierForbiddenInsideRenderPass);
+ }
+
+ for (barrier_index, barrier) in image_memory_barriers.iter().enumerate() {
+ // VUID-vkCmdPipelineBarrier2-image-04073
+ // TODO: How are you supposed to verify this in secondary command buffers,
+ // when there is no inherited framebuffer?
+ // The image is not known until you execute it in a primary command buffer.
+ if let Some(framebuffer) = &begin_render_pass_state.framebuffer {
+ let attachment_index = (framebuffer.attachments().iter())
+ .position(|attachment| attachment.image().inner().image == &barrier.image)
+ .ok_or(SynchronizationError::ImageMemoryBarrierNotInputAttachment {
+ barrier_index,
+ })? as u32;
+
+ if !(subpass_desc.input_attachments.iter().flatten())
+ .any(|atch_ref| atch_ref.attachment == attachment_index)
+ {
+ return Err(SynchronizationError::ImageMemoryBarrierNotInputAttachment {
+ barrier_index,
+ });
+ }
+
+ if !(subpass_desc.color_attachments.iter().flatten())
+ .chain(subpass_desc.depth_stencil_attachment.as_ref())
+ .any(|atch_ref| atch_ref.attachment == attachment_index)
+ {
+ return Err(SynchronizationError::ImageMemoryBarrierNotColorDepthStencilAttachment {
+ barrier_index,
+ });
+ }
+ }
+
+ // VUID-vkCmdPipelineBarrier2-oldLayout-01181
+ if barrier.old_layout != barrier.new_layout {
+ return Err(SynchronizationError::ImageMemoryBarrierLayoutTransitionForbiddenInsideRenderPass {
+ barrier_index,
+ });
+ }
+
+ // VUID-vkCmdPipelineBarrier2-srcQueueFamilyIndex-01182
+ if barrier.queue_family_ownership_transfer.is_some() {
+ return Err(SynchronizationError::ImageMemoryBarrierOwnershipTransferForbiddenInsideRenderPass {
+ barrier_index,
+ });
+ }
+ }
+ } else {
+ // VUID-vkCmdPipelineBarrier2-dependencyFlags-01186
+ if dependency_flags.intersects(DependencyFlags::VIEW_LOCAL) {
+ return Err(SynchronizationError::DependencyFlagsViewLocalNotAllowed);
+ }
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn pipeline_barrier_unchecked(
+ &mut self,
+ dependency_info: DependencyInfo,
+ ) -> &mut Self {
+ if dependency_info.is_empty() {
+ return self;
+ }
+
+ let &DependencyInfo {
+ dependency_flags,
+ ref memory_barriers,
+ ref buffer_memory_barriers,
+ ref image_memory_barriers,
+ _ne: _,
+ } = &dependency_info;
+
+ if self.device().enabled_features().synchronization2 {
+ let memory_barriers_vk: SmallVec<[_; 2]> = memory_barriers
+ .iter()
+ .map(|barrier| {
+ let &MemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ _ne: _,
+ } = barrier;
+
+ ash::vk::MemoryBarrier2 {
+ src_stage_mask: src_stages.into(),
+ src_access_mask: src_access.into(),
+ dst_stage_mask: dst_stages.into(),
+ dst_access_mask: dst_access.into(),
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let buffer_memory_barriers_vk: SmallVec<[_; 8]> = buffer_memory_barriers
+ .iter()
+ .map(|barrier| {
+ let &BufferMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ queue_family_ownership_transfer,
+ ref buffer,
+ ref range,
+ _ne: _,
+ } = barrier;
+
+ let (src_queue_family_index, dst_queue_family_index) =
+ queue_family_ownership_transfer.map_or(
+ (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED),
+ Into::into,
+ );
+
+ ash::vk::BufferMemoryBarrier2 {
+ src_stage_mask: src_stages.into(),
+ src_access_mask: src_access.into(),
+ dst_stage_mask: dst_stages.into(),
+ dst_access_mask: dst_access.into(),
+ src_queue_family_index,
+ dst_queue_family_index,
+ buffer: buffer.handle(),
+ offset: range.start,
+ size: range.end - range.start,
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let image_memory_barriers_vk: SmallVec<[_; 8]> = image_memory_barriers
+ .iter()
+ .map(|barrier| {
+ let &ImageMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ old_layout,
+ new_layout,
+ queue_family_ownership_transfer,
+ ref image,
+ ref subresource_range,
+ _ne: _,
+ } = barrier;
+
+ let (src_queue_family_index, dst_queue_family_index) =
+ queue_family_ownership_transfer.map_or(
+ (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED),
+ Into::into,
+ );
+
+ ash::vk::ImageMemoryBarrier2 {
+ src_stage_mask: src_stages.into(),
+ src_access_mask: src_access.into(),
+ dst_stage_mask: dst_stages.into(),
+ dst_access_mask: dst_access.into(),
+ old_layout: old_layout.into(),
+ new_layout: new_layout.into(),
+ src_queue_family_index,
+ dst_queue_family_index,
+ image: image.handle(),
+ subresource_range: subresource_range.clone().into(),
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let dependency_info_vk = ash::vk::DependencyInfo {
+ dependency_flags: dependency_flags.into(),
+ memory_barrier_count: memory_barriers_vk.len() as u32,
+ p_memory_barriers: memory_barriers_vk.as_ptr(),
+ buffer_memory_barrier_count: buffer_memory_barriers_vk.len() as u32,
+ p_buffer_memory_barriers: buffer_memory_barriers_vk.as_ptr(),
+ image_memory_barrier_count: image_memory_barriers_vk.len() as u32,
+ p_image_memory_barriers: image_memory_barriers_vk.as_ptr(),
+ ..Default::default()
+ };
+
+ let fns = self.device().fns();
+
+ if self.device().api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_pipeline_barrier2)(self.handle(), &dependency_info_vk);
+ } else {
+ debug_assert!(self.device().enabled_extensions().khr_synchronization2);
+ (fns.khr_synchronization2.cmd_pipeline_barrier2_khr)(
+ self.handle(),
+ &dependency_info_vk,
+ );
+ }
+ } else {
+ let mut src_stage_mask = ash::vk::PipelineStageFlags::empty();
+ let mut dst_stage_mask = ash::vk::PipelineStageFlags::empty();
+
+ let memory_barriers_vk: SmallVec<[_; 2]> = memory_barriers
+ .iter()
+ .map(|barrier| {
+ let &MemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ _ne: _,
+ } = barrier;
+
+ src_stage_mask |= src_stages.into();
+ dst_stage_mask |= dst_stages.into();
+
+ ash::vk::MemoryBarrier {
+ src_access_mask: src_access.into(),
+ dst_access_mask: dst_access.into(),
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let buffer_memory_barriers_vk: SmallVec<[_; 8]> = buffer_memory_barriers
+ .iter()
+ .map(|barrier| {
+ let &BufferMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ queue_family_ownership_transfer,
+ ref buffer,
+ ref range,
+ _ne: _,
+ } = barrier;
+
+ src_stage_mask |= src_stages.into();
+ dst_stage_mask |= dst_stages.into();
+
+ let (src_queue_family_index, dst_queue_family_index) =
+ queue_family_ownership_transfer.map_or(
+ (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED),
+ Into::into,
+ );
+
+ ash::vk::BufferMemoryBarrier {
+ src_access_mask: src_access.into(),
+ dst_access_mask: dst_access.into(),
+ src_queue_family_index,
+ dst_queue_family_index,
+ buffer: buffer.handle(),
+ offset: range.start,
+ size: range.end - range.start,
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let image_memory_barriers_vk: SmallVec<[_; 8]> = image_memory_barriers
+ .iter()
+ .map(|barrier| {
+ let &ImageMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ old_layout,
+ new_layout,
+ queue_family_ownership_transfer,
+ ref image,
+ ref subresource_range,
+ _ne: _,
+ } = barrier;
+
+ src_stage_mask |= src_stages.into();
+ dst_stage_mask |= dst_stages.into();
+
+ let (src_queue_family_index, dst_queue_family_index) =
+ queue_family_ownership_transfer.map_or(
+ (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED),
+ Into::into,
+ );
+
+ ash::vk::ImageMemoryBarrier {
+ src_access_mask: src_access.into(),
+ dst_access_mask: dst_access.into(),
+ old_layout: old_layout.into(),
+ new_layout: new_layout.into(),
+ src_queue_family_index,
+ dst_queue_family_index,
+ image: image.handle(),
+ subresource_range: subresource_range.clone().into(),
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ if src_stage_mask.is_empty() {
+ // "VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT is [...] equivalent to
+ // VK_PIPELINE_STAGE_2_NONE in the first scope."
+ src_stage_mask |= ash::vk::PipelineStageFlags::TOP_OF_PIPE;
+ }
+
+ if dst_stage_mask.is_empty() {
+ // "VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT is [...] equivalent to
+ // VK_PIPELINE_STAGE_2_NONE in the second scope."
+ dst_stage_mask |= ash::vk::PipelineStageFlags::BOTTOM_OF_PIPE;
+ }
+
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_pipeline_barrier)(
+ self.handle(),
+ src_stage_mask,
+ dst_stage_mask,
+ dependency_flags.into(),
+ memory_barriers_vk.len() as u32,
+ memory_barriers_vk.as_ptr(),
+ buffer_memory_barriers_vk.len() as u32,
+ buffer_memory_barriers_vk.as_ptr(),
+ image_memory_barriers_vk.len() as u32,
+ image_memory_barriers_vk.as_ptr(),
+ );
+ }
+
+ let command_index = self.next_command_index;
+ let command_name = "pipeline_barrier";
+ self.resources_usage_state.record_pipeline_barrier(
+ command_index,
+ command_name,
+ &dependency_info,
+ self.queue_family_properties().queue_flags,
+ );
+
+ self.resources
+ .reserve(buffer_memory_barriers.len() + image_memory_barriers.len());
+
+ for barrier in dependency_info.buffer_memory_barriers {
+ self.resources.push(Box::new(barrier.buffer));
+ }
+
+ for barrier in dependency_info.image_memory_barriers {
+ self.resources.push(Box::new(barrier.image));
+ }
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Signals an [`Event`] from the device.
+ ///
+ /// # Safety
+ ///
+ /// - All images that are accessed by the command must be in the expected image layout.
+ /// - For each element of `dependency_info.image_memory_barriers` that contains an image layout
+ /// transition, which is a write operation, the barrier must be defined appropriately to
+ /// ensure no memory access hazard occurs.
+ #[inline]
+ pub unsafe fn set_event(
+ &mut self,
+ event: Arc<Event>,
+ dependency_info: DependencyInfo,
+ ) -> Result<&mut Self, SynchronizationError> {
+ self.validate_set_event(&event, &dependency_info)?;
+
+ unsafe { Ok(self.set_event_unchecked(event, dependency_info)) }
+ }
+
+ fn validate_set_event(
+ &self,
+ event: &Event,
+ dependency_info: &DependencyInfo,
+ ) -> Result<(), SynchronizationError> {
+ // VUID-vkCmdSetEvent2-renderpass
+ if self.builder_state.render_pass.is_some() {
+ return Err(SynchronizationError::ForbiddenInsideRenderPass);
+ }
+
+ // VUID-vkCmdSetEvent2-commandBuffer-03826
+ // TODO:
+
+ let device = self.device();
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetEvent2-commandBuffer-cmdpool
+ if !queue_family_properties.queue_flags.intersects(
+ QueueFlags::GRAPHICS
+ | QueueFlags::COMPUTE
+ | QueueFlags::VIDEO_DECODE
+ | QueueFlags::VIDEO_ENCODE,
+ ) {
+ return Err(SynchronizationError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetEvent2-commonparent
+ assert_eq!(device, event.device());
+
+ let &DependencyInfo {
+ dependency_flags,
+ ref memory_barriers,
+ ref buffer_memory_barriers,
+ ref image_memory_barriers,
+ _ne: _,
+ } = dependency_info;
+
+ // VUID-VkDependencyInfo-dependencyFlags-parameter
+ dependency_flags.validate_device(device)?;
+
+ // VUID-vkCmdSetEvent2-dependencyFlags-03825
+ assert!(dependency_flags.is_empty());
+
+ let check_stages_access = |ty: char,
+ barrier_index: usize,
+ src_stages: PipelineStages,
+ src_access: AccessFlags,
+ dst_stages: PipelineStages,
+ dst_access: AccessFlags|
+ -> Result<(), SynchronizationError> {
+ for (stages, access) in [(src_stages, src_access), (dst_stages, dst_access)] {
+ // VUID-vkCmdSetEvent2-synchronization2-03824
+ if !device.enabled_features().synchronization2 {
+ if stages.is_2() {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where \
+ `src_stages` or `dst_stages` contains flags from \
+ `VkPipelineStageFlagBits2`",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }
+
+ if access.is_2() {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where \
+ `src_access` or `dst_access` contains flags from \
+ `VkAccessFlagBits2`",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-parameter
+ // VUID-VkMemoryBarrier2-dstStageMask-parameter
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-parameter
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-parameter
+ // VUID-VkImageMemoryBarrier2-srcStageMask-parameter
+ // VUID-VkImageMemoryBarrier2-dstStageMask-parameter
+ stages.validate_device(device)?;
+
+ // VUID-VkMemoryBarrier2-srcAccessMask-parameter
+ // VUID-VkMemoryBarrier2-dstAccessMask-parameter
+ // VUID-VkBufferMemoryBarrier2-srcAccessMask-parameter
+ // VUID-VkBufferMemoryBarrier2-dstAccessMask-parameter
+ // VUID-VkImageMemoryBarrier2-srcAccessMask-parameter
+ // VUID-VkImageMemoryBarrier2-dstAccessMask-parameter
+ access.validate_device(device)?;
+
+ // VUID-vkCmdSetEvent2-srcStageMask-03827
+ // VUID-vkCmdSetEvent2-dstStageMask-03828
+ if !PipelineStages::from(queue_family_properties.queue_flags).contains(stages) {
+ match ty {
+ 'm' => {
+ return Err(SynchronizationError::MemoryBarrierStageNotSupported {
+ barrier_index,
+ })
+ }
+ 'b' => {
+ return Err(
+ SynchronizationError::BufferMemoryBarrierStageNotSupported {
+ barrier_index,
+ },
+ )
+ }
+ 'i' => {
+ return Err(SynchronizationError::ImageMemoryBarrierStageNotSupported {
+ barrier_index,
+ })
+ }
+ _ => unreachable!(),
+ }
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03929
+ // VUID-VkMemoryBarrier2-dstStageMask-03929
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03929
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03929
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03930
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03930
+ if stages.intersects(PipelineStages::GEOMETRY_SHADER)
+ && !device.enabled_features().geometry_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::GEOMETRY_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["geometry_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03930
+ // VUID-VkMemoryBarrier2-dstStageMask-03930
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03930
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03930
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03930
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03930
+ if stages.intersects(
+ PipelineStages::TESSELLATION_CONTROL_SHADER
+ | PipelineStages::TESSELLATION_EVALUATION_SHADER,
+ ) && !device.enabled_features().tessellation_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::TESSELLATION_CONTROL_SHADER` or \
+ `PipelineStages::TESSELLATION_EVALUATION_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["tessellation_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03931
+ // VUID-VkMemoryBarrier2-dstStageMask-03931
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03931
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03931
+ // VUID-VImagekMemoryBarrier2-srcStageMask-03931
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03931
+ if stages.intersects(PipelineStages::CONDITIONAL_RENDERING)
+ && !device.enabled_features().conditional_rendering
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::CONDITIONAL_RENDERING`",
+ requires_one_of: RequiresOneOf {
+ features: &["conditional_rendering"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03932
+ // VUID-VkMemoryBarrier2-dstStageMask-03932
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03932
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03932
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03932
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03932
+ if stages.intersects(PipelineStages::FRAGMENT_DENSITY_PROCESS)
+ && !device.enabled_features().fragment_density_map
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::FRAGMENT_DENSITY_PROCESS`",
+ requires_one_of: RequiresOneOf {
+ features: &["fragment_density_map"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03933
+ // VUID-VkMemoryBarrier2-dstStageMask-03933
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03933
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03933
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03933
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03933
+ if stages.intersects(PipelineStages::TRANSFORM_FEEDBACK)
+ && !device.enabled_features().transform_feedback
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::TRANSFORM_FEEDBACK`",
+ requires_one_of: RequiresOneOf {
+ features: &["transform_feedback"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03934
+ // VUID-VkMemoryBarrier2-dstStageMask-03934
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03934
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03934
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03934
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03934
+ if stages.intersects(PipelineStages::MESH_SHADER)
+ && !device.enabled_features().mesh_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::MESH_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["mesh_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03935
+ // VUID-VkMemoryBarrier2-dstStageMask-03935
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03935
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03935
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03935
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03935
+ if stages.intersects(PipelineStages::TASK_SHADER)
+ && !device.enabled_features().task_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::TASK_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["task_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-shadingRateImage-07316
+ // VUID-VkMemoryBarrier2-shadingRateImage-07316
+ // VUID-VkBufferMemoryBarrier2-shadingRateImage-07316
+ // VUID-VkBufferMemoryBarrier2-shadingRateImage-07316
+ // VUID-VkImageMemoryBarrier2-shadingRateImage-07316
+ // VUID-VkImageMemoryBarrier2-shadingRateImage-07316
+ if stages.intersects(PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT)
+ && !(device.enabled_features().attachment_fragment_shading_rate
+ || device.enabled_features().shading_rate_image)
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT`",
+ requires_one_of: RequiresOneOf {
+ features: &["attachment_fragment_shading_rate", "shading_rate_image"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-04957
+ // VUID-VkMemoryBarrier2-dstStageMask-04957
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-04957
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-04957
+ // VUID-VkImageMemoryBarrier2-srcStageMask-04957
+ // VUID-VkImageMemoryBarrier2-dstStageMask-04957
+ if stages.intersects(PipelineStages::SUBPASS_SHADING)
+ && !device.enabled_features().subpass_shading
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::SUBPASS_SHADING`",
+ requires_one_of: RequiresOneOf {
+ features: &["subpass_shading"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-04995
+ // VUID-VkMemoryBarrier2-dstStageMask-04995
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-04995
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-04995
+ // VUID-VkImageMemoryBarrier2-srcStageMask-04995
+ // VUID-VkImageMemoryBarrier2-dstStageMask-04995
+ if stages.intersects(PipelineStages::INVOCATION_MASK)
+ && !device.enabled_features().invocation_mask
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::INVOCATION_MASK`",
+ requires_one_of: RequiresOneOf {
+ features: &["invocation_mask"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdSetEvent-stageMask-03937
+ if stages.is_empty() && !device.enabled_features().synchronization2 {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ is empty",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // A bit of a ridiculous number of VUIDs...
+
+ // VUID-VkMemoryBarrier2-srcAccessMask-03900
+ // ..
+ // VUID-VkMemoryBarrier2-srcAccessMask-07458
+
+ // VUID-VkMemoryBarrier2-dstAccessMask-03900
+ // ..
+ // VUID-VkMemoryBarrier2-dstAccessMask-07458
+
+ // VUID-VkBufferMemoryBarrier2-srcAccessMask-03900
+ // ..
+ // VUID-VkBufferMemoryBarrier2-srcAccessMask-07458
+
+ // VUID-VkBufferMemoryBarrier2-dstAccessMask-03900
+ // ..
+ // VUID-VkBufferMemoryBarrier2-dstAccessMask-07458
+
+ // VUID-VkImageMemoryBarrier2-srcAccessMask-03900
+ // ..
+ // VUID-VkImageMemoryBarrier2-srcAccessMask-07458
+
+ // VUID-VkImageMemoryBarrier2-dstAccessMask-03900
+ // ..
+ // VUID-VkImageMemoryBarrier2-dstAccessMask-07458
+
+ if !AccessFlags::from(stages).contains(access) {
+ match ty {
+ 'm' => {
+ return Err(
+ SynchronizationError::MemoryBarrierAccessNotSupportedByStages {
+ barrier_index,
+ },
+ )
+ }
+ 'b' => return Err(
+ SynchronizationError::BufferMemoryBarrierAccessNotSupportedByStages {
+ barrier_index,
+ },
+ ),
+ 'i' => return Err(
+ SynchronizationError::ImageMemoryBarrierAccessNotSupportedByStages {
+ barrier_index,
+ },
+ ),
+ _ => unreachable!(),
+ }
+ }
+ }
+
+ // VUID-VkMemoryBarrier2-srcAccessMask-06256
+ // VUID-VkBufferMemoryBarrier2-srcAccessMask-06256
+ // VUID-VkImageMemoryBarrier2-srcAccessMask-06256
+ if !device.enabled_features().ray_query
+ && src_access.intersects(AccessFlags::ACCELERATION_STRUCTURE_READ)
+ && src_stages.intersects(
+ PipelineStages::VERTEX_SHADER
+ | PipelineStages::TESSELLATION_CONTROL_SHADER
+ | PipelineStages::TESSELLATION_EVALUATION_SHADER
+ | PipelineStages::GEOMETRY_SHADER
+ | PipelineStages::FRAGMENT_SHADER
+ | PipelineStages::COMPUTE_SHADER
+ | PipelineStages::PRE_RASTERIZATION_SHADERS
+ | PipelineStages::TASK_SHADER
+ | PipelineStages::MESH_SHADER,
+ )
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where \
+ `src_access` contains `ACCELERATION_STRUCTURE_READ`, and \
+ `src_stages` contains a shader stage other than `RAY_TRACING_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["ray_query"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ };
+
+ let check_queue_family_ownership_transfer = |ty: char,
+ barrier_index: usize,
+ src_stages: PipelineStages,
+ dst_stages: PipelineStages,
+ queue_family_ownership_transfer: Option<
+ QueueFamilyOwnershipTransfer,
+ >,
+ sharing: &Sharing<_>|
+ -> Result<(), SynchronizationError> {
+ if let Some(transfer) = queue_family_ownership_transfer {
+ // VUID?
+ transfer.validate_device(device)?;
+
+ // VUID-VkBufferMemoryBarrier2-srcQueueFamilyIndex-04087
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-04070
+ // Ensured by the definition of `QueueFamilyOwnershipTransfer`.
+
+ // VUID-VkBufferMemoryBarrier2-buffer-04088
+ // VUID-VkImageMemoryBarrier2-image-04071
+ // Ensured by the definition of `QueueFamilyOwnershipTransfer`.
+
+ let queue_family_count =
+ device.physical_device().queue_family_properties().len() as u32;
+
+ let provided_queue_family_index = match (sharing, transfer) {
+ (
+ Sharing::Exclusive,
+ QueueFamilyOwnershipTransfer::ExclusiveBetweenLocal {
+ src_index,
+ dst_index,
+ },
+ ) => Some(max(src_index, dst_index)),
+ (
+ Sharing::Exclusive,
+ QueueFamilyOwnershipTransfer::ExclusiveToExternal { src_index }
+ | QueueFamilyOwnershipTransfer::ExclusiveToForeign { src_index },
+ ) => Some(src_index),
+ (
+ Sharing::Exclusive,
+ QueueFamilyOwnershipTransfer::ExclusiveFromExternal { dst_index }
+ | QueueFamilyOwnershipTransfer::ExclusiveFromForeign { dst_index },
+ ) => Some(dst_index),
+ (
+ Sharing::Concurrent(_),
+ QueueFamilyOwnershipTransfer::ConcurrentToExternal
+ | QueueFamilyOwnershipTransfer::ConcurrentFromExternal
+ | QueueFamilyOwnershipTransfer::ConcurrentToForeign
+ | QueueFamilyOwnershipTransfer::ConcurrentFromForeign,
+ ) => None,
+ _ => match ty {
+ 'b' => return Err(SynchronizationError::BufferMemoryBarrierOwnershipTransferSharingMismatch {
+ barrier_index,
+ }),
+ 'i' => return Err(SynchronizationError::ImageMemoryBarrierOwnershipTransferSharingMismatch {
+ barrier_index,
+ }),
+ _ => unreachable!(),
+ },
+ }.filter(|&index| index >= queue_family_count);
+
+ // VUID-VkBufferMemoryBarrier2-buffer-04089
+ // VUID-VkImageMemoryBarrier2-image-04072
+
+ if let Some(provided_queue_family_index) = provided_queue_family_index {
+ match ty {
+ 'b' => return Err(SynchronizationError::BufferMemoryBarrierOwnershipTransferIndexOutOfRange {
+ barrier_index,
+ provided_queue_family_index,
+ queue_family_count,
+ }),
+ 'i' => return Err(SynchronizationError::ImageMemoryBarrierOwnershipTransferIndexOutOfRange {
+ barrier_index,
+ provided_queue_family_index,
+ queue_family_count,
+ }),
+ _ => unreachable!(),
+ }
+ }
+
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03851
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03854
+ if src_stages.intersects(PipelineStages::HOST)
+ || dst_stages.intersects(PipelineStages::HOST)
+ {
+ match ty {
+ 'b' => return Err(SynchronizationError::BufferMemoryBarrierOwnershipTransferHostNotAllowed {
+ barrier_index,
+ }),
+ 'i' => return Err(SynchronizationError::ImageMemoryBarrierOwnershipTransferHostForbidden {
+ barrier_index,
+ }),
+ _ => unreachable!(),
+ }
+ }
+ }
+
+ Ok(())
+ };
+
+ for (barrier_index, barrier) in memory_barriers.iter().enumerate() {
+ let &MemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ _ne: _,
+ } = barrier;
+
+ /*
+ Check stages and access
+ */
+
+ check_stages_access(
+ 'm',
+ barrier_index,
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ )?;
+ }
+
+ for (barrier_index, barrier) in buffer_memory_barriers.iter().enumerate() {
+ let &BufferMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ queue_family_ownership_transfer,
+ ref buffer,
+ ref range,
+ _ne: _,
+ } = barrier;
+
+ // VUID-VkBufferMemoryBarrier2-buffer-01931
+ // Ensured by Buffer type construction.
+
+ /*
+ Check stages and access
+ */
+
+ check_stages_access(
+ 'b',
+ barrier_index,
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ )?;
+
+ /*
+ Check queue family transfer
+ */
+
+ check_queue_family_ownership_transfer(
+ 'b',
+ barrier_index,
+ src_stages,
+ dst_stages,
+ queue_family_ownership_transfer,
+ buffer.sharing(),
+ )?;
+
+ /*
+ Check range
+ */
+
+ // VUID-VkBufferMemoryBarrier2-size-01188
+ assert!(!range.is_empty());
+
+ // VUID-VkBufferMemoryBarrier2-offset-01187
+ // VUID-VkBufferMemoryBarrier2-size-01189
+ if range.end > buffer.size() {
+ return Err(SynchronizationError::BufferMemoryBarrierOutOfRange {
+ barrier_index,
+ range_end: range.end,
+ buffer_size: buffer.size(),
+ });
+ }
+ }
+
+ for (barrier_index, barrier) in image_memory_barriers.iter().enumerate() {
+ let &ImageMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ old_layout,
+ new_layout,
+ queue_family_ownership_transfer,
+ ref image,
+ ref subresource_range,
+ _ne: _,
+ } = barrier;
+
+ // VUID-VkImageMemoryBarrier2-image-01932
+ // Ensured by Image type construction.
+
+ /*
+ Check stages and access
+ */
+
+ check_stages_access(
+ 'i',
+ barrier_index,
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ )?;
+
+ /*
+ Check layouts
+ */
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-parameter
+ old_layout.validate_device(device)?;
+
+ // VUID-VkImageMemoryBarrier2-newLayout-parameter
+ new_layout.validate_device(device)?;
+
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03855
+ if src_stages.intersects(PipelineStages::HOST)
+ && !matches!(
+ old_layout,
+ ImageLayout::Preinitialized | ImageLayout::Undefined | ImageLayout::General
+ )
+ {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierOldLayoutFromHostInvalid {
+ barrier_index,
+ old_layout,
+ },
+ );
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01197
+ // Not checked yet, therefore unsafe.
+
+ // VUID-VkImageMemoryBarrier2-newLayout-01198
+ if matches!(
+ new_layout,
+ ImageLayout::Undefined | ImageLayout::Preinitialized
+ ) {
+ return Err(SynchronizationError::ImageMemoryBarrierNewLayoutInvalid {
+ barrier_index,
+ });
+ }
+
+ // VUID-VkImageMemoryBarrier2-attachmentFeedbackLoopLayout-07313
+ /*if !device.enabled_features().attachment_feedback_loop_layout
+ && matches!(new_layout, ImageLayout::AttachmentFeedbackLoopOptimal)
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`dependency_info.image_memory_barriers` has an element where \
+ `new_layout` is `AttachmentFeedbackLoopOptimal`",
+ requires_one_of: RequiresOneOf {
+ features: &["attachment_feedback_loop_layout"],
+ ..Default::default()
+ },
+ });
+ }*/
+
+ for layout in [old_layout, new_layout] {
+ // VUID-VkImageMemoryBarrier2-synchronization2-06911
+ /*if !device.enabled_features().synchronization2
+ && matches!(
+ layout,
+ ImageLayout::AttachmentOptimal | ImageLayout::ReadOnlyOptimal
+ )
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`dependency_info.image_memory_barriers` has an element \
+ where `old_layout` or `new_layout` is `AttachmentOptimal` or \
+ `ReadOnlyOptimal`",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }*/
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-07006
+ /*if layout == ImageLayout::AttachmentFeedbackLoopOptimal {
+ if !image.usage().intersects(
+ ImageUsage::COLOR_ATTACHMENT | ImageUsage::DEPTH_STENCIL_ATTACHMENT,
+ ) {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierImageMissingUsageForLayout {
+ barrier_index,
+ layout,
+ requires_one_of_usage: ImageUsage::COLOR_ATTACHMENT
+ | ImageUsage::DEPTH_STENCIL_ATTACHMENT,
+ },
+ );
+ }
+
+ if !image
+ .usage()
+ .intersects(ImageUsage::INPUT_ATTACHMENT | ImageUsage::SAMPLED)
+ {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierImageMissingUsageForLayout {
+ barrier_index,
+ layout,
+ requires_one_of_usage: ImageUsage::INPUT_ATTACHMENT
+ | ImageUsage::SAMPLED,
+ },
+ );
+ }
+
+ if !image
+ .usage()
+ .intersects(ImageUsage::ATTACHMENT_FEEDBACK_LOOP)
+ {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierImageMissingUsageForLayout {
+ barrier_index,
+ layout,
+ requires_one_of_usage: ImageUsage::ATTACHMENT_FEEDBACK_LOOP,
+ },
+ );
+ }
+ }*/
+
+ let requires_one_of_usage = match layout {
+ // VUID-VkImageMemoryBarrier2-oldLayout-01208
+ ImageLayout::ColorAttachmentOptimal => ImageUsage::COLOR_ATTACHMENT,
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01209
+ ImageLayout::DepthStencilAttachmentOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01210
+ ImageLayout::DepthStencilReadOnlyOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01211
+ ImageLayout::ShaderReadOnlyOptimal => {
+ ImageUsage::SAMPLED | ImageUsage::INPUT_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01212
+ ImageLayout::TransferSrcOptimal => ImageUsage::TRANSFER_SRC,
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01213
+ ImageLayout::TransferDstOptimal => ImageUsage::TRANSFER_DST,
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01658
+ ImageLayout::DepthReadOnlyStencilAttachmentOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01659
+ ImageLayout::DepthAttachmentStencilReadOnlyOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ }
+
+ /*
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-04065
+ ImageLayout::DepthReadOnlyOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ | ImageUsage::SAMPLED
+ | ImageUsage::INPUT_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-04066
+ ImageLayout::DepthAttachmentOptimal => ImageUsage::DEPTH_STENCIL_ATTACHMENT,
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-04067
+ ImageLayout::StencilReadOnlyOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ | ImageUsage::SAMPLED
+ | ImageUsage::INPUT_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-04068
+ ImageLayout::StencilAttachmentOptimal => ImageUsage::DEPTH_STENCIL_ATTACHMENT,
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-03938
+ ImageLayout::AttachmentOptimal => {
+ ImageUsage::COLOR_ATTACHMENT | ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-03939
+ ImageLayout::ReadOnlyOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ | ImageUsage::SAMPLED
+ | ImageUsage::INPUT_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-02088
+ ImageLayout::FragmentShadingRateAttachmentOptimal => {
+ ImageUsage::FRAGMENT_SHADING_RATE_ATTACHMENT
+ }
+ */
+ _ => continue,
+ };
+
+ if !image.usage().intersects(requires_one_of_usage) {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierImageMissingUsageForLayout {
+ barrier_index,
+ layout,
+ requires_one_of_usage,
+ },
+ );
+ }
+ }
+
+ /*
+ Check queue family tansfer
+ */
+
+ check_queue_family_ownership_transfer(
+ 'i',
+ barrier_index,
+ src_stages,
+ dst_stages,
+ queue_family_ownership_transfer,
+ image.sharing(),
+ )?;
+
+ /*
+ Check subresource range
+ */
+
+ // VUID-VkImageSubresourceRange-aspectMask-requiredbitmask
+ assert!(!subresource_range.aspects.is_empty());
+
+ // VUID-VkImageSubresourceRange-aspectMask-parameter
+ subresource_range.aspects.validate_device(device)?;
+
+ let image_aspects = image.format().unwrap().aspects();
+
+ // VUID-VkImageMemoryBarrier2-image-01673
+ // VUID-VkImageMemoryBarrier2-image-03319
+ if image_aspects.contains(subresource_range.aspects) {
+ return Err(SynchronizationError::ImageMemoryBarrierAspectsNotAllowed {
+ barrier_index,
+ aspects: subresource_range.aspects - image_aspects,
+ });
+ }
+
+ if image_aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL) {
+ // VUID-VkImageMemoryBarrier2-image-03320
+ if !device.enabled_features().separate_depth_stencil_layouts
+ && image_aspects.contains(ImageAspects::DEPTH | ImageAspects::STENCIL)
+ && !subresource_range
+ .aspects
+ .contains(ImageAspects::DEPTH | ImageAspects::STENCIL)
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`dependency_info.image_memory_barriers` has an element \
+ where `image` has both a depth and a stencil aspect, and \
+ `subresource_range.aspects` does not contain both aspects",
+ requires_one_of: RequiresOneOf {
+ features: &["separate_depth_stencil_layouts"],
+ ..Default::default()
+ },
+ });
+ }
+ } else {
+ // VUID-VkImageMemoryBarrier2-image-01671
+ if !image.flags().intersects(ImageCreateFlags::DISJOINT)
+ && subresource_range.aspects != ImageAspects::COLOR
+ {
+ return Err(SynchronizationError::ImageMemoryBarrierAspectsNotAllowed {
+ barrier_index,
+ aspects: subresource_range.aspects - ImageAspects::COLOR,
+ });
+ }
+ }
+
+ // VUID-VkImageSubresourceRange-levelCount-01720
+ assert!(!subresource_range.mip_levels.is_empty());
+
+ // VUID-VkImageMemoryBarrier2-subresourceRange-01486
+ // VUID-VkImageMemoryBarrier2-subresourceRange-01724
+ if subresource_range.mip_levels.end > image.mip_levels() {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierMipLevelsOutOfRange {
+ barrier_index,
+ mip_levels_range_end: subresource_range.mip_levels.end,
+ image_mip_levels: image.mip_levels(),
+ },
+ );
+ }
+
+ // VUID-VkImageSubresourceRange-layerCount-01721
+ assert!(!subresource_range.array_layers.is_empty());
+
+ // VUID-VkImageMemoryBarrier2-subresourceRange-01488
+ // VUID-VkImageMemoryBarrier2-subresourceRange-01725
+ if subresource_range.array_layers.end > image.dimensions().array_layers() {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierArrayLayersOutOfRange {
+ barrier_index,
+ array_layers_range_end: subresource_range.array_layers.end,
+ image_array_layers: image.dimensions().array_layers(),
+ },
+ );
+ }
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn set_event_unchecked(
+ &mut self,
+ event: Arc<Event>,
+ dependency_info: DependencyInfo,
+ ) -> &mut Self {
+ let DependencyInfo {
+ dependency_flags,
+ memory_barriers,
+ buffer_memory_barriers,
+ image_memory_barriers,
+ _ne: _,
+ } = dependency_info;
+
+ let fns = self.device().fns();
+
+ if self.device().enabled_features().synchronization2 {
+ let memory_barriers_vk: SmallVec<[_; 2]> = memory_barriers
+ .iter()
+ .map(|barrier| {
+ let &MemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ _ne: _,
+ } = barrier;
+
+ ash::vk::MemoryBarrier2 {
+ src_stage_mask: src_stages.into(),
+ src_access_mask: src_access.into(),
+ dst_stage_mask: dst_stages.into(),
+ dst_access_mask: dst_access.into(),
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let buffer_memory_barriers_vk: SmallVec<[_; 8]> = buffer_memory_barriers
+ .iter()
+ .map(|barrier| {
+ let &BufferMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ queue_family_ownership_transfer,
+ ref buffer,
+ ref range,
+ _ne: _,
+ } = barrier;
+
+ let (src_queue_family_index, dst_queue_family_index) =
+ queue_family_ownership_transfer.map_or(
+ (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED),
+ Into::into,
+ );
+
+ ash::vk::BufferMemoryBarrier2 {
+ src_stage_mask: src_stages.into(),
+ src_access_mask: src_access.into(),
+ dst_stage_mask: dst_stages.into(),
+ dst_access_mask: dst_access.into(),
+ src_queue_family_index,
+ dst_queue_family_index,
+ buffer: buffer.handle(),
+ offset: range.start,
+ size: range.end - range.start,
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let image_memory_barriers_vk: SmallVec<[_; 8]> = image_memory_barriers
+ .iter()
+ .map(|barrier| {
+ let &ImageMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ old_layout,
+ new_layout,
+ queue_family_ownership_transfer,
+ ref image,
+ ref subresource_range,
+ _ne: _,
+ } = barrier;
+
+ let (src_queue_family_index, dst_queue_family_index) =
+ queue_family_ownership_transfer.map_or(
+ (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED),
+ Into::into,
+ );
+
+ ash::vk::ImageMemoryBarrier2 {
+ src_stage_mask: src_stages.into(),
+ src_access_mask: src_access.into(),
+ dst_stage_mask: dst_stages.into(),
+ dst_access_mask: dst_access.into(),
+ old_layout: old_layout.into(),
+ new_layout: new_layout.into(),
+ src_queue_family_index,
+ dst_queue_family_index,
+ image: image.handle(),
+ subresource_range: subresource_range.clone().into(),
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let dependency_info_vk = ash::vk::DependencyInfo {
+ dependency_flags: dependency_flags.into(),
+ memory_barrier_count: memory_barriers_vk.len() as u32,
+ p_memory_barriers: memory_barriers_vk.as_ptr(),
+ buffer_memory_barrier_count: buffer_memory_barriers_vk.len() as u32,
+ p_buffer_memory_barriers: buffer_memory_barriers_vk.as_ptr(),
+ image_memory_barrier_count: image_memory_barriers_vk.len() as u32,
+ p_image_memory_barriers: image_memory_barriers_vk.as_ptr(),
+ ..Default::default()
+ };
+
+ if self.device().api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_set_event2)(self.handle(), event.handle(), &dependency_info_vk);
+ } else {
+ debug_assert!(self.device().enabled_extensions().khr_synchronization2);
+ (fns.khr_synchronization2.cmd_set_event2_khr)(
+ self.handle(),
+ event.handle(),
+ &dependency_info_vk,
+ );
+ }
+ } else {
+ // The original function only takes a source stage mask; the rest of the info is
+ // provided with `wait_events` instead. Therefore, we condense the source stages
+ // here and ignore the rest.
+
+ let mut stage_mask = ash::vk::PipelineStageFlags::empty();
+
+ for barrier in memory_barriers {
+ stage_mask |= barrier.src_stages.into();
+ }
+
+ for barrier in buffer_memory_barriers {
+ stage_mask |= barrier.src_stages.into();
+ }
+
+ for barrier in image_memory_barriers {
+ stage_mask |= barrier.src_stages.into();
+ }
+
+ if stage_mask.is_empty() {
+ // "VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT is [...] equivalent to
+ // VK_PIPELINE_STAGE_2_NONE in the first scope."
+ stage_mask |= ash::vk::PipelineStageFlags::TOP_OF_PIPE;
+ }
+
+ (fns.v1_0.cmd_set_event)(self.handle(), event.handle(), stage_mask);
+ }
+
+ self.resources.push(Box::new(event));
+
+ // TODO: sync state update
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Waits for one or more [`Event`]s to be signaled.
+ ///
+ /// # Safety
+ ///
+ /// - For each element in `events`, if the event is signaled by [`set_event`], that command
+ /// must have already been recorded or previously submitted to the queue, and the
+ /// `DependencyInfo` provided here must be equal to the `DependencyInfo` used in that
+ /// command.
+ /// - For each element in `events`, if the event is signaled by [`Event::set`], that function
+ /// must have already been called before submitting this command to a queue.
+ ///
+ /// [`set_event`]: Self::set_event
+ /// [`Event::set`]: Event::set
+ #[inline]
+ pub unsafe fn wait_events(
+ &mut self,
+ events: impl IntoIterator<Item = (Arc<Event>, DependencyInfo)>,
+ ) -> Result<&mut Self, SynchronizationError> {
+ let events: SmallVec<[(Arc<Event>, DependencyInfo); 4]> = events.into_iter().collect();
+ self.validate_wait_events(&events)?;
+
+ unsafe { Ok(self.wait_events_unchecked(events)) }
+ }
+
+ fn validate_wait_events(
+ &self,
+ events: &[(Arc<Event>, DependencyInfo)],
+ ) -> Result<(), SynchronizationError> {
+ // VUID-vkCmdWaitEvents2-commandBuffer-03846
+ // TODO:
+
+ let device = self.device();
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdWaitEvents2-commandBuffer-cmdpool
+ if !queue_family_properties.queue_flags.intersects(
+ QueueFlags::GRAPHICS
+ | QueueFlags::COMPUTE
+ | QueueFlags::VIDEO_DECODE
+ | QueueFlags::VIDEO_ENCODE,
+ ) {
+ return Err(SynchronizationError::NotSupportedByQueueFamily);
+ }
+
+ if events.is_empty() {
+ return Ok(());
+ }
+
+ for (event, dependency_info) in events {
+ // VUID-vkCmdWaitEvents2-commonparent
+ assert_eq!(device, event.device());
+
+ // VUID-vkCmdWaitEvents2-pEvents-03838
+ // TODO:
+
+ // VUID-vkCmdWaitEvents2-pEvents-03839
+ // TODO:
+
+ // VUID-vkCmdWaitEvents2-pEvents-03840
+ // TODO:
+
+ // VUID-vkCmdWaitEvents2-pEvents-03841
+ // TODO:
+
+ let &DependencyInfo {
+ dependency_flags,
+ ref memory_barriers,
+ ref buffer_memory_barriers,
+ ref image_memory_barriers,
+ _ne: _,
+ } = dependency_info;
+
+ // VUID-VkDependencyInfo-dependencyFlags-parameter
+ dependency_flags.validate_device(device)?;
+
+ let check_stages_access = |ty: char,
+ barrier_index: usize,
+ src_stages: PipelineStages,
+ src_access: AccessFlags,
+ dst_stages: PipelineStages,
+ dst_access: AccessFlags|
+ -> Result<(), SynchronizationError> {
+ for (stages, access) in [(src_stages, src_access), (dst_stages, dst_access)] {
+ // VUID-vkCmdWaitEvents2-synchronization2-03836
+ if !device.enabled_features().synchronization2 {
+ if stages.is_2() {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where \
+ `src_stages` or `dst_stages` contains flags from \
+ `VkPipelineStageFlagBits2`",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }
+
+ if access.is_2() {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where \
+ `src_access` or `dst_access` contains flags from \
+ `VkAccessFlagBits2`",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-parameter
+ // VUID-VkMemoryBarrier2-dstStageMask-parameter
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-parameter
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-parameter
+ // VUID-VkImageMemoryBarrier2-srcStageMask-parameter
+ // VUID-VkImageMemoryBarrier2-dstStageMask-parameter
+ stages.validate_device(device)?;
+
+ // VUID-VkMemoryBarrier2-srcAccessMask-parameter
+ // VUID-VkMemoryBarrier2-dstAccessMask-parameter
+ // VUID-VkBufferMemoryBarrier2-srcAccessMask-parameter
+ // VUID-VkBufferMemoryBarrier2-dstAccessMask-parameter
+ // VUID-VkImageMemoryBarrier2-srcAccessMask-parameter
+ // VUID-VkImageMemoryBarrier2-dstAccessMask-parameter
+ access.validate_device(device)?;
+
+ // VUID-vkCmdWaitEvents2-srcStageMask-03842
+ // VUID-vkCmdWaitEvents2-dstStageMask-03843
+ if !PipelineStages::from(queue_family_properties.queue_flags).contains(stages) {
+ match ty {
+ 'm' => {
+ return Err(SynchronizationError::MemoryBarrierStageNotSupported {
+ barrier_index,
+ })
+ }
+ 'b' => {
+ return Err(
+ SynchronizationError::BufferMemoryBarrierStageNotSupported {
+ barrier_index,
+ },
+ )
+ }
+ 'i' => {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierStageNotSupported {
+ barrier_index,
+ },
+ )
+ }
+ _ => unreachable!(),
+ }
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03929
+ // VUID-VkMemoryBarrier2-dstStageMask-03929
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03929
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03929
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03930
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03930
+ if stages.intersects(PipelineStages::GEOMETRY_SHADER)
+ && !device.enabled_features().geometry_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::GEOMETRY_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["geometry_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03930
+ // VUID-VkMemoryBarrier2-dstStageMask-03930
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03930
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03930
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03930
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03930
+ if stages.intersects(
+ PipelineStages::TESSELLATION_CONTROL_SHADER
+ | PipelineStages::TESSELLATION_EVALUATION_SHADER,
+ ) && !device.enabled_features().tessellation_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::TESSELLATION_CONTROL_SHADER` or \
+ `PipelineStages::TESSELLATION_EVALUATION_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["tessellation_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03931
+ // VUID-VkMemoryBarrier2-dstStageMask-03931
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03931
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03931
+ // VUID-VImagekMemoryBarrier2-srcStageMask-03931
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03931
+ if stages.intersects(PipelineStages::CONDITIONAL_RENDERING)
+ && !device.enabled_features().conditional_rendering
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::CONDITIONAL_RENDERING`",
+ requires_one_of: RequiresOneOf {
+ features: &["conditional_rendering"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03932
+ // VUID-VkMemoryBarrier2-dstStageMask-03932
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03932
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03932
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03932
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03932
+ if stages.intersects(PipelineStages::FRAGMENT_DENSITY_PROCESS)
+ && !device.enabled_features().fragment_density_map
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::FRAGMENT_DENSITY_PROCESS`",
+ requires_one_of: RequiresOneOf {
+ features: &["fragment_density_map"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03933
+ // VUID-VkMemoryBarrier2-dstStageMask-03933
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03933
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03933
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03933
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03933
+ if stages.intersects(PipelineStages::TRANSFORM_FEEDBACK)
+ && !device.enabled_features().transform_feedback
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::TRANSFORM_FEEDBACK`",
+ requires_one_of: RequiresOneOf {
+ features: &["transform_feedback"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03934
+ // VUID-VkMemoryBarrier2-dstStageMask-03934
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03934
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03934
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03934
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03934
+ if stages.intersects(PipelineStages::MESH_SHADER)
+ && !device.enabled_features().mesh_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::MESH_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["mesh_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03935
+ // VUID-VkMemoryBarrier2-dstStageMask-03935
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03935
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03935
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03935
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03935
+ if stages.intersects(PipelineStages::TASK_SHADER)
+ && !device.enabled_features().task_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::TASK_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["task_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-shadingRateImage-07316
+ // VUID-VkMemoryBarrier2-shadingRateImage-07316
+ // VUID-VkBufferMemoryBarrier2-shadingRateImage-07316
+ // VUID-VkBufferMemoryBarrier2-shadingRateImage-07316
+ // VUID-VkImageMemoryBarrier2-shadingRateImage-07316
+ // VUID-VkImageMemoryBarrier2-shadingRateImage-07316
+ if stages.intersects(PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT)
+ && !(device.enabled_features().attachment_fragment_shading_rate
+ || device.enabled_features().shading_rate_image)
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT`",
+ requires_one_of: RequiresOneOf {
+ features: &[
+ "attachment_fragment_shading_rate",
+ "shading_rate_image",
+ ],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-04957
+ // VUID-VkMemoryBarrier2-dstStageMask-04957
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-04957
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-04957
+ // VUID-VkImageMemoryBarrier2-srcStageMask-04957
+ // VUID-VkImageMemoryBarrier2-dstStageMask-04957
+ if stages.intersects(PipelineStages::SUBPASS_SHADING)
+ && !device.enabled_features().subpass_shading
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::SUBPASS_SHADING`",
+ requires_one_of: RequiresOneOf {
+ features: &["subpass_shading"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-04995
+ // VUID-VkMemoryBarrier2-dstStageMask-04995
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-04995
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-04995
+ // VUID-VkImageMemoryBarrier2-srcStageMask-04995
+ // VUID-VkImageMemoryBarrier2-dstStageMask-04995
+ if stages.intersects(PipelineStages::INVOCATION_MASK)
+ && !device.enabled_features().invocation_mask
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::INVOCATION_MASK`",
+ requires_one_of: RequiresOneOf {
+ features: &["invocation_mask"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdWaitEvents-srcStageMask-03937
+ // VUID-vkCmdWaitEvents-dstStageMask-03937
+ if stages.is_empty() && !device.enabled_features().synchronization2 {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ is empty",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // A bit of a ridiculous number of VUIDs...
+
+ // VUID-VkMemoryBarrier2-srcAccessMask-03900
+ // ..
+ // VUID-VkMemoryBarrier2-srcAccessMask-07458
+
+ // VUID-VkMemoryBarrier2-dstAccessMask-03900
+ // ..
+ // VUID-VkMemoryBarrier2-dstAccessMask-07458
+
+ // VUID-VkBufferMemoryBarrier2-srcAccessMask-03900
+ // ..
+ // VUID-VkBufferMemoryBarrier2-srcAccessMask-07458
+
+ // VUID-VkBufferMemoryBarrier2-dstAccessMask-03900
+ // ..
+ // VUID-VkBufferMemoryBarrier2-dstAccessMask-07458
+
+ // VUID-VkImageMemoryBarrier2-srcAccessMask-03900
+ // ..
+ // VUID-VkImageMemoryBarrier2-srcAccessMask-07458
+
+ // VUID-VkImageMemoryBarrier2-dstAccessMask-03900
+ // ..
+ // VUID-VkImageMemoryBarrier2-dstAccessMask-07458
+
+ if !AccessFlags::from(stages).contains(access) {
+ match ty {
+ 'm' => {
+ return Err(
+ SynchronizationError::MemoryBarrierAccessNotSupportedByStages {
+ barrier_index,
+ },
+ )
+ }
+ 'b' => return Err(
+ SynchronizationError::BufferMemoryBarrierAccessNotSupportedByStages {
+ barrier_index,
+ },
+ ),
+ 'i' => return Err(
+ SynchronizationError::ImageMemoryBarrierAccessNotSupportedByStages {
+ barrier_index,
+ },
+ ),
+ _ => unreachable!(),
+ }
+ }
+ }
+
+ // VUID-VkMemoryBarrier2-srcAccessMask-06256
+ // VUID-VkBufferMemoryBarrier2-srcAccessMask-06256
+ // VUID-VkImageMemoryBarrier2-srcAccessMask-06256
+ if !device.enabled_features().ray_query
+ && src_access.intersects(AccessFlags::ACCELERATION_STRUCTURE_READ)
+ && src_stages.intersects(
+ PipelineStages::VERTEX_SHADER
+ | PipelineStages::TESSELLATION_CONTROL_SHADER
+ | PipelineStages::TESSELLATION_EVALUATION_SHADER
+ | PipelineStages::GEOMETRY_SHADER
+ | PipelineStages::FRAGMENT_SHADER
+ | PipelineStages::COMPUTE_SHADER
+ | PipelineStages::PRE_RASTERIZATION_SHADERS
+ | PipelineStages::TASK_SHADER
+ | PipelineStages::MESH_SHADER,
+ )
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where \
+ `src_access` contains `ACCELERATION_STRUCTURE_READ`, and \
+ `src_stages` contains a shader stage other than `RAY_TRACING_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["ray_query"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdWaitEvents2-dependencyFlags-03844
+ if self.builder_state.render_pass.is_some()
+ && src_stages.intersects(PipelineStages::HOST)
+ {
+ todo!()
+ }
+
+ Ok(())
+ };
+
+ let check_queue_family_ownership_transfer =
+ |ty: char,
+ barrier_index: usize,
+ src_stages: PipelineStages,
+ dst_stages: PipelineStages,
+ queue_family_ownership_transfer: Option<QueueFamilyOwnershipTransfer>,
+ sharing: &Sharing<_>|
+ -> Result<(), SynchronizationError> {
+ if let Some(transfer) = queue_family_ownership_transfer {
+ // VUID?
+ transfer.validate_device(device)?;
+
+ // VUID-VkBufferMemoryBarrier2-srcQueueFamilyIndex-04087
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-04070
+ // Ensured by the definition of `QueueFamilyOwnershipTransfer`.
+
+ // VUID-VkBufferMemoryBarrier2-buffer-04088
+ // VUID-VkImageMemoryBarrier2-image-04071
+ // Ensured by the definition of `QueueFamilyOwnershipTransfer`.
+
+ let queue_family_count =
+ device.physical_device().queue_family_properties().len() as u32;
+
+ let provided_queue_family_index = match (sharing, transfer) {
+ (
+ Sharing::Exclusive,
+ QueueFamilyOwnershipTransfer::ExclusiveBetweenLocal {
+ src_index,
+ dst_index,
+ },
+ ) => Some(max(src_index, dst_index)),
+ (
+ Sharing::Exclusive,
+ QueueFamilyOwnershipTransfer::ExclusiveToExternal { src_index }
+ | QueueFamilyOwnershipTransfer::ExclusiveToForeign { src_index },
+ ) => Some(src_index),
+ (
+ Sharing::Exclusive,
+ QueueFamilyOwnershipTransfer::ExclusiveFromExternal { dst_index }
+ | QueueFamilyOwnershipTransfer::ExclusiveFromForeign { dst_index },
+ ) => Some(dst_index),
+ (
+ Sharing::Concurrent(_),
+ QueueFamilyOwnershipTransfer::ConcurrentToExternal
+ | QueueFamilyOwnershipTransfer::ConcurrentFromExternal
+ | QueueFamilyOwnershipTransfer::ConcurrentToForeign
+ | QueueFamilyOwnershipTransfer::ConcurrentFromForeign,
+ ) => None,
+ _ => match ty {
+ 'b' => return Err(SynchronizationError::BufferMemoryBarrierOwnershipTransferSharingMismatch {
+ barrier_index,
+ }),
+ 'i' => return Err(SynchronizationError::ImageMemoryBarrierOwnershipTransferSharingMismatch {
+ barrier_index,
+ }),
+ _ => unreachable!(),
+ },
+ }.filter(|&index| index >= queue_family_count);
+
+ // VUID-VkBufferMemoryBarrier2-buffer-04089
+ // VUID-VkImageMemoryBarrier2-image-04072
+
+ if let Some(provided_queue_family_index) = provided_queue_family_index {
+ match ty {
+ 'b' => return Err(SynchronizationError::BufferMemoryBarrierOwnershipTransferIndexOutOfRange {
+ barrier_index,
+ provided_queue_family_index,
+ queue_family_count,
+ }),
+ 'i' => return Err(SynchronizationError::ImageMemoryBarrierOwnershipTransferIndexOutOfRange {
+ barrier_index,
+ provided_queue_family_index,
+ queue_family_count,
+ }),
+ _ => unreachable!(),
+ }
+ }
+
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03851
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03854
+ if src_stages.intersects(PipelineStages::HOST)
+ || dst_stages.intersects(PipelineStages::HOST)
+ {
+ match ty {
+ 'b' => return Err(SynchronizationError::BufferMemoryBarrierOwnershipTransferHostNotAllowed {
+ barrier_index,
+ }),
+ 'i' => return Err(SynchronizationError::ImageMemoryBarrierOwnershipTransferHostForbidden {
+ barrier_index,
+ }),
+ _ => unreachable!(),
+ }
+ }
+ }
+
+ Ok(())
+ };
+
+ for (barrier_index, barrier) in memory_barriers.iter().enumerate() {
+ let &MemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ _ne: _,
+ } = barrier;
+
+ /*
+ Check stages and access
+ */
+
+ check_stages_access(
+ 'm',
+ barrier_index,
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ )?;
+ }
+
+ for (barrier_index, barrier) in buffer_memory_barriers.iter().enumerate() {
+ let &BufferMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ queue_family_ownership_transfer,
+ ref buffer,
+ ref range,
+ _ne: _,
+ } = barrier;
+
+ // VUID-VkBufferMemoryBarrier2-buffer-01931
+ // Ensured by Buffer type construction.
+
+ /*
+ Check stages and access
+ */
+
+ check_stages_access(
+ 'b',
+ barrier_index,
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ )?;
+
+ /*
+ Check queue family transfer
+ */
+
+ check_queue_family_ownership_transfer(
+ 'b',
+ barrier_index,
+ src_stages,
+ dst_stages,
+ queue_family_ownership_transfer,
+ buffer.sharing(),
+ )?;
+
+ /*
+ Check range
+ */
+
+ // VUID-VkBufferMemoryBarrier2-size-01188
+ assert!(!range.is_empty());
+
+ // VUID-VkBufferMemoryBarrier2-offset-01187
+ // VUID-VkBufferMemoryBarrier2-size-01189
+ if range.end > buffer.size() {
+ return Err(SynchronizationError::BufferMemoryBarrierOutOfRange {
+ barrier_index,
+ range_end: range.end,
+ buffer_size: buffer.size(),
+ });
+ }
+ }
+
+ for (barrier_index, barrier) in image_memory_barriers.iter().enumerate() {
+ let &ImageMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ old_layout,
+ new_layout,
+ queue_family_ownership_transfer,
+ ref image,
+ ref subresource_range,
+ _ne: _,
+ } = barrier;
+
+ // VUID-VkImageMemoryBarrier2-image-01932
+ // Ensured by Image type construction.
+
+ /*
+ Check stages and access
+ */
+
+ check_stages_access(
+ 'i',
+ barrier_index,
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ )?;
+
+ /*
+ Check layouts
+ */
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-parameter
+ old_layout.validate_device(device)?;
+
+ // VUID-VkImageMemoryBarrier2-newLayout-parameter
+ new_layout.validate_device(device)?;
+
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03855
+ if src_stages.intersects(PipelineStages::HOST)
+ && !matches!(
+ old_layout,
+ ImageLayout::Preinitialized | ImageLayout::Undefined | ImageLayout::General
+ )
+ {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierOldLayoutFromHostInvalid {
+ barrier_index,
+ old_layout,
+ },
+ );
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01197
+ // Not checked yet, therefore unsafe.
+
+ // VUID-VkImageMemoryBarrier2-newLayout-01198
+ if matches!(
+ new_layout,
+ ImageLayout::Undefined | ImageLayout::Preinitialized
+ ) {
+ return Err(SynchronizationError::ImageMemoryBarrierNewLayoutInvalid {
+ barrier_index,
+ });
+ }
+
+ // VUID-VkImageMemoryBarrier2-attachmentFeedbackLoopLayout-07313
+ /*if !device.enabled_features().attachment_feedback_loop_layout
+ && matches!(new_layout, ImageLayout::AttachmentFeedbackLoopOptimal)
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`dependency_info.image_memory_barriers` has an element where \
+ `new_layout` is `AttachmentFeedbackLoopOptimal`",
+ requires_one_of: RequiresOneOf {
+ features: &["attachment_feedback_loop_layout"],
+ ..Default::default()
+ },
+ });
+ }*/
+
+ for layout in [old_layout, new_layout] {
+ // VUID-VkImageMemoryBarrier2-synchronization2-06911
+ /*if !device.enabled_features().synchronization2
+ && matches!(
+ layout,
+ ImageLayout::AttachmentOptimal | ImageLayout::ReadOnlyOptimal
+ )
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`dependency_info.image_memory_barriers` has an element \
+ where `old_layout` or `new_layout` is `AttachmentOptimal` or \
+ `ReadOnlyOptimal`",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }*/
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-07006
+ /*if layout == ImageLayout::AttachmentFeedbackLoopOptimal {
+ if !image.usage().intersects(
+ ImageUsage::COLOR_ATTACHMENT | ImageUsage::DEPTH_STENCIL_ATTACHMENT,
+ ) {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierImageMissingUsageForLayout {
+ barrier_index,
+ layout,
+ requires_one_of_usage: ImageUsage::COLOR_ATTACHMENT
+ | ImageUsage::DEPTH_STENCIL_ATTACHMENT,
+ },
+ );
+ }
+
+ if !image
+ .usage()
+ .intersects(ImageUsage::INPUT_ATTACHMENT | ImageUsage::SAMPLED)
+ {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierImageMissingUsageForLayout {
+ barrier_index,
+ layout,
+ requires_one_of_usage: ImageUsage::INPUT_ATTACHMENT
+ | ImageUsage::SAMPLED,
+ },
+ );
+ }
+
+ if !image
+ .usage()
+ .intersects(ImageUsage::ATTACHMENT_FEEDBACK_LOOP)
+ {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierImageMissingUsageForLayout {
+ barrier_index,
+ layout,
+ requires_one_of_usage: ImageUsage::ATTACHMENT_FEEDBACK_LOOP,
+ },
+ );
+ }
+ }*/
+
+ let requires_one_of_usage = match layout {
+ // VUID-VkImageMemoryBarrier2-oldLayout-01208
+ ImageLayout::ColorAttachmentOptimal => ImageUsage::COLOR_ATTACHMENT,
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01209
+ ImageLayout::DepthStencilAttachmentOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01210
+ ImageLayout::DepthStencilReadOnlyOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01211
+ ImageLayout::ShaderReadOnlyOptimal => {
+ ImageUsage::SAMPLED | ImageUsage::INPUT_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01212
+ ImageLayout::TransferSrcOptimal => ImageUsage::TRANSFER_SRC,
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01213
+ ImageLayout::TransferDstOptimal => ImageUsage::TRANSFER_DST,
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01658
+ ImageLayout::DepthReadOnlyStencilAttachmentOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01659
+ ImageLayout::DepthAttachmentStencilReadOnlyOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ }
+
+ /*
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-04065
+ ImageLayout::DepthReadOnlyOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ | ImageUsage::SAMPLED
+ | ImageUsage::INPUT_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-04066
+ ImageLayout::DepthAttachmentOptimal => ImageUsage::DEPTH_STENCIL_ATTACHMENT,
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-04067
+ ImageLayout::StencilReadOnlyOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ | ImageUsage::SAMPLED
+ | ImageUsage::INPUT_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-04068
+ ImageLayout::StencilAttachmentOptimal => ImageUsage::DEPTH_STENCIL_ATTACHMENT,
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-03938
+ ImageLayout::AttachmentOptimal => {
+ ImageUsage::COLOR_ATTACHMENT | ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-03939
+ ImageLayout::ReadOnlyOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ | ImageUsage::SAMPLED
+ | ImageUsage::INPUT_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-02088
+ ImageLayout::FragmentShadingRateAttachmentOptimal => {
+ ImageUsage::FRAGMENT_SHADING_RATE_ATTACHMENT
+ }
+ */
+ _ => continue,
+ };
+
+ if !image.usage().intersects(requires_one_of_usage) {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierImageMissingUsageForLayout {
+ barrier_index,
+ layout,
+ requires_one_of_usage,
+ },
+ );
+ }
+ }
+
+ /*
+ Check queue family tansfer
+ */
+
+ check_queue_family_ownership_transfer(
+ 'i',
+ barrier_index,
+ src_stages,
+ dst_stages,
+ queue_family_ownership_transfer,
+ image.sharing(),
+ )?;
+
+ /*
+ Check subresource range
+ */
+
+ // VUID-VkImageSubresourceRange-aspectMask-requiredbitmask
+ assert!(!subresource_range.aspects.is_empty());
+
+ // VUID-VkImageSubresourceRange-aspectMask-parameter
+ subresource_range.aspects.validate_device(device)?;
+
+ let image_aspects = image.format().unwrap().aspects();
+
+ // VUID-VkImageMemoryBarrier2-image-01673
+ // VUID-VkImageMemoryBarrier2-image-03319
+ if image_aspects.contains(subresource_range.aspects) {
+ return Err(SynchronizationError::ImageMemoryBarrierAspectsNotAllowed {
+ barrier_index,
+ aspects: subresource_range.aspects - image_aspects,
+ });
+ }
+
+ if image_aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL) {
+ // VUID-VkImageMemoryBarrier2-image-03320
+ if !device.enabled_features().separate_depth_stencil_layouts
+ && image_aspects.contains(ImageAspects::DEPTH | ImageAspects::STENCIL)
+ && !subresource_range
+ .aspects
+ .contains(ImageAspects::DEPTH | ImageAspects::STENCIL)
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`dependency_info.image_memory_barriers` has an element \
+ where `image` has both a depth and a stencil aspect, and \
+ `subresource_range.aspects` does not contain both aspects",
+ requires_one_of: RequiresOneOf {
+ features: &["separate_depth_stencil_layouts"],
+ ..Default::default()
+ },
+ });
+ }
+ } else {
+ // VUID-VkImageMemoryBarrier2-image-01671
+ if !image.flags().intersects(ImageCreateFlags::DISJOINT)
+ && subresource_range.aspects != ImageAspects::COLOR
+ {
+ return Err(SynchronizationError::ImageMemoryBarrierAspectsNotAllowed {
+ barrier_index,
+ aspects: subresource_range.aspects - ImageAspects::COLOR,
+ });
+ }
+ }
+
+ // VUID-VkImageSubresourceRange-levelCount-01720
+ assert!(!subresource_range.mip_levels.is_empty());
+
+ // VUID-VkImageMemoryBarrier2-subresourceRange-01486
+ // VUID-VkImageMemoryBarrier2-subresourceRange-01724
+ if subresource_range.mip_levels.end > image.mip_levels() {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierMipLevelsOutOfRange {
+ barrier_index,
+ mip_levels_range_end: subresource_range.mip_levels.end,
+ image_mip_levels: image.mip_levels(),
+ },
+ );
+ }
+
+ // VUID-VkImageSubresourceRange-layerCount-01721
+ assert!(!subresource_range.array_layers.is_empty());
+
+ // VUID-VkImageMemoryBarrier2-subresourceRange-01488
+ // VUID-VkImageMemoryBarrier2-subresourceRange-01725
+ if subresource_range.array_layers.end > image.dimensions().array_layers() {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierArrayLayersOutOfRange {
+ barrier_index,
+ array_layers_range_end: subresource_range.array_layers.end,
+ image_array_layers: image.dimensions().array_layers(),
+ },
+ );
+ }
+ }
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn wait_events_unchecked(
+ &mut self,
+ events: impl IntoIterator<Item = (Arc<Event>, DependencyInfo)>,
+ ) -> &mut Self {
+ let events: SmallVec<[(Arc<Event>, DependencyInfo); 4]> = events.into_iter().collect();
+ let fns = self.device().fns();
+
+ // VUID-vkCmdWaitEvents2-pEvents-03837
+ // Ensured by using `vkCmdSetEvent2` and `vkCmdWaitEvents2` under the exact same
+ // conditions, i.e. when `synchronization2` is enabled.
+
+ if self.device().enabled_features().synchronization2 {
+ struct PerDependencyInfo {
+ memory_barriers_vk: SmallVec<[ash::vk::MemoryBarrier2; 2]>,
+ buffer_memory_barriers_vk: SmallVec<[ash::vk::BufferMemoryBarrier2; 8]>,
+ image_memory_barriers_vk: SmallVec<[ash::vk::ImageMemoryBarrier2; 8]>,
+ }
+
+ let mut events_vk: SmallVec<[_; 4]> = SmallVec::new();
+ let mut dependency_infos_vk: SmallVec<[_; 4]> = SmallVec::new();
+ let mut per_dependency_info_vk: SmallVec<[_; 4]> = SmallVec::new();
+
+ for (event, dependency_info) in &events {
+ let &DependencyInfo {
+ dependency_flags,
+ ref memory_barriers,
+ ref buffer_memory_barriers,
+ ref image_memory_barriers,
+ _ne: _,
+ } = dependency_info;
+
+ let memory_barriers_vk: SmallVec<[_; 2]> = memory_barriers
+ .iter()
+ .map(|barrier| {
+ let &MemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ _ne: _,
+ } = barrier;
+
+ ash::vk::MemoryBarrier2 {
+ src_stage_mask: src_stages.into(),
+ src_access_mask: src_access.into(),
+ dst_stage_mask: dst_stages.into(),
+ dst_access_mask: dst_access.into(),
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let buffer_memory_barriers_vk: SmallVec<[_; 8]> = buffer_memory_barriers
+ .iter()
+ .map(|barrier| {
+ let &BufferMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ queue_family_ownership_transfer,
+ ref buffer,
+ ref range,
+ _ne: _,
+ } = barrier;
+
+ let (src_queue_family_index, dst_queue_family_index) =
+ queue_family_ownership_transfer.map_or(
+ (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED),
+ Into::into,
+ );
+
+ ash::vk::BufferMemoryBarrier2 {
+ src_stage_mask: src_stages.into(),
+ src_access_mask: src_access.into(),
+ dst_stage_mask: dst_stages.into(),
+ dst_access_mask: dst_access.into(),
+ src_queue_family_index,
+ dst_queue_family_index,
+ buffer: buffer.handle(),
+ offset: range.start,
+ size: range.end - range.start,
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let image_memory_barriers_vk: SmallVec<[_; 8]> = image_memory_barriers
+ .iter()
+ .map(|barrier| {
+ let &ImageMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ old_layout,
+ new_layout,
+ queue_family_ownership_transfer,
+ ref image,
+ ref subresource_range,
+ _ne: _,
+ } = barrier;
+
+ let (src_queue_family_index, dst_queue_family_index) =
+ queue_family_ownership_transfer.map_or(
+ (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED),
+ Into::into,
+ );
+
+ ash::vk::ImageMemoryBarrier2 {
+ src_stage_mask: src_stages.into(),
+ src_access_mask: src_access.into(),
+ dst_stage_mask: dst_stages.into(),
+ dst_access_mask: dst_access.into(),
+ old_layout: old_layout.into(),
+ new_layout: new_layout.into(),
+ src_queue_family_index,
+ dst_queue_family_index,
+ image: image.handle(),
+ subresource_range: subresource_range.clone().into(),
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ events_vk.push(event.handle());
+ dependency_infos_vk.push(ash::vk::DependencyInfo {
+ dependency_flags: dependency_flags.into(),
+ memory_barrier_count: 0,
+ p_memory_barriers: ptr::null(),
+ buffer_memory_barrier_count: 0,
+ p_buffer_memory_barriers: ptr::null(),
+ image_memory_barrier_count: 0,
+ p_image_memory_barriers: ptr::null(),
+ ..Default::default()
+ });
+ per_dependency_info_vk.push(PerDependencyInfo {
+ memory_barriers_vk,
+ buffer_memory_barriers_vk,
+ image_memory_barriers_vk,
+ });
+ }
+
+ for (
+ dependency_info_vk,
+ PerDependencyInfo {
+ memory_barriers_vk,
+ buffer_memory_barriers_vk,
+ image_memory_barriers_vk,
+ },
+ ) in (dependency_infos_vk.iter_mut()).zip(per_dependency_info_vk.iter_mut())
+ {
+ *dependency_info_vk = ash::vk::DependencyInfo {
+ memory_barrier_count: memory_barriers_vk.len() as u32,
+ p_memory_barriers: memory_barriers_vk.as_ptr(),
+ buffer_memory_barrier_count: buffer_memory_barriers_vk.len() as u32,
+ p_buffer_memory_barriers: buffer_memory_barriers_vk.as_ptr(),
+ image_memory_barrier_count: image_memory_barriers_vk.len() as u32,
+ p_image_memory_barriers: image_memory_barriers_vk.as_ptr(),
+ ..*dependency_info_vk
+ }
+ }
+
+ if self.device().api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_wait_events2)(
+ self.handle(),
+ events_vk.len() as u32,
+ events_vk.as_ptr(),
+ dependency_infos_vk.as_ptr(),
+ );
+ } else {
+ debug_assert!(self.device().enabled_extensions().khr_synchronization2);
+ (fns.khr_synchronization2.cmd_wait_events2_khr)(
+ self.handle(),
+ events_vk.len() as u32,
+ events_vk.as_ptr(),
+ dependency_infos_vk.as_ptr(),
+ );
+ }
+ } else {
+ // With the original function, you can only specify a single dependency info for all
+ // events at once, rather than separately for each event. Therefore, to achieve the
+ // same behaviour as the "2" function, we split it up into multiple Vulkan API calls,
+ // one per event.
+
+ for (event, dependency_info) in &events {
+ let events_vk = [event.handle()];
+
+ let DependencyInfo {
+ dependency_flags: _,
+ memory_barriers,
+ buffer_memory_barriers,
+ image_memory_barriers,
+ _ne: _,
+ } = dependency_info;
+
+ let mut src_stage_mask = ash::vk::PipelineStageFlags::empty();
+ let mut dst_stage_mask = ash::vk::PipelineStageFlags::empty();
+
+ let memory_barriers_vk: SmallVec<[_; 2]> = memory_barriers
+ .iter()
+ .map(|barrier| {
+ let &MemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ _ne: _,
+ } = barrier;
+
+ src_stage_mask |= src_stages.into();
+ dst_stage_mask |= dst_stages.into();
+
+ ash::vk::MemoryBarrier {
+ src_access_mask: src_access.into(),
+ dst_access_mask: dst_access.into(),
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let buffer_memory_barriers_vk: SmallVec<[_; 8]> = buffer_memory_barriers
+ .iter()
+ .map(|barrier| {
+ let &BufferMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ queue_family_ownership_transfer,
+ ref buffer,
+ ref range,
+ _ne: _,
+ } = barrier;
+
+ src_stage_mask |= src_stages.into();
+ dst_stage_mask |= dst_stages.into();
+
+ let (src_queue_family_index, dst_queue_family_index) =
+ queue_family_ownership_transfer.map_or(
+ (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED),
+ Into::into,
+ );
+
+ ash::vk::BufferMemoryBarrier {
+ src_access_mask: src_access.into(),
+ dst_access_mask: dst_access.into(),
+ src_queue_family_index,
+ dst_queue_family_index,
+ buffer: buffer.handle(),
+ offset: range.start,
+ size: range.end - range.start,
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let image_memory_barriers_vk: SmallVec<[_; 8]> = image_memory_barriers
+ .iter()
+ .map(|barrier| {
+ let &ImageMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ old_layout,
+ new_layout,
+ queue_family_ownership_transfer,
+ ref image,
+ ref subresource_range,
+ _ne: _,
+ } = barrier;
+
+ src_stage_mask |= src_stages.into();
+ dst_stage_mask |= dst_stages.into();
+
+ let (src_queue_family_index, dst_queue_family_index) =
+ queue_family_ownership_transfer.map_or(
+ (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED),
+ Into::into,
+ );
+
+ ash::vk::ImageMemoryBarrier {
+ src_access_mask: src_access.into(),
+ dst_access_mask: dst_access.into(),
+ old_layout: old_layout.into(),
+ new_layout: new_layout.into(),
+ src_queue_family_index,
+ dst_queue_family_index,
+ image: image.handle(),
+ subresource_range: subresource_range.clone().into(),
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ if src_stage_mask.is_empty() {
+ // "VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT is [...] equivalent to
+ // VK_PIPELINE_STAGE_2_NONE in the first scope."
+ src_stage_mask |= ash::vk::PipelineStageFlags::TOP_OF_PIPE;
+ }
+
+ if dst_stage_mask.is_empty() {
+ // "VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT is [...] equivalent to
+ // VK_PIPELINE_STAGE_2_NONE in the second scope."
+ dst_stage_mask |= ash::vk::PipelineStageFlags::BOTTOM_OF_PIPE;
+ }
+
+ (fns.v1_0.cmd_wait_events)(
+ self.handle(),
+ 1,
+ events_vk.as_ptr(),
+ src_stage_mask,
+ dst_stage_mask,
+ memory_barriers_vk.len() as u32,
+ memory_barriers_vk.as_ptr(),
+ buffer_memory_barriers_vk.len() as u32,
+ buffer_memory_barriers_vk.as_ptr(),
+ image_memory_barriers_vk.len() as u32,
+ image_memory_barriers_vk.as_ptr(),
+ );
+ }
+ }
+
+ self.resources
+ .extend(events.into_iter().map(|(event, _)| Box::new(event) as _));
+
+ // TODO: sync state update
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Resets an [`Event`] back to the unsignaled state.
+ ///
+ /// # Safety
+ ///
+ /// - Appropriate synchronization must be provided for `event` against any previous
+ /// [`set_event`] or [`wait_events`] command.
+ ///
+ /// [`set_event`]: Self::set_event
+ /// [`wait_events`]: Self::wait_events
+ #[inline]
+ pub unsafe fn reset_event(
+ &mut self,
+ event: Arc<Event>,
+ stages: PipelineStages,
+ ) -> Result<&mut Self, SynchronizationError> {
+ self.validate_reset_event(&event, stages)?;
+
+ unsafe { Ok(self.reset_event_unchecked(event, stages)) }
+ }
+
+ fn validate_reset_event(
+ &self,
+ event: &Event,
+ stages: PipelineStages,
+ ) -> Result<(), SynchronizationError> {
+ // VUID-vkCmdResetEvent2-renderpass
+ if self.builder_state.render_pass.is_some() {
+ return Err(SynchronizationError::ForbiddenInsideRenderPass);
+ }
+
+ // VUID-vkCmdResetEvent2-commandBuffer-03833
+ // TODO:
+
+ let device = self.device();
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdResetEvent2-commandBuffer-cmdpool
+ if !queue_family_properties.queue_flags.intersects(
+ QueueFlags::GRAPHICS
+ | QueueFlags::COMPUTE
+ | QueueFlags::VIDEO_DECODE
+ | QueueFlags::VIDEO_ENCODE,
+ ) {
+ return Err(SynchronizationError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdResetEvent2-commonparent
+ assert_eq!(device, event.device());
+
+ // VUID-vkCmdResetEvent2-stageMask-parameter
+ stages.validate_device(device)?;
+
+ // VUID-vkCmdResetEvent2-synchronization2-03829
+ if !device.enabled_features().synchronization2 {
+ if stages.is_2() {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`stages` contains flags from `VkPipelineStageFlagBits2`",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+
+ // VUID-vkCmdResetEvent2-stageMask-03929
+ if stages.intersects(PipelineStages::GEOMETRY_SHADER)
+ && !device.enabled_features().geometry_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`stages` contains `PipelineStages::GEOMETRY_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["geometry_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdResetEvent2-stageMask-03930
+ if stages.intersects(
+ PipelineStages::TESSELLATION_CONTROL_SHADER
+ | PipelineStages::TESSELLATION_EVALUATION_SHADER,
+ ) && !device.enabled_features().tessellation_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`stages` contains `PipelineStages::TESSELLATION_CONTROL_SHADER` or \
+ `PipelineStages::TESSELLATION_EVALUATION_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["tessellation_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdResetEvent2-stageMask-03931
+ if stages.intersects(PipelineStages::CONDITIONAL_RENDERING)
+ && !device.enabled_features().conditional_rendering
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`stages` contains `PipelineStages::CONDITIONAL_RENDERING`",
+ requires_one_of: RequiresOneOf {
+ features: &["conditional_rendering"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdResetEvent2-stageMask-03932
+ if stages.intersects(PipelineStages::FRAGMENT_DENSITY_PROCESS)
+ && !device.enabled_features().fragment_density_map
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`stages` contains `PipelineStages::FRAGMENT_DENSITY_PROCESS`",
+ requires_one_of: RequiresOneOf {
+ features: &["fragment_density_map"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdResetEvent2-stageMask-03933
+ if stages.intersects(PipelineStages::TRANSFORM_FEEDBACK)
+ && !device.enabled_features().transform_feedback
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`stages` contains `PipelineStages::TRANSFORM_FEEDBACK`",
+ requires_one_of: RequiresOneOf {
+ features: &["transform_feedback"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdResetEvent2-stageMask-03934
+ if stages.intersects(PipelineStages::MESH_SHADER) && !device.enabled_features().mesh_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`stages` contains `PipelineStages::MESH_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["mesh_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdResetEvent2-stageMask-03935
+ if stages.intersects(PipelineStages::TASK_SHADER) && !device.enabled_features().task_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`stages` contains `PipelineStages::TASK_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["task_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdResetEvent2-shadingRateImage-07316
+ if stages.intersects(PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT)
+ && !(device.enabled_features().attachment_fragment_shading_rate
+ || device.enabled_features().shading_rate_image)
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`stages` contains \
+ `PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT`",
+ requires_one_of: RequiresOneOf {
+ features: &["attachment_fragment_shading_rate", "shading_rate_image"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdResetEvent2-stageMask-04957
+ if stages.intersects(PipelineStages::SUBPASS_SHADING)
+ && !device.enabled_features().subpass_shading
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`stages` contains `PipelineStages::SUBPASS_SHADING`",
+ requires_one_of: RequiresOneOf {
+ features: &["subpass_shading"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdResetEvent2-stageMask-04995
+ if stages.intersects(PipelineStages::INVOCATION_MASK)
+ && !device.enabled_features().invocation_mask
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`stages` contains `PipelineStages::INVOCATION_MASK`",
+ requires_one_of: RequiresOneOf {
+ features: &["invocation_mask"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdResetEvent-stageMask-03937
+ if stages.is_empty() && !device.enabled_features().synchronization2 {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`stages` is empty",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdResetEvent2-stageMask-03830
+ if stages.intersects(PipelineStages::HOST) {
+ todo!()
+ }
+
+ // VUID-vkCmdResetEvent2-event-03831
+ // VUID-vkCmdResetEvent2-event-03832
+ // TODO:
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn reset_event_unchecked(
+ &mut self,
+ event: Arc<Event>,
+ stages: PipelineStages,
+ ) -> &mut Self {
+ let fns = self.device().fns();
+
+ if self.device().enabled_features().synchronization2 {
+ if self.device().api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_reset_event2)(self.handle(), event.handle(), stages.into());
+ } else {
+ debug_assert!(self.device().enabled_extensions().khr_synchronization2);
+ (fns.khr_synchronization2.cmd_reset_event2_khr)(
+ self.handle(),
+ event.handle(),
+ stages.into(),
+ );
+ }
+ } else {
+ (fns.v1_0.cmd_reset_event)(self.handle(), event.handle(), stages.into());
+ }
+
+ self.resources.push(Box::new(event));
+
+ // TODO: sync state update
+
+ self.next_command_index += 1;
+ self
+ }
+}
+
+/// Error that can happen when recording a synchronization command.
+#[derive(Clone, Debug)]
+pub enum SynchronizationError {
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+
+ /// One or more accesses of a buffer memory barrier are not supported by the corresponding
+ /// pipeline stages.
+ BufferMemoryBarrierAccessNotSupportedByStages { barrier_index: usize },
+
+ /// Buffer memory barriers are forbidden inside a render pass instance.
+ BufferMemoryBarrierForbiddenInsideRenderPass,
+
+ /// The end of `range` of a buffer memory barrier is greater than the size of `buffer`.
+ BufferMemoryBarrierOutOfRange {
+ barrier_index: usize,
+ range_end: DeviceSize,
+ buffer_size: DeviceSize,
+ },
+
+ /// A buffer memory barrier contains a queue family ownership transfer, but either the
+ /// `src_stages` or `dst_stages` contain [`HOST`].
+ ///
+ /// [`HOST`]: crate::sync::PipelineStages::HOST
+ BufferMemoryBarrierOwnershipTransferHostNotAllowed { barrier_index: usize },
+
+ /// The provided `src_index` or `dst_index` in the queue family ownership transfer of a
+ /// buffer memory barrier is not less than the number of queue families in the physical device.
+ BufferMemoryBarrierOwnershipTransferIndexOutOfRange {
+ barrier_index: usize,
+ provided_queue_family_index: u32,
+ queue_family_count: u32,
+ },
+
+ /// The provided `queue_family_ownership_transfer` value of a buffer memory barrier does not
+ /// match the sharing mode of `buffer`.
+ BufferMemoryBarrierOwnershipTransferSharingMismatch { barrier_index: usize },
+
+ /// One or more pipeline stages of a buffer memory barrier are not supported by the queue
+ /// family of the command buffer.
+ BufferMemoryBarrierStageNotSupported { barrier_index: usize },
+
+ /// A render pass instance is not active, and the `VIEW_LOCAL` dependency flag was provided.
+ DependencyFlagsViewLocalNotAllowed,
+
+ /// Operation forbidden inside a render pass.
+ ForbiddenInsideRenderPass,
+
+ /// Operation forbidden inside a render pass instance that was begun with `begin_rendering`.
+ ForbiddenWithBeginRendering,
+
+ /// One or more accesses of an image memory barrier are not supported by the corresponding
+ /// pipeline stages.
+ ImageMemoryBarrierAccessNotSupportedByStages { barrier_index: usize },
+
+ /// The end of the range of array layers of the subresource range of an image memory barrier
+ /// is greater than the number of array layers in the image.
+ ImageMemoryBarrierArrayLayersOutOfRange {
+ barrier_index: usize,
+ array_layers_range_end: u32,
+ image_array_layers: u32,
+ },
+
+ /// The aspects of the subresource range of an image memory barrier contain aspects that are
+ /// not present in the image, or that are not allowed.
+ ImageMemoryBarrierAspectsNotAllowed {
+ barrier_index: usize,
+ aspects: ImageAspects,
+ },
+
+ /// For the `old_layout` or `new_layout` of an image memory barrier, `image` does not have a
+ /// usage that is required.
+ ImageMemoryBarrierImageMissingUsageForLayout {
+ barrier_index: usize,
+ layout: ImageLayout,
+ requires_one_of_usage: ImageUsage,
+ },
+
+ /// An image memory barrier contains an image layout transition, but a render pass
+ /// instance is active.
+ ImageMemoryBarrierLayoutTransitionForbiddenInsideRenderPass { barrier_index: usize },
+
+ /// The end of the range of mip levels of the subresource range of an image memory barrier
+ /// is greater than the number of mip levels in the image.
+ ImageMemoryBarrierMipLevelsOutOfRange {
+ barrier_index: usize,
+ mip_levels_range_end: u32,
+ image_mip_levels: u32,
+ },
+
+ /// The `new_layout` of an image memory barrier is `Undefined` or `Preinitialized`.
+ ImageMemoryBarrierNewLayoutInvalid { barrier_index: usize },
+
+ /// A render pass instance is active, and the image of an image memory barrier is not a color
+ /// or depth/stencil attachment of the current subpass.
+ ImageMemoryBarrierNotColorDepthStencilAttachment { barrier_index: usize },
+
+ /// A render pass instance is active, and the image of an image memory barrier is not an input
+ /// attachment of the current subpass.
+ ImageMemoryBarrierNotInputAttachment { barrier_index: usize },
+
+ /// The `src_stages` of an image memory barrier contains [`HOST`], but `old_layout` is not
+ /// `Preinitialized`, `Undefined` or `General`.
+ ///
+ /// [`HOST`]: crate::sync::PipelineStages::HOST
+ ImageMemoryBarrierOldLayoutFromHostInvalid {
+ barrier_index: usize,
+ old_layout: ImageLayout,
+ },
+
+ /// An image memory barrier contains a queue family ownership transfer, but a render pass
+ /// instance is active.
+ ImageMemoryBarrierOwnershipTransferForbiddenInsideRenderPass { barrier_index: usize },
+
+ /// An image memory barrier contains a queue family ownership transfer, but either the
+ /// `src_stages` or `dst_stages` contain [`HOST`].
+ ///
+ /// [`HOST`]: crate::sync::PipelineStages::HOST
+ ImageMemoryBarrierOwnershipTransferHostForbidden { barrier_index: usize },
+
+ /// The provided `src_index` or `dst_index` in the queue family ownership transfer of an
+ /// image memory barrier is not less than the number of queue families in the physical device.
+ ImageMemoryBarrierOwnershipTransferIndexOutOfRange {
+ barrier_index: usize,
+ provided_queue_family_index: u32,
+ queue_family_count: u32,
+ },
+
+ /// The provided `queue_family_ownership_transfer` value of an image memory barrier does not
+ /// match the sharing mode of `image`.
+ ImageMemoryBarrierOwnershipTransferSharingMismatch { barrier_index: usize },
+
+ /// One or more pipeline stages of an image memory barrier are not supported by the queue
+ /// family of the command buffer.
+ ImageMemoryBarrierStageNotSupported { barrier_index: usize },
+
+ /// One or more accesses of a memory barrier are not supported by the corresponding
+ /// pipeline stages.
+ MemoryBarrierAccessNotSupportedByStages { barrier_index: usize },
+
+ /// A render pass instance is active, but the render pass does not have a subpass
+ /// self-dependency for the current subpass that is a superset of the barriers.
+ MemoryBarrierNoMatchingSubpassSelfDependency,
+
+ /// One or more pipeline stages of a memory barrier are not supported by the queue
+ /// family of the command buffer.
+ MemoryBarrierStageNotSupported { barrier_index: usize },
+
+ /// The queue family doesn't allow this operation.
+ NotSupportedByQueueFamily,
+}
+
+impl Error for SynchronizationError {}
+
+impl Display for SynchronizationError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+
+ Self::BufferMemoryBarrierAccessNotSupportedByStages { barrier_index } => write!(
+ f,
+ "one or more accesses of buffer memory barrier {} are not supported by the \
+ corresponding pipeline stages",
+ barrier_index,
+ ),
+ Self::BufferMemoryBarrierForbiddenInsideRenderPass => write!(
+ f,
+ "buffer memory barriers are forbidden inside a render pass instance",
+ ),
+ Self::BufferMemoryBarrierOutOfRange {
+ barrier_index,
+ range_end,
+ buffer_size,
+ } => write!(
+ f,
+ "the end of `range` ({}) of buffer memory barrier {} is greater than the size of \
+ `buffer` ({})",
+ range_end, barrier_index, buffer_size,
+ ),
+ Self::BufferMemoryBarrierOwnershipTransferHostNotAllowed { barrier_index } => write!(
+ f,
+ "buffer memory barrier {} contains a queue family ownership transfer, but either \
+ the `src_stages` or `dst_stages` contain `HOST`",
+ barrier_index,
+ ),
+ Self::BufferMemoryBarrierOwnershipTransferIndexOutOfRange {
+ barrier_index,
+ provided_queue_family_index,
+ queue_family_count,
+ } => write!(
+ f,
+ "the provided `src_index` or `dst_index` ({}) in the queue family ownership \
+ transfer of buffer memory barrier {} is not less than the number of queue \
+ families in the physical device ({})",
+ provided_queue_family_index, barrier_index, queue_family_count,
+ ),
+ Self::BufferMemoryBarrierOwnershipTransferSharingMismatch { barrier_index } => write!(
+ f,
+ "the provided `queue_family_ownership_transfer` value of buffer memory barrier {} \
+ does not match the sharing mode of `buffer`",
+ barrier_index,
+ ),
+ Self::BufferMemoryBarrierStageNotSupported { barrier_index } => write!(
+ f,
+ "one or more pipeline stages of buffer memory barrier {} are not supported by the \
+ queue family of the command buffer",
+ barrier_index,
+ ),
+ Self::DependencyFlagsViewLocalNotAllowed => write!(
+ f,
+ "a render pass instance is not active, and the `VIEW_LOCAL` dependency flag was \
+ provided",
+ ),
+ Self::ForbiddenInsideRenderPass => {
+ write!(f, "operation forbidden inside a render pass")
+ }
+ Self::ForbiddenWithBeginRendering => write!(
+ f,
+ "operation forbidden inside a render pass instance that was begun with \
+ `begin_rendering`",
+ ),
+ Self::ImageMemoryBarrierAccessNotSupportedByStages { barrier_index } => write!(
+ f,
+ "one or more accesses of image memory barrier {} are not supported by the \
+ corresponding pipeline stages",
+ barrier_index,
+ ),
+ Self::ImageMemoryBarrierArrayLayersOutOfRange {
+ barrier_index,
+ array_layers_range_end,
+ image_array_layers,
+ } => write!(
+ f,
+ "the end of the range of array layers ({}) of the subresource range of image \
+ memory barrier {} is greater than the number of array layers in the image ({})",
+ array_layers_range_end, barrier_index, image_array_layers,
+ ),
+ Self::ImageMemoryBarrierAspectsNotAllowed {
+ barrier_index,
+ aspects,
+ } => write!(
+ f,
+ "the aspects of the subresource range of image memory barrier {} contain aspects \
+ that are not present in the image, or that are not allowed ({:?})",
+ barrier_index, aspects,
+ ),
+ Self::ImageMemoryBarrierImageMissingUsageForLayout {
+ barrier_index,
+ layout,
+ requires_one_of_usage,
+ } => write!(
+ f,
+ "for the `old_layout` or `new_layout` ({:?}) of image memory barrier {}, `image` \
+ does not have a usage that is required ({}{:?})",
+ layout,
+ barrier_index,
+ if requires_one_of_usage.count() > 1 {
+ "one of "
+ } else {
+ ""
+ },
+ requires_one_of_usage,
+ ),
+ Self::ImageMemoryBarrierLayoutTransitionForbiddenInsideRenderPass { barrier_index } => {
+ write!(
+ f,
+ "image memory barrier {} contains an image layout transition, but a render \
+ pass instance is active",
+ barrier_index,
+ )
+ }
+ Self::ImageMemoryBarrierMipLevelsOutOfRange {
+ barrier_index,
+ mip_levels_range_end,
+ image_mip_levels,
+ } => write!(
+ f,
+ "the end of the range of mip levels ({}) of the subresource range of image \
+ memory barrier {} is greater than the number of mip levels in the image ({})",
+ mip_levels_range_end, barrier_index, image_mip_levels,
+ ),
+ Self::ImageMemoryBarrierNewLayoutInvalid { barrier_index } => write!(
+ f,
+ "the `new_layout` of image memory barrier {} is `Undefined` or `Preinitialized`",
+ barrier_index,
+ ),
+ Self::ImageMemoryBarrierNotColorDepthStencilAttachment { barrier_index } => write!(
+ f,
+ "a render pass instance is active, and the image of image memory barrier {} is \
+ not a color or depth/stencil attachment of the current subpass",
+ barrier_index,
+ ),
+ Self::ImageMemoryBarrierNotInputAttachment { barrier_index } => write!(
+ f,
+ "a render pass instance is active, and the image of image memory barrier {} is \
+ not an input attachment of the current subpass",
+ barrier_index,
+ ),
+ Self::ImageMemoryBarrierOldLayoutFromHostInvalid {
+ barrier_index,
+ old_layout,
+ } => write!(
+ f,
+ "the `src_stages` of image memory barrier {} contains `HOST`, but `old_layout`
+ ({:?}) is not `Preinitialized`, `Undefined` or `General`",
+ barrier_index, old_layout,
+ ),
+ Self::ImageMemoryBarrierOwnershipTransferForbiddenInsideRenderPass {
+ barrier_index,
+ } => write!(
+ f,
+ "image memory barrier {} contains a queue family ownership transfer, but a render \
+ pass instance is active",
+ barrier_index,
+ ),
+ Self::ImageMemoryBarrierOwnershipTransferHostForbidden { barrier_index } => write!(
+ f,
+ "image memory barrier {} contains a queue family ownership transfer, but either \
+ the `src_stages` or `dst_stages` contain `HOST`",
+ barrier_index,
+ ),
+ Self::ImageMemoryBarrierOwnershipTransferIndexOutOfRange {
+ barrier_index,
+ provided_queue_family_index,
+ queue_family_count,
+ } => write!(
+ f,
+ "the provided `src_index` or `dst_index` ({}) in the queue family ownership \
+ transfer of image memory barrier {} is not less than the number of queue
+ families in the physical device ({})",
+ provided_queue_family_index, barrier_index, queue_family_count,
+ ),
+ Self::ImageMemoryBarrierOwnershipTransferSharingMismatch { barrier_index } => write!(
+ f,
+ "the provided `queue_family_ownership_transfer` value of image memory barrier {} \
+ does not match the sharing mode of `image`",
+ barrier_index,
+ ),
+ Self::ImageMemoryBarrierStageNotSupported { barrier_index } => write!(
+ f,
+ "one or more pipeline stages of image memory barrier {} are not supported by the \
+ queue family of the command buffer",
+ barrier_index,
+ ),
+ Self::MemoryBarrierAccessNotSupportedByStages { barrier_index } => write!(
+ f,
+ "one or more accesses of memory barrier {} are not supported by the \
+ corresponding pipeline stages",
+ barrier_index,
+ ),
+ Self::MemoryBarrierNoMatchingSubpassSelfDependency => write!(
+ f,
+ "a render pass instance is active, but the render pass does not have a subpass \
+ self-dependency for the current subpass that is a superset of the barriers",
+ ),
+ Self::MemoryBarrierStageNotSupported { barrier_index } => write!(
+ f,
+ "one or more pipeline stages of memory barrier {} are not supported by the \
+ queue family of the command buffer",
+ barrier_index,
+ ),
+ Self::NotSupportedByQueueFamily => {
+ write!(f, "the queue family doesn't allow this operation")
+ }
+ }
+ }
+}
+
+impl From<RequirementNotMet> for SynchronizationError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
+ }
+ }
+}
diff --git a/src/command_buffer/standard/mod.rs b/src/command_buffer/standard/mod.rs
new file mode 100644
index 0000000..56b6b9e
--- /dev/null
+++ b/src/command_buffer/standard/mod.rs
@@ -0,0 +1,175 @@
+// Copyright (c) 2022 The Vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+//! The standard command buffer and builder.
+//!
+//! Using `CommandBufferBuilder`, you must manually record synchronization commands to ensure
+//! correct operation.
+
+#![allow(dead_code)]
+
+pub use self::builder::*;
+use super::{
+ allocator::{CommandBufferAlloc, StandardCommandBufferAlloc},
+ CommandBufferExecError, CommandBufferInheritanceInfo, CommandBufferState, CommandBufferUsage,
+};
+use crate::{
+ device::{Device, DeviceOwned},
+ VulkanObject,
+};
+use parking_lot::Mutex;
+use std::{
+ any::Any,
+ sync::{
+ atomic::{AtomicBool, Ordering},
+ Arc,
+ },
+};
+
+mod builder;
+
+/// A command buffer that is finished recording, and can be submitted to a queue.
+pub struct PrimaryCommandBuffer<A = StandardCommandBufferAlloc>
+where
+ A: CommandBufferAlloc,
+{
+ alloc: A,
+ _usage: CommandBufferUsage,
+ _resources: Vec<Box<dyn Any + Send + Sync>>,
+
+ _state: Mutex<CommandBufferState>,
+}
+
+unsafe impl<A> VulkanObject for PrimaryCommandBuffer<A>
+where
+ A: CommandBufferAlloc,
+{
+ type Handle = ash::vk::CommandBuffer;
+
+ #[inline]
+ fn handle(&self) -> Self::Handle {
+ self.alloc.inner().handle()
+ }
+}
+
+unsafe impl<A> DeviceOwned for PrimaryCommandBuffer<A>
+where
+ A: CommandBufferAlloc,
+{
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ self.alloc.device()
+ }
+}
+
+/// A command buffer that is finished recording, and can be executed within a primary command
+/// buffer by calling [`execute_commands`].
+///
+/// [`execute_commands`]: CommandBufferBuilder::execute_commands
+pub struct SecondaryCommandBuffer<A = StandardCommandBufferAlloc>
+where
+ A: CommandBufferAlloc,
+{
+ alloc: A,
+ inheritance_info: CommandBufferInheritanceInfo,
+ usage: CommandBufferUsage,
+ _resources: Vec<Box<dyn Any + Send + Sync>>,
+
+ submit_state: SubmitState,
+}
+
+unsafe impl<A> VulkanObject for SecondaryCommandBuffer<A>
+where
+ A: CommandBufferAlloc,
+{
+ type Handle = ash::vk::CommandBuffer;
+
+ #[inline]
+ fn handle(&self) -> Self::Handle {
+ self.alloc.inner().handle()
+ }
+}
+
+unsafe impl<A> DeviceOwned for SecondaryCommandBuffer<A>
+where
+ A: CommandBufferAlloc,
+{
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ self.alloc.device()
+ }
+}
+
+impl<A> SecondaryCommandBuffer<A>
+where
+ A: CommandBufferAlloc,
+{
+ #[inline]
+ pub fn inheritance_info(&self) -> &CommandBufferInheritanceInfo {
+ &self.inheritance_info
+ }
+
+ pub fn lock_record(&self) -> Result<(), CommandBufferExecError> {
+ match self.submit_state {
+ SubmitState::OneTime {
+ ref already_submitted,
+ } => {
+ let was_already_submitted = already_submitted.swap(true, Ordering::Acquire);
+ if was_already_submitted {
+ return Err(CommandBufferExecError::OneTimeSubmitAlreadySubmitted);
+ }
+ }
+ SubmitState::ExclusiveUse { ref in_use } => {
+ let already_in_use = in_use.swap(true, Ordering::Acquire);
+ if already_in_use {
+ return Err(CommandBufferExecError::ExclusiveAlreadyInUse);
+ }
+ }
+ SubmitState::Concurrent => (),
+ };
+
+ Ok(())
+ }
+
+ pub unsafe fn unlock(&self) {
+ match self.submit_state {
+ SubmitState::OneTime {
+ ref already_submitted,
+ } => {
+ debug_assert!(already_submitted.load(Ordering::Relaxed));
+ }
+ SubmitState::ExclusiveUse { ref in_use } => {
+ let old_val = in_use.swap(false, Ordering::Release);
+ debug_assert!(old_val);
+ }
+ SubmitState::Concurrent => (),
+ };
+ }
+}
+
+/// Whether the command buffer can be submitted.
+#[derive(Debug)]
+enum SubmitState {
+ /// The command buffer was created with the "SimultaneousUse" flag. Can always be submitted at
+ /// any time.
+ Concurrent,
+
+ /// The command buffer can only be submitted once simultaneously.
+ ExclusiveUse {
+ /// True if the command buffer is current in use by the GPU.
+ in_use: AtomicBool,
+ },
+
+ /// The command buffer can only ever be submitted once.
+ OneTime {
+ /// True if the command buffer has already been submitted once and can be no longer be
+ /// submitted.
+ already_submitted: AtomicBool,
+ },
+}
diff --git a/src/command_buffer/state_cacher.rs b/src/command_buffer/state_cacher.rs
deleted file mode 100644
index 63bfc3d..0000000
--- a/src/command_buffer/state_cacher.rs
+++ /dev/null
@@ -1,484 +0,0 @@
-// Copyright (c) 2017 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::buffer::BufferAccess;
-use crate::command_buffer::DynamicState;
-use crate::descriptor_set::DescriptorSetWithOffsets;
-use crate::pipeline::input_assembly::IndexType;
-use crate::pipeline::ComputePipelineAbstract;
-use crate::pipeline::GraphicsPipelineAbstract;
-use crate::pipeline::PipelineBindPoint;
-use crate::DeviceSize;
-use crate::VulkanObject;
-use smallvec::SmallVec;
-use std::ops::Range;
-
-/// Keep track of the state of a command buffer builder, so that you don't need to bind objects
-/// that were already bound.
-///
-/// > **Important**: Executing a secondary command buffer invalidates the state of a command buffer
-/// > builder. When you do so, you need to call `invalidate()`.
-pub struct StateCacher {
- // The dynamic state to synchronize with `CmdSetState`.
- dynamic_state: DynamicState,
- // The compute pipeline currently bound. 0 if nothing bound.
- compute_pipeline: ash::vk::Pipeline,
- // The graphics pipeline currently bound. 0 if nothing bound.
- graphics_pipeline: ash::vk::Pipeline,
- // The descriptor sets for the compute pipeline.
- compute_descriptor_sets: SmallVec<[(ash::vk::DescriptorSet, SmallVec<[u32; 32]>); 12]>,
- // The descriptor sets for the graphics pipeline.
- graphics_descriptor_sets: SmallVec<[(ash::vk::DescriptorSet, SmallVec<[u32; 32]>); 12]>,
- // If the user starts comparing descriptor sets, but drops the helper struct in the middle of
- // the processing then we will end up in a weird state. This bool is true when we start
- // comparing sets, and is set to false when we end up comparing. If it was true when we start
- // comparing, we know that something bad happened and we flush the cache.
- poisoned_descriptor_sets: bool,
- // The vertex buffers currently bound.
- vertex_buffers: SmallVec<[(ash::vk::Buffer, DeviceSize); 12]>,
- // Same as `poisoned_descriptor_sets` but for vertex buffers.
- poisoned_vertex_buffers: bool,
- // The index buffer, offset, and index type currently bound. `None` if nothing bound.
- index_buffer: Option<(ash::vk::Buffer, DeviceSize, IndexType)>,
-}
-
-/// Outcome of an operation.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum StateCacherOutcome {
- /// The caller needs to perform the state change in the actual command buffer builder.
- NeedChange,
- /// The state change is not necessary.
- AlreadyOk,
-}
-
-impl StateCacher {
- /// Builds a new `StateCacher`.
- #[inline]
- pub fn new() -> StateCacher {
- StateCacher {
- dynamic_state: DynamicState::none(),
- compute_pipeline: ash::vk::Pipeline::null(),
- graphics_pipeline: ash::vk::Pipeline::null(),
- compute_descriptor_sets: SmallVec::new(),
- graphics_descriptor_sets: SmallVec::new(),
- poisoned_descriptor_sets: false,
- vertex_buffers: SmallVec::new(),
- poisoned_vertex_buffers: false,
- index_buffer: None,
- }
- }
-
- /// Resets the cache to its default state. You **must** call this after executing a secondary
- /// command buffer.
- #[inline]
- pub fn invalidate(&mut self) {
- self.dynamic_state = DynamicState::none();
- self.compute_pipeline = ash::vk::Pipeline::null();
- self.graphics_pipeline = ash::vk::Pipeline::null();
- self.compute_descriptor_sets = SmallVec::new();
- self.graphics_descriptor_sets = SmallVec::new();
- self.vertex_buffers = SmallVec::new();
- self.index_buffer = None;
- }
-
- /// Compares the current state with `incoming`, and returns a new state that contains the
- /// states that differ and that need to be actually set in the command buffer builder.
- ///
- /// This function also updates the state cacher. The state cacher assumes that the state
- /// changes are going to be performed after this function returns.
- pub fn dynamic_state(&mut self, incoming: &DynamicState) -> DynamicState {
- let mut changed = DynamicState::none();
-
- macro_rules! cmp {
- ($field:ident) => {
- if self.dynamic_state.$field != incoming.$field {
- changed.$field = incoming.$field.clone();
- if incoming.$field.is_some() {
- self.dynamic_state.$field = incoming.$field.clone();
- }
- }
- };
- }
-
- cmp!(line_width);
- cmp!(viewports);
- cmp!(scissors);
- cmp!(compare_mask);
- cmp!(reference);
- cmp!(write_mask);
-
- changed
- }
-
- /// Starts the process of comparing a list of descriptor sets to the descriptor sets currently
- /// in cache.
- ///
- /// After calling this function, call `add` for each set one by one. Then call `compare` in
- /// order to get the index of the first set to bind, or `None` if the sets were identical to
- /// what is in cache.
- ///
- /// This process also updates the state cacher. The state cacher assumes that the state
- /// changes are going to be performed after the `compare` function returns.
- #[inline]
- pub fn bind_descriptor_sets(
- &mut self,
- pipeline_bind_point: PipelineBindPoint,
- ) -> StateCacherDescriptorSets {
- if self.poisoned_descriptor_sets {
- self.compute_descriptor_sets = SmallVec::new();
- self.graphics_descriptor_sets = SmallVec::new();
- }
-
- self.poisoned_descriptor_sets = true;
-
- StateCacherDescriptorSets {
- poisoned: &mut self.poisoned_descriptor_sets,
- state: match pipeline_bind_point {
- PipelineBindPoint::Compute => &mut self.compute_descriptor_sets,
- PipelineBindPoint::Graphics => &mut self.graphics_descriptor_sets,
- },
- offset: 0,
- found_diff: None,
- }
- }
-
- /// Checks whether we need to bind a graphics pipeline. Returns `StateCacherOutcome::AlreadyOk`
- /// if the pipeline was already bound earlier, and `StateCacherOutcome::NeedChange` if you need
- /// to actually bind the pipeline.
- ///
- /// This function also updates the state cacher. The state cacher assumes that the state
- /// changes are going to be performed after this function returns.
- pub fn bind_graphics_pipeline<P>(&mut self, pipeline: &P) -> StateCacherOutcome
- where
- P: GraphicsPipelineAbstract,
- {
- let inner = GraphicsPipelineAbstract::inner(pipeline).internal_object();
- if inner == self.graphics_pipeline {
- StateCacherOutcome::AlreadyOk
- } else {
- self.graphics_pipeline = inner;
- StateCacherOutcome::NeedChange
- }
- }
-
- /// Checks whether we need to bind a compute pipeline. Returns `StateCacherOutcome::AlreadyOk`
- /// if the pipeline was already bound earlier, and `StateCacherOutcome::NeedChange` if you need
- /// to actually bind the pipeline.
- ///
- /// This function also updates the state cacher. The state cacher assumes that the state
- /// changes are going to be performed after this function returns.
- pub fn bind_compute_pipeline<P>(&mut self, pipeline: &P) -> StateCacherOutcome
- where
- P: ComputePipelineAbstract,
- {
- let inner = pipeline.inner().internal_object();
- if inner == self.compute_pipeline {
- StateCacherOutcome::AlreadyOk
- } else {
- self.compute_pipeline = inner;
- StateCacherOutcome::NeedChange
- }
- }
-
- /// Starts the process of comparing a list of vertex buffers to the vertex buffers currently
- /// in cache.
- ///
- /// After calling this function, call `add` for each set one by one. Then call `compare` in
- /// order to get the range of the vertex buffers to bind, or `None` if the sets were identical
- /// to what is in cache.
- ///
- /// This process also updates the state cacher. The state cacher assumes that the state
- /// changes are going to be performed after the `compare` function returns.
- #[inline]
- pub fn bind_vertex_buffers(&mut self) -> StateCacherVertexBuffers {
- if self.poisoned_vertex_buffers {
- self.vertex_buffers = SmallVec::new();
- }
-
- self.poisoned_vertex_buffers = true;
-
- StateCacherVertexBuffers {
- poisoned: &mut self.poisoned_vertex_buffers,
- state: &mut self.vertex_buffers,
- offset: 0,
- first_diff: None,
- last_diff: 0,
- }
- }
-
- /// Checks whether we need to bind an index buffer. Returns `StateCacherOutcome::AlreadyOk`
- /// if the index buffer was already bound earlier, and `StateCacherOutcome::NeedChange` if you
- /// need to actually bind the buffer.
- ///
- /// This function also updates the state cacher. The state cacher assumes that the state
- /// changes are going to be performed after this function returns.
- pub fn bind_index_buffer<B>(&mut self, index_buffer: &B, ty: IndexType) -> StateCacherOutcome
- where
- B: ?Sized + BufferAccess,
- {
- let value = {
- let inner = index_buffer.inner();
- (inner.buffer.internal_object(), inner.offset, ty)
- };
-
- if self.index_buffer == Some(value) {
- StateCacherOutcome::AlreadyOk
- } else {
- self.index_buffer = Some(value);
- StateCacherOutcome::NeedChange
- }
- }
-}
-
-/// Helper struct for comparing descriptor sets.
-///
-/// > **Note**: For reliability reasons, if you drop/leak this struct before calling `compare` then
-/// > the cache of the currently bound descriptor sets will be reset.
-pub struct StateCacherDescriptorSets<'s> {
- // Reference to the parent's `poisoned_descriptor_sets`.
- poisoned: &'s mut bool,
- // Reference to the descriptor sets list to compare to.
- state: &'s mut SmallVec<[(ash::vk::DescriptorSet, SmallVec<[u32; 32]>); 12]>,
- // Next offset within the list to compare to.
- offset: usize,
- // Contains the return value of `compare`.
- found_diff: Option<u32>,
-}
-
-impl<'s> StateCacherDescriptorSets<'s> {
- /// Adds a descriptor set to the list to compare.
- #[inline]
- pub fn add(&mut self, descriptor_set: &DescriptorSetWithOffsets) {
- let (descriptor_set, dynamic_offsets) = descriptor_set.as_ref();
- let raw = descriptor_set.inner().internal_object();
- let dynamic_offsets = dynamic_offsets.iter().copied().collect();
-
- if let Some(state) = self.state.get_mut(self.offset) {
- if (&state.0, &state.1) == (&raw, &dynamic_offsets) {
- self.offset += 1;
- return;
- }
-
- *state = (raw, dynamic_offsets);
- } else {
- self.state.push((raw, dynamic_offsets));
- }
-
- if self.found_diff.is_none() {
- self.found_diff = Some(self.offset as u32);
- }
- self.offset += 1;
- }
-
- /// Compares your list to the list in cache, and returns the offset of the first set to bind.
- /// Returns `None` if the two lists were identical.
- ///
- /// After this function returns, the cache will be updated to match your list.
- #[inline]
- pub fn compare(self) -> Option<u32> {
- *self.poisoned = false;
- // Removing from the cache any set that wasn't added with `add`.
- self.state.truncate(self.offset);
- self.found_diff
- }
-}
-
-/// Helper struct for comparing vertex buffers.
-///
-/// > **Note**: For reliability reasons, if you drop/leak this struct before calling `compare` then
-/// > the cache of the currently bound vertex buffers will be reset.
-pub struct StateCacherVertexBuffers<'s> {
- // Reference to the parent's `poisoned_vertex_buffers`.
- poisoned: &'s mut bool,
- // Reference to the vertex buffers list to compare to.
- state: &'s mut SmallVec<[(ash::vk::Buffer, DeviceSize); 12]>,
- // Next offset within the list to compare to.
- offset: usize,
- // Contains the offset of the first vertex buffer that differs.
- first_diff: Option<u32>,
- // Offset of the last vertex buffer that differs.
- last_diff: u32,
-}
-
-impl<'s> StateCacherVertexBuffers<'s> {
- /// Adds a vertex buffer to the list to compare.
- #[inline]
- pub fn add<B>(&mut self, buffer: &B)
- where
- B: ?Sized + BufferAccess,
- {
- let raw = {
- let inner = buffer.inner();
- let raw = inner.buffer.internal_object();
- let offset = inner.offset;
- (raw, offset)
- };
-
- if self.offset < self.state.len() {
- if self.state[self.offset] == raw {
- self.offset += 1;
- return;
- }
-
- self.state[self.offset] = raw;
- } else {
- self.state.push(raw);
- }
-
- self.last_diff = self.offset as u32;
- if self.first_diff.is_none() {
- self.first_diff = Some(self.offset as u32);
- }
- self.offset += 1;
- }
-
- /// Compares your list to the list in cache, and returns the range of the vertex buffers to
- /// bind. Returns `None` if the two lists were identical.
- ///
- /// After this function returns, the cache will be updated to match your list.
- ///
- /// > **Note**: Keep in mind that `range.end` is *after* the last element. For example the
- /// > range `1 .. 2` only contains one element.
- #[inline]
- pub fn compare(self) -> Option<Range<u32>> {
- *self.poisoned = false;
-
- // Removing from the cache any set that wasn't added with `add`.
- self.state.truncate(self.offset);
-
- self.first_diff.map(|first| {
- debug_assert!(first <= self.last_diff);
- first..(self.last_diff + 1)
- })
- }
-}
-
-#[cfg(test)]
-mod tests {
- use crate::buffer::BufferUsage;
- use crate::buffer::CpuAccessibleBuffer;
- use crate::command_buffer::state_cacher::StateCacher;
-
- #[test]
- fn vb_caching_single() {
- let (device, queue) = gfx_dev_and_queue!();
-
- const EMPTY: [i32; 0] = [];
- let buf =
- CpuAccessibleBuffer::from_data(device, BufferUsage::vertex_buffer(), false, EMPTY)
- .unwrap();
-
- let mut cacher = StateCacher::new();
-
- {
- let mut bind_vb = cacher.bind_vertex_buffers();
- bind_vb.add(&buf);
- assert_eq!(bind_vb.compare(), Some(0..1));
- }
-
- for _ in 0..3 {
- let mut bind_vb = cacher.bind_vertex_buffers();
- bind_vb.add(&buf);
- assert_eq!(bind_vb.compare(), None);
- }
- }
-
- #[test]
- fn vb_caching_invalidated() {
- let (device, queue) = gfx_dev_and_queue!();
-
- const EMPTY: [i32; 0] = [];
- let buf =
- CpuAccessibleBuffer::from_data(device, BufferUsage::vertex_buffer(), false, EMPTY)
- .unwrap();
-
- let mut cacher = StateCacher::new();
-
- {
- let mut bind_vb = cacher.bind_vertex_buffers();
- bind_vb.add(&buf);
- assert_eq!(bind_vb.compare(), Some(0..1));
- }
-
- {
- let mut bind_vb = cacher.bind_vertex_buffers();
- bind_vb.add(&buf);
- assert_eq!(bind_vb.compare(), None);
- }
-
- cacher.invalidate();
-
- {
- let mut bind_vb = cacher.bind_vertex_buffers();
- bind_vb.add(&buf);
- assert_eq!(bind_vb.compare(), Some(0..1));
- }
- }
-
- #[test]
- fn vb_caching_multi() {
- let (device, queue) = gfx_dev_and_queue!();
-
- const EMPTY: [i32; 0] = [];
- let buf1 = CpuAccessibleBuffer::from_data(
- device.clone(),
- BufferUsage::vertex_buffer(),
- false,
- EMPTY,
- )
- .unwrap();
- let buf2 = CpuAccessibleBuffer::from_data(
- device.clone(),
- BufferUsage::vertex_buffer(),
- false,
- EMPTY,
- )
- .unwrap();
- let buf3 =
- CpuAccessibleBuffer::from_data(device, BufferUsage::vertex_buffer(), false, EMPTY)
- .unwrap();
-
- let mut cacher = StateCacher::new();
-
- {
- let mut bind_vb = cacher.bind_vertex_buffers();
- bind_vb.add(&buf1);
- bind_vb.add(&buf2);
- assert_eq!(bind_vb.compare(), Some(0..2));
- }
-
- {
- let mut bind_vb = cacher.bind_vertex_buffers();
- bind_vb.add(&buf1);
- bind_vb.add(&buf2);
- bind_vb.add(&buf3);
- assert_eq!(bind_vb.compare(), Some(2..3));
- }
-
- {
- let mut bind_vb = cacher.bind_vertex_buffers();
- bind_vb.add(&buf1);
- assert_eq!(bind_vb.compare(), None);
- }
-
- {
- let mut bind_vb = cacher.bind_vertex_buffers();
- bind_vb.add(&buf1);
- bind_vb.add(&buf3);
- assert_eq!(bind_vb.compare(), Some(1..2));
- }
-
- {
- let mut bind_vb = cacher.bind_vertex_buffers();
- bind_vb.add(&buf2);
- bind_vb.add(&buf3);
- assert_eq!(bind_vb.compare(), Some(0..1));
- }
- }
-}
diff --git a/src/command_buffer/submit/bind_sparse.rs b/src/command_buffer/submit/bind_sparse.rs
deleted file mode 100644
index 313a09c..0000000
--- a/src/command_buffer/submit/bind_sparse.rs
+++ /dev/null
@@ -1,511 +0,0 @@
-// Copyright (c) 2017 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::buffer::sys::UnsafeBuffer;
-use crate::check_errors;
-use crate::device::Queue;
-use crate::image::sys::UnsafeImage;
-use crate::memory::DeviceMemory;
-use crate::sync::Fence;
-use crate::sync::Semaphore;
-use crate::DeviceSize;
-use crate::Error;
-use crate::OomError;
-use crate::SynchronizedVulkanObject;
-use crate::VulkanObject;
-use smallvec::SmallVec;
-use std::error;
-use std::fmt;
-use std::marker::PhantomData;
-
-// TODO: correctly implement Debug on all the structs of this module
-
-/// Prototype for a submission that binds sparse memory.
-// TODO: example here
-pub struct SubmitBindSparseBuilder<'a> {
- infos: SmallVec<[SubmitBindSparseBatchBuilder<'a>; 1]>,
- fence: ash::vk::Fence,
-}
-
-impl<'a> SubmitBindSparseBuilder<'a> {
- /// Builds a new empty `SubmitBindSparseBuilder`.
- #[inline]
- pub fn new() -> SubmitBindSparseBuilder<'a> {
- SubmitBindSparseBuilder {
- infos: SmallVec::new(),
- fence: ash::vk::Fence::null(),
- }
- }
-
- /// Adds a batch to the command.
- ///
- /// Batches start execution in order, but can finish in a different order. In other words any
- /// wait semaphore added to a batch will apply to further batches as well, but when a semaphore
- /// is signalled, it does **not** mean that previous batches have been completed.
- #[inline]
- pub fn add(&mut self, builder: SubmitBindSparseBatchBuilder<'a>) {
- self.infos.push(builder);
- }
-
- /// Returns true if this builder will signal a fence when submitted.
- ///
- /// # Example
- ///
- /// ```
- /// use vulkano::command_buffer::submit::SubmitBindSparseBuilder;
- /// use vulkano::sync::Fence;
- /// # let device: std::sync::Arc<vulkano::device::Device> = return;
- ///
- /// unsafe {
- /// let fence = Fence::from_pool(device.clone()).unwrap();
- ///
- /// let mut builder = SubmitBindSparseBuilder::new();
- /// assert!(!builder.has_fence());
- /// builder.set_fence_signal(&fence);
- /// assert!(builder.has_fence());
- /// }
- /// ```
- #[inline]
- pub fn has_fence(&self) -> bool {
- self.fence != ash::vk::Fence::null()
- }
-
- /// Adds an operation that signals a fence after this submission ends.
- ///
- /// # Example
- ///
- /// ```
- /// use std::time::Duration;
- /// use vulkano::command_buffer::submit::SubmitBindSparseBuilder;
- /// use vulkano::sync::Fence;
- /// # let device: std::sync::Arc<vulkano::device::Device> = return;
- /// # let queue: std::sync::Arc<vulkano::device::Queue> = return;
- ///
- /// unsafe {
- /// let fence = Fence::from_pool(device.clone()).unwrap();
- ///
- /// let mut builder = SubmitBindSparseBuilder::new();
- /// builder.set_fence_signal(&fence);
- ///
- /// builder.submit(&queue).unwrap();
- ///
- /// // We must not destroy the fence before it is signaled.
- /// fence.wait(None).unwrap();
- /// }
- /// ```
- ///
- /// # Safety
- ///
- /// - The fence must not be signaled at the time when you call `submit()`.
- ///
- /// - If you use the fence for multiple submissions, only one at a time must be executed by the
- /// GPU. In other words, you must submit one, wait for the fence to be signaled, then reset
- /// the fence, and then only submit the second.
- ///
- /// - If you submit this builder, the fence must be kept alive until it is signaled by the GPU.
- /// Destroying the fence earlier is an undefined behavior.
- ///
- /// - The fence, buffers, images, and semaphores must all belong to the same device.
- ///
- #[inline]
- pub unsafe fn set_fence_signal(&mut self, fence: &'a Fence) {
- self.fence = fence.internal_object();
- }
-
- /// Attempts to merge this builder with another one.
- ///
- /// If both builders have a fence already set, then this function will return `other` as an
- /// error.
- #[inline]
- pub fn merge(
- &mut self,
- other: SubmitBindSparseBuilder<'a>,
- ) -> Result<(), SubmitBindSparseBuilder<'a>> {
- if self.fence != ash::vk::Fence::null() && other.fence != ash::vk::Fence::null() {
- return Err(other);
- }
-
- self.infos.extend(other.infos.into_iter());
- Ok(())
- }
-
- /// Submits the command. Calls `vkQueueBindSparse`.
- pub fn submit(self, queue: &Queue) -> Result<(), SubmitBindSparseError> {
- unsafe {
- debug_assert!(queue.family().supports_sparse_binding());
-
- let fns = queue.device().fns();
- let queue = queue.internal_object_guard();
-
- // We start by storing all the `VkSparseBufferMemoryBindInfo`s of the whole command
- // in the same collection.
- let buffer_binds_storage: SmallVec<[_; 4]> = self
- .infos
- .iter()
- .flat_map(|infos| infos.buffer_binds.iter())
- .map(|buf_bind| ash::vk::SparseBufferMemoryBindInfo {
- buffer: buf_bind.buffer,
- bind_count: buf_bind.binds.len() as u32,
- p_binds: buf_bind.binds.as_ptr(),
- })
- .collect();
-
- // Same for all the `VkSparseImageOpaqueMemoryBindInfo`s.
- let image_opaque_binds_storage: SmallVec<[_; 4]> = self
- .infos
- .iter()
- .flat_map(|infos| infos.image_opaque_binds.iter())
- .map(|img_bind| ash::vk::SparseImageOpaqueMemoryBindInfo {
- image: img_bind.image,
- bind_count: img_bind.binds.len() as u32,
- p_binds: img_bind.binds.as_ptr(),
- })
- .collect();
-
- // And finally the `VkSparseImageMemoryBindInfo`s.
- let image_binds_storage: SmallVec<[_; 4]> = self
- .infos
- .iter()
- .flat_map(|infos| infos.image_binds.iter())
- .map(|img_bind| ash::vk::SparseImageMemoryBindInfo {
- image: img_bind.image,
- bind_count: img_bind.binds.len() as u32,
- p_binds: img_bind.binds.as_ptr(),
- })
- .collect();
-
- // Now building the collection of `VkBindSparseInfo`s.
- let bs_infos = {
- let mut bs_infos: SmallVec<[_; 4]> = SmallVec::new();
-
- // Since we stores all the bind infos contiguously, we keep track of the current
- // offset within these containers.
- let mut next_buffer_bind = 0;
- let mut next_image_opaque_bind = 0;
- let mut next_image_bind = 0;
-
- for builder in self.infos.iter() {
- bs_infos.push(ash::vk::BindSparseInfo {
- wait_semaphore_count: builder.wait_semaphores.len() as u32,
- p_wait_semaphores: builder.wait_semaphores.as_ptr(),
- buffer_bind_count: builder.buffer_binds.len() as u32,
- p_buffer_binds: if next_buffer_bind != 0 {
- // We need that `if` because `.as_ptr().offset(0)` is technically UB.
- buffer_binds_storage.as_ptr().offset(next_buffer_bind)
- } else {
- buffer_binds_storage.as_ptr()
- },
- image_opaque_bind_count: builder.image_opaque_binds.len() as u32,
- p_image_opaque_binds: if next_image_opaque_bind != 0 {
- // We need that `if` because `.as_ptr().offset(0)` is technically UB.
- image_opaque_binds_storage
- .as_ptr()
- .offset(next_image_opaque_bind)
- } else {
- image_opaque_binds_storage.as_ptr()
- },
- image_bind_count: builder.image_binds.len() as u32,
- p_image_binds: if next_image_bind != 0 {
- // We need that `if` because `.as_ptr().offset(0)` is technically UB.
- image_binds_storage.as_ptr().offset(next_image_bind)
- } else {
- image_binds_storage.as_ptr()
- },
- signal_semaphore_count: builder.signal_semaphores.len() as u32,
- p_signal_semaphores: builder.signal_semaphores.as_ptr(),
- ..Default::default()
- });
-
- next_buffer_bind += builder.buffer_binds.len() as isize;
- next_image_opaque_bind += builder.image_opaque_binds.len() as isize;
- next_image_bind += builder.image_binds.len() as isize;
- }
-
- // If these assertions fail, then there's something wrong in the code above.
- debug_assert_eq!(next_buffer_bind as usize, buffer_binds_storage.len());
- debug_assert_eq!(
- next_image_opaque_bind as usize,
- image_opaque_binds_storage.len()
- );
- debug_assert_eq!(next_image_bind as usize, image_binds_storage.len());
-
- bs_infos
- };
-
- // Finally executing the command.
- check_errors(fns.v1_0.queue_bind_sparse(
- *queue,
- bs_infos.len() as u32,
- bs_infos.as_ptr(),
- self.fence,
- ))?;
- Ok(())
- }
- }
-}
-
-impl<'a> fmt::Debug for SubmitBindSparseBuilder<'a> {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(fmt, "<Bind sparse operation>")
- }
-}
-
-/// A single batch of a sparse bind operation.
-pub struct SubmitBindSparseBatchBuilder<'a> {
- wait_semaphores: SmallVec<[ash::vk::Semaphore; 8]>,
- buffer_binds: SmallVec<[SubmitBindSparseBufferBindBuilder<'a>; 2]>,
- image_opaque_binds: SmallVec<[SubmitBindSparseImageOpaqueBindBuilder<'a>; 2]>,
- image_binds: SmallVec<[SubmitBindSparseImageBindBuilder<'a>; 2]>,
- signal_semaphores: SmallVec<[ash::vk::Semaphore; 8]>,
- marker: PhantomData<&'a ()>,
-}
-
-impl<'a> SubmitBindSparseBatchBuilder<'a> {
- /// Builds a new empty `SubmitBindSparseBatchBuilder`.
- #[inline]
- pub fn new() -> SubmitBindSparseBatchBuilder<'a> {
- SubmitBindSparseBatchBuilder {
- wait_semaphores: SmallVec::new(),
- buffer_binds: SmallVec::new(),
- image_opaque_binds: SmallVec::new(),
- image_binds: SmallVec::new(),
- signal_semaphores: SmallVec::new(),
- marker: PhantomData,
- }
- }
-
- /// Adds an operation that binds memory to a buffer.
- pub fn add_buffer(&mut self, cmd: SubmitBindSparseBufferBindBuilder<'a>) {
- self.buffer_binds.push(cmd);
- }
-
- /// Adds an operation that binds memory to an opaque image.
- pub fn add_image_opaque(&mut self, cmd: SubmitBindSparseImageOpaqueBindBuilder<'a>) {
- self.image_opaque_binds.push(cmd);
- }
-
- /// Adds an operation that binds memory to an image.
- pub fn add_image(&mut self, cmd: SubmitBindSparseImageBindBuilder<'a>) {
- self.image_binds.push(cmd);
- }
-
- /// Adds a semaphore to be waited upon before the sparse binding is executed.
- ///
- /// # Safety
- ///
- /// - If you submit this builder, the semaphore must be kept alive until you are guaranteed
- /// that the GPU has at least started executing the operation.
- ///
- /// - If you submit this builder, no other queue must be waiting on these semaphores. In other
- /// words, each semaphore signal can only correspond to one semaphore wait.
- ///
- /// - If you submit this builder, the semaphores must be signaled when the queue execution
- /// reaches this submission, or there must be one or more submissions in queues that are
- /// going to signal these semaphores. In other words, you must not block the queue with
- /// semaphores that can't get signaled.
- ///
- /// - The fence, buffers, images, and semaphores must all belong to the same device.
- ///
- #[inline]
- pub unsafe fn add_wait_semaphore(&mut self, semaphore: &'a Semaphore) {
- self.wait_semaphores.push(semaphore.internal_object());
- }
-
- /// Returns the number of semaphores to signal.
- ///
- /// In other words, this is the number of times `add_signal_semaphore` has been called.
- #[inline]
- pub fn num_signal_semaphores(&self) -> usize {
- self.signal_semaphores.len()
- }
-
- /// Adds a semaphore that is going to be signaled at the end of the submission.
- ///
- /// # Safety
- ///
- /// - If you submit this builder, the semaphore must be kept alive until you are guaranteed
- /// that the GPU has finished executing this submission.
- ///
- /// - The semaphore must be in the unsignaled state when queue execution reaches this
- /// submission.
- ///
- /// - The fence, buffers, images, and semaphores must all belong to the same device.
- ///
- #[inline]
- pub unsafe fn add_signal_semaphore(&mut self, semaphore: &'a Semaphore) {
- self.signal_semaphores.push(semaphore.internal_object());
- }
-}
-
-pub struct SubmitBindSparseBufferBindBuilder<'a> {
- buffer: ash::vk::Buffer,
- binds: SmallVec<[ash::vk::SparseMemoryBind; 1]>,
- marker: PhantomData<&'a ()>,
-}
-
-impl<'a> SubmitBindSparseBufferBindBuilder<'a> {
- ///
- /// # Safety
- ///
- /// - `buffer` must be a buffer with sparse binding enabled.
- pub unsafe fn new(buffer: &'a UnsafeBuffer) -> SubmitBindSparseBufferBindBuilder {
- SubmitBindSparseBufferBindBuilder {
- buffer: buffer.internal_object(),
- binds: SmallVec::new(),
- marker: PhantomData,
- }
- }
-
- pub unsafe fn add_bind(
- &mut self,
- offset: DeviceSize,
- size: DeviceSize,
- memory: &DeviceMemory,
- memory_offset: DeviceSize,
- ) {
- self.binds.push(ash::vk::SparseMemoryBind {
- resource_offset: offset,
- size,
- memory: memory.internal_object(),
- memory_offset,
- flags: ash::vk::SparseMemoryBindFlags::empty(), // Flags are only relevant for images.
- });
- }
-
- pub unsafe fn add_unbind(&mut self, offset: DeviceSize, size: DeviceSize) {
- self.binds.push(ash::vk::SparseMemoryBind {
- resource_offset: offset,
- size,
- memory: ash::vk::DeviceMemory::null(),
- memory_offset: 0,
- flags: ash::vk::SparseMemoryBindFlags::empty(),
- });
- }
-}
-
-pub struct SubmitBindSparseImageOpaqueBindBuilder<'a> {
- image: ash::vk::Image,
- binds: SmallVec<[ash::vk::SparseMemoryBind; 1]>,
- marker: PhantomData<&'a ()>,
-}
-
-impl<'a> SubmitBindSparseImageOpaqueBindBuilder<'a> {
- ///
- /// # Safety
- ///
- /// - `image` must be an image with sparse binding enabled.
- pub unsafe fn new(image: &'a UnsafeImage) -> SubmitBindSparseImageOpaqueBindBuilder {
- SubmitBindSparseImageOpaqueBindBuilder {
- image: image.internal_object(),
- binds: SmallVec::new(),
- marker: PhantomData,
- }
- }
-
- pub unsafe fn add_bind(
- &mut self,
- offset: DeviceSize,
- size: DeviceSize,
- memory: &DeviceMemory,
- memory_offset: DeviceSize,
- bind_metadata: bool,
- ) {
- self.binds.push(ash::vk::SparseMemoryBind {
- resource_offset: offset,
- size,
- memory: memory.internal_object(),
- memory_offset,
- flags: if bind_metadata {
- ash::vk::SparseMemoryBindFlags::METADATA
- } else {
- ash::vk::SparseMemoryBindFlags::empty()
- },
- });
- }
-
- pub unsafe fn add_unbind(&mut self, offset: DeviceSize, size: DeviceSize) {
- self.binds.push(ash::vk::SparseMemoryBind {
- resource_offset: offset,
- size,
- memory: ash::vk::DeviceMemory::null(),
- memory_offset: 0,
- flags: ash::vk::SparseMemoryBindFlags::empty(), // TODO: is that relevant?
- });
- }
-}
-
-pub struct SubmitBindSparseImageBindBuilder<'a> {
- image: ash::vk::Image,
- binds: SmallVec<[ash::vk::SparseImageMemoryBind; 1]>,
- marker: PhantomData<&'a ()>,
-}
-
-impl<'a> SubmitBindSparseImageBindBuilder<'a> {
- ///
- /// # Safety
- ///
- /// - `image` must be an image with sparse binding enabled.
- pub unsafe fn new(image: &'a UnsafeImage) -> SubmitBindSparseImageBindBuilder {
- SubmitBindSparseImageBindBuilder {
- image: image.internal_object(),
- binds: SmallVec::new(),
- marker: PhantomData,
- }
- }
-
- // TODO: finish
-}
-
-/// Error that can happen when submitting the present prototype.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-#[repr(u32)]
-pub enum SubmitBindSparseError {
- /// Not enough memory.
- OomError(OomError),
-
- /// The connection to the device has been lost.
- DeviceLost,
-}
-
-impl error::Error for SubmitBindSparseError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- SubmitBindSparseError::OomError(ref err) => Some(err),
- _ => None,
- }
- }
-}
-
-impl fmt::Display for SubmitBindSparseError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- SubmitBindSparseError::OomError(_) => "not enough memory",
- SubmitBindSparseError::DeviceLost => "the connection to the device has been lost",
- }
- )
- }
-}
-
-impl From<Error> for SubmitBindSparseError {
- #[inline]
- fn from(err: Error) -> SubmitBindSparseError {
- match err {
- err @ Error::OutOfHostMemory => SubmitBindSparseError::OomError(OomError::from(err)),
- err @ Error::OutOfDeviceMemory => SubmitBindSparseError::OomError(OomError::from(err)),
- Error::DeviceLost => SubmitBindSparseError::DeviceLost,
- _ => panic!("unexpected error: {:?}", err),
- }
- }
-}
diff --git a/src/command_buffer/submit/mod.rs b/src/command_buffer/submit/mod.rs
deleted file mode 100644
index 53c0d4b..0000000
--- a/src/command_buffer/submit/mod.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-//! Low-level builders that allow submitting an operation to a queue.
-//!
-//! In order to submit an operation to the GPU, you must use one of the builder structs of this
-//! module. These structs are low-level and unsafe, and are mostly used to implement other parts
-//! of vulkano, so you are encouraged to not use them directly.
-
-pub use self::bind_sparse::SubmitBindSparseBatchBuilder;
-pub use self::bind_sparse::SubmitBindSparseBufferBindBuilder;
-pub use self::bind_sparse::SubmitBindSparseBuilder;
-pub use self::bind_sparse::SubmitBindSparseError;
-pub use self::bind_sparse::SubmitBindSparseImageBindBuilder;
-pub use self::bind_sparse::SubmitBindSparseImageOpaqueBindBuilder;
-pub use self::queue_present::SubmitPresentBuilder;
-pub use self::queue_present::SubmitPresentError;
-pub use self::queue_submit::SubmitCommandBufferBuilder;
-pub use self::queue_submit::SubmitCommandBufferError;
-pub use self::semaphores_wait::SubmitSemaphoresWaitBuilder;
-
-mod bind_sparse;
-mod queue_present;
-mod queue_submit;
-mod semaphores_wait;
-
-/// Contains all the possible submission builders.
-#[derive(Debug)]
-pub enum SubmitAnyBuilder<'a> {
- Empty,
- SemaphoresWait(SubmitSemaphoresWaitBuilder<'a>),
- CommandBuffer(SubmitCommandBufferBuilder<'a>),
- QueuePresent(SubmitPresentBuilder<'a>),
- BindSparse(SubmitBindSparseBuilder<'a>),
-}
-
-impl<'a> SubmitAnyBuilder<'a> {
- /// Returns true if equal to `SubmitAnyBuilder::Empty`.
- #[inline]
- pub fn is_empty(&self) -> bool {
- match self {
- &SubmitAnyBuilder::Empty => true,
- _ => false,
- }
- }
-}
diff --git a/src/command_buffer/submit/queue_present.rs b/src/command_buffer/submit/queue_present.rs
deleted file mode 100644
index 28f4229..0000000
--- a/src/command_buffer/submit/queue_present.rs
+++ /dev/null
@@ -1,279 +0,0 @@
-// Copyright (c) 2017 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use smallvec::SmallVec;
-use std::error;
-use std::fmt;
-use std::marker::PhantomData;
-use std::ptr;
-
-use crate::device::DeviceOwned;
-use crate::device::Queue;
-use crate::swapchain::PresentRegion;
-use crate::swapchain::Swapchain;
-use crate::sync::Semaphore;
-
-use crate::check_errors;
-use crate::Error;
-use crate::OomError;
-use crate::SynchronizedVulkanObject;
-use crate::VulkanObject;
-
-/// Prototype for a submission that presents a swapchain on the screen.
-// TODO: example here
-pub struct SubmitPresentBuilder<'a> {
- wait_semaphores: SmallVec<[ash::vk::Semaphore; 8]>,
- swapchains: SmallVec<[ash::vk::SwapchainKHR; 4]>,
- image_indices: SmallVec<[u32; 4]>,
- present_regions: SmallVec<[ash::vk::PresentRegionKHR; 4]>,
- rect_layers: SmallVec<[ash::vk::RectLayerKHR; 4]>,
- marker: PhantomData<&'a ()>,
-}
-
-impl<'a> SubmitPresentBuilder<'a> {
- /// Builds a new empty `SubmitPresentBuilder`.
- #[inline]
- pub fn new() -> SubmitPresentBuilder<'a> {
- SubmitPresentBuilder {
- wait_semaphores: SmallVec::new(),
- swapchains: SmallVec::new(),
- image_indices: SmallVec::new(),
- present_regions: SmallVec::new(),
- rect_layers: SmallVec::new(),
- marker: PhantomData,
- }
- }
-
- /// Adds a semaphore to be waited upon before the presents are executed.
- ///
- /// # Safety
- ///
- /// - If you submit this builder, the semaphore must be kept alive until you are guaranteed
- /// that the GPU has presented the swapchains.
- ///
- /// - If you submit this builder, no other queue must be waiting on these semaphores. In other
- /// words, each semaphore signal can only correspond to one semaphore wait.
- ///
- /// - If you submit this builder, the semaphores must be signaled when the queue execution
- /// reaches this submission, or there must be one or more submissions in queues that are
- /// going to signal these semaphores. In other words, you must not block the queue with
- /// semaphores that can't get signaled.
- ///
- /// - The swapchains and semaphores must all belong to the same device.
- ///
- #[inline]
- pub unsafe fn add_wait_semaphore(&mut self, semaphore: &'a Semaphore) {
- self.wait_semaphores.push(semaphore.internal_object());
- }
-
- /// Adds an image of a swapchain to be presented.
- ///
- /// Allows to specify a present region.
- /// Areas outside the present region *can* be ignored by the Vulkan implementation for
- /// optimizations purposes.
- ///
- /// If `VK_KHR_incremental_present` is not enabled, the `present_region` parameter is ignored.
- ///
- /// # Safety
- ///
- /// - If you submit this builder, the swapchain must be kept alive until you are
- /// guaranteed that the GPU has finished presenting.
- ///
- /// - The swapchains and semaphores must all belong to the same device.
- ///
- #[inline]
- pub unsafe fn add_swapchain<W>(
- &mut self,
- swapchain: &'a Swapchain<W>,
- image_num: u32,
- present_region: Option<&'a PresentRegion>,
- ) {
- debug_assert!(image_num < swapchain.num_images());
-
- if swapchain
- .device()
- .enabled_extensions()
- .khr_incremental_present
- {
- let vk_present_region = match present_region {
- Some(present_region) => {
- assert!(present_region.is_compatible_with(swapchain));
- for rectangle in &present_region.rectangles {
- self.rect_layers.push(rectangle.into());
- }
- ash::vk::PresentRegionKHR {
- rectangle_count: present_region.rectangles.len() as u32,
- // Set this to null for now; in submit fill it with self.rect_layers
- p_rectangles: ptr::null(),
- }
- }
- None => ash::vk::PresentRegionKHR {
- rectangle_count: 0,
- p_rectangles: ptr::null(),
- },
- };
- self.present_regions.push(vk_present_region);
- }
-
- self.swapchains.push(swapchain.internal_object());
- self.image_indices.push(image_num);
- }
-
- /// Submits the command. Calls `vkQueuePresentKHR`.
- ///
- /// # Panic
- ///
- /// Panics if no swapchain image has been added to the builder.
- ///
- pub fn submit(mut self, queue: &Queue) -> Result<(), SubmitPresentError> {
- unsafe {
- debug_assert_eq!(self.swapchains.len(), self.image_indices.len());
- assert!(
- !self.swapchains.is_empty(),
- "Tried to submit a present command without any swapchain"
- );
-
- let present_regions = {
- if !self.present_regions.is_empty() {
- debug_assert!(queue.device().enabled_extensions().khr_incremental_present);
- debug_assert_eq!(self.swapchains.len(), self.present_regions.len());
- let mut current_index = 0;
- for present_region in &mut self.present_regions {
- present_region.p_rectangles = self.rect_layers[current_index..].as_ptr();
- current_index += present_region.rectangle_count as usize;
- }
- Some(ash::vk::PresentRegionsKHR {
- swapchain_count: self.present_regions.len() as u32,
- p_regions: self.present_regions.as_ptr(),
- ..Default::default()
- })
- } else {
- None
- }
- };
-
- let mut results = vec![ash::vk::Result::SUCCESS; self.swapchains.len()];
-
- let fns = queue.device().fns();
- let queue = queue.internal_object_guard();
-
- let infos = ash::vk::PresentInfoKHR {
- p_next: present_regions
- .as_ref()
- .map(|pr| pr as *const ash::vk::PresentRegionsKHR as *const _)
- .unwrap_or(ptr::null()),
- wait_semaphore_count: self.wait_semaphores.len() as u32,
- p_wait_semaphores: self.wait_semaphores.as_ptr(),
- swapchain_count: self.swapchains.len() as u32,
- p_swapchains: self.swapchains.as_ptr(),
- p_image_indices: self.image_indices.as_ptr(),
- p_results: results.as_mut_ptr(),
- ..Default::default()
- };
-
- check_errors(fns.khr_swapchain.queue_present_khr(*queue, &infos))?;
-
- for result in results {
- check_errors(result)?;
- }
-
- Ok(())
- }
- }
-}
-
-impl<'a> fmt::Debug for SubmitPresentBuilder<'a> {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- fmt.debug_struct("SubmitPresentBuilder")
- .field("wait_semaphores", &self.wait_semaphores)
- .field("swapchains", &self.swapchains)
- .field("image_indices", &self.image_indices)
- .finish()
- }
-}
-
-/// Error that can happen when submitting the present prototype.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-#[repr(u32)]
-pub enum SubmitPresentError {
- /// Not enough memory.
- OomError(OomError),
-
- /// The connection to the device has been lost.
- DeviceLost,
-
- /// The surface is no longer accessible and must be recreated.
- SurfaceLost,
-
- /// The swapchain has lost or doesn't have fullscreen exclusivity possibly for
- /// implementation-specific reasons outside of the application’s control.
- FullscreenExclusiveLost,
-
- /// The surface has changed in a way that makes the swapchain unusable. You must query the
- /// surface's new properties and recreate a new swapchain if you want to continue drawing.
- OutOfDate,
-}
-
-impl error::Error for SubmitPresentError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- SubmitPresentError::OomError(ref err) => Some(err),
- _ => None,
- }
- }
-}
-
-impl fmt::Display for SubmitPresentError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- SubmitPresentError::OomError(_) => "not enough memory",
- SubmitPresentError::DeviceLost => "the connection to the device has been lost",
- SubmitPresentError::SurfaceLost =>
- "the surface of this swapchain is no longer valid",
- SubmitPresentError::OutOfDate => "the swapchain needs to be recreated",
- SubmitPresentError::FullscreenExclusiveLost => {
- "the swapchain no longer has fullscreen exclusivity"
- }
- }
- )
- }
-}
-
-impl From<Error> for SubmitPresentError {
- #[inline]
- fn from(err: Error) -> SubmitPresentError {
- match err {
- err @ Error::OutOfHostMemory => SubmitPresentError::OomError(OomError::from(err)),
- err @ Error::OutOfDeviceMemory => SubmitPresentError::OomError(OomError::from(err)),
- Error::DeviceLost => SubmitPresentError::DeviceLost,
- Error::SurfaceLost => SubmitPresentError::SurfaceLost,
- Error::OutOfDate => SubmitPresentError::OutOfDate,
- Error::FullscreenExclusiveLost => SubmitPresentError::FullscreenExclusiveLost,
- _ => panic!("unexpected error: {:?}", err),
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn no_swapchain_added() {
- let (_, queue) = gfx_dev_and_queue!();
- assert_should_panic!("Tried to submit a present command without any swapchain", {
- let _ = SubmitPresentBuilder::new().submit(&queue);
- });
- }
-}
diff --git a/src/command_buffer/submit/queue_submit.rs b/src/command_buffer/submit/queue_submit.rs
deleted file mode 100644
index 8ffa129..0000000
--- a/src/command_buffer/submit/queue_submit.rs
+++ /dev/null
@@ -1,359 +0,0 @@
-// Copyright (c) 2017 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::check_errors;
-use crate::command_buffer::sys::UnsafeCommandBuffer;
-use crate::device::Queue;
-use crate::sync::Fence;
-use crate::sync::PipelineStages;
-use crate::sync::Semaphore;
-use crate::Error;
-use crate::OomError;
-use crate::SynchronizedVulkanObject;
-use crate::VulkanObject;
-use smallvec::SmallVec;
-use std::error;
-use std::fmt;
-use std::marker::PhantomData;
-
-/// Prototype for a submission that executes command buffers.
-// TODO: example here
-#[derive(Debug)]
-pub struct SubmitCommandBufferBuilder<'a> {
- wait_semaphores: SmallVec<[ash::vk::Semaphore; 16]>,
- destination_stages: SmallVec<[ash::vk::PipelineStageFlags; 8]>,
- signal_semaphores: SmallVec<[ash::vk::Semaphore; 16]>,
- command_buffers: SmallVec<[ash::vk::CommandBuffer; 4]>,
- fence: ash::vk::Fence,
- marker: PhantomData<&'a ()>,
-}
-
-impl<'a> SubmitCommandBufferBuilder<'a> {
- /// Builds a new empty `SubmitCommandBufferBuilder`.
- #[inline]
- pub fn new() -> SubmitCommandBufferBuilder<'a> {
- SubmitCommandBufferBuilder {
- wait_semaphores: SmallVec::new(),
- destination_stages: SmallVec::new(),
- signal_semaphores: SmallVec::new(),
- command_buffers: SmallVec::new(),
- fence: ash::vk::Fence::null(),
- marker: PhantomData,
- }
- }
-
- /// Returns true if this builder will signal a fence when submitted.
- ///
- /// # Example
- ///
- /// ```
- /// use vulkano::command_buffer::submit::SubmitCommandBufferBuilder;
- /// use vulkano::sync::Fence;
- /// # let device: std::sync::Arc<vulkano::device::Device> = return;
- ///
- /// unsafe {
- /// let fence = Fence::from_pool(device.clone()).unwrap();
- ///
- /// let mut builder = SubmitCommandBufferBuilder::new();
- /// assert!(!builder.has_fence());
- /// builder.set_fence_signal(&fence);
- /// assert!(builder.has_fence());
- /// }
- /// ```
- #[inline]
- pub fn has_fence(&self) -> bool {
- self.fence != ash::vk::Fence::null()
- }
-
- /// Adds an operation that signals a fence after this submission ends.
- ///
- /// # Example
- ///
- /// ```
- /// use std::time::Duration;
- /// use vulkano::command_buffer::submit::SubmitCommandBufferBuilder;
- /// use vulkano::sync::Fence;
- /// # let device: std::sync::Arc<vulkano::device::Device> = return;
- /// # let queue: std::sync::Arc<vulkano::device::Queue> = return;
- ///
- /// unsafe {
- /// let fence = Fence::from_pool(device.clone()).unwrap();
- ///
- /// let mut builder = SubmitCommandBufferBuilder::new();
- /// builder.set_fence_signal(&fence);
- ///
- /// builder.submit(&queue).unwrap();
- ///
- /// // We must not destroy the fence before it is signaled.
- /// fence.wait(Some(Duration::from_secs(5))).unwrap();
- /// }
- /// ```
- ///
- /// # Safety
- ///
- /// - The fence must not be signaled at the time when you call `submit()`.
- ///
- /// - If you use the fence for multiple submissions, only one at a time must be executed by the
- /// GPU. In other words, you must submit one, wait for the fence to be signaled, then reset
- /// the fence, and then only submit the second.
- ///
- /// - If you submit this builder, the fence must be kept alive until it is signaled by the GPU.
- /// Destroying the fence earlier is an undefined behavior.
- ///
- /// - The fence, command buffers, and semaphores must all belong to the same device.
- ///
- #[inline]
- pub unsafe fn set_fence_signal(&mut self, fence: &'a Fence) {
- self.fence = fence.internal_object();
- }
-
- /// Adds a semaphore to be waited upon before the command buffers are executed.
- ///
- /// Only the given `stages` of the command buffers added afterwards will wait upon
- /// the semaphore. Other stages not included in `stages` can execute before waiting.
- ///
- /// # Safety
- ///
- /// - The stages must be supported by the device.
- ///
- /// - If you submit this builder, the semaphore must be kept alive until you are guaranteed
- /// that the GPU has at least started executing the command buffers.
- ///
- /// - If you submit this builder, no other queue must be waiting on these semaphores. In other
- /// words, each semaphore signal can only correspond to one semaphore wait.
- ///
- /// - If you submit this builder, the semaphores must be signaled when the queue execution
- /// reaches this submission, or there must be one or more submissions in queues that are
- /// going to signal these semaphores. In other words, you must not block the queue with
- /// semaphores that can't get signaled.
- ///
- /// - The fence, command buffers, and semaphores must all belong to the same device.
- ///
- #[inline]
- pub unsafe fn add_wait_semaphore(&mut self, semaphore: &'a Semaphore, stages: PipelineStages) {
- debug_assert!(!ash::vk::PipelineStageFlags::from(stages).is_empty());
- // TODO: debug assert that the device supports the stages
- self.wait_semaphores.push(semaphore.internal_object());
- self.destination_stages.push(stages.into());
- }
-
- /// Adds a command buffer that is executed as part of this command.
- ///
- /// The command buffers are submitted in the order in which they are added.
- ///
- /// # Safety
- ///
- /// - If you submit this builder, the command buffer must be kept alive until you are
- /// guaranteed that the GPU has finished executing it.
- ///
- /// - Any calls to vkCmdSetEvent, vkCmdResetEvent or vkCmdWaitEvents that have been recorded
- /// into the command buffer must not reference any VkEvent that is referenced by any of
- /// those commands that is pending execution on another queue.
- /// TODO: rephrase ^ ?
- ///
- /// - The fence, command buffers, and semaphores must all belong to the same device.
- ///
- /// TODO: more here
- ///
- #[inline]
- pub unsafe fn add_command_buffer(&mut self, command_buffer: &'a UnsafeCommandBuffer) {
- self.command_buffers.push(command_buffer.internal_object());
- }
-
- /// Returns the number of semaphores to signal.
- ///
- /// In other words, this is the number of times `add_signal_semaphore` has been called.
- #[inline]
- pub fn num_signal_semaphores(&self) -> usize {
- self.signal_semaphores.len()
- }
-
- /// Adds a semaphore that is going to be signaled at the end of the submission.
- ///
- /// # Safety
- ///
- /// - If you submit this builder, the semaphore must be kept alive until you are guaranteed
- /// that the GPU has finished executing this submission.
- ///
- /// - The semaphore must be in the unsignaled state when queue execution reaches this
- /// submission.
- ///
- /// - The fence, command buffers, and semaphores must all belong to the same device.
- ///
- #[inline]
- pub unsafe fn add_signal_semaphore(&mut self, semaphore: &'a Semaphore) {
- self.signal_semaphores.push(semaphore.internal_object());
- }
-
- /// Submits the command buffer to the given queue.
- ///
- /// > **Note**: This is an expensive operation, so you may want to merge as many builders as
- /// > possible together and avoid submitting them one by one.
- ///
- pub fn submit(self, queue: &Queue) -> Result<(), SubmitCommandBufferError> {
- unsafe {
- let fns = queue.device().fns();
- let queue = queue.internal_object_guard();
-
- debug_assert_eq!(self.wait_semaphores.len(), self.destination_stages.len());
-
- let batch = ash::vk::SubmitInfo {
- wait_semaphore_count: self.wait_semaphores.len() as u32,
- p_wait_semaphores: self.wait_semaphores.as_ptr(),
- p_wait_dst_stage_mask: self.destination_stages.as_ptr(),
- command_buffer_count: self.command_buffers.len() as u32,
- p_command_buffers: self.command_buffers.as_ptr(),
- signal_semaphore_count: self.signal_semaphores.len() as u32,
- p_signal_semaphores: self.signal_semaphores.as_ptr(),
- ..Default::default()
- };
-
- check_errors(fns.v1_0.queue_submit(*queue, 1, &batch, self.fence))?;
- Ok(())
- }
- }
-
- /// Merges this builder with another builder.
- ///
- /// # Panic
- ///
- /// Panics if both builders have a fence already set.
- // TODO: create multiple batches instead
- pub fn merge(mut self, other: Self) -> Self {
- assert!(
- self.fence == ash::vk::Fence::null() || other.fence == ash::vk::Fence::null(),
- "Can't merge two queue submits that both have a fence"
- );
-
- self.wait_semaphores.extend(other.wait_semaphores);
- self.destination_stages.extend(other.destination_stages); // TODO: meh? will be solved if we submit multiple batches
- self.signal_semaphores.extend(other.signal_semaphores);
- self.command_buffers.extend(other.command_buffers);
-
- if self.fence == ash::vk::Fence::null() {
- self.fence = other.fence;
- }
-
- self
- }
-}
-
-/// Error that can happen when submitting the prototype.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-#[repr(u32)]
-pub enum SubmitCommandBufferError {
- /// Not enough memory.
- OomError(OomError),
-
- /// The connection to the device has been lost.
- DeviceLost,
-}
-
-impl error::Error for SubmitCommandBufferError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- SubmitCommandBufferError::OomError(ref err) => Some(err),
- _ => None,
- }
- }
-}
-
-impl fmt::Display for SubmitCommandBufferError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- SubmitCommandBufferError::OomError(_) => "not enough memory",
- SubmitCommandBufferError::DeviceLost =>
- "the connection to the device has been lost",
- }
- )
- }
-}
-
-impl From<Error> for SubmitCommandBufferError {
- #[inline]
- fn from(err: Error) -> SubmitCommandBufferError {
- match err {
- err @ Error::OutOfHostMemory => SubmitCommandBufferError::OomError(OomError::from(err)),
- err @ Error::OutOfDeviceMemory => {
- SubmitCommandBufferError::OomError(OomError::from(err))
- }
- Error::DeviceLost => SubmitCommandBufferError::DeviceLost,
- _ => panic!("unexpected error: {:?}", err),
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::sync::Fence;
- use std::time::Duration;
-
- #[test]
- fn empty_submit() {
- let (device, queue) = gfx_dev_and_queue!();
- let builder = SubmitCommandBufferBuilder::new();
- builder.submit(&queue).unwrap();
- }
-
- #[test]
- fn signal_fence() {
- unsafe {
- let (device, queue) = gfx_dev_and_queue!();
-
- let fence = Fence::alloc(device.clone()).unwrap();
- assert!(!fence.ready().unwrap());
-
- let mut builder = SubmitCommandBufferBuilder::new();
- builder.set_fence_signal(&fence);
-
- builder.submit(&queue).unwrap();
- fence.wait(Some(Duration::from_secs(5))).unwrap();
- assert!(fence.ready().unwrap());
- }
- }
-
- #[test]
- fn has_fence() {
- unsafe {
- let (device, queue) = gfx_dev_and_queue!();
-
- let fence = Fence::alloc(device.clone()).unwrap();
-
- let mut builder = SubmitCommandBufferBuilder::new();
- assert!(!builder.has_fence());
- builder.set_fence_signal(&fence);
- assert!(builder.has_fence());
- }
- }
-
- #[test]
- fn merge_both_have_fences() {
- unsafe {
- let (device, _) = gfx_dev_and_queue!();
-
- let fence1 = Fence::alloc(device.clone()).unwrap();
- let fence2 = Fence::alloc(device.clone()).unwrap();
-
- let mut builder1 = SubmitCommandBufferBuilder::new();
- builder1.set_fence_signal(&fence1);
- let mut builder2 = SubmitCommandBufferBuilder::new();
- builder2.set_fence_signal(&fence2);
-
- assert_should_panic!("Can't merge two queue submits that both have a fence", {
- let _ = builder1.merge(builder2);
- });
- }
- }
-}
diff --git a/src/command_buffer/submit/semaphores_wait.rs b/src/command_buffer/submit/semaphores_wait.rs
deleted file mode 100644
index 2ebcfed..0000000
--- a/src/command_buffer/submit/semaphores_wait.rs
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use smallvec::SmallVec;
-
-use crate::command_buffer::submit::SubmitCommandBufferBuilder;
-use crate::command_buffer::submit::SubmitPresentBuilder;
-use crate::sync::PipelineStages;
-use crate::sync::Semaphore;
-
-/// Prototype for a submission that waits on semaphores.
-///
-/// This prototype can't actually be submitted because it doesn't correspond to anything in Vulkan.
-/// However you can convert it into another builder prototype through the `Into` trait.
-#[derive(Debug)]
-pub struct SubmitSemaphoresWaitBuilder<'a> {
- semaphores: SmallVec<[&'a Semaphore; 8]>,
-}
-
-impl<'a> SubmitSemaphoresWaitBuilder<'a> {
- /// Builds a new empty `SubmitSemaphoresWaitBuilder`.
- #[inline]
- pub fn new() -> SubmitSemaphoresWaitBuilder<'a> {
- SubmitSemaphoresWaitBuilder {
- semaphores: SmallVec::new(),
- }
- }
-
- /// Adds an operation that waits on a semaphore.
- ///
- /// The semaphore must be signaled by a previous submission.
- #[inline]
- pub unsafe fn add_wait_semaphore(&mut self, semaphore: &'a Semaphore) {
- self.semaphores.push(semaphore);
- }
-
- /// Merges this builder with another builder.
- #[inline]
- pub fn merge(&mut self, mut other: SubmitSemaphoresWaitBuilder<'a>) {
- self.semaphores.extend(other.semaphores.drain(..));
- }
-}
-
-impl<'a> Into<SubmitCommandBufferBuilder<'a>> for SubmitSemaphoresWaitBuilder<'a> {
- #[inline]
- fn into(mut self) -> SubmitCommandBufferBuilder<'a> {
- unsafe {
- let mut builder = SubmitCommandBufferBuilder::new();
- for sem in self.semaphores.drain(..) {
- builder.add_wait_semaphore(
- sem,
- PipelineStages {
- // TODO: correct stages ; hard
- all_commands: true,
- ..PipelineStages::none()
- },
- );
- }
- builder
- }
- }
-}
-
-impl<'a> Into<SubmitPresentBuilder<'a>> for SubmitSemaphoresWaitBuilder<'a> {
- #[inline]
- fn into(mut self) -> SubmitPresentBuilder<'a> {
- unsafe {
- let mut builder = SubmitPresentBuilder::new();
- for sem in self.semaphores.drain(..) {
- builder.add_wait_semaphore(sem);
- }
- builder
- }
- }
-}
diff --git a/src/command_buffer/synced/builder.rs b/src/command_buffer/synced/builder.rs
index 541ccbb..4ad6029 100644
--- a/src/command_buffer/synced/builder.rs
+++ b/src/command_buffer/synced/builder.rs
@@ -7,41 +7,53 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-pub use self::commands::SyncCommandBufferBuilderBindDescriptorSets;
-pub use self::commands::SyncCommandBufferBuilderBindVertexBuffer;
-pub use self::commands::SyncCommandBufferBuilderExecuteCommands;
-use super::Command;
-use super::ResourceFinalState;
-use super::ResourceKey;
-use super::ResourceLocation;
-use super::SyncCommandBuffer;
-use crate::buffer::BufferAccess;
-use crate::command_buffer::pool::UnsafeCommandPoolAlloc;
-use crate::command_buffer::sys::UnsafeCommandBufferBuilder;
-use crate::command_buffer::sys::UnsafeCommandBufferBuilderPipelineBarrier;
-use crate::command_buffer::CommandBufferExecError;
-use crate::command_buffer::CommandBufferLevel;
-use crate::command_buffer::CommandBufferUsage;
-use crate::command_buffer::ImageUninitializedSafe;
-use crate::descriptor_set::DescriptorSet;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::image::ImageLayout;
-use crate::pipeline::{ComputePipelineAbstract, GraphicsPipelineAbstract, PipelineBindPoint};
-use crate::render_pass::FramebufferAbstract;
-use crate::sync::AccessFlags;
-use crate::sync::PipelineMemoryAccess;
-use crate::sync::PipelineStages;
-use crate::OomError;
-use fnv::FnvHashMap;
-use std::borrow::Cow;
-use std::collections::hash_map::Entry;
-use std::error;
-use std::fmt;
-use std::sync::Arc;
-
-#[path = "commands.rs"]
-mod commands;
+use super::{Command, Resource, SyncCommandBuffer};
+pub use crate::command_buffer::commands::{
+ bind_push::{
+ SyncCommandBufferBuilderBindDescriptorSets, SyncCommandBufferBuilderBindVertexBuffer,
+ },
+ secondary::SyncCommandBufferBuilderExecuteCommands,
+};
+use crate::{
+ buffer::{Buffer, Subbuffer},
+ command_buffer::{
+ pool::CommandPoolAlloc,
+ sys::{CommandBufferBeginInfo, UnsafeCommandBufferBuilder},
+ CommandBufferBufferRangeUsage, CommandBufferBufferUsage, CommandBufferExecError,
+ CommandBufferImageRangeUsage, CommandBufferImageUsage, CommandBufferLevel,
+ CommandBufferResourcesUsage, ResourceUseRef, SecondaryCommandBufferBufferUsage,
+ SecondaryCommandBufferImageUsage, SecondaryCommandBufferResourcesUsage,
+ },
+ descriptor_set::{DescriptorSetResources, DescriptorSetWithOffsets},
+ device::{Device, DeviceOwned},
+ image::{sys::Image, ImageAccess, ImageAspects, ImageLayout, ImageSubresourceRange},
+ pipeline::{
+ graphics::{
+ color_blend::LogicOp,
+ depth_stencil::{CompareOp, StencilOps},
+ input_assembly::{IndexType, PrimitiveTopology},
+ rasterization::{CullMode, DepthBias, FrontFace, LineStipple},
+ viewport::{Scissor, Viewport},
+ },
+ ComputePipeline, DynamicState, GraphicsPipeline, PipelineBindPoint, PipelineLayout,
+ },
+ range_map::RangeMap,
+ range_set::RangeSet,
+ sync::{
+ AccessFlags, BufferMemoryBarrier, DependencyInfo, ImageMemoryBarrier, PipelineMemoryAccess,
+ PipelineStages,
+ },
+ DeviceSize, OomError, VulkanObject,
+};
+use ahash::HashMap;
+use smallvec::SmallVec;
+use std::{
+ collections::hash_map::Entry,
+ error::Error,
+ fmt::{Debug, Display, Error as FmtError, Formatter},
+ ops::{Range, RangeInclusive},
+ sync::Arc,
+};
/// Wrapper around `UnsafeCommandBufferBuilder` that handles synchronization for you.
///
@@ -49,9 +61,6 @@ mod commands;
/// for `pipeline_layout` which is automatically handled. This wrapper automatically builds
/// pipeline barriers, keeps used resources alive and implements the `CommandBuffer` trait.
///
-/// Since the implementation needs to cache commands in a `Vec`, most methods have additional
-/// `Send + Sync + 'static` trait requirements on their generics.
-///
/// If this builder finds out that a command isn't valid because of synchronization reasons (eg.
/// trying to copy from a buffer to an image which share the same memory), then an error is
/// returned.
@@ -59,18 +68,16 @@ mod commands;
/// the commands except for synchronization purposes. The builder may panic if you pass invalid
/// commands.
pub struct SyncCommandBufferBuilder {
- // The actual Vulkan command buffer builder.
inner: UnsafeCommandBufferBuilder,
+ level: CommandBufferLevel,
// Stores all the commands that were added to the sync builder. Some of them are maybe not
// submitted to the inner builder yet.
- // Each command owns the resources it uses (buffers, images, pipelines, descriptor sets etc.),
- // references to any of these must be indirect in the form of a command index + resource id.
- commands: Vec<Arc<dyn Command + Send + Sync>>,
+ pub(in crate::command_buffer) commands: Vec<Box<dyn Command>>,
// Prototype for the pipeline barrier that must be submitted before flushing the commands
// in `commands`.
- pending_barrier: UnsafeCommandBufferBuilderPipelineBarrier,
+ pending_barrier: DependencyInfo,
// Locations within commands that pipeline barriers were inserted. For debugging purposes.
// TODO: present only in cfg(debug_assertions)?
@@ -82,33 +89,17 @@ pub struct SyncCommandBufferBuilder {
// If we're currently inside a render pass, contains the index of the `CmdBeginRenderPass`
// command.
- latest_render_pass_enter: Option<usize>,
+ pub(in crate::command_buffer) latest_render_pass_enter: Option<usize>,
// Stores the current state of buffers and images that are in use by the command buffer.
- resources: FnvHashMap<ResourceKey, ResourceState>,
+ buffers2: HashMap<Arc<Buffer>, RangeMap<DeviceSize, BufferState>>,
+ images2: HashMap<Arc<Image>, RangeMap<DeviceSize, ImageState>>,
// Resources and their accesses. Used for executing secondary command buffers in a primary.
- buffers: Vec<(ResourceLocation, PipelineMemoryAccess)>,
- images: Vec<(
- ResourceLocation,
- PipelineMemoryAccess,
- ImageLayout,
- ImageLayout,
- ImageUninitializedSafe,
- )>,
-
- // State of bindings.
- bindings: BindingState,
-
- // `true` if the builder has been put in an inconsistent state. This happens when
- // `append_command` throws an error, because some changes to the internal state have already
- // been made at that point and can't be reverted.
- // TODO: throw the error in `append_command` _before_ any state changes are made,
- // so that this is no longer needed.
- is_poisoned: bool,
-
- // True if we're a secondary command buffer.
- is_secondary: bool,
+ secondary_resources_usage: SecondaryCommandBufferResourcesUsage,
+
+ // Current binding/setting state.
+ pub(in crate::command_buffer) current_state: CurrentState,
}
impl SyncCommandBufferBuilder {
@@ -118,25 +109,24 @@ impl SyncCommandBufferBuilder {
/// # Safety
///
/// See `UnsafeCommandBufferBuilder::new()`.
- pub unsafe fn new<F>(
- pool_alloc: &UnsafeCommandPoolAlloc,
- level: CommandBufferLevel<F>,
- usage: CommandBufferUsage,
- ) -> Result<SyncCommandBufferBuilder, OomError>
- where
- F: FramebufferAbstract,
- {
- let (is_secondary, inside_render_pass) = match level {
- CommandBufferLevel::Primary => (false, false),
- CommandBufferLevel::Secondary(ref inheritance) => {
- (true, inheritance.render_pass.is_some())
- }
- };
+ #[inline]
+ pub unsafe fn new(
+ pool_alloc: &CommandPoolAlloc,
+ begin_info: CommandBufferBeginInfo,
+ ) -> Result<SyncCommandBufferBuilder, OomError> {
+ let level = pool_alloc.level();
+ let inside_render_pass = level == CommandBufferLevel::Secondary
+ && begin_info
+ .inheritance_info
+ .as_ref()
+ .unwrap()
+ .render_pass
+ .is_some();
+ let inner = UnsafeCommandBufferBuilder::new(pool_alloc, begin_info)?;
- let cmd = UnsafeCommandBufferBuilder::new(pool_alloc, level, usage)?;
Ok(SyncCommandBufferBuilder::from_unsafe_cmd(
- cmd,
- is_secondary,
+ inner,
+ level,
inside_render_pass,
))
}
@@ -152,504 +142,759 @@ impl SyncCommandBufferBuilder {
/// any existing resource usage.
#[inline]
pub unsafe fn from_unsafe_cmd(
- cmd: UnsafeCommandBufferBuilder,
- is_secondary: bool,
+ inner: UnsafeCommandBufferBuilder,
+ level: CommandBufferLevel,
inside_render_pass: bool,
) -> SyncCommandBufferBuilder {
let latest_render_pass_enter = if inside_render_pass { Some(0) } else { None };
SyncCommandBufferBuilder {
- inner: cmd,
+ inner,
+ level,
commands: Vec::new(),
- pending_barrier: UnsafeCommandBufferBuilderPipelineBarrier::new(),
+ pending_barrier: DependencyInfo::default(),
barriers: Vec::new(),
first_unflushed: 0,
latest_render_pass_enter,
- resources: FnvHashMap::default(),
- buffers: Vec::new(),
- images: Vec::new(),
- bindings: Default::default(),
- is_poisoned: false,
- is_secondary,
+ buffers2: HashMap::default(),
+ images2: HashMap::default(),
+ secondary_resources_usage: Default::default(),
+ current_state: Default::default(),
}
}
- // Adds a command to be processed by the builder.
- //
- // The `resources` argument should contain each buffer or image used by the command.
- // The function will take care of handling the pipeline barrier or flushing.
- //
- // - The index of the resource within the `resources` slice maps to the resource accessed
- // through `Command::buffer(..)` or `Command::image(..)`.
- // - `PipelineMemoryAccess` must match the way the resource has been used.
- // - `start_layout` and `end_layout` designate the image layout that the image is expected to be
- // in when the command starts, and the image layout that the image will be transitioned to
- // during the command. When it comes to buffers, you should pass `Undefined` for both.
+ /// Returns the binding/setting state.
#[inline]
- fn append_command<C>(
- &mut self,
- command: C,
- resources: &[(
- KeyTy,
- Option<(
- PipelineMemoryAccess,
- ImageLayout,
- ImageLayout,
- ImageUninitializedSafe,
- )>,
- )],
- ) -> Result<(), SyncCommandBufferBuilderError>
- where
- C: Command + Send + Sync + 'static,
- {
- // TODO: see comment for the `is_poisoned` member in the struct
- assert!(
- !self.is_poisoned,
- "The builder has been put in an inconsistent state by a previous error"
- );
-
- // Note that we don't submit the command to the inner command buffer yet.
- let (latest_command_id, end) = {
- self.commands.push(Arc::new(command));
- let latest_command_id = self.commands.len() - 1;
- let end = self.latest_render_pass_enter.unwrap_or(latest_command_id);
- (latest_command_id, end)
- };
- let mut last_cmd_buffer = 0;
- let mut last_cmd_image = 0;
+ pub fn state(&self) -> CommandBufferBuilderState<'_> {
+ CommandBufferBuilderState {
+ current_state: &self.current_state,
+ }
+ }
+
+ /// Resets the binding/setting state.
+ ///
+ /// This must be called after any command that changes the state in an undefined way, e.g.
+ /// executing a secondary command buffer.
+ #[inline]
+ pub fn reset_state(&mut self) {
+ self.current_state = Default::default();
+ }
- for &(resource_ty, resource) in resources {
- if let Some((memory, start_layout, end_layout, image_uninitialized_safe)) = resource {
- // Anti-dumbness checks.
+ pub(in crate::command_buffer) fn check_resource_conflicts(
+ &self,
+ resource: &(ResourceUseRef, Resource),
+ ) -> Result<(), SyncCommandBufferBuilderError> {
+ let &(current_use_ref, ref resource) = resource;
+
+ match *resource {
+ Resource::Buffer {
+ ref buffer,
+ ref range,
+ ref memory,
+ } => {
+ debug_assert!(AccessFlags::from(memory.stages).contains(memory.access));
+
+ if let Some(previous_use_ref) =
+ self.find_buffer_conflict(buffer, range.clone(), memory)
+ {
+ return Err(SyncCommandBufferBuilderError::Conflict {
+ current_use_ref,
+ previous_use_ref,
+ });
+ }
+ }
+ Resource::Image {
+ ref image,
+ ref subresource_range,
+ ref memory,
+ start_layout,
+ end_layout,
+ } => {
debug_assert!(memory.exclusive || start_layout == end_layout);
- debug_assert!(memory.access.is_compatible_with(&memory.stages));
- debug_assert!(resource_ty != KeyTy::Image || end_layout != ImageLayout::Undefined);
- debug_assert!(
- resource_ty != KeyTy::Buffer || start_layout == ImageLayout::Undefined
- );
- debug_assert!(resource_ty != KeyTy::Buffer || end_layout == ImageLayout::Undefined);
- debug_assert_ne!(end_layout, ImageLayout::Preinitialized);
+ debug_assert!(AccessFlags::from(memory.stages).contains(memory.access));
+ debug_assert!(end_layout != ImageLayout::Undefined);
+ debug_assert!(end_layout != ImageLayout::Preinitialized);
+
+ if let Some(previous_use) = self.find_image_conflict(
+ image,
+ subresource_range.clone(),
+ memory,
+ start_layout,
+ end_layout,
+ ) {
+ return Err(SyncCommandBufferBuilderError::Conflict {
+ current_use_ref,
+ previous_use_ref: previous_use,
+ });
+ }
+ }
+ }
- let (resource_key, resource_index) = match resource_ty {
- KeyTy::Buffer => {
- let buffer = self.commands[latest_command_id].buffer(last_cmd_buffer);
- (ResourceKey::from(buffer), last_cmd_buffer)
- }
- KeyTy::Image => {
- let image = self.commands[latest_command_id].image(last_cmd_image);
- (ResourceKey::from(image), last_cmd_image)
- }
+ Ok(())
+ }
+
+ fn find_buffer_conflict(
+ &self,
+ buffer: &Subbuffer<[u8]>,
+ mut range: Range<DeviceSize>,
+ memory: &PipelineMemoryAccess,
+ ) -> Option<ResourceUseRef> {
+ // Barriers work differently in render passes, so if we're in one, we can only insert a
+ // barrier before the start of the render pass.
+ let last_allowed_barrier_index =
+ self.latest_render_pass_enter.unwrap_or(self.commands.len());
+
+ range.start += buffer.offset();
+ range.end += buffer.offset();
+
+ let range_map = self.buffers2.get(buffer.buffer())?;
+
+ for (_range, state) in range_map
+ .range(&range)
+ .filter(|(_range, state)| !state.resource_uses.is_empty())
+ {
+ debug_assert!(state
+ .resource_uses
+ .iter()
+ .all(|resource_use| resource_use.command_index <= self.commands.len()));
+
+ if memory.exclusive || state.memory.exclusive {
+ // If there is a resource use at a position beyond where we can insert a
+ // barrier, then there is an unsolvable conflict.
+ if let Some(&use_ref) = state
+ .resource_uses
+ .iter()
+ .find(|resource_use| resource_use.command_index >= last_allowed_barrier_index)
+ {
+ return Some(use_ref);
+ }
+ }
+ }
+
+ None
+ }
+
+ fn find_image_conflict(
+ &self,
+ image: &dyn ImageAccess,
+ mut subresource_range: ImageSubresourceRange,
+ memory: &PipelineMemoryAccess,
+ start_layout: ImageLayout,
+ _end_layout: ImageLayout,
+ ) -> Option<ResourceUseRef> {
+ // Barriers work differently in render passes, so if we're in one, we can only insert a
+ // barrier before the start of the render pass.
+ let last_allowed_barrier_index =
+ self.latest_render_pass_enter.unwrap_or(self.commands.len());
+
+ let inner = image.inner();
+ subresource_range.array_layers.start += inner.first_layer;
+ subresource_range.array_layers.end += inner.first_layer;
+ subresource_range.mip_levels.start += inner.first_mipmap_level;
+ subresource_range.mip_levels.end += inner.first_mipmap_level;
+
+ let range_map = self.images2.get(inner.image)?;
+
+ for range in inner.image.iter_ranges(subresource_range) {
+ for (_range, state) in range_map
+ .range(&range)
+ .filter(|(_range, state)| !state.resource_uses.is_empty())
+ {
+ debug_assert!(state
+ .resource_uses
+ .iter()
+ .all(|resource_use| resource_use.command_index <= self.commands.len()));
+
+ // If the command expects the image to be undefined, then we can't
+ // transition it, so use the current layout for both old and new layout.
+ let start_layout = if start_layout == ImageLayout::Undefined {
+ state.current_layout
+ } else {
+ start_layout
};
- match self.resources.entry(resource_key) {
- // Situation where this resource was used before in this command buffer.
- Entry::Occupied(mut entry) => {
- // `collision_cmd_ids` contains the IDs of the commands that we are potentially
- // colliding with.
- let collision_cmd_ids = &entry.get().command_ids;
- debug_assert!(collision_cmd_ids.iter().all(|id| *id <= latest_command_id));
+ if memory.exclusive
+ || state.memory.exclusive
+ || state.current_layout != start_layout
+ {
+ // If there is a resource use at a position beyond where we can insert a
+ // barrier, then there is an unsolvable conflict.
+ if let Some(&use_ref) = state.resource_uses.iter().find(|resource_use| {
+ resource_use.command_index >= last_allowed_barrier_index
+ }) {
+ return Some(use_ref);
+ }
+ }
+ }
+ }
- let entry_key_resource_index = entry.get().resource_index;
+ None
+ }
- // Find out if we have a collision with the pending commands.
- if memory.exclusive
- || entry.get().memory.exclusive
- || entry.get().current_layout != start_layout
- {
- // Collision found between `latest_command_id` and `collision_cmd_id`.
-
- // We now want to modify the current pipeline barrier in order to handle the
- // collision. But since the pipeline barrier is going to be submitted before
- // the flushed commands, it would be a mistake if `collision_cmd_id` hasn't
- // been flushed yet.
- let first_unflushed_cmd_id = self.first_unflushed;
-
- if collision_cmd_ids
- .iter()
- .any(|command_id| *command_id >= first_unflushed_cmd_id)
- || entry.get().current_layout != start_layout
+ /// Adds a command to be processed by the builder.
+ ///
+ /// The `resources` argument should contain each buffer or image used by the command.
+ /// The function will take care of handling the pipeline barrier or flushing.
+ ///
+ /// - The index of the resource within the `resources` slice maps to the resource accessed
+ /// through `Command::buffer(..)` or `Command::image(..)`.
+ /// - `PipelineMemoryAccess` must match the way the resource has been used.
+ /// - `start_layout` and `end_layout` designate the image layout that the image is expected to
+ /// be in when the command starts, and the image layout that the image will be transitioned to
+ /// during the command. When it comes to buffers, you should pass `Undefined` for both.
+ pub(in crate::command_buffer) fn add_resource(&mut self, resource: (ResourceUseRef, Resource)) {
+ let (use_ref, resource) = resource;
+
+ match resource {
+ Resource::Buffer {
+ buffer,
+ range,
+ memory,
+ } => {
+ self.add_buffer(use_ref, buffer, range, memory);
+ }
+ Resource::Image {
+ image,
+ subresource_range,
+ memory,
+ start_layout,
+ end_layout,
+ } => {
+ self.add_image(
+ use_ref,
+ image,
+ subresource_range,
+ memory,
+ start_layout,
+ end_layout,
+ );
+ }
+ }
+ }
+
+ fn add_buffer(
+ &mut self,
+ use_ref: ResourceUseRef,
+ buffer: Subbuffer<[u8]>,
+ mut range: Range<DeviceSize>,
+ memory: PipelineMemoryAccess,
+ ) {
+ self.secondary_resources_usage
+ .buffers
+ .push(SecondaryCommandBufferBufferUsage {
+ use_ref,
+ buffer: buffer.clone(),
+ range: range.clone(),
+ memory,
+ });
+
+ // Barriers work differently in render passes, so if we're in one, we can only insert a
+ // barrier before the start of the render pass.
+ let last_allowed_barrier_index = self
+ .latest_render_pass_enter
+ .unwrap_or(self.commands.len() - 1);
+
+ range.start += buffer.offset();
+ range.end += buffer.offset();
+
+ let range_map = self
+ .buffers2
+ .entry(buffer.buffer().clone())
+ .or_insert_with(|| {
+ [(
+ 0..buffer.buffer().size(),
+ BufferState {
+ resource_uses: Vec::new(),
+ memory: PipelineMemoryAccess::default(),
+ exclusive_any: false,
+ },
+ )]
+ .into_iter()
+ .collect()
+ });
+ range_map.split_at(&range.start);
+ range_map.split_at(&range.end);
+
+ for (range, state) in range_map.range_mut(&range) {
+ if state.resource_uses.is_empty() {
+ // This is the first time we use this resource range in this command buffer.
+ state.resource_uses.push(use_ref);
+ state.memory = PipelineMemoryAccess {
+ stages: memory.stages,
+ access: memory.access,
+ exclusive: memory.exclusive,
+ };
+ state.exclusive_any = memory.exclusive;
+
+ match self.level {
+ CommandBufferLevel::Primary => {
+ // To be safe, we insert a barrier for all stages and accesses before
+ // the first use, so that there are no hazards with any command buffer
+ // that was previously submitted to the same queue.
+ // This is rather overkill, but since command buffers don't know what
+ // will come before them, it's the only thing that works for now.
+ // TODO: come up with something better
+ let barrier = BufferMemoryBarrier {
+ src_stages: PipelineStages::ALL_COMMANDS,
+ src_access: AccessFlags::MEMORY_READ | AccessFlags::MEMORY_WRITE,
+ dst_stages: PipelineStages::ALL_COMMANDS,
+ dst_access: AccessFlags::MEMORY_READ | AccessFlags::MEMORY_WRITE,
+ range: range.clone(),
+ ..BufferMemoryBarrier::buffer(buffer.buffer().clone())
+ };
+
+ self.pending_barrier.buffer_memory_barriers.push(barrier);
+ }
+ CommandBufferLevel::Secondary => (),
+ }
+ } else {
+ // This resource range was used before in this command buffer.
+
+ // Find out if we have a collision with the pending commands.
+ if memory.exclusive || state.memory.exclusive {
+ // Collision found between `latest_command_id` and `collision_cmd_id`.
+
+ // We now want to modify the current pipeline barrier in order to handle the
+ // collision. But since the pipeline barrier is going to be submitted before
+ // the flushed commands, it would be a mistake if `collision_cmd_id` hasn't
+ // been flushed yet.
+ if state
+ .resource_uses
+ .iter()
+ .any(|resource_use| resource_use.command_index >= self.first_unflushed)
+ {
+ unsafe {
+ // Flush the pending barrier.
+ self.inner.pipeline_barrier(&self.pending_barrier);
+ self.pending_barrier.clear();
+ self.barriers.push(self.first_unflushed); // Track inserted barriers
+
+ for command in
+ &mut self.commands[self.first_unflushed..last_allowed_barrier_index]
{
- unsafe {
- // Flush the pending barrier.
- self.inner.pipeline_barrier(&self.pending_barrier);
- self.pending_barrier =
- UnsafeCommandBufferBuilderPipelineBarrier::new();
-
- // Flush the commands if possible, or return an error if not possible.
- {
- let start = self.first_unflushed;
- self.barriers.push(start); // Track inserted barriers
-
- if let Some(collision_cmd_id) = collision_cmd_ids
- .iter()
- .find(|command_id| **command_id >= end)
- {
- // TODO: see comment for the `is_poisoned` member in the struct
- self.is_poisoned = true;
-
- let cmd1 = &self.commands[*collision_cmd_id];
- let cmd2 = &self.commands[latest_command_id];
-
- return Err(SyncCommandBufferBuilderError::Conflict {
- command1_name: cmd1.name(),
- command1_param: match resource_ty {
- KeyTy::Buffer => {
- cmd1.buffer_name(entry_key_resource_index)
- }
- KeyTy::Image => {
- cmd1.image_name(entry_key_resource_index)
- }
- },
- command1_offset: *collision_cmd_id,
-
- command2_name: cmd2.name(),
- command2_param: match resource_ty {
- KeyTy::Buffer => {
- cmd2.buffer_name(resource_index)
- }
- KeyTy::Image => cmd2.image_name(resource_index),
- },
- command2_offset: latest_command_id,
- });
- }
- for command in &mut self.commands[start..end] {
- command.send(&mut self.inner);
- }
- self.first_unflushed = end;
- }
- }
+ command.send(&mut self.inner);
}
- entry.get_mut().command_ids.push(latest_command_id);
- let entry = entry.into_mut();
+ self.first_unflushed = last_allowed_barrier_index;
+ }
+ }
+
+ // Modify the pipeline barrier to handle the collision.
+ self.pending_barrier
+ .buffer_memory_barriers
+ .push(BufferMemoryBarrier {
+ src_stages: state.memory.stages,
+ src_access: state.memory.access,
+ dst_stages: memory.stages,
+ dst_access: memory.access,
+ range: range.clone(),
+ ..BufferMemoryBarrier::buffer(buffer.buffer().clone())
+ });
+
+ // Update state.
+ state.memory = memory;
+ state.exclusive_any = true;
+ } else {
+ // There is no collision. Simply merge the stages and accesses.
+ state.memory.stages |= memory.stages;
+ state.memory.access |= memory.access;
+ }
+
+ state.resource_uses.push(use_ref);
+ }
+ }
+ }
- // Modify the pipeline barrier to handle the collision.
+ fn add_image(
+ &mut self,
+ use_ref: ResourceUseRef,
+ image: Arc<dyn ImageAccess>,
+ mut subresource_range: ImageSubresourceRange,
+ memory: PipelineMemoryAccess,
+ start_layout: ImageLayout,
+ end_layout: ImageLayout,
+ ) {
+ self.secondary_resources_usage
+ .images
+ .push(SecondaryCommandBufferImageUsage {
+ use_ref,
+ image: image.clone(),
+ subresource_range: subresource_range.clone(),
+ memory,
+ start_layout,
+ end_layout,
+ });
+
+ // Barriers work differently in render passes, so if we're in one, we can only insert a
+ // barrier before the start of the render pass.
+ let last_allowed_barrier_index = self
+ .latest_render_pass_enter
+ .unwrap_or(self.commands.len() - 1);
+
+ let inner = image.inner();
+ subresource_range.array_layers.start += inner.first_layer;
+ subresource_range.array_layers.end += inner.first_layer;
+ subresource_range.mip_levels.start += inner.first_mipmap_level;
+ subresource_range.mip_levels.end += inner.first_mipmap_level;
+
+ // VUID-VkImageMemoryBarrier2-image-03320
+ if !self
+ .device()
+ .enabled_features()
+ .separate_depth_stencil_layouts
+ && image
+ .format()
+ .aspects()
+ .contains(ImageAspects::DEPTH | ImageAspects::STENCIL)
+ {
+ subresource_range.aspects = ImageAspects::DEPTH | ImageAspects::STENCIL;
+ }
+
+ let range_map = self.images2.entry(inner.image.clone()).or_insert_with(|| {
+ [(
+ 0..inner.image.range_size(),
+ match self.level {
+ CommandBufferLevel::Primary => {
+ // In a primary command buffer, the initial layout is determined
+ // by the image.
+ let initial_layout = if !image.is_layout_initialized() {
unsafe {
- match resource_ty {
- KeyTy::Buffer => {
- let buf =
- self.commands[latest_command_id].buffer(resource_index);
-
- let b = &mut self.pending_barrier;
- b.add_buffer_memory_barrier(
- buf,
- entry.memory.stages,
- entry.memory.access,
- memory.stages,
- memory.access,
- true,
- None,
- 0,
- buf.size(),
+ image.layout_initialized();
+ }
+
+ image.initial_layout()
+ } else {
+ image.initial_layout_requirement()
+ };
+
+ ImageState {
+ resource_uses: Vec::new(),
+ memory: PipelineMemoryAccess::default(),
+ exclusive_any: false,
+ initial_layout,
+ current_layout: initial_layout,
+ final_layout: image.final_layout_requirement(),
+ }
+ }
+ CommandBufferLevel::Secondary => {
+ // In a secondary command buffer, the initial layout is the layout
+ // of the first use.
+ ImageState {
+ resource_uses: Vec::new(),
+ memory: PipelineMemoryAccess::default(),
+ exclusive_any: false,
+ initial_layout: ImageLayout::Undefined,
+ current_layout: ImageLayout::Undefined,
+ final_layout: ImageLayout::Undefined,
+ }
+ }
+ },
+ )]
+ .into_iter()
+ .collect()
+ });
+
+ for range in inner.image.iter_ranges(subresource_range) {
+ range_map.split_at(&range.start);
+ range_map.split_at(&range.end);
+
+ for (range, state) in range_map.range_mut(&range) {
+ if state.resource_uses.is_empty() {
+ // This is the first time we use this resource range in this command buffer.
+
+ debug_assert_eq!(state.initial_layout, state.current_layout);
+
+ state.resource_uses.push(use_ref);
+ state.memory = PipelineMemoryAccess {
+ stages: memory.stages,
+ access: memory.access,
+ exclusive: memory.exclusive,
+ };
+ state.exclusive_any = memory.exclusive;
+ state.current_layout = end_layout;
+
+ match self.level {
+ CommandBufferLevel::Primary => {
+ // To be safe, we insert a barrier for all stages and accesses before
+ // the first use, so that there are no hazards with any command buffer
+ // that was previously submitted to the same queue.
+ // This is rather overkill, but since command buffers don't know what
+ // will come before them, it's the only thing that works for now.
+ // TODO: come up with something better
+ let mut barrier = ImageMemoryBarrier {
+ src_stages: PipelineStages::ALL_COMMANDS,
+ src_access: AccessFlags::MEMORY_READ | AccessFlags::MEMORY_WRITE,
+ dst_stages: PipelineStages::ALL_COMMANDS,
+ dst_access: AccessFlags::MEMORY_READ | AccessFlags::MEMORY_WRITE,
+ old_layout: state.initial_layout,
+ new_layout: start_layout,
+ subresource_range: inner.image.range_to_subresources(range.clone()),
+ ..ImageMemoryBarrier::image(inner.image.clone())
+ };
+
+ // If the `new_layout` is Undefined or Preinitialized, this requires
+ // special handling. With the synchronization2 feature enabled, these
+ // values are permitted, as long as `new_layout` equals `old_layout`.
+ // Without synchronization2, these values are never permitted.
+ match barrier.new_layout {
+ ImageLayout::Undefined => {
+ // If the command expects Undefined, that really means it
+ // doesn't care about the layout at all and anything is valid.
+ // We try to keep the old layout, or do a "dummy" transition to
+ // the image's final layout if that isn't possible.
+ barrier.new_layout =
+ if !self.inner.device.enabled_features().synchronization2
+ && matches!(
+ barrier.old_layout,
+ ImageLayout::Undefined
+ | ImageLayout::Preinitialized
+ )
+ {
+ image.final_layout_requirement()
+ } else {
+ barrier.old_layout
+ };
+ }
+ ImageLayout::Preinitialized => {
+ // TODO: put this in find_image_conflict instead?
+
+ // The image must be in the Preinitialized layout already, we
+ // can't transition it.
+ if state.initial_layout != ImageLayout::Preinitialized {
+ panic!(
+ "The command requires the `Preinitialized layout`, but
+ the initial layout of the image is not `Preinitialized`"
);
}
- KeyTy::Image => {
- let img =
- self.commands[latest_command_id].image(resource_index);
-
- let b = &mut self.pending_barrier;
- b.add_image_memory_barrier(
- img,
- img.current_miplevels_access(),
- img.current_layer_levels_access(),
- entry.memory.stages,
- entry.memory.access,
- memory.stages,
- memory.access,
- true,
- None,
- entry.current_layout,
- start_layout,
+ // The image is in the Preinitialized layout, but we can't keep
+ // that layout because of the limitations of
+ // pre-synchronization2 barriers. So an error is all we can do.
+ if !self.inner.device.enabled_features().synchronization2 {
+ panic!(
+ "The command requires the `Preinitialized` layout, \
+ but this is not allowed in pipeline barriers without
+ the `synchronization2` feature enabled"
);
}
- };
+ }
+ _ => (),
}
- // Update state.
- entry.memory = memory;
- entry.exclusive_any = true;
- if memory.exclusive || end_layout != ImageLayout::Undefined {
- // Only modify the layout in case of a write, because buffer operations
- // pass `Undefined` for the layout. While a buffer write *must* set the
- // layout to `Undefined`, a buffer read must not touch it.
- entry.current_layout = end_layout;
+ // A layout transition is a write, so if we perform one, we
+ // need exclusive access.
+ if barrier.old_layout != barrier.new_layout {
+ state.exclusive_any = true;
}
- } else {
- // There is no collision. Simply merge the stages and accesses.
- // TODO: what about simplifying the newly-constructed stages/accesses?
- // this would simplify the job of the driver, but is it worth it?
- let entry = entry.into_mut();
- entry.memory.stages |= memory.stages;
- entry.memory.access |= memory.access;
+
+ self.pending_barrier.image_memory_barriers.push(barrier);
+ }
+ CommandBufferLevel::Secondary => {
+ state.initial_layout = start_layout;
}
}
+ } else {
+ // This resource range was used before in this command buffer.
+
+ // If the command expects the image to be undefined, then we can't
+ // transition it, so use the current layout for both old and new layout.
+ let start_layout = if start_layout == ImageLayout::Undefined {
+ state.current_layout
+ } else {
+ start_layout
+ };
- // Situation where this is the first time we use this resource in this command buffer.
- Entry::Vacant(entry) => {
- // We need to perform some tweaks if the initial layout requirement of the image
- // is different from the first layout usage.
- let mut actually_exclusive = memory.exclusive;
- let mut actual_start_layout = start_layout;
-
- if !self.is_secondary
- && resource_ty == KeyTy::Image
- && start_layout != ImageLayout::Undefined
- && start_layout != ImageLayout::Preinitialized
+ // Find out if we have a collision with the pending commands.
+ if memory.exclusive
+ || state.memory.exclusive
+ || state.current_layout != start_layout
+ {
+ // Collision found between `latest_command_id` and `collision_cmd_id`.
+
+ // We now want to modify the current pipeline barrier in order to handle the
+ // collision. But since the pipeline barrier is going to be submitted before
+ // the flushed commands, it would be a mistake if `collision_cmd_id` hasn't
+ // been flushed yet.
+ if state
+ .resource_uses
+ .iter()
+ .any(|resource_use| resource_use.command_index >= self.first_unflushed)
+ || state.current_layout != start_layout
{
- let img = self.commands[latest_command_id].image(resource_index);
- let initial_layout_requirement = img.initial_layout_requirement();
-
- // Checks if the image is initialized and transitions it
- // if it isn't
- let is_layout_initialized = img.is_layout_initialized();
-
- if initial_layout_requirement != start_layout || !is_layout_initialized
- {
- // Note that we transition from `bottom_of_pipe`, which means that we
- // wait for all the previous commands to be entirely finished. This is
- // suboptimal, but:
- //
- // - If we're at the start of the command buffer we have no choice anyway,
- // because we have no knowledge about what comes before.
- // - If we're in the middle of the command buffer, this pipeline is going
- // to be merged with an existing barrier. While it may still be
- // suboptimal in some cases, in the general situation it will be ok.
- //
- unsafe {
- let from_layout = if is_layout_initialized {
- actually_exclusive = true;
- initial_layout_requirement
- } else {
- if img.preinitialized_layout() {
- ImageLayout::Preinitialized
- } else {
- ImageLayout::Undefined
- }
- };
- if initial_layout_requirement != start_layout {
- actual_start_layout = initial_layout_requirement;
- }
- let b = &mut self.pending_barrier;
- b.add_image_memory_barrier(
- img,
- img.current_miplevels_access(),
- img.current_layer_levels_access(),
- PipelineStages {
- bottom_of_pipe: true,
- ..PipelineStages::none()
- },
- AccessFlags::none(),
- memory.stages,
- memory.access,
- true,
- None,
- from_layout,
- start_layout,
- );
- img.layout_initialized();
+ unsafe {
+ // Flush the pending barrier.
+ self.inner.pipeline_barrier(&self.pending_barrier);
+ self.pending_barrier.clear();
+ self.barriers.push(self.first_unflushed); // Track inserted barriers
+
+ for command in &mut self.commands
+ [self.first_unflushed..last_allowed_barrier_index]
+ {
+ command.send(&mut self.inner);
}
+ self.first_unflushed = last_allowed_barrier_index;
}
}
- entry.insert(ResourceState {
- command_ids: vec![latest_command_id],
- resource_index,
-
- memory: PipelineMemoryAccess {
- stages: memory.stages,
- access: memory.access,
- exclusive: actually_exclusive,
- },
- exclusive_any: actually_exclusive,
- initial_layout: actual_start_layout,
- current_layout: end_layout, // TODO: what if we reach the end with Undefined? that's not correct?
- image_uninitialized_safe,
- });
+ // Modify the pipeline barrier to handle the collision.
+ self.pending_barrier
+ .image_memory_barriers
+ .push(ImageMemoryBarrier {
+ src_stages: state.memory.stages,
+ src_access: state.memory.access,
+ dst_stages: memory.stages,
+ dst_access: memory.access,
+ old_layout: state.current_layout,
+ new_layout: start_layout,
+ subresource_range: inner.image.range_to_subresources(range.clone()),
+ ..ImageMemoryBarrier::image(inner.image.clone())
+ });
+
+ // Update state.
+ state.memory = memory;
+ state.exclusive_any = true;
+ if memory.exclusive || end_layout != ImageLayout::Undefined {
+ // Only modify the layout in case of a write, because buffer operations
+ // pass `Undefined` for the layout. While a buffer write *must* set the
+ // layout to `Undefined`, a buffer read must not touch it.
+ state.current_layout = end_layout;
+ }
+ } else {
+ // There is no collision. Simply merge the stages and accesses.
+ state.memory.stages |= memory.stages;
+ state.memory.access |= memory.access;
}
- }
-
- // Add the resources to the lists
- // TODO: Perhaps any barriers for a resource in the secondary command buffer will "protect"
- // its accesses so the primary needs less strict barriers.
- // Less barriers is more efficient, so worth investigating!
- let location = ResourceLocation {
- command_id: latest_command_id,
- resource_index,
- };
- match resource_ty {
- KeyTy::Buffer => {
- self.buffers.push((location, memory));
- last_cmd_buffer += 1;
- }
- KeyTy::Image => {
- self.images.push((
- location,
- memory,
- start_layout,
- end_layout,
- image_uninitialized_safe,
- ));
- last_cmd_image += 1;
- }
- }
- } else {
- match resource_ty {
- KeyTy::Buffer => {
- last_cmd_buffer += 1;
- }
- KeyTy::Image => {
- last_cmd_image += 1;
- }
+ state.resource_uses.push(use_ref);
}
}
}
-
- Ok(())
}
/// Builds the command buffer and turns it into a `SyncCommandBuffer`.
#[inline]
pub fn build(mut self) -> Result<SyncCommandBuffer, OomError> {
- // TODO: see comment for the `is_poisoned` member in the struct
- assert!(
- !self.is_poisoned,
- "The builder has been put in an inconsistent state by a previous error"
- );
-
debug_assert!(self.latest_render_pass_enter.is_none() || self.pending_barrier.is_empty());
// The commands that haven't been sent to the inner command buffer yet need to be sent.
unsafe {
self.inner.pipeline_barrier(&self.pending_barrier);
+ self.pending_barrier.clear();
let start = self.first_unflushed;
self.barriers.push(start); // Track inserted barriers
+
for command in &mut self.commands[start..] {
command.send(&mut self.inner);
}
}
// Transition images to their desired final layout.
- if !self.is_secondary {
+ if self.level == CommandBufferLevel::Primary {
unsafe {
- // TODO: this could be optimized by merging the barrier with the barrier above?
- let mut barrier = UnsafeCommandBufferBuilderPipelineBarrier::new();
-
- for (key, state) in self
- .resources
- .iter_mut()
- .filter(|(key, _)| matches!(key, ResourceKey::Image(..)))
- {
- let img = self.commands[state.command_ids[0]].image(state.resource_index);
- let requested_layout = img.final_layout_requirement();
- if requested_layout == state.current_layout {
- continue;
+ for (image, range_map) in self.images2.iter_mut() {
+ for (range, state) in range_map
+ .iter_mut()
+ .filter(|(_range, state)| state.final_layout != state.current_layout)
+ {
+ self.pending_barrier
+ .image_memory_barriers
+ .push(ImageMemoryBarrier {
+ src_stages: state.memory.stages,
+ src_access: state.memory.access,
+ dst_stages: PipelineStages::TOP_OF_PIPE,
+ dst_access: AccessFlags::empty(),
+ old_layout: state.current_layout,
+ new_layout: state.final_layout,
+ subresource_range: image.range_to_subresources(range.clone()),
+ ..ImageMemoryBarrier::image(image.clone())
+ });
+
+ state.exclusive_any = true;
}
-
- barrier.add_image_memory_barrier(
- img,
- img.current_miplevels_access(),
- img.current_layer_levels_access(),
- state.memory.stages,
- state.memory.access,
- PipelineStages {
- top_of_pipe: true,
- ..PipelineStages::none()
- },
- AccessFlags::none(),
- true,
- None, // TODO: queue transfers?
- state.current_layout,
- requested_layout,
- );
-
- state.exclusive_any = true;
- state.current_layout = requested_layout;
}
- self.inner.pipeline_barrier(&barrier);
+ self.inner.pipeline_barrier(&self.pending_barrier);
}
}
- // Build the final resources states.
- let final_resources_states: FnvHashMap<_, _> = {
- self.resources
+ let mut resource_usage = CommandBufferResourcesUsage {
+ buffers: self
+ .buffers2
.into_iter()
- .map(|(resource, state)| {
- let final_state = ResourceFinalState {
- command_ids: state.command_ids,
- resource_index: state.resource_index,
- final_stages: state.memory.stages,
- final_access: state.memory.access,
- exclusive: state.exclusive_any,
- initial_layout: state.initial_layout,
- final_layout: state.current_layout,
- image_uninitialized_safe: state.image_uninitialized_safe,
- };
- (resource, final_state)
+ .map(|(buffer, ranges)| CommandBufferBufferUsage {
+ buffer,
+ ranges: ranges
+ .into_iter()
+ .filter(|(_range, state)| !state.resource_uses.is_empty())
+ .map(|(range, state)| {
+ let first_use = state.resource_uses.into_iter().next();
+ (
+ range,
+ CommandBufferBufferRangeUsage {
+ first_use,
+ mutable: state.exclusive_any,
+ },
+ )
+ })
+ .collect(),
})
- .collect()
+ .collect(),
+ images: self
+ .images2
+ .into_iter()
+ .map(|(image, ranges)| CommandBufferImageUsage {
+ image,
+ ranges: ranges
+ .into_iter()
+ .filter(|(_range, state)| {
+ !state.resource_uses.is_empty()
+ || (self.level == CommandBufferLevel::Primary
+ && state.current_layout != state.final_layout)
+ })
+ .map(|(range, mut state)| {
+ if self.level == CommandBufferLevel::Primary {
+ state.current_layout = state.final_layout;
+ }
+
+ let first_use = state.resource_uses.into_iter().next();
+ (
+ range,
+ CommandBufferImageRangeUsage {
+ first_use,
+ mutable: state.exclusive_any,
+ expected_layout: state.initial_layout,
+ final_layout: state.current_layout,
+ },
+ )
+ })
+ .collect(),
+ })
+ .collect(),
+ buffer_indices: Default::default(),
+ image_indices: Default::default(),
};
+ resource_usage.buffer_indices = resource_usage
+ .buffers
+ .iter()
+ .enumerate()
+ .map(|(index, usage)| (usage.buffer.clone(), index))
+ .collect();
+ resource_usage.image_indices = resource_usage
+ .images
+ .iter()
+ .enumerate()
+ .map(|(index, usage)| (usage.image.clone(), index))
+ .collect();
+
Ok(SyncCommandBuffer {
inner: self.inner.build()?,
- buffers: self.buffers,
- images: self.images,
- resources: final_resources_states,
- commands: self.commands,
- barriers: self.barriers,
+ resources_usage: resource_usage,
+ secondary_resources_usage: self.secondary_resources_usage,
+ _commands: self.commands,
+ _barriers: self.barriers,
})
}
-
- /// Returns the descriptor set currently bound to a given set number, or `None` if nothing has
- /// been bound yet.
- pub(crate) fn bound_descriptor_set(
- &self,
- pipeline_bind_point: PipelineBindPoint,
- set_num: u32,
- ) -> Option<(&dyn DescriptorSet, &[u32])> {
- self.bindings
- .descriptor_sets
- .get(&pipeline_bind_point)
- .and_then(|sets| {
- sets.get(&set_num)
- .map(|cmd| cmd.bound_descriptor_set(set_num))
- })
- }
-
- /// Returns the index buffer currently bound, or `None` if nothing has been bound yet.
- pub(crate) fn bound_index_buffer(&self) -> Option<&dyn BufferAccess> {
- self.bindings
- .index_buffer
- .as_ref()
- .map(|cmd| cmd.bound_index_buffer())
- }
-
- /// Returns the compute pipeline currently bound, or `None` if nothing has been bound yet.
- pub(crate) fn bound_pipeline_compute(&self) -> Option<&dyn ComputePipelineAbstract> {
- self.bindings
- .pipeline_compute
- .as_ref()
- .map(|cmd| cmd.bound_pipeline_compute())
- }
-
- /// Returns the graphics pipeline currently bound, or `None` if nothing has been bound yet.
- pub(crate) fn bound_pipeline_graphics(&self) -> Option<&dyn GraphicsPipelineAbstract> {
- self.bindings
- .pipeline_graphics
- .as_ref()
- .map(|cmd| cmd.bound_pipeline_graphics())
- }
-
- /// Returns the vertex buffer currently bound to a given binding slot number, or `None` if
- /// nothing has been bound yet.
- pub(crate) fn bound_vertex_buffer(&self, binding_num: u32) -> Option<&dyn BufferAccess> {
- self.bindings
- .vertex_buffers
- .get(&binding_num)
- .map(|cmd| cmd.bound_vertex_buffer(binding_num))
- }
}
unsafe impl DeviceOwned for SyncCommandBufferBuilder {
@@ -659,10 +904,9 @@ unsafe impl DeviceOwned for SyncCommandBufferBuilder {
}
}
-impl fmt::Debug for SyncCommandBufferBuilder {
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Debug::fmt(&self.inner, f)
+impl Debug for SyncCommandBufferBuilder {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ Debug::fmt(&self.inner, f)
}
}
@@ -671,52 +915,49 @@ impl fmt::Debug for SyncCommandBufferBuilder {
pub enum SyncCommandBufferBuilderError {
/// Unsolvable conflict.
Conflict {
- command1_name: &'static str,
- command1_param: Cow<'static, str>,
- command1_offset: usize,
-
- command2_name: &'static str,
- command2_param: Cow<'static, str>,
- command2_offset: usize,
+ current_use_ref: ResourceUseRef,
+ previous_use_ref: ResourceUseRef,
},
ExecError(CommandBufferExecError),
}
-impl error::Error for SyncCommandBufferBuilderError {}
+impl Error for SyncCommandBufferBuilderError {}
-impl fmt::Display for SyncCommandBufferBuilderError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+impl Display for SyncCommandBufferBuilderError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
match self {
- SyncCommandBufferBuilderError::Conflict { .. } => write!(fmt, "unsolvable conflict"),
- SyncCommandBufferBuilderError::ExecError(err) => err.fmt(fmt),
+ SyncCommandBufferBuilderError::Conflict { .. } => write!(f, "unsolvable conflict"),
+ SyncCommandBufferBuilderError::ExecError(err) => Display::fmt(err, f),
}
}
}
impl From<CommandBufferExecError> for SyncCommandBufferBuilderError {
- #[inline]
fn from(val: CommandBufferExecError) -> Self {
SyncCommandBufferBuilderError::ExecError(val)
}
}
-/// Type of resource whose state is to be tracked.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-enum KeyTy {
- Buffer,
- Image,
+// State of a resource during the building of the command buffer.
+#[derive(Clone, PartialEq, Eq)]
+struct BufferState {
+ // Lists every use of the resource.
+ resource_uses: Vec<ResourceUseRef>,
+
+ // Memory access of the command that last used this resource.
+ memory: PipelineMemoryAccess,
+
+ // True if the resource was used in exclusive mode at any point during the building of the
+ // command buffer. Also true if an image layout transition or queue transfer has been performed.
+ exclusive_any: bool,
}
// State of a resource during the building of the command buffer.
-#[derive(Debug, Clone)]
-struct ResourceState {
- // Indices of the commands that contain the resource.
- command_ids: Vec<usize>,
-
- // Index of the resource within the first command in `command_ids`.
- resource_index: usize,
+#[derive(Clone, PartialEq, Eq)]
+struct ImageState {
+ // Lists every use of the resource.
+ resource_uses: Vec<ResourceUseRef>,
// Memory access of the command that last used this resource.
memory: PipelineMemoryAccess,
@@ -725,24 +966,494 @@ struct ResourceState {
// command buffer. Also true if an image layout transition or queue transfer has been performed.
exclusive_any: bool,
- // Layout at the first use of the resource by the command buffer. Can be `Undefined` if we
- // don't care.
+ // The layout that the image range must have when this command buffer is executed.
+ // Can be `Undefined` if we don't care.
initial_layout: ImageLayout,
// Current layout at this stage of the building.
current_layout: ImageLayout,
- // Extra context of how the image will be used
- image_uninitialized_safe: ImageUninitializedSafe,
+ // The layout that the image range will have at the end of the command buffer.
+ // This is only used for primary command buffers.
+ final_layout: ImageLayout,
+}
+
+/// Holds the current binding and setting state.
+#[derive(Default)]
+pub(in crate::command_buffer) struct CurrentState {
+ pub(in crate::command_buffer) descriptor_sets: HashMap<PipelineBindPoint, DescriptorSetState>,
+ pub(in crate::command_buffer) index_buffer: Option<(Subbuffer<[u8]>, IndexType)>,
+ pub(in crate::command_buffer) pipeline_compute: Option<Arc<ComputePipeline>>,
+ pub(in crate::command_buffer) pipeline_graphics: Option<Arc<GraphicsPipeline>>,
+ pub(in crate::command_buffer) vertex_buffers: HashMap<u32, Subbuffer<[u8]>>,
+
+ pub(in crate::command_buffer) push_constants: RangeSet<u32>,
+ pub(in crate::command_buffer) push_constants_pipeline_layout: Option<Arc<PipelineLayout>>,
+
+ pub(in crate::command_buffer) blend_constants: Option<[f32; 4]>,
+ pub(in crate::command_buffer) color_write_enable: Option<SmallVec<[bool; 4]>>,
+ pub(in crate::command_buffer) cull_mode: Option<CullMode>,
+ pub(in crate::command_buffer) depth_bias: Option<DepthBias>,
+ pub(in crate::command_buffer) depth_bias_enable: Option<bool>,
+ pub(in crate::command_buffer) depth_bounds: Option<RangeInclusive<f32>>,
+ pub(in crate::command_buffer) depth_bounds_test_enable: Option<bool>,
+ pub(in crate::command_buffer) depth_compare_op: Option<CompareOp>,
+ pub(in crate::command_buffer) depth_test_enable: Option<bool>,
+ pub(in crate::command_buffer) depth_write_enable: Option<bool>,
+ pub(in crate::command_buffer) discard_rectangle: HashMap<u32, Scissor>,
+ pub(in crate::command_buffer) front_face: Option<FrontFace>,
+ pub(in crate::command_buffer) line_stipple: Option<LineStipple>,
+ pub(in crate::command_buffer) line_width: Option<f32>,
+ pub(in crate::command_buffer) logic_op: Option<LogicOp>,
+ pub(in crate::command_buffer) patch_control_points: Option<u32>,
+ pub(in crate::command_buffer) primitive_restart_enable: Option<bool>,
+ pub(in crate::command_buffer) primitive_topology: Option<PrimitiveTopology>,
+ pub(in crate::command_buffer) rasterizer_discard_enable: Option<bool>,
+ pub(in crate::command_buffer) scissor: HashMap<u32, Scissor>,
+ pub(in crate::command_buffer) scissor_with_count: Option<SmallVec<[Scissor; 2]>>,
+ pub(in crate::command_buffer) stencil_compare_mask: StencilStateDynamic,
+ pub(in crate::command_buffer) stencil_op: StencilOpStateDynamic,
+ pub(in crate::command_buffer) stencil_reference: StencilStateDynamic,
+ pub(in crate::command_buffer) stencil_test_enable: Option<bool>,
+ pub(in crate::command_buffer) stencil_write_mask: StencilStateDynamic,
+ pub(in crate::command_buffer) viewport: HashMap<u32, Viewport>,
+ pub(in crate::command_buffer) viewport_with_count: Option<SmallVec<[Viewport; 2]>>,
+}
+
+impl CurrentState {
+ pub(in crate::command_buffer) fn reset_dynamic_states(
+ &mut self,
+ states: impl IntoIterator<Item = DynamicState>,
+ ) {
+ for state in states {
+ match state {
+ DynamicState::BlendConstants => self.blend_constants = None,
+ DynamicState::ColorWriteEnable => self.color_write_enable = None,
+ DynamicState::CullMode => self.cull_mode = None,
+ DynamicState::DepthBias => self.depth_bias = None,
+ DynamicState::DepthBiasEnable => self.depth_bias_enable = None,
+ DynamicState::DepthBounds => self.depth_bounds = None,
+ DynamicState::DepthBoundsTestEnable => self.depth_bounds_test_enable = None,
+ DynamicState::DepthCompareOp => self.depth_compare_op = None,
+ DynamicState::DepthTestEnable => self.depth_test_enable = None,
+ DynamicState::DepthWriteEnable => self.depth_write_enable = None,
+ DynamicState::DiscardRectangle => self.discard_rectangle.clear(),
+ DynamicState::ExclusiveScissor => (), // TODO;
+ DynamicState::FragmentShadingRate => (), // TODO:
+ DynamicState::FrontFace => self.front_face = None,
+ DynamicState::LineStipple => self.line_stipple = None,
+ DynamicState::LineWidth => self.line_width = None,
+ DynamicState::LogicOp => self.logic_op = None,
+ DynamicState::PatchControlPoints => self.patch_control_points = None,
+ DynamicState::PrimitiveRestartEnable => self.primitive_restart_enable = None,
+ DynamicState::PrimitiveTopology => self.primitive_topology = None,
+ DynamicState::RasterizerDiscardEnable => self.rasterizer_discard_enable = None,
+ DynamicState::RayTracingPipelineStackSize => (), // TODO:
+ DynamicState::SampleLocations => (), // TODO:
+ DynamicState::Scissor => self.scissor.clear(),
+ DynamicState::ScissorWithCount => self.scissor_with_count = None,
+ DynamicState::StencilCompareMask => self.stencil_compare_mask = Default::default(),
+ DynamicState::StencilOp => self.stencil_op = Default::default(),
+ DynamicState::StencilReference => self.stencil_reference = Default::default(),
+ DynamicState::StencilTestEnable => self.stencil_test_enable = None,
+ DynamicState::StencilWriteMask => self.stencil_write_mask = Default::default(),
+ DynamicState::VertexInput => (), // TODO:
+ DynamicState::VertexInputBindingStride => (), // TODO:
+ DynamicState::Viewport => self.viewport.clear(),
+ DynamicState::ViewportCoarseSampleOrder => (), // TODO:
+ DynamicState::ViewportShadingRatePalette => (), // TODO:
+ DynamicState::ViewportWScaling => (), // TODO:
+ DynamicState::ViewportWithCount => self.viewport_with_count = None,
+ DynamicState::TessellationDomainOrigin => (), // TODO:
+ DynamicState::DepthClampEnable => (), // TODO:
+ DynamicState::PolygonMode => (), // TODO:
+ DynamicState::RasterizationSamples => (), // TODO:
+ DynamicState::SampleMask => (), // TODO:
+ DynamicState::AlphaToCoverageEnable => (), // TODO:
+ DynamicState::AlphaToOneEnable => (), // TODO:
+ DynamicState::LogicOpEnable => (), // TODO:
+ DynamicState::ColorBlendEnable => (), // TODO:
+ DynamicState::ColorBlendEquation => (), // TODO:
+ DynamicState::ColorWriteMask => (), // TODO:
+ DynamicState::RasterizationStream => (), // TODO:
+ DynamicState::ConservativeRasterizationMode => (), // TODO:
+ DynamicState::ExtraPrimitiveOverestimationSize => (), // TODO:
+ DynamicState::DepthClipEnable => (), // TODO:
+ DynamicState::SampleLocationsEnable => (), // TODO:
+ DynamicState::ColorBlendAdvanced => (), // TODO:
+ DynamicState::ProvokingVertexMode => (), // TODO:
+ DynamicState::LineRasterizationMode => (), // TODO:
+ DynamicState::LineStippleEnable => (), // TODO:
+ DynamicState::DepthClipNegativeOneToOne => (), // TODO:
+ DynamicState::ViewportWScalingEnable => (), // TODO:
+ DynamicState::ViewportSwizzle => (), // TODO:
+ DynamicState::CoverageToColorEnable => (), // TODO:
+ DynamicState::CoverageToColorLocation => (), // TODO:
+ DynamicState::CoverageModulationMode => (), // TODO:
+ DynamicState::CoverageModulationTableEnable => (), // TODO:
+ DynamicState::CoverageModulationTable => (), // TODO:
+ DynamicState::ShadingRateImageEnable => (), // TODO:
+ DynamicState::RepresentativeFragmentTestEnable => (), // TODO:
+ DynamicState::CoverageReductionMode => (), // TODO:
+ }
+ }
+ }
+
+ pub(in crate::command_buffer) fn invalidate_descriptor_sets(
+ &mut self,
+ pipeline_bind_point: PipelineBindPoint,
+ pipeline_layout: Arc<PipelineLayout>,
+ first_set: u32,
+ num_descriptor_sets: u32,
+ ) -> &mut DescriptorSetState {
+ match self.descriptor_sets.entry(pipeline_bind_point) {
+ Entry::Vacant(entry) => entry.insert(DescriptorSetState {
+ descriptor_sets: Default::default(),
+ pipeline_layout,
+ }),
+ Entry::Occupied(entry) => {
+ let state = entry.into_mut();
+
+ let invalidate_from = if state.pipeline_layout.handle() == pipeline_layout.handle()
+ {
+ // If we're still using the exact same layout, then of course it's compatible.
+ None
+ } else if state.pipeline_layout.push_constant_ranges()
+ != pipeline_layout.push_constant_ranges()
+ {
+ // If the push constant ranges don't match,
+ // all bound descriptor sets are disturbed.
+ Some(0)
+ } else {
+ // Find the first descriptor set layout in the current pipeline layout that
+ // isn't compatible with the corresponding set in the new pipeline layout.
+ // If an incompatible set was found, all bound sets from that slot onwards will
+ // be disturbed.
+ let current_layouts = state.pipeline_layout.set_layouts();
+ let new_layouts = pipeline_layout.set_layouts();
+ let max = (current_layouts.len() as u32).min(first_set + num_descriptor_sets);
+ (0..max).find(|&num| {
+ let num = num as usize;
+ !current_layouts[num].is_compatible_with(&new_layouts[num])
+ })
+ };
+
+ if let Some(invalidate_from) = invalidate_from {
+ // Remove disturbed sets and set new pipeline layout.
+ state
+ .descriptor_sets
+ .retain(|&num, _| num < invalidate_from);
+ state.pipeline_layout = pipeline_layout;
+ } else if (first_set + num_descriptor_sets) as usize
+ >= state.pipeline_layout.set_layouts().len()
+ {
+ // New layout is a superset of the old one.
+ state.pipeline_layout = pipeline_layout;
+ }
+
+ state
+ }
+ }
+ }
+}
+
+pub(in crate::command_buffer) struct DescriptorSetState {
+ pub(in crate::command_buffer) descriptor_sets: HashMap<u32, SetOrPush>,
+ pub(in crate::command_buffer) pipeline_layout: Arc<PipelineLayout>,
+}
+
+#[derive(Clone)]
+pub enum SetOrPush {
+ Set(DescriptorSetWithOffsets),
+ Push(DescriptorSetResources),
+}
+
+impl SetOrPush {
+ #[inline]
+ pub fn resources(&self) -> &DescriptorSetResources {
+ match self {
+ Self::Set(set) => set.as_ref().0.resources(),
+ Self::Push(resources) => resources,
+ }
+ }
+
+ #[inline]
+ pub fn dynamic_offsets(&self) -> &[u32] {
+ match self {
+ Self::Set(set) => set.as_ref().1,
+ Self::Push(_) => &[],
+ }
+ }
+}
+
+/// Allows you to retrieve the current state of a command buffer builder.
+#[derive(Clone, Copy)]
+pub struct CommandBufferBuilderState<'a> {
+ current_state: &'a CurrentState,
+}
+
+impl<'a> CommandBufferBuilderState<'a> {
+ /// Returns the descriptor set currently bound to a given set number, or `None` if nothing has
+ /// been bound yet.
+ #[inline]
+ pub fn descriptor_set(
+ &self,
+ pipeline_bind_point: PipelineBindPoint,
+ set_num: u32,
+ ) -> Option<&'a SetOrPush> {
+ self.current_state
+ .descriptor_sets
+ .get(&pipeline_bind_point)
+ .and_then(|state| state.descriptor_sets.get(&set_num))
+ }
+
+ /// Returns the pipeline layout that describes all currently bound descriptor sets.
+ ///
+ /// This can be the layout used to perform the last bind operation, but it can also be the
+ /// layout of an earlier bind if it was compatible with more recent binds.
+ #[inline]
+ pub fn descriptor_sets_pipeline_layout(
+ &self,
+ pipeline_bind_point: PipelineBindPoint,
+ ) -> Option<&'a Arc<PipelineLayout>> {
+ self.current_state
+ .descriptor_sets
+ .get(&pipeline_bind_point)
+ .map(|state| &state.pipeline_layout)
+ }
+
+ /// Returns the index buffer currently bound, or `None` if nothing has been bound yet.
+ #[inline]
+ pub fn index_buffer(&self) -> Option<(&'a Subbuffer<[u8]>, IndexType)> {
+ self.current_state
+ .index_buffer
+ .as_ref()
+ .map(|(b, i)| (b, *i))
+ }
+
+ /// Returns the compute pipeline currently bound, or `None` if nothing has been bound yet.
+ #[inline]
+ pub fn pipeline_compute(&self) -> Option<&'a Arc<ComputePipeline>> {
+ self.current_state.pipeline_compute.as_ref()
+ }
+
+ /// Returns the graphics pipeline currently bound, or `None` if nothing has been bound yet.
+ #[inline]
+ pub fn pipeline_graphics(&self) -> Option<&'a Arc<GraphicsPipeline>> {
+ self.current_state.pipeline_graphics.as_ref()
+ }
+
+ /// Returns the vertex buffer currently bound to a given binding slot number, or `None` if
+ /// nothing has been bound yet.
+ #[inline]
+ pub fn vertex_buffer(&self, binding_num: u32) -> Option<&'a Subbuffer<[u8]>> {
+ self.current_state.vertex_buffers.get(&binding_num)
+ }
+
+ /// Returns a set containing push constant bytes that have been set.
+ #[inline]
+ pub fn push_constants(&self) -> &'a RangeSet<u32> {
+ &self.current_state.push_constants
+ }
+
+ /// Returns the pipeline layout that describes the current push constants.
+ ///
+ /// This is the layout used to perform the last push constant write operation.
+ #[inline]
+ pub fn push_constants_pipeline_layout(&self) -> Option<&'a Arc<PipelineLayout>> {
+ self.current_state.push_constants_pipeline_layout.as_ref()
+ }
+
+ /// Returns the current blend constants, or `None` if nothing has been set yet.
+ #[inline]
+ pub fn blend_constants(&self) -> Option<[f32; 4]> {
+ self.current_state.blend_constants
+ }
+
+ /// Returns the current color write enable settings, or `None` if nothing has been set yet.
+ #[inline]
+ pub fn color_write_enable(&self) -> Option<&'a [bool]> {
+ self.current_state
+ .color_write_enable
+ .as_ref()
+ .map(|x| x.as_slice())
+ }
+
+ /// Returns the current cull mode, or `None` if nothing has been set yet.
+ #[inline]
+ pub fn cull_mode(&self) -> Option<CullMode> {
+ self.current_state.cull_mode
+ }
+
+ /// Returns the current depth bias settings, or `None` if nothing has been set yet.
+ #[inline]
+ pub fn depth_bias(&self) -> Option<DepthBias> {
+ self.current_state.depth_bias
+ }
+
+ /// Returns whether depth bias is enabled, or `None` if nothing has been set yet.
+ #[inline]
+ pub fn depth_bias_enable(&self) -> Option<bool> {
+ self.current_state.depth_bias_enable
+ }
+
+ /// Returns the current depth bounds settings, or `None` if nothing has been set yet.
+ #[inline]
+ pub fn depth_bounds(&self) -> Option<RangeInclusive<f32>> {
+ self.current_state.depth_bounds.clone()
+ }
+
+ /// Returns whether depth bound testing is enabled, or `None` if nothing has been set yet.
+ #[inline]
+ pub fn depth_bounds_test_enable(&self) -> Option<bool> {
+ self.current_state.depth_bounds_test_enable
+ }
+
+ /// Returns the current depth compare op, or `None` if nothing has been set yet.
+ #[inline]
+ pub fn depth_compare_op(&self) -> Option<CompareOp> {
+ self.current_state.depth_compare_op
+ }
+
+ /// Returns whether depth testing is enabled, or `None` if nothing has been set yet.
+ #[inline]
+ pub fn depth_test_enable(&self) -> Option<bool> {
+ self.current_state.depth_test_enable
+ }
+
+ /// Returns whether depth write is enabled, or `None` if nothing has been set yet.
+ #[inline]
+ pub fn depth_write_enable(&self) -> Option<bool> {
+ self.current_state.depth_write_enable
+ }
+
+ /// Returns the current discard rectangles, or `None` if nothing has been set yet.
+ #[inline]
+ pub fn discard_rectangle(&self, num: u32) -> Option<&'a Scissor> {
+ self.current_state.discard_rectangle.get(&num)
+ }
+
+ /// Returns the current front face, or `None` if nothing has been set yet.
+ #[inline]
+ pub fn front_face(&self) -> Option<FrontFace> {
+ self.current_state.front_face
+ }
+
+ /// Returns the current line stipple settings, or `None` if nothing has been set yet.
+ #[inline]
+ pub fn line_stipple(&self) -> Option<LineStipple> {
+ self.current_state.line_stipple
+ }
+
+ /// Returns the current line width, or `None` if nothing has been set yet.
+ #[inline]
+ pub fn line_width(&self) -> Option<f32> {
+ self.current_state.line_width
+ }
+
+ /// Returns the current logic op, or `None` if nothing has been set yet.
+ #[inline]
+ pub fn logic_op(&self) -> Option<LogicOp> {
+ self.current_state.logic_op
+ }
+
+ /// Returns the current number of patch control points, or `None` if nothing has been set yet.
+ #[inline]
+ pub fn patch_control_points(&self) -> Option<u32> {
+ self.current_state.patch_control_points
+ }
+
+ /// Returns whether primitive restart is enabled, or `None` if nothing has been set yet.
+ #[inline]
+ pub fn primitive_restart_enable(&self) -> Option<bool> {
+ self.current_state.primitive_restart_enable
+ }
+
+ /// Returns the current primitive topology, or `None` if nothing has been set yet.
+ #[inline]
+ pub fn primitive_topology(&self) -> Option<PrimitiveTopology> {
+ self.current_state.primitive_topology
+ }
+
+ /// Returns whether rasterizer discard is enabled, or `None` if nothing has been set yet.
+ #[inline]
+ pub fn rasterizer_discard_enable(&self) -> Option<bool> {
+ self.current_state.rasterizer_discard_enable
+ }
+
+ /// Returns the current scissor for a given viewport slot, or `None` if nothing has been set
+ /// yet.
+ #[inline]
+ pub fn scissor(&self, num: u32) -> Option<&'a Scissor> {
+ self.current_state.scissor.get(&num)
+ }
+
+ /// Returns the current viewport-with-count settings, or `None` if nothing has been set yet.
+ #[inline]
+ pub fn scissor_with_count(&self) -> Option<&'a [Scissor]> {
+ self.current_state
+ .scissor_with_count
+ .as_ref()
+ .map(|x| x.as_slice())
+ }
+
+ /// Returns the current stencil compare masks.
+ #[inline]
+ pub fn stencil_compare_mask(&self) -> StencilStateDynamic {
+ self.current_state.stencil_compare_mask
+ }
+
+ /// Returns the current stencil ops.
+ #[inline]
+ pub fn stencil_op(&self) -> StencilOpStateDynamic {
+ self.current_state.stencil_op
+ }
+
+ /// Returns the current stencil references.
+ #[inline]
+ pub fn stencil_reference(&self) -> StencilStateDynamic {
+ self.current_state.stencil_reference
+ }
+
+ /// Returns whether stencil testing is enabled, or `None` if nothing has been set yet.
+ #[inline]
+ pub fn stencil_test_enable(&self) -> Option<bool> {
+ self.current_state.stencil_test_enable
+ }
+
+ /// Returns the current stencil write masks.
+ #[inline]
+ pub fn stencil_write_mask(&self) -> StencilStateDynamic {
+ self.current_state.stencil_write_mask
+ }
+
+ /// Returns the current viewport for a given viewport slot, or `None` if nothing has been set
+ /// yet.
+ #[inline]
+ pub fn viewport(&self, num: u32) -> Option<&'a Viewport> {
+ self.current_state.viewport.get(&num)
+ }
+
+ /// Returns the current viewport-with-count settings, or `None` if nothing has been set yet.
+ #[inline]
+ pub fn viewport_with_count(&self) -> Option<&'a [Viewport]> {
+ self.current_state
+ .viewport_with_count
+ .as_ref()
+ .map(|x| x.as_slice())
+ }
+}
+
+/// Holds the current stencil state of a command buffer builder.
+#[derive(Clone, Copy, Debug, Default)]
+pub struct StencilStateDynamic {
+ pub front: Option<u32>,
+ pub back: Option<u32>,
}
-/// Holds the index of the most recent command that binds a particular resource, or `None` if
-/// nothing has been bound yet.
-#[derive(Debug, Default)]
-struct BindingState {
- descriptor_sets: FnvHashMap<PipelineBindPoint, FnvHashMap<u32, Arc<dyn Command + Send + Sync>>>,
- index_buffer: Option<Arc<dyn Command + Send + Sync>>,
- pipeline_compute: Option<Arc<dyn Command + Send + Sync>>,
- pipeline_graphics: Option<Arc<dyn Command + Send + Sync>>,
- vertex_buffers: FnvHashMap<u32, Arc<dyn Command + Send + Sync>>,
+/// Holds the current per-face stencil op state of a command buffer builder.
+#[derive(Clone, Copy, Debug, Default)]
+pub struct StencilOpStateDynamic {
+ pub front: Option<StencilOps>,
+ pub back: Option<StencilOps>,
}
diff --git a/src/command_buffer/synced/commands.rs b/src/command_buffer/synced/commands.rs
deleted file mode 100644
index 6b49a5a..0000000
--- a/src/command_buffer/synced/commands.rs
+++ /dev/null
@@ -1,3123 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use super::Command;
-use crate::buffer::BufferAccess;
-use crate::buffer::TypedBufferAccess;
-use crate::command_buffer::synced::builder::KeyTy;
-use crate::command_buffer::synced::builder::SyncCommandBufferBuilder;
-use crate::command_buffer::synced::builder::SyncCommandBufferBuilderError;
-use crate::command_buffer::sys::UnsafeCommandBufferBuilder;
-use crate::command_buffer::sys::UnsafeCommandBufferBuilderBindVertexBuffer;
-use crate::command_buffer::sys::UnsafeCommandBufferBuilderBufferImageCopy;
-use crate::command_buffer::sys::UnsafeCommandBufferBuilderColorImageClear;
-use crate::command_buffer::sys::UnsafeCommandBufferBuilderExecuteCommands;
-use crate::command_buffer::sys::UnsafeCommandBufferBuilderImageBlit;
-use crate::command_buffer::sys::UnsafeCommandBufferBuilderImageCopy;
-use crate::command_buffer::CommandBufferExecError;
-use crate::command_buffer::ImageUninitializedSafe;
-use crate::command_buffer::SecondaryCommandBuffer;
-use crate::command_buffer::SubpassContents;
-use crate::descriptor_set::layout::DescriptorDescTy;
-use crate::descriptor_set::DescriptorSet;
-use crate::descriptor_set::DescriptorSetWithOffsets;
-use crate::format::ClearValue;
-use crate::image::ImageAccess;
-use crate::image::ImageLayout;
-use crate::pipeline::depth_stencil::StencilFaces;
-use crate::pipeline::input_assembly::IndexType;
-use crate::pipeline::layout::PipelineLayout;
-use crate::pipeline::shader::ShaderStages;
-use crate::pipeline::vertex::VertexInput;
-use crate::pipeline::viewport::Scissor;
-use crate::pipeline::viewport::Viewport;
-use crate::pipeline::ComputePipelineAbstract;
-use crate::pipeline::GraphicsPipelineAbstract;
-use crate::pipeline::PipelineBindPoint;
-use crate::query::QueryControlFlags;
-use crate::query::QueryPool;
-use crate::query::QueryResultElement;
-use crate::query::QueryResultFlags;
-use crate::render_pass::FramebufferAbstract;
-use crate::render_pass::LoadOp;
-use crate::sampler::Filter;
-use crate::sync::AccessFlags;
-use crate::sync::Event;
-use crate::sync::PipelineMemoryAccess;
-use crate::sync::PipelineStage;
-use crate::sync::PipelineStages;
-use crate::DeviceSize;
-use crate::SafeDeref;
-use crate::VulkanObject;
-use smallvec::SmallVec;
-use std::borrow::Cow;
-use std::ffi::CStr;
-use std::mem;
-use std::ops::Range;
-use std::ptr;
-use std::sync::{Arc, Mutex};
-
-impl SyncCommandBufferBuilder {
- /// Calls `vkCmdBeginQuery` on the builder.
- #[inline]
- pub unsafe fn begin_query(
- &mut self,
- query_pool: Arc<QueryPool>,
- query: u32,
- flags: QueryControlFlags,
- ) {
- struct Cmd {
- query_pool: Arc<QueryPool>,
- query: u32,
- flags: QueryControlFlags,
- }
-
- impl Command for Cmd {
- fn name(&self) -> &'static str {
- "vkCmdBeginQuery"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.begin_query(self.query_pool.query(self.query).unwrap(), self.flags);
- }
- }
-
- self.append_command(
- Cmd {
- query_pool,
- query,
- flags,
- },
- &[],
- )
- .unwrap();
- }
-
- /// Calls `vkBeginRenderPass` on the builder.
- // TODO: it shouldn't be possible to get an error if the framebuffer checked conflicts already
- // TODO: after begin_render_pass has been called, flushing should be forbidden and an error
- // returned if conflict
- #[inline]
- pub unsafe fn begin_render_pass<F, I>(
- &mut self,
- framebuffer: F,
- subpass_contents: SubpassContents,
- clear_values: I,
- ) -> Result<(), SyncCommandBufferBuilderError>
- where
- F: FramebufferAbstract + Send + Sync + 'static,
- I: IntoIterator<Item = ClearValue> + Send + Sync + 'static,
- {
- struct Cmd<F, I> {
- framebuffer: F,
- subpass_contents: SubpassContents,
- clear_values: Mutex<Option<I>>,
- }
-
- impl<F, I> Command for Cmd<F, I>
- where
- F: FramebufferAbstract + Send + Sync + 'static,
- I: IntoIterator<Item = ClearValue>,
- {
- fn name(&self) -> &'static str {
- "vkCmdBeginRenderPass"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.begin_render_pass(
- &self.framebuffer,
- self.subpass_contents,
- self.clear_values.lock().unwrap().take().unwrap(),
- );
- }
-
- fn image(&self, num: usize) -> &dyn ImageAccess {
- self.framebuffer.attached_image_view(num).unwrap().image()
- }
-
- fn image_name(&self, num: usize) -> Cow<'static, str> {
- format!("attachment {}", num).into()
- }
- }
-
- let resources = framebuffer
- .render_pass()
- .desc()
- .attachments()
- .iter()
- .map(|desc| {
- (
- KeyTy::Image,
- Some((
- PipelineMemoryAccess {
- stages: PipelineStages {
- all_commands: true,
- ..PipelineStages::none()
- }, // TODO: wrong!
- access: AccessFlags {
- input_attachment_read: true,
- color_attachment_read: true,
- color_attachment_write: true,
- depth_stencil_attachment_read: true,
- depth_stencil_attachment_write: true,
- ..AccessFlags::none()
- }, // TODO: suboptimal
- exclusive: true, // TODO: suboptimal ; note: remember to always pass true if desc.initial_layout != desc.final_layout
- },
- desc.initial_layout,
- desc.final_layout,
- match desc.initial_layout != ImageLayout::Undefined
- || desc.load == LoadOp::Clear
- {
- true => ImageUninitializedSafe::Safe,
- false => ImageUninitializedSafe::Unsafe,
- },
- )),
- )
- })
- .collect::<Vec<_>>();
-
- self.append_command(
- Cmd {
- framebuffer,
- subpass_contents,
- clear_values: Mutex::new(Some(clear_values)),
- },
- &resources,
- )?;
-
- self.latest_render_pass_enter = Some(self.commands.len() - 1);
- Ok(())
- }
-
- /// Starts the process of binding descriptor sets. Returns an intermediate struct which can be
- /// used to add the sets.
- #[inline]
- pub fn bind_descriptor_sets(&mut self) -> SyncCommandBufferBuilderBindDescriptorSets {
- SyncCommandBufferBuilderBindDescriptorSets {
- builder: self,
- descriptor_sets: SmallVec::new(),
- }
- }
-
- /// Calls `vkCmdBindIndexBuffer` on the builder.
- #[inline]
- pub unsafe fn bind_index_buffer<B>(
- &mut self,
- buffer: B,
- index_ty: IndexType,
- ) -> Result<(), SyncCommandBufferBuilderError>
- where
- B: BufferAccess + Send + Sync + 'static,
- {
- struct Cmd<B> {
- buffer: B,
- index_ty: IndexType,
- }
-
- impl<B> Command for Cmd<B>
- where
- B: BufferAccess + Send + Sync + 'static,
- {
- fn name(&self) -> &'static str {
- "vkCmdBindIndexBuffer"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.bind_index_buffer(&self.buffer, self.index_ty);
- }
-
- fn bound_index_buffer(&self) -> &dyn BufferAccess {
- &self.buffer
- }
- }
-
- self.append_command(Cmd { buffer, index_ty }, &[])?;
- self.bindings.index_buffer = self.commands.last().cloned();
-
- Ok(())
- }
-
- /// Calls `vkCmdBindPipeline` on the builder with a compute pipeline.
- #[inline]
- pub unsafe fn bind_pipeline_compute<Cp>(&mut self, pipeline: Cp)
- where
- Cp: ComputePipelineAbstract + Send + Sync + 'static,
- {
- struct Cmd<Gp> {
- pipeline: Gp,
- }
-
- impl<Gp> Command for Cmd<Gp>
- where
- Gp: ComputePipelineAbstract + Send + Sync + 'static,
- {
- fn name(&self) -> &'static str {
- "vkCmdBindPipeline"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.bind_pipeline_compute(&self.pipeline);
- }
-
- fn bound_pipeline_compute(&self) -> &dyn ComputePipelineAbstract {
- &self.pipeline
- }
- }
-
- self.append_command(Cmd { pipeline }, &[]).unwrap();
- self.bindings.pipeline_compute = self.commands.last().cloned();
- }
-
- /// Calls `vkCmdBindPipeline` on the builder with a graphics pipeline.
- #[inline]
- pub unsafe fn bind_pipeline_graphics<Gp>(&mut self, pipeline: Gp)
- where
- Gp: GraphicsPipelineAbstract + Send + Sync + 'static,
- {
- struct Cmd<Gp> {
- pipeline: Gp,
- }
-
- impl<Gp> Command for Cmd<Gp>
- where
- Gp: GraphicsPipelineAbstract + Send + Sync + 'static,
- {
- fn name(&self) -> &'static str {
- "vkCmdBindPipeline"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.bind_pipeline_graphics(&self.pipeline);
- }
-
- fn bound_pipeline_graphics(&self) -> &dyn GraphicsPipelineAbstract {
- &self.pipeline
- }
- }
-
- self.append_command(Cmd { pipeline }, &[]).unwrap();
- self.bindings.pipeline_graphics = self.commands.last().cloned();
- }
-
- /// Starts the process of binding vertex buffers. Returns an intermediate struct which can be
- /// used to add the buffers.
- #[inline]
- pub fn bind_vertex_buffers(&mut self) -> SyncCommandBufferBuilderBindVertexBuffer {
- SyncCommandBufferBuilderBindVertexBuffer {
- builder: self,
- inner: UnsafeCommandBufferBuilderBindVertexBuffer::new(),
- buffers: SmallVec::new(),
- }
- }
-
- /// Calls `vkCmdCopyImage` on the builder.
- ///
- /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
- /// usage of the command anyway.
- #[inline]
- pub unsafe fn copy_image<S, D, R>(
- &mut self,
- source: S,
- source_layout: ImageLayout,
- destination: D,
- destination_layout: ImageLayout,
- regions: R,
- ) -> Result<(), SyncCommandBufferBuilderError>
- where
- S: ImageAccess + Send + Sync + 'static,
- D: ImageAccess + Send + Sync + 'static,
- R: IntoIterator<Item = UnsafeCommandBufferBuilderImageCopy> + Send + Sync + 'static,
- {
- struct Cmd<S, D, R> {
- source: S,
- source_layout: ImageLayout,
- destination: D,
- destination_layout: ImageLayout,
- regions: Mutex<Option<R>>,
- }
-
- impl<S, D, R> Command for Cmd<S, D, R>
- where
- S: ImageAccess + Send + Sync + 'static,
- D: ImageAccess + Send + Sync + 'static,
- R: IntoIterator<Item = UnsafeCommandBufferBuilderImageCopy>,
- {
- fn name(&self) -> &'static str {
- "vkCmdCopyImage"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.copy_image(
- &self.source,
- self.source_layout,
- &self.destination,
- self.destination_layout,
- self.regions.lock().unwrap().take().unwrap(),
- );
- }
-
- fn image(&self, num: usize) -> &dyn ImageAccess {
- if num == 0 {
- &self.source
- } else if num == 1 {
- &self.destination
- } else {
- panic!()
- }
- }
-
- fn image_name(&self, num: usize) -> Cow<'static, str> {
- if num == 0 {
- "source".into()
- } else if num == 1 {
- "destination".into()
- } else {
- panic!()
- }
- }
- }
-
- self.append_command(
- Cmd {
- source,
- source_layout,
- destination,
- destination_layout,
- regions: Mutex::new(Some(regions)),
- },
- &[
- (
- KeyTy::Image,
- Some((
- PipelineMemoryAccess {
- stages: PipelineStages {
- transfer: true,
- ..PipelineStages::none()
- },
- access: AccessFlags {
- transfer_read: true,
- ..AccessFlags::none()
- },
- exclusive: false,
- },
- source_layout,
- source_layout,
- ImageUninitializedSafe::Unsafe,
- )),
- ),
- (
- KeyTy::Image,
- Some((
- PipelineMemoryAccess {
- stages: PipelineStages {
- transfer: true,
- ..PipelineStages::none()
- },
- access: AccessFlags {
- transfer_write: true,
- ..AccessFlags::none()
- },
- exclusive: true,
- },
- destination_layout,
- destination_layout,
- ImageUninitializedSafe::Safe,
- )),
- ),
- ],
- )?;
-
- Ok(())
- }
-
- /// Calls `vkCmdBlitImage` on the builder.
- ///
- /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
- /// usage of the command anyway.
- #[inline]
- pub unsafe fn blit_image<S, D, R>(
- &mut self,
- source: S,
- source_layout: ImageLayout,
- destination: D,
- destination_layout: ImageLayout,
- regions: R,
- filter: Filter,
- ) -> Result<(), SyncCommandBufferBuilderError>
- where
- S: ImageAccess + Send + Sync + 'static,
- D: ImageAccess + Send + Sync + 'static,
- R: IntoIterator<Item = UnsafeCommandBufferBuilderImageBlit> + Send + Sync + 'static,
- {
- struct Cmd<S, D, R> {
- source: S,
- source_layout: ImageLayout,
- destination: D,
- destination_layout: ImageLayout,
- regions: Mutex<Option<R>>,
- filter: Filter,
- }
-
- impl<S, D, R> Command for Cmd<S, D, R>
- where
- S: ImageAccess + Send + Sync + 'static,
- D: ImageAccess + Send + Sync + 'static,
- R: IntoIterator<Item = UnsafeCommandBufferBuilderImageBlit>,
- {
- fn name(&self) -> &'static str {
- "vkCmdBlitImage"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.blit_image(
- &self.source,
- self.source_layout,
- &self.destination,
- self.destination_layout,
- self.regions.lock().unwrap().take().unwrap(),
- self.filter,
- );
- }
-
- fn image(&self, num: usize) -> &dyn ImageAccess {
- if num == 0 {
- &self.source
- } else if num == 1 {
- &self.destination
- } else {
- panic!()
- }
- }
-
- fn image_name(&self, num: usize) -> Cow<'static, str> {
- if num == 0 {
- "source".into()
- } else if num == 1 {
- "destination".into()
- } else {
- panic!()
- }
- }
- }
-
- self.append_command(
- Cmd {
- source,
- source_layout,
- destination,
- destination_layout,
- regions: Mutex::new(Some(regions)),
- filter,
- },
- &[
- (
- KeyTy::Image,
- Some((
- PipelineMemoryAccess {
- stages: PipelineStages {
- transfer: true,
- ..PipelineStages::none()
- },
- access: AccessFlags {
- transfer_read: true,
- ..AccessFlags::none()
- },
- exclusive: false,
- },
- source_layout,
- source_layout,
- ImageUninitializedSafe::Unsafe,
- )),
- ),
- (
- KeyTy::Image,
- Some((
- PipelineMemoryAccess {
- stages: PipelineStages {
- transfer: true,
- ..PipelineStages::none()
- },
- access: AccessFlags {
- transfer_write: true,
- ..AccessFlags::none()
- },
- exclusive: true,
- },
- destination_layout,
- destination_layout,
- ImageUninitializedSafe::Safe,
- )),
- ),
- ],
- )?;
-
- Ok(())
- }
-
- /// Calls `vkCmdClearColorImage` on the builder.
- ///
- /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
- /// usage of the command anyway.
- pub unsafe fn clear_color_image<I, R>(
- &mut self,
- image: I,
- layout: ImageLayout,
- color: ClearValue,
- regions: R,
- ) -> Result<(), SyncCommandBufferBuilderError>
- where
- I: ImageAccess + Send + Sync + 'static,
- R: IntoIterator<Item = UnsafeCommandBufferBuilderColorImageClear> + Send + Sync + 'static,
- {
- struct Cmd<I, R> {
- image: I,
- layout: ImageLayout,
- color: ClearValue,
- regions: Mutex<Option<R>>,
- }
-
- impl<I, R> Command for Cmd<I, R>
- where
- I: ImageAccess + Send + Sync + 'static,
- R: IntoIterator<Item = UnsafeCommandBufferBuilderColorImageClear>
- + Send
- + Sync
- + 'static,
- {
- fn name(&self) -> &'static str {
- "vkCmdClearColorImage"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.clear_color_image(
- &self.image,
- self.layout,
- self.color,
- self.regions.lock().unwrap().take().unwrap(),
- );
- }
-
- fn image(&self, num: usize) -> &dyn ImageAccess {
- assert_eq!(num, 0);
- &self.image
- }
-
- fn image_name(&self, num: usize) -> Cow<'static, str> {
- assert_eq!(num, 0);
- "target".into()
- }
- }
-
- self.append_command(
- Cmd {
- image,
- layout,
- color,
- regions: Mutex::new(Some(regions)),
- },
- &[(
- KeyTy::Image,
- Some((
- PipelineMemoryAccess {
- stages: PipelineStages {
- transfer: true,
- ..PipelineStages::none()
- },
- access: AccessFlags {
- transfer_write: true,
- ..AccessFlags::none()
- },
- exclusive: true,
- },
- layout,
- layout,
- ImageUninitializedSafe::Safe,
- )),
- )],
- )?;
-
- Ok(())
- }
-
- /// Calls `vkCmdCopyBuffer` on the builder.
- ///
- /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
- /// usage of the command anyway.
- #[inline]
- pub unsafe fn copy_buffer<S, D, R>(
- &mut self,
- source: S,
- destination: D,
- regions: R,
- ) -> Result<(), SyncCommandBufferBuilderError>
- where
- S: BufferAccess + Send + Sync + 'static,
- D: BufferAccess + Send + Sync + 'static,
- R: IntoIterator<Item = (DeviceSize, DeviceSize, DeviceSize)> + Send + Sync + 'static,
- {
- struct Cmd<S, D, R> {
- source: S,
- destination: D,
- regions: Mutex<Option<R>>,
- }
-
- impl<S, D, R> Command for Cmd<S, D, R>
- where
- S: BufferAccess + Send + Sync + 'static,
- D: BufferAccess + Send + Sync + 'static,
- R: IntoIterator<Item = (DeviceSize, DeviceSize, DeviceSize)>,
- {
- fn name(&self) -> &'static str {
- "vkCmdCopyBuffer"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.copy_buffer(
- &self.source,
- &self.destination,
- self.regions.lock().unwrap().take().unwrap(),
- );
- }
-
- fn buffer(&self, num: usize) -> &dyn BufferAccess {
- match num {
- 0 => &self.source,
- 1 => &self.destination,
- _ => panic!(),
- }
- }
-
- fn buffer_name(&self, num: usize) -> Cow<'static, str> {
- match num {
- 0 => "source".into(),
- 1 => "destination".into(),
- _ => panic!(),
- }
- }
- }
-
- self.append_command(
- Cmd {
- source,
- destination,
- regions: Mutex::new(Some(regions)),
- },
- &[
- (
- KeyTy::Buffer,
- Some((
- PipelineMemoryAccess {
- stages: PipelineStages {
- transfer: true,
- ..PipelineStages::none()
- },
- access: AccessFlags {
- transfer_read: true,
- ..AccessFlags::none()
- },
- exclusive: false,
- },
- ImageLayout::Undefined,
- ImageLayout::Undefined,
- ImageUninitializedSafe::Unsafe,
- )),
- ),
- (
- KeyTy::Buffer,
- Some((
- PipelineMemoryAccess {
- stages: PipelineStages {
- transfer: true,
- ..PipelineStages::none()
- },
- access: AccessFlags {
- transfer_write: true,
- ..AccessFlags::none()
- },
- exclusive: true,
- },
- ImageLayout::Undefined,
- ImageLayout::Undefined,
- ImageUninitializedSafe::Unsafe,
- )),
- ),
- ],
- )?;
-
- Ok(())
- }
-
- /// Calls `vkCmdCopyBufferToImage` on the builder.
- ///
- /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
- /// usage of the command anyway.
- #[inline]
- pub unsafe fn copy_buffer_to_image<S, D, R>(
- &mut self,
- source: S,
- destination: D,
- destination_layout: ImageLayout,
- regions: R,
- ) -> Result<(), SyncCommandBufferBuilderError>
- where
- S: BufferAccess + Send + Sync + 'static,
- D: ImageAccess + Send + Sync + 'static,
- R: IntoIterator<Item = UnsafeCommandBufferBuilderBufferImageCopy> + Send + Sync + 'static,
- {
- struct Cmd<S, D, R> {
- source: S,
- destination: D,
- destination_layout: ImageLayout,
- regions: Mutex<Option<R>>,
- }
-
- impl<S, D, R> Command for Cmd<S, D, R>
- where
- S: BufferAccess + Send + Sync + 'static,
- D: ImageAccess + Send + Sync + 'static,
- R: IntoIterator<Item = UnsafeCommandBufferBuilderBufferImageCopy>,
- {
- fn name(&self) -> &'static str {
- "vkCmdCopyBufferToImage"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.copy_buffer_to_image(
- &self.source,
- &self.destination,
- self.destination_layout,
- self.regions.lock().unwrap().take().unwrap(),
- );
- }
-
- fn buffer(&self, num: usize) -> &dyn BufferAccess {
- assert_eq!(num, 0);
- &self.source
- }
-
- fn buffer_name(&self, num: usize) -> Cow<'static, str> {
- assert_eq!(num, 0);
- "source".into()
- }
-
- fn image(&self, num: usize) -> &dyn ImageAccess {
- assert_eq!(num, 0);
- &self.destination
- }
-
- fn image_name(&self, num: usize) -> Cow<'static, str> {
- assert_eq!(num, 0);
- "destination".into()
- }
- }
-
- self.append_command(
- Cmd {
- source,
- destination,
- destination_layout,
- regions: Mutex::new(Some(regions)),
- },
- &[
- (
- KeyTy::Buffer,
- Some((
- PipelineMemoryAccess {
- stages: PipelineStages {
- transfer: true,
- ..PipelineStages::none()
- },
- access: AccessFlags {
- transfer_read: true,
- ..AccessFlags::none()
- },
- exclusive: false,
- },
- ImageLayout::Undefined,
- ImageLayout::Undefined,
- ImageUninitializedSafe::Unsafe,
- )),
- ),
- (
- KeyTy::Image,
- Some((
- PipelineMemoryAccess {
- stages: PipelineStages {
- transfer: true,
- ..PipelineStages::none()
- },
- access: AccessFlags {
- transfer_write: true,
- ..AccessFlags::none()
- },
- exclusive: true,
- },
- destination_layout,
- destination_layout,
- ImageUninitializedSafe::Safe,
- )),
- ),
- ],
- )?;
-
- Ok(())
- }
-
- /// Calls `vkCmdCopyImageToBuffer` on the builder.
- ///
- /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
- /// usage of the command anyway.
- #[inline]
- pub unsafe fn copy_image_to_buffer<S, D, R>(
- &mut self,
- source: S,
- source_layout: ImageLayout,
- destination: D,
- regions: R,
- ) -> Result<(), SyncCommandBufferBuilderError>
- where
- S: ImageAccess + Send + Sync + 'static,
- D: BufferAccess + Send + Sync + 'static,
- R: IntoIterator<Item = UnsafeCommandBufferBuilderBufferImageCopy> + Send + Sync + 'static,
- {
- struct Cmd<S, D, R> {
- source: S,
- source_layout: ImageLayout,
- destination: D,
- regions: Mutex<Option<R>>,
- }
-
- impl<S, D, R> Command for Cmd<S, D, R>
- where
- S: ImageAccess + Send + Sync + 'static,
- D: BufferAccess + Send + Sync + 'static,
- R: IntoIterator<Item = UnsafeCommandBufferBuilderBufferImageCopy>,
- {
- fn name(&self) -> &'static str {
- "vkCmdCopyImageToBuffer"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.copy_image_to_buffer(
- &self.source,
- self.source_layout,
- &self.destination,
- self.regions.lock().unwrap().take().unwrap(),
- );
- }
-
- fn buffer(&self, num: usize) -> &dyn BufferAccess {
- assert_eq!(num, 0);
- &self.destination
- }
-
- fn buffer_name(&self, num: usize) -> Cow<'static, str> {
- assert_eq!(num, 0);
- "destination".into()
- }
-
- fn image(&self, num: usize) -> &dyn ImageAccess {
- assert_eq!(num, 0);
- &self.source
- }
-
- fn image_name(&self, num: usize) -> Cow<'static, str> {
- assert_eq!(num, 0);
- "source".into()
- }
- }
-
- self.append_command(
- Cmd {
- source,
- destination,
- source_layout,
- regions: Mutex::new(Some(regions)),
- },
- &[
- (
- KeyTy::Image,
- Some((
- PipelineMemoryAccess {
- stages: PipelineStages {
- transfer: true,
- ..PipelineStages::none()
- },
- access: AccessFlags {
- transfer_read: true,
- ..AccessFlags::none()
- },
- exclusive: false,
- },
- source_layout,
- source_layout,
- ImageUninitializedSafe::Unsafe,
- )),
- ),
- (
- KeyTy::Buffer,
- Some((
- PipelineMemoryAccess {
- stages: PipelineStages {
- transfer: true,
- ..PipelineStages::none()
- },
- access: AccessFlags {
- transfer_write: true,
- ..AccessFlags::none()
- },
- exclusive: true,
- },
- ImageLayout::Undefined,
- ImageLayout::Undefined,
- ImageUninitializedSafe::Unsafe,
- )),
- ),
- ],
- )?;
-
- Ok(())
- }
-
- /// Calls `vkCmdCopyQueryPoolResults` on the builder.
- ///
- /// # Safety
- /// `stride` must be at least the number of bytes that will be written by each query.
- pub unsafe fn copy_query_pool_results<D, T>(
- &mut self,
- query_pool: Arc<QueryPool>,
- queries: Range<u32>,
- destination: D,
- stride: DeviceSize,
- flags: QueryResultFlags,
- ) -> Result<(), SyncCommandBufferBuilderError>
- where
- D: BufferAccess + TypedBufferAccess<Content = [T]> + Send + Sync + 'static,
- T: QueryResultElement,
- {
- struct Cmd<D> {
- query_pool: Arc<QueryPool>,
- queries: Range<u32>,
- destination: D,
- stride: DeviceSize,
- flags: QueryResultFlags,
- }
-
- impl<D, T> Command for Cmd<D>
- where
- D: BufferAccess + TypedBufferAccess<Content = [T]> + Send + Sync + 'static,
- T: QueryResultElement,
- {
- fn name(&self) -> &'static str {
- "vkCmdCopyQueryPoolResults"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.copy_query_pool_results(
- self.query_pool.queries_range(self.queries.clone()).unwrap(),
- &self.destination,
- self.stride,
- self.flags,
- );
- }
-
- fn buffer(&self, num: usize) -> &dyn BufferAccess {
- assert_eq!(num, 0);
- &self.destination
- }
-
- fn buffer_name(&self, num: usize) -> Cow<'static, str> {
- assert_eq!(num, 0);
- "destination".into()
- }
- }
-
- self.append_command(
- Cmd {
- query_pool,
- queries,
- destination,
- stride,
- flags,
- },
- &[(
- KeyTy::Buffer,
- Some((
- PipelineMemoryAccess {
- stages: PipelineStages {
- transfer: true,
- ..PipelineStages::none()
- },
- access: AccessFlags {
- transfer_write: true,
- ..AccessFlags::none()
- },
- exclusive: true,
- },
- ImageLayout::Undefined,
- ImageLayout::Undefined,
- ImageUninitializedSafe::Unsafe,
- )),
- )],
- )?;
-
- Ok(())
- }
-
- /// Calls `vkCmdBeginDebugUtilsLabelEXT` on the builder.
- ///
- /// # Safety
- /// The command pool that this command buffer was allocated from must support graphics or
- /// compute operations
- #[inline]
- pub unsafe fn debug_marker_begin(&mut self, name: &'static CStr, color: [f32; 4]) {
- struct Cmd {
- name: &'static CStr,
- color: [f32; 4],
- }
-
- impl Command for Cmd {
- fn name(&self) -> &'static str {
- "vkCmdBeginDebugUtilsLabelEXT"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.debug_marker_begin(self.name, self.color);
- }
- }
-
- self.append_command(Cmd { name, color }, &[]).unwrap();
- }
-
- /// Calls `vkCmdEndDebugUtilsLabelEXT` on the builder.
- ///
- /// # Safety
- /// - The command pool that this command buffer was allocated from must support graphics or
- /// compute operations
- /// - There must be an outstanding `debug_marker_begin` command prior to the
- /// `debug_marker_end` on the queue.
- #[inline]
- pub unsafe fn debug_marker_end(&mut self) {
- struct Cmd {}
-
- impl Command for Cmd {
- fn name(&self) -> &'static str {
- "vkCmdEndDebugUtilsLabelEXT"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.debug_marker_end();
- }
- }
-
- self.append_command(Cmd {}, &[]).unwrap();
- }
-
- /// Calls `vkCmdInsertDebugUtilsLabelEXT` on the builder.
- ///
- /// # Safety
- /// The command pool that this command buffer was allocated from must support graphics or
- /// compute operations
- #[inline]
- pub unsafe fn debug_marker_insert(&mut self, name: &'static CStr, color: [f32; 4]) {
- struct Cmd {
- name: &'static CStr,
- color: [f32; 4],
- }
-
- impl Command for Cmd {
- fn name(&self) -> &'static str {
- "vkCmdInsertDebugUtilsLabelEXT"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.debug_marker_insert(self.name, self.color);
- }
- }
-
- self.append_command(Cmd { name, color }, &[]).unwrap();
- }
-
- /// Calls `vkCmdDispatch` on the builder.
- #[inline]
- pub unsafe fn dispatch(&mut self, group_counts: [u32; 3]) {
- struct Cmd {
- group_counts: [u32; 3],
- descriptor_sets: SmallVec<[Arc<dyn Command + Send + Sync>; 12]>,
- }
-
- impl Command for Cmd {
- fn name(&self) -> &'static str {
- "vkCmdDispatch"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.dispatch(self.group_counts);
- }
-
- fn buffer(&self, mut num: usize) -> &dyn BufferAccess {
- for set in self
- .descriptor_sets
- .iter()
- .enumerate()
- .map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0)
- {
- if let Some(buf) = set.buffer(num) {
- return buf.0;
- }
- num -= set.num_buffers();
- }
- panic!()
- }
-
- fn buffer_name(&self, mut num: usize) -> Cow<'static, str> {
- for (set_num, set) in self
- .descriptor_sets
- .iter()
- .enumerate()
- .map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0))
- {
- if let Some(buf) = set.buffer(num) {
- return format!("Buffer bound to set {} descriptor {}", set_num, buf.1)
- .into();
- }
- num -= set.num_buffers();
- }
- panic!()
- }
-
- fn image(&self, mut num: usize) -> &dyn ImageAccess {
- for set in self
- .descriptor_sets
- .iter()
- .enumerate()
- .map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0)
- {
- if let Some(img) = set.image(num) {
- return img.0.image();
- }
- num -= set.num_images();
- }
- panic!()
- }
-
- fn image_name(&self, mut num: usize) -> Cow<'static, str> {
- for (set_num, set) in self
- .descriptor_sets
- .iter()
- .enumerate()
- .map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0))
- {
- if let Some(img) = set.image(num) {
- return format!("Image bound to set {} descriptor {}", set_num, img.1)
- .into();
- }
- num -= set.num_images();
- }
- panic!()
- }
- }
-
- let pipeline = self
- .bindings
- .pipeline_compute
- .as_ref()
- .unwrap()
- .bound_pipeline_compute();
-
- let mut resources = Vec::new();
- let descriptor_sets = self.add_descriptor_set_resources(
- &mut resources,
- pipeline.layout(),
- PipelineBindPoint::Compute,
- );
-
- self.append_command(
- Cmd {
- group_counts,
- descriptor_sets,
- },
- &resources,
- )
- .unwrap();
- }
-
- /// Calls `vkCmdDispatchIndirect` on the builder.
- #[inline]
- pub unsafe fn dispatch_indirect<B>(
- &mut self,
- indirect_buffer: B,
- ) -> Result<(), SyncCommandBufferBuilderError>
- where
- B: BufferAccess + Send + Sync + 'static,
- {
- struct Cmd<B> {
- descriptor_sets: SmallVec<[Arc<dyn Command + Send + Sync>; 12]>,
- indirect_buffer: B,
- }
-
- impl<B> Command for Cmd<B>
- where
- B: BufferAccess + Send + Sync + 'static,
- {
- fn name(&self) -> &'static str {
- "vkCmdDispatchIndirect"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.dispatch_indirect(&self.indirect_buffer);
- }
-
- fn buffer(&self, mut num: usize) -> &dyn BufferAccess {
- for set in self
- .descriptor_sets
- .iter()
- .enumerate()
- .map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0)
- {
- if let Some(buf) = set.buffer(num) {
- return buf.0;
- }
- num -= set.num_buffers();
- }
- if num == 0 {
- return &self.indirect_buffer;
- }
- panic!()
- }
-
- fn buffer_name(&self, mut num: usize) -> Cow<'static, str> {
- for (set_num, set) in self
- .descriptor_sets
- .iter()
- .enumerate()
- .map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0))
- {
- if let Some(buf) = set.buffer(num) {
- return format!("Buffer bound to set {} descriptor {}", set_num, buf.1)
- .into();
- }
- num -= set.num_buffers();
- }
- if num == 0 {
- return "indirect buffer".into();
- }
- panic!()
- }
-
- fn image(&self, mut num: usize) -> &dyn ImageAccess {
- for set in self
- .descriptor_sets
- .iter()
- .enumerate()
- .map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0)
- {
- if let Some(img) = set.image(num) {
- return img.0.image();
- }
- num -= set.num_images();
- }
- panic!()
- }
-
- fn image_name(&self, mut num: usize) -> Cow<'static, str> {
- for (set_num, set) in self
- .descriptor_sets
- .iter()
- .enumerate()
- .map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0))
- {
- if let Some(img) = set.image(num) {
- return format!("Image bound to set {} descriptor {}", set_num, img.1)
- .into();
- }
- num -= set.num_images();
- }
- panic!()
- }
- }
-
- let pipeline = self
- .bindings
- .pipeline_compute
- .as_ref()
- .unwrap()
- .bound_pipeline_compute();
-
- let mut resources = Vec::new();
- let descriptor_sets = self.add_descriptor_set_resources(
- &mut resources,
- pipeline.layout(),
- PipelineBindPoint::Compute,
- );
- self.add_indirect_buffer_resources(&mut resources);
-
- self.append_command(
- Cmd {
- descriptor_sets,
- indirect_buffer,
- },
- &resources,
- )?;
-
- Ok(())
- }
-
- /// Calls `vkCmdDraw` on the builder.
- #[inline]
- pub unsafe fn draw(
- &mut self,
- vertex_count: u32,
- instance_count: u32,
- first_vertex: u32,
- first_instance: u32,
- ) {
- struct Cmd {
- descriptor_sets: SmallVec<[Arc<dyn Command + Send + Sync>; 12]>,
- vertex_buffers: SmallVec<[(u32, Arc<dyn Command + Send + Sync>); 4]>,
- vertex_count: u32,
- instance_count: u32,
- first_vertex: u32,
- first_instance: u32,
- }
-
- impl Command for Cmd {
- fn name(&self) -> &'static str {
- "vkCmdDraw"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.draw(
- self.vertex_count,
- self.instance_count,
- self.first_vertex,
- self.first_instance,
- );
- }
-
- fn buffer(&self, mut num: usize) -> &dyn BufferAccess {
- for set in self
- .descriptor_sets
- .iter()
- .enumerate()
- .map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0)
- {
- if let Some(buf) = set.buffer(num) {
- return buf.0;
- }
- num -= set.num_buffers();
- }
-
- for buffer in self
- .vertex_buffers
- .iter()
- .map(|(binding_num, cmd)| cmd.bound_vertex_buffer(*binding_num))
- {
- if num == 0 {
- return buffer;
- }
- num -= 1;
- }
-
- panic!()
- }
-
- fn buffer_name(&self, mut num: usize) -> Cow<'static, str> {
- for (set_num, set) in self
- .descriptor_sets
- .iter()
- .enumerate()
- .map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0))
- {
- if let Some(buf) = set.buffer(num) {
- return format!("Buffer bound to set {} descriptor {}", set_num, buf.1)
- .into();
- }
- num -= set.num_buffers();
- }
-
- for binding_num in self
- .vertex_buffers
- .iter()
- .map(|(binding_num, _)| *binding_num)
- {
- if num == 0 {
- return format!("Vertex buffer binding {}", binding_num).into();
- }
- num -= 1;
- }
-
- panic!()
- }
-
- fn image(&self, mut num: usize) -> &dyn ImageAccess {
- for set in self
- .descriptor_sets
- .iter()
- .enumerate()
- .map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0)
- {
- if let Some(img) = set.image(num) {
- return img.0.image();
- }
- num -= set.num_images();
- }
- panic!()
- }
-
- fn image_name(&self, mut num: usize) -> Cow<'static, str> {
- for (set_num, set) in self
- .descriptor_sets
- .iter()
- .enumerate()
- .map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0))
- {
- if let Some(img) = set.image(num) {
- return format!("Image bound to set {} descriptor {}", set_num, img.1)
- .into();
- }
- num -= set.num_images();
- }
- panic!()
- }
- }
-
- let pipeline = self
- .bindings
- .pipeline_graphics
- .as_ref()
- .unwrap()
- .bound_pipeline_graphics();
-
- let mut resources = Vec::new();
- let descriptor_sets = self.add_descriptor_set_resources(
- &mut resources,
- pipeline.layout(),
- PipelineBindPoint::Graphics,
- );
- let vertex_buffers =
- self.add_vertex_buffer_resources(&mut resources, pipeline.vertex_input());
-
- self.append_command(
- Cmd {
- descriptor_sets,
- vertex_buffers,
- vertex_count,
- instance_count,
- first_vertex,
- first_instance,
- },
- &resources,
- )
- .unwrap();
- }
-
- /// Calls `vkCmdDrawIndexed` on the builder.
- #[inline]
- pub unsafe fn draw_indexed(
- &mut self,
- index_count: u32,
- instance_count: u32,
- first_index: u32,
- vertex_offset: i32,
- first_instance: u32,
- ) {
- struct Cmd {
- descriptor_sets: SmallVec<[Arc<dyn Command + Send + Sync>; 12]>,
- vertex_buffers: SmallVec<[(u32, Arc<dyn Command + Send + Sync>); 4]>,
- index_buffer: Arc<dyn Command + Send + Sync>,
- index_count: u32,
- instance_count: u32,
- first_index: u32,
- vertex_offset: i32,
- first_instance: u32,
- }
-
- impl Command for Cmd {
- fn name(&self) -> &'static str {
- "vkCmdDrawIndexed"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.draw_indexed(
- self.index_count,
- self.instance_count,
- self.first_index,
- self.vertex_offset,
- self.first_instance,
- );
- }
-
- fn buffer(&self, mut num: usize) -> &dyn BufferAccess {
- for set in self
- .descriptor_sets
- .iter()
- .enumerate()
- .map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0)
- {
- if let Some(buf) = set.buffer(num) {
- return buf.0;
- }
- num -= set.num_buffers();
- }
-
- for buffer in self
- .vertex_buffers
- .iter()
- .map(|(binding_num, cmd)| cmd.bound_vertex_buffer(*binding_num))
- {
- if num == 0 {
- return buffer;
- }
- num -= 1;
- }
-
- if num == 0 {
- return self.index_buffer.bound_index_buffer();
- }
-
- panic!()
- }
-
- fn buffer_name(&self, mut num: usize) -> Cow<'static, str> {
- for (set_num, set) in self
- .descriptor_sets
- .iter()
- .enumerate()
- .map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0))
- {
- if let Some(buf) = set.buffer(num) {
- return format!("Buffer bound to set {} descriptor {}", set_num, buf.1)
- .into();
- }
- num -= set.num_buffers();
- }
-
- for binding_num in self
- .vertex_buffers
- .iter()
- .map(|(binding_num, _)| *binding_num)
- {
- if num == 0 {
- return format!("Vertex buffer binding {}", binding_num).into();
- }
- num -= 1;
- }
-
- if num == 0 {
- return "index buffer".into();
- }
-
- panic!()
- }
-
- fn image(&self, mut num: usize) -> &dyn ImageAccess {
- for set in self
- .descriptor_sets
- .iter()
- .enumerate()
- .map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0)
- {
- if let Some(img) = set.image(num) {
- return img.0.image();
- }
- num -= set.num_images();
- }
- panic!()
- }
-
- fn image_name(&self, mut num: usize) -> Cow<'static, str> {
- for (set_num, set) in self
- .descriptor_sets
- .iter()
- .enumerate()
- .map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0))
- {
- if let Some(img) = set.image(num) {
- return format!("Image bound to set {} descriptor {}", set_num, img.1)
- .into();
- }
- num -= set.num_images();
- }
- panic!()
- }
- }
-
- let pipeline = self
- .bindings
- .pipeline_graphics
- .as_ref()
- .unwrap()
- .bound_pipeline_graphics();
-
- let mut resources = Vec::new();
- let descriptor_sets = self.add_descriptor_set_resources(
- &mut resources,
- pipeline.layout(),
- PipelineBindPoint::Graphics,
- );
- let vertex_buffers =
- self.add_vertex_buffer_resources(&mut resources, pipeline.vertex_input());
- let index_buffer = self.add_index_buffer_resources(&mut resources);
-
- self.append_command(
- Cmd {
- descriptor_sets,
- vertex_buffers,
- index_buffer,
- index_count,
- instance_count,
- first_index,
- vertex_offset,
- first_instance,
- },
- &resources,
- )
- .unwrap();
- }
-
- /// Calls `vkCmdDrawIndirect` on the builder.
- #[inline]
- pub unsafe fn draw_indirect<B>(
- &mut self,
- indirect_buffer: B,
- draw_count: u32,
- stride: u32,
- ) -> Result<(), SyncCommandBufferBuilderError>
- where
- B: BufferAccess + Send + Sync + 'static,
- {
- struct Cmd<B> {
- descriptor_sets: SmallVec<[Arc<dyn Command + Send + Sync>; 12]>,
- vertex_buffers: SmallVec<[(u32, Arc<dyn Command + Send + Sync>); 4]>,
- indirect_buffer: B,
- draw_count: u32,
- stride: u32,
- }
-
- impl<B> Command for Cmd<B>
- where
- B: BufferAccess + Send + Sync + 'static,
- {
- fn name(&self) -> &'static str {
- "vkCmdDrawIndirect"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.draw_indirect(&self.indirect_buffer, self.draw_count, self.stride);
- }
-
- fn buffer(&self, mut num: usize) -> &dyn BufferAccess {
- for set in self
- .descriptor_sets
- .iter()
- .enumerate()
- .map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0)
- {
- if let Some(buf) = set.buffer(num) {
- return buf.0;
- }
- num -= set.num_buffers();
- }
-
- for buffer in self
- .vertex_buffers
- .iter()
- .map(|(binding_num, cmd)| cmd.bound_vertex_buffer(*binding_num))
- {
- if num == 0 {
- return buffer;
- }
- num -= 1;
- }
-
- if num == 0 {
- return &self.indirect_buffer;
- }
-
- panic!()
- }
-
- fn buffer_name(&self, mut num: usize) -> Cow<'static, str> {
- for (set_num, set) in self
- .descriptor_sets
- .iter()
- .enumerate()
- .map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0))
- {
- if let Some(buf) = set.buffer(num) {
- return format!("Buffer bound to set {} descriptor {}", set_num, buf.1)
- .into();
- }
- num -= set.num_buffers();
- }
-
- for binding_num in self
- .vertex_buffers
- .iter()
- .map(|(binding_num, _)| *binding_num)
- {
- if num == 0 {
- return format!("Vertex buffer binding {}", binding_num).into();
- }
- num -= 1;
- }
-
- if num == 0 {
- return "indirect buffer".into();
- }
-
- panic!()
- }
-
- fn image(&self, mut num: usize) -> &dyn ImageAccess {
- for set in self
- .descriptor_sets
- .iter()
- .enumerate()
- .map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0)
- {
- if let Some(img) = set.image(num) {
- return img.0.image();
- }
- num -= set.num_images();
- }
- panic!()
- }
-
- fn image_name(&self, mut num: usize) -> Cow<'static, str> {
- for (set_num, set) in self
- .descriptor_sets
- .iter()
- .enumerate()
- .map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0))
- {
- if let Some(img) = set.image(num) {
- return format!("Image bound to set {} descriptor {}", set_num, img.1)
- .into();
- }
- num -= set.num_images();
- }
- panic!()
- }
- }
-
- let pipeline = self
- .bindings
- .pipeline_graphics
- .as_ref()
- .unwrap()
- .bound_pipeline_graphics();
-
- let mut resources = Vec::new();
- let descriptor_sets = self.add_descriptor_set_resources(
- &mut resources,
- pipeline.layout(),
- PipelineBindPoint::Graphics,
- );
- let vertex_buffers =
- self.add_vertex_buffer_resources(&mut resources, pipeline.vertex_input());
- self.add_indirect_buffer_resources(&mut resources);
-
- self.append_command(
- Cmd {
- descriptor_sets,
- vertex_buffers,
- indirect_buffer,
- draw_count,
- stride,
- },
- &resources,
- )?;
-
- Ok(())
- }
-
- /// Calls `vkCmdDrawIndexedIndirect` on the builder.
- #[inline]
- pub unsafe fn draw_indexed_indirect<B>(
- &mut self,
- indirect_buffer: B,
- draw_count: u32,
- stride: u32,
- ) -> Result<(), SyncCommandBufferBuilderError>
- where
- B: BufferAccess + Send + Sync + 'static,
- {
- struct Cmd<B> {
- descriptor_sets: SmallVec<[Arc<dyn Command + Send + Sync>; 12]>,
- vertex_buffers: SmallVec<[(u32, Arc<dyn Command + Send + Sync>); 4]>,
- index_buffer: Arc<dyn Command + Send + Sync>,
- indirect_buffer: B,
- draw_count: u32,
- stride: u32,
- }
-
- impl<B> Command for Cmd<B>
- where
- B: BufferAccess + Send + Sync + 'static,
- {
- fn name(&self) -> &'static str {
- "vkCmdDrawIndexedIndirect"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.draw_indexed_indirect(&self.indirect_buffer, self.draw_count, self.stride);
- }
-
- fn buffer(&self, mut num: usize) -> &dyn BufferAccess {
- for set in self
- .descriptor_sets
- .iter()
- .enumerate()
- .map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0)
- {
- if let Some(buf) = set.buffer(num) {
- return buf.0;
- }
- num -= set.num_buffers();
- }
-
- for buffer in self
- .vertex_buffers
- .iter()
- .map(|(binding_num, cmd)| cmd.bound_vertex_buffer(*binding_num))
- {
- if num == 0 {
- return buffer;
- }
- num -= 1;
- }
-
- if num == 0 {
- return self.index_buffer.bound_index_buffer();
- } else if num == 1 {
- return &self.indirect_buffer;
- }
-
- panic!()
- }
-
- fn buffer_name(&self, mut num: usize) -> Cow<'static, str> {
- for (set_num, set) in self
- .descriptor_sets
- .iter()
- .enumerate()
- .map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0))
- {
- if let Some(buf) = set.buffer(num) {
- return format!("Buffer bound to set {} descriptor {}", set_num, buf.1)
- .into();
- }
- num -= set.num_buffers();
- }
-
- for binding_num in self
- .vertex_buffers
- .iter()
- .map(|(binding_num, _)| *binding_num)
- {
- if num == 0 {
- return format!("Vertex buffer binding {}", binding_num).into();
- }
- num -= 1;
- }
-
- if num == 0 {
- return "index buffer".into();
- } else if num == 1 {
- return "indirect buffer".into();
- }
-
- panic!()
- }
-
- fn image(&self, mut num: usize) -> &dyn ImageAccess {
- for set in self
- .descriptor_sets
- .iter()
- .enumerate()
- .map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0)
- {
- if let Some(img) = set.image(num) {
- return img.0.image();
- }
- num -= set.num_images();
- }
- panic!()
- }
-
- fn image_name(&self, mut num: usize) -> Cow<'static, str> {
- for (set_num, set) in self
- .descriptor_sets
- .iter()
- .enumerate()
- .map(|(set_num, cmd)| (set_num, cmd.bound_descriptor_set(set_num as u32).0))
- {
- if let Some(img) = set.image(num) {
- return format!("Image bound to set {} descriptor {}", set_num, img.1)
- .into();
- }
- num -= set.num_images();
- }
- panic!()
- }
- }
-
- let pipeline = self
- .bindings
- .pipeline_graphics
- .as_ref()
- .unwrap()
- .bound_pipeline_graphics();
-
- let mut resources = Vec::new();
- let descriptor_sets = self.add_descriptor_set_resources(
- &mut resources,
- pipeline.layout(),
- PipelineBindPoint::Graphics,
- );
- let vertex_buffers =
- self.add_vertex_buffer_resources(&mut resources, pipeline.vertex_input());
- let index_buffer = self.add_index_buffer_resources(&mut resources);
- self.add_indirect_buffer_resources(&mut resources);
-
- self.append_command(
- Cmd {
- descriptor_sets,
- vertex_buffers,
- index_buffer,
- indirect_buffer,
- draw_count,
- stride,
- },
- &resources,
- )?;
-
- Ok(())
- }
-
- /// Calls `vkCmdEndQuery` on the builder.
- #[inline]
- pub unsafe fn end_query(&mut self, query_pool: Arc<QueryPool>, query: u32) {
- struct Cmd {
- query_pool: Arc<QueryPool>,
- query: u32,
- }
-
- impl Command for Cmd {
- fn name(&self) -> &'static str {
- "vkCmdEndQuery"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.end_query(self.query_pool.query(self.query).unwrap());
- }
- }
-
- self.append_command(Cmd { query_pool, query }, &[]).unwrap();
- }
-
- /// Calls `vkCmdEndRenderPass` on the builder.
- #[inline]
- pub unsafe fn end_render_pass(&mut self) {
- struct Cmd;
-
- impl Command for Cmd {
- fn name(&self) -> &'static str {
- "vkCmdEndRenderPass"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.end_render_pass();
- }
- }
-
- self.append_command(Cmd, &[]).unwrap();
- debug_assert!(self.latest_render_pass_enter.is_some());
- self.latest_render_pass_enter = None;
- }
-
- /// Starts the process of executing secondary command buffers. Returns an intermediate struct
- /// which can be used to add the command buffers.
- #[inline]
- pub unsafe fn execute_commands(&mut self) -> SyncCommandBufferBuilderExecuteCommands {
- SyncCommandBufferBuilderExecuteCommands {
- builder: self,
- inner: Vec::new(),
- }
- }
-
- /// Calls `vkCmdFillBuffer` on the builder.
- #[inline]
- pub unsafe fn fill_buffer<B>(&mut self, buffer: B, data: u32)
- where
- B: BufferAccess + Send + Sync + 'static,
- {
- struct Cmd<B> {
- buffer: B,
- data: u32,
- }
-
- impl<B> Command for Cmd<B>
- where
- B: BufferAccess + Send + Sync + 'static,
- {
- fn name(&self) -> &'static str {
- "vkCmdFillBuffer"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.fill_buffer(&self.buffer, self.data);
- }
-
- fn buffer(&self, num: usize) -> &dyn BufferAccess {
- assert_eq!(num, 0);
- &self.buffer
- }
-
- fn buffer_name(&self, _: usize) -> Cow<'static, str> {
- "destination".into()
- }
- }
-
- self.append_command(
- Cmd { buffer, data },
- &[(
- KeyTy::Buffer,
- Some((
- PipelineMemoryAccess {
- stages: PipelineStages {
- transfer: true,
- ..PipelineStages::none()
- },
- access: AccessFlags {
- transfer_write: true,
- ..AccessFlags::none()
- },
- exclusive: true,
- },
- ImageLayout::Undefined,
- ImageLayout::Undefined,
- ImageUninitializedSafe::Unsafe,
- )),
- )],
- )
- .unwrap();
- }
-
- /// Calls `vkCmdNextSubpass` on the builder.
- #[inline]
- pub unsafe fn next_subpass(&mut self, subpass_contents: SubpassContents) {
- struct Cmd {
- subpass_contents: SubpassContents,
- }
-
- impl Command for Cmd {
- fn name(&self) -> &'static str {
- "vkCmdNextSubpass"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.next_subpass(self.subpass_contents);
- }
- }
-
- self.append_command(Cmd { subpass_contents }, &[]).unwrap();
- }
-
- /// Calls `vkCmdPushConstants` on the builder.
- #[inline]
- pub unsafe fn push_constants<D>(
- &mut self,
- pipeline_layout: Arc<PipelineLayout>,
- stages: ShaderStages,
- offset: u32,
- size: u32,
- data: &D,
- ) where
- D: ?Sized + Send + Sync + 'static,
- {
- struct Cmd {
- pipeline_layout: Arc<PipelineLayout>,
- stages: ShaderStages,
- offset: u32,
- size: u32,
- data: Box<[u8]>,
- }
-
- impl Command for Cmd {
- fn name(&self) -> &'static str {
- "vkCmdPushConstants"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.push_constants::<[u8]>(
- &self.pipeline_layout,
- self.stages,
- self.offset,
- self.size,
- &self.data,
- );
- }
- }
-
- debug_assert!(mem::size_of_val(data) >= size as usize);
-
- let mut out = Vec::with_capacity(size as usize);
- ptr::copy::<u8>(
- data as *const D as *const u8,
- out.as_mut_ptr(),
- size as usize,
- );
- out.set_len(size as usize);
-
- self.append_command(
- Cmd {
- pipeline_layout,
- stages,
- offset,
- size,
- data: out.into(),
- },
- &[],
- )
- .unwrap();
- }
-
- /// Calls `vkCmdResetEvent` on the builder.
- #[inline]
- pub unsafe fn reset_event(&mut self, event: Arc<Event>, stages: PipelineStages) {
- struct Cmd {
- event: Arc<Event>,
- stages: PipelineStages,
- }
-
- impl Command for Cmd {
- fn name(&self) -> &'static str {
- "vkCmdResetEvent"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.reset_event(&self.event, self.stages);
- }
- }
-
- self.append_command(Cmd { event, stages }, &[]).unwrap();
- }
-
- /// Calls `vkCmdResetQueryPool` on the builder.
- #[inline]
- pub unsafe fn reset_query_pool(&mut self, query_pool: Arc<QueryPool>, queries: Range<u32>) {
- struct Cmd {
- query_pool: Arc<QueryPool>,
- queries: Range<u32>,
- }
-
- impl Command for Cmd {
- fn name(&self) -> &'static str {
- "vkCmdResetQueryPool"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.reset_query_pool(self.query_pool.queries_range(self.queries.clone()).unwrap());
- }
- }
-
- self.append_command(
- Cmd {
- query_pool,
- queries,
- },
- &[],
- )
- .unwrap();
- }
-
- /// Calls `vkCmdSetBlendConstants` on the builder.
- #[inline]
- pub unsafe fn set_blend_constants(&mut self, constants: [f32; 4]) {
- struct Cmd {
- constants: [f32; 4],
- }
-
- impl Command for Cmd {
- fn name(&self) -> &'static str {
- "vkCmdSetBlendConstants"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.set_blend_constants(self.constants);
- }
- }
-
- self.append_command(Cmd { constants }, &[]).unwrap();
- }
-
- /// Calls `vkCmdSetDepthBias` on the builder.
- #[inline]
- pub unsafe fn set_depth_bias(&mut self, constant_factor: f32, clamp: f32, slope_factor: f32) {
- struct Cmd {
- constant_factor: f32,
- clamp: f32,
- slope_factor: f32,
- }
-
- impl Command for Cmd {
- fn name(&self) -> &'static str {
- "vkCmdSetDepthBias"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.set_depth_bias(self.constant_factor, self.clamp, self.slope_factor);
- }
- }
-
- self.append_command(
- Cmd {
- constant_factor,
- clamp,
- slope_factor,
- },
- &[],
- )
- .unwrap();
- }
-
- /// Calls `vkCmdSetDepthBounds` on the builder.
- #[inline]
- pub unsafe fn set_depth_bounds(&mut self, min: f32, max: f32) {
- struct Cmd {
- min: f32,
- max: f32,
- }
-
- impl Command for Cmd {
- fn name(&self) -> &'static str {
- "vkCmdSetDepthBounds"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.set_depth_bounds(self.min, self.max);
- }
- }
-
- self.append_command(Cmd { min, max }, &[]).unwrap();
- }
-
- /// Calls `vkCmdSetEvent` on the builder.
- #[inline]
- pub unsafe fn set_event(&mut self, event: Arc<Event>, stages: PipelineStages) {
- struct Cmd {
- event: Arc<Event>,
- stages: PipelineStages,
- }
-
- impl Command for Cmd {
- fn name(&self) -> &'static str {
- "vkCmdSetEvent"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.set_event(&self.event, self.stages);
- }
- }
-
- self.append_command(Cmd { event, stages }, &[]).unwrap();
- }
-
- /// Calls `vkCmdSetLineWidth` on the builder.
- #[inline]
- pub unsafe fn set_line_width(&mut self, line_width: f32) {
- struct Cmd {
- line_width: f32,
- }
-
- impl Command for Cmd {
- fn name(&self) -> &'static str {
- "vkCmdSetLineWidth"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.set_line_width(self.line_width);
- }
- }
-
- self.append_command(Cmd { line_width }, &[]).unwrap();
- }
-
- /// Calls `vkCmdSetStencilCompareMask` on the builder.
- #[inline]
- pub unsafe fn set_stencil_compare_mask(&mut self, face_mask: StencilFaces, compare_mask: u32) {
- struct Cmd {
- face_mask: StencilFaces,
- compare_mask: u32,
- }
-
- impl Command for Cmd {
- fn name(&self) -> &'static str {
- "vkCmdSetStencilCompareMask"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.set_stencil_compare_mask(self.face_mask, self.compare_mask);
- }
- }
-
- self.append_command(
- Cmd {
- face_mask,
- compare_mask,
- },
- &[],
- )
- .unwrap();
- }
-
- /// Calls `vkCmdSetStencilReference` on the builder.
- #[inline]
- pub unsafe fn set_stencil_reference(&mut self, face_mask: StencilFaces, reference: u32) {
- struct Cmd {
- face_mask: StencilFaces,
- reference: u32,
- }
-
- impl Command for Cmd {
- fn name(&self) -> &'static str {
- "vkCmdSetStencilReference"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.set_stencil_reference(self.face_mask, self.reference);
- }
- }
-
- self.append_command(
- Cmd {
- face_mask,
- reference,
- },
- &[],
- )
- .unwrap();
- }
-
- /// Calls `vkCmdSetStencilWriteMask` on the builder.
- #[inline]
- pub unsafe fn set_stencil_write_mask(&mut self, face_mask: StencilFaces, write_mask: u32) {
- struct Cmd {
- face_mask: StencilFaces,
- write_mask: u32,
- }
-
- impl Command for Cmd {
- fn name(&self) -> &'static str {
- "vkCmdSetStencilWriteMask"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.set_stencil_write_mask(self.face_mask, self.write_mask);
- }
- }
-
- self.append_command(
- Cmd {
- face_mask,
- write_mask,
- },
- &[],
- )
- .unwrap();
- }
-
- /// Calls `vkCmdSetScissor` on the builder.
- ///
- /// If the list is empty then the command is automatically ignored.
- #[inline]
- pub unsafe fn set_scissor<I>(&mut self, first_scissor: u32, scissors: I)
- where
- I: IntoIterator<Item = Scissor> + Send + Sync + 'static,
- {
- struct Cmd<I> {
- first_scissor: u32,
- scissors: Mutex<Option<I>>,
- }
-
- impl<I> Command for Cmd<I>
- where
- I: IntoIterator<Item = Scissor>,
- {
- fn name(&self) -> &'static str {
- "vkCmdSetScissor"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.set_scissor(
- self.first_scissor,
- self.scissors.lock().unwrap().take().unwrap(),
- );
- }
- }
-
- self.append_command(
- Cmd {
- first_scissor,
- scissors: Mutex::new(Some(scissors)),
- },
- &[],
- )
- .unwrap();
- }
-
- /// Calls `vkCmdSetViewport` on the builder.
- ///
- /// If the list is empty then the command is automatically ignored.
- #[inline]
- pub unsafe fn set_viewport<I>(&mut self, first_viewport: u32, viewports: I)
- where
- I: IntoIterator<Item = Viewport> + Send + Sync + 'static,
- {
- struct Cmd<I> {
- first_viewport: u32,
- viewports: Mutex<Option<I>>,
- }
-
- impl<I> Command for Cmd<I>
- where
- I: IntoIterator<Item = Viewport>,
- {
- fn name(&self) -> &'static str {
- "vkCmdSetViewport"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.set_viewport(
- self.first_viewport,
- self.viewports.lock().unwrap().take().unwrap(),
- );
- }
- }
-
- self.append_command(
- Cmd {
- first_viewport,
- viewports: Mutex::new(Some(viewports)),
- },
- &[],
- )
- .unwrap();
- }
-
- /// Calls `vkCmdUpdateBuffer` on the builder.
- #[inline]
- pub unsafe fn update_buffer<B, D, Dd>(&mut self, buffer: B, data: Dd)
- where
- B: BufferAccess + Send + Sync + 'static,
- D: ?Sized,
- Dd: SafeDeref<Target = D> + Send + Sync + 'static,
- {
- struct Cmd<B, Dd> {
- buffer: B,
- data: Dd,
- }
-
- impl<B, D, Dd> Command for Cmd<B, Dd>
- where
- B: BufferAccess + Send + Sync + 'static,
- D: ?Sized,
- Dd: SafeDeref<Target = D> + Send + Sync + 'static,
- {
- fn name(&self) -> &'static str {
- "vkCmdUpdateBuffer"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.update_buffer(&self.buffer, self.data.deref());
- }
-
- fn buffer(&self, num: usize) -> &dyn BufferAccess {
- assert_eq!(num, 0);
- &self.buffer
- }
-
- fn buffer_name(&self, _: usize) -> Cow<'static, str> {
- "destination".into()
- }
- }
-
- self.append_command(
- Cmd { buffer, data },
- &[(
- KeyTy::Buffer,
- Some((
- PipelineMemoryAccess {
- stages: PipelineStages {
- transfer: true,
- ..PipelineStages::none()
- },
- access: AccessFlags {
- transfer_write: true,
- ..AccessFlags::none()
- },
- exclusive: true,
- },
- ImageLayout::Undefined,
- ImageLayout::Undefined,
- ImageUninitializedSafe::Unsafe,
- )),
- )],
- )
- .unwrap();
- }
-
- /// Calls `vkCmdWriteTimestamp` on the builder.
- #[inline]
- pub unsafe fn write_timestamp(
- &mut self,
- query_pool: Arc<QueryPool>,
- query: u32,
- stage: PipelineStage,
- ) {
- struct Cmd {
- query_pool: Arc<QueryPool>,
- query: u32,
- stage: PipelineStage,
- }
-
- impl Command for Cmd {
- fn name(&self) -> &'static str {
- "vkCmdWriteTimestamp"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.write_timestamp(self.query_pool.query(self.query).unwrap(), self.stage);
- }
- }
-
- self.append_command(
- Cmd {
- query_pool,
- query,
- stage,
- },
- &[],
- )
- .unwrap();
- }
-
- fn add_descriptor_set_resources(
- &self,
- resources: &mut Vec<(
- KeyTy,
- Option<(
- PipelineMemoryAccess,
- ImageLayout,
- ImageLayout,
- ImageUninitializedSafe,
- )>,
- )>,
- pipeline_layout: &PipelineLayout,
- pipeline_bind_point: PipelineBindPoint,
- ) -> SmallVec<[Arc<dyn Command + Send + Sync>; 12]> {
- let descriptor_sets: SmallVec<[Arc<dyn Command + Send + Sync>; 12]> = (0..pipeline_layout
- .descriptor_set_layouts()
- .len()
- as u32)
- .map(|set_num| self.bindings.descriptor_sets[&pipeline_bind_point][&set_num].clone())
- .collect();
-
- for ds in descriptor_sets
- .iter()
- .enumerate()
- .map(|(set_num, cmd)| cmd.bound_descriptor_set(set_num as u32).0)
- {
- for buf_num in 0..ds.num_buffers() {
- let desc = ds
- .layout()
- .descriptor(ds.buffer(buf_num).unwrap().1 as usize)
- .unwrap();
- let exclusive = !desc.readonly;
- let (stages, access) = desc.pipeline_stages_and_access();
- resources.push((
- KeyTy::Buffer,
- Some((
- PipelineMemoryAccess {
- stages,
- access,
- exclusive,
- },
- ImageLayout::Undefined,
- ImageLayout::Undefined,
- ImageUninitializedSafe::Unsafe,
- )),
- ));
- }
- for img_num in 0..ds.num_images() {
- let (image_view, desc_num) = ds.image(img_num).unwrap();
- let desc = ds.layout().descriptor(desc_num as usize).unwrap();
- let exclusive = !desc.readonly;
- let (stages, access) = desc.pipeline_stages_and_access();
- let mut ignore_me_hack = false;
- let layouts = image_view
- .image()
- .descriptor_layouts()
- .expect("descriptor_layouts must return Some when used in an image view");
- let layout = match desc.ty {
- DescriptorDescTy::CombinedImageSampler(_) => layouts.combined_image_sampler,
- DescriptorDescTy::Image(ref img) => {
- if img.sampled {
- layouts.sampled_image
- } else {
- layouts.storage_image
- }
- }
- DescriptorDescTy::InputAttachment { .. } => {
- // FIXME: This is tricky. Since we read from the input attachment
- // and this input attachment is being written in an earlier pass,
- // vulkano will think that it needs to put a pipeline barrier and will
- // return a `Conflict` error. For now as a work-around we simply ignore
- // input attachments.
- ignore_me_hack = true;
- layouts.input_attachment
- }
- _ => panic!("Tried to bind an image to a non-image descriptor"),
- };
- resources.push((
- KeyTy::Image,
- if ignore_me_hack {
- None
- } else {
- Some((
- PipelineMemoryAccess {
- stages,
- access,
- exclusive,
- },
- layout,
- layout,
- ImageUninitializedSafe::Unsafe,
- ))
- },
- ));
- }
- }
-
- descriptor_sets
- }
-
- fn add_vertex_buffer_resources(
- &self,
- resources: &mut Vec<(
- KeyTy,
- Option<(
- PipelineMemoryAccess,
- ImageLayout,
- ImageLayout,
- ImageUninitializedSafe,
- )>,
- )>,
- vertex_input: &VertexInput,
- ) -> SmallVec<[(u32, Arc<dyn Command + Send + Sync>); 4]> {
- let vertex_buffers: SmallVec<[(u32, Arc<dyn Command + Send + Sync>); 4]> = vertex_input
- .bindings()
- .map(|(binding_num, _)| {
- (
- binding_num,
- self.bindings.vertex_buffers[&binding_num].clone(),
- )
- })
- .collect();
-
- resources.extend(vertex_buffers.iter().map(|_| {
- (
- KeyTy::Buffer,
- Some((
- PipelineMemoryAccess {
- stages: PipelineStages {
- vertex_input: true,
- ..PipelineStages::none()
- },
- access: AccessFlags {
- vertex_attribute_read: true,
- ..AccessFlags::none()
- },
- exclusive: false,
- },
- ImageLayout::Undefined,
- ImageLayout::Undefined,
- ImageUninitializedSafe::Unsafe,
- )),
- )
- }));
-
- vertex_buffers
- }
-
- fn add_index_buffer_resources(
- &self,
- resources: &mut Vec<(
- KeyTy,
- Option<(
- PipelineMemoryAccess,
- ImageLayout,
- ImageLayout,
- ImageUninitializedSafe,
- )>,
- )>,
- ) -> Arc<dyn Command + Send + Sync> {
- let index_buffer = self.bindings.index_buffer.as_ref().unwrap().clone();
-
- resources.push((
- KeyTy::Buffer,
- Some((
- PipelineMemoryAccess {
- stages: PipelineStages {
- vertex_input: true,
- ..PipelineStages::none()
- },
- access: AccessFlags {
- index_read: true,
- ..AccessFlags::none()
- },
- exclusive: false,
- },
- ImageLayout::Undefined,
- ImageLayout::Undefined,
- ImageUninitializedSafe::Unsafe,
- )),
- ));
-
- index_buffer
- }
-
- fn add_indirect_buffer_resources(
- &self,
- resources: &mut Vec<(
- KeyTy,
- Option<(
- PipelineMemoryAccess,
- ImageLayout,
- ImageLayout,
- ImageUninitializedSafe,
- )>,
- )>,
- ) {
- resources.push((
- KeyTy::Buffer,
- Some((
- PipelineMemoryAccess {
- stages: PipelineStages {
- draw_indirect: true,
- ..PipelineStages::none()
- }, // TODO: is draw_indirect correct for dispatch too?
- access: AccessFlags {
- indirect_command_read: true,
- ..AccessFlags::none()
- },
- exclusive: false,
- },
- ImageLayout::Undefined,
- ImageLayout::Undefined,
- ImageUninitializedSafe::Unsafe,
- )),
- ));
- }
-}
-
-pub struct SyncCommandBufferBuilderBindDescriptorSets<'b> {
- builder: &'b mut SyncCommandBufferBuilder,
- descriptor_sets: SmallVec<[DescriptorSetWithOffsets; 12]>,
-}
-
-impl<'b> SyncCommandBufferBuilderBindDescriptorSets<'b> {
- /// Adds a descriptor set to the list.
- #[inline]
- pub fn add<S>(&mut self, descriptor_set: S)
- where
- S: Into<DescriptorSetWithOffsets>,
- {
- self.descriptor_sets.push(descriptor_set.into());
- }
-
- #[inline]
- pub unsafe fn submit(
- self,
- pipeline_bind_point: PipelineBindPoint,
- pipeline_layout: Arc<PipelineLayout>,
- first_binding: u32,
- ) -> Result<(), SyncCommandBufferBuilderError> {
- if self.descriptor_sets.is_empty() {
- return Ok(());
- }
-
- struct Cmd {
- descriptor_sets: SmallVec<[DescriptorSetWithOffsets; 12]>,
- pipeline_bind_point: PipelineBindPoint,
- pipeline_layout: Arc<PipelineLayout>,
- first_binding: u32,
- }
-
- impl Command for Cmd {
- fn name(&self) -> &'static str {
- "vkCmdBindDescriptorSets"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- let descriptor_sets = self.descriptor_sets.iter().map(|x| x.as_ref().0.inner());
- let dynamic_offsets = self
- .descriptor_sets
- .iter()
- .map(|x| x.as_ref().1.iter().copied())
- .flatten();
-
- out.bind_descriptor_sets(
- self.pipeline_bind_point,
- &self.pipeline_layout,
- self.first_binding,
- descriptor_sets,
- dynamic_offsets,
- );
- }
-
- fn bound_descriptor_set(&self, set_num: u32) -> (&dyn DescriptorSet, &[u32]) {
- let index = set_num.checked_sub(self.first_binding).unwrap() as usize;
- self.descriptor_sets[index].as_ref()
- }
- }
-
- let num_descriptor_sets = self.descriptor_sets.len() as u32;
- self.builder.append_command(
- Cmd {
- descriptor_sets: self.descriptor_sets,
- pipeline_bind_point,
- pipeline_layout,
- first_binding,
- },
- &[],
- )?;
-
- let cmd = self.builder.commands.last().unwrap();
- let sets = self
- .builder
- .bindings
- .descriptor_sets
- .entry(pipeline_bind_point)
- .or_default();
- sets.retain(|&set_num, _| set_num < first_binding); // Remove all descriptor sets with a higher number
-
- for i in 0..num_descriptor_sets {
- sets.insert(first_binding + i, cmd.clone());
- }
-
- Ok(())
- }
-}
-
-/// Prototype for a `vkCmdBindVertexBuffers`.
-pub struct SyncCommandBufferBuilderBindVertexBuffer<'a> {
- builder: &'a mut SyncCommandBufferBuilder,
- inner: UnsafeCommandBufferBuilderBindVertexBuffer,
- buffers: SmallVec<[Box<dyn BufferAccess + Send + Sync>; 4]>,
-}
-
-impl<'a> SyncCommandBufferBuilderBindVertexBuffer<'a> {
- /// Adds a buffer to the list.
- #[inline]
- pub fn add<B>(&mut self, buffer: B)
- where
- B: BufferAccess + Send + Sync + 'static,
- {
- self.inner.add(&buffer);
- self.buffers.push(Box::new(buffer));
- }
-
- #[inline]
- pub unsafe fn submit(self, first_binding: u32) -> Result<(), SyncCommandBufferBuilderError> {
- struct Cmd {
- first_binding: u32,
- inner: Mutex<Option<UnsafeCommandBufferBuilderBindVertexBuffer>>,
- buffers: SmallVec<[Box<dyn BufferAccess + Send + Sync>; 4]>,
- }
-
- impl Command for Cmd {
- fn name(&self) -> &'static str {
- "vkCmdBindVertexBuffers"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- out.bind_vertex_buffers(
- self.first_binding,
- self.inner.lock().unwrap().take().unwrap(),
- );
- }
-
- fn bound_vertex_buffer(&self, binding_num: u32) -> &dyn BufferAccess {
- let index = binding_num.checked_sub(self.first_binding).unwrap() as usize;
- &self.buffers[index]
- }
- }
-
- let num_buffers = self.buffers.len() as u32;
- self.builder.append_command(
- Cmd {
- first_binding,
- inner: Mutex::new(Some(self.inner)),
- buffers: self.buffers,
- },
- &[],
- )?;
-
- let cmd = self.builder.commands.last().unwrap();
- for i in 0..num_buffers {
- self.builder
- .bindings
- .vertex_buffers
- .insert(first_binding + i, cmd.clone());
- }
-
- Ok(())
- }
-}
-
-/// Prototype for a `vkCmdExecuteCommands`.
-pub struct SyncCommandBufferBuilderExecuteCommands<'a> {
- builder: &'a mut SyncCommandBufferBuilder,
- inner: Vec<Box<dyn SecondaryCommandBuffer + Send + Sync>>,
-}
-
-impl<'a> SyncCommandBufferBuilderExecuteCommands<'a> {
- /// Adds a command buffer to the list.
- #[inline]
- pub fn add<C>(&mut self, command_buffer: C)
- where
- C: SecondaryCommandBuffer + Send + Sync + 'static,
- {
- self.inner.push(Box::new(command_buffer));
- }
-
- #[inline]
- pub unsafe fn submit(self) -> Result<(), SyncCommandBufferBuilderError> {
- struct DropUnlock(Box<dyn SecondaryCommandBuffer + Send + Sync>);
- impl std::ops::Deref for DropUnlock {
- type Target = Box<dyn SecondaryCommandBuffer + Send + Sync>;
-
- fn deref(&self) -> &Self::Target {
- &self.0
- }
- }
- unsafe impl SafeDeref for DropUnlock {}
-
- impl Drop for DropUnlock {
- fn drop(&mut self) {
- unsafe {
- self.unlock();
- }
- }
- }
-
- struct Cmd(Vec<DropUnlock>);
-
- impl Command for Cmd {
- fn name(&self) -> &'static str {
- "vkCmdExecuteCommands"
- }
-
- unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
- let mut execute = UnsafeCommandBufferBuilderExecuteCommands::new();
- self.0
- .iter()
- .for_each(|cbuf| execute.add_raw(cbuf.inner().internal_object()));
- out.execute_commands(execute);
- }
-
- fn buffer(&self, mut num: usize) -> &dyn BufferAccess {
- for cbuf in self.0.iter() {
- if let Some(buf) = cbuf.buffer(num) {
- return buf.0;
- }
- num -= cbuf.num_buffers();
- }
- panic!()
- }
-
- fn buffer_name(&self, mut num: usize) -> Cow<'static, str> {
- for (cbuf_num, cbuf) in self.0.iter().enumerate() {
- if let Some(buf) = cbuf.buffer(num) {
- return format!("Buffer bound to secondary command buffer {}", cbuf_num)
- .into();
- }
- num -= cbuf.num_buffers();
- }
- panic!()
- }
-
- fn image(&self, mut num: usize) -> &dyn ImageAccess {
- for cbuf in self.0.iter() {
- if let Some(img) = cbuf.image(num) {
- return img.0;
- }
- num -= cbuf.num_images();
- }
- panic!()
- }
-
- fn image_name(&self, mut num: usize) -> Cow<'static, str> {
- for (cbuf_num, cbuf) in self.0.iter().enumerate() {
- if let Some(img) = cbuf.image(num) {
- return format!("Image bound to secondary command buffer {}", cbuf_num)
- .into();
- }
- num -= cbuf.num_images();
- }
- panic!()
- }
- }
-
- let resources = {
- let mut resources = Vec::new();
- for cbuf in self.inner.iter() {
- for buf_num in 0..cbuf.num_buffers() {
- resources.push((
- KeyTy::Buffer,
- Some((
- cbuf.buffer(buf_num).unwrap().1,
- ImageLayout::Undefined,
- ImageLayout::Undefined,
- ImageUninitializedSafe::Unsafe,
- )),
- ));
- }
- for img_num in 0..cbuf.num_images() {
- let (_, memory, start_layout, end_layout, image_uninitialized_safe) =
- cbuf.image(img_num).unwrap();
- resources.push((
- KeyTy::Image,
- Some((memory, start_layout, end_layout, image_uninitialized_safe)),
- ));
- }
- }
- resources
- };
-
- self.builder.append_command(
- Cmd(self
- .inner
- .into_iter()
- .map(|cbuf| {
- cbuf.lock_record()?;
- Ok(DropUnlock(cbuf))
- })
- .collect::<Result<Vec<_>, CommandBufferExecError>>()?),
- &resources,
- )?;
-
- Ok(())
- }
-}
diff --git a/src/command_buffer/synced/mod.rs b/src/command_buffer/synced/mod.rs
index 4c65dda..e13000a 100644
--- a/src/command_buffer/synced/mod.rs
+++ b/src/command_buffer/synced/mod.rs
@@ -64,33 +64,28 @@
//! queue. If not possible, the queue will be entirely flushed and the command added to a fresh new
//! queue with a fresh new barrier prototype.
-pub use self::builder::SyncCommandBufferBuilder;
-pub use self::builder::SyncCommandBufferBuilderBindDescriptorSets;
-pub use self::builder::SyncCommandBufferBuilderBindVertexBuffer;
-pub use self::builder::SyncCommandBufferBuilderError;
-pub use self::builder::SyncCommandBufferBuilderExecuteCommands;
-use crate::buffer::BufferAccess;
-use crate::command_buffer::sys::UnsafeCommandBuffer;
-use crate::command_buffer::sys::UnsafeCommandBufferBuilder;
-use crate::command_buffer::CommandBufferExecError;
-use crate::command_buffer::ImageUninitializedSafe;
-use crate::descriptor_set::DescriptorSet;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::device::Queue;
-use crate::image::ImageAccess;
-use crate::image::ImageLayout;
-use crate::pipeline::{ComputePipelineAbstract, GraphicsPipelineAbstract};
-use crate::sync::AccessCheckError;
-use crate::sync::AccessError;
-use crate::sync::AccessFlags;
-use crate::sync::GpuFuture;
-use crate::sync::PipelineMemoryAccess;
-use crate::sync::PipelineStages;
-use fnv::FnvHashMap;
-use std::borrow::Cow;
-use std::ops::Range;
-use std::sync::Arc;
+pub use self::builder::{
+ CommandBufferBuilderState, SetOrPush, StencilOpStateDynamic, StencilStateDynamic,
+ SyncCommandBufferBuilder, SyncCommandBufferBuilderBindDescriptorSets,
+ SyncCommandBufferBuilderBindVertexBuffer, SyncCommandBufferBuilderError,
+ SyncCommandBufferBuilderExecuteCommands,
+};
+use super::{
+ sys::{UnsafeCommandBuffer, UnsafeCommandBufferBuilder},
+ CommandBufferResourcesUsage, SecondaryCommandBufferResourcesUsage,
+};
+use crate::{
+ buffer::Subbuffer,
+ device::{Device, DeviceOwned},
+ image::{ImageAccess, ImageLayout, ImageSubresourceRange},
+ sync::PipelineMemoryAccess,
+ DeviceSize,
+};
+use std::{
+ fmt::{Debug, Error as FmtError, Formatter},
+ ops::Range,
+ sync::Arc,
+};
mod builder;
@@ -102,282 +97,28 @@ pub struct SyncCommandBuffer {
// List of commands used by the command buffer. Used to hold the various resources that are
// being used.
- commands: Vec<Arc<dyn Command + Send + Sync>>,
+ _commands: Vec<Box<dyn Command>>,
// Locations within commands that pipeline barriers were inserted. For debugging purposes.
// TODO: present only in cfg(debug_assertions)?
- barriers: Vec<usize>,
+ _barriers: Vec<usize>,
- // State of all the resources used by this command buffer.
- resources: FnvHashMap<ResourceKey, ResourceFinalState>,
+ // Resources accessed by this command buffer.
+ resources_usage: CommandBufferResourcesUsage,
// Resources and their accesses. Used for executing secondary command buffers in a primary.
- buffers: Vec<(ResourceLocation, PipelineMemoryAccess)>,
- images: Vec<(
- ResourceLocation,
- PipelineMemoryAccess,
- ImageLayout,
- ImageLayout,
- ImageUninitializedSafe,
- )>,
+ secondary_resources_usage: SecondaryCommandBufferResourcesUsage,
}
impl SyncCommandBuffer {
- /// Tries to lock the resources used by the command buffer.
- ///
- /// > **Note**: You should call this in the implementation of the `CommandBuffer` trait.
- pub fn lock_submit(
- &self,
- future: &dyn GpuFuture,
- queue: &Queue,
- ) -> Result<(), CommandBufferExecError> {
- // Number of resources in `self.resources` that have been successfully locked.
- let mut locked_resources = 0;
- // Final return value of this function.
- let mut ret_value = Ok(());
-
- // Try locking resources. Updates `locked_resources` and `ret_value`, and break if an error
- // happens.
- for (key, state) in self.resources.iter() {
- let command = &self.commands[state.command_ids[0]];
-
- match key {
- ResourceKey::Buffer(..) => {
- let buf = command.buffer(state.resource_index);
-
- // Because try_gpu_lock needs to be called first,
- // this should never return Ok without first returning Err
- let prev_err = match future.check_buffer_access(&buf, state.exclusive, queue) {
- Ok(_) => {
- unsafe {
- buf.increase_gpu_lock();
- }
- locked_resources += 1;
- continue;
- }
- Err(err) => err,
- };
-
- match (buf.try_gpu_lock(state.exclusive, queue), prev_err) {
- (Ok(_), _) => (),
- (Err(err), AccessCheckError::Unknown)
- | (_, AccessCheckError::Denied(err)) => {
- ret_value = Err(CommandBufferExecError::AccessError {
- error: err,
- command_name: command.name().into(),
- command_param: command.buffer_name(state.resource_index),
- command_offset: state.command_ids[0],
- });
- break;
- }
- };
- }
-
- ResourceKey::Image(..) => {
- let img = command.image(state.resource_index);
-
- let prev_err = match future.check_image_access(
- img,
- state.initial_layout,
- state.exclusive,
- queue,
- ) {
- Ok(_) => {
- unsafe {
- img.increase_gpu_lock();
- }
- locked_resources += 1;
- continue;
- }
- Err(err) => err,
- };
-
- match (
- img.try_gpu_lock(
- state.exclusive,
- state.image_uninitialized_safe.is_safe(),
- state.initial_layout,
- ),
- prev_err,
- ) {
- (Ok(_), _) => (),
- (Err(err), AccessCheckError::Unknown)
- | (_, AccessCheckError::Denied(err)) => {
- ret_value = Err(CommandBufferExecError::AccessError {
- error: err,
- command_name: command.name().into(),
- command_param: command.image_name(state.resource_index),
- command_offset: state.command_ids[0],
- });
- break;
- }
- };
- }
- }
-
- locked_resources += 1;
- }
-
- // If we are going to return an error, we have to unlock all the resources we locked above.
- if let Err(_) = ret_value {
- for (key, state) in self.resources.iter().take(locked_resources) {
- let command = &self.commands[state.command_ids[0]];
-
- match key {
- ResourceKey::Buffer(..) => {
- let buf = command.buffer(state.resource_index);
- unsafe {
- buf.unlock();
- }
- }
-
- ResourceKey::Image(..) => {
- let command = &self.commands[state.command_ids[0]];
- let img = command.image(state.resource_index);
- let trans = if state.final_layout != state.initial_layout {
- Some(state.final_layout)
- } else {
- None
- };
- unsafe {
- img.unlock(trans);
- }
- }
- }
- }
- }
-
- // TODO: pipeline barriers if necessary?
-
- ret_value
- }
-
- /// Unlocks the resources used by the command buffer.
- ///
- /// > **Note**: You should call this in the implementation of the `CommandBuffer` trait.
- ///
- /// # Safety
- ///
- /// The command buffer must have been successfully locked with `lock_submit()`.
- ///
- pub unsafe fn unlock(&self) {
- for (key, state) in self.resources.iter() {
- let command = &self.commands[state.command_ids[0]];
-
- match key {
- ResourceKey::Buffer(..) => {
- let buf = command.buffer(state.resource_index);
- buf.unlock();
- }
-
- ResourceKey::Image(..) => {
- let img = command.image(state.resource_index);
- let trans = if state.final_layout != state.initial_layout {
- Some(state.final_layout)
- } else {
- None
- };
- img.unlock(trans);
- }
- }
- }
- }
-
- /// Checks whether this command buffer has access to a buffer.
- ///
- /// > **Note**: Suitable when implementing the `CommandBuffer` trait.
- #[inline]
- pub fn check_buffer_access(
- &self,
- buffer: &dyn BufferAccess,
- exclusive: bool,
- queue: &Queue,
- ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
- // TODO: check the queue family
- if let Some(value) = self.resources.get(&buffer.into()) {
- if !value.exclusive && exclusive {
- return Err(AccessCheckError::Unknown);
- }
-
- return Ok(Some((value.final_stages, value.final_access)));
- }
-
- Err(AccessCheckError::Unknown)
- }
-
- /// Checks whether this command buffer has access to an image.
- ///
- /// > **Note**: Suitable when implementing the `CommandBuffer` trait.
- #[inline]
- pub fn check_image_access(
- &self,
- image: &dyn ImageAccess,
- layout: ImageLayout,
- exclusive: bool,
- queue: &Queue,
- ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
- // TODO: check the queue family
- if let Some(value) = self.resources.get(&image.into()) {
- if layout != ImageLayout::Undefined && value.final_layout != layout {
- return Err(AccessCheckError::Denied(
- AccessError::UnexpectedImageLayout {
- allowed: value.final_layout,
- requested: layout,
- },
- ));
- }
-
- if !value.exclusive && exclusive {
- return Err(AccessCheckError::Unknown);
- }
-
- return Ok(Some((value.final_stages, value.final_access)));
- }
-
- Err(AccessCheckError::Unknown)
- }
-
- #[inline]
- pub fn num_buffers(&self) -> usize {
- self.buffers.len()
- }
-
#[inline]
- pub fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, PipelineMemoryAccess)> {
- self.buffers.get(index).map(|(location, memory)| {
- let cmd = &self.commands[location.command_id];
- (cmd.buffer(location.resource_index), *memory)
- })
+ pub(super) fn resources_usage(&self) -> &CommandBufferResourcesUsage {
+ &self.resources_usage
}
#[inline]
- pub fn num_images(&self) -> usize {
- self.images.len()
- }
-
- #[inline]
- pub fn image(
- &self,
- index: usize,
- ) -> Option<(
- &dyn ImageAccess,
- PipelineMemoryAccess,
- ImageLayout,
- ImageLayout,
- ImageUninitializedSafe,
- )> {
- self.images.get(index).map(
- |(location, memory, start_layout, end_layout, image_uninitialized_safe)| {
- let cmd = &self.commands[location.command_id];
- (
- cmd.image(location.resource_index),
- *memory,
- *start_layout,
- *end_layout,
- *image_uninitialized_safe,
- )
- },
- )
+ pub(super) fn secondary_resources_usage(&self) -> &SecondaryCommandBufferResourcesUsage {
+ &self.secondary_resources_usage
}
}
@@ -395,188 +136,88 @@ unsafe impl DeviceOwned for SyncCommandBuffer {
}
}
-// Key that identifies a resource. Implements `PartialEq`, `Eq` and `Hash` so that two resources
-// that conflict with each other compare equal.
-#[derive(Debug, PartialEq, Eq, Hash)]
-enum ResourceKey {
- Buffer((u64, u64)),
- Image(u64, Range<u32>, Range<u32>),
-}
-
-impl From<&dyn BufferAccess> for ResourceKey {
- #[inline]
- fn from(buffer: &dyn BufferAccess) -> Self {
- Self::Buffer(buffer.conflict_key())
- }
-}
-
-impl From<&dyn ImageAccess> for ResourceKey {
- #[inline]
- fn from(image: &dyn ImageAccess) -> Self {
- Self::Image(
- image.conflict_key(),
- image.current_miplevels_access(),
- image.current_layer_levels_access(),
- )
- }
-}
-
-// Usage of a resource in a finished command buffer.
-#[derive(Debug, Clone)]
-struct ResourceFinalState {
- // Indices of the commands that contain the resource.
- command_ids: Vec<usize>,
-
- // Index of the resource within the first command in `command_ids`.
- resource_index: usize,
-
- // Stages of the last command that uses the resource.
- final_stages: PipelineStages,
- // Access for the last command that uses the resource.
- final_access: AccessFlags,
-
- // True if the resource is used in exclusive mode.
- exclusive: bool,
-
- // Layout that an image must be in at the start of the command buffer. Can be `Undefined` if we
- // don't care.
- initial_layout: ImageLayout,
-
- // Layout the image will be in at the end of the command buffer.
- final_layout: ImageLayout, // TODO: maybe wrap in an Option to mean that the layout doesn't change? because of buffers?
-
- image_uninitialized_safe: ImageUninitializedSafe,
-}
-
-// Identifies a resource within the list of commands.
-#[derive(Clone, Copy, Debug)]
-struct ResourceLocation {
- // Index of the command that holds the resource.
- command_id: usize,
- // Index of the resource within the command.
- resource_index: usize,
+/// Type of resource whose state is to be tracked.
+#[derive(Clone)]
+pub(super) enum Resource {
+ Buffer {
+ buffer: Subbuffer<[u8]>,
+ range: Range<DeviceSize>,
+ memory: PipelineMemoryAccess,
+ },
+ Image {
+ image: Arc<dyn ImageAccess>,
+ subresource_range: ImageSubresourceRange,
+ memory: PipelineMemoryAccess,
+ start_layout: ImageLayout,
+ end_layout: ImageLayout,
+ },
}
// Trait for single commands within the list of commands.
-trait Command {
+pub(super) trait Command: Send + Sync {
// Returns a user-friendly name for the command, for error reporting purposes.
fn name(&self) -> &'static str;
// Sends the command to the `UnsafeCommandBufferBuilder`. Calling this method twice on the same
// object will likely lead to a panic.
unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder);
-
- // Gives access to the `num`th buffer used by the command.
- fn buffer(&self, _num: usize) -> &dyn BufferAccess {
- panic!()
- }
-
- // Gives access to the `num`th image used by the command.
- fn image(&self, _num: usize) -> &dyn ImageAccess {
- panic!()
- }
-
- // Returns a user-friendly name for the `num`th buffer used by the command, for error
- // reporting purposes.
- fn buffer_name(&self, _num: usize) -> Cow<'static, str> {
- panic!()
- }
-
- // Returns a user-friendly name for the `num`th image used by the command, for error
- // reporting purposes.
- fn image_name(&self, _num: usize) -> Cow<'static, str> {
- panic!()
- }
-
- fn bound_descriptor_set(&self, set_num: u32) -> (&dyn DescriptorSet, &[u32]) {
- panic!()
- }
-
- fn bound_index_buffer(&self) -> &dyn BufferAccess {
- panic!()
- }
-
- fn bound_pipeline_compute(&self) -> &dyn ComputePipelineAbstract {
- panic!()
- }
-
- fn bound_pipeline_graphics(&self) -> &dyn GraphicsPipelineAbstract {
- panic!()
- }
-
- fn bound_vertex_buffer(&self, binding_num: u32) -> &dyn BufferAccess {
- panic!()
- }
}
-impl std::fmt::Debug for dyn Command + Send + Sync {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+impl Debug for dyn Command {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
f.write_str(self.name())
}
}
#[cfg(test)]
mod tests {
- use super::SyncCommandBufferBuilder;
- use super::SyncCommandBufferBuilderError;
- use crate::buffer::BufferUsage;
- use crate::buffer::CpuAccessibleBuffer;
- use crate::buffer::ImmutableBuffer;
- use crate::command_buffer::pool::CommandPool;
- use crate::command_buffer::pool::CommandPoolBuilderAlloc;
- use crate::command_buffer::AutoCommandBufferBuilder;
- use crate::command_buffer::CommandBufferLevel;
- use crate::command_buffer::CommandBufferUsage;
- use crate::descriptor_set::layout::DescriptorDesc;
- use crate::descriptor_set::layout::DescriptorDescTy;
- use crate::descriptor_set::layout::DescriptorSetLayout;
- use crate::descriptor_set::PersistentDescriptorSet;
- use crate::device::Device;
- use crate::pipeline::layout::PipelineLayout;
- use crate::pipeline::shader::ShaderStages;
- use crate::pipeline::PipelineBindPoint;
- use crate::sampler::Sampler;
- use crate::sync::GpuFuture;
- use std::sync::Arc;
+ use super::*;
+ use crate::{
+ buffer::{Buffer, BufferCreateInfo, BufferUsage},
+ command_buffer::{
+ allocator::{
+ CommandBufferAllocator, CommandBufferBuilderAlloc, StandardCommandBufferAllocator,
+ },
+ sys::CommandBufferBeginInfo,
+ AutoCommandBufferBuilder, CommandBufferLevel, CommandBufferUsage,
+ PrimaryCommandBufferAbstract,
+ },
+ descriptor_set::{
+ allocator::StandardDescriptorSetAllocator,
+ layout::{
+ DescriptorSetLayout, DescriptorSetLayoutBinding, DescriptorSetLayoutCreateInfo,
+ DescriptorType,
+ },
+ PersistentDescriptorSet, WriteDescriptorSet,
+ },
+ memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
+ pipeline::{layout::PipelineLayoutCreateInfo, PipelineBindPoint, PipelineLayout},
+ sampler::{Sampler, SamplerCreateInfo},
+ shader::ShaderStages,
+ sync::GpuFuture,
+ };
#[test]
fn basic_creation() {
unsafe {
let (device, queue) = gfx_dev_and_queue!();
- let pool = Device::standard_command_pool(&device, queue.family());
- let pool_builder_alloc = pool.alloc(false, 1).unwrap().next().unwrap();
-
- assert!(matches!(
- SyncCommandBufferBuilder::new(
- &pool_builder_alloc.inner(),
- CommandBufferLevel::primary(),
- CommandBufferUsage::MultipleSubmit,
- ),
- Ok(_)
- ));
- }
- }
- #[test]
- fn basic_conflict() {
- unsafe {
- let (device, queue) = gfx_dev_and_queue!();
+ let allocator = StandardCommandBufferAllocator::new(device, Default::default());
- let pool = Device::standard_command_pool(&device, queue.family());
- let pool_builder_alloc = pool.alloc(false, 1).unwrap().next().unwrap();
- let mut sync = SyncCommandBufferBuilder::new(
- &pool_builder_alloc.inner(),
- CommandBufferLevel::primary(),
- CommandBufferUsage::MultipleSubmit,
+ let builder_alloc = allocator
+ .allocate(queue.queue_family_index(), CommandBufferLevel::Primary, 1)
+ .unwrap()
+ .next()
+ .unwrap();
+
+ SyncCommandBufferBuilder::new(
+ builder_alloc.inner(),
+ CommandBufferBeginInfo {
+ usage: CommandBufferUsage::MultipleSubmit,
+ ..Default::default()
+ },
)
.unwrap();
- let buf =
- CpuAccessibleBuffer::from_data(device, BufferUsage::all(), false, 0u32).unwrap();
-
- assert!(matches!(
- sync.copy_buffer(buf.clone(), buf.clone(), std::iter::once((0, 0, 4))),
- Err(SyncCommandBufferBuilderError::Conflict { .. })
- ));
}
}
@@ -585,14 +226,35 @@ mod tests {
unsafe {
let (device, queue) = gfx_dev_and_queue!();
+ let cb_allocator =
+ StandardCommandBufferAllocator::new(device.clone(), Default::default());
+ let cbb = AutoCommandBufferBuilder::primary(
+ &cb_allocator,
+ queue.queue_family_index(),
+ CommandBufferUsage::OneTimeSubmit,
+ )
+ .unwrap();
+
+ let memory_allocator = StandardMemoryAllocator::new_default(device);
// Create a tiny test buffer
- let (buf, future) = ImmutableBuffer::from_data(
+ let buffer = Buffer::from_data(
+ &memory_allocator,
+ BufferCreateInfo {
+ usage: BufferUsage::TRANSFER_DST,
+ ..Default::default()
+ },
+ AllocationCreateInfo {
+ usage: MemoryUsage::Upload,
+ ..Default::default()
+ },
0u32,
- BufferUsage::transfer_destination(),
- queue.clone(),
)
.unwrap();
- future
+
+ cbb.build()
+ .unwrap()
+ .execute(queue.clone())
+ .unwrap()
.then_signal_fence_and_flush()
.unwrap()
.wait(None)
@@ -601,25 +263,32 @@ mod tests {
// Two secondary command buffers that both write to the buffer
let secondary = (0..2)
.map(|_| {
- let mut builder = AutoCommandBufferBuilder::secondary_compute(
- device.clone(),
- queue.family(),
+ let mut builder = AutoCommandBufferBuilder::secondary(
+ &cb_allocator,
+ queue.queue_family_index(),
CommandBufferUsage::SimultaneousUse,
+ Default::default(),
)
.unwrap();
- builder.fill_buffer(buf.clone(), 42u32).unwrap();
+ builder
+ .fill_buffer(buffer.clone().into_slice(), 42)
+ .unwrap();
Arc::new(builder.build().unwrap())
})
.collect::<Vec<_>>();
- let pool = Device::standard_command_pool(&device, queue.family());
- let allocs = pool.alloc(false, 2).unwrap().collect::<Vec<_>>();
+ let allocs = cb_allocator
+ .allocate(queue.queue_family_index(), CommandBufferLevel::Primary, 2)
+ .unwrap()
+ .collect::<Vec<_>>();
{
let mut builder = SyncCommandBufferBuilder::new(
allocs[0].inner(),
- CommandBufferLevel::primary(),
- CommandBufferUsage::SimultaneousUse,
+ CommandBufferBeginInfo {
+ usage: CommandBufferUsage::SimultaneousUse,
+ ..Default::default()
+ },
)
.unwrap();
@@ -632,21 +301,23 @@ mod tests {
let primary = builder.build().unwrap();
let names = primary
- .commands
+ ._commands
.iter()
.map(|c| c.name())
.collect::<Vec<_>>();
// Ensure that the builder added a barrier between the two writes
- assert_eq!(&names, &["vkCmdExecuteCommands", "vkCmdExecuteCommands"]);
- assert_eq!(&primary.barriers, &[0, 1]);
+ assert_eq!(&names, &["execute_commands", "execute_commands"]);
+ assert_eq!(&primary._barriers, &[0, 1]);
}
{
let mut builder = SyncCommandBufferBuilder::new(
allocs[1].inner(),
- CommandBufferLevel::primary(),
- CommandBufferUsage::SimultaneousUse,
+ CommandBufferBeginInfo {
+ usage: CommandBufferUsage::SimultaneousUse,
+ ..Default::default()
+ },
)
.unwrap();
@@ -655,15 +326,7 @@ mod tests {
secondary.into_iter().for_each(|secondary| {
ec.add(secondary);
});
-
- // The two writes can't be split up by a barrier because they are part of the same
- // command. Therefore an error.
- // TODO: Would be nice if SyncCommandBufferBuilder would split the commands
- // automatically in order to insert a barrier.
- assert!(matches!(
- ec.submit(),
- Err(SyncCommandBufferBuilderError::Conflict { .. })
- ));
+ ec.submit().unwrap();
}
}
}
@@ -673,23 +336,43 @@ mod tests {
unsafe {
let (device, queue) = gfx_dev_and_queue!();
- let pool = Device::standard_command_pool(&device, queue.family());
- let pool_builder_alloc = pool.alloc(false, 1).unwrap().next().unwrap();
+ let cb_allocator =
+ StandardCommandBufferAllocator::new(device.clone(), Default::default());
+ let builder_alloc = cb_allocator
+ .allocate(queue.queue_family_index(), CommandBufferLevel::Primary, 1)
+ .unwrap()
+ .next()
+ .unwrap();
let mut sync = SyncCommandBufferBuilder::new(
- &pool_builder_alloc.inner(),
- CommandBufferLevel::primary(),
- CommandBufferUsage::MultipleSubmit,
+ builder_alloc.inner(),
+ CommandBufferBeginInfo {
+ usage: CommandBufferUsage::MultipleSubmit,
+ ..Default::default()
+ },
+ )
+ .unwrap();
+
+ let memory_allocator = StandardMemoryAllocator::new_default(device);
+ let buf = Buffer::from_data(
+ &memory_allocator,
+ BufferCreateInfo {
+ usage: BufferUsage::VERTEX_BUFFER,
+ ..Default::default()
+ },
+ AllocationCreateInfo {
+ usage: MemoryUsage::Upload,
+ ..Default::default()
+ },
+ 0u32,
)
.unwrap();
- let buf =
- CpuAccessibleBuffer::from_data(device, BufferUsage::all(), false, 0u32).unwrap();
let mut buf_builder = sync.bind_vertex_buffers();
- buf_builder.add(buf);
- buf_builder.submit(1).unwrap();
+ buf_builder.add(buf.into_bytes());
+ buf_builder.submit(1);
- assert!(sync.bound_vertex_buffer(0).is_none());
- assert!(sync.bound_vertex_buffer(1).is_some());
- assert!(sync.bound_vertex_buffer(2).is_none());
+ assert!(sync.state().vertex_buffer(0).is_none());
+ assert!(sync.state().vertex_buffer(1).is_some());
+ assert!(sync.state().vertex_buffer(2).is_none());
}
}
@@ -698,69 +381,127 @@ mod tests {
unsafe {
let (device, queue) = gfx_dev_and_queue!();
- let pool = Device::standard_command_pool(&device, queue.family());
- let pool_builder_alloc = pool.alloc(false, 1).unwrap().next().unwrap();
+ let cb_allocator =
+ StandardCommandBufferAllocator::new(device.clone(), Default::default());
+ let builder_alloc = cb_allocator
+ .allocate(queue.queue_family_index(), CommandBufferLevel::Primary, 1)
+ .unwrap()
+ .next()
+ .unwrap();
let mut sync = SyncCommandBufferBuilder::new(
- &pool_builder_alloc.inner(),
- CommandBufferLevel::primary(),
- CommandBufferUsage::MultipleSubmit,
+ builder_alloc.inner(),
+ CommandBufferBeginInfo {
+ usage: CommandBufferUsage::MultipleSubmit,
+ ..Default::default()
+ },
+ )
+ .unwrap();
+ let set_layout = DescriptorSetLayout::new(
+ device.clone(),
+ DescriptorSetLayoutCreateInfo {
+ bindings: [(
+ 0,
+ DescriptorSetLayoutBinding {
+ stages: ShaderStages::all_graphics(),
+ ..DescriptorSetLayoutBinding::descriptor_type(DescriptorType::Sampler)
+ },
+ )]
+ .into(),
+ ..Default::default()
+ },
+ )
+ .unwrap();
+ let pipeline_layout = PipelineLayout::new(
+ device.clone(),
+ PipelineLayoutCreateInfo {
+ set_layouts: [set_layout.clone(), set_layout.clone()].into(),
+ ..Default::default()
+ },
+ )
+ .unwrap();
+
+ let ds_allocator = StandardDescriptorSetAllocator::new(device.clone());
+
+ let set = PersistentDescriptorSet::new(
+ &ds_allocator,
+ set_layout.clone(),
+ [WriteDescriptorSet::sampler(
+ 0,
+ Sampler::new(device.clone(), SamplerCreateInfo::simple_repeat_linear())
+ .unwrap(),
+ )],
)
.unwrap();
- let set_layout = Arc::new(
- DescriptorSetLayout::new(
- device.clone(),
- [Some(DescriptorDesc {
- ty: DescriptorDescTy::Sampler,
- array_count: 1,
- stages: ShaderStages::all(),
- readonly: true,
- })],
- )
- .unwrap(),
- );
- let pipeline_layout = Arc::new(
- PipelineLayout::new(device.clone(), [set_layout.clone(), set_layout.clone()], [])
- .unwrap(),
- );
- let set = Arc::new(
- PersistentDescriptorSet::start(set_layout)
- .add_sampler(Sampler::simple_repeat_linear(device))
- .unwrap()
- .build()
- .unwrap(),
- );
let mut set_builder = sync.bind_descriptor_sets();
set_builder.add(set.clone());
- set_builder
- .submit(PipelineBindPoint::Graphics, pipeline_layout.clone(), 1)
- .unwrap();
+ set_builder.submit(PipelineBindPoint::Graphics, pipeline_layout.clone(), 1);
assert!(sync
- .bound_descriptor_set(PipelineBindPoint::Compute, 0)
+ .state()
+ .descriptor_set(PipelineBindPoint::Compute, 0)
.is_none());
assert!(sync
- .bound_descriptor_set(PipelineBindPoint::Graphics, 0)
+ .state()
+ .descriptor_set(PipelineBindPoint::Graphics, 0)
.is_none());
assert!(sync
- .bound_descriptor_set(PipelineBindPoint::Graphics, 1)
+ .state()
+ .descriptor_set(PipelineBindPoint::Graphics, 1)
.is_some());
assert!(sync
- .bound_descriptor_set(PipelineBindPoint::Graphics, 2)
+ .state()
+ .descriptor_set(PipelineBindPoint::Graphics, 2)
.is_none());
let mut set_builder = sync.bind_descriptor_sets();
set_builder.add(set);
- set_builder
- .submit(PipelineBindPoint::Graphics, pipeline_layout, 0)
- .unwrap();
+ set_builder.submit(PipelineBindPoint::Graphics, pipeline_layout, 0);
assert!(sync
- .bound_descriptor_set(PipelineBindPoint::Graphics, 0)
+ .state()
+ .descriptor_set(PipelineBindPoint::Graphics, 0)
+ .is_some());
+ assert!(sync
+ .state()
+ .descriptor_set(PipelineBindPoint::Graphics, 1)
.is_some());
+
+ let pipeline_layout = PipelineLayout::new(
+ device.clone(),
+ PipelineLayoutCreateInfo {
+ set_layouts: [
+ DescriptorSetLayout::new(device.clone(), Default::default()).unwrap(),
+ set_layout.clone(),
+ ]
+ .into(),
+ ..Default::default()
+ },
+ )
+ .unwrap();
+
+ let set = PersistentDescriptorSet::new(
+ &ds_allocator,
+ set_layout,
+ [WriteDescriptorSet::sampler(
+ 0,
+ Sampler::new(device, SamplerCreateInfo::simple_repeat_linear()).unwrap(),
+ )],
+ )
+ .unwrap();
+
+ let mut set_builder = sync.bind_descriptor_sets();
+ set_builder.add(set);
+ set_builder.submit(PipelineBindPoint::Graphics, pipeline_layout, 1);
+
assert!(sync
- .bound_descriptor_set(PipelineBindPoint::Graphics, 1)
+ .state()
+ .descriptor_set(PipelineBindPoint::Graphics, 0)
.is_none());
+ assert!(sync
+ .state()
+ .descriptor_set(PipelineBindPoint::Graphics, 1)
+ .is_some());
}
}
}
diff --git a/src/command_buffer/synced/tests.rs b/src/command_buffer/synced/tests.rs
deleted file mode 100644
index d40654b..0000000
--- a/src/command_buffer/synced/tests.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::buffer::BufferUsage;
-use crate::buffer::CpuAccessibleBuffer;
-use crate::command_buffer::pool::CommandPool;
-use crate::command_buffer::pool::CommandPoolBuilderAlloc;
-use crate::command_buffer::synced::base::SyncCommandBufferBuilder;
-use crate::command_buffer::synced::base::SyncCommandBufferBuilderError;
-use crate::command_buffer::sys::Flags;
-use crate::command_buffer::Kind;
-use crate::device::Device;
-use std::iter;
-
-#[test]
-fn basic_creation() {
- unsafe {
- let (device, queue) = gfx_dev_and_queue!();
- let pool = Device::standard_command_pool(&device, queue.family());
- let pool_builder_alloc = pool.alloc(false, 1).unwrap().next().unwrap();
- SyncCommandBufferBuilder::new(&pool_builder_alloc.inner(), Kind::primary(), Flags::None)
- .unwrap();
- }
-}
-
-#[test]
-fn basic_conflict() {
- unsafe {
- let (device, queue) = gfx_dev_and_queue!();
-
- let pool = Device::standard_command_pool(&device, queue.family());
- let pool_builder_alloc = pool.alloc(false, 1).unwrap().next().unwrap();
- let mut sync = SyncCommandBufferBuilder::new(
- &pool_builder_alloc.inner(),
- Kind::primary(),
- Flags::None,
- )
- .unwrap();
- let buf = CpuAccessibleBuffer::from_data(device, BufferUsage::all(), false, 0u32).unwrap();
-
- match sync.copy_buffer(buf.clone(), buf.clone(), iter::once((0, 0, 4))) {
- Err(SyncCommandBufferBuilderError::Conflict { .. }) => (),
- _ => panic!(),
- };
- }
-}
diff --git a/src/command_buffer/sys.rs b/src/command_buffer/sys.rs
index 0fb8b58..b0ac663 100644
--- a/src/command_buffer/sys.rs
+++ b/src/command_buffer/sys.rs
@@ -7,82 +7,42 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use crate::buffer::BufferAccess;
-use crate::buffer::BufferInner;
-use crate::buffer::TypedBufferAccess;
-use crate::check_errors;
-use crate::command_buffer::pool::UnsafeCommandPoolAlloc;
-use crate::command_buffer::CommandBufferInheritance;
-use crate::command_buffer::CommandBufferLevel;
-use crate::command_buffer::CommandBufferUsage;
-use crate::command_buffer::SecondaryCommandBuffer;
-use crate::command_buffer::SubpassContents;
-use crate::descriptor_set::sys::UnsafeDescriptorSet;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::format::ClearValue;
-use crate::format::FormatTy;
-use crate::image::ImageAccess;
-use crate::image::ImageAspect;
-use crate::image::ImageAspects;
-use crate::image::ImageLayout;
-use crate::image::SampleCount;
-use crate::pipeline::depth_stencil::StencilFaces;
-use crate::pipeline::input_assembly::IndexType;
-use crate::pipeline::layout::PipelineLayout;
-use crate::pipeline::shader::ShaderStages;
-use crate::pipeline::viewport::Scissor;
-use crate::pipeline::viewport::Viewport;
-use crate::pipeline::ComputePipelineAbstract;
-use crate::pipeline::GraphicsPipelineAbstract;
-use crate::pipeline::PipelineBindPoint;
-use crate::query::QueriesRange;
-use crate::query::Query;
-use crate::query::QueryControlFlags;
-use crate::query::QueryResultElement;
-use crate::query::QueryResultFlags;
-use crate::render_pass::FramebufferAbstract;
-use crate::sampler::Filter;
-use crate::sync::AccessFlags;
-use crate::sync::Event;
-use crate::sync::PipelineStage;
-use crate::sync::PipelineStages;
-use crate::DeviceSize;
-use crate::OomError;
-use crate::VulkanObject;
-use ash::vk::Handle;
+pub use super::commands::{
+ bind_push::UnsafeCommandBufferBuilderBindVertexBuffer,
+ secondary::UnsafeCommandBufferBuilderExecuteCommands,
+};
+use super::{
+ pool::CommandPoolAlloc, CommandBufferInheritanceInfo, CommandBufferLevel, CommandBufferUsage,
+};
+use crate::{
+ command_buffer::{
+ CommandBufferInheritanceRenderPassInfo, CommandBufferInheritanceRenderPassType,
+ CommandBufferInheritanceRenderingInfo,
+ },
+ device::{Device, DeviceOwned},
+ query::QueryControlFlags,
+ OomError, VulkanError, VulkanObject,
+};
use smallvec::SmallVec;
-use std::ffi::CStr;
-use std::fmt;
-use std::mem;
-use std::ops::Range;
-use std::sync::Arc;
+use std::{ptr, sync::Arc};
/// Command buffer being built.
///
-/// You can add commands to an `UnsafeCommandBufferBuilder` by using the `AddCommand` trait.
-/// The `AddCommand<&Cmd>` trait is implemented on the `UnsafeCommandBufferBuilder` for any `Cmd`
-/// that is a raw Vulkan command.
+/// # Safety
+///
+/// - All submitted commands must be valid and follow the requirements of the Vulkan specification.
+/// - Any resources used by submitted commands must outlive the returned builder and its created
+/// command buffer. They must be protected against data races through manual synchronization.
///
-/// When you are finished adding commands, you can use the `CommandBufferBuild` trait to turn this
-/// builder into an `UnsafeCommandBuffer`.
+/// > **Note**: Some checks are still made with `debug_assert!`. Do not expect to be able to
+/// > submit invalid commands.
+#[derive(Debug)]
pub struct UnsafeCommandBufferBuilder {
- command_buffer: ash::vk::CommandBuffer,
- device: Arc<Device>,
+ pub(super) handle: ash::vk::CommandBuffer,
+ pub(super) device: Arc<Device>,
usage: CommandBufferUsage,
}
-impl fmt::Debug for UnsafeCommandBufferBuilder {
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(
- f,
- "<Vulkan command buffer builder #{}>",
- self.command_buffer.as_raw()
- )
- }
-}
-
impl UnsafeCommandBufferBuilder {
/// Creates a new builder, for recording commands.
///
@@ -90,113 +50,141 @@ impl UnsafeCommandBufferBuilder {
///
/// - `pool_alloc` must outlive the returned builder and its created command buffer.
/// - `kind` must match how `pool_alloc` was created.
- /// - All submitted commands must be valid and follow the requirements of the Vulkan specification.
- /// - Any resources used by submitted commands must outlive the returned builder and its created command buffer. They must be protected against data races through manual synchronization.
- ///
- /// > **Note**: Some checks are still made with `debug_assert!`. Do not expect to be able to
- /// > submit invalid commands.
- pub unsafe fn new<F>(
- pool_alloc: &UnsafeCommandPoolAlloc,
- level: CommandBufferLevel<F>,
- usage: CommandBufferUsage,
- ) -> Result<UnsafeCommandBufferBuilder, OomError>
- where
- F: FramebufferAbstract,
- {
- let secondary = match level {
- CommandBufferLevel::Primary => false,
- CommandBufferLevel::Secondary(..) => true,
- };
+ #[inline]
+ pub unsafe fn new(
+ pool_alloc: &CommandPoolAlloc,
+ begin_info: CommandBufferBeginInfo,
+ ) -> Result<UnsafeCommandBufferBuilder, OomError> {
+ let CommandBufferBeginInfo {
+ usage,
+ inheritance_info,
+ _ne: _,
+ } = begin_info;
- let device = pool_alloc.device().clone();
- let fns = device.fns();
+ // VUID-vkBeginCommandBuffer-commandBuffer-00049
+ // Can't validate
- let vk_flags = {
- let a = ash::vk::CommandBufferUsageFlags::from(usage);
- let b = match level {
- CommandBufferLevel::Secondary(ref inheritance)
- if inheritance.render_pass.is_some() =>
- {
- ash::vk::CommandBufferUsageFlags::RENDER_PASS_CONTINUE
- }
- _ => ash::vk::CommandBufferUsageFlags::empty(),
- };
+ // VUID-vkBeginCommandBuffer-commandBuffer-00050
+ // Can't validate
- a | b
- };
+ let device = pool_alloc.device().clone();
- let (rp, sp, fb) = match level {
- CommandBufferLevel::Secondary(CommandBufferInheritance {
- render_pass: Some(ref render_pass),
- ..
- }) => {
- let rp = render_pass.subpass.render_pass().inner().internal_object();
- let sp = render_pass.subpass.index();
- let fb = match render_pass.framebuffer {
- Some(ref fb) => {
- // TODO: debug assert that the framebuffer is compatible with
- // the render pass?
- FramebufferAbstract::inner(fb).internal_object()
+ // VUID-vkBeginCommandBuffer-commandBuffer-00051
+ debug_assert_eq!(
+ pool_alloc.level() == CommandBufferLevel::Secondary,
+ inheritance_info.is_some()
+ );
+
+ {
+ // VUID-vkBeginCommandBuffer-commandBuffer-02840
+ // Guaranteed by use of enum
+ let mut flags = ash::vk::CommandBufferUsageFlags::from(usage);
+ let mut inheritance_info_vk = None;
+ let mut inheritance_rendering_info_vk = None;
+ let mut color_attachment_formats_vk: SmallVec<[_; 4]> = SmallVec::new();
+
+ if let Some(inheritance_info) = &inheritance_info {
+ let &CommandBufferInheritanceInfo {
+ ref render_pass,
+ occlusion_query,
+ query_statistics_flags,
+ _ne: _,
+ } = inheritance_info;
+
+ let inheritance_info_vk =
+ inheritance_info_vk.insert(ash::vk::CommandBufferInheritanceInfo {
+ render_pass: ash::vk::RenderPass::null(),
+ subpass: 0,
+ framebuffer: ash::vk::Framebuffer::null(),
+ occlusion_query_enable: ash::vk::FALSE,
+ query_flags: ash::vk::QueryControlFlags::empty(),
+ pipeline_statistics: query_statistics_flags.into(),
+ ..Default::default()
+ });
+
+ if let Some(flags) = occlusion_query {
+ inheritance_info_vk.occlusion_query_enable = ash::vk::TRUE;
+
+ if flags.intersects(QueryControlFlags::PRECISE) {
+ inheritance_info_vk.query_flags = ash::vk::QueryControlFlags::PRECISE;
}
- None => ash::vk::Framebuffer::null(),
- };
- (rp, sp, fb)
- }
- _ => (ash::vk::RenderPass::null(), 0, ash::vk::Framebuffer::null()),
- };
+ }
- let (oqe, qf, ps) = match level {
- CommandBufferLevel::Secondary(CommandBufferInheritance {
- occlusion_query,
- query_statistics_flags,
- ..
- }) => {
- let ps: ash::vk::QueryPipelineStatisticFlags = query_statistics_flags.into();
- let (oqe, qf) = match occlusion_query {
- Some(flags) => {
- let qf = if flags.precise {
- ash::vk::QueryControlFlags::PRECISE
- } else {
- ash::vk::QueryControlFlags::empty()
- };
- (ash::vk::TRUE, qf)
+ if let Some(render_pass) = render_pass {
+ flags |= ash::vk::CommandBufferUsageFlags::RENDER_PASS_CONTINUE;
+
+ match render_pass {
+ CommandBufferInheritanceRenderPassType::BeginRenderPass(
+ render_pass_info,
+ ) => {
+ let &CommandBufferInheritanceRenderPassInfo {
+ ref subpass,
+ ref framebuffer,
+ } = render_pass_info;
+
+ inheritance_info_vk.render_pass = subpass.render_pass().handle();
+ inheritance_info_vk.subpass = subpass.index();
+ inheritance_info_vk.framebuffer = framebuffer
+ .as_ref()
+ .map(|fb| fb.handle())
+ .unwrap_or_default();
+ }
+ CommandBufferInheritanceRenderPassType::BeginRendering(rendering_info) => {
+ let &CommandBufferInheritanceRenderingInfo {
+ view_mask,
+ ref color_attachment_formats,
+ depth_attachment_format,
+ stencil_attachment_format,
+ rasterization_samples,
+ } = rendering_info;
+
+ color_attachment_formats_vk.extend(
+ color_attachment_formats.iter().map(|format| {
+ format.map_or(ash::vk::Format::UNDEFINED, Into::into)
+ }),
+ );
+
+ let inheritance_rendering_info_vk = inheritance_rendering_info_vk
+ .insert(ash::vk::CommandBufferInheritanceRenderingInfo {
+ flags: ash::vk::RenderingFlags::empty(),
+ view_mask,
+ color_attachment_count: color_attachment_formats_vk.len()
+ as u32,
+ p_color_attachment_formats: color_attachment_formats_vk
+ .as_ptr(),
+ depth_attachment_format: depth_attachment_format
+ .map_or(ash::vk::Format::UNDEFINED, Into::into),
+ stencil_attachment_format: stencil_attachment_format
+ .map_or(ash::vk::Format::UNDEFINED, Into::into),
+ rasterization_samples: rasterization_samples.into(),
+ ..Default::default()
+ });
+
+ inheritance_info_vk.p_next =
+ inheritance_rendering_info_vk as *const _ as *const _;
+ }
}
- None => (0, ash::vk::QueryControlFlags::empty()),
- };
-
- (oqe, qf, ps)
+ }
}
- _ => (
- 0,
- ash::vk::QueryControlFlags::empty(),
- ash::vk::QueryPipelineStatisticFlags::empty(),
- ),
- };
- let inheritance = ash::vk::CommandBufferInheritanceInfo {
- render_pass: rp,
- subpass: sp,
- framebuffer: fb,
- occlusion_query_enable: oqe,
- query_flags: qf,
- pipeline_statistics: ps,
- ..Default::default()
- };
+ let begin_info_vk = ash::vk::CommandBufferBeginInfo {
+ flags,
+ p_inheritance_info: inheritance_info_vk
+ .as_ref()
+ .map_or(ptr::null(), |info| info),
+ ..Default::default()
+ };
- let infos = ash::vk::CommandBufferBeginInfo {
- flags: vk_flags,
- p_inheritance_info: &inheritance,
- ..Default::default()
- };
+ let fns = device.fns();
- check_errors(
- fns.v1_0
- .begin_command_buffer(pool_alloc.internal_object(), &infos),
- )?;
+ (fns.v1_0.begin_command_buffer)(pool_alloc.handle(), &begin_info_vk)
+ .result()
+ .map_err(VulkanError::from)?;
+ }
Ok(UnsafeCommandBufferBuilder {
- command_buffer: pool_alloc.internal_object(),
- device: device.clone(),
+ handle: pool_alloc.handle(),
+ device,
usage,
})
}
@@ -206,1350 +194,25 @@ impl UnsafeCommandBufferBuilder {
pub fn build(self) -> Result<UnsafeCommandBuffer, OomError> {
unsafe {
let fns = self.device.fns();
- check_errors(fns.v1_0.end_command_buffer(self.command_buffer))?;
+ (fns.v1_0.end_command_buffer)(self.handle)
+ .result()
+ .map_err(VulkanError::from)?;
Ok(UnsafeCommandBuffer {
- command_buffer: self.command_buffer,
+ command_buffer: self.handle,
device: self.device.clone(),
usage: self.usage,
})
}
}
+}
- /// Calls `vkCmdBeginQuery` on the builder.
- #[inline]
- pub unsafe fn begin_query(&mut self, query: Query, flags: QueryControlFlags) {
- let fns = self.device().fns();
- let cmd = self.internal_object();
- let flags = if flags.precise {
- ash::vk::QueryControlFlags::PRECISE
- } else {
- ash::vk::QueryControlFlags::empty()
- };
- fns.v1_0
- .cmd_begin_query(cmd, query.pool().internal_object(), query.index(), flags);
- }
-
- /// Calls `vkCmdBeginRenderPass` on the builder.
- #[inline]
- pub unsafe fn begin_render_pass<F, I>(
- &mut self,
- framebuffer: &F,
- subpass_contents: SubpassContents,
- clear_values: I,
- ) where
- F: ?Sized + FramebufferAbstract,
- I: IntoIterator<Item = ClearValue>,
- {
- let fns = self.device().fns();
- let cmd = self.internal_object();
-
- // TODO: allow passing a different render pass
- let raw_render_pass = framebuffer.render_pass().inner().internal_object();
- let raw_framebuffer = framebuffer.inner().internal_object();
-
- let raw_clear_values: SmallVec<[_; 12]> = clear_values
- .into_iter()
- .map(|clear_value| match clear_value {
- ClearValue::None => ash::vk::ClearValue {
- color: ash::vk::ClearColorValue { float32: [0.0; 4] },
- },
- ClearValue::Float(val) => ash::vk::ClearValue {
- color: ash::vk::ClearColorValue { float32: val },
- },
- ClearValue::Int(val) => ash::vk::ClearValue {
- color: ash::vk::ClearColorValue { int32: val },
- },
- ClearValue::Uint(val) => ash::vk::ClearValue {
- color: ash::vk::ClearColorValue { uint32: val },
- },
- ClearValue::Depth(val) => ash::vk::ClearValue {
- depth_stencil: ash::vk::ClearDepthStencilValue {
- depth: val,
- stencil: 0,
- },
- },
- ClearValue::Stencil(val) => ash::vk::ClearValue {
- depth_stencil: ash::vk::ClearDepthStencilValue {
- depth: 0.0,
- stencil: val,
- },
- },
- ClearValue::DepthStencil((depth, stencil)) => ash::vk::ClearValue {
- depth_stencil: ash::vk::ClearDepthStencilValue { depth, stencil },
- },
- })
- .collect();
-
- // TODO: allow customizing
- let rect = [
- 0..framebuffer.dimensions()[0],
- 0..framebuffer.dimensions()[1],
- ];
-
- let begin = ash::vk::RenderPassBeginInfo {
- render_pass: raw_render_pass,
- framebuffer: raw_framebuffer,
- render_area: ash::vk::Rect2D {
- offset: ash::vk::Offset2D {
- x: rect[0].start as i32,
- y: rect[1].start as i32,
- },
- extent: ash::vk::Extent2D {
- width: rect[0].end - rect[0].start,
- height: rect[1].end - rect[1].start,
- },
- },
- clear_value_count: raw_clear_values.len() as u32,
- p_clear_values: raw_clear_values.as_ptr(),
- ..Default::default()
- };
-
- fns.v1_0
- .cmd_begin_render_pass(cmd, &begin, subpass_contents.into());
- }
-
- /// Calls `vkCmdBindDescriptorSets` on the builder.
- ///
- /// Does nothing if the list of descriptor sets is empty, as it would be a no-op and isn't a
- /// valid usage of the command anyway.
- #[inline]
- pub unsafe fn bind_descriptor_sets<'s, S, I>(
- &mut self,
- pipeline_bind_point: PipelineBindPoint,
- pipeline_layout: &PipelineLayout,
- first_binding: u32,
- sets: S,
- dynamic_offsets: I,
- ) where
- S: IntoIterator<Item = &'s UnsafeDescriptorSet>,
- I: IntoIterator<Item = u32>,
- {
- let fns = self.device().fns();
- let cmd = self.internal_object();
-
- let sets: SmallVec<[_; 12]> = sets.into_iter().map(|s| s.internal_object()).collect();
- if sets.is_empty() {
- return;
- }
- let dynamic_offsets: SmallVec<[u32; 32]> = dynamic_offsets.into_iter().collect();
-
- let num_bindings = sets.len() as u32;
- debug_assert!(
- first_binding + num_bindings <= pipeline_layout.descriptor_set_layouts().len() as u32
- );
-
- fns.v1_0.cmd_bind_descriptor_sets(
- cmd,
- pipeline_bind_point.into(),
- pipeline_layout.internal_object(),
- first_binding,
- num_bindings,
- sets.as_ptr(),
- dynamic_offsets.len() as u32,
- dynamic_offsets.as_ptr(),
- );
- }
-
- /// Calls `vkCmdBindIndexBuffer` on the builder.
- #[inline]
- pub unsafe fn bind_index_buffer<B>(&mut self, buffer: &B, index_ty: IndexType)
- where
- B: ?Sized + BufferAccess,
- {
- let fns = self.device().fns();
- let cmd = self.internal_object();
-
- let inner = buffer.inner();
- debug_assert!(inner.offset < inner.buffer.size());
- debug_assert!(inner.buffer.usage().index_buffer);
-
- fns.v1_0.cmd_bind_index_buffer(
- cmd,
- inner.buffer.internal_object(),
- inner.offset,
- index_ty.into(),
- );
- }
-
- /// Calls `vkCmdBindPipeline` on the builder with a compute pipeline.
- #[inline]
- pub unsafe fn bind_pipeline_compute<Cp>(&mut self, pipeline: &Cp)
- where
- Cp: ?Sized + ComputePipelineAbstract,
- {
- let fns = self.device().fns();
- let cmd = self.internal_object();
- fns.v1_0.cmd_bind_pipeline(
- cmd,
- ash::vk::PipelineBindPoint::COMPUTE,
- pipeline.inner().internal_object(),
- );
- }
-
- /// Calls `vkCmdBindPipeline` on the builder with a graphics pipeline.
- #[inline]
- pub unsafe fn bind_pipeline_graphics<Gp>(&mut self, pipeline: &Gp)
- where
- Gp: ?Sized + GraphicsPipelineAbstract,
- {
- let fns = self.device().fns();
- let cmd = self.internal_object();
- let inner = GraphicsPipelineAbstract::inner(pipeline).internal_object();
- fns.v1_0
- .cmd_bind_pipeline(cmd, ash::vk::PipelineBindPoint::GRAPHICS, inner);
- }
-
- /// Calls `vkCmdBindVertexBuffers` on the builder.
- ///
- /// Does nothing if the list of buffers is empty, as it would be a no-op and isn't a valid
- /// usage of the command anyway.
- #[inline]
- pub unsafe fn bind_vertex_buffers(
- &mut self,
- first_binding: u32,
- params: UnsafeCommandBufferBuilderBindVertexBuffer,
- ) {
- debug_assert_eq!(params.raw_buffers.len(), params.offsets.len());
-
- if params.raw_buffers.is_empty() {
- return;
- }
-
- let fns = self.device().fns();
- let cmd = self.internal_object();
-
- let num_bindings = params.raw_buffers.len() as u32;
-
- debug_assert!({
- let max_bindings = self
- .device()
- .physical_device()
- .properties()
- .max_vertex_input_bindings;
- first_binding + num_bindings <= max_bindings
- });
-
- fns.v1_0.cmd_bind_vertex_buffers(
- cmd,
- first_binding,
- num_bindings,
- params.raw_buffers.as_ptr(),
- params.offsets.as_ptr(),
- );
- }
-
- /// Calls `vkCmdCopyImage` on the builder.
- ///
- /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
- /// usage of the command anyway.
- #[inline]
- pub unsafe fn copy_image<S, D, R>(
- &mut self,
- source: &S,
- source_layout: ImageLayout,
- destination: &D,
- destination_layout: ImageLayout,
- regions: R,
- ) where
- S: ?Sized + ImageAccess,
- D: ?Sized + ImageAccess,
- R: IntoIterator<Item = UnsafeCommandBufferBuilderImageCopy>,
- {
- // TODO: The correct check here is that the uncompressed element size of the source is
- // equal to the compressed element size of the destination.
- debug_assert!(
- source.format().ty() == FormatTy::Compressed
- || destination.format().ty() == FormatTy::Compressed
- || source.format().size() == destination.format().size()
- );
-
- // Depth/Stencil formats are required to match exactly.
- debug_assert!(
- !matches!(
- source.format().ty(),
- FormatTy::Depth | FormatTy::Stencil | FormatTy::DepthStencil
- ) || source.format() == destination.format()
- );
-
- debug_assert_eq!(source.samples(), destination.samples());
- let source = source.inner();
- debug_assert!(source.image.usage().transfer_source);
- debug_assert!(
- source_layout == ImageLayout::General
- || source_layout == ImageLayout::TransferSrcOptimal
- );
-
- let destination = destination.inner();
- debug_assert!(destination.image.usage().transfer_destination);
- debug_assert!(
- destination_layout == ImageLayout::General
- || destination_layout == ImageLayout::TransferDstOptimal
- );
-
- let regions: SmallVec<[_; 8]> = regions
- .into_iter()
- .filter_map(|copy| {
- // TODO: not everything is checked here
- debug_assert!(
- copy.source_base_array_layer + copy.layer_count <= source.num_layers as u32
- );
- debug_assert!(
- copy.destination_base_array_layer + copy.layer_count
- <= destination.num_layers as u32
- );
- debug_assert!(copy.source_mip_level < destination.num_mipmap_levels as u32);
- debug_assert!(copy.destination_mip_level < destination.num_mipmap_levels as u32);
-
- if copy.layer_count == 0 {
- return None;
- }
-
- Some(ash::vk::ImageCopy {
- src_subresource: ash::vk::ImageSubresourceLayers {
- aspect_mask: copy.aspects.into(),
- mip_level: copy.source_mip_level,
- base_array_layer: copy.source_base_array_layer + source.first_layer as u32,
- layer_count: copy.layer_count,
- },
- src_offset: ash::vk::Offset3D {
- x: copy.source_offset[0],
- y: copy.source_offset[1],
- z: copy.source_offset[2],
- },
- dst_subresource: ash::vk::ImageSubresourceLayers {
- aspect_mask: copy.aspects.into(),
- mip_level: copy.destination_mip_level,
- base_array_layer: copy.destination_base_array_layer
- + destination.first_layer as u32,
- layer_count: copy.layer_count,
- },
- dst_offset: ash::vk::Offset3D {
- x: copy.destination_offset[0],
- y: copy.destination_offset[1],
- z: copy.destination_offset[2],
- },
- extent: ash::vk::Extent3D {
- width: copy.extent[0],
- height: copy.extent[1],
- depth: copy.extent[2],
- },
- })
- })
- .collect();
-
- if regions.is_empty() {
- return;
- }
-
- let fns = self.device().fns();
- let cmd = self.internal_object();
- fns.v1_0.cmd_copy_image(
- cmd,
- source.image.internal_object(),
- source_layout.into(),
- destination.image.internal_object(),
- destination_layout.into(),
- regions.len() as u32,
- regions.as_ptr(),
- );
- }
-
- /// Calls `vkCmdBlitImage` on the builder.
- ///
- /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
- /// usage of the command anyway.
- #[inline]
- pub unsafe fn blit_image<S, D, R>(
- &mut self,
- source: &S,
- source_layout: ImageLayout,
- destination: &D,
- destination_layout: ImageLayout,
- regions: R,
- filter: Filter,
- ) where
- S: ?Sized + ImageAccess,
- D: ?Sized + ImageAccess,
- R: IntoIterator<Item = UnsafeCommandBufferBuilderImageBlit>,
- {
- debug_assert!(
- filter == Filter::Nearest
- || !matches!(
- source.format().ty(),
- FormatTy::Depth | FormatTy::Stencil | FormatTy::DepthStencil
- )
- );
- debug_assert!(
- (source.format().ty() == FormatTy::Uint)
- == (destination.format().ty() == FormatTy::Uint)
- );
- debug_assert!(
- (source.format().ty() == FormatTy::Sint)
- == (destination.format().ty() == FormatTy::Sint)
- );
- debug_assert!(
- source.format() == destination.format()
- || !matches!(
- source.format().ty(),
- FormatTy::Depth | FormatTy::Stencil | FormatTy::DepthStencil
- )
- );
-
- debug_assert_eq!(source.samples(), SampleCount::Sample1);
- let source = source.inner();
- debug_assert!(source.image.format_features().blit_src);
- debug_assert!(source.image.usage().transfer_source);
- debug_assert!(
- source_layout == ImageLayout::General
- || source_layout == ImageLayout::TransferSrcOptimal
- );
-
- debug_assert_eq!(destination.samples(), SampleCount::Sample1);
- let destination = destination.inner();
- debug_assert!(destination.image.format_features().blit_dst);
- debug_assert!(destination.image.usage().transfer_destination);
- debug_assert!(
- destination_layout == ImageLayout::General
- || destination_layout == ImageLayout::TransferDstOptimal
- );
-
- let regions: SmallVec<[_; 8]> = regions
- .into_iter()
- .filter_map(|blit| {
- // TODO: not everything is checked here
- debug_assert!(
- blit.source_base_array_layer + blit.layer_count <= source.num_layers as u32
- );
- debug_assert!(
- blit.destination_base_array_layer + blit.layer_count
- <= destination.num_layers as u32
- );
- debug_assert!(blit.source_mip_level < destination.num_mipmap_levels as u32);
- debug_assert!(blit.destination_mip_level < destination.num_mipmap_levels as u32);
-
- if blit.layer_count == 0 {
- return None;
- }
-
- Some(ash::vk::ImageBlit {
- src_subresource: ash::vk::ImageSubresourceLayers {
- aspect_mask: blit.aspects.into(),
- mip_level: blit.source_mip_level,
- base_array_layer: blit.source_base_array_layer + source.first_layer as u32,
- layer_count: blit.layer_count,
- },
- src_offsets: [
- ash::vk::Offset3D {
- x: blit.source_top_left[0],
- y: blit.source_top_left[1],
- z: blit.source_top_left[2],
- },
- ash::vk::Offset3D {
- x: blit.source_bottom_right[0],
- y: blit.source_bottom_right[1],
- z: blit.source_bottom_right[2],
- },
- ],
- dst_subresource: ash::vk::ImageSubresourceLayers {
- aspect_mask: blit.aspects.into(),
- mip_level: blit.destination_mip_level,
- base_array_layer: blit.destination_base_array_layer
- + destination.first_layer as u32,
- layer_count: blit.layer_count,
- },
- dst_offsets: [
- ash::vk::Offset3D {
- x: blit.destination_top_left[0],
- y: blit.destination_top_left[1],
- z: blit.destination_top_left[2],
- },
- ash::vk::Offset3D {
- x: blit.destination_bottom_right[0],
- y: blit.destination_bottom_right[1],
- z: blit.destination_bottom_right[2],
- },
- ],
- })
- })
- .collect();
-
- if regions.is_empty() {
- return;
- }
-
- let fns = self.device().fns();
- let cmd = self.internal_object();
- fns.v1_0.cmd_blit_image(
- cmd,
- source.image.internal_object(),
- source_layout.into(),
- destination.image.internal_object(),
- destination_layout.into(),
- regions.len() as u32,
- regions.as_ptr(),
- filter.into(),
- );
- }
-
- // TODO: missing structs
- /*/// Calls `vkCmdClearAttachments` on the builder.
- ///
- /// Does nothing if the list of attachments or the list of rects is empty, as it would be a
- /// no-op and isn't a valid usage of the command anyway.
- #[inline]
- pub unsafe fn clear_attachments<A, R>(&mut self, attachments: A, rects: R)
- where A: IntoIterator<Item = >,
- R: IntoIterator<Item = >
- {
- let attachments: SmallVec<[_; 16]> = attachments.map().collect();
- let rects: SmallVec<[_; 4]> = rects.map().collect();
-
- if attachments.is_empty() || rects.is_empty() {
- return;
- }
-
- let fns = self.device().fns();
- let cmd = self.internal_object();
- fns.v1_0.CmdClearAttachments(cmd, attachments.len() as u32, attachments.as_ptr(),
- rects.len() as u32, rects.as_ptr());
- }*/
-
- /// Calls `vkCmdClearColorImage` on the builder.
- ///
- /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
- /// usage of the command anyway.
- // TODO: ClearValue could be more precise
- pub unsafe fn clear_color_image<I, R>(
- &mut self,
- image: &I,
- layout: ImageLayout,
- color: ClearValue,
- regions: R,
- ) where
- I: ?Sized + ImageAccess,
- R: IntoIterator<Item = UnsafeCommandBufferBuilderColorImageClear>,
- {
- debug_assert!(
- image.format().ty() == FormatTy::Float
- || image.format().ty() == FormatTy::Uint
- || image.format().ty() == FormatTy::Sint
- );
-
- let image = image.inner();
- debug_assert!(image.image.usage().transfer_destination);
- debug_assert!(layout == ImageLayout::General || layout == ImageLayout::TransferDstOptimal);
-
- let color = match color {
- ClearValue::Float(val) => ash::vk::ClearColorValue { float32: val },
- ClearValue::Int(val) => ash::vk::ClearColorValue { int32: val },
- ClearValue::Uint(val) => ash::vk::ClearColorValue { uint32: val },
- _ => ash::vk::ClearColorValue { float32: [0.0; 4] },
- };
-
- let regions: SmallVec<[_; 8]> = regions
- .into_iter()
- .filter_map(|region| {
- debug_assert!(
- region.layer_count + region.base_array_layer <= image.num_layers as u32
- );
- debug_assert!(
- region.level_count + region.base_mip_level <= image.num_mipmap_levels as u32
- );
-
- if region.layer_count == 0 || region.level_count == 0 {
- return None;
- }
-
- Some(ash::vk::ImageSubresourceRange {
- aspect_mask: ash::vk::ImageAspectFlags::COLOR,
- base_mip_level: region.base_mip_level + image.first_mipmap_level as u32,
- level_count: region.level_count,
- base_array_layer: region.base_array_layer + image.first_layer as u32,
- layer_count: region.layer_count,
- })
- })
- .collect();
-
- if regions.is_empty() {
- return;
- }
-
- let fns = self.device().fns();
- let cmd = self.internal_object();
- fns.v1_0.cmd_clear_color_image(
- cmd,
- image.image.internal_object(),
- layout.into(),
- &color,
- regions.len() as u32,
- regions.as_ptr(),
- );
- }
-
- /// Calls `vkCmdCopyBuffer` on the builder.
- ///
- /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
- /// usage of the command anyway.
- #[inline]
- pub unsafe fn copy_buffer<S, D, R>(&mut self, source: &S, destination: &D, regions: R)
- where
- S: ?Sized + BufferAccess,
- D: ?Sized + BufferAccess,
- R: IntoIterator<Item = (DeviceSize, DeviceSize, DeviceSize)>,
- {
- // TODO: debug assert that there's no overlap in the destinations?
-
- let source = source.inner();
- debug_assert!(source.offset < source.buffer.size());
- debug_assert!(source.buffer.usage().transfer_source);
-
- let destination = destination.inner();
- debug_assert!(destination.offset < destination.buffer.size());
- debug_assert!(destination.buffer.usage().transfer_destination);
-
- let regions: SmallVec<[_; 8]> = regions
- .into_iter()
- .map(|(sr, de, sz)| ash::vk::BufferCopy {
- src_offset: sr + source.offset,
- dst_offset: de + destination.offset,
- size: sz,
- })
- .collect();
-
- if regions.is_empty() {
- return;
- }
-
- let fns = self.device().fns();
- let cmd = self.internal_object();
- fns.v1_0.cmd_copy_buffer(
- cmd,
- source.buffer.internal_object(),
- destination.buffer.internal_object(),
- regions.len() as u32,
- regions.as_ptr(),
- );
- }
-
- /// Calls `vkCmdCopyBufferToImage` on the builder.
- ///
- /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
- /// usage of the command anyway.
- #[inline]
- pub unsafe fn copy_buffer_to_image<S, D, R>(
- &mut self,
- source: &S,
- destination: &D,
- destination_layout: ImageLayout,
- regions: R,
- ) where
- S: ?Sized + BufferAccess,
- D: ?Sized + ImageAccess,
- R: IntoIterator<Item = UnsafeCommandBufferBuilderBufferImageCopy>,
- {
- let source = source.inner();
- debug_assert!(source.offset < source.buffer.size());
- debug_assert!(source.buffer.usage().transfer_source);
-
- debug_assert_eq!(destination.samples(), SampleCount::Sample1);
- let destination = destination.inner();
- debug_assert!(destination.image.usage().transfer_destination);
- debug_assert!(
- destination_layout == ImageLayout::General
- || destination_layout == ImageLayout::TransferDstOptimal
- );
-
- let regions: SmallVec<[_; 8]> = regions
- .into_iter()
- .map(|copy| {
- debug_assert!(copy.image_layer_count <= destination.num_layers as u32);
- debug_assert!(copy.image_mip_level < destination.num_mipmap_levels as u32);
-
- ash::vk::BufferImageCopy {
- buffer_offset: source.offset + copy.buffer_offset,
- buffer_row_length: copy.buffer_row_length,
- buffer_image_height: copy.buffer_image_height,
- image_subresource: ash::vk::ImageSubresourceLayers {
- aspect_mask: copy.image_aspect.into(),
- mip_level: copy.image_mip_level + destination.first_mipmap_level as u32,
- base_array_layer: copy.image_base_array_layer
- + destination.first_layer as u32,
- layer_count: copy.image_layer_count,
- },
- image_offset: ash::vk::Offset3D {
- x: copy.image_offset[0],
- y: copy.image_offset[1],
- z: copy.image_offset[2],
- },
- image_extent: ash::vk::Extent3D {
- width: copy.image_extent[0],
- height: copy.image_extent[1],
- depth: copy.image_extent[2],
- },
- }
- })
- .collect();
-
- if regions.is_empty() {
- return;
- }
-
- let fns = self.device().fns();
- let cmd = self.internal_object();
- fns.v1_0.cmd_copy_buffer_to_image(
- cmd,
- source.buffer.internal_object(),
- destination.image.internal_object(),
- destination_layout.into(),
- regions.len() as u32,
- regions.as_ptr(),
- );
- }
-
- /// Calls `vkCmdCopyImageToBuffer` on the builder.
- ///
- /// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
- /// usage of the command anyway.
- #[inline]
- pub unsafe fn copy_image_to_buffer<S, D, R>(
- &mut self,
- source: &S,
- source_layout: ImageLayout,
- destination: &D,
- regions: R,
- ) where
- S: ?Sized + ImageAccess,
- D: ?Sized + BufferAccess,
- R: IntoIterator<Item = UnsafeCommandBufferBuilderBufferImageCopy>,
- {
- debug_assert_eq!(source.samples(), SampleCount::Sample1);
- let source = source.inner();
- debug_assert!(source.image.usage().transfer_source);
- debug_assert!(
- source_layout == ImageLayout::General
- || source_layout == ImageLayout::TransferSrcOptimal
- );
-
- let destination = destination.inner();
- debug_assert!(destination.offset < destination.buffer.size());
- debug_assert!(destination.buffer.usage().transfer_destination);
-
- let regions: SmallVec<[_; 8]> = regions
- .into_iter()
- .map(|copy| {
- debug_assert!(copy.image_layer_count <= source.num_layers as u32);
- debug_assert!(copy.image_mip_level < source.num_mipmap_levels as u32);
-
- ash::vk::BufferImageCopy {
- buffer_offset: destination.offset + copy.buffer_offset,
- buffer_row_length: copy.buffer_row_length,
- buffer_image_height: copy.buffer_image_height,
- image_subresource: ash::vk::ImageSubresourceLayers {
- aspect_mask: copy.image_aspect.into(),
- mip_level: copy.image_mip_level + source.first_mipmap_level as u32,
- base_array_layer: copy.image_base_array_layer + source.first_layer as u32,
- layer_count: copy.image_layer_count,
- },
- image_offset: ash::vk::Offset3D {
- x: copy.image_offset[0],
- y: copy.image_offset[1],
- z: copy.image_offset[2],
- },
- image_extent: ash::vk::Extent3D {
- width: copy.image_extent[0],
- height: copy.image_extent[1],
- depth: copy.image_extent[2],
- },
- }
- })
- .collect();
-
- if regions.is_empty() {
- return;
- }
-
- let fns = self.device().fns();
- let cmd = self.internal_object();
- fns.v1_0.cmd_copy_image_to_buffer(
- cmd,
- source.image.internal_object(),
- source_layout.into(),
- destination.buffer.internal_object(),
- regions.len() as u32,
- regions.as_ptr(),
- );
- }
-
- /// Calls `vkCmdCopyQueryPoolResults` on the builder.
- #[inline]
- pub unsafe fn copy_query_pool_results<D, T>(
- &mut self,
- queries: QueriesRange,
- destination: D,
- stride: DeviceSize,
- flags: QueryResultFlags,
- ) where
- D: BufferAccess + TypedBufferAccess<Content = [T]>,
- T: QueryResultElement,
- {
- let destination = destination.inner();
- let range = queries.range();
- debug_assert!(destination.offset < destination.buffer.size());
- debug_assert!(destination.buffer.usage().transfer_destination);
- debug_assert!(destination.offset % std::mem::size_of::<T>() as DeviceSize == 0);
- debug_assert!(stride % std::mem::size_of::<T>() as DeviceSize == 0);
-
- let fns = self.device().fns();
- let cmd = self.internal_object();
- fns.v1_0.cmd_copy_query_pool_results(
- cmd,
- queries.pool().internal_object(),
- range.start,
- range.end - range.start,
- destination.buffer.internal_object(),
- destination.offset,
- stride,
- ash::vk::QueryResultFlags::from(flags) | T::FLAG,
- );
- }
-
- /// Calls `vkCmdDispatch` on the builder.
- #[inline]
- pub unsafe fn dispatch(&mut self, group_counts: [u32; 3]) {
- debug_assert!({
- let max_group_counts = self
- .device()
- .physical_device()
- .properties()
- .max_compute_work_group_count;
- group_counts[0] <= max_group_counts[0]
- && group_counts[1] <= max_group_counts[1]
- && group_counts[2] <= max_group_counts[2]
- });
-
- let fns = self.device().fns();
- let cmd = self.internal_object();
- fns.v1_0
- .cmd_dispatch(cmd, group_counts[0], group_counts[1], group_counts[2]);
- }
-
- /// Calls `vkCmdDispatchIndirect` on the builder.
- #[inline]
- pub unsafe fn dispatch_indirect<B>(&mut self, buffer: &B)
- where
- B: ?Sized + BufferAccess,
- {
- let fns = self.device().fns();
- let cmd = self.internal_object();
-
- let inner = buffer.inner();
- debug_assert!(inner.offset < inner.buffer.size());
- debug_assert!(inner.buffer.usage().indirect_buffer);
- debug_assert_eq!(inner.offset % 4, 0);
-
- fns.v1_0
- .cmd_dispatch_indirect(cmd, inner.buffer.internal_object(), inner.offset);
- }
-
- /// Calls `vkCmdDraw` on the builder.
- #[inline]
- pub unsafe fn draw(
- &mut self,
- vertex_count: u32,
- instance_count: u32,
- first_vertex: u32,
- first_instance: u32,
- ) {
- let fns = self.device().fns();
- let cmd = self.internal_object();
- fns.v1_0.cmd_draw(
- cmd,
- vertex_count,
- instance_count,
- first_vertex,
- first_instance,
- );
- }
-
- /// Calls `vkCmdDrawIndexed` on the builder.
- #[inline]
- pub unsafe fn draw_indexed(
- &mut self,
- index_count: u32,
- instance_count: u32,
- first_index: u32,
- vertex_offset: i32,
- first_instance: u32,
- ) {
- let fns = self.device().fns();
- let cmd = self.internal_object();
- fns.v1_0.cmd_draw_indexed(
- cmd,
- index_count,
- instance_count,
- first_index,
- vertex_offset,
- first_instance,
- );
- }
-
- /// Calls `vkCmdDrawIndirect` on the builder.
- #[inline]
- pub unsafe fn draw_indirect<B>(&mut self, buffer: &B, draw_count: u32, stride: u32)
- where
- B: ?Sized + BufferAccess,
- {
- let fns = self.device().fns();
- let cmd = self.internal_object();
-
- debug_assert!(
- draw_count == 0
- || ((stride % 4) == 0)
- && stride as usize >= mem::size_of::<ash::vk::DrawIndirectCommand>()
- );
-
- let inner = buffer.inner();
- debug_assert!(inner.offset < inner.buffer.size());
- debug_assert!(inner.buffer.usage().indirect_buffer);
-
- fns.v1_0.cmd_draw_indirect(
- cmd,
- inner.buffer.internal_object(),
- inner.offset,
- draw_count,
- stride,
- );
- }
-
- /// Calls `vkCmdDrawIndexedIndirect` on the builder.
- #[inline]
- pub unsafe fn draw_indexed_indirect<B>(&mut self, buffer: &B, draw_count: u32, stride: u32)
- where
- B: ?Sized + BufferAccess,
- {
- let fns = self.device().fns();
- let cmd = self.internal_object();
-
- let inner = buffer.inner();
- debug_assert!(inner.offset < inner.buffer.size());
- debug_assert!(inner.buffer.usage().indirect_buffer);
-
- fns.v1_0.cmd_draw_indexed_indirect(
- cmd,
- inner.buffer.internal_object(),
- inner.offset,
- draw_count,
- stride,
- );
- }
-
- /// Calls `vkCmdEndQuery` on the builder.
- #[inline]
- pub unsafe fn end_query(&mut self, query: Query) {
- let fns = self.device().fns();
- let cmd = self.internal_object();
- fns.v1_0
- .cmd_end_query(cmd, query.pool().internal_object(), query.index());
- }
-
- /// Calls `vkCmdEndRenderPass` on the builder.
- #[inline]
- pub unsafe fn end_render_pass(&mut self) {
- let fns = self.device().fns();
- let cmd = self.internal_object();
- fns.v1_0.cmd_end_render_pass(cmd);
- }
-
- /// Calls `vkCmdExecuteCommands` on the builder.
- ///
- /// Does nothing if the list of command buffers is empty, as it would be a no-op and isn't a
- /// valid usage of the command anyway.
- #[inline]
- pub unsafe fn execute_commands(&mut self, cbs: UnsafeCommandBufferBuilderExecuteCommands) {
- if cbs.raw_cbs.is_empty() {
- return;
- }
-
- let fns = self.device().fns();
- let cmd = self.internal_object();
- fns.v1_0
- .cmd_execute_commands(cmd, cbs.raw_cbs.len() as u32, cbs.raw_cbs.as_ptr());
- }
-
- /// Calls `vkCmdFillBuffer` on the builder.
- #[inline]
- pub unsafe fn fill_buffer<B>(&mut self, buffer: &B, data: u32)
- where
- B: ?Sized + BufferAccess,
- {
- let fns = self.device().fns();
- let cmd = self.internal_object();
-
- let size = buffer.size();
-
- let (buffer_handle, offset) = {
- let BufferInner {
- buffer: buffer_inner,
- offset,
- } = buffer.inner();
- debug_assert!(buffer_inner.usage().transfer_destination);
- debug_assert_eq!(offset % 4, 0);
- (buffer_inner.internal_object(), offset)
- };
-
- fns.v1_0
- .cmd_fill_buffer(cmd, buffer_handle, offset, size, data);
- }
-
- /// Calls `vkCmdNextSubpass` on the builder.
- #[inline]
- pub unsafe fn next_subpass(&mut self, subpass_contents: SubpassContents) {
- let fns = self.device().fns();
- let cmd = self.internal_object();
- fns.v1_0.cmd_next_subpass(cmd, subpass_contents.into());
- }
-
- #[inline]
- pub unsafe fn pipeline_barrier(&mut self, command: &UnsafeCommandBufferBuilderPipelineBarrier) {
- // If barrier is empty, don't do anything.
- if command.src_stage_mask.is_empty() || command.dst_stage_mask.is_empty() {
- debug_assert!(command.src_stage_mask.is_empty() && command.dst_stage_mask.is_empty());
- debug_assert!(command.memory_barriers.is_empty());
- debug_assert!(command.buffer_barriers.is_empty());
- debug_assert!(command.image_barriers.is_empty());
- return;
- }
-
- let fns = self.device().fns();
- let cmd = self.internal_object();
-
- debug_assert!(!command.src_stage_mask.is_empty());
- debug_assert!(!command.dst_stage_mask.is_empty());
-
- fns.v1_0.cmd_pipeline_barrier(
- cmd,
- command.src_stage_mask,
- command.dst_stage_mask,
- command.dependency_flags,
- command.memory_barriers.len() as u32,
- command.memory_barriers.as_ptr(),
- command.buffer_barriers.len() as u32,
- command.buffer_barriers.as_ptr(),
- command.image_barriers.len() as u32,
- command.image_barriers.as_ptr(),
- );
- }
-
- /// Calls `vkCmdPushConstants` on the builder.
- #[inline]
- pub unsafe fn push_constants<D>(
- &mut self,
- pipeline_layout: &PipelineLayout,
- stages: ShaderStages,
- offset: u32,
- size: u32,
- data: &D,
- ) where
- D: ?Sized,
- {
- let fns = self.device().fns();
- let cmd = self.internal_object();
-
- debug_assert!(stages != ShaderStages::none());
- debug_assert!(size > 0);
- debug_assert_eq!(size % 4, 0);
- debug_assert_eq!(offset % 4, 0);
- debug_assert!(mem::size_of_val(data) >= size as usize);
-
- fns.v1_0.cmd_push_constants(
- cmd,
- pipeline_layout.internal_object(),
- stages.into(),
- offset as u32,
- size as u32,
- data as *const D as *const _,
- );
- }
-
- /// Calls `vkCmdResetEvent` on the builder.
- #[inline]
- pub unsafe fn reset_event(&mut self, event: &Event, stages: PipelineStages) {
- let fns = self.device().fns();
- let cmd = self.internal_object();
-
- debug_assert!(!stages.host);
- debug_assert_ne!(stages, PipelineStages::none());
-
- fns.v1_0
- .cmd_reset_event(cmd, event.internal_object(), stages.into());
- }
-
- /// Calls `vkCmdResetQueryPool` on the builder.
- #[inline]
- pub unsafe fn reset_query_pool(&mut self, queries: QueriesRange) {
- let range = queries.range();
- let fns = self.device().fns();
- let cmd = self.internal_object();
- fns.v1_0.cmd_reset_query_pool(
- cmd,
- queries.pool().internal_object(),
- range.start,
- range.end - range.start,
- );
- }
-
- /// Calls `vkCmdSetBlendConstants` on the builder.
- #[inline]
- pub unsafe fn set_blend_constants(&mut self, constants: [f32; 4]) {
- let fns = self.device().fns();
- let cmd = self.internal_object();
- fns.v1_0.cmd_set_blend_constants(cmd, &constants);
- }
-
- /// Calls `vkCmdSetDepthBias` on the builder.
- #[inline]
- pub unsafe fn set_depth_bias(&mut self, constant_factor: f32, clamp: f32, slope_factor: f32) {
- let fns = self.device().fns();
- let cmd = self.internal_object();
- debug_assert!(clamp == 0.0 || self.device().enabled_features().depth_bias_clamp);
- fns.v1_0
- .cmd_set_depth_bias(cmd, constant_factor, clamp, slope_factor);
- }
-
- /// Calls `vkCmdSetDepthBounds` on the builder.
- #[inline]
- pub unsafe fn set_depth_bounds(&mut self, min: f32, max: f32) {
- let fns = self.device().fns();
- let cmd = self.internal_object();
- debug_assert!(min >= 0.0 && min <= 1.0);
- debug_assert!(max >= 0.0 && max <= 1.0);
- fns.v1_0.cmd_set_depth_bounds(cmd, min, max);
- }
-
- /// Calls `vkCmdSetEvent` on the builder.
- #[inline]
- pub unsafe fn set_event(&mut self, event: &Event, stages: PipelineStages) {
- let fns = self.device().fns();
- let cmd = self.internal_object();
-
- debug_assert!(!stages.host);
- debug_assert_ne!(stages, PipelineStages::none());
-
- fns.v1_0
- .cmd_set_event(cmd, event.internal_object(), stages.into());
- }
-
- /// Calls `vkCmdSetLineWidth` on the builder.
- #[inline]
- pub unsafe fn set_line_width(&mut self, line_width: f32) {
- let fns = self.device().fns();
- let cmd = self.internal_object();
- debug_assert!(line_width == 1.0 || self.device().enabled_features().wide_lines);
- fns.v1_0.cmd_set_line_width(cmd, line_width);
- }
-
- /// Calls `vkCmdSetStencilCompareMask` on the builder.
- #[inline]
- pub unsafe fn set_stencil_compare_mask(&mut self, face_mask: StencilFaces, compare_mask: u32) {
- let fns = self.device().fns();
- let cmd = self.internal_object();
- fns.v1_0
- .cmd_set_stencil_compare_mask(cmd, face_mask.into(), compare_mask);
- }
-
- /// Calls `vkCmdSetStencilReference` on the builder.
- #[inline]
- pub unsafe fn set_stencil_reference(&mut self, face_mask: StencilFaces, reference: u32) {
- let fns = self.device().fns();
- let cmd = self.internal_object();
- fns.v1_0
- .cmd_set_stencil_reference(cmd, face_mask.into(), reference);
- }
-
- /// Calls `vkCmdSetStencilWriteMask` on the builder.
- #[inline]
- pub unsafe fn set_stencil_write_mask(&mut self, face_mask: StencilFaces, write_mask: u32) {
- let fns = self.device().fns();
- let cmd = self.internal_object();
- fns.v1_0
- .cmd_set_stencil_write_mask(cmd, face_mask.into(), write_mask);
- }
-
- /// Calls `vkCmdSetScissor` on the builder.
- ///
- /// If the list is empty then the command is automatically ignored.
- #[inline]
- pub unsafe fn set_scissor<I>(&mut self, first_scissor: u32, scissors: I)
- where
- I: IntoIterator<Item = Scissor>,
- {
- let scissors = scissors
- .into_iter()
- .map(|v| ash::vk::Rect2D::from(v.clone()))
- .collect::<SmallVec<[_; 16]>>();
- if scissors.is_empty() {
- return;
- }
-
- debug_assert!(scissors.iter().all(|s| s.offset.x >= 0 && s.offset.y >= 0));
- debug_assert!(scissors.iter().all(|s| {
- s.extent.width < i32::MAX as u32
- && s.extent.height < i32::MAX as u32
- && s.offset.x.checked_add(s.extent.width as i32).is_some()
- && s.offset.y.checked_add(s.extent.height as i32).is_some()
- }));
- debug_assert!(
- (first_scissor == 0 && scissors.len() == 1)
- || self.device().enabled_features().multi_viewport
- );
- debug_assert!({
- let max = self
- .device()
- .physical_device()
- .properties()
- .max_viewports;
- first_scissor + scissors.len() as u32 <= max
- });
-
- let fns = self.device().fns();
- let cmd = self.internal_object();
- fns.v1_0
- .cmd_set_scissor(cmd, first_scissor, scissors.len() as u32, scissors.as_ptr());
- }
-
- /// Calls `vkCmdSetViewport` on the builder.
- ///
- /// If the list is empty then the command is automatically ignored.
- #[inline]
- pub unsafe fn set_viewport<I>(&mut self, first_viewport: u32, viewports: I)
- where
- I: IntoIterator<Item = Viewport>,
- {
- let viewports = viewports
- .into_iter()
- .map(|v| v.clone().into())
- .collect::<SmallVec<[_; 16]>>();
- if viewports.is_empty() {
- return;
- }
-
- debug_assert!(
- (first_viewport == 0 && viewports.len() == 1)
- || self.device().enabled_features().multi_viewport
- );
- debug_assert!({
- let max = self
- .device()
- .physical_device()
- .properties()
- .max_viewports;
- first_viewport + viewports.len() as u32 <= max
- });
-
- let fns = self.device().fns();
- let cmd = self.internal_object();
- fns.v1_0.cmd_set_viewport(
- cmd,
- first_viewport,
- viewports.len() as u32,
- viewports.as_ptr(),
- );
- }
-
- /// Calls `vkCmdUpdateBuffer` on the builder.
- #[inline]
- pub unsafe fn update_buffer<B, D>(&mut self, buffer: &B, data: &D)
- where
- B: ?Sized + BufferAccess,
- D: ?Sized,
- {
- let fns = self.device().fns();
- let cmd = self.internal_object();
-
- let size = buffer.size();
- debug_assert_eq!(size % 4, 0);
- debug_assert!(size <= 65536);
- debug_assert!(size <= mem::size_of_val(data) as DeviceSize);
-
- let (buffer_handle, offset) = {
- let BufferInner {
- buffer: buffer_inner,
- offset,
- } = buffer.inner();
- debug_assert!(buffer_inner.usage().transfer_destination);
- debug_assert_eq!(offset % 4, 0);
- (buffer_inner.internal_object(), offset)
- };
-
- fns.v1_0.cmd_update_buffer(
- cmd,
- buffer_handle,
- offset,
- size,
- data as *const D as *const _,
- );
- }
-
- /// Calls `vkCmdWriteTimestamp` on the builder.
- #[inline]
- pub unsafe fn write_timestamp(&mut self, query: Query, stage: PipelineStage) {
- let fns = self.device().fns();
- let cmd = self.internal_object();
- fns.v1_0.cmd_write_timestamp(
- cmd,
- stage.into(),
- query.pool().internal_object(),
- query.index(),
- );
- }
-
- /// Calls `vkCmdBeginDebugUtilsLabelEXT` on the builder.
- ///
- /// # Safety
- /// The command pool that this command buffer was allocated from must support graphics or
- /// compute operations
- #[inline]
- pub unsafe fn debug_marker_begin(&mut self, name: &CStr, color: [f32; 4]) {
- let fns = self.device().instance().fns();
- let cmd = self.internal_object();
- let info = ash::vk::DebugUtilsLabelEXT {
- p_label_name: name.as_ptr(),
- color,
- ..Default::default()
- };
- fns.ext_debug_utils
- .cmd_begin_debug_utils_label_ext(cmd, &info);
- }
-
- /// Calls `vkCmdEndDebugUtilsLabelEXT` on the builder.
- ///
- /// # Safety
- /// There must be an outstanding `vkCmdBeginDebugUtilsLabelEXT` command prior to the
- /// `vkQueueEndDebugUtilsLabelEXT` on the queue tha `CommandBuffer` is submitted to.
- #[inline]
- pub unsafe fn debug_marker_end(&mut self) {
- let fns = self.device().instance().fns();
- let cmd = self.internal_object();
- fns.ext_debug_utils.cmd_end_debug_utils_label_ext(cmd);
- }
+unsafe impl VulkanObject for UnsafeCommandBufferBuilder {
+ type Handle = ash::vk::CommandBuffer;
- /// Calls `vkCmdInsertDebugUtilsLabelEXT` on the builder.
- ///
- /// # Safety
- /// The command pool that this command buffer was allocated from must support graphics or
- /// compute operations
#[inline]
- pub unsafe fn debug_marker_insert(&mut self, name: &CStr, color: [f32; 4]) {
- let fns = self.device().instance().fns();
- let cmd = self.internal_object();
- let info = ash::vk::DebugUtilsLabelEXT {
- p_label_name: name.as_ptr(),
- color,
- ..Default::default()
- };
- fns.ext_debug_utils
- .cmd_insert_debug_utils_label_ext(cmd, &info);
+ fn handle(&self) -> Self::Handle {
+ self.handle
}
}
@@ -1560,379 +223,32 @@ unsafe impl DeviceOwned for UnsafeCommandBufferBuilder {
}
}
-unsafe impl VulkanObject for UnsafeCommandBufferBuilder {
- type Object = ash::vk::CommandBuffer;
-
- #[inline]
- fn internal_object(&self) -> ash::vk::CommandBuffer {
- self.command_buffer
- }
-}
-
-/// Prototype for a `vkCmdBindVertexBuffers`.
-pub struct UnsafeCommandBufferBuilderBindVertexBuffer {
- // Raw handles of the buffers to bind.
- raw_buffers: SmallVec<[ash::vk::Buffer; 4]>,
- // Raw offsets of the buffers to bind.
- offsets: SmallVec<[DeviceSize; 4]>,
-}
-
-impl UnsafeCommandBufferBuilderBindVertexBuffer {
- /// Builds a new empty list.
- #[inline]
- pub fn new() -> UnsafeCommandBufferBuilderBindVertexBuffer {
- UnsafeCommandBufferBuilderBindVertexBuffer {
- raw_buffers: SmallVec::new(),
- offsets: SmallVec::new(),
- }
- }
-
- /// Adds a buffer to the list.
- #[inline]
- pub fn add<B>(&mut self, buffer: &B)
- where
- B: ?Sized + BufferAccess,
- {
- let inner = buffer.inner();
- debug_assert!(inner.buffer.usage().vertex_buffer);
- self.raw_buffers.push(inner.buffer.internal_object());
- self.offsets.push(inner.offset);
- }
-}
-
-/// Prototype for a `vkCmdExecuteCommands`.
-pub struct UnsafeCommandBufferBuilderExecuteCommands {
- // Raw handles of the command buffers to execute.
- raw_cbs: SmallVec<[ash::vk::CommandBuffer; 4]>,
-}
-
-impl UnsafeCommandBufferBuilderExecuteCommands {
- /// Builds a new empty list.
- #[inline]
- pub fn new() -> UnsafeCommandBufferBuilderExecuteCommands {
- UnsafeCommandBufferBuilderExecuteCommands {
- raw_cbs: SmallVec::new(),
- }
- }
-
- /// Adds a command buffer to the list.
- #[inline]
- pub fn add<C>(&mut self, cb: &C)
- where
- C: ?Sized + SecondaryCommandBuffer,
- {
- // TODO: debug assert that it is a secondary command buffer?
- self.raw_cbs.push(cb.inner().internal_object());
- }
-
- /// Adds a command buffer to the list.
- #[inline]
- pub unsafe fn add_raw(&mut self, cb: ash::vk::CommandBuffer) {
- self.raw_cbs.push(cb);
- }
-}
-
-// TODO: move somewhere else?
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct UnsafeCommandBufferBuilderColorImageClear {
- pub base_mip_level: u32,
- pub level_count: u32,
- pub base_array_layer: u32,
- pub layer_count: u32,
-}
-
-// TODO: move somewhere else?
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct UnsafeCommandBufferBuilderBufferImageCopy {
- pub buffer_offset: DeviceSize,
- pub buffer_row_length: u32,
- pub buffer_image_height: u32,
- pub image_aspect: ImageAspect,
- pub image_mip_level: u32,
- pub image_base_array_layer: u32,
- pub image_layer_count: u32,
- pub image_offset: [i32; 3],
- pub image_extent: [u32; 3],
-}
-
-// TODO: move somewhere else?
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct UnsafeCommandBufferBuilderImageCopy {
- pub aspects: ImageAspects,
- pub source_mip_level: u32,
- pub destination_mip_level: u32,
- pub source_base_array_layer: u32,
- pub destination_base_array_layer: u32,
- pub layer_count: u32,
- pub source_offset: [i32; 3],
- pub destination_offset: [i32; 3],
- pub extent: [u32; 3],
-}
-
-// TODO: move somewhere else?
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct UnsafeCommandBufferBuilderImageBlit {
- pub aspects: ImageAspects,
- pub source_mip_level: u32,
- pub destination_mip_level: u32,
- pub source_base_array_layer: u32,
- pub destination_base_array_layer: u32,
- pub layer_count: u32,
- pub source_top_left: [i32; 3],
- pub source_bottom_right: [i32; 3],
- pub destination_top_left: [i32; 3],
- pub destination_bottom_right: [i32; 3],
-}
-
-/// Command that adds a pipeline barrier to a command buffer builder.
-///
-/// A pipeline barrier is a low-level system-ish command that is often necessary for safety. By
-/// default all commands that you add to a command buffer can potentially run simultaneously.
-/// Adding a pipeline barrier separates commands before the barrier from commands after the barrier
-/// and prevents them from running simultaneously.
-///
-/// Please take a look at the Vulkan specifications for more information. Pipeline barriers are a
-/// complex topic and explaining them in this documentation would be redundant.
-///
-/// > **Note**: We use a builder-like API here so that users can pass multiple buffers or images of
-/// > multiple different types. Doing so with a single function would be very tedious in terms of
-/// > API.
-pub struct UnsafeCommandBufferBuilderPipelineBarrier {
- src_stage_mask: ash::vk::PipelineStageFlags,
- dst_stage_mask: ash::vk::PipelineStageFlags,
- dependency_flags: ash::vk::DependencyFlags,
- memory_barriers: SmallVec<[ash::vk::MemoryBarrier; 2]>,
- buffer_barriers: SmallVec<[ash::vk::BufferMemoryBarrier; 8]>,
- image_barriers: SmallVec<[ash::vk::ImageMemoryBarrier; 8]>,
-}
-
-impl UnsafeCommandBufferBuilderPipelineBarrier {
- /// Creates a new empty pipeline barrier command.
- #[inline]
- pub fn new() -> UnsafeCommandBufferBuilderPipelineBarrier {
- UnsafeCommandBufferBuilderPipelineBarrier {
- src_stage_mask: ash::vk::PipelineStageFlags::empty(),
- dst_stage_mask: ash::vk::PipelineStageFlags::empty(),
- dependency_flags: ash::vk::DependencyFlags::BY_REGION,
- memory_barriers: SmallVec::new(),
- buffer_barriers: SmallVec::new(),
- image_barriers: SmallVec::new(),
- }
- }
-
- /// Returns true if no barrier or execution dependency has been added yet.
- #[inline]
- pub fn is_empty(&self) -> bool {
- self.src_stage_mask.is_empty() || self.dst_stage_mask.is_empty()
- }
-
- /// Merges another pipeline builder into this one.
- #[inline]
- pub fn merge(&mut self, other: UnsafeCommandBufferBuilderPipelineBarrier) {
- self.src_stage_mask |= other.src_stage_mask;
- self.dst_stage_mask |= other.dst_stage_mask;
- self.dependency_flags &= other.dependency_flags;
-
- self.memory_barriers
- .extend(other.memory_barriers.into_iter());
- self.buffer_barriers
- .extend(other.buffer_barriers.into_iter());
- self.image_barriers.extend(other.image_barriers.into_iter());
- }
-
- /// Adds an execution dependency. This means that all the stages in `source` of the previous
- /// commands must finish before any of the stages in `destination` of the following commands can start.
- ///
- /// # Safety
- ///
- /// - If the pipeline stages include geometry or tessellation stages, then the corresponding
- /// features must have been enabled in the device.
- /// - There are certain rules regarding the pipeline barriers inside render passes.
+/// Parameters to begin recording a command buffer.
+#[derive(Clone, Debug)]
+pub struct CommandBufferBeginInfo {
+ /// How the command buffer will be used.
///
- #[inline]
- pub unsafe fn add_execution_dependency(
- &mut self,
- source: PipelineStages,
- destination: PipelineStages,
- by_region: bool,
- ) {
- if !by_region {
- self.dependency_flags = ash::vk::DependencyFlags::empty();
- }
+ /// The default value is [`CommandBufferUsage::MultipleSubmit`].
+ pub usage: CommandBufferUsage,
- debug_assert_ne!(source, PipelineStages::none());
- debug_assert_ne!(destination, PipelineStages::none());
-
- self.src_stage_mask |= ash::vk::PipelineStageFlags::from(source);
- self.dst_stage_mask |= ash::vk::PipelineStageFlags::from(destination);
- }
-
- /// Adds a memory barrier. This means that all the memory writes by the given source stages
- /// for the given source accesses must be visible by the given destination stages for the given
- /// destination accesses.
- ///
- /// Also adds an execution dependency similar to `add_execution_dependency`.
+ /// For a secondary command buffer, this must be `Some`, containing the context that will be
+ /// inherited from the primary command buffer. For a primary command buffer, this must be
+ /// `None`.
///
- /// # Safety
- ///
- /// - Same as `add_execution_dependency`.
- ///
- pub unsafe fn add_memory_barrier(
- &mut self,
- source_stage: PipelineStages,
- source_access: AccessFlags,
- destination_stage: PipelineStages,
- destination_access: AccessFlags,
- by_region: bool,
- ) {
- debug_assert!(source_access.is_compatible_with(&source_stage));
- debug_assert!(destination_access.is_compatible_with(&destination_stage));
-
- self.add_execution_dependency(source_stage, destination_stage, by_region);
+ /// The default value is `None`.
+ pub inheritance_info: Option<CommandBufferInheritanceInfo>,
- self.memory_barriers.push(ash::vk::MemoryBarrier {
- src_access_mask: source_access.into(),
- dst_access_mask: destination_access.into(),
- ..Default::default()
- });
- }
-
- /// Adds a buffer memory barrier. This means that all the memory writes to the given buffer by
- /// the given source stages for the given source accesses must be visible by the given dest
- /// stages for the given destination accesses.
- ///
- /// Also adds an execution dependency similar to `add_execution_dependency`.
- ///
- /// Also allows transferring buffer ownership between queues.
- ///
- /// # Safety
- ///
- /// - Same as `add_execution_dependency`.
- /// - The buffer must be alive for at least as long as the command buffer to which this barrier
- /// is added.
- /// - Queue ownership transfers must be correct.
- ///
- pub unsafe fn add_buffer_memory_barrier<B>(
- &mut self,
- buffer: &B,
- source_stage: PipelineStages,
- source_access: AccessFlags,
- destination_stage: PipelineStages,
- destination_access: AccessFlags,
- by_region: bool,
- queue_transfer: Option<(u32, u32)>,
- offset: DeviceSize,
- size: DeviceSize,
- ) where
- B: ?Sized + BufferAccess,
- {
- debug_assert!(source_access.is_compatible_with(&source_stage));
- debug_assert!(destination_access.is_compatible_with(&destination_stage));
-
- self.add_execution_dependency(source_stage, destination_stage, by_region);
-
- debug_assert!(size <= buffer.size());
- let BufferInner {
- buffer,
- offset: org_offset,
- } = buffer.inner();
- let offset = offset + org_offset;
-
- let (src_queue, dest_queue) = if let Some((src_queue, dest_queue)) = queue_transfer {
- (src_queue, dest_queue)
- } else {
- (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED)
- };
-
- self.buffer_barriers.push(ash::vk::BufferMemoryBarrier {
- src_access_mask: source_access.into(),
- dst_access_mask: destination_access.into(),
- src_queue_family_index: src_queue,
- dst_queue_family_index: dest_queue,
- buffer: buffer.internal_object(),
- offset,
- size,
- ..Default::default()
- });
- }
-
- /// Adds an image memory barrier. This is the equivalent of `add_buffer_memory_barrier` but
- /// for images.
- ///
- /// In addition to transferring image ownership between queues, it also allows changing the
- /// layout of images.
- ///
- /// Also adds an execution dependency similar to `add_execution_dependency`.
- ///
- /// # Safety
- ///
- /// - Same as `add_execution_dependency`.
- /// - The buffer must be alive for at least as long as the command buffer to which this barrier
- /// is added.
- /// - Queue ownership transfers must be correct.
- /// - Image layouts transfers must be correct.
- /// - Access flags must be compatible with the image usage flags passed at image creation.
- ///
- pub unsafe fn add_image_memory_barrier<I>(
- &mut self,
- image: &I,
- mipmaps: Range<u32>,
- layers: Range<u32>,
- source_stage: PipelineStages,
- source_access: AccessFlags,
- destination_stage: PipelineStages,
- destination_access: AccessFlags,
- by_region: bool,
- queue_transfer: Option<(u32, u32)>,
- current_layout: ImageLayout,
- new_layout: ImageLayout,
- ) where
- I: ?Sized + ImageAccess,
- {
- debug_assert!(source_access.is_compatible_with(&source_stage));
- debug_assert!(destination_access.is_compatible_with(&destination_stage));
-
- self.add_execution_dependency(source_stage, destination_stage, by_region);
-
- debug_assert_ne!(new_layout, ImageLayout::Undefined);
- debug_assert_ne!(new_layout, ImageLayout::Preinitialized);
-
- debug_assert!(mipmaps.start < mipmaps.end);
- debug_assert!(mipmaps.end <= image.mipmap_levels());
- debug_assert!(layers.start < layers.end);
- debug_assert!(layers.end <= image.dimensions().array_layers());
-
- let (src_queue, dest_queue) = if let Some((src_queue, dest_queue)) = queue_transfer {
- (src_queue, dest_queue)
- } else {
- (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED)
- };
+ pub _ne: crate::NonExhaustive,
+}
- if image.format().ty() == FormatTy::Ycbcr {
- unimplemented!();
+impl Default for CommandBufferBeginInfo {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ usage: CommandBufferUsage::MultipleSubmit,
+ inheritance_info: None,
+ _ne: crate::NonExhaustive(()),
}
-
- // TODO: Let user choose
- let aspects = image.format().aspects();
- let image = image.inner();
-
- self.image_barriers.push(ash::vk::ImageMemoryBarrier {
- src_access_mask: source_access.into(),
- dst_access_mask: destination_access.into(),
- old_layout: current_layout.into(),
- new_layout: new_layout.into(),
- src_queue_family_index: src_queue,
- dst_queue_family_index: dest_queue,
- image: image.image.internal_object(),
- subresource_range: ash::vk::ImageSubresourceRange {
- aspect_mask: aspects.into(),
- base_mip_level: mipmaps.start + image.first_mipmap_level as u32,
- level_count: mipmaps.end - mipmaps.start,
- base_array_layer: layers.start + image.first_layer as u32,
- layer_count: layers.end - layers.start,
- },
- ..Default::default()
- });
}
}
@@ -1942,6 +258,7 @@ impl UnsafeCommandBufferBuilderPipelineBarrier {
///
/// The command buffer must not outlive the command pool that it was created from,
/// nor the resources used by the recorded commands.
+#[derive(Debug)]
pub struct UnsafeCommandBuffer {
command_buffer: ash::vk::CommandBuffer,
device: Arc<Device>,
@@ -1963,10 +280,10 @@ unsafe impl DeviceOwned for UnsafeCommandBuffer {
}
unsafe impl VulkanObject for UnsafeCommandBuffer {
- type Object = ash::vk::CommandBuffer;
+ type Handle = ash::vk::CommandBuffer;
#[inline]
- fn internal_object(&self) -> ash::vk::CommandBuffer {
+ fn handle(&self) -> Self::Handle {
self.command_buffer
}
}
diff --git a/src/command_buffer/traits.rs b/src/command_buffer/traits.rs
index 5252073..80469d8 100644
--- a/src/command_buffer/traits.rs
+++ b/src/command_buffer/traits.rs
@@ -7,81 +7,69 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use crate::buffer::BufferAccess;
-use crate::command_buffer::submit::SubmitAnyBuilder;
-use crate::command_buffer::submit::SubmitCommandBufferBuilder;
-use crate::command_buffer::sys::UnsafeCommandBuffer;
-use crate::command_buffer::CommandBufferInheritance;
-use crate::command_buffer::ImageUninitializedSafe;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::device::Queue;
-use crate::image::ImageAccess;
-use crate::image::ImageLayout;
-use crate::render_pass::FramebufferAbstract;
-use crate::sync::now;
-use crate::sync::AccessCheckError;
-use crate::sync::AccessError;
-use crate::sync::AccessFlags;
-use crate::sync::FlushError;
-use crate::sync::GpuFuture;
-use crate::sync::NowFuture;
-use crate::sync::PipelineMemoryAccess;
-use crate::sync::PipelineStages;
-use crate::SafeDeref;
-use crate::VulkanObject;
-use std::borrow::Cow;
-use std::error;
-use std::fmt;
-use std::sync::atomic::AtomicBool;
-use std::sync::atomic::Ordering;
-use std::sync::Arc;
-use std::sync::Mutex;
-
-pub unsafe trait PrimaryCommandBuffer: DeviceOwned {
- /// Returns the underlying `UnsafeCommandBuffer` of this command buffer.
- fn inner(&self) -> &UnsafeCommandBuffer;
-
- /// Checks whether this command buffer is allowed to be submitted after the `future` and on
- /// the given queue, and if so locks it.
- ///
- /// If you call this function, then you should call `unlock` afterwards.
- fn lock_submit(
- &self,
- future: &dyn GpuFuture,
- queue: &Queue,
- ) -> Result<(), CommandBufferExecError>;
+use super::{
+ CommandBufferInheritanceInfo, CommandBufferResourcesUsage, CommandBufferState,
+ CommandBufferUsage, SecondaryCommandBufferResourcesUsage, SemaphoreSubmitInfo, SubmitInfo,
+};
+use crate::{
+ buffer::Buffer,
+ device::{Device, DeviceOwned, Queue},
+ image::{sys::Image, ImageLayout},
+ swapchain::Swapchain,
+ sync::{
+ future::{
+ now, AccessCheckError, AccessError, FlushError, GpuFuture, NowFuture, SubmitAnyBuilder,
+ },
+ PipelineStages,
+ },
+ DeviceSize, SafeDeref, VulkanObject,
+};
+use parking_lot::{Mutex, MutexGuard};
+use std::{
+ borrow::Cow,
+ error::Error,
+ fmt::{Debug, Display, Error as FmtError, Formatter},
+ ops::Range,
+ sync::{
+ atomic::{AtomicBool, Ordering},
+ Arc,
+ },
+ thread,
+};
- /// Unlocks the command buffer. Should be called once for each call to `lock_submit`.
- ///
- /// # Safety
- ///
- /// Must not be called if you haven't called `lock_submit` before.
- unsafe fn unlock(&self);
+pub unsafe trait PrimaryCommandBufferAbstract:
+ VulkanObject<Handle = ash::vk::CommandBuffer> + DeviceOwned + Send + Sync
+{
+ /// Returns the usage of this command buffer.
+ fn usage(&self) -> CommandBufferUsage;
/// Executes this command buffer on a queue.
///
- /// This function returns an object that implements the `GpuFuture` trait. See the
- /// documentation of the `sync` module for more information.
+ /// This function returns an object that implements the [`GpuFuture`] trait. See the
+ /// documentation of the [`future`][crate::sync::future] module for more information.
///
- /// The command buffer is not actually executed until you call `flush()` on the object.
- /// You are encouraged to chain together as many futures as possible before calling `flush()`,
- /// and call `.then_signal_future()` before doing so. Note however that once you called
- /// `execute()` there is no way to cancel the execution, even if you didn't flush yet.
+ /// The command buffer is not actually executed until you call [`flush()`][GpuFuture::flush] on
+ /// the future. You are encouraged to chain together as many futures as possible prior to
+ /// calling [`flush()`][GpuFuture::flush]. In order to know when the future has completed, call
+ /// one of [`then_signal_fence()`][GpuFuture::then_signal_fence] or
+ /// [`then_signal_semaphore()`][GpuFuture::then_signal_semaphore]. You can do both together
+ /// with [`then_signal_fence_and_flush()`][GpuFuture::then_signal_fence_and_flush] or
+ /// [`then_signal_semaphore_and_flush()`][GpuFuture::then_signal_semaphore_and_flush],
+ /// respectively.
///
/// > **Note**: In the future this function may return `-> impl GpuFuture` instead of a
/// > concrete type.
///
/// > **Note**: This is just a shortcut for `execute_after(vulkano::sync::now(), queue)`.
///
- /// # Panic
+ /// # Panics
///
- /// Panics if the device of the command buffer is not the same as the device of the future.
+ /// - Panics if the device of the command buffer is not the same as the device of the future.
#[inline]
fn execute(
self,
queue: Arc<Queue>,
- ) -> Result<CommandBufferExecFuture<NowFuture, Self>, CommandBufferExecError>
+ ) -> Result<CommandBufferExecFuture<NowFuture>, CommandBufferExecError>
where
Self: Sized + 'static,
{
@@ -91,13 +79,17 @@ pub unsafe trait PrimaryCommandBuffer: DeviceOwned {
/// Executes the command buffer after an existing future.
///
- /// This function returns an object that implements the `GpuFuture` trait. See the
- /// documentation of the `sync` module for more information.
+ /// This function returns an object that implements the [`GpuFuture`] trait. See the
+ /// documentation of the [`future`][crate::sync::future] module for more information.
///
- /// The command buffer is not actually executed until you call `flush()` on the object.
- /// You are encouraged to chain together as many futures as possible before calling `flush()`,
- /// and call `.then_signal_future()` before doing so. Note however that once you called
- /// `execute()` there is no way to cancel the execution, even if you didn't flush yet.
+ /// The command buffer is not actually executed until you call [`flush()`][GpuFuture::flush] on
+ /// the future. You are encouraged to chain together as many futures as possible prior to
+ /// calling [`flush()`][GpuFuture::flush]. In order to know when the future has completed, call
+ /// one of [`then_signal_fence()`][GpuFuture::then_signal_fence] or
+ /// [`then_signal_semaphore()`][GpuFuture::then_signal_semaphore]. You can do both together
+ /// with [`then_signal_fence_and_flush()`][GpuFuture::then_signal_fence_and_flush] or
+ /// [`then_signal_semaphore_and_flush()`][GpuFuture::then_signal_semaphore_and_flush],
+ /// respectively.
///
/// > **Note**: In the future this function may return `-> impl GpuFuture` instead of a
/// > concrete type.
@@ -108,104 +100,73 @@ pub unsafe trait PrimaryCommandBuffer: DeviceOwned {
/// `std::mem::forget` on that object and "unlock" these resources. For more information about
/// this problem, search the web for "rust thread scoped leakpocalypse".
///
- /// # Panic
+ /// # Panics
///
- /// Panics if the device of the command buffer is not the same as the device of the future.
- #[inline]
+ /// - Panics if the device of the command buffer is not the same as the device of the future.
fn execute_after<F>(
self,
future: F,
queue: Arc<Queue>,
- ) -> Result<CommandBufferExecFuture<F, Self>, CommandBufferExecError>
+ ) -> Result<CommandBufferExecFuture<F>, CommandBufferExecError>
where
Self: Sized + 'static,
F: GpuFuture,
{
- assert_eq!(
- self.device().internal_object(),
- future.device().internal_object()
- );
+ assert_eq!(self.device().handle(), future.device().handle());
if !future.queue_change_allowed() {
- assert!(future.queue().unwrap().is_same(&queue));
+ assert!(future.queue().unwrap() == queue);
}
- self.lock_submit(&future, &queue)?;
-
Ok(CommandBufferExecFuture {
previous: future,
- command_buffer: self,
+ command_buffer: Arc::new(self),
queue,
submitted: Mutex::new(false),
finished: AtomicBool::new(false),
})
}
- fn check_buffer_access(
- &self,
- buffer: &dyn BufferAccess,
- exclusive: bool,
- queue: &Queue,
- ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>;
+ #[doc(hidden)]
+ fn state(&self) -> MutexGuard<'_, CommandBufferState>;
- fn check_image_access(
- &self,
- image: &dyn ImageAccess,
- layout: ImageLayout,
- exclusive: bool,
- queue: &Queue,
- ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>;
+ #[doc(hidden)]
+ fn resources_usage(&self) -> &CommandBufferResourcesUsage;
}
-unsafe impl<T> PrimaryCommandBuffer for T
-where
- T: SafeDeref,
- T::Target: PrimaryCommandBuffer,
-{
- #[inline]
- fn inner(&self) -> &UnsafeCommandBuffer {
- (**self).inner()
- }
-
- #[inline]
- fn lock_submit(
- &self,
- future: &dyn GpuFuture,
- queue: &Queue,
- ) -> Result<(), CommandBufferExecError> {
- (**self).lock_submit(future, queue)
+impl Debug for dyn PrimaryCommandBufferAbstract {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ Debug::fmt(&self.handle(), f)
}
+}
- #[inline]
- unsafe fn unlock(&self) {
- (**self).unlock();
+unsafe impl<T> PrimaryCommandBufferAbstract for T
+where
+ T: VulkanObject<Handle = ash::vk::CommandBuffer> + SafeDeref + Send + Sync,
+ T::Target: PrimaryCommandBufferAbstract,
+{
+ fn usage(&self) -> CommandBufferUsage {
+ (**self).usage()
}
- #[inline]
- fn check_buffer_access(
- &self,
- buffer: &dyn BufferAccess,
- exclusive: bool,
- queue: &Queue,
- ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
- (**self).check_buffer_access(buffer, exclusive, queue)
+ fn state(&self) -> MutexGuard<'_, CommandBufferState> {
+ (**self).state()
}
- #[inline]
- fn check_image_access(
- &self,
- image: &dyn ImageAccess,
- layout: ImageLayout,
- exclusive: bool,
- queue: &Queue,
- ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
- (**self).check_image_access(image, layout, exclusive, queue)
+ fn resources_usage(&self) -> &CommandBufferResourcesUsage {
+ (**self).resources_usage()
}
}
-pub unsafe trait SecondaryCommandBuffer: DeviceOwned {
- /// Returns the underlying `UnsafeCommandBuffer` of this command buffer.
- fn inner(&self) -> &UnsafeCommandBuffer;
+pub unsafe trait SecondaryCommandBufferAbstract:
+ VulkanObject<Handle = ash::vk::CommandBuffer> + DeviceOwned + Send + Sync
+{
+ /// Returns the usage of this command buffer.
+ fn usage(&self) -> CommandBufferUsage;
+
+ /// Returns a `CommandBufferInheritance` value describing the properties that the command
+ /// buffer inherits from its parent primary command buffer.
+ fn inheritance_info(&self) -> &CommandBufferInheritanceInfo;
/// Checks whether this command buffer is allowed to be recorded to a command buffer,
/// and if so locks it.
@@ -220,101 +181,46 @@ pub unsafe trait SecondaryCommandBuffer: DeviceOwned {
/// Must not be called if you haven't called `lock_record` before.
unsafe fn unlock(&self);
- /// Returns a `CommandBufferInheritance` value describing the properties that the command
- /// buffer inherits from its parent primary command buffer.
- fn inheritance(&self) -> CommandBufferInheritance<&dyn FramebufferAbstract>;
-
- /// Returns the number of buffers accessed by this command buffer.
- fn num_buffers(&self) -> usize;
-
- /// Returns the `index`th buffer of this command buffer, or `None` if out of range.
- ///
- /// The valid range is between 0 and `num_buffers()`.
- fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, PipelineMemoryAccess)>;
-
- /// Returns the number of images accessed by this command buffer.
- fn num_images(&self) -> usize;
-
- /// Returns the `index`th image of this command buffer, or `None` if out of range.
- ///
- /// The valid range is between 0 and `num_images()`.
- fn image(
- &self,
- index: usize,
- ) -> Option<(
- &dyn ImageAccess,
- PipelineMemoryAccess,
- ImageLayout,
- ImageLayout,
- ImageUninitializedSafe,
- )>;
+ #[doc(hidden)]
+ fn resources_usage(&self) -> &SecondaryCommandBufferResourcesUsage;
}
-unsafe impl<T> SecondaryCommandBuffer for T
+unsafe impl<T> SecondaryCommandBufferAbstract for T
where
- T: SafeDeref,
- T::Target: SecondaryCommandBuffer,
+ T: VulkanObject<Handle = ash::vk::CommandBuffer> + SafeDeref + Send + Sync,
+ T::Target: SecondaryCommandBufferAbstract,
{
- #[inline]
- fn inner(&self) -> &UnsafeCommandBuffer {
- (**self).inner()
+ fn usage(&self) -> CommandBufferUsage {
+ (**self).usage()
+ }
+
+ fn inheritance_info(&self) -> &CommandBufferInheritanceInfo {
+ (**self).inheritance_info()
}
- #[inline]
fn lock_record(&self) -> Result<(), CommandBufferExecError> {
(**self).lock_record()
}
- #[inline]
unsafe fn unlock(&self) {
(**self).unlock();
}
- #[inline]
- fn inheritance(&self) -> CommandBufferInheritance<&dyn FramebufferAbstract> {
- (**self).inheritance()
- }
-
- #[inline]
- fn num_buffers(&self) -> usize {
- (**self).num_buffers()
- }
-
- #[inline]
- fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, PipelineMemoryAccess)> {
- (**self).buffer(index)
- }
-
- #[inline]
- fn num_images(&self) -> usize {
- (**self).num_images()
- }
-
- #[inline]
- fn image(
- &self,
- index: usize,
- ) -> Option<(
- &dyn ImageAccess,
- PipelineMemoryAccess,
- ImageLayout,
- ImageLayout,
- ImageUninitializedSafe,
- )> {
- (**self).image(index)
+ fn resources_usage(&self) -> &SecondaryCommandBufferResourcesUsage {
+ (**self).resources_usage()
}
}
/// Represents a command buffer being executed by the GPU and the moment when the execution
/// finishes.
+#[derive(Debug)]
#[must_use = "Dropping this object will immediately block the thread until the GPU has finished processing the submission"]
-pub struct CommandBufferExecFuture<F, Cb>
+pub struct CommandBufferExecFuture<F>
where
F: GpuFuture,
- Cb: PrimaryCommandBuffer,
{
previous: F,
- command_buffer: Cb,
+ command_buffer: Arc<dyn PrimaryCommandBufferAbstract>,
queue: Arc<Queue>,
// True if the command buffer has already been submitted.
// If flush is called multiple times, we want to block so that only one flushing is executed.
@@ -323,34 +229,48 @@ where
finished: AtomicBool,
}
-unsafe impl<F, Cb> GpuFuture for CommandBufferExecFuture<F, Cb>
+impl<F> CommandBufferExecFuture<F>
where
F: GpuFuture,
- Cb: PrimaryCommandBuffer,
{
- #[inline]
- fn cleanup_finished(&mut self) {
- self.previous.cleanup_finished();
- }
-
- unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
+ // Implementation of `build_submission`. Doesn't check whenever the future was already flushed.
+ // You must make sure to not submit same command buffer multiple times.
+ unsafe fn build_submission_impl(&self) -> Result<SubmitAnyBuilder, FlushError> {
Ok(match self.previous.build_submission()? {
- SubmitAnyBuilder::Empty => {
- let mut builder = SubmitCommandBufferBuilder::new();
- builder.add_command_buffer(self.command_buffer.inner());
- SubmitAnyBuilder::CommandBuffer(builder)
+ SubmitAnyBuilder::Empty => SubmitAnyBuilder::CommandBuffer(
+ SubmitInfo {
+ command_buffers: vec![self.command_buffer.clone()],
+ ..Default::default()
+ },
+ None,
+ ),
+ SubmitAnyBuilder::SemaphoresWait(semaphores) => {
+ SubmitAnyBuilder::CommandBuffer(
+ SubmitInfo {
+ wait_semaphores: semaphores
+ .into_iter()
+ .map(|semaphore| {
+ SemaphoreSubmitInfo {
+ // TODO: correct stages ; hard
+ stages: PipelineStages::ALL_COMMANDS,
+ ..SemaphoreSubmitInfo::semaphore(semaphore)
+ }
+ })
+ .collect(),
+ command_buffers: vec![self.command_buffer.clone()],
+ ..Default::default()
+ },
+ None,
+ )
}
- SubmitAnyBuilder::SemaphoresWait(sem) => {
- let mut builder: SubmitCommandBufferBuilder = sem.into();
- builder.add_command_buffer(self.command_buffer.inner());
- SubmitAnyBuilder::CommandBuffer(builder)
- }
- SubmitAnyBuilder::CommandBuffer(mut builder) => {
+ SubmitAnyBuilder::CommandBuffer(mut submit_info, fence) => {
// FIXME: add pipeline barrier
- builder.add_command_buffer(self.command_buffer.inner());
- SubmitAnyBuilder::CommandBuffer(builder)
+ submit_info
+ .command_buffers
+ .push(self.command_buffer.clone());
+ SubmitAnyBuilder::CommandBuffer(submit_info, fence)
}
- SubmitAnyBuilder::QueuePresent(_) | SubmitAnyBuilder::BindSparse(_) => {
+ SubmitAnyBuilder::QueuePresent(_) | SubmitAnyBuilder::BindSparse(_, _) => {
unimplemented!() // TODO:
/*present.submit(); // TODO: wrong
let mut builder = SubmitCommandBufferBuilder::new();
@@ -359,21 +279,37 @@ where
}
})
}
+}
+
+unsafe impl<F> GpuFuture for CommandBufferExecFuture<F>
+where
+ F: GpuFuture,
+{
+ fn cleanup_finished(&mut self) {
+ self.previous.cleanup_finished();
+ }
+
+ unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
+ if *self.submitted.lock() {
+ return Ok(SubmitAnyBuilder::Empty);
+ }
+
+ self.build_submission_impl()
+ }
- #[inline]
fn flush(&self) -> Result<(), FlushError> {
unsafe {
- let mut submitted = self.submitted.lock().unwrap();
+ let mut submitted = self.submitted.lock();
if *submitted {
return Ok(());
}
- let queue = self.queue.clone();
-
- match self.build_submission()? {
+ match self.build_submission_impl()? {
SubmitAnyBuilder::Empty => {}
- SubmitAnyBuilder::CommandBuffer(builder) => {
- builder.submit(&queue)?;
+ SubmitAnyBuilder::CommandBuffer(submit_info, fence) => {
+ self.queue.with(|mut q| {
+ q.submit_with_future(submit_info, fence, &self.previous, &self.queue)
+ })?;
}
_ => unreachable!(),
};
@@ -384,91 +320,134 @@ where
}
}
- #[inline]
unsafe fn signal_finished(&self) {
- if self.finished.swap(true, Ordering::SeqCst) == false {
- self.command_buffer.unlock();
- }
-
+ self.finished.store(true, Ordering::SeqCst);
self.previous.signal_finished();
}
- #[inline]
fn queue_change_allowed(&self) -> bool {
false
}
- #[inline]
fn queue(&self) -> Option<Arc<Queue>> {
Some(self.queue.clone())
}
- #[inline]
fn check_buffer_access(
&self,
- buffer: &dyn BufferAccess,
+ buffer: &Buffer,
+ range: Range<DeviceSize>,
exclusive: bool,
queue: &Queue,
- ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
- match self
- .command_buffer
- .check_buffer_access(buffer, exclusive, queue)
- {
- Ok(v) => Ok(v),
+ ) -> Result<(), AccessCheckError> {
+ let resources_usage = self.command_buffer.resources_usage();
+ let usage = match resources_usage.buffer_indices.get(buffer) {
+ Some(&index) => &resources_usage.buffers[index],
+ None => return Err(AccessCheckError::Unknown),
+ };
+
+ // TODO: check the queue family
+
+ let result = usage
+ .ranges
+ .range(&range)
+ .try_fold((), |_, (_range, range_usage)| {
+ if !range_usage.mutable && exclusive {
+ Err(AccessCheckError::Unknown)
+ } else {
+ Ok(())
+ }
+ });
+
+ match result {
+ Ok(()) => Ok(()),
Err(AccessCheckError::Denied(err)) => Err(AccessCheckError::Denied(err)),
- Err(AccessCheckError::Unknown) => {
- self.previous.check_buffer_access(buffer, exclusive, queue)
- }
+ Err(AccessCheckError::Unknown) => self
+ .previous
+ .check_buffer_access(buffer, range, exclusive, queue),
}
}
- #[inline]
fn check_image_access(
&self,
- image: &dyn ImageAccess,
- layout: ImageLayout,
+ image: &Image,
+ range: Range<DeviceSize>,
exclusive: bool,
+ expected_layout: ImageLayout,
queue: &Queue,
- ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
- match self
- .command_buffer
- .check_image_access(image, layout, exclusive, queue)
- {
- Ok(v) => Ok(v),
+ ) -> Result<(), AccessCheckError> {
+ let resources_usage = self.command_buffer.resources_usage();
+ let usage = match resources_usage.image_indices.get(image) {
+ Some(&index) => &resources_usage.images[index],
+ None => return Err(AccessCheckError::Unknown),
+ };
+
+ // TODO: check the queue family
+
+ let result = usage
+ .ranges
+ .range(&range)
+ .try_fold((), |_, (_range, range_usage)| {
+ if expected_layout != ImageLayout::Undefined
+ && range_usage.final_layout != expected_layout
+ {
+ return Err(AccessCheckError::Denied(
+ AccessError::UnexpectedImageLayout {
+ allowed: range_usage.final_layout,
+ requested: expected_layout,
+ },
+ ));
+ }
+
+ if !range_usage.mutable && exclusive {
+ Err(AccessCheckError::Unknown)
+ } else {
+ Ok(())
+ }
+ });
+
+ match result {
+ Ok(()) => Ok(()),
Err(AccessCheckError::Denied(err)) => Err(AccessCheckError::Denied(err)),
- Err(AccessCheckError::Unknown) => self
- .previous
- .check_image_access(image, layout, exclusive, queue),
+ Err(AccessCheckError::Unknown) => {
+ self.previous
+ .check_image_access(image, range, exclusive, expected_layout, queue)
+ }
}
}
+
+ #[inline]
+ fn check_swapchain_image_acquired(
+ &self,
+ swapchain: &Swapchain,
+ image_index: u32,
+ _before: bool,
+ ) -> Result<(), AccessCheckError> {
+ self.previous
+ .check_swapchain_image_acquired(swapchain, image_index, false)
+ }
}
-unsafe impl<F, Cb> DeviceOwned for CommandBufferExecFuture<F, Cb>
+unsafe impl<F> DeviceOwned for CommandBufferExecFuture<F>
where
F: GpuFuture,
- Cb: PrimaryCommandBuffer,
{
- #[inline]
fn device(&self) -> &Arc<Device> {
self.command_buffer.device()
}
}
-impl<F, Cb> Drop for CommandBufferExecFuture<F, Cb>
+impl<F> Drop for CommandBufferExecFuture<F>
where
F: GpuFuture,
- Cb: PrimaryCommandBuffer,
{
fn drop(&mut self) {
- unsafe {
- if !*self.finished.get_mut() {
- // TODO: handle errors?
- self.flush().unwrap();
- // Block until the queue finished.
- self.queue.wait().unwrap();
- self.command_buffer.unlock();
- self.previous.signal_finished();
- }
+ if !*self.finished.get_mut() && !thread::panicking() {
+ // TODO: handle errors?
+ self.flush().unwrap();
+ // Block until the queue finished.
+ self.queue.with(|mut q| q.wait_idle()).unwrap();
+ unsafe { self.previous.signal_finished() };
}
}
}
@@ -494,33 +473,31 @@ pub enum CommandBufferExecError {
// TODO: missing entries (eg. wrong queue family, secondary command buffer)
}
-impl error::Error for CommandBufferExecError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- CommandBufferExecError::AccessError { ref error, .. } => Some(error),
+impl Error for CommandBufferExecError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ CommandBufferExecError::AccessError { error, .. } => Some(error),
_ => None,
}
}
}
-impl fmt::Display for CommandBufferExecError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+impl Display for CommandBufferExecError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
write!(
- fmt,
+ f,
"{}",
- match *self {
+ match self {
CommandBufferExecError::AccessError { .. } =>
"access to a resource has been denied",
CommandBufferExecError::OneTimeSubmitAlreadySubmitted => {
"the command buffer or one of the secondary command buffers it executes was \
- created with the \"one time submit\" flag, but has already been submitted in \
- the past"
+ created with the \"one time submit\" flag, but has already been submitted in \
+ the past"
}
CommandBufferExecError::ExclusiveAlreadyInUse => {
"the command buffer or one of the secondary command buffers it executes is \
- already in use was not created with the \"concurrent\" flag"
+ already in use was not created with the \"concurrent\" flag"
}
}
)
diff --git a/src/command_buffer/validity/blit_image.rs b/src/command_buffer/validity/blit_image.rs
deleted file mode 100644
index aae58f6..0000000
--- a/src/command_buffer/validity/blit_image.rs
+++ /dev/null
@@ -1,302 +0,0 @@
-// Copyright (c) 2017 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::device::Device;
-use crate::format::FormatTy;
-use crate::image::ImageAccess;
-use crate::image::ImageDimensions;
-use crate::image::SampleCount;
-use crate::sampler::Filter;
-use crate::VulkanObject;
-use std::error;
-use std::fmt;
-
-/// Checks whether a blit image command is valid.
-///
-/// Note that this doesn't check whether `layer_count` is equal to 0. TODO: change that?
-///
-/// # Panic
-///
-/// - Panics if the source or the destination was not created with `device`.
-///
-pub fn check_blit_image<S, D>(
- device: &Device,
- source: &S,
- source_top_left: [i32; 3],
- source_bottom_right: [i32; 3],
- source_base_array_layer: u32,
- source_mip_level: u32,
- destination: &D,
- destination_top_left: [i32; 3],
- destination_bottom_right: [i32; 3],
- destination_base_array_layer: u32,
- destination_mip_level: u32,
- layer_count: u32,
- filter: Filter,
-) -> Result<(), CheckBlitImageError>
-where
- S: ?Sized + ImageAccess,
- D: ?Sized + ImageAccess,
-{
- let source_inner = source.inner();
- let destination_inner = destination.inner();
-
- assert_eq!(
- source_inner.image.device().internal_object(),
- device.internal_object()
- );
- assert_eq!(
- destination_inner.image.device().internal_object(),
- device.internal_object()
- );
-
- if !source_inner.image.usage().transfer_source {
- return Err(CheckBlitImageError::MissingTransferSourceUsage);
- }
-
- if !destination_inner.image.usage().transfer_destination {
- return Err(CheckBlitImageError::MissingTransferDestinationUsage);
- }
-
- if !source_inner.image.format_features().blit_src {
- return Err(CheckBlitImageError::SourceFormatNotSupported);
- }
-
- if !destination_inner.image.format_features().blit_dst {
- return Err(CheckBlitImageError::DestinationFormatNotSupported);
- }
-
- if source.samples() != SampleCount::Sample1 || destination.samples() != SampleCount::Sample1 {
- return Err(CheckBlitImageError::UnexpectedMultisampled);
- }
-
- let source_format_ty = source.format().ty();
- let destination_format_ty = destination.format().ty();
-
- if matches!(
- source_format_ty,
- FormatTy::Depth | FormatTy::Stencil | FormatTy::DepthStencil
- ) {
- if source.format() != destination.format() {
- return Err(CheckBlitImageError::DepthStencilFormatMismatch);
- }
-
- if filter != Filter::Nearest {
- return Err(CheckBlitImageError::DepthStencilNearestMandatory);
- }
- }
-
- let types_should_be_same = source_format_ty == FormatTy::Uint
- || destination_format_ty == FormatTy::Uint
- || source_format_ty == FormatTy::Sint
- || destination_format_ty == FormatTy::Sint;
- if types_should_be_same && (source_format_ty != destination_format_ty) {
- return Err(CheckBlitImageError::IncompatibleFormatsTypes {
- source_format_ty: source.format().ty(),
- destination_format_ty: destination.format().ty(),
- });
- }
-
- let source_dimensions = match source.dimensions().mipmap_dimensions(source_mip_level) {
- Some(d) => d,
- None => return Err(CheckBlitImageError::SourceCoordinatesOutOfRange),
- };
-
- let destination_dimensions = match destination
- .dimensions()
- .mipmap_dimensions(destination_mip_level)
- {
- Some(d) => d,
- None => return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange),
- };
-
- if source_base_array_layer + layer_count > source_dimensions.array_layers() {
- return Err(CheckBlitImageError::SourceCoordinatesOutOfRange);
- }
-
- if destination_base_array_layer + layer_count > destination_dimensions.array_layers() {
- return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange);
- }
-
- if source_top_left[0] < 0 || source_top_left[0] > source_dimensions.width() as i32 {
- return Err(CheckBlitImageError::SourceCoordinatesOutOfRange);
- }
-
- if source_top_left[1] < 0 || source_top_left[1] > source_dimensions.height() as i32 {
- return Err(CheckBlitImageError::SourceCoordinatesOutOfRange);
- }
-
- if source_top_left[2] < 0 || source_top_left[2] > source_dimensions.depth() as i32 {
- return Err(CheckBlitImageError::SourceCoordinatesOutOfRange);
- }
-
- if source_bottom_right[0] < 0 || source_bottom_right[0] > source_dimensions.width() as i32 {
- return Err(CheckBlitImageError::SourceCoordinatesOutOfRange);
- }
-
- if source_bottom_right[1] < 0 || source_bottom_right[1] > source_dimensions.height() as i32 {
- return Err(CheckBlitImageError::SourceCoordinatesOutOfRange);
- }
-
- if source_bottom_right[2] < 0 || source_bottom_right[2] > source_dimensions.depth() as i32 {
- return Err(CheckBlitImageError::SourceCoordinatesOutOfRange);
- }
-
- if destination_top_left[0] < 0
- || destination_top_left[0] > destination_dimensions.width() as i32
- {
- return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange);
- }
-
- if destination_top_left[1] < 0
- || destination_top_left[1] > destination_dimensions.height() as i32
- {
- return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange);
- }
-
- if destination_top_left[2] < 0
- || destination_top_left[2] > destination_dimensions.depth() as i32
- {
- return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange);
- }
-
- if destination_bottom_right[0] < 0
- || destination_bottom_right[0] > destination_dimensions.width() as i32
- {
- return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange);
- }
-
- if destination_bottom_right[1] < 0
- || destination_bottom_right[1] > destination_dimensions.height() as i32
- {
- return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange);
- }
-
- if destination_bottom_right[2] < 0
- || destination_bottom_right[2] > destination_dimensions.depth() as i32
- {
- return Err(CheckBlitImageError::DestinationCoordinatesOutOfRange);
- }
-
- match source_dimensions {
- ImageDimensions::Dim1d { .. } => {
- if source_top_left[1] != 0 || source_bottom_right[1] != 1 {
- return Err(CheckBlitImageError::IncompatibleRangeForImageType);
- }
- if source_top_left[2] != 0 || source_bottom_right[2] != 1 {
- return Err(CheckBlitImageError::IncompatibleRangeForImageType);
- }
- }
- ImageDimensions::Dim2d { .. } => {
- if source_top_left[2] != 0 || source_bottom_right[2] != 1 {
- return Err(CheckBlitImageError::IncompatibleRangeForImageType);
- }
- }
- ImageDimensions::Dim3d { .. } => {}
- }
-
- match destination_dimensions {
- ImageDimensions::Dim1d { .. } => {
- if destination_top_left[1] != 0 || destination_bottom_right[1] != 1 {
- return Err(CheckBlitImageError::IncompatibleRangeForImageType);
- }
- if destination_top_left[2] != 0 || destination_bottom_right[2] != 1 {
- return Err(CheckBlitImageError::IncompatibleRangeForImageType);
- }
- }
- ImageDimensions::Dim2d { .. } => {
- if destination_top_left[2] != 0 || destination_bottom_right[2] != 1 {
- return Err(CheckBlitImageError::IncompatibleRangeForImageType);
- }
- }
- ImageDimensions::Dim3d { .. } => {}
- }
-
- Ok(())
-}
-
-/// Error that can happen from `check_clear_color_image`.
-#[derive(Debug, Copy, Clone)]
-pub enum CheckBlitImageError {
- /// The source is missing the transfer source usage.
- MissingTransferSourceUsage,
- /// The destination is missing the transfer destination usage.
- MissingTransferDestinationUsage,
- /// The format of the source image doesn't support blit operations.
- SourceFormatNotSupported,
- /// The format of the destination image doesn't support blit operations.
- DestinationFormatNotSupported,
- /// You must use the nearest filter when blitting depth/stencil images.
- DepthStencilNearestMandatory,
- /// The format of the source and destination must be equal when blitting depth/stencil images.
- DepthStencilFormatMismatch,
- /// The types of the source format and the destination format aren't compatible.
- IncompatibleFormatsTypes {
- source_format_ty: FormatTy,
- destination_format_ty: FormatTy,
- },
- /// Blitting between multisampled images is forbidden.
- UnexpectedMultisampled,
- /// The offsets, array layers and/or mipmap levels are out of range in the source image.
- SourceCoordinatesOutOfRange,
- /// The offsets, array layers and/or mipmap levels are out of range in the destination image.
- DestinationCoordinatesOutOfRange,
- /// The top-left and/or bottom-right coordinates are incompatible with the image type.
- IncompatibleRangeForImageType,
-}
-
-impl error::Error for CheckBlitImageError {}
-
-impl fmt::Display for CheckBlitImageError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- CheckBlitImageError::MissingTransferSourceUsage => {
- "the source is missing the transfer source usage"
- }
- CheckBlitImageError::MissingTransferDestinationUsage => {
- "the destination is missing the transfer destination usage"
- }
- CheckBlitImageError::SourceFormatNotSupported => {
- "the format of the source image doesn't support blit operations"
- }
- CheckBlitImageError::DestinationFormatNotSupported => {
- "the format of the destination image doesn't support blit operations"
- }
- CheckBlitImageError::DepthStencilNearestMandatory => {
- "you must use the nearest filter when blitting depth/stencil images"
- }
- CheckBlitImageError::DepthStencilFormatMismatch => {
- "the format of the source and destination must be equal when blitting \
- depth/stencil images"
- }
- CheckBlitImageError::IncompatibleFormatsTypes { .. } => {
- "the types of the source format and the destination format aren't compatible"
- }
- CheckBlitImageError::UnexpectedMultisampled => {
- "blitting between multisampled images is forbidden"
- }
- CheckBlitImageError::SourceCoordinatesOutOfRange => {
- "the offsets, array layers and/or mipmap levels are out of range in the source \
- image"
- }
- CheckBlitImageError::DestinationCoordinatesOutOfRange => {
- "the offsets, array layers and/or mipmap levels are out of range in the \
- destination image"
- }
- CheckBlitImageError::IncompatibleRangeForImageType => {
- "the top-left and/or bottom-right coordinates are incompatible with the image type"
- }
- }
- )
- }
-}
diff --git a/src/command_buffer/validity/clear_color_image.rs b/src/command_buffer/validity/clear_color_image.rs
deleted file mode 100644
index 6ecb68f..0000000
--- a/src/command_buffer/validity/clear_color_image.rs
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use std::error;
-use std::fmt;
-
-use crate::device::Device;
-use crate::image::ImageAccess;
-use crate::VulkanObject;
-
-/// Checks whether a clear color image command is valid.
-///
-/// # Panic
-///
-/// - Panics if the destination was not created with `device`.
-///
-pub fn check_clear_color_image<I>(
- device: &Device,
- image: &I,
- first_layer: u32,
- num_layers: u32,
- first_mipmap: u32,
- num_mipmaps: u32,
-) -> Result<(), CheckClearColorImageError>
-where
- I: ?Sized + ImageAccess,
-{
- assert_eq!(
- image.inner().image.device().internal_object(),
- device.internal_object()
- );
-
- if !image.inner().image.usage().transfer_destination {
- return Err(CheckClearColorImageError::MissingTransferUsage);
- }
-
- if first_layer + num_layers > image.dimensions().array_layers() {
- return Err(CheckClearColorImageError::OutOfRange);
- }
-
- if first_mipmap + num_mipmaps > image.mipmap_levels() {
- return Err(CheckClearColorImageError::OutOfRange);
- }
-
- Ok(())
-}
-
-/// Error that can happen from `check_clear_color_image`.
-#[derive(Debug, Copy, Clone)]
-pub enum CheckClearColorImageError {
- /// The image is missing the transfer destination usage.
- MissingTransferUsage,
- /// The array layers and mipmap levels are out of range.
- OutOfRange,
-}
-
-impl error::Error for CheckClearColorImageError {}
-
-impl fmt::Display for CheckClearColorImageError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- CheckClearColorImageError::MissingTransferUsage => {
- "the image is missing the transfer destination usage"
- }
- CheckClearColorImageError::OutOfRange => {
- "the array layers and mipmap levels are out of range"
- }
- }
- )
- }
-}
diff --git a/src/command_buffer/validity/copy_buffer.rs b/src/command_buffer/validity/copy_buffer.rs
deleted file mode 100644
index 3691860..0000000
--- a/src/command_buffer/validity/copy_buffer.rs
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::buffer::TypedBufferAccess;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::DeviceSize;
-use crate::VulkanObject;
-use std::cmp;
-use std::error;
-use std::fmt;
-
-/// Checks whether a copy buffer command is valid.
-///
-/// # Panic
-///
-/// - Panics if the source and destination were not created with `device`.
-///
-pub fn check_copy_buffer<S, D, T>(
- device: &Device,
- source: &S,
- destination: &D,
-) -> Result<CheckCopyBuffer, CheckCopyBufferError>
-where
- S: ?Sized + TypedBufferAccess<Content = T>,
- D: ?Sized + TypedBufferAccess<Content = T>,
- T: ?Sized,
-{
- assert_eq!(
- source.inner().buffer.device().internal_object(),
- device.internal_object()
- );
- assert_eq!(
- destination.inner().buffer.device().internal_object(),
- device.internal_object()
- );
-
- if !source.inner().buffer.usage().transfer_source {
- return Err(CheckCopyBufferError::SourceMissingTransferUsage);
- }
-
- if !destination.inner().buffer.usage().transfer_destination {
- return Err(CheckCopyBufferError::DestinationMissingTransferUsage);
- }
-
- let copy_size = cmp::min(source.size(), destination.size());
-
- if source.conflict_key() == destination.conflict_key() {
- return Err(CheckCopyBufferError::OverlappingRanges);
- } else {
- debug_assert!(destination.conflict_key() != source.conflict_key());
- }
-
- Ok(CheckCopyBuffer { copy_size })
-}
-
-/// Information returned if `check_copy_buffer` succeeds.
-pub struct CheckCopyBuffer {
- /// Size of the transfer in bytes.
- ///
- /// If the size of the source and destination are not equal, then the value is equal to the
- /// smallest of the two.
- pub copy_size: DeviceSize,
-}
-
-/// Error that can happen from `check_copy_buffer`.
-#[derive(Debug, Copy, Clone)]
-pub enum CheckCopyBufferError {
- /// The source buffer is missing the transfer source usage.
- SourceMissingTransferUsage,
- /// The destination buffer is missing the transfer destination usage.
- DestinationMissingTransferUsage,
- /// The source and destination are overlapping.
- OverlappingRanges,
-}
-
-impl error::Error for CheckCopyBufferError {}
-
-impl fmt::Display for CheckCopyBufferError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- CheckCopyBufferError::SourceMissingTransferUsage => {
- "the source buffer is missing the transfer source usage"
- }
- CheckCopyBufferError::DestinationMissingTransferUsage => {
- "the destination buffer is missing the transfer destination usage"
- }
- CheckCopyBufferError::OverlappingRanges =>
- "the source and destination are overlapping",
- }
- )
- }
-}
diff --git a/src/command_buffer/validity/copy_image.rs b/src/command_buffer/validity/copy_image.rs
deleted file mode 100644
index b55e73d..0000000
--- a/src/command_buffer/validity/copy_image.rs
+++ /dev/null
@@ -1,243 +0,0 @@
-// Copyright (c) 2017 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::device::Device;
-use crate::format::FormatTy;
-use crate::image::ImageAccess;
-use crate::image::ImageDimensions;
-use crate::VulkanObject;
-use std::error;
-use std::fmt;
-
-/// Checks whether a copy image command is valid.
-///
-/// Note that this doesn't check whether `layer_count` is equal to 0. TODO: change that?
-///
-/// # Panic
-///
-/// - Panics if the source or the destination was not created with `device`.
-///
-pub fn check_copy_image<S, D>(
- device: &Device,
- source: &S,
- source_offset: [i32; 3],
- source_base_array_layer: u32,
- source_mip_level: u32,
- destination: &D,
- destination_offset: [i32; 3],
- destination_base_array_layer: u32,
- destination_mip_level: u32,
- extent: [u32; 3],
- layer_count: u32,
-) -> Result<(), CheckCopyImageError>
-where
- S: ?Sized + ImageAccess,
- D: ?Sized + ImageAccess,
-{
- let source_inner = source.inner();
- let destination_inner = destination.inner();
-
- assert_eq!(
- source_inner.image.device().internal_object(),
- device.internal_object()
- );
- assert_eq!(
- destination_inner.image.device().internal_object(),
- device.internal_object()
- );
-
- if !source_inner.image.usage().transfer_source {
- return Err(CheckCopyImageError::MissingTransferSourceUsage);
- }
-
- if !destination_inner.image.usage().transfer_destination {
- return Err(CheckCopyImageError::MissingTransferDestinationUsage);
- }
-
- if source.samples() != destination.samples() {
- return Err(CheckCopyImageError::SampleCountMismatch);
- }
-
- let source_format_ty = source.format().ty();
- let destination_format_ty = destination.format().ty();
-
- if matches!(
- source_format_ty,
- FormatTy::Depth | FormatTy::Stencil | FormatTy::DepthStencil
- ) {
- if source.format() != destination.format() {
- return Err(CheckCopyImageError::DepthStencilFormatMismatch);
- }
- }
-
- // TODO: The correct check here is that the uncompressed element size of the source is
- // equal to the compressed element size of the destination. However, format doesn't
- // currently expose this information, so to be safe, we simply disallow compressed formats.
- if source.format().ty() == FormatTy::Compressed
- || destination.format().ty() == FormatTy::Compressed
- || (source.format().size() != destination.format().size())
- {
- return Err(CheckCopyImageError::SizeIncompatibleFormatsTypes {
- source_format_ty: source.format().ty(),
- destination_format_ty: destination.format().ty(),
- });
- }
-
- let source_dimensions = match source.dimensions().mipmap_dimensions(source_mip_level) {
- Some(d) => d,
- None => return Err(CheckCopyImageError::SourceCoordinatesOutOfRange),
- };
-
- let destination_dimensions = match destination
- .dimensions()
- .mipmap_dimensions(destination_mip_level)
- {
- Some(d) => d,
- None => return Err(CheckCopyImageError::DestinationCoordinatesOutOfRange),
- };
-
- if source_base_array_layer + layer_count > source_dimensions.array_layers() {
- return Err(CheckCopyImageError::SourceCoordinatesOutOfRange);
- }
-
- if destination_base_array_layer + layer_count > destination_dimensions.array_layers() {
- return Err(CheckCopyImageError::DestinationCoordinatesOutOfRange);
- }
-
- if source_offset[0] < 0 || source_offset[0] as u32 + extent[0] > source_dimensions.width() {
- return Err(CheckCopyImageError::SourceCoordinatesOutOfRange);
- }
-
- if source_offset[1] < 0 || source_offset[1] as u32 + extent[1] > source_dimensions.height() {
- return Err(CheckCopyImageError::SourceCoordinatesOutOfRange);
- }
-
- if source_offset[2] < 0 || source_offset[2] as u32 + extent[2] > source_dimensions.depth() {
- return Err(CheckCopyImageError::SourceCoordinatesOutOfRange);
- }
-
- if destination_offset[0] < 0
- || destination_offset[0] as u32 + extent[0] > destination_dimensions.width()
- {
- return Err(CheckCopyImageError::DestinationCoordinatesOutOfRange);
- }
-
- if destination_offset[1] < 0
- || destination_offset[1] as u32 + extent[1] > destination_dimensions.height()
- {
- return Err(CheckCopyImageError::DestinationCoordinatesOutOfRange);
- }
-
- if destination_offset[2] < 0
- || destination_offset[2] as u32 + extent[2] > destination_dimensions.depth()
- {
- return Err(CheckCopyImageError::DestinationCoordinatesOutOfRange);
- }
-
- match source_dimensions {
- ImageDimensions::Dim1d { .. } => {
- if source_offset[1] != 0 || extent[1] != 1 {
- return Err(CheckCopyImageError::IncompatibleRangeForImageType);
- }
- if source_offset[2] != 0 || extent[2] != 1 {
- return Err(CheckCopyImageError::IncompatibleRangeForImageType);
- }
- }
- ImageDimensions::Dim2d { .. } => {
- if source_offset[2] != 0 || extent[2] != 1 {
- return Err(CheckCopyImageError::IncompatibleRangeForImageType);
- }
- }
- ImageDimensions::Dim3d { .. } => {}
- }
-
- match destination_dimensions {
- ImageDimensions::Dim1d { .. } => {
- if destination_offset[1] != 0 || extent[1] != 1 {
- return Err(CheckCopyImageError::IncompatibleRangeForImageType);
- }
- if destination_offset[2] != 0 || extent[2] != 1 {
- return Err(CheckCopyImageError::IncompatibleRangeForImageType);
- }
- }
- ImageDimensions::Dim2d { .. } => {
- if destination_offset[2] != 0 || extent[2] != 1 {
- return Err(CheckCopyImageError::IncompatibleRangeForImageType);
- }
- }
- ImageDimensions::Dim3d { .. } => {}
- }
-
- Ok(())
-}
-
-/// Error that can happen from `check_copy_image`.
-#[derive(Debug, Copy, Clone)]
-pub enum CheckCopyImageError {
- /// The source is missing the transfer source usage.
- MissingTransferSourceUsage,
- /// The destination is missing the transfer destination usage.
- MissingTransferDestinationUsage,
- /// The number of samples in the source and destination do not match.
- SampleCountMismatch,
- /// The format of the source and destination must be equal when copying depth/stencil images.
- DepthStencilFormatMismatch,
- /// The types of the source format and the destination format aren't size-compatible.
- SizeIncompatibleFormatsTypes {
- source_format_ty: FormatTy,
- destination_format_ty: FormatTy,
- },
- /// The offsets, array layers and/or mipmap levels are out of range in the source image.
- SourceCoordinatesOutOfRange,
- /// The offsets, array layers and/or mipmap levels are out of range in the destination image.
- DestinationCoordinatesOutOfRange,
- /// The offsets or extent are incompatible with the image type.
- IncompatibleRangeForImageType,
-}
-
-impl error::Error for CheckCopyImageError {}
-
-impl fmt::Display for CheckCopyImageError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- CheckCopyImageError::MissingTransferSourceUsage => {
- "the source is missing the transfer source usage"
- }
- CheckCopyImageError::MissingTransferDestinationUsage => {
- "the destination is missing the transfer destination usage"
- }
- CheckCopyImageError::SampleCountMismatch => {
- "the number of samples in the source and destination do not match"
- }
- CheckCopyImageError::DepthStencilFormatMismatch => {
- "the format of the source and destination must be equal when copying \
- depth/stencil images"
- }
- CheckCopyImageError::SizeIncompatibleFormatsTypes { .. } => {
- "the types of the source format and the destination format aren't size-compatible"
- }
- CheckCopyImageError::SourceCoordinatesOutOfRange => {
- "the offsets, array layers and/or mipmap levels are out of range in the source \
- image"
- }
- CheckCopyImageError::DestinationCoordinatesOutOfRange => {
- "the offsets, array layers and/or mipmap levels are out of range in the \
- destination image"
- }
- CheckCopyImageError::IncompatibleRangeForImageType => {
- "the offsets or extent are incompatible with the image type"
- }
- }
- )
- }
-}
diff --git a/src/command_buffer/validity/copy_image_buffer.rs b/src/command_buffer/validity/copy_image_buffer.rs
deleted file mode 100644
index 77224b1..0000000
--- a/src/command_buffer/validity/copy_image_buffer.rs
+++ /dev/null
@@ -1,266 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::buffer::TypedBufferAccess;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::format::Format;
-use crate::format::IncompatiblePixelsType;
-use crate::format::Pixel;
-use crate::image::ImageAccess;
-use crate::image::SampleCount;
-use crate::DeviceSize;
-use crate::VulkanObject;
-use std::error;
-use std::fmt;
-
-/// Type of operation to check.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub enum CheckCopyBufferImageTy {
- BufferToImage,
- ImageToBuffer,
-}
-
-/// Checks whether a copy buffer-image command is valid. Can check both buffer-to-image copies and
-/// image-to-buffer copies.
-///
-/// # Panic
-///
-/// - Panics if the buffer and image were not created with `device`.
-///
-pub fn check_copy_buffer_image<B, I, Px>(
- device: &Device,
- buffer: &B,
- image: &I,
- ty: CheckCopyBufferImageTy,
- image_offset: [u32; 3],
- image_size: [u32; 3],
- image_first_layer: u32,
- image_num_layers: u32,
- image_mipmap: u32,
-) -> Result<(), CheckCopyBufferImageError>
-where
- I: ?Sized + ImageAccess,
- B: ?Sized + TypedBufferAccess<Content = [Px]>,
- Px: Pixel, // TODO: use a trait on the image itself instead
-{
- let buffer_inner = buffer.inner();
- let image_inner = image.inner();
-
- assert_eq!(
- buffer_inner.buffer.device().internal_object(),
- device.internal_object()
- );
- assert_eq!(
- image_inner.image.device().internal_object(),
- device.internal_object()
- );
-
- match ty {
- CheckCopyBufferImageTy::BufferToImage => {
- if !buffer_inner.buffer.usage().transfer_source {
- return Err(CheckCopyBufferImageError::SourceMissingTransferUsage);
- }
- if !image_inner.image.usage().transfer_destination {
- return Err(CheckCopyBufferImageError::DestinationMissingTransferUsage);
- }
- }
- CheckCopyBufferImageTy::ImageToBuffer => {
- if !image_inner.image.usage().transfer_source {
- return Err(CheckCopyBufferImageError::SourceMissingTransferUsage);
- }
- if !buffer_inner.buffer.usage().transfer_destination {
- return Err(CheckCopyBufferImageError::DestinationMissingTransferUsage);
- }
- }
- }
-
- if image.samples() != SampleCount::Sample1 {
- return Err(CheckCopyBufferImageError::UnexpectedMultisampled);
- }
-
- let image_dimensions = match image.dimensions().mipmap_dimensions(image_mipmap) {
- Some(d) => d,
- None => return Err(CheckCopyBufferImageError::ImageCoordinatesOutOfRange),
- };
-
- if image_first_layer + image_num_layers > image_dimensions.array_layers() {
- return Err(CheckCopyBufferImageError::ImageCoordinatesOutOfRange);
- }
-
- if image_offset[0] + image_size[0] > image_dimensions.width() {
- return Err(CheckCopyBufferImageError::ImageCoordinatesOutOfRange);
- }
-
- if image_offset[1] + image_size[1] > image_dimensions.height() {
- return Err(CheckCopyBufferImageError::ImageCoordinatesOutOfRange);
- }
-
- if image_offset[2] + image_size[2] > image_dimensions.depth() {
- return Err(CheckCopyBufferImageError::ImageCoordinatesOutOfRange);
- }
-
- Px::ensure_accepts(image.format())?;
-
- {
- let required_len =
- required_len_for_format::<Px>(image.format(), image_size, image_num_layers);
- if required_len > buffer.len() {
- return Err(CheckCopyBufferImageError::BufferTooSmall {
- required_len,
- actual_len: buffer.len(),
- });
- }
- }
-
- // TODO: check memory overlap?
-
- Ok(())
-}
-
-/// Computes the minimum required len in elements for buffer with image data in specified
-/// format of specified size.
-fn required_len_for_format<Px>(
- format: Format,
- image_size: [u32; 3],
- image_num_layers: u32,
-) -> DeviceSize
-where
- Px: Pixel,
-{
- let (block_width, block_height) = format.block_dimensions();
- let num_blocks = (image_size[0] + block_width - 1) / block_width
- * ((image_size[1] + block_height - 1) / block_height)
- * image_size[2]
- * image_num_layers;
- let required_len = num_blocks as DeviceSize * Px::rate(format) as DeviceSize;
-
- return required_len;
-}
-
-#[cfg(test)]
-mod tests {
- use crate::command_buffer::validity::copy_image_buffer::required_len_for_format;
- use crate::format::Format;
-
- #[test]
- fn test_required_len_for_format() {
- // issue #1292
- assert_eq!(
- required_len_for_format::<u8>(Format::BC1_RGBUnormBlock, [2048, 2048, 1], 1),
- 2097152
- );
- // other test cases
- assert_eq!(
- required_len_for_format::<u8>(Format::R8G8B8A8Unorm, [2048, 2048, 1], 1),
- 16777216
- );
- assert_eq!(
- required_len_for_format::<u8>(Format::R4G4UnormPack8, [512, 512, 1], 1),
- 262144
- );
- assert_eq!(
- required_len_for_format::<u8>(Format::R8G8B8Uscaled, [512, 512, 1], 1),
- 786432
- );
- assert_eq!(
- required_len_for_format::<u8>(Format::R32G32Uint, [512, 512, 1], 1),
- 2097152
- );
- assert_eq!(
- required_len_for_format::<u32>(Format::R32G32Uint, [512, 512, 1], 1),
- 524288
- );
- assert_eq!(
- required_len_for_format::<[u32; 2]>(Format::R32G32Uint, [512, 512, 1], 1),
- 262144
- );
- assert_eq!(
- required_len_for_format::<u8>(Format::ASTC_8x8UnormBlock, [512, 512, 1], 1),
- 65536
- );
- assert_eq!(
- required_len_for_format::<u8>(Format::ASTC_12x12SrgbBlock, [512, 512, 1], 1),
- 29584
- );
- }
-}
-
-/// Error that can happen from `check_copy_buffer_image`.
-#[derive(Debug, Copy, Clone)]
-pub enum CheckCopyBufferImageError {
- /// The source buffer or image is missing the transfer source usage.
- SourceMissingTransferUsage,
- /// The destination buffer or image is missing the transfer destination usage.
- DestinationMissingTransferUsage,
- /// The source and destination are overlapping.
- OverlappingRanges,
- /// The image must not be multisampled.
- UnexpectedMultisampled,
- /// The image coordinates are out of range.
- ImageCoordinatesOutOfRange,
- /// The type of pixels in the buffer isn't compatible with the image format.
- WrongPixelType(IncompatiblePixelsType),
- /// The buffer is too small for the copy operation.
- BufferTooSmall {
- /// Required number of elements in the buffer.
- required_len: DeviceSize,
- /// Actual number of elements in the buffer.
- actual_len: DeviceSize,
- },
-}
-
-impl error::Error for CheckCopyBufferImageError {
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- CheckCopyBufferImageError::WrongPixelType(ref err) => Some(err),
- _ => None,
- }
- }
-}
-
-impl fmt::Display for CheckCopyBufferImageError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- CheckCopyBufferImageError::SourceMissingTransferUsage => {
- "the source buffer is missing the transfer source usage"
- }
- CheckCopyBufferImageError::DestinationMissingTransferUsage => {
- "the destination buffer is missing the transfer destination usage"
- }
- CheckCopyBufferImageError::OverlappingRanges => {
- "the source and destination are overlapping"
- }
- CheckCopyBufferImageError::UnexpectedMultisampled => {
- "the image must not be multisampled"
- }
- CheckCopyBufferImageError::ImageCoordinatesOutOfRange => {
- "the image coordinates are out of range"
- }
- CheckCopyBufferImageError::WrongPixelType(_) => {
- "the type of pixels in the buffer isn't compatible with the image format"
- }
- CheckCopyBufferImageError::BufferTooSmall { .. } => {
- "the buffer is too small for the copy operation"
- }
- }
- )
- }
-}
-
-impl From<IncompatiblePixelsType> for CheckCopyBufferImageError {
- #[inline]
- fn from(err: IncompatiblePixelsType) -> CheckCopyBufferImageError {
- CheckCopyBufferImageError::WrongPixelType(err)
- }
-}
diff --git a/src/command_buffer/validity/debug_marker.rs b/src/command_buffer/validity/debug_marker.rs
deleted file mode 100644
index 9a80e7f..0000000
--- a/src/command_buffer/validity/debug_marker.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-use std::{error, fmt};
-
-/// Checks whether the specified color is valid as debug marker color.
-///
-/// The color parameter must contain RGBA values in order, in the range 0.0 to 1.0.
-pub fn check_debug_marker_color(color: [f32; 4]) -> Result<(), CheckColorError> {
- // The values contain RGBA values in order, in the range 0.0 to 1.0.
- if color.iter().any(|x| !(0f32..=1f32).contains(x)) {
- return Err(CheckColorError);
- }
-
- Ok(())
-}
-
-/// Error that can happen from `check_debug_marker_color`.
-#[derive(Debug, Copy, Clone)]
-pub struct CheckColorError;
-
-impl error::Error for CheckColorError {}
-
-impl fmt::Display for CheckColorError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- CheckColorError => "color parameter does contains values out of 0.0 to 1.0 range",
- }
- )
- }
-}
diff --git a/src/command_buffer/validity/descriptor_sets.rs b/src/command_buffer/validity/descriptor_sets.rs
deleted file mode 100644
index 227101b..0000000
--- a/src/command_buffer/validity/descriptor_sets.rs
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright (c) 2017 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use std::error;
-use std::fmt;
-
-use crate::descriptor_set::layout::DescriptorDescSupersetError;
-use crate::descriptor_set::DescriptorSetWithOffsets;
-use crate::pipeline::layout::PipelineLayout;
-
-/// Checks whether descriptor sets are compatible with the pipeline.
-pub fn check_descriptor_sets_validity(
- pipeline_layout: &PipelineLayout,
- descriptor_sets: &[DescriptorSetWithOffsets],
-) -> Result<(), CheckDescriptorSetsValidityError> {
- // What's important is not that the pipeline layout and the descriptor sets *match*. Instead
- // what's important is that the descriptor sets are a superset of the pipeline layout. It's not
- // a problem if the descriptor sets provide more elements than expected.
-
- for (set_num, set) in pipeline_layout.descriptor_set_layouts().iter().enumerate() {
- for (binding_num, pipeline_desc) in
- (0..set.num_bindings()).filter_map(|i| set.descriptor(i).map(|d| (i, d)))
- {
- let set_desc = descriptor_sets
- .get(set_num)
- .and_then(|so| so.as_ref().0.layout().descriptor(binding_num));
-
- let set_desc = match set_desc {
- Some(s) => s,
- None => {
- return Err(CheckDescriptorSetsValidityError::MissingDescriptor {
- set_num: set_num,
- binding_num: binding_num,
- })
- }
- };
-
- if let Err(err) = set_desc.ensure_superset_of(&pipeline_desc) {
- return Err(CheckDescriptorSetsValidityError::IncompatibleDescriptor {
- error: err,
- set_num: set_num,
- binding_num: binding_num,
- });
- }
- }
- }
-
- Ok(())
-}
-
-/// Error that can happen when checking descriptor sets validity.
-#[derive(Debug, Clone)]
-pub enum CheckDescriptorSetsValidityError {
- /// A descriptor is missing in the descriptor sets that were provided.
- MissingDescriptor {
- /// The index of the set of the descriptor.
- set_num: usize,
- /// The binding number of the descriptor.
- binding_num: usize,
- },
-
- /// A descriptor in the provided sets is not compatible with what is expected.
- IncompatibleDescriptor {
- /// The reason why the two descriptors aren't compatible.
- error: DescriptorDescSupersetError,
- /// The index of the set of the descriptor.
- set_num: usize,
- /// The binding number of the descriptor.
- binding_num: usize,
- },
-}
-
-impl error::Error for CheckDescriptorSetsValidityError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- CheckDescriptorSetsValidityError::IncompatibleDescriptor { ref error, .. } => {
- Some(error)
- }
- _ => None,
- }
- }
-}
-
-impl fmt::Display for CheckDescriptorSetsValidityError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- CheckDescriptorSetsValidityError::MissingDescriptor { .. } => {
- "a descriptor is missing in the descriptor sets that were provided"
- }
- CheckDescriptorSetsValidityError::IncompatibleDescriptor { .. } => {
- "a descriptor in the provided sets is not compatible with what is expected"
- }
- }
- )
- }
-}
-
-// TODO: tests
diff --git a/src/command_buffer/validity/dispatch.rs b/src/command_buffer/validity/dispatch.rs
deleted file mode 100644
index 297c1f6..0000000
--- a/src/command_buffer/validity/dispatch.rs
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright (c) 2017 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use std::error;
-use std::fmt;
-
-use crate::device::Device;
-
-/// Checks whether the dispatch dimensions are supported by the device.
-pub fn check_dispatch(device: &Device, dimensions: [u32; 3]) -> Result<(), CheckDispatchError> {
- let max = device
- .physical_device()
- .properties()
- .max_compute_work_group_count;
-
- if dimensions[0] > max[0] || dimensions[1] > max[1] || dimensions[2] > max[2] {
- return Err(CheckDispatchError::UnsupportedDimensions {
- requested: dimensions,
- max_supported: max,
- });
- }
-
- Ok(())
-}
-
-/// Error that can happen when checking dispatch command validity.
-#[derive(Debug, Copy, Clone)]
-pub enum CheckDispatchError {
- /// The dimensions are too large for the device's limits.
- UnsupportedDimensions {
- /// The requested dimensions.
- requested: [u32; 3],
- /// The actual supported dimensions.
- max_supported: [u32; 3],
- },
-}
-
-impl error::Error for CheckDispatchError {}
-
-impl fmt::Display for CheckDispatchError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- CheckDispatchError::UnsupportedDimensions { .. } => {
- "the dimensions are too large for the device's limits"
- }
- }
- )
- }
-}
-
-#[cfg(test)]
-mod tests {
- use crate::command_buffer::validity;
-
- #[test]
- fn max_checked() {
- let (device, _) = gfx_dev_and_queue!();
-
- let attempted = [u32::MAX, u32::MAX, u32::MAX];
-
- // Just in case the device is some kind of software implementation.
- if device
- .physical_device()
- .properties()
- .max_compute_work_group_count
- == attempted
- {
- return;
- }
-
- match validity::check_dispatch(&device, attempted) {
- Err(validity::CheckDispatchError::UnsupportedDimensions { requested, .. }) => {
- assert_eq!(requested, attempted);
- }
- _ => panic!(),
- }
- }
-}
diff --git a/src/command_buffer/validity/dynamic_state.rs b/src/command_buffer/validity/dynamic_state.rs
deleted file mode 100644
index f9a65ad..0000000
--- a/src/command_buffer/validity/dynamic_state.rs
+++ /dev/null
@@ -1,215 +0,0 @@
-// Copyright (c) 2017 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use std::error;
-use std::fmt;
-
-use crate::command_buffer::DynamicState;
-use crate::pipeline::GraphicsPipelineAbstract;
-
-/// Checks whether states that are about to be set are correct.
-pub fn check_dynamic_state_validity<Pl>(
- pipeline: &Pl,
- state: &DynamicState,
-) -> Result<(), CheckDynamicStateValidityError>
-where
- Pl: GraphicsPipelineAbstract,
-{
- let device = pipeline.device();
-
- if pipeline.has_dynamic_line_width() {
- if let Some(value) = state.line_width {
- if value != 1.0 && !pipeline.device().enabled_features().wide_lines {
- return Err(CheckDynamicStateValidityError::LineWidthMissingExtension);
- }
- } else {
- return Err(CheckDynamicStateValidityError::LineWidthMissing);
- }
- } else {
- if state.line_width.is_some() {
- return Err(CheckDynamicStateValidityError::LineWidthNotDynamic);
- }
- }
-
- if pipeline.has_dynamic_viewports() {
- if let Some(ref viewports) = state.viewports {
- if viewports.len() != pipeline.num_viewports() as usize {
- return Err(CheckDynamicStateValidityError::ViewportsCountMismatch {
- expected: pipeline.num_viewports() as usize,
- obtained: viewports.len(),
- });
- }
- } else {
- return Err(CheckDynamicStateValidityError::ViewportsMissing);
- }
- } else {
- if state.viewports.is_some() {
- return Err(CheckDynamicStateValidityError::ViewportsNotDynamic);
- }
- }
-
- if pipeline.has_dynamic_scissors() {
- if let Some(ref scissors) = state.scissors {
- if scissors.len() != pipeline.num_viewports() as usize {
- return Err(CheckDynamicStateValidityError::ScissorsCountMismatch {
- expected: pipeline.num_viewports() as usize,
- obtained: scissors.len(),
- });
- }
- } else {
- return Err(CheckDynamicStateValidityError::ScissorsMissing);
- }
- } else {
- if state.scissors.is_some() {
- return Err(CheckDynamicStateValidityError::ScissorsNotDynamic);
- }
- }
-
- if pipeline.has_dynamic_stencil_compare_mask() {
- if let None = state.compare_mask {
- return Err(CheckDynamicStateValidityError::CompareMaskMissing);
- }
- } else {
- if state.compare_mask.is_some() {
- return Err(CheckDynamicStateValidityError::CompareMaskNotDynamic);
- }
- }
-
- if pipeline.has_dynamic_stencil_write_mask() {
- if let None = state.write_mask {
- return Err(CheckDynamicStateValidityError::WriteMaskMissing);
- }
- } else {
- if state.write_mask.is_some() {
- return Err(CheckDynamicStateValidityError::WriteMaskNotDynamic);
- }
- }
-
- if pipeline.has_dynamic_stencil_reference() {
- if let None = state.reference {
- return Err(CheckDynamicStateValidityError::ReferenceMissing);
- }
- } else {
- if state.reference.is_some() {
- return Err(CheckDynamicStateValidityError::ReferenceNotDynamic);
- }
- }
-
- Ok(())
-}
-
-/// Error that can happen when validating dynamic states.
-#[derive(Debug, Copy, Clone)]
-pub enum CheckDynamicStateValidityError {
- /// Passed a dynamic line width, while the pipeline doesn't have line width set as dynamic.
- LineWidthNotDynamic,
- /// The pipeline has a dynamic line width, but no line width value was passed.
- LineWidthMissing,
- /// The `wide_lines` extension must be enabled in order to use line width values different
- /// from 1.0.
- LineWidthMissingExtension,
- /// Passed dynamic viewports, while the pipeline doesn't have viewports set as dynamic.
- ViewportsNotDynamic,
- /// The pipeline has dynamic viewports, but no viewports were passed.
- ViewportsMissing,
- /// The number of dynamic viewports doesn't match the expected number of viewports.
- ViewportsCountMismatch {
- /// Expected number of viewports.
- expected: usize,
- /// Number of viewports that were passed.
- obtained: usize,
- },
- /// Passed dynamic scissors, while the pipeline doesn't have scissors set as dynamic.
- ScissorsNotDynamic,
- /// The pipeline has dynamic scissors, but no scissors were passed.
- ScissorsMissing,
- /// The number of dynamic scissors doesn't match the expected number of scissors.
- ScissorsCountMismatch {
- /// Expected number of scissors.
- expected: usize,
- /// Number of scissors that were passed.
- obtained: usize,
- },
- /// Passed dynamic compare mask, while the pipeline doesn't have the compare mask set as dynamic.
- CompareMaskNotDynamic,
- /// The pipeline has dynamic compare mask, but no compare mask was passed.
- CompareMaskMissing,
- /// Passed dynamic write mask, while the pipeline doesn't have the write mask set as dynamic.
- WriteMaskNotDynamic,
- /// The pipeline has dynamic write mask, but no write mask was passed.
- WriteMaskMissing,
- /// Passed dynamic reference, while the pipeline doesn't have the reference set as dynamic.
- ReferenceNotDynamic,
- /// The pipeline has dynamic reference, but no reference was passed.
- ReferenceMissing,
-}
-
-impl error::Error for CheckDynamicStateValidityError {}
-
-impl fmt::Display for CheckDynamicStateValidityError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- CheckDynamicStateValidityError::LineWidthNotDynamic => {
- "passed a dynamic line width, while the pipeline doesn't have line width set as \
- dynamic"
- }
- CheckDynamicStateValidityError::LineWidthMissing => {
- "the pipeline has a dynamic line width, but no line width value was passed"
- }
- CheckDynamicStateValidityError::LineWidthMissingExtension => {
- "the `wide_lines` extension must be enabled in order to use line width values \
- different from 1.0"
- }
- CheckDynamicStateValidityError::ViewportsNotDynamic => {
- "passed dynamic viewports, while the pipeline doesn't have viewports set as \
- dynamic"
- }
- CheckDynamicStateValidityError::ViewportsMissing => {
- "the pipeline has dynamic viewports, but no viewports were passed"
- }
- CheckDynamicStateValidityError::ViewportsCountMismatch { .. } => {
- "the number of dynamic viewports doesn't match the expected number of viewports"
- }
- CheckDynamicStateValidityError::ScissorsNotDynamic => {
- "passed dynamic scissors, while the pipeline doesn't have scissors set as dynamic"
- }
- CheckDynamicStateValidityError::ScissorsMissing => {
- "the pipeline has dynamic scissors, but no scissors were passed"
- }
- CheckDynamicStateValidityError::ScissorsCountMismatch { .. } => {
- "the number of dynamic scissors doesn't match the expected number of scissors"
- }
- CheckDynamicStateValidityError::CompareMaskNotDynamic => {
- "passed dynamic compare mask, while the pipeline doesn't have compare mask set as dynamic"
- }
- CheckDynamicStateValidityError::CompareMaskMissing => {
- "the pipeline has dynamic compare mask, but no compare mask was passed"
- }
- CheckDynamicStateValidityError::WriteMaskNotDynamic => {
- "passed dynamic write mask, while the pipeline doesn't have write mask set as dynamic"
- }
- CheckDynamicStateValidityError::WriteMaskMissing => {
- "the pipeline has dynamic write mask, but no write mask was passed"
- }
- CheckDynamicStateValidityError::ReferenceNotDynamic => {
- "passed dynamic Reference, while the pipeline doesn't have reference set as dynamic"
- }
- CheckDynamicStateValidityError::ReferenceMissing => {
- "the pipeline has dynamic reference, but no reference was passed"
- }
- }
- )
- }
-}
-
-// TODO: tests
diff --git a/src/command_buffer/validity/fill_buffer.rs b/src/command_buffer/validity/fill_buffer.rs
deleted file mode 100644
index a02f47d..0000000
--- a/src/command_buffer/validity/fill_buffer.rs
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright (c) 2017 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use std::error;
-use std::fmt;
-
-use crate::buffer::BufferAccess;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::VulkanObject;
-
-/// Checks whether a fill buffer command is valid.
-///
-/// # Panic
-///
-/// - Panics if the buffer not created with `device`.
-///
-pub fn check_fill_buffer<B>(device: &Device, buffer: &B) -> Result<(), CheckFillBufferError>
-where
- B: ?Sized + BufferAccess,
-{
- assert_eq!(
- buffer.inner().buffer.device().internal_object(),
- device.internal_object()
- );
-
- if !buffer.inner().buffer.usage().transfer_destination {
- return Err(CheckFillBufferError::BufferMissingUsage);
- }
-
- if buffer.inner().offset % 4 != 0 {
- return Err(CheckFillBufferError::WrongAlignment);
- }
-
- Ok(())
-}
-
-/// Error that can happen when attempting to add a `fill_buffer` command.
-#[derive(Debug, Copy, Clone)]
-pub enum CheckFillBufferError {
- /// The "transfer destination" usage must be enabled on the buffer.
- BufferMissingUsage,
- /// The data or size must be 4-bytes aligned.
- WrongAlignment,
-}
-
-impl error::Error for CheckFillBufferError {}
-
-impl fmt::Display for CheckFillBufferError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- CheckFillBufferError::BufferMissingUsage => {
- "the transfer destination usage must be enabled on the buffer"
- }
- CheckFillBufferError::WrongAlignment =>
- "the offset or size are not aligned to 4 bytes",
- }
- )
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::buffer::BufferUsage;
- use crate::buffer::CpuAccessibleBuffer;
-
- #[test]
- fn missing_usage() {
- let (device, queue) = gfx_dev_and_queue!();
- let buffer = CpuAccessibleBuffer::from_data(
- device.clone(),
- BufferUsage::vertex_buffer(),
- false,
- 0u32,
- )
- .unwrap();
-
- match check_fill_buffer(&device, &buffer) {
- Err(CheckFillBufferError::BufferMissingUsage) => (),
- _ => panic!(),
- }
- }
-
- #[test]
- fn wrong_device() {
- let (dev1, queue) = gfx_dev_and_queue!();
- let (dev2, _) = gfx_dev_and_queue!();
- let buffer = CpuAccessibleBuffer::from_data(dev1, BufferUsage::all(), false, 0u32).unwrap();
-
- assert_should_panic!({
- let _ = check_fill_buffer(&dev2, &buffer);
- });
- }
-}
diff --git a/src/command_buffer/validity/index_buffer.rs b/src/command_buffer/validity/index_buffer.rs
deleted file mode 100644
index 52f2bdc..0000000
--- a/src/command_buffer/validity/index_buffer.rs
+++ /dev/null
@@ -1,148 +0,0 @@
-// Copyright (c) 2017 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use std::error;
-use std::fmt;
-
-use crate::buffer::BufferAccess;
-use crate::buffer::TypedBufferAccess;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::pipeline::input_assembly::Index;
-use crate::VulkanObject;
-
-/// Checks whether an index buffer can be bound.
-///
-/// # Panic
-///
-/// - Panics if the buffer was not created with `device`.
-///
-pub fn check_index_buffer<B, I>(
- device: &Device,
- buffer: &B,
-) -> Result<CheckIndexBuffer, CheckIndexBufferError>
-where
- B: ?Sized + BufferAccess + TypedBufferAccess<Content = [I]>,
- I: Index,
-{
- assert_eq!(
- buffer.inner().buffer.device().internal_object(),
- device.internal_object()
- );
-
- if !buffer.inner().buffer.usage().index_buffer {
- return Err(CheckIndexBufferError::BufferMissingUsage);
- }
-
- // TODO: The sum of offset and the address of the range of VkDeviceMemory object that is
- // backing buffer, must be a multiple of the type indicated by indexType
-
- // TODO: full_draw_index_uint32 feature
-
- Ok(CheckIndexBuffer {
- num_indices: buffer.len() as u32,
- })
-}
-
-/// Information returned if `check_index_buffer` succeeds.
-pub struct CheckIndexBuffer {
- /// Number of indices in the index buffer.
- pub num_indices: u32,
-}
-
-/// Error that can happen when checking whether binding an index buffer is valid.
-#[derive(Debug, Copy, Clone)]
-pub enum CheckIndexBufferError {
- /// The "index buffer" usage must be enabled on the index buffer.
- BufferMissingUsage,
- /// The data or size must be 4-bytes aligned.
- WrongAlignment,
- /// The type of the indices is not supported by the device.
- UnsupportIndexType,
-}
-
-impl error::Error for CheckIndexBufferError {}
-
-impl fmt::Display for CheckIndexBufferError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- CheckIndexBufferError::BufferMissingUsage => {
- "the index buffer usage must be enabled on the index buffer"
- }
- CheckIndexBufferError::WrongAlignment => {
- "the sum of offset and the address of the range of VkDeviceMemory object that is \
- backing buffer, must be a multiple of the type indicated by indexType"
- }
- CheckIndexBufferError::UnsupportIndexType => {
- "the type of the indices is not supported by the device"
- }
- }
- )
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::buffer::BufferUsage;
- use crate::buffer::CpuAccessibleBuffer;
-
- #[test]
- fn num_indices() {
- let (device, queue) = gfx_dev_and_queue!();
- let buffer = CpuAccessibleBuffer::from_iter(
- device.clone(),
- BufferUsage::index_buffer(),
- false,
- 0..500u32,
- )
- .unwrap();
-
- match check_index_buffer(&device, &buffer) {
- Ok(CheckIndexBuffer { num_indices }) => {
- assert_eq!(num_indices, 500);
- }
- _ => panic!(),
- }
- }
-
- #[test]
- fn missing_usage() {
- let (device, queue) = gfx_dev_and_queue!();
- let buffer = CpuAccessibleBuffer::from_iter(
- device.clone(),
- BufferUsage::vertex_buffer(),
- false,
- 0..500u32,
- )
- .unwrap();
-
- match check_index_buffer(&device, &buffer) {
- Err(CheckIndexBufferError::BufferMissingUsage) => (),
- _ => panic!(),
- }
- }
-
- #[test]
- fn wrong_device() {
- let (dev1, queue) = gfx_dev_and_queue!();
- let (dev2, _) = gfx_dev_and_queue!();
-
- let buffer =
- CpuAccessibleBuffer::from_iter(dev1, BufferUsage::all(), false, 0..500u32).unwrap();
-
- assert_should_panic!({
- let _ = check_index_buffer(&dev2, &buffer);
- });
- }
-}
diff --git a/src/command_buffer/validity/indirect_buffer.rs b/src/command_buffer/validity/indirect_buffer.rs
deleted file mode 100644
index 3acd4b2..0000000
--- a/src/command_buffer/validity/indirect_buffer.rs
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright (c) 2021 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::buffer::BufferAccess;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::VulkanObject;
-use std::error;
-use std::fmt;
-
-/// Checks whether an indirect buffer can be bound.
-pub fn check_indirect_buffer<Inb>(
- device: &Device,
- buffer: &Inb,
-) -> Result<(), CheckIndirectBufferError>
-where
- Inb: BufferAccess + Send + Sync + 'static,
-{
- assert_eq!(
- buffer.inner().buffer.device().internal_object(),
- device.internal_object()
- );
-
- if !buffer.inner().buffer.usage().indirect_buffer {
- return Err(CheckIndirectBufferError::BufferMissingUsage);
- }
-
- Ok(())
-}
-
-/// Error that can happen when checking whether binding an indirect buffer is valid.
-#[derive(Debug, Copy, Clone)]
-pub enum CheckIndirectBufferError {
- /// The "indirect buffer" usage must be enabled on the indirect buffer.
- BufferMissingUsage,
- /// The maximum number of indirect draws has been exceeded.
- MaxDrawIndirectCountLimitExceeded {
- /// The limit that must be fulfilled.
- limit: u32,
- /// What was requested.
- requested: u32,
- },
-}
-
-impl error::Error for CheckIndirectBufferError {}
-
-impl fmt::Display for CheckIndirectBufferError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- CheckIndirectBufferError::BufferMissingUsage => {
- "the indirect buffer usage must be enabled on the indirect buffer"
- }
- CheckIndirectBufferError::MaxDrawIndirectCountLimitExceeded {
- limit,
- requested,
- } => {
- "the maximum number of indirect draws has been exceeded"
- }
- }
- )
- }
-}
diff --git a/src/command_buffer/validity/mod.rs b/src/command_buffer/validity/mod.rs
deleted file mode 100644
index d4c7a9e..0000000
--- a/src/command_buffer/validity/mod.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright (c) 2017 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-//! Functions that check the validity of commands.
-
-pub use self::blit_image::{check_blit_image, CheckBlitImageError};
-pub use self::clear_color_image::{check_clear_color_image, CheckClearColorImageError};
-pub use self::copy_buffer::{check_copy_buffer, CheckCopyBuffer, CheckCopyBufferError};
-pub use self::copy_image::{check_copy_image, CheckCopyImageError};
-pub use self::copy_image_buffer::{
- check_copy_buffer_image, CheckCopyBufferImageError, CheckCopyBufferImageTy,
-};
-pub use self::debug_marker::{check_debug_marker_color, CheckColorError};
-pub use self::descriptor_sets::{check_descriptor_sets_validity, CheckDescriptorSetsValidityError};
-pub use self::dispatch::{check_dispatch, CheckDispatchError};
-pub use self::dynamic_state::{check_dynamic_state_validity, CheckDynamicStateValidityError};
-pub use self::fill_buffer::{check_fill_buffer, CheckFillBufferError};
-pub use self::index_buffer::{check_index_buffer, CheckIndexBuffer, CheckIndexBufferError};
-pub use self::indirect_buffer::{check_indirect_buffer, CheckIndirectBufferError};
-pub use self::push_constants::{check_push_constants_validity, CheckPushConstantsValidityError};
-pub use self::query::{
- check_begin_query, check_copy_query_pool_results, check_end_query, check_reset_query_pool,
- check_write_timestamp, CheckBeginQueryError, CheckCopyQueryPoolResultsError,
- CheckEndQueryError, CheckResetQueryPoolError, CheckWriteTimestampError,
-};
-pub use self::update_buffer::{check_update_buffer, CheckUpdateBufferError};
-pub use self::vertex_buffers::{check_vertex_buffers, CheckVertexBuffer, CheckVertexBufferError};
-
-mod blit_image;
-mod clear_color_image;
-mod copy_buffer;
-mod copy_image;
-mod copy_image_buffer;
-mod debug_marker;
-mod descriptor_sets;
-mod dispatch;
-mod dynamic_state;
-mod fill_buffer;
-mod index_buffer;
-mod indirect_buffer;
-mod push_constants;
-mod query;
-mod update_buffer;
-mod vertex_buffers;
diff --git a/src/command_buffer/validity/push_constants.rs b/src/command_buffer/validity/push_constants.rs
deleted file mode 100644
index 65b749e..0000000
--- a/src/command_buffer/validity/push_constants.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright (c) 2017 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::pipeline::layout::PipelineLayout;
-use std::error;
-use std::fmt;
-
-/// Checks whether push constants are compatible with the pipeline.
-pub fn check_push_constants_validity<Pc>(
- pipeline_layout: &PipelineLayout,
- push_constants: &Pc,
-) -> Result<(), CheckPushConstantsValidityError>
-where
- Pc: ?Sized,
-{
- // TODO
- if !true {
- return Err(CheckPushConstantsValidityError::IncompatiblePushConstants);
- }
-
- Ok(())
-}
-
-/// Error that can happen when checking push constants validity.
-#[derive(Debug, Copy, Clone)]
-pub enum CheckPushConstantsValidityError {
- /// The push constants are incompatible with the pipeline layout.
- IncompatiblePushConstants,
-}
-
-impl error::Error for CheckPushConstantsValidityError {}
-
-impl fmt::Display for CheckPushConstantsValidityError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- CheckPushConstantsValidityError::IncompatiblePushConstants => {
- "the push constants are incompatible with the pipeline layout"
- }
- }
- )
- }
-}
diff --git a/src/command_buffer/validity/query.rs b/src/command_buffer/validity/query.rs
deleted file mode 100644
index 52781f4..0000000
--- a/src/command_buffer/validity/query.rs
+++ /dev/null
@@ -1,391 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::buffer::TypedBufferAccess;
-use crate::device::physical::QueueFamily;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::query::GetResultsError;
-use crate::query::QueryControlFlags;
-use crate::query::QueryPool;
-use crate::query::QueryResultElement;
-use crate::query::QueryResultFlags;
-use crate::query::QueryType;
-use crate::sync::PipelineStage;
-use crate::DeviceSize;
-use crate::VulkanObject;
-use std::error;
-use std::fmt;
-use std::ops::Range;
-
-/// Checks whether a `begin_query` command is valid.
-///
-/// # Panic
-///
-/// - Panics if the query pool was not created with `device`.
-pub fn check_begin_query(
- device: &Device,
- query_pool: &QueryPool,
- query: u32,
- flags: QueryControlFlags,
-) -> Result<(), CheckBeginQueryError> {
- assert_eq!(
- device.internal_object(),
- query_pool.device().internal_object(),
- );
- query_pool
- .query(query)
- .ok_or(CheckBeginQueryError::OutOfRange)?;
-
- match query_pool.ty() {
- QueryType::Occlusion => {
- if flags.precise && !device.enabled_features().occlusion_query_precise {
- return Err(CheckBeginQueryError::OcclusionQueryPreciseFeatureNotEnabled);
- }
- }
- QueryType::PipelineStatistics(_) => {
- if flags.precise {
- return Err(CheckBeginQueryError::InvalidFlags);
- }
- }
- QueryType::Timestamp => return Err(CheckBeginQueryError::NotPermitted),
- }
-
- Ok(())
-}
-
-/// Error that can happen from `check_begin_query`.
-#[derive(Debug, Copy, Clone)]
-pub enum CheckBeginQueryError {
- /// The provided flags are not allowed for this type of query.
- InvalidFlags,
- /// This operation is not permitted on this query type.
- NotPermitted,
- /// `QueryControlFlags::precise` was requested, but the `occlusion_query_precise` feature was not enabled.
- OcclusionQueryPreciseFeatureNotEnabled,
- /// The provided query index is not valid for this pool.
- OutOfRange,
-}
-
-impl error::Error for CheckBeginQueryError {}
-
-impl fmt::Display for CheckBeginQueryError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- Self::InvalidFlags => {
- "the provided flags are not allowed for this type of query"
- }
- Self::NotPermitted => {
- "this operation is not permitted on this query type"
- }
- Self::OcclusionQueryPreciseFeatureNotEnabled => {
- "QueryControlFlags::precise was requested, but the occlusion_query_precise feature was not enabled"
- }
- Self::OutOfRange => {
- "the provided query index is not valid for this pool"
- }
- }
- )
- }
-}
-
-/// Checks whether a `end_query` command is valid.
-///
-/// # Panic
-///
-/// - Panics if the query pool was not created with `device`.
-pub fn check_end_query(
- device: &Device,
- query_pool: &QueryPool,
- query: u32,
-) -> Result<(), CheckEndQueryError> {
- assert_eq!(
- device.internal_object(),
- query_pool.device().internal_object(),
- );
-
- query_pool
- .query(query)
- .ok_or(CheckEndQueryError::OutOfRange)?;
-
- Ok(())
-}
-
-/// Error that can happen from `check_end_query`.
-#[derive(Debug, Copy, Clone)]
-pub enum CheckEndQueryError {
- /// The provided query index is not valid for this pool.
- OutOfRange,
-}
-
-impl error::Error for CheckEndQueryError {}
-
-impl fmt::Display for CheckEndQueryError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- Self::OutOfRange => {
- "the provided query index is not valid for this pool"
- }
- }
- )
- }
-}
-
-/// Checks whether a `write_timestamp` command is valid.
-///
-/// # Panic
-///
-/// - Panics if the query pool was not created with `device`.
-pub fn check_write_timestamp(
- device: &Device,
- queue_family: QueueFamily,
- query_pool: &QueryPool,
- query: u32,
- stage: PipelineStage,
-) -> Result<(), CheckWriteTimestampError> {
- assert_eq!(
- device.internal_object(),
- query_pool.device().internal_object(),
- );
-
- if !matches!(query_pool.ty(), QueryType::Timestamp) {
- return Err(CheckWriteTimestampError::NotPermitted);
- }
-
- query_pool
- .query(query)
- .ok_or(CheckWriteTimestampError::OutOfRange)?;
-
- if queue_family.timestamp_valid_bits().is_none() {
- return Err(CheckWriteTimestampError::NoTimestampValidBits);
- }
-
- if !queue_family.supports_stage(stage) {
- return Err(CheckWriteTimestampError::StageNotSupported);
- }
-
- match stage {
- PipelineStage::GeometryShader => {
- if !device.enabled_features().geometry_shader {
- return Err(CheckWriteTimestampError::GeometryShaderFeatureNotEnabled);
- }
- }
- PipelineStage::TessellationControlShader | PipelineStage::TessellationEvaluationShader => {
- if !device.enabled_features().tessellation_shader {
- return Err(CheckWriteTimestampError::TessellationShaderFeatureNotEnabled);
- }
- }
- _ => (),
- }
-
- Ok(())
-}
-
-/// Error that can happen from `check_write_timestamp`.
-#[derive(Debug, Copy, Clone)]
-pub enum CheckWriteTimestampError {
- /// The geometry shader stage was requested, but the `geometry_shader` feature was not enabled.
- GeometryShaderFeatureNotEnabled,
- /// The queue family's `timestamp_valid_bits` value is `None`.
- NoTimestampValidBits,
- /// This operation is not permitted on this query type.
- NotPermitted,
- /// The provided query index is not valid for this pool.
- OutOfRange,
- /// The provided stage is not supported by the queue family.
- StageNotSupported,
- /// A tessellation shader stage was requested, but the `tessellation_shader` feature was not enabled.
- TessellationShaderFeatureNotEnabled,
-}
-
-impl error::Error for CheckWriteTimestampError {}
-
-impl fmt::Display for CheckWriteTimestampError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- Self::GeometryShaderFeatureNotEnabled => {
- "the geometry shader stage was requested, but the geometry_shader feature was not enabled"
- }
- Self::NoTimestampValidBits => {
- "the queue family's timestamp_valid_bits value is None"
- }
- Self::NotPermitted => {
- "this operation is not permitted on this query type"
- }
- Self::OutOfRange => {
- "the provided query index is not valid for this pool"
- }
- Self::StageNotSupported => {
- "the provided stage is not supported by the queue family"
- }
- Self::TessellationShaderFeatureNotEnabled => {
- "a tessellation shader stage was requested, but the tessellation_shader feature was not enabled"
- }
- }
- )
- }
-}
-
-/// Checks whether a `copy_query_pool_results` command is valid.
-///
-/// # Panic
-///
-/// - Panics if the query pool or buffer was not created with `device`.
-pub fn check_copy_query_pool_results<D, T>(
- device: &Device,
- query_pool: &QueryPool,
- queries: Range<u32>,
- destination: &D,
- flags: QueryResultFlags,
-) -> Result<DeviceSize, CheckCopyQueryPoolResultsError>
-where
- D: ?Sized + TypedBufferAccess<Content = [T]>,
- T: QueryResultElement,
-{
- let buffer_inner = destination.inner();
- assert_eq!(
- device.internal_object(),
- buffer_inner.buffer.device().internal_object(),
- );
- assert_eq!(
- device.internal_object(),
- query_pool.device().internal_object(),
- );
-
- if !buffer_inner.buffer.usage().transfer_destination {
- return Err(CheckCopyQueryPoolResultsError::DestinationMissingTransferUsage);
- }
-
- let queries_range = query_pool
- .queries_range(queries)
- .ok_or(CheckCopyQueryPoolResultsError::OutOfRange)?;
-
- Ok(queries_range.check_query_pool_results::<T>(
- buffer_inner.offset,
- destination.len(),
- flags,
- )?)
-}
-
-/// Error that can happen from `check_copy_query_pool_results`.
-#[derive(Debug, Copy, Clone)]
-pub enum CheckCopyQueryPoolResultsError {
- /// The buffer is too small for the copy operation.
- BufferTooSmall {
- /// Required number of elements in the buffer.
- required_len: DeviceSize,
- /// Actual number of elements in the buffer.
- actual_len: DeviceSize,
- },
- /// The destination buffer is missing the transfer destination usage.
- DestinationMissingTransferUsage,
- /// The provided flags are not allowed for this type of query.
- InvalidFlags,
- /// The provided queries range is not valid for this pool.
- OutOfRange,
-}
-
-impl From<GetResultsError> for CheckCopyQueryPoolResultsError {
- #[inline]
- fn from(value: GetResultsError) -> Self {
- match value {
- GetResultsError::BufferTooSmall {
- required_len,
- actual_len,
- } => CheckCopyQueryPoolResultsError::BufferTooSmall {
- required_len,
- actual_len,
- },
- GetResultsError::InvalidFlags => CheckCopyQueryPoolResultsError::InvalidFlags,
- GetResultsError::DeviceLost | GetResultsError::OomError(_) => unreachable!(),
- }
- }
-}
-
-impl error::Error for CheckCopyQueryPoolResultsError {}
-
-impl fmt::Display for CheckCopyQueryPoolResultsError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- Self::BufferTooSmall { .. } => {
- "the buffer is too small for the copy operation"
- }
- Self::DestinationMissingTransferUsage => {
- "the destination buffer is missing the transfer destination usage"
- }
- Self::InvalidFlags => {
- "the provided flags are not allowed for this type of query"
- }
- Self::OutOfRange => {
- "the provided queries range is not valid for this pool"
- }
- }
- )
- }
-}
-
-/// Checks whether a `reset_query_pool` command is valid.
-///
-/// # Panic
-///
-/// - Panics if the query pool was not created with `device`.
-pub fn check_reset_query_pool(
- device: &Device,
- query_pool: &QueryPool,
- queries: Range<u32>,
-) -> Result<(), CheckResetQueryPoolError> {
- assert_eq!(
- device.internal_object(),
- query_pool.device().internal_object(),
- );
- query_pool
- .queries_range(queries)
- .ok_or(CheckResetQueryPoolError::OutOfRange)?;
- Ok(())
-}
-
-/// Error that can happen from `check_reset_query_pool`.
-#[derive(Debug, Copy, Clone)]
-pub enum CheckResetQueryPoolError {
- /// The provided queries range is not valid for this pool.
- OutOfRange,
-}
-
-impl error::Error for CheckResetQueryPoolError {}
-
-impl fmt::Display for CheckResetQueryPoolError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- Self::OutOfRange => {
- "the provided queries range is not valid for this pool"
- }
- }
- )
- }
-}
diff --git a/src/command_buffer/validity/update_buffer.rs b/src/command_buffer/validity/update_buffer.rs
deleted file mode 100644
index 39f60be..0000000
--- a/src/command_buffer/validity/update_buffer.rs
+++ /dev/null
@@ -1,181 +0,0 @@
-// Copyright (c) 2017 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::buffer::TypedBufferAccess;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::DeviceSize;
-use crate::VulkanObject;
-use std::cmp;
-use std::error;
-use std::fmt;
-use std::mem;
-
-/// Checks whether an update buffer command is valid.
-///
-/// # Panic
-///
-/// - Panics if the buffer not created with `device`.
-///
-pub fn check_update_buffer<B, D>(
- device: &Device,
- buffer: &B,
- data: &D,
-) -> Result<(), CheckUpdateBufferError>
-where
- B: ?Sized + TypedBufferAccess<Content = D>,
- D: ?Sized,
-{
- assert_eq!(
- buffer.inner().buffer.device().internal_object(),
- device.internal_object()
- );
-
- if !buffer.inner().buffer.usage().transfer_destination {
- return Err(CheckUpdateBufferError::BufferMissingUsage);
- }
-
- if buffer.inner().offset % 4 != 0 {
- return Err(CheckUpdateBufferError::WrongAlignment);
- }
-
- let size = cmp::min(buffer.size(), mem::size_of_val(data) as DeviceSize);
-
- if size % 4 != 0 {
- return Err(CheckUpdateBufferError::WrongAlignment);
- }
-
- if size > 65536 {
- return Err(CheckUpdateBufferError::DataTooLarge);
- }
-
- Ok(())
-}
-
-/// Error that can happen when attempting to add an `update_buffer` command.
-#[derive(Debug, Copy, Clone)]
-pub enum CheckUpdateBufferError {
- /// The "transfer destination" usage must be enabled on the buffer.
- BufferMissingUsage,
- /// The data or size must be 4-bytes aligned.
- WrongAlignment,
- /// The data must not be larger than 64k bytes.
- DataTooLarge,
-}
-
-impl error::Error for CheckUpdateBufferError {}
-
-impl fmt::Display for CheckUpdateBufferError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- CheckUpdateBufferError::BufferMissingUsage => {
- "the transfer destination usage must be enabled on the buffer"
- }
- CheckUpdateBufferError::WrongAlignment => {
- "the offset or size are not aligned to 4 bytes"
- }
- CheckUpdateBufferError::DataTooLarge => "data is too large",
- }
- )
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::buffer::BufferAccess;
- use crate::buffer::BufferUsage;
- use crate::buffer::CpuAccessibleBuffer;
-
- #[test]
- fn missing_usage() {
- let (device, queue) = gfx_dev_and_queue!();
- let buffer = CpuAccessibleBuffer::from_data(
- device.clone(),
- BufferUsage::vertex_buffer(),
- false,
- 0u32,
- )
- .unwrap();
-
- match check_update_buffer(&device, &buffer, &0) {
- Err(CheckUpdateBufferError::BufferMissingUsage) => (),
- _ => panic!(),
- }
- }
-
- #[test]
- fn data_too_large() {
- let (device, queue) = gfx_dev_and_queue!();
- let buffer = CpuAccessibleBuffer::from_iter(
- device.clone(),
- BufferUsage::transfer_destination(),
- false,
- 0..65536,
- )
- .unwrap();
- let data = (0..65536).collect::<Vec<u32>>();
-
- match check_update_buffer(&device, &buffer, &data[..]) {
- Err(CheckUpdateBufferError::DataTooLarge) => (),
- _ => panic!(),
- }
- }
-
- #[test]
- fn data_just_large_enough() {
- let (device, queue) = gfx_dev_and_queue!();
- let buffer = CpuAccessibleBuffer::from_iter(
- device.clone(),
- BufferUsage::transfer_destination(),
- false,
- (0..100000).map(|_| 0),
- )
- .unwrap();
- let data = (0..65536).map(|_| 0).collect::<Vec<u8>>();
-
- match check_update_buffer(&device, &buffer, &data[..]) {
- Ok(_) => (),
- _ => panic!(),
- }
- }
-
- #[test]
- fn wrong_alignment() {
- let (device, queue) = gfx_dev_and_queue!();
- let buffer = CpuAccessibleBuffer::from_iter(
- device.clone(),
- BufferUsage::transfer_destination(),
- false,
- 0..100,
- )
- .unwrap();
- let data = (0..30).collect::<Vec<u8>>();
-
- match check_update_buffer(&device, &buffer.slice(1..50).unwrap(), &data[..]) {
- Err(CheckUpdateBufferError::WrongAlignment) => (),
- _ => panic!(),
- }
- }
-
- #[test]
- fn wrong_device() {
- let (dev1, queue) = gfx_dev_and_queue!();
- let (dev2, _) = gfx_dev_and_queue!();
- let buffer = CpuAccessibleBuffer::from_data(dev1, BufferUsage::all(), false, 0u32).unwrap();
-
- assert_should_panic!({
- let _ = check_update_buffer(&dev2, &buffer, &0);
- });
- }
-}
diff --git a/src/command_buffer/validity/vertex_buffers.rs b/src/command_buffer/validity/vertex_buffers.rs
deleted file mode 100644
index 9031498..0000000
--- a/src/command_buffer/validity/vertex_buffers.rs
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright (c) 2017 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use std::error;
-use std::fmt;
-
-use crate::buffer::BufferAccess;
-use crate::device::DeviceOwned;
-use crate::pipeline::vertex::VertexSource;
-use crate::pipeline::GraphicsPipelineAbstract;
-use crate::VulkanObject;
-
-/// Checks whether vertex buffers can be bound.
-///
-/// # Panic
-///
-/// - Panics if one of the vertex buffers was not created with the same device as `pipeline`.
-///
-pub fn check_vertex_buffers<GP, V>(
- pipeline: &GP,
- vertex_buffers: V,
-) -> Result<CheckVertexBuffer, CheckVertexBufferError>
-where
- GP: GraphicsPipelineAbstract + DeviceOwned + VertexSource<V>,
-{
- let (vertex_buffers, vertex_count, instance_count) = pipeline.decode(vertex_buffers);
-
- for (num, buf) in vertex_buffers.iter().enumerate() {
- assert_eq!(
- buf.inner().buffer.device().internal_object(),
- pipeline.device().internal_object()
- );
-
- if !buf.inner().buffer.usage().vertex_buffer {
- return Err(CheckVertexBufferError::BufferMissingUsage { num_buffer: num });
- }
- }
-
- if let Some(multiview) = pipeline.subpass().render_pass().desc().multiview() {
- let max_instance_index = pipeline
- .device()
- .physical_device()
- .properties()
- .max_multiview_instance_index
- .unwrap_or(0) as usize;
-
- // vulkano currently always uses `0` as the first instance which means the highest
- // used index will just be `instance_count - 1`
- if instance_count > max_instance_index + 1 {
- return Err(CheckVertexBufferError::TooManyInstances {
- instance_count,
- max_instance_count: max_instance_index + 1,
- });
- }
- }
-
- Ok(CheckVertexBuffer {
- vertex_buffers,
- vertex_count: vertex_count as u32,
- instance_count: instance_count as u32,
- })
-}
-
-/// Information returned if `check_vertex_buffer` succeeds.
-pub struct CheckVertexBuffer {
- /// The list of vertex buffers.
- pub vertex_buffers: Vec<Box<dyn BufferAccess + Send + Sync>>,
- /// Number of vertices available in the intersection of the buffers.
- pub vertex_count: u32,
- /// Number of instances available in the intersection of the buffers.
- pub instance_count: u32,
-}
-
-/// Error that can happen when checking whether the vertex buffers are valid.
-#[derive(Debug, Copy, Clone)]
-pub enum CheckVertexBufferError {
- /// The "vertex buffer" usage must be enabled on the buffer.
- BufferMissingUsage {
- /// Index of the buffer that is missing usage.
- num_buffer: usize,
- },
-
- /// The vertex buffer has too many instances.
- /// When the `multiview` feature is used the maximum amount of instances may be reduced
- /// because the implementation may use instancing internally to implement `multiview`.
- TooManyInstances {
- /// The used amount of instances.
- instance_count: usize,
- /// The allowed amount of instances.
- max_instance_count: usize,
- },
-}
-
-impl error::Error for CheckVertexBufferError {}
-
-impl fmt::Display for CheckVertexBufferError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- CheckVertexBufferError::BufferMissingUsage { .. } => {
- "the vertex buffer usage is missing on a vertex buffer"
- }
- CheckVertexBufferError::TooManyInstances { .. } => {
- "the vertex buffer has too many instances"
- }
- }
- )
- }
-}
diff --git a/src/descriptor_set/allocator.rs b/src/descriptor_set/allocator.rs
new file mode 100644
index 0000000..954db3f
--- /dev/null
+++ b/src/descriptor_set/allocator.rs
@@ -0,0 +1,576 @@
+// Copyright (c) 2021 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+//! In the Vulkan API, descriptor sets must be allocated from *descriptor pools*.
+//!
+//! A descriptor pool holds and manages the memory of one or more descriptor sets. If you destroy a
+//! descriptor pool, all of its descriptor sets are automatically destroyed.
+//!
+//! In vulkano, creating a descriptor set requires passing an implementation of the
+//! [`DescriptorSetAllocator`] trait, which you can implement yourself or use the vulkano-provided
+//! [`StandardDescriptorSetAllocator`].
+
+use self::sorted_map::SortedMap;
+use super::{
+ layout::DescriptorSetLayout,
+ pool::{
+ DescriptorPool, DescriptorPoolAllocError, DescriptorPoolCreateInfo,
+ DescriptorSetAllocateInfo,
+ },
+ sys::UnsafeDescriptorSet,
+};
+use crate::{
+ device::{Device, DeviceOwned},
+ OomError,
+};
+use crossbeam_queue::ArrayQueue;
+use std::{cell::UnsafeCell, mem::ManuallyDrop, num::NonZeroU64, sync::Arc, thread};
+use thread_local::ThreadLocal;
+
+const MAX_POOLS: usize = 32;
+
+const MAX_SETS: usize = 256;
+
+/// Types that manage the memory of descriptor sets.
+///
+/// # Safety
+///
+/// A Vulkan descriptor pool must be externally synchronized as if it owned the descriptor sets that
+/// were allocated from it. This includes allocating from the pool, freeing from the pool and
+/// resetting the pool or individual descriptor sets. The implementation of `DescriptorSetAllocator`
+/// is expected to manage this.
+///
+/// The destructor of the [`DescriptorSetAlloc`] is expected to free the descriptor set, reset the
+/// descriptor set, or add it to a pool so that it gets reused. If the implementation frees or
+/// resets the descriptor set, it must not forget that this operation must be externally
+/// synchronized.
+pub unsafe trait DescriptorSetAllocator: DeviceOwned {
+ /// Object that represented an allocated descriptor set.
+ ///
+ /// The destructor of this object should free the descriptor set.
+ type Alloc: DescriptorSetAlloc;
+
+ /// Allocates a descriptor set.
+ fn allocate(
+ &self,
+ layout: &Arc<DescriptorSetLayout>,
+ variable_descriptor_count: u32,
+ ) -> Result<Self::Alloc, OomError>;
+}
+
+/// An allocated descriptor set.
+pub trait DescriptorSetAlloc: Send + Sync {
+ /// Returns the inner unsafe descriptor set object.
+ fn inner(&self) -> &UnsafeDescriptorSet;
+
+ /// Returns the inner unsafe descriptor set object.
+ fn inner_mut(&mut self) -> &mut UnsafeDescriptorSet;
+}
+
+/// Standard implementation of a descriptor set allocator.
+///
+/// The intended way to use this allocator is to have one that is used globally for the duration of
+/// the program, in order to avoid creating and destroying [`DescriptorPool`]s, as that is
+/// expensive. Alternatively, you can have one locally on a thread for the duration of the thread.
+///
+/// Internally, this allocator uses one or more `DescriptorPool`s per descriptor set layout per
+/// thread, using Thread-Local Storage. When a thread first allocates, an entry is reserved for the
+/// thread and descriptor set layout combination. After a thread exits and the allocator wasn't
+/// dropped yet, its entries are freed, but the pools it used are not dropped. The next time a new
+/// thread allocates for the first time, the entries are reused along with the pools. If all
+/// threads drop their reference to the allocator, all entries along with the allocator are
+/// dropped, even if the threads didn't exit yet, which is why you should keep the allocator alive
+/// for as long as you need to allocate so that the pools can keep being reused.
+///
+/// This allocator only needs to lock when a thread first allocates or when a thread that
+/// previously allocated exits. In all other cases, allocation is lock-free.
+///
+/// [`DescriptorPool`]: crate::descriptor_set::pool::DescriptorPool
+#[derive(Debug)]
+pub struct StandardDescriptorSetAllocator {
+ device: Arc<Device>,
+ pools: ThreadLocal<UnsafeCell<SortedMap<NonZeroU64, Entry>>>,
+}
+
+#[derive(Debug)]
+enum Entry {
+ Fixed(FixedEntry),
+ Variable(VariableEntry),
+}
+
+// This is needed because of the blanket impl of `Send` on `Arc<T>`, which requires that `T` is
+// `Send + Sync`. `FixedPool` and `VariablePool` are `Send + !Sync` because `DescriptorPool` is
+// `!Sync`. That's fine however because we never access the `DescriptorPool` concurrently.
+unsafe impl Send for Entry {}
+
+impl StandardDescriptorSetAllocator {
+ /// Creates a new `StandardDescriptorSetAllocator`.
+ #[inline]
+ pub fn new(device: Arc<Device>) -> StandardDescriptorSetAllocator {
+ StandardDescriptorSetAllocator {
+ device,
+ pools: ThreadLocal::new(),
+ }
+ }
+
+ /// Clears the entry for the given descriptor set layout and the current thread. This does not
+ /// mean that the pools are dropped immediately. A pool is kept alive for as long as descriptor
+ /// sets allocated from it exist.
+ ///
+ /// This has no effect if the entry was not initialized yet.
+ #[inline]
+ pub fn clear(&self, layout: &Arc<DescriptorSetLayout>) {
+ unsafe { &mut *self.pools.get_or(Default::default).get() }.remove(layout.id())
+ }
+
+ /// Clears all entries for the current thread. This does not mean that the pools are dropped
+ /// immediately. A pool is kept alive for as long as descriptor sets allocated from it exist.
+ ///
+ /// This has no effect if no entries were initialized yet.
+ #[inline]
+ pub fn clear_all(&self) {
+ unsafe { *self.pools.get_or(Default::default).get() = SortedMap::default() };
+ }
+}
+
+unsafe impl DescriptorSetAllocator for StandardDescriptorSetAllocator {
+ type Alloc = StandardDescriptorSetAlloc;
+
+ /// Allocates a descriptor set.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the provided `layout` is for push descriptors rather than regular descriptor
+ /// sets.
+ /// - Panics if the provided `variable_descriptor_count` is greater than the maximum number of
+ /// variable count descriptors in the set.
+ #[inline]
+ fn allocate(
+ &self,
+ layout: &Arc<DescriptorSetLayout>,
+ variable_descriptor_count: u32,
+ ) -> Result<StandardDescriptorSetAlloc, OomError> {
+ assert!(
+ !layout.push_descriptor(),
+ "the provided descriptor set layout is for push descriptors, and cannot be used to \
+ build a descriptor set object",
+ );
+
+ let max_count = layout.variable_descriptor_count();
+
+ assert!(
+ variable_descriptor_count <= max_count,
+ "the provided variable_descriptor_count ({}) is greater than the maximum number of \
+ variable count descriptors in the set ({})",
+ variable_descriptor_count,
+ max_count,
+ );
+
+ let pools = self.pools.get_or(Default::default);
+ let entry = unsafe { &mut *pools.get() }.get_or_try_insert(layout.id(), || {
+ if max_count == 0 {
+ FixedEntry::new(layout.clone()).map(Entry::Fixed)
+ } else {
+ VariableEntry::new(layout.clone()).map(Entry::Variable)
+ }
+ })?;
+
+ match entry {
+ Entry::Fixed(entry) => entry.allocate(),
+ Entry::Variable(entry) => entry.allocate(variable_descriptor_count),
+ }
+ }
+}
+
+unsafe impl DescriptorSetAllocator for Arc<StandardDescriptorSetAllocator> {
+ type Alloc = StandardDescriptorSetAlloc;
+
+ #[inline]
+ fn allocate(
+ &self,
+ layout: &Arc<DescriptorSetLayout>,
+ variable_descriptor_count: u32,
+ ) -> Result<Self::Alloc, OomError> {
+ (**self).allocate(layout, variable_descriptor_count)
+ }
+}
+
+unsafe impl DeviceOwned for StandardDescriptorSetAllocator {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+}
+
+#[derive(Debug)]
+struct FixedEntry {
+ // The `FixedPool` struct contains an actual Vulkan pool. Every time it is full we create
+ // a new pool and replace the current one with the new one.
+ pool: Arc<FixedPool>,
+ // The amount of sets available to use when we create a new Vulkan pool.
+ set_count: usize,
+ // The descriptor set layout that this pool is for.
+ layout: Arc<DescriptorSetLayout>,
+}
+
+impl FixedEntry {
+ fn new(layout: Arc<DescriptorSetLayout>) -> Result<Self, OomError> {
+ Ok(FixedEntry {
+ pool: FixedPool::new(&layout, MAX_SETS)?,
+ set_count: MAX_SETS,
+ layout,
+ })
+ }
+
+ fn allocate(&mut self) -> Result<StandardDescriptorSetAlloc, OomError> {
+ let inner = if let Some(inner) = self.pool.reserve.pop() {
+ inner
+ } else {
+ self.set_count *= 2;
+ self.pool = FixedPool::new(&self.layout, self.set_count)?;
+
+ self.pool.reserve.pop().unwrap()
+ };
+
+ Ok(StandardDescriptorSetAlloc {
+ inner: ManuallyDrop::new(inner),
+ parent: AllocParent::Fixed(self.pool.clone()),
+ })
+ }
+}
+
+#[derive(Debug)]
+struct FixedPool {
+ // The actual Vulkan descriptor pool. This field isn't actually used anywhere, but we need to
+ // keep the pool alive in order to keep the descriptor sets valid.
+ _inner: DescriptorPool,
+ // List of descriptor sets. When `alloc` is called, a descriptor will be extracted from this
+ // list. When a `SingleLayoutPoolAlloc` is dropped, its descriptor set is put back in this list.
+ reserve: ArrayQueue<UnsafeDescriptorSet>,
+}
+
+impl FixedPool {
+ fn new(layout: &Arc<DescriptorSetLayout>, set_count: usize) -> Result<Arc<Self>, OomError> {
+ let inner = DescriptorPool::new(
+ layout.device().clone(),
+ DescriptorPoolCreateInfo {
+ max_sets: set_count as u32,
+ pool_sizes: layout
+ .descriptor_counts()
+ .iter()
+ .map(|(&ty, &count)| (ty, count * set_count as u32))
+ .collect(),
+ ..Default::default()
+ },
+ )?;
+
+ let allocate_infos = (0..set_count).map(|_| DescriptorSetAllocateInfo {
+ layout,
+ variable_descriptor_count: 0,
+ });
+
+ let reserve = match unsafe { inner.allocate_descriptor_sets(allocate_infos) } {
+ Ok(allocs) => {
+ let reserve = ArrayQueue::new(set_count);
+ for alloc in allocs {
+ let _ = reserve.push(alloc);
+ }
+
+ reserve
+ }
+ Err(DescriptorPoolAllocError::OutOfHostMemory) => {
+ return Err(OomError::OutOfHostMemory);
+ }
+ Err(DescriptorPoolAllocError::OutOfDeviceMemory) => {
+ return Err(OomError::OutOfDeviceMemory);
+ }
+ Err(DescriptorPoolAllocError::FragmentedPool) => {
+ // This can't happen as we don't free individual sets.
+ unreachable!();
+ }
+ Err(DescriptorPoolAllocError::OutOfPoolMemory) => {
+ // We created the pool with an exact size.
+ unreachable!();
+ }
+ };
+
+ Ok(Arc::new(FixedPool {
+ _inner: inner,
+ reserve,
+ }))
+ }
+}
+
+#[derive(Debug)]
+struct VariableEntry {
+ // The `VariablePool` struct contains an actual Vulkan pool. Every time it is full
+ // we grab one from the reserve, or create a new pool if there are none.
+ pool: Arc<VariablePool>,
+ // When a `VariablePool` is dropped, it returns its Vulkan pool here for reuse.
+ reserve: Arc<ArrayQueue<DescriptorPool>>,
+ // The descriptor set layout that this pool is for.
+ layout: Arc<DescriptorSetLayout>,
+ // The number of sets currently allocated from the Vulkan pool.
+ allocations: usize,
+}
+
+impl VariableEntry {
+ fn new(layout: Arc<DescriptorSetLayout>) -> Result<Self, OomError> {
+ let reserve = Arc::new(ArrayQueue::new(MAX_POOLS));
+
+ Ok(VariableEntry {
+ pool: VariablePool::new(&layout, reserve.clone())?,
+ reserve,
+ layout,
+ allocations: 0,
+ })
+ }
+
+ fn allocate(
+ &mut self,
+ variable_descriptor_count: u32,
+ ) -> Result<StandardDescriptorSetAlloc, OomError> {
+ if self.allocations >= MAX_SETS {
+ self.pool = if let Some(inner) = self.reserve.pop() {
+ Arc::new(VariablePool {
+ inner: ManuallyDrop::new(inner),
+ reserve: self.reserve.clone(),
+ })
+ } else {
+ VariablePool::new(&self.layout, self.reserve.clone())?
+ };
+ self.allocations = 0;
+ }
+
+ let allocate_info = DescriptorSetAllocateInfo {
+ layout: &self.layout,
+ variable_descriptor_count,
+ };
+
+ let inner = match unsafe { self.pool.inner.allocate_descriptor_sets([allocate_info]) } {
+ Ok(mut sets) => sets.next().unwrap(),
+ Err(DescriptorPoolAllocError::OutOfHostMemory) => {
+ return Err(OomError::OutOfHostMemory);
+ }
+ Err(DescriptorPoolAllocError::OutOfDeviceMemory) => {
+ return Err(OomError::OutOfDeviceMemory);
+ }
+ Err(DescriptorPoolAllocError::FragmentedPool) => {
+ // This can't happen as we don't free individual sets.
+ unreachable!();
+ }
+ Err(DescriptorPoolAllocError::OutOfPoolMemory) => {
+ // We created the pool to fit the maximum variable descriptor count.
+ unreachable!();
+ }
+ };
+
+ self.allocations += 1;
+
+ Ok(StandardDescriptorSetAlloc {
+ inner: ManuallyDrop::new(inner),
+ parent: AllocParent::Variable(self.pool.clone()),
+ })
+ }
+}
+
+#[derive(Debug)]
+struct VariablePool {
+ // The actual Vulkan descriptor pool.
+ inner: ManuallyDrop<DescriptorPool>,
+ // Where we return the Vulkan descriptor pool in our `Drop` impl.
+ reserve: Arc<ArrayQueue<DescriptorPool>>,
+}
+
+impl VariablePool {
+ fn new(
+ layout: &Arc<DescriptorSetLayout>,
+ reserve: Arc<ArrayQueue<DescriptorPool>>,
+ ) -> Result<Arc<Self>, OomError> {
+ DescriptorPool::new(
+ layout.device().clone(),
+ DescriptorPoolCreateInfo {
+ max_sets: MAX_SETS as u32,
+ pool_sizes: layout
+ .descriptor_counts()
+ .iter()
+ .map(|(&ty, &count)| (ty, count * MAX_SETS as u32))
+ .collect(),
+ ..Default::default()
+ },
+ )
+ .map(|inner| {
+ Arc::new(Self {
+ inner: ManuallyDrop::new(inner),
+ reserve,
+ })
+ })
+ }
+}
+
+impl Drop for VariablePool {
+ fn drop(&mut self) {
+ let inner = unsafe { ManuallyDrop::take(&mut self.inner) };
+
+ if thread::panicking() {
+ return;
+ }
+
+ unsafe { inner.reset() }.unwrap();
+
+ // If there is not enough space in the reserve, we destroy the pool. The only way this can
+ // happen is if something is resource hogging, forcing new pools to be created such that
+ // the number exceeds `MAX_POOLS`, and then drops them all at once.
+ let _ = self.reserve.push(inner);
+ }
+}
+
+/// A descriptor set allocated from a [`StandardDescriptorSetAllocator`].
+#[derive(Debug)]
+pub struct StandardDescriptorSetAlloc {
+ // The actual descriptor set.
+ inner: ManuallyDrop<UnsafeDescriptorSet>,
+ // The pool where we allocated from. Needed for our `Drop` impl.
+ parent: AllocParent,
+}
+
+#[derive(Debug)]
+enum AllocParent {
+ Fixed(Arc<FixedPool>),
+ Variable(Arc<VariablePool>),
+}
+
+// This is needed because of the blanket impl of `Send` on `Arc<T>`, which requires that `T` is
+// `Send + Sync`. `FixedPool` and `VariablePool` are `Send + !Sync` because `DescriptorPool` is
+// `!Sync`. That's fine however because we never access the `DescriptorPool` concurrently.
+unsafe impl Send for StandardDescriptorSetAlloc {}
+unsafe impl Sync for StandardDescriptorSetAlloc {}
+
+impl DescriptorSetAlloc for StandardDescriptorSetAlloc {
+ #[inline]
+ fn inner(&self) -> &UnsafeDescriptorSet {
+ &self.inner
+ }
+
+ #[inline]
+ fn inner_mut(&mut self) -> &mut UnsafeDescriptorSet {
+ &mut self.inner
+ }
+}
+
+impl Drop for StandardDescriptorSetAlloc {
+ #[inline]
+ fn drop(&mut self) {
+ let inner = unsafe { ManuallyDrop::take(&mut self.inner) };
+
+ match &self.parent {
+ AllocParent::Fixed(pool) => {
+ let _ = pool.reserve.push(inner);
+ }
+ AllocParent::Variable(_) => {}
+ }
+ }
+}
+
+mod sorted_map {
+ use smallvec::SmallVec;
+
+ /// Minimal implementation of a `SortedMap`. This outperforms both a [`BTreeMap`] and
+ /// [`HashMap`] for small numbers of elements. In Vulkan, having too many descriptor set
+ /// layouts is highly discouraged, which is why this optimization makes sense.
+ #[derive(Debug)]
+ pub(super) struct SortedMap<K, V> {
+ inner: SmallVec<[(K, V); 8]>,
+ }
+
+ impl<K, V> Default for SortedMap<K, V> {
+ fn default() -> Self {
+ Self {
+ inner: SmallVec::default(),
+ }
+ }
+ }
+
+ impl<K: Ord + Copy, V> SortedMap<K, V> {
+ pub fn get_or_try_insert<E>(
+ &mut self,
+ key: K,
+ f: impl FnOnce() -> Result<V, E>,
+ ) -> Result<&mut V, E> {
+ match self.inner.binary_search_by_key(&key, |&(k, _)| k) {
+ Ok(index) => Ok(&mut self.inner[index].1),
+ Err(index) => {
+ self.inner.insert(index, (key, f()?));
+ Ok(&mut self.inner[index].1)
+ }
+ }
+ }
+
+ pub fn remove(&mut self, key: K) {
+ if let Ok(index) = self.inner.binary_search_by_key(&key, |&(k, _)| k) {
+ self.inner.remove(index);
+ }
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::{
+ descriptor_set::layout::{
+ DescriptorSetLayoutBinding, DescriptorSetLayoutCreateInfo, DescriptorType,
+ },
+ shader::ShaderStages,
+ VulkanObject,
+ };
+ use std::thread;
+
+ #[test]
+ fn threads_use_different_pools() {
+ let (device, _) = gfx_dev_and_queue!();
+
+ let layout = DescriptorSetLayout::new(
+ device.clone(),
+ DescriptorSetLayoutCreateInfo {
+ bindings: [(
+ 0,
+ DescriptorSetLayoutBinding {
+ stages: ShaderStages::all_graphics(),
+ ..DescriptorSetLayoutBinding::descriptor_type(DescriptorType::UniformBuffer)
+ },
+ )]
+ .into(),
+ ..Default::default()
+ },
+ )
+ .unwrap();
+
+ let allocator = StandardDescriptorSetAllocator::new(device);
+
+ let pool1 =
+ if let AllocParent::Fixed(pool) = &allocator.allocate(&layout, 0).unwrap().parent {
+ pool._inner.handle()
+ } else {
+ unreachable!()
+ };
+
+ thread::spawn(move || {
+ let pool2 =
+ if let AllocParent::Fixed(pool) = &allocator.allocate(&layout, 0).unwrap().parent {
+ pool._inner.handle()
+ } else {
+ unreachable!()
+ };
+ assert_ne!(pool1, pool2);
+ })
+ .join()
+ .unwrap();
+ }
+}
diff --git a/src/descriptor_set/collection.rs b/src/descriptor_set/collection.rs
index d62c15a..77eb4fa 100644
--- a/src/descriptor_set/collection.rs
+++ b/src/descriptor_set/collection.rs
@@ -25,7 +25,6 @@ unsafe impl<T> DescriptorSetsCollection for T
where
T: Into<DescriptorSetWithOffsets>,
{
- #[inline]
fn into_vec(self) -> Vec<DescriptorSetWithOffsets> {
vec![self.into()]
}
@@ -35,7 +34,6 @@ unsafe impl<T> DescriptorSetsCollection for Vec<T>
where
T: Into<DescriptorSetWithOffsets>,
{
- #[inline]
fn into_vec(self) -> Vec<DescriptorSetWithOffsets> {
self.into_iter().map(|x| x.into()).collect()
}
@@ -48,17 +46,10 @@ macro_rules! impl_collection {
$(, $others: Into<DescriptorSetWithOffsets>)*
{
#[inline]
+ #[allow(non_snake_case)]
fn into_vec(self) -> Vec<DescriptorSetWithOffsets> {
- #![allow(non_snake_case)]
-
let ($first, $($others,)*) = self;
-
- let mut list = Vec::new();
- list.push($first.into());
- $(
- list.push($others.into());
- )+
- list
+ vec![$first.into() $(, $others.into())+]
}
}
diff --git a/src/descriptor_set/fixed_size_pool.rs b/src/descriptor_set/fixed_size_pool.rs
deleted file mode 100644
index 248f794..0000000
--- a/src/descriptor_set/fixed_size_pool.rs
+++ /dev/null
@@ -1,604 +0,0 @@
-// Copyright (c) 2017 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-//! Pool of descriptor sets of a specific capacity that are automatically reclaimed.
-//!
-//! You are encouraged to use this type when you need a different descriptor set at each frame, or
-//! regularly during the execution.
-//!
-//! # Example
-//!
-//! At initialization, create a `FixedSizeDescriptorSetsPool`.
-//!
-//! ```rust
-//! use vulkano::descriptor_set::FixedSizeDescriptorSetsPool;
-//! # use vulkano::pipeline::GraphicsPipelineAbstract;
-//! # use std::sync::Arc;
-//! # let graphics_pipeline: Arc<GraphicsPipelineAbstract> = return;
-//! // use vulkano::pipeline::GraphicsPipelineAbstract;
-//! // let graphics_pipeline: Arc<GraphicsPipelineAbstract> = ...;
-//!
-//! let layout = graphics_pipeline.layout().descriptor_set_layouts().get(0).unwrap();
-//! let pool = FixedSizeDescriptorSetsPool::new(layout.clone());
-//! ```
-//!
-//! You would then typically store the pool in a struct for later. Then whenever you need a
-//! descriptor set, call `pool.next()` to start the process of building it.
-//!
-//! ```rust
-//! # use std::sync::Arc;
-//! # use vulkano::descriptor_set::FixedSizeDescriptorSetsPool;
-//! # use vulkano::pipeline::GraphicsPipelineAbstract;
-//! # let mut pool: FixedSizeDescriptorSetsPool = return;
-//! let descriptor_set = pool.next()
-//! //.add_buffer(...)
-//! //.add_sampled_image(...)
-//! .build().unwrap();
-//! ```
-//!
-//! Note that `next()` requires exclusive (`mut`) access to the pool. You can use a `Mutex` around
-//! the pool if you can't provide this.
-
-use crate::buffer::BufferAccess;
-use crate::buffer::BufferViewRef;
-use crate::descriptor_set::layout::DescriptorSetLayout;
-use crate::descriptor_set::persistent::*;
-use crate::descriptor_set::pool::DescriptorPool;
-use crate::descriptor_set::pool::DescriptorPoolAlloc;
-use crate::descriptor_set::pool::DescriptorPoolAllocError;
-use crate::descriptor_set::pool::UnsafeDescriptorPool;
-use crate::descriptor_set::DescriptorSet;
-use crate::descriptor_set::UnsafeDescriptorSet;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::image::view::ImageViewAbstract;
-use crate::sampler::Sampler;
-use crate::OomError;
-use crate::VulkanObject;
-use crossbeam_queue::SegQueue;
-use std::hash::Hash;
-use std::hash::Hasher;
-use std::sync::Arc;
-
-/// Pool of descriptor sets of a specific capacity that are automatically reclaimed.
-#[derive(Clone)]
-pub struct FixedSizeDescriptorSetsPool {
- layout: Arc<DescriptorSetLayout>,
- // We hold a local implementation of the `DescriptorPool` trait for our own purpose. Since we
- // don't want to expose this trait impl in our API, we use a separate struct.
- pool: LocalPool,
-}
-
-impl FixedSizeDescriptorSetsPool {
- /// Initializes a new pool. The pool is configured to allocate sets that corresponds to the
- /// parameters passed to this function.
- pub fn new(layout: Arc<DescriptorSetLayout>) -> FixedSizeDescriptorSetsPool {
- let device = layout.device().clone();
-
- FixedSizeDescriptorSetsPool {
- layout,
- pool: LocalPool {
- device,
- next_capacity: 3,
- current_pool: None,
- },
- }
- }
-
- /// Starts the process of building a new descriptor set.
- ///
- /// The set will corresponds to the set layout that was passed to `new`.
- #[inline]
- pub fn next(&mut self) -> FixedSizeDescriptorSetBuilder<()> {
- let inner = PersistentDescriptorSet::start(self.layout.clone());
-
- FixedSizeDescriptorSetBuilder { pool: self, inner }
- }
-}
-
-/// A descriptor set created from a `FixedSizeDescriptorSetsPool`.
-pub struct FixedSizeDescriptorSet<R> {
- inner: PersistentDescriptorSet<R, LocalPoolAlloc>,
-}
-
-unsafe impl<R> DescriptorSet for FixedSizeDescriptorSet<R>
-where
- R: PersistentDescriptorSetResources,
-{
- #[inline]
- fn inner(&self) -> &UnsafeDescriptorSet {
- self.inner.inner()
- }
-
- #[inline]
- fn layout(&self) -> &Arc<DescriptorSetLayout> {
- self.inner.layout()
- }
-
- #[inline]
- fn num_buffers(&self) -> usize {
- self.inner.num_buffers()
- }
-
- #[inline]
- fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)> {
- self.inner.buffer(index)
- }
-
- #[inline]
- fn num_images(&self) -> usize {
- self.inner.num_images()
- }
-
- #[inline]
- fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)> {
- self.inner.image(index)
- }
-}
-
-unsafe impl<R> DeviceOwned for FixedSizeDescriptorSet<R> {
- #[inline]
- fn device(&self) -> &Arc<Device> {
- self.inner.device()
- }
-}
-
-impl<R> PartialEq for FixedSizeDescriptorSet<R>
-where
- R: PersistentDescriptorSetResources,
-{
- #[inline]
- fn eq(&self, other: &Self) -> bool {
- self.inner().internal_object() == other.inner().internal_object()
- && self.device() == other.device()
- }
-}
-
-impl<R> Eq for FixedSizeDescriptorSet<R> where R: PersistentDescriptorSetResources {}
-
-impl<R> Hash for FixedSizeDescriptorSet<R>
-where
- R: PersistentDescriptorSetResources,
-{
- #[inline]
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.inner().internal_object().hash(state);
- self.device().hash(state);
- }
-}
-
-// The fields of this struct can be considered as fields of the `FixedSizeDescriptorSet`. They are
-// in a separate struct because we don't want to expose the fact that we implement the
-// `DescriptorPool` trait.
-#[derive(Clone)]
-struct LocalPool {
- // The `LocalPoolInner` struct contains an actual Vulkan pool. Every time it is full, we create
- // a new pool and replace the current one with the new one.
- current_pool: Option<Arc<LocalPoolInner>>,
- // Capacity to use when we create a new Vulkan pool.
- next_capacity: u32,
- // The Vulkan device.
- device: Arc<Device>,
-}
-
-struct LocalPoolInner {
- // The actual Vulkan descriptor pool. This field isn't actually used anywhere, but we need to
- // keep the pool alive in order to keep the descriptor sets valid.
- actual_pool: UnsafeDescriptorPool,
-
- // List of descriptor sets. When `alloc` is called, a descriptor will be extracted from this
- // list. When a `LocalPoolAlloc` is dropped, its descriptor set is put back in this list.
- reserve: SegQueue<UnsafeDescriptorSet>,
-}
-
-struct LocalPoolAlloc {
- // The `LocalPoolInner` we were allocated from. We need to keep a copy of it in each allocation
- // so that we can put back the allocation in the list in our `Drop` impl.
- pool: Arc<LocalPoolInner>,
-
- // The actual descriptor set, wrapped inside an `Option` so that we can extract it in our
- // `Drop` impl.
- actual_alloc: Option<UnsafeDescriptorSet>,
-}
-
-unsafe impl DescriptorPool for LocalPool {
- type Alloc = LocalPoolAlloc;
-
- fn alloc(&mut self, layout: &DescriptorSetLayout) -> Result<Self::Alloc, OomError> {
- loop {
- // Try to extract a descriptor from the current pool if any exist.
- // This is the most common case.
- if let Some(ref mut current_pool) = self.current_pool {
- if let Some(already_existing_set) = current_pool.reserve.pop() {
- return Ok(LocalPoolAlloc {
- actual_alloc: Some(already_existing_set),
- pool: current_pool.clone(),
- });
- }
- }
-
- // If we failed to grab an existing set, that means the current pool is full. Create a
- // new one of larger capacity.
- let count = *layout.descriptors_count() * self.next_capacity;
- let mut new_pool =
- UnsafeDescriptorPool::new(self.device.clone(), &count, self.next_capacity, false)?;
- let alloc = unsafe {
- match new_pool.alloc((0..self.next_capacity).map(|_| layout)) {
- Ok(iter) => {
- let stack = SegQueue::new();
- for elem in iter {
- stack.push(elem);
- }
- stack
- }
- Err(DescriptorPoolAllocError::OutOfHostMemory) => {
- return Err(OomError::OutOfHostMemory);
- }
- Err(DescriptorPoolAllocError::OutOfDeviceMemory) => {
- return Err(OomError::OutOfDeviceMemory);
- }
- Err(DescriptorPoolAllocError::FragmentedPool) => {
- // This can't happen as we don't free individual sets.
- unreachable!()
- }
- Err(DescriptorPoolAllocError::OutOfPoolMemory) => unreachable!(),
- }
- };
-
- self.next_capacity = self.next_capacity.saturating_mul(2);
- self.current_pool = Some(Arc::new(LocalPoolInner {
- actual_pool: new_pool,
- reserve: alloc,
- }));
- }
- }
-}
-
-unsafe impl DeviceOwned for LocalPool {
- #[inline]
- fn device(&self) -> &Arc<Device> {
- &self.device
- }
-}
-
-impl DescriptorPoolAlloc for LocalPoolAlloc {
- #[inline]
- fn inner(&self) -> &UnsafeDescriptorSet {
- self.actual_alloc.as_ref().unwrap()
- }
-
- #[inline]
- fn inner_mut(&mut self) -> &mut UnsafeDescriptorSet {
- self.actual_alloc.as_mut().unwrap()
- }
-}
-
-impl Drop for LocalPoolAlloc {
- fn drop(&mut self) {
- let inner = self.actual_alloc.take().unwrap();
- self.pool.reserve.push(inner);
- }
-}
-
-/// Prototype of a `FixedSizeDescriptorSet`.
-///
-/// The template parameter `R` is an unspecified type that represents the list of resources.
-///
-/// See the docs of `FixedSizeDescriptorSetsPool` for an example.
-pub struct FixedSizeDescriptorSetBuilder<'a, R> {
- pool: &'a mut FixedSizeDescriptorSetsPool,
- inner: PersistentDescriptorSetBuilder<R>,
-}
-
-impl<'a, R> FixedSizeDescriptorSetBuilder<'a, R> {
- /// Builds a `FixedSizeDescriptorSet` from the builder.
- #[inline]
- pub fn build(self) -> Result<FixedSizeDescriptorSet<R>, PersistentDescriptorSetBuildError> {
- let inner = self.inner.build_with_pool(&mut self.pool.pool)?;
- Ok(FixedSizeDescriptorSet { inner })
- }
-
- /// Call this function if the next element of the set is an array in order to set the value of
- /// each element.
- ///
- /// Returns an error if the descriptor is empty.
- ///
- /// This function can be called even if the descriptor isn't an array, and it is valid to enter
- /// the "array", add one element, then leave.
- #[inline]
- pub fn enter_array(
- self,
- ) -> Result<FixedSizeDescriptorSetBuilderArray<'a, R>, PersistentDescriptorSetError> {
- Ok(FixedSizeDescriptorSetBuilderArray {
- pool: self.pool,
- inner: self.inner.enter_array()?,
- })
- }
-
- /// Skips the current descriptor if it is empty.
- #[inline]
- pub fn add_empty(
- self,
- ) -> Result<FixedSizeDescriptorSetBuilder<'a, R>, PersistentDescriptorSetError> {
- Ok(FixedSizeDescriptorSetBuilder {
- pool: self.pool,
- inner: self.inner.add_empty()?,
- })
- }
-
- /// Binds a buffer as the next descriptor.
- ///
- /// An error is returned if the buffer isn't compatible with the descriptor.
- ///
- /// # Panic
- ///
- /// Panics if the buffer doesn't have the same device as the descriptor set layout.
- ///
- #[inline]
- pub fn add_buffer<T>(
- self,
- buffer: T,
- ) -> Result<
- FixedSizeDescriptorSetBuilder<'a, (R, PersistentDescriptorSetBuf<T>)>,
- PersistentDescriptorSetError,
- >
- where
- T: BufferAccess,
- {
- Ok(FixedSizeDescriptorSetBuilder {
- pool: self.pool,
- inner: self.inner.add_buffer(buffer)?,
- })
- }
-
- /// Binds a buffer view as the next descriptor.
- ///
- /// An error is returned if the buffer isn't compatible with the descriptor.
- ///
- /// # Panic
- ///
- /// Panics if the buffer view doesn't have the same device as the descriptor set layout.
- ///
- pub fn add_buffer_view<T>(
- self,
- view: T,
- ) -> Result<
- FixedSizeDescriptorSetBuilder<'a, (R, PersistentDescriptorSetBufView<T>)>,
- PersistentDescriptorSetError,
- >
- where
- T: BufferViewRef,
- {
- Ok(FixedSizeDescriptorSetBuilder {
- pool: self.pool,
- inner: self.inner.add_buffer_view(view)?,
- })
- }
-
- /// Binds an image view as the next descriptor.
- ///
- /// An error is returned if the image view isn't compatible with the descriptor.
- ///
- /// # Panic
- ///
- /// Panics if the image view doesn't have the same device as the descriptor set layout.
- ///
- #[inline]
- pub fn add_image<T>(
- self,
- image_view: T,
- ) -> Result<
- FixedSizeDescriptorSetBuilder<'a, (R, PersistentDescriptorSetImg<T>)>,
- PersistentDescriptorSetError,
- >
- where
- T: ImageViewAbstract,
- {
- Ok(FixedSizeDescriptorSetBuilder {
- pool: self.pool,
- inner: self.inner.add_image(image_view)?,
- })
- }
-
- /// Binds an image view with a sampler as the next descriptor.
- ///
- /// An error is returned if the image view isn't compatible with the descriptor.
- ///
- /// # Panic
- ///
- /// Panics if the image view or the sampler doesn't have the same device as the descriptor set layout.
- ///
- #[inline]
- pub fn add_sampled_image<T>(
- self,
- image_view: T,
- sampler: Arc<Sampler>,
- ) -> Result<
- FixedSizeDescriptorSetBuilder<
- 'a,
- (
- (R, PersistentDescriptorSetImg<T>),
- PersistentDescriptorSetSampler,
- ),
- >,
- PersistentDescriptorSetError,
- >
- where
- T: ImageViewAbstract,
- {
- Ok(FixedSizeDescriptorSetBuilder {
- pool: self.pool,
- inner: self.inner.add_sampled_image(image_view, sampler)?,
- })
- }
-
- /// Binds a sampler as the next descriptor.
- ///
- /// An error is returned if the sampler isn't compatible with the descriptor.
- ///
- /// # Panic
- ///
- /// Panics if the sampler doesn't have the same device as the descriptor set layout.
- ///
- #[inline]
- pub fn add_sampler(
- self,
- sampler: Arc<Sampler>,
- ) -> Result<
- FixedSizeDescriptorSetBuilder<'a, (R, PersistentDescriptorSetSampler)>,
- PersistentDescriptorSetError,
- > {
- Ok(FixedSizeDescriptorSetBuilder {
- pool: self.pool,
- inner: self.inner.add_sampler(sampler)?,
- })
- }
-}
-
-/// Same as `FixedSizeDescriptorSetBuilder`, but we're in an array.
-pub struct FixedSizeDescriptorSetBuilderArray<'a, R> {
- pool: &'a mut FixedSizeDescriptorSetsPool,
- inner: PersistentDescriptorSetBuilderArray<R>,
-}
-
-impl<'a, R> FixedSizeDescriptorSetBuilderArray<'a, R> {
- /// Leaves the array. Call this once you added all the elements of the array.
- pub fn leave_array(
- self,
- ) -> Result<FixedSizeDescriptorSetBuilder<'a, R>, PersistentDescriptorSetError> {
- Ok(FixedSizeDescriptorSetBuilder {
- pool: self.pool,
- inner: self.inner.leave_array()?,
- })
- }
-
- /// Binds a buffer as the next element in the array.
- ///
- /// An error is returned if the buffer isn't compatible with the descriptor.
- ///
- /// # Panic
- ///
- /// Panics if the buffer doesn't have the same device as the descriptor set layout.
- ///
- pub fn add_buffer<T>(
- self,
- buffer: T,
- ) -> Result<
- FixedSizeDescriptorSetBuilderArray<'a, (R, PersistentDescriptorSetBuf<T>)>,
- PersistentDescriptorSetError,
- >
- where
- T: BufferAccess,
- {
- Ok(FixedSizeDescriptorSetBuilderArray {
- pool: self.pool,
- inner: self.inner.add_buffer(buffer)?,
- })
- }
-
- /// Binds a buffer view as the next element in the array.
- ///
- /// An error is returned if the buffer isn't compatible with the descriptor.
- ///
- /// # Panic
- ///
- /// Panics if the buffer view doesn't have the same device as the descriptor set layout.
- ///
- pub fn add_buffer_view<T>(
- self,
- view: T,
- ) -> Result<
- FixedSizeDescriptorSetBuilderArray<'a, (R, PersistentDescriptorSetBufView<T>)>,
- PersistentDescriptorSetError,
- >
- where
- T: BufferViewRef,
- {
- Ok(FixedSizeDescriptorSetBuilderArray {
- pool: self.pool,
- inner: self.inner.add_buffer_view(view)?,
- })
- }
-
- /// Binds an image view as the next element in the array.
- ///
- /// An error is returned if the image view isn't compatible with the descriptor.
- ///
- /// # Panic
- ///
- /// Panics if the image view doesn't have the same device as the descriptor set layout.
- ///
- pub fn add_image<T>(
- self,
- image_view: T,
- ) -> Result<
- FixedSizeDescriptorSetBuilderArray<'a, (R, PersistentDescriptorSetImg<T>)>,
- PersistentDescriptorSetError,
- >
- where
- T: ImageViewAbstract,
- {
- Ok(FixedSizeDescriptorSetBuilderArray {
- pool: self.pool,
- inner: self.inner.add_image(image_view)?,
- })
- }
-
- /// Binds an image view with a sampler as the next element in the array.
- ///
- /// An error is returned if the image view isn't compatible with the descriptor.
- ///
- /// # Panic
- ///
- /// Panics if the image or the sampler doesn't have the same device as the descriptor set layout.
- ///
- pub fn add_sampled_image<T>(
- self,
- image_view: T,
- sampler: Arc<Sampler>,
- ) -> Result<
- FixedSizeDescriptorSetBuilderArray<
- 'a,
- (
- (R, PersistentDescriptorSetImg<T>),
- PersistentDescriptorSetSampler,
- ),
- >,
- PersistentDescriptorSetError,
- >
- where
- T: ImageViewAbstract,
- {
- Ok(FixedSizeDescriptorSetBuilderArray {
- pool: self.pool,
- inner: self.inner.add_sampled_image(image_view, sampler)?,
- })
- }
-
- /// Binds a sampler as the next element in the array.
- ///
- /// An error is returned if the sampler isn't compatible with the descriptor.
- ///
- /// # Panic
- ///
- /// Panics if the sampler doesn't have the same device as the descriptor set layout.
- ///
- pub fn add_sampler(
- self,
- sampler: Arc<Sampler>,
- ) -> Result<
- FixedSizeDescriptorSetBuilderArray<'a, (R, PersistentDescriptorSetSampler)>,
- PersistentDescriptorSetError,
- > {
- Ok(FixedSizeDescriptorSetBuilderArray {
- pool: self.pool,
- inner: self.inner.add_sampler(sampler)?,
- })
- }
-}
diff --git a/src/descriptor_set/layout.rs b/src/descriptor_set/layout.rs
new file mode 100644
index 0000000..7000e0a
--- /dev/null
+++ b/src/descriptor_set/layout.rs
@@ -0,0 +1,951 @@
+// Copyright (c) 2021 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+//! Describes the layout of all descriptors within a descriptor set.
+//!
+//! When creating a new descriptor set, you must provide a *layout* object to create it from.
+
+use crate::{
+ device::{Device, DeviceOwned},
+ macros::{impl_id_counter, vulkan_enum},
+ sampler::Sampler,
+ shader::{DescriptorBindingRequirements, ShaderStages},
+ OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject,
+};
+use ahash::HashMap;
+use std::{
+ collections::BTreeMap,
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+ mem::MaybeUninit,
+ num::NonZeroU64,
+ ptr,
+ sync::Arc,
+};
+
+/// Describes to the Vulkan implementation the layout of all descriptors within a descriptor set.
+#[derive(Debug)]
+pub struct DescriptorSetLayout {
+ handle: ash::vk::DescriptorSetLayout,
+ device: Arc<Device>,
+ id: NonZeroU64,
+
+ bindings: BTreeMap<u32, DescriptorSetLayoutBinding>,
+ push_descriptor: bool,
+
+ descriptor_counts: HashMap<DescriptorType, u32>,
+}
+
+impl DescriptorSetLayout {
+ /// Creates a new `DescriptorSetLayout`.
+ #[inline]
+ pub fn new(
+ device: Arc<Device>,
+ mut create_info: DescriptorSetLayoutCreateInfo,
+ ) -> Result<Arc<DescriptorSetLayout>, DescriptorSetLayoutCreationError> {
+ let descriptor_counts = Self::validate(&device, &mut create_info)?;
+ let handle = unsafe { Self::create(&device, &create_info)? };
+
+ let DescriptorSetLayoutCreateInfo {
+ bindings,
+ push_descriptor,
+ _ne: _,
+ } = create_info;
+
+ Ok(Arc::new(DescriptorSetLayout {
+ handle,
+ device,
+ id: Self::next_id(),
+ bindings,
+ push_descriptor,
+ descriptor_counts,
+ }))
+ }
+
+ /// Creates a new `DescriptorSetLayout` from a raw object handle.
+ ///
+ /// # Safety
+ ///
+ /// - `handle` must be a valid Vulkan object handle created from `device`.
+ /// - `create_info` must match the info used to create the object.
+ #[inline]
+ pub unsafe fn from_handle(
+ device: Arc<Device>,
+ handle: ash::vk::DescriptorSetLayout,
+ create_info: DescriptorSetLayoutCreateInfo,
+ ) -> Arc<DescriptorSetLayout> {
+ let DescriptorSetLayoutCreateInfo {
+ bindings,
+ push_descriptor,
+ _ne: _,
+ } = create_info;
+
+ let mut descriptor_counts = HashMap::default();
+ for binding in bindings.values() {
+ if binding.descriptor_count != 0 {
+ *descriptor_counts
+ .entry(binding.descriptor_type)
+ .or_default() += binding.descriptor_count;
+ }
+ }
+
+ Arc::new(DescriptorSetLayout {
+ handle,
+ device,
+ id: Self::next_id(),
+ bindings,
+ push_descriptor,
+ descriptor_counts,
+ })
+ }
+
+ fn validate(
+ device: &Device,
+ create_info: &mut DescriptorSetLayoutCreateInfo,
+ ) -> Result<HashMap<DescriptorType, u32>, DescriptorSetLayoutCreationError> {
+ let &mut DescriptorSetLayoutCreateInfo {
+ ref bindings,
+ push_descriptor,
+ _ne: _,
+ } = create_info;
+
+ let mut descriptor_counts = HashMap::default();
+
+ if push_descriptor {
+ if !device.enabled_extensions().khr_push_descriptor {
+ return Err(DescriptorSetLayoutCreationError::RequirementNotMet {
+ required_for: "`create_info.push_descriptor` is set",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["khr_push_descriptor"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+
+ let highest_binding_num = bindings.keys().copied().next_back();
+
+ for (&binding_num, binding) in bindings.iter() {
+ let &DescriptorSetLayoutBinding {
+ descriptor_type,
+ descriptor_count,
+ variable_descriptor_count,
+ stages,
+ ref immutable_samplers,
+ _ne: _,
+ } = binding;
+
+ // VUID-VkDescriptorSetLayoutBinding-descriptorType-parameter
+ descriptor_type.validate_device(device)?;
+
+ if descriptor_count != 0 {
+ // VUID-VkDescriptorSetLayoutBinding-descriptorCount-00283
+ stages.validate_device(device)?;
+
+ *descriptor_counts.entry(descriptor_type).or_default() += descriptor_count;
+ }
+
+ if push_descriptor {
+ // VUID-VkDescriptorSetLayoutCreateInfo-flags-00280
+ if matches!(
+ descriptor_type,
+ DescriptorType::StorageBufferDynamic | DescriptorType::UniformBufferDynamic
+ ) {
+ return Err(
+ DescriptorSetLayoutCreationError::PushDescriptorDescriptorTypeIncompatible {
+ binding_num,
+ },
+ );
+ }
+
+ // VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-flags-03003
+ if variable_descriptor_count {
+ return Err(
+ DescriptorSetLayoutCreationError::PushDescriptorVariableDescriptorCount {
+ binding_num,
+ },
+ );
+ }
+ }
+
+ if !immutable_samplers.is_empty() {
+ if immutable_samplers
+ .iter()
+ .any(|sampler| sampler.sampler_ycbcr_conversion().is_some())
+ {
+ if !matches!(descriptor_type, DescriptorType::CombinedImageSampler) {
+ return Err(
+ DescriptorSetLayoutCreationError::ImmutableSamplersDescriptorTypeIncompatible {
+ binding_num,
+ },
+ );
+ }
+ } else {
+ if !matches!(
+ descriptor_type,
+ DescriptorType::Sampler | DescriptorType::CombinedImageSampler
+ ) {
+ return Err(
+ DescriptorSetLayoutCreationError::ImmutableSamplersDescriptorTypeIncompatible {
+ binding_num,
+ },
+ );
+ }
+ }
+
+ // VUID-VkDescriptorSetLayoutBinding-descriptorType-00282
+ if descriptor_count != immutable_samplers.len() as u32 {
+ return Err(
+ DescriptorSetLayoutCreationError::ImmutableSamplersCountMismatch {
+ binding_num,
+ sampler_count: immutable_samplers.len() as u32,
+ descriptor_count,
+ },
+ );
+ }
+ }
+
+ // VUID-VkDescriptorSetLayoutBinding-descriptorType-01510
+ // If descriptorType is VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT and descriptorCount is not 0, then stageFlags must be 0 or VK_SHADER_STAGE_FRAGMENT_BIT
+
+ if variable_descriptor_count {
+ // VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-descriptorBindingVariableDescriptorCount-03014
+ if !device
+ .enabled_features()
+ .descriptor_binding_variable_descriptor_count
+ {
+ return Err(DescriptorSetLayoutCreationError::RequirementNotMet {
+ required_for: "`create_info.bindings` has an element where \
+ `variable_descriptor_count` is set",
+ requires_one_of: RequiresOneOf {
+ features: &["descriptor_binding_variable_descriptor_count"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-pBindingFlags-03004
+ if Some(binding_num) != highest_binding_num {
+ return Err(
+ DescriptorSetLayoutCreationError::VariableDescriptorCountBindingNotHighest {
+ binding_num,
+ highest_binding_num: highest_binding_num.unwrap(),
+ },
+ );
+ }
+
+ // VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-pBindingFlags-03015
+ if matches!(
+ descriptor_type,
+ DescriptorType::UniformBufferDynamic | DescriptorType::StorageBufferDynamic
+ ) {
+ return Err(
+ DescriptorSetLayoutCreationError::VariableDescriptorCountDescriptorTypeIncompatible {
+ binding_num,
+ },
+ );
+ }
+ }
+ }
+
+ // VUID-VkDescriptorSetLayoutCreateInfo-flags-00281
+ if push_descriptor
+ && descriptor_counts.values().copied().sum::<u32>()
+ > device
+ .physical_device()
+ .properties()
+ .max_push_descriptors
+ .unwrap_or(0)
+ {
+ return Err(
+ DescriptorSetLayoutCreationError::MaxPushDescriptorsExceeded {
+ provided: descriptor_counts.values().copied().sum(),
+ max_supported: device
+ .physical_device()
+ .properties()
+ .max_push_descriptors
+ .unwrap_or(0),
+ },
+ );
+ }
+
+ Ok(descriptor_counts)
+ }
+
+ unsafe fn create(
+ device: &Device,
+ create_info: &DescriptorSetLayoutCreateInfo,
+ ) -> Result<ash::vk::DescriptorSetLayout, DescriptorSetLayoutCreationError> {
+ let &DescriptorSetLayoutCreateInfo {
+ ref bindings,
+ push_descriptor,
+ _ne: _,
+ } = create_info;
+
+ let mut bindings_vk = Vec::with_capacity(bindings.len());
+ let mut binding_flags_vk = Vec::with_capacity(bindings.len());
+ let mut immutable_samplers_vk: Vec<Box<[ash::vk::Sampler]>> = Vec::new(); // only to keep the arrays of handles alive
+ let mut flags = ash::vk::DescriptorSetLayoutCreateFlags::empty();
+
+ if push_descriptor {
+ flags |= ash::vk::DescriptorSetLayoutCreateFlags::PUSH_DESCRIPTOR_KHR;
+ }
+
+ for (&binding_num, binding) in bindings.iter() {
+ let mut binding_flags = ash::vk::DescriptorBindingFlags::empty();
+
+ let p_immutable_samplers = if !binding.immutable_samplers.is_empty() {
+ // VUID-VkDescriptorSetLayoutBinding-descriptorType-00282
+ let sampler_handles = binding
+ .immutable_samplers
+ .iter()
+ .map(|s| s.handle())
+ .collect::<Vec<_>>()
+ .into_boxed_slice();
+ let p_immutable_samplers = sampler_handles.as_ptr();
+ immutable_samplers_vk.push(sampler_handles);
+ p_immutable_samplers
+ } else {
+ ptr::null()
+ };
+
+ if binding.variable_descriptor_count {
+ binding_flags |= ash::vk::DescriptorBindingFlags::VARIABLE_DESCRIPTOR_COUNT;
+ }
+
+ // VUID-VkDescriptorSetLayoutCreateInfo-binding-00279
+ // Guaranteed by BTreeMap
+ bindings_vk.push(ash::vk::DescriptorSetLayoutBinding {
+ binding: binding_num,
+ descriptor_type: binding.descriptor_type.into(),
+ descriptor_count: binding.descriptor_count,
+ stage_flags: binding.stages.into(),
+ p_immutable_samplers,
+ });
+ binding_flags_vk.push(binding_flags);
+ }
+
+ let mut binding_flags_create_info = if device.api_version() >= Version::V1_2
+ || device.enabled_extensions().ext_descriptor_indexing
+ {
+ Some(ash::vk::DescriptorSetLayoutBindingFlagsCreateInfo {
+ // VUID-VkDescriptorSetLayoutBindingFlagsCreateInfo-bindingCount-03002
+ binding_count: binding_flags_vk.len() as u32,
+ p_binding_flags: binding_flags_vk.as_ptr(),
+ ..Default::default()
+ })
+ } else {
+ None
+ };
+
+ let mut create_info = ash::vk::DescriptorSetLayoutCreateInfo {
+ flags,
+ binding_count: bindings_vk.len() as u32,
+ p_bindings: bindings_vk.as_ptr(),
+ ..Default::default()
+ };
+
+ if let Some(binding_flags_create_info) = binding_flags_create_info.as_mut() {
+ binding_flags_create_info.p_next = create_info.p_next;
+ create_info.p_next = binding_flags_create_info as *const _ as *const _;
+ }
+
+ let handle = {
+ let fns = device.fns();
+ let mut output = MaybeUninit::uninit();
+ (fns.v1_0.create_descriptor_set_layout)(
+ device.handle(),
+ &create_info,
+ ptr::null(),
+ output.as_mut_ptr(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+ output.assume_init()
+ };
+
+ Ok(handle)
+ }
+
+ pub(crate) fn id(&self) -> NonZeroU64 {
+ self.id
+ }
+
+ /// Returns the bindings of the descriptor set layout.
+ #[inline]
+ pub fn bindings(&self) -> &BTreeMap<u32, DescriptorSetLayoutBinding> {
+ &self.bindings
+ }
+
+ /// Returns whether the descriptor set layout is for push descriptors or regular descriptor
+ /// sets.
+ #[inline]
+ pub fn push_descriptor(&self) -> bool {
+ self.push_descriptor
+ }
+
+ /// Returns the number of descriptors of each type.
+ ///
+ /// The map is guaranteed to not contain any elements with a count of `0`.
+ #[inline]
+ pub fn descriptor_counts(&self) -> &HashMap<DescriptorType, u32> {
+ &self.descriptor_counts
+ }
+
+ /// If the highest-numbered binding has a variable count, returns its `descriptor_count`.
+ /// Otherwise returns `0`.
+ #[inline]
+ pub fn variable_descriptor_count(&self) -> u32 {
+ self.bindings
+ .values()
+ .next_back()
+ .map(|binding| {
+ if binding.variable_descriptor_count {
+ binding.descriptor_count
+ } else {
+ 0
+ }
+ })
+ .unwrap_or(0)
+ }
+
+ /// Returns whether `self` is compatible with `other`.
+ ///
+ /// "Compatible" in this sense is defined by the Vulkan specification under the section
+ /// "Pipeline layout compatibility": either the two are the same descriptor set layout object,
+ /// or they must be identically defined to the Vulkan API.
+ #[inline]
+ pub fn is_compatible_with(&self, other: &DescriptorSetLayout) -> bool {
+ self == other
+ || (self.bindings == other.bindings && self.push_descriptor == other.push_descriptor)
+ }
+}
+
+impl Drop for DescriptorSetLayout {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ let fns = self.device.fns();
+ (fns.v1_0.destroy_descriptor_set_layout)(
+ self.device.handle(),
+ self.handle,
+ ptr::null(),
+ );
+ }
+ }
+}
+
+unsafe impl VulkanObject for DescriptorSetLayout {
+ type Handle = ash::vk::DescriptorSetLayout;
+
+ #[inline]
+ fn handle(&self) -> Self::Handle {
+ self.handle
+ }
+}
+
+unsafe impl DeviceOwned for DescriptorSetLayout {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+}
+
+impl_id_counter!(DescriptorSetLayout);
+
+/// Error related to descriptor set layout.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum DescriptorSetLayoutCreationError {
+ /// Out of Memory.
+ OomError(OomError),
+
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+
+ /// A binding includes immutable samplers but their number differs from `descriptor_count`.
+ ImmutableSamplersCountMismatch {
+ binding_num: u32,
+ sampler_count: u32,
+ descriptor_count: u32,
+ },
+
+ /// A binding includes immutable samplers but it has an incompatible `descriptor_type`.
+ ImmutableSamplersDescriptorTypeIncompatible { binding_num: u32 },
+
+ /// More descriptors were provided in all bindings than the
+ /// [`max_push_descriptors`](crate::device::Properties::max_push_descriptors) limit.
+ MaxPushDescriptorsExceeded { provided: u32, max_supported: u32 },
+
+ /// `push_descriptor` is enabled, but a binding has an incompatible `descriptor_type`.
+ PushDescriptorDescriptorTypeIncompatible { binding_num: u32 },
+
+ /// `push_descriptor` is enabled, but a binding has `variable_descriptor_count` enabled.
+ PushDescriptorVariableDescriptorCount { binding_num: u32 },
+
+ /// A binding has `variable_descriptor_count` enabled, but it is not the highest-numbered
+ /// binding.
+ VariableDescriptorCountBindingNotHighest {
+ binding_num: u32,
+ highest_binding_num: u32,
+ },
+
+ /// A binding has `variable_descriptor_count` enabled, but it has an incompatible
+ /// `descriptor_type`.
+ VariableDescriptorCountDescriptorTypeIncompatible { binding_num: u32 },
+}
+
+impl From<VulkanError> for DescriptorSetLayoutCreationError {
+ fn from(error: VulkanError) -> Self {
+ Self::OomError(error.into())
+ }
+}
+
+impl Error for DescriptorSetLayoutCreationError {}
+
+impl Display for DescriptorSetLayoutCreationError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::OomError(_) => {
+ write!(f, "out of memory")
+ }
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ Self::ImmutableSamplersCountMismatch {
+ binding_num,
+ sampler_count,
+ descriptor_count,
+ } => write!(
+ f,
+ "binding {} includes immutable samplers but their number ({}) differs from \
+ `descriptor_count` ({})",
+ binding_num, sampler_count, descriptor_count,
+ ),
+ Self::ImmutableSamplersDescriptorTypeIncompatible { binding_num } => write!(
+ f,
+ "binding {} includes immutable samplers but it has an incompatible \
+ `descriptor_type`",
+ binding_num,
+ ),
+ Self::MaxPushDescriptorsExceeded {
+ provided,
+ max_supported,
+ } => write!(
+ f,
+ "more descriptors were provided in all bindings ({}) than the \
+ `max_push_descriptors` limit ({})",
+ provided, max_supported,
+ ),
+ Self::PushDescriptorDescriptorTypeIncompatible { binding_num } => write!(
+ f,
+ "`push_descriptor` is enabled, but binding {} has an incompatible \
+ `descriptor_type`",
+ binding_num,
+ ),
+ Self::PushDescriptorVariableDescriptorCount { binding_num } => write!(
+ f,
+ "`push_descriptor` is enabled, but binding {} has `variable_descriptor_count` \
+ enabled",
+ binding_num,
+ ),
+ Self::VariableDescriptorCountBindingNotHighest {
+ binding_num,
+ highest_binding_num,
+ } => write!(
+ f,
+ "binding {} has `variable_descriptor_count` enabled, but it is not the \
+ highest-numbered binding ({})",
+ binding_num, highest_binding_num,
+ ),
+ Self::VariableDescriptorCountDescriptorTypeIncompatible { binding_num } => write!(
+ f,
+ "binding {} has `variable_descriptor_count` enabled, but it has an incompatible \
+ `descriptor_type`",
+ binding_num,
+ ),
+ }
+ }
+}
+
+impl From<RequirementNotMet> for DescriptorSetLayoutCreationError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
+ }
+ }
+}
+
+/// Parameters to create a new `DescriptorSetLayout`.
+#[derive(Clone, Debug)]
+pub struct DescriptorSetLayoutCreateInfo {
+ /// The bindings of the desriptor set layout. These are specified according to binding number.
+ ///
+ /// It is generally advisable to keep the binding numbers low. Higher binding numbers may
+ /// use more memory inside Vulkan.
+ ///
+ /// The default value is empty.
+ pub bindings: BTreeMap<u32, DescriptorSetLayoutBinding>,
+
+ /// Whether the descriptor set layout should be created for push descriptors.
+ ///
+ /// If `true`, the layout can only be used for push descriptors, and if `false`, it can only
+ /// be used for regular descriptor sets.
+ ///
+ /// If set to `true`, the
+ /// [`khr_push_descriptor`](crate::device::DeviceExtensions::khr_push_descriptor) extension must
+ /// be enabled on the device, and there are several restrictions:
+ /// - There must be no bindings with a type of [`DescriptorType::UniformBufferDynamic`]
+ /// or [`DescriptorType::StorageBufferDynamic`].
+ /// - There must be no bindings with `variable_descriptor_count` enabled.
+ /// - The total number of descriptors across all bindings must be less than the
+ /// [`max_push_descriptors`](crate::device::Properties::max_push_descriptors) limit.
+ ///
+ /// The default value is `false`.
+ pub push_descriptor: bool,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for DescriptorSetLayoutCreateInfo {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ bindings: BTreeMap::new(),
+ push_descriptor: false,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+impl DescriptorSetLayoutCreateInfo {
+ /// Builds a list of `DescriptorSetLayoutCreateInfo` from an iterator of
+ /// `DescriptorBindingRequirements` originating from a shader.
+ pub fn from_requirements<'a>(
+ descriptor_requirements: impl IntoIterator<
+ Item = ((u32, u32), &'a DescriptorBindingRequirements),
+ >,
+ ) -> Vec<Self> {
+ let mut create_infos: Vec<Self> = Vec::new();
+
+ for ((set_num, binding_num), reqs) in descriptor_requirements {
+ let set_num = set_num as usize;
+
+ if set_num >= create_infos.len() {
+ create_infos.resize(set_num + 1, Self::default());
+ }
+
+ let bindings = &mut create_infos[set_num].bindings;
+ bindings.insert(binding_num, reqs.into());
+ }
+
+ create_infos
+ }
+}
+
+/// A binding in a descriptor set layout.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct DescriptorSetLayoutBinding {
+ /// The content and layout of each array element of a binding.
+ ///
+ /// There is no default value.
+ pub descriptor_type: DescriptorType,
+
+ /// How many descriptors (array elements) this binding is made of.
+ ///
+ /// If the binding is a single element rather than an array, then you must specify `1`.
+ ///
+ /// The default value is `1`.
+ pub descriptor_count: u32,
+
+ /// Whether the binding has a variable number of descriptors.
+ ///
+ /// If set to `true`, the [`descriptor_binding_variable_descriptor_count`] feature must be
+ /// enabled. The value of `descriptor_count` specifies the maximum number of descriptors
+ /// allowed.
+ ///
+ /// There may only be one binding with a variable count in a descriptor set, and it must be the
+ /// binding with the highest binding number. The `descriptor_type` must not be
+ /// [`DescriptorType::UniformBufferDynamic`] or [`DescriptorType::StorageBufferDynamic`].
+ ///
+ /// The default value is `false`.
+ ///
+ /// [`descriptor_binding_variable_descriptor_count`]: crate::device::Features::descriptor_binding_variable_descriptor_count
+ pub variable_descriptor_count: bool,
+
+ /// Which shader stages are going to access the descriptors in this binding.
+ ///
+ /// The default value is [`ShaderStages::empty()`], which must be overridden.
+ pub stages: ShaderStages,
+
+ /// Samplers that are included as a fixed part of the descriptor set layout. Once bound, they
+ /// do not need to be provided when creating a descriptor set.
+ ///
+ /// The list must be either empty, or contain exactly `descriptor_count` samplers. It can only
+ /// be non-empty if `descriptor_type` is [`DescriptorType::Sampler`] or
+ /// [`DescriptorType::CombinedImageSampler`]. If any of the samplers has an attached sampler
+ /// YCbCr conversion, then only [`DescriptorType::CombinedImageSampler`] is allowed.
+ ///
+ /// The default value is empty.
+ pub immutable_samplers: Vec<Arc<Sampler>>,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl DescriptorSetLayoutBinding {
+ /// Returns a `DescriptorSetLayoutBinding` with the given type.
+ #[inline]
+ pub fn descriptor_type(descriptor_type: DescriptorType) -> Self {
+ Self {
+ descriptor_type,
+ descriptor_count: 1,
+ variable_descriptor_count: false,
+ stages: ShaderStages::empty(),
+ immutable_samplers: Vec::new(),
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+
+ /// Checks whether the descriptor of a pipeline layout `self` is compatible with the
+ /// requirements of a shader `other`.
+ #[inline]
+ pub fn ensure_compatible_with_shader(
+ &self,
+ binding_requirements: &DescriptorBindingRequirements,
+ ) -> Result<(), DescriptorRequirementsNotMet> {
+ let &DescriptorBindingRequirements {
+ ref descriptor_types,
+ descriptor_count,
+ image_format: _,
+ image_multisampled: _,
+ image_scalar_type: _,
+ image_view_type: _,
+ stages,
+ descriptors: _,
+ } = binding_requirements;
+
+ if !descriptor_types.contains(&self.descriptor_type) {
+ return Err(DescriptorRequirementsNotMet::DescriptorType {
+ required: descriptor_types.clone(),
+ obtained: self.descriptor_type,
+ });
+ }
+
+ if let Some(required) = descriptor_count {
+ if self.descriptor_count < required {
+ return Err(DescriptorRequirementsNotMet::DescriptorCount {
+ required,
+ obtained: self.descriptor_count,
+ });
+ }
+ }
+
+ if !self.stages.contains(stages) {
+ return Err(DescriptorRequirementsNotMet::ShaderStages {
+ required: stages,
+ obtained: self.stages,
+ });
+ }
+
+ Ok(())
+ }
+}
+
+impl From<&DescriptorBindingRequirements> for DescriptorSetLayoutBinding {
+ #[inline]
+ fn from(reqs: &DescriptorBindingRequirements) -> Self {
+ Self {
+ descriptor_type: reqs.descriptor_types[0],
+ descriptor_count: reqs.descriptor_count.unwrap_or(0),
+ variable_descriptor_count: false,
+ stages: reqs.stages,
+ immutable_samplers: Vec::new(),
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// Error when checking whether the requirements for a binding have been met.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum DescriptorRequirementsNotMet {
+ /// The binding's `descriptor_type` is not one of those required.
+ DescriptorType {
+ required: Vec<DescriptorType>,
+ obtained: DescriptorType,
+ },
+
+ /// The binding's `descriptor_count` is less than what is required.
+ DescriptorCount { required: u32, obtained: u32 },
+
+ /// The binding's `stages` does not contain the stages that are required.
+ ShaderStages {
+ required: ShaderStages,
+ obtained: ShaderStages,
+ },
+}
+
+impl Error for DescriptorRequirementsNotMet {}
+
+impl Display for DescriptorRequirementsNotMet {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::DescriptorType { required, obtained } => write!(
+ f,
+ "the descriptor's type ({:?}) is not one of those required ({:?})",
+ obtained, required,
+ ),
+ Self::DescriptorCount { required, obtained } => write!(
+ f,
+ "the descriptor count ({}) is less than what is required ({})",
+ obtained, required,
+ ),
+ Self::ShaderStages { .. } => write!(
+ f,
+ "the descriptor's shader stages do not contain the stages that are required",
+ ),
+ }
+ }
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// Describes what kind of resource may later be bound to a descriptor.
+ DescriptorType = DescriptorType(i32);
+
+ /// Describes how a `SampledImage` descriptor should be read.
+ Sampler = SAMPLER,
+
+ /// Combines `SampledImage` and `Sampler` in one descriptor.
+ CombinedImageSampler = COMBINED_IMAGE_SAMPLER,
+
+ /// Gives read-only access to an image via a sampler. The image must be combined with a sampler
+ /// inside the shader.
+ SampledImage = SAMPLED_IMAGE,
+
+ /// Gives read and/or write access to individual pixels in an image. The image cannot be
+ /// sampled, so you have exactly specify which pixel to read or write.
+ StorageImage = STORAGE_IMAGE,
+
+ /// Gives read-only access to the content of a buffer, interpreted as an array of texel data.
+ UniformTexelBuffer = UNIFORM_TEXEL_BUFFER,
+
+ /// Gives read and/or write access to the content of a buffer, interpreted as an array of texel
+ /// data. Less restrictive but sometimes slower than a uniform texel buffer.
+ StorageTexelBuffer = STORAGE_TEXEL_BUFFER,
+
+ /// Gives read-only access to the content of a buffer, interpreted as a structure.
+ UniformBuffer = UNIFORM_BUFFER,
+
+ /// Gives read and/or write access to the content of a buffer, interpreted as a structure. Less
+ /// restrictive but sometimes slower than a uniform buffer.
+ StorageBuffer = STORAGE_BUFFER,
+
+ /// As `UniformBuffer`, but the offset within the buffer is specified at the time the descriptor
+ /// set is bound, rather than when the descriptor set is updated.
+ UniformBufferDynamic = UNIFORM_BUFFER_DYNAMIC,
+
+ /// As `StorageBuffer`, but the offset within the buffer is specified at the time the descriptor
+ /// set is bound, rather than when the descriptor set is updated.
+ StorageBufferDynamic = STORAGE_BUFFER_DYNAMIC,
+
+ /// Gives access to an image inside a fragment shader via a render pass. You can only access the
+ /// pixel that is currently being processed by the fragment shader.
+ InputAttachment = INPUT_ATTACHMENT,
+
+ /* TODO: enable
+ // TODO: document
+ InlineUniformBlock = INLINE_UNIFORM_BLOCK {
+ api_version: V1_3,
+ device_extensions: [ext_inline_uniform_block],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ AccelerationStructure = ACCELERATION_STRUCTURE_KHR {
+ device_extensions: [khr_acceleration_structure],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ AccelerationStructureNV = ACCELERATION_STRUCTURE_NV {
+ device_extensions: [nv_ray_tracing],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ SampleWeightImage = SAMPLE_WEIGHT_IMAGE_QCOM {
+ device_extensions: [qcom_image_processing],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ BlockMatchImage = BLOCK_MATCH_IMAGE_QCOM {
+ device_extensions: [qcom_image_processing],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ Mutable = MUTABLE_VALVE {
+ device_extensions: [valve_mutable_descriptor_type],
+ },*/
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::{
+ descriptor_set::layout::{
+ DescriptorSetLayout, DescriptorSetLayoutBinding, DescriptorSetLayoutCreateInfo,
+ DescriptorType,
+ },
+ shader::ShaderStages,
+ };
+ use ahash::HashMap;
+
+ #[test]
+ fn empty() {
+ let (device, _) = gfx_dev_and_queue!();
+ let _layout = DescriptorSetLayout::new(device, Default::default());
+ }
+
+ #[test]
+ fn basic_create() {
+ let (device, _) = gfx_dev_and_queue!();
+
+ let sl = DescriptorSetLayout::new(
+ device,
+ DescriptorSetLayoutCreateInfo {
+ bindings: [(
+ 0,
+ DescriptorSetLayoutBinding {
+ stages: ShaderStages::all_graphics(),
+ ..DescriptorSetLayoutBinding::descriptor_type(DescriptorType::UniformBuffer)
+ },
+ )]
+ .into(),
+ ..Default::default()
+ },
+ )
+ .unwrap();
+
+ assert_eq!(
+ sl.descriptor_counts(),
+ &[(DescriptorType::UniformBuffer, 1)]
+ .into_iter()
+ .collect::<HashMap<_, _>>(),
+ );
+ }
+}
diff --git a/src/descriptor_set/layout/desc.rs b/src/descriptor_set/layout/desc.rs
deleted file mode 100644
index 1516861..0000000
--- a/src/descriptor_set/layout/desc.rs
+++ /dev/null
@@ -1,889 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-//! Description of a single descriptor.
-//!
-//! This module contains traits and structs related to describing a single descriptor. A descriptor
-//! is a slot where you can bind a buffer or an image so that it can be accessed from your shaders.
-//! In order to specify which buffer or image to bind to a descriptor, see the `descriptor_set`
-//! module.
-//!
-//! There are four different kinds of descriptors that give access to buffers:
-//!
-//! - Uniform texel buffers. Gives read-only access to the content of a buffer. Only supports
-//! certain buffer formats.
-//! - Storage texel buffers. Gives read and/or write access to the content of a buffer. Only
-//! supports certain buffer formats. Less restrictive but sometimes slower than uniform texel
-//! buffers.
-//! - Uniform buffers. Gives read-only access to the content of a buffer. Less restrictive but
-//! sometimes slower than uniform texel buffers.
-//! - Storage buffers. Gives read and/or write access to the content of a buffer. Less restrictive
-//! but sometimes slower than uniform buffers and storage texel buffers.
-//!
-//! There are five different kinds of descriptors related to images:
-//!
-//! - Storage images. Gives read and/or write access to individual pixels in an image. The image
-//! cannot be sampled. In other words, you have exactly specify which pixel to read or write.
-//! - Sampled images. Gives read-only access to an image. Before you can use a sampled image in a
-//! a shader, you have to combine it with a sampler (see below). The sampler describes how
-//! reading the image will behave.
-//! - Samplers. Doesn't contain an image but a sampler object that describes how an image will be
-//! accessed. This is meant to be combined with a sampled image (see above).
-//! - Combined image and sampler. Similar to a sampled image, but also directly includes the
-//! sampler which indicates how the sampling is done.
-//! - Input attachments. The fastest but also most restrictive access to images. Must be integrated
-//! in a render pass. Can only give access to the same pixel as the one you're processing.
-//!
-
-use crate::format::Format;
-use crate::image::view::ImageViewType;
-use crate::pipeline::shader::ShaderStages;
-use crate::pipeline::shader::ShaderStagesSupersetError;
-use crate::sync::AccessFlags;
-use crate::sync::PipelineStages;
-use smallvec::SmallVec;
-use std::cmp;
-use std::error;
-use std::fmt;
-
-#[derive(Clone, Debug, Default)]
-pub struct DescriptorSetDesc {
- descriptors: SmallVec<[Option<DescriptorDesc>; 32]>,
-}
-
-impl DescriptorSetDesc {
- /// Builds a new `DescriptorSetDesc` with the given descriptors.
- ///
- /// The descriptors must be passed in the order of the bindings. In order words, descriptor
- /// at bind point 0 first, then descriptor at bind point 1, and so on. If a binding must remain
- /// empty, you can make the iterator yield `None` for an element.
- #[inline]
- pub fn new<I>(descriptors: I) -> DescriptorSetDesc
- where
- I: IntoIterator<Item = Option<DescriptorDesc>>,
- {
- DescriptorSetDesc {
- descriptors: descriptors.into_iter().collect(),
- }
- }
-
- /// Builds a new empty `DescriptorSetDesc`.
- #[inline]
- pub fn empty() -> DescriptorSetDesc {
- DescriptorSetDesc {
- descriptors: SmallVec::new(),
- }
- }
-
- /// Returns the descriptors in the set.
- pub fn bindings(&self) -> &[Option<DescriptorDesc>] {
- &self.descriptors
- }
-
- /// Returns the descriptor with the given binding number, or `None` if the binding is empty.
- #[inline]
- pub fn descriptor(&self, num: usize) -> Option<&DescriptorDesc> {
- self.descriptors.get(num).and_then(|b| b.as_ref())
- }
-
- /// Builds the union of this layout description and another.
- #[inline]
- pub fn union(
- first: &DescriptorSetDesc,
- second: &DescriptorSetDesc,
- ) -> Result<DescriptorSetDesc, ()> {
- let num_bindings = cmp::max(first.descriptors.len(), second.descriptors.len());
- let descriptors = (0..num_bindings)
- .map(|binding_num| {
- DescriptorDesc::union(
- first
- .descriptors
- .get(binding_num)
- .map(|desc| desc.as_ref())
- .flatten(),
- second
- .descriptors
- .get(binding_num)
- .map(|desc| desc.as_ref())
- .flatten(),
- )
- })
- .collect::<Result<_, ()>>()?;
- Ok(DescriptorSetDesc { descriptors })
- }
-
- /// Builds the union of multiple descriptor sets.
- pub fn union_multiple(
- first: &[DescriptorSetDesc],
- second: &[DescriptorSetDesc],
- ) -> Result<Vec<DescriptorSetDesc>, ()> {
- // Ewwwwwww
- let empty = DescriptorSetDesc::empty();
- let num_sets = cmp::max(first.len(), second.len());
-
- (0..num_sets)
- .map(|set_num| {
- Ok(DescriptorSetDesc::union(
- first.get(set_num).unwrap_or_else(|| &empty),
- second.get(set_num).unwrap_or_else(|| &empty),
- )?)
- })
- .collect()
- }
-
- /// Transforms a `DescriptorSetDesc`.
- ///
- /// Used to adjust automatically inferred `DescriptorSetDesc`s with information that cannot be inferred.
- pub fn tweak<I>(&mut self, dynamic_buffers: I)
- where
- I: IntoIterator<Item = usize>,
- {
- for binding_num in dynamic_buffers {
- debug_assert!(
- self.descriptor(binding_num)
- .map_or(false, |desc| match desc.ty {
- DescriptorDescTy::Buffer(_) => true,
- _ => false,
- }),
- "tried to make the non-buffer descriptor at binding {} a dynamic buffer",
- binding_num
- );
-
- let binding = self
- .descriptors
- .get_mut(binding_num)
- .and_then(|b| b.as_mut());
-
- if let Some(desc) = binding {
- if let DescriptorDescTy::Buffer(ref buffer_desc) = desc.ty {
- desc.ty = DescriptorDescTy::Buffer(DescriptorBufferDesc {
- dynamic: Some(true),
- ..*buffer_desc
- });
- }
- }
- }
- }
-
- pub fn tweak_multiple<I>(sets: &mut [DescriptorSetDesc], dynamic_buffers: I)
- where
- I: IntoIterator<Item = (usize, usize)>,
- {
- for (set_num, binding_num) in dynamic_buffers {
- debug_assert!(
- set_num < sets.len(),
- "tried to make a dynamic buffer in the nonexistent set {}",
- set_num,
- );
-
- sets.get_mut(set_num).map(|set| set.tweak([binding_num]));
- }
- }
-
- /// Returns whether `self` is a superset of `other`.
- pub fn ensure_superset_of(
- &self,
- other: &DescriptorSetDesc,
- ) -> Result<(), DescriptorSetDescSupersetError> {
- if self.descriptors.len() < other.descriptors.len() {
- return Err(DescriptorSetDescSupersetError::DescriptorsCountMismatch {
- self_num: self.descriptors.len() as u32,
- other_num: other.descriptors.len() as u32,
- });
- }
-
- for binding_num in 0..other.descriptors.len() {
- let self_desc = self.descriptor(binding_num);
- let other_desc = self.descriptor(binding_num);
-
- match (self_desc, other_desc) {
- (Some(mine), Some(other)) => {
- if let Err(err) = mine.ensure_superset_of(&other) {
- return Err(DescriptorSetDescSupersetError::IncompatibleDescriptors {
- error: err,
- binding_num: binding_num as u32,
- });
- }
- }
- (None, Some(_)) => {
- return Err(DescriptorSetDescSupersetError::ExpectedEmptyDescriptor {
- binding_num: binding_num as u32,
- })
- }
- _ => (),
- }
- }
-
- Ok(())
- }
-}
-
-impl<I> From<I> for DescriptorSetDesc
-where
- I: IntoIterator<Item = Option<DescriptorDesc>>,
-{
- #[inline]
- fn from(val: I) -> Self {
- DescriptorSetDesc {
- descriptors: val.into_iter().collect(),
- }
- }
-}
-
-/// Contains the exact description of a single descriptor.
-///
-/// > **Note**: You are free to fill a `DescriptorDesc` struct the way you want, but its validity
-/// > will be checked when you create a pipeline layout, a descriptor set, or when you try to bind
-/// > a descriptor set.
-// TODO: add example
-#[derive(Clone, Debug, PartialEq)]
-pub struct DescriptorDesc {
- /// Describes the content and layout of each array element of a descriptor.
- pub ty: DescriptorDescTy,
-
- /// How many array elements this descriptor is made of. The value 0 is invalid and may trigger
- /// a panic depending on the situation.
- pub array_count: u32,
-
- /// Which shader stages are going to access this descriptor.
- pub stages: ShaderStages,
-
- /// True if the attachment is only ever read by the shader. False if it is also written.
- pub readonly: bool,
-}
-
-impl DescriptorDesc {
- /// Checks whether we are a superset of another descriptor.
- ///
- /// Returns true if `self` is the same descriptor as `other`, or if `self` is the same as
- /// `other` but with a larger array elements count and/or more shader stages.
- ///
- ///# Example
- ///```
- ///use vulkano::descriptor_set::layout::DescriptorDesc;
- ///use vulkano::descriptor_set::layout::DescriptorDescTy::*;
- ///use vulkano::pipeline::shader::ShaderStages;
- ///
- ///let desc_super = DescriptorDesc{ ty: Sampler, array_count: 2, stages: ShaderStages{
- /// vertex: true,
- /// tessellation_control: true,
- /// tessellation_evaluation: true,
- /// geometry: true,
- /// fragment: true,
- /// compute: true
- ///}, readonly: false };
- ///let desc_sub = DescriptorDesc{ ty: Sampler, array_count: 1, stages: ShaderStages{
- /// vertex: true,
- /// tessellation_control: false,
- /// tessellation_evaluation: false,
- /// geometry: false,
- /// fragment: true,
- /// compute: false
- ///}, readonly: true };
- ///
- ///assert_eq!(desc_super.ensure_superset_of(&desc_sub).unwrap(), ());
- ///
- ///```
- #[inline]
- pub fn ensure_superset_of(
- &self,
- other: &DescriptorDesc,
- ) -> Result<(), DescriptorDescSupersetError> {
- self.ty.ensure_superset_of(&other.ty)?;
- self.stages.ensure_superset_of(&other.stages)?;
-
- if self.array_count < other.array_count {
- return Err(DescriptorDescSupersetError::ArrayTooSmall {
- len: self.array_count,
- required: other.array_count,
- });
- }
-
- if self.readonly && !other.readonly {
- return Err(DescriptorDescSupersetError::MutabilityRequired);
- }
-
- Ok(())
- }
-
- /// Builds a `DescriptorDesc` that is the union of `self` and `other`, if possible.
- ///
- /// The returned value will be a superset of both `self` and `other`, or `None` if both were
- /// `None`.
- ///
- /// `Err` is returned if the descriptors are not compatible.
- ///
- ///# Example
- ///```
- ///use vulkano::descriptor_set::layout::DescriptorDesc;
- ///use vulkano::descriptor_set::layout::DescriptorDescTy::*;
- ///use vulkano::pipeline::shader::ShaderStages;
- ///
- ///let desc_part1 = DescriptorDesc{ ty: Sampler, array_count: 2, stages: ShaderStages{
- /// vertex: true,
- /// tessellation_control: true,
- /// tessellation_evaluation: false,
- /// geometry: true,
- /// fragment: false,
- /// compute: true
- ///}, readonly: false };
- ///
- ///let desc_part2 = DescriptorDesc{ ty: Sampler, array_count: 1, stages: ShaderStages{
- /// vertex: true,
- /// tessellation_control: false,
- /// tessellation_evaluation: true,
- /// geometry: false,
- /// fragment: true,
- /// compute: true
- ///}, readonly: true };
- ///
- ///let desc_union = DescriptorDesc{ ty: Sampler, array_count: 2, stages: ShaderStages{
- /// vertex: true,
- /// tessellation_control: true,
- /// tessellation_evaluation: true,
- /// geometry: true,
- /// fragment: true,
- /// compute: true
- ///}, readonly: false };
- ///
- ///assert_eq!(DescriptorDesc::union(Some(&desc_part1), Some(&desc_part2)), Ok(Some(desc_union)));
- ///```
- #[inline]
- pub fn union(
- first: Option<&DescriptorDesc>,
- second: Option<&DescriptorDesc>,
- ) -> Result<Option<DescriptorDesc>, ()> {
- if let (Some(first), Some(second)) = (first, second) {
- if first.ty != second.ty {
- return Err(());
- }
-
- Ok(Some(DescriptorDesc {
- ty: first.ty.clone(),
- array_count: cmp::max(first.array_count, second.array_count),
- stages: first.stages | second.stages,
- readonly: first.readonly && second.readonly,
- }))
- } else {
- Ok(first.or(second).cloned())
- }
- }
-
- /// Returns the pipeline stages and access flags corresponding to the usage of this descriptor.
- ///
- /// # Panic
- ///
- /// Panics if the type is `Sampler`.
- ///
- pub fn pipeline_stages_and_access(&self) -> (PipelineStages, AccessFlags) {
- let stages: PipelineStages = self.stages.into();
-
- let access = match self.ty {
- DescriptorDescTy::Sampler => panic!(),
- DescriptorDescTy::CombinedImageSampler(_) | DescriptorDescTy::Image(_) => AccessFlags {
- shader_read: true,
- shader_write: !self.readonly,
- ..AccessFlags::none()
- },
- DescriptorDescTy::TexelBuffer { .. } => AccessFlags {
- shader_read: true,
- shader_write: !self.readonly,
- ..AccessFlags::none()
- },
- DescriptorDescTy::InputAttachment { .. } => AccessFlags {
- input_attachment_read: true,
- ..AccessFlags::none()
- },
- DescriptorDescTy::Buffer(ref buf) => {
- if buf.storage {
- AccessFlags {
- shader_read: true,
- shader_write: !self.readonly,
- ..AccessFlags::none()
- }
- } else {
- AccessFlags {
- uniform_read: true,
- ..AccessFlags::none()
- }
- }
- }
- };
-
- (stages, access)
- }
-}
-
-/// Describes the content and layout of each array element of a descriptor.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum DescriptorDescTy {
- Sampler, // TODO: the sampler has some restrictions as well
- CombinedImageSampler(DescriptorImageDesc), // TODO: the sampler has some restrictions as well
- Image(DescriptorImageDesc),
- TexelBuffer {
- /// If `true`, this describes a storage texel buffer.
- storage: bool,
-
- /// The format of the content, or `None` if the format is unknown. Depending on the
- /// context, it may be invalid to have a `None` value here. If the format is `Some`, only
- /// buffer views that have this exact format can be attached to this descriptor.
- format: Option<Format>,
- },
- InputAttachment {
- /// If `true`, the input attachment is multisampled. Only multisampled images can be
- /// attached to this descriptor. If `false`, only single-sampled images can be attached.
- multisampled: bool,
- array_layers: DescriptorImageDescArray,
- },
- Buffer(DescriptorBufferDesc),
-}
-
-impl DescriptorDescTy {
- /// Returns the type of descriptor.
- // TODO: add example
- pub fn ty(&self) -> DescriptorType {
- match *self {
- DescriptorDescTy::Sampler => DescriptorType::Sampler,
- DescriptorDescTy::CombinedImageSampler(_) => DescriptorType::CombinedImageSampler,
- DescriptorDescTy::Image(ref desc) => {
- if desc.sampled {
- DescriptorType::SampledImage
- } else {
- DescriptorType::StorageImage
- }
- }
- DescriptorDescTy::InputAttachment { .. } => DescriptorType::InputAttachment,
- DescriptorDescTy::Buffer(ref desc) => {
- let dynamic = desc.dynamic.unwrap_or(false);
- match (desc.storage, dynamic) {
- (false, false) => DescriptorType::UniformBuffer,
- (true, false) => DescriptorType::StorageBuffer,
- (false, true) => DescriptorType::UniformBufferDynamic,
- (true, true) => DescriptorType::StorageBufferDynamic,
- }
- }
- DescriptorDescTy::TexelBuffer { storage, .. } => {
- if storage {
- DescriptorType::StorageTexelBuffer
- } else {
- DescriptorType::UniformTexelBuffer
- }
- }
- }
- }
-
- /// Checks whether we are a superset of another descriptor type.
- // TODO: add example
- #[inline]
- pub fn ensure_superset_of(
- &self,
- other: &DescriptorDescTy,
- ) -> Result<(), DescriptorDescSupersetError> {
- match (self, other) {
- (&DescriptorDescTy::Sampler, &DescriptorDescTy::Sampler) => Ok(()),
-
- (
- &DescriptorDescTy::CombinedImageSampler(ref me),
- &DescriptorDescTy::CombinedImageSampler(ref other),
- ) => me.ensure_superset_of(other),
-
- (&DescriptorDescTy::Image(ref me), &DescriptorDescTy::Image(ref other)) => {
- me.ensure_superset_of(other)
- }
-
- (
- &DescriptorDescTy::InputAttachment {
- multisampled: me_multisampled,
- array_layers: me_array_layers,
- },
- &DescriptorDescTy::InputAttachment {
- multisampled: other_multisampled,
- array_layers: other_array_layers,
- },
- ) => {
- if me_multisampled != other_multisampled {
- return Err(DescriptorDescSupersetError::MultisampledMismatch {
- provided: me_multisampled,
- expected: other_multisampled,
- });
- }
-
- if me_array_layers != other_array_layers {
- return Err(DescriptorDescSupersetError::IncompatibleArrayLayers {
- provided: me_array_layers,
- required: other_array_layers,
- });
- }
-
- Ok(())
- }
-
- (&DescriptorDescTy::Buffer(ref me), &DescriptorDescTy::Buffer(ref other)) => {
- if me.storage != other.storage {
- return Err(DescriptorDescSupersetError::TypeMismatch);
- }
-
- match (me.dynamic, other.dynamic) {
- (Some(_), None) => Ok(()),
- (Some(m), Some(o)) => {
- if m == o {
- Ok(())
- } else {
- Err(DescriptorDescSupersetError::TypeMismatch)
- }
- }
- (None, None) => Ok(()),
- (None, Some(_)) => Err(DescriptorDescSupersetError::TypeMismatch),
- }
- }
-
- (
- &DescriptorDescTy::TexelBuffer {
- storage: me_storage,
- format: me_format,
- },
- &DescriptorDescTy::TexelBuffer {
- storage: other_storage,
- format: other_format,
- },
- ) => {
- if me_storage != other_storage {
- return Err(DescriptorDescSupersetError::TypeMismatch);
- }
-
- match (me_format, other_format) {
- (Some(_), None) => Ok(()),
- (Some(m), Some(o)) => {
- if m == o {
- Ok(())
- } else {
- Err(DescriptorDescSupersetError::FormatMismatch {
- provided: Some(m),
- expected: o,
- })
- }
- }
- (None, None) => Ok(()),
- (None, Some(a)) => Err(DescriptorDescSupersetError::FormatMismatch {
- provided: Some(a),
- expected: a,
- }),
- }
- }
-
- // Any other combination is invalid.
- _ => Err(DescriptorDescSupersetError::TypeMismatch),
- }
- }
-}
-
-/// Additional description for descriptors that contain images.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct DescriptorImageDesc {
- /// If `true`, the image can be sampled by the shader. Only images that were created with the
- /// `sampled` usage can be attached to the descriptor.
- pub sampled: bool,
- /// The kind of image: one-dimensional, two-dimensional, three-dimensional, or cube.
- pub dimensions: DescriptorImageDescDimensions,
- /// The format of the image, or `None` if the format is unknown. If `Some`, only images with
- /// exactly that format can be attached.
- pub format: Option<Format>,
- /// True if the image is multisampled.
- pub multisampled: bool,
- /// Whether the descriptor contains one or more array layers of an image.
- pub array_layers: DescriptorImageDescArray,
-}
-
-impl DescriptorImageDesc {
- /// Checks whether we are a superset of another image.
- // TODO: add example
- #[inline]
- pub fn ensure_superset_of(
- &self,
- other: &DescriptorImageDesc,
- ) -> Result<(), DescriptorDescSupersetError> {
- if self.dimensions != other.dimensions {
- return Err(DescriptorDescSupersetError::DimensionsMismatch {
- provided: self.dimensions,
- expected: other.dimensions,
- });
- }
-
- if self.multisampled != other.multisampled {
- return Err(DescriptorDescSupersetError::MultisampledMismatch {
- provided: self.multisampled,
- expected: other.multisampled,
- });
- }
-
- match (self.format, other.format) {
- (Some(a), Some(b)) => {
- if a != b {
- return Err(DescriptorDescSupersetError::FormatMismatch {
- provided: Some(a),
- expected: b,
- });
- }
- }
- (Some(_), None) => (),
- (None, None) => (),
- (None, Some(a)) => {
- return Err(DescriptorDescSupersetError::FormatMismatch {
- provided: None,
- expected: a,
- });
- }
- };
-
- match (self.array_layers, other.array_layers) {
- (DescriptorImageDescArray::NonArrayed, DescriptorImageDescArray::NonArrayed) => (),
- (
- DescriptorImageDescArray::Arrayed { max_layers: my_max },
- DescriptorImageDescArray::Arrayed {
- max_layers: other_max,
- },
- ) => {
- match (my_max, other_max) {
- (Some(m), Some(o)) => {
- if m < o {
- return Err(DescriptorDescSupersetError::IncompatibleArrayLayers {
- provided: DescriptorImageDescArray::Arrayed { max_layers: my_max },
- required: DescriptorImageDescArray::Arrayed {
- max_layers: other_max,
- },
- });
- }
- }
- (Some(_), None) => (),
- (None, Some(m)) => {
- return Err(DescriptorDescSupersetError::IncompatibleArrayLayers {
- provided: DescriptorImageDescArray::Arrayed { max_layers: my_max },
- required: DescriptorImageDescArray::Arrayed {
- max_layers: other_max,
- },
- });
- }
- (None, None) => (), // TODO: is this correct?
- };
- }
- (a, b) => {
- return Err(DescriptorDescSupersetError::IncompatibleArrayLayers {
- provided: a,
- required: b,
- })
- }
- };
-
- Ok(())
- }
-}
-
-// TODO: documentation
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum DescriptorImageDescArray {
- NonArrayed,
- Arrayed { max_layers: Option<u32> },
-}
-
-// TODO: documentation
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum DescriptorImageDescDimensions {
- OneDimensional,
- TwoDimensional,
- ThreeDimensional,
- Cube,
-}
-
-impl DescriptorImageDescDimensions {
- /// Builds the `DescriptorImageDescDimensions` that corresponds to the view type.
- #[inline]
- pub fn from_image_view_type(ty: ImageViewType) -> DescriptorImageDescDimensions {
- match ty {
- ImageViewType::Dim1d => DescriptorImageDescDimensions::OneDimensional,
- ImageViewType::Dim1dArray => DescriptorImageDescDimensions::OneDimensional,
- ImageViewType::Dim2d => DescriptorImageDescDimensions::TwoDimensional,
- ImageViewType::Dim2dArray => DescriptorImageDescDimensions::TwoDimensional,
- ImageViewType::Dim3d => DescriptorImageDescDimensions::ThreeDimensional,
- ImageViewType::Cubemap => DescriptorImageDescDimensions::Cube,
- ImageViewType::CubemapArray => DescriptorImageDescDimensions::Cube,
- }
- }
-}
-
-/// Additional description for descriptors that contain buffers.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct DescriptorBufferDesc {
- /// If `true`, this buffer is a dynamic buffer. Assumes false if `None`.
- pub dynamic: Option<bool>,
- /// If `true`, this buffer is a storage buffer.
- pub storage: bool,
-}
-
-/// Describes what kind of resource may later be bound to a descriptor.
-///
-/// This is mostly the same as a `DescriptorDescTy` but with less precise information.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-#[repr(i32)]
-pub enum DescriptorType {
- Sampler = ash::vk::DescriptorType::SAMPLER.as_raw(),
- CombinedImageSampler = ash::vk::DescriptorType::COMBINED_IMAGE_SAMPLER.as_raw(),
- SampledImage = ash::vk::DescriptorType::SAMPLED_IMAGE.as_raw(),
- StorageImage = ash::vk::DescriptorType::STORAGE_IMAGE.as_raw(),
- UniformTexelBuffer = ash::vk::DescriptorType::UNIFORM_TEXEL_BUFFER.as_raw(),
- StorageTexelBuffer = ash::vk::DescriptorType::STORAGE_TEXEL_BUFFER.as_raw(),
- UniformBuffer = ash::vk::DescriptorType::UNIFORM_BUFFER.as_raw(),
- StorageBuffer = ash::vk::DescriptorType::STORAGE_BUFFER.as_raw(),
- UniformBufferDynamic = ash::vk::DescriptorType::UNIFORM_BUFFER_DYNAMIC.as_raw(),
- StorageBufferDynamic = ash::vk::DescriptorType::STORAGE_BUFFER_DYNAMIC.as_raw(),
- InputAttachment = ash::vk::DescriptorType::INPUT_ATTACHMENT.as_raw(),
-}
-
-impl From<DescriptorType> for ash::vk::DescriptorType {
- #[inline]
- fn from(val: DescriptorType) -> Self {
- Self::from_raw(val as i32)
- }
-}
-
-/// Error when checking whether a descriptor set is a superset of another one.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum DescriptorSetDescSupersetError {
- /// There are more descriptors in the child than in the parent layout.
- DescriptorsCountMismatch { self_num: u32, other_num: u32 },
-
- /// Expected an empty descriptor, but got something instead.
- ExpectedEmptyDescriptor { binding_num: u32 },
-
- /// Two descriptors are incompatible.
- IncompatibleDescriptors {
- error: DescriptorDescSupersetError,
- binding_num: u32,
- },
-}
-
-impl error::Error for DescriptorSetDescSupersetError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- DescriptorSetDescSupersetError::IncompatibleDescriptors { ref error, .. } => {
- Some(error)
- }
- _ => None,
- }
- }
-}
-
-impl fmt::Display for DescriptorSetDescSupersetError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- DescriptorSetDescSupersetError::DescriptorsCountMismatch { .. } => {
- "there are more descriptors in the child than in the parent layout"
- }
- DescriptorSetDescSupersetError::ExpectedEmptyDescriptor { .. } => {
- "expected an empty descriptor, but got something instead"
- }
- DescriptorSetDescSupersetError::IncompatibleDescriptors { .. } => {
- "two descriptors are incompatible"
- }
- }
- )
- }
-}
-
-/// Error when checking whether a descriptor is a superset of another one.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum DescriptorDescSupersetError {
- /// The number of array elements of the descriptor is smaller than expected.
- ArrayTooSmall {
- len: u32,
- required: u32,
- },
-
- DimensionsMismatch {
- provided: DescriptorImageDescDimensions,
- expected: DescriptorImageDescDimensions,
- },
-
- FormatMismatch {
- provided: Option<Format>,
- expected: Format,
- },
-
- IncompatibleArrayLayers {
- provided: DescriptorImageDescArray,
- required: DescriptorImageDescArray,
- },
-
- MultisampledMismatch {
- provided: bool,
- expected: bool,
- },
-
- /// The descriptor is marked as read-only, but the other is not.
- MutabilityRequired,
-
- /// The shader stages are not a superset of one another.
- ShaderStagesNotSuperset,
-
- /// The descriptor type doesn't match the type of the other descriptor.
- TypeMismatch,
-}
-
-impl error::Error for DescriptorDescSupersetError {}
-
-impl fmt::Display for DescriptorDescSupersetError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- DescriptorDescSupersetError::ArrayTooSmall { .. } => {
- "the number of array elements of the descriptor is smaller than expected"
- }
- DescriptorDescSupersetError::TypeMismatch => {
- "the descriptor type doesn't match the type of the other descriptor"
- }
- DescriptorDescSupersetError::MutabilityRequired => {
- "the descriptor is marked as read-only, but the other is not"
- }
- DescriptorDescSupersetError::ShaderStagesNotSuperset => {
- "the shader stages are not a superset of one another"
- }
- DescriptorDescSupersetError::DimensionsMismatch { .. } => {
- "mismatch between the dimensions of the two descriptors"
- }
- DescriptorDescSupersetError::FormatMismatch { .. } => {
- "mismatch between the format of the two descriptors"
- }
- DescriptorDescSupersetError::MultisampledMismatch { .. } => {
- "mismatch between whether the descriptors are multisampled"
- }
- DescriptorDescSupersetError::IncompatibleArrayLayers { .. } => {
- "the array layers of the descriptors aren't compatible"
- }
- }
- )
- }
-}
-
-impl From<ShaderStagesSupersetError> for DescriptorDescSupersetError {
- #[inline]
- fn from(err: ShaderStagesSupersetError) -> DescriptorDescSupersetError {
- match err {
- ShaderStagesSupersetError::NotSuperset => {
- DescriptorDescSupersetError::ShaderStagesNotSuperset
- }
- }
- }
-}
diff --git a/src/descriptor_set/layout/mod.rs b/src/descriptor_set/layout/mod.rs
deleted file mode 100644
index 272e480..0000000
--- a/src/descriptor_set/layout/mod.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2021 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-//! Describes the layout of all descriptors within a descriptor set.
-//!
-//! When creating a new descriptor set, you must provide a *layout* object to create it from. You
-//! can create a descriptor set layout manually, but it is normally created automatically by each
-//! pipeline layout.
-
-pub use self::desc::DescriptorBufferDesc;
-pub use self::desc::DescriptorDesc;
-pub use self::desc::DescriptorDescSupersetError;
-pub use self::desc::DescriptorDescTy;
-pub use self::desc::DescriptorImageDesc;
-pub use self::desc::DescriptorImageDescArray;
-pub use self::desc::DescriptorImageDescDimensions;
-pub use self::desc::DescriptorSetDesc;
-pub use self::desc::DescriptorSetDescSupersetError;
-pub use self::desc::DescriptorType;
-pub use self::sys::DescriptorSetLayout;
-
-mod desc;
-mod sys;
diff --git a/src/descriptor_set/layout/sys.rs b/src/descriptor_set/layout/sys.rs
deleted file mode 100644
index 656f767..0000000
--- a/src/descriptor_set/layout/sys.rs
+++ /dev/null
@@ -1,202 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::check_errors;
-use crate::descriptor_set::layout::DescriptorDesc;
-use crate::descriptor_set::layout::DescriptorSetDesc;
-use crate::descriptor_set::pool::DescriptorsCount;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::OomError;
-use crate::VulkanObject;
-use smallvec::SmallVec;
-use std::mem::MaybeUninit;
-use std::ptr;
-use std::sync::Arc;
-
-/// Describes to the Vulkan implementation the layout of all descriptors within a descriptor set.
-#[derive(Debug)]
-pub struct DescriptorSetLayout {
- // The layout.
- handle: ash::vk::DescriptorSetLayout,
- // The device this layout belongs to.
- device: Arc<Device>,
- // Descriptors.
- desc: DescriptorSetDesc,
- // Number of descriptors.
- descriptors_count: DescriptorsCount,
-}
-
-impl DescriptorSetLayout {
- /// Builds a new `DescriptorSetLayout` with the given descriptors.
- ///
- /// The descriptors must be passed in the order of the bindings. In order words, descriptor
- /// at bind point 0 first, then descriptor at bind point 1, and so on. If a binding must remain
- /// empty, you can make the iterator yield `None` for an element.
- pub fn new<D>(device: Arc<Device>, desc: D) -> Result<DescriptorSetLayout, OomError>
- where
- D: Into<DescriptorSetDesc>,
- {
- let desc = desc.into();
- let mut descriptors_count = DescriptorsCount::zero();
-
- let bindings = desc
- .bindings()
- .iter()
- .enumerate()
- .filter_map(|(binding, desc)| {
- let desc = match desc {
- Some(d) => d,
- None => return None,
- };
-
- // FIXME: it is not legal to pass eg. the TESSELLATION_SHADER bit when the device
- // doesn't have tess shaders enabled
-
- let ty = desc.ty.ty();
- descriptors_count.add_num(ty, desc.array_count);
-
- Some(ash::vk::DescriptorSetLayoutBinding {
- binding: binding as u32,
- descriptor_type: ty.into(),
- descriptor_count: desc.array_count,
- stage_flags: desc.stages.into(),
- p_immutable_samplers: ptr::null(), // FIXME: not yet implemented
- })
- })
- .collect::<SmallVec<[_; 32]>>();
-
- // Note that it seems legal to have no descriptor at all in the set.
-
- let handle = unsafe {
- let infos = ash::vk::DescriptorSetLayoutCreateInfo {
- flags: ash::vk::DescriptorSetLayoutCreateFlags::empty(),
- binding_count: bindings.len() as u32,
- p_bindings: bindings.as_ptr(),
- ..Default::default()
- };
-
- let mut output = MaybeUninit::uninit();
- let fns = device.fns();
- check_errors(fns.v1_0.create_descriptor_set_layout(
- device.internal_object(),
- &infos,
- ptr::null(),
- output.as_mut_ptr(),
- ))?;
- output.assume_init()
- };
-
- Ok(DescriptorSetLayout {
- handle,
- device,
- desc,
- descriptors_count,
- })
- }
-
- pub(crate) fn desc(&self) -> &DescriptorSetDesc {
- &self.desc
- }
-
- /// Returns the number of descriptors of each type.
- #[inline]
- pub fn descriptors_count(&self) -> &DescriptorsCount {
- &self.descriptors_count
- }
-
- /// Returns the number of binding slots in the set.
- #[inline]
- pub fn num_bindings(&self) -> usize {
- self.desc.bindings().len()
- }
-
- /// Returns a description of a descriptor, or `None` if out of range.
- #[inline]
- pub fn descriptor(&self, binding: usize) -> Option<DescriptorDesc> {
- self.desc.bindings().get(binding).cloned().unwrap_or(None)
- }
-}
-
-unsafe impl DeviceOwned for DescriptorSetLayout {
- #[inline]
- fn device(&self) -> &Arc<Device> {
- &self.device
- }
-}
-
-unsafe impl VulkanObject for DescriptorSetLayout {
- type Object = ash::vk::DescriptorSetLayout;
-
- #[inline]
- fn internal_object(&self) -> ash::vk::DescriptorSetLayout {
- self.handle
- }
-}
-
-impl Drop for DescriptorSetLayout {
- #[inline]
- fn drop(&mut self) {
- unsafe {
- let fns = self.device.fns();
- fns.v1_0.destroy_descriptor_set_layout(
- self.device.internal_object(),
- self.handle,
- ptr::null(),
- );
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use crate::descriptor_set::layout::DescriptorBufferDesc;
- use crate::descriptor_set::layout::DescriptorDesc;
- use crate::descriptor_set::layout::DescriptorDescTy;
- use crate::descriptor_set::layout::DescriptorSetDesc;
- use crate::descriptor_set::layout::DescriptorSetLayout;
- use crate::descriptor_set::pool::DescriptorsCount;
- use crate::pipeline::shader::ShaderStages;
- use std::iter;
-
- #[test]
- fn empty() {
- let (device, _) = gfx_dev_and_queue!();
- let _layout = DescriptorSetLayout::new(device, DescriptorSetDesc::empty());
- }
-
- #[test]
- fn basic_create() {
- let (device, _) = gfx_dev_and_queue!();
-
- let layout = DescriptorDesc {
- ty: DescriptorDescTy::Buffer(DescriptorBufferDesc {
- dynamic: Some(false),
- storage: false,
- }),
- array_count: 1,
- stages: ShaderStages::all_graphics(),
- readonly: true,
- };
-
- let sl = DescriptorSetLayout::new(
- device.clone(),
- DescriptorSetDesc::new(iter::once(Some(layout))),
- )
- .unwrap();
-
- assert_eq!(
- sl.descriptors_count(),
- &DescriptorsCount {
- uniform_buffer: 1,
- ..DescriptorsCount::zero()
- }
- );
- }
-}
diff --git a/src/descriptor_set/mod.rs b/src/descriptor_set/mod.rs
index b69deee..82d4199 100644
--- a/src/descriptor_set/mod.rs
+++ b/src/descriptor_set/mod.rs
@@ -22,7 +22,7 @@
//! that are often used together in the same set so that you can keep the same set binding through
//! multiple draws.
//!
-//! # Example
+//! # Examples
//!
//! > **Note**: This section describes the simple way to bind resources. There are more optimized
//! > ways.
@@ -52,236 +52,439 @@
//!
//! - A `DescriptorSetLayout` is a Vulkan object that describes to the Vulkan implementation the
//! layout of a future descriptor set. When you allocate a descriptor set, you have to pass an
-//! instance of this object. This is represented with the `DescriptorSetLayout` type in
+//! instance of this object. This is represented with the [`DescriptorSetLayout`] type in
//! vulkano.
//! - A `DescriptorPool` is a Vulkan object that holds the memory of descriptor sets and that can
//! be used to allocate and free individual descriptor sets. This is represented with the
-//! `UnsafeDescriptorPool` type in vulkano.
+//! [`DescriptorPool`] type in vulkano.
//! - A `DescriptorSet` contains the bindings to resources and is allocated from a pool. This is
-//! represented with the `UnsafeDescriptorSet` type in vulkano.
+//! represented with the [`UnsafeDescriptorSet`] type in vulkano.
//!
//! In addition to this, vulkano defines the following:
//!
-//! - The `DescriptorPool` trait can be implemented on types from which you can allocate and free
-//! descriptor sets. However it is different from Vulkan descriptor pools in the sense that an
-//! implementation of the `DescriptorPool` trait can manage multiple Vulkan descriptor pools.
-//! - The `StdDescriptorPool` type is a default implementation of the `DescriptorPool` trait.
-//! - The `DescriptorSet` trait is implemented on types that wrap around Vulkan descriptor sets in
+//! - The [`DescriptorSetAllocator`] trait can be implemented on types from which you can allocate
+//! and free descriptor sets. However it is different from Vulkan descriptor pools in the sense
+//! that an implementation of the [`DescriptorSetAllocator`] trait can manage multiple Vulkan
+//! descriptor pools.
+//! - The [`StandardDescriptorSetAllocator`] type is a default implementation of the
+//! [`DescriptorSetAllocator`] trait.
+//! - The [`DescriptorSet`] trait is implemented on types that wrap around Vulkan descriptor sets in
//! a safe way. A Vulkan descriptor set is inherently unsafe, so we need safe wrappers around
//! them.
-//! - The `SimpleDescriptorSet` type is a default implementation of the `DescriptorSet` trait.
-//! - The `DescriptorSetsCollection` trait is implemented on collections of types that implement
-//! `DescriptorSet`. It is what you pass to the draw functions.
-
-pub use self::collection::DescriptorSetsCollection;
-pub use self::fixed_size_pool::FixedSizeDescriptorSetsPool;
-use self::layout::DescriptorSetLayout;
-pub use self::persistent::PersistentDescriptorSet;
-pub use self::persistent::PersistentDescriptorSetBuildError;
-pub use self::persistent::PersistentDescriptorSetError;
-use self::sys::UnsafeDescriptorSet;
-use crate::buffer::BufferAccess;
-use crate::descriptor_set::layout::{DescriptorBufferDesc, DescriptorDescTy};
-use crate::device::DeviceOwned;
-use crate::image::view::ImageViewAbstract;
-use crate::SafeDeref;
-use crate::VulkanObject;
-use smallvec::SmallVec;
-use std::hash::Hash;
-use std::hash::Hasher;
-use std::sync::Arc;
+//! - The [`DescriptorSetsCollection`] trait is implemented on collections of types that implement
+//! [`DescriptorSet`]. It is what you pass to the draw functions.
+//!
+//! [`DescriptorPool`]: pool::DescriptorPool
+//! [`DescriptorSetAllocator`]: allocator::DescriptorSetAllocator
+//! [`StandardDescriptorSetAllocator`]: allocator::StandardDescriptorSetAllocator
+
+pub(crate) use self::update::{check_descriptor_write, DescriptorWriteInfo};
+pub use self::{
+ collection::DescriptorSetsCollection,
+ persistent::PersistentDescriptorSet,
+ update::{DescriptorSetUpdateError, WriteDescriptorSet, WriteDescriptorSetElements},
+};
+use self::{layout::DescriptorSetLayout, sys::UnsafeDescriptorSet};
+use crate::{
+ buffer::{view::BufferView, Subbuffer},
+ descriptor_set::layout::DescriptorType,
+ device::DeviceOwned,
+ image::view::ImageViewAbstract,
+ sampler::Sampler,
+ DeviceSize, OomError, VulkanObject,
+};
+use ahash::HashMap;
+use smallvec::{smallvec, SmallVec};
+use std::{
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+ hash::{Hash, Hasher},
+ ops::Range,
+ ptr,
+ sync::Arc,
+};
+pub mod allocator;
mod collection;
-pub mod fixed_size_pool;
pub mod layout;
pub mod persistent;
pub mod pool;
pub mod sys;
+mod update;
/// Trait for objects that contain a collection of resources that will be accessible by shaders.
///
/// Objects of this type can be passed when submitting a draw command.
-pub unsafe trait DescriptorSet: DeviceOwned {
+pub unsafe trait DescriptorSet: DeviceOwned + Send + Sync {
/// Returns the inner `UnsafeDescriptorSet`.
fn inner(&self) -> &UnsafeDescriptorSet;
/// Returns the layout of this descriptor set.
fn layout(&self) -> &Arc<DescriptorSetLayout>;
+ /// Returns the variable descriptor count that this descriptor set was allocated with.
+ fn variable_descriptor_count(&self) -> u32;
+
/// Creates a [`DescriptorSetWithOffsets`] with the given dynamic offsets.
- fn offsets<I>(self, dynamic_offsets: I) -> DescriptorSetWithOffsets
+ fn offsets(
+ self: Arc<Self>,
+ dynamic_offsets: impl IntoIterator<Item = u32>,
+ ) -> DescriptorSetWithOffsets
where
- Self: Sized + Send + Sync + 'static,
- I: IntoIterator<Item = u32>,
+ Self: Sized + 'static,
{
DescriptorSetWithOffsets::new(self, dynamic_offsets)
}
- /// Returns the number of buffers within this descriptor set.
- fn num_buffers(&self) -> usize;
+ /// Returns the resources bound to this descriptor set.
+ fn resources(&self) -> &DescriptorSetResources;
+}
- /// Returns the `index`th buffer of this descriptor set, or `None` if out of range. Also
- /// returns the index of the descriptor that uses this buffer.
- ///
- /// The valid range is between 0 and `num_buffers()`.
- fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)>;
+impl PartialEq for dyn DescriptorSet {
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ self.inner() == other.inner()
+ }
+}
- /// Returns the number of images within this descriptor set.
- fn num_images(&self) -> usize;
+impl Eq for dyn DescriptorSet {}
- /// Returns the `index`th image of this descriptor set, or `None` if out of range. Also returns
- /// the index of the descriptor that uses this image.
- ///
- /// The valid range is between 0 and `num_images()`.
- fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)>;
+impl Hash for dyn DescriptorSet {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.inner().hash(state);
+ }
}
-unsafe impl<T> DescriptorSet for T
-where
- T: SafeDeref,
- T::Target: DescriptorSet,
-{
- #[inline]
- fn inner(&self) -> &UnsafeDescriptorSet {
- (**self).inner()
+pub(crate) struct DescriptorSetInner {
+ layout: Arc<DescriptorSetLayout>,
+ variable_descriptor_count: u32,
+ resources: DescriptorSetResources,
+}
+
+impl DescriptorSetInner {
+ pub(crate) fn new(
+ handle: ash::vk::DescriptorSet,
+ layout: Arc<DescriptorSetLayout>,
+ variable_descriptor_count: u32,
+ descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>,
+ ) -> Result<Self, DescriptorSetUpdateError> {
+ assert!(
+ !layout.push_descriptor(),
+ "the provided descriptor set layout is for push descriptors, and cannot be used to \
+ build a descriptor set object",
+ );
+
+ let max_count = layout.variable_descriptor_count();
+
+ assert!(
+ variable_descriptor_count <= max_count,
+ "the provided variable_descriptor_count ({}) is greater than the maximum number of \
+ variable count descriptors in the layout ({})",
+ variable_descriptor_count,
+ max_count,
+ );
+
+ let mut resources = DescriptorSetResources::new(&layout, variable_descriptor_count);
+
+ let descriptor_writes = descriptor_writes.into_iter();
+ let (lower_size_bound, _) = descriptor_writes.size_hint();
+ let mut descriptor_write_info: SmallVec<[_; 8]> = SmallVec::with_capacity(lower_size_bound);
+ let mut write_descriptor_set: SmallVec<[_; 8]> = SmallVec::with_capacity(lower_size_bound);
+
+ for write in descriptor_writes {
+ let layout_binding =
+ check_descriptor_write(&write, &layout, variable_descriptor_count)?;
+
+ resources.update(&write);
+ descriptor_write_info.push(write.to_vulkan_info(layout_binding.descriptor_type));
+ write_descriptor_set.push(write.to_vulkan(handle, layout_binding.descriptor_type));
+ }
+
+ if !write_descriptor_set.is_empty() {
+ for (info, write) in descriptor_write_info
+ .iter()
+ .zip(write_descriptor_set.iter_mut())
+ {
+ match info {
+ DescriptorWriteInfo::Image(info) => {
+ write.descriptor_count = info.len() as u32;
+ write.p_image_info = info.as_ptr();
+ }
+ DescriptorWriteInfo::Buffer(info) => {
+ write.descriptor_count = info.len() as u32;
+ write.p_buffer_info = info.as_ptr();
+ }
+ DescriptorWriteInfo::BufferView(info) => {
+ write.descriptor_count = info.len() as u32;
+ write.p_texel_buffer_view = info.as_ptr();
+ }
+ }
+ }
+ }
+
+ unsafe {
+ let fns = layout.device().fns();
+
+ (fns.v1_0.update_descriptor_sets)(
+ layout.device().handle(),
+ write_descriptor_set.len() as u32,
+ write_descriptor_set.as_ptr(),
+ 0,
+ ptr::null(),
+ );
+ }
+
+ Ok(DescriptorSetInner {
+ layout,
+ variable_descriptor_count,
+ resources,
+ })
}
- #[inline]
- fn layout(&self) -> &Arc<DescriptorSetLayout> {
- (**self).layout()
+ pub(crate) fn layout(&self) -> &Arc<DescriptorSetLayout> {
+ &self.layout
}
- #[inline]
- fn num_buffers(&self) -> usize {
- (**self).num_buffers()
+ pub(crate) fn resources(&self) -> &DescriptorSetResources {
+ &self.resources
}
+}
+/// The resources that are bound to a descriptor set.
+#[derive(Clone)]
+pub struct DescriptorSetResources {
+ binding_resources: HashMap<u32, DescriptorBindingResources>,
+}
+
+impl DescriptorSetResources {
+ /// Creates a new `DescriptorSetResources` matching the provided descriptor set layout, and
+ /// all descriptors set to `None`.
#[inline]
- fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)> {
- (**self).buffer(index)
+ pub fn new(layout: &DescriptorSetLayout, variable_descriptor_count: u32) -> Self {
+ assert!(variable_descriptor_count <= layout.variable_descriptor_count());
+
+ let binding_resources = layout
+ .bindings()
+ .iter()
+ .map(|(&binding_num, binding)| {
+ let count = if binding.variable_descriptor_count {
+ variable_descriptor_count
+ } else {
+ binding.descriptor_count
+ } as usize;
+
+ let binding_resources = match binding.descriptor_type {
+ DescriptorType::UniformBuffer
+ | DescriptorType::StorageBuffer
+ | DescriptorType::UniformBufferDynamic
+ | DescriptorType::StorageBufferDynamic => {
+ DescriptorBindingResources::Buffer(smallvec![None; count])
+ }
+ DescriptorType::UniformTexelBuffer | DescriptorType::StorageTexelBuffer => {
+ DescriptorBindingResources::BufferView(smallvec![None; count])
+ }
+ DescriptorType::SampledImage
+ | DescriptorType::StorageImage
+ | DescriptorType::InputAttachment => {
+ DescriptorBindingResources::ImageView(smallvec![None; count])
+ }
+ DescriptorType::CombinedImageSampler => {
+ if binding.immutable_samplers.is_empty() {
+ DescriptorBindingResources::ImageViewSampler(smallvec![None; count])
+ } else {
+ DescriptorBindingResources::ImageView(smallvec![None; count])
+ }
+ }
+ DescriptorType::Sampler => {
+ if binding.immutable_samplers.is_empty() {
+ DescriptorBindingResources::Sampler(smallvec![None; count])
+ } else if layout.push_descriptor() {
+ // For push descriptors, no resource is written by default, this needs
+ // to be done explicitly via a dummy write.
+ DescriptorBindingResources::None(smallvec![None; count])
+ } else {
+ // For regular descriptor sets, all descriptors are considered valid
+ // from the start.
+ DescriptorBindingResources::None(smallvec![Some(()); count])
+ }
+ }
+ };
+ (binding_num, binding_resources)
+ })
+ .collect();
+
+ Self { binding_resources }
}
+ /// Applies a descriptor write to the resources.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the binding number of a write does not exist in the resources.
+ /// - See also [`DescriptorBindingResources::update`].
#[inline]
- fn num_images(&self) -> usize {
- (**self).num_images()
+ pub fn update(&mut self, write: &WriteDescriptorSet) {
+ self.binding_resources
+ .get_mut(&write.binding())
+ .expect("descriptor write has invalid binding number")
+ .update(write)
}
+ /// Returns a reference to the bound resources for `binding`. Returns `None` if the binding
+ /// doesn't exist.
#[inline]
- fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)> {
- (**self).image(index)
+ pub fn binding(&self, binding: u32) -> Option<&DescriptorBindingResources> {
+ self.binding_resources.get(&binding)
}
}
-impl PartialEq for dyn DescriptorSet + Send + Sync {
- #[inline]
- fn eq(&self, other: &Self) -> bool {
- self.inner().internal_object() == other.inner().internal_object()
- && self.device() == other.device()
- }
+/// The resources that are bound to a single descriptor set binding.
+#[derive(Clone)]
+pub enum DescriptorBindingResources {
+ None(Elements<()>),
+ Buffer(Elements<(Subbuffer<[u8]>, Range<DeviceSize>)>),
+ BufferView(Elements<Arc<BufferView>>),
+ ImageView(Elements<Arc<dyn ImageViewAbstract>>),
+ ImageViewSampler(Elements<(Arc<dyn ImageViewAbstract>, Arc<Sampler>)>),
+ Sampler(Elements<Arc<Sampler>>),
}
-impl Eq for dyn DescriptorSet + Send + Sync {}
+type Elements<T> = SmallVec<[Option<T>; 1]>;
-impl Hash for dyn DescriptorSet + Send + Sync {
+impl DescriptorBindingResources {
+ /// Applies a descriptor write to the resources.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the resource types do not match.
+ /// - Panics if the write goes out of bounds.
#[inline]
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.inner().internal_object().hash(state);
- self.device().hash(state);
+ pub fn update(&mut self, write: &WriteDescriptorSet) {
+ fn write_resources<T: Clone>(first: usize, resources: &mut [Option<T>], elements: &[T]) {
+ resources
+ .get_mut(first..first + elements.len())
+ .expect("descriptor write for binding out of bounds")
+ .iter_mut()
+ .zip(elements)
+ .for_each(|(resource, element)| {
+ *resource = Some(element.clone());
+ });
+ }
+
+ let first = write.first_array_element() as usize;
+
+ match (self, write.elements()) {
+ (
+ DescriptorBindingResources::None(resources),
+ WriteDescriptorSetElements::None(num_elements),
+ ) => {
+ resources
+ .get_mut(first..first + *num_elements as usize)
+ .expect("descriptor write for binding out of bounds")
+ .iter_mut()
+ .for_each(|resource| {
+ *resource = Some(());
+ });
+ }
+ (
+ DescriptorBindingResources::Buffer(resources),
+ WriteDescriptorSetElements::Buffer(elements),
+ ) => write_resources(first, resources, elements),
+ (
+ DescriptorBindingResources::BufferView(resources),
+ WriteDescriptorSetElements::BufferView(elements),
+ ) => write_resources(first, resources, elements),
+ (
+ DescriptorBindingResources::ImageView(resources),
+ WriteDescriptorSetElements::ImageView(elements),
+ ) => write_resources(first, resources, elements),
+ (
+ DescriptorBindingResources::ImageViewSampler(resources),
+ WriteDescriptorSetElements::ImageViewSampler(elements),
+ ) => write_resources(first, resources, elements),
+ (
+ DescriptorBindingResources::Sampler(resources),
+ WriteDescriptorSetElements::Sampler(elements),
+ ) => write_resources(first, resources, elements),
+ _ => panic!(
+ "descriptor write for binding {} has wrong resource type",
+ write.binding(),
+ ),
+ }
}
}
+#[derive(Clone)]
pub struct DescriptorSetWithOffsets {
- descriptor_set: Box<dyn DescriptorSet + Send + Sync>,
+ descriptor_set: Arc<dyn DescriptorSet>,
dynamic_offsets: SmallVec<[u32; 4]>,
}
impl DescriptorSetWithOffsets {
- #[inline]
- pub fn new<S, O>(descriptor_set: S, dynamic_offsets: O) -> Self
- where
- S: DescriptorSet + Send + Sync + 'static,
- O: IntoIterator<Item = u32>,
- {
- let dynamic_offsets: SmallVec<_> = dynamic_offsets.into_iter().collect();
- let layout = descriptor_set.layout();
- let properties = layout.device().physical_device().properties();
- let min_uniform_off_align = properties.min_uniform_buffer_offset_alignment as u32;
- let min_storage_off_align = properties.min_storage_buffer_offset_alignment as u32;
- let mut dynamic_offset_index = 0;
-
- // Ensure that the number of dynamic_offsets is correct and that each
- // dynamic offset is a multiple of the minimum offset alignment specified
- // by the physical device.
- for desc in layout.desc().bindings() {
- let desc = desc.as_ref().unwrap();
- if let DescriptorDescTy::Buffer(DescriptorBufferDesc {
- dynamic: Some(true),
- storage,
- }) = desc.ty
- {
- // Don't check alignment if there are not enough offsets anyway
- if dynamic_offsets.len() > dynamic_offset_index {
- if storage {
- assert!(
- dynamic_offsets[dynamic_offset_index] % min_storage_off_align == 0,
- "Dynamic storage buffer offset must be a multiple of min_storage_buffer_offset_alignment: got {}, expected a multiple of {}",
- dynamic_offsets[dynamic_offset_index],
- min_storage_off_align
- );
- } else {
- assert!(
- dynamic_offsets[dynamic_offset_index] % min_uniform_off_align == 0,
- "Dynamic uniform buffer offset must be a multiple of min_uniform_buffer_offset_alignment: got {}, expected a multiple of {}",
- dynamic_offsets[dynamic_offset_index],
- min_uniform_off_align
- );
- }
- }
- dynamic_offset_index += 1;
- }
- }
-
- assert!(
- !(dynamic_offsets.len() < dynamic_offset_index),
- "Too few dynamic offsets: got {}, expected {}",
- dynamic_offsets.len(),
- dynamic_offset_index
- );
- assert!(
- !(dynamic_offsets.len() > dynamic_offset_index),
- "Too many dynamic offsets: got {}, expected {}",
- dynamic_offsets.len(),
- dynamic_offset_index
- );
-
- DescriptorSetWithOffsets {
- descriptor_set: Box::new(descriptor_set),
- dynamic_offsets,
+ pub fn new(
+ descriptor_set: Arc<dyn DescriptorSet>,
+ dynamic_offsets: impl IntoIterator<Item = u32>,
+ ) -> Self {
+ Self {
+ descriptor_set,
+ dynamic_offsets: dynamic_offsets.into_iter().collect(),
}
}
#[inline]
- pub fn as_ref(&self) -> (&dyn DescriptorSet, &[u32]) {
+ pub fn as_ref(&self) -> (&Arc<dyn DescriptorSet>, &[u32]) {
(&self.descriptor_set, &self.dynamic_offsets)
}
#[inline]
- pub fn into_tuple(
- self,
- ) -> (
- Box<dyn DescriptorSet + Send + Sync>,
- impl ExactSizeIterator<Item = u32>,
- ) {
+ pub fn into_tuple(self) -> (Arc<dyn DescriptorSet>, impl ExactSizeIterator<Item = u32>) {
(self.descriptor_set, self.dynamic_offsets.into_iter())
}
}
-impl<S> From<S> for DescriptorSetWithOffsets
+impl<S> From<Arc<S>> for DescriptorSetWithOffsets
where
- S: DescriptorSet + Send + Sync + 'static,
+ S: DescriptorSet + 'static,
{
- #[inline]
- fn from(descriptor_set: S) -> Self {
- Self::new(descriptor_set, std::iter::empty())
+ fn from(descriptor_set: Arc<S>) -> Self {
+ DescriptorSetWithOffsets::new(descriptor_set, std::iter::empty())
+ }
+}
+
+#[derive(Clone, Copy, Debug)]
+pub enum DescriptorSetCreationError {
+ DescriptorSetUpdateError(DescriptorSetUpdateError),
+ OomError(OomError),
+}
+
+impl Error for DescriptorSetCreationError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::DescriptorSetUpdateError(err) => Some(err),
+ Self::OomError(err) => Some(err),
+ }
+ }
+}
+
+impl Display for DescriptorSetCreationError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::DescriptorSetUpdateError(_) => {
+ write!(f, "an error occurred while updating the descriptor set")
+ }
+ Self::OomError(_) => write!(f, "out of memory"),
+ }
+ }
+}
+
+impl From<DescriptorSetUpdateError> for DescriptorSetCreationError {
+ fn from(err: DescriptorSetUpdateError) -> Self {
+ Self::DescriptorSetUpdateError(err)
+ }
+}
+
+impl From<OomError> for DescriptorSetCreationError {
+ fn from(err: OomError) -> Self {
+ Self::OomError(err)
}
}
diff --git a/src/descriptor_set/persistent.rs b/src/descriptor_set/persistent.rs
index c949f88..cfa3f07 100644
--- a/src/descriptor_set/persistent.rs
+++ b/src/descriptor_set/persistent.rs
@@ -18,1287 +18,136 @@
//! > actual allocation, you can skip this allocation and make it acceptable to use a persistent
//! > descriptor set in performance-critical paths..
//!
-//! The template parameter of the `PersistentDescriptorSet` is complex, and you shouldn't try to
-//! express it explicitly. If you want to store your descriptor set in a struct or in a `Vec` for
-//! example, you are encouraged to turn the `PersistentDescriptorSet` into a `Box<DescriptorSet>`
-//! or a `Arc<DescriptorSet>`.
-//!
-//! # Example
+//! # Examples
//! TODO:
-use crate::buffer::BufferAccess;
-use crate::buffer::BufferViewRef;
-use crate::descriptor_set::layout::DescriptorDesc;
-use crate::descriptor_set::layout::DescriptorDescTy;
-use crate::descriptor_set::layout::DescriptorImageDesc;
-use crate::descriptor_set::layout::DescriptorImageDescArray;
-use crate::descriptor_set::layout::DescriptorImageDescDimensions;
-use crate::descriptor_set::layout::DescriptorSetLayout;
-use crate::descriptor_set::layout::DescriptorType;
-use crate::descriptor_set::pool::standard::StdDescriptorPoolAlloc;
-use crate::descriptor_set::pool::DescriptorPool;
-use crate::descriptor_set::pool::DescriptorPoolAlloc;
-use crate::descriptor_set::sys::DescriptorWrite;
-use crate::descriptor_set::DescriptorSet;
-use crate::descriptor_set::UnsafeDescriptorSet;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::format::Format;
-use crate::image::view::ImageViewAbstract;
-use crate::image::SampleCount;
-use crate::sampler::Sampler;
-use crate::OomError;
-use crate::VulkanObject;
-use std::error;
-use std::fmt;
-use std::hash::Hash;
-use std::hash::Hasher;
-use std::sync::Arc;
+use crate::{
+ descriptor_set::{
+ allocator::{DescriptorSetAlloc, DescriptorSetAllocator, StandardDescriptorSetAlloc},
+ update::WriteDescriptorSet,
+ DescriptorSet, DescriptorSetCreationError, DescriptorSetInner, DescriptorSetLayout,
+ DescriptorSetResources, UnsafeDescriptorSet,
+ },
+ device::{Device, DeviceOwned},
+ VulkanObject,
+};
+use std::{
+ hash::{Hash, Hasher},
+ sync::Arc,
+};
/// A simple, immutable descriptor set that is expected to be long-lived.
-pub struct PersistentDescriptorSet<R, P = StdDescriptorPoolAlloc> {
- inner: P,
- resources: R,
- layout: Arc<DescriptorSetLayout>,
-}
-
-impl PersistentDescriptorSet<()> {
- /// Starts the process of building a `PersistentDescriptorSet`. Returns a builder.
- ///
- /// # Panic
- ///
- /// - Panics if the set id is out of range.
- ///
- pub fn start(layout: Arc<DescriptorSetLayout>) -> PersistentDescriptorSetBuilder<()> {
- let cap = layout.num_bindings();
-
- PersistentDescriptorSetBuilder {
- layout,
- binding_id: 0,
- writes: Vec::with_capacity(cap),
- resources: (),
- }
- }
-}
-
-unsafe impl<R, P> DescriptorSet for PersistentDescriptorSet<R, P>
-where
- P: DescriptorPoolAlloc,
- R: PersistentDescriptorSetResources,
-{
- #[inline]
- fn inner(&self) -> &UnsafeDescriptorSet {
- self.inner.inner()
- }
-
- #[inline]
- fn layout(&self) -> &Arc<DescriptorSetLayout> {
- &self.layout
- }
-
- #[inline]
- fn num_buffers(&self) -> usize {
- self.resources.num_buffers()
- }
-
- #[inline]
- fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)> {
- self.resources.buffer(index)
- }
-
- #[inline]
- fn num_images(&self) -> usize {
- self.resources.num_images()
- }
-
- #[inline]
- fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)> {
- self.resources.image(index)
- }
-}
-
-unsafe impl<R, P> DeviceOwned for PersistentDescriptorSet<R, P> {
- #[inline]
- fn device(&self) -> &Arc<Device> {
- self.layout.device()
- }
+pub struct PersistentDescriptorSet<P = StandardDescriptorSetAlloc> {
+ alloc: P,
+ inner: DescriptorSetInner,
}
-impl<R, P> PartialEq for PersistentDescriptorSet<R, P>
-where
- P: DescriptorPoolAlloc,
- R: PersistentDescriptorSetResources,
-{
- #[inline]
- fn eq(&self, other: &Self) -> bool {
- self.inner().internal_object() == other.inner().internal_object()
- && self.device() == other.device()
- }
-}
-
-impl<R, P> Eq for PersistentDescriptorSet<R, P>
-where
- P: DescriptorPoolAlloc,
- R: PersistentDescriptorSetResources,
-{
-}
-
-impl<R, P> Hash for PersistentDescriptorSet<R, P>
-where
- P: DescriptorPoolAlloc,
- R: PersistentDescriptorSetResources,
-{
- #[inline]
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.inner().internal_object().hash(state);
- self.device().hash(state);
- }
-}
-
-/// Prototype of a `PersistentDescriptorSet`.
-///
-/// The template parameter `R` is an unspecified type that represents the list of resources.
-///
-/// See the docs of `PersistentDescriptorSet` for an example.
-pub struct PersistentDescriptorSetBuilder<R> {
- // The descriptor set layout.
- layout: Arc<DescriptorSetLayout>,
- // Binding currently being filled.
- binding_id: usize,
- // The writes to perform on a descriptor set in order to put the resources in it.
- writes: Vec<DescriptorWrite>,
- // Holds the resources alive.
- resources: R,
-}
-
-// TODO: lots of checks are still missing, see the docs of
-// VkDescriptorImageInfo and VkWriteDescriptorSet
-
-impl<R> PersistentDescriptorSetBuilder<R> {
- /// Builds a `PersistentDescriptorSet` from the builder.
- #[inline]
- pub fn build(
- self,
- ) -> Result<PersistentDescriptorSet<R, StdDescriptorPoolAlloc>, PersistentDescriptorSetBuildError>
- {
- let mut pool = Device::standard_descriptor_pool(self.layout.device());
- self.build_with_pool(&mut pool)
- }
-
- /// Builds a `PersistentDescriptorSet` from the builder.
- ///
- /// # Panic
- ///
- /// Panics if the pool doesn't have the same device as the descriptor set layout.
- ///
- pub fn build_with_pool<P>(
- self,
- pool: &mut P,
- ) -> Result<PersistentDescriptorSet<R, P::Alloc>, PersistentDescriptorSetBuildError>
- where
- P: ?Sized + DescriptorPool,
- {
- assert_eq!(
- self.layout.device().internal_object(),
- pool.device().internal_object()
- );
-
- let expected_desc = self.layout.num_bindings();
-
- if expected_desc > self.binding_id {
- return Err(PersistentDescriptorSetBuildError::MissingDescriptors {
- expected: expected_desc as u32,
- obtained: self.binding_id as u32,
- });
- }
-
- debug_assert_eq!(expected_desc, self.binding_id);
-
- let set = unsafe {
- let mut set = pool.alloc(&self.layout)?;
- set.inner_mut()
- .write(pool.device(), self.writes.into_iter());
- set
- };
-
- Ok(PersistentDescriptorSet {
- inner: set,
- resources: self.resources,
- layout: self.layout,
- })
- }
-
- /// Call this function if the next element of the set is an array in order to set the value of
- /// each element.
- ///
- /// Returns an error if the descriptor is empty.
- ///
- /// This function can be called even if the descriptor isn't an array, and it is valid to enter
- /// the "array", add one element, then leave.
- #[inline]
- pub fn enter_array(
- self,
- ) -> Result<PersistentDescriptorSetBuilderArray<R>, PersistentDescriptorSetError> {
- let desc = match self.layout.descriptor(self.binding_id) {
- Some(d) => d,
- None => return Err(PersistentDescriptorSetError::EmptyExpected),
- };
-
- Ok(PersistentDescriptorSetBuilderArray {
- builder: self,
- desc,
- array_element: 0,
- })
- }
-
- /// Skips the current descriptor if it is empty.
- #[inline]
- pub fn add_empty(
- mut self,
- ) -> Result<PersistentDescriptorSetBuilder<R>, PersistentDescriptorSetError> {
- match self.layout.descriptor(self.binding_id) {
- None => (),
- Some(desc) => {
- return Err(PersistentDescriptorSetError::WrongDescriptorTy {
- expected: desc.ty.ty(),
- })
- }
- }
-
- self.binding_id += 1;
- Ok(self)
- }
-
- /// Binds a buffer as the next descriptor.
- ///
- /// An error is returned if the buffer isn't compatible with the descriptor.
- ///
- /// # Panic
- ///
- /// Panics if the buffer doesn't have the same device as the descriptor set layout.
- ///
- #[inline]
- pub fn add_buffer<T>(
- self,
- buffer: T,
- ) -> Result<
- PersistentDescriptorSetBuilder<(R, PersistentDescriptorSetBuf<T>)>,
- PersistentDescriptorSetError,
- >
- where
- T: BufferAccess,
- {
- self.enter_array()?.add_buffer(buffer)?.leave_array()
- }
-
- /// Binds a buffer view as the next descriptor.
- ///
- /// An error is returned if the buffer isn't compatible with the descriptor.
- ///
- /// # Panic
- ///
- /// Panics if the buffer view doesn't have the same device as the descriptor set layout.
- ///
- pub fn add_buffer_view<T>(
- self,
- view: T,
- ) -> Result<
- PersistentDescriptorSetBuilder<(R, PersistentDescriptorSetBufView<T>)>,
- PersistentDescriptorSetError,
- >
- where
- T: BufferViewRef,
- {
- self.enter_array()?.add_buffer_view(view)?.leave_array()
- }
-
- /// Binds an image view as the next descriptor.
- ///
- /// An error is returned if the image view isn't compatible with the descriptor.
- ///
- /// # Panic
- ///
- /// Panics if the image view doesn't have the same device as the descriptor set layout.
+impl PersistentDescriptorSet {
+ /// Creates and returns a new descriptor set with a variable descriptor count of 0.
///
+ /// See `new_with_pool` for more.
#[inline]
- pub fn add_image<T>(
- self,
- image_view: T,
- ) -> Result<
- PersistentDescriptorSetBuilder<(R, PersistentDescriptorSetImg<T>)>,
- PersistentDescriptorSetError,
- >
+ pub fn new<A>(
+ allocator: &A,
+ layout: Arc<DescriptorSetLayout>,
+ descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>,
+ ) -> Result<Arc<PersistentDescriptorSet<A::Alloc>>, DescriptorSetCreationError>
where
- T: ImageViewAbstract,
+ A: DescriptorSetAllocator + ?Sized,
{
- self.enter_array()?.add_image(image_view)?.leave_array()
+ Self::new_variable(allocator, layout, 0, descriptor_writes)
}
- /// Binds an image view with a sampler as the next descriptor.
- ///
- /// An error is returned if the image view isn't compatible with the descriptor.
+ /// Creates and returns a new descriptor set with the requested variable descriptor count,
+ /// allocating it from the provided pool.
///
- /// # Panic
+ /// # Panics
///
- /// Panics if the image view or the sampler doesn't have the same device as the descriptor set
- /// layout.
- ///
- #[inline]
- pub fn add_sampled_image<T>(
- self,
- image_view: T,
- sampler: Arc<Sampler>,
- ) -> Result<
- PersistentDescriptorSetBuilder<(
- (R, PersistentDescriptorSetImg<T>),
- PersistentDescriptorSetSampler,
- )>,
- PersistentDescriptorSetError,
- >
+ /// - Panics if `layout` was created for push descriptors rather than descriptor sets.
+ /// - Panics if `variable_descriptor_count` is too large for the given `layout`.
+ pub fn new_variable<A>(
+ allocator: &A,
+ layout: Arc<DescriptorSetLayout>,
+ variable_descriptor_count: u32,
+ descriptor_writes: impl IntoIterator<Item = WriteDescriptorSet>,
+ ) -> Result<Arc<PersistentDescriptorSet<A::Alloc>>, DescriptorSetCreationError>
where
- T: ImageViewAbstract,
+ A: DescriptorSetAllocator + ?Sized,
{
- self.enter_array()?
- .add_sampled_image(image_view, sampler)?
- .leave_array()
- }
-
- /// Binds a sampler as the next descriptor.
- ///
- /// An error is returned if the sampler isn't compatible with the descriptor.
- ///
- /// # Panic
- ///
- /// Panics if the sampler doesn't have the same device as the descriptor set layout.
- ///
- #[inline]
- pub fn add_sampler(
- self,
- sampler: Arc<Sampler>,
- ) -> Result<
- PersistentDescriptorSetBuilder<(R, PersistentDescriptorSetSampler)>,
- PersistentDescriptorSetError,
- > {
- self.enter_array()?.add_sampler(sampler)?.leave_array()
- }
-}
-
-/// Same as `PersistentDescriptorSetBuilder`, but we're in an array.
-pub struct PersistentDescriptorSetBuilderArray<R> {
- // The original builder.
- builder: PersistentDescriptorSetBuilder<R>,
- // Current array elements.
- array_element: usize,
- // Description of the descriptor.
- desc: DescriptorDesc,
-}
-
-impl<R> PersistentDescriptorSetBuilderArray<R> {
- /// Leaves the array. Call this once you added all the elements of the array.
- pub fn leave_array(
- mut self,
- ) -> Result<PersistentDescriptorSetBuilder<R>, PersistentDescriptorSetError> {
- if self.desc.array_count > self.array_element as u32 {
- return Err(PersistentDescriptorSetError::MissingArrayElements {
- expected: self.desc.array_count,
- obtained: self.array_element as u32,
- });
- }
-
- debug_assert_eq!(self.desc.array_count, self.array_element as u32);
-
- self.builder.binding_id += 1;
- Ok(self.builder)
- }
-
- /// Binds a buffer as the next element in the array.
- ///
- /// An error is returned if the buffer isn't compatible with the descriptor.
- ///
- /// # Panic
- ///
- /// Panics if the buffer doesn't have the same device as the descriptor set layout.
- ///
- pub fn add_buffer<T>(
- mut self,
- buffer: T,
- ) -> Result<
- PersistentDescriptorSetBuilderArray<(R, PersistentDescriptorSetBuf<T>)>,
- PersistentDescriptorSetError,
- >
- where
- T: BufferAccess,
- {
- assert_eq!(
- self.builder.layout.device().internal_object(),
- buffer.inner().buffer.device().internal_object()
+ assert!(
+ !layout.push_descriptor(),
+ "the provided descriptor set layout is for push descriptors, and cannot be used to \
+ build a descriptor set object",
);
- if self.array_element as u32 >= self.desc.array_count {
- return Err(PersistentDescriptorSetError::ArrayOutOfBounds);
- }
-
- self.builder.writes.push(match self.desc.ty {
- DescriptorDescTy::Buffer(ref buffer_desc) => {
- // Note that the buffer content is not checked. This is technically not unsafe as
- // long as the data in the buffer has no invalid memory representation (ie. no
- // bool, no enum, no pointer, no str) and as long as the robust buffer access
- // feature is enabled.
- // TODO: this is not checked ^
-
- // TODO: eventually shouldn't be an assert ; for now robust_buffer_access is always
- // enabled so this assert should never fail in practice, but we put it anyway
- // in case we forget to adjust this code
- assert!(
- self.builder
- .layout
- .device()
- .enabled_features()
- .robust_buffer_access
- );
-
- if buffer_desc.storage {
- if !buffer.inner().buffer.usage().storage_buffer {
- return Err(PersistentDescriptorSetError::MissingBufferUsage(
- MissingBufferUsage::StorageBuffer,
- ));
- }
+ let max_count = layout.variable_descriptor_count();
- unsafe {
- DescriptorWrite::storage_buffer(
- self.builder.binding_id as u32,
- self.array_element as u32,
- &buffer,
- )
- }
- } else {
- if !buffer.inner().buffer.usage().uniform_buffer {
- return Err(PersistentDescriptorSetError::MissingBufferUsage(
- MissingBufferUsage::UniformBuffer,
- ));
- }
-
- if buffer_desc.dynamic.unwrap_or(false) {
- unsafe {
- DescriptorWrite::dynamic_uniform_buffer(
- self.builder.binding_id as u32,
- self.array_element as u32,
- &buffer,
- )
- }
- } else {
- unsafe {
- DescriptorWrite::uniform_buffer(
- self.builder.binding_id as u32,
- self.array_element as u32,
- &buffer,
- )
- }
- }
- }
- }
- ref d => {
- return Err(PersistentDescriptorSetError::WrongDescriptorTy { expected: d.ty() });
- }
- });
-
- Ok(PersistentDescriptorSetBuilderArray {
- builder: PersistentDescriptorSetBuilder {
- layout: self.builder.layout,
- binding_id: self.builder.binding_id,
- writes: self.builder.writes,
- resources: (
- self.builder.resources,
- PersistentDescriptorSetBuf {
- buffer,
- descriptor_num: self.builder.binding_id as u32,
- },
- ),
- },
- desc: self.desc,
- array_element: self.array_element + 1,
- })
- }
-
- /// Binds a buffer view as the next element in the array.
- ///
- /// An error is returned if the buffer isn't compatible with the descriptor.
- ///
- /// # Panic
- ///
- /// Panics if the buffer view doesn't have the same device as the descriptor set layout.
- ///
- pub fn add_buffer_view<T>(
- mut self,
- view: T,
- ) -> Result<
- PersistentDescriptorSetBuilderArray<(R, PersistentDescriptorSetBufView<T>)>,
- PersistentDescriptorSetError,
- >
- where
- T: BufferViewRef,
- {
- assert_eq!(
- self.builder.layout.device().internal_object(),
- view.view().device().internal_object()
+ assert!(
+ variable_descriptor_count <= max_count,
+ "the provided variable_descriptor_count ({}) is greater than the maximum number of \
+ variable count descriptors in the set ({})",
+ variable_descriptor_count,
+ max_count,
);
- if self.array_element as u32 >= self.desc.array_count {
- return Err(PersistentDescriptorSetError::ArrayOutOfBounds);
- }
-
- self.builder.writes.push(match self.desc.ty {
- DescriptorDescTy::TexelBuffer { storage, .. } => {
- if storage {
- // TODO: storage_texel_buffer_atomic
-
- if !view.view().storage_texel_buffer() {
- return Err(PersistentDescriptorSetError::MissingBufferUsage(
- MissingBufferUsage::StorageTexelBuffer,
- ));
- }
-
- DescriptorWrite::storage_texel_buffer(
- self.builder.binding_id as u32,
- self.array_element as u32,
- view.view(),
- )
- } else {
- if !view.view().uniform_texel_buffer() {
- return Err(PersistentDescriptorSetError::MissingBufferUsage(
- MissingBufferUsage::UniformTexelBuffer,
- ));
- }
-
- DescriptorWrite::uniform_texel_buffer(
- self.builder.binding_id as u32,
- self.array_element as u32,
- view.view(),
- )
- }
- }
- ref d => {
- return Err(PersistentDescriptorSetError::WrongDescriptorTy { expected: d.ty() });
- }
- });
-
- Ok(PersistentDescriptorSetBuilderArray {
- builder: PersistentDescriptorSetBuilder {
- layout: self.builder.layout,
- binding_id: self.builder.binding_id,
- writes: self.builder.writes,
- resources: (
- self.builder.resources,
- PersistentDescriptorSetBufView {
- view,
- descriptor_num: self.builder.binding_id as u32,
- },
- ),
- },
- desc: self.desc,
- array_element: self.array_element + 1,
- })
- }
-
- /// Binds an image view as the next element in the array.
- ///
- /// An error is returned if the image view isn't compatible with the descriptor.
- ///
- /// # Panic
- ///
- /// Panics if the image view doesn't have the same device as the descriptor set layout.
- ///
- pub fn add_image<T>(
- mut self,
- image_view: T,
- ) -> Result<
- PersistentDescriptorSetBuilderArray<(R, PersistentDescriptorSetImg<T>)>,
- PersistentDescriptorSetError,
- >
- where
- T: ImageViewAbstract,
- {
- assert_eq!(
- self.builder.layout.device().internal_object(),
- image_view.image().inner().image.device().internal_object()
- );
-
- if self.array_element as u32 >= self.desc.array_count {
- return Err(PersistentDescriptorSetError::ArrayOutOfBounds);
- }
-
- let desc = match self.builder.layout.descriptor(self.builder.binding_id) {
- Some(d) => d,
- None => return Err(PersistentDescriptorSetError::EmptyExpected),
- };
-
- self.builder.writes.push(match desc.ty {
- DescriptorDescTy::Image(ref desc) => {
- image_match_desc(&image_view, &desc)?;
-
- if desc.sampled {
- DescriptorWrite::sampled_image(
- self.builder.binding_id as u32,
- self.array_element as u32,
- &image_view,
- )
- } else {
- if !image_view.component_mapping().is_identity() {
- return Err(PersistentDescriptorSetError::NotIdentitySwizzled);
- }
-
- DescriptorWrite::storage_image(
- self.builder.binding_id as u32,
- self.array_element as u32,
- &image_view,
- )
- }
- }
- DescriptorDescTy::InputAttachment {
- multisampled,
- array_layers,
- } => {
- if !image_view.image().inner().image.usage().input_attachment {
- return Err(PersistentDescriptorSetError::MissingImageUsage(
- MissingImageUsage::InputAttachment,
- ));
- }
-
- if !image_view.component_mapping().is_identity() {
- return Err(PersistentDescriptorSetError::NotIdentitySwizzled);
- }
-
- if multisampled && image_view.image().samples() == SampleCount::Sample1 {
- return Err(PersistentDescriptorSetError::ExpectedMultisampled);
- } else if !multisampled && image_view.image().samples() != SampleCount::Sample1 {
- return Err(PersistentDescriptorSetError::UnexpectedMultisampled);
- }
-
- let image_layers = image_view.array_layers();
- let num_layers = image_layers.end - image_layers.start;
-
- match array_layers {
- DescriptorImageDescArray::NonArrayed => {
- if num_layers != 1 {
- return Err(PersistentDescriptorSetError::ArrayLayersMismatch {
- expected: 1,
- obtained: num_layers,
- });
- }
- }
- DescriptorImageDescArray::Arrayed {
- max_layers: Some(max_layers),
- } => {
- if num_layers > max_layers {
- // TODO: is this correct? "max" layers? or is it in fact min layers?
- return Err(PersistentDescriptorSetError::ArrayLayersMismatch {
- expected: max_layers,
- obtained: num_layers,
- });
- }
- }
- DescriptorImageDescArray::Arrayed { max_layers: None } => {}
- };
-
- DescriptorWrite::input_attachment(
- self.builder.binding_id as u32,
- self.array_element as u32,
- &image_view,
- )
- }
- ty => {
- return Err(PersistentDescriptorSetError::WrongDescriptorTy { expected: ty.ty() });
- }
- });
-
- Ok(PersistentDescriptorSetBuilderArray {
- builder: PersistentDescriptorSetBuilder {
- layout: self.builder.layout,
- binding_id: self.builder.binding_id,
- writes: self.builder.writes,
- resources: (
- self.builder.resources,
- PersistentDescriptorSetImg {
- image: image_view,
- descriptor_num: self.builder.binding_id as u32,
- },
- ),
- },
- desc: self.desc,
- array_element: self.array_element + 1,
- })
- }
-
- /// Binds an image view with a sampler as the next element in the array.
- ///
- /// An error is returned if the image view isn't compatible with the descriptor.
- ///
- /// # Panic
- ///
- /// Panics if the image or the sampler doesn't have the same device as the descriptor set layout.
- ///
- pub fn add_sampled_image<T>(
- mut self,
- image_view: T,
- sampler: Arc<Sampler>,
- ) -> Result<
- PersistentDescriptorSetBuilderArray<(
- (R, PersistentDescriptorSetImg<T>),
- PersistentDescriptorSetSampler,
- )>,
- PersistentDescriptorSetError,
- >
- where
- T: ImageViewAbstract,
- {
- assert_eq!(
- self.builder.layout.device().internal_object(),
- image_view.image().inner().image.device().internal_object()
- );
- assert_eq!(
- self.builder.layout.device().internal_object(),
- sampler.device().internal_object()
- );
-
- if self.array_element as u32 >= self.desc.array_count {
- return Err(PersistentDescriptorSetError::ArrayOutOfBounds);
- }
-
- let desc = match self.builder.layout.descriptor(self.builder.binding_id) {
- Some(d) => d,
- None => return Err(PersistentDescriptorSetError::EmptyExpected),
- };
-
- if !image_view.can_be_sampled(&sampler) {
- return Err(PersistentDescriptorSetError::IncompatibleImageViewSampler);
- }
-
- self.builder.writes.push(match desc.ty {
- DescriptorDescTy::CombinedImageSampler(ref desc) => {
- image_match_desc(&image_view, &desc)?;
- DescriptorWrite::combined_image_sampler(
- self.builder.binding_id as u32,
- self.array_element as u32,
- &sampler,
- &image_view,
- )
- }
- ty => {
- return Err(PersistentDescriptorSetError::WrongDescriptorTy { expected: ty.ty() });
- }
- });
-
- Ok(PersistentDescriptorSetBuilderArray {
- builder: PersistentDescriptorSetBuilder {
- layout: self.builder.layout,
- binding_id: self.builder.binding_id,
- writes: self.builder.writes,
- resources: (
- (
- self.builder.resources,
- PersistentDescriptorSetImg {
- image: image_view,
- descriptor_num: self.builder.binding_id as u32,
- },
- ),
- PersistentDescriptorSetSampler { sampler },
- ),
- },
- desc: self.desc,
- array_element: self.array_element + 1,
- })
- }
-
- /// Binds a sampler as the next element in the array.
- ///
- /// An error is returned if the sampler isn't compatible with the descriptor.
- ///
- /// # Panic
- ///
- /// Panics if the sampler doesn't have the same device as the descriptor set layout.
- ///
- pub fn add_sampler(
- mut self,
- sampler: Arc<Sampler>,
- ) -> Result<
- PersistentDescriptorSetBuilderArray<(R, PersistentDescriptorSetSampler)>,
- PersistentDescriptorSetError,
- > {
- assert_eq!(
- self.builder.layout.device().internal_object(),
- sampler.device().internal_object()
- );
-
- if self.array_element as u32 >= self.desc.array_count {
- return Err(PersistentDescriptorSetError::ArrayOutOfBounds);
- }
-
- let desc = match self.builder.layout.descriptor(self.builder.binding_id) {
- Some(d) => d,
- None => return Err(PersistentDescriptorSetError::EmptyExpected),
- };
-
- self.builder.writes.push(match desc.ty {
- DescriptorDescTy::Sampler => DescriptorWrite::sampler(
- self.builder.binding_id as u32,
- self.array_element as u32,
- &sampler,
- ),
- ty => {
- return Err(PersistentDescriptorSetError::WrongDescriptorTy { expected: ty.ty() });
- }
- });
-
- Ok(PersistentDescriptorSetBuilderArray {
- builder: PersistentDescriptorSetBuilder {
- layout: self.builder.layout,
- binding_id: self.builder.binding_id,
- writes: self.builder.writes,
- resources: (
- self.builder.resources,
- PersistentDescriptorSetSampler { sampler },
- ),
- },
- desc: self.desc,
- array_element: self.array_element + 1,
- })
- }
-}
-
-// Checks whether an image view matches the descriptor.
-fn image_match_desc<I>(
- image_view: &I,
- desc: &DescriptorImageDesc,
-) -> Result<(), PersistentDescriptorSetError>
-where
- I: ?Sized + ImageViewAbstract,
-{
- if desc.sampled && !image_view.image().inner().image.usage().sampled {
- return Err(PersistentDescriptorSetError::MissingImageUsage(
- MissingImageUsage::Sampled,
- ));
- } else if !desc.sampled && !image_view.image().inner().image.usage().storage {
- return Err(PersistentDescriptorSetError::MissingImageUsage(
- MissingImageUsage::Storage,
- ));
- }
-
- let image_view_ty = DescriptorImageDescDimensions::from_image_view_type(image_view.ty());
- if image_view_ty != desc.dimensions {
- return Err(PersistentDescriptorSetError::ImageViewTypeMismatch {
- expected: desc.dimensions,
- obtained: image_view_ty,
- });
- }
-
- if let Some(format) = desc.format {
- if image_view.format() != format {
- return Err(PersistentDescriptorSetError::ImageViewFormatMismatch {
- expected: format,
- obtained: image_view.format(),
- });
- }
- }
-
- if desc.multisampled && image_view.image().samples() == SampleCount::Sample1 {
- return Err(PersistentDescriptorSetError::ExpectedMultisampled);
- } else if !desc.multisampled && image_view.image().samples() != SampleCount::Sample1 {
- return Err(PersistentDescriptorSetError::UnexpectedMultisampled);
- }
-
- let image_layers = image_view.array_layers();
- let num_layers = image_layers.end - image_layers.start;
-
- match desc.array_layers {
- DescriptorImageDescArray::NonArrayed => {
- // TODO: when a non-array is expected, can we pass an image view that is in fact an
- // array with one layer? need to check
- let required_layers = if desc.dimensions == DescriptorImageDescDimensions::Cube {
- 6
- } else {
- 1
- };
-
- if num_layers != required_layers {
- return Err(PersistentDescriptorSetError::ArrayLayersMismatch {
- expected: 1,
- obtained: num_layers,
- });
- }
- }
- DescriptorImageDescArray::Arrayed {
- max_layers: Some(max_layers),
- } => {
- let required_layers = if desc.dimensions == DescriptorImageDescDimensions::Cube {
- max_layers * 6
- } else {
- max_layers
- };
-
- // TODO: is this correct? "max" layers? or is it in fact min layers?
- if num_layers > required_layers {
- return Err(PersistentDescriptorSetError::ArrayLayersMismatch {
- expected: max_layers,
- obtained: num_layers,
- });
- }
- }
- DescriptorImageDescArray::Arrayed { max_layers: None } => {}
- };
-
- Ok(())
-}
-
-pub unsafe trait PersistentDescriptorSetResources {
- fn num_buffers(&self) -> usize;
- fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)>;
- fn num_images(&self) -> usize;
- fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)>;
-}
-
-unsafe impl PersistentDescriptorSetResources for () {
- #[inline]
- fn num_buffers(&self) -> usize {
- 0
- }
-
- #[inline]
- fn buffer(&self, _: usize) -> Option<(&dyn BufferAccess, u32)> {
- None
- }
-
- #[inline]
- fn num_images(&self) -> usize {
- 0
- }
+ let alloc = allocator.allocate(&layout, variable_descriptor_count)?;
+ let inner = DescriptorSetInner::new(
+ alloc.inner().handle(),
+ layout,
+ variable_descriptor_count,
+ descriptor_writes,
+ )?;
- #[inline]
- fn image(&self, _: usize) -> Option<(&dyn ImageViewAbstract, u32)> {
- None
+ Ok(Arc::new(PersistentDescriptorSet { alloc, inner }))
}
}
-/// Internal object related to the `PersistentDescriptorSet` system.
-pub struct PersistentDescriptorSetBuf<B> {
- buffer: B,
- descriptor_num: u32,
-}
-
-unsafe impl<R, B> PersistentDescriptorSetResources for (R, PersistentDescriptorSetBuf<B>)
+unsafe impl<P> DescriptorSet for PersistentDescriptorSet<P>
where
- R: PersistentDescriptorSetResources,
- B: BufferAccess,
+ P: DescriptorSetAlloc,
{
- #[inline]
- fn num_buffers(&self) -> usize {
- self.0.num_buffers() + 1
+ fn inner(&self) -> &UnsafeDescriptorSet {
+ self.alloc.inner()
}
- #[inline]
- fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)> {
- if let Some(buf) = self.0.buffer(index) {
- Some(buf)
- } else if index == self.0.num_buffers() {
- Some((&self.1.buffer, self.1.descriptor_num))
- } else {
- None
- }
+ fn layout(&self) -> &Arc<DescriptorSetLayout> {
+ self.inner.layout()
}
- #[inline]
- fn num_images(&self) -> usize {
- self.0.num_images()
+ fn variable_descriptor_count(&self) -> u32 {
+ self.inner.variable_descriptor_count
}
- #[inline]
- fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)> {
- self.0.image(index)
+ fn resources(&self) -> &DescriptorSetResources {
+ self.inner.resources()
}
}
-/// Internal object related to the `PersistentDescriptorSet` system.
-pub struct PersistentDescriptorSetBufView<V>
+unsafe impl<P> DeviceOwned for PersistentDescriptorSet<P>
where
- V: BufferViewRef,
+ P: DescriptorSetAlloc,
{
- view: V,
- descriptor_num: u32,
-}
-
-unsafe impl<R, V> PersistentDescriptorSetResources for (R, PersistentDescriptorSetBufView<V>)
-where
- R: PersistentDescriptorSetResources,
- V: BufferViewRef,
-{
- #[inline]
- fn num_buffers(&self) -> usize {
- self.0.num_buffers() + 1
- }
-
- #[inline]
- fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)> {
- if let Some(buf) = self.0.buffer(index) {
- Some(buf)
- } else if index == self.0.num_buffers() {
- Some((self.1.view.view().buffer(), self.1.descriptor_num))
- } else {
- None
- }
- }
-
- #[inline]
- fn num_images(&self) -> usize {
- self.0.num_images()
- }
-
- #[inline]
- fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)> {
- self.0.image(index)
+ fn device(&self) -> &Arc<Device> {
+ self.inner.layout().device()
}
}
-/// Internal object related to the `PersistentDescriptorSet` system.
-pub struct PersistentDescriptorSetImg<I> {
- image: I,
- descriptor_num: u32,
-}
-
-unsafe impl<R, I> PersistentDescriptorSetResources for (R, PersistentDescriptorSetImg<I>)
+impl<P> PartialEq for PersistentDescriptorSet<P>
where
- R: PersistentDescriptorSetResources,
- I: ImageViewAbstract,
+ P: DescriptorSetAlloc,
{
- #[inline]
- fn num_buffers(&self) -> usize {
- self.0.num_buffers()
- }
-
- #[inline]
- fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)> {
- self.0.buffer(index)
- }
-
- #[inline]
- fn num_images(&self) -> usize {
- self.0.num_images() + 1
- }
-
- #[inline]
- fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)> {
- if let Some(img) = self.0.image(index) {
- Some(img)
- } else if index == self.0.num_images() {
- Some((&self.1.image, self.1.descriptor_num))
- } else {
- None
- }
+ fn eq(&self, other: &Self) -> bool {
+ self.inner() == other.inner()
}
}
-/// Internal object related to the `PersistentDescriptorSet` system.
-pub struct PersistentDescriptorSetSampler {
- sampler: Arc<Sampler>,
-}
+impl<P> Eq for PersistentDescriptorSet<P> where P: DescriptorSetAlloc {}
-unsafe impl<R> PersistentDescriptorSetResources for (R, PersistentDescriptorSetSampler)
+impl<P> Hash for PersistentDescriptorSet<P>
where
- R: PersistentDescriptorSetResources,
+ P: DescriptorSetAlloc,
{
- #[inline]
- fn num_buffers(&self) -> usize {
- self.0.num_buffers()
- }
-
- #[inline]
- fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, u32)> {
- self.0.buffer(index)
- }
-
- #[inline]
- fn num_images(&self) -> usize {
- self.0.num_images()
- }
-
- #[inline]
- fn image(&self, index: usize) -> Option<(&dyn ImageViewAbstract, u32)> {
- self.0.image(index)
- }
-}
-
-// Part of the PersistentDescriptorSetError for the case
-// of missing usage on a buffer.
-#[derive(Debug, Clone)]
-pub enum MissingBufferUsage {
- StorageBuffer,
- UniformBuffer,
- StorageTexelBuffer,
- UniformTexelBuffer,
-}
-
-// Part of the PersistentDescriptorSetError for the case
-// of missing usage on an image.
-#[derive(Debug, Clone)]
-pub enum MissingImageUsage {
- InputAttachment,
- Sampled,
- Storage,
-}
-
-/// Error related to the persistent descriptor set.
-#[derive(Debug, Clone)]
-pub enum PersistentDescriptorSetError {
- /// The number of array layers of an image doesn't match what was expected.
- ArrayLayersMismatch {
- /// Number of expected array layers for the image.
- expected: u32,
- /// Number of array layers of the image that was added.
- obtained: u32,
- },
-
- /// Tried to add too many elements to an array.
- ArrayOutOfBounds,
-
- /// Expected nothing.
- EmptyExpected,
-
- /// Expected a multisampled image, but got a single-sampled image.
- ExpectedMultisampled,
-
- /// The format of an image view doesn't match what was expected.
- ImageViewFormatMismatch {
- /// Expected format.
- expected: Format,
- /// Format of the image view that was passed.
- obtained: Format,
- },
-
- /// The type of an image view doesn't match what was expected.
- ImageViewTypeMismatch {
- /// Expected type.
- expected: DescriptorImageDescDimensions,
- /// Type of the image view that was passed.
- obtained: DescriptorImageDescDimensions,
- },
-
- /// The image view isn't compatible with the sampler.
- IncompatibleImageViewSampler,
-
- /// Didn't fill all the elements of an array before leaving.
- MissingArrayElements {
- /// Number of expected elements.
- expected: u32,
- /// Number of elements that were added.
- obtained: u32,
- },
-
- /// The buffer is missing the correct usage.
- MissingBufferUsage(MissingBufferUsage),
-
- /// The image is missing the correct usage.
- MissingImageUsage(MissingImageUsage),
-
- /// The image view has a component swizzle that is different from identity.
- NotIdentitySwizzled,
-
- /// Expected a single-sampled image, but got a multisampled image.
- UnexpectedMultisampled,
-
- /// Expected one type of resource but got another.
- WrongDescriptorTy {
- /// The expected descriptor type.
- expected: DescriptorType,
- },
-}
-
-impl error::Error for PersistentDescriptorSetError {}
-
-impl fmt::Display for PersistentDescriptorSetError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- PersistentDescriptorSetError::ArrayLayersMismatch { .. } => {
- "the number of array layers of an image doesn't match what was expected"
- }
- PersistentDescriptorSetError::ArrayOutOfBounds => {
- "tried to add too many elements to an array"
- }
- PersistentDescriptorSetError::EmptyExpected => {
- "expected an empty descriptor but got something"
- }
- PersistentDescriptorSetError::ExpectedMultisampled => {
- "expected a multisampled image, but got a single-sampled image"
- }
- PersistentDescriptorSetError::ImageViewFormatMismatch { .. } => {
- "the format of an image view doesn't match what was expected"
- }
- PersistentDescriptorSetError::ImageViewTypeMismatch { .. } => {
- "the type of an image view doesn't match what was expected"
- }
- PersistentDescriptorSetError::IncompatibleImageViewSampler => {
- "the image view isn't compatible with the sampler"
- }
- PersistentDescriptorSetError::MissingArrayElements { .. } => {
- "didn't fill all the elements of an array before leaving"
- }
- PersistentDescriptorSetError::MissingBufferUsage { .. } => {
- "the buffer is missing the correct usage"
- }
- PersistentDescriptorSetError::MissingImageUsage { .. } => {
- "the image is missing the correct usage"
- }
- PersistentDescriptorSetError::NotIdentitySwizzled => {
- "the image view's component mapping is not identity swizzled"
- }
- PersistentDescriptorSetError::UnexpectedMultisampled => {
- "expected a single-sampled image, but got a multisampled image"
- }
- PersistentDescriptorSetError::WrongDescriptorTy { .. } => {
- "expected one type of resource but got another"
- }
- }
- )
- }
-}
-
-/// Error when building a persistent descriptor set.
-#[derive(Debug, Clone)]
-pub enum PersistentDescriptorSetBuildError {
- /// Out of memory.
- OomError(OomError),
-
- /// Didn't fill all the descriptors before building.
- MissingDescriptors {
- /// Number of expected descriptors.
- expected: u32,
- /// Number of descriptors that were added.
- obtained: u32,
- },
-}
-
-impl error::Error for PersistentDescriptorSetBuildError {}
-
-impl From<OomError> for PersistentDescriptorSetBuildError {
- #[inline]
- fn from(err: OomError) -> PersistentDescriptorSetBuildError {
- PersistentDescriptorSetBuildError::OomError(err)
- }
-}
-
-impl fmt::Display for PersistentDescriptorSetBuildError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- PersistentDescriptorSetBuildError::MissingDescriptors { .. } => {
- "didn't fill all the descriptors before building"
- }
- PersistentDescriptorSetBuildError::OomError(_) => "not enough memory available",
- }
- )
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.inner().hash(state);
}
}
diff --git a/src/descriptor_set/pool.rs b/src/descriptor_set/pool.rs
new file mode 100644
index 0000000..708cb6e
--- /dev/null
+++ b/src/descriptor_set/pool.rs
@@ -0,0 +1,592 @@
+// Copyright (c) 2021 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use crate::{
+ descriptor_set::{
+ layout::{DescriptorSetLayout, DescriptorType},
+ sys::UnsafeDescriptorSet,
+ },
+ device::{Device, DeviceOwned},
+ macros::impl_id_counter,
+ OomError, Version, VulkanError, VulkanObject,
+};
+use ahash::HashMap;
+use smallvec::SmallVec;
+use std::{
+ cell::Cell,
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+ marker::PhantomData,
+ mem::MaybeUninit,
+ num::NonZeroU64,
+ ptr,
+ sync::Arc,
+};
+
+/// Pool that descriptors are allocated from.
+///
+/// A pool has a maximum number of descriptor sets and a maximum number of descriptors (one value
+/// per descriptor type) it can allocate.
+#[derive(Debug)]
+pub struct DescriptorPool {
+ handle: ash::vk::DescriptorPool,
+ device: Arc<Device>,
+ id: NonZeroU64,
+
+ max_sets: u32,
+ pool_sizes: HashMap<DescriptorType, u32>,
+ can_free_descriptor_sets: bool,
+ // Unimplement `Sync`, as Vulkan descriptor pools are not thread safe.
+ _marker: PhantomData<Cell<ash::vk::DescriptorPool>>,
+}
+
+impl DescriptorPool {
+ /// Creates a new `UnsafeDescriptorPool`.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `create_info.max_sets` is `0`.
+ /// - Panics if `create_info.pool_sizes` is empty.
+ /// - Panics if `create_info.pool_sizes` contains a descriptor type with a count of `0`.
+ pub fn new(
+ device: Arc<Device>,
+ create_info: DescriptorPoolCreateInfo,
+ ) -> Result<DescriptorPool, OomError> {
+ let DescriptorPoolCreateInfo {
+ max_sets,
+ pool_sizes,
+ can_free_descriptor_sets,
+ _ne: _,
+ } = create_info;
+
+ // VUID-VkDescriptorPoolCreateInfo-maxSets-00301
+ assert!(max_sets != 0);
+
+ // VUID-VkDescriptorPoolCreateInfo-poolSizeCount-arraylength
+ assert!(!pool_sizes.is_empty());
+
+ let handle = {
+ let pool_sizes: SmallVec<[_; 8]> = pool_sizes
+ .iter()
+ .map(|(&ty, &descriptor_count)| {
+ // VUID-VkDescriptorPoolSize-descriptorCount-00302
+ assert!(descriptor_count != 0);
+
+ ash::vk::DescriptorPoolSize {
+ ty: ty.into(),
+ descriptor_count,
+ }
+ })
+ .collect();
+
+ let mut flags = ash::vk::DescriptorPoolCreateFlags::empty();
+
+ if can_free_descriptor_sets {
+ flags |= ash::vk::DescriptorPoolCreateFlags::FREE_DESCRIPTOR_SET;
+ }
+
+ let create_info = ash::vk::DescriptorPoolCreateInfo {
+ flags,
+ max_sets,
+ pool_size_count: pool_sizes.len() as u32,
+ p_pool_sizes: pool_sizes.as_ptr(),
+ ..Default::default()
+ };
+
+ unsafe {
+ let fns = device.fns();
+ let mut output = MaybeUninit::uninit();
+ (fns.v1_0.create_descriptor_pool)(
+ device.handle(),
+ &create_info,
+ ptr::null(),
+ output.as_mut_ptr(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+ output.assume_init()
+ }
+ };
+
+ Ok(DescriptorPool {
+ handle,
+ device,
+ id: Self::next_id(),
+ max_sets,
+ pool_sizes,
+ can_free_descriptor_sets,
+ _marker: PhantomData,
+ })
+ }
+
+ /// Creates a new `UnsafeDescriptorPool` from a raw object handle.
+ ///
+ /// # Safety
+ ///
+ /// - `handle` must be a valid Vulkan object handle created from `device`.
+ /// - `create_info` must match the info used to create the object.
+ #[inline]
+ pub unsafe fn from_handle(
+ device: Arc<Device>,
+ handle: ash::vk::DescriptorPool,
+ create_info: DescriptorPoolCreateInfo,
+ ) -> DescriptorPool {
+ let DescriptorPoolCreateInfo {
+ max_sets,
+ pool_sizes,
+ can_free_descriptor_sets,
+ _ne: _,
+ } = create_info;
+
+ DescriptorPool {
+ handle,
+ device,
+ id: Self::next_id(),
+ max_sets,
+ pool_sizes,
+ can_free_descriptor_sets,
+ _marker: PhantomData,
+ }
+ }
+
+ /// Returns the maximum number of sets that can be allocated from the pool.
+ #[inline]
+ pub fn max_sets(&self) -> u32 {
+ self.max_sets
+ }
+
+ /// Returns the number of descriptors of each type that the pool was created with.
+ #[inline]
+ pub fn pool_sizes(&self) -> &HashMap<DescriptorType, u32> {
+ &self.pool_sizes
+ }
+
+ /// Returns whether the descriptor sets allocated from the pool can be individually freed.
+ #[inline]
+ pub fn can_free_descriptor_sets(&self) -> bool {
+ self.can_free_descriptor_sets
+ }
+
+ /// Allocates descriptor sets from the pool, one for each element in `create_info`.
+ /// Returns an iterator to the allocated sets, or an error.
+ ///
+ /// The `FragmentedPool` errors often can't be prevented. If the function returns this error,
+ /// you should just create a new pool.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if one of the layouts wasn't created with the same device as the pool.
+ ///
+ /// # Safety
+ ///
+ /// See also the `new` function.
+ ///
+ /// - The total descriptors of the layouts must fit in the pool.
+ /// - The total number of descriptor sets allocated from the pool must not overflow the pool.
+ /// - You must ensure that the allocated descriptor sets are no longer in use when the pool
+ /// is destroyed, as destroying the pool is equivalent to freeing all the sets.
+ pub unsafe fn allocate_descriptor_sets<'a>(
+ &self,
+ allocate_info: impl IntoIterator<Item = DescriptorSetAllocateInfo<'a>>,
+ ) -> Result<impl ExactSizeIterator<Item = UnsafeDescriptorSet>, DescriptorPoolAllocError> {
+ let (layouts, variable_descriptor_counts): (SmallVec<[_; 1]>, SmallVec<[_; 1]>) =
+ allocate_info
+ .into_iter()
+ .map(|info| {
+ assert_eq!(self.device.handle(), info.layout.device().handle(),);
+ debug_assert!(!info.layout.push_descriptor());
+ debug_assert!(
+ info.variable_descriptor_count <= info.layout.variable_descriptor_count()
+ );
+
+ (info.layout.handle(), info.variable_descriptor_count)
+ })
+ .unzip();
+
+ let output = if layouts.is_empty() {
+ vec![]
+ } else {
+ let variable_desc_count_alloc_info = if (self.device.api_version() >= Version::V1_2
+ || self.device.enabled_extensions().ext_descriptor_indexing)
+ && variable_descriptor_counts.iter().any(|c| *c != 0)
+ {
+ Some(ash::vk::DescriptorSetVariableDescriptorCountAllocateInfo {
+ descriptor_set_count: layouts.len() as u32,
+ p_descriptor_counts: variable_descriptor_counts.as_ptr(),
+ ..Default::default()
+ })
+ } else {
+ None
+ };
+
+ let infos = ash::vk::DescriptorSetAllocateInfo {
+ descriptor_pool: self.handle,
+ descriptor_set_count: layouts.len() as u32,
+ p_set_layouts: layouts.as_ptr(),
+ p_next: if let Some(next) = variable_desc_count_alloc_info.as_ref() {
+ next as *const _ as *const _
+ } else {
+ ptr::null()
+ },
+ ..Default::default()
+ };
+
+ let mut output = Vec::with_capacity(layouts.len());
+
+ let fns = self.device.fns();
+ let ret = (fns.v1_0.allocate_descriptor_sets)(
+ self.device.handle(),
+ &infos,
+ output.as_mut_ptr(),
+ );
+
+ // According to the specs, because `VK_ERROR_FRAGMENTED_POOL` was added after version
+ // 1.0 of Vulkan, any negative return value except out-of-memory errors must be
+ // considered as a fragmented pool error.
+ match ret {
+ ash::vk::Result::ERROR_OUT_OF_HOST_MEMORY => {
+ return Err(DescriptorPoolAllocError::OutOfHostMemory);
+ }
+ ash::vk::Result::ERROR_OUT_OF_DEVICE_MEMORY => {
+ return Err(DescriptorPoolAllocError::OutOfDeviceMemory);
+ }
+ ash::vk::Result::ERROR_OUT_OF_POOL_MEMORY_KHR => {
+ return Err(DescriptorPoolAllocError::OutOfPoolMemory);
+ }
+ c if c.as_raw() < 0 => {
+ return Err(DescriptorPoolAllocError::FragmentedPool);
+ }
+ _ => (),
+ };
+
+ output.set_len(layouts.len());
+ output
+ };
+
+ Ok(output.into_iter().map(UnsafeDescriptorSet::new))
+ }
+
+ /// Frees some descriptor sets.
+ ///
+ /// Note that it is not mandatory to free sets. Destroying or resetting the pool destroys all
+ /// the descriptor sets.
+ ///
+ /// # Safety
+ ///
+ /// - The pool must have been created with `free_descriptor_set_bit` set to `true`.
+ /// - The descriptor sets must have been allocated from the pool.
+ /// - The descriptor sets must not be free'd twice.
+ /// - The descriptor sets must not be in use by the GPU.
+ pub unsafe fn free_descriptor_sets(
+ &self,
+ descriptor_sets: impl IntoIterator<Item = UnsafeDescriptorSet>,
+ ) -> Result<(), OomError> {
+ let sets: SmallVec<[_; 8]> = descriptor_sets.into_iter().map(|s| s.handle()).collect();
+ if !sets.is_empty() {
+ let fns = self.device.fns();
+ (fns.v1_0.free_descriptor_sets)(
+ self.device.handle(),
+ self.handle,
+ sets.len() as u32,
+ sets.as_ptr(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+ }
+
+ Ok(())
+ }
+
+ /// Resets the pool.
+ ///
+ /// This destroys all descriptor sets and empties the pool.
+ #[inline]
+ pub unsafe fn reset(&self) -> Result<(), OomError> {
+ let fns = self.device.fns();
+ (fns.v1_0.reset_descriptor_pool)(
+ self.device.handle(),
+ self.handle,
+ ash::vk::DescriptorPoolResetFlags::empty(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+
+ Ok(())
+ }
+}
+
+impl Drop for DescriptorPool {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ let fns = self.device.fns();
+ (fns.v1_0.destroy_descriptor_pool)(self.device.handle(), self.handle, ptr::null());
+ }
+ }
+}
+
+unsafe impl VulkanObject for DescriptorPool {
+ type Handle = ash::vk::DescriptorPool;
+
+ #[inline]
+ fn handle(&self) -> Self::Handle {
+ self.handle
+ }
+}
+
+unsafe impl DeviceOwned for DescriptorPool {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+}
+
+impl_id_counter!(DescriptorPool);
+
+/// Parameters to create a new `UnsafeDescriptorPool`.
+#[derive(Clone, Debug)]
+pub struct DescriptorPoolCreateInfo {
+ /// The maximum number of descriptor sets that can be allocated from the pool.
+ ///
+ /// The default value is `0`, which must be overridden.
+ pub max_sets: u32,
+
+ /// The number of descriptors of each type to allocate for the pool.
+ ///
+ /// The default value is empty, which must be overridden.
+ pub pool_sizes: HashMap<DescriptorType, u32>,
+
+ /// Whether individual descriptor sets can be freed from the pool. Otherwise you must reset or
+ /// destroy the whole pool at once.
+ ///
+ /// The default value is `false`.
+ pub can_free_descriptor_sets: bool,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for DescriptorPoolCreateInfo {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ max_sets: 0,
+ pool_sizes: HashMap::default(),
+ can_free_descriptor_sets: false,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// Parameters to allocate a new `UnsafeDescriptorSet` from an `UnsafeDescriptorPool`.
+#[derive(Clone, Debug)]
+pub struct DescriptorSetAllocateInfo<'a> {
+ /// The descriptor set layout to create the set for.
+ pub layout: &'a DescriptorSetLayout,
+
+ /// For layouts with a variable-count binding, the number of descriptors to allocate for that
+ /// binding. This should be 0 for layouts that don't have a variable-count binding.
+ pub variable_descriptor_count: u32,
+}
+
+/// Error that can be returned when creating a device.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum DescriptorPoolAllocError {
+ /// There is no memory available on the host (ie. the CPU, RAM, etc.).
+ OutOfHostMemory,
+ /// There is no memory available on the device (ie. video memory).
+ OutOfDeviceMemory,
+ /// Allocation has failed because the pool is too fragmented.
+ FragmentedPool,
+ /// There is no more space available in the descriptor pool.
+ OutOfPoolMemory,
+}
+
+impl Error for DescriptorPoolAllocError {}
+
+impl Display for DescriptorPoolAllocError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ write!(
+ f,
+ "{}",
+ match self {
+ DescriptorPoolAllocError::OutOfHostMemory => "no memory available on the host",
+ DescriptorPoolAllocError::OutOfDeviceMemory => {
+ "no memory available on the graphical device"
+ }
+ DescriptorPoolAllocError::FragmentedPool => {
+ "allocation has failed because the pool is too fragmented"
+ }
+ DescriptorPoolAllocError::OutOfPoolMemory => {
+ "there is no more space available in the descriptor pool"
+ }
+ }
+ )
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::{DescriptorPool, DescriptorPoolCreateInfo};
+ use crate::{
+ descriptor_set::{
+ layout::{
+ DescriptorSetLayout, DescriptorSetLayoutBinding, DescriptorSetLayoutCreateInfo,
+ DescriptorType,
+ },
+ pool::DescriptorSetAllocateInfo,
+ },
+ shader::ShaderStages,
+ };
+
+ #[test]
+ fn pool_create() {
+ let (device, _) = gfx_dev_and_queue!();
+
+ let _ = DescriptorPool::new(
+ device,
+ DescriptorPoolCreateInfo {
+ max_sets: 10,
+ pool_sizes: [(DescriptorType::UniformBuffer, 1)].into_iter().collect(),
+ ..Default::default()
+ },
+ )
+ .unwrap();
+ }
+
+ #[test]
+ fn zero_max_set() {
+ let (device, _) = gfx_dev_and_queue!();
+
+ assert_should_panic!({
+ let _ = DescriptorPool::new(
+ device,
+ DescriptorPoolCreateInfo {
+ max_sets: 0,
+ pool_sizes: [(DescriptorType::UniformBuffer, 1)].into_iter().collect(),
+ ..Default::default()
+ },
+ );
+ });
+ }
+
+ #[test]
+ fn zero_descriptors() {
+ let (device, _) = gfx_dev_and_queue!();
+
+ assert_should_panic!({
+ let _ = DescriptorPool::new(
+ device,
+ DescriptorPoolCreateInfo {
+ max_sets: 10,
+ ..Default::default()
+ },
+ );
+ });
+ }
+
+ #[test]
+ fn basic_alloc() {
+ let (device, _) = gfx_dev_and_queue!();
+
+ let set_layout = DescriptorSetLayout::new(
+ device.clone(),
+ DescriptorSetLayoutCreateInfo {
+ bindings: [(
+ 0,
+ DescriptorSetLayoutBinding {
+ stages: ShaderStages::all_graphics(),
+ ..DescriptorSetLayoutBinding::descriptor_type(DescriptorType::UniformBuffer)
+ },
+ )]
+ .into(),
+ ..Default::default()
+ },
+ )
+ .unwrap();
+
+ let pool = DescriptorPool::new(
+ device,
+ DescriptorPoolCreateInfo {
+ max_sets: 10,
+ pool_sizes: [(DescriptorType::UniformBuffer, 10)].into_iter().collect(),
+ ..Default::default()
+ },
+ )
+ .unwrap();
+ unsafe {
+ let sets = pool
+ .allocate_descriptor_sets([DescriptorSetAllocateInfo {
+ layout: set_layout.as_ref(),
+ variable_descriptor_count: 0,
+ }])
+ .unwrap();
+ assert_eq!(sets.count(), 1);
+ }
+ }
+
+ #[test]
+ fn alloc_diff_device() {
+ let (device1, _) = gfx_dev_and_queue!();
+ let (device2, _) = gfx_dev_and_queue!();
+
+ let set_layout = DescriptorSetLayout::new(
+ device1,
+ DescriptorSetLayoutCreateInfo {
+ bindings: [(
+ 0,
+ DescriptorSetLayoutBinding {
+ stages: ShaderStages::all_graphics(),
+ ..DescriptorSetLayoutBinding::descriptor_type(DescriptorType::UniformBuffer)
+ },
+ )]
+ .into(),
+ ..Default::default()
+ },
+ )
+ .unwrap();
+
+ assert_should_panic!({
+ let pool = DescriptorPool::new(
+ device2,
+ DescriptorPoolCreateInfo {
+ max_sets: 10,
+ pool_sizes: [(DescriptorType::UniformBuffer, 10)].into_iter().collect(),
+ ..Default::default()
+ },
+ )
+ .unwrap();
+
+ unsafe {
+ let _ = pool.allocate_descriptor_sets([DescriptorSetAllocateInfo {
+ layout: set_layout.as_ref(),
+ variable_descriptor_count: 0,
+ }]);
+ }
+ });
+ }
+
+ #[test]
+ fn alloc_zero() {
+ let (device, _) = gfx_dev_and_queue!();
+
+ let pool = DescriptorPool::new(
+ device,
+ DescriptorPoolCreateInfo {
+ max_sets: 1,
+ pool_sizes: [(DescriptorType::UniformBuffer, 1)].into_iter().collect(),
+ ..Default::default()
+ },
+ )
+ .unwrap();
+ unsafe {
+ let sets = pool.allocate_descriptor_sets([]).unwrap();
+ assert_eq!(sets.count(), 0);
+ }
+ }
+}
diff --git a/src/descriptor_set/pool/mod.rs b/src/descriptor_set/pool/mod.rs
deleted file mode 100644
index e29209c..0000000
--- a/src/descriptor_set/pool/mod.rs
+++ /dev/null
@@ -1,220 +0,0 @@
-// Copyright (c) 2021 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-//! A pool from which descriptor sets can be allocated.
-
-pub use self::standard::StdDescriptorPool;
-pub use self::sys::DescriptorPoolAllocError;
-pub use self::sys::UnsafeDescriptorPool;
-pub use self::sys::UnsafeDescriptorPoolAllocIter;
-use crate::descriptor_set::layout::DescriptorSetLayout;
-use crate::descriptor_set::layout::DescriptorType;
-use crate::descriptor_set::UnsafeDescriptorSet;
-use crate::device::DeviceOwned;
-use crate::OomError;
-use std::cmp;
-use std::ops;
-
-pub mod standard;
-mod sys;
-
-/// A pool from which descriptor sets can be allocated.
-///
-/// Since the destructor of `Alloc` must free the descriptor set, this trait is usually implemented
-/// on `Arc<T>` or `&'a T` and not `T` directly, so that the `Alloc` object can hold the pool.
-pub unsafe trait DescriptorPool: DeviceOwned {
- /// Object that represented an allocated descriptor set.
- ///
- /// The destructor of this object should free the descriptor set.
- type Alloc: DescriptorPoolAlloc;
-
- /// Allocates a descriptor set.
- fn alloc(&mut self, layout: &DescriptorSetLayout) -> Result<Self::Alloc, OomError>;
-}
-
-/// An allocated descriptor set.
-pub trait DescriptorPoolAlloc {
- /// Returns the inner unsafe descriptor set object.
- fn inner(&self) -> &UnsafeDescriptorSet;
-
- /// Returns the inner unsafe descriptor set object.
- fn inner_mut(&mut self) -> &mut UnsafeDescriptorSet;
-}
-
-macro_rules! descriptors_count {
- ($($name:ident,)+) => (
- /// Number of available descriptors slots in a pool.
- ///
- /// # Example
- ///
- /// ```
- /// use vulkano::descriptor_set::pool::DescriptorsCount;
- ///
- /// let _descriptors = DescriptorsCount {
- /// uniform_buffer: 10,
- /// input_attachment: 5,
- /// .. DescriptorsCount::zero()
- /// };
- /// ```
- ///
- #[derive(Debug, Copy, Clone)]
- pub struct DescriptorsCount {
- $(
- pub $name: u32,
- )+
- }
-
- impl DescriptorsCount {
- /// Returns a `DescriptorsCount` object with all fields set to 0.
- #[inline]
- pub fn zero() -> DescriptorsCount {
- DescriptorsCount {
- $(
- $name: 0,
- )+
- }
- }
- /// Adds one descriptor of the given type to the count.
- #[inline]
- pub fn add_one(&mut self, ty: DescriptorType) {
- self.add_num(ty, 1);
- }
-
- /// Adds `num` descriptors of the given type to the count.
- #[inline]
- pub fn add_num(&mut self, ty: DescriptorType, num: u32) {
- match ty {
- DescriptorType::Sampler => self.sampler += num,
- DescriptorType::CombinedImageSampler => self.combined_image_sampler += num,
- DescriptorType::SampledImage => self.sampled_image += num,
- DescriptorType::StorageImage => self.storage_image += num,
- DescriptorType::UniformTexelBuffer => self.uniform_texel_buffer += num,
- DescriptorType::StorageTexelBuffer => self.storage_texel_buffer += num,
- DescriptorType::UniformBuffer => self.uniform_buffer += num,
- DescriptorType::StorageBuffer => self.storage_buffer += num,
- DescriptorType::UniformBufferDynamic => self.uniform_buffer_dynamic += num,
- DescriptorType::StorageBufferDynamic => self.storage_buffer_dynamic += num,
- DescriptorType::InputAttachment => self.input_attachment += num,
- };
- }
- }
-
- impl cmp::PartialEq for DescriptorsCount {
- #[inline]
- fn eq(&self, other: &DescriptorsCount) -> bool {
- self.partial_cmp(other) == Some(cmp::Ordering::Equal)
- }
- }
-
- impl cmp::Eq for DescriptorsCount {
- }
-
- impl cmp::PartialOrd for DescriptorsCount {
- fn partial_cmp(&self, other: &DescriptorsCount) -> Option<cmp::Ordering> {
- if $(self.$name > other.$name)&&+ {
- Some(cmp::Ordering::Greater)
- } else if $(self.$name < other.$name)&&+ {
- Some(cmp::Ordering::Less)
- } else if $(self.$name == other.$name)&&+ {
- Some(cmp::Ordering::Equal)
- } else {
- None
- }
- }
-
- fn le(&self, other: &DescriptorsCount) -> bool {
- $(self.$name <= other.$name)&&+
- }
-
- fn ge(&self, other: &DescriptorsCount) -> bool {
- $(self.$name >= other.$name)&&+
- }
- }
-
- impl ops::Sub for DescriptorsCount {
- type Output = DescriptorsCount;
-
- #[inline]
- fn sub(self, rhs: DescriptorsCount) -> DescriptorsCount {
- DescriptorsCount {
- $(
- $name: self.$name - rhs.$name,
- )+
- }
- }
- }
-
- impl ops::SubAssign for DescriptorsCount {
- #[inline]
- fn sub_assign(&mut self, rhs: DescriptorsCount) {
- $(
- self.$name -= rhs.$name;
- )+
- }
- }
-
- impl ops::Add for DescriptorsCount {
- type Output = DescriptorsCount;
-
- #[inline]
- fn add(self, rhs: DescriptorsCount) -> DescriptorsCount {
- DescriptorsCount {
- $(
- $name: self.$name + rhs.$name,
- )+
- }
- }
- }
-
- impl ops::AddAssign for DescriptorsCount {
- #[inline]
- fn add_assign(&mut self, rhs: DescriptorsCount) {
- $(
- self.$name += rhs.$name;
- )+
- }
- }
-
- impl ops::Mul<u32> for DescriptorsCount {
- type Output = DescriptorsCount;
-
- #[inline]
- fn mul(self, rhs: u32) -> DescriptorsCount {
- DescriptorsCount {
- $(
- $name: self.$name * rhs,
- )+
- }
- }
- }
-
- impl ops::MulAssign<u32> for DescriptorsCount {
- #[inline]
- fn mul_assign(&mut self, rhs: u32) {
- $(
- self.$name *= rhs;
- )+
- }
- }
- );
-}
-
-descriptors_count! {
- uniform_buffer,
- storage_buffer,
- uniform_buffer_dynamic,
- storage_buffer_dynamic,
- uniform_texel_buffer,
- storage_texel_buffer,
- sampled_image,
- storage_image,
- sampler,
- combined_image_sampler,
- input_attachment,
-}
diff --git a/src/descriptor_set/pool/standard.rs b/src/descriptor_set/pool/standard.rs
deleted file mode 100644
index 287cac1..0000000
--- a/src/descriptor_set/pool/standard.rs
+++ /dev/null
@@ -1,213 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::descriptor_set::layout::DescriptorSetLayout;
-use crate::descriptor_set::pool::DescriptorPool;
-use crate::descriptor_set::pool::DescriptorPoolAlloc;
-use crate::descriptor_set::pool::DescriptorPoolAllocError;
-use crate::descriptor_set::pool::DescriptorsCount;
-use crate::descriptor_set::pool::UnsafeDescriptorPool;
-use crate::descriptor_set::UnsafeDescriptorSet;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::OomError;
-use std::sync::Arc;
-use std::sync::Mutex;
-
-/// Standard implementation of a descriptor pool.
-///
-/// It is guaranteed that the `Arc<StdDescriptorPool>` is kept alive by its allocations. This is
-/// desirable so that we can store a `Weak<StdDescriptorPool>`.
-///
-/// Whenever a set is allocated, this implementation will try to find a pool that has some space
-/// for it. If there is one, allocate from it. If there is none, create a new pool whose capacity
-/// is 40 sets and 40 times the requested descriptors. This number is arbitrary.
-pub struct StdDescriptorPool {
- device: Arc<Device>,
- pools: Mutex<Vec<Arc<Mutex<Pool>>>>,
-}
-
-struct Pool {
- pool: UnsafeDescriptorPool,
- remaining_capacity: DescriptorsCount,
- remaining_sets_count: u32,
-}
-
-impl StdDescriptorPool {
- /// Builds a new `StdDescriptorPool`.
- pub fn new(device: Arc<Device>) -> StdDescriptorPool {
- StdDescriptorPool {
- device: device,
- pools: Mutex::new(Vec::new()),
- }
- }
-}
-
-/// A descriptor set allocated from a `StdDescriptorPool`.
-pub struct StdDescriptorPoolAlloc {
- pool: Arc<Mutex<Pool>>,
- // The set. Inside an option so that we can extract it in the destructor.
- set: Option<UnsafeDescriptorSet>,
- // We need to keep track of this count in order to add it back to the capacity when freeing.
- descriptors: DescriptorsCount,
- // We keep the parent of the pool alive, otherwise it would be destroyed.
- pool_parent: Arc<StdDescriptorPool>,
-}
-
-unsafe impl DescriptorPool for Arc<StdDescriptorPool> {
- type Alloc = StdDescriptorPoolAlloc;
-
- // TODO: eventually use a lock-free algorithm?
- fn alloc(&mut self, layout: &DescriptorSetLayout) -> Result<StdDescriptorPoolAlloc, OomError> {
- let mut pools = self.pools.lock().unwrap();
-
- // Try find an existing pool with some free space.
- for pool_arc in pools.iter_mut() {
- let mut pool = pool_arc.lock().unwrap();
-
- if pool.remaining_sets_count == 0 {
- continue;
- }
-
- if !(pool.remaining_capacity >= *layout.descriptors_count()) {
- continue;
- }
-
- // Note that we decrease these values *before* trying to allocate from the pool.
- // If allocating from the pool results in an error, we just ignore it. In order to
- // avoid trying the same failing pool every time, we "pollute" it by reducing the
- // available space.
- pool.remaining_sets_count -= 1;
- pool.remaining_capacity -= *layout.descriptors_count();
-
- let alloc = unsafe {
- match pool.pool.alloc(Some(layout)) {
- Ok(mut sets) => sets.next().unwrap(),
- // An error can happen if we're out of memory, or if the pool is fragmented.
- // We handle these errors by just ignoring this pool and trying the next ones.
- Err(_) => continue,
- }
- };
-
- return Ok(StdDescriptorPoolAlloc {
- pool: pool_arc.clone(),
- set: Some(alloc),
- descriptors: *layout.descriptors_count(),
- pool_parent: self.clone(),
- });
- }
-
- // No existing pool can be used. Create a new one.
- // We use an arbitrary number of 40 sets and 40 times the requested descriptors.
- let count = layout.descriptors_count().clone() * 40;
- // Failure to allocate a new pool results in an error for the whole function because
- // there's no way we can recover from that.
- let mut new_pool = UnsafeDescriptorPool::new(self.device.clone(), &count, 40, true)?;
-
- let alloc = unsafe {
- match new_pool.alloc(Some(layout)) {
- Ok(mut sets) => sets.next().unwrap(),
- Err(DescriptorPoolAllocError::OutOfHostMemory) => {
- return Err(OomError::OutOfHostMemory);
- }
- Err(DescriptorPoolAllocError::OutOfDeviceMemory) => {
- return Err(OomError::OutOfDeviceMemory);
- }
- // A fragmented pool error can't happen at the first ever allocation.
- Err(DescriptorPoolAllocError::FragmentedPool) => unreachable!(),
- // Out of pool memory cannot happen at the first ever allocation.
- Err(DescriptorPoolAllocError::OutOfPoolMemory) => unreachable!(),
- }
- };
-
- let pool_obj = Arc::new(Mutex::new(Pool {
- pool: new_pool,
- remaining_capacity: count - *layout.descriptors_count(),
- remaining_sets_count: 40 - 1,
- }));
-
- pools.push(pool_obj.clone());
-
- Ok(StdDescriptorPoolAlloc {
- pool: pool_obj,
- set: Some(alloc),
- descriptors: *layout.descriptors_count(),
- pool_parent: self.clone(),
- })
- }
-}
-
-unsafe impl DeviceOwned for StdDescriptorPool {
- #[inline]
- fn device(&self) -> &Arc<Device> {
- &self.device
- }
-}
-
-impl DescriptorPoolAlloc for StdDescriptorPoolAlloc {
- #[inline]
- fn inner(&self) -> &UnsafeDescriptorSet {
- self.set.as_ref().unwrap()
- }
-
- #[inline]
- fn inner_mut(&mut self) -> &mut UnsafeDescriptorSet {
- self.set.as_mut().unwrap()
- }
-}
-
-impl Drop for StdDescriptorPoolAlloc {
- // This is the destructor of a single allocation (not of the whole pool).
- fn drop(&mut self) {
- unsafe {
- let mut pool = self.pool.lock().unwrap();
- pool.pool.free(self.set.take()).unwrap();
- // Add back the capacity only after freeing, in case of a panic during the free.
- pool.remaining_sets_count += 1;
- pool.remaining_capacity += self.descriptors;
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use crate::descriptor_set::layout::DescriptorDesc;
- use crate::descriptor_set::layout::DescriptorDescTy;
- use crate::descriptor_set::layout::DescriptorSetDesc;
- use crate::descriptor_set::layout::DescriptorSetLayout;
- use crate::descriptor_set::pool::DescriptorPool;
- use crate::descriptor_set::pool::StdDescriptorPool;
- use crate::pipeline::shader::ShaderStages;
- use std::iter;
- use std::sync::Arc;
-
- #[test]
- fn desc_pool_kept_alive() {
- // Test that the `StdDescriptorPool` is kept alive by its allocations.
- let (device, _) = gfx_dev_and_queue!();
-
- let desc = DescriptorDesc {
- ty: DescriptorDescTy::Sampler,
- array_count: 1,
- stages: ShaderStages::all(),
- readonly: false,
- };
- let layout = DescriptorSetLayout::new(
- device.clone(),
- DescriptorSetDesc::new(iter::once(Some(desc))),
- )
- .unwrap();
-
- let mut pool = Arc::new(StdDescriptorPool::new(device));
- let pool_weak = Arc::downgrade(&pool);
- let alloc = pool.alloc(&layout);
- drop(pool);
- assert!(pool_weak.upgrade().is_some());
- }
-}
diff --git a/src/descriptor_set/pool/sys.rs b/src/descriptor_set/pool/sys.rs
deleted file mode 100644
index 134ddc7..0000000
--- a/src/descriptor_set/pool/sys.rs
+++ /dev/null
@@ -1,503 +0,0 @@
-// Copyright (c) 2021 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::check_errors;
-use crate::descriptor_set::layout::DescriptorSetLayout;
-use crate::descriptor_set::pool::DescriptorsCount;
-use crate::descriptor_set::UnsafeDescriptorSet;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::OomError;
-use crate::VulkanObject;
-use smallvec::SmallVec;
-use std::error;
-use std::fmt;
-use std::mem::MaybeUninit;
-use std::ptr;
-use std::sync::Arc;
-use std::vec::IntoIter as VecIntoIter;
-
-/// Pool from which descriptor sets are allocated from.
-///
-/// A pool has a maximum number of descriptor sets and a maximum number of descriptors (one value
-/// per descriptor type) it can allocate.
-pub struct UnsafeDescriptorPool {
- pool: ash::vk::DescriptorPool,
- device: Arc<Device>,
-}
-
-impl UnsafeDescriptorPool {
- /// Initializes a new pool.
- ///
- /// Initializes a pool whose capacity is given by `count` and `max_sets`. At most `count`
- /// descriptors or `max_sets` descriptor sets can be allocated at once with this pool.
- ///
- /// If `free_descriptor_set_bit` is `true`, then individual descriptor sets can be free'd from
- /// the pool. Otherwise you must reset or destroy the whole pool at once.
- ///
- /// # Panic
- ///
- /// - Panics if all the descriptors count are 0.
- /// - Panics if `max_sets` is 0.
- ///
- pub fn new(
- device: Arc<Device>,
- count: &DescriptorsCount,
- max_sets: u32,
- free_descriptor_set_bit: bool,
- ) -> Result<UnsafeDescriptorPool, OomError> {
- let fns = device.fns();
-
- assert_ne!(max_sets, 0, "The maximum number of sets can't be 0");
-
- let mut pool_sizes: SmallVec<[_; 10]> = SmallVec::new();
-
- macro_rules! elem {
- ($field:ident, $ty:expr) => {
- if count.$field >= 1 {
- pool_sizes.push(ash::vk::DescriptorPoolSize {
- ty: $ty,
- descriptor_count: count.$field,
- });
- }
- };
- }
-
- elem!(uniform_buffer, ash::vk::DescriptorType::UNIFORM_BUFFER);
- elem!(storage_buffer, ash::vk::DescriptorType::STORAGE_BUFFER);
- elem!(
- uniform_buffer_dynamic,
- ash::vk::DescriptorType::UNIFORM_BUFFER_DYNAMIC
- );
- elem!(
- storage_buffer_dynamic,
- ash::vk::DescriptorType::STORAGE_BUFFER_DYNAMIC
- );
- elem!(
- uniform_texel_buffer,
- ash::vk::DescriptorType::UNIFORM_TEXEL_BUFFER
- );
- elem!(
- storage_texel_buffer,
- ash::vk::DescriptorType::STORAGE_TEXEL_BUFFER
- );
- elem!(sampled_image, ash::vk::DescriptorType::SAMPLED_IMAGE);
- elem!(storage_image, ash::vk::DescriptorType::STORAGE_IMAGE);
- elem!(sampler, ash::vk::DescriptorType::SAMPLER);
- elem!(
- combined_image_sampler,
- ash::vk::DescriptorType::COMBINED_IMAGE_SAMPLER
- );
- elem!(input_attachment, ash::vk::DescriptorType::INPUT_ATTACHMENT);
-
- assert!(
- !pool_sizes.is_empty(),
- "All the descriptors count of a pool are 0"
- );
-
- let pool = unsafe {
- let infos = ash::vk::DescriptorPoolCreateInfo {
- flags: if free_descriptor_set_bit {
- ash::vk::DescriptorPoolCreateFlags::FREE_DESCRIPTOR_SET
- } else {
- ash::vk::DescriptorPoolCreateFlags::empty()
- },
- max_sets: max_sets,
- pool_size_count: pool_sizes.len() as u32,
- p_pool_sizes: pool_sizes.as_ptr(),
- ..Default::default()
- };
-
- let mut output = MaybeUninit::uninit();
- check_errors(fns.v1_0.create_descriptor_pool(
- device.internal_object(),
- &infos,
- ptr::null(),
- output.as_mut_ptr(),
- ))?;
- output.assume_init()
- };
-
- Ok(UnsafeDescriptorPool {
- pool,
- device: device.clone(),
- })
- }
-
- /// Allocates descriptor sets from the pool, one for each layout.
- /// Returns an iterator to the allocated sets, or an error.
- ///
- /// The `FragmentedPool` errors often can't be prevented. If the function returns this error,
- /// you should just create a new pool.
- ///
- /// # Panic
- ///
- /// - Panics if one of the layouts wasn't created with the same device as the pool.
- ///
- /// # Safety
- ///
- /// See also the `new` function.
- ///
- /// - The total descriptors of the layouts must fit in the pool.
- /// - The total number of descriptor sets allocated from the pool must not overflow the pool.
- /// - You must ensure that the allocated descriptor sets are no longer in use when the pool
- /// is destroyed, as destroying the pool is equivalent to freeing all the sets.
- ///
- #[inline]
- pub unsafe fn alloc<'l, I>(
- &mut self,
- layouts: I,
- ) -> Result<UnsafeDescriptorPoolAllocIter, DescriptorPoolAllocError>
- where
- I: IntoIterator<Item = &'l DescriptorSetLayout>,
- {
- let layouts: SmallVec<[_; 8]> = layouts
- .into_iter()
- .map(|l| {
- assert_eq!(
- self.device.internal_object(),
- l.device().internal_object(),
- "Tried to allocate from a pool with a set layout of a different \
- device"
- );
- l.internal_object()
- })
- .collect();
-
- self.alloc_impl(&layouts)
- }
-
- // Actual implementation of `alloc`. Separated so that it is not inlined.
- unsafe fn alloc_impl(
- &mut self,
- layouts: &SmallVec<[ash::vk::DescriptorSetLayout; 8]>,
- ) -> Result<UnsafeDescriptorPoolAllocIter, DescriptorPoolAllocError> {
- let num = layouts.len();
-
- if num == 0 {
- return Ok(UnsafeDescriptorPoolAllocIter {
- sets: vec![].into_iter(),
- });
- }
-
- let infos = ash::vk::DescriptorSetAllocateInfo {
- descriptor_pool: self.pool,
- descriptor_set_count: layouts.len() as u32,
- p_set_layouts: layouts.as_ptr(),
- ..Default::default()
- };
-
- let mut output = Vec::with_capacity(num);
-
- let fns = self.device.fns();
- let ret = fns.v1_0.allocate_descriptor_sets(
- self.device.internal_object(),
- &infos,
- output.as_mut_ptr(),
- );
-
- // According to the specs, because `VK_ERROR_FRAGMENTED_POOL` was added after version
- // 1.0 of Vulkan, any negative return value except out-of-memory errors must be
- // considered as a fragmented pool error.
- match ret {
- ash::vk::Result::ERROR_OUT_OF_HOST_MEMORY => {
- return Err(DescriptorPoolAllocError::OutOfHostMemory);
- }
- ash::vk::Result::ERROR_OUT_OF_DEVICE_MEMORY => {
- return Err(DescriptorPoolAllocError::OutOfDeviceMemory);
- }
- ash::vk::Result::ERROR_OUT_OF_POOL_MEMORY_KHR => {
- return Err(DescriptorPoolAllocError::OutOfPoolMemory);
- }
- c if c.as_raw() < 0 => {
- return Err(DescriptorPoolAllocError::FragmentedPool);
- }
- _ => (),
- };
-
- output.set_len(num);
-
- Ok(UnsafeDescriptorPoolAllocIter {
- sets: output.into_iter(),
- })
- }
-
- /// Frees some descriptor sets.
- ///
- /// Note that it is not mandatory to free sets. Destroying or resetting the pool destroys all
- /// the descriptor sets.
- ///
- /// # Safety
- ///
- /// - The pool must have been created with `free_descriptor_set_bit` set to `true`.
- /// - The descriptor sets must have been allocated from the pool.
- /// - The descriptor sets must not be free'd twice.
- /// - The descriptor sets must not be in use by the GPU.
- ///
- #[inline]
- pub unsafe fn free<I>(&mut self, descriptor_sets: I) -> Result<(), OomError>
- where
- I: IntoIterator<Item = UnsafeDescriptorSet>,
- {
- let sets: SmallVec<[_; 8]> = descriptor_sets
- .into_iter()
- .map(|s| s.internal_object())
- .collect();
- if !sets.is_empty() {
- self.free_impl(&sets)
- } else {
- Ok(())
- }
- }
-
- // Actual implementation of `free`. Separated so that it is not inlined.
- unsafe fn free_impl(
- &mut self,
- sets: &SmallVec<[ash::vk::DescriptorSet; 8]>,
- ) -> Result<(), OomError> {
- let fns = self.device.fns();
- check_errors(fns.v1_0.free_descriptor_sets(
- self.device.internal_object(),
- self.pool,
- sets.len() as u32,
- sets.as_ptr(),
- ))?;
- Ok(())
- }
-
- /// Resets the pool.
- ///
- /// This destroys all descriptor sets and empties the pool.
- pub unsafe fn reset(&mut self) -> Result<(), OomError> {
- let fns = self.device.fns();
- check_errors(fns.v1_0.reset_descriptor_pool(
- self.device.internal_object(),
- self.pool,
- ash::vk::DescriptorPoolResetFlags::empty(),
- ))?;
- Ok(())
- }
-}
-
-unsafe impl DeviceOwned for UnsafeDescriptorPool {
- #[inline]
- fn device(&self) -> &Arc<Device> {
- &self.device
- }
-}
-
-impl fmt::Debug for UnsafeDescriptorPool {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- fmt.debug_struct("UnsafeDescriptorPool")
- .field("raw", &self.pool)
- .field("device", &self.device)
- .finish()
- }
-}
-
-impl Drop for UnsafeDescriptorPool {
- #[inline]
- fn drop(&mut self) {
- unsafe {
- let fns = self.device.fns();
- fns.v1_0
- .destroy_descriptor_pool(self.device.internal_object(), self.pool, ptr::null());
- }
- }
-}
-
-/// Error that can be returned when creating a device.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum DescriptorPoolAllocError {
- /// There is no memory available on the host (ie. the CPU, RAM, etc.).
- OutOfHostMemory,
- /// There is no memory available on the device (ie. video memory).
- OutOfDeviceMemory,
- /// Allocation has failed because the pool is too fragmented.
- FragmentedPool,
- /// There is no more space available in the descriptor pool.
- OutOfPoolMemory,
-}
-
-impl error::Error for DescriptorPoolAllocError {}
-
-impl fmt::Display for DescriptorPoolAllocError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- DescriptorPoolAllocError::OutOfHostMemory => "no memory available on the host",
- DescriptorPoolAllocError::OutOfDeviceMemory => {
- "no memory available on the graphical device"
- }
- DescriptorPoolAllocError::FragmentedPool => {
- "allocation has failed because the pool is too fragmented"
- }
- DescriptorPoolAllocError::OutOfPoolMemory => {
- "there is no more space available in the descriptor pool"
- }
- }
- )
- }
-}
-
-/// Iterator to the descriptor sets allocated from an unsafe descriptor pool.
-#[derive(Debug)]
-pub struct UnsafeDescriptorPoolAllocIter {
- sets: VecIntoIter<ash::vk::DescriptorSet>,
-}
-
-impl Iterator for UnsafeDescriptorPoolAllocIter {
- type Item = UnsafeDescriptorSet;
-
- #[inline]
- fn next(&mut self) -> Option<UnsafeDescriptorSet> {
- self.sets.next().map(|s| UnsafeDescriptorSet { set: s })
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.sets.size_hint()
- }
-}
-
-impl ExactSizeIterator for UnsafeDescriptorPoolAllocIter {}
-
-#[cfg(test)]
-mod tests {
- use crate::descriptor_set::layout::DescriptorBufferDesc;
- use crate::descriptor_set::layout::DescriptorDesc;
- use crate::descriptor_set::layout::DescriptorDescTy;
- use crate::descriptor_set::layout::DescriptorSetDesc;
- use crate::descriptor_set::layout::DescriptorSetLayout;
- use crate::descriptor_set::pool::DescriptorsCount;
- use crate::descriptor_set::pool::UnsafeDescriptorPool;
- use crate::pipeline::shader::ShaderStages;
- use std::iter;
-
- #[test]
- fn pool_create() {
- let (device, _) = gfx_dev_and_queue!();
- let desc = DescriptorsCount {
- uniform_buffer: 1,
- ..DescriptorsCount::zero()
- };
-
- let _ = UnsafeDescriptorPool::new(device, &desc, 10, false).unwrap();
- }
-
- #[test]
- fn zero_max_set() {
- let (device, _) = gfx_dev_and_queue!();
- let desc = DescriptorsCount {
- uniform_buffer: 1,
- ..DescriptorsCount::zero()
- };
-
- assert_should_panic!("The maximum number of sets can't be 0", {
- let _ = UnsafeDescriptorPool::new(device, &desc, 0, false);
- });
- }
-
- #[test]
- fn zero_descriptors() {
- let (device, _) = gfx_dev_and_queue!();
-
- assert_should_panic!("All the descriptors count of a pool are 0", {
- let _ = UnsafeDescriptorPool::new(device, &DescriptorsCount::zero(), 10, false);
- });
- }
-
- #[test]
- fn basic_alloc() {
- let (device, _) = gfx_dev_and_queue!();
-
- let layout = DescriptorDesc {
- ty: DescriptorDescTy::Buffer(DescriptorBufferDesc {
- dynamic: Some(false),
- storage: false,
- }),
- array_count: 1,
- stages: ShaderStages::all_graphics(),
- readonly: true,
- };
-
- let set_layout = DescriptorSetLayout::new(
- device.clone(),
- DescriptorSetDesc::new(iter::once(Some(layout))),
- )
- .unwrap();
-
- let desc = DescriptorsCount {
- uniform_buffer: 10,
- ..DescriptorsCount::zero()
- };
-
- let mut pool = UnsafeDescriptorPool::new(device, &desc, 10, false).unwrap();
- unsafe {
- let sets = pool.alloc(iter::once(&set_layout)).unwrap();
- assert_eq!(sets.count(), 1);
- }
- }
-
- #[test]
- fn alloc_diff_device() {
- let (device1, _) = gfx_dev_and_queue!();
- let (device2, _) = gfx_dev_and_queue!();
-
- let layout = DescriptorDesc {
- ty: DescriptorDescTy::Buffer(DescriptorBufferDesc {
- dynamic: Some(false),
- storage: false,
- }),
- array_count: 1,
- stages: ShaderStages::all_graphics(),
- readonly: true,
- };
-
- let set_layout =
- DescriptorSetLayout::new(device1, DescriptorSetDesc::new(iter::once(Some(layout))))
- .unwrap();
-
- let desc = DescriptorsCount {
- uniform_buffer: 10,
- ..DescriptorsCount::zero()
- };
-
- assert_should_panic!(
- "Tried to allocate from a pool with a set layout \
- of a different device",
- {
- let mut pool = UnsafeDescriptorPool::new(device2, &desc, 10, false).unwrap();
-
- unsafe {
- let _ = pool.alloc(iter::once(&set_layout));
- }
- }
- );
- }
-
- #[test]
- fn alloc_zero() {
- let (device, _) = gfx_dev_and_queue!();
-
- let desc = DescriptorsCount {
- uniform_buffer: 1,
- ..DescriptorsCount::zero()
- };
-
- let mut pool = UnsafeDescriptorPool::new(device, &desc, 1, false).unwrap();
- unsafe {
- let sets = pool.alloc(iter::empty()).unwrap();
- assert_eq!(sets.count(), 0);
- }
- }
-}
diff --git a/src/descriptor_set/sys.rs b/src/descriptor_set/sys.rs
index d1c7cc1..76042df 100644
--- a/src/descriptor_set/sys.rs
+++ b/src/descriptor_set/sys.rs
@@ -9,580 +9,125 @@
//! Low-level descriptor set.
-use crate::buffer::BufferAccess;
-use crate::buffer::BufferInner;
-use crate::buffer::BufferView;
-use crate::descriptor_set::layout::DescriptorType;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::image::view::ImageViewAbstract;
-use crate::sampler::Sampler;
-use crate::DeviceSize;
-use crate::VulkanObject;
+use crate::{
+ descriptor_set::{
+ layout::DescriptorSetLayout,
+ update::{DescriptorWriteInfo, WriteDescriptorSet},
+ },
+ device::DeviceOwned,
+ macros::impl_id_counter,
+ VulkanObject,
+};
use smallvec::SmallVec;
-use std::fmt;
-use std::ptr;
-use std::sync::Arc;
+use std::{
+ fmt::{Debug, Error as FmtError, Formatter},
+ num::NonZeroU64,
+ ptr,
+};
/// Low-level descriptor set.
///
/// Contrary to most other objects in this library, this one doesn't free itself automatically and
/// doesn't hold the pool or the device it is associated to.
-/// Instead it is an object meant to be used with the `UnsafeDescriptorPool`.
+/// Instead it is an object meant to be used with the [`DescriptorPool`].
+///
+/// [`DescriptorPool`]: super::pool::DescriptorPool
pub struct UnsafeDescriptorSet {
- pub(super) set: ash::vk::DescriptorSet,
+ handle: ash::vk::DescriptorSet,
+ id: NonZeroU64,
}
impl UnsafeDescriptorSet {
- // TODO: add copying from other descriptor sets
- // add a `copy` method that just takes a copy, and an `update` method that takes both
- // writes and copies and that actually performs the operation
+ pub(crate) fn new(handle: ash::vk::DescriptorSet) -> Self {
+ Self {
+ handle,
+ id: Self::next_id(),
+ }
+ }
/// Modifies a descriptor set. Doesn't check that the writes or copies are correct, and
/// doesn't check whether the descriptor set is in use.
///
- /// **Important**: You must ensure that the `DescriptorSetLayout` object is alive before
- /// updating a descriptor set.
- ///
/// # Safety
///
/// - The `Device` must be the device the pool of this set was created with.
- /// - The `DescriptorSetLayout` object this set was created with must be alive.
/// - Doesn't verify that the things you write in the descriptor set match its layout.
/// - Doesn't keep the resources alive. You have to do that yourself.
/// - Updating a descriptor set obeys synchronization rules that aren't checked here. Once a
/// command buffer contains a pointer/reference to a descriptor set, it is illegal to write
/// to it.
- ///
- pub unsafe fn write<I>(&mut self, device: &Device, writes: I)
- where
- I: Iterator<Item = DescriptorWrite>,
- {
- let fns = device.fns();
-
- // In this function, we build 4 arrays: one array of image descriptors (image_descriptors),
- // one for buffer descriptors (buffer_descriptors), one for buffer view descriptors
- // (buffer_views_descriptors), and one for the final list of writes (raw_writes).
- // Only the final list is passed to Vulkan, but it will contain pointers to the first three
- // lists in `pImageInfo`, `pBufferInfo` and `pTexelBufferView`.
- //
- // In order to handle that, we start by writing null pointers as placeholders in the final
- // writes, and we store in `raw_writes_img_infos`, `raw_writes_buf_infos` and
- // `raw_writes_buf_view_infos` the offsets of the pointers compared to the start of the
- // list.
- // Once we have finished iterating all the writes requested by the user, we modify
- // `raw_writes` to point to the correct locations.
-
- let mut buffer_descriptors: SmallVec<[_; 64]> = SmallVec::new();
- let mut image_descriptors: SmallVec<[_; 64]> = SmallVec::new();
- let mut buffer_views_descriptors: SmallVec<[_; 64]> = SmallVec::new();
-
- let mut raw_writes: SmallVec<[_; 64]> = SmallVec::new();
- let mut raw_writes_img_infos: SmallVec<[_; 64]> = SmallVec::new();
- let mut raw_writes_buf_infos: SmallVec<[_; 64]> = SmallVec::new();
- let mut raw_writes_buf_view_infos: SmallVec<[_; 64]> = SmallVec::new();
-
- for indiv_write in writes {
- // Since the `DescriptorWrite` objects are built only through functions, we know for
- // sure that it's impossible to have an empty descriptor write.
- debug_assert!(!indiv_write.inner.is_empty());
+ pub unsafe fn write<'a>(
+ &mut self,
+ layout: &DescriptorSetLayout,
+ writes: impl IntoIterator<Item = &'a WriteDescriptorSet>,
+ ) {
+ let (infos, mut writes): (SmallVec<[_; 8]>, SmallVec<[_; 8]>) = writes
+ .into_iter()
+ .map(|write| {
+ let descriptor_type = layout.bindings()[&write.binding()].descriptor_type;
+
+ (
+ write.to_vulkan_info(descriptor_type),
+ write.to_vulkan(self.handle, descriptor_type),
+ )
+ })
+ .unzip();
- // The whole struct thats written here is valid, except for pImageInfo, pBufferInfo
- // and pTexelBufferView which are placeholder values.
- raw_writes.push(ash::vk::WriteDescriptorSet {
- dst_set: self.set,
- dst_binding: indiv_write.binding,
- dst_array_element: indiv_write.first_array_element,
- descriptor_count: indiv_write.inner.len() as u32,
- descriptor_type: indiv_write.ty().into(),
- p_image_info: ptr::null(),
- p_buffer_info: ptr::null(),
- p_texel_buffer_view: ptr::null(),
- ..Default::default()
- });
+ // It is forbidden to call `vkUpdateDescriptorSets` with 0 writes, so we need to perform
+ // this emptiness check.
+ if writes.is_empty() {
+ return;
+ }
- match indiv_write.inner[0] {
- DescriptorWriteInner::Sampler(_)
- | DescriptorWriteInner::CombinedImageSampler(_, _, _)
- | DescriptorWriteInner::SampledImage(_, _)
- | DescriptorWriteInner::StorageImage(_, _)
- | DescriptorWriteInner::InputAttachment(_, _) => {
- raw_writes_img_infos.push(Some(image_descriptors.len()));
- raw_writes_buf_infos.push(None);
- raw_writes_buf_view_infos.push(None);
+ // Set the info pointers separately.
+ for (info, write) in infos.iter().zip(writes.iter_mut()) {
+ match info {
+ DescriptorWriteInfo::Image(info) => {
+ write.descriptor_count = info.len() as u32;
+ write.p_image_info = info.as_ptr();
}
- DescriptorWriteInner::UniformBuffer(_, _, _)
- | DescriptorWriteInner::StorageBuffer(_, _, _)
- | DescriptorWriteInner::DynamicUniformBuffer(_, _, _)
- | DescriptorWriteInner::DynamicStorageBuffer(_, _, _) => {
- raw_writes_img_infos.push(None);
- raw_writes_buf_infos.push(Some(buffer_descriptors.len()));
- raw_writes_buf_view_infos.push(None);
+ DescriptorWriteInfo::Buffer(info) => {
+ write.descriptor_count = info.len() as u32;
+ write.p_buffer_info = info.as_ptr();
}
- DescriptorWriteInner::UniformTexelBuffer(_)
- | DescriptorWriteInner::StorageTexelBuffer(_) => {
- raw_writes_img_infos.push(None);
- raw_writes_buf_infos.push(None);
- raw_writes_buf_view_infos.push(Some(buffer_views_descriptors.len()));
+ DescriptorWriteInfo::BufferView(info) => {
+ write.descriptor_count = info.len() as u32;
+ write.p_texel_buffer_view = info.as_ptr();
}
}
- for elem in indiv_write.inner.iter() {
- match *elem {
- DescriptorWriteInner::UniformBuffer(buffer, offset, size)
- | DescriptorWriteInner::DynamicUniformBuffer(buffer, offset, size) => {
- buffer_descriptors.push(ash::vk::DescriptorBufferInfo {
- buffer,
- offset,
- range: size,
- });
- }
- DescriptorWriteInner::StorageBuffer(buffer, offset, size)
- | DescriptorWriteInner::DynamicStorageBuffer(buffer, offset, size) => {
- buffer_descriptors.push(ash::vk::DescriptorBufferInfo {
- buffer,
- offset,
- range: size,
- });
- }
- DescriptorWriteInner::Sampler(sampler) => {
- image_descriptors.push(ash::vk::DescriptorImageInfo {
- sampler,
- image_view: ash::vk::ImageView::null(),
- image_layout: ash::vk::ImageLayout::UNDEFINED,
- });
- }
- DescriptorWriteInner::CombinedImageSampler(sampler, view, layout) => {
- image_descriptors.push(ash::vk::DescriptorImageInfo {
- sampler,
- image_view: view,
- image_layout: layout,
- });
- }
- DescriptorWriteInner::StorageImage(view, layout) => {
- image_descriptors.push(ash::vk::DescriptorImageInfo {
- sampler: ash::vk::Sampler::null(),
- image_view: view,
- image_layout: layout,
- });
- }
- DescriptorWriteInner::SampledImage(view, layout) => {
- image_descriptors.push(ash::vk::DescriptorImageInfo {
- sampler: ash::vk::Sampler::null(),
- image_view: view,
- image_layout: layout,
- });
- }
- DescriptorWriteInner::InputAttachment(view, layout) => {
- image_descriptors.push(ash::vk::DescriptorImageInfo {
- sampler: ash::vk::Sampler::null(),
- image_view: view,
- image_layout: layout,
- });
- }
- DescriptorWriteInner::UniformTexelBuffer(view)
- | DescriptorWriteInner::StorageTexelBuffer(view) => {
- buffer_views_descriptors.push(view);
- }
- }
- }
+ debug_assert!(write.descriptor_count != 0);
}
- // Now that `image_descriptors`, `buffer_descriptors` and `buffer_views_descriptors` are
- // entirely filled and will never move again, we can fill the pointers in `raw_writes`.
- for (i, write) in raw_writes.iter_mut().enumerate() {
- write.p_image_info = match raw_writes_img_infos[i] {
- Some(off) => image_descriptors.as_ptr().offset(off as isize),
- None => ptr::null(),
- };
-
- write.p_buffer_info = match raw_writes_buf_infos[i] {
- Some(off) => buffer_descriptors.as_ptr().offset(off as isize),
- None => ptr::null(),
- };
+ let fns = layout.device().fns();
- write.p_texel_buffer_view = match raw_writes_buf_view_infos[i] {
- Some(off) => buffer_views_descriptors.as_ptr().offset(off as isize),
- None => ptr::null(),
- };
- }
-
- // It is forbidden to call `vkUpdateDescriptorSets` with 0 writes, so we need to perform
- // this emptiness check.
- if !raw_writes.is_empty() {
- fns.v1_0.update_descriptor_sets(
- device.internal_object(),
- raw_writes.len() as u32,
- raw_writes.as_ptr(),
- 0,
- ptr::null(),
- );
- }
+ (fns.v1_0.update_descriptor_sets)(
+ layout.device().handle(),
+ writes.len() as u32,
+ writes.as_ptr(),
+ 0,
+ ptr::null(),
+ );
}
+
+ // TODO: add copying from other descriptor sets
+ // add a `copy` method that just takes a copy, and an `update` method that takes both
+ // writes and copies and that actually performs the operation
}
unsafe impl VulkanObject for UnsafeDescriptorSet {
- type Object = ash::vk::DescriptorSet;
+ type Handle = ash::vk::DescriptorSet;
#[inline]
- fn internal_object(&self) -> ash::vk::DescriptorSet {
- self.set
+ fn handle(&self) -> Self::Handle {
+ self.handle
}
}
-impl fmt::Debug for UnsafeDescriptorSet {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(fmt, "<Vulkan descriptor set {:?}>", self.set)
+impl Debug for UnsafeDescriptorSet {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ write!(f, "<Vulkan descriptor set {:?}>", self.handle)
}
}
-/// Represents a single write entry to a descriptor set.
-///
-/// Use the various constructors to build a `DescriptorWrite`. While it is safe to build a
-/// `DescriptorWrite`, it is unsafe to actually use it to write to a descriptor set.
-// TODO: allow binding whole arrays at once
-pub struct DescriptorWrite {
- binding: u32,
- first_array_element: u32,
- inner: SmallVec<[DescriptorWriteInner; 1]>,
-}
-
-#[derive(Debug, Clone)]
-enum DescriptorWriteInner {
- Sampler(ash::vk::Sampler),
- StorageImage(ash::vk::ImageView, ash::vk::ImageLayout),
- SampledImage(ash::vk::ImageView, ash::vk::ImageLayout),
- CombinedImageSampler(ash::vk::Sampler, ash::vk::ImageView, ash::vk::ImageLayout),
- UniformTexelBuffer(ash::vk::BufferView),
- StorageTexelBuffer(ash::vk::BufferView),
- UniformBuffer(ash::vk::Buffer, DeviceSize, DeviceSize),
- StorageBuffer(ash::vk::Buffer, DeviceSize, DeviceSize),
- DynamicUniformBuffer(ash::vk::Buffer, DeviceSize, DeviceSize),
- DynamicStorageBuffer(ash::vk::Buffer, DeviceSize, DeviceSize),
- InputAttachment(ash::vk::ImageView, ash::vk::ImageLayout),
-}
-
-macro_rules! smallvec {
- ($elem:expr) => {{
- let mut s = SmallVec::new();
- s.push($elem);
- s
- }};
-}
-
-impl DescriptorWrite {
- #[inline]
- pub fn storage_image<I>(binding: u32, array_element: u32, image_view: &I) -> DescriptorWrite
- where
- I: ImageViewAbstract,
- {
- let layouts = image_view
- .image()
- .descriptor_layouts()
- .expect("descriptor_layouts must return Some when used in an image view");
-
- DescriptorWrite {
- binding,
- first_array_element: array_element,
- inner: smallvec!({
- DescriptorWriteInner::StorageImage(
- image_view.inner().internal_object(),
- layouts.storage_image.into(),
- )
- }),
- }
- }
-
- #[inline]
- pub fn sampler(binding: u32, array_element: u32, sampler: &Arc<Sampler>) -> DescriptorWrite {
- DescriptorWrite {
- binding,
- first_array_element: array_element,
- inner: smallvec!(DescriptorWriteInner::Sampler(sampler.internal_object())),
- }
- }
-
- #[inline]
- pub fn sampled_image<I>(binding: u32, array_element: u32, image_view: &I) -> DescriptorWrite
- where
- I: ImageViewAbstract,
- {
- let layouts = image_view
- .image()
- .descriptor_layouts()
- .expect("descriptor_layouts must return Some when used in an image view");
-
- DescriptorWrite {
- binding,
- first_array_element: array_element,
- inner: smallvec!({
- DescriptorWriteInner::SampledImage(
- image_view.inner().internal_object(),
- layouts.sampled_image.into(),
- )
- }),
- }
- }
-
- #[inline]
- pub fn combined_image_sampler<I>(
- binding: u32,
- array_element: u32,
- sampler: &Arc<Sampler>,
- image_view: &I,
- ) -> DescriptorWrite
- where
- I: ImageViewAbstract,
- {
- let layouts = image_view
- .image()
- .descriptor_layouts()
- .expect("descriptor_layouts must return Some when used in an image view");
-
- DescriptorWrite {
- binding,
- first_array_element: array_element,
- inner: smallvec!({
- DescriptorWriteInner::CombinedImageSampler(
- sampler.internal_object(),
- image_view.inner().internal_object(),
- layouts.combined_image_sampler.into(),
- )
- }),
- }
- }
-
- #[inline]
- pub fn uniform_texel_buffer<'a, B>(
- binding: u32,
- array_element: u32,
- view: &BufferView<B>,
- ) -> DescriptorWrite
- where
- B: BufferAccess,
- {
- assert!(view.uniform_texel_buffer());
-
- DescriptorWrite {
- binding,
- first_array_element: array_element,
- inner: smallvec!(DescriptorWriteInner::UniformTexelBuffer(
- view.internal_object()
- )),
- }
- }
-
- #[inline]
- pub fn storage_texel_buffer<'a, B>(
- binding: u32,
- array_element: u32,
- view: &BufferView<B>,
- ) -> DescriptorWrite
- where
- B: BufferAccess,
- {
- assert!(view.storage_texel_buffer());
-
- DescriptorWrite {
- binding,
- first_array_element: array_element,
- inner: smallvec!(DescriptorWriteInner::StorageTexelBuffer(
- view.internal_object()
- )),
- }
- }
-
- #[inline]
- pub unsafe fn uniform_buffer<B>(binding: u32, array_element: u32, buffer: &B) -> DescriptorWrite
- where
- B: BufferAccess,
- {
- let size = buffer.size();
- let BufferInner { buffer, offset } = buffer.inner();
-
- debug_assert_eq!(
- offset
- % buffer
- .device()
- .physical_device()
- .properties()
- .min_uniform_buffer_offset_alignment,
- 0
- );
- debug_assert!(
- size <= buffer
- .device()
- .physical_device()
- .properties()
- .max_uniform_buffer_range as DeviceSize
- );
-
- DescriptorWrite {
- binding,
- first_array_element: array_element,
- inner: smallvec!({
- DescriptorWriteInner::UniformBuffer(buffer.internal_object(), offset, size)
- }),
- }
- }
-
- #[inline]
- pub unsafe fn storage_buffer<B>(binding: u32, array_element: u32, buffer: &B) -> DescriptorWrite
- where
- B: BufferAccess,
- {
- let size = buffer.size();
- let BufferInner { buffer, offset } = buffer.inner();
-
- debug_assert_eq!(
- offset
- % buffer
- .device()
- .physical_device()
- .properties()
- .min_storage_buffer_offset_alignment,
- 0
- );
- debug_assert!(
- size <= buffer
- .device()
- .physical_device()
- .properties()
- .max_storage_buffer_range as DeviceSize
- );
-
- DescriptorWrite {
- binding,
- first_array_element: array_element,
- inner: smallvec!({
- DescriptorWriteInner::StorageBuffer(buffer.internal_object(), offset, size)
- }),
- }
- }
-
- #[inline]
- pub unsafe fn dynamic_uniform_buffer<B>(
- binding: u32,
- array_element: u32,
- buffer: &B,
- ) -> DescriptorWrite
- where
- B: BufferAccess,
- {
- let size = buffer.size();
- let BufferInner { buffer, offset } = buffer.inner();
-
- debug_assert_eq!(
- offset
- % buffer
- .device()
- .physical_device()
- .properties()
- .min_uniform_buffer_offset_alignment,
- 0
- );
- debug_assert!(
- size <= buffer
- .device()
- .physical_device()
- .properties()
- .max_uniform_buffer_range as DeviceSize
- );
-
- DescriptorWrite {
- binding,
- first_array_element: array_element,
- inner: smallvec!(DescriptorWriteInner::DynamicUniformBuffer(
- buffer.internal_object(),
- offset,
- size
- )),
- }
- }
-
- #[inline]
- pub unsafe fn dynamic_storage_buffer<B>(
- binding: u32,
- array_element: u32,
- buffer: &B,
- ) -> DescriptorWrite
- where
- B: BufferAccess,
- {
- let size = buffer.size();
- let BufferInner { buffer, offset } = buffer.inner();
-
- debug_assert_eq!(
- offset
- % buffer
- .device()
- .physical_device()
- .properties()
- .min_storage_buffer_offset_alignment,
- 0
- );
- debug_assert!(
- size <= buffer
- .device()
- .physical_device()
- .properties()
- .max_storage_buffer_range as DeviceSize
- );
-
- DescriptorWrite {
- binding,
- first_array_element: array_element,
- inner: smallvec!(DescriptorWriteInner::DynamicStorageBuffer(
- buffer.internal_object(),
- offset,
- size
- )),
- }
- }
-
- #[inline]
- pub fn input_attachment<I>(binding: u32, array_element: u32, image_view: &I) -> DescriptorWrite
- where
- I: ImageViewAbstract,
- {
- let layouts = image_view
- .image()
- .descriptor_layouts()
- .expect("descriptor_layouts must return Some when used in an image view");
-
- DescriptorWrite {
- binding,
- first_array_element: array_element,
- inner: smallvec!({
- DescriptorWriteInner::InputAttachment(
- image_view.inner().internal_object(),
- layouts.input_attachment.into(),
- )
- }),
- }
- }
-
- /// Returns the type corresponding to this write.
- #[inline]
- pub fn ty(&self) -> DescriptorType {
- match self.inner[0] {
- DescriptorWriteInner::Sampler(_) => DescriptorType::Sampler,
- DescriptorWriteInner::CombinedImageSampler(_, _, _) => {
- DescriptorType::CombinedImageSampler
- }
- DescriptorWriteInner::SampledImage(_, _) => DescriptorType::SampledImage,
- DescriptorWriteInner::StorageImage(_, _) => DescriptorType::StorageImage,
- DescriptorWriteInner::UniformTexelBuffer(_) => DescriptorType::UniformTexelBuffer,
- DescriptorWriteInner::StorageTexelBuffer(_) => DescriptorType::StorageTexelBuffer,
- DescriptorWriteInner::UniformBuffer(_, _, _) => DescriptorType::UniformBuffer,
- DescriptorWriteInner::StorageBuffer(_, _, _) => DescriptorType::StorageBuffer,
- DescriptorWriteInner::DynamicUniformBuffer(_, _, _) => {
- DescriptorType::UniformBufferDynamic
- }
- DescriptorWriteInner::DynamicStorageBuffer(_, _, _) => {
- DescriptorType::StorageBufferDynamic
- }
- DescriptorWriteInner::InputAttachment(_, _) => DescriptorType::InputAttachment,
- }
- }
-}
+impl_id_counter!(UnsafeDescriptorSet);
diff --git a/src/descriptor_set/update.rs b/src/descriptor_set/update.rs
new file mode 100644
index 0000000..8ba61c5
--- /dev/null
+++ b/src/descriptor_set/update.rs
@@ -0,0 +1,1204 @@
+// Copyright (c) 2017 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use super::layout::{DescriptorSetLayout, DescriptorSetLayoutBinding, DescriptorType};
+use crate::{
+ buffer::{view::BufferView, BufferUsage, Subbuffer},
+ device::DeviceOwned,
+ image::{view::ImageViewType, ImageAspects, ImageType, ImageUsage, ImageViewAbstract},
+ sampler::{Sampler, SamplerImageViewIncompatibleError},
+ DeviceSize, RequiresOneOf, VulkanObject,
+};
+use smallvec::SmallVec;
+use std::{
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+ ops::Range,
+ ptr,
+ sync::Arc,
+};
+
+/// Represents a single write operation to the binding of a descriptor set.
+///
+/// `WriteDescriptorSet` specifies the binding number and target array index, and includes one or
+/// more resources of a given type that need to be written to that location. Two constructors are
+/// provided for each resource type:
+/// - The basic constructor variant writes a single element to array index 0. It is intended for
+/// non-arrayed bindings, where `descriptor_count` in the descriptor set layout is 1.
+/// - The `_array` variant writes several elements and allows specifying the target array index.
+/// At least one element must be provided; a panic results if the provided iterator is empty.
+pub struct WriteDescriptorSet {
+ binding: u32,
+ first_array_element: u32,
+ elements: WriteDescriptorSetElements,
+}
+
+impl WriteDescriptorSet {
+ /// Write an empty element to array element 0.
+ ///
+ /// This is used for push descriptors in combination with `Sampler` descriptors that have
+ /// immutable samplers in the layout. The Vulkan spec requires these elements to be explicitly
+ /// written, but since there is no data to write, a dummy write is provided instead.
+ ///
+ /// For regular descriptor sets, the data for such descriptors is automatically valid, and dummy
+ /// writes are not allowed.
+ #[inline]
+ pub fn none(binding: u32) -> Self {
+ Self::none_array(binding, 0, 1)
+ }
+
+ /// Write a number of consecutive empty elements.
+ ///
+ /// See [`none`](Self::none) for more information.
+ #[inline]
+ pub fn none_array(binding: u32, first_array_element: u32, num_elements: u32) -> Self {
+ assert!(num_elements != 0);
+ Self {
+ binding,
+ first_array_element,
+ elements: WriteDescriptorSetElements::None(num_elements),
+ }
+ }
+
+ /// Write a single buffer to array element 0, with the bound range covering the whole buffer.
+ ///
+ /// For dynamic buffer bindings, this will bind the whole buffer, and only a dynamic offset
+ /// of zero will be valid, which is probably not what you want.
+ /// Use [`buffer_with_range`](Self::buffer_with_range) instead.
+ #[inline]
+ pub fn buffer(binding: u32, buffer: Subbuffer<impl ?Sized>) -> Self {
+ let range = 0..buffer.size();
+ Self::buffer_with_range_array(binding, 0, [(buffer, range)])
+ }
+
+ /// Write a number of consecutive buffer elements.
+ ///
+ /// See [`buffer`](Self::buffer) for more information.
+ #[inline]
+ pub fn buffer_array(
+ binding: u32,
+ first_array_element: u32,
+ elements: impl IntoIterator<Item = Subbuffer<impl ?Sized>>,
+ ) -> Self {
+ Self::buffer_with_range_array(
+ binding,
+ first_array_element,
+ elements.into_iter().map(|buffer| {
+ let range = 0..buffer.size();
+ (buffer, range)
+ }),
+ )
+ }
+
+ /// Write a single buffer to array element 0, specifying the range of the buffer to be bound.
+ ///
+ /// `range` is the slice of bytes in `buffer` that will be made available to the shader.
+ /// `range` must not be outside the range `buffer`.
+ ///
+ /// For dynamic buffer bindings, `range` specifies the slice that is to be bound if the
+ /// dynamic offset were zero. When binding the descriptor set, the effective value of `range`
+ /// shifts forward by the offset that was provided. For example, if `range` is specified as
+ /// `0..8` when writing the descriptor set, and then when binding the descriptor set the
+ /// offset `16` is used, then the range of `buffer` that will actually be bound is `16..24`.
+ #[inline]
+ pub fn buffer_with_range(
+ binding: u32,
+ buffer: Subbuffer<impl ?Sized>,
+ range: Range<DeviceSize>,
+ ) -> Self {
+ Self::buffer_with_range_array(binding, 0, [(buffer, range)])
+ }
+
+ /// Write a number of consecutive buffer elements, specifying the ranges of the buffers to be
+ /// bound.
+ ///
+ /// See [`buffer_with_range`](Self::buffer_with_range) for more information.
+ pub fn buffer_with_range_array(
+ binding: u32,
+ first_array_element: u32,
+ elements: impl IntoIterator<Item = (Subbuffer<impl ?Sized>, Range<DeviceSize>)>,
+ ) -> Self {
+ let elements: SmallVec<_> = elements
+ .into_iter()
+ .map(|(buffer, range)| (buffer.into_bytes(), range))
+ .collect();
+ assert!(!elements.is_empty());
+
+ Self {
+ binding,
+ first_array_element,
+ elements: WriteDescriptorSetElements::Buffer(elements),
+ }
+ }
+
+ /// Write a single buffer view to array element 0.
+ #[inline]
+ pub fn buffer_view(binding: u32, buffer_view: Arc<BufferView>) -> Self {
+ Self::buffer_view_array(binding, 0, [buffer_view])
+ }
+
+ /// Write a number of consecutive buffer view elements.
+ pub fn buffer_view_array(
+ binding: u32,
+ first_array_element: u32,
+ elements: impl IntoIterator<Item = Arc<BufferView>>,
+ ) -> Self {
+ let elements: SmallVec<_> = elements.into_iter().collect();
+ assert!(!elements.is_empty());
+ Self {
+ binding,
+ first_array_element,
+ elements: WriteDescriptorSetElements::BufferView(elements),
+ }
+ }
+
+ /// Write a single image view to array element 0.
+ #[inline]
+ pub fn image_view(binding: u32, image_view: Arc<dyn ImageViewAbstract>) -> Self {
+ Self::image_view_array(binding, 0, [image_view])
+ }
+
+ /// Write a number of consecutive image view elements.
+ pub fn image_view_array(
+ binding: u32,
+ first_array_element: u32,
+ elements: impl IntoIterator<Item = Arc<dyn ImageViewAbstract>>,
+ ) -> Self {
+ let elements: SmallVec<_> = elements.into_iter().collect();
+ assert!(!elements.is_empty());
+ Self {
+ binding,
+ first_array_element,
+ elements: WriteDescriptorSetElements::ImageView(elements),
+ }
+ }
+
+ /// Write a single image view and sampler to array element 0.
+ #[inline]
+ pub fn image_view_sampler(
+ binding: u32,
+ image_view: Arc<dyn ImageViewAbstract>,
+ sampler: Arc<Sampler>,
+ ) -> Self {
+ Self::image_view_sampler_array(binding, 0, [(image_view, sampler)])
+ }
+
+ /// Write a number of consecutive image view and sampler elements.
+ pub fn image_view_sampler_array(
+ binding: u32,
+ first_array_element: u32,
+ elements: impl IntoIterator<Item = (Arc<dyn ImageViewAbstract>, Arc<Sampler>)>,
+ ) -> Self {
+ let elements: SmallVec<_> = elements.into_iter().collect();
+ assert!(!elements.is_empty());
+ Self {
+ binding,
+ first_array_element,
+ elements: WriteDescriptorSetElements::ImageViewSampler(elements),
+ }
+ }
+
+ /// Write a single sampler to array element 0.
+ #[inline]
+ pub fn sampler(binding: u32, sampler: Arc<Sampler>) -> Self {
+ Self::sampler_array(binding, 0, [sampler])
+ }
+
+ /// Write a number of consecutive sampler elements.
+ pub fn sampler_array(
+ binding: u32,
+ first_array_element: u32,
+ elements: impl IntoIterator<Item = Arc<Sampler>>,
+ ) -> Self {
+ let elements: SmallVec<_> = elements.into_iter().collect();
+ assert!(!elements.is_empty());
+ Self {
+ binding,
+ first_array_element,
+ elements: WriteDescriptorSetElements::Sampler(elements),
+ }
+ }
+
+ /// Returns the binding number that is updated by this descriptor write.
+ #[inline]
+ pub fn binding(&self) -> u32 {
+ self.binding
+ }
+
+ /// Returns the first array element in the binding that is updated by this descriptor write.
+ #[inline]
+ pub fn first_array_element(&self) -> u32 {
+ self.first_array_element
+ }
+
+ /// Returns a reference to the elements held by this descriptor write.
+ #[inline]
+ pub fn elements(&self) -> &WriteDescriptorSetElements {
+ &self.elements
+ }
+
+ pub(crate) fn to_vulkan_info(&self, descriptor_type: DescriptorType) -> DescriptorWriteInfo {
+ match &self.elements {
+ WriteDescriptorSetElements::None(num_elements) => {
+ debug_assert!(matches!(descriptor_type, DescriptorType::Sampler));
+ DescriptorWriteInfo::Image(
+ std::iter::repeat_with(|| ash::vk::DescriptorImageInfo {
+ sampler: ash::vk::Sampler::null(),
+ image_view: ash::vk::ImageView::null(),
+ image_layout: ash::vk::ImageLayout::UNDEFINED,
+ })
+ .take(*num_elements as usize)
+ .collect(),
+ )
+ }
+ WriteDescriptorSetElements::Buffer(elements) => {
+ debug_assert!(matches!(
+ descriptor_type,
+ DescriptorType::UniformBuffer
+ | DescriptorType::StorageBuffer
+ | DescriptorType::UniformBufferDynamic
+ | DescriptorType::StorageBufferDynamic
+ ));
+ DescriptorWriteInfo::Buffer(
+ elements
+ .iter()
+ .map(|(buffer, range)| {
+ debug_assert!(!range.is_empty());
+ debug_assert!(range.end <= buffer.buffer().size());
+
+ ash::vk::DescriptorBufferInfo {
+ buffer: buffer.buffer().handle(),
+ offset: buffer.offset() + range.start,
+ range: range.end - range.start,
+ }
+ })
+ .collect(),
+ )
+ }
+ WriteDescriptorSetElements::BufferView(elements) => {
+ debug_assert!(matches!(
+ descriptor_type,
+ DescriptorType::UniformTexelBuffer | DescriptorType::StorageTexelBuffer
+ ));
+ DescriptorWriteInfo::BufferView(
+ elements
+ .iter()
+ .map(|buffer_view| buffer_view.handle())
+ .collect(),
+ )
+ }
+ WriteDescriptorSetElements::ImageView(elements) => {
+ // Note: combined image sampler can occur with immutable samplers
+ debug_assert!(matches!(
+ descriptor_type,
+ DescriptorType::CombinedImageSampler
+ | DescriptorType::SampledImage
+ | DescriptorType::StorageImage
+ | DescriptorType::InputAttachment
+ ));
+ DescriptorWriteInfo::Image(
+ elements
+ .iter()
+ .map(|image_view| {
+ let layouts = image_view.image().descriptor_layouts().expect(
+ "descriptor_layouts must return Some when used in an image view",
+ );
+ ash::vk::DescriptorImageInfo {
+ sampler: ash::vk::Sampler::null(),
+ image_view: image_view.handle(),
+ image_layout: layouts.layout_for(descriptor_type).into(),
+ }
+ })
+ .collect(),
+ )
+ }
+ WriteDescriptorSetElements::ImageViewSampler(elements) => {
+ debug_assert!(matches!(
+ descriptor_type,
+ DescriptorType::CombinedImageSampler
+ ));
+ DescriptorWriteInfo::Image(
+ elements
+ .iter()
+ .map(|(image_view, sampler)| {
+ let layouts = image_view.image().descriptor_layouts().expect(
+ "descriptor_layouts must return Some when used in an image view",
+ );
+ ash::vk::DescriptorImageInfo {
+ sampler: sampler.handle(),
+ image_view: image_view.handle(),
+ image_layout: layouts.layout_for(descriptor_type).into(),
+ }
+ })
+ .collect(),
+ )
+ }
+ WriteDescriptorSetElements::Sampler(elements) => {
+ debug_assert!(matches!(descriptor_type, DescriptorType::Sampler));
+ DescriptorWriteInfo::Image(
+ elements
+ .iter()
+ .map(|sampler| ash::vk::DescriptorImageInfo {
+ sampler: sampler.handle(),
+ image_view: ash::vk::ImageView::null(),
+ image_layout: ash::vk::ImageLayout::UNDEFINED,
+ })
+ .collect(),
+ )
+ }
+ }
+ }
+
+ pub(crate) fn to_vulkan(
+ &self,
+ dst_set: ash::vk::DescriptorSet,
+ descriptor_type: DescriptorType,
+ ) -> ash::vk::WriteDescriptorSet {
+ ash::vk::WriteDescriptorSet {
+ dst_set,
+ dst_binding: self.binding,
+ dst_array_element: self.first_array_element,
+ descriptor_count: 0,
+ descriptor_type: descriptor_type.into(),
+ p_image_info: ptr::null(),
+ p_buffer_info: ptr::null(),
+ p_texel_buffer_view: ptr::null(),
+ ..Default::default()
+ }
+ }
+}
+
+/// The elements held by a `WriteDescriptorSet`.
+pub enum WriteDescriptorSetElements {
+ None(u32),
+ Buffer(SmallVec<[(Subbuffer<[u8]>, Range<DeviceSize>); 1]>),
+ BufferView(SmallVec<[Arc<BufferView>; 1]>),
+ ImageView(SmallVec<[Arc<dyn ImageViewAbstract>; 1]>),
+ ImageViewSampler(SmallVec<[(Arc<dyn ImageViewAbstract>, Arc<Sampler>); 1]>),
+ Sampler(SmallVec<[Arc<Sampler>; 1]>),
+}
+
+impl WriteDescriptorSetElements {
+ /// Returns the number of elements.
+ #[inline]
+ pub fn len(&self) -> u32 {
+ match self {
+ Self::None(num_elements) => *num_elements,
+ Self::Buffer(elements) => elements.len() as u32,
+ Self::BufferView(elements) => elements.len() as u32,
+ Self::ImageView(elements) => elements.len() as u32,
+ Self::ImageViewSampler(elements) => elements.len() as u32,
+ Self::Sampler(elements) => elements.len() as u32,
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
+pub(crate) enum DescriptorWriteInfo {
+ Image(SmallVec<[ash::vk::DescriptorImageInfo; 1]>),
+ Buffer(SmallVec<[ash::vk::DescriptorBufferInfo; 1]>),
+ BufferView(SmallVec<[ash::vk::BufferView; 1]>),
+}
+
+pub(crate) fn check_descriptor_write<'a>(
+ write: &WriteDescriptorSet,
+ layout: &'a DescriptorSetLayout,
+ variable_descriptor_count: u32,
+) -> Result<&'a DescriptorSetLayoutBinding, DescriptorSetUpdateError> {
+ fn provided_element_type(elements: &WriteDescriptorSetElements) -> &'static str {
+ match elements {
+ WriteDescriptorSetElements::None(_) => "none",
+ WriteDescriptorSetElements::Buffer(_) => "buffer",
+ WriteDescriptorSetElements::BufferView(_) => "buffer_view",
+ WriteDescriptorSetElements::ImageView(_) => "image_view",
+ WriteDescriptorSetElements::ImageViewSampler(_) => "image_view_sampler",
+ WriteDescriptorSetElements::Sampler(_) => "sampler",
+ }
+ }
+
+ let device = layout.device();
+
+ let layout_binding = match layout.bindings().get(&write.binding()) {
+ Some(binding) => binding,
+ None => {
+ return Err(DescriptorSetUpdateError::InvalidBinding {
+ binding: write.binding(),
+ })
+ }
+ };
+
+ let max_descriptor_count = if layout_binding.variable_descriptor_count {
+ variable_descriptor_count
+ } else {
+ layout_binding.descriptor_count
+ };
+
+ let binding = write.binding();
+ let elements = write.elements();
+ let num_elements = elements.len();
+ debug_assert!(num_elements != 0);
+
+ let descriptor_range_start = write.first_array_element();
+ let descriptor_range_end = descriptor_range_start + num_elements;
+
+ if descriptor_range_end > max_descriptor_count {
+ return Err(DescriptorSetUpdateError::ArrayIndexOutOfBounds {
+ binding,
+ available_count: max_descriptor_count,
+ written_count: descriptor_range_end,
+ });
+ }
+
+ match layout_binding.descriptor_type {
+ DescriptorType::Sampler => {
+ if layout_binding.immutable_samplers.is_empty() {
+ let elements = if let WriteDescriptorSetElements::Sampler(elements) = elements {
+ elements
+ } else {
+ return Err(DescriptorSetUpdateError::IncompatibleElementType {
+ binding,
+ provided_element_type: provided_element_type(elements),
+ allowed_element_types: &["sampler"],
+ });
+ };
+
+ for (index, sampler) in elements.iter().enumerate() {
+ assert_eq!(device, sampler.device());
+
+ if sampler.sampler_ycbcr_conversion().is_some() {
+ return Err(DescriptorSetUpdateError::SamplerHasSamplerYcbcrConversion {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ });
+ }
+ }
+ } else if layout.push_descriptor() {
+ // For push descriptors, we must write a dummy element.
+ if let WriteDescriptorSetElements::None(_) = elements {
+ // Do nothing
+ } else {
+ return Err(DescriptorSetUpdateError::IncompatibleElementType {
+ binding,
+ provided_element_type: provided_element_type(elements),
+ allowed_element_types: &["none"],
+ });
+ }
+ } else {
+ // For regular descriptors, no element must be written.
+ return Err(DescriptorSetUpdateError::IncompatibleElementType {
+ binding,
+ provided_element_type: provided_element_type(elements),
+ allowed_element_types: &[],
+ });
+ }
+ }
+
+ DescriptorType::CombinedImageSampler => {
+ if layout_binding.immutable_samplers.is_empty() {
+ let elements =
+ if let WriteDescriptorSetElements::ImageViewSampler(elements) = elements {
+ elements
+ } else {
+ return Err(DescriptorSetUpdateError::IncompatibleElementType {
+ binding,
+ provided_element_type: provided_element_type(elements),
+ allowed_element_types: &["image_view_sampler"],
+ });
+ };
+
+ for (index, (image_view, sampler)) in elements.iter().enumerate() {
+ assert_eq!(device, image_view.device());
+ assert_eq!(device, sampler.device());
+
+ // VUID-VkWriteDescriptorSet-descriptorType-00337
+ if !image_view.usage().intersects(ImageUsage::SAMPLED) {
+ return Err(DescriptorSetUpdateError::MissingUsage {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ usage: "sampled",
+ });
+ }
+
+ // VUID-VkDescriptorImageInfo-imageView-00343
+ if matches!(
+ image_view.view_type(),
+ ImageViewType::Dim2d | ImageViewType::Dim2dArray
+ ) && image_view.image().inner().image.dimensions().image_type()
+ == ImageType::Dim3d
+ {
+ return Err(DescriptorSetUpdateError::ImageView2dFrom3d {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ });
+ }
+
+ // VUID-VkDescriptorImageInfo-imageView-01976
+ if image_view
+ .subresource_range()
+ .aspects
+ .contains(ImageAspects::DEPTH | ImageAspects::STENCIL)
+ {
+ return Err(DescriptorSetUpdateError::ImageViewDepthAndStencil {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ });
+ }
+
+ // VUID-VkDescriptorImageInfo-mutableComparisonSamplers-04450
+ if device.enabled_extensions().khr_portability_subset
+ && !device.enabled_features().mutable_comparison_samplers
+ && sampler.compare().is_some()
+ {
+ return Err(DescriptorSetUpdateError::RequirementNotMet {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ required_for: "this device is a portability subset device, and \
+ `sampler.compare()` is `Some`",
+ requires_one_of: RequiresOneOf {
+ features: &["mutable_comparison_samplers"],
+ ..Default::default()
+ },
+ });
+ }
+
+ if image_view.sampler_ycbcr_conversion().is_some() {
+ return Err(
+ DescriptorSetUpdateError::ImageViewHasSamplerYcbcrConversion {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ },
+ );
+ }
+
+ if sampler.sampler_ycbcr_conversion().is_some() {
+ return Err(DescriptorSetUpdateError::SamplerHasSamplerYcbcrConversion {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ });
+ }
+
+ if let Err(error) = sampler.check_can_sample(image_view.as_ref()) {
+ return Err(DescriptorSetUpdateError::ImageViewIncompatibleSampler {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ error,
+ });
+ }
+ }
+ } else {
+ let elements = if let WriteDescriptorSetElements::ImageView(elements) = elements {
+ elements
+ } else {
+ return Err(DescriptorSetUpdateError::IncompatibleElementType {
+ binding,
+ provided_element_type: provided_element_type(elements),
+ allowed_element_types: &["image_view"],
+ });
+ };
+
+ let immutable_samplers = &layout_binding.immutable_samplers
+ [descriptor_range_start as usize..descriptor_range_end as usize];
+
+ for (index, (image_view, sampler)) in
+ elements.iter().zip(immutable_samplers).enumerate()
+ {
+ assert_eq!(device, image_view.device());
+
+ // VUID-VkWriteDescriptorSet-descriptorType-00337
+ if !image_view.usage().intersects(ImageUsage::SAMPLED) {
+ return Err(DescriptorSetUpdateError::MissingUsage {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ usage: "sampled",
+ });
+ }
+
+ // VUID-VkDescriptorImageInfo-imageView-00343
+ if matches!(
+ image_view.view_type(),
+ ImageViewType::Dim2d | ImageViewType::Dim2dArray
+ ) && image_view.image().inner().image.dimensions().image_type()
+ == ImageType::Dim3d
+ {
+ return Err(DescriptorSetUpdateError::ImageView2dFrom3d {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ });
+ }
+
+ // VUID-VkDescriptorImageInfo-imageView-01976
+ if image_view
+ .subresource_range()
+ .aspects
+ .contains(ImageAspects::DEPTH | ImageAspects::STENCIL)
+ {
+ return Err(DescriptorSetUpdateError::ImageViewDepthAndStencil {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ });
+ }
+
+ if let Err(error) = sampler.check_can_sample(image_view.as_ref()) {
+ return Err(DescriptorSetUpdateError::ImageViewIncompatibleSampler {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ error,
+ });
+ }
+ }
+ }
+ }
+
+ DescriptorType::SampledImage => {
+ let elements = if let WriteDescriptorSetElements::ImageView(elements) = elements {
+ elements
+ } else {
+ return Err(DescriptorSetUpdateError::IncompatibleElementType {
+ binding,
+ provided_element_type: provided_element_type(elements),
+ allowed_element_types: &["image_view"],
+ });
+ };
+
+ for (index, image_view) in elements.iter().enumerate() {
+ assert_eq!(device, image_view.device());
+
+ // VUID-VkWriteDescriptorSet-descriptorType-00337
+ if !image_view.usage().intersects(ImageUsage::SAMPLED) {
+ return Err(DescriptorSetUpdateError::MissingUsage {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ usage: "sampled",
+ });
+ }
+
+ // VUID-VkDescriptorImageInfo-imageView-00343
+ if matches!(
+ image_view.view_type(),
+ ImageViewType::Dim2d | ImageViewType::Dim2dArray
+ ) && image_view.image().inner().image.dimensions().image_type()
+ == ImageType::Dim3d
+ {
+ return Err(DescriptorSetUpdateError::ImageView2dFrom3d {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ });
+ }
+
+ // VUID-VkDescriptorImageInfo-imageView-01976
+ if image_view
+ .subresource_range()
+ .aspects
+ .contains(ImageAspects::DEPTH | ImageAspects::STENCIL)
+ {
+ return Err(DescriptorSetUpdateError::ImageViewDepthAndStencil {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ });
+ }
+
+ // VUID-VkWriteDescriptorSet-descriptorType-01946
+ if image_view.sampler_ycbcr_conversion().is_some() {
+ return Err(
+ DescriptorSetUpdateError::ImageViewHasSamplerYcbcrConversion {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ },
+ );
+ }
+ }
+ }
+
+ DescriptorType::StorageImage => {
+ let elements = if let WriteDescriptorSetElements::ImageView(elements) = elements {
+ elements
+ } else {
+ return Err(DescriptorSetUpdateError::IncompatibleElementType {
+ binding,
+ provided_element_type: provided_element_type(elements),
+ allowed_element_types: &["image_view"],
+ });
+ };
+
+ for (index, image_view) in elements.iter().enumerate() {
+ assert_eq!(device, image_view.device());
+
+ // VUID-VkWriteDescriptorSet-descriptorType-00339
+ if !image_view.usage().intersects(ImageUsage::STORAGE) {
+ return Err(DescriptorSetUpdateError::MissingUsage {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ usage: "storage",
+ });
+ }
+
+ // VUID-VkDescriptorImageInfo-imageView-00343
+ if matches!(
+ image_view.view_type(),
+ ImageViewType::Dim2d | ImageViewType::Dim2dArray
+ ) && image_view.image().inner().image.dimensions().image_type()
+ == ImageType::Dim3d
+ {
+ return Err(DescriptorSetUpdateError::ImageView2dFrom3d {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ });
+ }
+
+ // VUID-VkDescriptorImageInfo-imageView-01976
+ if image_view
+ .subresource_range()
+ .aspects
+ .contains(ImageAspects::DEPTH | ImageAspects::STENCIL)
+ {
+ return Err(DescriptorSetUpdateError::ImageViewDepthAndStencil {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ });
+ }
+
+ // VUID-VkWriteDescriptorSet-descriptorType-00336
+ if !image_view.component_mapping().is_identity() {
+ return Err(DescriptorSetUpdateError::ImageViewNotIdentitySwizzled {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ });
+ }
+
+ // VUID??
+ if image_view.sampler_ycbcr_conversion().is_some() {
+ return Err(
+ DescriptorSetUpdateError::ImageViewHasSamplerYcbcrConversion {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ },
+ );
+ }
+ }
+ }
+
+ DescriptorType::UniformTexelBuffer => {
+ let elements = if let WriteDescriptorSetElements::BufferView(elements) = elements {
+ elements
+ } else {
+ return Err(DescriptorSetUpdateError::IncompatibleElementType {
+ binding,
+ provided_element_type: provided_element_type(elements),
+ allowed_element_types: &["buffer_view"],
+ });
+ };
+
+ for (index, buffer_view) in elements.iter().enumerate() {
+ assert_eq!(device, buffer_view.device());
+
+ if !buffer_view
+ .buffer()
+ .buffer()
+ .usage()
+ .intersects(BufferUsage::UNIFORM_TEXEL_BUFFER)
+ {
+ return Err(DescriptorSetUpdateError::MissingUsage {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ usage: "uniform_texel_buffer",
+ });
+ }
+ }
+ }
+
+ DescriptorType::StorageTexelBuffer => {
+ let elements = if let WriteDescriptorSetElements::BufferView(elements) = elements {
+ elements
+ } else {
+ return Err(DescriptorSetUpdateError::IncompatibleElementType {
+ binding,
+ provided_element_type: provided_element_type(elements),
+ allowed_element_types: &["buffer_view"],
+ });
+ };
+
+ for (index, buffer_view) in elements.iter().enumerate() {
+ assert_eq!(device, buffer_view.device());
+
+ // TODO: storage_texel_buffer_atomic
+ if !buffer_view
+ .buffer()
+ .buffer()
+ .usage()
+ .intersects(BufferUsage::STORAGE_TEXEL_BUFFER)
+ {
+ return Err(DescriptorSetUpdateError::MissingUsage {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ usage: "storage_texel_buffer",
+ });
+ }
+ }
+ }
+
+ DescriptorType::UniformBuffer | DescriptorType::UniformBufferDynamic => {
+ let elements = if let WriteDescriptorSetElements::Buffer(elements) = elements {
+ elements
+ } else {
+ return Err(DescriptorSetUpdateError::IncompatibleElementType {
+ binding,
+ provided_element_type: provided_element_type(elements),
+ allowed_element_types: &["buffer"],
+ });
+ };
+
+ for (index, (buffer, range)) in elements.iter().enumerate() {
+ assert_eq!(device, buffer.device());
+
+ if !buffer
+ .buffer()
+ .usage()
+ .intersects(BufferUsage::UNIFORM_BUFFER)
+ {
+ return Err(DescriptorSetUpdateError::MissingUsage {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ usage: "uniform_buffer",
+ });
+ }
+
+ assert!(!range.is_empty());
+
+ if range.end > buffer.size() {
+ return Err(DescriptorSetUpdateError::RangeOutOfBufferBounds {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ range_end: range.end,
+ buffer_size: buffer.size(),
+ });
+ }
+ }
+ }
+
+ DescriptorType::StorageBuffer | DescriptorType::StorageBufferDynamic => {
+ let elements = if let WriteDescriptorSetElements::Buffer(elements) = elements {
+ elements
+ } else {
+ return Err(DescriptorSetUpdateError::IncompatibleElementType {
+ binding,
+ provided_element_type: provided_element_type(elements),
+ allowed_element_types: &["buffer"],
+ });
+ };
+
+ for (index, (buffer, range)) in elements.iter().enumerate() {
+ assert_eq!(device, buffer.device());
+
+ if !buffer
+ .buffer()
+ .usage()
+ .intersects(BufferUsage::STORAGE_BUFFER)
+ {
+ return Err(DescriptorSetUpdateError::MissingUsage {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ usage: "storage_buffer",
+ });
+ }
+
+ assert!(!range.is_empty());
+
+ if range.end > buffer.size() {
+ return Err(DescriptorSetUpdateError::RangeOutOfBufferBounds {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ range_end: range.end,
+ buffer_size: buffer.size(),
+ });
+ }
+ }
+ }
+
+ DescriptorType::InputAttachment => {
+ let elements = if let WriteDescriptorSetElements::ImageView(elements) = elements {
+ elements
+ } else {
+ return Err(DescriptorSetUpdateError::IncompatibleElementType {
+ binding,
+ provided_element_type: provided_element_type(elements),
+ allowed_element_types: &["image_view"],
+ });
+ };
+
+ for (index, image_view) in elements.iter().enumerate() {
+ assert_eq!(device, image_view.device());
+
+ // VUID-VkWriteDescriptorSet-descriptorType-00338
+ if !image_view.usage().intersects(ImageUsage::INPUT_ATTACHMENT) {
+ return Err(DescriptorSetUpdateError::MissingUsage {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ usage: "input_attachment",
+ });
+ }
+
+ // VUID-VkDescriptorImageInfo-imageView-00343
+ if matches!(
+ image_view.view_type(),
+ ImageViewType::Dim2d | ImageViewType::Dim2dArray
+ ) && image_view.image().inner().image.dimensions().image_type()
+ == ImageType::Dim3d
+ {
+ return Err(DescriptorSetUpdateError::ImageView2dFrom3d {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ });
+ }
+
+ // VUID-VkDescriptorImageInfo-imageView-01976
+ if image_view
+ .subresource_range()
+ .aspects
+ .contains(ImageAspects::DEPTH | ImageAspects::STENCIL)
+ {
+ return Err(DescriptorSetUpdateError::ImageViewDepthAndStencil {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ });
+ }
+
+ // VUID-VkWriteDescriptorSet-descriptorType-00336
+ if !image_view.component_mapping().is_identity() {
+ return Err(DescriptorSetUpdateError::ImageViewNotIdentitySwizzled {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ });
+ }
+
+ // VUID??
+ if image_view.sampler_ycbcr_conversion().is_some() {
+ return Err(
+ DescriptorSetUpdateError::ImageViewHasSamplerYcbcrConversion {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ },
+ );
+ }
+
+ // VUID??
+ if image_view.view_type().is_arrayed() {
+ return Err(DescriptorSetUpdateError::ImageViewIsArrayed {
+ binding: write.binding(),
+ index: descriptor_range_start + index as u32,
+ });
+ }
+ }
+ }
+ }
+
+ Ok(layout_binding)
+}
+
+#[derive(Clone, Copy, Debug)]
+pub enum DescriptorSetUpdateError {
+ RequirementNotMet {
+ binding: u32,
+ index: u32,
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+
+ /// Tried to write more elements than were available in a binding.
+ ArrayIndexOutOfBounds {
+ /// Binding that is affected.
+ binding: u32,
+ /// Number of available descriptors in the binding.
+ available_count: u32,
+ /// The number of descriptors that were in the update.
+ written_count: u32,
+ },
+
+ /// Tried to write an image view with a 2D type and a 3D underlying image.
+ ImageView2dFrom3d { binding: u32, index: u32 },
+
+ /// Tried to write an image view that has both the `depth` and `stencil` aspects.
+ ImageViewDepthAndStencil { binding: u32, index: u32 },
+
+ /// Tried to write an image view with an attached sampler YCbCr conversion to a binding that
+ /// does not support it.
+ ImageViewHasSamplerYcbcrConversion { binding: u32, index: u32 },
+
+ /// Tried to write an image view of an arrayed type to a descriptor type that does not support
+ /// it.
+ ImageViewIsArrayed { binding: u32, index: u32 },
+
+ /// Tried to write an image view that was not compatible with the sampler that was provided as
+ /// part of the update or immutably in the layout.
+ ImageViewIncompatibleSampler {
+ binding: u32,
+ index: u32,
+ error: SamplerImageViewIncompatibleError,
+ },
+
+ /// Tried to write an image view to a descriptor type that requires it to be identity swizzled,
+ /// but it was not.
+ ImageViewNotIdentitySwizzled { binding: u32, index: u32 },
+
+ /// Tried to write an element type that was not compatible with the descriptor type in the
+ /// layout.
+ IncompatibleElementType {
+ binding: u32,
+ provided_element_type: &'static str,
+ allowed_element_types: &'static [&'static str],
+ },
+
+ /// Tried to write to a nonexistent binding.
+ InvalidBinding { binding: u32 },
+
+ /// A resource was missing a usage flag that was required.
+ MissingUsage {
+ binding: u32,
+ index: u32,
+ usage: &'static str,
+ },
+
+ /// The end of the provided `range` for a buffer is larger than the size of the buffer.
+ RangeOutOfBufferBounds {
+ binding: u32,
+ index: u32,
+ range_end: DeviceSize,
+ buffer_size: DeviceSize,
+ },
+
+ /// Tried to write a sampler that has an attached sampler YCbCr conversion.
+ SamplerHasSamplerYcbcrConversion { binding: u32, index: u32 },
+}
+
+impl Error for DescriptorSetUpdateError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::ImageViewIncompatibleSampler { error, .. } => Some(error),
+ _ => None,
+ }
+ }
+}
+
+impl Display for DescriptorSetUpdateError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::RequirementNotMet {
+ binding,
+ index,
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement on binding {} index {} was not met for: {}; requires one of: {}",
+ binding, index, required_for, requires_one_of,
+ ),
+
+ Self::ArrayIndexOutOfBounds {
+ binding,
+ available_count,
+ written_count,
+ } => write!(
+ f,
+ "tried to write up to element {} to binding {}, but only {} descriptors are \
+ available",
+ written_count, binding, available_count,
+ ),
+ Self::ImageView2dFrom3d { binding, index } => write!(
+ f,
+ "tried to write an image view to binding {} index {} with a 2D type and a 3D \
+ underlying image",
+ binding, index,
+ ),
+ Self::ImageViewDepthAndStencil { binding, index } => write!(
+ f,
+ "tried to write an image view to binding {} index {} that has both the `depth` and \
+ `stencil` aspects",
+ binding, index,
+ ),
+ Self::ImageViewHasSamplerYcbcrConversion { binding, index } => write!(
+ f,
+ "tried to write an image view to binding {} index {} with an attached sampler \
+ YCbCr conversion to binding that does not support it",
+ binding, index,
+ ),
+ Self::ImageViewIsArrayed { binding, index } => write!(
+ f,
+ "tried to write an image view of an arrayed type to binding {} index {}, but this \
+ binding has a descriptor type that does not support arrayed image views",
+ binding, index,
+ ),
+ Self::ImageViewIncompatibleSampler { binding, index, .. } => write!(
+ f,
+ "tried to write an image view to binding {} index {}, that was not compatible with \
+ the sampler that was provided as part of the update or immutably in the layout",
+ binding, index,
+ ),
+ Self::ImageViewNotIdentitySwizzled { binding, index } => write!(
+ f,
+ "tried to write an image view with non-identity swizzling to binding {} index {}, \
+ but this binding has a descriptor type that requires it to be identity swizzled",
+ binding, index,
+ ),
+ Self::IncompatibleElementType {
+ binding,
+ provided_element_type,
+ allowed_element_types,
+ } => write!(
+ f,
+ "tried to write a resource to binding {} whose type ({}) was not one of the \
+ resource types allowed for the descriptor type (",
+ binding, provided_element_type,
+ )
+ .and_then(|_| {
+ let mut first = true;
+
+ for elem_type in *allowed_element_types {
+ if first {
+ write!(f, "{}", elem_type)?;
+ first = false;
+ } else {
+ write!(f, ", {}", elem_type)?;
+ }
+ }
+
+ Ok(())
+ })
+ .and_then(|_| write!(f, ") that can be bound to this buffer")),
+ Self::InvalidBinding { binding } => {
+ write!(f, "tried to write to a nonexistent binding {}", binding,)
+ }
+ Self::MissingUsage {
+ binding,
+ index,
+ usage,
+ } => write!(
+ f,
+ "tried to write a resource to binding {} index {} that did not have the required \
+ usage {} enabled",
+ binding, index, usage,
+ ),
+ Self::RangeOutOfBufferBounds {
+ binding,
+ index,
+ range_end,
+ buffer_size,
+ } => write!(
+ f,
+ "the end of the provided `range` for the buffer at binding {} index {} ({:?}) is
+ larger than the size of the buffer ({})",
+ binding, index, range_end, buffer_size,
+ ),
+ Self::SamplerHasSamplerYcbcrConversion { binding, index } => write!(
+ f,
+ "tried to write a sampler to binding {} index {} that has an attached sampler \
+ YCbCr conversion",
+ binding, index,
+ ),
+ }
+ }
+}
diff --git a/src/device/extensions.rs b/src/device/extensions.rs
index b6d0c44..a4b29c1 100644
--- a/src/device/extensions.rs
+++ b/src/device/extensions.rs
@@ -7,148 +7,10 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use crate::device::physical::PhysicalDevice;
-pub use crate::extensions::{
- ExtensionRestriction, ExtensionRestrictionError, SupportedExtensionsError,
-};
+pub use crate::extensions::{ExtensionRestriction, ExtensionRestrictionError};
-macro_rules! device_extensions {
- (
- $($member:ident => {
- doc: $doc:expr,
- raw: $raw:expr,
- requires_core: $requires_core:expr,
- requires_device_extensions: [$($requires_device_extension:ident),*],
- requires_instance_extensions: [$($requires_instance_extension:ident),*],
- required_if_supported: $required_if_supported:expr,
- conflicts_device_extensions: [$($conflicts_device_extension:ident),*],
- },)*
- ) => (
- extensions! {
- DeviceExtensions,
- $( $member => {
- doc: $doc,
- raw: $raw,
- requires_core: $requires_core,
- requires_device_extensions: [$($requires_device_extension),*],
- requires_instance_extensions: [$($requires_instance_extension),*],
- },)*
- }
-
- impl DeviceExtensions {
- /// Checks enabled extensions against the device version, instance extensions and each other.
- pub(super) fn check_requirements(
- &self,
- supported: &DeviceExtensions,
- api_version: crate::Version,
- instance_extensions: &InstanceExtensions,
- ) -> Result<(), crate::extensions::ExtensionRestrictionError> {
- $(
- if self.$member {
- if !supported.$member {
- return Err(crate::extensions::ExtensionRestrictionError {
- extension: stringify!($member),
- restriction: crate::extensions::ExtensionRestriction::NotSupported,
- });
- }
-
- if api_version < $requires_core {
- return Err(crate::extensions::ExtensionRestrictionError {
- extension: stringify!($member),
- restriction: crate::extensions::ExtensionRestriction::RequiresCore($requires_core),
- });
- }
-
- $(
- if !self.$requires_device_extension {
- return Err(crate::extensions::ExtensionRestrictionError {
- extension: stringify!($member),
- restriction: crate::extensions::ExtensionRestriction::RequiresDeviceExtension(stringify!($requires_device_extension)),
- });
- }
- )*
-
- $(
- if !instance_extensions.$requires_instance_extension {
- return Err(crate::extensions::ExtensionRestrictionError {
- extension: stringify!($member),
- restriction: crate::extensions::ExtensionRestriction::RequiresInstanceExtension(stringify!($requires_instance_extension)),
- });
- }
- )*
-
- $(
- if self.$conflicts_device_extension {
- return Err(crate::extensions::ExtensionRestrictionError {
- extension: stringify!($member),
- restriction: crate::extensions::ExtensionRestriction::ConflictsDeviceExtension(stringify!($conflicts_device_extension)),
- });
- }
- )*
- } else {
- if $required_if_supported && supported.$member {
- return Err(crate::extensions::ExtensionRestrictionError {
- extension: stringify!($member),
- restriction: crate::extensions::ExtensionRestriction::RequiredIfSupported,
- });
- }
- }
- )*
- Ok(())
- }
-
- pub(crate) fn required_if_supported_extensions() -> Self {
- Self {
- $(
- $member: $required_if_supported,
- )*
- _unbuildable: crate::extensions::Unbuildable(())
- }
- }
- }
- );
-}
-
-pub use crate::autogen::DeviceExtensions;
-pub(crate) use device_extensions;
-
-impl DeviceExtensions {
- /// See the docs of supported_by_device().
- #[deprecated(
- since = "0.25",
- note = "Use PhysicalDevice::supported_extensions instead"
- )]
- pub fn supported_by_device_raw(
- physical_device: PhysicalDevice,
- ) -> Result<Self, SupportedExtensionsError> {
- Ok(*physical_device.supported_extensions())
- }
-
- /// Returns a `DeviceExtensions` object with extensions supported by the `PhysicalDevice`.
- #[deprecated(
- since = "0.25",
- note = "Use PhysicalDevice::supported_extensions instead"
- )]
- pub fn supported_by_device(physical_device: PhysicalDevice) -> Self {
- *physical_device.supported_extensions()
- }
-
- /// Returns a `DeviceExtensions` object with extensions required as well as supported by the `PhysicalDevice`.
- /// They are needed to be passed to `Device::new(...)`.
- #[deprecated(
- since = "0.25",
- note = "Use PhysicalDevice::required_extensions instead"
- )]
- pub fn required_extensions(physical_device: PhysicalDevice) -> Self {
- *physical_device.required_extensions()
- }
-}
-
-/// This helper type can only be instantiated inside this module.
-/// See `*Extensions::_unbuildable`.
-#[doc(hidden)]
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct Unbuildable(());
+// Generated by build.rs
+include!(concat!(env!("OUT_DIR"), "/device_extensions.rs"));
#[cfg(test)]
mod tests {
@@ -157,18 +19,22 @@ mod tests {
#[test]
fn empty_extensions() {
- let d: Vec<CString> = (&DeviceExtensions::none()).into();
- assert!(d.iter().next().is_none());
+ let d: Vec<CString> = (&DeviceExtensions::empty()).into();
+ assert!(d.get(0).is_none());
}
#[test]
- fn required_if_supported_extensions() {
- assert_eq!(
- DeviceExtensions::required_if_supported_extensions(),
- DeviceExtensions {
- khr_portability_subset: true,
- ..DeviceExtensions::none()
+ fn into_iter() {
+ let extensions = DeviceExtensions {
+ khr_swapchain: true,
+ ..DeviceExtensions::empty()
+ };
+ for (name, enabled) in extensions {
+ if name == "VK_KHR_swapchain" {
+ assert!(enabled);
+ } else {
+ assert!(!enabled);
}
- )
+ }
}
}
diff --git a/src/device/features.rs b/src/device/features.rs
index 1d83545..592ce3b 100644
--- a/src/device/features.rs
+++ b/src/device/features.rs
@@ -7,179 +7,13 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use std::error;
-use std::fmt;
+use std::{
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+};
-macro_rules! features {
- {
- $($member:ident => {
- doc: $doc:expr,
- ffi_name: $ffi_field:ident,
- ffi_members: [$($ffi_struct:ident $(.$ffi_struct_field:ident)?),+],
- requires_features: [$($requires_feature:ident),*],
- conflicts_features: [$($conflicts_feature:ident),*],
- required_by_extensions: [$($required_by_extension:ident),*],
- },)*
- } => {
- /// Represents all the features that are available on a physical device or enabled on
- /// a logical device.
- ///
- /// Note that the `robust_buffer_access` is guaranteed to be supported by all Vulkan
- /// implementations.
- ///
- /// # Example
- ///
- /// ```
- /// use vulkano::device::Features;
- /// # let physical_device: vulkano::device::physical::PhysicalDevice = return;
- /// let minimal_features = Features {
- /// geometry_shader: true,
- /// .. Features::none()
- /// };
- ///
- /// let optimal_features = vulkano::device::Features {
- /// geometry_shader: true,
- /// tessellation_shader: true,
- /// .. Features::none()
- /// };
- ///
- /// if !physical_device.supported_features().is_superset_of(&minimal_features) {
- /// panic!("The physical device is not good enough for this application.");
- /// }
- ///
- /// assert!(optimal_features.is_superset_of(&minimal_features));
- /// let features_to_request = optimal_features.intersection(physical_device.supported_features());
- /// ```
- ///
- #[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
- #[allow(missing_docs)]
- pub struct Features {
- $(
- #[doc = $doc]
- pub $member: bool,
- )*
- }
-
- impl Features {
- /// Checks enabled features against the device version, device extensions and each other.
- pub(super) fn check_requirements(
- &self,
- supported: &Features,
- api_version:
- crate::Version,
- extensions: &crate::device::DeviceExtensions,
- ) -> Result<(), crate::device::features::FeatureRestrictionError> {
- $(
- if self.$member {
- if !supported.$member {
- return Err(crate::device::features::FeatureRestrictionError {
- feature: stringify!($member),
- restriction: crate::device::features::FeatureRestriction::NotSupported,
- });
- }
-
- $(
- if !self.$requires_feature {
- return Err(crate::device::features::FeatureRestrictionError {
- feature: stringify!($member),
- restriction: crate::device::features::FeatureRestriction::RequiresFeature(stringify!($requires_feature)),
- });
- }
- )*
-
- $(
- if self.$conflicts_feature {
- return Err(crate::device::features::FeatureRestrictionError {
- feature: stringify!($member),
- restriction: crate::device::features::FeatureRestriction::ConflictsFeature(stringify!($conflicts_feature)),
- });
- }
- )*
- } else {
- $(
- if extensions.$required_by_extension {
- return Err(crate::device::features::FeatureRestrictionError {
- feature: stringify!($member),
- restriction: crate::device::features::FeatureRestriction::RequiredByExtension(stringify!($required_by_extension)),
- });
- }
- )*
- }
- )*
- Ok(())
- }
-
- /// Builds a `Features` object with all values to false.
- pub const fn none() -> Features {
- Features {
- $($member: false,)*
- }
- }
-
- /// Builds a `Features` object with all values to true.
- ///
- /// > **Note**: This function is used for testing purposes, and is probably useless in
- /// > a real code.
- pub const fn all() -> Features {
- Features {
- $($member: true,)*
- }
- }
-
- /// Returns true if `self` is a superset of the parameter.
- ///
- /// That is, for each feature of the parameter that is true, the corresponding value
- /// in self is true as well.
- pub fn is_superset_of(&self, other: &Features) -> bool {
- $((self.$member == true || other.$member == false))&&+
- }
-
- /// Builds a `Features` that is the intersection of `self` and another `Features`
- /// object.
- ///
- /// The result's field will be true if it is also true in both `self` and `other`.
- pub fn intersection(&self, other: &Features) -> Features {
- Features {
- $($member: self.$member && other.$member,)*
- }
- }
-
- /// Builds a `Features` that is the difference of another `Features` object from `self`.
- ///
- /// The result's field will be true if it is true in `self` but not `other`.
- pub fn difference(&self, other: &Features) -> Features {
- Features {
- $($member: self.$member && !other.$member,)*
- }
- }
- }
-
- impl FeaturesFfi {
- pub(crate) fn write(&mut self, features: &Features) {
- $(
- std::array::IntoIter::new([
- $(self.$ffi_struct.as_mut().map(|s| &mut s$(.$ffi_struct_field)?.$ffi_field)),+
- ]).flatten().next().map(|f| *f = features.$member as ash::vk::Bool32);
- )*
- }
- }
-
- impl From<&FeaturesFfi> for Features {
- fn from(features_ffi: &FeaturesFfi) -> Self {
- Features {
- $(
- $member: std::array::IntoIter::new([
- $(features_ffi.$ffi_struct.map(|s| s$(.$ffi_struct_field)?.$ffi_field)),+
- ]).flatten().next().unwrap_or(0) != 0,
- )*
- }
- }
- }
- };
-}
-
-pub use crate::autogen::Features;
-pub(crate) use features;
+// Generated by build.rs
+include!(concat!(env!("OUT_DIR"), "/features.rs"));
/// An error that can happen when enabling a feature on a device.
#[derive(Clone, Copy, Debug)]
@@ -190,13 +24,12 @@ pub struct FeatureRestrictionError {
pub restriction: FeatureRestriction,
}
-impl error::Error for FeatureRestrictionError {}
+impl Error for FeatureRestrictionError {}
-impl fmt::Display for FeatureRestrictionError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+impl Display for FeatureRestrictionError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
write!(
- fmt,
+ f,
"a restriction for the feature {} was not met: {}",
self.feature, self.restriction,
)
@@ -215,76 +48,41 @@ pub enum FeatureRestriction {
RequiredByExtension(&'static str),
}
-impl fmt::Display for FeatureRestriction {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+impl Display for FeatureRestriction {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
match *self {
FeatureRestriction::NotSupported => {
- write!(fmt, "not supported by the physical device")
+ write!(f, "not supported by the physical device")
}
FeatureRestriction::RequiresFeature(feat) => {
- write!(fmt, "requires feature {} to be enabled", feat)
+ write!(f, "requires feature {} to be enabled", feat)
}
FeatureRestriction::ConflictsFeature(feat) => {
- write!(fmt, "requires feature {} to be disabled", feat)
+ write!(f, "requires feature {} to be disabled", feat)
}
FeatureRestriction::RequiredByExtension(ext) => {
- write!(fmt, "required to be enabled by extension {}", ext)
+ write!(f, "required to be enabled by extension {}", ext)
}
}
}
}
-macro_rules! features_ffi {
- {
- $api_version:ident,
- $device_extensions:ident,
- $instance_extensions:ident,
- $($member:ident => {
- ty: $ty:ident,
- provided_by: [$($provided_by:expr),+],
- conflicts: [$($conflicts:ident),*],
- },)+
- } => {
- #[derive(Default)]
- pub(crate) struct FeaturesFfi {
- features_vulkan10: Option<ash::vk::PhysicalDeviceFeatures2KHR>,
-
- $(
- $member: Option<ash::vk::$ty>,
- )+
- }
-
- impl FeaturesFfi {
- pub(crate) fn make_chain(
- &mut self,
- $api_version: crate::Version,
- $device_extensions: &DeviceExtensions,
- $instance_extensions: &InstanceExtensions,
- ) {
- self.features_vulkan10 = Some(Default::default());
- let head = self.features_vulkan10.as_mut().unwrap();
-
- $(
- if std::array::IntoIter::new([$($provided_by),+]).any(|x| x) &&
- std::array::IntoIter::new([$(self.$conflicts.is_none()),*]).all(|x| x) {
- self.$member = Some(Default::default());
- let member = self.$member.as_mut().unwrap();
- member.p_next = head.p_next;
- head.p_next = member as *mut _ as _;
- }
- )+
- }
-
- pub(crate) fn head_as_ref(&self) -> &ash::vk::PhysicalDeviceFeatures2KHR {
- self.features_vulkan10.as_ref().unwrap()
- }
-
- pub(crate) fn head_as_mut(&mut self) -> &mut ash::vk::PhysicalDeviceFeatures2KHR {
- self.features_vulkan10.as_mut().unwrap()
+#[cfg(test)]
+mod tests {
+ use super::Features;
+
+ #[test]
+ fn into_iter() {
+ let features = Features {
+ tessellation_shader: true,
+ ..Features::empty()
+ };
+ for (name, enabled) in features {
+ if name == "tessellationShader" {
+ assert!(enabled);
+ } else {
+ assert!(!enabled);
}
}
- };
+ }
}
-
-pub(crate) use {crate::autogen::FeaturesFfi, features_ffi};
diff --git a/src/device/mod.rs b/src/device/mod.rs
index 036ef5d..af5354d 100644
--- a/src/device/mod.rs
+++ b/src/device/mod.rs
@@ -15,31 +15,42 @@
//! Basic example:
//!
//! ```no_run
-//! use vulkano::device::Device;
-//! use vulkano::device::DeviceExtensions;
-//! use vulkano::device::Features;
-//! use vulkano::instance::Instance;
-//! use vulkano::instance::InstanceExtensions;
-//! use vulkano::device::physical::PhysicalDevice;
-//! use vulkano::Version;
+//! use vulkano::{
+//! device::{physical::PhysicalDevice, Device, DeviceCreateInfo, DeviceExtensions, Features, QueueCreateInfo},
+//! instance::{Instance, InstanceExtensions},
+//! Version, VulkanLibrary,
+//! };
//!
//! // Creating the instance. See the documentation of the `instance` module.
-//! let instance = match Instance::new(None, Version::V1_1, &InstanceExtensions::none(), None) {
-//! Ok(i) => i,
-//! Err(err) => panic!("Couldn't build instance: {:?}", err)
-//! };
+//! let library = VulkanLibrary::new()
+//! .unwrap_or_else(|err| panic!("Couldn't load Vulkan library: {:?}", err));
+//! let instance = Instance::new(library, Default::default())
+//! .unwrap_or_else(|err| panic!("Couldn't create instance: {:?}", err));
//!
//! // We just choose the first physical device. In a real application you would choose depending
//! // on the capabilities of the physical device and the user's preferences.
-//! let physical_device = PhysicalDevice::enumerate(&instance).next().expect("No physical device");
+//! let physical_device = instance
+//! .enumerate_physical_devices()
+//! .unwrap_or_else(|err| panic!("Couldn't enumerate physical devices: {:?}", err))
+//! .next().expect("No physical device");
//!
//! // Here is the device-creating code.
//! let device = {
-//! let queue_family = physical_device.queue_families().next().unwrap();
-//! let features = Features::none();
-//! let ext = DeviceExtensions::none();
+//! let features = Features::empty();
+//! let extensions = DeviceExtensions::empty();
//!
-//! match Device::new(physical_device, &features, &ext, Some((queue_family, 1.0))) {
+//! match Device::new(
+//! physical_device,
+//! DeviceCreateInfo {
+//! enabled_extensions: extensions,
+//! enabled_features: features,
+//! queue_create_infos: vec![QueueCreateInfo {
+//! queue_family_index: 0,
+//! ..Default::default()
+//! }],
+//! ..Default::default()
+//! },
+//! ) {
//! Ok(d) => d,
//! Err(err) => panic!("Couldn't build device: {:?}", err)
//! }
@@ -90,130 +101,191 @@
//!
//! TODO: write
-pub(crate) use self::features::FeaturesFfi;
-pub use self::features::{FeatureRestriction, FeatureRestrictionError, Features};
-pub use self::properties::Properties;
-pub(crate) use self::properties::PropertiesFfi;
-pub use crate::autogen::DeviceExtensions;
-use crate::check_errors;
-use crate::command_buffer::pool::StandardCommandPool;
-use crate::descriptor_set::pool::StdDescriptorPool;
-use crate::device::physical::PhysicalDevice;
-use crate::device::physical::QueueFamily;
-pub use crate::extensions::{
- ExtensionRestriction, ExtensionRestrictionError, SupportedExtensionsError,
+use self::physical::PhysicalDevice;
+pub(crate) use self::{features::FeaturesFfi, properties::PropertiesFfi};
+pub use self::{
+ features::{FeatureRestriction, FeatureRestrictionError, Features},
+ properties::Properties,
+ queue::{Queue, QueueError, QueueFamilyProperties, QueueFlags, QueueGuard},
+};
+pub use crate::{
+ device::extensions::DeviceExtensions,
+ extensions::{ExtensionRestriction, ExtensionRestrictionError},
+ fns::DeviceFunctions,
+};
+use crate::{
+ instance::Instance, macros::impl_id_counter, memory::ExternalMemoryHandleType, OomError,
+ RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject,
};
-use crate::fns::DeviceFunctions;
-use crate::format::Format;
-use crate::image::ImageCreateFlags;
-use crate::image::ImageFormatProperties;
-use crate::image::ImageTiling;
-use crate::image::ImageType;
-use crate::image::ImageUsage;
-use crate::instance::Instance;
-use crate::memory::pool::StdMemoryPool;
-use crate::Error;
-use crate::OomError;
-use crate::SynchronizedVulkanObject;
-use crate::Version;
-use crate::VulkanObject;
use ash::vk::Handle;
-use fnv::FnvHasher;
+use parking_lot::Mutex;
use smallvec::SmallVec;
-use std::collections::hash_map::Entry;
-use std::collections::HashMap;
-use std::error;
-use std::ffi::CStr;
-use std::ffi::CString;
-use std::fmt;
-use std::hash::BuildHasherDefault;
-use std::hash::Hash;
-use std::hash::Hasher;
-use std::mem;
-use std::mem::MaybeUninit;
-use std::ops::Deref;
-use std::ptr;
-use std::sync::Arc;
-use std::sync::Mutex;
-use std::sync::MutexGuard;
-use std::sync::Weak;
+use std::{
+ error::Error,
+ ffi::CString,
+ fmt::{Display, Error as FmtError, Formatter},
+ fs::File,
+ mem::MaybeUninit,
+ num::NonZeroU64,
+ ops::Deref,
+ ptr,
+ sync::{
+ atomic::{AtomicU32, Ordering},
+ Arc,
+ },
+};
pub(crate) mod extensions;
pub(crate) mod features;
pub mod physical;
pub(crate) mod properties;
+mod queue;
/// Represents a Vulkan context.
+#[derive(Debug)]
pub struct Device {
- instance: Arc<Instance>,
- physical_device: usize,
- device: ash::vk::Device,
+ handle: ash::vk::Device,
+ physical_device: Arc<PhysicalDevice>,
+ id: NonZeroU64,
// The highest version that is supported for this device.
// This is the minimum of Instance::max_api_version and PhysicalDevice::api_version.
api_version: Version,
fns: DeviceFunctions,
- standard_pool: Mutex<Weak<StdMemoryPool>>,
- standard_descriptor_pool: Mutex<Weak<StdDescriptorPool>>,
- standard_command_pools:
- Mutex<HashMap<u32, Weak<StandardCommandPool>, BuildHasherDefault<FnvHasher>>>,
- features: Features,
- extensions: DeviceExtensions,
- active_queue_families: SmallVec<[u32; 8]>,
- allocation_count: Mutex<u32>,
+ enabled_extensions: DeviceExtensions,
+ enabled_features: Features,
+ active_queue_family_indices: SmallVec<[u32; 2]>,
+ // This is required for validation in `memory::device_memory`, the count must only be modified
+ // in that module.
+ pub(crate) allocation_count: AtomicU32,
fence_pool: Mutex<Vec<ash::vk::Fence>>,
semaphore_pool: Mutex<Vec<ash::vk::Semaphore>>,
event_pool: Mutex<Vec<ash::vk::Event>>,
}
-// The `StandardCommandPool` type doesn't implement Send/Sync, so we have to manually reimplement
-// them for the device itself.
-unsafe impl Send for Device {}
-unsafe impl Sync for Device {}
-
impl Device {
- /// Builds a new Vulkan device for the given physical device.
- ///
- /// You must pass two things when creating a logical device:
- ///
- /// - A list of optional Vulkan features that must be enabled on the device. Note that if a
- /// feature is not enabled at device creation, you can't use it later even it it's supported
- /// by the physical device.
+ /// Creates a new `Device`.
///
- /// - An iterator to a list of queues to create. Each element of the iterator must indicate
- /// the family whose queue belongs to and a priority between 0.0 and 1.0 to assign to it.
- /// A queue with a higher value indicates that the commands will execute faster than on a
- /// queue with a lower value. Note however that no guarantee can be made on the way the
- /// priority value is handled by the implementation.
- ///
- /// # Panic
- ///
- /// - Panics if one of the queue families doesn't belong to the given device.
+ /// # Panics
///
- // TODO: return Arc<Queue> and handle synchronization in the Queue
- // TODO: should take the PhysicalDevice by value
- pub fn new<'a, I>(
- physical_device: PhysicalDevice,
- requested_features: &Features,
- requested_extensions: &DeviceExtensions,
- queue_families: I,
- ) -> Result<(Arc<Device>, QueuesIter), DeviceCreationError>
- where
- I: IntoIterator<Item = (QueueFamily<'a>, f32)>,
- {
+ /// - Panics if `create_info.queues` is empty.
+ /// - Panics if one of the queue families in `create_info.queues` doesn't belong to the given
+ /// physical device.
+ /// - Panics if `create_info.queues` contains multiple elements for the same queue family.
+ /// - Panics if `create_info.queues` contains an element where `queues` is empty.
+ /// - Panics if `create_info.queues` contains an element where `queues` contains a value that is
+ /// not between 0.0 and 1.0 inclusive.
+ pub fn new(
+ physical_device: Arc<PhysicalDevice>,
+ create_info: DeviceCreateInfo,
+ ) -> Result<(Arc<Device>, impl ExactSizeIterator<Item = Arc<Queue>>), DeviceCreationError> {
+ let DeviceCreateInfo {
+ mut enabled_extensions,
+ mut enabled_features,
+ queue_create_infos,
+ _ne: _,
+ } = create_info;
+
let instance = physical_device.instance();
let fns_i = instance.fns();
let api_version = physical_device.api_version();
- // Check if the extensions are correct
- requested_extensions.check_requirements(
- physical_device.supported_extensions(),
+ /*
+ Queues
+ */
+
+ struct QueueToGet {
+ queue_family_index: u32,
+ id: u32,
+ }
+
+ // VUID-VkDeviceCreateInfo-queueCreateInfoCount-arraylength
+ assert!(!queue_create_infos.is_empty());
+
+ let mut queue_create_infos_vk: SmallVec<[_; 2]> =
+ SmallVec::with_capacity(queue_create_infos.len());
+ let mut active_queue_family_indices: SmallVec<[_; 2]> =
+ SmallVec::with_capacity(queue_create_infos.len());
+ let mut queues_to_get: SmallVec<[_; 2]> = SmallVec::with_capacity(queue_create_infos.len());
+
+ for queue_create_info in &queue_create_infos {
+ let &QueueCreateInfo {
+ queue_family_index,
+ ref queues,
+ _ne: _,
+ } = queue_create_info;
+
+ // VUID-VkDeviceQueueCreateInfo-queueFamilyIndex-00381
+ // TODO: return error instead of panicking?
+ let queue_family_properties =
+ &physical_device.queue_family_properties()[queue_family_index as usize];
+
+ // VUID-VkDeviceCreateInfo-queueFamilyIndex-02802
+ assert!(
+ queue_create_infos
+ .iter()
+ .filter(|qc2| qc2.queue_family_index == queue_family_index)
+ .count()
+ == 1
+ );
+
+ // VUID-VkDeviceQueueCreateInfo-queueCount-arraylength
+ assert!(!queues.is_empty());
+
+ // VUID-VkDeviceQueueCreateInfo-pQueuePriorities-00383
+ assert!(queues
+ .iter()
+ .all(|&priority| (0.0..=1.0).contains(&priority)));
+
+ if queues.len() > queue_family_properties.queue_count as usize {
+ return Err(DeviceCreationError::TooManyQueuesForFamily);
+ }
+
+ queue_create_infos_vk.push(ash::vk::DeviceQueueCreateInfo {
+ flags: ash::vk::DeviceQueueCreateFlags::empty(),
+ queue_family_index,
+ queue_count: queues.len() as u32,
+ p_queue_priorities: queues.as_ptr(), // borrows from queue_create
+ ..Default::default()
+ });
+ active_queue_family_indices.push(queue_family_index);
+ queues_to_get.extend((0..queues.len() as u32).map(move |id| QueueToGet {
+ queue_family_index,
+ id,
+ }));
+ }
+
+ active_queue_family_indices.sort_unstable();
+ active_queue_family_indices.dedup();
+ let supported_extensions = physical_device.supported_extensions();
+
+ if supported_extensions.khr_portability_subset {
+ enabled_extensions.khr_portability_subset = true;
+ }
+
+ /*
+ Extensions
+ */
+
+ // VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-01840
+ // VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-03328
+ // VUID-VkDeviceCreateInfo-pProperties-04451
+ enabled_extensions.check_requirements(
+ supported_extensions,
api_version,
instance.enabled_extensions(),
)?;
- let mut requested_features = requested_features.clone();
+ let enabled_extensions_strings = Vec::<CString>::from(&enabled_extensions);
+ let enabled_extensions_ptrs = enabled_extensions_strings
+ .iter()
+ .map(|extension| extension.as_ptr())
+ .collect::<SmallVec<[_; 16]>>();
+
+ /*
+ Features
+ */
// TODO: The plan regarding `robust_buffer_access` is to check the shaders' code to see
// if they can possibly perform out-of-bounds reads and writes. If the user tries
@@ -231,531 +303,349 @@ impl Device {
//
// Note that if we ever remove this, don't forget to adjust the change in
// `Device`'s construction below.
- requested_features.robust_buffer_access = true;
-
- // Check if the features are correct
- requested_features.check_requirements(
+ enabled_features.robust_buffer_access = true;
+
+ // VUID-VkDeviceCreateInfo-pNext-04748
+ // VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-04476
+ // VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-02831
+ // VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-02832
+ // VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-02833
+ // VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-02834
+ // VUID-VkDeviceCreateInfo-ppEnabledExtensionNames-02835
+ // VUID-VkDeviceCreateInfo-shadingRateImage-04478
+ // VUID-VkDeviceCreateInfo-shadingRateImage-04479
+ // VUID-VkDeviceCreateInfo-shadingRateImage-04480
+ // VUID-VkDeviceCreateInfo-fragmentDensityMap-04481
+ // VUID-VkDeviceCreateInfo-fragmentDensityMap-04482
+ // VUID-VkDeviceCreateInfo-fragmentDensityMap-04483
+ // VUID-VkDeviceCreateInfo-None-04896
+ // VUID-VkDeviceCreateInfo-None-04897
+ // VUID-VkDeviceCreateInfo-None-04898
+ // VUID-VkDeviceCreateInfo-sparseImageFloat32AtomicMinMax-04975
+ enabled_features.check_requirements(
physical_device.supported_features(),
api_version,
- requested_extensions,
+ &enabled_extensions,
)?;
- // device creation
- let (device, queues) = unsafe {
- // each element of `queues` is a `(queue_family, priorities)`
- // each queue family must only have one entry in `queues`
- let mut queues: Vec<(u32, Vec<f32>)> =
- Vec::with_capacity(physical_device.queue_families().len());
-
- // this variable will contain the queue family ID and queue ID of each requested queue
- let mut output_queues: SmallVec<[(u32, u32); 8]> = SmallVec::new();
-
- for (queue_family, priority) in queue_families {
- // checking the parameters
- assert_eq!(
- queue_family.physical_device().internal_object(),
- physical_device.internal_object()
- );
- if priority < 0.0 || priority > 1.0 {
- return Err(DeviceCreationError::PriorityOutOfRange);
- }
-
- // adding to `queues` and `output_queues`
- if let Some(q) = queues.iter_mut().find(|q| q.0 == queue_family.id()) {
- output_queues.push((queue_family.id(), q.1.len() as u32));
- q.1.push(priority);
- if q.1.len() > queue_family.queues_count() {
- return Err(DeviceCreationError::TooManyQueuesForFamily);
- }
- continue;
- }
- queues.push((queue_family.id(), vec![priority]));
- output_queues.push((queue_family.id(), 0));
- }
+ // VUID-VkDeviceCreateInfo-pNext-02829
+ // VUID-VkDeviceCreateInfo-pNext-02830
+ // VUID-VkDeviceCreateInfo-pNext-06532
+ let mut features_ffi = FeaturesFfi::default();
+ features_ffi.make_chain(
+ api_version,
+ &enabled_extensions,
+ instance.enabled_extensions(),
+ );
+ features_ffi.write(&enabled_features);
+
+ // Device layers were deprecated in Vulkan 1.0.13, and device layer requests should be
+ // ignored by the driver. For backwards compatibility, the spec recommends passing the
+ // exact instance layers to the device as well. There's no need to support separate
+ // requests at device creation time for legacy drivers: the spec claims that "[at] the
+ // time of deprecation there were no known device-only layers."
+ //
+ // Because there's no way to query the list of layers enabled for an instance, we need
+ // to save it alongside the instance. (`vkEnumerateDeviceLayerProperties` should get
+ // the right list post-1.0.13, but not pre-1.0.13, so we can't use it here.)
+ let enabled_layers_cstr: Vec<CString> = instance
+ .enabled_layers()
+ .iter()
+ .map(|name| CString::new(name.clone()).unwrap())
+ .collect();
+ let enabled_layers_ptrs = enabled_layers_cstr
+ .iter()
+ .map(|layer| layer.as_ptr())
+ .collect::<SmallVec<[_; 2]>>();
+
+ /*
+ Create the device
+ */
+
+ let has_khr_get_physical_device_properties2 = instance
+ .enabled_extensions()
+ .khr_get_physical_device_properties2;
+
+ let mut create_info = ash::vk::DeviceCreateInfo {
+ flags: ash::vk::DeviceCreateFlags::empty(),
+ queue_create_info_count: queue_create_infos_vk.len() as u32,
+ p_queue_create_infos: queue_create_infos_vk.as_ptr(),
+ enabled_layer_count: enabled_layers_ptrs.len() as u32,
+ pp_enabled_layer_names: enabled_layers_ptrs.as_ptr(),
+ enabled_extension_count: enabled_extensions_ptrs.len() as u32,
+ pp_enabled_extension_names: enabled_extensions_ptrs.as_ptr(),
+ p_enabled_features: ptr::null(),
+ ..Default::default()
+ };
- // turning `queues` into an array of `vkDeviceQueueCreateInfo` suitable for Vulkan
- let queues = queues
- .iter()
- .map(
- |&(queue_id, ref priorities)| ash::vk::DeviceQueueCreateInfo {
- flags: ash::vk::DeviceQueueCreateFlags::empty(),
- queue_family_index: queue_id,
- queue_count: priorities.len() as u32,
- p_queue_priorities: priorities.as_ptr(),
- ..Default::default()
- },
- )
- .collect::<SmallVec<[_; 16]>>();
-
- let mut features_ffi = FeaturesFfi::default();
- features_ffi.make_chain(
- api_version,
- requested_extensions,
- instance.enabled_extensions(),
- );
- features_ffi.write(&requested_features);
-
- // Device layers were deprecated in Vulkan 1.0.13, and device layer requests should be
- // ignored by the driver. For backwards compatibility, the spec recommends passing the
- // exact instance layers to the device as well. There's no need to support separate
- // requests at device creation time for legacy drivers: the spec claims that "[at] the
- // time of deprecation there were no known device-only layers."
- //
- // Because there's no way to query the list of layers enabled for an instance, we need
- // to save it alongside the instance. (`vkEnumerateDeviceLayerProperties` should get
- // the right list post-1.0.13, but not pre-1.0.13, so we can't use it here.)
- let layers_ptrs = instance
- .enabled_layers()
- .map(|layer| layer.as_ptr())
- .collect::<SmallVec<[_; 16]>>();
-
- let extensions_strings: Vec<CString> = requested_extensions.into();
- let extensions_ptrs = extensions_strings
- .iter()
- .map(|extension| extension.as_ptr())
- .collect::<SmallVec<[_; 16]>>();
-
- let has_khr_get_physical_device_properties2 = instance
- .enabled_extensions()
- .khr_get_physical_device_properties2;
-
- let infos = ash::vk::DeviceCreateInfo {
- p_next: if has_khr_get_physical_device_properties2 {
- features_ffi.head_as_ref() as *const _ as _
- } else {
- ptr::null()
- },
- flags: ash::vk::DeviceCreateFlags::empty(),
- queue_create_info_count: queues.len() as u32,
- p_queue_create_infos: queues.as_ptr(),
- enabled_layer_count: layers_ptrs.len() as u32,
- pp_enabled_layer_names: layers_ptrs.as_ptr(),
- enabled_extension_count: extensions_ptrs.len() as u32,
- pp_enabled_extension_names: extensions_ptrs.as_ptr(),
- p_enabled_features: if has_khr_get_physical_device_properties2 {
- ptr::null()
- } else {
- &features_ffi.head_as_ref().features
- },
- ..Default::default()
- };
+ // VUID-VkDeviceCreateInfo-pNext-00373
+ if has_khr_get_physical_device_properties2 {
+ create_info.p_next = features_ffi.head_as_ref() as *const _ as _;
+ } else {
+ create_info.p_enabled_features = &features_ffi.head_as_ref().features;
+ }
+ let handle = unsafe {
let mut output = MaybeUninit::uninit();
- check_errors(fns_i.v1_0.create_device(
- physical_device.internal_object(),
- &infos,
+ (fns_i.v1_0.create_device)(
+ physical_device.handle(),
+ &create_info,
ptr::null(),
output.as_mut_ptr(),
- ))?;
-
- (output.assume_init(), output_queues)
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+ output.assume_init()
};
// loading the function pointers of the newly-created device
let fns = DeviceFunctions::load(|name| unsafe {
- mem::transmute(fns_i.v1_0.get_device_proc_addr(device, name.as_ptr()))
+ (fns_i.v1_0.get_device_proc_addr)(handle, name.as_ptr())
+ .map_or(ptr::null(), |func| func as _)
});
- let mut active_queue_families: SmallVec<[u32; 8]> = SmallVec::new();
- for (queue_family, _) in queues.iter() {
- if let None = active_queue_families
- .iter()
- .find(|&&qf| qf == *queue_family)
- {
- active_queue_families.push(*queue_family);
- }
- }
-
let device = Arc::new(Device {
- instance: physical_device.instance().clone(),
- physical_device: physical_device.index(),
- device: device,
+ handle,
+ physical_device,
+ id: Self::next_id(),
api_version,
fns,
- standard_pool: Mutex::new(Weak::new()),
- standard_descriptor_pool: Mutex::new(Weak::new()),
- standard_command_pools: Mutex::new(Default::default()),
- features: Features {
- // Always enabled ; see above
- robust_buffer_access: true,
- ..requested_features.clone()
- },
- extensions: requested_extensions.clone(),
- active_queue_families,
- allocation_count: Mutex::new(0),
+ enabled_extensions,
+ enabled_features,
+ active_queue_family_indices,
+ allocation_count: AtomicU32::new(0),
fence_pool: Mutex::new(Vec::new()),
semaphore_pool: Mutex::new(Vec::new()),
event_pool: Mutex::new(Vec::new()),
});
- // Iterator for the produced queues.
- let queues = QueuesIter {
- next_queue: 0,
- device: device.clone(),
- families_and_ids: queues,
+ // Iterator to return the queues
+ let queues_iter = {
+ let device = device.clone();
+ queues_to_get.into_iter().map(
+ move |QueueToGet {
+ queue_family_index,
+ id,
+ }| unsafe {
+ let fns = device.fns();
+ let mut output = MaybeUninit::uninit();
+ (fns.v1_0.get_device_queue)(
+ handle,
+ queue_family_index,
+ id,
+ output.as_mut_ptr(),
+ );
+
+ Queue::from_handle(device.clone(), output.assume_init(), queue_family_index, id)
+ },
+ )
};
- Ok((device, queues))
+ Ok((device, queues_iter))
}
/// Returns the Vulkan version supported by the device.
///
/// This is the lower of the
- /// [physical device's supported version](crate::instance::PhysicalDevice::api_version) and
- /// the instance's [`max_api_version`](crate::instance::Instance::max_api_version).
+ /// [physical device's supported version](crate::device::physical::PhysicalDevice::api_version)
+ /// and the instance's [`max_api_version`](crate::instance::Instance::max_api_version).
#[inline]
pub fn api_version(&self) -> Version {
self.api_version
}
- /// Grants access to the Vulkan functions of the device.
+ /// Returns pointers to the raw Vulkan functions of the device.
#[inline]
pub fn fns(&self) -> &DeviceFunctions {
&self.fns
}
- /// Waits until all work on this device has finished. You should never need to call
- /// this function, but it can be useful for debugging or benchmarking purposes.
- ///
- /// > **Note**: This is the Vulkan equivalent of OpenGL's `glFinish`.
- ///
- /// # Safety
- ///
- /// This function is not thread-safe. You must not submit anything to any of the queue
- /// of the device (either explicitly or implicitly, for example with a future's destructor)
- /// while this function is waiting.
- ///
- pub unsafe fn wait(&self) -> Result<(), OomError> {
- check_errors(self.fns.v1_0.device_wait_idle(self.device))?;
- Ok(())
+ /// Returns the physical device that was used to create this device.
+ #[inline]
+ pub fn physical_device(&self) -> &Arc<PhysicalDevice> {
+ &self.physical_device
}
/// Returns the instance used to create this device.
#[inline]
pub fn instance(&self) -> &Arc<Instance> {
- &self.instance
+ self.physical_device.instance()
}
- /// Returns the physical device that was used to create this device.
+ /// Returns the queue family indices that this device uses.
#[inline]
- pub fn physical_device(&self) -> PhysicalDevice {
- PhysicalDevice::from_index(&self.instance, self.physical_device).unwrap()
+ pub fn active_queue_family_indices(&self) -> &[u32] {
+ &self.active_queue_family_indices
}
- /// Returns an iterator to the list of queues families that this device uses.
- ///
- /// > **Note**: Will return `-> impl ExactSizeIterator<Item = QueueFamily>` in the future.
- // TODO: ^
+ /// Returns the extensions that have been enabled on the device.
#[inline]
- pub fn active_queue_families<'a>(
- &'a self,
- ) -> Box<dyn ExactSizeIterator<Item = QueueFamily<'a>> + 'a> {
- let physical_device = self.physical_device();
- Box::new(
- self.active_queue_families
- .iter()
- .map(move |&id| physical_device.queue_family_by_id(id).unwrap()),
- )
+ pub fn enabled_extensions(&self) -> &DeviceExtensions {
+ &self.enabled_extensions
}
/// Returns the features that have been enabled on the device.
#[inline]
pub fn enabled_features(&self) -> &Features {
- &self.features
+ &self.enabled_features
}
- /// Returns the extensions that have been enabled on the device.
+ /// Returns the current number of active [`DeviceMemory`] allocations the device has.
+ ///
+ /// [`DeviceMemory`]: crate::memory::DeviceMemory
#[inline]
- pub fn enabled_extensions(&self) -> &DeviceExtensions {
- &self.extensions
+ pub fn allocation_count(&self) -> u32 {
+ self.allocation_count.load(Ordering::Acquire)
}
- /// Returns the standard memory pool used by default if you don't provide any other pool.
- pub fn standard_pool(me: &Arc<Self>) -> Arc<StdMemoryPool> {
- let mut pool = me.standard_pool.lock().unwrap();
-
- if let Some(p) = pool.upgrade() {
- return p;
- }
-
- // The weak pointer is empty, so we create the pool.
- let new_pool = StdMemoryPool::new(me.clone());
- *pool = Arc::downgrade(&new_pool);
- new_pool
+ pub(crate) fn fence_pool(&self) -> &Mutex<Vec<ash::vk::Fence>> {
+ &self.fence_pool
}
- /// Returns the standard descriptor pool used by default if you don't provide any other pool.
- pub fn standard_descriptor_pool(me: &Arc<Self>) -> Arc<StdDescriptorPool> {
- let mut pool = me.standard_descriptor_pool.lock().unwrap();
-
- if let Some(p) = pool.upgrade() {
- return p;
- }
+ pub(crate) fn semaphore_pool(&self) -> &Mutex<Vec<ash::vk::Semaphore>> {
+ &self.semaphore_pool
+ }
- // The weak pointer is empty, so we create the pool.
- let new_pool = Arc::new(StdDescriptorPool::new(me.clone()));
- *pool = Arc::downgrade(&new_pool);
- new_pool
+ pub(crate) fn event_pool(&self) -> &Mutex<Vec<ash::vk::Event>> {
+ &self.event_pool
}
- /// Returns the standard command buffer pool used by default if you don't provide any other
- /// pool.
+ /// Retrieves the properties of an external file descriptor when imported as a given external
+ /// handle type.
///
- /// # Panic
+ /// An error will be returned if the
+ /// [`khr_external_memory_fd`](DeviceExtensions::khr_external_memory_fd) extension was not
+ /// enabled on the device, or if `handle_type` is [`ExternalMemoryHandleType::OpaqueFd`].
///
- /// - Panics if the device and the queue family don't belong to the same physical device.
+ /// # Safety
///
- pub fn standard_command_pool(me: &Arc<Self>, queue: QueueFamily) -> Arc<StandardCommandPool> {
- let mut standard_command_pools = me.standard_command_pools.lock().unwrap();
-
- match standard_command_pools.entry(queue.id()) {
- Entry::Occupied(mut entry) => {
- if let Some(pool) = entry.get().upgrade() {
- return pool;
- }
-
- let new_pool = Arc::new(StandardCommandPool::new(me.clone(), queue));
- *entry.get_mut() = Arc::downgrade(&new_pool);
- new_pool
- }
- Entry::Vacant(entry) => {
- let new_pool = Arc::new(StandardCommandPool::new(me.clone(), queue));
- entry.insert(Arc::downgrade(&new_pool));
- new_pool
- }
+ /// - `file` must be a handle to external memory that was created outside the Vulkan API.
+ #[cfg_attr(not(unix), allow(unused_variables))]
+ #[inline]
+ pub unsafe fn memory_fd_properties(
+ &self,
+ handle_type: ExternalMemoryHandleType,
+ file: File,
+ ) -> Result<MemoryFdProperties, MemoryFdPropertiesError> {
+ if !self.enabled_extensions().khr_external_memory_fd {
+ return Err(MemoryFdPropertiesError::NotSupported);
}
- }
- /// Used to track the number of allocations on this device.
- ///
- /// To ensure valid usage of the Vulkan API, we cannot call `vkAllocateMemory` when
- /// `maxMemoryAllocationCount` has been exceeded. See the Vulkan specs:
- /// https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#vkAllocateMemory
- ///
- /// Warning: You should never modify this value, except in `device_memory` module
- pub(crate) fn allocation_count(&self) -> &Mutex<u32> {
- &self.allocation_count
- }
+ #[cfg(not(unix))]
+ unreachable!("`khr_external_memory_fd` was somehow enabled on a non-Unix system");
- pub(crate) fn fence_pool(&self) -> &Mutex<Vec<ash::vk::Fence>> {
- &self.fence_pool
- }
+ #[cfg(unix)]
+ {
+ use std::os::unix::io::IntoRawFd;
- pub(crate) fn semaphore_pool(&self) -> &Mutex<Vec<ash::vk::Semaphore>> {
- &self.semaphore_pool
- }
+ // VUID-vkGetMemoryFdPropertiesKHR-handleType-parameter
+ handle_type.validate_device(self)?;
- pub(crate) fn event_pool(&self) -> &Mutex<Vec<ash::vk::Event>> {
- &self.event_pool
+ // VUID-vkGetMemoryFdPropertiesKHR-handleType-00674
+ if handle_type == ExternalMemoryHandleType::OpaqueFd {
+ return Err(MemoryFdPropertiesError::InvalidExternalHandleType);
+ }
+
+ let mut memory_fd_properties = ash::vk::MemoryFdPropertiesKHR::default();
+
+ let fns = self.fns();
+ (fns.khr_external_memory_fd.get_memory_fd_properties_khr)(
+ self.handle,
+ handle_type.into(),
+ file.into_raw_fd(),
+ &mut memory_fd_properties,
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+
+ Ok(MemoryFdProperties {
+ memory_type_bits: memory_fd_properties.memory_type_bits,
+ })
+ }
}
/// Assigns a human-readable name to `object` for debugging purposes.
///
+ /// If `object_name` is `None`, a previously set object name is removed.
+ ///
/// # Panics
- /// * If `object` is not owned by this device.
- pub fn set_object_name<T: VulkanObject + DeviceOwned>(
+ /// - If `object` is not owned by this device.
+ pub fn set_debug_utils_object_name<T: VulkanObject + DeviceOwned>(
&self,
object: &T,
- name: &CStr,
+ object_name: Option<&str>,
) -> Result<(), OomError> {
- assert!(object.device().internal_object() == self.internal_object());
- unsafe {
- self.set_object_name_raw(T::Object::TYPE, object.internal_object().as_raw(), name)
- }
- }
+ assert!(object.device().handle() == self.handle());
- /// Assigns a human-readable name to `object` for debugging purposes.
- ///
- /// # Safety
- /// `object` must be a Vulkan handle owned by this device, and its type must be accurately described by `ty`.
- pub unsafe fn set_object_name_raw(
- &self,
- ty: ash::vk::ObjectType,
- object: u64,
- name: &CStr,
- ) -> Result<(), OomError> {
+ let object_name_vk = object_name.map(|object_name| CString::new(object_name).unwrap());
let info = ash::vk::DebugUtilsObjectNameInfoEXT {
- object_type: ty,
- object_handle: object,
- p_object_name: name.as_ptr(),
+ object_type: T::Handle::TYPE,
+ object_handle: object.handle().as_raw(),
+ p_object_name: object_name_vk.map_or(ptr::null(), |object_name| object_name.as_ptr()),
..Default::default()
};
- check_errors(
- self.instance
- .fns()
- .ext_debug_utils
- .set_debug_utils_object_name_ext(self.device, &info),
- )?;
- Ok(())
- }
- /// Checks the given combination of image attributes/configuration for compatibility with the physical device.
- ///
- /// Returns a struct with additional capabilities available for this image configuration.
- pub fn image_format_properties(
- &self,
- format: Format,
- ty: ImageType,
- tiling: ImageTiling,
- usage: ImageUsage,
- create_flags: ImageCreateFlags,
- ) -> Result<ImageFormatProperties, String> {
- let fns_i = self.instance().fns();
- let mut output = MaybeUninit::uninit();
- let physical_device = self.physical_device().internal_object();
unsafe {
- let r = fns_i.v1_0.get_physical_device_image_format_properties(
- physical_device,
- format.into(),
- ty.into(),
- tiling.into(),
- usage.into(),
- create_flags.into(),
- output.as_mut_ptr(),
- );
-
- match check_errors(r) {
- Ok(_) => Ok(output.assume_init().into()),
- Err(e) => {
- return Err(String::from(format!(
- "Image properties not supported. {:#?}",
- e
- )))
- }
- }
+ let fns = self.instance().fns();
+ (fns.ext_debug_utils.set_debug_utils_object_name_ext)(self.handle, &info)
+ .result()
+ .map_err(VulkanError::from)?;
}
- }
-}
-impl fmt::Debug for Device {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(fmt, "<Vulkan device {:?}>", self.device)
+ Ok(())
}
-}
-
-unsafe impl VulkanObject for Device {
- type Object = ash::vk::Device;
+ /// Waits until all work on this device has finished. You should never need to call
+ /// this function, but it can be useful for debugging or benchmarking purposes.
+ ///
+ /// > **Note**: This is the Vulkan equivalent of OpenGL's `glFinish`.
+ ///
+ /// # Safety
+ ///
+ /// This function is not thread-safe. You must not submit anything to any of the queue
+ /// of the device (either explicitly or implicitly, for example with a future's destructor)
+ /// while this function is waiting.
#[inline]
- fn internal_object(&self) -> ash::vk::Device {
- self.device
+ pub unsafe fn wait_idle(&self) -> Result<(), OomError> {
+ let fns = self.fns();
+ (fns.v1_0.device_wait_idle)(self.handle)
+ .result()
+ .map_err(VulkanError::from)?;
+
+ Ok(())
}
}
impl Drop for Device {
#[inline]
fn drop(&mut self) {
+ let fns = self.fns();
+
unsafe {
- for &raw_fence in self.fence_pool.lock().unwrap().iter() {
- self.fns
- .v1_0
- .destroy_fence(self.device, raw_fence, ptr::null());
+ for &raw_fence in self.fence_pool.lock().iter() {
+ (fns.v1_0.destroy_fence)(self.handle, raw_fence, ptr::null());
}
- for &raw_sem in self.semaphore_pool.lock().unwrap().iter() {
- self.fns
- .v1_0
- .destroy_semaphore(self.device, raw_sem, ptr::null());
+ for &raw_sem in self.semaphore_pool.lock().iter() {
+ (fns.v1_0.destroy_semaphore)(self.handle, raw_sem, ptr::null());
}
- for &raw_event in self.event_pool.lock().unwrap().iter() {
- self.fns
- .v1_0
- .destroy_event(self.device, raw_event, ptr::null());
+ for &raw_event in self.event_pool.lock().iter() {
+ (fns.v1_0.destroy_event)(self.handle, raw_event, ptr::null());
}
- self.fns.v1_0.destroy_device(self.device, ptr::null());
+ (fns.v1_0.destroy_device)(self.handle, ptr::null());
}
}
}
-impl PartialEq for Device {
- #[inline]
- fn eq(&self, other: &Self) -> bool {
- self.device == other.device && self.instance == other.instance
- }
-}
-
-impl Eq for Device {}
-
-impl Hash for Device {
- #[inline]
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.device.hash(state);
- self.instance.hash(state);
- }
-}
-
-/// Implemented on objects that belong to a Vulkan device.
-///
-/// # Safety
-///
-/// - `device()` must return the correct device.
-///
-pub unsafe trait DeviceOwned {
- /// Returns the device that owns `Self`.
- fn device(&self) -> &Arc<Device>;
-}
-
-unsafe impl<T> DeviceOwned for T
-where
- T: Deref,
- T::Target: DeviceOwned,
-{
- #[inline]
- fn device(&self) -> &Arc<Device> {
- (**self).device()
- }
-}
-
-/// Iterator that returns the queues produced when creating a device.
-pub struct QueuesIter {
- next_queue: usize,
- device: Arc<Device>,
- families_and_ids: SmallVec<[(u32, u32); 8]>,
-}
-
-unsafe impl DeviceOwned for QueuesIter {
- fn device(&self) -> &Arc<Device> {
- &self.device
- }
-}
-
-impl Iterator for QueuesIter {
- type Item = Arc<Queue>;
-
- fn next(&mut self) -> Option<Arc<Queue>> {
- unsafe {
- let &(family, id) = match self.families_and_ids.get(self.next_queue) {
- Some(a) => a,
- None => return None,
- };
-
- self.next_queue += 1;
-
- let mut output = MaybeUninit::uninit();
- self.device.fns.v1_0.get_device_queue(
- self.device.device,
- family,
- id,
- output.as_mut_ptr(),
- );
-
- Some(Arc::new(Queue {
- queue: Mutex::new(output.assume_init()),
- device: self.device.clone(),
- family: family,
- id: id,
- }))
- }
- }
+unsafe impl VulkanObject for Device {
+ type Handle = ash::vk::Device;
#[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- let len = self.families_and_ids.len().saturating_sub(self.next_queue);
- (len, Some(len))
+ fn handle(&self) -> Self::Handle {
+ self.handle
}
}
-impl ExactSizeIterator for QueuesIter {}
+impl_id_counter!(Device);
/// Error that can be returned when creating a device.
#[derive(Copy, Clone, Debug)]
@@ -785,164 +675,246 @@ pub enum DeviceCreationError {
FeatureRestrictionNotMet(FeatureRestrictionError),
}
-impl error::Error for DeviceCreationError {}
-
-impl fmt::Display for DeviceCreationError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- match *self {
- DeviceCreationError::InitializationFailed => {
- write!(
- fmt,
- "failed to create the device for an implementation-specific reason"
- )
- }
- DeviceCreationError::OutOfHostMemory => write!(fmt, "no memory available on the host"),
- DeviceCreationError::OutOfDeviceMemory => {
- write!(fmt, "no memory available on the graphical device")
- }
- DeviceCreationError::DeviceLost => write!(fmt, "failed to connect to the device"),
- DeviceCreationError::TooManyQueuesForFamily => {
- write!(fmt, "tried to create too many queues for a given family")
- }
- DeviceCreationError::FeatureNotPresent => {
- write!(
- fmt,
- "some of the requested features are unsupported by the physical device"
- )
+impl Error for DeviceCreationError {}
+
+impl Display for DeviceCreationError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::InitializationFailed => write!(
+ f,
+ "failed to create the device for an implementation-specific reason",
+ ),
+ Self::OutOfHostMemory => write!(f, "no memory available on the host"),
+ Self::OutOfDeviceMemory => {
+ write!(f, "no memory available on the graphical device")
}
- DeviceCreationError::PriorityOutOfRange => {
- write!(
- fmt,
- "the priority of one of the queues is out of the [0.0; 1.0] range"
- )
+ Self::DeviceLost => write!(f, "failed to connect to the device"),
+ Self::TooManyQueuesForFamily => {
+ write!(f, "tried to create too many queues for a given family")
}
- DeviceCreationError::ExtensionNotPresent => {
- write!(fmt,"some of the requested device extensions are not supported by the physical device")
- }
- DeviceCreationError::TooManyObjects => {
- write!(fmt,"you have reached the limit to the number of devices that can be created from the same physical device")
- }
- DeviceCreationError::ExtensionRestrictionNotMet(err) => err.fmt(fmt),
- DeviceCreationError::FeatureRestrictionNotMet(err) => err.fmt(fmt),
+ Self::FeatureNotPresent => write!(
+ f,
+ "some of the requested features are unsupported by the physical device",
+ ),
+ Self::PriorityOutOfRange => write!(
+ f,
+ "the priority of one of the queues is out of the [0.0; 1.0] range",
+ ),
+ Self::ExtensionNotPresent => write!(
+ f,
+ "some of the requested device extensions are not supported by the physical device",
+ ),
+ Self::TooManyObjects => write!(
+ f,
+ "you have reached the limit to the number of devices that can be created from the \
+ same physical device",
+ ),
+ Self::ExtensionRestrictionNotMet(err) => err.fmt(f),
+ Self::FeatureRestrictionNotMet(err) => err.fmt(f),
}
}
}
-impl From<Error> for DeviceCreationError {
- #[inline]
- fn from(err: Error) -> DeviceCreationError {
+impl From<VulkanError> for DeviceCreationError {
+ fn from(err: VulkanError) -> Self {
match err {
- Error::InitializationFailed => DeviceCreationError::InitializationFailed,
- Error::OutOfHostMemory => DeviceCreationError::OutOfHostMemory,
- Error::OutOfDeviceMemory => DeviceCreationError::OutOfDeviceMemory,
- Error::DeviceLost => DeviceCreationError::DeviceLost,
- Error::ExtensionNotPresent => DeviceCreationError::ExtensionNotPresent,
- Error::FeatureNotPresent => DeviceCreationError::FeatureNotPresent,
- Error::TooManyObjects => DeviceCreationError::TooManyObjects,
- _ => panic!("Unexpected error value: {}", err as i32),
+ VulkanError::InitializationFailed => Self::InitializationFailed,
+ VulkanError::OutOfHostMemory => Self::OutOfHostMemory,
+ VulkanError::OutOfDeviceMemory => Self::OutOfDeviceMemory,
+ VulkanError::DeviceLost => Self::DeviceLost,
+ VulkanError::ExtensionNotPresent => Self::ExtensionNotPresent,
+ VulkanError::FeatureNotPresent => Self::FeatureNotPresent,
+ VulkanError::TooManyObjects => Self::TooManyObjects,
+ _ => panic!("Unexpected error value"),
}
}
}
impl From<ExtensionRestrictionError> for DeviceCreationError {
- #[inline]
fn from(err: ExtensionRestrictionError) -> Self {
Self::ExtensionRestrictionNotMet(err)
}
}
impl From<FeatureRestrictionError> for DeviceCreationError {
- #[inline]
fn from(err: FeatureRestrictionError) -> Self {
Self::FeatureRestrictionNotMet(err)
}
}
-/// Represents a queue where commands can be submitted.
-// TODO: should use internal synchronization?
-#[derive(Debug)]
-pub struct Queue {
- queue: Mutex<ash::vk::Queue>,
- device: Arc<Device>,
- family: u32,
- id: u32, // id within family
-}
+/// Parameters to create a new `Device`.
+#[derive(Clone, Debug)]
+pub struct DeviceCreateInfo {
+ /// The extensions to enable on the device.
+ ///
+ /// If the [`khr_portability_subset`](DeviceExtensions::khr_portability_subset) extension is
+ /// available, it will be enabled automatically, so you do not have to do this yourself.
+ /// You are responsible for ensuring that your program can work correctly on such devices.
+ /// See [the documentation of the `instance` module](crate::instance#portability-subset-devices-and-the-enumerate_portability-flag)
+ /// for more information.
+ ///
+ /// The default value is [`DeviceExtensions::empty()`].
+ pub enabled_extensions: DeviceExtensions,
-impl Queue {
- /// Returns the device this queue belongs to.
- #[inline]
- pub fn device(&self) -> &Arc<Device> {
- &self.device
- }
+ /// The features to enable on the device.
+ ///
+ /// The default value is [`Features::empty()`].
+ pub enabled_features: Features,
- /// Returns true if this is the same queue as another one.
- #[inline]
- pub fn is_same(&self, other: &Queue) -> bool {
- self.id == other.id
- && self.family == other.family
- && self.device.internal_object() == other.device.internal_object()
- }
+ /// The queues to create for the device.
+ ///
+ /// The default value is empty, which must be overridden.
+ pub queue_create_infos: Vec<QueueCreateInfo>,
- /// Returns the family this queue belongs to.
- #[inline]
- pub fn family(&self) -> QueueFamily {
- self.device
- .physical_device()
- .queue_family_by_id(self.family)
- .unwrap()
- }
+ pub _ne: crate::NonExhaustive,
+}
- /// Returns the index of this queue within its family.
+impl Default for DeviceCreateInfo {
#[inline]
- pub fn id_within_family(&self) -> u32 {
- self.id
+ fn default() -> Self {
+ Self {
+ enabled_extensions: DeviceExtensions::empty(),
+ enabled_features: Features::empty(),
+ queue_create_infos: Vec::new(),
+ _ne: crate::NonExhaustive(()),
+ }
}
+}
+
+/// Parameters to create queues in a new `Device`.
+#[derive(Clone, Debug)]
+pub struct QueueCreateInfo {
+ /// The index of the queue family to create queues for.
+ ///
+ /// The default value is `0`.
+ pub queue_family_index: u32,
- /// Waits until all work on this queue has finished.
+ /// The queues to create for the given queue family, each with a relative priority.
+ ///
+ /// The relative priority value is an arbitrary number between 0.0 and 1.0. Giving a queue a
+ /// higher priority is a hint to the driver that the queue should be given more processing time.
+ /// As this is only a hint, different drivers may handle this value differently and there are no
+ /// guarantees about its behavior.
///
- /// Just like `Device::wait()`, you shouldn't have to call this function in a typical program.
+ /// The default value is a single queue with a priority of 0.5.
+ pub queues: Vec<f32>,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for QueueCreateInfo {
#[inline]
- pub fn wait(&self) -> Result<(), OomError> {
- unsafe {
- let fns = self.device.fns();
- let queue = self.queue.lock().unwrap();
- check_errors(fns.v1_0.queue_wait_idle(*queue))?;
- Ok(())
+ fn default() -> Self {
+ Self {
+ queue_family_index: 0,
+ queues: vec![0.5],
+ _ne: crate::NonExhaustive(()),
}
}
}
-impl PartialEq for Queue {
- fn eq(&self, other: &Self) -> bool {
- self.is_same(other)
+/// Implemented on objects that belong to a Vulkan device.
+///
+/// # Safety
+///
+/// - `device()` must return the correct device.
+pub unsafe trait DeviceOwned {
+ /// Returns the device that owns `Self`.
+ fn device(&self) -> &Arc<Device>;
+}
+
+unsafe impl<T> DeviceOwned for T
+where
+ T: Deref,
+ T::Target: DeviceOwned,
+{
+ fn device(&self) -> &Arc<Device> {
+ (**self).device()
}
}
-impl Eq for Queue {}
+/// The properties of a Unix file descriptor when it is imported.
+#[derive(Clone, Debug)]
+#[non_exhaustive]
+pub struct MemoryFdProperties {
+ /// A bitmask of the indices of memory types that can be used with the file.
+ pub memory_type_bits: u32,
+}
-unsafe impl DeviceOwned for Queue {
- fn device(&self) -> &Arc<Device> {
- &self.device
+/// Error that can happen when calling `memory_fd_properties`.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum MemoryFdPropertiesError {
+ /// No memory available on the host.
+ OutOfHostMemory,
+
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+
+ /// The provided external handle was not valid.
+ InvalidExternalHandle,
+
+ /// The provided external handle type was not valid.
+ InvalidExternalHandleType,
+
+ /// The `khr_external_memory_fd` extension was not enabled on the device.
+ NotSupported,
+}
+
+impl Error for MemoryFdPropertiesError {}
+
+impl Display for MemoryFdPropertiesError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::OutOfHostMemory => write!(f, "no memory available on the host"),
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ Self::InvalidExternalHandle => {
+ write!(f, "the provided external handle was not valid")
+ }
+ Self::InvalidExternalHandleType => {
+ write!(f, "the provided external handle type was not valid")
+ }
+ Self::NotSupported => write!(
+ f,
+ "the `khr_external_memory_fd` extension was not enabled on the device",
+ ),
+ }
}
}
-unsafe impl SynchronizedVulkanObject for Queue {
- type Object = ash::vk::Queue;
+impl From<VulkanError> for MemoryFdPropertiesError {
+ fn from(err: VulkanError) -> Self {
+ match err {
+ VulkanError::OutOfHostMemory => Self::OutOfHostMemory,
+ VulkanError::InvalidExternalHandle => Self::InvalidExternalHandle,
+ _ => panic!("Unexpected error value"),
+ }
+ }
+}
- #[inline]
- fn internal_object_guard(&self) -> MutexGuard<ash::vk::Queue> {
- self.queue.lock().unwrap()
+impl From<RequirementNotMet> for MemoryFdPropertiesError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
+ }
}
}
#[cfg(test)]
mod tests {
- use crate::device::physical::PhysicalDevice;
- use crate::device::Device;
- use crate::device::DeviceCreationError;
- use crate::device::DeviceExtensions;
- use crate::device::{FeatureRestriction, FeatureRestrictionError, Features};
+ use crate::device::{
+ Device, DeviceCreateInfo, DeviceCreationError, FeatureRestriction, FeatureRestrictionError,
+ Features, QueueCreateInfo,
+ };
use std::sync::Arc;
#[test]
@@ -954,51 +926,63 @@ mod tests {
#[test]
fn too_many_queues() {
let instance = instance!();
- let physical = match PhysicalDevice::enumerate(&instance).next() {
+ let physical_device = match instance.enumerate_physical_devices().unwrap().next() {
Some(p) => p,
None => return,
};
- let family = physical.queue_families().next().unwrap();
- let queues = (0..family.queues_count() + 1).map(|_| (family, 1.0));
+ let queue_family_index = 0;
+ let queue_family_properties =
+ &physical_device.queue_family_properties()[queue_family_index as usize];
+ let queues = (0..queue_family_properties.queue_count + 1)
+ .map(|_| (0.5))
+ .collect();
match Device::new(
- physical,
- &Features::none(),
- &DeviceExtensions::none(),
- queues,
+ physical_device,
+ DeviceCreateInfo {
+ queue_create_infos: vec![QueueCreateInfo {
+ queue_family_index,
+ queues,
+ ..Default::default()
+ }],
+ ..Default::default()
+ },
) {
- Err(DeviceCreationError::TooManyQueuesForFamily) => return, // Success
+ Err(DeviceCreationError::TooManyQueuesForFamily) => (), // Success
_ => panic!(),
};
}
#[test]
- fn unsupposed_features() {
+ fn unsupported_features() {
let instance = instance!();
- let physical = match PhysicalDevice::enumerate(&instance).next() {
+ let physical_device = match instance.enumerate_physical_devices().unwrap().next() {
Some(p) => p,
None => return,
};
- let family = physical.queue_families().next().unwrap();
-
let features = Features::all();
// In the unlikely situation where the device supports everything, we ignore the test.
- if physical.supported_features().is_superset_of(&features) {
+ if physical_device.supported_features().contains(&features) {
return;
}
match Device::new(
- physical,
- &features,
- &DeviceExtensions::none(),
- Some((family, 1.0)),
+ physical_device,
+ DeviceCreateInfo {
+ enabled_features: features,
+ queue_create_infos: vec![QueueCreateInfo {
+ queue_family_index: 0,
+ ..Default::default()
+ }],
+ ..Default::default()
+ },
) {
Err(DeviceCreationError::FeatureRestrictionNotMet(FeatureRestrictionError {
restriction: FeatureRestriction::NotSupported,
..
- })) => return, // Success
+ })) => (), // Success
_ => panic!(),
};
}
@@ -1006,31 +990,37 @@ mod tests {
#[test]
fn priority_out_of_range() {
let instance = instance!();
- let physical = match PhysicalDevice::enumerate(&instance).next() {
+ let physical_device = match instance.enumerate_physical_devices().unwrap().next() {
Some(p) => p,
None => return,
};
- let family = physical.queue_families().next().unwrap();
-
- match Device::new(
- physical,
- &Features::none(),
- &DeviceExtensions::none(),
- Some((family, 1.4)),
- ) {
- Err(DeviceCreationError::PriorityOutOfRange) => (), // Success
- _ => panic!(),
- };
+ assert_should_panic!({
+ Device::new(
+ physical_device.clone(),
+ DeviceCreateInfo {
+ queue_create_infos: vec![QueueCreateInfo {
+ queue_family_index: 0,
+ queues: vec![1.4],
+ ..Default::default()
+ }],
+ ..Default::default()
+ },
+ )
+ });
- match Device::new(
- physical,
- &Features::none(),
- &DeviceExtensions::none(),
- Some((family, -0.2)),
- ) {
- Err(DeviceCreationError::PriorityOutOfRange) => (), // Success
- _ => panic!(),
- };
+ assert_should_panic!({
+ Device::new(
+ physical_device,
+ DeviceCreateInfo {
+ queue_create_infos: vec![QueueCreateInfo {
+ queue_family_index: 0,
+ queues: vec![-0.2],
+ ..Default::default()
+ }],
+ ..Default::default()
+ },
+ )
+ });
}
}
diff --git a/src/device/physical.rs b/src/device/physical.rs
index feaea4b..cfee295 100644
--- a/src/device/physical.rs
+++ b/src/device/physical.rs
@@ -7,768 +7,2459 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use crate::check_errors;
-use crate::device::{DeviceExtensions, Features, FeaturesFfi, Properties, PropertiesFfi};
-use crate::instance::{Instance, InstanceCreationError};
-use crate::sync::PipelineStage;
-use crate::DeviceSize;
-use crate::Version;
-use crate::VulkanObject;
-use std::convert::TryFrom;
-use std::ffi::CStr;
-use std::fmt;
-use std::hash::Hash;
-use std::mem::MaybeUninit;
-use std::ptr;
-use std::sync::Arc;
-
-#[derive(Clone, Debug)]
-pub(crate) struct PhysicalDeviceInfo {
+use super::QueueFamilyProperties;
+use crate::{
+ buffer::{ExternalBufferInfo, ExternalBufferProperties},
+ cache::OnceCache,
+ device::{properties::Properties, DeviceExtensions, Features, FeaturesFfi, PropertiesFfi},
+ format::{Format, FormatProperties},
+ image::{
+ ImageAspects, ImageFormatInfo, ImageFormatProperties, ImageUsage, SparseImageFormatInfo,
+ SparseImageFormatProperties,
+ },
+ instance::Instance,
+ macros::{impl_id_counter, vulkan_bitflags, vulkan_enum},
+ memory::{ExternalMemoryHandleType, MemoryProperties},
+ swapchain::{
+ ColorSpace, FullScreenExclusive, PresentMode, Surface, SurfaceApi, SurfaceCapabilities,
+ SurfaceInfo, SurfaceTransforms,
+ },
+ sync::{
+ fence::{ExternalFenceInfo, ExternalFenceProperties},
+ semaphore::{ExternalSemaphoreInfo, ExternalSemaphoreProperties},
+ },
+ ExtensionProperties, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject,
+};
+use bytemuck::cast_slice;
+use std::{
+ error::Error,
+ fmt::{Debug, Display, Error as FmtError, Formatter},
+ mem::MaybeUninit,
+ num::NonZeroU64,
+ ptr,
+ sync::Arc,
+};
+
+/// Represents one of the available physical devices on this machine.
+///
+/// # Examples
+///
+/// ```no_run
+/// # use vulkano::{
+/// # instance::{Instance, InstanceExtensions},
+/// # Version, VulkanLibrary,
+/// # };
+/// use vulkano::device::physical::PhysicalDevice;
+///
+/// # let library = VulkanLibrary::new().unwrap();
+/// # let instance = Instance::new(library, Default::default()).unwrap();
+/// for physical_device in instance.enumerate_physical_devices().unwrap() {
+/// print_infos(&physical_device);
+/// }
+///
+/// fn print_infos(dev: &PhysicalDevice) {
+/// println!("Name: {}", dev.properties().device_name);
+/// }
+/// ```
+#[derive(Debug)]
+pub struct PhysicalDevice {
handle: ash::vk::PhysicalDevice,
+ instance: Arc<Instance>,
+ id: NonZeroU64,
+
+ // Data queried at `PhysicalDevice` creation.
api_version: Version,
supported_extensions: DeviceExtensions,
- required_extensions: DeviceExtensions,
supported_features: Features,
properties: Properties,
- memory_properties: ash::vk::PhysicalDeviceMemoryProperties,
- queue_families: Vec<ash::vk::QueueFamilyProperties>,
+ extension_properties: Vec<ExtensionProperties>,
+ memory_properties: MemoryProperties,
+ queue_family_properties: Vec<QueueFamilyProperties>,
+
+ // Data queried by the user at runtime, cached for faster lookups.
+ external_buffer_properties: OnceCache<ExternalBufferInfo, ExternalBufferProperties>,
+ external_fence_properties: OnceCache<ExternalFenceInfo, ExternalFenceProperties>,
+ external_semaphore_properties: OnceCache<ExternalSemaphoreInfo, ExternalSemaphoreProperties>,
+ format_properties: OnceCache<Format, FormatProperties>,
+ image_format_properties: OnceCache<ImageFormatInfo, Option<ImageFormatProperties>>,
+ sparse_image_format_properties:
+ OnceCache<SparseImageFormatInfo, Vec<SparseImageFormatProperties>>,
}
-pub(crate) fn init_physical_devices(
- instance: &Instance,
-) -> Result<Vec<PhysicalDeviceInfo>, InstanceCreationError> {
- let fns = instance.fns();
- let instance_extensions = instance.enabled_extensions();
+impl PhysicalDevice {
+ /// Creates a new `PhysicalDevice` from a raw object handle.
+ ///
+ /// # Safety
+ ///
+ /// - `handle` must be a valid Vulkan object handle created from `instance`.
+ pub unsafe fn from_handle(
+ instance: Arc<Instance>,
+ handle: ash::vk::PhysicalDevice,
+ ) -> Result<Arc<Self>, VulkanError> {
+ let api_version = Self::get_api_version(handle, &instance);
+ let extension_properties = Self::get_extension_properties(handle, &instance)?;
+ let supported_extensions: DeviceExtensions = extension_properties
+ .iter()
+ .map(|property| property.extension_name.as_str())
+ .collect();
+
+ let supported_features;
+ let properties;
+ let memory_properties;
+ let queue_family_properties;
+
+ // Get the remaining infos.
+ // If possible, we use VK_KHR_get_physical_device_properties2.
+ if api_version >= Version::V1_1
+ || instance
+ .enabled_extensions()
+ .khr_get_physical_device_properties2
+ {
+ supported_features =
+ Self::get_features2(handle, &instance, api_version, &supported_extensions);
+ properties =
+ Self::get_properties2(handle, &instance, api_version, &supported_extensions);
+ memory_properties = Self::get_memory_properties2(handle, &instance);
+ queue_family_properties = Self::get_queue_family_properties2(handle, &instance);
+ } else {
+ supported_features = Self::get_features(handle, &instance);
+ properties =
+ Self::get_properties(handle, &instance, api_version, &supported_extensions);
+ memory_properties = Self::get_memory_properties(handle, &instance);
+ queue_family_properties = Self::get_queue_family_properties(handle, &instance);
+ };
- let handles: Vec<ash::vk::PhysicalDevice> = unsafe {
- let mut num = 0;
- check_errors(fns.v1_0.enumerate_physical_devices(
- instance.internal_object(),
- &mut num,
- ptr::null_mut(),
- ))?;
+ Ok(Arc::new(PhysicalDevice {
+ handle,
+ instance,
+ id: Self::next_id(),
+ api_version,
+ supported_extensions,
+ supported_features,
+ properties,
+ extension_properties,
+ memory_properties,
+ queue_family_properties,
+ external_buffer_properties: OnceCache::new(),
+ external_fence_properties: OnceCache::new(),
+ external_semaphore_properties: OnceCache::new(),
+ format_properties: OnceCache::new(),
+ image_format_properties: OnceCache::new(),
+ sparse_image_format_properties: OnceCache::new(),
+ }))
+ }
- let mut handles = Vec::with_capacity(num as usize);
- check_errors(fns.v1_0.enumerate_physical_devices(
- instance.internal_object(),
- &mut num,
- handles.as_mut_ptr(),
- ))?;
- handles.set_len(num as usize);
- handles
- };
-
- let mut infos: Vec<PhysicalDeviceInfo> = handles
- .into_iter()
- .enumerate()
- .map(|(index, handle)| -> Result<_, InstanceCreationError> {
- let api_version = unsafe {
- let mut output = MaybeUninit::uninit();
- fns.v1_0
- .get_physical_device_properties(handle, output.as_mut_ptr());
- let api_version = Version::try_from(output.assume_init().api_version).unwrap();
- std::cmp::min(instance.max_api_version(), api_version)
- };
+ unsafe fn get_api_version(handle: ash::vk::PhysicalDevice, instance: &Instance) -> Version {
+ let fns = instance.fns();
+ let mut output = MaybeUninit::uninit();
+ (fns.v1_0.get_physical_device_properties)(handle, output.as_mut_ptr());
+ let api_version = Version::try_from(output.assume_init().api_version).unwrap();
+ std::cmp::min(instance.max_api_version(), api_version)
+ }
- let extension_properties: Vec<ash::vk::ExtensionProperties> = unsafe {
- let mut num = 0;
- check_errors(fns.v1_0.enumerate_device_extension_properties(
- handle,
- ptr::null(),
- &mut num,
- ptr::null_mut(),
- ))?;
-
- let mut properties = Vec::with_capacity(num as usize);
- check_errors(fns.v1_0.enumerate_device_extension_properties(
- handle,
- ptr::null(),
- &mut num,
- properties.as_mut_ptr(),
- ))?;
- properties.set_len(num as usize);
- properties
- };
+ unsafe fn get_extension_properties(
+ handle: ash::vk::PhysicalDevice,
+ instance: &Instance,
+ ) -> Result<Vec<ExtensionProperties>, VulkanError> {
+ let fns = instance.fns();
+
+ loop {
+ let mut count = 0;
+ (fns.v1_0.enumerate_device_extension_properties)(
+ handle,
+ ptr::null(),
+ &mut count,
+ ptr::null_mut(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
- let supported_extensions = DeviceExtensions::from(
- extension_properties
- .iter()
- .map(|property| unsafe { CStr::from_ptr(property.extension_name.as_ptr()) }),
+ let mut output = Vec::with_capacity(count as usize);
+ let result = (fns.v1_0.enumerate_device_extension_properties)(
+ handle,
+ ptr::null(),
+ &mut count,
+ output.as_mut_ptr(),
);
- let required_extensions = supported_extensions
- .intersection(&DeviceExtensions::required_if_supported_extensions());
+ match result {
+ ash::vk::Result::SUCCESS => {
+ output.set_len(count as usize);
+ return Ok(output.into_iter().map(Into::into).collect());
+ }
+ ash::vk::Result::INCOMPLETE => (),
+ err => return Err(VulkanError::from(err)),
+ }
+ }
+ }
- Ok(PhysicalDeviceInfo {
- handle,
- api_version,
- supported_extensions,
- required_extensions,
- supported_features: Default::default(),
- properties: Default::default(),
- memory_properties: Default::default(),
- queue_families: Default::default(),
- })
- })
- .collect::<Result<_, _>>()?;
-
- // Getting the remaining infos.
- // If possible, we use VK_KHR_get_physical_device_properties2.
- if instance.api_version() >= Version::V1_1
- || instance_extensions.khr_get_physical_device_properties2
- {
- init_physical_devices_inner2(instance, &mut infos)
- } else {
- init_physical_devices_inner(instance, &mut infos)
- };
-
- Ok(infos)
-}
+ unsafe fn get_features(handle: ash::vk::PhysicalDevice, instance: &Instance) -> Features {
+ let mut output = FeaturesFfi::default();
-/// Initialize all physical devices
-fn init_physical_devices_inner(instance: &Instance, infos: &mut [PhysicalDeviceInfo]) {
- let fns = instance.fns();
+ let fns = instance.fns();
+ (fns.v1_0.get_physical_device_features)(handle, &mut output.head_as_mut().features);
- for info in infos.into_iter() {
- info.supported_features = unsafe {
- let mut output = FeaturesFfi::default();
- fns.v1_0
- .get_physical_device_features(info.handle, &mut output.head_as_mut().features);
- Features::from(&output)
- };
+ Features::from(&output)
+ }
- info.properties = unsafe {
- let mut output = PropertiesFfi::default();
- output.make_chain(
- info.api_version,
- &info.supported_extensions,
- instance.enabled_extensions(),
- );
- fns.v1_0
- .get_physical_device_properties(info.handle, &mut output.head_as_mut().properties);
- Properties::from(&output)
- };
+ unsafe fn get_features2(
+ handle: ash::vk::PhysicalDevice,
+ instance: &Instance,
+ api_version: Version,
+ supported_extensions: &DeviceExtensions,
+ ) -> Features {
+ let mut output = FeaturesFfi::default();
+ output.make_chain(
+ api_version,
+ supported_extensions,
+ instance.enabled_extensions(),
+ );
+
+ let fns = instance.fns();
+
+ if instance.api_version() >= Version::V1_1 {
+ (fns.v1_1.get_physical_device_features2)(handle, output.head_as_mut());
+ } else {
+ (fns.khr_get_physical_device_properties2
+ .get_physical_device_features2_khr)(handle, output.head_as_mut());
+ }
- info.memory_properties = unsafe {
- let mut output = MaybeUninit::uninit();
- fns.v1_0
- .get_physical_device_memory_properties(info.handle, output.as_mut_ptr());
- output.assume_init()
- };
+ Features::from(&output)
+ }
- info.queue_families = unsafe {
- let mut num = 0;
- fns.v1_0.get_physical_device_queue_family_properties(
- info.handle,
+ unsafe fn get_properties(
+ handle: ash::vk::PhysicalDevice,
+ instance: &Instance,
+ api_version: Version,
+ supported_extensions: &DeviceExtensions,
+ ) -> Properties {
+ let mut output = PropertiesFfi::default();
+ output.make_chain(
+ api_version,
+ supported_extensions,
+ instance.enabled_extensions(),
+ );
+
+ let fns = instance.fns();
+ (fns.v1_0.get_physical_device_properties)(handle, &mut output.head_as_mut().properties);
+
+ Properties::from(&output)
+ }
+
+ unsafe fn get_properties2(
+ handle: ash::vk::PhysicalDevice,
+ instance: &Instance,
+ api_version: Version,
+ supported_extensions: &DeviceExtensions,
+ ) -> Properties {
+ let mut output = PropertiesFfi::default();
+ output.make_chain(
+ api_version,
+ supported_extensions,
+ instance.enabled_extensions(),
+ );
+
+ let fns = instance.fns();
+
+ if instance.api_version() >= Version::V1_1 {
+ (fns.v1_1.get_physical_device_properties2)(handle, output.head_as_mut());
+ } else {
+ (fns.khr_get_physical_device_properties2
+ .get_physical_device_properties2_khr)(handle, output.head_as_mut());
+ }
+
+ Properties::from(&output)
+ }
+
+ unsafe fn get_memory_properties(
+ handle: ash::vk::PhysicalDevice,
+ instance: &Instance,
+ ) -> MemoryProperties {
+ let mut output = MaybeUninit::uninit();
+
+ let fns = instance.fns();
+ (fns.v1_0.get_physical_device_memory_properties)(handle, output.as_mut_ptr());
+
+ output.assume_init().into()
+ }
+
+ unsafe fn get_memory_properties2(
+ handle: ash::vk::PhysicalDevice,
+ instance: &Instance,
+ ) -> MemoryProperties {
+ let mut output = ash::vk::PhysicalDeviceMemoryProperties2KHR::default();
+
+ let fns = instance.fns();
+
+ if instance.api_version() >= Version::V1_1 {
+ (fns.v1_1.get_physical_device_memory_properties2)(handle, &mut output);
+ } else {
+ (fns.khr_get_physical_device_properties2
+ .get_physical_device_memory_properties2_khr)(handle, &mut output);
+ }
+
+ output.memory_properties.into()
+ }
+
+ unsafe fn get_queue_family_properties(
+ handle: ash::vk::PhysicalDevice,
+ instance: &Instance,
+ ) -> Vec<QueueFamilyProperties> {
+ let fns = instance.fns();
+
+ let mut num = 0;
+ (fns.v1_0.get_physical_device_queue_family_properties)(handle, &mut num, ptr::null_mut());
+
+ let mut output = Vec::with_capacity(num as usize);
+ (fns.v1_0.get_physical_device_queue_family_properties)(
+ handle,
+ &mut num,
+ output.as_mut_ptr(),
+ );
+ output.set_len(num as usize);
+
+ output.into_iter().map(Into::into).collect()
+ }
+
+ unsafe fn get_queue_family_properties2(
+ handle: ash::vk::PhysicalDevice,
+ instance: &Instance,
+ ) -> Vec<QueueFamilyProperties> {
+ let mut num = 0;
+ let fns = instance.fns();
+
+ if instance.api_version() >= Version::V1_1 {
+ (fns.v1_1.get_physical_device_queue_family_properties2)(
+ handle,
&mut num,
ptr::null_mut(),
);
-
- let mut families = Vec::with_capacity(num as usize);
- fns.v1_0.get_physical_device_queue_family_properties(
- info.handle,
+ } else {
+ (fns.khr_get_physical_device_properties2
+ .get_physical_device_queue_family_properties2_khr)(
+ handle,
&mut num,
- families.as_mut_ptr(),
+ ptr::null_mut(),
);
- families.set_len(num as usize);
- families
- };
- }
-}
+ }
-/// Initialize all physical devices, but use VK_KHR_get_physical_device_properties2
-/// TODO: Query extension-specific physical device properties, once a new instance extension is supported.
-fn init_physical_devices_inner2(instance: &Instance, infos: &mut [PhysicalDeviceInfo]) {
- let fns = instance.fns();
-
- for info in infos.into_iter() {
- info.supported_features = unsafe {
- let mut output = FeaturesFfi::default();
- output.make_chain(
- info.api_version,
- &info.supported_extensions,
- instance.enabled_extensions(),
+ let mut output = vec![ash::vk::QueueFamilyProperties2::default(); num as usize];
+
+ if instance.api_version() >= Version::V1_1 {
+ (fns.v1_1.get_physical_device_queue_family_properties2)(
+ handle,
+ &mut num,
+ output.as_mut_ptr(),
+ );
+ } else {
+ (fns.khr_get_physical_device_properties2
+ .get_physical_device_queue_family_properties2_khr)(
+ handle,
+ &mut num,
+ output.as_mut_ptr(),
);
+ }
- if instance.api_version() >= Version::V1_1 {
- fns.v1_1
- .get_physical_device_features2(info.handle, output.head_as_mut());
- } else {
- fns.khr_get_physical_device_properties2
- .get_physical_device_features2_khr(info.handle, output.head_as_mut());
- }
+ output
+ .into_iter()
+ .map(|family| family.queue_family_properties.into())
+ .collect()
+ }
- Features::from(&output)
- };
+ /// Returns the instance that owns the physical device.
+ #[inline]
+ pub fn instance(&self) -> &Arc<Instance> {
+ &self.instance
+ }
- info.properties = unsafe {
- let mut output = PropertiesFfi::default();
- output.make_chain(
- info.api_version,
- &info.supported_extensions,
- instance.enabled_extensions(),
- );
+ /// Returns the version of Vulkan supported by the physical device.
+ ///
+ /// Unlike the `api_version` property, which is the version reported by the device directly,
+ /// this function returns the version the device can actually support, based on the instance's
+ /// `max_api_version`.
+ #[inline]
+ pub fn api_version(&self) -> Version {
+ self.api_version
+ }
- if instance.api_version() >= Version::V1_1 {
- fns.v1_1
- .get_physical_device_properties2(info.handle, output.head_as_mut());
- } else {
- fns.khr_get_physical_device_properties2
- .get_physical_device_properties2_khr(info.handle, output.head_as_mut());
- }
+ /// Returns the properties reported by the physical device.
+ #[inline]
+ pub fn properties(&self) -> &Properties {
+ &self.properties
+ }
- Properties::from(&output)
- };
+ /// Returns the extension properties reported by the physical device.
+ #[inline]
+ pub fn extension_properties(&self) -> &[ExtensionProperties] {
+ &self.extension_properties
+ }
- info.memory_properties = unsafe {
- let mut output = ash::vk::PhysicalDeviceMemoryProperties2KHR::default();
+ /// Returns the extensions that are supported by the physical device.
+ #[inline]
+ pub fn supported_extensions(&self) -> &DeviceExtensions {
+ &self.supported_extensions
+ }
- if instance.api_version() >= Version::V1_1 {
- fns.v1_1
- .get_physical_device_memory_properties2(info.handle, &mut output);
- } else {
- fns.khr_get_physical_device_properties2
- .get_physical_device_memory_properties2_khr(info.handle, &mut output);
- }
+ /// Returns the features that are supported by the physical device.
+ #[inline]
+ pub fn supported_features(&self) -> &Features {
+ &self.supported_features
+ }
- output.memory_properties
- };
+ /// Returns the memory properties reported by the physical device.
+ #[inline]
+ pub fn memory_properties(&self) -> &MemoryProperties {
+ &self.memory_properties
+ }
- info.queue_families = unsafe {
- let mut num = 0;
+ /// Returns the queue family properties reported by the physical device.
+ #[inline]
+ pub fn queue_family_properties(&self) -> &[QueueFamilyProperties] {
+ &self.queue_family_properties
+ }
- if instance.api_version() >= Version::V1_1 {
- fns.v1_1.get_physical_device_queue_family_properties2(
- info.handle,
- &mut num,
- ptr::null_mut(),
- );
- } else {
- fns.khr_get_physical_device_properties2
- .get_physical_device_queue_family_properties2_khr(
- info.handle,
- &mut num,
- ptr::null_mut(),
- );
- }
+ /// Queries whether the physical device supports presenting to DirectFB surfaces from queues of
+ /// the given queue family.
+ ///
+ /// # Safety
+ ///
+ /// - `dfb` must be a valid DirectFB `IDirectFB` handle.
+ #[inline]
+ pub unsafe fn directfb_presentation_support<D>(
+ &self,
+ queue_family_index: u32,
+ dfb: *const D,
+ ) -> Result<bool, PhysicalDeviceError> {
+ self.validate_directfb_presentation_support(queue_family_index, dfb)?;
+
+ Ok(self.directfb_presentation_support_unchecked(queue_family_index, dfb))
+ }
- let mut families = vec![ash::vk::QueueFamilyProperties2::default(); num as usize];
+ fn validate_directfb_presentation_support<D>(
+ &self,
+ queue_family_index: u32,
+ _dfb: *const D,
+ ) -> Result<(), PhysicalDeviceError> {
+ if !self.instance.enabled_extensions().ext_directfb_surface {
+ return Err(PhysicalDeviceError::RequirementNotMet {
+ required_for: "`PhysicalDevice::directfb_presentation_support`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["ext_directfb_surface"],
+ ..Default::default()
+ },
+ });
+ }
- if instance.api_version() >= Version::V1_1 {
- fns.v1_1.get_physical_device_queue_family_properties2(
- info.handle,
- &mut num,
- families.as_mut_ptr(),
- );
- } else {
- fns.khr_get_physical_device_properties2
- .get_physical_device_queue_family_properties2_khr(
- info.handle,
- &mut num,
- families.as_mut_ptr(),
- );
- }
+ // VUID-vkGetPhysicalDeviceDirectFBPresentationSupportEXT-queueFamilyIndex-04119
+ if queue_family_index >= self.queue_family_properties.len() as u32 {
+ return Err(PhysicalDeviceError::QueueFamilyIndexOutOfRange {
+ queue_family_index,
+ queue_family_count: self.queue_family_properties.len() as u32,
+ });
+ }
- families
- .into_iter()
- .map(|family| family.queue_family_properties)
- .collect()
- };
+ // VUID-vkGetPhysicalDeviceDirectFBPresentationSupportEXT-dfb-parameter
+ // Can't validate, therefore unsafe
+
+ Ok(())
}
-}
-/// Represents one of the available devices on this machine.
-///
-/// This struct simply contains a pointer to an instance and a number representing the physical
-/// device. You are therefore encouraged to pass this around by value instead of by reference.
-///
-/// # Example
-///
-/// ```no_run
-/// # use vulkano::instance::Instance;
-/// # use vulkano::instance::InstanceExtensions;
-/// # use vulkano::Version;
-/// use vulkano::device::physical::PhysicalDevice;
-///
-/// # let instance = Instance::new(None, Version::V1_1, &InstanceExtensions::none(), None).unwrap();
-/// for physical_device in PhysicalDevice::enumerate(&instance) {
-/// print_infos(physical_device);
-/// }
-///
-/// fn print_infos(dev: PhysicalDevice) {
-/// println!("Name: {}", dev.properties().device_name);
-/// }
-/// ```
-#[derive(Clone, Copy, Debug)]
-pub struct PhysicalDevice<'a> {
- instance: &'a Arc<Instance>,
- index: usize,
- info: &'a PhysicalDeviceInfo,
-}
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ #[inline]
+ pub unsafe fn directfb_presentation_support_unchecked<D>(
+ &self,
+ queue_family_index: u32,
+ dfb: *const D,
+ ) -> bool {
+ let fns = self.instance.fns();
+ (fns.ext_directfb_surface
+ .get_physical_device_direct_fb_presentation_support_ext)(
+ self.handle,
+ queue_family_index,
+ dfb as *mut _,
+ ) != 0
+ }
-impl<'a> PhysicalDevice<'a> {
- /// Returns an iterator that enumerates the physical devices available.
+ /// Retrieves the external memory properties supported for buffers with a given configuration.
///
- /// # Example
+ /// Instance API version must be at least 1.1, or the [`khr_external_memory_capabilities`]
+ /// extension must be enabled on the instance.
///
- /// ```no_run
- /// # use vulkano::instance::Instance;
- /// # use vulkano::instance::InstanceExtensions;
- /// # use vulkano::Version;
- /// use vulkano::device::physical::PhysicalDevice;
+ /// The results of this function are cached, so that future calls with the same arguments
+ /// do not need to make a call to the Vulkan API again.
///
- /// # let instance = Instance::new(None, Version::V1_1, &InstanceExtensions::none(), None).unwrap();
- /// for physical_device in PhysicalDevice::enumerate(&instance) {
- /// println!("Available device: {}", physical_device.properties().device_name);
- /// }
- /// ```
+ /// [`khr_external_memory_capabilities`]: crate::instance::InstanceExtensions::khr_external_memory_capabilities
#[inline]
- pub fn enumerate(
- instance: &'a Arc<Instance>,
- ) -> impl ExactSizeIterator<Item = PhysicalDevice<'a>> {
- instance
- .physical_device_infos
- .iter()
- .enumerate()
- .map(move |(index, info)| PhysicalDevice {
- instance,
- index,
- info,
- })
+ pub fn external_buffer_properties(
+ &self,
+ info: ExternalBufferInfo,
+ ) -> Result<ExternalBufferProperties, PhysicalDeviceError> {
+ self.validate_external_buffer_properties(&info)?;
+
+ unsafe { Ok(self.external_buffer_properties_unchecked(info)) }
}
- /// Returns a physical device from its index. Returns `None` if out of range.
- ///
- /// Indices range from 0 to the number of devices.
- ///
- /// # Example
- ///
- /// ```no_run
- /// use vulkano::instance::Instance;
- /// use vulkano::instance::InstanceExtensions;
- /// use vulkano::device::physical::PhysicalDevice;
- /// use vulkano::Version;
- ///
- /// let instance = Instance::new(None, Version::V1_1, &InstanceExtensions::none(), None).unwrap();
- /// let first_physical_device = PhysicalDevice::from_index(&instance, 0).unwrap();
- /// ```
+ fn validate_external_buffer_properties(
+ &self,
+ info: &ExternalBufferInfo,
+ ) -> Result<(), PhysicalDeviceError> {
+ if !(self.instance.api_version() >= Version::V1_1
+ || self
+ .instance
+ .enabled_extensions()
+ .khr_external_memory_capabilities)
+ {
+ return Err(PhysicalDeviceError::RequirementNotMet {
+ required_for: "`PhysicalDevice::external_buffer_properties`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_1),
+ instance_extensions: &["khr_external_memory_capabilities"],
+ ..Default::default()
+ },
+ });
+ }
+
+ let &ExternalBufferInfo {
+ handle_type,
+ usage,
+ sparse: _,
+ _ne: _,
+ } = info;
+
+ // VUID-VkPhysicalDeviceExternalBufferInfo-usage-parameter
+ usage.validate_physical_device(self)?;
+
+ // VUID-VkPhysicalDeviceExternalBufferInfo-usage-requiredbitmask
+ assert!(!usage.is_empty());
+
+ // VUID-VkPhysicalDeviceExternalBufferInfo-handleType-parameter
+ handle_type.validate_physical_device(self)?;
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
#[inline]
- pub fn from_index(instance: &'a Arc<Instance>, index: usize) -> Option<PhysicalDevice<'a>> {
- instance
- .physical_device_infos
- .get(index)
- .map(|info| PhysicalDevice {
- instance,
- index,
- info,
- })
+ pub unsafe fn external_buffer_properties_unchecked(
+ &self,
+ info: ExternalBufferInfo,
+ ) -> ExternalBufferProperties {
+ self.external_buffer_properties.get_or_insert(info, |info| {
+ /* Input */
+
+ let &ExternalBufferInfo {
+ handle_type,
+ usage,
+ sparse,
+ _ne: _,
+ } = info;
+
+ let external_buffer_info = ash::vk::PhysicalDeviceExternalBufferInfo {
+ flags: sparse.map(Into::into).unwrap_or_default(),
+ usage: usage.into(),
+ handle_type: handle_type.into(),
+ ..Default::default()
+ };
+
+ /* Output */
+
+ let mut external_buffer_properties = ash::vk::ExternalBufferProperties::default();
+
+ /* Call */
+
+ let fns = self.instance.fns();
+
+ if self.instance.api_version() >= Version::V1_1 {
+ (fns.v1_1.get_physical_device_external_buffer_properties)(
+ self.handle,
+ &external_buffer_info,
+ &mut external_buffer_properties,
+ )
+ } else {
+ (fns.khr_external_memory_capabilities
+ .get_physical_device_external_buffer_properties_khr)(
+ self.handle,
+ &external_buffer_info,
+ &mut external_buffer_properties,
+ );
+ }
+
+ ExternalBufferProperties {
+ external_memory_properties: external_buffer_properties
+ .external_memory_properties
+ .into(),
+ }
+ })
}
- /// Returns the instance corresponding to this physical device.
+ /// Retrieves the external handle properties supported for fences with a given
+ /// configuration.
///
- /// # Example
+ /// The instance API version must be at least 1.1, or the [`khr_external_fence_capabilities`]
+ /// extension must be enabled on the instance.
///
- /// ```no_run
- /// use vulkano::device::physical::PhysicalDevice;
+ /// The results of this function are cached, so that future calls with the same arguments
+ /// do not need to make a call to the Vulkan API again.
///
- /// fn do_something(physical_device: PhysicalDevice) {
- /// let _loaded_extensions = physical_device.instance().enabled_extensions();
- /// // ...
- /// }
- /// ```
+ /// [`khr_external_fence_capabilities`]: crate::instance::InstanceExtensions::khr_external_fence_capabilities
#[inline]
- pub fn instance(&self) -> &'a Arc<Instance> {
- &self.instance
+ pub fn external_fence_properties(
+ &self,
+ info: ExternalFenceInfo,
+ ) -> Result<ExternalFenceProperties, PhysicalDeviceError> {
+ self.validate_external_fence_properties(&info)?;
+
+ unsafe { Ok(self.external_fence_properties_unchecked(info)) }
}
- /// Returns the index of the physical device in the physical devices list.
- ///
- /// This index never changes and can be used later to retrieve a `PhysicalDevice` from an
- /// instance and an index.
- #[inline]
- pub fn index(&self) -> usize {
- self.index
+ fn validate_external_fence_properties(
+ &self,
+ info: &ExternalFenceInfo,
+ ) -> Result<(), PhysicalDeviceError> {
+ if !(self.instance.api_version() >= Version::V1_1
+ || self
+ .instance
+ .enabled_extensions()
+ .khr_external_fence_capabilities)
+ {
+ return Err(PhysicalDeviceError::RequirementNotMet {
+ required_for: "`PhysicalDevice::external_fence_properties`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_1),
+ instance_extensions: &["khr_external_fence_capabilities"],
+ ..Default::default()
+ },
+ });
+ }
+
+ let &ExternalFenceInfo {
+ handle_type,
+ _ne: _,
+ } = info;
+
+ // VUID-VkPhysicalDeviceExternalFenceInfo-handleType-parameter
+ handle_type.validate_physical_device(self)?;
+
+ Ok(())
}
- /// Returns the version of Vulkan supported by this device.
- ///
- /// Unlike the `api_version` property, which is the version reported by the device directly,
- /// this function returns the version the device can actually support, based on the instance's,
- /// `max_api_version`.
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
#[inline]
- pub fn api_version(&self) -> Version {
- self.info.api_version
+ pub unsafe fn external_fence_properties_unchecked(
+ &self,
+ info: ExternalFenceInfo,
+ ) -> ExternalFenceProperties {
+ self.external_fence_properties.get_or_insert(info, |info| {
+ /* Input */
+
+ let &ExternalFenceInfo {
+ handle_type,
+ _ne: _,
+ } = info;
+
+ let external_fence_info = ash::vk::PhysicalDeviceExternalFenceInfo {
+ handle_type: handle_type.into(),
+ ..Default::default()
+ };
+
+ /* Output */
+
+ let mut external_fence_properties = ash::vk::ExternalFenceProperties::default();
+
+ /* Call */
+
+ let fns = self.instance.fns();
+
+ if self.instance.api_version() >= Version::V1_1 {
+ (fns.v1_1.get_physical_device_external_fence_properties)(
+ self.handle,
+ &external_fence_info,
+ &mut external_fence_properties,
+ )
+ } else {
+ (fns.khr_external_fence_capabilities
+ .get_physical_device_external_fence_properties_khr)(
+ self.handle,
+ &external_fence_info,
+ &mut external_fence_properties,
+ );
+ }
+
+ ExternalFenceProperties {
+ exportable: external_fence_properties
+ .external_fence_features
+ .intersects(ash::vk::ExternalFenceFeatureFlags::EXPORTABLE),
+ importable: external_fence_properties
+ .external_fence_features
+ .intersects(ash::vk::ExternalFenceFeatureFlags::IMPORTABLE),
+ export_from_imported_handle_types: external_fence_properties
+ .export_from_imported_handle_types
+ .into(),
+ compatible_handle_types: external_fence_properties.compatible_handle_types.into(),
+ }
+ })
}
- /// Returns the extensions that are supported by this physical device.
+ /// Retrieves the external handle properties supported for semaphores with a given
+ /// configuration.
+ ///
+ /// The instance API version must be at least 1.1, or the
+ /// [`khr_external_semaphore_capabilities`] extension must be enabled on the instance.
+ ///
+ /// The results of this function are cached, so that future calls with the same arguments
+ /// do not need to make a call to the Vulkan API again.
+ ///
+ /// [`khr_external_semaphore_capabilities`]: crate::instance::InstanceExtensions::khr_external_semaphore_capabilities
#[inline]
- pub fn supported_extensions(&self) -> &'a DeviceExtensions {
- &self.info.supported_extensions
+ pub fn external_semaphore_properties(
+ &self,
+ info: ExternalSemaphoreInfo,
+ ) -> Result<ExternalSemaphoreProperties, PhysicalDeviceError> {
+ self.validate_external_semaphore_properties(&info)?;
+
+ unsafe { Ok(self.external_semaphore_properties_unchecked(info)) }
}
- /// Returns the extensions that must be enabled as a minimum when creating a `Device` from this
- /// physical device.
- pub fn required_extensions(&self) -> &'a DeviceExtensions {
- &self.info.required_extensions
+ fn validate_external_semaphore_properties(
+ &self,
+ info: &ExternalSemaphoreInfo,
+ ) -> Result<(), PhysicalDeviceError> {
+ if !(self.instance.api_version() >= Version::V1_1
+ || self
+ .instance
+ .enabled_extensions()
+ .khr_external_semaphore_capabilities)
+ {
+ return Err(PhysicalDeviceError::RequirementNotMet {
+ required_for: "`PhysicalDevice::external_semaphore_properties`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_1),
+ instance_extensions: &["khr_external_semaphore_capabilities"],
+ ..Default::default()
+ },
+ });
+ }
+
+ let &ExternalSemaphoreInfo {
+ handle_type,
+ _ne: _,
+ } = info;
+
+ // VUID-VkPhysicalDeviceExternalSemaphoreInfo-handleType-parameter
+ handle_type.validate_physical_device(self)?;
+
+ Ok(())
}
- /// Returns the properties reported by the device.
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
#[inline]
- pub fn properties(&self) -> &'a Properties {
- &self.info.properties
+ pub unsafe fn external_semaphore_properties_unchecked(
+ &self,
+ info: ExternalSemaphoreInfo,
+ ) -> ExternalSemaphoreProperties {
+ self.external_semaphore_properties
+ .get_or_insert(info, |info| {
+ /* Input */
+
+ let &ExternalSemaphoreInfo {
+ handle_type,
+ _ne: _,
+ } = info;
+
+ let external_semaphore_info = ash::vk::PhysicalDeviceExternalSemaphoreInfo {
+ handle_type: handle_type.into(),
+ ..Default::default()
+ };
+
+ /* Output */
+
+ let mut external_semaphore_properties =
+ ash::vk::ExternalSemaphoreProperties::default();
+
+ /* Call */
+
+ let fns = self.instance.fns();
+
+ if self.instance.api_version() >= Version::V1_1 {
+ (fns.v1_1.get_physical_device_external_semaphore_properties)(
+ self.handle,
+ &external_semaphore_info,
+ &mut external_semaphore_properties,
+ )
+ } else {
+ (fns.khr_external_semaphore_capabilities
+ .get_physical_device_external_semaphore_properties_khr)(
+ self.handle,
+ &external_semaphore_info,
+ &mut external_semaphore_properties,
+ );
+ }
+
+ ExternalSemaphoreProperties {
+ exportable: external_semaphore_properties
+ .external_semaphore_features
+ .intersects(ash::vk::ExternalSemaphoreFeatureFlags::EXPORTABLE),
+ importable: external_semaphore_properties
+ .external_semaphore_features
+ .intersects(ash::vk::ExternalSemaphoreFeatureFlags::IMPORTABLE),
+ export_from_imported_handle_types: external_semaphore_properties
+ .export_from_imported_handle_types
+ .into(),
+ compatible_handle_types: external_semaphore_properties
+ .compatible_handle_types
+ .into(),
+ }
+ })
}
- /// Returns the features that are supported by this physical device.
+ /// Retrieves the properties of a format when used by this physical device.
+ ///
+ /// The results of this function are cached, so that future calls with the same arguments
+ /// do not need to make a call to the Vulkan API again.
#[inline]
- pub fn supported_features(&self) -> &'a Features {
- &self.info.supported_features
+ pub fn format_properties(
+ &self,
+ format: Format,
+ ) -> Result<FormatProperties, PhysicalDeviceError> {
+ self.validate_format_properties(format)?;
+
+ unsafe { Ok(self.format_properties_unchecked(format)) }
}
- /// Builds an iterator that enumerates all the memory types on this physical device.
+ fn validate_format_properties(&self, format: Format) -> Result<(), PhysicalDeviceError> {
+ // VUID-vkGetPhysicalDeviceFormatProperties2-format-parameter
+ format.validate_physical_device(self)?;
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
#[inline]
- pub fn memory_types(&self) -> impl ExactSizeIterator<Item = MemoryType<'a>> {
- let physical_device = *self;
- self.info.memory_properties.memory_types
- [0..self.info.memory_properties.memory_type_count as usize]
- .iter()
- .enumerate()
- .map(move |(id, info)| MemoryType {
- physical_device,
- id: id as u32,
- info,
- })
+ pub unsafe fn format_properties_unchecked(&self, format: Format) -> FormatProperties {
+ self.format_properties.get_or_insert(format, |&format| {
+ let mut format_properties2 = ash::vk::FormatProperties2::default();
+ let mut format_properties3 = if self.api_version() >= Version::V1_3
+ || self.supported_extensions().khr_format_feature_flags2
+ {
+ Some(ash::vk::FormatProperties3KHR::default())
+ } else {
+ None
+ };
+
+ if let Some(next) = format_properties3.as_mut() {
+ next.p_next = format_properties2.p_next;
+ format_properties2.p_next = next as *mut _ as *mut _;
+ }
+
+ let fns = self.instance.fns();
+
+ if self.api_version() >= Version::V1_1 {
+ (fns.v1_1.get_physical_device_format_properties2)(
+ self.handle,
+ format.into(),
+ &mut format_properties2,
+ );
+ } else if self
+ .instance
+ .enabled_extensions()
+ .khr_get_physical_device_properties2
+ {
+ (fns.khr_get_physical_device_properties2
+ .get_physical_device_format_properties2_khr)(
+ self.handle,
+ format.into(),
+ &mut format_properties2,
+ );
+ } else {
+ (fns.v1_0.get_physical_device_format_properties)(
+ self.handle(),
+ format.into(),
+ &mut format_properties2.format_properties,
+ );
+ }
+
+ match format_properties3 {
+ Some(format_properties3) => FormatProperties {
+ linear_tiling_features: format_properties3.linear_tiling_features.into(),
+ optimal_tiling_features: format_properties3.optimal_tiling_features.into(),
+ buffer_features: format_properties3.buffer_features.into(),
+ _ne: crate::NonExhaustive(()),
+ },
+ None => FormatProperties {
+ linear_tiling_features: format_properties2
+ .format_properties
+ .linear_tiling_features
+ .into(),
+ optimal_tiling_features: format_properties2
+ .format_properties
+ .optimal_tiling_features
+ .into(),
+ buffer_features: format_properties2.format_properties.buffer_features.into(),
+ _ne: crate::NonExhaustive(()),
+ },
+ }
+ })
}
- /// Returns the memory type with the given index, or `None` if out of range.
+ /// Returns the properties supported for images with a given image configuration.
+ ///
+ /// `Some` is returned if the configuration is supported, `None` if it is not.
+ ///
+ /// The results of this function are cached, so that future calls with the same arguments
+ /// do not need to make a call to the Vulkan API again.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `image_format_info.format` is `None`.
#[inline]
- pub fn memory_type_by_id(&self, id: u32) -> Option<MemoryType<'a>> {
- if id < self.info.memory_properties.memory_type_count {
- Some(MemoryType {
- physical_device: *self,
- id,
- info: &self.info.memory_properties.memory_types[id as usize],
- })
+ pub fn image_format_properties(
+ &self,
+ image_format_info: ImageFormatInfo,
+ ) -> Result<Option<ImageFormatProperties>, PhysicalDeviceError> {
+ self.validate_image_format_properties(&image_format_info)?;
+
+ unsafe { Ok(self.image_format_properties_unchecked(image_format_info)?) }
+ }
+
+ // FIXME: Shouldn't this be private?
+ pub fn validate_image_format_properties(
+ &self,
+ image_format_info: &ImageFormatInfo,
+ ) -> Result<(), PhysicalDeviceError> {
+ let &ImageFormatInfo {
+ flags: _,
+ format,
+ image_type,
+ tiling,
+ usage,
+ mut stencil_usage,
+ external_memory_handle_type,
+ image_view_type,
+ _ne: _,
+ } = image_format_info;
+
+ let format = format.unwrap();
+ let aspects = format.aspects();
+
+ let has_separate_stencil_usage = if stencil_usage.is_empty()
+ || !aspects.contains(ImageAspects::DEPTH | ImageAspects::STENCIL)
+ {
+ stencil_usage = usage;
+ false
} else {
- None
+ stencil_usage == usage
+ };
+
+ // VUID-VkPhysicalDeviceImageFormatInfo2-format-parameter
+ format.validate_physical_device(self)?;
+
+ // VUID-VkPhysicalDeviceImageFormatInfo2-imageType-parameter
+ image_type.validate_physical_device(self)?;
+
+ // VUID-VkPhysicalDeviceImageFormatInfo2-tiling-parameter
+ tiling.validate_physical_device(self)?;
+
+ // VUID-VkPhysicalDeviceImageFormatInfo2-usage-parameter
+ usage.validate_physical_device(self)?;
+
+ // VUID-VkPhysicalDeviceImageFormatInfo2-usage-requiredbitmask
+ assert!(!usage.is_empty());
+
+ if has_separate_stencil_usage {
+ if !(self.api_version() >= Version::V1_2
+ || self.supported_extensions().ext_separate_stencil_usage)
+ {
+ return Err(PhysicalDeviceError::RequirementNotMet {
+ required_for: "`image_format_info.stencil_usage` is `Some` and \
+ `image_format_info.format` has both a depth and a stencil aspect",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_2),
+ device_extensions: &["ext_separate_stencil_usage"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkImageStencilUsageCreateInfo-stencilUsage-parameter
+ stencil_usage.validate_physical_device(self)?;
+
+ // VUID-VkImageStencilUsageCreateInfo-usage-requiredbitmask
+ assert!(!stencil_usage.is_empty());
}
+
+ if let Some(handle_type) = external_memory_handle_type {
+ if !(self.api_version() >= Version::V1_1
+ || self
+ .instance()
+ .enabled_extensions()
+ .khr_external_memory_capabilities)
+ {
+ return Err(PhysicalDeviceError::RequirementNotMet {
+ required_for: "`image_format_info.external_memory_handle_type` is `Some`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_1),
+ instance_extensions: &["khr_external_memory_capabilities"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkPhysicalDeviceExternalImageFormatInfo-handleType-parameter
+ handle_type.validate_physical_device(self)?;
+ }
+
+ if let Some(image_view_type) = image_view_type {
+ if !self.supported_extensions().ext_filter_cubic {
+ return Err(PhysicalDeviceError::RequirementNotMet {
+ required_for: "`image_format_info.image_view_type` is `Some`",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["ext_filter_cubic"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkPhysicalDeviceImageViewImageFormatInfoEXT-imageViewType-parameter
+ image_view_type.validate_physical_device(self)?;
+ }
+
+ // TODO: VUID-VkPhysicalDeviceImageFormatInfo2-tiling-02313
+ // Currently there is nothing in Vulkano for for adding a VkImageFormatListCreateInfo.
+
+ Ok(())
}
- /// Builds an iterator that enumerates all the memory heaps on this physical device.
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
#[inline]
- pub fn memory_heaps(&self) -> impl ExactSizeIterator<Item = MemoryHeap<'a>> {
- let physical_device = *self;
- self.info.memory_properties.memory_heaps
- [0..self.info.memory_properties.memory_heap_count as usize]
- .iter()
- .enumerate()
- .map(move |(id, info)| MemoryHeap {
- physical_device,
- id: id as u32,
- info,
+ pub unsafe fn image_format_properties_unchecked(
+ &self,
+ mut image_format_info: ImageFormatInfo,
+ ) -> Result<Option<ImageFormatProperties>, VulkanError> {
+ {
+ let ImageFormatInfo {
+ format,
+ usage,
+ stencil_usage,
+ ..
+ } = &mut image_format_info;
+
+ let aspects = format.unwrap().aspects();
+
+ if stencil_usage.is_empty()
+ || !aspects.contains(ImageAspects::DEPTH | ImageAspects::STENCIL)
+ {
+ *stencil_usage = *usage;
+ }
+ }
+
+ self.image_format_properties
+ .get_or_try_insert(image_format_info, |image_format_info| {
+ /* Input */
+ let &ImageFormatInfo {
+ flags,
+ format,
+ image_type,
+ tiling,
+ usage,
+ stencil_usage,
+ external_memory_handle_type,
+ image_view_type,
+ _ne: _,
+ } = image_format_info;
+
+ let has_separate_stencil_usage = stencil_usage == usage;
+
+ let mut info2_vk = ash::vk::PhysicalDeviceImageFormatInfo2 {
+ format: format.unwrap().into(),
+ ty: image_type.into(),
+ tiling: tiling.into(),
+ usage: usage.into(),
+ flags: flags.into(),
+ ..Default::default()
+ };
+ let mut external_info_vk = None;
+ let mut image_view_info_vk = None;
+ let mut stencil_usage_info_vk = None;
+
+ if let Some(handle_type) = external_memory_handle_type {
+ let next =
+ external_info_vk.insert(ash::vk::PhysicalDeviceExternalImageFormatInfo {
+ handle_type: handle_type.into(),
+ ..Default::default()
+ });
+
+ next.p_next = info2_vk.p_next;
+ info2_vk.p_next = next as *const _ as *const _;
+ }
+
+ if let Some(image_view_type) = image_view_type {
+ let next = image_view_info_vk.insert(
+ ash::vk::PhysicalDeviceImageViewImageFormatInfoEXT {
+ image_view_type: image_view_type.into(),
+ ..Default::default()
+ },
+ );
+
+ next.p_next = info2_vk.p_next as *mut _;
+ info2_vk.p_next = next as *const _ as *const _;
+ }
+
+ if has_separate_stencil_usage {
+ let next = stencil_usage_info_vk.insert(ash::vk::ImageStencilUsageCreateInfo {
+ stencil_usage: stencil_usage.into(),
+ ..Default::default()
+ });
+
+ next.p_next = info2_vk.p_next as *mut _;
+ info2_vk.p_next = next as *const _ as *const _;
+ }
+
+ /* Output */
+
+ let mut properties2_vk = ash::vk::ImageFormatProperties2::default();
+ let mut external_properties_vk = None;
+ let mut filter_cubic_image_view_properties_vk = None;
+
+ if external_info_vk.is_some() {
+ let next = external_properties_vk
+ .insert(ash::vk::ExternalImageFormatProperties::default());
+
+ next.p_next = properties2_vk.p_next;
+ properties2_vk.p_next = next as *mut _ as *mut _;
+ }
+
+ if image_view_info_vk.is_some() {
+ let next = filter_cubic_image_view_properties_vk
+ .insert(ash::vk::FilterCubicImageViewImageFormatPropertiesEXT::default());
+
+ next.p_next = properties2_vk.p_next;
+ properties2_vk.p_next = next as *mut _ as *mut _;
+ }
+
+ let result = {
+ let fns = self.instance.fns();
+
+ if self.api_version() >= Version::V1_1 {
+ (fns.v1_1.get_physical_device_image_format_properties2)(
+ self.handle,
+ &info2_vk,
+ &mut properties2_vk,
+ )
+ } else if self
+ .instance
+ .enabled_extensions()
+ .khr_get_physical_device_properties2
+ {
+ (fns.khr_get_physical_device_properties2
+ .get_physical_device_image_format_properties2_khr)(
+ self.handle,
+ &info2_vk,
+ &mut properties2_vk,
+ )
+ } else {
+ // Can't query this, return unsupported
+ if !info2_vk.p_next.is_null() {
+ return Ok(None);
+ }
+ if let Some(ExternalMemoryHandleType::DmaBuf) = external_memory_handle_type
+ {
+ // VUID-vkGetPhysicalDeviceImageFormatProperties-tiling-02248
+ // VUID-VkPhysicalDeviceImageFormatInfo2-tiling-02249
+ return Ok(None);
+ }
+
+ (fns.v1_0.get_physical_device_image_format_properties)(
+ self.handle,
+ info2_vk.format,
+ info2_vk.ty,
+ info2_vk.tiling,
+ info2_vk.usage,
+ info2_vk.flags,
+ &mut properties2_vk.image_format_properties,
+ )
+ }
+ .result()
+ .map_err(VulkanError::from)
+ };
+
+ Ok(match result {
+ Ok(_) => Some(ImageFormatProperties {
+ external_memory_properties: external_properties_vk
+ .map(|properties| properties.external_memory_properties.into())
+ .unwrap_or_default(),
+ filter_cubic: filter_cubic_image_view_properties_vk
+ .map_or(false, |properties| {
+ properties.filter_cubic != ash::vk::FALSE
+ }),
+ filter_cubic_minmax: filter_cubic_image_view_properties_vk
+ .map_or(false, |properties| {
+ properties.filter_cubic_minmax != ash::vk::FALSE
+ }),
+ ..properties2_vk.image_format_properties.into()
+ }),
+ Err(VulkanError::FormatNotSupported) => None,
+ Err(err) => return Err(err),
+ })
})
}
- /// Returns the memory heap with the given index, or `None` if out of range.
- #[inline]
- pub fn memory_heap_by_id(&self, id: u32) -> Option<MemoryHeap<'a>> {
- if id < self.info.memory_properties.memory_heap_count {
- Some(MemoryHeap {
- physical_device: *self,
- id,
- info: &self.info.memory_properties.memory_heaps[id as usize],
- })
- } else {
- None
+ /// Queries whether the physical device supports presenting to QNX Screen surfaces from queues
+ /// of the given queue family.
+ ///
+ /// # Safety
+ ///
+ /// - `window` must be a valid QNX Screen `_screen_window` handle.
+ pub unsafe fn qnx_screen_presentation_support<W>(
+ &self,
+ queue_family_index: u32,
+ window: *const W,
+ ) -> Result<bool, PhysicalDeviceError> {
+ self.validate_qnx_screen_presentation_support(queue_family_index, window)?;
+
+ Ok(self.qnx_screen_presentation_support_unchecked(queue_family_index, window))
+ }
+
+ fn validate_qnx_screen_presentation_support<W>(
+ &self,
+ queue_family_index: u32,
+ _window: *const W,
+ ) -> Result<(), PhysicalDeviceError> {
+ if !self.instance.enabled_extensions().qnx_screen_surface {
+ return Err(PhysicalDeviceError::RequirementNotMet {
+ required_for: "`PhysicalDevice::qnx_screen_presentation_support`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["qnx_screen_surface"],
+ ..Default::default()
+ },
+ });
}
+
+ // VUID-vkGetPhysicalDeviceScreenPresentationSupportQNX-queueFamilyIndex-04743
+ if queue_family_index >= self.queue_family_properties.len() as u32 {
+ return Err(PhysicalDeviceError::QueueFamilyIndexOutOfRange {
+ queue_family_index,
+ queue_family_count: self.queue_family_properties.len() as u32,
+ });
+ }
+
+ // VUID-vkGetPhysicalDeviceScreenPresentationSupportQNX-window-parameter
+ // Can't validate, therefore unsafe
+
+ Ok(())
}
- /// Builds an iterator that enumerates all the queue families on this physical device.
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn qnx_screen_presentation_support_unchecked<W>(
+ &self,
+ queue_family_index: u32,
+ window: *const W,
+ ) -> bool {
+ let fns = self.instance.fns();
+ (fns.qnx_screen_surface
+ .get_physical_device_screen_presentation_support_qnx)(
+ self.handle,
+ queue_family_index,
+ window as *mut _,
+ ) != 0
+ }
+
+ /// Returns the properties of sparse images with a given image configuration.
+ ///
+ /// The results of this function are cached, so that future calls with the same arguments
+ /// do not need to make a call to the Vulkan API again.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `format_info.format` is `None`.
#[inline]
- pub fn queue_families(&self) -> impl ExactSizeIterator<Item = QueueFamily<'a>> {
- let physical_device = *self;
- self.info
- .queue_families
- .iter()
- .enumerate()
- .map(move |(id, properties)| QueueFamily {
- physical_device,
- id: id as u32,
- properties,
- })
+ pub fn sparse_image_format_properties(
+ &self,
+ format_info: SparseImageFormatInfo,
+ ) -> Result<Vec<SparseImageFormatProperties>, PhysicalDeviceError> {
+ self.validate_sparse_image_format_properties(&format_info)?;
+
+ unsafe { Ok(self.sparse_image_format_properties_unchecked(format_info)) }
}
- /// Returns the queue family with the given index, or `None` if out of range.
+ fn validate_sparse_image_format_properties(
+ &self,
+ format_info: &SparseImageFormatInfo,
+ ) -> Result<(), PhysicalDeviceError> {
+ let &SparseImageFormatInfo {
+ format,
+ image_type,
+ samples,
+ usage,
+ tiling,
+ _ne: _,
+ } = format_info;
+
+ let format = format.unwrap();
+
+ // VUID-VkPhysicalDeviceSparseImageFormatInfo2-format-parameter
+ format.validate_physical_device(self)?;
+
+ // VUID-VkPhysicalDeviceSparseImageFormatInfo2-type-parameter
+ image_type.validate_physical_device(self)?;
+
+ // VUID-VkPhysicalDeviceSparseImageFormatInfo2-samples-parameter
+ samples.validate_physical_device(self)?;
+
+ // VUID-VkPhysicalDeviceSparseImageFormatInfo2-usage-parameter
+ usage.validate_physical_device(self)?;
+
+ // VUID-VkPhysicalDeviceSparseImageFormatInfo2-usage-requiredbitmask
+ assert!(!usage.is_empty());
+
+ // VUID-VkPhysicalDeviceSparseImageFormatInfo2-tiling-parameter
+ tiling.validate_physical_device(self)?;
+
+ // VUID-VkPhysicalDeviceSparseImageFormatInfo2-samples-01095
+ // TODO:
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
#[inline]
- pub fn queue_family_by_id(&self, id: u32) -> Option<QueueFamily<'a>> {
- if (id as usize) < self.info.queue_families.len() {
- Some(QueueFamily {
- physical_device: *self,
- id,
- properties: &self.info.queue_families[id as usize],
+ pub unsafe fn sparse_image_format_properties_unchecked(
+ &self,
+ format_info: SparseImageFormatInfo,
+ ) -> Vec<SparseImageFormatProperties> {
+ self.sparse_image_format_properties
+ .get_or_insert(format_info, |format_info| {
+ let &SparseImageFormatInfo {
+ format,
+ image_type,
+ samples,
+ usage,
+ tiling,
+ _ne: _,
+ } = format_info;
+
+ let format_info2 = ash::vk::PhysicalDeviceSparseImageFormatInfo2 {
+ format: format.unwrap().into(),
+ ty: image_type.into(),
+ samples: samples.into(),
+ usage: usage.into(),
+ tiling: tiling.into(),
+ ..Default::default()
+ };
+
+ let fns = self.instance.fns();
+
+ if self.api_version() >= Version::V1_1
+ || self
+ .instance
+ .enabled_extensions()
+ .khr_get_physical_device_properties2
+ {
+ let mut count = 0;
+
+ if self.api_version() >= Version::V1_1 {
+ (fns.v1_1.get_physical_device_sparse_image_format_properties2)(
+ self.handle,
+ &format_info2,
+ &mut count,
+ ptr::null_mut(),
+ );
+ } else {
+ (fns.khr_get_physical_device_properties2
+ .get_physical_device_sparse_image_format_properties2_khr)(
+ self.handle,
+ &format_info2,
+ &mut count,
+ ptr::null_mut(),
+ );
+ }
+
+ let mut sparse_image_format_properties2 =
+ vec![ash::vk::SparseImageFormatProperties2::default(); count as usize];
+
+ if self.api_version() >= Version::V1_1 {
+ (fns.v1_1.get_physical_device_sparse_image_format_properties2)(
+ self.handle,
+ &format_info2,
+ &mut count,
+ sparse_image_format_properties2.as_mut_ptr(),
+ );
+ } else {
+ (fns.khr_get_physical_device_properties2
+ .get_physical_device_sparse_image_format_properties2_khr)(
+ self.handle,
+ &format_info2,
+ &mut count,
+ sparse_image_format_properties2.as_mut_ptr(),
+ );
+ }
+
+ sparse_image_format_properties2.set_len(count as usize);
+
+ sparse_image_format_properties2
+ .into_iter()
+ .map(
+ |sparse_image_format_properties2| SparseImageFormatProperties {
+ aspects: sparse_image_format_properties2
+ .properties
+ .aspect_mask
+ .into(),
+ image_granularity: [
+ sparse_image_format_properties2
+ .properties
+ .image_granularity
+ .width,
+ sparse_image_format_properties2
+ .properties
+ .image_granularity
+ .height,
+ sparse_image_format_properties2
+ .properties
+ .image_granularity
+ .depth,
+ ],
+ flags: sparse_image_format_properties2.properties.flags.into(),
+ },
+ )
+ .collect()
+ } else {
+ let mut count = 0;
+
+ (fns.v1_0.get_physical_device_sparse_image_format_properties)(
+ self.handle,
+ format_info2.format,
+ format_info2.ty,
+ format_info2.samples,
+ format_info2.usage,
+ format_info2.tiling,
+ &mut count,
+ ptr::null_mut(),
+ );
+
+ let mut sparse_image_format_properties =
+ vec![ash::vk::SparseImageFormatProperties::default(); count as usize];
+
+ (fns.v1_0.get_physical_device_sparse_image_format_properties)(
+ self.handle,
+ format_info2.format,
+ format_info2.ty,
+ format_info2.samples,
+ format_info2.usage,
+ format_info2.tiling,
+ &mut count,
+ sparse_image_format_properties.as_mut_ptr(),
+ );
+
+ sparse_image_format_properties.set_len(count as usize);
+
+ sparse_image_format_properties
+ .into_iter()
+ .map(
+ |sparse_image_format_properties| SparseImageFormatProperties {
+ aspects: sparse_image_format_properties.aspect_mask.into(),
+ image_granularity: [
+ sparse_image_format_properties.image_granularity.width,
+ sparse_image_format_properties.image_granularity.height,
+ sparse_image_format_properties.image_granularity.depth,
+ ],
+ flags: sparse_image_format_properties.flags.into(),
+ },
+ )
+ .collect()
+ }
})
- } else {
- None
- }
}
-}
-unsafe impl<'a> VulkanObject for PhysicalDevice<'a> {
- type Object = ash::vk::PhysicalDevice;
+ /// Returns the capabilities that are supported by the physical device for the given surface.
+ ///
+ /// The results of this function are cached, so that future calls with the same arguments
+ /// do not need to make a call to the Vulkan API again.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the physical device and the surface don't belong to the same instance.
+ pub fn surface_capabilities(
+ &self,
+ surface: &Surface,
+ surface_info: SurfaceInfo,
+ ) -> Result<SurfaceCapabilities, PhysicalDeviceError> {
+ self.validate_surface_capabilities(surface, &surface_info)?;
+
+ unsafe { Ok(self.surface_capabilities_unchecked(surface, surface_info)?) }
+ }
- #[inline]
- fn internal_object(&self) -> ash::vk::PhysicalDevice {
- self.info.handle
+ fn validate_surface_capabilities(
+ &self,
+ surface: &Surface,
+ surface_info: &SurfaceInfo,
+ ) -> Result<(), PhysicalDeviceError> {
+ if !(self
+ .instance
+ .enabled_extensions()
+ .khr_get_surface_capabilities2
+ || self.instance.enabled_extensions().khr_surface)
+ {
+ return Err(PhysicalDeviceError::RequirementNotMet {
+ required_for: "`PhysicalDevice::surface_capabilities`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["khr_get_surface_capabilities2", "khr_surface"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkGetPhysicalDeviceSurfaceCapabilities2KHR-commonparent
+ assert_eq!(self.instance(), surface.instance());
+
+ // VUID-vkGetPhysicalDeviceSurfaceCapabilities2KHR-pSurfaceInfo-06210
+ if !(0..self.queue_family_properties.len() as u32).any(|index| unsafe {
+ self.surface_support_unchecked(index, surface)
+ .unwrap_or_default()
+ }) {
+ return Err(PhysicalDeviceError::SurfaceNotSupported);
+ }
+
+ let &SurfaceInfo {
+ full_screen_exclusive,
+ win32_monitor,
+ _ne: _,
+ } = surface_info;
+
+ if !self.supported_extensions().ext_full_screen_exclusive
+ && full_screen_exclusive != FullScreenExclusive::Default
+ {
+ return Err(PhysicalDeviceError::NotSupported);
+ }
+
+ // VUID-VkPhysicalDeviceSurfaceInfo2KHR-pNext-02672
+ if (surface.api() == SurfaceApi::Win32
+ && full_screen_exclusive == FullScreenExclusive::ApplicationControlled)
+ != win32_monitor.is_some()
+ {
+ return Err(PhysicalDeviceError::NotSupported);
+ }
+
+ Ok(())
}
-}
-/// Type of a physical device.
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
-#[repr(i32)]
-pub enum PhysicalDeviceType {
- /// The device is an integrated GPU.
- IntegratedGpu = ash::vk::PhysicalDeviceType::INTEGRATED_GPU.as_raw(),
- /// The device is a discrete GPU.
- DiscreteGpu = ash::vk::PhysicalDeviceType::DISCRETE_GPU.as_raw(),
- /// The device is a virtual GPU.
- VirtualGpu = ash::vk::PhysicalDeviceType::VIRTUAL_GPU.as_raw(),
- /// The device is a CPU.
- Cpu = ash::vk::PhysicalDeviceType::CPU.as_raw(),
- /// The device is something else.
- Other = ash::vk::PhysicalDeviceType::OTHER.as_raw(),
-}
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn surface_capabilities_unchecked(
+ &self,
+ surface: &Surface,
+ surface_info: SurfaceInfo,
+ ) -> Result<SurfaceCapabilities, VulkanError> {
+ /* Input */
+
+ let SurfaceInfo {
+ full_screen_exclusive,
+ win32_monitor,
+ _ne: _,
+ } = surface_info;
+
+ let mut info_vk = ash::vk::PhysicalDeviceSurfaceInfo2KHR {
+ surface: surface.handle(),
+ ..Default::default()
+ };
+ let mut full_screen_exclusive_info_vk = None;
+ let mut full_screen_exclusive_win32_info_vk = None;
+
+ if self.supported_extensions().ext_full_screen_exclusive && win32_monitor.is_some() {
+ let next =
+ full_screen_exclusive_info_vk.insert(ash::vk::SurfaceFullScreenExclusiveInfoEXT {
+ full_screen_exclusive: full_screen_exclusive.into(),
+ ..Default::default()
+ });
+
+ next.p_next = info_vk.p_next as *mut _;
+ info_vk.p_next = next as *const _ as *const _;
+ }
-/// VkPhysicalDeviceType::Other is represented as 0
-impl Default for PhysicalDeviceType {
- fn default() -> Self {
- PhysicalDeviceType::Other
- }
-}
+ if let Some(win32_monitor) = win32_monitor {
+ let next = full_screen_exclusive_win32_info_vk.insert(
+ ash::vk::SurfaceFullScreenExclusiveWin32InfoEXT {
+ hmonitor: win32_monitor.0,
+ ..Default::default()
+ },
+ );
-impl TryFrom<ash::vk::PhysicalDeviceType> for PhysicalDeviceType {
- type Error = ();
+ next.p_next = info_vk.p_next as *mut _;
+ info_vk.p_next = next as *const _ as *const _;
+ }
- #[inline]
- fn try_from(val: ash::vk::PhysicalDeviceType) -> Result<Self, Self::Error> {
- match val {
- ash::vk::PhysicalDeviceType::INTEGRATED_GPU => Ok(Self::IntegratedGpu),
- ash::vk::PhysicalDeviceType::DISCRETE_GPU => Ok(Self::DiscreteGpu),
- ash::vk::PhysicalDeviceType::VIRTUAL_GPU => Ok(Self::VirtualGpu),
- ash::vk::PhysicalDeviceType::CPU => Ok(Self::Cpu),
- ash::vk::PhysicalDeviceType::OTHER => Ok(Self::Other),
- _ => Err(()),
+ /* Output */
+
+ let mut capabilities_vk = ash::vk::SurfaceCapabilities2KHR::default();
+ let mut capabilities_full_screen_exclusive_vk = None;
+ let mut protected_capabilities_vk = None;
+
+ if full_screen_exclusive_info_vk.is_some() {
+ let next = capabilities_full_screen_exclusive_vk
+ .insert(ash::vk::SurfaceCapabilitiesFullScreenExclusiveEXT::default());
+
+ next.p_next = capabilities_vk.p_next as *mut _;
+ capabilities_vk.p_next = next as *mut _ as *mut _;
}
+
+ if self
+ .instance
+ .enabled_extensions()
+ .khr_surface_protected_capabilities
+ {
+ let next = protected_capabilities_vk
+ .insert(ash::vk::SurfaceProtectedCapabilitiesKHR::default());
+
+ next.p_next = capabilities_vk.p_next as *mut _;
+ capabilities_vk.p_next = next as *mut _ as *mut _;
+ }
+
+ let fns = self.instance.fns();
+
+ if self
+ .instance
+ .enabled_extensions()
+ .khr_get_surface_capabilities2
+ {
+ (fns.khr_get_surface_capabilities2
+ .get_physical_device_surface_capabilities2_khr)(
+ self.handle(),
+ &info_vk,
+ &mut capabilities_vk,
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+ } else {
+ (fns.khr_surface.get_physical_device_surface_capabilities_khr)(
+ self.handle(),
+ info_vk.surface,
+ &mut capabilities_vk.surface_capabilities,
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+ };
+
+ Ok(SurfaceCapabilities {
+ min_image_count: capabilities_vk.surface_capabilities.min_image_count,
+ max_image_count: if capabilities_vk.surface_capabilities.max_image_count == 0 {
+ None
+ } else {
+ Some(capabilities_vk.surface_capabilities.max_image_count)
+ },
+ current_extent: if capabilities_vk.surface_capabilities.current_extent.width
+ == 0xffffffff
+ && capabilities_vk.surface_capabilities.current_extent.height == 0xffffffff
+ {
+ None
+ } else {
+ Some([
+ capabilities_vk.surface_capabilities.current_extent.width,
+ capabilities_vk.surface_capabilities.current_extent.height,
+ ])
+ },
+ min_image_extent: [
+ capabilities_vk.surface_capabilities.min_image_extent.width,
+ capabilities_vk.surface_capabilities.min_image_extent.height,
+ ],
+ max_image_extent: [
+ capabilities_vk.surface_capabilities.max_image_extent.width,
+ capabilities_vk.surface_capabilities.max_image_extent.height,
+ ],
+ max_image_array_layers: capabilities_vk.surface_capabilities.max_image_array_layers,
+ supported_transforms: capabilities_vk
+ .surface_capabilities
+ .supported_transforms
+ .into(),
+
+ current_transform: SurfaceTransforms::from(
+ capabilities_vk.surface_capabilities.current_transform,
+ )
+ .into_iter()
+ .next()
+ .unwrap(), // TODO:
+ supported_composite_alpha: capabilities_vk
+ .surface_capabilities
+ .supported_composite_alpha
+ .into(),
+ supported_usage_flags: {
+ let usage =
+ ImageUsage::from(capabilities_vk.surface_capabilities.supported_usage_flags);
+ debug_assert!(usage.intersects(ImageUsage::COLOR_ATTACHMENT)); // specs say that this must be true
+ usage
+ },
+
+ supports_protected: protected_capabilities_vk
+ .map_or(false, |c| c.supports_protected != 0),
+
+ full_screen_exclusive_supported: capabilities_full_screen_exclusive_vk
+ .map_or(false, |c| c.full_screen_exclusive_supported != 0),
+ })
}
-}
-/// Represents a memory type in a physical device.
-#[derive(Debug, Copy, Clone)]
-pub struct MemoryType<'a> {
- physical_device: PhysicalDevice<'a>,
- id: u32,
- info: &'a ash::vk::MemoryType,
-}
+ /// Returns the combinations of format and color space that are supported by the physical device
+ /// for the given surface.
+ ///
+ /// The results of this function are cached, so that future calls with the same arguments
+ /// do not need to make a call to the Vulkan API again.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the physical device and the surface don't belong to the same instance.
+ pub fn surface_formats(
+ &self,
+ surface: &Surface,
+ surface_info: SurfaceInfo,
+ ) -> Result<Vec<(Format, ColorSpace)>, PhysicalDeviceError> {
+ self.validate_surface_formats(surface, &surface_info)?;
+
+ unsafe { Ok(self.surface_formats_unchecked(surface, surface_info)?) }
+ }
-impl<'a> MemoryType<'a> {
- /// Returns the physical device associated to this memory type.
- #[inline]
- pub fn physical_device(&self) -> PhysicalDevice<'a> {
- self.physical_device
+ fn validate_surface_formats(
+ &self,
+ surface: &Surface,
+ surface_info: &SurfaceInfo,
+ ) -> Result<(), PhysicalDeviceError> {
+ if !(self
+ .instance
+ .enabled_extensions()
+ .khr_get_surface_capabilities2
+ || self.instance.enabled_extensions().khr_surface)
+ {
+ return Err(PhysicalDeviceError::RequirementNotMet {
+ required_for: "`PhysicalDevice::surface_formats`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["khr_get_surface_capabilities2", "khr_surface"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkGetPhysicalDeviceSurfaceFormats2KHR-commonparent
+ assert_eq!(self.instance(), surface.instance());
+
+ // VUID-vkGetPhysicalDeviceSurfaceFormats2KHR-pSurfaceInfo-06522
+ if !(0..self.queue_family_properties.len() as u32).any(|index| unsafe {
+ self.surface_support_unchecked(index, surface)
+ .unwrap_or_default()
+ }) {
+ return Err(PhysicalDeviceError::SurfaceNotSupported);
+ }
+
+ let &SurfaceInfo {
+ full_screen_exclusive,
+ win32_monitor,
+ _ne: _,
+ } = surface_info;
+
+ if self
+ .instance
+ .enabled_extensions()
+ .khr_get_surface_capabilities2
+ {
+ if !self.supported_extensions().ext_full_screen_exclusive
+ && full_screen_exclusive != FullScreenExclusive::Default
+ {
+ return Err(PhysicalDeviceError::NotSupported);
+ }
+
+ // VUID-VkPhysicalDeviceSurfaceInfo2KHR-pNext-02672
+ if (surface.api() == SurfaceApi::Win32
+ && full_screen_exclusive == FullScreenExclusive::ApplicationControlled)
+ != win32_monitor.is_some()
+ {
+ return Err(PhysicalDeviceError::NotSupported);
+ }
+ } else {
+ if full_screen_exclusive != FullScreenExclusive::Default {
+ return Err(PhysicalDeviceError::NotSupported);
+ }
+
+ if win32_monitor.is_some() {
+ return Err(PhysicalDeviceError::NotSupported);
+ }
+ }
+
+ Ok(())
}
- /// Returns the identifier of this memory type within the physical device.
- #[inline]
- pub fn id(&self) -> u32 {
- self.id
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn surface_formats_unchecked(
+ &self,
+ surface: &Surface,
+ surface_info: SurfaceInfo,
+ ) -> Result<Vec<(Format, ColorSpace)>, VulkanError> {
+ surface.surface_formats.get_or_try_insert(
+ (self.handle, surface_info),
+ |(_, surface_info)| {
+ let &SurfaceInfo {
+ full_screen_exclusive,
+ win32_monitor,
+ _ne: _,
+ } = surface_info;
+
+ let mut surface_full_screen_exclusive_info = (full_screen_exclusive
+ != FullScreenExclusive::Default)
+ .then(|| ash::vk::SurfaceFullScreenExclusiveInfoEXT {
+ full_screen_exclusive: full_screen_exclusive.into(),
+ ..Default::default()
+ });
+
+ let mut surface_full_screen_exclusive_win32_info =
+ win32_monitor.map(|win32_monitor| {
+ ash::vk::SurfaceFullScreenExclusiveWin32InfoEXT {
+ hmonitor: win32_monitor.0,
+ ..Default::default()
+ }
+ });
+
+ let mut surface_info2 = ash::vk::PhysicalDeviceSurfaceInfo2KHR {
+ surface: surface.handle(),
+ ..Default::default()
+ };
+
+ if let Some(surface_full_screen_exclusive_info) =
+ surface_full_screen_exclusive_info.as_mut()
+ {
+ surface_full_screen_exclusive_info.p_next = surface_info2.p_next as *mut _;
+ surface_info2.p_next =
+ surface_full_screen_exclusive_info as *const _ as *const _;
+ }
+
+ if let Some(surface_full_screen_exclusive_win32_info) =
+ surface_full_screen_exclusive_win32_info.as_mut()
+ {
+ surface_full_screen_exclusive_win32_info.p_next =
+ surface_info2.p_next as *mut _;
+ surface_info2.p_next =
+ surface_full_screen_exclusive_win32_info as *const _ as *const _;
+ }
+
+ let fns = self.instance.fns();
+
+ if self
+ .instance
+ .enabled_extensions()
+ .khr_get_surface_capabilities2
+ {
+ let surface_format2s = loop {
+ let mut count = 0;
+ (fns.khr_get_surface_capabilities2
+ .get_physical_device_surface_formats2_khr)(
+ self.handle(),
+ &surface_info2,
+ &mut count,
+ ptr::null_mut(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+
+ let mut surface_format2s =
+ vec![ash::vk::SurfaceFormat2KHR::default(); count as usize];
+ let result = (fns
+ .khr_get_surface_capabilities2
+ .get_physical_device_surface_formats2_khr)(
+ self.handle(),
+ &surface_info2,
+ &mut count,
+ surface_format2s.as_mut_ptr(),
+ );
+
+ match result {
+ ash::vk::Result::SUCCESS => {
+ surface_format2s.set_len(count as usize);
+ break surface_format2s;
+ }
+ ash::vk::Result::INCOMPLETE => (),
+ err => return Err(VulkanError::from(err)),
+ }
+ };
+
+ Ok(surface_format2s
+ .into_iter()
+ .filter_map(|surface_format2| {
+ (surface_format2.surface_format.format.try_into().ok())
+ .zip(surface_format2.surface_format.color_space.try_into().ok())
+ })
+ .collect())
+ } else {
+ let surface_formats = loop {
+ let mut count = 0;
+ (fns.khr_surface.get_physical_device_surface_formats_khr)(
+ self.handle(),
+ surface.handle(),
+ &mut count,
+ ptr::null_mut(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+
+ let mut surface_formats = Vec::with_capacity(count as usize);
+ let result = (fns.khr_surface.get_physical_device_surface_formats_khr)(
+ self.handle(),
+ surface.handle(),
+ &mut count,
+ surface_formats.as_mut_ptr(),
+ );
+
+ match result {
+ ash::vk::Result::SUCCESS => {
+ surface_formats.set_len(count as usize);
+ break surface_formats;
+ }
+ ash::vk::Result::INCOMPLETE => (),
+ err => return Err(VulkanError::from(err)),
+ }
+ };
+
+ Ok(surface_formats
+ .into_iter()
+ .filter_map(|surface_format| {
+ (surface_format.format.try_into().ok())
+ .zip(surface_format.color_space.try_into().ok())
+ })
+ .collect())
+ }
+ },
+ )
}
- /// Returns the heap that corresponds to this memory type.
- #[inline]
- pub fn heap(&self) -> MemoryHeap<'a> {
- self.physical_device
- .memory_heap_by_id(self.info.heap_index)
- .unwrap()
+ /// Returns the present modes that are supported by the physical device for the given surface.
+ ///
+ /// The results of this function are cached, so that future calls with the same arguments
+ /// do not need to make a call to the Vulkan API again.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the physical device and the surface don't belong to the same instance.
+ pub fn surface_present_modes(
+ &self,
+ surface: &Surface,
+ ) -> Result<impl Iterator<Item = PresentMode>, PhysicalDeviceError> {
+ self.validate_surface_present_modes(surface)?;
+
+ unsafe { Ok(self.surface_present_modes_unchecked(surface)?) }
}
- /// Returns true if the memory type is located on the device, which means that it's the most
- /// efficient for GPU accesses.
- #[inline]
- pub fn is_device_local(&self) -> bool {
- !(self.info.property_flags & ash::vk::MemoryPropertyFlags::DEVICE_LOCAL).is_empty()
+ fn validate_surface_present_modes(&self, surface: &Surface) -> Result<(), PhysicalDeviceError> {
+ if !self.instance.enabled_extensions().khr_surface {
+ return Err(PhysicalDeviceError::RequirementNotMet {
+ required_for: "`PhysicalDevice::surface_present_modes`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["khr_surface"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkGetPhysicalDeviceSurfacePresentModesKHR-commonparent
+ assert_eq!(self.instance(), surface.instance());
+
+ // VUID-vkGetPhysicalDeviceSurfacePresentModesKHR-surface-06525
+ if !(0..self.queue_family_properties.len() as u32).any(|index| unsafe {
+ self.surface_support_unchecked(index, surface)
+ .unwrap_or_default()
+ }) {
+ return Err(PhysicalDeviceError::SurfaceNotSupported);
+ }
+
+ Ok(())
}
- /// Returns true if the memory type can be accessed by the host.
- #[inline]
- pub fn is_host_visible(&self) -> bool {
- !(self.info.property_flags & ash::vk::MemoryPropertyFlags::HOST_VISIBLE).is_empty()
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn surface_present_modes_unchecked(
+ &self,
+ surface: &Surface,
+ ) -> Result<impl Iterator<Item = PresentMode>, VulkanError> {
+ surface
+ .surface_present_modes
+ .get_or_try_insert(self.handle, |_| {
+ let fns = self.instance.fns();
+
+ let modes = loop {
+ let mut count = 0;
+ (fns.khr_surface
+ .get_physical_device_surface_present_modes_khr)(
+ self.handle(),
+ surface.handle(),
+ &mut count,
+ ptr::null_mut(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+
+ let mut modes = Vec::with_capacity(count as usize);
+ let result = (fns
+ .khr_surface
+ .get_physical_device_surface_present_modes_khr)(
+ self.handle(),
+ surface.handle(),
+ &mut count,
+ modes.as_mut_ptr(),
+ );
+
+ match result {
+ ash::vk::Result::SUCCESS => {
+ modes.set_len(count as usize);
+ break modes;
+ }
+ ash::vk::Result::INCOMPLETE => (),
+ err => return Err(VulkanError::from(err)),
+ }
+ };
+
+ Ok(modes
+ .into_iter()
+ .filter_map(|mode_vk| mode_vk.try_into().ok())
+ .collect())
+ })
+ .map(IntoIterator::into_iter)
}
- /// Returns true if modifications made by the host or the GPU on this memory type are
- /// instantaneously visible to the other party. False means that changes have to be flushed.
+ /// Returns whether queues of the given queue family can draw on the given surface.
///
- /// You don't need to worry about this, as this library handles that for you.
+ /// The results of this function are cached, so that future calls with the same arguments
+ /// do not need to make a call to the Vulkan API again.
#[inline]
- pub fn is_host_coherent(&self) -> bool {
- !(self.info.property_flags & ash::vk::MemoryPropertyFlags::HOST_COHERENT).is_empty()
+ pub fn surface_support(
+ &self,
+ queue_family_index: u32,
+ surface: &Surface,
+ ) -> Result<bool, PhysicalDeviceError> {
+ self.validate_surface_support(queue_family_index, surface)?;
+
+ unsafe { Ok(self.surface_support_unchecked(queue_family_index, surface)?) }
}
- /// Returns true if memory of this memory type is cached by the host. Host memory accesses to
- /// cached memory is faster than for uncached memory. However you are not guaranteed that it
- /// is coherent.
- #[inline]
- pub fn is_host_cached(&self) -> bool {
- !(self.info.property_flags & ash::vk::MemoryPropertyFlags::HOST_CACHED).is_empty()
+ fn validate_surface_support(
+ &self,
+ queue_family_index: u32,
+ _surface: &Surface,
+ ) -> Result<(), PhysicalDeviceError> {
+ if !self.instance.enabled_extensions().khr_surface {
+ return Err(PhysicalDeviceError::RequirementNotMet {
+ required_for: "`PhysicalDevice::surface_support`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["khr_surface"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkGetPhysicalDeviceSurfaceSupportKHR-queueFamilyIndex-01269
+ if queue_family_index >= self.queue_family_properties.len() as u32 {
+ return Err(PhysicalDeviceError::QueueFamilyIndexOutOfRange {
+ queue_family_index,
+ queue_family_count: self.queue_family_properties.len() as u32,
+ });
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn surface_support_unchecked(
+ &self,
+ queue_family_index: u32,
+ surface: &Surface,
+ ) -> Result<bool, VulkanError> {
+ surface
+ .surface_support
+ .get_or_try_insert((self.handle, queue_family_index), |_| {
+ let fns = self.instance.fns();
+
+ let mut output = MaybeUninit::uninit();
+ (fns.khr_surface.get_physical_device_surface_support_khr)(
+ self.handle,
+ queue_family_index,
+ surface.handle(),
+ output.as_mut_ptr(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+
+ Ok(output.assume_init() != 0)
+ })
}
- /// Returns true if allocations made to this memory type is lazy.
+ /// Retrieves the properties of tools that are currently active on the physical device.
///
- /// This means that no actual allocation is performed. Instead memory is automatically
- /// allocated by the Vulkan implementation.
+ /// These properties may change during runtime, so the result only reflects the current
+ /// situation and is not cached.
///
- /// Memory of this type can only be used on images created with a certain flag. Memory of this
- /// type is never host-visible.
+ /// The physical device API version must be at least 1.3, or the
+ /// [`ext_tooling_info`](crate::device::DeviceExtensions::ext_tooling_info)
+ /// extension must be supported by the physical device.
#[inline]
- pub fn is_lazily_allocated(&self) -> bool {
- !(self.info.property_flags & ash::vk::MemoryPropertyFlags::LAZILY_ALLOCATED).is_empty()
+ pub fn tool_properties(&self) -> Result<Vec<ToolProperties>, PhysicalDeviceError> {
+ self.validate_tool_properties()?;
+
+ unsafe { Ok(self.tool_properties_unchecked()?) }
}
-}
-/// Represents a memory heap in a physical device.
-#[derive(Debug, Copy, Clone)]
-pub struct MemoryHeap<'a> {
- physical_device: PhysicalDevice<'a>,
- id: u32,
- info: &'a ash::vk::MemoryHeap,
-}
+ fn validate_tool_properties(&self) -> Result<(), PhysicalDeviceError> {
+ if !(self.api_version() >= Version::V1_3 || self.supported_extensions().ext_tooling_info) {
+ return Err(PhysicalDeviceError::RequirementNotMet {
+ required_for: "`PhysicalDevice::tooling_properties`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ device_extensions: &["ext_tooling_info"],
+ ..Default::default()
+ },
+ });
+ }
-impl<'a> MemoryHeap<'a> {
- /// Returns the physical device associated to this memory heap.
- #[inline]
- pub fn physical_device(&self) -> PhysicalDevice<'a> {
- self.physical_device
+ Ok(())
}
- /// Returns the identifier of this memory heap within the physical device.
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
#[inline]
- pub fn id(&self) -> u32 {
- self.id
+ pub unsafe fn tool_properties_unchecked(&self) -> Result<Vec<ToolProperties>, VulkanError> {
+ let fns = self.instance.fns();
+
+ loop {
+ let mut count = 0;
+
+ if self.api_version() >= Version::V1_3 {
+ (fns.v1_3.get_physical_device_tool_properties)(
+ self.handle(),
+ &mut count,
+ ptr::null_mut(),
+ )
+ } else {
+ (fns.ext_tooling_info.get_physical_device_tool_properties_ext)(
+ self.handle(),
+ &mut count,
+ ptr::null_mut(),
+ )
+ }
+ .result()
+ .map_err(VulkanError::from)?;
+
+ let mut tool_properties = Vec::with_capacity(count as usize);
+ let result = if self.api_version() >= Version::V1_3 {
+ (fns.v1_3.get_physical_device_tool_properties)(
+ self.handle(),
+ &mut count,
+ tool_properties.as_mut_ptr(),
+ )
+ } else {
+ (fns.ext_tooling_info.get_physical_device_tool_properties_ext)(
+ self.handle(),
+ &mut count,
+ tool_properties.as_mut_ptr(),
+ )
+ };
+
+ match result {
+ ash::vk::Result::INCOMPLETE => (),
+ ash::vk::Result::SUCCESS => {
+ tool_properties.set_len(count as usize);
+
+ return Ok(tool_properties
+ .into_iter()
+ .map(|tool_properties| ToolProperties {
+ name: {
+ let bytes = cast_slice(tool_properties.name.as_slice());
+ let end = bytes.iter().position(|&b| b == 0).unwrap_or(bytes.len());
+ String::from_utf8_lossy(&bytes[0..end]).into()
+ },
+ version: {
+ let bytes = cast_slice(tool_properties.version.as_slice());
+ let end = bytes.iter().position(|&b| b == 0).unwrap_or(bytes.len());
+ String::from_utf8_lossy(&bytes[0..end]).into()
+ },
+ purposes: tool_properties.purposes.into(),
+ description: {
+ let bytes = cast_slice(tool_properties.description.as_slice());
+ let end = bytes.iter().position(|&b| b == 0).unwrap_or(bytes.len());
+ String::from_utf8_lossy(&bytes[0..end]).into()
+ },
+ layer: {
+ let bytes = cast_slice(tool_properties.layer.as_slice());
+ let end = bytes.iter().position(|&b| b == 0).unwrap_or(bytes.len());
+ String::from_utf8_lossy(&bytes[0..end]).into()
+ },
+ })
+ .collect());
+ }
+ err => return Err(VulkanError::from(err)),
+ }
+ }
}
- /// Returns the size in bytes on this heap.
- #[inline]
- pub fn size(&self) -> DeviceSize {
- self.info.size
+ /// Queries whether the physical device supports presenting to Wayland surfaces from queues of
+ /// the given queue family.
+ ///
+ /// # Safety
+ ///
+ /// - `display` must be a valid Wayland `wl_display` handle.
+ pub unsafe fn wayland_presentation_support<D>(
+ &self,
+ queue_family_index: u32,
+ display: *const D,
+ ) -> Result<bool, PhysicalDeviceError> {
+ self.validate_wayland_presentation_support(queue_family_index, display)?;
+
+ Ok(self.wayland_presentation_support_unchecked(queue_family_index, display))
}
- /// Returns true if the heap is local to the GPU.
- #[inline]
- pub fn is_device_local(&self) -> bool {
- !(self.info.flags & ash::vk::MemoryHeapFlags::DEVICE_LOCAL).is_empty()
+ fn validate_wayland_presentation_support<D>(
+ &self,
+ queue_family_index: u32,
+ _display: *const D,
+ ) -> Result<(), PhysicalDeviceError> {
+ if !self.instance.enabled_extensions().khr_wayland_surface {
+ return Err(PhysicalDeviceError::RequirementNotMet {
+ required_for: "`PhysicalDevice::wayland_presentation_support`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["khr_wayland_surface"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkGetPhysicalDeviceWaylandPresentationSupportKHR-queueFamilyIndex-01306
+ if queue_family_index >= self.queue_family_properties.len() as u32 {
+ return Err(PhysicalDeviceError::QueueFamilyIndexOutOfRange {
+ queue_family_index,
+ queue_family_count: self.queue_family_properties.len() as u32,
+ });
+ }
+
+ // VUID-vkGetPhysicalDeviceWaylandPresentationSupportKHR-display-parameter
+ // Can't validate, therefore unsafe
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn wayland_presentation_support_unchecked<D>(
+ &self,
+ queue_family_index: u32,
+ display: *const D,
+ ) -> bool {
+ let fns = self.instance.fns();
+ (fns.khr_wayland_surface
+ .get_physical_device_wayland_presentation_support_khr)(
+ self.handle,
+ queue_family_index,
+ display as *mut _,
+ ) != 0
}
- /// Returns true if the heap is multi-instance enabled, that is allocation from such
- /// heap will replicate to each physical-device's instance of heap.
+ /// Queries whether the physical device supports presenting to Win32 surfaces from queues of the
+ /// given queue family.
#[inline]
- pub fn is_multi_instance(&self) -> bool {
- !(self.info.flags & ash::vk::MemoryHeapFlags::MULTI_INSTANCE).is_empty()
+ pub fn win32_presentation_support(
+ &self,
+ queue_family_index: u32,
+ ) -> Result<bool, PhysicalDeviceError> {
+ self.validate_win32_presentation_support(queue_family_index)?;
+
+ unsafe { Ok(self.win32_presentation_support_unchecked(queue_family_index)) }
}
-}
-/// Represents a queue family in a physical device.
-///
-/// A queue family is group of one or multiple queues. All queues of one family have the same
-/// characteristics.
-#[derive(Debug, Copy, Clone)]
-pub struct QueueFamily<'a> {
- physical_device: PhysicalDevice<'a>,
- id: u32,
- properties: &'a ash::vk::QueueFamilyProperties,
-}
+ fn validate_win32_presentation_support(
+ &self,
+ queue_family_index: u32,
+ ) -> Result<(), PhysicalDeviceError> {
+ if !self.instance.enabled_extensions().khr_win32_surface {
+ return Err(PhysicalDeviceError::RequirementNotMet {
+ required_for: "`PhysicalDevice::win32_presentation_support`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["khr_win32_surface"],
+ ..Default::default()
+ },
+ });
+ }
-impl<'a> QueueFamily<'a> {
- /// Returns the physical device associated to this queue family.
- #[inline]
- pub fn physical_device(&self) -> PhysicalDevice<'a> {
- self.physical_device
+ // VUID-vkGetPhysicalDeviceWin32PresentationSupportKHR-queueFamilyIndex-01309
+ if queue_family_index >= self.queue_family_properties.len() as u32 {
+ return Err(PhysicalDeviceError::QueueFamilyIndexOutOfRange {
+ queue_family_index,
+ queue_family_count: self.queue_family_properties.len() as u32,
+ });
+ }
+
+ Ok(())
}
- /// Returns the identifier of this queue family within the physical device.
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
#[inline]
- pub fn id(&self) -> u32 {
- self.id
+ pub unsafe fn win32_presentation_support_unchecked(&self, queue_family_index: u32) -> bool {
+ let fns = self.instance.fns();
+ (fns.khr_win32_surface
+ .get_physical_device_win32_presentation_support_khr)(
+ self.handle, queue_family_index
+ ) != 0
}
- /// Returns the number of queues that belong to this family.
+ /// Queries whether the physical device supports presenting to XCB surfaces from queues of the
+ /// given queue family.
///
- /// Guaranteed to be at least 1 (or else that family wouldn't exist).
- #[inline]
- pub fn queues_count(&self) -> usize {
- self.properties.queue_count as usize
+ /// # Safety
+ ///
+ /// - `connection` must be a valid X11 `xcb_connection_t` handle.
+ pub unsafe fn xcb_presentation_support<C>(
+ &self,
+ queue_family_index: u32,
+ connection: *const C,
+ visual_id: ash::vk::xcb_visualid_t,
+ ) -> Result<bool, PhysicalDeviceError> {
+ self.validate_xcb_presentation_support(queue_family_index, connection, visual_id)?;
+
+ Ok(self.xcb_presentation_support_unchecked(queue_family_index, connection, visual_id))
}
- /// If timestamps are supported, returns the number of bits supported by timestamp operations.
- /// The returned value will be in the range 36..64.
- /// If timestamps are not supported, returns None.
- #[inline]
- pub fn timestamp_valid_bits(&self) -> Option<u32> {
- let value = self.properties.timestamp_valid_bits;
- if value == 0 {
- None
- } else {
- Some(value)
+ fn validate_xcb_presentation_support<C>(
+ &self,
+ queue_family_index: u32,
+ _connection: *const C,
+ _visual_id: ash::vk::xcb_visualid_t,
+ ) -> Result<(), PhysicalDeviceError> {
+ if !self.instance.enabled_extensions().khr_xcb_surface {
+ return Err(PhysicalDeviceError::RequirementNotMet {
+ required_for: "`PhysicalDevice::xcb_presentation_support`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["khr_xcb_surface"],
+ ..Default::default()
+ },
+ });
}
- }
- /// Returns the minimum granularity supported for image transfers in terms
- /// of `[width, height, depth]`
- #[inline]
- pub fn min_image_transfer_granularity(&self) -> [u32; 3] {
- let ref granularity = self.properties.min_image_transfer_granularity;
- [granularity.width, granularity.height, granularity.depth]
+ // VUID-vkGetPhysicalDeviceXcbPresentationSupportKHR-queueFamilyIndex-01312
+ if queue_family_index >= self.queue_family_properties.len() as u32 {
+ return Err(PhysicalDeviceError::QueueFamilyIndexOutOfRange {
+ queue_family_index,
+ queue_family_count: self.queue_family_properties.len() as u32,
+ });
+ }
+
+ // VUID-vkGetPhysicalDeviceXcbPresentationSupportKHR-connection-parameter
+ // Can't validate, therefore unsafe
+
+ Ok(())
}
- /// Returns `true` if queues of this family can execute graphics operations.
- #[inline]
- pub fn supports_graphics(&self) -> bool {
- !(self.properties.queue_flags & ash::vk::QueueFlags::GRAPHICS).is_empty()
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn xcb_presentation_support_unchecked<C>(
+ &self,
+ queue_family_index: u32,
+ connection: *const C,
+ visual_id: ash::vk::VisualID,
+ ) -> bool {
+ let fns = self.instance.fns();
+ (fns.khr_xcb_surface
+ .get_physical_device_xcb_presentation_support_khr)(
+ self.handle,
+ queue_family_index,
+ connection as *mut _,
+ visual_id,
+ ) != 0
}
- /// Returns `true` if queues of this family can execute compute operations.
- #[inline]
- pub fn supports_compute(&self) -> bool {
- !(self.properties.queue_flags & ash::vk::QueueFlags::COMPUTE).is_empty()
+ /// Queries whether the physical device supports presenting to Xlib surfaces from queues of the
+ /// given queue family.
+ ///
+ /// # Safety
+ ///
+ /// - `display` must be a valid Xlib `Display` handle.
+ pub unsafe fn xlib_presentation_support<D>(
+ &self,
+ queue_family_index: u32,
+ display: *const D,
+ visual_id: ash::vk::VisualID,
+ ) -> Result<bool, PhysicalDeviceError> {
+ self.validate_xlib_presentation_support(queue_family_index, display, visual_id)?;
+
+ Ok(self.xlib_presentation_support_unchecked(queue_family_index, display, visual_id))
}
- /// Returns `true` if queues of this family can execute transfer operations.
- /// > **Note**: While all queues that can perform graphics or compute operations can implicitly perform
- /// > transfer operations, graphics & compute queues only optionally indicate support for tranfers.
- /// > Many discrete cards will have one queue family that exclusively sets the VK_QUEUE_TRANSFER_BIT
- /// > to indicate a special relationship with the DMA module and more efficient transfers.
- #[inline]
- pub fn explicitly_supports_transfers(&self) -> bool {
- !(self.properties.queue_flags & ash::vk::QueueFlags::TRANSFER).is_empty()
+ fn validate_xlib_presentation_support<D>(
+ &self,
+ queue_family_index: u32,
+ _display: *const D,
+ _visual_id: ash::vk::VisualID,
+ ) -> Result<(), PhysicalDeviceError> {
+ if !self.instance.enabled_extensions().khr_xlib_surface {
+ return Err(PhysicalDeviceError::RequirementNotMet {
+ required_for: "`PhysicalDevice::xlib_presentation_support`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["khr_xlib_surface"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkGetPhysicalDeviceXlibPresentationSupportKHR-queueFamilyIndex-01315
+ if queue_family_index >= self.queue_family_properties.len() as u32 {
+ return Err(PhysicalDeviceError::QueueFamilyIndexOutOfRange {
+ queue_family_index,
+ queue_family_count: self.queue_family_properties.len() as u32,
+ });
+ }
+
+ // VUID-vkGetPhysicalDeviceXlibPresentationSupportKHR-dpy-parameter
+ // Can't validate, therefore unsafe
+
+ Ok(())
}
- /// Returns `true` if queues of this family can execute sparse resources binding operations.
- #[inline]
- pub fn supports_sparse_binding(&self) -> bool {
- !(self.properties.queue_flags & ash::vk::QueueFlags::SPARSE_BINDING).is_empty()
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn xlib_presentation_support_unchecked<D>(
+ &self,
+ queue_family_index: u32,
+ display: *const D,
+ visual_id: ash::vk::VisualID,
+ ) -> bool {
+ let fns = self.instance.fns();
+ (fns.khr_xlib_surface
+ .get_physical_device_xlib_presentation_support_khr)(
+ self.handle,
+ queue_family_index,
+ display as *mut _,
+ visual_id,
+ ) != 0
}
+}
+
+unsafe impl VulkanObject for PhysicalDevice {
+ type Handle = ash::vk::PhysicalDevice;
- /// Returns `true` if the queues of this family support a particular pipeline stage.
#[inline]
- pub fn supports_stage(&self, stage: PipelineStage) -> bool {
- !(self.properties.queue_flags & stage.required_queue_flags()).is_empty()
+ fn handle(&self) -> Self::Handle {
+ self.handle
}
}
-impl<'a> PartialEq for QueueFamily<'a> {
- fn eq(&self, other: &Self) -> bool {
- self.id == other.id
- && self.physical_device.internal_object() == other.physical_device.internal_object()
- }
+impl_id_counter!(PhysicalDevice);
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// Type of a physical device.
+ PhysicalDeviceType = PhysicalDeviceType(i32);
+
+ /// The device is an integrated GPU.
+ IntegratedGpu = INTEGRATED_GPU,
+
+ /// The device is a discrete GPU.
+ DiscreteGpu = DISCRETE_GPU,
+
+ /// The device is a virtual GPU.
+ VirtualGpu = VIRTUAL_GPU,
+
+ /// The device is a CPU.
+ Cpu = CPU,
+
+ /// The device is something else.
+ Other = OTHER,
}
-impl<'a> Eq for QueueFamily<'a> {}
+impl Default for PhysicalDeviceType {
+ #[inline]
+ fn default() -> Self {
+ PhysicalDeviceType::Other
+ }
+}
/// The version of the Vulkan conformance test that a driver is conformant against.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
@@ -791,137 +2482,215 @@ impl From<ash::vk::ConformanceVersion> for ConformanceVersion {
}
}
-impl fmt::Debug for ConformanceVersion {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch)
+impl Debug for ConformanceVersion {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
}
}
-impl fmt::Display for ConformanceVersion {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- fmt::Debug::fmt(self, formatter)
+impl Display for ConformanceVersion {
+ #[inline]
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ Debug::fmt(self, f)
}
}
-/// An identifier for the driver of a physical device.
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-#[repr(i32)]
-pub enum DriverId {
- AMDProprietary = ash::vk::DriverId::AMD_PROPRIETARY.as_raw(),
- AMDOpenSource = ash::vk::DriverId::AMD_OPEN_SOURCE.as_raw(),
- MesaRADV = ash::vk::DriverId::MESA_RADV.as_raw(),
- NvidiaProprietary = ash::vk::DriverId::NVIDIA_PROPRIETARY.as_raw(),
- IntelProprietaryWindows = ash::vk::DriverId::INTEL_PROPRIETARY_WINDOWS.as_raw(),
- IntelOpenSourceMesa = ash::vk::DriverId::INTEL_OPEN_SOURCE_MESA.as_raw(),
- ImaginationProprietary = ash::vk::DriverId::IMAGINATION_PROPRIETARY.as_raw(),
- QualcommProprietary = ash::vk::DriverId::QUALCOMM_PROPRIETARY.as_raw(),
- ARMProprietary = ash::vk::DriverId::ARM_PROPRIETARY.as_raw(),
- GoogleSwiftshader = ash::vk::DriverId::GOOGLE_SWIFTSHADER.as_raw(),
- GGPProprietary = ash::vk::DriverId::GGP_PROPRIETARY.as_raw(),
- BroadcomProprietary = ash::vk::DriverId::BROADCOM_PROPRIETARY.as_raw(),
- MesaLLVMpipe = ash::vk::DriverId::MESA_LLVMPIPE.as_raw(),
- MoltenVK = ash::vk::DriverId::MOLTENVK.as_raw(),
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// An identifier for the driver of a physical device.
+ DriverId = DriverId(i32);
+
+ // TODO: document
+ AMDProprietary = AMD_PROPRIETARY,
+
+ // TODO: document
+ AMDOpenSource = AMD_OPEN_SOURCE,
+
+ // TODO: document
+ MesaRADV = MESA_RADV,
+
+ // TODO: document
+ NvidiaProprietary = NVIDIA_PROPRIETARY,
+
+ // TODO: document
+ IntelProprietaryWindows = INTEL_PROPRIETARY_WINDOWS,
+
+ // TODO: document
+ IntelOpenSourceMesa = INTEL_OPEN_SOURCE_MESA,
+
+ // TODO: document
+ ImaginationProprietary = IMAGINATION_PROPRIETARY,
+
+ // TODO: document
+ QualcommProprietary = QUALCOMM_PROPRIETARY,
+
+ // TODO: document
+ ARMProprietary = ARM_PROPRIETARY,
+
+ // TODO: document
+ GoogleSwiftshader = GOOGLE_SWIFTSHADER,
+
+ // TODO: document
+ GGPProprietary = GGP_PROPRIETARY,
+
+ // TODO: document
+ BroadcomProprietary = BROADCOM_PROPRIETARY,
+
+ // TODO: document
+ MesaLLVMpipe = MESA_LLVMPIPE,
+
+ // TODO: document
+ MoltenVK = MOLTENVK,
+
+ // TODO: document
+ CoreAVIProprietary = COREAVI_PROPRIETARY,
+
+ // TODO: document
+ JuiceProprietary = JUICE_PROPRIETARY,
+
+ // TODO: document
+ VeriSiliconPropertary = VERISILICON_PROPRIETARY,
+
+ // TODO: document
+ MesaTurnip = MESA_TURNIP,
+
+ // TODO: document
+ MesaV3DV = MESA_V3DV,
+
+ // TODO: document
+ MesaPanVK = MESA_PANVK,
+
+ // TODO: document
+ SamsungProprietary = SAMSUNG_PROPRIETARY,
+
+ // TODO: document
+ MesaVenus = MESA_VENUS,
+
+ // TODO: document
+ MesaDozen = MESA_DOZEN,
}
-impl TryFrom<ash::vk::DriverId> for DriverId {
- type Error = ();
-
- #[inline]
- fn try_from(val: ash::vk::DriverId) -> Result<Self, Self::Error> {
- match val {
- ash::vk::DriverId::AMD_PROPRIETARY => Ok(Self::AMDProprietary),
- ash::vk::DriverId::AMD_OPEN_SOURCE => Ok(Self::AMDOpenSource),
- ash::vk::DriverId::MESA_RADV => Ok(Self::MesaRADV),
- ash::vk::DriverId::NVIDIA_PROPRIETARY => Ok(Self::NvidiaProprietary),
- ash::vk::DriverId::INTEL_PROPRIETARY_WINDOWS => Ok(Self::IntelProprietaryWindows),
- ash::vk::DriverId::INTEL_OPEN_SOURCE_MESA => Ok(Self::IntelOpenSourceMesa),
- ash::vk::DriverId::IMAGINATION_PROPRIETARY => Ok(Self::ImaginationProprietary),
- ash::vk::DriverId::QUALCOMM_PROPRIETARY => Ok(Self::QualcommProprietary),
- ash::vk::DriverId::ARM_PROPRIETARY => Ok(Self::ARMProprietary),
- ash::vk::DriverId::GOOGLE_SWIFTSHADER => Ok(Self::GoogleSwiftshader),
- ash::vk::DriverId::GGP_PROPRIETARY => Ok(Self::GGPProprietary),
- ash::vk::DriverId::BROADCOM_PROPRIETARY => Ok(Self::BroadcomProprietary),
- ash::vk::DriverId::MESA_LLVMPIPE => Ok(Self::MesaLLVMpipe),
- ash::vk::DriverId::MOLTENVK => Ok(Self::MoltenVK),
- _ => Err(()),
- }
- }
+/// Information provided about an active tool.
+#[derive(Clone, Debug)]
+#[non_exhaustive]
+pub struct ToolProperties {
+ /// The name of the tool.
+ pub name: String,
+
+ /// The version of the tool.
+ pub version: String,
+
+ /// The purposes supported by the tool.
+ pub purposes: ToolPurposes,
+
+ /// A description of the tool.
+ pub description: String,
+
+ /// The layer implementing the tool, or empty if it is not implemented by a layer.
+ pub layer: String,
}
-/// Specifies which subgroup operations are supported.
-#[derive(Clone, Copy, Debug)]
-pub struct SubgroupFeatures {
- pub basic: bool,
- pub vote: bool,
- pub arithmetic: bool,
- pub ballot: bool,
- pub shuffle: bool,
- pub shuffle_relative: bool,
- pub clustered: bool,
- pub quad: bool,
+vulkan_bitflags! {
+ #[non_exhaustive]
+
+ /// The purpose of an active tool.
+ ToolPurposes = ToolPurposeFlags(u32);
+
+ /// The tool provides validation of API usage.
+ VALIDATION = VALIDATION,
+
+ /// The tool provides profiling of API usage.
+ PROFILING = PROFILING,
+
+ /// The tool is capturing data about the application's API usage.
+ TRACING = TRACING,
+
+ /// The tool provides additional API features or extensions on top of the underlying
+ /// implementation.
+ ADDITIONAL_FEATURES = ADDITIONAL_FEATURES,
+
+ /// The tool modifies the API features, limits or extensions presented to the application.
+ MODIFYING_FEATURES = MODIFYING_FEATURES,
+
+ /// The tool reports information to the user via a
+ /// [`DebugUtilsMessenger`](crate::instance::debug::DebugUtilsMessenger).
+ DEBUG_REPORTING = DEBUG_REPORTING_EXT {
+ instance_extensions: [ext_debug_utils, ext_debug_report],
+ },
+
+ /// The tool consumes debug markers or object debug annotation, queue labels or command buffer
+ /// labels.
+ DEBUG_MARKERS = DEBUG_MARKERS_EXT {
+ device_extensions: [ext_debug_marker],
+ instance_extensions: [ext_debug_utils],
+ },
}
-impl From<ash::vk::SubgroupFeatureFlags> for SubgroupFeatures {
- #[inline]
- fn from(val: ash::vk::SubgroupFeatureFlags) -> Self {
- Self {
- basic: val.intersects(ash::vk::SubgroupFeatureFlags::BASIC),
- vote: val.intersects(ash::vk::SubgroupFeatureFlags::VOTE),
- arithmetic: val.intersects(ash::vk::SubgroupFeatureFlags::ARITHMETIC),
- ballot: val.intersects(ash::vk::SubgroupFeatureFlags::BALLOT),
- shuffle: val.intersects(ash::vk::SubgroupFeatureFlags::SHUFFLE),
- shuffle_relative: val.intersects(ash::vk::SubgroupFeatureFlags::SHUFFLE_RELATIVE),
- clustered: val.intersects(ash::vk::SubgroupFeatureFlags::CLUSTERED),
- quad: val.intersects(ash::vk::SubgroupFeatureFlags::QUAD),
- }
- }
+vulkan_bitflags! {
+ #[non_exhaustive]
+
+ /// Specifies which subgroup operations are supported.
+ SubgroupFeatures = SubgroupFeatureFlags(u32);
+
+ // TODO: document
+ BASIC = BASIC,
+
+ // TODO: document
+ VOTE = VOTE,
+
+ // TODO: document
+ ARITHMETIC = ARITHMETIC,
+
+ // TODO: document
+ BALLOT = BALLOT,
+
+ // TODO: document
+ SHUFFLE = SHUFFLE,
+
+ // TODO: document
+ SHUFFLE_RELATIVE = SHUFFLE_RELATIVE,
+
+ // TODO: document
+ CLUSTERED = CLUSTERED,
+
+ // TODO: document
+ QUAD = QUAD,
+
+ // TODO: document
+ PARTITIONED = PARTITIONED_NV {
+ device_extensions: [nv_shader_subgroup_partitioned],
+ },
}
-/// Specifies how the device clips single point primitives.
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-#[repr(i32)]
-pub enum PointClippingBehavior {
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// Specifies how the device clips single point primitives.
+ PointClippingBehavior = PointClippingBehavior(i32);
+
/// Points are clipped if they lie outside any clip plane, both those bounding the view volume
/// and user-defined clip planes.
- AllClipPlanes = ash::vk::PointClippingBehavior::ALL_CLIP_PLANES.as_raw(),
+ AllClipPlanes = ALL_CLIP_PLANES,
+
/// Points are clipped only if they lie outside a user-defined clip plane.
- UserClipPlanesOnly = ash::vk::PointClippingBehavior::USER_CLIP_PLANES_ONLY.as_raw(),
+ UserClipPlanesOnly = USER_CLIP_PLANES_ONLY,
}
-impl TryFrom<ash::vk::PointClippingBehavior> for PointClippingBehavior {
- type Error = ();
+vulkan_enum! {
+ #[non_exhaustive]
- #[inline]
- fn try_from(val: ash::vk::PointClippingBehavior) -> Result<Self, Self::Error> {
- match val {
- ash::vk::PointClippingBehavior::ALL_CLIP_PLANES => Ok(Self::AllClipPlanes),
- ash::vk::PointClippingBehavior::USER_CLIP_PLANES_ONLY => Ok(Self::UserClipPlanesOnly),
- _ => Err(()),
- }
- }
-}
+ /// Specifies whether, and how, shader float controls can be set independently.
+ ShaderFloatControlsIndependence = ShaderFloatControlsIndependence(i32);
-/// Specifies whether, and how, shader float controls can be set independently.
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-#[repr(i32)]
-pub enum ShaderFloatControlsIndependence {
- Float32Only = ash::vk::ShaderFloatControlsIndependence::TYPE_32_ONLY.as_raw(),
- All = ash::vk::ShaderFloatControlsIndependence::ALL.as_raw(),
- None = ash::vk::ShaderFloatControlsIndependence::NONE.as_raw(),
-}
+ // TODO: document
+ Float32Only = TYPE_32_ONLY,
-impl TryFrom<ash::vk::ShaderFloatControlsIndependence> for ShaderFloatControlsIndependence {
- type Error = ();
+ // TODO: document
+ All = ALL,
- #[inline]
- fn try_from(val: ash::vk::ShaderFloatControlsIndependence) -> Result<Self, Self::Error> {
- match val {
- ash::vk::ShaderFloatControlsIndependence::TYPE_32_ONLY => Ok(Self::Float32Only),
- ash::vk::ShaderFloatControlsIndependence::ALL => Ok(Self::All),
- ash::vk::ShaderFloatControlsIndependence::NONE => Ok(Self::None),
- _ => Err(()),
- }
- }
+ // TODO: document
+ None = NONE,
}
/// Specifies shader core properties.
@@ -930,7 +2699,169 @@ pub struct ShaderCoreProperties {}
impl From<ash::vk::ShaderCorePropertiesFlagsAMD> for ShaderCoreProperties {
#[inline]
- fn from(val: ash::vk::ShaderCorePropertiesFlagsAMD) -> Self {
+ fn from(_val: ash::vk::ShaderCorePropertiesFlagsAMD) -> Self {
Self {}
}
}
+
+vulkan_bitflags! {
+ #[non_exhaustive]
+
+ // TODO: document
+ MemoryDecompressionMethods = MemoryDecompressionMethodFlagsNV(u64);
+
+ // TODO: document
+ GDEFLATE_1_0 = GDEFLATE_1_0,
+}
+
+vulkan_bitflags! {
+ #[non_exhaustive]
+
+ // TODO: document
+ OpticalFlowGridSizes = OpticalFlowGridSizeFlagsNV(u32);
+
+ // TODO: document
+ SIZE_1X1 = TYPE_1X1,
+
+ // TODO: document
+ SIZE_2X2 = TYPE_2X2,
+
+ // TODO: document
+ SIZE_4X4 = TYPE_4X4,
+
+ // TODO: document
+ SIZE_8X8 = TYPE_8X8,
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ // TODO: document
+ PipelineRobustnessBufferBehavior = PipelineRobustnessBufferBehaviorEXT(i32);
+
+ // TODO: document
+ DeviceDefault = DEVICE_DEFAULT,
+
+ // TODO: document
+ Disabled = DISABLED,
+
+ // TODO: document
+ RobustBufferAccess = ROBUST_BUFFER_ACCESS,
+
+ // TODO: document
+ RobustBufferAccess2 = ROBUST_BUFFER_ACCESS_2,
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ // TODO: document
+ PipelineRobustnessImageBehavior = PipelineRobustnessImageBehaviorEXT(i32);
+
+ // TODO: document
+ DeviceDefault = DEVICE_DEFAULT,
+
+ // TODO: document
+ Disabled = DISABLED,
+
+ // TODO: document
+ RobustImageAccess = ROBUST_IMAGE_ACCESS,
+
+ // TODO: document
+ RobustImageAccess2 = ROBUST_IMAGE_ACCESS_2,
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ // TODO: document
+ RayTracingInvocationReorderMode = RayTracingInvocationReorderModeNV(i32);
+
+ // TODO: document
+ None = NONE,
+
+ // TODO: document
+ Reorder = REORDER,
+}
+
+/// Error that can happen when using a physical device.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum PhysicalDeviceError {
+ VulkanError(VulkanError),
+
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+
+ // The given `SurfaceInfo` values are not supported for the surface by the physical device.
+ NotSupported,
+
+ /// The provided `queue_family_index` was not less than the number of queue families in the
+ /// physical device.
+ QueueFamilyIndexOutOfRange {
+ queue_family_index: u32,
+ queue_family_count: u32,
+ },
+
+ // The provided `surface` is not supported by any of the physical device's queue families.
+ SurfaceNotSupported,
+}
+
+impl Error for PhysicalDeviceError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::VulkanError(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+impl Display for PhysicalDeviceError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::VulkanError(_) => write!(f, "a runtime error occurred"),
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ Self::NotSupported => write!(
+ f,
+ "the given `SurfaceInfo` values are not supported for the surface by the physical \
+ device",
+ ),
+ Self::QueueFamilyIndexOutOfRange {
+ queue_family_index,
+ queue_family_count,
+ } => write!(
+ f,
+ "the provided `queue_family_index` ({}) was not less than the number of queue \
+ families in the physical device ({})",
+ queue_family_index, queue_family_count,
+ ),
+ Self::SurfaceNotSupported => write!(
+ f,
+ "the provided `surface` is not supported by any of the physical device's queue families",
+ ),
+ }
+ }
+}
+
+impl From<VulkanError> for PhysicalDeviceError {
+ fn from(err: VulkanError) -> Self {
+ Self::VulkanError(err)
+ }
+}
+
+impl From<RequirementNotMet> for PhysicalDeviceError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
+ }
+ }
+}
diff --git a/src/device/properties.rs b/src/device/properties.rs
index 8628cb0..85e189c 100644
--- a/src/device/properties.rs
+++ b/src/device/properties.rs
@@ -1,138 +1,25 @@
-use crate::device::physical::{
- ConformanceVersion, DriverId, PhysicalDeviceType, PointClippingBehavior, ShaderCoreProperties,
+use super::physical::{
+ ConformanceVersion, DriverId, MemoryDecompressionMethods, OpticalFlowGridSizes,
+ PhysicalDeviceType, PipelineRobustnessBufferBehavior, PipelineRobustnessImageBehavior,
+ PointClippingBehavior, RayTracingInvocationReorderMode, ShaderCoreProperties,
ShaderFloatControlsIndependence, SubgroupFeatures,
};
-use crate::image::{SampleCount, SampleCounts};
-use crate::pipeline::shader::ShaderStages;
-use crate::render_pass::ResolveModes;
-use crate::Version;
-use std::convert::TryInto;
-use std::ffi::CStr;
-
-/// this is a macro that outputs either T or Option<T> depending on the 2nd argument
-macro_rules! property_type {
- ($ty:ty, true) => {
- $ty
- };
- ($ty:ty, false) => {
- Option<$ty>
- };
-}
-
-pub(crate) use property_type;
-
-/// this is a macro that executes the correct from_vulkan call depending on whether or not the type is Option<T>
-macro_rules! property_from_vulkan {
- ($ty:ty, [$($ffi_struct:ident $(.$ffi_struct_field:ident)*),+], $ffi_field:ident, true, $properties:ident) => {
- std::array::IntoIter::new([
- $($properties.$ffi_struct$(.$ffi_struct_field)*.$ffi_field),+
- ]).next().and_then(|x| <$ty>::from_vulkan(x)).expect(concat!("expected good ", stringify!($ffi_field)))
- };
- ($ty:ty, [$($ffi_struct:ident $(.$ffi_struct_field:ident)*),+], $ffi_field:ident, false, $properties:ident) => {
- std::array::IntoIter::new([
- $($properties.$ffi_struct.map(|s| s$(.$ffi_struct_field)*.$ffi_field)),+
- ]).flatten().next().and_then(|x| <$ty>::from_vulkan(x))
- };
-}
-
-pub(crate) use property_from_vulkan;
-
-macro_rules! properties {
- {
- $($member:ident => {
- doc: $doc:expr,
- ty: $ty:ty,
- ffi_name: $ffi_field:ident,
- ffi_members: [$($ffi_struct:ident $(.$ffi_struct_field:ident)*),+],
- required: $required:tt,
- },)*
- } => {
- /// Represents all the properties of a physical device.
- ///
- /// Depending on the highest version of Vulkan supported by the physical device, and the
- /// available extensions, not every property may be available. For that reason, properties
- /// are wrapped in an `Option`.
- #[derive(Clone, Debug, Default)]
- #[allow(missing_docs)]
- pub struct Properties {
- $(
- #[doc = $doc]
- pub $member: $crate::device::properties::property_type!($ty, $required),
- )*
- }
-
- impl From<&PropertiesFfi> for Properties {
- fn from(properties_ffi: &PropertiesFfi) -> Self {
- use crate::device::properties::FromVulkan;
-
- Properties {
- $(
- $member: crate::device::properties::property_from_vulkan!($ty, [ $($ffi_struct$(.$ffi_struct_field)*),+ ], $ffi_field, $required, properties_ffi),
- )*
- }
- }
- }
- };
-}
-
-pub use crate::autogen::Properties;
-pub(crate) use properties;
-
-macro_rules! properties_ffi {
- {
- $api_version:ident,
- $device_extensions:ident,
- $instance_extensions:ident,
- $($member:ident => {
- ty: $ty:ident,
- provided_by: [$($provided_by:expr),+],
- conflicts: [$($conflicts:ident),*],
- },)+
- } => {
- #[derive(Default)]
- pub(crate) struct PropertiesFfi {
- properties_vulkan10: ash::vk::PhysicalDeviceProperties2KHR,
-
- $(
- $member: Option<ash::vk::$ty>,
- )+
- }
-
- impl PropertiesFfi {
- pub(crate) fn make_chain(
- &mut self,
- $api_version: crate::Version,
- $device_extensions: &crate::device::DeviceExtensions,
- $instance_extensions: &crate::instance::InstanceExtensions,
- ) {
- self.properties_vulkan10 = Default::default();
- let head = &mut self.properties_vulkan10;
-
- $(
- if std::array::IntoIter::new([$($provided_by),+]).any(|x| x) &&
- std::array::IntoIter::new([$(self.$conflicts.is_none()),*]).all(|x| x) {
- self.$member = Some(Default::default());
- let member = self.$member.as_mut().unwrap();
- member.p_next = head.p_next;
- head.p_next = member as *mut _ as _;
- }
- )+
- }
-
- pub(crate) fn head_as_ref(&self) -> &ash::vk::PhysicalDeviceProperties2KHR {
- &self.properties_vulkan10
- }
-
- pub(crate) fn head_as_mut(&mut self) -> &mut ash::vk::PhysicalDeviceProperties2KHR {
- &mut self.properties_vulkan10
- }
- }
- };
-}
-
-pub(crate) use {crate::autogen::PropertiesFfi, properties_ffi};
+use crate::{
+ device::{DeviceExtensions, QueueFlags},
+ image::{SampleCount, SampleCounts},
+ instance::InstanceExtensions,
+ memory::DeviceAlignment,
+ render_pass::ResolveModes,
+ shader::ShaderStages,
+ DeviceSize, Version,
+};
+use std::{ffi::CStr, os::raw::c_char};
+
+// Generated by build.rs
+include!(concat!(env!("OUT_DIR"), "/properties.rs"));
// A bit of a hack...
+// TODO: integrate into autogen?
pub(crate) trait FromVulkan<F>
where
Self: Sized,
@@ -175,6 +62,13 @@ impl FromVulkan<u64> for u64 {
}
}
+impl FromVulkan<u64> for DeviceAlignment {
+ #[inline]
+ fn from_vulkan(val: u64) -> Option<Self> {
+ DeviceAlignment::new(val)
+ }
+}
+
impl FromVulkan<usize> for usize {
#[inline]
fn from_vulkan(val: usize) -> Option<Self> {
@@ -210,9 +104,9 @@ impl<const N: usize> FromVulkan<[f32; N]> for [f32; N] {
}
}
-impl<const N: usize> FromVulkan<[std::os::raw::c_char; N]> for String {
+impl<const N: usize> FromVulkan<[c_char; N]> for String {
#[inline]
- fn from_vulkan(val: [std::os::raw::c_char; N]) -> Option<Self> {
+ fn from_vulkan(val: [c_char; N]) -> Option<Self> {
Some(unsafe { CStr::from_ptr(val.as_ptr()).to_string_lossy().into_owned() })
}
}
@@ -252,6 +146,20 @@ impl FromVulkan<ash::vk::Extent2D> for [u32; 2] {
}
}
+impl FromVulkan<ash::vk::MemoryDecompressionMethodFlagsNV> for MemoryDecompressionMethods {
+ #[inline]
+ fn from_vulkan(val: ash::vk::MemoryDecompressionMethodFlagsNV) -> Option<Self> {
+ Some(val.into())
+ }
+}
+
+impl FromVulkan<ash::vk::OpticalFlowGridSizeFlagsNV> for OpticalFlowGridSizes {
+ #[inline]
+ fn from_vulkan(val: ash::vk::OpticalFlowGridSizeFlagsNV) -> Option<Self> {
+ Some(val.into())
+ }
+}
+
impl FromVulkan<ash::vk::PhysicalDeviceType> for PhysicalDeviceType {
#[inline]
fn from_vulkan(val: ash::vk::PhysicalDeviceType) -> Option<Self> {
@@ -259,6 +167,20 @@ impl FromVulkan<ash::vk::PhysicalDeviceType> for PhysicalDeviceType {
}
}
+impl FromVulkan<ash::vk::PipelineRobustnessBufferBehaviorEXT> for PipelineRobustnessBufferBehavior {
+ #[inline]
+ fn from_vulkan(val: ash::vk::PipelineRobustnessBufferBehaviorEXT) -> Option<Self> {
+ val.try_into().ok()
+ }
+}
+
+impl FromVulkan<ash::vk::PipelineRobustnessImageBehaviorEXT> for PipelineRobustnessImageBehavior {
+ #[inline]
+ fn from_vulkan(val: ash::vk::PipelineRobustnessImageBehaviorEXT) -> Option<Self> {
+ val.try_into().ok()
+ }
+}
+
impl FromVulkan<ash::vk::PointClippingBehavior> for PointClippingBehavior {
#[inline]
fn from_vulkan(val: ash::vk::PointClippingBehavior) -> Option<Self> {
@@ -266,6 +188,20 @@ impl FromVulkan<ash::vk::PointClippingBehavior> for PointClippingBehavior {
}
}
+impl FromVulkan<ash::vk::QueueFlags> for QueueFlags {
+ #[inline]
+ fn from_vulkan(val: ash::vk::QueueFlags) -> Option<Self> {
+ Some(val.into())
+ }
+}
+
+impl FromVulkan<ash::vk::RayTracingInvocationReorderModeNV> for RayTracingInvocationReorderMode {
+ #[inline]
+ fn from_vulkan(val: ash::vk::RayTracingInvocationReorderModeNV) -> Option<Self> {
+ val.try_into().ok()
+ }
+}
+
impl FromVulkan<ash::vk::ResolveModeFlags> for ResolveModes {
#[inline]
fn from_vulkan(val: ash::vk::ResolveModeFlags) -> Option<Self> {
diff --git a/src/device/queue.rs b/src/device/queue.rs
new file mode 100644
index 0000000..11fc703
--- /dev/null
+++ b/src/device/queue.rs
@@ -0,0 +1,1730 @@
+// Copyright (c) 2022 The Vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use super::{Device, DeviceOwned};
+use crate::{
+ buffer::BufferState,
+ command_buffer::{
+ CommandBufferResourcesUsage, CommandBufferState, CommandBufferUsage, SemaphoreSubmitInfo,
+ SubmitInfo,
+ },
+ image::{sys::ImageState, ImageAccess},
+ instance::debug::DebugUtilsLabel,
+ macros::vulkan_bitflags,
+ memory::{
+ BindSparseInfo, SparseBufferMemoryBind, SparseImageMemoryBind, SparseImageOpaqueMemoryBind,
+ },
+ swapchain::{PresentInfo, SwapchainPresentInfo},
+ sync::{
+ fence::{Fence, FenceState},
+ future::{AccessCheckError, FlushError, GpuFuture},
+ semaphore::SemaphoreState,
+ },
+ OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject,
+};
+use ahash::HashMap;
+use parking_lot::{Mutex, MutexGuard};
+use smallvec::{smallvec, SmallVec};
+use std::{
+ collections::VecDeque,
+ error::Error,
+ ffi::CString,
+ fmt::{Display, Error as FmtError, Formatter},
+ hash::{Hash, Hasher},
+ mem::take,
+ ptr,
+ sync::{atomic::Ordering, Arc},
+};
+
+/// Represents a queue where commands can be submitted.
+// TODO: should use internal synchronization?
+#[derive(Debug)]
+pub struct Queue {
+ handle: ash::vk::Queue,
+ device: Arc<Device>,
+ queue_family_index: u32,
+ id: u32, // id within family
+
+ state: Mutex<QueueState>,
+}
+
+impl Queue {
+ // TODO: Make public
+ #[inline]
+ pub(super) fn from_handle(
+ device: Arc<Device>,
+ handle: ash::vk::Queue,
+ queue_family_index: u32,
+ id: u32,
+ ) -> Arc<Self> {
+ Arc::new(Queue {
+ handle,
+ device,
+ queue_family_index,
+ id,
+ state: Mutex::new(Default::default()),
+ })
+ }
+
+ /// Returns the device that this queue belongs to.
+ #[inline]
+ pub fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+
+ /// Returns the index of the queue family that this queue belongs to.
+ #[inline]
+ pub fn queue_family_index(&self) -> u32 {
+ self.queue_family_index
+ }
+
+ /// Returns the index of this queue within its queue family.
+ #[inline]
+ pub fn id_within_family(&self) -> u32 {
+ self.id
+ }
+
+ /// Locks the queue and then calls the provided closure, providing it with an object that
+ /// can be used to perform operations on the queue, such as command buffer submissions.
+ #[inline]
+ pub fn with<'a, R>(self: &'a Arc<Self>, func: impl FnOnce(QueueGuard<'a>) -> R) -> R {
+ func(QueueGuard {
+ queue: self,
+ state: self.state.lock(),
+ })
+ }
+}
+
+impl Drop for Queue {
+ #[inline]
+ fn drop(&mut self) {
+ let state = self.state.get_mut();
+ let _ = state.wait_idle(&self.device, self.handle);
+ }
+}
+
+unsafe impl VulkanObject for Queue {
+ type Handle = ash::vk::Queue;
+
+ #[inline]
+ fn handle(&self) -> Self::Handle {
+ self.handle
+ }
+}
+
+unsafe impl DeviceOwned for Queue {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+}
+
+impl PartialEq for Queue {
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ self.id == other.id
+ && self.queue_family_index == other.queue_family_index
+ && self.device == other.device
+ }
+}
+
+impl Eq for Queue {}
+
+impl Hash for Queue {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.id.hash(state);
+ self.queue_family_index.hash(state);
+ self.device.hash(state);
+ }
+}
+
+pub struct QueueGuard<'a> {
+ queue: &'a Arc<Queue>,
+ state: MutexGuard<'a, QueueState>,
+}
+
+impl<'a> QueueGuard<'a> {
+ pub(crate) unsafe fn fence_signaled(&mut self, fence: &Fence) {
+ self.state.fence_signaled(fence)
+ }
+
+ /// Waits until all work on this queue has finished, then releases ownership of all resources
+ /// that were in use by the queue.
+ ///
+ /// This is equivalent to submitting a fence to the queue, waiting on it, and then calling
+ /// `cleanup_finished`.
+ ///
+ /// Just like [`Device::wait_idle`], you shouldn't have to call this function in a typical
+ /// program.
+ #[inline]
+ pub fn wait_idle(&mut self) -> Result<(), OomError> {
+ self.state.wait_idle(&self.queue.device, self.queue.handle)
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub(crate) unsafe fn bind_sparse_unchecked(
+ &mut self,
+ bind_infos: impl IntoIterator<Item = BindSparseInfo>,
+ fence: Option<Arc<Fence>>,
+ ) -> Result<(), VulkanError> {
+ let bind_infos: SmallVec<[_; 4]> = bind_infos.into_iter().collect();
+ let mut states = States::from_bind_infos(&bind_infos);
+
+ self.bind_sparse_unchecked_locked(
+ &bind_infos,
+ fence.as_ref().map(|fence| {
+ let state = fence.state();
+ (fence, state)
+ }),
+ &mut states,
+ )
+ }
+
+ unsafe fn bind_sparse_unchecked_locked(
+ &mut self,
+ bind_infos: &SmallVec<[BindSparseInfo; 4]>,
+ fence: Option<(&Arc<Fence>, MutexGuard<'_, FenceState>)>,
+ states: &mut States<'_>,
+ ) -> Result<(), VulkanError> {
+ struct PerBindSparseInfo {
+ wait_semaphores_vk: SmallVec<[ash::vk::Semaphore; 4]>,
+ buffer_bind_infos_vk: SmallVec<[ash::vk::SparseBufferMemoryBindInfo; 4]>,
+ buffer_binds_vk: SmallVec<[SmallVec<[ash::vk::SparseMemoryBind; 4]>; 4]>,
+ image_opaque_bind_infos_vk: SmallVec<[ash::vk::SparseImageOpaqueMemoryBindInfo; 4]>,
+ image_opaque_binds_vk: SmallVec<[SmallVec<[ash::vk::SparseMemoryBind; 4]>; 4]>,
+ image_bind_infos_vk: SmallVec<[ash::vk::SparseImageMemoryBindInfo; 4]>,
+ image_binds_vk: SmallVec<[SmallVec<[ash::vk::SparseImageMemoryBind; 4]>; 4]>,
+ signal_semaphores_vk: SmallVec<[ash::vk::Semaphore; 4]>,
+ }
+
+ let (mut bind_infos_vk, mut per_bind_vk): (SmallVec<[_; 4]>, SmallVec<[_; 4]>) = bind_infos
+ .iter()
+ .map(|bind_info| {
+ let &BindSparseInfo {
+ ref wait_semaphores,
+ ref buffer_binds,
+ ref image_opaque_binds,
+ ref image_binds,
+ ref signal_semaphores,
+ _ne: _,
+ } = bind_info;
+
+ let wait_semaphores_vk: SmallVec<[_; 4]> = wait_semaphores
+ .iter()
+ .map(|semaphore| semaphore.handle())
+ .collect();
+
+ let (buffer_bind_infos_vk, buffer_binds_vk): (SmallVec<[_; 4]>, SmallVec<[_; 4]>) =
+ buffer_binds
+ .iter()
+ .map(|(buffer, memory_binds)| {
+ (
+ ash::vk::SparseBufferMemoryBindInfo {
+ buffer: buffer.buffer().handle(),
+ bind_count: 0,
+ p_binds: ptr::null(),
+ },
+ memory_binds
+ .iter()
+ .map(|memory_bind| {
+ let &SparseBufferMemoryBind {
+ offset,
+ size,
+ ref memory,
+ } = memory_bind;
+
+ let (memory, memory_offset) = memory.as_ref().map_or_else(
+ Default::default,
+ |(memory, memory_offset)| {
+ (memory.handle(), *memory_offset)
+ },
+ );
+
+ ash::vk::SparseMemoryBind {
+ resource_offset: offset,
+ size,
+ memory,
+ memory_offset,
+ flags: ash::vk::SparseMemoryBindFlags::empty(),
+ }
+ })
+ .collect::<SmallVec<[_; 4]>>(),
+ )
+ })
+ .unzip();
+
+ let (image_opaque_bind_infos_vk, image_opaque_binds_vk): (
+ SmallVec<[_; 4]>,
+ SmallVec<[_; 4]>,
+ ) = image_opaque_binds
+ .iter()
+ .map(|(image, memory_binds)| {
+ (
+ ash::vk::SparseImageOpaqueMemoryBindInfo {
+ image: image.inner().image.handle(),
+ bind_count: 0,
+ p_binds: ptr::null(),
+ },
+ memory_binds
+ .iter()
+ .map(|memory_bind| {
+ let &SparseImageOpaqueMemoryBind {
+ offset,
+ size,
+ ref memory,
+ metadata,
+ } = memory_bind;
+
+ let (memory, memory_offset) = memory.as_ref().map_or_else(
+ Default::default,
+ |(memory, memory_offset)| (memory.handle(), *memory_offset),
+ );
+
+ ash::vk::SparseMemoryBind {
+ resource_offset: offset,
+ size,
+ memory,
+ memory_offset,
+ flags: if metadata {
+ ash::vk::SparseMemoryBindFlags::METADATA
+ } else {
+ ash::vk::SparseMemoryBindFlags::empty()
+ },
+ }
+ })
+ .collect::<SmallVec<[_; 4]>>(),
+ )
+ })
+ .unzip();
+
+ let (image_bind_infos_vk, image_binds_vk): (SmallVec<[_; 4]>, SmallVec<[_; 4]>) =
+ image_binds
+ .iter()
+ .map(|(image, memory_binds)| {
+ (
+ ash::vk::SparseImageMemoryBindInfo {
+ image: image.inner().image.handle(),
+ bind_count: 0,
+ p_binds: ptr::null(),
+ },
+ memory_binds
+ .iter()
+ .map(|memory_bind| {
+ let &SparseImageMemoryBind {
+ aspects,
+ mip_level,
+ array_layer,
+ offset,
+ extent,
+ ref memory,
+ } = memory_bind;
+
+ let (memory, memory_offset) = memory.as_ref().map_or_else(
+ Default::default,
+ |(memory, memory_offset)| {
+ (memory.handle(), *memory_offset)
+ },
+ );
+
+ ash::vk::SparseImageMemoryBind {
+ subresource: ash::vk::ImageSubresource {
+ aspect_mask: aspects.into(),
+ mip_level,
+ array_layer,
+ },
+ offset: ash::vk::Offset3D {
+ x: offset[0] as i32,
+ y: offset[1] as i32,
+ z: offset[2] as i32,
+ },
+ extent: ash::vk::Extent3D {
+ width: extent[0],
+ height: extent[1],
+ depth: extent[2],
+ },
+ memory,
+ memory_offset,
+ flags: ash::vk::SparseMemoryBindFlags::empty(),
+ }
+ })
+ .collect::<SmallVec<[_; 4]>>(),
+ )
+ })
+ .unzip();
+
+ let signal_semaphores_vk: SmallVec<[_; 4]> = signal_semaphores
+ .iter()
+ .map(|semaphore| semaphore.handle())
+ .collect();
+
+ (
+ ash::vk::BindSparseInfo::default(),
+ PerBindSparseInfo {
+ wait_semaphores_vk,
+ buffer_bind_infos_vk,
+ buffer_binds_vk,
+ image_opaque_bind_infos_vk,
+ image_opaque_binds_vk,
+ image_bind_infos_vk,
+ image_binds_vk,
+ signal_semaphores_vk,
+ },
+ )
+ })
+ .unzip();
+
+ for (
+ bind_info_vk,
+ PerBindSparseInfo {
+ wait_semaphores_vk,
+ buffer_bind_infos_vk,
+ buffer_binds_vk,
+ image_opaque_bind_infos_vk,
+ image_opaque_binds_vk,
+ image_bind_infos_vk,
+ image_binds_vk,
+ signal_semaphores_vk,
+ },
+ ) in (bind_infos_vk.iter_mut()).zip(per_bind_vk.iter_mut())
+ {
+ for (buffer_bind_infos_vk, buffer_binds_vk) in
+ (buffer_bind_infos_vk.iter_mut()).zip(buffer_binds_vk.iter())
+ {
+ *buffer_bind_infos_vk = ash::vk::SparseBufferMemoryBindInfo {
+ bind_count: buffer_binds_vk.len() as u32,
+ p_binds: buffer_binds_vk.as_ptr(),
+ ..*buffer_bind_infos_vk
+ };
+ }
+
+ for (image_opaque_bind_infos_vk, image_opaque_binds_vk) in
+ (image_opaque_bind_infos_vk.iter_mut()).zip(image_opaque_binds_vk.iter())
+ {
+ *image_opaque_bind_infos_vk = ash::vk::SparseImageOpaqueMemoryBindInfo {
+ bind_count: image_opaque_binds_vk.len() as u32,
+ p_binds: image_opaque_binds_vk.as_ptr(),
+ ..*image_opaque_bind_infos_vk
+ };
+ }
+
+ for (image_bind_infos_vk, image_binds_vk) in
+ (image_bind_infos_vk.iter_mut()).zip(image_binds_vk.iter())
+ {
+ *image_bind_infos_vk = ash::vk::SparseImageMemoryBindInfo {
+ bind_count: image_binds_vk.len() as u32,
+ p_binds: image_binds_vk.as_ptr(),
+ ..*image_bind_infos_vk
+ };
+ }
+
+ *bind_info_vk = ash::vk::BindSparseInfo {
+ wait_semaphore_count: wait_semaphores_vk.len() as u32,
+ p_wait_semaphores: wait_semaphores_vk.as_ptr(),
+ buffer_bind_count: buffer_bind_infos_vk.len() as u32,
+ p_buffer_binds: buffer_bind_infos_vk.as_ptr(),
+ image_opaque_bind_count: image_opaque_bind_infos_vk.len() as u32,
+ p_image_opaque_binds: image_opaque_bind_infos_vk.as_ptr(),
+ image_bind_count: image_bind_infos_vk.len() as u32,
+ p_image_binds: image_bind_infos_vk.as_ptr(),
+ signal_semaphore_count: signal_semaphores_vk.len() as u32,
+ p_signal_semaphores: signal_semaphores_vk.as_ptr(),
+ ..*bind_info_vk
+ }
+ }
+
+ let fns = self.queue.device.fns();
+ (fns.v1_0.queue_bind_sparse)(
+ self.queue.handle,
+ bind_infos_vk.len() as u32,
+ bind_infos_vk.as_ptr(),
+ fence
+ .as_ref()
+ .map_or_else(Default::default, |(fence, _)| fence.handle()),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+
+ for bind_info in bind_infos {
+ let BindSparseInfo {
+ wait_semaphores,
+ buffer_binds: _,
+ image_opaque_binds: _,
+ image_binds: _,
+ signal_semaphores,
+ _ne: _,
+ } = bind_info;
+
+ for semaphore in wait_semaphores {
+ let state = states.semaphores.get_mut(&semaphore.handle()).unwrap();
+ state.add_queue_wait(self.queue);
+ }
+
+ for semaphore in signal_semaphores {
+ let state = states.semaphores.get_mut(&semaphore.handle()).unwrap();
+ state.add_queue_wait(self.queue);
+ }
+ }
+
+ let fence = fence.map(|(fence, mut state)| {
+ state.add_queue_signal(self.queue);
+ fence.clone()
+ });
+
+ self.state
+ .operations
+ .push_back((bind_infos.clone().into(), fence));
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ #[inline]
+ pub unsafe fn present_unchecked(
+ &mut self,
+ present_info: PresentInfo,
+ ) -> Result<impl ExactSizeIterator<Item = Result<bool, VulkanError>>, VulkanError> {
+ let mut states = States::from_present_info(&present_info);
+ self.present_unchecked_locked(&present_info, &mut states)
+ }
+
+ unsafe fn present_unchecked_locked(
+ &mut self,
+ present_info: &PresentInfo,
+ states: &mut States<'_>,
+ ) -> Result<impl ExactSizeIterator<Item = Result<bool, VulkanError>>, VulkanError> {
+ let PresentInfo {
+ ref wait_semaphores,
+ ref swapchain_infos,
+ _ne: _,
+ } = present_info;
+
+ let wait_semaphores_vk: SmallVec<[_; 4]> = wait_semaphores
+ .iter()
+ .map(|semaphore| semaphore.handle())
+ .collect();
+
+ let mut swapchains_vk: SmallVec<[_; 4]> = SmallVec::with_capacity(swapchain_infos.len());
+ let mut image_indices_vk: SmallVec<[_; 4]> = SmallVec::with_capacity(swapchain_infos.len());
+ let mut present_ids_vk: SmallVec<[_; 4]> = SmallVec::with_capacity(swapchain_infos.len());
+ let mut present_regions_vk: SmallVec<[_; 4]> =
+ SmallVec::with_capacity(swapchain_infos.len());
+ let mut rectangles_vk: SmallVec<[_; 4]> = SmallVec::with_capacity(swapchain_infos.len());
+
+ let mut has_present_ids = false;
+ let mut has_present_regions = false;
+
+ for swapchain_info in swapchain_infos {
+ let &SwapchainPresentInfo {
+ ref swapchain,
+ image_index,
+ present_id,
+ ref present_regions,
+ _ne: _,
+ } = swapchain_info;
+
+ swapchains_vk.push(swapchain.handle());
+ image_indices_vk.push(image_index);
+ present_ids_vk.push(present_id.map_or(0, u64::from));
+ present_regions_vk.push(ash::vk::PresentRegionKHR::default());
+ rectangles_vk.push(
+ present_regions
+ .iter()
+ .map(ash::vk::RectLayerKHR::from)
+ .collect::<SmallVec<[_; 4]>>(),
+ );
+
+ if present_id.is_some() {
+ has_present_ids = true;
+ }
+
+ if !present_regions.is_empty() {
+ has_present_regions = true;
+ }
+ }
+
+ let mut results = vec![ash::vk::Result::SUCCESS; swapchain_infos.len()];
+ let mut info_vk = ash::vk::PresentInfoKHR {
+ wait_semaphore_count: wait_semaphores_vk.len() as u32,
+ p_wait_semaphores: wait_semaphores_vk.as_ptr(),
+ swapchain_count: swapchains_vk.len() as u32,
+ p_swapchains: swapchains_vk.as_ptr(),
+ p_image_indices: image_indices_vk.as_ptr(),
+ p_results: results.as_mut_ptr(),
+ ..Default::default()
+ };
+ let mut present_id_info_vk = None;
+ let mut present_region_info_vk = None;
+
+ if has_present_ids {
+ let next = present_id_info_vk.insert(ash::vk::PresentIdKHR {
+ swapchain_count: present_ids_vk.len() as u32,
+ p_present_ids: present_ids_vk.as_ptr(),
+ ..Default::default()
+ });
+
+ next.p_next = info_vk.p_next;
+ info_vk.p_next = next as *const _ as *const _;
+ }
+
+ if has_present_regions {
+ for (present_regions_vk, rectangles_vk) in
+ (present_regions_vk.iter_mut()).zip(rectangles_vk.iter())
+ {
+ *present_regions_vk = ash::vk::PresentRegionKHR {
+ rectangle_count: rectangles_vk.len() as u32,
+ p_rectangles: rectangles_vk.as_ptr(),
+ };
+ }
+
+ let next = present_region_info_vk.insert(ash::vk::PresentRegionsKHR {
+ swapchain_count: present_regions_vk.len() as u32,
+ p_regions: present_regions_vk.as_ptr(),
+ ..Default::default()
+ });
+
+ next.p_next = info_vk.p_next;
+ info_vk.p_next = next as *const _ as *const _;
+ }
+
+ let fns = self.queue.device().fns();
+ let result = (fns.khr_swapchain.queue_present_khr)(self.queue.handle, &info_vk);
+
+ // Per the documentation of `vkQueuePresentKHR`, certain results indicate that the whole
+ // operation has failed, while others only indicate failure of a particular present.
+ // If we got a result that is not one of these per-present ones, we return it directly.
+ // Otherwise, we consider the present to be enqueued.
+ if !matches!(
+ result,
+ ash::vk::Result::SUCCESS
+ | ash::vk::Result::SUBOPTIMAL_KHR
+ | ash::vk::Result::ERROR_OUT_OF_DATE_KHR
+ | ash::vk::Result::ERROR_SURFACE_LOST_KHR
+ | ash::vk::Result::ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT,
+ ) {
+ return Err(VulkanError::from(result));
+ }
+
+ for semaphore in wait_semaphores {
+ let state = states.semaphores.get_mut(&semaphore.handle()).unwrap();
+ state.add_queue_wait(self.queue);
+ }
+
+ self.state
+ .operations
+ .push_back((present_info.clone().into(), None));
+
+ // If a presentation results in a loss of full-screen exclusive mode,
+ // signal that to the relevant swapchain.
+ for (&result, swapchain_info) in results.iter().zip(&present_info.swapchain_infos) {
+ if result == ash::vk::Result::ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT {
+ swapchain_info
+ .swapchain
+ .full_screen_exclusive_held()
+ .store(false, Ordering::SeqCst);
+ }
+ }
+
+ Ok(results.into_iter().map(|result| match result {
+ ash::vk::Result::SUCCESS => Ok(false),
+ ash::vk::Result::SUBOPTIMAL_KHR => Ok(true),
+ err => Err(VulkanError::from(err)),
+ }))
+ }
+
+ // Temporary function to keep futures working.
+ pub(crate) unsafe fn submit_with_future(
+ &mut self,
+ submit_info: SubmitInfo,
+ fence: Option<Arc<Fence>>,
+ future: &dyn GpuFuture,
+ queue: &Queue,
+ ) -> Result<(), FlushError> {
+ let submit_infos: SmallVec<[_; 4]> = smallvec![submit_info];
+ let mut states = States::from_submit_infos(&submit_infos);
+
+ for submit_info in &submit_infos {
+ for command_buffer in &submit_info.command_buffers {
+ let state = states
+ .command_buffers
+ .get(&command_buffer.handle())
+ .unwrap();
+
+ match command_buffer.usage() {
+ CommandBufferUsage::OneTimeSubmit => {
+ // VUID-vkQueueSubmit2-commandBuffer-03874
+ if state.has_been_submitted() {
+ return Err(FlushError::OneTimeSubmitAlreadySubmitted);
+ }
+ }
+ CommandBufferUsage::MultipleSubmit => {
+ // VUID-vkQueueSubmit2-commandBuffer-03875
+ if state.is_submit_pending() {
+ return Err(FlushError::ExclusiveAlreadyInUse);
+ }
+ }
+ CommandBufferUsage::SimultaneousUse => (),
+ }
+
+ let CommandBufferResourcesUsage {
+ buffers,
+ images,
+ buffer_indices: _,
+ image_indices: _,
+ } = command_buffer.resources_usage();
+
+ for usage in buffers {
+ let state = states.buffers.get_mut(&usage.buffer.handle()).unwrap();
+
+ for (range, range_usage) in usage.ranges.iter() {
+ match future.check_buffer_access(
+ &usage.buffer,
+ range.clone(),
+ range_usage.mutable,
+ queue,
+ ) {
+ Err(AccessCheckError::Denied(error)) => {
+ return Err(FlushError::ResourceAccessError {
+ error,
+ use_ref: range_usage.first_use,
+ });
+ }
+ Err(AccessCheckError::Unknown) => {
+ let result = if range_usage.mutable {
+ state.check_gpu_write(range.clone())
+ } else {
+ state.check_gpu_read(range.clone())
+ };
+
+ if let Err(error) = result {
+ return Err(FlushError::ResourceAccessError {
+ error,
+ use_ref: range_usage.first_use,
+ });
+ }
+ }
+ _ => (),
+ }
+ }
+ }
+
+ for usage in images {
+ let state = states.images.get_mut(&usage.image.handle()).unwrap();
+
+ for (range, range_usage) in usage.ranges.iter() {
+ match future.check_image_access(
+ &usage.image,
+ range.clone(),
+ range_usage.mutable,
+ range_usage.expected_layout,
+ queue,
+ ) {
+ Err(AccessCheckError::Denied(error)) => {
+ return Err(FlushError::ResourceAccessError {
+ error,
+ use_ref: range_usage.first_use,
+ });
+ }
+ Err(AccessCheckError::Unknown) => {
+ let result = if range_usage.mutable {
+ state
+ .check_gpu_write(range.clone(), range_usage.expected_layout)
+ } else {
+ state.check_gpu_read(range.clone(), range_usage.expected_layout)
+ };
+
+ if let Err(error) = result {
+ return Err(FlushError::ResourceAccessError {
+ error,
+ use_ref: range_usage.first_use,
+ });
+ }
+ }
+ _ => (),
+ };
+ }
+ }
+ }
+ }
+
+ Ok(self.submit_unchecked_locked(
+ &submit_infos,
+ fence.as_ref().map(|fence| {
+ let state = fence.state();
+ (fence, state)
+ }),
+ &mut states,
+ )?)
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn submit_unchecked(
+ &mut self,
+ submit_infos: impl IntoIterator<Item = SubmitInfo>,
+ fence: Option<Arc<Fence>>,
+ ) -> Result<(), VulkanError> {
+ let submit_infos: SmallVec<[_; 4]> = submit_infos.into_iter().collect();
+ let mut states = States::from_submit_infos(&submit_infos);
+
+ self.submit_unchecked_locked(
+ &submit_infos,
+ fence.as_ref().map(|fence| {
+ let state = fence.state();
+ (fence, state)
+ }),
+ &mut states,
+ )
+ }
+
+ unsafe fn submit_unchecked_locked(
+ &mut self,
+ submit_infos: &SmallVec<[SubmitInfo; 4]>,
+ fence: Option<(&Arc<Fence>, MutexGuard<'_, FenceState>)>,
+ states: &mut States<'_>,
+ ) -> Result<(), VulkanError> {
+ if self.queue.device.enabled_features().synchronization2 {
+ struct PerSubmitInfo {
+ wait_semaphore_infos_vk: SmallVec<[ash::vk::SemaphoreSubmitInfo; 4]>,
+ command_buffer_infos_vk: SmallVec<[ash::vk::CommandBufferSubmitInfo; 4]>,
+ signal_semaphore_infos_vk: SmallVec<[ash::vk::SemaphoreSubmitInfo; 4]>,
+ }
+
+ let (mut submit_info_vk, per_submit_vk): (SmallVec<[_; 4]>, SmallVec<[_; 4]>) =
+ submit_infos
+ .iter()
+ .map(|submit_info| {
+ let &SubmitInfo {
+ ref wait_semaphores,
+ ref command_buffers,
+ ref signal_semaphores,
+ _ne: _,
+ } = submit_info;
+
+ let wait_semaphore_infos_vk = wait_semaphores
+ .iter()
+ .map(|semaphore_submit_info| {
+ let &SemaphoreSubmitInfo {
+ ref semaphore,
+ stages,
+ _ne: _,
+ } = semaphore_submit_info;
+
+ ash::vk::SemaphoreSubmitInfo {
+ semaphore: semaphore.handle(),
+ value: 0, // TODO:
+ stage_mask: stages.into(),
+ device_index: 0, // TODO:
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let command_buffer_infos_vk = command_buffers
+ .iter()
+ .map(|cb| ash::vk::CommandBufferSubmitInfo {
+ command_buffer: cb.handle(),
+ device_mask: 0, // TODO:
+ ..Default::default()
+ })
+ .collect();
+
+ let signal_semaphore_infos_vk = signal_semaphores
+ .iter()
+ .map(|semaphore_submit_info| {
+ let &SemaphoreSubmitInfo {
+ ref semaphore,
+ stages,
+ _ne: _,
+ } = semaphore_submit_info;
+
+ ash::vk::SemaphoreSubmitInfo {
+ semaphore: semaphore.handle(),
+ value: 0, // TODO:
+ stage_mask: stages.into(),
+ device_index: 0, // TODO:
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ (
+ ash::vk::SubmitInfo2 {
+ flags: ash::vk::SubmitFlags::empty(), // TODO:
+ wait_semaphore_info_count: 0,
+ p_wait_semaphore_infos: ptr::null(),
+ command_buffer_info_count: 0,
+ p_command_buffer_infos: ptr::null(),
+ signal_semaphore_info_count: 0,
+ p_signal_semaphore_infos: ptr::null(),
+ ..Default::default()
+ },
+ PerSubmitInfo {
+ wait_semaphore_infos_vk,
+ command_buffer_infos_vk,
+ signal_semaphore_infos_vk,
+ },
+ )
+ })
+ .unzip();
+
+ for (
+ submit_info_vk,
+ PerSubmitInfo {
+ wait_semaphore_infos_vk,
+ command_buffer_infos_vk,
+ signal_semaphore_infos_vk,
+ },
+ ) in (submit_info_vk.iter_mut()).zip(per_submit_vk.iter())
+ {
+ *submit_info_vk = ash::vk::SubmitInfo2 {
+ wait_semaphore_info_count: wait_semaphore_infos_vk.len() as u32,
+ p_wait_semaphore_infos: wait_semaphore_infos_vk.as_ptr(),
+ command_buffer_info_count: command_buffer_infos_vk.len() as u32,
+ p_command_buffer_infos: command_buffer_infos_vk.as_ptr(),
+ signal_semaphore_info_count: signal_semaphore_infos_vk.len() as u32,
+ p_signal_semaphore_infos: signal_semaphore_infos_vk.as_ptr(),
+ ..*submit_info_vk
+ };
+ }
+
+ let fns = self.queue.device.fns();
+
+ if self.queue.device.api_version() >= Version::V1_3 {
+ (fns.v1_3.queue_submit2)(
+ self.queue.handle,
+ submit_info_vk.len() as u32,
+ submit_info_vk.as_ptr(),
+ fence
+ .as_ref()
+ .map_or_else(Default::default, |(fence, _)| fence.handle()),
+ )
+ } else {
+ debug_assert!(self.queue.device.enabled_extensions().khr_synchronization2);
+ (fns.khr_synchronization2.queue_submit2_khr)(
+ self.queue.handle,
+ submit_info_vk.len() as u32,
+ submit_info_vk.as_ptr(),
+ fence
+ .as_ref()
+ .map_or_else(Default::default, |(fence, _)| fence.handle()),
+ )
+ }
+ .result()
+ .map_err(VulkanError::from)?;
+ } else {
+ struct PerSubmitInfo {
+ wait_semaphores_vk: SmallVec<[ash::vk::Semaphore; 4]>,
+ wait_dst_stage_mask_vk: SmallVec<[ash::vk::PipelineStageFlags; 4]>,
+ command_buffers_vk: SmallVec<[ash::vk::CommandBuffer; 4]>,
+ signal_semaphores_vk: SmallVec<[ash::vk::Semaphore; 4]>,
+ }
+
+ let (mut submit_info_vk, per_submit_vk): (SmallVec<[_; 4]>, SmallVec<[_; 4]>) =
+ submit_infos
+ .iter()
+ .map(|submit_info| {
+ let &SubmitInfo {
+ ref wait_semaphores,
+ ref command_buffers,
+ ref signal_semaphores,
+ _ne: _,
+ } = submit_info;
+
+ let (wait_semaphores_vk, wait_dst_stage_mask_vk) = wait_semaphores
+ .iter()
+ .map(|semaphore_submit_info| {
+ let &SemaphoreSubmitInfo {
+ ref semaphore,
+ stages,
+ _ne: _,
+ } = semaphore_submit_info;
+
+ (semaphore.handle(), stages.into())
+ })
+ .unzip();
+
+ let command_buffers_vk =
+ command_buffers.iter().map(|cb| cb.handle()).collect();
+
+ let signal_semaphores_vk = signal_semaphores
+ .iter()
+ .map(|semaphore_submit_info| {
+ let &SemaphoreSubmitInfo {
+ ref semaphore,
+ stages: _,
+ _ne: _,
+ } = semaphore_submit_info;
+
+ semaphore.handle()
+ })
+ .collect();
+
+ (
+ ash::vk::SubmitInfo {
+ wait_semaphore_count: 0,
+ p_wait_semaphores: ptr::null(),
+ p_wait_dst_stage_mask: ptr::null(),
+ command_buffer_count: 0,
+ p_command_buffers: ptr::null(),
+ signal_semaphore_count: 0,
+ p_signal_semaphores: ptr::null(),
+ ..Default::default()
+ },
+ PerSubmitInfo {
+ wait_semaphores_vk,
+ wait_dst_stage_mask_vk,
+ command_buffers_vk,
+ signal_semaphores_vk,
+ },
+ )
+ })
+ .unzip();
+
+ for (
+ submit_info_vk,
+ PerSubmitInfo {
+ wait_semaphores_vk,
+ wait_dst_stage_mask_vk,
+ command_buffers_vk,
+ signal_semaphores_vk,
+ },
+ ) in (submit_info_vk.iter_mut()).zip(per_submit_vk.iter())
+ {
+ *submit_info_vk = ash::vk::SubmitInfo {
+ wait_semaphore_count: wait_semaphores_vk.len() as u32,
+ p_wait_semaphores: wait_semaphores_vk.as_ptr(),
+ p_wait_dst_stage_mask: wait_dst_stage_mask_vk.as_ptr(),
+ command_buffer_count: command_buffers_vk.len() as u32,
+ p_command_buffers: command_buffers_vk.as_ptr(),
+ signal_semaphore_count: signal_semaphores_vk.len() as u32,
+ p_signal_semaphores: signal_semaphores_vk.as_ptr(),
+ ..*submit_info_vk
+ };
+ }
+
+ let fns = self.queue.device.fns();
+ (fns.v1_0.queue_submit)(
+ self.queue.handle,
+ submit_info_vk.len() as u32,
+ submit_info_vk.as_ptr(),
+ fence
+ .as_ref()
+ .map_or_else(Default::default, |(fence, _)| fence.handle()),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+ }
+
+ for submit_info in submit_infos {
+ let SubmitInfo {
+ wait_semaphores,
+ command_buffers,
+ signal_semaphores,
+ _ne: _,
+ } = submit_info;
+
+ for semaphore_submit_info in wait_semaphores {
+ let state = states
+ .semaphores
+ .get_mut(&semaphore_submit_info.semaphore.handle())
+ .unwrap();
+ state.add_queue_wait(self.queue);
+ }
+
+ for command_buffer in command_buffers {
+ let state = states
+ .command_buffers
+ .get_mut(&command_buffer.handle())
+ .unwrap();
+ state.add_queue_submit();
+
+ let CommandBufferResourcesUsage {
+ buffers,
+ images,
+ buffer_indices: _,
+ image_indices: _,
+ } = command_buffer.resources_usage();
+
+ for usage in buffers {
+ let state = states.buffers.get_mut(&usage.buffer.handle()).unwrap();
+
+ for (range, range_usage) in usage.ranges.iter() {
+ if range_usage.mutable {
+ state.gpu_write_lock(range.clone());
+ } else {
+ state.gpu_read_lock(range.clone());
+ }
+ }
+ }
+
+ for usage in images {
+ let state = states.images.get_mut(&usage.image.handle()).unwrap();
+
+ for (range, range_usage) in usage.ranges.iter() {
+ if range_usage.mutable {
+ state.gpu_write_lock(range.clone(), range_usage.final_layout);
+ } else {
+ state.gpu_read_lock(range.clone());
+ }
+ }
+ }
+ }
+
+ for semaphore_submit_info in signal_semaphores {
+ let state = states
+ .semaphores
+ .get_mut(&semaphore_submit_info.semaphore.handle())
+ .unwrap();
+ state.add_queue_signal(self.queue);
+ }
+ }
+
+ let fence = fence.map(|(fence, mut state)| {
+ state.add_queue_signal(self.queue);
+ fence.clone()
+ });
+
+ self.state
+ .operations
+ .push_back((submit_infos.clone().into(), fence));
+
+ Ok(())
+ }
+
+ /// Opens a queue debug label region.
+ ///
+ /// The [`ext_debug_utils`] extension must be enabled on the instance.
+ ///
+ /// [`ext_debug_utils`]: crate::instance::InstanceExtensions::ext_debug_utils
+ #[inline]
+ pub fn begin_debug_utils_label(
+ &mut self,
+ label_info: DebugUtilsLabel,
+ ) -> Result<(), QueueError> {
+ self.validate_begin_debug_utils_label(&label_info)?;
+
+ unsafe {
+ self.begin_debug_utils_label_unchecked(label_info);
+ Ok(())
+ }
+ }
+
+ fn validate_begin_debug_utils_label(
+ &self,
+ _label_info: &DebugUtilsLabel,
+ ) -> Result<(), QueueError> {
+ if !self
+ .queue
+ .device
+ .instance()
+ .enabled_extensions()
+ .ext_debug_utils
+ {
+ return Err(QueueError::RequirementNotMet {
+ required_for: "`QueueGuard::begin_debug_utils_label`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["ext_debug_utils"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ #[inline]
+ pub unsafe fn begin_debug_utils_label_unchecked(&mut self, label_info: DebugUtilsLabel) {
+ let DebugUtilsLabel {
+ label_name,
+ color,
+ _ne: _,
+ } = label_info;
+
+ let label_name_vk = CString::new(label_name.as_str()).unwrap();
+ let label_info = ash::vk::DebugUtilsLabelEXT {
+ p_label_name: label_name_vk.as_ptr(),
+ color,
+ ..Default::default()
+ };
+
+ let fns = self.queue.device.instance().fns();
+ (fns.ext_debug_utils.queue_begin_debug_utils_label_ext)(self.queue.handle, &label_info);
+ }
+
+ /// Closes a queue debug label region.
+ ///
+ /// The [`ext_debug_utils`](crate::instance::InstanceExtensions::ext_debug_utils) must be
+ /// enabled on the instance.
+ ///
+ /// # Safety
+ ///
+ /// - There must be an outstanding queue label region begun with `begin_debug_utils_label` in
+ /// the queue.
+ #[inline]
+ pub unsafe fn end_debug_utils_label(&mut self) -> Result<(), QueueError> {
+ self.validate_end_debug_utils_label()?;
+ self.end_debug_utils_label_unchecked();
+
+ Ok(())
+ }
+
+ fn validate_end_debug_utils_label(&self) -> Result<(), QueueError> {
+ if !self
+ .queue
+ .device
+ .instance()
+ .enabled_extensions()
+ .ext_debug_utils
+ {
+ return Err(QueueError::RequirementNotMet {
+ required_for: "`QueueGuard::end_debug_utils_label`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["ext_debug_utils"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkQueueEndDebugUtilsLabelEXT-None-01911
+ // TODO: not checked, so unsafe for now
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ #[inline]
+ pub unsafe fn end_debug_utils_label_unchecked(&mut self) {
+ let fns = self.queue.device.instance().fns();
+ (fns.ext_debug_utils.queue_end_debug_utils_label_ext)(self.queue.handle);
+ }
+
+ /// Inserts a queue debug label.
+ ///
+ /// The [`ext_debug_utils`](crate::instance::InstanceExtensions::ext_debug_utils) must be
+ /// enabled on the instance.
+ #[inline]
+ pub fn insert_debug_utils_label(
+ &mut self,
+ label_info: DebugUtilsLabel,
+ ) -> Result<(), QueueError> {
+ self.validate_insert_debug_utils_label(&label_info)?;
+
+ unsafe {
+ self.insert_debug_utils_label_unchecked(label_info);
+ Ok(())
+ }
+ }
+
+ fn validate_insert_debug_utils_label(
+ &self,
+ _label_info: &DebugUtilsLabel,
+ ) -> Result<(), QueueError> {
+ if !self
+ .queue
+ .device
+ .instance()
+ .enabled_extensions()
+ .ext_debug_utils
+ {
+ return Err(QueueError::RequirementNotMet {
+ required_for: "`QueueGuard::insert_debug_utils_label`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["ext_debug_utils"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ #[inline]
+ pub unsafe fn insert_debug_utils_label_unchecked(&mut self, label_info: DebugUtilsLabel) {
+ let DebugUtilsLabel {
+ label_name,
+ color,
+ _ne: _,
+ } = label_info;
+
+ let label_name_vk = CString::new(label_name.as_str()).unwrap();
+ let label_info = ash::vk::DebugUtilsLabelEXT {
+ p_label_name: label_name_vk.as_ptr(),
+ color,
+ ..Default::default()
+ };
+
+ let fns = self.queue.device.instance().fns();
+ (fns.ext_debug_utils.queue_insert_debug_utils_label_ext)(self.queue.handle, &label_info);
+ }
+}
+
+#[derive(Debug, Default)]
+struct QueueState {
+ operations: VecDeque<(QueueOperation, Option<Arc<Fence>>)>,
+}
+
+impl QueueState {
+ fn wait_idle(&mut self, device: &Device, handle: ash::vk::Queue) -> Result<(), OomError> {
+ unsafe {
+ let fns = device.fns();
+ (fns.v1_0.queue_wait_idle)(handle)
+ .result()
+ .map_err(VulkanError::from)?;
+
+ // Since we now know that the queue is finished with all work,
+ // we can safely release all resources.
+ for (operation, _) in take(&mut self.operations) {
+ operation.set_finished();
+ }
+
+ Ok(())
+ }
+ }
+
+ /// Called by `fence` when it finds that it is signaled.
+ fn fence_signaled(&mut self, fence: &Fence) {
+ // Find the most recent operation that uses `fence`.
+ let fence_index = self
+ .operations
+ .iter()
+ .enumerate()
+ .rev()
+ .find_map(|(index, (_, f))| {
+ f.as_ref().map_or(false, |f| **f == *fence).then_some(index)
+ });
+
+ if let Some(index) = fence_index {
+ // Remove all operations up to this index, and perform cleanup if needed.
+ for (operation, fence) in self.operations.drain(..index + 1) {
+ unsafe {
+ operation.set_finished();
+
+ if let Some(fence) = fence {
+ fence.state().set_signal_finished();
+ }
+ }
+ }
+ }
+ }
+}
+
+#[derive(Debug)]
+enum QueueOperation {
+ BindSparse(SmallVec<[BindSparseInfo; 4]>),
+ Present(PresentInfo),
+ Submit(SmallVec<[SubmitInfo; 4]>),
+}
+
+impl QueueOperation {
+ unsafe fn set_finished(self) {
+ match self {
+ QueueOperation::BindSparse(bind_infos) => {
+ for bind_info in bind_infos {
+ for semaphore in bind_info.wait_semaphores {
+ semaphore.state().set_wait_finished();
+ }
+
+ for semaphore in bind_info.signal_semaphores {
+ semaphore.state().set_signal_finished();
+ }
+ }
+
+ // TODO: Do we need to unlock buffers and images here?
+ }
+ QueueOperation::Present(present_info) => {
+ for semaphore in present_info.wait_semaphores {
+ semaphore.state().set_wait_finished();
+ }
+ }
+ QueueOperation::Submit(submit_infos) => {
+ for submit_info in submit_infos {
+ for semaphore_submit_info in submit_info.wait_semaphores {
+ semaphore_submit_info.semaphore.state().set_wait_finished();
+ }
+
+ for semaphore_submit_info in submit_info.signal_semaphores {
+ semaphore_submit_info
+ .semaphore
+ .state()
+ .set_signal_finished();
+ }
+
+ for command_buffer in submit_info.command_buffers {
+ let resource_usage = command_buffer.resources_usage();
+
+ for usage in &resource_usage.buffers {
+ let mut state = usage.buffer.state();
+
+ for (range, range_usage) in usage.ranges.iter() {
+ if range_usage.mutable {
+ state.gpu_write_unlock(range.clone());
+ } else {
+ state.gpu_read_unlock(range.clone());
+ }
+ }
+ }
+
+ for usage in &resource_usage.images {
+ let mut state = usage.image.state();
+
+ for (range, range_usage) in usage.ranges.iter() {
+ if range_usage.mutable {
+ state.gpu_write_unlock(range.clone());
+ } else {
+ state.gpu_read_unlock(range.clone());
+ }
+ }
+ }
+
+ command_buffer.state().set_submit_finished();
+ }
+ }
+ }
+ }
+ }
+}
+
+impl From<SmallVec<[BindSparseInfo; 4]>> for QueueOperation {
+ #[inline]
+ fn from(val: SmallVec<[BindSparseInfo; 4]>) -> Self {
+ Self::BindSparse(val)
+ }
+}
+
+impl From<PresentInfo> for QueueOperation {
+ #[inline]
+ fn from(val: PresentInfo) -> Self {
+ Self::Present(val)
+ }
+}
+
+impl From<SmallVec<[SubmitInfo; 4]>> for QueueOperation {
+ #[inline]
+ fn from(val: SmallVec<[SubmitInfo; 4]>) -> Self {
+ Self::Submit(val)
+ }
+}
+
+// This struct exists to ensure that every object gets locked exactly once.
+// Otherwise we get deadlocks.
+#[derive(Debug)]
+struct States<'a> {
+ buffers: HashMap<ash::vk::Buffer, MutexGuard<'a, BufferState>>,
+ command_buffers: HashMap<ash::vk::CommandBuffer, MutexGuard<'a, CommandBufferState>>,
+ images: HashMap<ash::vk::Image, MutexGuard<'a, ImageState>>,
+ semaphores: HashMap<ash::vk::Semaphore, MutexGuard<'a, SemaphoreState>>,
+}
+
+impl<'a> States<'a> {
+ fn from_bind_infos(bind_infos: &'a [BindSparseInfo]) -> Self {
+ let mut buffers = HashMap::default();
+ let mut images = HashMap::default();
+ let mut semaphores = HashMap::default();
+
+ for bind_info in bind_infos {
+ let BindSparseInfo {
+ wait_semaphores,
+ buffer_binds,
+ image_opaque_binds,
+ image_binds,
+ signal_semaphores,
+ _ne: _,
+ } = bind_info;
+
+ for semaphore in wait_semaphores {
+ semaphores
+ .entry(semaphore.handle())
+ .or_insert_with(|| semaphore.state());
+ }
+
+ for (buffer, _) in buffer_binds {
+ let buffer = buffer.buffer();
+ buffers
+ .entry(buffer.handle())
+ .or_insert_with(|| buffer.state());
+ }
+
+ for (image, _) in image_opaque_binds {
+ let image = &image.inner().image;
+ images
+ .entry(image.handle())
+ .or_insert_with(|| image.state());
+ }
+
+ for (image, _) in image_binds {
+ let image = &image.inner().image;
+ images
+ .entry(image.handle())
+ .or_insert_with(|| image.state());
+ }
+
+ for semaphore in signal_semaphores {
+ semaphores
+ .entry(semaphore.handle())
+ .or_insert_with(|| semaphore.state());
+ }
+ }
+
+ Self {
+ buffers,
+ command_buffers: HashMap::default(),
+ images,
+ semaphores,
+ }
+ }
+
+ fn from_present_info(present_info: &'a PresentInfo) -> Self {
+ let mut semaphores = HashMap::default();
+
+ let PresentInfo {
+ wait_semaphores,
+ swapchain_infos: _,
+ _ne: _,
+ } = present_info;
+
+ for semaphore in wait_semaphores {
+ semaphores
+ .entry(semaphore.handle())
+ .or_insert_with(|| semaphore.state());
+ }
+
+ Self {
+ buffers: HashMap::default(),
+ command_buffers: HashMap::default(),
+ images: HashMap::default(),
+ semaphores,
+ }
+ }
+
+ fn from_submit_infos(submit_infos: &'a [SubmitInfo]) -> Self {
+ let mut buffers = HashMap::default();
+ let mut command_buffers = HashMap::default();
+ let mut images = HashMap::default();
+ let mut semaphores = HashMap::default();
+
+ for submit_info in submit_infos {
+ let SubmitInfo {
+ wait_semaphores,
+ command_buffers: info_command_buffers,
+ signal_semaphores,
+ _ne: _,
+ } = submit_info;
+
+ for semaphore_submit_info in wait_semaphores {
+ let semaphore = &semaphore_submit_info.semaphore;
+ semaphores
+ .entry(semaphore.handle())
+ .or_insert_with(|| semaphore.state());
+ }
+
+ for command_buffer in info_command_buffers {
+ command_buffers
+ .entry(command_buffer.handle())
+ .or_insert_with(|| command_buffer.state());
+
+ let CommandBufferResourcesUsage {
+ buffers: buffers_usage,
+ images: images_usage,
+ buffer_indices: _,
+ image_indices: _,
+ } = command_buffer.resources_usage();
+
+ for usage in buffers_usage {
+ let buffer = &usage.buffer;
+ buffers
+ .entry(buffer.handle())
+ .or_insert_with(|| buffer.state());
+ }
+
+ for usage in images_usage {
+ let image = &usage.image;
+ images
+ .entry(image.handle())
+ .or_insert_with(|| image.state());
+ }
+ }
+
+ for semaphore_submit_info in signal_semaphores {
+ let semaphore = &semaphore_submit_info.semaphore;
+ semaphores
+ .entry(semaphore.handle())
+ .or_insert_with(|| semaphore.state());
+ }
+ }
+
+ Self {
+ buffers,
+ command_buffers,
+ images,
+ semaphores,
+ }
+ }
+}
+
+/// Properties of a queue family in a physical device.
+#[derive(Clone, Debug)]
+#[non_exhaustive]
+pub struct QueueFamilyProperties {
+ /// Attributes of the queue family.
+ pub queue_flags: QueueFlags,
+
+ /// The number of queues available in this family.
+ ///
+ /// This guaranteed to be at least 1 (or else that family wouldn't exist).
+ pub queue_count: u32,
+
+ /// If timestamps are supported, the number of bits supported by timestamp operations.
+ /// The returned value will be in the range 36..64.
+ ///
+ /// If timestamps are not supported, this is `None`.
+ pub timestamp_valid_bits: Option<u32>,
+
+ /// The minimum granularity supported for image transfers, in terms of `[width, height, depth]`.
+ pub min_image_transfer_granularity: [u32; 3],
+}
+
+impl From<ash::vk::QueueFamilyProperties> for QueueFamilyProperties {
+ #[inline]
+ fn from(val: ash::vk::QueueFamilyProperties) -> Self {
+ Self {
+ queue_flags: val.queue_flags.into(),
+ queue_count: val.queue_count,
+ timestamp_valid_bits: (val.timestamp_valid_bits != 0)
+ .then_some(val.timestamp_valid_bits),
+ min_image_transfer_granularity: [
+ val.min_image_transfer_granularity.width,
+ val.min_image_transfer_granularity.height,
+ val.min_image_transfer_granularity.depth,
+ ],
+ }
+ }
+}
+
+vulkan_bitflags! {
+ #[non_exhaustive]
+
+ /// Attributes of a queue or queue family.
+ QueueFlags = QueueFlags(u32);
+
+ /// Queues of this family can execute graphics operations.
+ GRAPHICS = GRAPHICS,
+
+ /// Queues of this family can execute compute operations.
+ COMPUTE = COMPUTE,
+
+ /// Queues of this family can execute transfer operations.
+ TRANSFER = TRANSFER,
+
+ /// Queues of this family can execute sparse memory management operations.
+ SPARSE_BINDING = SPARSE_BINDING,
+
+ /// Queues of this family can be created using the `protected` flag.
+ PROTECTED = PROTECTED {
+ api_version: V1_1,
+ },
+
+ /// Queues of this family can execute video decode operations.
+ VIDEO_DECODE = VIDEO_DECODE_KHR {
+ device_extensions: [khr_video_decode_queue],
+ },
+
+ /// Queues of this family can execute video encode operations.
+ VIDEO_ENCODE = VIDEO_ENCODE_KHR {
+ device_extensions: [khr_video_encode_queue],
+ },
+
+ /// Queues of this family can execute optical flow operations.
+ OPTICAL_FLOW = OPTICAL_FLOW_NV {
+ device_extensions: [nv_optical_flow],
+ },
+}
+
+/// Error that can happen when submitting work to a queue.
+#[derive(Clone, Debug)]
+pub enum QueueError {
+ VulkanError(VulkanError),
+
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+}
+
+impl Error for QueueError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ QueueError::VulkanError(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+impl Display for QueueError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::VulkanError(_) => write!(f, "a runtime error occurred"),
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ }
+ }
+}
+
+impl From<VulkanError> for QueueError {
+ fn from(err: VulkanError) -> Self {
+ Self::VulkanError(err)
+ }
+}
+
+impl From<RequirementNotMet> for QueueError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::sync::fence::Fence;
+ use std::{sync::Arc, time::Duration};
+
+ #[test]
+ fn empty_submit() {
+ let (_device, queue) = gfx_dev_and_queue!();
+
+ queue
+ .with(|mut q| unsafe { q.submit_unchecked([Default::default()], None) })
+ .unwrap();
+ }
+
+ #[test]
+ fn signal_fence() {
+ unsafe {
+ let (device, queue) = gfx_dev_and_queue!();
+
+ let fence = Arc::new(Fence::new(device, Default::default()).unwrap());
+ assert!(!fence.is_signaled().unwrap());
+
+ queue
+ .with(|mut q| q.submit_unchecked([Default::default()], Some(fence.clone())))
+ .unwrap();
+
+ fence.wait(Some(Duration::from_secs(5))).unwrap();
+ assert!(fence.is_signaled().unwrap());
+ }
+ }
+}
diff --git a/src/extensions.rs b/src/extensions.rs
index 822eb67..1e09e8b 100644
--- a/src/extensions.rs
+++ b/src/extensions.rs
@@ -7,192 +7,33 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use crate::instance::loader::LoadingError;
-use crate::Error;
-use crate::OomError;
-use crate::Version;
-use std::error;
-use std::fmt;
-
-macro_rules! extensions {
- (
- $sname:ident,
- $($member:ident => {
- doc: $doc:expr,
- raw: $raw:expr,
- requires_core: $requires_core:expr,
- requires_device_extensions: [$($requires_device_extension:ident),*],
- requires_instance_extensions: [$($requires_instance_extension:ident),*]$(,)?
- },)*
- ) => (
- /// List of extensions that are enabled or available.
- #[derive(Copy, Clone, PartialEq, Eq)]
- pub struct $sname {
- $(
- #[doc = $doc]
- pub $member: bool,
- )*
-
- /// This field ensures that an instance of this `Extensions` struct
- /// can only be created through Vulkano functions and the update
- /// syntax. This way, extensions can be added to Vulkano without
- /// breaking existing code.
- pub _unbuildable: crate::extensions::Unbuildable,
- }
-
- impl $sname {
- /// Returns an `Extensions` object with all members set to `false`.
- #[inline]
- pub const fn none() -> $sname {
- $sname {
- $($member: false,)*
- _unbuildable: crate::extensions::Unbuildable(())
- }
- }
-
- /// Returns true if `self` is a superset of the parameter.
- ///
- /// That is, for each extension of the parameter that is true, the corresponding value
- /// in self is true as well.
- pub fn is_superset_of(&self, other: &$sname) -> bool {
- $((self.$member == true || other.$member == false))&&+
- }
-
- /// Returns the union of this list and another list.
- #[inline]
- pub const fn union(&self, other: &$sname) -> $sname {
- $sname {
- $(
- $member: self.$member || other.$member,
- )*
- _unbuildable: crate::extensions::Unbuildable(())
- }
- }
-
- /// Returns the intersection of this list and another list.
- #[inline]
- pub const fn intersection(&self, other: &$sname) -> $sname {
- $sname {
- $(
- $member: self.$member && other.$member,
- )*
- _unbuildable: crate::extensions::Unbuildable(())
- }
- }
-
- /// Returns the difference of another list from this list.
- #[inline]
- pub const fn difference(&self, other: &$sname) -> $sname {
- $sname {
- $(
- $member: self.$member && !other.$member,
- )*
- _unbuildable: crate::extensions::Unbuildable(())
- }
- }
- }
-
- impl std::fmt::Debug for $sname {
- #[allow(unused_assignments)]
- fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
- write!(f, "[")?;
-
- let mut first = true;
-
- $(
- if self.$member {
- if !first { write!(f, ", ")? }
- else { first = false; }
- f.write_str(std::str::from_utf8($raw).unwrap())?;
- }
- )*
-
- write!(f, "]")
- }
- }
-
- impl<'a, I> From<I> for $sname where I: IntoIterator<Item = &'a std::ffi::CStr> {
- fn from(names: I) -> Self {
- let mut extensions = Self::none();
- for name in names {
- match name.to_bytes() {
- $(
- $raw => { extensions.$member = true; }
- )*
- _ => (),
- }
- }
- extensions
- }
- }
-
- impl<'a> From<&'a $sname> for Vec<std::ffi::CString> {
- fn from(x: &'a $sname) -> Self {
- let mut data = Self::new();
- $(if x.$member { data.push(std::ffi::CString::new(&$raw[..]).unwrap()); })*
- data
- }
- }
- );
-}
-
-/// Error that can happen when loading the list of layers.
+use crate::RequiresOneOf;
+use bytemuck::cast_slice;
+use std::{
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+};
+
+/// Properties of an extension in the loader or a physical device.
#[derive(Clone, Debug)]
-pub enum SupportedExtensionsError {
- /// Failed to load the Vulkan shared library.
- LoadingError(LoadingError),
- /// Not enough memory.
- OomError(OomError),
-}
-
-impl error::Error for SupportedExtensionsError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- SupportedExtensionsError::LoadingError(ref err) => Some(err),
- SupportedExtensionsError::OomError(ref err) => Some(err),
- }
- }
-}
+pub struct ExtensionProperties {
+ /// The name of the extension.
+ pub extension_name: String,
-impl fmt::Display for SupportedExtensionsError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- SupportedExtensionsError::LoadingError(_) =>
- "failed to load the Vulkan shared library",
- SupportedExtensionsError::OomError(_) => "not enough memory available",
- }
- )
- }
+ /// The version of the extension.
+ pub spec_version: u32,
}
-impl From<OomError> for SupportedExtensionsError {
+impl From<ash::vk::ExtensionProperties> for ExtensionProperties {
#[inline]
- fn from(err: OomError) -> SupportedExtensionsError {
- SupportedExtensionsError::OomError(err)
- }
-}
-
-impl From<LoadingError> for SupportedExtensionsError {
- #[inline]
- fn from(err: LoadingError) -> SupportedExtensionsError {
- SupportedExtensionsError::LoadingError(err)
- }
-}
-
-impl From<Error> for SupportedExtensionsError {
- #[inline]
- fn from(err: Error) -> SupportedExtensionsError {
- match err {
- err @ Error::OutOfHostMemory => SupportedExtensionsError::OomError(OomError::from(err)),
- err @ Error::OutOfDeviceMemory => {
- SupportedExtensionsError::OomError(OomError::from(err))
- }
- _ => panic!("unexpected error: {:?}", err),
+ fn from(val: ash::vk::ExtensionProperties) -> Self {
+ Self {
+ extension_name: {
+ let bytes = cast_slice(val.extension_name.as_slice());
+ let end = bytes.iter().position(|&b| b == 0).unwrap_or(bytes.len());
+ String::from_utf8_lossy(&bytes[0..end]).into()
+ },
+ spec_version: val.spec_version,
}
}
}
@@ -206,13 +47,12 @@ pub struct ExtensionRestrictionError {
pub restriction: ExtensionRestriction,
}
-impl error::Error for ExtensionRestrictionError {}
+impl Error for ExtensionRestrictionError {}
-impl fmt::Display for ExtensionRestrictionError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+impl Display for ExtensionRestrictionError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
write!(
- fmt,
+ f,
"a restriction for the extension {} was not met: {}",
self.extension, self.restriction,
)
@@ -223,49 +63,33 @@ impl fmt::Display for ExtensionRestrictionError {
pub enum ExtensionRestriction {
/// Not supported by the loader or physical device.
NotSupported,
- /// Requires a minimum Vulkan API version.
- RequiresCore(Version),
- /// Requires a device extension to be enabled.
- RequiresDeviceExtension(&'static str),
- /// Requires an instance extension to be enabled.
- RequiresInstanceExtension(&'static str),
/// Required to be enabled by the physical device.
RequiredIfSupported,
+ /// Requires one of the following.
+ Requires(RequiresOneOf),
/// Requires a device extension to be disabled.
ConflictsDeviceExtension(&'static str),
}
-impl fmt::Display for ExtensionRestriction {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+impl Display for ExtensionRestriction {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
match *self {
ExtensionRestriction::NotSupported => {
- write!(fmt, "not supported by the loader or physical device")
- }
- ExtensionRestriction::RequiresCore(version) => {
- write!(
- fmt,
- "requires Vulkan API version {}.{}",
- version.major, version.minor
- )
- }
- ExtensionRestriction::RequiresDeviceExtension(ext) => {
- write!(fmt, "requires device extension {} to be enabled", ext)
- }
- ExtensionRestriction::RequiresInstanceExtension(ext) => {
- write!(fmt, "requires instance extension {} to be enabled", ext)
+ write!(f, "not supported by the loader or physical device")
}
ExtensionRestriction::RequiredIfSupported => {
- write!(fmt, "required to be enabled by the physical device")
+ write!(f, "required to be enabled by the physical device")
+ }
+ ExtensionRestriction::Requires(requires) => {
+ if requires.len() > 1 {
+ write!(f, "requires one of: {}", requires)
+ } else {
+ write!(f, "requires: {}", requires)
+ }
}
ExtensionRestriction::ConflictsDeviceExtension(ext) => {
- write!(fmt, "requires device extension {} to be disabled", ext)
+ write!(f, "requires device extension {} to be disabled", ext)
}
}
}
}
-
-/// This helper type can only be instantiated inside this module.
-#[doc(hidden)]
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct Unbuildable(pub(crate) ());
diff --git a/src/fns.rs b/src/fns.rs
index 88a8354..bae0ea8 100644
--- a/src/fns.rs
+++ b/src/fns.rs
@@ -7,27 +7,7 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-macro_rules! fns {
- ($struct_name:ident, { $($member:ident => $fn_struct:ident,)+ }) => {
- pub struct $struct_name {
- $(
- pub $member: ash::vk::$fn_struct,
- )+
- }
+use std::ffi::{c_void, CStr};
- impl $struct_name {
- pub fn load<F>(mut load_fn: F) -> $struct_name
- where F: FnMut(&std::ffi::CStr) -> *const std::ffi::c_void
- {
- $struct_name {
- $(
- $member: ash::vk::$fn_struct::load(&mut load_fn),
- )+
- }
- }
- }
- };
-}
-
-pub use crate::autogen::{DeviceFunctions, EntryFunctions, InstanceFunctions};
-pub(crate) use fns;
+// Generated by build.rs
+include!(concat!(env!("OUT_DIR"), "/fns.rs"));
diff --git a/src/format.rs b/src/format.rs
index 679eaf9..c86fd5e 100644
--- a/src/format.rs
+++ b/src/format.rs
@@ -7,679 +7,707 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-//! All the formats of images supported by Vulkan.
+//! All the formats supported by Vulkan.
//!
-//! # Formats
+//! A format is mostly used to describe the texel data of an image. However, formats also show up in
+//! a few other places, most notably to describe the format of vertex buffers.
//!
-//! List of suffixes:
+//! # Format support
//!
-//! - `Unorm` means that the values are unsigned integers that are converted into floating points.
-//! The maximum possible representable value becomes `1.0`, and the minimum representable value
-//! becomes `0.0`. For example the value `255` in a `R8Unorm` will be interpreted as `1.0`.
+//! Not all formats are supported by every device. Those that devices do support may only be
+//! supported for certain use cases. It is an error to use a format where it is not supported, but
+//! you can query a device beforehand for its support by calling `format_properties` on the physical
+//! device. You can use this to select a usable format from one or more suitable alternatives.
+//! Some formats are required to be always supported for a particular usage. These are listed in the
+//! [tables in the Vulkan specification](https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap43.html#features-required-format-support).
//!
-//! - `Snorm` is the same as `Unorm`, but the integers are signed and the range is from `-1.0` to
-//! `1.0` instead.
+//! # Special format types
//!
-//! - `Uscaled` means that the values are unsigned integers that are converted into floating points.
-//! No change in the value is done. For example the value `255` in a `R8Uscaled` will be
-//! interpreted as `255.0`.
+//! ## Depth/stencil formats
//!
-//! - `Sscaled` is the same as `Uscaled` expect that the integers are signed.
+//! Depth/stencil formats can be identified by the `D` and `S` components in their names. They are
+//! used primarily as the format for framebuffer attachments, for the purposes of depth and stencil
+//! testing.
//!
-//! - `Uint` means that the values are unsigned integers. No conversion is performed.
+//! Some formats have only a depth or stencil component, while others combine both. The two
+//! components are represented as separate *aspects*, which means that they can be accessed
+//! individually as separate images. These pseudo-images have the same resolution, but different
+//! bit depth and numeric representation.
//!
-//! - `Sint` means that the values are signed integers. No conversion is performed.
+//! Depth/stencil formats deviate from the others in a few more ways. Their data representation is
+//! considered opaque, meaning that they do not have a fixed layout in memory nor a fixed size per
+//! texel. They also have special limitations in several operations such as copying; a depth/stencil
+//! format is not compatible with any other format, only with itself.
//!
-//! - `Ufloat` means that the values are unsigned floating points. No conversion is performed. This
-//! format is very unusual.
+//! ## Block-compressed formats
//!
-//! - `Sfloat` means that the values are regular floating points. No conversion is performed.
+//! A block-compressed format uses compression to encode a larger block of texels into a smaller
+//! number of bytes. Individual texels are no longer represented in memory, only the block as a
+//! whole. An image must consist of a whole number of blocks, so the dimensions of an image must be
+//! a whole multiple of the block dimensions. Vulkan supports several different compression schemes,
+//! represented in Vulkano by the `CompressionType` enum.
//!
-//! - `Srgb` is the same as `Unorm`, except that the value is interpreted as being in the sRGB
-//! color space. This means that its value will be converted to fit in the RGB color space when
-//! it is read. The fourth channel (usually used for alpha), if present, is not concerned by the
-//! conversion.
+//! Overall, block-compressed formats do not behave significantly differently from regular formats.
+//! They are mostly restricted in terms of compatibility. Because of the compression, the notion of
+//! bits per component does not apply, so the `components` method will only return whether a
+//! component is present or not.
//!
-//! # Choosing a format
+//! ## YCbCr formats
//!
-//! The following formats are guaranteed to be supported for everything that is related to
-//! texturing (ie. blitting source and sampling them linearly). You should choose one of these
-//! formats if you have an image that you are going to sample from:
+//! YCbCr, also known as YUV, is an alternative image representation with three components:
+//! Y for luminance or *luma* (overall brightness) and two color or *chroma* components Cb and Cr
+//! encoding the blueness and redness respectively. YCbCr formats are primarily used in video
+//! applications. In Vulkan, the formats used to encode YCbCr data use the green channel to
+//! represent the luma component, while the blue and red components hold the chroma.
//!
-//! - B4G4R4A4UnormPack16
-//! - R5G6B5UnormPack16
-//! - A1R5G5B5UnormPack16
-//! - R8Unorm
-//! - R8Snorm
-//! - R8G8Unorm
-//! - R8G8Snorm
-//! - R8G8B8A8Unorm
-//! - R8G8B8A8Snorm
-//! - R8G8B8A8Srgb
-//! - B8G8R8A8Unorm
-//! - B8G8R8A8Srgb
-//! - A8B8G8R8UnormPack32
-//! - A8B8G8R8SnormPack32
-//! - A8B8G8R8SrgbPack32
-//! - A2B10G10R10UnormPack32
-//! - R16Sfloat
-//! - R16G16Sfloat
-//! - R16G16B16A16Sfloat
-//! - B10G11R11UfloatPack32
-//! - E5B9G9R9UfloatPack32
+//! To use most YCbCr formats in an [image view](crate::image::view), a
+//! [sampler YCbCr conversion](crate::sampler::ycbcr) object must be created, and attached to both
+//! the image view and the sampler. To query whether a format requires the conversion, you can call
+//! `ycbcr_chroma_sampling` on a format. As a rule, any format with `444`, `422`, `420`,
+//! `3PACK` or `4PACK` in the name requires it.
//!
-//! The following formats are guaranteed to be supported for everything that is related to
-//! intermediate render targets (ie. blitting destination, color attachment and sampling linearly):
+//! Many YCbCr formats make use of **chroma subsampling**. This is a technique whereby the two
+//! chroma components are encoded using a lower resolution than the luma component. The human eye is
+//! less sensitive to color detail than to detail in brightness, so this allows more detail to be
+//! encoded in less data. Chroma subsampling is indicated with one of three numbered suffixes in a
+//! format name:
+//! - `444` indicates a YCbCr format without chroma subsampling. All components have the same
+//! resolution.
+//! - `422` indicates horizontal chroma subsampling. The horizontal resolution of the chroma
+//! components is halved, so a single value is shared within a 2x1 block of texels.
+//! - `420` indicates horizontal and vertical chroma subsampling. Both dimensions of the chroma
+//! components are halved, so a single value is shared within a 2x2 block of texels.
//!
-//! - R5G6B5UnormPack16
-//! - A1R5G5B5UnormPack16
-//! - R8Unorm
-//! - R8G8Unorm
-//! - R8G8B8A8Unorm
-//! - R8G8B8A8Srgb
-//! - B8G8R8A8Unorm
-//! - B8G8R8A8Srgb
-//! - A8B8G8R8UnormPack32
-//! - A8B8G8R8SrgbPack32
-//! - A2B10G10R10UnormPack32
-//! - R16Sfloat
-//! - R16G16Sfloat
-//! - R16G16B16A16Sfloat
+//! Most YCbCr formats, including all of the `444` and `420` formats, are **multi-planar**. Instead
+//! of storing the components of a single texel together in memory, the components are separated
+//! into *planes*, which act like independent images. In 3-plane formats, the planes hold the Y,
+//! Cb and Cr components respectively, while in 2-plane formats, Cb and Cr are combined into a
+//! two-component plane. Where chroma subsampling is applied, plane 0 has the full resolution, while
+//! planes 1 and 2 have reduced resolution. Effectively, they are standalone images with half the
+//! resolution of the original.
//!
-//! For depth images, only `D16Unorm` is guaranteed to be supported. For depth-stencil images,
-//! it is guaranteed that either `D24Unorm_S8Uint` or `D32Sfloat_S8Uint` are supported.
-//!
-//! // TODO: storage formats
-//!
-
-use crate::device::physical::PhysicalDevice;
-use crate::image::ImageAspects;
-use crate::DeviceSize;
-use crate::VulkanObject;
-use half::f16;
-use std::convert::TryFrom;
-use std::mem::MaybeUninit;
-use std::vec::IntoIter as VecIntoIter;
-use std::{error, fmt, mem};
-
-macro_rules! formats {
- ($($name:ident => { vk: $vk:ident, bdim: $bdim:expr, size: $sz:expr, ty: $f_ty:ident$(, planes: $planes:expr)?},)+) => (
- /// An enumeration of all the possible formats.
- #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
- #[repr(i32)]
- #[allow(missing_docs)]
- #[allow(non_camel_case_types)]
- pub enum Format {
- $($name = ash::vk::Format::$vk.as_raw(),)+
- }
-
- impl Format {
- /*pub fn is_supported_for_vertex_attributes(&self) -> bool {
-
- }
-
- .. other functions ..
- */
-
- /// Returns the size in bytes of an element of this format. For block based formats
- /// this will be the size of a single block. Returns `None` if the
- /// size is irrelevant.
- #[inline]
- pub const fn size(&self) -> Option<DeviceSize> {
- match *self {
- $(
- Format::$name => $sz,
- )+
- }
- }
+//! The texels of multi-planar images cannot be accessed individually, for example to copy or blit,
+//! since the components of each texel are split across the planes. Instead, you must access each
+//! plane as an individual *aspect* of the image. A single-plane aspect of a multi-planar image
+//! behaves as a regular image, and even has its own format, which can be queried with the `plane`
+//! method on a format.
- /// Returns (width, height) of the dimensions for block based formats. For
- /// non block formats will return (1,1)
- #[inline]
- pub const fn block_dimensions(&self) -> (u32, u32) {
- match *self {
- $(
- Format::$name => $bdim,
- )+
- }
- }
-
- /// Returns the data type of the format.
- #[inline]
- pub const fn ty(&self) -> FormatTy {
- match *self {
- $(
- Format::$name => FormatTy::$f_ty,
- )+
- }
- }
-
- /// Returns the number of planes that images of this format have.
- ///
- /// Returns 0 if the format is not multi-planar.
- #[inline]
- pub const fn planes(&self) -> u8 {
- match *self {
- $(
- $(Format::$name => $planes,)?
- )+
- _ => 0,
- }
- }
- }
-
- impl TryFrom<ash::vk::Format> for Format {
- type Error = ();
-
- #[inline]
- fn try_from(val: ash::vk::Format) -> Result<Format, ()> {
- match val {
- $(
- ash::vk::Format::$vk => Ok(Format::$name),
- )+
- _ => Err(()),
- }
- }
- }
+use crate::{
+ device::physical::PhysicalDevice, image::ImageAspects, macros::vulkan_bitflags,
+ shader::spirv::ImageFormat, DeviceSize,
+};
- impl From<Format> for ash::vk::Format {
- #[inline]
- fn from(val: Format) -> Self {
- ash::vk::Format::from_raw(val as i32)
- }
- }
- );
-}
-
-formats! {
- R4G4UnormPack8 => {vk: R4G4_UNORM_PACK8, bdim: (1, 1), size: Some(1), ty: Float},
- R4G4B4A4UnormPack16 => {vk: R4G4B4A4_UNORM_PACK16, bdim: (1, 1), size: Some(2), ty: Float},
- B4G4R4A4UnormPack16 => {vk: B4G4R4A4_UNORM_PACK16, bdim: (1, 1), size: Some(2), ty: Float},
- R5G6B5UnormPack16 => {vk: R5G6B5_UNORM_PACK16, bdim: (1, 1), size: Some(2), ty: Float},
- B5G6R5UnormPack16 => {vk: B5G6R5_UNORM_PACK16, bdim: (1, 1), size: Some(2), ty: Float},
- R5G5B5A1UnormPack16 => {vk: R5G5B5A1_UNORM_PACK16, bdim: (1, 1), size: Some(2), ty: Float},
- B5G5R5A1UnormPack16 => {vk: B5G5R5A1_UNORM_PACK16, bdim: (1, 1), size: Some(2), ty: Float},
- A1R5G5B5UnormPack16 => {vk: A1R5G5B5_UNORM_PACK16, bdim: (1, 1), size: Some(2), ty: Float},
- R8Unorm => {vk: R8_UNORM, bdim: (1, 1), size: Some(1), ty: Float},
- R8Snorm => {vk: R8_SNORM, bdim: (1, 1), size: Some(1), ty: Float},
- R8Uscaled => {vk: R8_USCALED, bdim: (1, 1), size: Some(1), ty: Float},
- R8Sscaled => {vk: R8_SSCALED, bdim: (1, 1), size: Some(1), ty: Float},
- R8Uint => {vk: R8_UINT, bdim: (1, 1), size: Some(1), ty: Uint},
- R8Sint => {vk: R8_SINT, bdim: (1, 1), size: Some(1), ty: Sint},
- R8Srgb => {vk: R8_SRGB, bdim: (1, 1), size: Some(1), ty: Float},
- R8G8Unorm => {vk: R8G8_UNORM, bdim: (1, 1), size: Some(2), ty: Float},
- R8G8Snorm => {vk: R8G8_SNORM, bdim: (1, 1), size: Some(2), ty: Float},
- R8G8Uscaled => {vk: R8G8_USCALED, bdim: (1, 1), size: Some(2), ty: Float},
- R8G8Sscaled => {vk: R8G8_SSCALED, bdim: (1, 1), size: Some(2), ty: Float},
- R8G8Uint => {vk: R8G8_UINT, bdim: (1, 1), size: Some(2), ty: Uint},
- R8G8Sint => {vk: R8G8_SINT, bdim: (1, 1), size: Some(2), ty: Sint},
- R8G8Srgb => {vk: R8G8_SRGB, bdim: (1, 1), size: Some(2), ty: Float},
- R8G8B8Unorm => {vk: R8G8B8_UNORM, bdim: (1, 1), size: Some(3), ty: Float},
- R8G8B8Snorm => {vk: R8G8B8_SNORM, bdim: (1, 1), size: Some(3), ty: Float},
- R8G8B8Uscaled => {vk: R8G8B8_USCALED, bdim: (1, 1), size: Some(3), ty: Float},
- R8G8B8Sscaled => {vk: R8G8B8_SSCALED, bdim: (1, 1), size: Some(3), ty: Float},
- R8G8B8Uint => {vk: R8G8B8_UINT, bdim: (1, 1), size: Some(3), ty: Uint},
- R8G8B8Sint => {vk: R8G8B8_SINT, bdim: (1, 1), size: Some(3), ty: Sint},
- R8G8B8Srgb => {vk: R8G8B8_SRGB, bdim: (1, 1), size: Some(3), ty: Float},
- B8G8R8Unorm => {vk: B8G8R8_UNORM, bdim: (1, 1), size: Some(3), ty: Float},
- B8G8R8Snorm => {vk: B8G8R8_SNORM, bdim: (1, 1), size: Some(3), ty: Float},
- B8G8R8Uscaled => {vk: B8G8R8_USCALED, bdim: (1, 1), size: Some(3), ty: Float},
- B8G8R8Sscaled => {vk: B8G8R8_SSCALED, bdim: (1, 1), size: Some(3), ty: Float},
- B8G8R8Uint => {vk: B8G8R8_UINT, bdim: (1, 1), size: Some(3), ty: Uint},
- B8G8R8Sint => {vk: B8G8R8_SINT, bdim: (1, 1), size: Some(3), ty: Sint},
- B8G8R8Srgb => {vk: B8G8R8_SRGB, bdim: (1, 1), size: Some(3), ty: Float},
- R8G8B8A8Unorm => {vk: R8G8B8A8_UNORM, bdim: (1, 1), size: Some(4), ty: Float},
- R8G8B8A8Snorm => {vk: R8G8B8A8_SNORM, bdim: (1, 1), size: Some(4), ty: Float},
- R8G8B8A8Uscaled => {vk: R8G8B8A8_USCALED, bdim: (1, 1), size: Some(4), ty: Float},
- R8G8B8A8Sscaled => {vk: R8G8B8A8_SSCALED, bdim: (1, 1), size: Some(4), ty: Float},
- R8G8B8A8Uint => {vk: R8G8B8A8_UINT, bdim: (1, 1), size: Some(4), ty: Uint},
- R8G8B8A8Sint => {vk: R8G8B8A8_SINT, bdim: (1, 1), size: Some(4), ty: Sint},
- R8G8B8A8Srgb => {vk: R8G8B8A8_SRGB, bdim: (1, 1), size: Some(4), ty: Float},
- B8G8R8A8Unorm => {vk: B8G8R8A8_UNORM, bdim: (1, 1), size: Some(4), ty: Float},
- B8G8R8A8Snorm => {vk: B8G8R8A8_SNORM, bdim: (1, 1), size: Some(4), ty: Float},
- B8G8R8A8Uscaled => {vk: B8G8R8A8_USCALED, bdim: (1, 1), size: Some(4), ty: Float},
- B8G8R8A8Sscaled => {vk: B8G8R8A8_SSCALED, bdim: (1, 1), size: Some(4), ty: Float},
- B8G8R8A8Uint => {vk: B8G8R8A8_UINT, bdim: (1, 1), size: Some(4), ty: Uint},
- B8G8R8A8Sint => {vk: B8G8R8A8_SINT, bdim: (1, 1), size: Some(4), ty: Sint},
- B8G8R8A8Srgb => {vk: B8G8R8A8_SRGB, bdim: (1, 1), size: Some(4), ty: Float},
- A8B8G8R8UnormPack32 => {vk: A8B8G8R8_UNORM_PACK32, bdim: (1, 1), size: Some(4), ty: Float},
- A8B8G8R8SnormPack32 => {vk: A8B8G8R8_SNORM_PACK32, bdim: (1, 1), size: Some(4), ty: Float},
- A8B8G8R8UscaledPack32 => {vk: A8B8G8R8_USCALED_PACK32, bdim: (1, 1), size: Some(4), ty: Float},
- A8B8G8R8SscaledPack32 => {vk: A8B8G8R8_SSCALED_PACK32, bdim: (1, 1), size: Some(4), ty: Float},
- A8B8G8R8UintPack32 => {vk: A8B8G8R8_UINT_PACK32, bdim: (1, 1), size: Some(4), ty: Uint},
- A8B8G8R8SintPack32 => {vk: A8B8G8R8_SINT_PACK32, bdim: (1, 1), size: Some(4), ty: Sint},
- A8B8G8R8SrgbPack32 => {vk: A8B8G8R8_SRGB_PACK32, bdim: (1, 1), size: Some(4), ty: Float},
- A2R10G10B10UnormPack32 => {vk: A2R10G10B10_UNORM_PACK32, bdim: (1, 1), size: Some(4), ty: Float},
- A2R10G10B10SnormPack32 => {vk: A2R10G10B10_SNORM_PACK32, bdim: (1, 1), size: Some(4), ty: Float},
- A2R10G10B10UscaledPack32 => {vk: A2R10G10B10_USCALED_PACK32, bdim: (1, 1), size: Some(4), ty: Float},
- A2R10G10B10SscaledPack32 => {vk: A2R10G10B10_SSCALED_PACK32, bdim: (1, 1), size: Some(4), ty: Float},
- A2R10G10B10UintPack32 => {vk: A2R10G10B10_UINT_PACK32, bdim: (1, 1), size: Some(4), ty: Uint},
- A2R10G10B10SintPack32 => {vk: A2R10G10B10_SINT_PACK32, bdim: (1, 1), size: Some(4), ty: Sint},
- A2B10G10R10UnormPack32 => {vk: A2B10G10R10_UNORM_PACK32, bdim: (1, 1), size: Some(4), ty: Float},
- A2B10G10R10SnormPack32 => {vk: A2B10G10R10_SNORM_PACK32, bdim: (1, 1), size: Some(4), ty: Float},
- A2B10G10R10UscaledPack32 => {vk: A2B10G10R10_USCALED_PACK32, bdim: (1, 1), size: Some(4), ty: Float},
- A2B10G10R10SscaledPack32 => {vk: A2B10G10R10_SSCALED_PACK32, bdim: (1, 1), size: Some(4), ty: Float},
- A2B10G10R10UintPack32 => {vk: A2B10G10R10_UINT_PACK32, bdim: (1, 1), size: Some(4), ty: Uint},
- A2B10G10R10SintPack32 => {vk: A2B10G10R10_SINT_PACK32, bdim: (1, 1), size: Some(4), ty: Sint},
- R16Unorm => {vk: R16_UNORM, bdim: (1, 1), size: Some(2), ty: Float},
- R16Snorm => {vk: R16_SNORM, bdim: (1, 1), size: Some(2), ty: Float},
- R16Uscaled => {vk: R16_USCALED, bdim: (1, 1), size: Some(2), ty: Float},
- R16Sscaled => {vk: R16_SSCALED, bdim: (1, 1), size: Some(2), ty: Float},
- R16Uint => {vk: R16_UINT, bdim: (1, 1), size: Some(2), ty: Uint},
- R16Sint => {vk: R16_SINT, bdim: (1, 1), size: Some(2), ty: Sint},
- R16Sfloat => {vk: R16_SFLOAT, bdim: (1, 1), size: Some(2), ty: Float},
- R16G16Unorm => {vk: R16G16_UNORM, bdim: (1, 1), size: Some(4), ty: Float},
- R16G16Snorm => {vk: R16G16_SNORM, bdim: (1, 1), size: Some(4), ty: Float},
- R16G16Uscaled => {vk: R16G16_USCALED, bdim: (1, 1), size: Some(4), ty: Float},
- R16G16Sscaled => {vk: R16G16_SSCALED, bdim: (1, 1), size: Some(4), ty: Float},
- R16G16Uint => {vk: R16G16_UINT, bdim: (1, 1), size: Some(4), ty: Uint},
- R16G16Sint => {vk: R16G16_SINT, bdim: (1, 1), size: Some(4), ty: Sint},
- R16G16Sfloat => {vk: R16G16_SFLOAT, bdim: (1, 1), size: Some(4), ty: Float},
- R16G16B16Unorm => {vk: R16G16B16_UNORM, bdim: (1, 1), size: Some(6), ty: Float},
- R16G16B16Snorm => {vk: R16G16B16_SNORM, bdim: (1, 1), size: Some(6), ty: Float},
- R16G16B16Uscaled => {vk: R16G16B16_USCALED, bdim: (1, 1), size: Some(6), ty: Float},
- R16G16B16Sscaled => {vk: R16G16B16_SSCALED, bdim: (1, 1), size: Some(6), ty: Float},
- R16G16B16Uint => {vk: R16G16B16_UINT, bdim: (1, 1), size: Some(6), ty: Uint},
- R16G16B16Sint => {vk: R16G16B16_SINT, bdim: (1, 1), size: Some(6), ty: Sint},
- R16G16B16Sfloat => {vk: R16G16B16_SFLOAT, bdim: (1, 1), size: Some(6), ty: Float},
- R16G16B16A16Unorm => {vk: R16G16B16A16_UNORM, bdim: (1, 1), size: Some(8), ty: Float},
- R16G16B16A16Snorm => {vk: R16G16B16A16_SNORM, bdim: (1, 1), size: Some(8), ty: Float},
- R16G16B16A16Uscaled => {vk: R16G16B16A16_USCALED, bdim: (1, 1), size: Some(8), ty: Float},
- R16G16B16A16Sscaled => {vk: R16G16B16A16_SSCALED, bdim: (1, 1), size: Some(8), ty: Float},
- R16G16B16A16Uint => {vk: R16G16B16A16_UINT, bdim: (1, 1), size: Some(8), ty: Uint},
- R16G16B16A16Sint => {vk: R16G16B16A16_SINT, bdim: (1, 1), size: Some(8), ty: Sint},
- R16G16B16A16Sfloat => {vk: R16G16B16A16_SFLOAT, bdim: (1, 1), size: Some(8), ty: Float},
- R32Uint => {vk: R32_UINT, bdim: (1, 1), size: Some(4), ty: Uint},
- R32Sint => {vk: R32_SINT, bdim: (1, 1), size: Some(4), ty: Sint},
- R32Sfloat => {vk: R32_SFLOAT, bdim: (1, 1), size: Some(4), ty: Float},
- R32G32Uint => {vk: R32G32_UINT, bdim: (1, 1), size: Some(8), ty: Uint},
- R32G32Sint => {vk: R32G32_SINT, bdim: (1, 1), size: Some(8), ty: Sint},
- R32G32Sfloat => {vk: R32G32_SFLOAT, bdim: (1, 1), size: Some(8), ty: Float},
- R32G32B32Uint => {vk: R32G32B32_UINT, bdim: (1, 1), size: Some(12), ty: Uint},
- R32G32B32Sint => {vk: R32G32B32_SINT, bdim: (1, 1), size: Some(12), ty: Sint},
- R32G32B32Sfloat => {vk: R32G32B32_SFLOAT, bdim: (1, 1), size: Some(12), ty: Float},
- R32G32B32A32Uint => {vk: R32G32B32A32_UINT, bdim: (1, 1), size: Some(16), ty: Uint},
- R32G32B32A32Sint => {vk: R32G32B32A32_SINT, bdim: (1, 1), size: Some(16), ty: Sint},
- R32G32B32A32Sfloat => {vk: R32G32B32A32_SFLOAT, bdim: (1, 1), size: Some(16), ty: Float},
- R64Uint => {vk: R64_UINT, bdim: (1, 1), size: Some(8), ty: Uint},
- R64Sint => {vk: R64_SINT, bdim: (1, 1), size: Some(8), ty: Sint},
- R64Sfloat => {vk: R64_SFLOAT, bdim: (1, 1), size: Some(8), ty: Float},
- R64G64Uint => {vk: R64G64_UINT, bdim: (1, 1), size: Some(16), ty: Uint},
- R64G64Sint => {vk: R64G64_SINT, bdim: (1, 1), size: Some(16), ty: Sint},
- R64G64Sfloat => {vk: R64G64_SFLOAT, bdim: (1, 1), size: Some(16), ty: Float},
- R64G64B64Uint => {vk: R64G64B64_UINT, bdim: (1, 1), size: Some(24), ty: Uint},
- R64G64B64Sint => {vk: R64G64B64_SINT, bdim: (1, 1), size: Some(24), ty: Sint},
- R64G64B64Sfloat => {vk: R64G64B64_SFLOAT, bdim: (1, 1), size: Some(24), ty: Float},
- R64G64B64A64Uint => {vk: R64G64B64A64_UINT, bdim: (1, 1), size: Some(32), ty: Uint},
- R64G64B64A64Sint => {vk: R64G64B64A64_SINT, bdim: (1, 1), size: Some(32), ty: Sint},
- R64G64B64A64Sfloat => {vk: R64G64B64A64_SFLOAT, bdim: (1, 1), size: Some(32), ty: Float},
- B10G11R11UfloatPack32 => {vk: B10G11R11_UFLOAT_PACK32, bdim: (1, 1), size: Some(4), ty: Float},
- E5B9G9R9UfloatPack32 => {vk: E5B9G9R9_UFLOAT_PACK32, bdim: (1, 1), size: Some(4), ty: Float},
- D16Unorm => {vk: D16_UNORM, bdim: (1, 1), size: Some(2), ty: Depth},
- X8_D24UnormPack32 => {vk: X8_D24_UNORM_PACK32, bdim: (1, 1), size: Some(4), ty: Depth},
- D32Sfloat => {vk: D32_SFLOAT, bdim: (1, 1), size: Some(4), ty: Depth},
- S8Uint => {vk: S8_UINT, bdim: (1, 1), size: Some(1), ty: Stencil},
- D16Unorm_S8Uint => {vk: D16_UNORM_S8_UINT, bdim: (1, 1), size: None, ty: DepthStencil},
- D24Unorm_S8Uint => {vk: D24_UNORM_S8_UINT, bdim: (1, 1), size: None, ty: DepthStencil},
- D32Sfloat_S8Uint => {vk: D32_SFLOAT_S8_UINT, bdim: (1, 1), size: None, ty: DepthStencil},
- BC1_RGBUnormBlock => {vk: BC1_RGB_UNORM_BLOCK, bdim: (4, 4), size: Some(8), ty: Compressed},
- BC1_RGBSrgbBlock => {vk: BC1_RGB_SRGB_BLOCK, bdim: (4, 4), size: Some(8), ty: Compressed},
- BC1_RGBAUnormBlock => {vk: BC1_RGBA_UNORM_BLOCK, bdim: (4, 4), size: Some(8), ty: Compressed},
- BC1_RGBASrgbBlock => {vk: BC1_RGBA_SRGB_BLOCK, bdim: (4, 4), size: Some(8), ty: Compressed},
- BC2UnormBlock => {vk: BC2_UNORM_BLOCK, bdim: (4, 4), size: Some(16), ty: Compressed},
- BC2SrgbBlock => {vk: BC2_SRGB_BLOCK, bdim: (4, 4), size: Some(16), ty: Compressed},
- BC3UnormBlock => {vk: BC3_UNORM_BLOCK, bdim: (4, 4), size: Some(16), ty: Compressed},
- BC3SrgbBlock => {vk: BC3_SRGB_BLOCK, bdim: (4, 4), size: Some(16), ty: Compressed},
- BC4UnormBlock => {vk: BC4_UNORM_BLOCK, bdim: (4, 4), size: Some(8), ty: Compressed},
- BC4SnormBlock => {vk: BC4_SNORM_BLOCK, bdim: (4, 4), size: Some(8), ty: Compressed},
- BC5UnormBlock => {vk: BC5_UNORM_BLOCK, bdim: (4, 4), size: Some(16), ty: Compressed},
- BC5SnormBlock => {vk: BC5_SNORM_BLOCK, bdim: (4, 4), size: Some(16), ty: Compressed},
- BC6HUfloatBlock => {vk: BC6H_UFLOAT_BLOCK, bdim: (4, 4), size: Some(16), ty: Compressed},
- BC6HSfloatBlock => {vk: BC6H_SFLOAT_BLOCK, bdim: (4, 4), size: Some(16), ty: Compressed},
- BC7UnormBlock => {vk: BC7_UNORM_BLOCK, bdim: (4, 4), size: Some(16), ty: Compressed},
- BC7SrgbBlock => {vk: BC7_SRGB_BLOCK, bdim: (4, 4), size: Some(16), ty: Compressed},
- ETC2_R8G8B8UnormBlock => {vk: ETC2_R8G8B8_UNORM_BLOCK, bdim: (4, 4), size: Some(8), ty: Compressed},
- ETC2_R8G8B8SrgbBlock => {vk: ETC2_R8G8B8_SRGB_BLOCK, bdim: (4, 4), size: Some(8), ty: Compressed},
- ETC2_R8G8B8A1UnormBlock => {vk: ETC2_R8G8B8A1_UNORM_BLOCK, bdim: (4, 4), size: Some(8), ty: Compressed},
- ETC2_R8G8B8A1SrgbBlock => {vk: ETC2_R8G8B8A1_SRGB_BLOCK, bdim: (4, 4), size: Some(8), ty: Compressed},
- ETC2_R8G8B8A8UnormBlock => {vk: ETC2_R8G8B8A8_UNORM_BLOCK, bdim: (4, 4), size: Some(16), ty: Compressed},
- ETC2_R8G8B8A8SrgbBlock => {vk: ETC2_R8G8B8A8_SRGB_BLOCK, bdim: (4, 4), size: Some(16), ty: Compressed},
- EAC_R11UnormBlock => {vk: EAC_R11_UNORM_BLOCK, bdim: (4, 4), size: Some(8), ty: Compressed},
- EAC_R11SnormBlock => {vk: EAC_R11_SNORM_BLOCK, bdim: (4, 4), size: Some(8), ty: Compressed},
- EAC_R11G11UnormBlock => {vk: EAC_R11G11_UNORM_BLOCK, bdim: (4, 4), size: Some(16), ty: Compressed},
- EAC_R11G11SnormBlock => {vk: EAC_R11G11_SNORM_BLOCK, bdim: (4, 4), size: Some(16), ty: Compressed},
- ASTC_4x4UnormBlock => {vk: ASTC_4X4_UNORM_BLOCK, bdim: (4, 4), size: Some(16), ty: Compressed},
- ASTC_4x4SrgbBlock => {vk: ASTC_4X4_SRGB_BLOCK, bdim: (4, 4), size: Some(16), ty: Compressed},
- ASTC_5x4UnormBlock => {vk: ASTC_5X4_UNORM_BLOCK, bdim: (5, 4), size: Some(16), ty: Compressed},
- ASTC_5x4SrgbBlock => {vk: ASTC_5X4_SRGB_BLOCK, bdim: (5, 4), size: Some(16), ty: Compressed},
- ASTC_5x5UnormBlock => {vk: ASTC_5X5_UNORM_BLOCK, bdim: (5, 5), size: Some(16), ty: Compressed},
- ASTC_5x5SrgbBlock => {vk: ASTC_5X5_SRGB_BLOCK, bdim: (5, 5), size: Some(16), ty: Compressed},
- ASTC_6x5UnormBlock => {vk: ASTC_6X5_UNORM_BLOCK, bdim: (6, 5), size: Some(16), ty: Compressed},
- ASTC_6x5SrgbBlock => {vk: ASTC_6X5_SRGB_BLOCK, bdim: (6, 5), size: Some(16), ty: Compressed},
- ASTC_6x6UnormBlock => {vk: ASTC_6X6_UNORM_BLOCK, bdim: (6, 6), size: Some(16), ty: Compressed},
- ASTC_6x6SrgbBlock => {vk: ASTC_6X6_SRGB_BLOCK, bdim: (6, 6), size: Some(16), ty: Compressed},
- ASTC_8x5UnormBlock => {vk: ASTC_8X5_UNORM_BLOCK, bdim: (8, 5), size: Some(16), ty: Compressed},
- ASTC_8x5SrgbBlock => {vk: ASTC_8X5_SRGB_BLOCK, bdim: (8, 5), size: Some(16), ty: Compressed},
- ASTC_8x6UnormBlock => {vk: ASTC_8X6_UNORM_BLOCK, bdim: (8, 6), size: Some(16), ty: Compressed},
- ASTC_8x6SrgbBlock => {vk: ASTC_8X6_SRGB_BLOCK, bdim: (8, 6), size: Some(16), ty: Compressed},
- ASTC_8x8UnormBlock => {vk: ASTC_8X8_UNORM_BLOCK, bdim: (8, 8), size: Some(16), ty: Compressed},
- ASTC_8x8SrgbBlock => {vk: ASTC_8X8_SRGB_BLOCK, bdim: (8, 8), size: Some(16), ty: Compressed},
- ASTC_10x5UnormBlock => {vk: ASTC_10X5_UNORM_BLOCK, bdim: (10, 5), size: Some(16), ty: Compressed},
- ASTC_10x5SrgbBlock => {vk: ASTC_10X5_SRGB_BLOCK, bdim: (10, 5), size: Some(16), ty: Compressed},
- ASTC_10x6UnormBlock => {vk: ASTC_10X6_UNORM_BLOCK, bdim: (10, 6), size: Some(16), ty: Compressed},
- ASTC_10x6SrgbBlock => {vk: ASTC_10X6_SRGB_BLOCK, bdim: (10, 6), size: Some(16), ty: Compressed},
- ASTC_10x8UnormBlock => {vk: ASTC_10X8_UNORM_BLOCK, bdim: (10, 8), size: Some(16), ty: Compressed},
- ASTC_10x8SrgbBlock => {vk: ASTC_10X8_SRGB_BLOCK, bdim: (10, 8), size: Some(16), ty: Compressed},
- ASTC_10x10UnormBlock => {vk: ASTC_10X10_UNORM_BLOCK, bdim: (10, 10), size: Some(16), ty: Compressed},
- ASTC_10x10SrgbBlock => {vk: ASTC_10X10_SRGB_BLOCK, bdim: (10, 10), size: Some(16), ty: Compressed},
- ASTC_12x10UnormBlock => {vk: ASTC_12X10_UNORM_BLOCK, bdim: (12, 10), size: Some(16), ty: Compressed},
- ASTC_12x10SrgbBlock => {vk: ASTC_12X10_SRGB_BLOCK, bdim: (12, 10), size: Some(16), ty: Compressed},
- ASTC_12x12UnormBlock => {vk: ASTC_12X12_UNORM_BLOCK, bdim: (12, 12), size: Some(16), ty: Compressed},
- ASTC_12x12SrgbBlock => {vk: ASTC_12X12_SRGB_BLOCK, bdim: (12, 12), size: Some(16), ty: Compressed},
- G8B8R8_3PLANE420Unorm => {vk: G8_B8_R8_3PLANE_420_UNORM, bdim: (1, 1), size: None, ty: Ycbcr, planes: 3},
- G8B8R8_2PLANE420Unorm => {vk: G8_B8R8_2PLANE_420_UNORM, bdim: (1, 1), size: None, ty: Ycbcr, planes: 2},
-}
+// Generated by build.rs
+include!(concat!(env!("OUT_DIR"), "/formats.rs"));
impl Format {
- /// Returns the aspects that images of this format have.
- #[inline]
- pub const fn aspects(&self) -> ImageAspects {
- let ty = self.ty();
- let planes = self.planes();
- ImageAspects {
- color: matches!(
- ty,
- FormatTy::Float | FormatTy::Uint | FormatTy::Sint | FormatTy::Compressed
- ),
- depth: matches!(ty, FormatTy::Depth | FormatTy::DepthStencil),
- stencil: matches!(ty, FormatTy::Stencil | FormatTy::DepthStencil),
- plane0: planes >= 1,
- plane1: planes >= 2,
- plane2: planes >= 3,
- ..ImageAspects::none()
- }
- }
-
/// Retrieves the properties of a format when used by a certain device.
+ #[deprecated(
+ since = "0.28.0",
+ note = "Use PhysicalDevice::format_properties instead"
+ )]
#[inline]
- pub fn properties(&self, physical_device: PhysicalDevice) -> FormatProperties {
- let vk_properties = unsafe {
- let fns_i = physical_device.instance().fns();
- let mut output = MaybeUninit::uninit();
- fns_i.v1_0.get_physical_device_format_properties(
- physical_device.internal_object(),
- (*self).into(),
- output.as_mut_ptr(),
- );
- output.assume_init()
- };
-
- FormatProperties {
- linear_tiling_features: vk_properties.linear_tiling_features.into(),
- optimal_tiling_features: vk_properties.optimal_tiling_features.into(),
- buffer_features: vk_properties.buffer_features.into(),
- }
+ pub fn properties(self, physical_device: PhysicalDevice) -> FormatProperties {
+ physical_device.format_properties(self).unwrap()
}
+ /// Returns whether the format can be used with a storage image, without specifying
+ /// the format in the shader, if the
+ /// [`shader_storage_image_read_without_format`](crate::device::Features::shader_storage_image_read_without_format)
+ /// and/or
+ /// [`shader_storage_image_write_without_format`](crate::device::Features::shader_storage_image_write_without_format)
+ /// features are enabled on the device.
#[inline]
- pub fn decode_clear_value(&self, value: ClearValue) -> ClearValue {
- match (self.ty(), value) {
- (FormatTy::Float, f @ ClearValue::Float(_)) => f,
- (FormatTy::Compressed, f @ ClearValue::Float(_)) => f,
- (FormatTy::Sint, f @ ClearValue::Int(_)) => f,
- (FormatTy::Uint, f @ ClearValue::Uint(_)) => f,
- (FormatTy::Depth, f @ ClearValue::Depth(_)) => f,
- (FormatTy::Stencil, f @ ClearValue::Stencil(_)) => f,
- (FormatTy::DepthStencil, f @ ClearValue::DepthStencil(_)) => f,
- _ => panic!("Wrong clear value"),
- }
+ pub fn shader_storage_image_without_format(self) -> bool {
+ matches!(
+ self,
+ Format::R8G8B8A8_UNORM
+ | Format::R8G8B8A8_SNORM
+ | Format::R8G8B8A8_UINT
+ | Format::R8G8B8A8_SINT
+ | Format::R32_UINT
+ | Format::R32_SINT
+ | Format::R32_SFLOAT
+ | Format::R32G32_UINT
+ | Format::R32G32_SINT
+ | Format::R32G32_SFLOAT
+ | Format::R32G32B32A32_UINT
+ | Format::R32G32B32A32_SINT
+ | Format::R32G32B32A32_SFLOAT
+ | Format::R16G16B16A16_UINT
+ | Format::R16G16B16A16_SINT
+ | Format::R16G16B16A16_SFLOAT
+ | Format::R16G16_SFLOAT
+ | Format::B10G11R11_UFLOAT_PACK32
+ | Format::R16_SFLOAT
+ | Format::R16G16B16A16_UNORM
+ | Format::A2B10G10R10_UNORM_PACK32
+ | Format::R16G16_UNORM
+ | Format::R8G8_UNORM
+ | Format::R16_UNORM
+ | Format::R8_UNORM
+ | Format::R16G16B16A16_SNORM
+ | Format::R16G16_SNORM
+ | Format::R8G8_SNORM
+ | Format::R16_SNORM
+ | Format::R8_SNORM
+ | Format::R16G16_SINT
+ | Format::R8G8_SINT
+ | Format::R16_SINT
+ | Format::R8_SINT
+ | Format::A2B10G10R10_UINT_PACK32
+ | Format::R16G16_UINT
+ | Format::R8G8_UINT
+ | Format::R16_UINT
+ | Format::R8_UINT
+ )
}
}
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub enum FormatTy {
- Float,
- Uint,
- Sint,
- Depth,
- Stencil,
- DepthStencil,
- Compressed,
- Ycbcr,
+impl From<Format> for ash::vk::Format {
+ #[inline]
+ fn from(val: Format) -> Self {
+ ash::vk::Format::from_raw(val as i32)
+ }
}
-/// Trait for Rust types that can represent a pixel in an image.
-pub unsafe trait Pixel {
- /// Returns an error if `Self` cannot be used as a source of pixels for `format`.
- fn ensure_accepts(format: Format) -> Result<(), IncompatiblePixelsType>;
-
- /// The number of `Self`s which make up a single pixel.
- ///
- /// # Panics
- ///
- /// May panic if `ensure_accepts` would not return `Ok(())`.
- fn rate(format: Format) -> u32;
+// https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap46.html#spirvenv-image-formats
+impl From<ImageFormat> for Option<Format> {
+ #[inline]
+ fn from(val: ImageFormat) -> Self {
+ match val {
+ ImageFormat::Unknown => None,
+ ImageFormat::Rgba32f => Some(Format::R32G32B32A32_SFLOAT),
+ ImageFormat::Rgba16f => Some(Format::R16G16B16A16_SFLOAT),
+ ImageFormat::R32f => Some(Format::R32_SFLOAT),
+ ImageFormat::Rgba8 => Some(Format::R8G8B8A8_UNORM),
+ ImageFormat::Rgba8Snorm => Some(Format::R8G8B8A8_SNORM),
+ ImageFormat::Rg32f => Some(Format::R32G32_SFLOAT),
+ ImageFormat::Rg16f => Some(Format::R16G16_SFLOAT),
+ ImageFormat::R11fG11fB10f => Some(Format::B10G11R11_UFLOAT_PACK32),
+ ImageFormat::R16f => Some(Format::R16_SFLOAT),
+ ImageFormat::Rgba16 => Some(Format::R16G16B16A16_UNORM),
+ ImageFormat::Rgb10A2 => Some(Format::A2B10G10R10_UNORM_PACK32),
+ ImageFormat::Rg16 => Some(Format::R16G16_UNORM),
+ ImageFormat::Rg8 => Some(Format::R8G8_UNORM),
+ ImageFormat::R16 => Some(Format::R16_UNORM),
+ ImageFormat::R8 => Some(Format::R8_UNORM),
+ ImageFormat::Rgba16Snorm => Some(Format::R16G16B16A16_SNORM),
+ ImageFormat::Rg16Snorm => Some(Format::R16G16_SNORM),
+ ImageFormat::Rg8Snorm => Some(Format::R8G8_SNORM),
+ ImageFormat::R16Snorm => Some(Format::R16_SNORM),
+ ImageFormat::R8Snorm => Some(Format::R8_SNORM),
+ ImageFormat::Rgba32i => Some(Format::R32G32B32A32_SINT),
+ ImageFormat::Rgba16i => Some(Format::R16G16B16A16_SINT),
+ ImageFormat::Rgba8i => Some(Format::R8G8B8A8_SINT),
+ ImageFormat::R32i => Some(Format::R32_SINT),
+ ImageFormat::Rg32i => Some(Format::R32G32_SINT),
+ ImageFormat::Rg16i => Some(Format::R16G16_SINT),
+ ImageFormat::Rg8i => Some(Format::R8G8_SINT),
+ ImageFormat::R16i => Some(Format::R16_SINT),
+ ImageFormat::R8i => Some(Format::R8_SINT),
+ ImageFormat::Rgba32ui => Some(Format::R32G32B32A32_UINT),
+ ImageFormat::Rgba16ui => Some(Format::R16G16B16A16_UINT),
+ ImageFormat::Rgba8ui => Some(Format::R8G8B8A8_UINT),
+ ImageFormat::R32ui => Some(Format::R32_UINT),
+ ImageFormat::Rgb10a2ui => Some(Format::A2B10G10R10_UINT_PACK32),
+ ImageFormat::Rg32ui => Some(Format::R32G32_UINT),
+ ImageFormat::Rg16ui => Some(Format::R16G16_UINT),
+ ImageFormat::Rg8ui => Some(Format::R8G8_UINT),
+ ImageFormat::R16ui => Some(Format::R16_UINT),
+ ImageFormat::R8ui => Some(Format::R8_UINT),
+ ImageFormat::R64ui => Some(Format::R64_UINT),
+ ImageFormat::R64i => Some(Format::R64_SINT),
+ }
+ }
}
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct IncompatiblePixelsType;
-
-impl error::Error for IncompatiblePixelsType {}
+/// The block compression scheme used in a format.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+#[allow(non_camel_case_types)]
+pub enum CompressionType {
+ /// Adaptive Scalable Texture Compression, low dynamic range.
+ ASTC_LDR,
+ /// Adaptive Scalable Texture Compression, high dynamic range.
+ ASTC_HDR,
+ /// S3TC Block Compression.
+ BC,
+ /// Ericsson Texture Compression 2.
+ ETC2,
+ /// ETC2 Alpha Compression.
+ EAC,
+ /// PowerVR Texture Compression.
+ PVRTC,
+}
-impl fmt::Display for IncompatiblePixelsType {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- "supplied pixels' type is incompatible with this format"
- )
- }
+/// For YCbCr formats, the type of chroma sampling used.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub enum ChromaSampling {
+ /// The chroma components are represented at the same resolution as the luma component.
+ Mode444,
+ /// The chroma components have half the horizontal resolution as the luma component.
+ Mode422,
+ /// The chroma components have half the horizontal and vertical resolution as the luma
+ /// component.
+ Mode420,
}
-macro_rules! impl_pixel {
- {$($ty:ty;)+} => {
- $(impl_pixel!(inner $ty);)*
- $(impl_pixel!(inner [$ty; 1]);)*
- $(impl_pixel!(inner [$ty; 2]);)*
- $(impl_pixel!(inner [$ty; 3]);)*
- $(impl_pixel!(inner [$ty; 4]);)*
- $(impl_pixel!(inner ($ty,));)*
- $(impl_pixel!(inner ($ty, $ty));)*
- $(impl_pixel!(inner ($ty, $ty, $ty));)*
- $(impl_pixel!(inner ($ty, $ty, $ty, $ty));)*
- };
- (inner $ty:ty) => {
- unsafe impl Pixel for $ty {
- fn ensure_accepts(format: Format) -> Result<(), IncompatiblePixelsType> {
- // TODO: Be more strict: accept only if the format has a matching AcceptsPixels impl.
- if format.size().map_or(false, |x| x % mem::size_of::<$ty>() as DeviceSize == 0) {
- Ok(())
- } else {
- Err(IncompatiblePixelsType)
- }
+impl ChromaSampling {
+ #[inline]
+ pub fn subsampled_extent(self, mut extent: [u32; 3]) -> [u32; 3] {
+ match self {
+ ChromaSampling::Mode444 => (),
+ ChromaSampling::Mode422 => {
+ debug_assert!(extent[0] % 2 == 0);
+ extent[0] /= 2;
}
-
- fn rate(format: Format) -> u32 {
- (format.size().expect("this format cannot accept pixels") / mem::size_of::<$ty>() as DeviceSize) as u32
+ ChromaSampling::Mode420 => {
+ debug_assert!(extent[0] % 2 == 0 && extent[1] % 2 == 0);
+ extent[0] /= 2;
+ extent[1] /= 2;
}
}
+
+ extent
}
}
-impl_pixel! {
- u8; i8; u16; i16; u32; i32; u64; i64; f16; f32; f64;
+/// The numeric type that represents data of a format in memory.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub enum NumericType {
+ /// Signed floating-point number.
+ SFLOAT,
+ /// Unsigned floating-point number.
+ UFLOAT,
+ /// Signed integer.
+ SINT,
+ /// Unsigned integer.
+ UINT,
+ /// Signed integer that represents a normalized floating-point value in the range \[-1,1].
+ SNORM,
+ /// Unsigned integer that represents a normalized floating-point value in the range \[0,1].
+ UNORM,
+ /// Signed integer that is converted to a floating-point value directly.
+ SSCALED,
+ /// Unsigned integer that is converted to a floating-point value directly.
+ USCALED,
+ /// Unsigned integer where R, G, B components represent a normalized floating-point value in the
+ /// sRGB color space, while the A component is a simple normalized value as in `UNORM`.
+ SRGB,
+}
+
+/// An opaque type that represents a format compatibility class.
+///
+/// Two formats are compatible if their compatibility classes compare equal.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+#[repr(transparent)]
+pub struct FormatCompatibility(pub(crate) &'static FormatCompatibilityInner);
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+#[allow(non_camel_case_types)]
+pub(crate) enum FormatCompatibilityInner {
+ Class_8bit,
+ Class_16bit,
+ Class_24bit,
+ Class_32bit,
+ Class_48bit,
+ Class_64bit,
+ Class_96bit,
+ Class_128bit,
+ Class_192bit,
+ Class_256bit,
+ Class_D16,
+ Class_D24,
+ Class_D32,
+ Class_S8,
+ Class_D16S8,
+ Class_D24S8,
+ Class_D32S8,
+ Class_64bit_R10G10B10A10,
+ Class_64bit_R12G12B12A12,
+ Class_BC1_RGB,
+ Class_BC1_RGBA,
+ Class_BC2,
+ Class_BC3,
+ Class_BC4,
+ Class_BC5,
+ Class_BC6H,
+ Class_BC7,
+ Class_ETC2_RGB,
+ Class_ETC2_RGBA,
+ Class_ETC2_EAC_RGBA,
+ Class_EAC_R,
+ Class_EAC_RG,
+ Class_ASTC_4x4,
+ Class_ASTC_5x4,
+ Class_ASTC_5x5,
+ Class_ASTC_6x5,
+ Class_ASTC_6x6,
+ Class_ASTC_8x5,
+ Class_ASTC_8x6,
+ Class_ASTC_8x8,
+ Class_ASTC_10x5,
+ Class_ASTC_10x6,
+ Class_ASTC_10x8,
+ Class_ASTC_10x10,
+ Class_ASTC_12x10,
+ Class_ASTC_12x12,
+ Class_PVRTC1_2BPP,
+ Class_PVRTC1_4BPP,
+ Class_PVRTC2_2BPP,
+ Class_PVRTC2_4BPP,
+ Class_32bit_G8B8G8R8,
+ Class_32bit_B8G8R8G8,
+ Class_64bit_G10B10G10R10,
+ Class_64bit_B10G10R10G10,
+ Class_64bit_G12B12G12R12,
+ Class_64bit_B12G12R12G12,
+ Class_64bit_G16B16G16R16,
+ Class_64bit_B16G16R16G16,
+ Class_8bit_3plane_420,
+ Class_8bit_2plane_420,
+ Class_10bit_3plane_420,
+ Class_10bit_2plane_420,
+ Class_12bit_3plane_420,
+ Class_12bit_2plane_420,
+ Class_16bit_3plane_420,
+ Class_16bit_2plane_420,
+ Class_8bit_3plane_422,
+ Class_8bit_2plane_422,
+ Class_10bit_3plane_422,
+ Class_10bit_2plane_422,
+ Class_12bit_3plane_422,
+ Class_12bit_2plane_422,
+ Class_16bit_3plane_422,
+ Class_16bit_2plane_422,
+ Class_8bit_3plane_444,
+ Class_10bit_3plane_444,
+ Class_12bit_3plane_444,
+ Class_16bit_3plane_444,
+ Class_8bit_2plane_444,
+ Class_10bit_2plane_444,
+ Class_12bit_2plane_444,
+ Class_16bit_2plane_444,
}
/// Describes a uniform value that will be used to fill an image.
-// TODO: should have the same layout as `vk::ClearValue` for performance
-#[derive(Debug, Copy, Clone, PartialEq)]
+#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ClearValue {
- /// Entry for attachments that aren't cleared.
- None,
- /// Value for floating-point attachments, including `Unorm`, `Snorm`, `Sfloat`.
+ /// Value for floating-point attachments, including `UNORM`, `SNORM`, `SFLOAT`.
Float([f32; 4]),
- /// Value for integer attachments, including `Int`.
+
+ /// Value for integer attachments, including `SINT`.
Int([i32; 4]),
- /// Value for unsigned integer attachments, including `Uint`.
+
+ /// Value for unsigned integer attachments, including `UINT`.
Uint([u32; 4]),
+
/// Value for depth attachments.
Depth(f32),
+
/// Value for stencil attachments.
Stencil(u32),
+
/// Value for depth and stencil attachments.
DepthStencil((f32, u32)),
}
-// TODO: remove all these From implementations once they are no longer needed
+impl From<ClearValue> for ash::vk::ClearValue {
+ #[inline]
+ fn from(val: ClearValue) -> Self {
+ match val {
+ ClearValue::Float(val) => Self {
+ color: ash::vk::ClearColorValue { float32: val },
+ },
+ ClearValue::Int(val) => Self {
+ color: ash::vk::ClearColorValue { int32: val },
+ },
+ ClearValue::Uint(val) => Self {
+ color: ash::vk::ClearColorValue { uint32: val },
+ },
+ ClearValue::Depth(depth) => Self {
+ depth_stencil: ash::vk::ClearDepthStencilValue { depth, stencil: 0 },
+ },
+ ClearValue::Stencil(stencil) => Self {
+ depth_stencil: ash::vk::ClearDepthStencilValue {
+ depth: 0.0,
+ stencil,
+ },
+ },
+ ClearValue::DepthStencil((depth, stencil)) => Self {
+ depth_stencil: ash::vk::ClearDepthStencilValue { depth, stencil },
+ },
+ }
+ }
+}
+
+impl From<ClearColorValue> for ClearValue {
+ #[inline]
+ fn from(val: ClearColorValue) -> Self {
+ match val {
+ ClearColorValue::Float(val) => Self::Float(val),
+ ClearColorValue::Int(val) => Self::Int(val),
+ ClearColorValue::Uint(val) => Self::Uint(val),
+ }
+ }
+}
impl From<[f32; 1]> for ClearValue {
#[inline]
- fn from(val: [f32; 1]) -> ClearValue {
- ClearValue::Float([val[0], 0.0, 0.0, 1.0])
+ fn from(val: [f32; 1]) -> Self {
+ Self::Float([val[0], 0.0, 0.0, 1.0])
}
}
impl From<[f32; 2]> for ClearValue {
#[inline]
- fn from(val: [f32; 2]) -> ClearValue {
- ClearValue::Float([val[0], val[1], 0.0, 1.0])
+ fn from(val: [f32; 2]) -> Self {
+ Self::Float([val[0], val[1], 0.0, 1.0])
}
}
impl From<[f32; 3]> for ClearValue {
#[inline]
- fn from(val: [f32; 3]) -> ClearValue {
- ClearValue::Float([val[0], val[1], val[2], 1.0])
+ fn from(val: [f32; 3]) -> Self {
+ Self::Float([val[0], val[1], val[2], 1.0])
}
}
impl From<[f32; 4]> for ClearValue {
#[inline]
- fn from(val: [f32; 4]) -> ClearValue {
- ClearValue::Float(val)
+ fn from(val: [f32; 4]) -> Self {
+ Self::Float(val)
}
}
impl From<[u32; 1]> for ClearValue {
#[inline]
- fn from(val: [u32; 1]) -> ClearValue {
- ClearValue::Uint([val[0], 0, 0, 0]) // TODO: is alpha value 0 correct?
+ fn from(val: [u32; 1]) -> Self {
+ Self::Uint([val[0], 0, 0, 0]) // TODO: is alpha value 0 correct?
}
}
impl From<[u32; 2]> for ClearValue {
#[inline]
- fn from(val: [u32; 2]) -> ClearValue {
- ClearValue::Uint([val[0], val[1], 0, 0]) // TODO: is alpha value 0 correct?
+ fn from(val: [u32; 2]) -> Self {
+ Self::Uint([val[0], val[1], 0, 0]) // TODO: is alpha value 0 correct?
}
}
impl From<[u32; 3]> for ClearValue {
#[inline]
- fn from(val: [u32; 3]) -> ClearValue {
- ClearValue::Uint([val[0], val[1], val[2], 0]) // TODO: is alpha value 0 correct?
+ fn from(val: [u32; 3]) -> Self {
+ Self::Uint([val[0], val[1], val[2], 0]) // TODO: is alpha value 0 correct?
}
}
impl From<[u32; 4]> for ClearValue {
#[inline]
- fn from(val: [u32; 4]) -> ClearValue {
- ClearValue::Uint(val)
+ fn from(val: [u32; 4]) -> Self {
+ Self::Uint(val)
}
}
impl From<[i32; 1]> for ClearValue {
#[inline]
- fn from(val: [i32; 1]) -> ClearValue {
- ClearValue::Int([val[0], 0, 0, 0]) // TODO: is alpha value 0 correct?
+ fn from(val: [i32; 1]) -> Self {
+ Self::Int([val[0], 0, 0, 0]) // TODO: is alpha value 0 correct?
}
}
impl From<[i32; 2]> for ClearValue {
#[inline]
- fn from(val: [i32; 2]) -> ClearValue {
- ClearValue::Int([val[0], val[1], 0, 0]) // TODO: is alpha value 0 correct?
+ fn from(val: [i32; 2]) -> Self {
+ Self::Int([val[0], val[1], 0, 0]) // TODO: is alpha value 0 correct?
}
}
impl From<[i32; 3]> for ClearValue {
#[inline]
- fn from(val: [i32; 3]) -> ClearValue {
- ClearValue::Int([val[0], val[1], val[2], 0]) // TODO: is alpha value 0 correct?
+ fn from(val: [i32; 3]) -> Self {
+ Self::Int([val[0], val[1], val[2], 0]) // TODO: is alpha value 0 correct?
}
}
impl From<[i32; 4]> for ClearValue {
#[inline]
- fn from(val: [i32; 4]) -> ClearValue {
- ClearValue::Int(val)
+ fn from(val: [i32; 4]) -> Self {
+ Self::Int(val)
}
}
impl From<f32> for ClearValue {
#[inline]
- fn from(val: f32) -> ClearValue {
- ClearValue::Depth(val)
+ fn from(val: f32) -> Self {
+ Self::Depth(val)
}
}
impl From<u32> for ClearValue {
#[inline]
- fn from(val: u32) -> ClearValue {
- ClearValue::Stencil(val)
+ fn from(val: u32) -> Self {
+ Self::Stencil(val)
}
}
impl From<(f32, u32)> for ClearValue {
#[inline]
- fn from(val: (f32, u32)) -> ClearValue {
- ClearValue::DepthStencil(val)
+ fn from(val: (f32, u32)) -> Self {
+ Self::DepthStencil(val)
}
}
-// TODO: remove once no longer needed
-pub unsafe trait ClearValuesTuple {
- type Iter: Iterator<Item = ClearValue>;
- fn iter(self) -> Self::Iter;
+/// A value that will be used to clear a color image.
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum ClearColorValue {
+ /// Value for formats with a numeric type that is not `SINT` or `UINT`.
+ Float([f32; 4]),
+ /// Value for formats with a numeric type of `SINT`.
+ Int([i32; 4]),
+ /// Value for formats with a numeric type of `UINT`.
+ Uint([u32; 4]),
}
-macro_rules! impl_clear_values_tuple {
- ($first:ident $($others:ident)+) => (
- #[allow(non_snake_case)]
- unsafe impl<$first $(, $others)*> ClearValuesTuple for ($first, $($others,)+)
- where $first: Into<ClearValue> $(, $others: Into<ClearValue>)*
- {
- type Iter = VecIntoIter<ClearValue>;
- #[inline]
- fn iter(self) -> VecIntoIter<ClearValue> {
- let ($first, $($others,)+) = self;
- vec![
- $first.into() $(, $others.into())+
- ].into_iter()
- }
+impl From<ClearColorValue> for ash::vk::ClearColorValue {
+ #[inline]
+ fn from(val: ClearColorValue) -> Self {
+ match val {
+ ClearColorValue::Float(float32) => Self { float32 },
+ ClearColorValue::Int(int32) => Self { int32 },
+ ClearColorValue::Uint(uint32) => Self { uint32 },
}
+ }
+}
- impl_clear_values_tuple!($($others)*);
- );
-
- ($first:ident) => (
- unsafe impl<$first> ClearValuesTuple for ($first,)
- where $first: Into<ClearValue>
- {
- type Iter = VecIntoIter<ClearValue>;
- #[inline]
- fn iter(self) -> VecIntoIter<ClearValue> {
- vec![self.0.into()].into_iter()
- }
+impl From<[f32; 1]> for ClearColorValue {
+ #[inline]
+ fn from(val: [f32; 1]) -> Self {
+ Self::Float([val[0], 0.0, 0.0, 1.0])
+ }
+}
+
+impl From<[f32; 2]> for ClearColorValue {
+ #[inline]
+ fn from(val: [f32; 2]) -> Self {
+ Self::Float([val[0], val[1], 0.0, 1.0])
+ }
+}
+
+impl From<[f32; 3]> for ClearColorValue {
+ #[inline]
+ fn from(val: [f32; 3]) -> Self {
+ Self::Float([val[0], val[1], val[2], 1.0])
+ }
+}
+
+impl From<[f32; 4]> for ClearColorValue {
+ #[inline]
+ fn from(val: [f32; 4]) -> Self {
+ Self::Float(val)
+ }
+}
+
+impl From<[i32; 1]> for ClearColorValue {
+ #[inline]
+ fn from(val: [i32; 1]) -> Self {
+ Self::Int([val[0], 0, 0, 1])
+ }
+}
+
+impl From<[i32; 2]> for ClearColorValue {
+ #[inline]
+ fn from(val: [i32; 2]) -> Self {
+ Self::Int([val[0], val[1], 0, 1])
+ }
+}
+
+impl From<[i32; 3]> for ClearColorValue {
+ #[inline]
+ fn from(val: [i32; 3]) -> Self {
+ Self::Int([val[0], val[1], val[2], 1])
+ }
+}
+
+impl From<[i32; 4]> for ClearColorValue {
+ #[inline]
+ fn from(val: [i32; 4]) -> Self {
+ Self::Int(val)
+ }
+}
+
+impl From<[u32; 1]> for ClearColorValue {
+ #[inline]
+ fn from(val: [u32; 1]) -> Self {
+ Self::Uint([val[0], 0, 0, 1])
+ }
+}
+
+impl From<[u32; 2]> for ClearColorValue {
+ #[inline]
+ fn from(val: [u32; 2]) -> Self {
+ Self::Uint([val[0], val[1], 0, 1])
+ }
+}
+
+impl From<[u32; 3]> for ClearColorValue {
+ #[inline]
+ fn from(val: [u32; 3]) -> Self {
+ Self::Uint([val[0], val[1], val[2], 1])
+ }
+}
+
+impl From<[u32; 4]> for ClearColorValue {
+ #[inline]
+ fn from(val: [u32; 4]) -> Self {
+ Self::Uint(val)
+ }
+}
+
+/// A value that will be used to clear a depth/stencil image.
+#[derive(Clone, Copy, Debug, Default, PartialEq)]
+pub struct ClearDepthStencilValue {
+ /// Value for the depth component.
+ pub depth: f32,
+ /// Value for the stencil component.
+ pub stencil: u32,
+}
+
+impl From<ClearDepthStencilValue> for ash::vk::ClearDepthStencilValue {
+ #[inline]
+ fn from(val: ClearDepthStencilValue) -> Self {
+ Self {
+ depth: val.depth,
+ stencil: val.stencil,
}
- );
+ }
}
-impl_clear_values_tuple!(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z);
+impl From<f32> for ClearDepthStencilValue {
+ #[inline]
+ fn from(depth: f32) -> Self {
+ Self { depth, stencil: 0 }
+ }
+}
-/// The properties of an image format that are supported by a physical device.
-#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
+impl From<u32> for ClearDepthStencilValue {
+ #[inline]
+ fn from(stencil: u32) -> Self {
+ Self {
+ depth: 0.0,
+ stencil,
+ }
+ }
+}
+
+impl From<(f32, u32)> for ClearDepthStencilValue {
+ #[inline]
+ fn from((depth, stencil): (f32, u32)) -> Self {
+ Self { depth, stencil }
+ }
+}
+
+/// The properties of a format that are supported by a physical device.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct FormatProperties {
/// Features available for images with linear tiling.
pub linear_tiling_features: FormatFeatures,
@@ -689,71 +717,265 @@ pub struct FormatProperties {
/// Features available for buffers.
pub buffer_features: FormatFeatures,
+
+ pub _ne: crate::NonExhaustive,
}
-/// The features supported by images with a particular format.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
-#[allow(missing_docs)]
-pub struct FormatFeatures {
- pub sampled_image: bool,
- pub storage_image: bool,
- pub storage_image_atomic: bool,
- pub uniform_texel_buffer: bool,
- pub storage_texel_buffer: bool,
- pub storage_texel_buffer_atomic: bool,
- pub vertex_buffer: bool,
- pub color_attachment: bool,
- pub color_attachment_blend: bool,
- pub depth_stencil_attachment: bool,
- pub blit_src: bool,
- pub blit_dst: bool,
- pub sampled_image_filter_linear: bool,
- pub transfer_src: bool,
- pub transfer_dst: bool,
- pub midpoint_chroma_samples: bool,
- pub sampled_image_ycbcr_conversion_linear_filter: bool,
- pub sampled_image_ycbcr_conversion_separate_reconstruction_filter: bool,
- pub sampled_image_ycbcr_conversion_chroma_reconstruction_explicit: bool,
- pub sampled_image_ycbcr_conversion_chroma_reconstruction_explicit_forceable: bool,
- pub disjoint: bool,
- pub cosited_chroma_samples: bool,
- pub sampled_image_filter_minmax: bool,
- pub img_sampled_image_filter_cubic: bool,
- pub khr_acceleration_structure_vertex_buffer: bool,
- pub ext_fragment_density_map: bool,
+impl Default for FormatProperties {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ linear_tiling_features: Default::default(),
+ optimal_tiling_features: Default::default(),
+ buffer_features: Default::default(),
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+impl FormatProperties {
+ /// Returns the potential format features, following the definition of
+ /// <https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap43.html#potential-format-features>.
+ #[inline]
+ pub fn potential_format_features(&self) -> FormatFeatures {
+ self.linear_tiling_features | self.optimal_tiling_features
+ }
+}
+
+vulkan_bitflags! {
+ #[non_exhaustive]
+
+ /// The features supported by a device for an image or buffer with a particular format.
+ FormatFeatures = FormatFeatureFlags2(u64);
+
+ /* Image usage */
+
+ /// Can be used with a sampled image descriptor.
+ SAMPLED_IMAGE = SAMPLED_IMAGE,
+
+ /// Can be used with a storage image descriptor.
+ STORAGE_IMAGE = STORAGE_IMAGE,
+
+ /// Can be used with a storage image descriptor with atomic operations in a shader.
+ STORAGE_IMAGE_ATOMIC = STORAGE_IMAGE_ATOMIC,
+
+ /// Can be used with a storage image descriptor for reading, without specifying a format on the
+ /// image view.
+ STORAGE_READ_WITHOUT_FORMAT = STORAGE_READ_WITHOUT_FORMAT {
+ api_version: V1_3,
+ device_extensions: [khr_format_feature_flags2],
+ },
+
+ /// Can be used with a storage image descriptor for writing, without specifying a format on the
+ /// image view.
+ STORAGE_WRITE_WITHOUT_FORMAT = STORAGE_WRITE_WITHOUT_FORMAT {
+ api_version: V1_3,
+ device_extensions: [khr_format_feature_flags2],
+ },
+
+ /// Can be used with a color attachment in a framebuffer, or with an input attachment
+ /// descriptor.
+ COLOR_ATTACHMENT = COLOR_ATTACHMENT,
+
+ /// Can be used with a color attachment in a framebuffer with blending, or with an input
+ /// attachment descriptor.
+ COLOR_ATTACHMENT_BLEND = COLOR_ATTACHMENT_BLEND,
+
+ /// Can be used with a depth/stencil attachment in a framebuffer, or with an input attachment
+ /// descriptor.
+ DEPTH_STENCIL_ATTACHMENT = DEPTH_STENCIL_ATTACHMENT,
+
+ /// Can be used with a fragment density map attachment in a framebuffer.
+ FRAGMENT_DENSITY_MAP = FRAGMENT_DENSITY_MAP_EXT {
+ device_extensions: [ext_fragment_density_map],
+ },
+
+ /// Can be used with a fragment shading rate attachment in a framebuffer.
+ FRAGMENT_SHADING_RATE_ATTACHMENT = FRAGMENT_SHADING_RATE_ATTACHMENT_KHR {
+ device_extensions: [khr_fragment_shading_rate],
+ },
+
+ /// Can be used with the source image in a transfer (copy) operation.
+ TRANSFER_SRC = TRANSFER_SRC {
+ api_version: V1_1,
+ device_extensions: [khr_maintenance1],
+ },
+
+ /// Can be used with the destination image in a transfer (copy) operation.
+ TRANSFER_DST = TRANSFER_DST {
+ api_version: V1_1,
+ device_extensions: [khr_maintenance1],
+ },
+
+ /// Can be used with the source image in a blit operation.
+ BLIT_SRC = BLIT_SRC,
+
+ /// Can be used with the destination image in a blit operation.
+ BLIT_DST = BLIT_DST,
+
+ /* Sampling */
+
+ /// Can be used with samplers or as a blit source, using the
+ /// [`Linear`](crate::sampler::Filter::Linear) filter.
+ SAMPLED_IMAGE_FILTER_LINEAR = SAMPLED_IMAGE_FILTER_LINEAR,
+
+ /// Can be used with samplers or as a blit source, using the
+ /// [`Cubic`](crate::sampler::Filter::Cubic) filter.
+ SAMPLED_IMAGE_FILTER_CUBIC = SAMPLED_IMAGE_FILTER_CUBIC_EXT {
+ device_extensions: [ext_filter_cubic, img_filter_cubic],
+ },
+
+ /// Can be used with samplers using a reduction mode of
+ /// [`Min`](crate::sampler::SamplerReductionMode::Min) or
+ /// [`Max`](crate::sampler::SamplerReductionMode::Max).
+ SAMPLED_IMAGE_FILTER_MINMAX = SAMPLED_IMAGE_FILTER_MINMAX {
+ api_version: V1_2,
+ device_extensions: [ext_sampler_filter_minmax],
+ },
+
+ /// Can be used with sampler YCbCr conversions using a chroma offset of
+ /// [`Midpoint`](crate::sampler::ycbcr::ChromaLocation::Midpoint).
+ MIDPOINT_CHROMA_SAMPLES = MIDPOINT_CHROMA_SAMPLES {
+ api_version: V1_1,
+ device_extensions: [khr_sampler_ycbcr_conversion],
+ },
+
+ /// Can be used with sampler YCbCr conversions using a chroma offset of
+ /// [`CositedEven`](crate::sampler::ycbcr::ChromaLocation::CositedEven).
+ COSITED_CHROMA_SAMPLES = COSITED_CHROMA_SAMPLES {
+ api_version: V1_1,
+ device_extensions: [khr_sampler_ycbcr_conversion],
+ },
+
+ /// Can be used with sampler YCbCr conversions using the
+ /// [`Linear`](crate::sampler::Filter::Linear) chroma filter.
+ SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER = SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER {
+ api_version: V1_1,
+ device_extensions: [khr_sampler_ycbcr_conversion],
+ },
+
+ /// Can be used with sampler YCbCr conversions whose chroma filter differs from the filters of
+ /// the base sampler.
+ SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER = SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER {
+ api_version: V1_1,
+ device_extensions: [khr_sampler_ycbcr_conversion],
+ },
+
+ /// When used with a sampler YCbCr conversion, the implementation will always perform
+ /// explicit chroma reconstruction.
+ SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT = SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT {
+ api_version: V1_1,
+ device_extensions: [khr_sampler_ycbcr_conversion],
+ },
+
+ /// Can be used with sampler YCbCr conversions with forced explicit reconstruction.
+ SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE = SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE {
+ api_version: V1_1,
+ device_extensions: [khr_sampler_ycbcr_conversion],
+ },
+
+ /// Can be used with samplers using depth comparison.
+ SAMPLED_IMAGE_DEPTH_COMPARISON = SAMPLED_IMAGE_DEPTH_COMPARISON {
+ api_version: V1_3,
+ device_extensions: [khr_format_feature_flags2],
+ },
+
+ /* Video */
+
+ /// Can be used with the output image of a video decode operation.
+ VIDEO_DECODE_OUTPUT = VIDEO_DECODE_OUTPUT_KHR {
+ device_extensions: [khr_video_decode_queue],
+ },
+
+ /// Can be used with the DPB image of a video decode operation.
+ VIDEO_DECODE_DPB = VIDEO_DECODE_DPB_KHR {
+ device_extensions: [khr_video_decode_queue],
+ },
+
+ /// Can be used with the input image of a video encode operation.
+ VIDEO_ENCODE_INPUT = VIDEO_ENCODE_INPUT_KHR {
+ device_extensions: [khr_video_encode_queue],
+ },
+
+ /// Can be used with the DPB image of a video encode operation.
+ VIDEO_ENCODE_DPB = VIDEO_ENCODE_DPB_KHR {
+ device_extensions: [khr_video_encode_queue],
+ },
+
+ /* Misc image features */
+
+ /// For multi-planar formats, can be used with images created with the [`DISJOINT`] flag.
+ ///
+ /// [`DISJOINT`]: crate::image::ImageCreateFlags::DISJOINT
+ DISJOINT = DISJOINT {
+ api_version: V1_1,
+ device_extensions: [khr_sampler_ycbcr_conversion],
+ },
+
+ // TODO: document
+ LINEAR_COLOR_ATTACHMENT = LINEAR_COLOR_ATTACHMENT_NV {
+ device_extensions: [nv_linear_color_attachment],
+ },
+
+ // TODO: document
+ WEIGHT_IMAGE = WEIGHT_IMAGE_QCOM {
+ device_extensions: [qcom_image_processing],
+ },
+
+ // TODO: document
+ WEIGHT_SAMPLED_IMAGE = WEIGHT_SAMPLED_IMAGE_QCOM {
+ device_extensions: [qcom_image_processing],
+ },
+
+ // TODO: document
+ BLOCK_MATCHING = BLOCK_MATCHING_QCOM {
+ device_extensions: [qcom_image_processing],
+ },
+
+ // TODO: document
+ BOX_FILTER_SAMPLED = BOX_FILTER_SAMPLED_QCOM {
+ device_extensions: [qcom_image_processing],
+ },
+
+ // TODO: document
+ OPTICAL_FLOW_IMAGE = OPTICAL_FLOW_IMAGE_NV {
+ device_extensions: [nv_optical_flow],
+ },
+
+ // TODO: document
+ OPTICAL_FLOW_VECTOR = OPTICAL_FLOW_VECTOR_NV {
+ device_extensions: [nv_optical_flow],
+ },
+
+ // TODO: document
+ OPTICAL_FLOW_COST = OPTICAL_FLOW_COST_NV {
+ device_extensions: [nv_optical_flow],
+ },
+
+ /* Buffer usage */
+
+ /// Can be used with a uniform texel buffer descriptor.
+ UNIFORM_TEXEL_BUFFER = UNIFORM_TEXEL_BUFFER,
+
+ /// Can be used with a storage texel buffer descriptor.
+ STORAGE_TEXEL_BUFFER = STORAGE_TEXEL_BUFFER,
+
+ /// Can be used with a storage texel buffer descriptor with atomic operations in a shader.
+ STORAGE_TEXEL_BUFFER_ATOMIC = STORAGE_TEXEL_BUFFER_ATOMIC,
+
+ /// Can be used as the format of a vertex attribute in the vertex input state of a graphics
+ /// pipeline.
+ VERTEX_BUFFER = VERTEX_BUFFER,
+
+ /// Can be used with the vertex buffer of an acceleration structure.
+ ACCELERATION_STRUCTURE_VERTEX_BUFFER = ACCELERATION_STRUCTURE_VERTEX_BUFFER_KHR {
+ device_extensions: [khr_acceleration_structure],
+ },
}
impl From<ash::vk::FormatFeatureFlags> for FormatFeatures {
#[inline]
- #[rustfmt::skip]
- fn from(val: ash::vk::FormatFeatureFlags) -> FormatFeatures {
- FormatFeatures {
- sampled_image: !(val & ash::vk::FormatFeatureFlags::SAMPLED_IMAGE).is_empty(),
- storage_image: !(val & ash::vk::FormatFeatureFlags::STORAGE_IMAGE).is_empty(),
- storage_image_atomic: !(val & ash::vk::FormatFeatureFlags::STORAGE_IMAGE_ATOMIC).is_empty(),
- uniform_texel_buffer: !(val & ash::vk::FormatFeatureFlags::UNIFORM_TEXEL_BUFFER).is_empty(),
- storage_texel_buffer: !(val & ash::vk::FormatFeatureFlags::STORAGE_TEXEL_BUFFER).is_empty(),
- storage_texel_buffer_atomic: !(val & ash::vk::FormatFeatureFlags::STORAGE_TEXEL_BUFFER_ATOMIC).is_empty(),
- vertex_buffer: !(val & ash::vk::FormatFeatureFlags::VERTEX_BUFFER).is_empty(),
- color_attachment: !(val & ash::vk::FormatFeatureFlags::COLOR_ATTACHMENT).is_empty(),
- color_attachment_blend: !(val & ash::vk::FormatFeatureFlags::COLOR_ATTACHMENT_BLEND).is_empty(),
- depth_stencil_attachment: !(val & ash::vk::FormatFeatureFlags::DEPTH_STENCIL_ATTACHMENT).is_empty(),
- blit_src: !(val & ash::vk::FormatFeatureFlags::BLIT_SRC).is_empty(),
- blit_dst: !(val & ash::vk::FormatFeatureFlags::BLIT_DST).is_empty(),
- sampled_image_filter_linear: !(val & ash::vk::FormatFeatureFlags::SAMPLED_IMAGE_FILTER_LINEAR).is_empty(),
- transfer_src: !(val & ash::vk::FormatFeatureFlags::TRANSFER_SRC).is_empty(),
- transfer_dst: !(val & ash::vk::FormatFeatureFlags::TRANSFER_DST).is_empty(),
- midpoint_chroma_samples: !(val & ash::vk::FormatFeatureFlags::MIDPOINT_CHROMA_SAMPLES).is_empty(),
- sampled_image_ycbcr_conversion_linear_filter: !(val & ash::vk::FormatFeatureFlags::SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER).is_empty(),
- sampled_image_ycbcr_conversion_separate_reconstruction_filter: !(val & ash::vk::FormatFeatureFlags::SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER).is_empty(),
- sampled_image_ycbcr_conversion_chroma_reconstruction_explicit: !(val & ash::vk::FormatFeatureFlags::SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT).is_empty(),
- sampled_image_ycbcr_conversion_chroma_reconstruction_explicit_forceable: !(val & ash::vk::FormatFeatureFlags::SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE).is_empty(),
- disjoint: !(val & ash::vk::FormatFeatureFlags::DISJOINT).is_empty(),
- cosited_chroma_samples: !(val & ash::vk::FormatFeatureFlags::COSITED_CHROMA_SAMPLES).is_empty(),
- sampled_image_filter_minmax: !(val & ash::vk::FormatFeatureFlags::SAMPLED_IMAGE_FILTER_MINMAX).is_empty(),
- img_sampled_image_filter_cubic: !(val & ash::vk::FormatFeatureFlags::SAMPLED_IMAGE_FILTER_CUBIC_IMG).is_empty(),
- khr_acceleration_structure_vertex_buffer: !(val & ash::vk::FormatFeatureFlags::ACCELERATION_STRUCTURE_VERTEX_BUFFER_KHR).is_empty(),
- ext_fragment_density_map: !(val & ash::vk::FormatFeatureFlags::FRAGMENT_DENSITY_MAP_EXT).is_empty(),
- }
+ fn from(val: ash::vk::FormatFeatureFlags) -> Self {
+ Self::from(ash::vk::FormatFeatureFlags2::from_raw(val.as_raw() as u64))
}
}
diff --git a/src/image/aspect.rs b/src/image/aspect.rs
index 41d834e..849d8d3 100644
--- a/src/image/aspect.rs
+++ b/src/image/aspect.rs
@@ -7,139 +7,90 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use std::ops::BitOr;
+use crate::macros::vulkan_bitflags_enum;
-/// An individual data type within an image.
-///
-/// Most images have only the `Color` aspect, but some may have several.
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-#[repr(u32)]
-pub enum ImageAspect {
- Color = ash::vk::ImageAspectFlags::COLOR.as_raw(),
- Depth = ash::vk::ImageAspectFlags::DEPTH.as_raw(),
- Stencil = ash::vk::ImageAspectFlags::STENCIL.as_raw(),
- Metadata = ash::vk::ImageAspectFlags::METADATA.as_raw(),
- Plane0 = ash::vk::ImageAspectFlags::PLANE_0.as_raw(),
- Plane1 = ash::vk::ImageAspectFlags::PLANE_1.as_raw(),
- Plane2 = ash::vk::ImageAspectFlags::PLANE_2.as_raw(),
- MemoryPlane0 = ash::vk::ImageAspectFlags::MEMORY_PLANE_0_EXT.as_raw(),
- MemoryPlane1 = ash::vk::ImageAspectFlags::MEMORY_PLANE_1_EXT.as_raw(),
- MemoryPlane2 = ash::vk::ImageAspectFlags::MEMORY_PLANE_2_EXT.as_raw(),
-}
+vulkan_bitflags_enum! {
+ #[non_exhaustive]
-impl From<ImageAspect> for ash::vk::ImageAspectFlags {
- #[inline]
- fn from(val: ImageAspect) -> Self {
- Self::from_raw(val as u32)
- }
-}
+ /// A set of [`ImageAspect`] values.
+ ImageAspects,
-/// A mask specifying one or more `ImageAspect`s.
-#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
-pub struct ImageAspects {
- pub color: bool,
- pub depth: bool,
- pub stencil: bool,
- pub metadata: bool,
- pub plane0: bool,
- pub plane1: bool,
- pub plane2: bool,
- pub memory_plane0: bool,
- pub memory_plane1: bool,
- pub memory_plane2: bool,
-}
+ /// An individual data type within an image.
+ ///
+ /// Most images have only the [`Color`] aspect, but some may have others.
+ ///
+ /// [`Color`]: ImageAspect::Color
+ ImageAspect,
-impl ImageAspects {
- /// Builds an `ImageAspect` with all values set to false. Useful as a default value.
- #[inline]
- pub const fn none() -> ImageAspects {
- ImageAspects {
- color: false,
- depth: false,
- stencil: false,
- metadata: false,
- plane0: false,
- plane1: false,
- plane2: false,
- memory_plane0: false,
- memory_plane1: false,
- memory_plane2: false,
- }
- }
-}
+ = ImageAspectFlags(u32);
-impl BitOr for ImageAspects {
- type Output = Self;
+ /// The single aspect of images with a color [format], or the combined aspect of all planes of
+ /// images with a multi-planar format.
+ ///
+ /// [format]: crate::format::Format
+ COLOR, Color = COLOR,
- #[inline]
- fn bitor(self, rhs: Self) -> Self {
- ImageAspects {
- color: self.color || rhs.color,
- depth: self.depth || rhs.depth,
- stencil: self.stencil || rhs.stencil,
- metadata: self.metadata || rhs.metadata,
- plane0: self.plane0 || rhs.plane0,
- plane1: self.plane1 || rhs.plane1,
- plane2: self.plane2 || rhs.plane2,
- memory_plane0: self.memory_plane0 || rhs.memory_plane0,
- memory_plane1: self.memory_plane1 || rhs.memory_plane1,
- memory_plane2: self.memory_plane2 || rhs.memory_plane2,
- }
- }
-}
+ /// The single aspect of images with a depth [format], or one of the two aspects of images
+ /// with a combined depth/stencil format.
+ ///
+ /// [format]: crate::format::Format
+ DEPTH, Depth = DEPTH,
-impl From<ImageAspects> for ash::vk::ImageAspectFlags {
- #[inline]
- fn from(value: ImageAspects) -> ash::vk::ImageAspectFlags {
- let mut result = ash::vk::ImageAspectFlags::empty();
- if value.color {
- result |= ash::vk::ImageAspectFlags::COLOR;
- }
- if value.depth {
- result |= ash::vk::ImageAspectFlags::DEPTH;
- }
- if value.stencil {
- result |= ash::vk::ImageAspectFlags::STENCIL;
- }
- if value.metadata {
- result |= ash::vk::ImageAspectFlags::METADATA;
- }
- if value.plane0 {
- result |= ash::vk::ImageAspectFlags::PLANE_0;
- }
- if value.plane1 {
- result |= ash::vk::ImageAspectFlags::PLANE_1;
- }
- if value.plane2 {
- result |= ash::vk::ImageAspectFlags::PLANE_2;
- }
- if value.memory_plane0 {
- result |= ash::vk::ImageAspectFlags::MEMORY_PLANE_0_EXT;
- }
- if value.memory_plane1 {
- result |= ash::vk::ImageAspectFlags::MEMORY_PLANE_1_EXT;
- }
- if value.memory_plane2 {
- result |= ash::vk::ImageAspectFlags::MEMORY_PLANE_2_EXT
- }
- result
- }
-}
+ /// The single aspect of images with a stencil [format], or one of the two aspects of images
+ /// with a combined depth/stencil format.
+ ///
+ /// [format]: crate::format::Format
+ STENCIL, Stencil = STENCIL,
+
+ /// An aspect used with sparse memory on some implementations, to hold implementation-defined
+ /// metadata of an image.
+ METADATA, Metadata = METADATA,
+
+ /// The first plane of an image with a multi-planar [format], holding the green color component.
+ ///
+ /// [format]: crate::format::Format
+ PLANE_0, Plane0 = PLANE_0 {
+ api_version: V1_1,
+ device_extensions: [khr_sampler_ycbcr_conversion],
+ },
+
+ /// The second plane of an image with a multi-planar [format], holding the blue color component
+ /// if the format has three planes, and a combination of blue and red if the format has two
+ /// planes.
+ ///
+ /// [format]: crate::format::Format
+ PLANE_1, Plane1 = PLANE_1 {
+ api_version: V1_1,
+ device_extensions: [khr_sampler_ycbcr_conversion],
+ },
+
+ /// The third plane of an image with a multi-planar [format], holding the red color component.
+ PLANE_2, Plane2 = PLANE_2 {
+ api_version: V1_1,
+ device_extensions: [khr_sampler_ycbcr_conversion],
+ },
+
+ /// The first memory plane of images created through the [`ext_image_drm_format_modifier`]
+ /// extension.
+ ///
+ /// [`ext_image_drm_format_modifier`]: crate::device::DeviceExtensions::ext_image_drm_format_modifier
+ MEMORY_PLANE_0, MemoryPlane0 = MEMORY_PLANE_0_EXT {
+ device_extensions: [ext_image_drm_format_modifier],
+ },
+
+ /// The second memory plane of images created through the [`ext_image_drm_format_modifier`]
+ /// extension.
+ ///
+ /// [`ext_image_drm_format_modifier`]: crate::device::DeviceExtensions::ext_image_drm_format_modifier
+ MEMORY_PLANE_1, MemoryPlane1 = MEMORY_PLANE_1_EXT {
+ device_extensions: [ext_image_drm_format_modifier],
+ },
-impl From<ash::vk::ImageAspectFlags> for ImageAspects {
- #[inline]
- fn from(val: ash::vk::ImageAspectFlags) -> ImageAspects {
- ImageAspects {
- color: !(val & ash::vk::ImageAspectFlags::COLOR).is_empty(),
- depth: !(val & ash::vk::ImageAspectFlags::DEPTH).is_empty(),
- stencil: !(val & ash::vk::ImageAspectFlags::STENCIL).is_empty(),
- metadata: !(val & ash::vk::ImageAspectFlags::METADATA).is_empty(),
- plane0: !(val & ash::vk::ImageAspectFlags::PLANE_0).is_empty(),
- plane1: !(val & ash::vk::ImageAspectFlags::PLANE_1).is_empty(),
- plane2: !(val & ash::vk::ImageAspectFlags::PLANE_2).is_empty(),
- memory_plane0: !(val & ash::vk::ImageAspectFlags::MEMORY_PLANE_0_EXT).is_empty(),
- memory_plane1: !(val & ash::vk::ImageAspectFlags::MEMORY_PLANE_1_EXT).is_empty(),
- memory_plane2: !(val & ash::vk::ImageAspectFlags::MEMORY_PLANE_2_EXT).is_empty(),
- }
- }
+ /// The third memory plane of images created through the [`ext_image_drm_format_modifier`]
+ /// extension.
+ ///
+ /// [`ext_image_drm_format_modifier`]: crate::device::DeviceExtensions::ext_image_drm_format_modifier
+ MEMORY_PLANE_2, MemoryPlane2 = MEMORY_PLANE_2_EXT {
+ device_extensions: [ext_image_drm_format_modifier],
+ },
}
diff --git a/src/image/attachment.rs b/src/image/attachment.rs
index 5892d3c..1a4faaf 100644
--- a/src/image/attachment.rs
+++ b/src/image/attachment.rs
@@ -7,39 +7,34 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use crate::device::Device;
-use crate::format::ClearValue;
-use crate::format::Format;
-use crate::format::FormatTy;
-use crate::image::sys::ImageCreationError;
-use crate::image::sys::UnsafeImage;
-use crate::image::traits::ImageAccess;
-use crate::image::traits::ImageClearValue;
-use crate::image::traits::ImageContent;
-use crate::image::ImageCreateFlags;
-use crate::image::ImageDescriptorLayouts;
-use crate::image::ImageDimensions;
-use crate::image::ImageInner;
-use crate::image::ImageLayout;
-use crate::image::ImageUsage;
-use crate::image::SampleCount;
-use crate::memory::pool::AllocFromRequirementsFilter;
-use crate::memory::pool::AllocLayout;
-use crate::memory::pool::MappingRequirement;
-use crate::memory::pool::MemoryPool;
-use crate::memory::pool::MemoryPoolAlloc;
-use crate::memory::pool::PotentialDedicatedAllocation;
-use crate::memory::pool::StdMemoryPoolAlloc;
-use crate::memory::DedicatedAlloc;
-use crate::sync::AccessError;
-use crate::sync::Sharing;
-use std::hash::Hash;
-use std::hash::Hasher;
-use std::iter::Empty;
-use std::sync::atomic::AtomicBool;
-use std::sync::atomic::AtomicUsize;
-use std::sync::atomic::Ordering;
-use std::sync::Arc;
+use super::{
+ sys::{Image, ImageMemory, RawImage},
+ traits::ImageContent,
+ ImageAccess, ImageAspects, ImageDescriptorLayouts, ImageError, ImageInner, ImageLayout,
+ ImageUsage, SampleCount,
+};
+use crate::{
+ device::{Device, DeviceOwned},
+ format::Format,
+ image::{sys::ImageCreateInfo, ImageCreateFlags, ImageDimensions, ImageFormatInfo},
+ memory::{
+ allocator::{
+ AllocationCreateInfo, AllocationType, MemoryAllocatePreference, MemoryAllocator,
+ MemoryUsage,
+ },
+ is_aligned, DedicatedAllocation, DeviceMemoryError, ExternalMemoryHandleType,
+ ExternalMemoryHandleTypes,
+ },
+ DeviceSize,
+};
+use std::{
+ fs::File,
+ hash::{Hash, Hasher},
+ sync::{
+ atomic::{AtomicBool, Ordering},
+ Arc,
+ },
+};
/// ImageAccess whose purpose is to be used as a framebuffer attachment.
///
@@ -71,15 +66,8 @@ use std::sync::Arc;
///
// TODO: forbid reading transient images outside render passes?
#[derive(Debug)]
-pub struct AttachmentImage<A = PotentialDedicatedAllocation<StdMemoryPoolAlloc>> {
- // Inner implementation.
- image: UnsafeImage,
-
- // Memory used to back the image.
- memory: A,
-
- // Format.
- format: Format,
+pub struct AttachmentImage {
+ inner: Arc<Image>,
// Layout to use when the image is used as a framebuffer attachment.
// Must be either "depth-stencil optimal" or "color optimal".
@@ -87,10 +75,7 @@ pub struct AttachmentImage<A = PotentialDedicatedAllocation<StdMemoryPoolAlloc>>
// If true, then the image is in the layout of `attachment_layout` (above). If false, then it
// is still `Undefined`.
- initialized: AtomicBool,
-
- // Number of times this image is locked on the GPU side.
- gpu_lock: AtomicUsize,
+ layout_initialized: AtomicBool,
}
impl AttachmentImage {
@@ -100,16 +85,16 @@ impl AttachmentImage {
/// format as a framebuffer attachment.
#[inline]
pub fn new(
- device: Arc<Device>,
+ allocator: &(impl MemoryAllocator + ?Sized),
dimensions: [u32; 2],
format: Format,
- ) -> Result<Arc<AttachmentImage>, ImageCreationError> {
+ ) -> Result<Arc<AttachmentImage>, ImageError> {
AttachmentImage::new_impl(
- device,
+ allocator,
dimensions,
1,
format,
- ImageUsage::none(),
+ ImageUsage::empty(),
SampleCount::Sample1,
)
}
@@ -119,17 +104,14 @@ impl AttachmentImage {
/// > **Note**: This function is just a convenient shortcut for `with_usage`.
#[inline]
pub fn input_attachment(
- device: Arc<Device>,
+ allocator: &(impl MemoryAllocator + ?Sized),
dimensions: [u32; 2],
format: Format,
- ) -> Result<Arc<AttachmentImage>, ImageCreationError> {
- let base_usage = ImageUsage {
- input_attachment: true,
- ..ImageUsage::none()
- };
+ ) -> Result<Arc<AttachmentImage>, ImageError> {
+ let base_usage = ImageUsage::INPUT_ATTACHMENT;
AttachmentImage::new_impl(
- device,
+ allocator,
dimensions,
1,
format,
@@ -144,12 +126,19 @@ impl AttachmentImage {
/// > want a regular image.
#[inline]
pub fn multisampled(
- device: Arc<Device>,
+ allocator: &(impl MemoryAllocator + ?Sized),
dimensions: [u32; 2],
samples: SampleCount,
format: Format,
- ) -> Result<Arc<AttachmentImage>, ImageCreationError> {
- AttachmentImage::new_impl(device, dimensions, 1, format, ImageUsage::none(), samples)
+ ) -> Result<Arc<AttachmentImage>, ImageError> {
+ AttachmentImage::new_impl(
+ allocator,
+ dimensions,
+ 1,
+ format,
+ ImageUsage::empty(),
+ samples,
+ )
}
/// Same as `multisampled`, but creates an image that can be used as an input attachment.
@@ -157,17 +146,14 @@ impl AttachmentImage {
/// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`.
#[inline]
pub fn multisampled_input_attachment(
- device: Arc<Device>,
+ allocator: &(impl MemoryAllocator + ?Sized),
dimensions: [u32; 2],
samples: SampleCount,
format: Format,
- ) -> Result<Arc<AttachmentImage>, ImageCreationError> {
- let base_usage = ImageUsage {
- input_attachment: true,
- ..ImageUsage::none()
- };
+ ) -> Result<Arc<AttachmentImage>, ImageError> {
+ let base_usage = ImageUsage::INPUT_ATTACHMENT;
- AttachmentImage::new_impl(device, dimensions, 1, format, base_usage, samples)
+ AttachmentImage::new_impl(allocator, dimensions, 1, format, base_usage, samples)
}
/// Same as `new`, but lets you specify additional usages.
@@ -177,12 +163,19 @@ impl AttachmentImage {
/// addition to these two.
#[inline]
pub fn with_usage(
- device: Arc<Device>,
+ allocator: &(impl MemoryAllocator + ?Sized),
dimensions: [u32; 2],
format: Format,
usage: ImageUsage,
- ) -> Result<Arc<AttachmentImage>, ImageCreationError> {
- AttachmentImage::new_impl(device, dimensions, 1, format, usage, SampleCount::Sample1)
+ ) -> Result<Arc<AttachmentImage>, ImageError> {
+ AttachmentImage::new_impl(
+ allocator,
+ dimensions,
+ 1,
+ format,
+ usage,
+ SampleCount::Sample1,
+ )
}
/// Same as `with_usage`, but creates a multisampled image.
@@ -191,13 +184,13 @@ impl AttachmentImage {
/// > want a regular image.
#[inline]
pub fn multisampled_with_usage(
- device: Arc<Device>,
+ allocator: &(impl MemoryAllocator + ?Sized),
dimensions: [u32; 2],
samples: SampleCount,
format: Format,
usage: ImageUsage,
- ) -> Result<Arc<AttachmentImage>, ImageCreationError> {
- AttachmentImage::new_impl(device, dimensions, 1, format, usage, samples)
+ ) -> Result<Arc<AttachmentImage>, ImageError> {
+ AttachmentImage::new_impl(allocator, dimensions, 1, format, usage, samples)
}
/// Same as `multisampled_with_usage`, but creates an image with multiple layers.
@@ -206,14 +199,14 @@ impl AttachmentImage {
/// > want a regular image.
#[inline]
pub fn multisampled_with_usage_with_layers(
- device: Arc<Device>,
+ allocator: &(impl MemoryAllocator + ?Sized),
dimensions: [u32; 2],
array_layers: u32,
samples: SampleCount,
format: Format,
usage: ImageUsage,
- ) -> Result<Arc<AttachmentImage>, ImageCreationError> {
- AttachmentImage::new_impl(device, dimensions, array_layers, format, usage, samples)
+ ) -> Result<Arc<AttachmentImage>, ImageError> {
+ AttachmentImage::new_impl(allocator, dimensions, array_layers, format, usage, samples)
}
/// Same as `new`, except that the image can later be sampled.
@@ -221,17 +214,14 @@ impl AttachmentImage {
/// > **Note**: This function is just a convenient shortcut for `with_usage`.
#[inline]
pub fn sampled(
- device: Arc<Device>,
+ allocator: &(impl MemoryAllocator + ?Sized),
dimensions: [u32; 2],
format: Format,
- ) -> Result<Arc<AttachmentImage>, ImageCreationError> {
- let base_usage = ImageUsage {
- sampled: true,
- ..ImageUsage::none()
- };
+ ) -> Result<Arc<AttachmentImage>, ImageError> {
+ let base_usage = ImageUsage::SAMPLED;
AttachmentImage::new_impl(
- device,
+ allocator,
dimensions,
1,
format,
@@ -245,18 +235,14 @@ impl AttachmentImage {
/// > **Note**: This function is just a convenient shortcut for `with_usage`.
#[inline]
pub fn sampled_input_attachment(
- device: Arc<Device>,
+ allocator: &(impl MemoryAllocator + ?Sized),
dimensions: [u32; 2],
format: Format,
- ) -> Result<Arc<AttachmentImage>, ImageCreationError> {
- let base_usage = ImageUsage {
- sampled: true,
- input_attachment: true,
- ..ImageUsage::none()
- };
+ ) -> Result<Arc<AttachmentImage>, ImageError> {
+ let base_usage = ImageUsage::SAMPLED | ImageUsage::INPUT_ATTACHMENT;
AttachmentImage::new_impl(
- device,
+ allocator,
dimensions,
1,
format,
@@ -273,17 +259,14 @@ impl AttachmentImage {
/// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`.
#[inline]
pub fn sampled_multisampled(
- device: Arc<Device>,
+ allocator: &(impl MemoryAllocator + ?Sized),
dimensions: [u32; 2],
samples: SampleCount,
format: Format,
- ) -> Result<Arc<AttachmentImage>, ImageCreationError> {
- let base_usage = ImageUsage {
- sampled: true,
- ..ImageUsage::none()
- };
+ ) -> Result<Arc<AttachmentImage>, ImageError> {
+ let base_usage = ImageUsage::SAMPLED;
- AttachmentImage::new_impl(device, dimensions, 1, format, base_usage, samples)
+ AttachmentImage::new_impl(allocator, dimensions, 1, format, base_usage, samples)
}
/// Same as `sampled_multisampled`, but creates an image that can be used as an input
@@ -292,18 +275,14 @@ impl AttachmentImage {
/// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`.
#[inline]
pub fn sampled_multisampled_input_attachment(
- device: Arc<Device>,
+ allocator: &(impl MemoryAllocator + ?Sized),
dimensions: [u32; 2],
samples: SampleCount,
format: Format,
- ) -> Result<Arc<AttachmentImage>, ImageCreationError> {
- let base_usage = ImageUsage {
- sampled: true,
- input_attachment: true,
- ..ImageUsage::none()
- };
+ ) -> Result<Arc<AttachmentImage>, ImageError> {
+ let base_usage = ImageUsage::SAMPLED | ImageUsage::INPUT_ATTACHMENT;
- AttachmentImage::new_impl(device, dimensions, 1, format, base_usage, samples)
+ AttachmentImage::new_impl(allocator, dimensions, 1, format, base_usage, samples)
}
/// Same as `new`, except that the image will be transient.
@@ -314,17 +293,14 @@ impl AttachmentImage {
/// > **Note**: This function is just a convenient shortcut for `with_usage`.
#[inline]
pub fn transient(
- device: Arc<Device>,
+ allocator: &(impl MemoryAllocator + ?Sized),
dimensions: [u32; 2],
format: Format,
- ) -> Result<Arc<AttachmentImage>, ImageCreationError> {
- let base_usage = ImageUsage {
- transient_attachment: true,
- ..ImageUsage::none()
- };
+ ) -> Result<Arc<AttachmentImage>, ImageError> {
+ let base_usage = ImageUsage::TRANSIENT_ATTACHMENT;
AttachmentImage::new_impl(
- device,
+ allocator,
dimensions,
1,
format,
@@ -338,18 +314,14 @@ impl AttachmentImage {
/// > **Note**: This function is just a convenient shortcut for `with_usage`.
#[inline]
pub fn transient_input_attachment(
- device: Arc<Device>,
+ allocator: &(impl MemoryAllocator + ?Sized),
dimensions: [u32; 2],
format: Format,
- ) -> Result<Arc<AttachmentImage>, ImageCreationError> {
- let base_usage = ImageUsage {
- transient_attachment: true,
- input_attachment: true,
- ..ImageUsage::none()
- };
+ ) -> Result<Arc<AttachmentImage>, ImageError> {
+ let base_usage = ImageUsage::TRANSIENT_ATTACHMENT | ImageUsage::INPUT_ATTACHMENT;
AttachmentImage::new_impl(
- device,
+ allocator,
dimensions,
1,
format,
@@ -366,17 +338,14 @@ impl AttachmentImage {
/// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`.
#[inline]
pub fn transient_multisampled(
- device: Arc<Device>,
+ allocator: &(impl MemoryAllocator + ?Sized),
dimensions: [u32; 2],
samples: SampleCount,
format: Format,
- ) -> Result<Arc<AttachmentImage>, ImageCreationError> {
- let base_usage = ImageUsage {
- transient_attachment: true,
- ..ImageUsage::none()
- };
+ ) -> Result<Arc<AttachmentImage>, ImageError> {
+ let base_usage = ImageUsage::TRANSIENT_ATTACHMENT;
- AttachmentImage::new_impl(device, dimensions, 1, format, base_usage, samples)
+ AttachmentImage::new_impl(allocator, dimensions, 1, format, base_usage, samples)
}
/// Same as `transient_multisampled`, but creates an image that can be used as an input
@@ -385,116 +354,246 @@ impl AttachmentImage {
/// > **Note**: This function is just a convenient shortcut for `multisampled_with_usage`.
#[inline]
pub fn transient_multisampled_input_attachment(
- device: Arc<Device>,
+ allocator: &(impl MemoryAllocator + ?Sized),
dimensions: [u32; 2],
samples: SampleCount,
format: Format,
- ) -> Result<Arc<AttachmentImage>, ImageCreationError> {
- let base_usage = ImageUsage {
- transient_attachment: true,
- input_attachment: true,
- ..ImageUsage::none()
- };
+ ) -> Result<Arc<AttachmentImage>, ImageError> {
+ let base_usage = ImageUsage::TRANSIENT_ATTACHMENT | ImageUsage::INPUT_ATTACHMENT;
- AttachmentImage::new_impl(device, dimensions, 1, format, base_usage, samples)
+ AttachmentImage::new_impl(allocator, dimensions, 1, format, base_usage, samples)
}
// All constructors dispatch to this one.
fn new_impl(
- device: Arc<Device>,
+ allocator: &(impl MemoryAllocator + ?Sized),
dimensions: [u32; 2],
array_layers: u32,
format: Format,
- base_usage: ImageUsage,
+ mut usage: ImageUsage,
samples: SampleCount,
- ) -> Result<Arc<AttachmentImage>, ImageCreationError> {
- // TODO: check dimensions against the max_framebuffer_width/height/layers limits
-
- let is_depth = match format.ty() {
- FormatTy::Depth => true,
- FormatTy::DepthStencil => true,
- FormatTy::Stencil => true,
- FormatTy::Compressed => panic!(),
- _ => false,
- };
+ ) -> Result<Arc<AttachmentImage>, ImageError> {
+ let physical_device = allocator.device().physical_device();
+ let device_properties = physical_device.properties();
- let usage = ImageUsage {
- color_attachment: !is_depth,
- depth_stencil_attachment: is_depth,
- ..base_usage
- };
+ if dimensions[0] > device_properties.max_framebuffer_height {
+ panic!("AttachmentImage height exceeds physical device's max_framebuffer_height");
+ }
+ if dimensions[1] > device_properties.max_framebuffer_width {
+ panic!("AttachmentImage width exceeds physical device's max_framebuffer_width");
+ }
+ if array_layers > device_properties.max_framebuffer_layers {
+ panic!("AttachmentImage layer count exceeds physical device's max_framebuffer_layers");
+ }
- let (image, mem_reqs) = unsafe {
- let dims = ImageDimensions::Dim2d {
- width: dimensions[0],
- height: dimensions[1],
- array_layers,
- };
+ let aspects = format.aspects();
+ let is_depth_stencil = aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL);
- UnsafeImage::new(
- device.clone(),
- usage,
- format,
- ImageCreateFlags::none(),
- dims,
+ if is_depth_stencil {
+ usage -= ImageUsage::COLOR_ATTACHMENT;
+ usage |= ImageUsage::DEPTH_STENCIL_ATTACHMENT;
+ } else {
+ usage |= ImageUsage::COLOR_ATTACHMENT;
+ usage -= ImageUsage::DEPTH_STENCIL_ATTACHMENT;
+ }
+
+ if format.compression().is_some() {
+ panic!() // TODO: message?
+ }
+
+ let raw_image = RawImage::new(
+ allocator.device().clone(),
+ ImageCreateInfo {
+ dimensions: ImageDimensions::Dim2d {
+ width: dimensions[0],
+ height: dimensions[1],
+ array_layers,
+ },
+ format: Some(format),
samples,
- 1,
- Sharing::Exclusive::<Empty<u32>>,
- false,
- false,
- )?
+ usage,
+ ..Default::default()
+ },
+ )?;
+ let requirements = raw_image.memory_requirements()[0];
+ let res = unsafe {
+ allocator.allocate_unchecked(
+ requirements,
+ AllocationType::NonLinear,
+ AllocationCreateInfo {
+ usage: MemoryUsage::DeviceOnly,
+ allocate_preference: MemoryAllocatePreference::Unknown,
+ _ne: crate::NonExhaustive(()),
+ },
+ Some(DedicatedAllocation::Image(&raw_image)),
+ )
};
- let memory = MemoryPool::alloc_from_requirements(
- &Device::standard_pool(&device),
- &mem_reqs,
- AllocLayout::Optimal,
- MappingRequirement::DoNotMap,
- DedicatedAlloc::Image(&image),
- |t| {
- if t.is_device_local() {
- AllocFromRequirementsFilter::Preferred
- } else {
- AllocFromRequirementsFilter::Allowed
- }
+ match res {
+ Ok(alloc) => {
+ debug_assert!(is_aligned(alloc.offset(), requirements.layout.alignment()));
+ debug_assert!(alloc.size() == requirements.layout.size());
+
+ let inner = Arc::new(
+ unsafe { raw_image.bind_memory_unchecked([alloc]) }
+ .map_err(|(err, _, _)| err)?,
+ );
+
+ Ok(Arc::new(AttachmentImage {
+ inner,
+ attachment_layout: if is_depth_stencil {
+ ImageLayout::DepthStencilAttachmentOptimal
+ } else {
+ ImageLayout::ColorAttachmentOptimal
+ },
+ layout_initialized: AtomicBool::new(false),
+ }))
+ }
+ Err(err) => Err(err.into()),
+ }
+ }
+
+ pub fn new_with_exportable_fd(
+ allocator: &(impl MemoryAllocator + ?Sized),
+ dimensions: [u32; 2],
+ array_layers: u32,
+ format: Format,
+ mut usage: ImageUsage,
+ samples: SampleCount,
+ ) -> Result<Arc<AttachmentImage>, ImageError> {
+ let physical_device = allocator.device().physical_device();
+ let device_properties = physical_device.properties();
+
+ if dimensions[0] > device_properties.max_framebuffer_height {
+ panic!("AttachmentImage height exceeds physical device's max_framebuffer_height");
+ }
+ if dimensions[1] > device_properties.max_framebuffer_width {
+ panic!("AttachmentImage width exceeds physical device's max_framebuffer_width");
+ }
+ if array_layers > device_properties.max_framebuffer_layers {
+ panic!("AttachmentImage layer count exceeds physical device's max_framebuffer_layers");
+ }
+
+ let aspects = format.aspects();
+ let is_depth_stencil = aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL);
+
+ if is_depth_stencil {
+ usage -= ImageUsage::COLOR_ATTACHMENT;
+ usage |= ImageUsage::DEPTH_STENCIL_ATTACHMENT;
+ } else {
+ usage |= ImageUsage::COLOR_ATTACHMENT;
+ usage -= ImageUsage::DEPTH_STENCIL_ATTACHMENT;
+ }
+
+ let external_memory_properties = allocator
+ .device()
+ .physical_device()
+ .image_format_properties(ImageFormatInfo {
+ flags: ImageCreateFlags::MUTABLE_FORMAT,
+ format: Some(format),
+ usage,
+ external_memory_handle_type: Some(ExternalMemoryHandleType::OpaqueFd),
+ ..Default::default()
+ })
+ .unwrap()
+ .unwrap()
+ .external_memory_properties;
+ // VUID-VkExportMemoryAllocateInfo-handleTypes-00656
+ assert!(external_memory_properties.exportable);
+
+ // VUID-VkMemoryAllocateInfo-pNext-00639
+ // Guaranteed because we always create a dedicated allocation
+
+ let external_memory_handle_types = ExternalMemoryHandleTypes::OPAQUE_FD;
+ let raw_image = RawImage::new(
+ allocator.device().clone(),
+ ImageCreateInfo {
+ flags: ImageCreateFlags::MUTABLE_FORMAT,
+ dimensions: ImageDimensions::Dim2d {
+ width: dimensions[0],
+ height: dimensions[1],
+ array_layers,
+ },
+ format: Some(format),
+ samples,
+ usage,
+ external_memory_handle_types,
+ ..Default::default()
},
)?;
- debug_assert!((memory.offset() % mem_reqs.alignment) == 0);
- unsafe {
- image.bind_memory(memory.memory(), memory.offset())?;
+ let requirements = raw_image.memory_requirements()[0];
+ let memory_type_index = allocator
+ .find_memory_type_index(
+ requirements.memory_type_bits,
+ MemoryUsage::DeviceOnly.into(),
+ )
+ .expect("failed to find a suitable memory type");
+
+ match unsafe {
+ allocator.allocate_dedicated_unchecked(
+ memory_type_index,
+ requirements.layout.size(),
+ Some(DedicatedAllocation::Image(&raw_image)),
+ external_memory_handle_types,
+ )
+ } {
+ Ok(alloc) => {
+ debug_assert!(is_aligned(alloc.offset(), requirements.layout.alignment()));
+ debug_assert!(alloc.size() == requirements.layout.size());
+
+ let inner = Arc::new(unsafe {
+ raw_image
+ .bind_memory_unchecked([alloc])
+ .map_err(|(err, _, _)| err)?
+ });
+
+ Ok(Arc::new(AttachmentImage {
+ inner,
+ attachment_layout: if is_depth_stencil {
+ ImageLayout::DepthStencilAttachmentOptimal
+ } else {
+ ImageLayout::ColorAttachmentOptimal
+ },
+ layout_initialized: AtomicBool::new(false),
+ }))
+ }
+ Err(err) => Err(err.into()),
}
+ }
- Ok(Arc::new(AttachmentImage {
- image,
- memory,
- format,
- attachment_layout: if is_depth {
- ImageLayout::DepthStencilAttachmentOptimal
- } else {
- ImageLayout::ColorAttachmentOptimal
- },
- initialized: AtomicBool::new(false),
- gpu_lock: AtomicUsize::new(0),
- }))
+ /// Exports posix file descriptor for the allocated memory.
+ /// Requires `khr_external_memory_fd` and `khr_external_memory` extensions to be loaded.
+ #[inline]
+ pub fn export_posix_fd(&self) -> Result<File, DeviceMemoryError> {
+ let allocation = match self.inner.memory() {
+ ImageMemory::Normal(a) => &a[0],
+ _ => unreachable!(),
+ };
+
+ allocation
+ .device_memory()
+ .export_fd(ExternalMemoryHandleType::OpaqueFd)
}
-}
-impl<A> AttachmentImage<A> {
- /// Returns the dimensions of the image.
+ /// Return the size of the allocated memory (used e.g. with cuda).
#[inline]
- pub fn dimensions(&self) -> [u32; 2] {
- let dims = self.image.dimensions();
- [dims.width(), dims.height()]
+ pub fn mem_size(&self) -> DeviceSize {
+ let allocation = match self.inner.memory() {
+ ImageMemory::Normal(a) => &a[0],
+ _ => unreachable!(),
+ };
+
+ allocation.device_memory().allocation_size()
}
}
-unsafe impl<A> ImageAccess for AttachmentImage<A> {
+unsafe impl ImageAccess for AttachmentImage {
#[inline]
- fn inner(&self) -> ImageInner {
+ fn inner(&self) -> ImageInner<'_> {
ImageInner {
- image: &self.image,
+ image: &self.inner,
first_layer: 0,
- num_layers: self.image.dimensions().array_layers() as usize,
+ num_layers: self.inner.dimensions().array_layers(),
first_mipmap_level: 0,
num_mipmap_levels: 1,
}
@@ -513,7 +612,7 @@ unsafe impl<A> ImageAccess for AttachmentImage<A> {
#[inline]
fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
Some(ImageDescriptorLayouts {
- storage_image: ImageLayout::ShaderReadOnlyOptimal,
+ storage_image: ImageLayout::General,
combined_image_sampler: ImageLayout::ShaderReadOnlyOptimal,
sampled_image: ImageLayout::ShaderReadOnlyOptimal,
input_attachment: ImageLayout::ShaderReadOnlyOptimal,
@@ -521,139 +620,69 @@ unsafe impl<A> ImageAccess for AttachmentImage<A> {
}
#[inline]
- fn conflict_key(&self) -> u64 {
- self.image.key()
- }
-
- #[inline]
- fn try_gpu_lock(
- &self,
- _: bool,
- uninitialized_safe: bool,
- expected_layout: ImageLayout,
- ) -> Result<(), AccessError> {
- if expected_layout != self.attachment_layout && expected_layout != ImageLayout::Undefined {
- if self.initialized.load(Ordering::SeqCst) {
- return Err(AccessError::UnexpectedImageLayout {
- requested: expected_layout,
- allowed: self.attachment_layout,
- });
- } else {
- return Err(AccessError::UnexpectedImageLayout {
- requested: expected_layout,
- allowed: ImageLayout::Undefined,
- });
- }
- }
-
- if !uninitialized_safe && expected_layout != ImageLayout::Undefined {
- if !self.initialized.load(Ordering::SeqCst) {
- return Err(AccessError::ImageNotInitialized {
- requested: expected_layout,
- });
- }
- }
-
- if self
- .gpu_lock
- .compare_exchange(0, 1, Ordering::SeqCst, Ordering::SeqCst)
- .unwrap_or_else(|e| e)
- == 0
- {
- Ok(())
- } else {
- Err(AccessError::AlreadyInUse)
- }
- }
-
- #[inline]
- unsafe fn increase_gpu_lock(&self) {
- let val = self.gpu_lock.fetch_add(1, Ordering::SeqCst);
- debug_assert!(val >= 1);
- }
-
- #[inline]
- unsafe fn unlock(&self, new_layout: Option<ImageLayout>) {
- if let Some(new_layout) = new_layout {
- debug_assert_eq!(new_layout, self.attachment_layout);
- self.initialized.store(true, Ordering::SeqCst);
- }
-
- let prev_val = self.gpu_lock.fetch_sub(1, Ordering::SeqCst);
- debug_assert!(prev_val >= 1);
- }
-
- #[inline]
unsafe fn layout_initialized(&self) {
- self.initialized.store(true, Ordering::SeqCst);
+ self.layout_initialized.store(true, Ordering::SeqCst);
}
#[inline]
fn is_layout_initialized(&self) -> bool {
- self.initialized.load(Ordering::SeqCst)
- }
-
- #[inline]
- fn current_miplevels_access(&self) -> std::ops::Range<u32> {
- 0..self.mipmap_levels()
- }
-
- #[inline]
- fn current_layer_levels_access(&self) -> std::ops::Range<u32> {
- 0..1
+ self.layout_initialized.load(Ordering::SeqCst)
}
}
-unsafe impl<A> ImageClearValue<ClearValue> for Arc<AttachmentImage<A>> {
+unsafe impl DeviceOwned for AttachmentImage {
#[inline]
- fn decode(&self, value: ClearValue) -> Option<ClearValue> {
- Some(self.format.decode_clear_value(value))
+ fn device(&self) -> &Arc<Device> {
+ self.inner.device()
}
}
-unsafe impl<P, A> ImageContent<P> for Arc<AttachmentImage<A>> {
- #[inline]
+unsafe impl<P> ImageContent<P> for AttachmentImage {
fn matches_format(&self) -> bool {
true // FIXME:
}
}
-impl<A> PartialEq for AttachmentImage<A> {
+impl PartialEq for AttachmentImage {
#[inline]
fn eq(&self, other: &Self) -> bool {
- ImageAccess::inner(self) == ImageAccess::inner(other)
+ self.inner() == other.inner()
}
}
-impl<A> Eq for AttachmentImage<A> {}
+impl Eq for AttachmentImage {}
-impl<A> Hash for AttachmentImage<A> {
- #[inline]
+impl Hash for AttachmentImage {
fn hash<H: Hasher>(&self, state: &mut H) {
- ImageAccess::inner(self).hash(state);
+ self.inner().hash(state);
}
}
#[cfg(test)]
mod tests {
- use super::AttachmentImage;
- use crate::format::Format;
+ use super::*;
+ use crate::memory::allocator::StandardMemoryAllocator;
#[test]
fn create_regular() {
let (device, _) = gfx_dev_and_queue!();
- let _img = AttachmentImage::new(device, [32, 32], Format::R8G8B8A8Unorm).unwrap();
+ let memory_allocator = StandardMemoryAllocator::new_default(device);
+ let _img =
+ AttachmentImage::new(&memory_allocator, [32, 32], Format::R8G8B8A8_UNORM).unwrap();
}
#[test]
fn create_transient() {
let (device, _) = gfx_dev_and_queue!();
- let _img = AttachmentImage::transient(device, [32, 32], Format::R8G8B8A8Unorm).unwrap();
+ let memory_allocator = StandardMemoryAllocator::new_default(device);
+ let _img = AttachmentImage::transient(&memory_allocator, [32, 32], Format::R8G8B8A8_UNORM)
+ .unwrap();
}
#[test]
fn d16_unorm_always_supported() {
let (device, _) = gfx_dev_and_queue!();
- let _img = AttachmentImage::new(device, [32, 32], Format::D16Unorm).unwrap();
+ let memory_allocator = StandardMemoryAllocator::new_default(device);
+ let _img = AttachmentImage::new(&memory_allocator, [32, 32], Format::D16_UNORM).unwrap();
}
}
diff --git a/src/image/immutable.rs b/src/image/immutable.rs
index 6a6e093..4250379 100644
--- a/src/image/immutable.rs
+++ b/src/image/immutable.rs
@@ -7,112 +7,49 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use crate::buffer::BufferAccess;
-use crate::buffer::BufferUsage;
-use crate::buffer::CpuAccessibleBuffer;
-use crate::buffer::TypedBufferAccess;
-use crate::command_buffer::AutoCommandBufferBuilder;
-use crate::command_buffer::CommandBufferExecFuture;
-use crate::command_buffer::CommandBufferUsage;
-use crate::command_buffer::PrimaryAutoCommandBuffer;
-use crate::command_buffer::PrimaryCommandBuffer;
-use crate::device::physical::QueueFamily;
-use crate::device::Device;
-use crate::device::Queue;
-use crate::format::Format;
-use crate::format::Pixel;
-use crate::image::sys::ImageCreationError;
-use crate::image::sys::UnsafeImage;
-use crate::image::traits::ImageAccess;
-use crate::image::traits::ImageContent;
-use crate::image::ImageCreateFlags;
-use crate::image::ImageDescriptorLayouts;
-use crate::image::ImageDimensions;
-use crate::image::ImageInner;
-use crate::image::ImageLayout;
-use crate::image::ImageUsage;
-use crate::image::MipmapsCount;
-use crate::image::SampleCount;
-use crate::memory::pool::AllocFromRequirementsFilter;
-use crate::memory::pool::AllocLayout;
-use crate::memory::pool::MappingRequirement;
-use crate::memory::pool::MemoryPool;
-use crate::memory::pool::MemoryPoolAlloc;
-use crate::memory::pool::PotentialDedicatedAllocation;
-use crate::memory::pool::StdMemoryPoolAlloc;
-use crate::memory::DedicatedAlloc;
-use crate::sampler::Filter;
-use crate::sync::AccessError;
-use crate::sync::NowFuture;
-use crate::sync::Sharing;
-use smallvec::SmallVec;
-use std::hash::Hash;
-use std::hash::Hasher;
-use std::sync::atomic::AtomicBool;
-use std::sync::atomic::Ordering;
-use std::sync::Arc;
+use super::{
+ sys::{Image, RawImage},
+ traits::ImageContent,
+ ImageAccess, ImageCreateFlags, ImageDescriptorLayouts, ImageDimensions, ImageError, ImageInner,
+ ImageLayout, ImageSubresourceLayers, ImageUsage, MipmapsCount,
+};
+use crate::{
+ buffer::{Buffer, BufferContents, BufferCreateInfo, BufferError, BufferUsage, Subbuffer},
+ command_buffer::{
+ allocator::CommandBufferAllocator, AutoCommandBufferBuilder, BlitImageInfo,
+ BufferImageCopy, CommandBufferBeginError, CopyBufferToImageInfo, ImageBlit,
+ },
+ device::{Device, DeviceOwned},
+ format::Format,
+ image::sys::ImageCreateInfo,
+ memory::{
+ allocator::{
+ AllocationCreateInfo, AllocationCreationError, AllocationType,
+ MemoryAllocatePreference, MemoryAllocator, MemoryUsage,
+ },
+ is_aligned, DedicatedAllocation,
+ },
+ sampler::Filter,
+ sync::Sharing,
+ DeviceSize, VulkanError,
+};
+use smallvec::{smallvec, SmallVec};
+use std::{
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+ hash::{Hash, Hasher},
+ sync::Arc,
+};
/// Image whose purpose is to be used for read-only purposes. You can write to the image once,
/// but then you must only ever read from it.
// TODO: type (2D, 3D, array, etc.) as template parameter
#[derive(Debug)]
-pub struct ImmutableImage<A = PotentialDedicatedAllocation<StdMemoryPoolAlloc>> {
- image: UnsafeImage,
- dimensions: ImageDimensions,
- memory: A,
- format: Format,
- initialized: AtomicBool,
- layout: ImageLayout,
-}
-
-/// Image whose purpose is to access only a part of one image, for any kind of access
-/// We define a part of one image here by a level of mipmap, or a layer of an array
-/// The image attribute must be an implementation of ImageAccess
-/// The mip_levels_access must be a range showing which mipmaps will be accessed
-/// The layer_levels_access must be a range showing which layers will be accessed
-/// The layout must be the layout of the image at the beginning and at the end of the command buffer
-pub struct SubImage {
- image: Arc<dyn ImageAccess + Sync + Send>,
- mip_levels_access: std::ops::Range<u32>,
- layer_levels_access: std::ops::Range<u32>,
+pub struct ImmutableImage {
+ inner: Arc<Image>,
layout: ImageLayout,
}
-impl SubImage {
- pub fn new(
- image: Arc<dyn ImageAccess + Sync + Send>,
- mip_level: u32,
- mip_level_count: u32,
- layer_level: u32,
- layer_level_count: u32,
- layout: ImageLayout,
- ) -> Arc<SubImage> {
- debug_assert!(mip_level + mip_level_count <= image.mipmap_levels());
- debug_assert!(layer_level + layer_level_count <= image.dimensions().array_layers());
-
- let last_level = mip_level + mip_level_count;
- let mip_levels_access = mip_level..last_level;
-
- let last_level = layer_level + layer_level_count;
- let layer_levels_access = layer_level..last_level;
-
- Arc::new(SubImage {
- image,
- mip_levels_access,
- layer_levels_access,
- layout: ImageLayout::ShaderReadOnlyOptimal,
- })
- }
-}
-
-// Must not implement Clone, as that would lead to multiple `used` values.
-pub struct ImmutableImageInitialization<A = PotentialDedicatedAllocation<StdMemoryPoolAlloc>> {
- image: Arc<ImmutableImage<A>>,
- used: AtomicBool,
- mip_levels_access: std::ops::Range<u32>,
- layer_levels_access: std::ops::Range<u32>,
-}
-
fn has_mipmaps(mipmaps: MipmapsCount) -> bool {
match mipmaps {
MipmapsCount::One => false,
@@ -121,340 +58,277 @@ fn has_mipmaps(mipmaps: MipmapsCount) -> bool {
}
}
-fn generate_mipmaps<L, Img>(
- cbb: &mut AutoCommandBufferBuilder<L>,
- image: Arc<Img>,
+fn generate_mipmaps<L, Cba>(
+ cbb: &mut AutoCommandBufferBuilder<L, Cba>,
+ image: Arc<dyn ImageAccess>,
dimensions: ImageDimensions,
- layout: ImageLayout,
+ _layout: ImageLayout,
) where
- Img: ImageAccess + Send + Sync + 'static,
+ Cba: CommandBufferAllocator,
{
- for level in 1..image.mipmap_levels() {
- let [xs, ys, ds] = dimensions
- .mipmap_dimensions(level - 1)
+ for level in 1..image.mip_levels() {
+ let src_size = dimensions
+ .mip_level_dimensions(level - 1)
.unwrap()
.width_height_depth();
- let [xd, yd, dd] = dimensions
- .mipmap_dimensions(level)
+ let dst_size = dimensions
+ .mip_level_dimensions(level)
.unwrap()
.width_height_depth();
- let src = SubImage::new(
- image.clone(),
- level - 1,
- 1,
- 0,
- dimensions.array_layers(),
- layout,
- );
-
- let dst = SubImage::new(
- image.clone(),
- level,
- 1,
- 0,
- dimensions.array_layers(),
- layout,
- );
-
- cbb.blit_image(
- src, //source
- [0, 0, 0], //source_top_left
- [xs as i32, ys as i32, ds as i32], //source_bottom_right
- 0, //source_base_array_layer
- level - 1, //source_mip_level
- dst, //destination
- [0, 0, 0], //destination_top_left
- [xd as i32, yd as i32, dd as i32], //destination_bottom_right
- 0, //destination_base_array_layer
- level, //destination_mip_level
- 1, //layer_count
- Filter::Linear, //filter
- )
+ cbb.blit_image(BlitImageInfo {
+ regions: [ImageBlit {
+ src_subresource: ImageSubresourceLayers {
+ mip_level: level - 1,
+ ..image.subresource_layers()
+ },
+ src_offsets: [[0; 3], src_size],
+ dst_subresource: ImageSubresourceLayers {
+ mip_level: level,
+ ..image.subresource_layers()
+ },
+ dst_offsets: [[0; 3], dst_size],
+ ..Default::default()
+ }]
+ .into(),
+ filter: Filter::Linear,
+ ..BlitImageInfo::images(image.clone(), image.clone())
+ })
.expect("failed to blit a mip map to image!");
}
}
impl ImmutableImage {
- #[deprecated(note = "use ImmutableImage::uninitialized instead")]
- #[inline]
- pub fn new<'a, I>(
- device: Arc<Device>,
- dimensions: ImageDimensions,
- format: Format,
- queue_families: I,
- ) -> Result<Arc<ImmutableImage>, ImageCreationError>
- where
- I: IntoIterator<Item = QueueFamily<'a>>,
- {
- #[allow(deprecated)]
- ImmutableImage::with_mipmaps(
- device,
- dimensions,
- format,
- MipmapsCount::One,
- queue_families,
- )
- }
-
- #[deprecated(note = "use ImmutableImage::uninitialized instead")]
- #[inline]
- pub fn with_mipmaps<'a, I, M>(
- device: Arc<Device>,
- dimensions: ImageDimensions,
- format: Format,
- mipmaps: M,
- queue_families: I,
- ) -> Result<Arc<ImmutableImage>, ImageCreationError>
- where
- I: IntoIterator<Item = QueueFamily<'a>>,
- M: Into<MipmapsCount>,
- {
- let usage = ImageUsage {
- transfer_source: true, // for blits
- transfer_destination: true,
- sampled: true,
- ..ImageUsage::none()
- };
-
- let flags = ImageCreateFlags::none();
-
- let (image, _) = ImmutableImage::uninitialized(
- device,
- dimensions,
- format,
- mipmaps,
- usage,
- flags,
- ImageLayout::ShaderReadOnlyOptimal,
- queue_families,
- )?;
- image.initialized.store(true, Ordering::Relaxed); // Allow uninitialized access for backwards compatibility
- Ok(image)
- }
-
/// Builds an uninitialized immutable image.
///
- /// Returns two things: the image, and a special access that should be used for the initial upload to the image.
- pub fn uninitialized<'a, I, M>(
- device: Arc<Device>,
+ /// Returns two things: the image, and a special access that should be used for the initial
+ /// upload to the image.
+ pub fn uninitialized(
+ allocator: &(impl MemoryAllocator + ?Sized),
dimensions: ImageDimensions,
format: Format,
- mipmaps: M,
+ mip_levels: impl Into<MipmapsCount>,
usage: ImageUsage,
flags: ImageCreateFlags,
layout: ImageLayout,
- queue_families: I,
- ) -> Result<(Arc<ImmutableImage>, ImmutableImageInitialization), ImageCreationError>
- where
- I: IntoIterator<Item = QueueFamily<'a>>,
- M: Into<MipmapsCount>,
+ queue_family_indices: impl IntoIterator<Item = u32>,
+ ) -> Result<(Arc<ImmutableImage>, Arc<ImmutableImageInitialization>), ImmutableImageCreationError>
{
- let queue_families = queue_families
- .into_iter()
- .map(|f| f.id())
- .collect::<SmallVec<[u32; 4]>>();
-
- let (image, mem_reqs) = unsafe {
- let sharing = if queue_families.len() >= 2 {
- Sharing::Concurrent(queue_families.iter().cloned())
- } else {
- Sharing::Exclusive
- };
+ let queue_family_indices: SmallVec<[_; 4]> = queue_family_indices.into_iter().collect();
+ assert!(!flags.intersects(ImageCreateFlags::DISJOINT)); // TODO: adjust the code below to make this safe
- UnsafeImage::new(
- device.clone(),
- usage,
- format,
+ let raw_image = RawImage::new(
+ allocator.device().clone(),
+ ImageCreateInfo {
flags,
dimensions,
- SampleCount::Sample1,
- mipmaps,
- sharing,
- false,
- false,
- )?
- };
-
- let memory = MemoryPool::alloc_from_requirements(
- &Device::standard_pool(&device),
- &mem_reqs,
- AllocLayout::Optimal,
- MappingRequirement::DoNotMap,
- DedicatedAlloc::Image(&image),
- |t| {
- if t.is_device_local() {
- AllocFromRequirementsFilter::Preferred
+ format: Some(format),
+ mip_levels: match mip_levels.into() {
+ MipmapsCount::Specific(num) => num,
+ MipmapsCount::Log2 => dimensions.max_mip_levels(),
+ MipmapsCount::One => 1,
+ },
+ usage,
+ sharing: if queue_family_indices.len() >= 2 {
+ Sharing::Concurrent(queue_family_indices)
} else {
- AllocFromRequirementsFilter::Allowed
- }
+ Sharing::Exclusive
+ },
+ ..Default::default()
},
)?;
- debug_assert!((memory.offset() % mem_reqs.alignment) == 0);
- unsafe {
- image.bind_memory(memory.memory(), memory.offset())?;
- }
+ let requirements = raw_image.memory_requirements()[0];
+ let res = unsafe {
+ allocator.allocate_unchecked(
+ requirements,
+ AllocationType::NonLinear,
+ AllocationCreateInfo {
+ usage: MemoryUsage::DeviceOnly,
+ allocate_preference: MemoryAllocatePreference::Unknown,
+ _ne: crate::NonExhaustive(()),
+ },
+ Some(DedicatedAllocation::Image(&raw_image)),
+ )
+ };
- let image = Arc::new(ImmutableImage {
- image,
- memory,
- dimensions,
- format,
- initialized: AtomicBool::new(false),
- layout,
- });
+ match res {
+ Ok(alloc) => {
+ debug_assert!(is_aligned(alloc.offset(), requirements.layout.alignment()));
+ debug_assert!(alloc.size() == requirements.layout.size());
- let init = ImmutableImageInitialization {
- image: image.clone(),
- used: AtomicBool::new(false),
- mip_levels_access: 0..image.mipmap_levels(),
- layer_levels_access: 0..image.dimensions().array_layers(),
- };
+ let inner = Arc::new(
+ unsafe { raw_image.bind_memory_unchecked([alloc]) }
+ .map_err(|(err, _, _)| err)?,
+ );
+
+ let image = Arc::new(ImmutableImage { inner, layout });
+
+ let init = Arc::new(ImmutableImageInitialization {
+ image: image.clone(),
+ });
- Ok((image, init))
+ Ok((image, init))
+ }
+ Err(err) => Err(err.into()),
+ }
}
/// Construct an ImmutableImage from the contents of `iter`.
- #[inline]
- pub fn from_iter<Px, I>(
+ ///
+ /// This is a convenience function, equivalent to creating a `CpuAccessibleBuffer`, writing
+ /// `iter` to it, then calling [`from_buffer`](ImmutableImage::from_buffer) to copy the data
+ /// over.
+ pub fn from_iter<Px, I, L, A>(
+ allocator: &(impl MemoryAllocator + ?Sized),
iter: I,
dimensions: ImageDimensions,
- mipmaps: MipmapsCount,
+ mip_levels: MipmapsCount,
format: Format,
- queue: Arc<Queue>,
- ) -> Result<
- (
- Arc<Self>,
- CommandBufferExecFuture<NowFuture, PrimaryAutoCommandBuffer>,
- ),
- ImageCreationError,
- >
+ command_buffer_builder: &mut AutoCommandBufferBuilder<L, A>,
+ ) -> Result<Arc<Self>, ImmutableImageCreationError>
where
- Px: Pixel + Send + Sync + Clone + 'static,
- I: ExactSizeIterator<Item = Px>,
+ Px: BufferContents,
+ I: IntoIterator<Item = Px>,
+ I::IntoIter: ExactSizeIterator,
+ A: CommandBufferAllocator,
{
- let source = CpuAccessibleBuffer::from_iter(
- queue.device().clone(),
- BufferUsage::transfer_source(),
- false,
+ let source = Buffer::from_iter(
+ allocator,
+ BufferCreateInfo {
+ usage: BufferUsage::TRANSFER_SRC,
+ ..Default::default()
+ },
+ AllocationCreateInfo {
+ usage: MemoryUsage::Upload,
+ ..Default::default()
+ },
iter,
- )?;
- ImmutableImage::from_buffer(source, dimensions, mipmaps, format, queue)
+ )
+ .map_err(|err| match err {
+ BufferError::AllocError(err) => err,
+ // We don't use sparse-binding, concurrent sharing or external memory, therefore the
+ // other errors can't happen.
+ _ => unreachable!(),
+ })?;
+
+ ImmutableImage::from_buffer(
+ allocator,
+ source,
+ dimensions,
+ mip_levels,
+ format,
+ command_buffer_builder,
+ )
}
/// Construct an ImmutableImage containing a copy of the data in `source`.
- pub fn from_buffer<B, Px>(
- source: B,
+ ///
+ /// This is a convenience function, equivalent to calling
+ /// [`uninitialized`](ImmutableImage::uninitialized) with the queue family index of
+ /// `command_buffer_builder`, then recording a `copy_buffer_to_image` command to
+ /// `command_buffer_builder`.
+ ///
+ /// `command_buffer_builder` can then be used to record other commands, built, and executed as
+ /// normal. If it is not executed, the image contents will be left undefined.
+ pub fn from_buffer<L, A>(
+ allocator: &(impl MemoryAllocator + ?Sized),
+ source: Subbuffer<impl ?Sized>,
dimensions: ImageDimensions,
- mipmaps: MipmapsCount,
+ mip_levels: MipmapsCount,
format: Format,
- queue: Arc<Queue>,
- ) -> Result<
- (
- Arc<Self>,
- CommandBufferExecFuture<NowFuture, PrimaryAutoCommandBuffer>,
- ),
- ImageCreationError,
- >
+ command_buffer_builder: &mut AutoCommandBufferBuilder<L, A>,
+ ) -> Result<Arc<Self>, ImmutableImageCreationError>
where
- B: BufferAccess + TypedBufferAccess<Content = [Px]> + 'static + Clone + Send + Sync,
- Px: Pixel + Send + Sync + Clone + 'static,
+ A: CommandBufferAllocator,
{
- let need_to_generate_mipmaps = has_mipmaps(mipmaps);
- let usage = ImageUsage {
- transfer_destination: true,
- transfer_source: need_to_generate_mipmaps,
- sampled: true,
- ..ImageUsage::none()
+ let region = BufferImageCopy {
+ image_subresource: ImageSubresourceLayers::from_parameters(
+ format,
+ dimensions.array_layers(),
+ ),
+ image_extent: dimensions.width_height_depth(),
+ ..Default::default()
};
- let flags = ImageCreateFlags::none();
+ let required_size = region.buffer_copy_size(format);
+
+ if source.size() < required_size {
+ return Err(ImmutableImageCreationError::SourceTooSmall {
+ source_size: source.size(),
+ required_size,
+ });
+ }
+
+ let need_to_generate_mipmaps = has_mipmaps(mip_levels);
+ let usage = ImageUsage::TRANSFER_DST
+ | ImageUsage::SAMPLED
+ | if need_to_generate_mipmaps {
+ ImageUsage::TRANSFER_SRC
+ } else {
+ ImageUsage::empty()
+ };
+ let flags = ImageCreateFlags::empty();
let layout = ImageLayout::ShaderReadOnlyOptimal;
let (image, initializer) = ImmutableImage::uninitialized(
- source.device().clone(),
+ allocator,
dimensions,
format,
- mipmaps,
+ mip_levels,
usage,
flags,
layout,
- source.device().active_queue_families(),
+ source
+ .device()
+ .active_queue_family_indices()
+ .iter()
+ .copied(),
)?;
- let init = SubImage::new(
- Arc::new(initializer),
- 0,
- 1,
- 0,
- 1,
- ImageLayout::ShaderReadOnlyOptimal,
- );
-
- let mut cbb = AutoCommandBufferBuilder::primary(
- source.device().clone(),
- queue.family(),
- CommandBufferUsage::MultipleSubmit,
- )?;
- cbb.copy_buffer_to_image_dimensions(
- source,
- init,
- [0, 0, 0],
- dimensions.width_height_depth(),
- 0,
- dimensions.array_layers(),
- 0,
- )
- .unwrap();
+ command_buffer_builder
+ .copy_buffer_to_image(CopyBufferToImageInfo {
+ regions: smallvec![region],
+ ..CopyBufferToImageInfo::buffer_image(source, initializer)
+ })
+ .unwrap();
if need_to_generate_mipmaps {
generate_mipmaps(
- &mut cbb,
+ command_buffer_builder,
image.clone(),
- image.dimensions,
+ image.inner.dimensions(),
ImageLayout::ShaderReadOnlyOptimal,
);
}
- let cb = cbb.build().unwrap();
-
- let future = match cb.execute(queue) {
- Ok(f) => f,
- Err(e) => unreachable!("{:?}", e),
- };
-
- image.initialized.store(true, Ordering::Relaxed);
-
- Ok((image, future))
+ Ok(image)
}
}
-impl<A> ImmutableImage<A> {
- /// Returns the dimensions of the image.
- #[inline]
- pub fn dimensions(&self) -> ImageDimensions {
- self.dimensions
- }
-
- /// Returns the number of mipmap levels of the image.
+unsafe impl DeviceOwned for ImmutableImage {
#[inline]
- pub fn mipmap_levels(&self) -> u32 {
- self.image.mipmap_levels()
+ fn device(&self) -> &Arc<Device> {
+ self.inner.device()
}
}
-unsafe impl<A> ImageAccess for ImmutableImage<A> {
+unsafe impl ImageAccess for ImmutableImage {
#[inline]
- fn inner(&self) -> ImageInner {
+ fn inner(&self) -> ImageInner<'_> {
ImageInner {
- image: &self.image,
+ image: &self.inner,
first_layer: 0,
- num_layers: self.image.dimensions().array_layers() as usize,
+ num_layers: self.inner.dimensions().array_layers(),
first_mipmap_level: 0,
- num_mipmap_levels: self.image.mipmap_levels() as usize,
+ num_mipmap_levels: self.inner.mip_levels(),
}
}
#[inline]
+ fn is_layout_initialized(&self) -> bool {
+ true
+ }
+
+ #[inline]
fn initial_layout_requirement(&self) -> ImageLayout {
self.layout
}
@@ -467,237 +341,149 @@ unsafe impl<A> ImageAccess for ImmutableImage<A> {
#[inline]
fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
Some(ImageDescriptorLayouts {
- storage_image: self.layout,
+ storage_image: ImageLayout::General,
combined_image_sampler: self.layout,
sampled_image: self.layout,
input_attachment: self.layout,
})
}
+}
- #[inline]
- fn conflict_key(&self) -> u64 {
- self.image.key()
+unsafe impl<P> ImageContent<P> for ImmutableImage {
+ fn matches_format(&self) -> bool {
+ true // FIXME:
}
+}
+impl PartialEq for ImmutableImage {
#[inline]
- fn try_gpu_lock(
- &self,
- exclusive_access: bool,
- uninitialized_safe: bool,
- expected_layout: ImageLayout,
- ) -> Result<(), AccessError> {
- if expected_layout != self.layout && expected_layout != ImageLayout::Undefined {
- return Err(AccessError::UnexpectedImageLayout {
- requested: expected_layout,
- allowed: self.layout,
- });
- }
-
- if exclusive_access {
- return Err(AccessError::ExclusiveDenied);
- }
-
- if !self.initialized.load(Ordering::Relaxed) {
- return Err(AccessError::BufferNotInitialized);
- }
-
- Ok(())
+ fn eq(&self, other: &Self) -> bool {
+ self.inner() == other.inner()
}
+}
- #[inline]
- unsafe fn increase_gpu_lock(&self) {}
-
- #[inline]
- unsafe fn unlock(&self, new_layout: Option<ImageLayout>) {
- debug_assert!(new_layout.is_none());
- }
+impl Eq for ImmutableImage {}
- #[inline]
- fn current_miplevels_access(&self) -> std::ops::Range<u32> {
- 0..self.mipmap_levels()
+impl Hash for ImmutableImage {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.inner().hash(state);
}
+}
- #[inline]
- fn current_layer_levels_access(&self) -> std::ops::Range<u32> {
- 0..self.dimensions().array_layers()
- }
+// Must not implement Clone, as that would lead to multiple `used` values.
+pub struct ImmutableImageInitialization {
+ image: Arc<ImmutableImage>,
}
-unsafe impl<P, A> ImageContent<P> for ImmutableImage<A> {
+unsafe impl DeviceOwned for ImmutableImageInitialization {
#[inline]
- fn matches_format(&self) -> bool {
- true // FIXME:
+ fn device(&self) -> &Arc<Device> {
+ self.image.device()
}
}
-unsafe impl ImageAccess for SubImage {
+unsafe impl ImageAccess for ImmutableImageInitialization {
#[inline]
- fn inner(&self) -> ImageInner {
+ fn inner(&self) -> ImageInner<'_> {
self.image.inner()
}
#[inline]
fn initial_layout_requirement(&self) -> ImageLayout {
- self.image.initial_layout_requirement()
+ ImageLayout::Undefined
}
#[inline]
fn final_layout_requirement(&self) -> ImageLayout {
- self.image.final_layout_requirement()
+ self.image.layout
}
#[inline]
fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
None
}
-
- fn current_miplevels_access(&self) -> std::ops::Range<u32> {
- self.mip_levels_access.clone()
- }
-
- fn current_layer_levels_access(&self) -> std::ops::Range<u32> {
- self.layer_levels_access.clone()
- }
-
- #[inline]
- fn conflict_key(&self) -> u64 {
- self.image.conflict_key()
- }
-
- #[inline]
- fn try_gpu_lock(
- &self,
- exclusive_access: bool,
- uninitialized_safe: bool,
- expected_layout: ImageLayout,
- ) -> Result<(), AccessError> {
- if expected_layout != self.layout && expected_layout != ImageLayout::Undefined {
- return Err(AccessError::UnexpectedImageLayout {
- requested: expected_layout,
- allowed: self.layout,
- });
- }
-
- Ok(())
- }
-
- #[inline]
- unsafe fn increase_gpu_lock(&self) {
- self.image.increase_gpu_lock()
- }
-
- #[inline]
- unsafe fn unlock(&self, new_layout: Option<ImageLayout>) {
- self.image.unlock(new_layout)
- }
}
-impl<A> PartialEq for ImmutableImage<A> {
+impl PartialEq for ImmutableImageInitialization {
#[inline]
fn eq(&self, other: &Self) -> bool {
- ImageAccess::inner(self) == ImageAccess::inner(other)
+ self.inner() == other.inner()
}
}
-impl<A> Eq for ImmutableImage<A> {}
+impl Eq for ImmutableImageInitialization {}
-impl<A> Hash for ImmutableImage<A> {
- #[inline]
+impl Hash for ImmutableImageInitialization {
fn hash<H: Hasher>(&self, state: &mut H) {
- ImageAccess::inner(self).hash(state);
+ self.inner().hash(state);
}
}
-unsafe impl<A> ImageAccess for ImmutableImageInitialization<A> {
- #[inline]
- fn inner(&self) -> ImageInner {
- ImageAccess::inner(&self.image)
- }
-
- #[inline]
- fn initial_layout_requirement(&self) -> ImageLayout {
- ImageLayout::Undefined
- }
-
- #[inline]
- fn final_layout_requirement(&self) -> ImageLayout {
- self.image.layout
- }
-
- #[inline]
- fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
- None
- }
-
- #[inline]
- fn conflict_key(&self) -> u64 {
- self.image.image.key()
- }
-
- #[inline]
- fn try_gpu_lock(
- &self,
- _: bool,
- uninitialized_safe: bool,
- expected_layout: ImageLayout,
- ) -> Result<(), AccessError> {
- if expected_layout != ImageLayout::Undefined {
- return Err(AccessError::UnexpectedImageLayout {
- requested: expected_layout,
- allowed: ImageLayout::Undefined,
- });
- }
-
- if self.image.initialized.load(Ordering::Relaxed) {
- return Err(AccessError::AlreadyInUse);
- }
+/// Error that can happen when creating an `ImmutableImage`.
+#[derive(Clone, Debug)]
+pub enum ImmutableImageCreationError {
+ ImageCreationError(ImageError),
+ AllocError(AllocationCreationError),
+ CommandBufferBeginError(CommandBufferBeginError),
+
+ /// The size of the provided source data is less than the required size for an image with the
+ /// given format and dimensions.
+ SourceTooSmall {
+ source_size: DeviceSize,
+ required_size: DeviceSize,
+ },
+}
- // FIXME: Mipmapped textures require multiple writes to initialize
- if !self
- .used
- .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
- .unwrap_or_else(|e| e)
- {
- Ok(())
- } else {
- Err(AccessError::AlreadyInUse)
+impl Error for ImmutableImageCreationError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::ImageCreationError(err) => Some(err),
+ Self::AllocError(err) => Some(err),
+ Self::CommandBufferBeginError(err) => Some(err),
+ _ => None,
}
}
+}
- #[inline]
- unsafe fn increase_gpu_lock(&self) {
- debug_assert!(self.used.load(Ordering::Relaxed));
- }
-
- #[inline]
- unsafe fn unlock(&self, new_layout: Option<ImageLayout>) {
- assert_eq!(new_layout, Some(self.image.layout));
- self.image.initialized.store(true, Ordering::Relaxed);
+impl Display for ImmutableImageCreationError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::ImageCreationError(err) => err.fmt(f),
+ Self::AllocError(err) => err.fmt(f),
+ Self::CommandBufferBeginError(err) => err.fmt(f),
+ Self::SourceTooSmall {
+ source_size,
+ required_size,
+ } => write!(
+ f,
+ "the size of the provided source data ({} bytes) is less than the required size \
+ for an image of the given format and dimensions ({} bytes)",
+ source_size, required_size,
+ ),
+ }
}
+}
- #[inline]
- fn current_miplevels_access(&self) -> std::ops::Range<u32> {
- self.mip_levels_access.clone()
+impl From<ImageError> for ImmutableImageCreationError {
+ fn from(err: ImageError) -> Self {
+ Self::ImageCreationError(err)
}
+}
- #[inline]
- fn current_layer_levels_access(&self) -> std::ops::Range<u32> {
- self.layer_levels_access.clone()
+impl From<AllocationCreationError> for ImmutableImageCreationError {
+ fn from(err: AllocationCreationError) -> Self {
+ Self::AllocError(err)
}
}
-impl<A> PartialEq for ImmutableImageInitialization<A> {
- #[inline]
- fn eq(&self, other: &Self) -> bool {
- ImageAccess::inner(self) == ImageAccess::inner(other)
+impl From<VulkanError> for ImmutableImageCreationError {
+ fn from(err: VulkanError) -> Self {
+ Self::AllocError(err.into())
}
}
-impl<A> Eq for ImmutableImageInitialization<A> {}
-
-impl<A> Hash for ImmutableImageInitialization<A> {
- #[inline]
- fn hash<H: Hasher>(&self, state: &mut H) {
- ImageAccess::inner(self).hash(state);
+impl From<CommandBufferBeginError> for ImmutableImageCreationError {
+ fn from(err: CommandBufferBeginError) -> Self {
+ Self::CommandBufferBeginError(err)
}
}
diff --git a/src/image/layout.rs b/src/image/layout.rs
index 2e29f58..16f4bc0 100644
--- a/src/image/layout.rs
+++ b/src/image/layout.rs
@@ -7,42 +7,202 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-/// Layout of an image.
-///
-/// > **Note**: In vulkano, image layouts are mostly a low-level detail. You can ignore them,
-/// > unless you use an unsafe function that states in its documentation that you must take care of
-/// > an image's layout.
-///
-/// In the Vulkan API, each mipmap level of each array layer is in one of the layouts of this enum.
-///
-/// Unless you use some sort of high-level shortcut function, an image always starts in either
-/// the `Undefined` or the `Preinitialized` layout.
-/// Before you can use an image for a given purpose, you must ensure that the image in question is
-/// in the layout required for that purpose. For example if you want to write data to an image, you
-/// must first transition the image to the `TransferDstOptimal` layout. The `General` layout can
-/// also be used as a general-purpose fit-all layout, but using it will result in slower operations.
-///
-/// Transitioning between layouts can only be done through a GPU-side operation that is part of
-/// a command buffer.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-#[repr(i32)]
-pub enum ImageLayout {
- Undefined = ash::vk::ImageLayout::UNDEFINED.as_raw(),
- General = ash::vk::ImageLayout::GENERAL.as_raw(),
- ColorAttachmentOptimal = ash::vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL.as_raw(),
- DepthStencilAttachmentOptimal = ash::vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL.as_raw(),
- DepthStencilReadOnlyOptimal = ash::vk::ImageLayout::DEPTH_STENCIL_READ_ONLY_OPTIMAL.as_raw(),
- ShaderReadOnlyOptimal = ash::vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL.as_raw(),
- TransferSrcOptimal = ash::vk::ImageLayout::TRANSFER_SRC_OPTIMAL.as_raw(),
- TransferDstOptimal = ash::vk::ImageLayout::TRANSFER_DST_OPTIMAL.as_raw(),
- Preinitialized = ash::vk::ImageLayout::PREINITIALIZED.as_raw(),
- PresentSrc = ash::vk::ImageLayout::PRESENT_SRC_KHR.as_raw(),
+use crate::{descriptor_set::layout::DescriptorType, macros::vulkan_enum};
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// In-memory layout of the pixel data of an image.
+ ///
+ /// The pixel data of a Vulkan image is arranged in a particular way, which is called its
+ /// *layout*. Each image subresource (mipmap level and array layer) in an image can have a
+ /// different layout, but usually the whole image has its data in the same layout. Layouts are
+ /// abstract in the sense that the user does not know the specific details of each layout; the
+ /// device driver is free to implement each layout in the way it sees fit.
+ ///
+ /// The layout of a newly created image is either `Undefined` or `Preinitialized`. Every
+ /// operation that can be performed on an image is only possible with specific layouts, so
+ /// before the operation is performed, the user must perform a *layout transition* on the
+ /// image. This rearranges the pixel data from one layout into another. Layout transitions are
+ /// performed as part of pipeline barriers in a command buffer.
+ ///
+ /// The `General` layout is compatible with any operation, so layout transitions are never
+ /// needed. However, the other layouts, while more restricted, are usually better optimised for
+ /// a particular type of operation than `General`, so they are usually preferred.
+ ///
+ /// Vulkan does not keep track of layouts itself, so it is the responsibility of the user to
+ /// keep track of this information. When performing a layout transition, the previous layout
+ /// must be specified as well. Some operations allow for different layouts, but require the
+ /// user to specify which one. Vulkano helps with this by providing sensible defaults,
+ /// automatically tracking the layout of each image when creating a command buffer, and adding
+ /// layout transitions where needed.
+ ImageLayout = ImageLayout(i32);
+
+ /// The layout of the data is unknown, and the image is treated as containing no valid data.
+ /// Transitioning from `Undefined` will discard any existing pixel data.
+ Undefined = UNDEFINED,
+
+ /// A general-purpose layout that can be used for any operation. Some operations may only allow
+ /// `General`, such as storage images, but many have a more specific layout that is better
+ /// optimized for that purpose.
+ General = GENERAL,
+
+ /// For a color image used as a color or resolve attachment in a framebuffer. Images that are
+ /// transitioned into this layout must have the `color_attachment` usage enabled.
+ ColorAttachmentOptimal = COLOR_ATTACHMENT_OPTIMAL,
+
+ /// For a depth/stencil image used as a depth/stencil attachment in a framebuffer.
+ DepthStencilAttachmentOptimal = DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
+
+ /// For a depth/stencil image used as a read-only depth/stencil attachment in a framebuffer, or
+ /// as a (combined) sampled image or input attachment in a shader.
+ DepthStencilReadOnlyOptimal = DEPTH_STENCIL_READ_ONLY_OPTIMAL,
+
+ /// For a color image used as a (combined) sampled image or input attachment in a shader.
+ /// Images that are transitioned into this layout must have the `sampled` or `input_attachment`
+ /// usages enabled.
+ ShaderReadOnlyOptimal = SHADER_READ_ONLY_OPTIMAL,
+
+ /// For operations that transfer data from an image (copy, blit).
+ TransferSrcOptimal = TRANSFER_SRC_OPTIMAL,
+
+ /// For operations that transfer data to an image (copy, blit, clear).
+ TransferDstOptimal = TRANSFER_DST_OPTIMAL,
+
+ /// When creating an image, this specifies that the initial data is going to be directly
+ /// written to from the CPU. Unlike `Undefined`, the image is assumed to contain valid data when
+ /// transitioning from this layout. However, this only works right when the image has linear
+ /// tiling, optimal tiling gives undefined results.
+ Preinitialized = PREINITIALIZED,
+
+ /// A combination of `DepthStencilReadOnlyOptimal` for the depth aspect of the image,
+ /// and `DepthStencilAttachmentOptimal` for the stencil aspect of the image.
+ DepthReadOnlyStencilAttachmentOptimal = DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL {
+ api_version: V1_1,
+ device_extensions: [khr_maintenance2],
+ },
+
+ /// A combination of `DepthStencilAttachmentOptimal` for the depth aspect of the image,
+ /// and `DepthStencilReadOnlyOptimal` for the stencil aspect of the image.
+ DepthAttachmentStencilReadOnlyOptimal = DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL {
+ api_version: V1_1,
+ device_extensions: [khr_maintenance2],
+ },
+
+ /* TODO: enable
+ // TODO: document
+ DepthAttachmentOptimal = DEPTH_ATTACHMENT_OPTIMAL {
+ api_version: V1_2,
+ device_extensions: [khr_separate_depth_stencil_layouts],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ DepthReadOnlyOptimal = DEPTH_READ_ONLY_OPTIMAL {
+ api_version: V1_2,
+ device_extensions: [khr_separate_depth_stencil_layouts],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ StencilAttachmentOptimal = STENCIL_ATTACHMENT_OPTIMAL {
+ api_version: V1_2,
+ device_extensions: [khr_separate_depth_stencil_layouts],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ StencilReadOnlyOptimal = STENCIL_READ_ONLY_OPTIMAL {
+ api_version: V1_2,
+ device_extensions: [khr_separate_depth_stencil_layouts],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ ReadOnlyOptimal = READ_ONLY_OPTIMAL {
+ api_version: V1_3,
+ device_extensions: [khr_synchronization2],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ AttachmentOptimal = ATTACHMENT_OPTIMAL {
+ api_version: V1_3,
+ device_extensions: [khr_synchronization2],
+ },*/
+
+ /// The layout of images that are held in a swapchain. Images are in this layout when they are
+ /// acquired from the swapchain, and must be transitioned back into this layout before
+ /// presenting them.
+ PresentSrc = PRESENT_SRC_KHR {
+ device_extensions: [khr_swapchain],
+ },
+
+ /* TODO: enable
+ // TODO: document
+ VideoDecodeDst = VIDEO_DECODE_DST_KHR {
+ device_extensions: [khr_video_decode_queue],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ VideoDecodeSrc = VIDEO_DECODE_SRC_KHR {
+ device_extensions: [khr_video_decode_queue],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ VideoDecodeDpb = VIDEO_DECODE_DPB_KHR {
+ device_extensions: [khr_video_decode_queue],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ SharedPresent = SHARED_PRESENT_KHR {
+ device_extensions: [khr_shared_presentable_image],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ FragmentDensityMapOptimal = FRAGMENT_DENSITY_MAP_OPTIMAL_EXT {
+ device_extensions: [ext_fragment_density_map],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ FragmentShadingRateAttachmentOptimal = FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR {
+ device_extensions: [khr_fragment_shading_rate],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ VideoEncodeDst = VIDEO_ENCODE_DST_KHR {
+ device_extensions: [khr_video_encode_queue],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ VideoEncodeSrc = VIDEO_ENCODE_SRC_KHR {
+ device_extensions: [khr_video_encode_queue],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ VideoEncodeDpb = VIDEO_ENCODE_DPB_KHR {
+ device_extensions: [khr_video_encode_queue],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ AttachmentFeedbackLoopOptimal = ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT {
+ device_extensions: [ext_attachment_feedback_loop_layout],
+ },*/
}
-impl From<ImageLayout> for ash::vk::ImageLayout {
+impl Default for ImageLayout {
#[inline]
- fn from(val: ImageLayout) -> Self {
- Self::from_raw(val as i32)
+ fn default() -> Self {
+ ImageLayout::Undefined
}
}
@@ -58,3 +218,18 @@ pub struct ImageDescriptorLayouts {
/// The image layout to use in a descriptor as an input attachment.
pub input_attachment: ImageLayout,
}
+
+impl ImageDescriptorLayouts {
+ /// Returns the layout for the given descriptor type. Panics if `descriptor_type` is not an
+ /// image descriptor type.
+ #[inline]
+ pub fn layout_for(&self, descriptor_type: DescriptorType) -> ImageLayout {
+ match descriptor_type {
+ DescriptorType::CombinedImageSampler => self.combined_image_sampler,
+ DescriptorType::SampledImage => self.sampled_image,
+ DescriptorType::StorageImage => self.storage_image,
+ DescriptorType::InputAttachment => self.input_attachment,
+ _ => panic!("{:?} is not an image descriptor type", descriptor_type),
+ }
+ }
+}
diff --git a/src/image/mod.rs b/src/image/mod.rs
index 4e7f4af..6b8c2b6 100644
--- a/src/image/mod.rs
+++ b/src/image/mod.rs
@@ -46,21 +46,29 @@
//! To be written.
//!
-pub use self::aspect::ImageAspect;
-pub use self::aspect::ImageAspects;
-pub use self::attachment::AttachmentImage;
-pub use self::immutable::ImmutableImage;
-pub use self::layout::ImageDescriptorLayouts;
-pub use self::layout::ImageLayout;
-pub use self::storage::StorageImage;
-pub use self::swapchain::SwapchainImage;
-pub use self::sys::ImageCreationError;
-pub use self::traits::ImageAccess;
-pub use self::traits::ImageInner;
-pub use self::usage::ImageUsage;
-pub use self::view::ImageViewAbstract;
-use std::cmp;
-use std::convert::TryFrom;
+pub use self::{
+ aspect::{ImageAspect, ImageAspects},
+ attachment::AttachmentImage,
+ immutable::ImmutableImage,
+ layout::{ImageDescriptorLayouts, ImageLayout},
+ storage::StorageImage,
+ swapchain::SwapchainImage,
+ sys::ImageError,
+ traits::{ImageAccess, ImageInner},
+ usage::ImageUsage,
+ view::{ImageViewAbstract, ImageViewType},
+};
+
+#[cfg(target_os = "linux")]
+pub use self::storage::SubresourceData;
+
+use crate::{
+ format::Format,
+ macros::{vulkan_bitflags, vulkan_bitflags_enum, vulkan_enum},
+ memory::{ExternalMemoryHandleType, ExternalMemoryProperties},
+ DeviceSize,
+};
+use std::{cmp, ops::Range};
mod aspect;
pub mod attachment; // TODO: make private
@@ -73,40 +81,220 @@ pub mod traits;
mod usage;
pub mod view;
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-#[repr(u32)]
-pub enum SampleCount {
- Sample1 = ash::vk::SampleCountFlags::TYPE_1.as_raw(),
- Sample2 = ash::vk::SampleCountFlags::TYPE_2.as_raw(),
- Sample4 = ash::vk::SampleCountFlags::TYPE_4.as_raw(),
- Sample8 = ash::vk::SampleCountFlags::TYPE_8.as_raw(),
- Sample16 = ash::vk::SampleCountFlags::TYPE_16.as_raw(),
- Sample32 = ash::vk::SampleCountFlags::TYPE_32.as_raw(),
- Sample64 = ash::vk::SampleCountFlags::TYPE_64.as_raw(),
-}
+vulkan_bitflags! {
+ #[non_exhaustive]
-impl From<SampleCount> for ash::vk::SampleCountFlags {
- #[inline]
- fn from(val: SampleCount) -> Self {
- Self::from_raw(val as u32)
- }
+ /// Flags that can be set when creating a new image.
+ ImageCreateFlags = ImageCreateFlags(u32);
+
+ /* TODO: enable
+ /// The image will be backed by sparse memory binding (through queue commands) instead of
+ /// regular binding (through [`bind_memory`]).
+ ///
+ /// The [`sparse_binding`] feature must be enabled on the device.
+ ///
+ /// [`bind_memory`]: sys::RawImage::bind_memory
+ /// [`sparse_binding`]: crate::device::Features::sparse_binding
+ SPARSE_BINDING = SPARSE_BINDING,*/
+
+ /* TODO: enable
+ /// The image can be used without being fully resident in memory at the time of use.
+ ///
+ /// This requires the `sparse_binding` flag as well.
+ ///
+ /// Depending on the image dimensions, either the [`sparse_residency_image2_d`] or the
+ /// [`sparse_residency_image3_d`] feature must be enabled on the device.
+ /// For a multisampled image, the one of the features [`sparse_residency2_samples`],
+ /// [`sparse_residency4_samples`], [`sparse_residency8_samples`] or
+ /// [`sparse_residency16_samples`], corresponding to the sample count of the image, must
+ /// be enabled on the device.
+ ///
+ /// [`sparse_binding`]: crate::device::Features::sparse_binding
+ /// [`sparse_residency_image2_d`]: crate::device::Features::sparse_residency_image2_d
+ /// [`sparse_residency_image2_3`]: crate::device::Features::sparse_residency_image3_d
+ /// [`sparse_residency2_samples`]: crate::device::Features::sparse_residency2_samples
+ /// [`sparse_residency4_samples`]: crate::device::Features::sparse_residency4_samples
+ /// [`sparse_residency8_samples`]: crate::device::Features::sparse_residency8_samples
+ /// [`sparse_residency16_samples`]: crate::device::Features::sparse_residency16_samples
+ SPARSE_RESIDENCY = SPARSE_RESIDENCY,*/
+
+ /* TODO: enable
+ /// The buffer's memory can alias with another image or a different part of the same image.
+ ///
+ /// This requires the `sparse_binding` flag as well.
+ ///
+ /// The [`sparse_residency_aliased`] feature must be enabled on the device.
+ ///
+ /// [`sparse_residency_aliased`]: crate::device::Features::sparse_residency_aliased
+ SPARSE_ALIASED = SPARSE_ALIASED,*/
+
+ /// For non-multi-planar formats, whether an image view wrapping the image can have a
+ /// different format.
+ ///
+ /// For multi-planar formats, whether an image view wrapping the image can be created from a
+ /// single plane of the image.
+ MUTABLE_FORMAT = MUTABLE_FORMAT,
+
+ /// For 2D images, whether an image view of type [`ImageViewType::Cube`] or
+ /// [`ImageViewType::CubeArray`] can be created from the image.
+ ///
+ /// [`ImageViewType::Cube`]: crate::image::view::ImageViewType::Cube
+ /// [`ImageViewType::CubeArray`]: crate::image::view::ImageViewType::CubeArray
+ CUBE_COMPATIBLE = CUBE_COMPATIBLE,
+
+ /* TODO: enable
+ // TODO: document
+ ALIAS = ALIAS {
+ api_version: V1_1,
+ device_extensions: [khr_bind_memory2],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ SPLIT_INSTANCE_BIND_REGIONS = SPLIT_INSTANCE_BIND_REGIONS {
+ api_version: V1_1,
+ device_extensions: [khr_device_group],
+ },*/
+
+ /// For 3D images, whether an image view of type [`ImageViewType::Dim2d`] or
+ /// [`ImageViewType::Dim2dArray`] can be created from the image.
+ ///
+ /// On [portability subset] devices, the [`image_view2_d_on3_d_image`] feature must be enabled
+ /// on the device.
+ ///
+ /// [`ImageViewType::Dim2d`]: crate::image::view::ImageViewType::Dim2d
+ /// [`ImageViewType::Dim2dArray`]: crate::image::view::ImageViewType::Dim2dArray
+ /// [portability subset]: crate::instance#portability-subset-devices-and-the-enumerate_portability-flag
+ /// [`image_view2_d_on3_d_image`]: crate::device::Features::image_view2_d_on3_d_image
+ ARRAY_2D_COMPATIBLE = TYPE_2D_ARRAY_COMPATIBLE {
+ api_version: V1_1,
+ device_extensions: [khr_maintenance1],
+ },
+
+ /// For images with a compressed format, whether an image view with an uncompressed
+ /// format can be created from the image, where each texel in the view will correspond to a
+ /// compressed texel block in the image.
+ ///
+ /// Requires `mutable_format`.
+ BLOCK_TEXEL_VIEW_COMPATIBLE = BLOCK_TEXEL_VIEW_COMPATIBLE {
+ api_version: V1_1,
+ device_extensions: [khr_maintenance2],
+ },
+
+ /* TODO: enable
+ // TODO: document
+ EXTENDED_USAGE = EXTENDED_USAGE {
+ api_version: V1_1,
+ device_extensions: [khr_maintenance2],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ PROTECTED = PROTECTED {
+ api_version: V1_1,
+ },*/
+
+ /// For images with a multi-planar format, whether each plane will have its memory bound
+ /// separately, rather than having a single memory binding for the whole image.
+ DISJOINT = DISJOINT {
+ api_version: V1_1,
+ device_extensions: [khr_sampler_ycbcr_conversion],
+ },
+
+ /* TODO: enable
+ // TODO: document
+ CORNER_SAMPLED = CORNER_SAMPLED_NV {
+ device_extensions: [nv_corner_sampled_image],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ SAMPLE_LOCATIONS_COMPATIBLE_DEPTH = SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_EXT {
+ device_extensions: [ext_sample_locations],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ SUBSAMPLED = SUBSAMPLED_EXT {
+ device_extensions: [ext_fragment_density_map],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED = MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_EXT {
+ device_extensions: [ext_multisampled_render_to_single_sampled],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ TYPE_2D_VIEW_COMPATIBLE = TYPE_2D_VIEW_COMPATIBLE_EXT {
+ device_extensions: [ext_image_2d_view_of_3d],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ FRAGMENT_DENSITY_MAP_OFFSET = FRAGMENT_DENSITY_MAP_OFFSET_QCOM {
+ device_extensions: [qcom_fragment_density_map_offset],
+ },*/
}
-impl TryFrom<ash::vk::SampleCountFlags> for SampleCount {
- type Error = ();
+vulkan_bitflags_enum! {
+ #[non_exhaustive]
- #[inline]
- fn try_from(val: ash::vk::SampleCountFlags) -> Result<Self, Self::Error> {
- match val {
- ash::vk::SampleCountFlags::TYPE_1 => Ok(Self::Sample1),
- ash::vk::SampleCountFlags::TYPE_2 => Ok(Self::Sample2),
- ash::vk::SampleCountFlags::TYPE_4 => Ok(Self::Sample4),
- ash::vk::SampleCountFlags::TYPE_8 => Ok(Self::Sample8),
- ash::vk::SampleCountFlags::TYPE_16 => Ok(Self::Sample16),
- ash::vk::SampleCountFlags::TYPE_32 => Ok(Self::Sample32),
- ash::vk::SampleCountFlags::TYPE_64 => Ok(Self::Sample64),
- _ => Err(()),
+ /// A set of [`SampleCount`] values.
+ SampleCounts impl {
+ /// Returns the maximum sample count in `self`.
+ #[inline]
+ pub const fn max_count(self) -> SampleCount {
+ if self.intersects(SampleCounts::SAMPLE_64) {
+ SampleCount::Sample64
+ } else if self.intersects(SampleCounts::SAMPLE_32) {
+ SampleCount::Sample32
+ } else if self.intersects(SampleCounts::SAMPLE_16) {
+ SampleCount::Sample16
+ } else if self.intersects(SampleCounts::SAMPLE_8) {
+ SampleCount::Sample8
+ } else if self.intersects(SampleCounts::SAMPLE_4) {
+ SampleCount::Sample4
+ } else if self.intersects(SampleCounts::SAMPLE_2) {
+ SampleCount::Sample2
+ } else {
+ SampleCount::Sample1
+ }
}
+ },
+
+ /// The number of samples per texel of an image.
+ SampleCount,
+
+ = SampleCountFlags(u32);
+
+ /// 1 sample per texel.
+ SAMPLE_1, Sample1 = TYPE_1,
+
+ /// 2 samples per texel.
+ SAMPLE_2, Sample2 = TYPE_2,
+
+ /// 4 samples per texel.
+ SAMPLE_4, Sample4 = TYPE_4,
+
+ /// 8 samples per texel.
+ SAMPLE_8, Sample8 = TYPE_8,
+
+ /// 16 samples per texel.
+ SAMPLE_16, Sample16 = TYPE_16,
+
+ /// 32 samples per texel.
+ SAMPLE_32, Sample32 = TYPE_32,
+
+ /// 64 samples per texel.
+ SAMPLE_64, Sample64 = TYPE_64,
+}
+
+impl From<SampleCount> for u32 {
+ #[inline]
+ fn from(value: SampleCount) -> Self {
+ value as u32
}
}
@@ -128,73 +316,10 @@ impl TryFrom<u32> for SampleCount {
}
}
-/// Specifies how many sample counts supported for an image used for storage operations.
-#[derive(Debug, Copy, Clone, Default)]
-pub struct SampleCounts {
- // specify an image with one sample per pixel
- pub sample1: bool,
- // specify an image with 2 samples per pixel
- pub sample2: bool,
- // specify an image with 4 samples per pixel
- pub sample4: bool,
- // specify an image with 8 samples per pixel
- pub sample8: bool,
- // specify an image with 16 samples per pixel
- pub sample16: bool,
- // specify an image with 32 samples per pixel
- pub sample32: bool,
- // specify an image with 64 samples per pixel
- pub sample64: bool,
-}
-
-impl From<ash::vk::SampleCountFlags> for SampleCounts {
- fn from(sample_counts: ash::vk::SampleCountFlags) -> SampleCounts {
- SampleCounts {
- sample1: !(sample_counts & ash::vk::SampleCountFlags::TYPE_1).is_empty(),
- sample2: !(sample_counts & ash::vk::SampleCountFlags::TYPE_2).is_empty(),
- sample4: !(sample_counts & ash::vk::SampleCountFlags::TYPE_4).is_empty(),
- sample8: !(sample_counts & ash::vk::SampleCountFlags::TYPE_8).is_empty(),
- sample16: !(sample_counts & ash::vk::SampleCountFlags::TYPE_16).is_empty(),
- sample32: !(sample_counts & ash::vk::SampleCountFlags::TYPE_32).is_empty(),
- sample64: !(sample_counts & ash::vk::SampleCountFlags::TYPE_64).is_empty(),
- }
- }
-}
-
-impl From<SampleCounts> for ash::vk::SampleCountFlags {
- fn from(val: SampleCounts) -> ash::vk::SampleCountFlags {
- let mut sample_counts = ash::vk::SampleCountFlags::default();
-
- if val.sample1 {
- sample_counts |= ash::vk::SampleCountFlags::TYPE_1;
- }
- if val.sample2 {
- sample_counts |= ash::vk::SampleCountFlags::TYPE_2;
- }
- if val.sample4 {
- sample_counts |= ash::vk::SampleCountFlags::TYPE_4;
- }
- if val.sample8 {
- sample_counts |= ash::vk::SampleCountFlags::TYPE_8;
- }
- if val.sample16 {
- sample_counts |= ash::vk::SampleCountFlags::TYPE_16;
- }
- if val.sample32 {
- sample_counts |= ash::vk::SampleCountFlags::TYPE_32;
- }
- if val.sample64 {
- sample_counts |= ash::vk::SampleCountFlags::TYPE_64;
- }
-
- sample_counts
- }
-}
-
/// Specifies how many mipmaps must be allocated.
///
/// Note that at least one mipmap must be allocated, to store the main level of the image.
-#[derive(Debug, Copy, Clone)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum MipmapsCount {
/// Allocates the number of mipmaps required to store all the mipmaps of the image where each
/// mipmap is half the dimensions of the previous level. Guaranteed to be always supported.
@@ -218,151 +343,38 @@ impl From<u32> for MipmapsCount {
}
}
-/// Helper type for creating extents
-#[derive(Debug, Copy, Clone)]
-pub enum Extent {
- E1D([u32; 1]),
- E2D([u32; 2]),
- E3D([u32; 3]),
-}
+vulkan_enum! {
+ #[non_exhaustive]
-impl From<ash::vk::Extent2D> for Extent {
- fn from(extent: ash::vk::Extent2D) -> Self {
- Extent::E2D([extent.width, extent.height])
- }
-}
-
-impl From<ash::vk::Extent3D> for Extent {
- fn from(extent: ash::vk::Extent3D) -> Self {
- Extent::E3D([extent.width, extent.height, extent.depth])
- }
-}
-impl TryFrom<Extent> for ash::vk::Extent2D {
- type Error = ();
+ // TODO: document
+ ImageType = ImageType(i32);
- fn try_from(extent: Extent) -> Result<Self, Self::Error> {
- match extent {
- Extent::E2D(a) => Ok(ash::vk::Extent2D {
- width: a[0],
- height: a[1],
- }),
- _ => Err(()),
- }
- }
-}
+ // TODO: document
+ Dim1d = TYPE_1D,
-impl TryFrom<Extent> for ash::vk::Extent3D {
- type Error = ();
+ // TODO: document
+ Dim2d = TYPE_2D,
- fn try_from(extent: Extent) -> Result<Self, Self::Error> {
- match extent {
- Extent::E3D(a) => Ok(ash::vk::Extent3D {
- width: a[0],
- height: a[1],
- depth: a[2],
- }),
- _ => Err(()),
- }
- }
+ // TODO: document
+ Dim3d = TYPE_3D,
}
-/// Helper type returned from Device's `fn image_format_properties()`
-pub struct ImageFormatProperties {
- pub max_extent: Extent,
- pub max_mip_levels: MipmapsCount,
- pub max_array_layers: u32,
- pub sample_counts: SampleCounts,
- pub max_resource_size: usize,
-}
+vulkan_enum! {
+ #[non_exhaustive]
-impl From<ash::vk::ImageFormatProperties> for ImageFormatProperties {
- fn from(props: ash::vk::ImageFormatProperties) -> Self {
- Self {
- max_extent: props.max_extent.into(),
- max_mip_levels: props.max_mip_levels.into(),
- max_array_layers: props.max_array_layers,
- sample_counts: props.sample_counts.into(),
- max_resource_size: props.max_resource_size as usize,
- }
- }
-}
+ // TODO: document
+ ImageTiling = ImageTiling(i32);
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
-pub struct ImageCreateFlags {
- pub sparse_binding: bool,
- pub sparse_residency: bool,
- pub sparse_aliased: bool,
- pub mutable_format: bool,
- pub cube_compatible: bool,
- pub array_2d_compatible: bool,
-}
+ // TODO: document
+ Optimal = OPTIMAL,
-impl ImageCreateFlags {
- pub fn all() -> Self {
- Self {
- sparse_binding: true,
- sparse_residency: true,
- sparse_aliased: true,
- mutable_format: true,
- cube_compatible: true,
- array_2d_compatible: true,
- }
- }
+ // TODO: document
+ Linear = LINEAR,
- pub fn none() -> Self {
- Self::default()
- }
-}
-
-impl From<ImageCreateFlags> for ash::vk::ImageCreateFlags {
- fn from(flags: ImageCreateFlags) -> Self {
- let mut vk_flags = Self::default();
- if flags.sparse_binding {
- vk_flags |= ash::vk::ImageCreateFlags::SPARSE_BINDING
- };
- if flags.sparse_residency {
- vk_flags |= ash::vk::ImageCreateFlags::SPARSE_RESIDENCY
- };
- if flags.sparse_aliased {
- vk_flags |= ash::vk::ImageCreateFlags::SPARSE_ALIASED
- };
- if flags.mutable_format {
- vk_flags |= ash::vk::ImageCreateFlags::MUTABLE_FORMAT
- };
- if flags.cube_compatible {
- vk_flags |= ash::vk::ImageCreateFlags::CUBE_COMPATIBLE
- };
- if flags.array_2d_compatible {
- vk_flags |= ash::vk::ImageCreateFlags::TYPE_2D_ARRAY_COMPATIBLE_KHR
- };
- vk_flags
- }
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-#[repr(i32)]
-pub enum ImageType {
- Dim1d = ash::vk::ImageType::TYPE_1D.as_raw(),
- Dim2d = ash::vk::ImageType::TYPE_2D.as_raw(),
- Dim3d = ash::vk::ImageType::TYPE_3D.as_raw(),
-}
-impl From<ImageType> for ash::vk::ImageType {
- fn from(val: ImageType) -> Self {
- ash::vk::ImageType::from_raw(val as i32)
- }
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-#[repr(i32)]
-pub enum ImageTiling {
- Optimal = ash::vk::ImageTiling::OPTIMAL.as_raw(),
- Linear = ash::vk::ImageTiling::LINEAR.as_raw(),
-}
-
-impl From<ImageTiling> for ash::vk::ImageTiling {
- fn from(val: ImageTiling) -> Self {
- ash::vk::ImageTiling::from_raw(val as i32)
- }
+ // TODO: document
+ DrmFormatModifier = DRM_FORMAT_MODIFIER_EXT {
+ device_extensions: [ext_image_drm_format_modifier],
+ },
}
/// The dimensions of an image.
@@ -437,11 +449,20 @@ impl ImageDimensions {
self.width() * self.height() * self.depth() * self.array_layers()
}
- /// Returns the maximum number of mipmaps for these image dimensions.
+ #[inline]
+ pub fn image_type(&self) -> ImageType {
+ match *self {
+ ImageDimensions::Dim1d { .. } => ImageType::Dim1d,
+ ImageDimensions::Dim2d { .. } => ImageType::Dim2d,
+ ImageDimensions::Dim3d { .. } => ImageType::Dim3d,
+ }
+ }
+
+ /// Returns the maximum number of mipmap levels for these image dimensions.
///
- /// The returned value is always at least superior or equal to 1.
+ /// The returned value is always at least 1.
///
- /// # Example
+ /// # Examples
///
/// ```
/// use vulkano::image::ImageDimensions;
@@ -452,19 +473,29 @@ impl ImageDimensions {
/// array_layers: 1,
/// };
///
- /// assert_eq!(dims.max_mipmaps(), 6);
+ /// assert_eq!(dims.max_mip_levels(), 6);
/// ```
- ///
- pub fn max_mipmaps(&self) -> u32 {
- 32 - (self.width() | self.height() | self.depth()).leading_zeros()
+ #[inline]
+ pub fn max_mip_levels(&self) -> u32 {
+ // This calculates `log2(max(width, height, depth)) + 1` using fast integer operations.
+ let max = match *self {
+ ImageDimensions::Dim1d { width, .. } => width,
+ ImageDimensions::Dim2d { width, height, .. } => width | height,
+ ImageDimensions::Dim3d {
+ width,
+ height,
+ depth,
+ } => width | height | depth,
+ };
+ 32 - max.leading_zeros()
}
/// Returns the dimensions of the `level`th mipmap level. If `level` is 0, then the dimensions
/// are left unchanged.
///
- /// Returns `None` if `level` is superior or equal to `max_mipmaps()`.
+ /// Returns `None` if `level` is superior or equal to `max_mip_levels()`.
///
- /// # Example
+ /// # Examples
///
/// ```
/// use vulkano::image::ImageDimensions;
@@ -475,36 +506,36 @@ impl ImageDimensions {
/// array_layers: 1,
/// };
///
- /// assert_eq!(dims.mipmap_dimensions(0), Some(dims));
- /// assert_eq!(dims.mipmap_dimensions(1), Some(ImageDimensions::Dim2d {
+ /// assert_eq!(dims.mip_level_dimensions(0), Some(dims));
+ /// assert_eq!(dims.mip_level_dimensions(1), Some(ImageDimensions::Dim2d {
/// width: 481,
/// height: 128,
/// array_layers: 1,
/// }));
- /// assert_eq!(dims.mipmap_dimensions(6), Some(ImageDimensions::Dim2d {
+ /// assert_eq!(dims.mip_level_dimensions(6), Some(ImageDimensions::Dim2d {
/// width: 15,
/// height: 4,
/// array_layers: 1,
/// }));
- /// assert_eq!(dims.mipmap_dimensions(9), Some(ImageDimensions::Dim2d {
+ /// assert_eq!(dims.mip_level_dimensions(9), Some(ImageDimensions::Dim2d {
/// width: 1,
/// height: 1,
/// array_layers: 1,
/// }));
- /// assert_eq!(dims.mipmap_dimensions(11), None);
+ /// assert_eq!(dims.mip_level_dimensions(11), None);
/// ```
///
- /// # Panic
- ///
- /// In debug mode, Panics if `width`, `height` or `depth` is equal to 0. In release, returns
- /// an unspecified value.
+ /// # Panics
///
- pub fn mipmap_dimensions(&self, level: u32) -> Option<ImageDimensions> {
+ /// - In debug mode, panics if `width`, `height` or `depth` is equal to 0. In release, returns
+ /// an unspecified value.
+ #[inline]
+ pub fn mip_level_dimensions(&self, level: u32) -> Option<ImageDimensions> {
if level == 0 {
return Some(*self);
}
- if level >= self.max_mipmaps() {
+ if level >= self.max_mip_levels() {
return None;
}
@@ -551,47 +582,436 @@ impl ImageDimensions {
}
}
+/// One or more subresources of an image, spanning a single mip level, that should be accessed by a
+/// command.
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct ImageSubresourceLayers {
+ /// Selects the aspects that will be included.
+ ///
+ /// The value must not be empty, and must not include any of the `memory_plane` aspects.
+ /// The `color` aspect cannot be selected together any of with the `plane` aspects.
+ pub aspects: ImageAspects,
+
+ /// Selects mip level that will be included.
+ pub mip_level: u32,
+
+ /// Selects the range of array layers that will be included.
+ ///
+ /// The range must not be empty.
+ pub array_layers: Range<u32>,
+}
+
+impl ImageSubresourceLayers {
+ /// Returns an `ImageSubresourceLayers` from the given image parameters, covering the first
+ /// mip level of the image. All aspects of the image are selected, or `plane0` if the image
+ /// is multi-planar.
+ #[inline]
+ pub fn from_parameters(format: Format, array_layers: u32) -> Self {
+ Self {
+ aspects: {
+ let aspects = format.aspects();
+
+ if aspects.intersects(ImageAspects::PLANE_0) {
+ ImageAspects::PLANE_0
+ } else {
+ aspects
+ }
+ },
+ mip_level: 0,
+ array_layers: 0..array_layers,
+ }
+ }
+}
+
+impl From<ImageSubresourceLayers> for ash::vk::ImageSubresourceLayers {
+ #[inline]
+ fn from(val: ImageSubresourceLayers) -> Self {
+ Self {
+ aspect_mask: val.aspects.into(),
+ mip_level: val.mip_level,
+ base_array_layer: val.array_layers.start,
+ layer_count: val.array_layers.end - val.array_layers.start,
+ }
+ }
+}
+
+/// One or more subresources of an image that should be accessed by a command.
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct ImageSubresourceRange {
+ /// Selects the aspects that will be included.
+ ///
+ /// The value must not be empty, and must not include any of the `memory_plane` aspects.
+ /// The `color` aspect cannot be selected together any of with the `plane` aspects.
+ pub aspects: ImageAspects,
+
+ /// Selects the range of the mip levels that will be included.
+ ///
+ /// The range must not be empty.
+ pub mip_levels: Range<u32>,
+
+ /// Selects the range of array layers that will be included.
+ ///
+ /// The range must not be empty.
+ pub array_layers: Range<u32>,
+}
+
+impl ImageSubresourceRange {
+ /// Returns an `ImageSubresourceRange` from the given image parameters, covering the whole
+ /// image. If the image is multi-planar, only the `color` aspect is selected.
+ #[inline]
+ pub fn from_parameters(format: Format, mip_levels: u32, array_layers: u32) -> Self {
+ Self {
+ aspects: format.aspects()
+ - (ImageAspects::PLANE_0 | ImageAspects::PLANE_1 | ImageAspects::PLANE_2),
+ mip_levels: 0..mip_levels,
+ array_layers: 0..array_layers,
+ }
+ }
+}
+
+impl From<ImageSubresourceRange> for ash::vk::ImageSubresourceRange {
+ #[inline]
+ fn from(val: ImageSubresourceRange) -> Self {
+ Self {
+ aspect_mask: val.aspects.into(),
+ base_mip_level: val.mip_levels.start,
+ level_count: val.mip_levels.end - val.mip_levels.start,
+ base_array_layer: val.array_layers.start,
+ layer_count: val.array_layers.end - val.array_layers.start,
+ }
+ }
+}
+
+impl From<ImageSubresourceLayers> for ImageSubresourceRange {
+ #[inline]
+ fn from(val: ImageSubresourceLayers) -> Self {
+ Self {
+ aspects: val.aspects,
+ mip_levels: val.mip_level..val.mip_level + 1,
+ array_layers: val.array_layers,
+ }
+ }
+}
+
+/// Describes the memory layout of an image.
+///
+/// The address of a texel at `(x, y, z, layer)` is `layer * array_pitch + z * depth_pitch +
+/// y * row_pitch + x * size_of_each_texel + offset`. `size_of_each_texel` must be determined
+/// depending on the format. The same formula applies for compressed formats, except that the
+/// coordinates must be in number of blocks.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub struct SubresourceLayout {
+ /// The number of bytes from the start of the memory where the subresource begins.
+ pub offset: DeviceSize,
+
+ /// The size in bytes in the subresource. It includes any extra memory that is required based on
+ /// `row_pitch`.
+ pub size: DeviceSize,
+
+ /// The number of bytes between adjacent rows of texels.
+ pub row_pitch: DeviceSize,
+
+ /// The number of bytes between adjacent array layers.
+ ///
+ /// This value is undefined for images with only one array layer.
+ pub array_pitch: DeviceSize,
+
+ /// The number of bytes between adjacent depth slices.
+ ///
+ /// This value is undefined for images that are not three-dimensional.
+ pub depth_pitch: DeviceSize,
+}
+
+/// The image configuration to query in
+/// [`PhysicalDevice::image_format_properties`](crate::device::physical::PhysicalDevice::image_format_properties).
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct ImageFormatInfo {
+ /// The `flags` that the image will have.
+ ///
+ /// The default value is [`ImageCreateFlags::empty()`].
+ pub flags: ImageCreateFlags,
+
+ /// The `format` that the image will have.
+ ///
+ /// The default value is `None`, which must be overridden.
+ pub format: Option<Format>,
+
+ /// The dimension type that the image will have.
+ ///
+ /// The default value is [`ImageType::Dim2d`].
+ pub image_type: ImageType,
+
+ /// The `tiling` that the image will have.
+ ///
+ /// The default value is [`ImageTiling::Optimal`].
+ pub tiling: ImageTiling,
+
+ /// The `usage` that the image will have.
+ ///
+ /// The default value is [`ImageUsage::empty()`], which must be overridden.
+ pub usage: ImageUsage,
+
+ /// The `stencil_usage` that the image will have.
+ ///
+ /// If `stencil_usage` is empty or if `format` does not have both a depth and a stencil aspect,
+ /// then it is automatically set to equal `usage`.
+ ///
+ /// If after this, `stencil_usage` does not equal `usage`,
+ /// then the physical device API version must be at least 1.2, or the
+ /// [`ext_separate_stencil_usage`](crate::device::DeviceExtensions::ext_separate_stencil_usage)
+ /// extension must be supported by the physical device.
+ ///
+ /// The default value is [`ImageUsage::empty()`].
+ pub stencil_usage: ImageUsage,
+
+ /// An external memory handle type that will be imported to or exported from the image.
+ ///
+ /// This is needed to retrieve the
+ /// [`external_memory_properties`](ImageFormatProperties::external_memory_properties) value,
+ /// and the physical device API version must be at least 1.1 or the
+ /// [`khr_external_memory_capabilities`](crate::instance::InstanceExtensions::khr_external_memory_capabilities)
+ /// extension must be enabled on the instance.
+ ///
+ /// The default value is `None`.
+ pub external_memory_handle_type: Option<ExternalMemoryHandleType>,
+
+ /// The image view type that will be created from the image.
+ ///
+ /// This is needed to retrieve the
+ /// [`filter_cubic`](ImageFormatProperties::filter_cubic) and
+ /// [`filter_cubic_minmax`](ImageFormatProperties::filter_cubic_minmax) values, and the
+ /// [`ext_filter_cubic`](crate::device::DeviceExtensions::ext_filter_cubic) extension must be
+ /// supported on the physical device.
+ ///
+ /// The default value is `None`.
+ pub image_view_type: Option<ImageViewType>,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for ImageFormatInfo {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ flags: ImageCreateFlags::empty(),
+ format: None,
+ image_type: ImageType::Dim2d,
+ tiling: ImageTiling::Optimal,
+ usage: ImageUsage::empty(),
+ stencil_usage: ImageUsage::empty(),
+ external_memory_handle_type: None,
+ image_view_type: None,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// The properties that are supported by a physical device for images of a certain type.
+#[derive(Clone, Debug)]
+#[non_exhaustive]
+pub struct ImageFormatProperties {
+ /// The maximum dimensions.
+ pub max_extent: [u32; 3],
+
+ /// The maximum number of mipmap levels.
+ pub max_mip_levels: u32,
+
+ /// The maximum number of array layers.
+ pub max_array_layers: u32,
+
+ /// The supported sample counts.
+ pub sample_counts: SampleCounts,
+
+ /// The maximum total size of an image, in bytes. This is guaranteed to be at least
+ /// 0x80000000.
+ pub max_resource_size: DeviceSize,
+
+ /// The properties for external memory.
+ /// This will be [`ExternalMemoryProperties::default()`] if `external_handle_type` was `None`.
+ pub external_memory_properties: ExternalMemoryProperties,
+
+ /// When querying with an image view type, whether such image views support sampling with
+ /// a [`Cubic`](crate::sampler::Filter::Cubic) `mag_filter` or `min_filter`.
+ pub filter_cubic: bool,
+
+ /// When querying with an image view type, whether such image views support sampling with
+ /// a [`Cubic`](crate::sampler::Filter::Cubic) `mag_filter` or `min_filter`, and with a
+ /// [`Min`](crate::sampler::SamplerReductionMode::Min) or
+ /// [`Max`](crate::sampler::SamplerReductionMode::Max) `reduction_mode`.
+ pub filter_cubic_minmax: bool,
+}
+
+impl From<ash::vk::ImageFormatProperties> for ImageFormatProperties {
+ #[inline]
+ fn from(props: ash::vk::ImageFormatProperties) -> Self {
+ Self {
+ max_extent: [
+ props.max_extent.width,
+ props.max_extent.height,
+ props.max_extent.depth,
+ ],
+ max_mip_levels: props.max_mip_levels,
+ max_array_layers: props.max_array_layers,
+ sample_counts: props.sample_counts.into(),
+ max_resource_size: props.max_resource_size,
+ external_memory_properties: Default::default(),
+ filter_cubic: false,
+ filter_cubic_minmax: false,
+ }
+ }
+}
+
+/// The image configuration to query in
+/// [`PhysicalDevice::sparse_image_format_properties`](crate::device::physical::PhysicalDevice::sparse_image_format_properties).
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct SparseImageFormatInfo {
+ /// The `format` that the image will have.
+ ///
+ /// The default value is `None`, which must be overridden.
+ pub format: Option<Format>,
+
+ /// The dimension type that the image will have.
+ ///
+ /// The default value is [`ImageType::Dim2d`].
+ pub image_type: ImageType,
+
+ /// The `samples` that the image will have.
+ ///
+ /// The default value is `SampleCount::Sample1`.
+ pub samples: SampleCount,
+
+ /// The `usage` that the image will have.
+ ///
+ /// The default value is [`ImageUsage::empty()`], which must be overridden.
+ pub usage: ImageUsage,
+
+ /// The `tiling` that the image will have.
+ ///
+ /// The default value is [`ImageTiling::Optimal`].
+ pub tiling: ImageTiling,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for SparseImageFormatInfo {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ format: None,
+ image_type: ImageType::Dim2d,
+ samples: SampleCount::Sample1,
+ usage: ImageUsage::empty(),
+ tiling: ImageTiling::Optimal,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// The properties that are supported by a physical device for sparse images of a certain type.
+#[derive(Clone, Debug)]
+#[non_exhaustive]
+pub struct SparseImageFormatProperties {
+ /// The aspects of the image that the properties apply to.
+ pub aspects: ImageAspects,
+
+ /// The size of the sparse image block, in texels or compressed texel blocks.
+ ///
+ /// If `flags.nonstandard_block_size` is set, then these values do not match the standard
+ /// sparse block dimensions for the given format.
+ pub image_granularity: [u32; 3],
+
+ /// Additional information about the sparse image.
+ pub flags: SparseImageFormatFlags,
+}
+
+vulkan_bitflags! {
+ #[non_exhaustive]
+
+ /// Flags specifying information about a sparse resource.
+ SparseImageFormatFlags = SparseImageFormatFlags(u32);
+
+ /// The image uses a single mip tail region for all array layers, instead of one mip tail region
+ /// per array layer.
+ SINGLE_MIPTAIL = SINGLE_MIPTAIL,
+
+ /// The image's mip tail region begins with the first mip level whose dimensions are not an
+ /// integer multiple of the corresponding sparse image block dimensions.
+ ALIGNED_MIP_SIZE = ALIGNED_MIP_SIZE,
+
+ /// The image uses non-standard sparse image block dimensions.
+ NONSTANDARD_BLOCK_SIZE = NONSTANDARD_BLOCK_SIZE,
+}
+
+/// Requirements for binding memory to a sparse image.
+#[derive(Clone, Debug)]
+#[non_exhaustive]
+pub struct SparseImageMemoryRequirements {
+ /// The properties of the image format.
+ pub format_properties: SparseImageFormatProperties,
+
+ /// The first mip level at which image subresources are included in the mip tail region.
+ pub image_mip_tail_first_lod: u32,
+
+ /// The size in bytes of the mip tail region. This value is guaranteed to be a multiple of the
+ /// sparse block size in bytes.
+ ///
+ /// If `format_properties.flags.single_miptail` is set, then this is the size of the whole
+ /// mip tail. Otherwise it is the size of the mip tail of a single array layer.
+ pub image_mip_tail_size: DeviceSize,
+
+ /// The memory offset that must be used to bind the mip tail region.
+ pub image_mip_tail_offset: DeviceSize,
+
+ /// If `format_properties.flags.single_miptail` is not set, specifies the stride between
+ /// the mip tail regions of each array layer.
+ pub image_mip_tail_stride: Option<DeviceSize>,
+}
+
#[cfg(test)]
mod tests {
- use crate::format::Format;
- use crate::image::ImageDimensions;
- use crate::image::ImmutableImage;
- use crate::image::MipmapsCount;
+ use crate::{
+ command_buffer::{
+ allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage,
+ },
+ format::Format,
+ image::{ImageAccess, ImageDimensions, ImmutableImage, MipmapsCount},
+ memory::allocator::StandardMemoryAllocator,
+ };
#[test]
- fn max_mipmaps() {
+ fn max_mip_levels() {
let dims = ImageDimensions::Dim2d {
width: 2,
height: 1,
array_layers: 1,
};
- assert_eq!(dims.max_mipmaps(), 2);
+ assert_eq!(dims.max_mip_levels(), 2);
let dims = ImageDimensions::Dim2d {
width: 2,
height: 3,
array_layers: 1,
};
- assert_eq!(dims.max_mipmaps(), 2);
+ assert_eq!(dims.max_mip_levels(), 2);
let dims = ImageDimensions::Dim2d {
width: 512,
height: 512,
array_layers: 1,
};
- assert_eq!(dims.max_mipmaps(), 10);
+ assert_eq!(dims.max_mip_levels(), 10);
}
#[test]
- fn mipmap_dimensions() {
+ fn mip_level_dimensions() {
let dims = ImageDimensions::Dim2d {
width: 283,
height: 175,
array_layers: 1,
};
- assert_eq!(dims.mipmap_dimensions(0), Some(dims));
+ assert_eq!(dims.mip_level_dimensions(0), Some(dims));
assert_eq!(
- dims.mipmap_dimensions(1),
+ dims.mip_level_dimensions(1),
Some(ImageDimensions::Dim2d {
width: 141,
height: 87,
@@ -599,7 +1019,7 @@ mod tests {
})
);
assert_eq!(
- dims.mipmap_dimensions(2),
+ dims.mip_level_dimensions(2),
Some(ImageDimensions::Dim2d {
width: 70,
height: 43,
@@ -607,7 +1027,7 @@ mod tests {
})
);
assert_eq!(
- dims.mipmap_dimensions(3),
+ dims.mip_level_dimensions(3),
Some(ImageDimensions::Dim2d {
width: 35,
height: 21,
@@ -616,7 +1036,7 @@ mod tests {
);
assert_eq!(
- dims.mipmap_dimensions(4),
+ dims.mip_level_dimensions(4),
Some(ImageDimensions::Dim2d {
width: 17,
height: 10,
@@ -624,7 +1044,7 @@ mod tests {
})
);
assert_eq!(
- dims.mipmap_dimensions(5),
+ dims.mip_level_dimensions(5),
Some(ImageDimensions::Dim2d {
width: 8,
height: 5,
@@ -632,7 +1052,7 @@ mod tests {
})
);
assert_eq!(
- dims.mipmap_dimensions(6),
+ dims.mip_level_dimensions(6),
Some(ImageDimensions::Dim2d {
width: 4,
height: 2,
@@ -640,7 +1060,7 @@ mod tests {
})
);
assert_eq!(
- dims.mipmap_dimensions(7),
+ dims.mip_level_dimensions(7),
Some(ImageDimensions::Dim2d {
width: 2,
height: 1,
@@ -648,20 +1068,29 @@ mod tests {
})
);
assert_eq!(
- dims.mipmap_dimensions(8),
+ dims.mip_level_dimensions(8),
Some(ImageDimensions::Dim2d {
width: 1,
height: 1,
array_layers: 1,
})
);
- assert_eq!(dims.mipmap_dimensions(9), None);
+ assert_eq!(dims.mip_level_dimensions(9), None);
}
#[test]
fn mipmap_working_immutable_image() {
let (device, queue) = gfx_dev_and_queue!();
+ let cb_allocator = StandardCommandBufferAllocator::new(device.clone(), Default::default());
+ let mut cbb = AutoCommandBufferBuilder::primary(
+ &cb_allocator,
+ queue.queue_family_index(),
+ CommandBufferUsage::OneTimeSubmit,
+ )
+ .unwrap();
+
+ let memory_allocator = StandardMemoryAllocator::new_default(device);
let dimensions = ImageDimensions::Dim2d {
width: 512,
height: 512,
@@ -672,30 +1101,32 @@ mod tests {
vec.resize(512 * 512, 0u8);
- let (image, _) = ImmutableImage::from_iter(
+ let image = ImmutableImage::from_iter(
+ &memory_allocator,
vec.into_iter(),
dimensions,
MipmapsCount::One,
- Format::R8Unorm,
- queue.clone(),
+ Format::R8_UNORM,
+ &mut cbb,
)
.unwrap();
- assert_eq!(image.mipmap_levels(), 1);
+ assert_eq!(image.mip_levels(), 1);
}
{
let mut vec = Vec::new();
vec.resize(512 * 512, 0u8);
- let (image, _) = ImmutableImage::from_iter(
+ let image = ImmutableImage::from_iter(
+ &memory_allocator,
vec.into_iter(),
dimensions,
MipmapsCount::Log2,
- Format::R8Unorm,
- queue.clone(),
+ Format::R8_UNORM,
+ &mut cbb,
)
.unwrap();
- assert_eq!(image.mipmap_levels(), 10);
+ assert_eq!(image.mip_levels(), 10);
}
}
}
diff --git a/src/image/storage.rs b/src/image/storage.rs
index 627d43a..f4fb2e1 100644
--- a/src/image/storage.rs
+++ b/src/image/storage.rs
@@ -7,190 +7,472 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use crate::device::physical::QueueFamily;
-use crate::device::Device;
-use crate::format::ClearValue;
-use crate::format::Format;
-use crate::format::FormatTy;
-use crate::image::sys::ImageCreationError;
-use crate::image::sys::UnsafeImage;
-use crate::image::traits::ImageAccess;
-use crate::image::traits::ImageClearValue;
-use crate::image::traits::ImageContent;
-use crate::image::ImageCreateFlags;
-use crate::image::ImageDescriptorLayouts;
-use crate::image::ImageDimensions;
-use crate::image::ImageInner;
-use crate::image::ImageLayout;
-use crate::image::ImageUsage;
-use crate::image::SampleCount;
-use crate::memory::pool::AllocFromRequirementsFilter;
-use crate::memory::pool::AllocLayout;
-use crate::memory::pool::MappingRequirement;
-use crate::memory::pool::MemoryPool;
-use crate::memory::pool::MemoryPoolAlloc;
-use crate::memory::pool::PotentialDedicatedAllocation;
-use crate::memory::pool::StdMemoryPool;
-use crate::memory::DedicatedAlloc;
-use crate::sync::AccessError;
-use crate::sync::Sharing;
+use super::{
+ sys::{Image, ImageMemory, RawImage},
+ traits::ImageContent,
+ ImageAccess, ImageAspects, ImageCreateFlags, ImageDescriptorLayouts, ImageDimensions,
+ ImageError, ImageInner, ImageLayout, ImageUsage,
+};
+use crate::{
+ device::{Device, DeviceOwned, Queue},
+ format::Format,
+ image::{sys::ImageCreateInfo, view::ImageView, ImageFormatInfo},
+ memory::{
+ allocator::{
+ AllocationCreateInfo, AllocationType, MemoryAllocatePreference, MemoryAllocator,
+ MemoryUsage,
+ },
+ is_aligned, DedicatedAllocation, DeviceMemoryError, ExternalMemoryHandleType,
+ ExternalMemoryHandleTypes,
+ },
+ sync::Sharing,
+ DeviceSize,
+};
use smallvec::SmallVec;
-use std::hash::Hash;
-use std::hash::Hasher;
-use std::sync::atomic::AtomicUsize;
-use std::sync::atomic::Ordering;
-use std::sync::Arc;
+
+#[cfg(target_os = "linux")]
+use crate::{
+ image::ImageTiling,
+ memory::{allocator::MemoryAlloc, DeviceMemory, MemoryAllocateFlags, MemoryAllocateInfo},
+};
+#[cfg(target_os = "linux")]
+use ash::vk::{ImageDrmFormatModifierExplicitCreateInfoEXT, SubresourceLayout};
+#[cfg(target_os = "linux")]
+use std::os::unix::prelude::{FromRawFd, IntoRawFd, RawFd};
+
+use std::{
+ fs::File,
+ hash::{Hash, Hasher},
+ sync::{
+ atomic::{AtomicBool, Ordering},
+ Arc,
+ },
+};
/// General-purpose image in device memory. Can be used for any usage, but will be slower than a
/// specialized image.
#[derive(Debug)]
-pub struct StorageImage<A = Arc<StdMemoryPool>>
-where
- A: MemoryPool,
-{
- // Inner implementation.
- image: UnsafeImage,
-
- // Memory used to back the image.
- memory: PotentialDedicatedAllocation<A::Alloc>,
-
- // Dimensions of the image.
- dimensions: ImageDimensions,
-
- // Format.
- format: Format,
+pub struct StorageImage {
+ inner: Arc<Image>,
- // Queue families allowed to access this image.
- queue_families: SmallVec<[u32; 4]>,
-
- // Number of times this image is locked on the GPU side.
- gpu_lock: AtomicUsize,
+ // If true, then the image is in the layout `General`. If false, then it
+ // is still `Undefined`.
+ layout_initialized: AtomicBool,
}
impl StorageImage {
/// Creates a new image with the given dimensions and format.
- #[inline]
- pub fn new<'a, I>(
- device: Arc<Device>,
+ pub fn new(
+ allocator: &(impl MemoryAllocator + ?Sized),
dimensions: ImageDimensions,
format: Format,
- queue_families: I,
- ) -> Result<Arc<StorageImage>, ImageCreationError>
- where
- I: IntoIterator<Item = QueueFamily<'a>>,
- {
- let is_depth = match format.ty() {
- FormatTy::Depth => true,
- FormatTy::DepthStencil => true,
- FormatTy::Stencil => true,
- FormatTy::Compressed => panic!(),
- _ => false,
- };
+ queue_family_indices: impl IntoIterator<Item = u32>,
+ ) -> Result<Arc<StorageImage>, ImageError> {
+ let aspects = format.aspects();
+ let is_depth_stencil = aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL);
- let usage = ImageUsage {
- transfer_source: true,
- transfer_destination: true,
- sampled: true,
- storage: true,
- color_attachment: !is_depth,
- depth_stencil_attachment: is_depth,
- input_attachment: true,
- transient_attachment: false,
- };
- let flags = ImageCreateFlags::none();
+ if format.compression().is_some() {
+ panic!() // TODO: message?
+ }
+
+ let usage = ImageUsage::TRANSFER_SRC
+ | ImageUsage::TRANSFER_DST
+ | ImageUsage::SAMPLED
+ | ImageUsage::STORAGE
+ | ImageUsage::INPUT_ATTACHMENT
+ | if is_depth_stencil {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ } else {
+ ImageUsage::COLOR_ATTACHMENT
+ };
+ let flags = ImageCreateFlags::empty();
- StorageImage::with_usage(device, dimensions, format, usage, flags, queue_families)
+ StorageImage::with_usage(
+ allocator,
+ dimensions,
+ format,
+ usage,
+ flags,
+ queue_family_indices,
+ )
}
/// Same as `new`, but allows specifying the usage.
- pub fn with_usage<'a, I>(
- device: Arc<Device>,
+ pub fn with_usage(
+ allocator: &(impl MemoryAllocator + ?Sized),
dimensions: ImageDimensions,
format: Format,
usage: ImageUsage,
flags: ImageCreateFlags,
- queue_families: I,
- ) -> Result<Arc<StorageImage>, ImageCreationError>
- where
- I: IntoIterator<Item = QueueFamily<'a>>,
- {
- let queue_families = queue_families
- .into_iter()
- .map(|f| f.id())
- .collect::<SmallVec<[u32; 4]>>();
-
- let (image, mem_reqs) = unsafe {
- let sharing = if queue_families.len() >= 2 {
- Sharing::Concurrent(queue_families.iter().cloned())
- } else {
- Sharing::Exclusive
- };
-
- UnsafeImage::new(
- device.clone(),
- usage,
- format,
+ queue_family_indices: impl IntoIterator<Item = u32>,
+ ) -> Result<Arc<StorageImage>, ImageError> {
+ let queue_family_indices: SmallVec<[_; 4]> = queue_family_indices.into_iter().collect();
+ assert!(!flags.intersects(ImageCreateFlags::DISJOINT)); // TODO: adjust the code below to make this safe
+
+ let raw_image = RawImage::new(
+ allocator.device().clone(),
+ ImageCreateInfo {
flags,
dimensions,
- SampleCount::Sample1,
- 1,
- sharing,
- false,
- false,
- )?
+ format: Some(format),
+ usage,
+ sharing: if queue_family_indices.len() >= 2 {
+ Sharing::Concurrent(queue_family_indices)
+ } else {
+ Sharing::Exclusive
+ },
+ ..Default::default()
+ },
+ )?;
+ let requirements = raw_image.memory_requirements()[0];
+ let res = unsafe {
+ allocator.allocate_unchecked(
+ requirements,
+ AllocationType::NonLinear,
+ AllocationCreateInfo {
+ usage: MemoryUsage::DeviceOnly,
+ allocate_preference: MemoryAllocatePreference::Unknown,
+ _ne: crate::NonExhaustive(()),
+ },
+ Some(DedicatedAllocation::Image(&raw_image)),
+ )
};
- let memory = MemoryPool::alloc_from_requirements(
- &Device::standard_pool(&device),
- &mem_reqs,
- AllocLayout::Optimal,
- MappingRequirement::DoNotMap,
- DedicatedAlloc::Image(&image),
- |t| {
- if t.is_device_local() {
- AllocFromRequirementsFilter::Preferred
+ match res {
+ Ok(alloc) => {
+ debug_assert!(is_aligned(alloc.offset(), requirements.layout.alignment()));
+ debug_assert!(alloc.size() == requirements.layout.size());
+
+ let inner = Arc::new(
+ unsafe { raw_image.bind_memory_unchecked([alloc]) }
+ .map_err(|(err, _, _)| err)?,
+ );
+
+ Ok(Arc::new(StorageImage {
+ inner,
+ layout_initialized: AtomicBool::new(false),
+ }))
+ }
+ Err(err) => Err(err.into()),
+ }
+ }
+
+ pub fn new_with_exportable_fd(
+ allocator: &(impl MemoryAllocator + ?Sized),
+ dimensions: ImageDimensions,
+ format: Format,
+ usage: ImageUsage,
+ flags: ImageCreateFlags,
+ queue_family_indices: impl IntoIterator<Item = u32>,
+ ) -> Result<Arc<StorageImage>, ImageError> {
+ let queue_family_indices: SmallVec<[_; 4]> = queue_family_indices.into_iter().collect();
+ assert!(!flags.intersects(ImageCreateFlags::DISJOINT)); // TODO: adjust the code below to make this safe
+
+ let external_memory_properties = allocator
+ .device()
+ .physical_device()
+ .image_format_properties(ImageFormatInfo {
+ flags,
+ format: Some(format),
+ image_type: dimensions.image_type(),
+ usage,
+ external_memory_handle_type: Some(ExternalMemoryHandleType::OpaqueFd),
+ ..Default::default()
+ })
+ .unwrap()
+ .unwrap()
+ .external_memory_properties;
+ // VUID-VkExportMemoryAllocateInfo-handleTypes-00656
+ assert!(external_memory_properties.exportable);
+
+ // VUID-VkMemoryAllocateInfo-pNext-00639
+ // Guaranteed because we always create a dedicated allocation
+
+ let external_memory_handle_types = ExternalMemoryHandleTypes::OPAQUE_FD;
+ let raw_image = RawImage::new(
+ allocator.device().clone(),
+ ImageCreateInfo {
+ flags,
+ dimensions,
+ format: Some(format),
+ usage,
+ sharing: if queue_family_indices.len() >= 2 {
+ Sharing::Concurrent(queue_family_indices)
} else {
- AllocFromRequirementsFilter::Allowed
- }
+ Sharing::Exclusive
+ },
+ external_memory_handle_types,
+ ..Default::default()
},
)?;
- debug_assert!((memory.offset() % mem_reqs.alignment) == 0);
- unsafe {
- image.bind_memory(memory.memory(), memory.offset())?;
+ let requirements = raw_image.memory_requirements()[0];
+ let memory_type_index = allocator
+ .find_memory_type_index(
+ requirements.memory_type_bits,
+ MemoryUsage::DeviceOnly.into(),
+ )
+ .expect("failed to find a suitable memory type");
+
+ match unsafe {
+ allocator.allocate_dedicated_unchecked(
+ memory_type_index,
+ requirements.layout.size(),
+ Some(DedicatedAllocation::Image(&raw_image)),
+ external_memory_handle_types,
+ )
+ } {
+ Ok(alloc) => {
+ debug_assert!(is_aligned(alloc.offset(), requirements.layout.alignment()));
+ debug_assert!(alloc.size() == requirements.layout.size());
+
+ let inner = Arc::new(unsafe {
+ raw_image
+ .bind_memory_unchecked([alloc])
+ .map_err(|(err, _, _)| err)?
+ });
+
+ Ok(Arc::new(StorageImage {
+ inner,
+ layout_initialized: AtomicBool::new(false),
+ }))
+ }
+ Err(err) => Err(err.into()),
+ }
+ }
+
+ #[cfg(target_os = "linux")]
+ /// Creates a new image from a set of Linux dma_buf file descriptors. The memory will be imported from the file desciptors, and will be bound to the image.
+ /// # Arguments
+ /// * `fds` - The list of file descriptors to import from. Single planar images should only use one, and multiplanar images can use multiple, for example, for each color.
+ /// * `offset` - The byte offset from the start of the image of the plane where the image subresource begins.
+ /// * `pitch` - Describes the number of bytes between each row of texels in an image.
+ pub fn new_from_dma_buf_fd(
+ allocator: &(impl MemoryAllocator + ?Sized),
+ device: Arc<Device>,
+ dimensions: ImageDimensions,
+ format: Format,
+ usage: ImageUsage,
+ flags: ImageCreateFlags,
+ queue_family_indices: impl IntoIterator<Item = u32>,
+ mut subresource_data: Vec<SubresourceData>,
+ drm_format_modifier: u64,
+ ) -> Result<Arc<StorageImage>, ImageError> {
+ let queue_family_indices: SmallVec<[_; 4]> = queue_family_indices.into_iter().collect();
+
+ // TODO: Support multiplanar image importing from Linux FD
+ if subresource_data.len() > 1 {
+ todo!();
}
+ // Create a vector of the layout of each image plane.
+
+ // All of the following are automatically true, since the values are explicitly set as such:
+ // VUID-VkImageDrmFormatModifierExplicitCreateInfoEXT-size-02267
+ // VUID-VkImageDrmFormatModifierExplicitCreateInfoEXT-arrayPitch-02268
+ // VUID-VkImageDrmFormatModifierExplicitCreateInfoEXT-depthPitch-02269
+ let layout: Vec<SubresourceLayout> = subresource_data
+ .iter_mut()
+ .map(
+ |SubresourceData {
+ fd: _,
+ offset,
+ row_pitch,
+ }| {
+ SubresourceLayout {
+ offset: *offset,
+ size: 0,
+ row_pitch: *row_pitch,
+ array_pitch: 0_u64,
+ depth_pitch: 0_u64,
+ }
+ },
+ )
+ .collect();
+
+ let fds: Vec<RawFd> = subresource_data
+ .iter_mut()
+ .map(
+ |SubresourceData {
+ fd,
+ offset: _,
+ row_pitch: _,
+ }| { *fd },
+ )
+ .collect();
+
+ let drm_mod = ImageDrmFormatModifierExplicitCreateInfoEXT::builder()
+ .drm_format_modifier(drm_format_modifier)
+ .plane_layouts(layout.as_ref())
+ .build();
+
+ let external_memory_handle_types = ExternalMemoryHandleTypes::DMA_BUF;
+
+ let image = RawImage::new(
+ device.clone(),
+ ImageCreateInfo {
+ flags,
+ dimensions,
+ format: Some(format),
+ usage,
+ sharing: if queue_family_indices.len() >= 2 {
+ Sharing::Concurrent(queue_family_indices)
+ } else {
+ Sharing::Exclusive
+ },
+ external_memory_handle_types,
+ tiling: ImageTiling::DrmFormatModifier,
+ image_drm_format_modifier_create_info: Some(drm_mod),
+ ..Default::default()
+ },
+ )?;
+
+ let requirements = image.memory_requirements()[0];
+ let memory_type_index = allocator
+ .find_memory_type_index(
+ requirements.memory_type_bits,
+ MemoryUsage::DeviceOnly.into(),
+ )
+ .expect("failed to find a suitable memory type");
+
+ assert!(device.enabled_extensions().khr_external_memory_fd);
+ assert!(device.enabled_extensions().khr_external_memory);
+ assert!(device.enabled_extensions().ext_external_memory_dma_buf);
+
+ let memory = unsafe {
+ // TODO: For completeness, importing memory from muliple file descriptors should be added (In order to support importing multiplanar images). As of now, only single planar image importing will work.
+ if fds.len() != 1 {
+ todo!();
+ }
+
+ // Try cloning underlying fd
+ let file = File::from_raw_fd(*fds.first().expect("file descriptor Vec is empty"));
+ let new_file = file.try_clone().expect("error cloning file descriptor");
+
+ // Turn the original file descriptor back into a raw fd to avoid ownership problems
+ file.into_raw_fd();
+ DeviceMemory::import(
+ device,
+ MemoryAllocateInfo {
+ allocation_size: requirements.layout.size(),
+ memory_type_index,
+ dedicated_allocation: Some(DedicatedAllocation::Image(&image)),
+ export_handle_types: ExternalMemoryHandleTypes::empty(),
+ flags: MemoryAllocateFlags::empty(),
+ ..Default::default()
+ },
+ crate::memory::MemoryImportInfo::Fd {
+ handle_type: crate::memory::ExternalMemoryHandleType::DmaBuf,
+ file: new_file,
+ },
+ )
+ .unwrap() // TODO: Handle
+ };
+
+ let mem_alloc = MemoryAlloc::new(memory).unwrap();
+
+ debug_assert!(mem_alloc.offset() % requirements.layout.alignment().as_nonzero() == 0);
+ debug_assert!(mem_alloc.size() == requirements.layout.size());
+
+ let inner = Arc::new(unsafe {
+ image
+ .bind_memory_unchecked([mem_alloc])
+ .map_err(|(err, _, _)| err)?
+ });
Ok(Arc::new(StorageImage {
- image,
- memory,
- dimensions,
- format,
- queue_families,
- gpu_lock: AtomicUsize::new(0),
+ inner,
+ layout_initialized: AtomicBool::new(false),
}))
}
+ /// Allows the creation of a simple 2D general purpose image view from `StorageImage`.
+ #[inline]
+ pub fn general_purpose_image_view(
+ allocator: &(impl MemoryAllocator + ?Sized),
+ queue: Arc<Queue>,
+ size: [u32; 2],
+ format: Format,
+ usage: ImageUsage,
+ ) -> Result<Arc<ImageView<StorageImage>>, ImageError> {
+ let dims = ImageDimensions::Dim2d {
+ width: size[0],
+ height: size[1],
+ array_layers: 1,
+ };
+ let flags = ImageCreateFlags::empty();
+ let image_result = StorageImage::with_usage(
+ allocator,
+ dims,
+ format,
+ usage,
+ flags,
+ Some(queue.queue_family_index()),
+ );
+
+ match image_result {
+ Ok(image) => {
+ let image_view = ImageView::new_default(image);
+ match image_view {
+ Ok(view) => Ok(view),
+ Err(e) => Err(ImageError::DirectImageViewCreationFailed(e)),
+ }
+ }
+ Err(e) => Err(e),
+ }
+ }
+
+ /// Exports posix file descriptor for the allocated memory.
+ /// Requires `khr_external_memory_fd` and `khr_external_memory` extensions to be loaded.
+ #[inline]
+ pub fn export_posix_fd(&self) -> Result<File, DeviceMemoryError> {
+ let allocation = match self.inner.memory() {
+ ImageMemory::Normal(a) => &a[0],
+ _ => unreachable!(),
+ };
+
+ allocation
+ .device_memory()
+ .export_fd(ExternalMemoryHandleType::OpaqueFd)
+ }
+
+ /// Return the size of the allocated memory (used e.g. with cuda).
+ #[inline]
+ pub fn mem_size(&self) -> DeviceSize {
+ let allocation = match self.inner.memory() {
+ ImageMemory::Normal(a) => &a[0],
+ _ => unreachable!(),
+ };
+
+ allocation.device_memory().allocation_size()
+ }
}
-impl<A> StorageImage<A>
-where
- A: MemoryPool,
-{
- /// Returns the dimensions of the image.
+#[cfg(target_os = "linux")]
+/// Struct that contains a Linux file descriptor for importing, when creating an image. Since a file descriptor is used for each
+/// plane in the case of multiplanar images, each fd needs to have an offset and a row pitch in order to interpret the imported data.
+pub struct SubresourceData {
+ /// The file descriptor handle of a layer of an image.
+ pub fd: RawFd,
+
+ /// The byte offset from the start of the plane where the image subresource begins.
+ pub offset: u64,
+
+ /// Describes the number of bytes between each row of texels in an image plane.
+ pub row_pitch: u64,
+}
+
+unsafe impl DeviceOwned for StorageImage {
#[inline]
- pub fn dimensions(&self) -> ImageDimensions {
- self.dimensions
+ fn device(&self) -> &Arc<Device> {
+ self.inner.device()
}
}
-unsafe impl<A> ImageAccess for StorageImage<A>
-where
- A: MemoryPool,
-{
+unsafe impl ImageAccess for StorageImage {
#[inline]
- fn inner(&self) -> ImageInner {
+ fn inner(&self) -> ImageInner<'_> {
ImageInner {
- image: &self.image,
+ image: &self.inner,
first_layer: 0,
- num_layers: self.dimensions.array_layers() as usize,
+ num_layers: self.inner.dimensions().array_layers(),
first_mipmap_level: 0,
num_mipmap_levels: 1,
}
@@ -207,6 +489,16 @@ where
}
#[inline]
+ unsafe fn layout_initialized(&self) {
+ self.layout_initialized.store(true, Ordering::Relaxed);
+ }
+
+ #[inline]
+ fn is_layout_initialized(&self) -> bool {
+ self.layout_initialized.load(Ordering::Relaxed)
+ }
+
+ #[inline]
fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
Some(ImageDescriptorLayouts {
storage_image: ImageLayout::General,
@@ -215,122 +507,86 @@ where
input_attachment: ImageLayout::General,
})
}
-
- #[inline]
- fn conflict_key(&self) -> u64 {
- self.image.key()
- }
-
- #[inline]
- fn try_gpu_lock(
- &self,
- _: bool,
- uninitialized_safe: bool,
- expected_layout: ImageLayout,
- ) -> Result<(), AccessError> {
- // TODO: handle initial layout transition
- if expected_layout != ImageLayout::General && expected_layout != ImageLayout::Undefined {
- return Err(AccessError::UnexpectedImageLayout {
- requested: expected_layout,
- allowed: ImageLayout::General,
- });
- }
-
- let val = self
- .gpu_lock
- .compare_exchange(0, 1, Ordering::SeqCst, Ordering::SeqCst)
- .unwrap_or_else(|e| e);
- if val == 0 {
- Ok(())
- } else {
- Err(AccessError::AlreadyInUse)
- }
- }
-
- #[inline]
- unsafe fn increase_gpu_lock(&self) {
- let val = self.gpu_lock.fetch_add(1, Ordering::SeqCst);
- debug_assert!(val >= 1);
- }
-
- #[inline]
- unsafe fn unlock(&self, new_layout: Option<ImageLayout>) {
- assert!(new_layout.is_none() || new_layout == Some(ImageLayout::General));
- self.gpu_lock.fetch_sub(1, Ordering::SeqCst);
- }
-
- #[inline]
- fn current_miplevels_access(&self) -> std::ops::Range<u32> {
- 0..self.mipmap_levels()
- }
-
- #[inline]
- fn current_layer_levels_access(&self) -> std::ops::Range<u32> {
- 0..self.dimensions().array_layers()
- }
}
-unsafe impl<A> ImageClearValue<ClearValue> for StorageImage<A>
-where
- A: MemoryPool,
-{
- #[inline]
- fn decode(&self, value: ClearValue) -> Option<ClearValue> {
- Some(self.format.decode_clear_value(value))
- }
-}
-
-unsafe impl<P, A> ImageContent<P> for StorageImage<A>
-where
- A: MemoryPool,
-{
- #[inline]
+unsafe impl<P> ImageContent<P> for StorageImage {
fn matches_format(&self) -> bool {
true // FIXME:
}
}
-impl<A> PartialEq for StorageImage<A>
-where
- A: MemoryPool,
-{
+impl PartialEq for StorageImage {
#[inline]
fn eq(&self, other: &Self) -> bool {
- ImageAccess::inner(self) == ImageAccess::inner(other)
+ self.inner() == other.inner()
}
}
-impl<A> Eq for StorageImage<A> where A: MemoryPool {}
+impl Eq for StorageImage {}
-impl<A> Hash for StorageImage<A>
-where
- A: MemoryPool,
-{
- #[inline]
+impl Hash for StorageImage {
fn hash<H: Hasher>(&self, state: &mut H) {
- ImageAccess::inner(self).hash(state);
+ self.inner().hash(state);
}
}
#[cfg(test)]
mod tests {
- use super::StorageImage;
- use crate::format::Format;
- use crate::image::ImageDimensions;
+ use super::*;
+ use crate::{image::view::ImageViewCreationError, memory::allocator::StandardMemoryAllocator};
#[test]
fn create() {
let (device, queue) = gfx_dev_and_queue!();
+ let memory_allocator = StandardMemoryAllocator::new_default(device);
let _img = StorageImage::new(
- device,
+ &memory_allocator,
ImageDimensions::Dim2d {
width: 32,
height: 32,
array_layers: 1,
},
- Format::R8G8B8A8Unorm,
- Some(queue.family()),
+ Format::R8G8B8A8_UNORM,
+ Some(queue.queue_family_index()),
)
.unwrap();
}
+
+ #[test]
+ fn create_general_purpose_image_view() {
+ let (device, queue) = gfx_dev_and_queue!();
+ let memory_allocator = StandardMemoryAllocator::new_default(device);
+ let usage =
+ ImageUsage::TRANSFER_SRC | ImageUsage::TRANSFER_DST | ImageUsage::COLOR_ATTACHMENT;
+ let img_view = StorageImage::general_purpose_image_view(
+ &memory_allocator,
+ queue,
+ [32, 32],
+ Format::R8G8B8A8_UNORM,
+ usage,
+ )
+ .unwrap();
+ assert_eq!(img_view.image().usage(), usage);
+ }
+
+ #[test]
+ fn create_general_purpose_image_view_failed() {
+ let (device, queue) = gfx_dev_and_queue!();
+ let memory_allocator = StandardMemoryAllocator::new_default(device);
+ // Not valid for image view...
+ let usage = ImageUsage::TRANSFER_SRC;
+ let img_result = StorageImage::general_purpose_image_view(
+ &memory_allocator,
+ queue,
+ [32, 32],
+ Format::R8G8B8A8_UNORM,
+ usage,
+ );
+ assert_eq!(
+ img_result,
+ Err(ImageError::DirectImageViewCreationFailed(
+ ImageViewCreationError::ImageMissingUsage
+ ))
+ );
+ }
}
diff --git a/src/image/swapchain.rs b/src/image/swapchain.rs
index 9cd3fe5..6fa6853 100644
--- a/src/image/swapchain.rs
+++ b/src/image/swapchain.rs
@@ -7,19 +7,20 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use crate::format::ClearValue;
-use crate::image::traits::ImageAccess;
-use crate::image::traits::ImageClearValue;
-use crate::image::traits::ImageContent;
-use crate::image::ImageDescriptorLayouts;
-use crate::image::ImageInner;
-use crate::image::ImageLayout;
-use crate::swapchain::Swapchain;
-use crate::sync::AccessError;
-use crate::OomError;
-use std::hash::Hash;
-use std::hash::Hasher;
-use std::sync::Arc;
+use super::{
+ sys::{Image, ImageMemory},
+ traits::ImageContent,
+ ImageAccess, ImageDescriptorLayouts, ImageInner, ImageLayout,
+};
+use crate::{
+ device::{Device, DeviceOwned},
+ swapchain::Swapchain,
+ OomError,
+};
+use std::{
+ hash::{Hash, Hasher},
+ sync::Arc,
+};
/// An image that is part of a swapchain.
///
@@ -34,156 +35,105 @@ use std::sync::Arc;
/// method on the swapchain), which will have the effect of showing the content of the image to
/// the screen. Once an image has been presented, it can no longer be used unless it is acquired
/// again.
-// TODO: #[derive(Debug)]
-pub struct SwapchainImage<W> {
- swapchain: Arc<Swapchain<W>>,
- image_offset: usize,
+#[derive(Debug)]
+pub struct SwapchainImage {
+ inner: Arc<Image>,
}
-impl<W> SwapchainImage<W> {
- /// Builds a `SwapchainImage` from raw components.
- ///
- /// This is an internal method that you shouldn't call.
- pub unsafe fn from_raw(
- swapchain: Arc<Swapchain<W>>,
- id: usize,
- ) -> Result<Arc<SwapchainImage<W>>, OomError> {
- let image = swapchain.raw_image(id).unwrap();
-
+impl SwapchainImage {
+ pub(crate) unsafe fn from_handle(
+ handle: ash::vk::Image,
+ swapchain: Arc<Swapchain>,
+ image_index: u32,
+ ) -> Result<Arc<SwapchainImage>, OomError> {
Ok(Arc::new(SwapchainImage {
- swapchain: swapchain.clone(),
- image_offset: id,
+ inner: Arc::new(Image::from_swapchain(handle, swapchain, image_index)),
}))
}
- /// Returns the dimensions of the image.
- ///
- /// A `SwapchainImage` is always two-dimensional.
- #[inline]
- pub fn dimensions(&self) -> [u32; 2] {
- let dims = self.my_image().image.dimensions();
- [dims.width(), dims.height()]
- }
-
/// Returns the swapchain this image belongs to.
- #[inline]
- pub fn swapchain(&self) -> &Arc<Swapchain<W>> {
- &self.swapchain
- }
-
- #[inline]
- fn my_image(&self) -> ImageInner {
- self.swapchain.raw_image(self.image_offset).unwrap()
- }
-
- #[inline]
- fn layout_initialized(&self) {
- self.swapchain.image_layout_initialized(self.image_offset);
+ pub fn swapchain(&self) -> &Arc<Swapchain> {
+ match self.inner.memory() {
+ ImageMemory::Swapchain {
+ swapchain,
+ image_index: _,
+ } => swapchain,
+ _ => unreachable!(),
+ }
}
+}
- #[inline]
- fn is_layout_initialized(&self) -> bool {
- self.swapchain
- .is_image_layout_initialized(self.image_offset)
+unsafe impl DeviceOwned for SwapchainImage {
+ fn device(&self) -> &Arc<Device> {
+ self.inner.device()
}
}
-unsafe impl<W> ImageAccess for SwapchainImage<W> {
- #[inline]
- fn inner(&self) -> ImageInner {
- self.my_image()
+unsafe impl ImageAccess for SwapchainImage {
+ fn inner(&self) -> ImageInner<'_> {
+ ImageInner {
+ image: &self.inner,
+ first_layer: 0,
+ num_layers: self.inner.dimensions().array_layers(),
+ first_mipmap_level: 0,
+ num_mipmap_levels: 1,
+ }
}
- #[inline]
fn initial_layout_requirement(&self) -> ImageLayout {
ImageLayout::PresentSrc
}
- #[inline]
fn final_layout_requirement(&self) -> ImageLayout {
ImageLayout::PresentSrc
}
- #[inline]
fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
Some(ImageDescriptorLayouts {
- storage_image: ImageLayout::ShaderReadOnlyOptimal,
+ storage_image: ImageLayout::General,
combined_image_sampler: ImageLayout::ShaderReadOnlyOptimal,
sampled_image: ImageLayout::ShaderReadOnlyOptimal,
input_attachment: ImageLayout::ShaderReadOnlyOptimal,
})
}
- #[inline]
- fn conflict_key(&self) -> u64 {
- self.my_image().image.key()
- }
-
- #[inline]
- fn try_gpu_lock(&self, _: bool, _: bool, _: ImageLayout) -> Result<(), AccessError> {
- if self.swapchain.is_fullscreen_exclusive() {
- Ok(())
- } else {
- // Swapchain image are only accessible after being acquired.
- Err(AccessError::SwapchainImageAcquireOnly)
- }
- }
-
- #[inline]
unsafe fn layout_initialized(&self) {
- self.layout_initialized();
+ match self.inner.memory() {
+ &ImageMemory::Swapchain {
+ ref swapchain,
+ image_index,
+ } => swapchain.image_layout_initialized(image_index),
+ _ => unreachable!(),
+ }
}
- #[inline]
fn is_layout_initialized(&self) -> bool {
- self.is_layout_initialized()
- }
-
- #[inline]
- unsafe fn increase_gpu_lock(&self) {}
-
- #[inline]
- unsafe fn unlock(&self, _: Option<ImageLayout>) {
- // TODO: store that the image was initialized
- }
-
- #[inline]
- fn current_miplevels_access(&self) -> std::ops::Range<u32> {
- 0..self.mipmap_levels()
- }
-
- #[inline]
- fn current_layer_levels_access(&self) -> std::ops::Range<u32> {
- 0..1
- }
-}
-
-unsafe impl<W> ImageClearValue<ClearValue> for SwapchainImage<W> {
- #[inline]
- fn decode(&self, value: ClearValue) -> Option<ClearValue> {
- Some(self.swapchain.format().decode_clear_value(value))
+ match self.inner.memory() {
+ &ImageMemory::Swapchain {
+ ref swapchain,
+ image_index,
+ } => swapchain.is_image_layout_initialized(image_index),
+ _ => unreachable!(),
+ }
}
}
-unsafe impl<P, W> ImageContent<P> for SwapchainImage<W> {
- #[inline]
+unsafe impl<P> ImageContent<P> for SwapchainImage {
fn matches_format(&self) -> bool {
true // FIXME:
}
}
-impl<W> PartialEq for SwapchainImage<W> {
- #[inline]
+impl PartialEq for SwapchainImage {
fn eq(&self, other: &Self) -> bool {
- ImageAccess::inner(self) == ImageAccess::inner(other)
+ self.inner() == other.inner()
}
}
-impl<W> Eq for SwapchainImage<W> {}
+impl Eq for SwapchainImage {}
-impl<W> Hash for SwapchainImage<W> {
- #[inline]
+impl Hash for SwapchainImage {
fn hash<H: Hasher>(&self, state: &mut H) {
- ImageAccess::inner(self).hash(state);
+ self.inner().hash(state);
}
}
diff --git a/src/image/sys.rs b/src/image/sys.rs
index c810478..1933ffe 100644
--- a/src/image/sys.rs
+++ b/src/image/sys.rs
@@ -13,1089 +13,3307 @@
//! other image types of this library, and all custom image types
//! that you create must wrap around the types in this module.
-use crate::check_errors;
-use crate::device::Device;
-use crate::format::Format;
-use crate::format::FormatFeatures;
-use crate::format::FormatTy;
-use crate::image::ImageAspect;
-use crate::image::ImageCreateFlags;
-use crate::image::ImageDimensions;
-use crate::image::ImageUsage;
-use crate::image::MipmapsCount;
-use crate::image::SampleCount;
-use crate::memory::DeviceMemory;
-use crate::memory::DeviceMemoryAllocError;
-use crate::memory::MemoryRequirements;
-use crate::sync::Sharing;
-use crate::DeviceSize;
-use crate::Error;
-use crate::OomError;
-use crate::Version;
-use crate::VulkanObject;
-use ash::vk::Handle;
-use smallvec::SmallVec;
-use std::error;
-use std::fmt;
-use std::hash::Hash;
-use std::hash::Hasher;
-use std::mem::MaybeUninit;
-use std::ops::Range;
-use std::ptr;
-use std::sync::Arc;
-
-/// A storage for pixels or arbitrary data.
-///
-/// # Safety
-///
-/// This type is not just unsafe but very unsafe. Don't use it directly.
-///
-/// - You must manually bind memory to the image with `bind_memory`. The memory must respect the
-/// requirements returned by `new`.
-/// - The memory that you bind to the image must be manually kept alive.
-/// - The queue family ownership must be manually enforced.
-/// - The usage must be manually enforced.
-/// - The image layout must be manually enforced and transitioned.
+use super::{
+ ImageAspect, ImageAspects, ImageCreateFlags, ImageDimensions, ImageLayout,
+ ImageSubresourceLayers, ImageSubresourceRange, ImageTiling, ImageUsage, SampleCount,
+ SampleCounts, SparseImageMemoryRequirements,
+};
+use crate::{
+ buffer::subbuffer::{ReadLockError, WriteLockError},
+ cache::OnceCache,
+ device::{Device, DeviceOwned},
+ format::{ChromaSampling, Format, FormatFeatures, NumericType},
+ image::{
+ view::ImageViewCreationError, ImageFormatInfo, ImageFormatProperties, ImageType,
+ SparseImageFormatProperties,
+ },
+ macros::impl_id_counter,
+ memory::{
+ allocator::{AllocationCreationError, AllocationType, DeviceLayout, MemoryAlloc},
+ is_aligned, DedicatedTo, DeviceAlignment, ExternalMemoryHandleType,
+ ExternalMemoryHandleTypes, MemoryPropertyFlags, MemoryRequirements,
+ },
+ range_map::RangeMap,
+ swapchain::Swapchain,
+ sync::{future::AccessError, CurrentAccess, Sharing},
+ DeviceSize, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject,
+};
+use ash::vk::ImageDrmFormatModifierExplicitCreateInfoEXT;
+use parking_lot::{Mutex, MutexGuard};
+use smallvec::{smallvec, SmallVec};
+use std::{
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+ hash::{Hash, Hasher},
+ iter::{FusedIterator, Peekable},
+ mem::{size_of_val, MaybeUninit},
+ num::NonZeroU64,
+ ops::Range,
+ ptr,
+ sync::Arc,
+};
+
+/// A raw image, with no memory backing it.
///
-pub struct UnsafeImage {
- image: ash::vk::Image,
+/// This is the basic image type, a direct translation of a `VkImage` object, but it is mostly
+/// useless in this form. After creating a raw image, you must call `bind_memory` to make a
+/// complete image object.
+#[derive(Debug)]
+pub struct RawImage {
+ handle: ash::vk::Image,
device: Arc<Device>,
- usage: ImageUsage,
- format: Format,
- flags: ImageCreateFlags,
+ id: NonZeroU64,
+ flags: ImageCreateFlags,
dimensions: ImageDimensions,
- samples: SampleCount,
- mipmaps: u32,
-
- // Features that are supported for this particular format.
+ format: Option<Format>,
format_features: FormatFeatures,
+ initial_layout: ImageLayout,
+ mip_levels: u32,
+ samples: SampleCount,
+ tiling: ImageTiling,
+ usage: ImageUsage,
+ sharing: Sharing<SmallVec<[u32; 4]>>,
+ stencil_usage: ImageUsage,
+ external_memory_handle_types: ExternalMemoryHandleTypes,
- // `vkDestroyImage` is called only if `needs_destruction` is true.
- needs_destruction: bool,
- preinitialized_layout: bool,
+ memory_requirements: SmallVec<[MemoryRequirements; 3]>,
+ needs_destruction: bool, // `vkDestroyImage` is called only if true.
+ subresource_layout: OnceCache<(ImageAspect, u32, u32), SubresourceLayout>,
}
-impl UnsafeImage {
- /// Creates a new image and allocates memory for it.
- ///
- /// # Panic
+impl RawImage {
+ /// Creates a new `RawImage`.
///
- /// - Panics if one of the dimensions is 0.
- /// - Panics if the number of mipmaps is 0.
- /// - Panics if the number of samples is 0.
+ /// # Panics
///
+ /// - Panics if one of the values in `create_info.dimensions` is zero.
+ /// - Panics if `create_info.format` is `None`.
+ /// - Panics if `create_info.block_texel_view_compatible` is set but not
+ /// `create_info.mutable_format`.
+ /// - Panics if `create_info.mip_levels` is `0`.
+ /// - Panics if `create_info.sharing` is [`Sharing::Concurrent`] with less than 2 items.
+ /// - Panics if `create_info.initial_layout` is something other than
+ /// [`ImageLayout::Undefined`] or [`ImageLayout::Preinitialized`].
+ /// - Panics if `create_info.usage` is empty.
+ /// - Panics if `create_info.usage` contains `transient_attachment`, but does not also contain
+ /// at least one of `color_attachment`, `depth_stencil_attachment`, `input_attachment`, or
+ /// if it contains values other than these.
#[inline]
- pub unsafe fn new<'a, Mi, I>(
+ pub fn new(
device: Arc<Device>,
- usage: ImageUsage,
- format: Format,
- flags: ImageCreateFlags,
- dimensions: ImageDimensions,
- num_samples: SampleCount,
- mipmaps: Mi,
- sharing: Sharing<I>,
- linear_tiling: bool,
- preinitialized_layout: bool,
- ) -> Result<(UnsafeImage, MemoryRequirements), ImageCreationError>
- where
- Mi: Into<MipmapsCount>,
- I: Iterator<Item = u32>,
- {
- let sharing = match sharing {
- Sharing::Exclusive => (ash::vk::SharingMode::EXCLUSIVE, SmallVec::<[u32; 8]>::new()),
- Sharing::Concurrent(ids) => (ash::vk::SharingMode::CONCURRENT, ids.collect()),
- };
+ mut create_info: ImageCreateInfo,
+ ) -> Result<RawImage, ImageError> {
+ match &mut create_info.sharing {
+ Sharing::Exclusive => (),
+ Sharing::Concurrent(queue_family_indices) => {
+ // VUID-VkImageCreateInfo-sharingMode-01420
+ queue_family_indices.sort_unstable();
+ queue_family_indices.dedup();
+ }
+ }
- UnsafeImage::new_impl(
- device,
- usage,
- format,
- flags,
- dimensions,
- num_samples,
- mipmaps.into(),
- sharing,
- linear_tiling,
- preinitialized_layout,
- )
+ Self::validate_new(&device, &create_info)?;
+
+ unsafe { Ok(RawImage::new_unchecked(device, create_info)?) }
}
- // Non-templated version to avoid inlining and improve compile times.
- unsafe fn new_impl(
- device: Arc<Device>,
- usage: ImageUsage,
- format: Format,
- flags: ImageCreateFlags,
- dimensions: ImageDimensions,
- num_samples: SampleCount,
- mipmaps: MipmapsCount,
- (sh_mode, sh_indices): (ash::vk::SharingMode, SmallVec<[u32; 8]>),
- linear_tiling: bool,
- preinitialized_layout: bool,
- ) -> Result<(UnsafeImage, MemoryRequirements), ImageCreationError> {
- // TODO: doesn't check that the proper features are enabled
-
- if flags.sparse_binding
- || flags.sparse_residency
- || flags.sparse_aliased
- || flags.mutable_format
+ fn validate_new(
+ device: &Device,
+ create_info: &ImageCreateInfo,
+ ) -> Result<FormatFeatures, ImageError> {
+ let &ImageCreateInfo {
+ flags,
+ dimensions,
+ format,
+ mip_levels,
+ samples,
+ tiling,
+ usage,
+ mut stencil_usage,
+ ref sharing,
+ initial_layout,
+ external_memory_handle_types,
+ _ne: _,
+ image_drm_format_modifier_create_info,
+ } = create_info;
+
+ let physical_device = device.physical_device();
+ let device_properties = physical_device.properties();
+
+ let format = format.unwrap(); // Can be None for "external formats" but Vulkano doesn't support that yet
+ let aspects = format.aspects();
+
+ let has_separate_stencil_usage = if stencil_usage.is_empty()
+ || !aspects.contains(ImageAspects::DEPTH | ImageAspects::STENCIL)
{
- unimplemented!();
+ stencil_usage = usage;
+ false
+ } else {
+ stencil_usage == usage
+ };
+
+ // VUID-VkImageCreateInfo-flags-parameter
+ flags.validate_device(device)?;
+
+ // VUID-VkImageCreateInfo-format-parameter
+ format.validate_device(device)?;
+
+ // VUID-VkImageCreateInfo-samples-parameter
+ samples.validate_device(device)?;
+
+ // VUID-VkImageCreateInfo-tiling-parameter
+ tiling.validate_device(device)?;
+
+ // VUID-VkImageCreateInfo-usage-parameter
+ usage.validate_device(device)?;
+
+ // VUID-VkImageCreateInfo-usage-requiredbitmask
+ assert!(!usage.is_empty());
+
+ if has_separate_stencil_usage {
+ if !(device.api_version() >= Version::V1_2
+ || device.enabled_extensions().ext_separate_stencil_usage)
+ {
+ return Err(ImageError::RequirementNotMet {
+ required_for: "`create_info.stencil_usage` is `Some` and `create_info.format` \
+ has both a depth and a stencil aspect",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_2),
+ device_extensions: &["ext_separate_stencil_usage"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkImageStencilUsageCreateInfo-stencilUsage-parameter
+ stencil_usage.validate_device(device)?;
+
+ // VUID-VkImageStencilUsageCreateInfo-usage-requiredbitmask
+ assert!(!stencil_usage.is_empty());
}
- let fns = device.fns();
- let fns_i = device.instance().fns();
+ // VUID-VkImageCreateInfo-initialLayout-parameter
+ initial_layout.validate_device(device)?;
- // Checking if image usage conforms to what is supported.
- let format_features = {
- let format_properties = format.properties(device.physical_device());
+ // VUID-VkImageCreateInfo-initialLayout-00993
+ assert!(matches!(
+ initial_layout,
+ ImageLayout::Undefined | ImageLayout::Preinitialized
+ ));
- let features = if linear_tiling {
- format_properties.linear_tiling_features
- } else {
- format_properties.optimal_tiling_features
- };
+ // VUID-VkImageCreateInfo-flags-01573
+ assert!(
+ !flags.intersects(ImageCreateFlags::BLOCK_TEXEL_VIEW_COMPATIBLE)
+ || flags.intersects(ImageCreateFlags::MUTABLE_FORMAT)
+ );
+
+ // VUID-VkImageCreateInfo-tiling-02261
+ // VUID-VkImageCreateInfo-pNext-02262
+ if (tiling == ImageTiling::DrmFormatModifier)
+ != image_drm_format_modifier_create_info.is_some()
+ {
+ return Err(ImageError::DrmFormatModifierRequiresCreateInfo);
+ }
- if features == FormatFeatures::default() {
- return Err(ImageCreationError::FormatNotSupported);
+ // Get format features
+ let format_features = {
+ // Use unchecked, because all validation has been done above.
+ let format_properties = unsafe { physical_device.format_properties_unchecked(format) };
+ match tiling {
+ ImageTiling::Linear => format_properties.linear_tiling_features,
+ ImageTiling::Optimal => format_properties.optimal_tiling_features,
+ ImageTiling::DrmFormatModifier => format_properties.linear_tiling_features, // TODO: Improve
}
+ };
+
+ // TODO: VUID-VkImageCreateInfo-tiling-02353
+ // Vulkano currently has no high-level way to add or check for VkImageFormatListCreateInfo.
+
+ // Format isn't supported at all?
+ if format_features.is_empty() {
+ return Err(ImageError::FormatNotSupported);
+ }
+
+ // Decode the dimensions
+ let (image_type, extent, array_layers) = match dimensions {
+ ImageDimensions::Dim1d {
+ width,
+ array_layers,
+ } => (ImageType::Dim1d, [width, 1, 1], array_layers),
+ ImageDimensions::Dim2d {
+ width,
+ height,
+ array_layers,
+ } => (ImageType::Dim2d, [width, height, 1], array_layers),
+ ImageDimensions::Dim3d {
+ width,
+ height,
+ depth,
+ } => (ImageType::Dim3d, [width, height, depth], 1),
+ };
+
+ // VUID-VkImageCreateInfo-extent-00944
+ assert!(extent[0] != 0);
+
+ // VUID-VkImageCreateInfo-extent-00945
+ assert!(extent[1] != 0);
- if usage.sampled && !features.sampled_image {
- return Err(ImageCreationError::UnsupportedUsage);
+ // VUID-VkImageCreateInfo-extent-00946
+ assert!(extent[2] != 0);
+
+ // VUID-VkImageCreateInfo-arrayLayers-00948
+ assert!(array_layers != 0);
+
+ // VUID-VkImageCreateInfo-mipLevels-00947
+ assert!(mip_levels != 0);
+
+ // Check mip levels
+
+ let max_mip_levels = dimensions.max_mip_levels();
+ debug_assert!(max_mip_levels >= 1);
+
+ // VUID-VkImageCreateInfo-mipLevels-00958
+ if mip_levels > max_mip_levels {
+ return Err(ImageError::MaxMipLevelsExceeded {
+ mip_levels,
+ max: max_mip_levels,
+ });
+ }
+
+ // VUID-VkImageCreateInfo-samples-02257
+ if samples != SampleCount::Sample1 {
+ if image_type != ImageType::Dim2d {
+ return Err(ImageError::MultisampleNot2d);
}
- if usage.storage && !features.storage_image {
- return Err(ImageCreationError::UnsupportedUsage);
+
+ if flags.intersects(ImageCreateFlags::CUBE_COMPATIBLE) {
+ return Err(ImageError::MultisampleCubeCompatible);
}
- if usage.color_attachment && !features.color_attachment {
- return Err(ImageCreationError::UnsupportedUsage);
+
+ if mip_levels != 1 {
+ return Err(ImageError::MultisampleMultipleMipLevels);
}
- if usage.depth_stencil_attachment && !features.depth_stencil_attachment {
- return Err(ImageCreationError::UnsupportedUsage);
+
+ if tiling == ImageTiling::Linear {
+ return Err(ImageError::MultisampleLinearTiling);
}
- if usage.input_attachment
- && !(features.color_attachment || features.depth_stencil_attachment)
+
+ // VUID-VkImageCreateInfo-multisampleArrayImage-04460
+ if device.enabled_extensions().khr_portability_subset
+ && !device.enabled_features().multisample_array_image
+ && array_layers != 1
{
- return Err(ImageCreationError::UnsupportedUsage);
+ return Err(ImageError::RequirementNotMet {
+ required_for: "this device is a portability subset device, \
+ `create_info.samples` is not `SampleCount::Sample1` and \
+ `create_info.dimensions.array_layers()` is greater than `1`",
+ requires_one_of: RequiresOneOf {
+ features: &["multisample_array_image"],
+ ..Default::default()
+ },
+ });
}
- if device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_maintenance1
- {
- if usage.transfer_source && !features.transfer_src {
- return Err(ImageCreationError::UnsupportedUsage);
+ }
+
+ // Check limits for YCbCr formats
+ if let Some(chroma_sampling) = format.ycbcr_chroma_sampling() {
+ // VUID-VkImageCreateInfo-format-06410
+ if mip_levels != 1 {
+ return Err(ImageError::YcbcrFormatMultipleMipLevels);
+ }
+
+ // VUID-VkImageCreateInfo-format-06411
+ if samples != SampleCount::Sample1 {
+ return Err(ImageError::YcbcrFormatMultisampling);
+ }
+
+ // VUID-VkImageCreateInfo-format-06412
+ if image_type != ImageType::Dim2d {
+ return Err(ImageError::YcbcrFormatNot2d);
+ }
+
+ // VUID-VkImageCreateInfo-format-06413
+ if array_layers > 1 && !device.enabled_features().ycbcr_image_arrays {
+ return Err(ImageError::RequirementNotMet {
+ required_for: "`create_info.format.ycbcr_chroma_sampling()` is `Some` and \
+ `create_info.dimensions.array_layers()` is greater than `1`",
+ requires_one_of: RequiresOneOf {
+ features: &["ycbcr_image_arrays"],
+ ..Default::default()
+ },
+ });
+ }
+
+ match chroma_sampling {
+ ChromaSampling::Mode444 => (),
+ ChromaSampling::Mode422 => {
+ // VUID-VkImageCreateInfo-format-04712
+ if extent[0] % 2 != 0 {
+ return Err(ImageError::YcbcrFormatInvalidDimensions);
+ }
}
- if usage.transfer_destination && !features.transfer_dst {
- return Err(ImageCreationError::UnsupportedUsage);
+ ChromaSampling::Mode420 => {
+ // VUID-VkImageCreateInfo-format-04712
+ // VUID-VkImageCreateInfo-format-04713
+ if !(extent[0] % 2 == 0 && extent[1] % 2 == 0) {
+ return Err(ImageError::YcbcrFormatInvalidDimensions);
+ }
}
}
+ }
- features
- };
+ /* Check usage requirements */
+
+ let combined_usage = usage | stencil_usage;
+
+ if combined_usage.intersects(ImageUsage::SAMPLED)
+ && !format_features.intersects(FormatFeatures::SAMPLED_IMAGE)
+ {
+ return Err(ImageError::FormatUsageNotSupported { usage: "sampled" });
+ }
- // VUID-VkImageCreateInfo-usage-requiredbitmask: usage must not be 0
- if usage == ImageUsage::none() {
- return Err(ImageCreationError::UnsupportedUsage);
+ if combined_usage.intersects(ImageUsage::COLOR_ATTACHMENT)
+ && !format_features.intersects(FormatFeatures::COLOR_ATTACHMENT)
+ {
+ return Err(ImageError::FormatUsageNotSupported {
+ usage: "color_attachment",
+ });
}
- // If `transient_attachment` is true, then only `color_attachment`,
- // `depth_stencil_attachment` and `input_attachment` can be true as well.
- if usage.transient_attachment {
- let u = ImageUsage {
- transient_attachment: false,
- color_attachment: false,
- depth_stencil_attachment: false,
- input_attachment: false,
- ..usage.clone()
- };
+ if combined_usage.intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT)
+ && !format_features.intersects(FormatFeatures::DEPTH_STENCIL_ATTACHMENT)
+ {
+ return Err(ImageError::FormatUsageNotSupported {
+ usage: "depth_stencil_attachment",
+ });
+ }
+
+ if combined_usage.intersects(ImageUsage::INPUT_ATTACHMENT)
+ && !format_features.intersects(
+ FormatFeatures::COLOR_ATTACHMENT | FormatFeatures::DEPTH_STENCIL_ATTACHMENT,
+ )
+ {
+ return Err(ImageError::FormatUsageNotSupported {
+ usage: "input_attachment",
+ });
+ }
- if u != ImageUsage::none() {
- return Err(ImageCreationError::UnsupportedUsage);
+ if combined_usage.intersects(
+ ImageUsage::COLOR_ATTACHMENT
+ | ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ | ImageUsage::INPUT_ATTACHMENT
+ | ImageUsage::TRANSIENT_ATTACHMENT,
+ ) {
+ // VUID-VkImageCreateInfo-usage-00964
+ // VUID-VkImageCreateInfo-usage-00965
+ // VUID-VkImageCreateInfo-Format-02536
+ // VUID-VkImageCreateInfo-format-02537
+ if extent[0] > device_properties.max_framebuffer_width
+ || extent[1] > device_properties.max_framebuffer_height
+ {
+ return Err(ImageError::MaxFramebufferDimensionsExceeded {
+ extent: [extent[0], extent[1]],
+ max: [
+ device_properties.max_framebuffer_width,
+ device_properties.max_framebuffer_height,
+ ],
+ });
}
}
- // This function is going to perform various checks and write to `capabilities_error` in
- // case of error.
- //
- // If `capabilities_error` is not `None` after the checks are finished, the function will
- // check for additional image capabilities (section 31.4 of the specs).
- let mut capabilities_error = None;
+ if combined_usage.intersects(ImageUsage::STORAGE) {
+ if !format_features.intersects(FormatFeatures::STORAGE_IMAGE) {
+ return Err(ImageError::FormatUsageNotSupported { usage: "storage" });
+ }
- // Compute the number of mipmaps.
- let mipmaps = match mipmaps.into() {
- MipmapsCount::Specific(num) => {
- let max_mipmaps = dimensions.max_mipmaps();
- debug_assert!(max_mipmaps >= 1);
- if num < 1 {
- return Err(ImageCreationError::InvalidMipmapsCount {
- obtained: num,
- valid_range: 1..max_mipmaps + 1,
- });
- } else if num > max_mipmaps {
- capabilities_error = Some(ImageCreationError::InvalidMipmapsCount {
- obtained: num,
- valid_range: 1..max_mipmaps + 1,
- });
- }
+ // VUID-VkImageCreateInfo-usage-00968
+ // VUID-VkImageCreateInfo-format-02538
+ if !device.enabled_features().shader_storage_image_multisample
+ && samples != SampleCount::Sample1
+ {
+ return Err(ImageError::RequirementNotMet {
+ required_for: "`create_info.usage` or `create_info.stencil_usage` contains \
+ `ImageUsage::STORAGE`, and `create_info.samples` is not \
+ `SampleCount::Sample1`",
+ requires_one_of: RequiresOneOf {
+ features: &["shader_storage_image_multisample"],
+ ..Default::default()
+ },
+ });
+ }
+ }
- num
+ // These flags only exist in later versions, ignore them otherwise
+ if device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_maintenance1 {
+ if combined_usage.intersects(ImageUsage::TRANSFER_SRC)
+ && !format_features.intersects(FormatFeatures::TRANSFER_SRC)
+ {
+ return Err(ImageError::FormatUsageNotSupported {
+ usage: "transfer_src",
+ });
}
- MipmapsCount::Log2 => dimensions.max_mipmaps(),
- MipmapsCount::One => 1,
- };
- // Checking whether the number of samples is supported.
- let mut supported_samples = ash::vk::SampleCountFlags::from_raw(0x7f); // all bits up to VK_SAMPLE_COUNT_64_BIT
+ if combined_usage.intersects(ImageUsage::TRANSFER_DST)
+ && !format_features.intersects(FormatFeatures::TRANSFER_DST)
+ {
+ return Err(ImageError::FormatUsageNotSupported {
+ usage: "transfer_dst",
+ });
+ }
+ }
- if usage.sampled {
- match format.ty() {
- FormatTy::Float | FormatTy::Compressed => {
- supported_samples &= device
- .physical_device()
- .properties()
- .sampled_image_color_sample_counts
- .into();
- }
- FormatTy::Uint | FormatTy::Sint => {
- supported_samples &= device
- .physical_device()
- .properties()
- .sampled_image_integer_sample_counts
- .into();
- }
- FormatTy::Depth => {
- supported_samples &= device
- .physical_device()
- .properties()
- .sampled_image_depth_sample_counts
- .into();
- }
- FormatTy::Stencil => {
- supported_samples &= device
- .physical_device()
- .properties()
- .sampled_image_stencil_sample_counts
- .into();
- }
- FormatTy::DepthStencil => {
- supported_samples &= device
- .physical_device()
- .properties()
- .sampled_image_depth_sample_counts
- .into();
- supported_samples &= device
- .physical_device()
- .properties()
- .sampled_image_stencil_sample_counts
- .into();
- }
- FormatTy::Ycbcr => {
- /*
- * VUID-VkImageCreateInfo-format-02562: If the image format is one of
- * those formats requiring sampler ycbcr conversion, samples *must* be
- * VK_SAMPLE_COUNT_1_BIT
- */
- supported_samples &= ash::vk::SampleCountFlags::TYPE_1;
+ if usage.intersects(ImageUsage::TRANSIENT_ATTACHMENT) {
+ // VUID-VkImageCreateInfo-usage-00966
+ assert!(usage.intersects(
+ ImageUsage::COLOR_ATTACHMENT
+ | ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ | ImageUsage::INPUT_ATTACHMENT
+ ));
+
+ // VUID-VkImageCreateInfo-usage-00963
+ assert!((usage
+ - (ImageUsage::TRANSIENT_ATTACHMENT
+ | ImageUsage::COLOR_ATTACHMENT
+ | ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ | ImageUsage::INPUT_ATTACHMENT))
+ .is_empty())
+ }
+
+ if has_separate_stencil_usage {
+ // VUID-VkImageCreateInfo-format-02795
+ // VUID-VkImageCreateInfo-format-02796
+ if usage.intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT)
+ != stencil_usage.intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT)
+ {
+ return Err(ImageError::StencilUsageMismatch {
+ usage,
+ stencil_usage,
+ });
+ }
+
+ // VUID-VkImageCreateInfo-format-02797
+ // VUID-VkImageCreateInfo-format-02798
+ if usage.intersects(ImageUsage::TRANSIENT_ATTACHMENT)
+ != stencil_usage.intersects(ImageUsage::TRANSIENT_ATTACHMENT)
+ {
+ return Err(ImageError::StencilUsageMismatch {
+ usage,
+ stencil_usage,
+ });
+ }
+
+ if stencil_usage.intersects(ImageUsage::TRANSIENT_ATTACHMENT) {
+ // VUID-VkImageStencilUsageCreateInfo-stencilUsage-02539
+ assert!((stencil_usage
+ - (ImageUsage::TRANSIENT_ATTACHMENT
+ | ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ | ImageUsage::INPUT_ATTACHMENT))
+ .is_empty())
+ }
+ }
+
+ /* Check flags requirements */
+
+ if flags.intersects(ImageCreateFlags::CUBE_COMPATIBLE) {
+ // VUID-VkImageCreateInfo-flags-00949
+ if image_type != ImageType::Dim2d {
+ return Err(ImageError::CubeCompatibleNot2d);
+ }
+
+ // VUID-VkImageCreateInfo-imageType-00954
+ if extent[0] != extent[1] {
+ return Err(ImageError::CubeCompatibleNotSquare);
+ }
+
+ // VUID-VkImageCreateInfo-imageType-00954
+ if array_layers < 6 {
+ return Err(ImageError::CubeCompatibleNotEnoughArrayLayers);
+ }
+ }
+
+ if flags.intersects(ImageCreateFlags::ARRAY_2D_COMPATIBLE) {
+ // VUID-VkImageCreateInfo-flags-00950
+ if image_type != ImageType::Dim3d {
+ return Err(ImageError::Array2dCompatibleNot3d);
+ }
+
+ // VUID-VkImageCreateInfo-imageView2DOn3DImage-04459
+ if device.enabled_extensions().khr_portability_subset
+ && !device.enabled_features().image_view2_d_on3_d_image
+ {
+ return Err(ImageError::RequirementNotMet {
+ required_for: "this device is a portability subset device, and \
+ `create_info.flags` contains `ImageCreateFlags::ARRAY_2D_COMPATIBLE`",
+ requires_one_of: RequiresOneOf {
+ features: &["image_view2_d_on3_d_image"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+
+ if flags.intersects(ImageCreateFlags::BLOCK_TEXEL_VIEW_COMPATIBLE) {
+ // VUID-VkImageCreateInfo-flags-01572
+ if format.compression().is_none() {
+ return Err(ImageError::BlockTexelViewCompatibleNotCompressed);
+ }
+ }
+
+ if flags.intersects(ImageCreateFlags::DISJOINT) {
+ // VUID-VkImageCreateInfo-format-01577
+ if format.planes().len() < 2 {
+ return Err(ImageError::DisjointFormatNotSupported);
+ }
+
+ // VUID-VkImageCreateInfo-imageCreateFormatFeatures-02260
+ if !format_features.intersects(FormatFeatures::DISJOINT) {
+ return Err(ImageError::DisjointFormatNotSupported);
+ }
+ }
+
+ /* Check sharing mode and queue families */
+
+ match sharing {
+ Sharing::Exclusive => (),
+ Sharing::Concurrent(queue_family_indices) => {
+ // VUID-VkImageCreateInfo-sharingMode-00942
+ assert!(queue_family_indices.len() >= 2);
+
+ for &queue_family_index in queue_family_indices {
+ // VUID-VkImageCreateInfo-sharingMode-01420
+ if queue_family_index
+ >= device.physical_device().queue_family_properties().len() as u32
+ {
+ return Err(ImageError::SharingQueueFamilyIndexOutOfRange {
+ queue_family_index,
+ queue_family_count: device
+ .physical_device()
+ .queue_family_properties()
+ .len() as u32,
+ });
+ }
}
}
+ }
+
+ /* External memory handles */
+
+ if !external_memory_handle_types.is_empty() {
+ if !(device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_external_memory)
+ {
+ return Err(ImageError::RequirementNotMet {
+ required_for: "`create_info.external_memory_handle_types` is not empty",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_1),
+ device_extensions: &["khr_external_memory"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkExternalMemoryImageCreateInfo-handleTypes-parameter
+ external_memory_handle_types.validate_device(device)?;
+
+ // VUID-VkImageCreateInfo-pNext-01443
+ if initial_layout != ImageLayout::Undefined {
+ return Err(ImageError::ExternalMemoryInvalidInitialLayout);
+ }
+ }
- if usage.storage {
- supported_samples &= device
+ /*
+ Some device limits can be exceeded, but only for particular image configurations, which
+ must be queried with `image_format_properties`. See:
+ https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap44.html#capabilities-image
+ First, we check if this is the case, then query the device if so.
+ */
+
+ // https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap44.html#features-extentperimagetype
+ let extent_must_query = || match image_type {
+ ImageType::Dim1d => {
+ let limit = device.physical_device().properties().max_image_dimension1_d;
+ extent[0] > limit
+ }
+ ImageType::Dim2d if flags.intersects(ImageCreateFlags::CUBE_COMPATIBLE) => {
+ let limit = device
.physical_device()
.properties()
- .storage_image_sample_counts
- .into();
+ .max_image_dimension_cube;
+ extent[0] > limit
+ }
+ ImageType::Dim2d => {
+ let limit = device.physical_device().properties().max_image_dimension2_d;
+ extent[0] > limit || extent[1] > limit
+ }
+ ImageType::Dim3d => {
+ let limit = device.physical_device().properties().max_image_dimension3_d;
+ extent[0] > limit || extent[1] > limit || extent[2] > limit
+ }
+ };
+ // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkImageFormatProperties.html
+ let mip_levels_must_query = || {
+ if mip_levels > 1 {
+ // TODO: for external memory, the spec says:
+ // "handle type included in the handleTypes member for which mipmap image support is
+ // not required". But which handle types are those?
+ !external_memory_handle_types.is_empty()
+ } else {
+ false
+ }
+ };
+ // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkImageFormatProperties.html
+ let array_layers_must_query = || {
+ if array_layers > device.physical_device().properties().max_image_array_layers {
+ true
+ } else if array_layers > 1 {
+ image_type == ImageType::Dim3d
+ } else {
+ false
+ }
+ };
+ // https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap44.html#features-supported-sample-counts
+ let samples_must_query = || {
+ if samples == SampleCount::Sample1 {
+ return false;
}
- if usage.color_attachment
- || usage.depth_stencil_attachment
- || usage.input_attachment
- || usage.transient_attachment
+ if combined_usage.intersects(ImageUsage::COLOR_ATTACHMENT)
+ && !device_properties
+ .framebuffer_color_sample_counts
+ .contains_enum(samples)
{
- match format.ty() {
- FormatTy::Float | FormatTy::Compressed | FormatTy::Uint | FormatTy::Sint => {
- supported_samples &= device
- .physical_device()
- .properties()
- .framebuffer_color_sample_counts
- .into();
- }
- FormatTy::Depth => {
- supported_samples &= device
- .physical_device()
- .properties()
- .framebuffer_depth_sample_counts
- .into();
- }
- FormatTy::Stencil => {
- supported_samples &= device
- .physical_device()
- .properties()
- .framebuffer_stencil_sample_counts
- .into();
+ // TODO: how to handle framebuffer_integer_color_sample_counts limit, which only
+ // exists >= Vulkan 1.2
+ return true;
+ }
+
+ if combined_usage.intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT) {
+ if aspects.intersects(ImageAspects::DEPTH)
+ && !device_properties
+ .framebuffer_depth_sample_counts
+ .contains_enum(samples)
+ {
+ return true;
+ }
+
+ if aspects.intersects(ImageAspects::STENCIL)
+ && !device_properties
+ .framebuffer_stencil_sample_counts
+ .contains_enum(samples)
+ {
+ return true;
+ }
+ }
+
+ if combined_usage.intersects(ImageUsage::SAMPLED) {
+ if let Some(numeric_type) = format.type_color() {
+ match numeric_type {
+ NumericType::UINT | NumericType::SINT => {
+ if !device_properties
+ .sampled_image_integer_sample_counts
+ .contains_enum(samples)
+ {
+ return true;
+ }
+ }
+ NumericType::SFLOAT
+ | NumericType::UFLOAT
+ | NumericType::SNORM
+ | NumericType::UNORM
+ | NumericType::SSCALED
+ | NumericType::USCALED
+ | NumericType::SRGB => {
+ if !device_properties
+ .sampled_image_color_sample_counts
+ .contains_enum(samples)
+ {
+ return true;
+ }
+ }
}
- FormatTy::DepthStencil => {
- supported_samples &= device
- .physical_device()
- .properties()
- .framebuffer_depth_sample_counts
- .into();
- supported_samples &= device
- .physical_device()
- .properties()
- .framebuffer_stencil_sample_counts
- .into();
+ } else {
+ if aspects.intersects(ImageAspects::DEPTH)
+ && !device_properties
+ .sampled_image_depth_sample_counts
+ .contains_enum(samples)
+ {
+ return true;
}
- FormatTy::Ycbcr => {
- /*
- * It's generally not possible to use a Ycbcr image as a framebuffer color
- * attachment.
- */
- return Err(ImageCreationError::UnsupportedUsage);
+
+ if aspects.intersects(ImageAspects::STENCIL)
+ && device_properties
+ .sampled_image_stencil_sample_counts
+ .contains_enum(samples)
+ {
+ return true;
}
}
}
- if (ash::vk::SampleCountFlags::from(num_samples) & supported_samples).is_empty() {
- let err = ImageCreationError::UnsupportedSamplesCount {
- obtained: num_samples,
- };
- capabilities_error = Some(err);
+ if combined_usage.intersects(ImageUsage::STORAGE)
+ && !device_properties
+ .storage_image_sample_counts
+ .contains_enum(samples)
+ {
+ return true;
}
- }
- // If the `shaderStorageImageMultisample` feature is not enabled and we have
- // `usage_storage` set to true, then the number of samples must be 1.
- if usage.storage && num_samples as u32 > 1 {
- if !device.enabled_features().shader_storage_image_multisample {
- return Err(ImageCreationError::ShaderStorageImageMultisampleFeatureNotEnabled);
+ false
+ };
+ // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkImageCreateInfo.html#_description
+ let linear_must_query = || {
+ if tiling == ImageTiling::Linear {
+ !(image_type == ImageType::Dim2d
+ && format.type_color().is_some()
+ && mip_levels == 1
+ && array_layers == 1
+ // VUID-VkImageCreateInfo-samples-02257 already states that multisampling+linear
+ // is invalid so no need to check for that here.
+ && (usage - (ImageUsage::TRANSFER_SRC | ImageUsage::TRANSFER_DST)).is_empty())
+ } else {
+ false
+ }
+ };
+
+ let must_query_device = extent_must_query()
+ || mip_levels_must_query()
+ || array_layers_must_query()
+ || samples_must_query()
+ || linear_must_query();
+
+ // We determined that we must query the device in order to be sure that the image
+ // configuration is supported.
+ if must_query_device {
+ let external_memory_handle_types: SmallVec<[Option<ExternalMemoryHandleType>; 4]> =
+ if !external_memory_handle_types.is_empty() {
+ // If external memory handles are used, the properties need to be queried
+ // individually for each handle type.
+ external_memory_handle_types.into_iter().map(Some).collect()
+ } else {
+ smallvec![None]
+ };
+
+ for external_memory_handle_type in external_memory_handle_types {
+ // Use unchecked, because all validation has been done above.
+ let image_format_properties = unsafe {
+ device
+ .physical_device()
+ .image_format_properties_unchecked(ImageFormatInfo {
+ flags,
+ format: Some(format),
+ image_type,
+ tiling,
+ usage,
+ external_memory_handle_type,
+ ..Default::default()
+ })?
+ };
+
+ let ImageFormatProperties {
+ max_extent,
+ max_mip_levels,
+ max_array_layers,
+ sample_counts,
+ max_resource_size: _,
+ ..
+ } = match image_format_properties {
+ Some(x) => x,
+ None => return Err(ImageError::ImageFormatPropertiesNotSupported),
+ };
+
+ // VUID-VkImageCreateInfo-extent-02252
+ // VUID-VkImageCreateInfo-extent-02253
+ // VUID-VkImageCreateInfo-extent-02254
+ if extent[0] > max_extent[0]
+ || extent[1] > max_extent[1]
+ || extent[2] > max_extent[2]
+ {
+ return Err(ImageError::MaxDimensionsExceeded {
+ extent,
+ max: max_extent,
+ });
+ }
+
+ // VUID-VkImageCreateInfo-mipLevels-02255
+ if mip_levels > max_mip_levels {
+ return Err(ImageError::MaxMipLevelsExceeded {
+ mip_levels,
+ max: max_mip_levels,
+ });
+ }
+
+ // VUID-VkImageCreateInfo-arrayLayers-02256
+ if array_layers > max_array_layers {
+ return Err(ImageError::MaxArrayLayersExceeded {
+ array_layers,
+ max: max_array_layers,
+ });
+ }
+
+ // VUID-VkImageCreateInfo-samples-02258
+ if !sample_counts.contains_enum(samples) {
+ return Err(ImageError::SampleCountNotSupported {
+ samples,
+ supported: sample_counts,
+ });
+ }
+
+ // TODO: check resource size?
}
}
- // Decoding the dimensions.
- let (ty, extent, array_layers) = match dimensions {
+ Ok(format_features)
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ #[inline]
+ pub unsafe fn new_unchecked(
+ device: Arc<Device>,
+ create_info: ImageCreateInfo,
+ ) -> Result<Self, VulkanError> {
+ let &ImageCreateInfo {
+ flags,
+ dimensions,
+ format,
+ mip_levels,
+ samples,
+ tiling,
+ usage,
+ mut stencil_usage,
+ ref sharing,
+ initial_layout,
+ external_memory_handle_types,
+ _ne: _,
+ mut image_drm_format_modifier_create_info,
+ } = &create_info;
+
+ let aspects = format.map_or_else(Default::default, |format| format.aspects());
+
+ let has_separate_stencil_usage = if stencil_usage.is_empty()
+ || !aspects.contains(ImageAspects::DEPTH | ImageAspects::STENCIL)
+ {
+ stencil_usage = usage;
+ false
+ } else {
+ stencil_usage == usage
+ };
+
+ let (image_type, extent, array_layers) = match dimensions {
ImageDimensions::Dim1d {
width,
array_layers,
- } => {
- if width == 0 || array_layers == 0 {
- return Err(ImageCreationError::UnsupportedDimensions { dimensions });
- }
- let extent = ash::vk::Extent3D {
- width,
- height: 1,
- depth: 1,
- };
- (ash::vk::ImageType::TYPE_1D, extent, array_layers)
- }
+ } => (ImageType::Dim1d, [width, 1, 1], array_layers),
ImageDimensions::Dim2d {
width,
height,
array_layers,
- } => {
- if width == 0 || height == 0 || array_layers == 0 {
- return Err(ImageCreationError::UnsupportedDimensions { dimensions });
- }
- let extent = ash::vk::Extent3D {
- width,
- height,
- depth: 1,
- };
- (ash::vk::ImageType::TYPE_2D, extent, array_layers)
- }
+ } => (ImageType::Dim2d, [width, height, 1], array_layers),
ImageDimensions::Dim3d {
width,
height,
depth,
- } => {
- if width == 0 || height == 0 || depth == 0 {
- return Err(ImageCreationError::UnsupportedDimensions { dimensions });
- }
- let extent = ash::vk::Extent3D {
- width,
- height,
- depth,
- };
- (ash::vk::ImageType::TYPE_3D, extent, 1)
- }
+ } => (ImageType::Dim3d, [width, height, depth], 1),
};
- // Checking flags requirements.
- if flags.cube_compatible {
- if !(ty == ash::vk::ImageType::TYPE_2D
- && extent.width == extent.height
- && array_layers >= 6)
- {
- return Err(ImageCreationError::CreationFlagRequirementsNotMet);
- }
+ let (sharing_mode, queue_family_index_count, p_queue_family_indices) = match sharing {
+ Sharing::Exclusive => (ash::vk::SharingMode::EXCLUSIVE, 0, &[] as _),
+ Sharing::Concurrent(queue_family_indices) => (
+ ash::vk::SharingMode::CONCURRENT,
+ queue_family_indices.len() as u32,
+ queue_family_indices.as_ptr(),
+ ),
+ };
+
+ let mut info_vk = ash::vk::ImageCreateInfo {
+ flags: flags.into(),
+ image_type: image_type.into(),
+ format: format.map(Into::into).unwrap_or_default(),
+ extent: ash::vk::Extent3D {
+ width: extent[0],
+ height: extent[1],
+ depth: extent[2],
+ },
+ mip_levels,
+ array_layers,
+ samples: samples.into(),
+ tiling: tiling.into(),
+ usage: usage.into(),
+ sharing_mode,
+ queue_family_index_count,
+ p_queue_family_indices,
+ initial_layout: initial_layout.into(),
+ ..Default::default()
+ };
+ let mut external_memory_info_vk = None;
+ let mut stencil_usage_info_vk = None;
+
+ if !external_memory_handle_types.is_empty() {
+ let next = external_memory_info_vk.insert(ash::vk::ExternalMemoryImageCreateInfo {
+ handle_types: external_memory_handle_types.into(),
+ ..Default::default()
+ });
+
+ next.p_next = info_vk.p_next;
+ info_vk.p_next = next as *const _ as *const _;
}
- if flags.array_2d_compatible {
- if !(ty == ash::vk::ImageType::TYPE_3D) {
- return Err(ImageCreationError::CreationFlagRequirementsNotMet);
- }
+ if has_separate_stencil_usage {
+ let next = stencil_usage_info_vk.insert(ash::vk::ImageStencilUsageCreateInfo {
+ stencil_usage: stencil_usage.into(),
+ ..Default::default()
+ });
+
+ next.p_next = info_vk.p_next;
+ info_vk.p_next = next as *const _ as *const _;
}
- // Checking the dimensions against the limits.
- if array_layers
- > device
- .physical_device()
- .properties()
- .max_image_array_layers
+ if external_memory_handle_types.intersects(ExternalMemoryHandleTypes::DMA_BUF) {
+ let next = image_drm_format_modifier_create_info.as_mut().unwrap();
+
+ next.p_next = info_vk.p_next;
+ info_vk.p_next = next as *const _ as *const _;
+ }
+
+ let handle = {
+ let fns = device.fns();
+ let mut output = MaybeUninit::uninit();
+ (fns.v1_0.create_image)(device.handle(), &info_vk, ptr::null(), output.as_mut_ptr())
+ .result()
+ .map_err(VulkanError::from)?;
+ output.assume_init()
+ };
+
+ Ok(Self::from_handle(device, handle, create_info))
+ }
+
+ /// Creates a new `RawImage` from a raw object handle.
+ ///
+ /// # Safety
+ ///
+ /// - `handle` must be a valid Vulkan object handle created from `device`.
+ /// - `handle` must refer to an image that has not yet had memory bound to it.
+ /// - `create_info` must match the info used to create the object.
+ #[inline]
+ pub unsafe fn from_handle(
+ device: Arc<Device>,
+ handle: ash::vk::Image,
+ create_info: ImageCreateInfo,
+ ) -> Self {
+ Self::from_handle_with_destruction(device, handle, create_info, true)
+ }
+
+ unsafe fn from_handle_with_destruction(
+ device: Arc<Device>,
+ handle: ash::vk::Image,
+ create_info: ImageCreateInfo,
+ needs_destruction: bool,
+ ) -> Self {
+ let ImageCreateInfo {
+ flags,
+ dimensions,
+ format,
+ mip_levels,
+ samples,
+ tiling,
+ usage,
+ mut stencil_usage,
+ sharing,
+ initial_layout,
+ external_memory_handle_types,
+ _ne: _,
+ image_drm_format_modifier_create_info: _,
+ } = create_info;
+
+ let aspects = format.map_or_else(Default::default, |format| format.aspects());
+
+ if stencil_usage.is_empty()
+ || !aspects.contains(ImageAspects::DEPTH | ImageAspects::STENCIL)
{
- let err = ImageCreationError::UnsupportedDimensions { dimensions };
- capabilities_error = Some(err);
+ stencil_usage = usage;
}
- match ty {
- ash::vk::ImageType::TYPE_1D => {
- if extent.width
- > device
- .physical_device()
- .properties()
- .max_image_dimension1_d
- {
- let err = ImageCreationError::UnsupportedDimensions { dimensions };
- capabilities_error = Some(err);
- }
- }
- ash::vk::ImageType::TYPE_2D => {
- let limit = device
- .physical_device()
- .properties()
- .max_image_dimension2_d;
- if extent.width > limit || extent.height > limit {
- let err = ImageCreationError::UnsupportedDimensions { dimensions };
- capabilities_error = Some(err);
- }
- if flags.cube_compatible {
- let limit = device
- .physical_device()
- .properties()
- .max_image_dimension_cube;
- if extent.width > limit {
- let err = ImageCreationError::UnsupportedDimensions { dimensions };
- capabilities_error = Some(err);
- }
- }
+ // Get format features
+ let format_features = {
+ // Use unchecked, because `create_info` is assumed to match the info of the handle, and
+ // therefore already valid.
+ let format_properties = device
+ .physical_device()
+ .format_properties_unchecked(format.unwrap());
+ match tiling {
+ ImageTiling::Linear => format_properties.linear_tiling_features,
+ ImageTiling::Optimal => format_properties.optimal_tiling_features,
+ ImageTiling::DrmFormatModifier => format_properties.linear_tiling_features, // TODO: improve
}
- ash::vk::ImageType::TYPE_3D => {
- let limit = device
- .physical_device()
- .properties()
- .max_image_dimension3_d;
- if extent.width > limit || extent.height > limit || extent.depth > limit {
- let err = ImageCreationError::UnsupportedDimensions { dimensions };
- capabilities_error = Some(err);
- }
+ };
+
+ let memory_requirements = if needs_destruction {
+ if flags.intersects(ImageCreateFlags::DISJOINT) {
+ (0..format.unwrap().planes().len())
+ .map(|plane| Self::get_memory_requirements(&device, handle, Some(plane)))
+ .collect()
+ } else {
+ smallvec![Self::get_memory_requirements(&device, handle, None)]
}
- _ => unreachable!(),
+ } else {
+ smallvec![]
+ };
+
+ RawImage {
+ handle,
+ device,
+ id: Self::next_id(),
+ flags,
+ dimensions,
+ format,
+ format_features,
+ mip_levels,
+ initial_layout,
+ samples,
+ tiling,
+ usage,
+ stencil_usage,
+ sharing,
+ external_memory_handle_types,
+ memory_requirements,
+ needs_destruction,
+ subresource_layout: OnceCache::new(),
+ }
+ }
+
+ fn get_memory_requirements(
+ device: &Device,
+ handle: ash::vk::Image,
+ plane: Option<usize>,
+ ) -> MemoryRequirements {
+ let mut info_vk = ash::vk::ImageMemoryRequirementsInfo2 {
+ image: handle,
+ ..Default::default()
};
+ let mut plane_info_vk = None;
- let usage_bits = usage.into();
+ if let Some(plane) = plane {
+ debug_assert!(
+ device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_get_memory_requirements2
+ && device.enabled_extensions().khr_sampler_ycbcr_conversion
+ );
- // Now that all checks have been performed, if any of the check failed we query the Vulkan
- // implementation for additional image capabilities.
- if let Some(capabilities_error) = capabilities_error {
- let tiling = if linear_tiling {
- ash::vk::ImageTiling::LINEAR
- } else {
- ash::vk::ImageTiling::OPTIMAL
- };
+ let next = plane_info_vk.insert(ash::vk::ImagePlaneMemoryRequirementsInfo {
+ plane_aspect: match plane {
+ 0 => ash::vk::ImageAspectFlags::PLANE_0,
+ 1 => ash::vk::ImageAspectFlags::PLANE_1,
+ 2 => ash::vk::ImageAspectFlags::PLANE_2,
+ _ => unreachable!(),
+ },
+ ..Default::default()
+ });
- let mut output = MaybeUninit::uninit();
- let physical_device = device.physical_device().internal_object();
- let r = fns_i.v1_0.get_physical_device_image_format_properties(
- physical_device,
- format.into(),
- ty,
- tiling,
- usage_bits,
- ash::vk::ImageCreateFlags::empty(), /* TODO */
- output.as_mut_ptr(),
+ next.p_next = info_vk.p_next;
+ info_vk.p_next = next as *mut _ as *mut _;
+ }
+
+ let mut memory_requirements2_vk = ash::vk::MemoryRequirements2::default();
+ let mut memory_dedicated_requirements_vk = None;
+
+ if device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_dedicated_allocation
+ {
+ debug_assert!(
+ device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_get_memory_requirements2
);
- match check_errors(r) {
- Ok(_) => (),
- Err(Error::FormatNotSupported) => {
- return Err(ImageCreationError::FormatNotSupported)
+ let next = memory_dedicated_requirements_vk
+ .insert(ash::vk::MemoryDedicatedRequirements::default());
+
+ next.p_next = memory_requirements2_vk.p_next;
+ memory_requirements2_vk.p_next = next as *mut _ as *mut _;
+ }
+
+ unsafe {
+ let fns = device.fns();
+
+ if device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_get_memory_requirements2
+ {
+ if device.api_version() >= Version::V1_1 {
+ (fns.v1_1.get_image_memory_requirements2)(
+ device.handle(),
+ &info_vk,
+ &mut memory_requirements2_vk,
+ );
+ } else {
+ (fns.khr_get_memory_requirements2
+ .get_image_memory_requirements2_khr)(
+ device.handle(),
+ &info_vk,
+ &mut memory_requirements2_vk,
+ );
}
- Err(err) => return Err(err.into()),
+ } else {
+ (fns.v1_0.get_image_memory_requirements)(
+ device.handle(),
+ handle,
+ &mut memory_requirements2_vk.memory_requirements,
+ );
}
+ }
- let output = output.assume_init();
+ MemoryRequirements {
+ layout: DeviceLayout::from_size_alignment(
+ memory_requirements2_vk.memory_requirements.size,
+ memory_requirements2_vk.memory_requirements.alignment,
+ )
+ .unwrap(),
+ memory_type_bits: memory_requirements2_vk.memory_requirements.memory_type_bits,
+ prefers_dedicated_allocation: memory_dedicated_requirements_vk
+ .map_or(false, |dreqs| dreqs.prefers_dedicated_allocation != 0),
+ requires_dedicated_allocation: memory_dedicated_requirements_vk
+ .map_or(false, |dreqs| dreqs.requires_dedicated_allocation != 0),
+ }
+ }
+
+ #[inline]
+ #[allow(dead_code)] // Remove when sparse memory is implemented
+ fn get_sparse_memory_requirements(&self) -> Vec<SparseImageMemoryRequirements> {
+ let device = &self.device;
+
+ unsafe {
+ let fns = self.device.fns();
- if extent.width > output.max_extent.width
- || extent.height > output.max_extent.height
- || extent.depth > output.max_extent.depth
- || mipmaps > output.max_mip_levels
- || array_layers > output.max_array_layers
- || (ash::vk::SampleCountFlags::from(num_samples) & output.sample_counts).is_empty()
+ if device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_get_memory_requirements2
{
- return Err(capabilities_error);
- }
- }
-
- // Everything now ok. Creating the image.
- let image = {
- let infos = ash::vk::ImageCreateInfo {
- flags: flags.into(),
- image_type: ty,
- format: format.into(),
- extent,
- mip_levels: mipmaps,
- array_layers: array_layers,
- samples: num_samples.into(),
- tiling: if linear_tiling {
- ash::vk::ImageTiling::LINEAR
- } else {
- ash::vk::ImageTiling::OPTIMAL
- },
- usage: usage_bits,
- sharing_mode: sh_mode,
- queue_family_index_count: sh_indices.len() as u32,
- p_queue_family_indices: sh_indices.as_ptr(),
- initial_layout: if preinitialized_layout {
- ash::vk::ImageLayout::PREINITIALIZED
+ let info2 = ash::vk::ImageSparseMemoryRequirementsInfo2 {
+ image: self.handle,
+ ..Default::default()
+ };
+
+ let mut count = 0;
+
+ if device.api_version() >= Version::V1_1 {
+ (fns.v1_1.get_image_sparse_memory_requirements2)(
+ device.handle(),
+ &info2,
+ &mut count,
+ ptr::null_mut(),
+ );
} else {
- ash::vk::ImageLayout::UNDEFINED
- },
- ..Default::default()
- };
+ (fns.khr_get_memory_requirements2
+ .get_image_sparse_memory_requirements2_khr)(
+ device.handle(),
+ &info2,
+ &mut count,
+ ptr::null_mut(),
+ );
+ }
- let mut output = MaybeUninit::uninit();
- check_errors(fns.v1_0.create_image(
- device.internal_object(),
- &infos,
- ptr::null(),
- output.as_mut_ptr(),
- ))?;
- output.assume_init()
- };
+ let mut sparse_image_memory_requirements2 =
+ vec![ash::vk::SparseImageMemoryRequirements2::default(); count as usize];
- let mem_reqs = if device.api_version() >= Version::V1_1
- || device.enabled_extensions().khr_get_memory_requirements2
- {
- let infos = ash::vk::ImageMemoryRequirementsInfo2 {
- image,
- ..Default::default()
- };
+ if device.api_version() >= Version::V1_1 {
+ (fns.v1_1.get_image_sparse_memory_requirements2)(
+ self.device.handle(),
+ &info2,
+ &mut count,
+ sparse_image_memory_requirements2.as_mut_ptr(),
+ );
+ } else {
+ (fns.khr_get_memory_requirements2
+ .get_image_sparse_memory_requirements2_khr)(
+ self.device.handle(),
+ &info2,
+ &mut count,
+ sparse_image_memory_requirements2.as_mut_ptr(),
+ );
+ }
- let mut output2 = if device.api_version() >= Version::V1_1
- || device.enabled_extensions().khr_dedicated_allocation
- {
- Some(ash::vk::MemoryDedicatedRequirements::default())
+ sparse_image_memory_requirements2.set_len(count as usize);
+
+ sparse_image_memory_requirements2
+ .into_iter()
+ .map(
+ |sparse_image_memory_requirements2| SparseImageMemoryRequirements {
+ format_properties: SparseImageFormatProperties {
+ aspects: sparse_image_memory_requirements2
+ .memory_requirements
+ .format_properties
+ .aspect_mask
+ .into(),
+ image_granularity: [
+ sparse_image_memory_requirements2
+ .memory_requirements
+ .format_properties
+ .image_granularity
+ .width,
+ sparse_image_memory_requirements2
+ .memory_requirements
+ .format_properties
+ .image_granularity
+ .height,
+ sparse_image_memory_requirements2
+ .memory_requirements
+ .format_properties
+ .image_granularity
+ .depth,
+ ],
+ flags: sparse_image_memory_requirements2
+ .memory_requirements
+ .format_properties
+ .flags
+ .into(),
+ },
+ image_mip_tail_first_lod: sparse_image_memory_requirements2
+ .memory_requirements
+ .image_mip_tail_first_lod,
+ image_mip_tail_size: sparse_image_memory_requirements2
+ .memory_requirements
+ .image_mip_tail_size,
+ image_mip_tail_offset: sparse_image_memory_requirements2
+ .memory_requirements
+ .image_mip_tail_offset,
+ image_mip_tail_stride: (!sparse_image_memory_requirements2
+ .memory_requirements
+ .format_properties
+ .flags
+ .intersects(ash::vk::SparseImageFormatFlags::SINGLE_MIPTAIL))
+ .then_some(
+ sparse_image_memory_requirements2
+ .memory_requirements
+ .image_mip_tail_stride,
+ ),
+ },
+ )
+ .collect()
} else {
- None
- };
+ let mut count = 0;
- let mut output = ash::vk::MemoryRequirements2 {
- p_next: output2
- .as_mut()
- .map(|o| o as *mut _)
- .unwrap_or(ptr::null_mut()) as *mut _,
- ..Default::default()
- };
+ (fns.v1_0.get_image_sparse_memory_requirements)(
+ device.handle(),
+ self.handle,
+ &mut count,
+ ptr::null_mut(),
+ );
+
+ let mut sparse_image_memory_requirements =
+ vec![ash::vk::SparseImageMemoryRequirements::default(); count as usize];
- if device.api_version() >= Version::V1_1 {
- fns.v1_1.get_image_memory_requirements2(
- device.internal_object(),
- &infos,
- &mut output,
+ (fns.v1_0.get_image_sparse_memory_requirements)(
+ device.handle(),
+ self.handle,
+ &mut count,
+ sparse_image_memory_requirements.as_mut_ptr(),
);
- } else {
- fns.khr_get_memory_requirements2
- .get_image_memory_requirements2_khr(
- device.internal_object(),
- &infos,
- &mut output,
- );
+
+ sparse_image_memory_requirements.set_len(count as usize);
+
+ sparse_image_memory_requirements
+ .into_iter()
+ .map(
+ |sparse_image_memory_requirements| SparseImageMemoryRequirements {
+ format_properties: SparseImageFormatProperties {
+ aspects: sparse_image_memory_requirements
+ .format_properties
+ .aspect_mask
+ .into(),
+ image_granularity: [
+ sparse_image_memory_requirements
+ .format_properties
+ .image_granularity
+ .width,
+ sparse_image_memory_requirements
+ .format_properties
+ .image_granularity
+ .height,
+ sparse_image_memory_requirements
+ .format_properties
+ .image_granularity
+ .depth,
+ ],
+ flags: sparse_image_memory_requirements
+ .format_properties
+ .flags
+ .into(),
+ },
+ image_mip_tail_first_lod: sparse_image_memory_requirements
+ .image_mip_tail_first_lod,
+ image_mip_tail_size: sparse_image_memory_requirements
+ .image_mip_tail_size,
+ image_mip_tail_offset: sparse_image_memory_requirements
+ .image_mip_tail_offset,
+ image_mip_tail_stride: (!sparse_image_memory_requirements
+ .format_properties
+ .flags
+ .intersects(ash::vk::SparseImageFormatFlags::SINGLE_MIPTAIL))
+ .then_some(sparse_image_memory_requirements.image_mip_tail_stride),
+ },
+ )
+ .collect()
}
+ }
+ }
- debug_assert!(output.memory_requirements.memory_type_bits != 0);
+ pub(crate) fn id(&self) -> NonZeroU64 {
+ self.id
+ }
- let mut out = MemoryRequirements::from(output.memory_requirements);
- if let Some(output2) = output2 {
- debug_assert_eq!(output2.requires_dedicated_allocation, 0);
- out.prefer_dedicated = output2.prefers_dedicated_allocation != 0;
+ /// Binds device memory to this image.
+ ///
+ /// - If `self.flags().disjoint` is not set, then `allocations` must contain exactly one
+ /// element. This element may be a dedicated allocation.
+ /// - If `self.flags().disjoint` is set, then `allocations` must contain exactly
+ /// `self.format().unwrap().planes().len()` elements. These elements must not be dedicated
+ /// allocations.
+ pub fn bind_memory(
+ self,
+ allocations: impl IntoIterator<Item = MemoryAlloc>,
+ ) -> Result<
+ Image,
+ (
+ ImageError,
+ RawImage,
+ impl ExactSizeIterator<Item = MemoryAlloc>,
+ ),
+ > {
+ let allocations: SmallVec<[_; 3]> = allocations.into_iter().collect();
+
+ if let Err(err) = self.validate_bind_memory(&allocations) {
+ return Err((err, self, allocations.into_iter()));
+ }
+
+ unsafe { self.bind_memory_unchecked(allocations) }.map_err(|(err, image, allocations)| {
+ (
+ err.into(),
+ image,
+ allocations
+ .into_iter()
+ .collect::<SmallVec<[_; 3]>>()
+ .into_iter(),
+ )
+ })
+ }
+
+ fn validate_bind_memory(&self, allocations: &[MemoryAlloc]) -> Result<(), ImageError> {
+ if self.flags.intersects(ImageCreateFlags::DISJOINT) {
+ if allocations.len() != self.format.unwrap().planes().len() {
+ return Err(ImageError::AllocationsWrongNumberOfElements {
+ provided: allocations.len(),
+ required: self.format.unwrap().planes().len(),
+ });
}
- out
} else {
- let mut output: MaybeUninit<ash::vk::MemoryRequirements> = MaybeUninit::uninit();
- fns.v1_0.get_image_memory_requirements(
- device.internal_object(),
- image,
- output.as_mut_ptr(),
- );
- let output = output.assume_init();
- debug_assert!(output.memory_type_bits != 0);
- MemoryRequirements::from(output)
- };
+ if allocations.len() != 1 {
+ return Err(ImageError::AllocationsWrongNumberOfElements {
+ provided: allocations.len(),
+ required: 1,
+ });
+ }
+ }
- let image = UnsafeImage {
- device: device.clone(),
- image,
- usage,
- format,
- flags,
- dimensions,
- samples: num_samples,
- mipmaps,
- format_features,
- needs_destruction: true,
- preinitialized_layout,
- };
+ for (allocations_index, (allocation, memory_requirements)) in (allocations.iter())
+ .zip(self.memory_requirements.iter())
+ .enumerate()
+ {
+ assert_ne!(allocation.allocation_type(), AllocationType::Linear);
- Ok((image, mem_reqs))
- }
+ let memory = allocation.device_memory();
+ let memory_offset = allocation.offset();
+ let memory_type = &self
+ .device
+ .physical_device()
+ .memory_properties()
+ .memory_types[memory.memory_type_index() as usize];
- /// Creates an image from a raw handle. The image won't be destroyed.
- ///
- /// This function is for example used at the swapchain's initialization.
- pub unsafe fn from_raw(
- device: Arc<Device>,
- handle: ash::vk::Image,
- usage: ImageUsage,
- format: Format,
- flags: ImageCreateFlags,
- dimensions: ImageDimensions,
- samples: SampleCount,
- mipmaps: u32,
- ) -> UnsafeImage {
- let format_properties = format.properties(device.physical_device());
+ // VUID-VkBindImageMemoryInfo-commonparent
+ assert_eq!(self.device(), memory.device());
- // TODO: check that usage is correct in regard to `output`?
+ // VUID-VkBindImageMemoryInfo-image-07460
+ // Ensured by taking ownership of `RawImage`.
- UnsafeImage {
- device: device.clone(),
- image: handle,
- usage,
- format,
- flags,
- dimensions,
- samples,
- mipmaps,
- format_features: format_properties.optimal_tiling_features,
- needs_destruction: false, // TODO: pass as parameter
- preinitialized_layout: false, // TODO: Maybe this should be passed in?
+ // VUID-VkBindImageMemoryInfo-image-01045
+ // Currently ensured by not having sparse binding flags, but this needs to be checked
+ // once those are enabled.
+
+ // VUID-VkBindImageMemoryInfo-memoryOffset-01046
+ // Assume that `allocation` was created correctly.
+
+ if let Some(dedicated_to) = memory.dedicated_to() {
+ // VUID-VkBindImageMemoryInfo-memory-02628
+ match dedicated_to {
+ DedicatedTo::Image(id) if id == self.id => {}
+ _ => return Err(ImageError::DedicatedAllocationMismatch),
+ }
+ debug_assert!(memory_offset == 0); // This should be ensured by the allocator
+ } else {
+ // VUID-VkBindImageMemoryInfo-image-01445
+ if memory_requirements.requires_dedicated_allocation {
+ return Err(ImageError::DedicatedAllocationRequired);
+ }
+ }
+
+ // VUID-VkBindImageMemoryInfo-None-01901
+ if memory_type
+ .property_flags
+ .intersects(MemoryPropertyFlags::PROTECTED)
+ {
+ return Err(ImageError::MemoryProtectedMismatch {
+ allocations_index,
+ image_protected: false,
+ memory_protected: true,
+ });
+ }
+
+ // VUID-VkBindImageMemoryInfo-memory-02728
+ if !memory.export_handle_types().is_empty()
+ && !memory
+ .export_handle_types()
+ .intersects(self.external_memory_handle_types)
+ {
+ return Err(ImageError::MemoryExternalHandleTypesDisjoint {
+ allocations_index,
+ image_handle_types: self.external_memory_handle_types,
+ memory_export_handle_types: memory.export_handle_types(),
+ });
+ }
+
+ if let Some(handle_type) = memory.imported_handle_type() {
+ // VUID-VkBindImageMemoryInfo-memory-02989
+ if !ExternalMemoryHandleTypes::from(handle_type)
+ .intersects(self.external_memory_handle_types)
+ {
+ return Err(ImageError::MemoryImportedHandleTypeNotEnabled {
+ allocations_index,
+ image_handle_types: self.external_memory_handle_types,
+ memory_imported_handle_type: handle_type,
+ });
+ }
+ }
+
+ // VUID-VkBindImageMemoryInfo-pNext-01615
+ // VUID-VkBindImageMemoryInfo-pNext-01619
+ if memory_requirements.memory_type_bits & (1 << memory.memory_type_index()) == 0 {
+ return Err(ImageError::MemoryTypeNotAllowed {
+ allocations_index,
+ provided_memory_type_index: memory.memory_type_index(),
+ allowed_memory_type_bits: memory_requirements.memory_type_bits,
+ });
+ }
+
+ // VUID-VkBindImageMemoryInfo-pNext-01616
+ // VUID-VkBindImageMemoryInfo-pNext-01620
+ if !is_aligned(memory_offset, memory_requirements.layout.alignment()) {
+ return Err(ImageError::MemoryAllocationNotAligned {
+ allocations_index,
+ allocation_offset: memory_offset,
+ required_alignment: memory_requirements.layout.alignment(),
+ });
+ }
+
+ // VUID-VkBindImageMemoryInfo-pNext-01617
+ // VUID-VkBindImageMemoryInfo-pNext-01621
+ if allocation.size() < memory_requirements.layout.size() {
+ return Err(ImageError::MemoryAllocationTooSmall {
+ allocations_index,
+ allocation_size: allocation.size(),
+ required_size: memory_requirements.layout.size(),
+ });
+ }
}
+
+ Ok(())
}
- pub unsafe fn bind_memory(
- &self,
- memory: &DeviceMemory,
- offset: DeviceSize,
- ) -> Result<(), OomError> {
+ /// # Safety
+ ///
+ /// - If `self.flags().disjoint` is not set, then `allocations` must contain exactly one
+ /// element.
+ /// - If `self.flags().disjoint` is set, then `allocations` must contain exactly
+ /// `self.format().unwrap().planes().len()` elements.
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn bind_memory_unchecked(
+ self,
+ allocations: impl IntoIterator<Item = MemoryAlloc>,
+ ) -> Result<
+ Image,
+ (
+ VulkanError,
+ RawImage,
+ impl ExactSizeIterator<Item = MemoryAlloc>,
+ ),
+ > {
+ let allocations: SmallVec<[_; 3]> = allocations.into_iter().collect();
let fns = self.device.fns();
- // We check for correctness in debug mode.
- debug_assert!({
- let mut mem_reqs = MaybeUninit::uninit();
- fns.v1_0.get_image_memory_requirements(
- self.device.internal_object(),
- self.image,
- mem_reqs.as_mut_ptr(),
- );
+ let result = if self.device.api_version() >= Version::V1_1
+ || self.device.enabled_extensions().khr_bind_memory2
+ {
+ let mut infos_vk: SmallVec<[_; 3]> = SmallVec::with_capacity(3);
+ let mut plane_infos_vk: SmallVec<[_; 3]> = SmallVec::with_capacity(3);
- let mem_reqs = mem_reqs.assume_init();
- mem_reqs.size <= memory.size() - offset
- && offset % mem_reqs.alignment == 0
- && mem_reqs.memory_type_bits & (1 << memory.memory_type().id()) != 0
- });
+ if self.flags.intersects(ImageCreateFlags::DISJOINT) {
+ debug_assert_eq!(allocations.len(), self.format.unwrap().planes().len());
- check_errors(fns.v1_0.bind_image_memory(
- self.device.internal_object(),
- self.image,
- memory.internal_object(),
- offset,
- ))?;
- Ok(())
+ for (plane, allocation) in allocations.iter().enumerate() {
+ let memory = allocation.device_memory();
+ let memory_offset = allocation.offset();
+
+ infos_vk.push(ash::vk::BindImageMemoryInfo {
+ image: self.handle,
+ memory: memory.handle(),
+ memory_offset,
+ ..Default::default()
+ });
+ // VUID-VkBindImageMemoryInfo-pNext-01618
+ plane_infos_vk.push(ash::vk::BindImagePlaneMemoryInfo {
+ plane_aspect: match plane {
+ 0 => ash::vk::ImageAspectFlags::PLANE_0,
+ 1 => ash::vk::ImageAspectFlags::PLANE_1,
+ 2 => ash::vk::ImageAspectFlags::PLANE_2,
+ _ => unreachable!(),
+ },
+ ..Default::default()
+ });
+ }
+ } else {
+ debug_assert_eq!(allocations.len(), 1);
+
+ let allocation = &allocations[0];
+ let memory = allocation.device_memory();
+ let memory_offset = allocation.offset();
+
+ infos_vk.push(ash::vk::BindImageMemoryInfo {
+ image: self.handle,
+ memory: memory.handle(),
+ memory_offset,
+ ..Default::default()
+ });
+ };
+
+ for (info_vk, plane_info_vk) in (infos_vk.iter_mut()).zip(plane_infos_vk.iter_mut()) {
+ info_vk.p_next = plane_info_vk as *mut _ as *mut _;
+ }
+
+ if self.device.api_version() >= Version::V1_1 {
+ (fns.v1_1.bind_image_memory2)(
+ self.device.handle(),
+ infos_vk.len() as u32,
+ infos_vk.as_ptr(),
+ )
+ } else {
+ (fns.khr_bind_memory2.bind_image_memory2_khr)(
+ self.device.handle(),
+ infos_vk.len() as u32,
+ infos_vk.as_ptr(),
+ )
+ }
+ } else {
+ debug_assert_eq!(allocations.len(), 1);
+
+ let allocation = &allocations[0];
+ let memory = allocation.device_memory();
+ let memory_offset = allocation.offset();
+
+ (fns.v1_0.bind_image_memory)(
+ self.device.handle(),
+ self.handle,
+ memory.handle(),
+ memory_offset,
+ )
+ }
+ .result();
+
+ if let Err(err) = result {
+ return Err((VulkanError::from(err), self, allocations.into_iter()));
+ }
+
+ Ok(Image::from_raw(self, ImageMemory::Normal(allocations)))
}
+ /// Returns the memory requirements for this image.
+ ///
+ /// - If the image is a swapchain image, this returns a slice with a length of 0.
+ /// - If `self.flags().disjoint` is not set, this returns a slice with a length of 1.
+ /// - If `self.flags().disjoint` is set, this returns a slice with a length equal to
+ /// `self.format().unwrap().planes().len()`.
#[inline]
- pub fn device(&self) -> &Arc<Device> {
- &self.device
+ pub fn memory_requirements(&self) -> &[MemoryRequirements] {
+ &self.memory_requirements
+ }
+
+ /// Returns the flags the image was created with.
+ #[inline]
+ pub fn flags(&self) -> ImageCreateFlags {
+ self.flags
+ }
+
+ /// Returns the dimensions of the image.
+ #[inline]
+ pub fn dimensions(&self) -> ImageDimensions {
+ self.dimensions
}
+ /// Returns the image's format.
#[inline]
- pub fn format(&self) -> Format {
+ pub fn format(&self) -> Option<Format> {
self.format
}
- pub fn create_flags(&self) -> ImageCreateFlags {
- self.flags
+ /// Returns the features supported by the image's format.
+ #[inline]
+ pub fn format_features(&self) -> FormatFeatures {
+ self.format_features
}
+ /// Returns the number of mipmap levels in the image.
#[inline]
- pub fn mipmap_levels(&self) -> u32 {
- self.mipmaps
+ pub fn mip_levels(&self) -> u32 {
+ self.mip_levels
}
+ /// Returns the initial layout of the image.
#[inline]
- pub fn dimensions(&self) -> ImageDimensions {
- self.dimensions
+ pub fn initial_layout(&self) -> ImageLayout {
+ self.initial_layout
}
+ /// Returns the number of samples for the image.
#[inline]
pub fn samples(&self) -> SampleCount {
self.samples
}
- /// Returns a key unique to each `UnsafeImage`. Can be used for the `conflicts_key` method.
+ /// Returns the tiling of the image.
+ #[inline]
+ pub fn tiling(&self) -> ImageTiling {
+ self.tiling
+ }
+
+ /// Returns the usage the image was created with.
+ #[inline]
+ pub fn usage(&self) -> ImageUsage {
+ self.usage
+ }
+
+ /// Returns the stencil usage the image was created with.
+ #[inline]
+ pub fn stencil_usage(&self) -> ImageUsage {
+ self.stencil_usage
+ }
+
+ /// Returns the sharing the image was created with.
+ #[inline]
+ pub fn sharing(&self) -> &Sharing<SmallVec<[u32; 4]>> {
+ &self.sharing
+ }
+
+ /// Returns the external memory handle types that are supported with this image.
+ #[inline]
+ pub fn external_memory_handle_types(&self) -> ExternalMemoryHandleTypes {
+ self.external_memory_handle_types
+ }
+
+ /// Returns an `ImageSubresourceLayers` covering the first mip level of the image. All aspects
+ /// of the image are selected, or `plane0` if the image is multi-planar.
#[inline]
- pub fn key(&self) -> u64 {
- self.image.as_raw()
+ pub fn subresource_layers(&self) -> ImageSubresourceLayers {
+ ImageSubresourceLayers {
+ aspects: {
+ let aspects = self.format.unwrap().aspects();
+
+ if aspects.intersects(ImageAspects::PLANE_0) {
+ ImageAspects::PLANE_0
+ } else {
+ aspects
+ }
+ },
+ mip_level: 0,
+ array_layers: 0..self.dimensions.array_layers(),
+ }
}
- /// Queries the layout of an image in memory. Only valid for images with linear tiling.
+ /// Returns an `ImageSubresourceRange` covering the whole image. If the image is multi-planar,
+ /// only the `color` aspect is selected.
+ #[inline]
+ pub fn subresource_range(&self) -> ImageSubresourceRange {
+ ImageSubresourceRange {
+ aspects: self.format.unwrap().aspects()
+ - (ImageAspects::PLANE_0 | ImageAspects::PLANE_1 | ImageAspects::PLANE_2),
+ mip_levels: 0..self.mip_levels,
+ array_layers: 0..self.dimensions.array_layers(),
+ }
+ }
+
+ /// Queries the memory layout of a single subresource of the image.
///
- /// This function is only valid for images with a color format. See the other similar functions
- /// for the other aspects.
+ /// Only images with linear tiling are supported, if they do not have a format with both a
+ /// depth and a stencil format. Images with optimal tiling have an opaque image layout that is
+ /// not suitable for direct memory accesses, and likewise for combined depth/stencil formats.
+ /// Multi-planar formats are supported, but you must specify one of the planes as the `aspect`,
+ /// not [`ImageAspect::Color`].
///
- /// The layout is invariant for each image. However it is not cached, as this would waste
- /// memory in the case of non-linear-tiling images. You are encouraged to store the layout
- /// somewhere in order to avoid calling this semi-expensive function at every single memory
- /// access.
+ /// The results of this function are cached, so that future calls with the same arguments
+ /// do not need to make a call to the Vulkan API again.
+ pub fn subresource_layout(
+ &self,
+ aspect: ImageAspect,
+ mip_level: u32,
+ array_layer: u32,
+ ) -> Result<SubresourceLayout, ImageError> {
+ self.validate_subresource_layout(aspect, mip_level, array_layer)?;
+
+ unsafe { Ok(self.subresource_layout_unchecked(aspect, mip_level, array_layer)) }
+ }
+
+ fn validate_subresource_layout(
+ &self,
+ aspect: ImageAspect,
+ mip_level: u32,
+ array_layer: u32,
+ ) -> Result<(), ImageError> {
+ // VUID-VkImageSubresource-aspectMask-parameter
+ aspect.validate_device(&self.device)?;
+
+ // VUID-VkImageSubresource-aspectMask-requiredbitmask
+ // VUID-vkGetImageSubresourceLayout-aspectMask-00997
+ // Ensured by use of enum `ImageAspect`.
+
+ // VUID-vkGetImageSubresourceLayout-image-02270
+ if !matches!(
+ self.tiling,
+ ImageTiling::DrmFormatModifier | ImageTiling::Linear
+ ) {
+ return Err(ImageError::OptimalTilingNotSupported);
+ }
+
+ // VUID-vkGetImageSubresourceLayout-mipLevel-01716
+ if mip_level >= self.mip_levels {
+ return Err(ImageError::MipLevelOutOfRange {
+ provided_mip_level: mip_level,
+ image_mip_levels: self.mip_levels,
+ });
+ }
+
+ // VUID-vkGetImageSubresourceLayout-arrayLayer-01717
+ if array_layer >= self.dimensions.array_layers() {
+ return Err(ImageError::ArrayLayerOutOfRange {
+ provided_array_layer: array_layer,
+ image_array_layers: self.dimensions.array_layers(),
+ });
+ }
+
+ let mut allowed_aspects = self.format.unwrap().aspects();
+
+ // Follows from the combination of these three VUIDs. See:
+ // https://github.com/KhronosGroup/Vulkan-Docs/issues/1942
+ // VUID-vkGetImageSubresourceLayout-aspectMask-00997
+ // VUID-vkGetImageSubresourceLayout-format-04462
+ // VUID-vkGetImageSubresourceLayout-format-04463
+ if allowed_aspects.contains(ImageAspects::DEPTH | ImageAspects::STENCIL) {
+ return Err(ImageError::DepthStencilFormatsNotSupported);
+ }
+
+ if allowed_aspects
+ .intersects(ImageAspects::PLANE_0 | ImageAspects::PLANE_1 | ImageAspects::PLANE_2)
+ {
+ allowed_aspects -= ImageAspects::COLOR;
+ }
+
+ // TODO: VUID-vkGetImageSubresourceLayout-tiling-02271
+ //if self.tiling == ImageTiling::DrmFormatModifier {
+ // Only one-plane image importing is possible for now.
+ //}
+
+ // VUID-vkGetImageSubresourceLayout-format-04461
+ // VUID-vkGetImageSubresourceLayout-format-04462
+ // VUID-vkGetImageSubresourceLayout-format-04463
+ // VUID-vkGetImageSubresourceLayout-format-04464
+ // VUID-vkGetImageSubresourceLayout-format-01581
+ // VUID-vkGetImageSubresourceLayout-format-01582
+ if !allowed_aspects.contains(aspect.into()) {
+ return Err(ImageError::AspectNotAllowed {
+ provided_aspect: aspect,
+ allowed_aspects,
+ });
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn subresource_layout_unchecked(
+ &self,
+ aspect: ImageAspect,
+ mip_level: u32,
+ array_layer: u32,
+ ) -> SubresourceLayout {
+ self.subresource_layout.get_or_insert(
+ (aspect, mip_level, array_layer),
+ |&(aspect, mip_level, array_layer)| {
+ let fns = self.device.fns();
+
+ let subresource = ash::vk::ImageSubresource {
+ aspect_mask: aspect.into(),
+ mip_level,
+ array_layer,
+ };
+
+ let mut output = MaybeUninit::uninit();
+ (fns.v1_0.get_image_subresource_layout)(
+ self.device.handle(),
+ self.handle,
+ &subresource,
+ output.as_mut_ptr(),
+ );
+ let output = output.assume_init();
+
+ SubresourceLayout {
+ offset: output.offset,
+ size: output.size,
+ row_pitch: output.row_pitch,
+ array_pitch: (self.dimensions.array_layers() > 1).then_some(output.array_pitch),
+ depth_pitch: matches!(self.dimensions, ImageDimensions::Dim3d { .. })
+ .then_some(output.depth_pitch),
+ }
+ },
+ )
+ }
+}
+
+impl Drop for RawImage {
+ #[inline]
+ fn drop(&mut self) {
+ if !self.needs_destruction {
+ return;
+ }
+
+ unsafe {
+ let fns = self.device.fns();
+ (fns.v1_0.destroy_image)(self.device.handle(), self.handle, ptr::null());
+ }
+ }
+}
+
+unsafe impl VulkanObject for RawImage {
+ type Handle = ash::vk::Image;
+
+ #[inline]
+ fn handle(&self) -> Self::Handle {
+ self.handle
+ }
+}
+
+unsafe impl DeviceOwned for RawImage {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+}
+
+impl_id_counter!(RawImage);
+
+/// Parameters to create a new `Image`.
+#[derive(Clone, Debug)]
+pub struct ImageCreateInfo {
+ /// Flags to enable.
///
- /// Note that while Vulkan allows querying the array layers other than 0, it is redundant as
- /// you can easily calculate the position of any layer.
+ /// The default value is [`ImageCreateFlags::empty()`].
+ pub flags: ImageCreateFlags,
+
+ /// The type, extent and number of array layers to create the image with.
///
- /// # Panic
+ /// On [portability subset](crate::instance#portability-subset-devices-and-the-enumerate_portability-flag)
+ /// devices, if `samples` is not [`SampleCount::Sample1`] and `dimensions.array_layers()` is
+ /// not 1, the [`multisample_array_image`](crate::device::Features::multisample_array_image)
+ /// feature must be enabled on the device.
///
- /// - Panics if the mipmap level is out of range.
+ /// The default value is `ImageDimensions::Dim2d { width: 0, height: 0, array_layers: 1 }`,
+ /// which must be overridden.
+ pub dimensions: ImageDimensions,
+
+ /// The format used to store the image data.
///
- /// # Safety
+ /// The default value is `None`, which must be overridden.
+ pub format: Option<Format>,
+
+ /// The number of mip levels to create the image with.
///
- /// - The image must *not* have a depth, stencil or depth-stencil format.
- /// - The image must have been created with linear tiling.
+ /// The default value is `1`.
+ pub mip_levels: u32,
+
+ /// The number of samples per texel that the image should use.
///
- #[inline]
- pub unsafe fn color_linear_layout(&self, mip_level: u32) -> LinearLayout {
- self.linear_layout_impl(mip_level, ImageAspect::Color)
- }
+ /// On [portability subset](crate::instance#portability-subset-devices-and-the-enumerate_portability-flag)
+ /// devices, if `samples` is not [`SampleCount::Sample1`] and `dimensions.array_layers()` is
+ /// not 1, the [`multisample_array_image`](crate::device::Features::multisample_array_image)
+ /// feature must be enabled on the device.
+ ///
+ /// The default value is [`SampleCount::Sample1`].
+ pub samples: SampleCount,
- /// Same as `color_linear_layout`, except that it retrieves the depth component of the image.
+ /// The memory arrangement of the texel blocks.
///
- /// # Panic
+ /// The default value is [`ImageTiling::Optimal`].
+ pub tiling: ImageTiling,
+
+ /// How the image is going to be used.
///
- /// - Panics if the mipmap level is out of range.
+ /// The default value is [`ImageUsage::empty()`], which must be overridden.
+ pub usage: ImageUsage,
+
+ /// How the stencil aspect of the image is going to be used, if any.
///
- /// # Safety
+ /// If `stencil_usage` is empty or if `format` does not have both a depth and a stencil aspect,
+ /// then it is automatically set to equal `usage`.
///
- /// - The image must have a depth or depth-stencil format.
- /// - The image must have been created with linear tiling.
+ /// If after this, `stencil_usage` does not equal `usage`,
+ /// then the device API version must be at least 1.2, or the
+ /// [`ext_separate_stencil_usage`](crate::device::DeviceExtensions::ext_separate_stencil_usage)
+ /// extension must be enabled on the device.
///
- #[inline]
- pub unsafe fn depth_linear_layout(&self, mip_level: u32) -> LinearLayout {
- self.linear_layout_impl(mip_level, ImageAspect::Depth)
- }
+ /// The default value is [`ImageUsage::empty()`].
+ pub stencil_usage: ImageUsage,
- /// Same as `color_linear_layout`, except that it retrieves the stencil component of the image.
+ /// Whether the image can be shared across multiple queues, or is limited to a single queue.
///
- /// # Panic
- ///
- /// - Panics if the mipmap level is out of range.
+ /// The default value is [`Sharing::Exclusive`].
+ pub sharing: Sharing<SmallVec<[u32; 4]>>,
+
+ /// The image layout that the image will have when it is created.
///
- /// # Safety
+ /// The default value is [`ImageLayout::Undefined`].
+ pub initial_layout: ImageLayout,
+
+ /// The external memory handle types that are going to be used with the image.
///
- /// - The image must have a stencil or depth-stencil format.
- /// - The image must have been created with linear tiling.
+ /// If any of the fields in this value are set, the device must either support API version 1.1
+ /// or the [`khr_external_memory`](crate::device::DeviceExtensions::khr_external_memory)
+ /// extension must be enabled, and `initial_layout` must be set to
+ /// [`ImageLayout::Undefined`].
///
+ /// The default value is [`ExternalMemoryHandleTypes::empty()`].
+ pub external_memory_handle_types: ExternalMemoryHandleTypes,
+
+ /// Specify that an image be created with the provided DRM format modifier and explicit memory layout
+ pub image_drm_format_modifier_create_info: Option<ImageDrmFormatModifierExplicitCreateInfoEXT>,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for ImageCreateInfo {
#[inline]
- pub unsafe fn stencil_linear_layout(&self, mip_level: u32) -> LinearLayout {
- self.linear_layout_impl(mip_level, ImageAspect::Stencil)
+ fn default() -> Self {
+ Self {
+ flags: ImageCreateFlags::empty(),
+ dimensions: ImageDimensions::Dim2d {
+ width: 0,
+ height: 0,
+ array_layers: 1,
+ },
+ format: None,
+ mip_levels: 1,
+ samples: SampleCount::Sample1,
+ tiling: ImageTiling::Optimal,
+ usage: ImageUsage::empty(),
+ stencil_usage: ImageUsage::empty(),
+ sharing: Sharing::Exclusive,
+ initial_layout: ImageLayout::Undefined,
+ external_memory_handle_types: ExternalMemoryHandleTypes::empty(),
+ image_drm_format_modifier_create_info: None,
+ _ne: crate::NonExhaustive(()),
+ }
}
+}
- /// Same as `color_linear_layout`, except that it retrieves layout for the requested ycbcr
- /// component too if the format is a YcbCr format.
+/// A multi-dimensioned storage for texel data.
+///
+/// Unlike [`RawImage`], an `Image` has memory backing it, and can be used normally.
+#[derive(Debug)]
+pub struct Image {
+ inner: RawImage,
+ memory: ImageMemory,
+
+ aspect_list: SmallVec<[ImageAspect; 4]>,
+ aspect_size: DeviceSize,
+ mip_level_size: DeviceSize,
+ range_size: DeviceSize,
+ state: Mutex<ImageState>,
+}
+
+/// The type of backing memory that an image can have.
+#[derive(Debug)]
+pub enum ImageMemory {
+ /// The image is backed by normal memory, bound with [`bind_memory`].
///
- /// # Panic
+ /// [`bind_memory`]: RawImage::bind_memory
+ Normal(SmallVec<[MemoryAlloc; 3]>),
+
+ /// The image is backed by sparse memory, bound with [`bind_sparse`].
///
- /// - Panics if plane aspect is out of range.
- /// - Panics if the aspect is not a color or planar aspect.
- /// - Panics if the number of mipmaps is not 1.
- #[inline]
- pub unsafe fn multiplane_color_layout(&self, aspect: ImageAspect) -> LinearLayout {
- // This function only supports color and planar aspects currently.
- assert!(matches!(
- aspect,
- ImageAspect::Color | ImageAspect::Plane0 | ImageAspect::Plane1 | ImageAspect::Plane2
- ));
- assert!(self.mipmaps == 1);
+ /// [`bind_sparse`]: crate::device::QueueGuard::bind_sparse
+ Sparse(Vec<SparseImageMemoryRequirements>),
- if matches!(
- aspect,
- ImageAspect::Plane0 | ImageAspect::Plane1 | ImageAspect::Plane2
- ) {
- assert_eq!(self.format.ty(), FormatTy::Ycbcr);
- if aspect == ImageAspect::Plane2 {
- // Vulkano only supports NV12 and YV12 currently. If that changes, this will too.
- assert!(self.format == Format::G8B8R8_3PLANE420Unorm);
- }
- }
+ /// The image is backed by memory owned by a [`Swapchain`].
+ Swapchain {
+ swapchain: Arc<Swapchain>,
+ image_index: u32,
+ },
+}
- self.linear_layout_impl(0, aspect)
+impl Image {
+ fn from_raw(inner: RawImage, memory: ImageMemory) -> Self {
+ let aspects = inner.format.unwrap().aspects();
+ let aspect_list: SmallVec<[ImageAspect; 4]> = aspects.into_iter().collect();
+ let mip_level_size = inner.dimensions.array_layers() as DeviceSize;
+ let aspect_size = mip_level_size * inner.mip_levels as DeviceSize;
+ let range_size = aspect_list.len() as DeviceSize * aspect_size;
+ let state = Mutex::new(ImageState::new(range_size, inner.initial_layout));
+
+ Image {
+ inner,
+ memory,
+
+ aspect_list,
+ aspect_size,
+ mip_level_size,
+ range_size,
+ state,
+ }
}
- // Implementation of the `*_layout` functions.
- unsafe fn linear_layout_impl(&self, mip_level: u32, aspect: ImageAspect) -> LinearLayout {
- let fns = self.device.fns();
-
- assert!(mip_level < self.mipmaps);
-
- let subresource = ash::vk::ImageSubresource {
- aspect_mask: ash::vk::ImageAspectFlags::from(aspect),
- mip_level: mip_level,
- array_layer: 0,
+ pub(crate) unsafe fn from_swapchain(
+ handle: ash::vk::Image,
+ swapchain: Arc<Swapchain>,
+ image_index: u32,
+ ) -> Self {
+ let create_info = ImageCreateInfo {
+ flags: ImageCreateFlags::empty(),
+ dimensions: ImageDimensions::Dim2d {
+ width: swapchain.image_extent()[0],
+ height: swapchain.image_extent()[1],
+ array_layers: swapchain.image_array_layers(),
+ },
+ format: Some(swapchain.image_format()),
+ initial_layout: ImageLayout::Undefined,
+ mip_levels: 1,
+ samples: SampleCount::Sample1,
+ tiling: ImageTiling::Optimal,
+ usage: swapchain.image_usage(),
+ stencil_usage: swapchain.image_usage(),
+ sharing: swapchain.image_sharing().clone(),
+ ..Default::default()
};
- let mut out = MaybeUninit::uninit();
- fns.v1_0.get_image_subresource_layout(
- self.device.internal_object(),
- self.image,
- &subresource,
- out.as_mut_ptr(),
- );
+ Self::from_raw(
+ RawImage::from_handle_with_destruction(
+ swapchain.device().clone(),
+ handle,
+ create_info,
+ false,
+ ),
+ ImageMemory::Swapchain {
+ swapchain,
+ image_index,
+ },
+ )
+ }
- let out = out.assume_init();
- LinearLayout {
- offset: out.offset,
- size: out.size,
- row_pitch: out.row_pitch,
- array_pitch: out.array_pitch,
- depth_pitch: out.depth_pitch,
- }
+ /// Returns the type of memory that is backing this image.
+ #[inline]
+ pub fn memory(&self) -> &ImageMemory {
+ &self.memory
+ }
+
+ /// Returns the memory requirements for this image.
+ ///
+ /// - If the image is a swapchain image, this returns a slice with a length of 0.
+ /// - If `self.flags().disjoint` is not set, this returns a slice with a length of 1.
+ /// - If `self.flags().disjoint` is set, this returns a slice with a length equal to
+ /// `self.format().unwrap().planes().len()`.
+ #[inline]
+ pub fn memory_requirements(&self) -> &[MemoryRequirements] {
+ &self.inner.memory_requirements
}
/// Returns the flags the image was created with.
#[inline]
pub fn flags(&self) -> ImageCreateFlags {
- self.flags
+ self.inner.flags
+ }
+
+ /// Returns the dimensions of the image.
+ #[inline]
+ pub fn dimensions(&self) -> ImageDimensions {
+ self.inner.dimensions
+ }
+
+ /// Returns the image's format.
+ #[inline]
+ pub fn format(&self) -> Option<Format> {
+ self.inner.format
}
/// Returns the features supported by the image's format.
#[inline]
pub fn format_features(&self) -> FormatFeatures {
- self.format_features
+ self.inner.format_features
+ }
+
+ /// Returns the number of mipmap levels in the image.
+ #[inline]
+ pub fn mip_levels(&self) -> u32 {
+ self.inner.mip_levels
+ }
+
+ /// Returns the initial layout of the image.
+ #[inline]
+ pub fn initial_layout(&self) -> ImageLayout {
+ self.inner.initial_layout
+ }
+
+ /// Returns the number of samples for the image.
+ #[inline]
+ pub fn samples(&self) -> SampleCount {
+ self.inner.samples
+ }
+
+ /// Returns the tiling of the image.
+ #[inline]
+ pub fn tiling(&self) -> ImageTiling {
+ self.inner.tiling
}
/// Returns the usage the image was created with.
#[inline]
pub fn usage(&self) -> ImageUsage {
- self.usage
+ self.inner.usage
}
+ /// Returns the stencil usage the image was created with.
#[inline]
- pub fn preinitialized_layout(&self) -> bool {
- self.preinitialized_layout
+ pub fn stencil_usage(&self) -> ImageUsage {
+ self.inner.stencil_usage
}
-}
-unsafe impl VulkanObject for UnsafeImage {
- type Object = ash::vk::Image;
+ /// Returns the sharing the image was created with.
+ #[inline]
+ pub fn sharing(&self) -> &Sharing<SmallVec<[u32; 4]>> {
+ &self.inner.sharing
+ }
+ /// Returns the external memory handle types that are supported with this image.
#[inline]
- fn internal_object(&self) -> ash::vk::Image {
- self.image
+ pub fn external_memory_handle_types(&self) -> ExternalMemoryHandleTypes {
+ self.inner.external_memory_handle_types
}
-}
-impl fmt::Debug for UnsafeImage {
+ /// Returns an `ImageSubresourceLayers` covering the first mip level of the image. All aspects
+ /// of the image are selected, or `plane0` if the image is multi-planar.
#[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(fmt, "<Vulkan image {:?}>", self.image)
+ pub fn subresource_layers(&self) -> ImageSubresourceLayers {
+ self.inner.subresource_layers()
}
-}
-impl Drop for UnsafeImage {
+ /// Returns an `ImageSubresourceRange` covering the whole image. If the image is multi-planar,
+ /// only the `color` aspect is selected.
#[inline]
- fn drop(&mut self) {
- if !self.needs_destruction {
- return;
- }
+ pub fn subresource_range(&self) -> ImageSubresourceRange {
+ self.inner.subresource_range()
+ }
- unsafe {
- let fns = self.device.fns();
- fns.v1_0
- .destroy_image(self.device.internal_object(), self.image, ptr::null());
+ /// Queries the memory layout of a single subresource of the image.
+ ///
+ /// Only images with linear tiling are supported, if they do not have a format with both a
+ /// depth and a stencil format. Images with optimal tiling have an opaque image layout that is
+ /// not suitable for direct memory accesses, and likewise for combined depth/stencil formats.
+ /// Multi-planar formats are supported, but you must specify one of the planes as the `aspect`,
+ /// not [`ImageAspect::Color`].
+ ///
+ /// The layout is invariant for each image. However it is not cached, as this would waste
+ /// memory in the case of non-linear-tiling images. You are encouraged to store the layout
+ /// somewhere in order to avoid calling this semi-expensive function at every single memory
+ /// access.
+ #[inline]
+ pub fn subresource_layout(
+ &self,
+ aspect: ImageAspect,
+ mip_level: u32,
+ array_layer: u32,
+ ) -> Result<SubresourceLayout, ImageError> {
+ self.inner
+ .subresource_layout(aspect, mip_level, array_layer)
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ #[inline]
+ pub unsafe fn subresource_layout_unchecked(
+ &self,
+ aspect: ImageAspect,
+ mip_level: u32,
+ array_layer: u32,
+ ) -> SubresourceLayout {
+ self.inner
+ .subresource_layout_unchecked(aspect, mip_level, array_layer)
+ }
+
+ pub(crate) fn range_size(&self) -> DeviceSize {
+ self.range_size
+ }
+
+ /// Returns an iterator over subresource ranges.
+ ///
+ /// In ranges, the subresources are "flattened" to `DeviceSize`, where each index in the range
+ /// is a single array layer. The layers are arranged hierarchically: aspects at the top level,
+ /// with the mip levels in that aspect, and the array layers in that mip level.
+ pub(crate) fn iter_ranges(
+ &self,
+ subresource_range: ImageSubresourceRange,
+ ) -> SubresourceRangeIterator {
+ assert!(self
+ .format()
+ .unwrap()
+ .aspects()
+ .contains(subresource_range.aspects));
+ assert!(subresource_range.mip_levels.end <= self.inner.mip_levels);
+ assert!(subresource_range.array_layers.end <= self.inner.dimensions.array_layers());
+
+ SubresourceRangeIterator::new(
+ subresource_range,
+ &self.aspect_list,
+ self.aspect_size,
+ self.inner.mip_levels,
+ self.mip_level_size,
+ self.inner.dimensions.array_layers(),
+ )
+ }
+
+ pub(crate) fn range_to_subresources(
+ &self,
+ mut range: Range<DeviceSize>,
+ ) -> ImageSubresourceRange {
+ debug_assert!(!range.is_empty());
+ debug_assert!(range.end <= self.range_size);
+
+ if range.end - range.start > self.aspect_size {
+ debug_assert!(range.start % self.aspect_size == 0);
+ debug_assert!(range.end % self.aspect_size == 0);
+
+ let start_aspect_num = (range.start / self.aspect_size) as usize;
+ let end_aspect_num = (range.end / self.aspect_size) as usize;
+
+ ImageSubresourceRange {
+ aspects: self.aspect_list[start_aspect_num..end_aspect_num]
+ .iter()
+ .copied()
+ .collect(),
+ mip_levels: 0..self.inner.mip_levels,
+ array_layers: 0..self.inner.dimensions.array_layers(),
+ }
+ } else {
+ let aspect_num = (range.start / self.aspect_size) as usize;
+ range.start %= self.aspect_size;
+ range.end %= self.aspect_size;
+
+ // Wraparound
+ if range.end == 0 {
+ range.end = self.aspect_size;
+ }
+
+ if range.end - range.start > self.mip_level_size {
+ debug_assert!(range.start % self.mip_level_size == 0);
+ debug_assert!(range.end % self.mip_level_size == 0);
+
+ let start_mip_level = (range.start / self.mip_level_size) as u32;
+ let end_mip_level = (range.end / self.mip_level_size) as u32;
+
+ ImageSubresourceRange {
+ aspects: self.aspect_list[aspect_num].into(),
+ mip_levels: start_mip_level..end_mip_level,
+ array_layers: 0..self.inner.dimensions.array_layers(),
+ }
+ } else {
+ let mip_level = (range.start / self.mip_level_size) as u32;
+ range.start %= self.mip_level_size;
+ range.end %= self.mip_level_size;
+
+ // Wraparound
+ if range.end == 0 {
+ range.end = self.mip_level_size;
+ }
+
+ let start_array_layer = range.start as u32;
+ let end_array_layer = range.end as u32;
+
+ ImageSubresourceRange {
+ aspects: self.aspect_list[aspect_num].into(),
+ mip_levels: mip_level..mip_level + 1,
+ array_layers: start_array_layer..end_array_layer,
+ }
+ }
}
}
+
+ pub(crate) fn state(&self) -> MutexGuard<'_, ImageState> {
+ self.state.lock()
+ }
}
-impl PartialEq for UnsafeImage {
+unsafe impl VulkanObject for Image {
+ type Handle = ash::vk::Image;
+
#[inline]
- fn eq(&self, other: &Self) -> bool {
- self.image == other.image && self.device == other.device
+ fn handle(&self) -> Self::Handle {
+ self.inner.handle
}
}
-impl Eq for UnsafeImage {}
+unsafe impl DeviceOwned for Image {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ &self.inner.device
+ }
+}
-impl Hash for UnsafeImage {
+impl PartialEq for Image {
#[inline]
+ fn eq(&self, other: &Self) -> bool {
+ self.inner == other.inner
+ }
+}
+
+impl Eq for Image {}
+
+impl Hash for Image {
fn hash<H: Hasher>(&self, state: &mut H) {
- self.image.hash(state);
- self.device.hash(state);
+ self.inner.hash(state);
}
}
-/// Error that can happen when creating an instance.
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum ImageCreationError {
- /// Allocating memory failed.
- AllocError(DeviceMemoryAllocError),
- /// The specified creation flags have requirements (e.g. specific dimension) that were not met.
- CreationFlagRequirementsNotMet,
- /// A wrong number of mipmaps was provided.
- FormatNotSupported,
- /// The format is supported, but at least one of the requested usages is not supported.
- InvalidMipmapsCount {
- obtained: u32,
- valid_range: Range<u32>,
- },
- /// The requested number of samples is not supported, or is 0.
- UnsupportedSamplesCount { obtained: SampleCount },
- /// The dimensions are too large, or one of the dimensions is 0.
- UnsupportedDimensions { dimensions: ImageDimensions },
- /// The requested format is not supported by the Vulkan implementation.
- UnsupportedUsage,
- /// The `shader_storage_image_multisample` feature must be enabled to create such an image.
- ShaderStorageImageMultisampleFeatureNotEnabled,
+/// The current state of an image.
+#[derive(Debug)]
+pub(crate) struct ImageState {
+ ranges: RangeMap<DeviceSize, ImageRangeState>,
}
-impl error::Error for ImageCreationError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- ImageCreationError::AllocError(ref err) => Some(err),
- _ => None,
+impl ImageState {
+ fn new(size: DeviceSize, initial_layout: ImageLayout) -> Self {
+ ImageState {
+ ranges: [(
+ 0..size,
+ ImageRangeState {
+ current_access: CurrentAccess::Shared {
+ cpu_reads: 0,
+ gpu_reads: 0,
+ },
+ layout: initial_layout,
+ },
+ )]
+ .into_iter()
+ .collect(),
}
}
-}
-impl fmt::Display for ImageCreationError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- ImageCreationError::AllocError(_) => "allocating memory failed",
- ImageCreationError::CreationFlagRequirementsNotMet => {
- "the requested creation flags have additional requirements that were not met"
- }
- ImageCreationError::FormatNotSupported => {
- "the requested format is not supported by the Vulkan implementation"
- }
- ImageCreationError::InvalidMipmapsCount { .. } => {
- "a wrong number of mipmaps was provided"
+ #[allow(dead_code)]
+ pub(crate) fn check_cpu_read(&self, range: Range<DeviceSize>) -> Result<(), ReadLockError> {
+ for (_range, state) in self.ranges.range(&range) {
+ match &state.current_access {
+ CurrentAccess::CpuExclusive { .. } => return Err(ReadLockError::CpuWriteLocked),
+ CurrentAccess::GpuExclusive { .. } => return Err(ReadLockError::GpuWriteLocked),
+ CurrentAccess::Shared { .. } => (),
+ }
+ }
+
+ Ok(())
+ }
+
+ #[allow(dead_code)]
+ pub(crate) unsafe fn cpu_read_lock(&mut self, range: Range<DeviceSize>) {
+ self.ranges.split_at(&range.start);
+ self.ranges.split_at(&range.end);
+
+ for (_range, state) in self.ranges.range_mut(&range) {
+ match &mut state.current_access {
+ CurrentAccess::Shared { cpu_reads, .. } => {
+ *cpu_reads += 1;
}
- ImageCreationError::UnsupportedSamplesCount { .. } => {
- "the requested number of samples is not supported, or is 0"
+ _ => unreachable!("Image is being written by the CPU or GPU"),
+ }
+ }
+ }
+
+ #[allow(dead_code)]
+ pub(crate) unsafe fn cpu_read_unlock(&mut self, range: Range<DeviceSize>) {
+ self.ranges.split_at(&range.start);
+ self.ranges.split_at(&range.end);
+
+ for (_range, state) in self.ranges.range_mut(&range) {
+ match &mut state.current_access {
+ CurrentAccess::Shared { cpu_reads, .. } => *cpu_reads -= 1,
+ _ => unreachable!("Image was not locked for CPU read"),
+ }
+ }
+ }
+
+ #[allow(dead_code)]
+ pub(crate) fn check_cpu_write(&self, range: Range<DeviceSize>) -> Result<(), WriteLockError> {
+ for (_range, state) in self.ranges.range(&range) {
+ match &state.current_access {
+ CurrentAccess::CpuExclusive => return Err(WriteLockError::CpuLocked),
+ CurrentAccess::GpuExclusive { .. } => return Err(WriteLockError::GpuLocked),
+ CurrentAccess::Shared {
+ cpu_reads: 0,
+ gpu_reads: 0,
+ } => (),
+ CurrentAccess::Shared { cpu_reads, .. } if *cpu_reads > 0 => {
+ return Err(WriteLockError::CpuLocked)
}
- ImageCreationError::UnsupportedDimensions { .. } => {
- "the dimensions are too large, or one of the dimensions is 0"
+ CurrentAccess::Shared { .. } => return Err(WriteLockError::GpuLocked),
+ }
+ }
+
+ Ok(())
+ }
+
+ #[allow(dead_code)]
+ pub(crate) unsafe fn cpu_write_lock(&mut self, range: Range<DeviceSize>) {
+ self.ranges.split_at(&range.start);
+ self.ranges.split_at(&range.end);
+
+ for (_range, state) in self.ranges.range_mut(&range) {
+ state.current_access = CurrentAccess::CpuExclusive;
+ }
+ }
+
+ #[allow(dead_code)]
+ pub(crate) unsafe fn cpu_write_unlock(&mut self, range: Range<DeviceSize>) {
+ self.ranges.split_at(&range.start);
+ self.ranges.split_at(&range.end);
+
+ for (_range, state) in self.ranges.range_mut(&range) {
+ match &mut state.current_access {
+ CurrentAccess::CpuExclusive => {
+ state.current_access = CurrentAccess::Shared {
+ cpu_reads: 0,
+ gpu_reads: 0,
+ }
}
- ImageCreationError::UnsupportedUsage => {
- "the format is supported, but at least one of the requested usages is not \
- supported"
+ _ => unreachable!("Image was not locked for CPU write"),
+ }
+ }
+ }
+
+ pub(crate) fn check_gpu_read(
+ &self,
+ range: Range<DeviceSize>,
+ expected_layout: ImageLayout,
+ ) -> Result<(), AccessError> {
+ for (_range, state) in self.ranges.range(&range) {
+ match &state.current_access {
+ CurrentAccess::Shared { .. } => (),
+ _ => return Err(AccessError::AlreadyInUse),
+ }
+
+ if expected_layout != ImageLayout::Undefined && state.layout != expected_layout {
+ return Err(AccessError::UnexpectedImageLayout {
+ allowed: state.layout,
+ requested: expected_layout,
+ });
+ }
+ }
+
+ Ok(())
+ }
+
+ pub(crate) unsafe fn gpu_read_lock(&mut self, range: Range<DeviceSize>) {
+ self.ranges.split_at(&range.start);
+ self.ranges.split_at(&range.end);
+
+ for (_range, state) in self.ranges.range_mut(&range) {
+ match &mut state.current_access {
+ CurrentAccess::GpuExclusive { gpu_reads, .. }
+ | CurrentAccess::Shared { gpu_reads, .. } => *gpu_reads += 1,
+ _ => unreachable!("Image is being written by the CPU"),
+ }
+ }
+ }
+
+ pub(crate) unsafe fn gpu_read_unlock(&mut self, range: Range<DeviceSize>) {
+ self.ranges.split_at(&range.start);
+ self.ranges.split_at(&range.end);
+
+ for (_range, state) in self.ranges.range_mut(&range) {
+ match &mut state.current_access {
+ CurrentAccess::GpuExclusive { gpu_reads, .. } => *gpu_reads -= 1,
+ CurrentAccess::Shared { gpu_reads, .. } => *gpu_reads -= 1,
+ _ => unreachable!("Buffer was not locked for GPU read"),
+ }
+ }
+ }
+
+ pub(crate) fn check_gpu_write(
+ &self,
+ range: Range<DeviceSize>,
+ expected_layout: ImageLayout,
+ ) -> Result<(), AccessError> {
+ for (_range, state) in self.ranges.range(&range) {
+ match &state.current_access {
+ CurrentAccess::Shared {
+ cpu_reads: 0,
+ gpu_reads: 0,
+ } => (),
+ _ => return Err(AccessError::AlreadyInUse),
+ }
+
+ if expected_layout != ImageLayout::Undefined && state.layout != expected_layout {
+ return Err(AccessError::UnexpectedImageLayout {
+ allowed: state.layout,
+ requested: expected_layout,
+ });
+ }
+ }
+
+ Ok(())
+ }
+
+ pub(crate) unsafe fn gpu_write_lock(
+ &mut self,
+ range: Range<DeviceSize>,
+ destination_layout: ImageLayout,
+ ) {
+ debug_assert!(!matches!(
+ destination_layout,
+ ImageLayout::Undefined | ImageLayout::Preinitialized
+ ));
+
+ self.ranges.split_at(&range.start);
+ self.ranges.split_at(&range.end);
+
+ for (_range, state) in self.ranges.range_mut(&range) {
+ match &mut state.current_access {
+ CurrentAccess::GpuExclusive { gpu_writes, .. } => *gpu_writes += 1,
+ &mut CurrentAccess::Shared {
+ cpu_reads: 0,
+ gpu_reads,
+ } => {
+ state.current_access = CurrentAccess::GpuExclusive {
+ gpu_reads,
+ gpu_writes: 1,
+ }
}
- ImageCreationError::ShaderStorageImageMultisampleFeatureNotEnabled => {
- "the `shader_storage_image_multisample` feature must be enabled to create such \
- an image"
+ _ => unreachable!("Image is being accessed by the CPU"),
+ }
+
+ state.layout = destination_layout;
+ }
+ }
+
+ pub(crate) unsafe fn gpu_write_unlock(&mut self, range: Range<DeviceSize>) {
+ self.ranges.split_at(&range.start);
+ self.ranges.split_at(&range.end);
+
+ for (_range, state) in self.ranges.range_mut(&range) {
+ match &mut state.current_access {
+ &mut CurrentAccess::GpuExclusive {
+ gpu_reads,
+ gpu_writes: 1,
+ } => {
+ state.current_access = CurrentAccess::Shared {
+ cpu_reads: 0,
+ gpu_reads,
+ }
}
+ CurrentAccess::GpuExclusive { gpu_writes, .. } => *gpu_writes -= 1,
+ _ => unreachable!("Image was not locked for GPU write"),
}
- )
+ }
}
}
-impl From<OomError> for ImageCreationError {
- #[inline]
- fn from(err: OomError) -> ImageCreationError {
- ImageCreationError::AllocError(DeviceMemoryAllocError::OomError(err))
- }
+/// The current state of a specific subresource range in an image.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+struct ImageRangeState {
+ current_access: CurrentAccess,
+ layout: ImageLayout,
}
-impl From<DeviceMemoryAllocError> for ImageCreationError {
- #[inline]
- fn from(err: DeviceMemoryAllocError) -> ImageCreationError {
- ImageCreationError::AllocError(err)
- }
+#[derive(Clone)]
+pub(crate) struct SubresourceRangeIterator {
+ next_fn: fn(&mut Self) -> Option<Range<DeviceSize>>,
+ image_aspect_size: DeviceSize,
+ image_mip_level_size: DeviceSize,
+ mip_levels: Range<u32>,
+ array_layers: Range<u32>,
+
+ aspect_nums: Peekable<smallvec::IntoIter<[usize; 4]>>,
+ current_aspect_num: Option<usize>,
+ current_mip_level: u32,
}
-impl From<Error> for ImageCreationError {
- #[inline]
- fn from(err: Error) -> ImageCreationError {
- match err {
- err @ Error::OutOfHostMemory => ImageCreationError::AllocError(err.into()),
- err @ Error::OutOfDeviceMemory => ImageCreationError::AllocError(err.into()),
- _ => panic!("unexpected error: {:?}", err),
+impl SubresourceRangeIterator {
+ fn new(
+ subresource_range: ImageSubresourceRange,
+ image_aspect_list: &[ImageAspect],
+ image_aspect_size: DeviceSize,
+ image_mip_levels: u32,
+ image_mip_level_size: DeviceSize,
+ image_array_layers: u32,
+ ) -> Self {
+ assert!(!subresource_range.mip_levels.is_empty());
+ assert!(!subresource_range.array_layers.is_empty());
+
+ let next_fn = if subresource_range.array_layers.start != 0
+ || subresource_range.array_layers.end != image_array_layers
+ {
+ Self::next_some_layers
+ } else if subresource_range.mip_levels.start != 0
+ || subresource_range.mip_levels.end != image_mip_levels
+ {
+ Self::next_some_levels_all_layers
+ } else {
+ Self::next_all_levels_all_layers
+ };
+
+ let mut aspect_nums = subresource_range
+ .aspects
+ .into_iter()
+ .map(|aspect| image_aspect_list.iter().position(|&a| a == aspect).unwrap())
+ .collect::<SmallVec<[usize; 4]>>()
+ .into_iter()
+ .peekable();
+ assert!(aspect_nums.len() != 0);
+ let current_aspect_num = aspect_nums.next();
+ let current_mip_level = subresource_range.mip_levels.start;
+
+ Self {
+ next_fn,
+ image_aspect_size,
+ image_mip_level_size,
+ mip_levels: subresource_range.mip_levels,
+ array_layers: subresource_range.array_layers,
+
+ aspect_nums,
+ current_aspect_num,
+ current_mip_level,
}
}
+
+ /// Used when the requested range contains only a subset of the array layers in the image.
+ /// The iterator returns one range for each mip level and aspect, each covering the range of
+ /// array layers of that mip level and aspect.
+ fn next_some_layers(&mut self) -> Option<Range<DeviceSize>> {
+ self.current_aspect_num.map(|aspect_num| {
+ let mip_level_offset = aspect_num as DeviceSize * self.image_aspect_size
+ + self.current_mip_level as DeviceSize * self.image_mip_level_size;
+ self.current_mip_level += 1;
+
+ if self.current_mip_level >= self.mip_levels.end {
+ self.current_mip_level = self.mip_levels.start;
+ self.current_aspect_num = self.aspect_nums.next();
+ }
+
+ let start = mip_level_offset + self.array_layers.start as DeviceSize;
+ let end = mip_level_offset + self.array_layers.end as DeviceSize;
+ start..end
+ })
+ }
+
+ /// Used when the requested range contains all array layers in the image, but not all mip
+ /// levels. The iterator returns one range for each aspect, each covering all layers of the
+ /// range of mip levels of that aspect.
+ fn next_some_levels_all_layers(&mut self) -> Option<Range<DeviceSize>> {
+ self.current_aspect_num.map(|aspect_num| {
+ let aspect_offset = aspect_num as DeviceSize * self.image_aspect_size;
+ self.current_aspect_num = self.aspect_nums.next();
+
+ let start =
+ aspect_offset + self.mip_levels.start as DeviceSize * self.image_mip_level_size;
+ let end = aspect_offset + self.mip_levels.end as DeviceSize * self.image_mip_level_size;
+ start..end
+ })
+ }
+
+ /// Used when the requested range contains all array layers and mip levels in the image.
+ /// The iterator returns one range for each series of adjacent aspect numbers, each covering
+ /// all mip levels and all layers of those aspects. If the range contains the whole image, then
+ /// exactly one range is returned since all aspect numbers will be adjacent.
+ fn next_all_levels_all_layers(&mut self) -> Option<Range<DeviceSize>> {
+ self.current_aspect_num.map(|aspect_num_start| {
+ self.current_aspect_num = self.aspect_nums.next();
+ let mut aspect_num_end = aspect_num_start + 1;
+
+ while self.current_aspect_num == Some(aspect_num_end) {
+ self.current_aspect_num = self.aspect_nums.next();
+ aspect_num_end += 1;
+ }
+
+ let start = aspect_num_start as DeviceSize * self.image_aspect_size;
+ let end = aspect_num_end as DeviceSize * self.image_aspect_size;
+ start..end
+ })
+ }
}
-/// Describes the memory layout of an image with linear tiling.
-///
-/// Obtained by calling `*_linear_layout` on the image.
+impl Iterator for SubresourceRangeIterator {
+ type Item = Range<DeviceSize>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ (self.next_fn)(self)
+ }
+}
+
+impl FusedIterator for SubresourceRangeIterator {}
+
+/// Describes the memory layout of a single subresource of an image.
///
/// The address of a texel at `(x, y, z, layer)` is `layer * array_pitch + z * depth_pitch +
/// y * row_pitch + x * size_of_each_texel + offset`. `size_of_each_texel` must be determined
/// depending on the format. The same formula applies for compressed formats, except that the
/// coordinates must be in number of blocks.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct LinearLayout {
- /// Number of bytes from the start of the memory and the start of the queried subresource.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub struct SubresourceLayout {
+ /// The number of bytes from the start of the memory to the start of the queried subresource.
pub offset: DeviceSize,
- /// Total number of bytes for the queried subresource. Can be used for a safety check.
+
+ /// The total number of bytes for the queried subresource.
pub size: DeviceSize,
- /// Number of bytes between two texels or two blocks in adjacent rows.
+
+ /// The number of bytes between two texels or two blocks in adjacent rows.
pub row_pitch: DeviceSize,
- /// Number of bytes between two texels or two blocks in adjacent array layers. This value is
- /// undefined for images with only one array layer.
- pub array_pitch: DeviceSize,
- /// Number of bytes between two texels or two blocks in adjacent depth layers. This value is
- /// undefined for images that are not three-dimensional.
- pub depth_pitch: DeviceSize,
+
+ /// For images with more than one array layer, the number of bytes between two texels or two
+ /// blocks in adjacent array layers.
+ pub array_pitch: Option<DeviceSize>,
+
+ /// For 3D images, the number of bytes between two texels or two blocks in adjacent depth
+ /// layers.
+ pub depth_pitch: Option<DeviceSize>,
+}
+
+/// Error that can happen in image functions.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum ImageError {
+ VulkanError(VulkanError),
+
+ /// Allocating memory failed.
+ AllocError(AllocationCreationError),
+
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+
+ /// The provided number of elements in `allocations` is not what is required for `image`.
+ AllocationsWrongNumberOfElements {
+ provided: usize,
+ required: usize,
+ },
+
+ /// The `array_2d_compatible` flag was enabled, but the image type was not 3D.
+ Array2dCompatibleNot3d,
+
+ /// The provided array layer is not less than the number of array layers in the image.
+ ArrayLayerOutOfRange {
+ provided_array_layer: u32,
+ image_array_layers: u32,
+ },
+
+ /// The provided aspect is not present in the image, or is not allowed.
+ AspectNotAllowed {
+ provided_aspect: ImageAspect,
+ allowed_aspects: ImageAspects,
+ },
+
+ /// The `block_texel_view_compatible` flag was enabled, but the given format was not compressed.
+ BlockTexelViewCompatibleNotCompressed,
+
+ /// The `cube_compatible` flag was enabled, but the image type was not 2D.
+ CubeCompatibleNot2d,
+
+ /// The `cube_compatible` flag was enabled, but the number of array layers was less than 6.
+ CubeCompatibleNotEnoughArrayLayers,
+
+ /// The `cube_compatible` flag was enabled, but the image dimensions were not square.
+ CubeCompatibleNotSquare,
+
+ /// The `cube_compatible` flag was enabled together with multisampling.
+ CubeCompatibleMultisampling,
+
+ /// The memory was created dedicated to a resource, but not to this image.
+ DedicatedAllocationMismatch,
+
+ /// A dedicated allocation is required for this image, but one was not provided.
+ DedicatedAllocationRequired,
+
+ /// The image has a format with both a depth and a stencil aspect, which is not supported for
+ /// this operation.
+ DepthStencilFormatsNotSupported,
+
+ /// The `disjoint` flag was enabled, but the given format is either not multi-planar, or does
+ /// not support disjoint images.
+ DisjointFormatNotSupported,
+
+ /// One or more external memory handle types were provided, but the initial layout was not
+ /// `Undefined`.
+ ExternalMemoryInvalidInitialLayout,
+
+ /// The given format was not supported by the device.
+ FormatNotSupported,
+
+ /// A requested usage flag was not supported by the given format.
+ FormatUsageNotSupported {
+ usage: &'static str,
+ },
+
+ /// The image configuration as queried through the `image_format_properties` function was not
+ /// supported by the device.
+ ImageFormatPropertiesNotSupported,
+
+ /// The number of array layers exceeds the maximum supported by the device for this image
+ /// configuration.
+ MaxArrayLayersExceeded {
+ array_layers: u32,
+ max: u32,
+ },
+
+ /// The specified dimensions exceed the maximum supported by the device for this image
+ /// configuration.
+ MaxDimensionsExceeded {
+ extent: [u32; 3],
+ max: [u32; 3],
+ },
+
+ /// The usage included one of the attachment types, and the specified width and height exceeded
+ /// the `max_framebuffer_width` or `max_framebuffer_height` limits.
+ MaxFramebufferDimensionsExceeded {
+ extent: [u32; 2],
+ max: [u32; 2],
+ },
+
+ /// The maximum number of mip levels for the given dimensions has been exceeded.
+ MaxMipLevelsExceeded {
+ mip_levels: u32,
+ max: u32,
+ },
+
+ /// In an `allocations` element, the offset of the allocation does not have the required
+ /// alignment.
+ MemoryAllocationNotAligned {
+ allocations_index: usize,
+ allocation_offset: DeviceSize,
+ required_alignment: DeviceAlignment,
+ },
+
+ /// In an `allocations` element, the size of the allocation is smaller than what is required.
+ MemoryAllocationTooSmall {
+ allocations_index: usize,
+ allocation_size: DeviceSize,
+ required_size: DeviceSize,
+ },
+
+ /// In an `allocations` element, the memory was created with export handle types, but none of
+ /// these handle types were enabled on the image.
+ MemoryExternalHandleTypesDisjoint {
+ allocations_index: usize,
+ image_handle_types: ExternalMemoryHandleTypes,
+ memory_export_handle_types: ExternalMemoryHandleTypes,
+ },
+
+ /// In an `allocations` element, the memory was created with an import, but the import's handle
+ /// type was not enabled on the image.
+ MemoryImportedHandleTypeNotEnabled {
+ allocations_index: usize,
+ image_handle_types: ExternalMemoryHandleTypes,
+ memory_imported_handle_type: ExternalMemoryHandleType,
+ },
+
+ /// In an `allocations` element, the protection of image and memory are not equal.
+ MemoryProtectedMismatch {
+ allocations_index: usize,
+ image_protected: bool,
+ memory_protected: bool,
+ },
+
+ /// In an `allocations` element, the provided memory type is not one of the allowed memory
+ /// types that can be bound to this image or image plane.
+ MemoryTypeNotAllowed {
+ allocations_index: usize,
+ provided_memory_type_index: u32,
+ allowed_memory_type_bits: u32,
+ },
+
+ /// The provided mip level is not less than the number of mip levels in the image.
+ MipLevelOutOfRange {
+ provided_mip_level: u32,
+ image_mip_levels: u32,
+ },
+
+ /// Multisampling was enabled, and the `cube_compatible` flag was set.
+ MultisampleCubeCompatible,
+
+ /// Multisampling was enabled, and tiling was `Linear`.
+ MultisampleLinearTiling,
+
+ /// Multisampling was enabled, and multiple mip levels were specified.
+ MultisampleMultipleMipLevels,
+
+ /// Multisampling was enabled, but the image type was not 2D.
+ MultisampleNot2d,
+
+ /// The image has optimal tiling, which is not supported for this operation.
+ OptimalTilingNotSupported,
+
+ /// The sample count is not supported by the device for this image configuration.
+ SampleCountNotSupported {
+ samples: SampleCount,
+ supported: SampleCounts,
+ },
+
+ /// The sharing mode was set to `Concurrent`, but one of the specified queue family indices was
+ /// out of range.
+ SharingQueueFamilyIndexOutOfRange {
+ queue_family_index: u32,
+ queue_family_count: u32,
+ },
+
+ /// The provided `usage` and `stencil_usage` have different values for
+ /// `depth_stencil_attachment` or `transient_attachment`.
+ StencilUsageMismatch {
+ usage: ImageUsage,
+ stencil_usage: ImageUsage,
+ },
+
+ /// A YCbCr format was given, but the specified width and/or height was not a multiple of 2
+ /// as required by the format's chroma subsampling.
+ YcbcrFormatInvalidDimensions,
+
+ /// A YCbCr format was given, and multiple mip levels were specified.
+ YcbcrFormatMultipleMipLevels,
+
+ /// A YCbCr format was given, and multisampling was enabled.
+ YcbcrFormatMultisampling,
+
+ /// A YCbCr format was given, but the image type was not 2D.
+ YcbcrFormatNot2d,
+
+ DirectImageViewCreationFailed(ImageViewCreationError),
+
+ /// If and only if tiling is `DRMFormatModifier`, then `image_drm_format_modifier_create_info` must not be `None`.
+ DrmFormatModifierRequiresCreateInfo,
+}
+
+impl Error for ImageError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ ImageError::AllocError(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+impl Display for ImageError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::VulkanError(_) => write!(f, "a runtime error occurred"),
+ Self::AllocError(_) => write!(f, "allocating memory failed"),
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ Self::AllocationsWrongNumberOfElements { provided, required } => write!(
+ f,
+ "the provided number of elements in `allocations` ({}) is not what is required for \
+ `image` ({})",
+ provided, required,
+ ),
+ Self::Array2dCompatibleNot3d => write!(
+ f,
+ "the `array_2d_compatible` flag was enabled, but the image type was not 3D",
+ ),
+ Self::ArrayLayerOutOfRange {
+ provided_array_layer,
+ image_array_layers,
+ } => write!(
+ f,
+ "the provided array layer ({}) is not less than the number of array layers in the image ({})",
+ provided_array_layer, image_array_layers,
+ ),
+ Self::AspectNotAllowed {
+ provided_aspect,
+ allowed_aspects,
+ } => write!(
+ f,
+ "the provided aspect ({:?}) is not present in the image, or is not allowed ({:?})",
+ provided_aspect, allowed_aspects,
+ ),
+ Self::BlockTexelViewCompatibleNotCompressed => write!(
+ f,
+ "the `block_texel_view_compatible` flag was enabled, but the given format was not \
+ compressed",
+ ),
+ Self::CubeCompatibleNot2d => write!(
+ f,
+ "the `cube_compatible` flag was enabled, but the image type was not 2D",
+ ),
+ Self::CubeCompatibleNotEnoughArrayLayers => write!(
+ f,
+ "the `cube_compatible` flag was enabled, but the number of array layers was less \
+ than 6",
+ ),
+ Self::CubeCompatibleNotSquare => write!(
+ f,
+ "the `cube_compatible` flag was enabled, but the image dimensions were not square",
+ ),
+ Self::CubeCompatibleMultisampling => write!(
+ f,
+ "the `cube_compatible` flag was enabled together with multisampling",
+ ),
+ Self::DedicatedAllocationMismatch => write!(
+ f,
+ "the memory was created dedicated to a resource, but not to this image",
+ ),
+ Self::DedicatedAllocationRequired => write!(
+ f,
+ "a dedicated allocation is required for this image, but one was not provided"
+ ),
+ Self::DepthStencilFormatsNotSupported => write!(
+ f,
+ "the image has a format with both a depth and a stencil aspect, which is not \
+ supported for this operation",
+ ),
+ Self::DisjointFormatNotSupported => write!(
+ f,
+ "the `disjoint` flag was enabled, but the given format is either not multi-planar, \
+ or does not support disjoint images",
+ ),
+ Self::ExternalMemoryInvalidInitialLayout => write!(
+ f,
+ "one or more external memory handle types were provided, but the initial layout \
+ was not `Undefined`",
+ ),
+ Self::FormatNotSupported => {
+ write!(f, "the given format was not supported by the device")
+ }
+ Self::FormatUsageNotSupported { .. } => write!(
+ f,
+ "a requested usage flag was not supported by the given format",
+ ),
+ Self::ImageFormatPropertiesNotSupported => write!(
+ f,
+ "the image configuration as queried through the `image_format_properties` function \
+ was not supported by the device",
+ ),
+ Self::MaxArrayLayersExceeded { .. } => write!(
+ f,
+ "the number of array layers exceeds the maximum supported by the device for this \
+ image configuration",
+ ),
+ Self::MaxDimensionsExceeded { .. } => write!(
+ f,
+ "the specified dimensions exceed the maximum supported by the device for this \
+ image configuration",
+ ),
+ Self::MaxFramebufferDimensionsExceeded { .. } => write!(
+ f,
+ "the usage included one of the attachment types, and the specified width and \
+ height exceeded the `max_framebuffer_width` or `max_framebuffer_height` limits",
+ ),
+ Self::MaxMipLevelsExceeded { .. } => write!(
+ f,
+ "the maximum number of mip levels for the given dimensions has been exceeded",
+ ),
+ Self::MemoryAllocationNotAligned {
+ allocations_index,
+ allocation_offset,
+ required_alignment,
+ } => write!(
+ f,
+ "in `allocations` element {}, the offset of the allocation ({}) does not have the \
+ required alignment ({:?})",
+ allocations_index, allocation_offset, required_alignment,
+ ),
+ Self::MemoryAllocationTooSmall {
+ allocations_index,
+ allocation_size,
+ required_size,
+ } => write!(
+ f,
+ "in `allocations` element {}, the size of the allocation ({}) is smaller than what \
+ is required ({})",
+ allocations_index, allocation_size, required_size,
+ ),
+ Self::MemoryExternalHandleTypesDisjoint {
+ allocations_index, ..
+ } => write!(
+ f,
+ "in `allocations` element {}, the memory was created with export handle types, but \
+ none of these handle types were enabled on the image",
+ allocations_index,
+ ),
+ Self::MemoryImportedHandleTypeNotEnabled {
+ allocations_index, ..
+ } => write!(
+ f,
+ "in `allocations` element {}, the memory was created with an import, but the \
+ import's handle type was not enabled on the image",
+ allocations_index,
+ ),
+ Self::MemoryProtectedMismatch {
+ allocations_index,
+ image_protected,
+ memory_protected,
+ } => write!(
+ f,
+ "in `allocations` element {}, the protection of image ({}) and memory ({}) are not \
+ equal",
+ allocations_index, image_protected, memory_protected,
+ ),
+ Self::MemoryTypeNotAllowed {
+ allocations_index,
+ provided_memory_type_index,
+ allowed_memory_type_bits,
+ } => write!(
+ f,
+ "in `allocations` element {}, the provided memory type ({}) is not one of the \
+ allowed memory types (",
+ allocations_index, provided_memory_type_index,
+ )
+ .and_then(|_| {
+ let mut first = true;
+
+ for i in (0..size_of_val(allowed_memory_type_bits))
+ .filter(|i| allowed_memory_type_bits & (1 << i) != 0)
+ {
+ if first {
+ write!(f, "{}", i)?;
+ first = false;
+ } else {
+ write!(f, ", {}", i)?;
+ }
+ }
+
+ Ok(())
+ })
+ .and_then(|_| write!(f, ") that can be bound to this buffer")),
+ Self::MipLevelOutOfRange {
+ provided_mip_level,
+ image_mip_levels,
+ } => write!(
+ f,
+ "the provided mip level ({}) is not less than the number of mip levels in the image ({})",
+ provided_mip_level, image_mip_levels,
+ ),
+ Self::MultisampleCubeCompatible => write!(
+ f,
+ "multisampling was enabled, and the `cube_compatible` flag was set",
+ ),
+ Self::MultisampleLinearTiling => {
+ write!(f, "multisampling was enabled, and tiling was `Linear`")
+ }
+ Self::MultisampleMultipleMipLevels => write!(
+ f,
+ "multisampling was enabled, and multiple mip levels were specified",
+ ),
+ Self::MultisampleNot2d => write!(
+ f,
+ "multisampling was enabled, but the image type was not 2D",
+ ),
+ Self::OptimalTilingNotSupported => write!(
+ f,
+ "the image has optimal tiling, which is not supported for this operation",
+ ),
+ Self::SampleCountNotSupported { .. } => write!(
+ f,
+ "the sample count is not supported by the device for this image configuration",
+ ),
+ Self::SharingQueueFamilyIndexOutOfRange { .. } => write!(
+ f,
+ "the sharing mode was set to `Concurrent`, but one of the specified queue family \
+ indices was out of range",
+ ),
+ Self::StencilUsageMismatch {
+ usage: _,
+ stencil_usage: _,
+ } => write!(
+ f,
+ "the provided `usage` and `stencil_usage` have different values for \
+ `depth_stencil_attachment` or `transient_attachment`",
+ ),
+ Self::YcbcrFormatInvalidDimensions => write!(
+ f,
+ "a YCbCr format was given, but the specified width and/or height was not a \
+ multiple of 2 as required by the format's chroma subsampling",
+ ),
+ Self::YcbcrFormatMultipleMipLevels => write!(
+ f,
+ "a YCbCr format was given, and multiple mip levels were specified",
+ ),
+ Self::YcbcrFormatMultisampling => {
+ write!(f, "a YCbCr format was given, and multisampling was enabled")
+ }
+ Self::YcbcrFormatNot2d => {
+ write!(f, "a YCbCr format was given, but the image type was not 2D")
+ }
+ Self::DirectImageViewCreationFailed(e) => write!(f, "Image view creation failed {}", e),
+ Self::DrmFormatModifierRequiresCreateInfo => write!(f, "If and only if tiling is `DRMFormatModifier`, then `image_drm_format_modifier_create_info` must be `Some`"),
+ }
+ }
+}
+
+impl From<VulkanError> for ImageError {
+ fn from(err: VulkanError) -> Self {
+ Self::VulkanError(err)
+ }
+}
+
+impl From<AllocationCreationError> for ImageError {
+ fn from(err: AllocationCreationError) -> Self {
+ Self::AllocError(err)
+ }
+}
+
+impl From<RequirementNotMet> for ImageError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
+ }
+ }
}
#[cfg(test)]
mod tests {
- use super::ImageCreateFlags;
- use super::ImageCreationError;
- use super::ImageUsage;
- use super::UnsafeImage;
- use crate::format::Format;
- use crate::image::ImageDimensions;
- use crate::image::SampleCount;
- use crate::sync::Sharing;
- use std::iter::Empty;
- use std::u32;
+ use super::{ImageCreateInfo, ImageError, ImageUsage, RawImage};
+ use crate::{
+ format::Format,
+ image::{
+ sys::SubresourceRangeIterator, ImageAspect, ImageAspects, ImageCreateFlags,
+ ImageDimensions, ImageSubresourceRange, SampleCount,
+ },
+ DeviceSize, RequiresOneOf,
+ };
+ use smallvec::SmallVec;
#[test]
fn create_sampled() {
let (device, _) = gfx_dev_and_queue!();
- let usage = ImageUsage {
- sampled: true,
- ..ImageUsage::none()
- };
-
- let (_img, _) = unsafe {
- UnsafeImage::new(
- device,
- usage,
- Format::R8G8B8A8Unorm,
- ImageCreateFlags::none(),
- ImageDimensions::Dim2d {
+ let _ = RawImage::new(
+ device,
+ ImageCreateInfo {
+ dimensions: ImageDimensions::Dim2d {
width: 32,
height: 32,
array_layers: 1,
},
- SampleCount::Sample1,
- 1,
- Sharing::Exclusive::<Empty<_>>,
- false,
- false,
- )
- }
+ format: Some(Format::R8G8B8A8_UNORM),
+ usage: ImageUsage::SAMPLED,
+ ..Default::default()
+ },
+ )
.unwrap();
}
@@ -1103,30 +3321,19 @@ mod tests {
fn create_transient() {
let (device, _) = gfx_dev_and_queue!();
- let usage = ImageUsage {
- transient_attachment: true,
- color_attachment: true,
- ..ImageUsage::none()
- };
-
- let (_img, _) = unsafe {
- UnsafeImage::new(
- device,
- usage,
- Format::R8G8B8A8Unorm,
- ImageCreateFlags::none(),
- ImageDimensions::Dim2d {
+ let _ = RawImage::new(
+ device,
+ ImageCreateInfo {
+ dimensions: ImageDimensions::Dim2d {
width: 32,
height: 32,
array_layers: 1,
},
- SampleCount::Sample1,
- 1,
- Sharing::Exclusive::<Empty<_>>,
- false,
- false,
- )
- }
+ format: Some(Format::R8G8B8A8_UNORM),
+ usage: ImageUsage::TRANSIENT_ATTACHMENT | ImageUsage::COLOR_ATTACHMENT,
+ ..Default::default()
+ },
+ )
.unwrap();
}
@@ -1134,73 +3341,45 @@ mod tests {
fn zero_mipmap() {
let (device, _) = gfx_dev_and_queue!();
- let usage = ImageUsage {
- sampled: true,
- ..ImageUsage::none()
- };
-
- let res = unsafe {
- UnsafeImage::new(
+ assert_should_panic!({
+ let _ = RawImage::new(
device,
- usage,
- Format::R8G8B8A8Unorm,
- ImageCreateFlags::none(),
- ImageDimensions::Dim2d {
- width: 32,
- height: 32,
- array_layers: 1,
+ ImageCreateInfo {
+ dimensions: ImageDimensions::Dim2d {
+ width: 32,
+ height: 32,
+ array_layers: 1,
+ },
+ format: Some(Format::R8G8B8A8_UNORM),
+ mip_levels: 0,
+ usage: ImageUsage::SAMPLED,
+ ..Default::default()
},
- SampleCount::Sample1,
- 0,
- Sharing::Exclusive::<Empty<_>>,
- false,
- false,
- )
- };
-
- match res {
- Err(ImageCreationError::InvalidMipmapsCount { .. }) => (),
- _ => panic!(),
- };
+ );
+ });
}
#[test]
- #[ignore] // TODO: AMD card seems to support a u32::MAX number of mipmaps
fn mipmaps_too_high() {
let (device, _) = gfx_dev_and_queue!();
- let usage = ImageUsage {
- sampled: true,
- ..ImageUsage::none()
- };
-
- let res = unsafe {
- UnsafeImage::new(
- device,
- usage,
- Format::R8G8B8A8Unorm,
- ImageCreateFlags::none(),
- ImageDimensions::Dim2d {
+ let res = RawImage::new(
+ device,
+ ImageCreateInfo {
+ dimensions: ImageDimensions::Dim2d {
width: 32,
height: 32,
array_layers: 1,
},
- SampleCount::Sample1,
- u32::MAX,
- Sharing::Exclusive::<Empty<_>>,
- false,
- false,
- )
- };
+ format: Some(Format::R8G8B8A8_UNORM),
+ mip_levels: u32::MAX,
+ usage: ImageUsage::SAMPLED,
+ ..Default::default()
+ },
+ );
match res {
- Err(ImageCreationError::InvalidMipmapsCount {
- obtained,
- valid_range,
- }) => {
- assert_eq!(obtained, u32::MAX);
- assert_eq!(valid_range.start, 1);
- }
+ Err(ImageError::MaxMipLevelsExceeded { .. }) => (),
_ => panic!(),
};
}
@@ -1209,33 +3388,27 @@ mod tests {
fn shader_storage_image_multisample() {
let (device, _) = gfx_dev_and_queue!();
- let usage = ImageUsage {
- storage: true,
- ..ImageUsage::none()
- };
-
- let res = unsafe {
- UnsafeImage::new(
- device,
- usage,
- Format::R8G8B8A8Unorm,
- ImageCreateFlags::none(),
- ImageDimensions::Dim2d {
+ let res = RawImage::new(
+ device,
+ ImageCreateInfo {
+ dimensions: ImageDimensions::Dim2d {
width: 32,
height: 32,
array_layers: 1,
},
- SampleCount::Sample2,
- 1,
- Sharing::Exclusive::<Empty<_>>,
- false,
- false,
- )
- };
+ format: Some(Format::R8G8B8A8_UNORM),
+ samples: SampleCount::Sample2,
+ usage: ImageUsage::STORAGE,
+ ..Default::default()
+ },
+ );
match res {
- Err(ImageCreationError::ShaderStorageImageMultisampleFeatureNotEnabled) => (),
- Err(ImageCreationError::UnsupportedSamplesCount { .. }) => (), // unlikely but possible
+ Err(ImageError::RequirementNotMet {
+ requires_one_of: RequiresOneOf { features, .. },
+ ..
+ }) if features.contains(&"shader_storage_image_multisample") => (),
+ Err(ImageError::SampleCountNotSupported { .. }) => (), // unlikely but possible
_ => panic!(),
};
}
@@ -1244,33 +3417,25 @@ mod tests {
fn compressed_not_color_attachment() {
let (device, _) = gfx_dev_and_queue!();
- let usage = ImageUsage {
- color_attachment: true,
- ..ImageUsage::none()
- };
-
- let res = unsafe {
- UnsafeImage::new(
- device,
- usage,
- Format::ASTC_5x4UnormBlock,
- ImageCreateFlags::none(),
- ImageDimensions::Dim2d {
+ let res = RawImage::new(
+ device,
+ ImageCreateInfo {
+ dimensions: ImageDimensions::Dim2d {
width: 32,
height: 32,
array_layers: 1,
},
- SampleCount::Sample1,
- u32::MAX,
- Sharing::Exclusive::<Empty<_>>,
- false,
- false,
- )
- };
+ format: Some(Format::ASTC_5x4_UNORM_BLOCK),
+ usage: ImageUsage::COLOR_ATTACHMENT,
+ ..Default::default()
+ },
+ );
match res {
- Err(ImageCreationError::FormatNotSupported) => (),
- Err(ImageCreationError::UnsupportedUsage) => (),
+ Err(ImageError::FormatNotSupported) => (),
+ Err(ImageError::FormatUsageNotSupported {
+ usage: "color_attachment",
+ }) => (),
_ => panic!(),
};
}
@@ -1279,71 +3444,170 @@ mod tests {
fn transient_forbidden_with_some_usages() {
let (device, _) = gfx_dev_and_queue!();
- let usage = ImageUsage {
- transient_attachment: true,
- sampled: true,
- ..ImageUsage::none()
- };
-
- let res = unsafe {
- UnsafeImage::new(
+ assert_should_panic!({
+ let _ = RawImage::new(
device,
- usage,
- Format::R8G8B8A8Unorm,
- ImageCreateFlags::none(),
- ImageDimensions::Dim2d {
- width: 32,
- height: 32,
- array_layers: 1,
+ ImageCreateInfo {
+ dimensions: ImageDimensions::Dim2d {
+ width: 32,
+ height: 32,
+ array_layers: 1,
+ },
+ format: Some(Format::R8G8B8A8_UNORM),
+ usage: ImageUsage::TRANSIENT_ATTACHMENT | ImageUsage::SAMPLED,
+ ..Default::default()
},
- SampleCount::Sample1,
- 1,
- Sharing::Exclusive::<Empty<_>>,
- false,
- false,
- )
- };
-
- match res {
- Err(ImageCreationError::UnsupportedUsage) => (),
- _ => panic!(),
- };
+ );
+ })
}
#[test]
fn cubecompatible_dims_mismatch() {
let (device, _) = gfx_dev_and_queue!();
- let usage = ImageUsage {
- sampled: true,
- ..ImageUsage::none()
- };
-
- let res = unsafe {
- UnsafeImage::new(
- device,
- usage,
- Format::R8G8B8A8Unorm,
- ImageCreateFlags {
- cube_compatible: true,
- ..ImageCreateFlags::none()
- },
- ImageDimensions::Dim2d {
+ let res = RawImage::new(
+ device,
+ ImageCreateInfo {
+ flags: ImageCreateFlags::CUBE_COMPATIBLE,
+ dimensions: ImageDimensions::Dim2d {
width: 32,
height: 64,
array_layers: 1,
},
- SampleCount::Sample1,
- 1,
- Sharing::Exclusive::<Empty<_>>,
- false,
- false,
- )
- };
+ format: Some(Format::R8G8B8A8_UNORM),
+ usage: ImageUsage::SAMPLED,
+ ..Default::default()
+ },
+ );
match res {
- Err(ImageCreationError::CreationFlagRequirementsNotMet) => (),
+ Err(ImageError::CubeCompatibleNotEnoughArrayLayers) => (),
+ Err(ImageError::CubeCompatibleNotSquare) => (),
_ => panic!(),
};
}
+
+ #[test]
+ #[allow(clippy::erasing_op, clippy::identity_op)]
+ fn subresource_range_iterator() {
+ // A fictitious set of aspects that no real image would actually ever have.
+ let image_aspect_list: SmallVec<[ImageAspect; 4]> = (ImageAspects::COLOR
+ | ImageAspects::DEPTH
+ | ImageAspects::STENCIL
+ | ImageAspects::PLANE_0)
+ .into_iter()
+ .collect();
+ let image_mip_levels = 6;
+ let image_array_layers = 8;
+
+ let mip = image_array_layers as DeviceSize;
+ let asp = mip * image_mip_levels as DeviceSize;
+
+ // Whole image
+ let mut iter = SubresourceRangeIterator::new(
+ ImageSubresourceRange {
+ aspects: ImageAspects::COLOR
+ | ImageAspects::DEPTH
+ | ImageAspects::STENCIL
+ | ImageAspects::PLANE_0,
+ mip_levels: 0..6,
+ array_layers: 0..8,
+ },
+ &image_aspect_list,
+ asp,
+ image_mip_levels,
+ mip,
+ image_array_layers,
+ );
+
+ assert_eq!(iter.next(), Some(0 * asp..4 * asp));
+ assert_eq!(iter.next(), None);
+
+ // Only some aspects
+ let mut iter = SubresourceRangeIterator::new(
+ ImageSubresourceRange {
+ aspects: ImageAspects::COLOR | ImageAspects::DEPTH | ImageAspects::PLANE_0,
+ mip_levels: 0..6,
+ array_layers: 0..8,
+ },
+ &image_aspect_list,
+ asp,
+ image_mip_levels,
+ mip,
+ image_array_layers,
+ );
+
+ assert_eq!(iter.next(), Some(0 * asp..2 * asp));
+ assert_eq!(iter.next(), Some(3 * asp..4 * asp));
+ assert_eq!(iter.next(), None);
+
+ // Two aspects, and only some of the mip levels
+ let mut iter = SubresourceRangeIterator::new(
+ ImageSubresourceRange {
+ aspects: ImageAspects::DEPTH | ImageAspects::STENCIL,
+ mip_levels: 2..4,
+ array_layers: 0..8,
+ },
+ &image_aspect_list,
+ asp,
+ image_mip_levels,
+ mip,
+ image_array_layers,
+ );
+ assert_eq!(iter.next(), Some(1 * asp + 2 * mip..1 * asp + 4 * mip));
+ assert_eq!(iter.next(), Some(2 * asp + 2 * mip..2 * asp + 4 * mip));
+ assert_eq!(iter.next(), None);
+
+ // One aspect, one mip level, only some of the array layers
+ let mut iter = SubresourceRangeIterator::new(
+ ImageSubresourceRange {
+ aspects: ImageAspects::COLOR,
+
+ mip_levels: 0..1,
+ array_layers: 2..4,
+ },
+ &image_aspect_list,
+ asp,
+ image_mip_levels,
+ mip,
+ image_array_layers,
+ );
+
+ assert_eq!(
+ iter.next(),
+ Some(0 * asp + 0 * mip + 2..0 * asp + 0 * mip + 4)
+ );
+ assert_eq!(iter.next(), None);
+
+ // Two aspects, two mip levels, only some of the array layers
+ let mut iter = SubresourceRangeIterator::new(
+ ImageSubresourceRange {
+ aspects: ImageAspects::DEPTH | ImageAspects::STENCIL,
+ mip_levels: 2..4,
+ array_layers: 6..8,
+ },
+ &image_aspect_list,
+ asp,
+ image_mip_levels,
+ mip,
+ image_array_layers,
+ );
+ assert_eq!(
+ iter.next(),
+ Some(1 * asp + 2 * mip + 6..1 * asp + 2 * mip + 8)
+ );
+ assert_eq!(
+ iter.next(),
+ Some(1 * asp + 3 * mip + 6..1 * asp + 3 * mip + 8)
+ );
+ assert_eq!(
+ iter.next(),
+ Some(2 * asp + 2 * mip + 6..2 * asp + 2 * mip + 8)
+ );
+ assert_eq!(
+ iter.next(),
+ Some(2 * asp + 3 * mip + 6..2 * asp + 3 * mip + 8)
+ );
+ assert_eq!(iter.next(), None);
+ }
}
diff --git a/src/image/traits.rs b/src/image/traits.rs
index 4c6a5c8..5b5a6a5 100644
--- a/src/image/traits.rs
+++ b/src/image/traits.rs
@@ -7,61 +7,82 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use crate::format::ClearValue;
-use crate::format::Format;
-use crate::format::FormatTy;
-use crate::image::sys::UnsafeImage;
-use crate::image::ImageDescriptorLayouts;
-use crate::image::ImageDimensions;
-use crate::image::ImageLayout;
-use crate::image::SampleCount;
-use crate::sync::AccessError;
-use crate::SafeDeref;
-use std::hash::Hash;
-use std::hash::Hasher;
+use super::{
+ sys::Image, ImageAspects, ImageDescriptorLayouts, ImageDimensions, ImageLayout,
+ ImageSubresourceLayers, ImageSubresourceRange, ImageUsage, SampleCount,
+};
+use crate::{
+ device::{Device, DeviceOwned},
+ format::{Format, FormatFeatures},
+ SafeDeref,
+};
+use std::{
+ fmt::{Debug, Error as FmtError, Formatter},
+ hash::{Hash, Hasher},
+ sync::Arc,
+};
/// Trait for types that represent the way a GPU can access an image.
-pub unsafe trait ImageAccess {
+pub unsafe trait ImageAccess: DeviceOwned + Send + Sync {
/// Returns the inner unsafe image object used by this image.
- fn inner(&self) -> ImageInner;
+ fn inner(&self) -> ImageInner<'_>;
- /// Returns the format of this image.
- #[inline]
- fn format(&self) -> Format {
- self.inner().image.format()
- }
-
- /// Returns true if the image is a color image.
+ /// Returns the dimensions of the image.
#[inline]
- fn has_color(&self) -> bool {
- matches!(
- self.format().ty(),
- FormatTy::Float | FormatTy::Uint | FormatTy::Sint | FormatTy::Compressed
- )
+ fn dimensions(&self) -> ImageDimensions {
+ let inner = self.inner();
+
+ match self
+ .inner()
+ .image
+ .dimensions()
+ .mip_level_dimensions(inner.first_mipmap_level)
+ .unwrap()
+ {
+ ImageDimensions::Dim1d {
+ width,
+ array_layers: _,
+ } => ImageDimensions::Dim1d {
+ width,
+ array_layers: inner.num_layers,
+ },
+ ImageDimensions::Dim2d {
+ width,
+ height,
+ array_layers: _,
+ } => ImageDimensions::Dim2d {
+ width,
+ height,
+ array_layers: inner.num_layers,
+ },
+ ImageDimensions::Dim3d {
+ width,
+ height,
+ depth,
+ } => ImageDimensions::Dim3d {
+ width,
+ height,
+ depth,
+ },
+ }
}
- /// Returns true if the image has a depth component. In other words, if it is a depth or a
- /// depth-stencil format.
+ /// Returns the format of this image.
#[inline]
- fn has_depth(&self) -> bool {
- matches!(self.format().ty(), FormatTy::Depth | FormatTy::DepthStencil)
+ fn format(&self) -> Format {
+ self.inner().image.format().unwrap()
}
- /// Returns true if the image has a stencil component. In other words, if it is a stencil or a
- /// depth-stencil format.
+ /// Returns the features supported by the image's format.
#[inline]
- fn has_stencil(&self) -> bool {
- matches!(
- self.format().ty(),
- FormatTy::Stencil | FormatTy::DepthStencil
- )
+ fn format_features(&self) -> FormatFeatures {
+ self.inner().image.format_features()
}
/// Returns the number of mipmap levels of this image.
#[inline]
- fn mipmap_levels(&self) -> u32 {
- // TODO: not necessarily correct because of the new inner() design?
- self.inner().image.mipmap_levels()
+ fn mip_levels(&self) -> u32 {
+ self.inner().num_mipmap_levels
}
/// Returns the number of samples of this image.
@@ -70,23 +91,35 @@ pub unsafe trait ImageAccess {
self.inner().image.samples()
}
- /// Returns the dimensions of the image.
+ /// Returns the usage the image was created with.
#[inline]
- fn dimensions(&self) -> ImageDimensions {
- // TODO: not necessarily correct because of the new inner() design?
- self.inner().image.dimensions()
+ fn usage(&self) -> ImageUsage {
+ self.inner().image.usage()
}
- /// Returns true if the image can be used as a source for blits.
+ /// Returns the stencil usage the image was created with.
#[inline]
- fn supports_blit_source(&self) -> bool {
- self.inner().image.format_features().blit_src
+ fn stencil_usage(&self) -> ImageUsage {
+ self.inner().image.stencil_usage()
}
- /// Returns true if the image can be used as a destination for blits.
+ /// Returns an `ImageSubresourceLayers` covering the first mip level of the image. All aspects
+ /// of the image are selected, or `plane0` if the image is multi-planar.
#[inline]
- fn supports_blit_destination(&self) -> bool {
- self.inner().image.format_features().blit_dst
+ fn subresource_layers(&self) -> ImageSubresourceLayers {
+ ImageSubresourceLayers::from_parameters(self.format(), self.dimensions().array_layers())
+ }
+
+ /// Returns an `ImageSubresourceRange` covering the whole image. If the image is multi-planar,
+ /// only the `color` aspect is selected.
+ #[inline]
+ fn subresource_range(&self) -> ImageSubresourceRange {
+ ImageSubresourceRange {
+ aspects: self.format().aspects()
+ - (ImageAspects::PLANE_0 | ImageAspects::PLANE_1 | ImageAspects::PLANE_2),
+ mip_levels: 0..self.mip_levels(),
+ array_layers: 0..self.dimensions().array_layers(),
+ }
}
/// When images are created their memory layout is initially `Undefined` or `Preinitialized`.
@@ -102,14 +135,17 @@ pub unsafe trait ImageAccess {
/// `Preinitialized` state, this may result in the vulkan implementation attempting to use
/// an image in an invalid layout. The same problem must be considered by the implementer
/// of the method.
+ #[inline]
unsafe fn layout_initialized(&self) {}
+ #[inline]
fn is_layout_initialized(&self) -> bool {
false
}
- unsafe fn preinitialized_layout(&self) -> bool {
- self.inner().image.preinitialized_layout()
+ #[inline]
+ fn initial_layout(&self) -> ImageLayout {
+ self.inner().image.initial_layout()
}
/// Returns the layout that the image has when it is first used in a primary command buffer.
@@ -138,14 +174,14 @@ pub unsafe trait ImageAccess {
unsafe fn forced_undefined_initial_layout(
self,
preinitialized: bool,
- ) -> ImageAccessFromUndefinedLayout<Self>
+ ) -> Arc<ImageAccessFromUndefinedLayout<Self>>
where
Self: Sized,
{
- ImageAccessFromUndefinedLayout {
+ Arc::new(ImageAccessFromUndefinedLayout {
image: self,
preinitialized,
- }
+ })
}
/// Returns an [`ImageDescriptorLayouts`] structure specifying the image layout to use
@@ -153,180 +189,45 @@ pub unsafe trait ImageAccess {
///
/// This must return `Some` if the image is to be used to create an image view.
fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts>;
-
- /// Returns a key that uniquely identifies the memory content of the image.
- /// Two ranges that potentially overlap in memory must return the same key.
- ///
- /// The key is shared amongst all buffers and images, which means that you can make several
- /// different image objects share the same memory, or make some image objects share memory
- /// with buffers, as long as they return the same key.
- ///
- /// Since it is possible to accidentally return the same key for memory ranges that don't
- /// overlap, the `conflicts_image` or `conflicts_buffer` function should always be called to
- /// verify whether they actually overlap.
- fn conflict_key(&self) -> u64;
-
- /// Returns the current mip level that is accessed by the gpu
- fn current_miplevels_access(&self) -> std::ops::Range<u32>;
-
- /// Returns the current layer level that is accessed by the gpu
- fn current_layer_levels_access(&self) -> std::ops::Range<u32>;
-
- /// Locks the resource for usage on the GPU. Returns an error if the lock can't be acquired.
- ///
- /// After this function returns `Ok`, you are authorized to use the image on the GPU. If the
- /// GPU operation requires an exclusive access to the image (which includes image layout
- /// transitions) then `exclusive_access` should be true.
- ///
- /// The `expected_layout` is the layout we expect the image to be in when we lock it. If the
- /// actual layout doesn't match this expected layout, then an error should be returned. If
- /// `Undefined` is passed, that means that the caller doesn't care about the actual layout,
- /// and that a layout mismatch shouldn't return an error.
- ///
- /// This function exists to prevent the user from causing a data race by reading and writing
- /// to the same resource at the same time.
- ///
- /// If you call this function, you should call `unlock()` once the resource is no longer in use
- /// by the GPU. The implementation is not expected to automatically perform any unlocking and
- /// can rely on the fact that `unlock()` is going to be called.
- fn try_gpu_lock(
- &self,
- exclusive_access: bool,
- uninitialized_safe: bool,
- expected_layout: ImageLayout,
- ) -> Result<(), AccessError>;
-
- /// Locks the resource for usage on the GPU. Supposes that the resource is already locked, and
- /// simply increases the lock by one.
- ///
- /// Must only be called after `try_gpu_lock()` succeeded.
- ///
- /// If you call this function, you should call `unlock()` once the resource is no longer in use
- /// by the GPU. The implementation is not expected to automatically perform any unlocking and
- /// can rely on the fact that `unlock()` is going to be called.
- unsafe fn increase_gpu_lock(&self);
-
- /// Unlocks the resource previously acquired with `try_gpu_lock` or `increase_gpu_lock`.
- ///
- /// If the GPU operation that we unlock from transitioned the image to another layout, then
- /// it should be passed as parameter.
- ///
- /// A layout transition requires exclusive access to the image, which means two things:
- ///
- /// - The implementation can panic if it finds out that the layout is not the same as it
- /// currently is and that it is not locked in exclusive mode.
- /// - There shouldn't be any possible race between `unlock` and `try_gpu_lock`, since
- /// `try_gpu_lock` should fail if the image is already locked in exclusive mode.
- ///
- /// # Safety
- ///
- /// - Must only be called once per previous lock.
- /// - The transitioned layout must be supported by the image (eg. the layout shouldn't be
- /// `ColorAttachmentOptimal` if the image wasn't created with the `color_attachment` usage).
- /// - The transitioned layout must not be `Undefined`.
- ///
- unsafe fn unlock(&self, transitioned_layout: Option<ImageLayout>);
}
/// Inner information about an image.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct ImageInner<'a> {
/// The underlying image object.
- pub image: &'a UnsafeImage,
+ pub image: &'a Arc<Image>,
/// The first layer of `image` to consider.
- pub first_layer: usize,
+ pub first_layer: u32,
/// The number of layers of `image` to consider.
- pub num_layers: usize,
+ pub num_layers: u32,
/// The first mipmap level of `image` to consider.
- pub first_mipmap_level: usize,
+ pub first_mipmap_level: u32,
/// The number of mipmap levels of `image` to consider.
- pub num_mipmap_levels: usize,
+ pub num_mipmap_levels: u32,
}
-unsafe impl<T> ImageAccess for T
-where
- T: SafeDeref,
- T::Target: ImageAccess,
-{
- #[inline]
- fn inner(&self) -> ImageInner {
- (**self).inner()
- }
-
- #[inline]
- fn initial_layout_requirement(&self) -> ImageLayout {
- (**self).initial_layout_requirement()
- }
-
- #[inline]
- fn final_layout_requirement(&self) -> ImageLayout {
- (**self).final_layout_requirement()
- }
-
- #[inline]
- fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
- (**self).descriptor_layouts()
- }
-
- #[inline]
- fn conflict_key(&self) -> u64 {
- (**self).conflict_key()
- }
-
- #[inline]
- fn try_gpu_lock(
- &self,
- exclusive_access: bool,
- uninitialized_safe: bool,
- expected_layout: ImageLayout,
- ) -> Result<(), AccessError> {
- (**self).try_gpu_lock(exclusive_access, uninitialized_safe, expected_layout)
- }
-
- #[inline]
- unsafe fn increase_gpu_lock(&self) {
- (**self).increase_gpu_lock()
- }
-
- #[inline]
- unsafe fn unlock(&self, transitioned_layout: Option<ImageLayout>) {
- (**self).unlock(transitioned_layout)
- }
-
- #[inline]
- unsafe fn layout_initialized(&self) {
- (**self).layout_initialized();
- }
-
- #[inline]
- fn is_layout_initialized(&self) -> bool {
- (**self).is_layout_initialized()
- }
-
- fn current_miplevels_access(&self) -> std::ops::Range<u32> {
- (**self).current_miplevels_access()
- }
-
- fn current_layer_levels_access(&self) -> std::ops::Range<u32> {
- (**self).current_layer_levels_access()
+impl Debug for dyn ImageAccess {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ f.debug_struct("dyn ImageAccess")
+ .field("inner", &self.inner())
+ .finish()
}
}
-impl PartialEq for dyn ImageAccess + Send + Sync {
+impl PartialEq for dyn ImageAccess {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.inner() == other.inner()
}
}
-impl Eq for dyn ImageAccess + Send + Sync {}
+impl Eq for dyn ImageAccess {}
-impl Hash for dyn ImageAccess + Send + Sync {
- #[inline]
+impl Hash for dyn ImageAccess {
fn hash<H: Hasher>(&self, state: &mut H) {
self.inner().hash(state);
}
@@ -340,16 +241,23 @@ pub struct ImageAccessFromUndefinedLayout<I> {
preinitialized: bool,
}
+unsafe impl<I> DeviceOwned for ImageAccessFromUndefinedLayout<I>
+where
+ I: ImageAccess,
+{
+ fn device(&self) -> &Arc<Device> {
+ self.image.device()
+ }
+}
+
unsafe impl<I> ImageAccess for ImageAccessFromUndefinedLayout<I>
where
I: ImageAccess,
{
- #[inline]
- fn inner(&self) -> ImageInner {
+ fn inner(&self) -> ImageInner<'_> {
self.image.inner()
}
- #[inline]
fn initial_layout_requirement(&self) -> ImageLayout {
if self.preinitialized {
ImageLayout::Preinitialized
@@ -358,56 +266,19 @@ where
}
}
- #[inline]
fn final_layout_requirement(&self) -> ImageLayout {
self.image.final_layout_requirement()
}
- #[inline]
fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
self.image.descriptor_layouts()
}
-
- #[inline]
- fn conflict_key(&self) -> u64 {
- self.image.conflict_key()
- }
-
- #[inline]
- fn try_gpu_lock(
- &self,
- exclusive_access: bool,
- uninitialized_safe: bool,
- expected_layout: ImageLayout,
- ) -> Result<(), AccessError> {
- self.image
- .try_gpu_lock(exclusive_access, uninitialized_safe, expected_layout)
- }
-
- #[inline]
- unsafe fn increase_gpu_lock(&self) {
- self.image.increase_gpu_lock()
- }
-
- #[inline]
- unsafe fn unlock(&self, new_layout: Option<ImageLayout>) {
- self.image.unlock(new_layout)
- }
-
- fn current_miplevels_access(&self) -> std::ops::Range<u32> {
- self.image.current_miplevels_access()
- }
-
- fn current_layer_levels_access(&self) -> std::ops::Range<u32> {
- self.image.current_layer_levels_access()
- }
}
impl<I> PartialEq for ImageAccessFromUndefinedLayout<I>
where
I: ImageAccess,
{
- #[inline]
fn eq(&self, other: &Self) -> bool {
self.inner() == other.inner()
}
@@ -419,20 +290,42 @@ impl<I> Hash for ImageAccessFromUndefinedLayout<I>
where
I: ImageAccess,
{
- #[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.inner().hash(state);
}
}
-/// Extension trait for images. Checks whether the value `T` can be used as a clear value for the
-/// given image.
-// TODO: isn't that for image views instead?
-pub unsafe trait ImageClearValue<T>: ImageAccess {
- fn decode(&self, value: T) -> Option<ClearValue>;
-}
-
pub unsafe trait ImageContent<P>: ImageAccess {
/// Checks whether pixels of type `P` match the format of the image.
fn matches_format(&self) -> bool;
}
+
+unsafe impl<T> ImageAccess for T
+where
+ T: SafeDeref + Send + Sync,
+ T::Target: ImageAccess,
+{
+ fn inner(&self) -> ImageInner<'_> {
+ (**self).inner()
+ }
+
+ fn initial_layout_requirement(&self) -> ImageLayout {
+ (**self).initial_layout_requirement()
+ }
+
+ fn final_layout_requirement(&self) -> ImageLayout {
+ (**self).final_layout_requirement()
+ }
+
+ fn descriptor_layouts(&self) -> Option<ImageDescriptorLayouts> {
+ (**self).descriptor_layouts()
+ }
+
+ unsafe fn layout_initialized(&self) {
+ (**self).layout_initialized();
+ }
+
+ fn is_layout_initialized(&self) -> bool {
+ (**self).is_layout_initialized()
+ }
+}
diff --git a/src/image/usage.rs b/src/image/usage.rs
index da64809..b6b223d 100644
--- a/src/image/usage.rs
+++ b/src/image/usage.rs
@@ -7,216 +7,117 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use std::ops::BitOr;
+use crate::macros::vulkan_bitflags;
-/// Describes how an image is going to be used. This is **not** just an optimization.
-///
-/// If you try to use an image in a way that you didn't declare, a panic will happen.
-///
-/// If `transient_attachment` is true, then only `color_attachment`, `depth_stencil_attachment`
-/// and `input_attachment` can be true as well. The rest must be false or an error will be returned
-/// when creating the image.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub struct ImageUsage {
- /// Can be used as a source for transfers. Includes blits.
- pub transfer_source: bool,
+vulkan_bitflags! {
+ #[non_exhaustive]
- /// Can be used as a destination for transfers. Includes blits.
- pub transfer_destination: bool,
+ /// Describes how an image is going to be used. This is **not** just an optimization.
+ ///
+ /// If you try to use an image in a way that you didn't declare, an error will occur.
+ ImageUsage = ImageUsageFlags(u32);
+
+ /// The image can be used as a source for transfer, blit, resolve and clear commands.
+ TRANSFER_SRC = TRANSFER_SRC,
- /// Can be sampled from a shader.
- pub sampled: bool,
+ /// The image can be used as a destination for transfer, blit, resolve and clear commands.
+ TRANSFER_DST = TRANSFER_DST,
- /// Can be used as an image storage in a shader.
- pub storage: bool,
+ /// The image can be used as a sampled image in a shader.
+ SAMPLED = SAMPLED,
- /// Can be attached as a color attachment to a framebuffer.
- pub color_attachment: bool,
+ /// The image can be used as a storage image in a shader.
+ STORAGE = STORAGE,
- /// Can be attached as a depth, stencil or depth-stencil attachment to a framebuffer.
- pub depth_stencil_attachment: bool,
+ /// The image can be used as a color attachment in a render pass/framebuffer.
+ COLOR_ATTACHMENT = COLOR_ATTACHMENT,
- /// Indicates that this image will only ever be used as a temporary framebuffer attachment.
+ /// The image can be used as a depth/stencil attachment in a render pass/framebuffer.
+ DEPTH_STENCIL_ATTACHMENT = DEPTH_STENCIL_ATTACHMENT,
+
+ /// The image will be used as an attachment, and will only ever be used temporarily.
/// As soon as you leave a render pass, the content of transient images becomes undefined.
///
/// This is a hint to the Vulkan implementation that it may not need allocate any memory for
/// this image if the image can live entirely in some cache.
- pub transient_attachment: bool,
-
- /// Can be used as an input attachment. In other words, you can draw to it in a subpass then
- /// read from it in a following pass.
- pub input_attachment: bool,
-}
-
-impl ImageUsage {
- /// Builds a `ImageUsage` with all values set to true. Note that using the returned value will
- /// produce an error because of `transient_attachment` being true.
- #[inline]
- pub fn all() -> ImageUsage {
- ImageUsage {
- transfer_source: true,
- transfer_destination: true,
- sampled: true,
- storage: true,
- color_attachment: true,
- depth_stencil_attachment: true,
- transient_attachment: true,
- input_attachment: true,
- }
- }
-
- /// Builds a `ImageUsage` with all values set to false. Useful as a default value.
- ///
- /// # Example
///
- /// ```rust
- /// use vulkano::image::ImageUsage as ImageUsage;
- ///
- /// let _usage = ImageUsage {
- /// transfer_destination: true,
- /// sampled: true,
- /// .. ImageUsage::none()
- /// };
- /// ```
- #[inline]
- pub fn none() -> ImageUsage {
- ImageUsage {
- transfer_source: false,
- transfer_destination: false,
- sampled: false,
- storage: false,
- color_attachment: false,
- depth_stencil_attachment: false,
- transient_attachment: false,
- input_attachment: false,
- }
- }
-
- /// Builds a ImageUsage with color_attachment set to true and the rest to false.
- #[inline]
- pub fn color_attachment() -> ImageUsage {
- ImageUsage {
- transfer_source: false,
- transfer_destination: false,
- sampled: false,
- storage: false,
- color_attachment: true,
- depth_stencil_attachment: false,
- transient_attachment: false,
- input_attachment: false,
- }
- }
-
- /// Builds a ImageUsage with depth_stencil_attachment set to true and the rest to false.
- #[inline]
- pub fn depth_stencil_attachment() -> ImageUsage {
- ImageUsage {
- transfer_source: false,
- transfer_destination: false,
- sampled: false,
- storage: false,
- color_attachment: false,
- depth_stencil_attachment: true,
- transient_attachment: false,
- input_attachment: false,
- }
- }
-
- /// Builds a ImageUsage with color_attachment and transient_attachment set to true and the rest to false.
- #[inline]
- pub fn transient_color_attachment() -> ImageUsage {
- ImageUsage {
- transfer_source: false,
- transfer_destination: false,
- sampled: false,
- storage: false,
- color_attachment: true,
- depth_stencil_attachment: false,
- transient_attachment: true,
- input_attachment: false,
- }
- }
-
- /// Builds a ImageUsage with depth_stencil_attachment and transient_attachment set to true and the rest to false.
- #[inline]
- pub fn transient_depth_stencil_attachment() -> ImageUsage {
- ImageUsage {
- transfer_source: false,
- transfer_destination: false,
- sampled: false,
- storage: false,
- color_attachment: false,
- depth_stencil_attachment: true,
- transient_attachment: true,
- input_attachment: false,
- }
- }
-}
-
-impl From<ImageUsage> for ash::vk::ImageUsageFlags {
- #[inline]
- fn from(val: ImageUsage) -> Self {
- let mut result = ash::vk::ImageUsageFlags::empty();
- if val.transfer_source {
- result |= ash::vk::ImageUsageFlags::TRANSFER_SRC;
- }
- if val.transfer_destination {
- result |= ash::vk::ImageUsageFlags::TRANSFER_DST;
- }
- if val.sampled {
- result |= ash::vk::ImageUsageFlags::SAMPLED;
- }
- if val.storage {
- result |= ash::vk::ImageUsageFlags::STORAGE;
- }
- if val.color_attachment {
- result |= ash::vk::ImageUsageFlags::COLOR_ATTACHMENT;
- }
- if val.depth_stencil_attachment {
- result |= ash::vk::ImageUsageFlags::DEPTH_STENCIL_ATTACHMENT;
- }
- if val.transient_attachment {
- result |= ash::vk::ImageUsageFlags::TRANSIENT_ATTACHMENT;
- }
- if val.input_attachment {
- result |= ash::vk::ImageUsageFlags::INPUT_ATTACHMENT;
- }
- result
- }
-}
-
-impl From<ash::vk::ImageUsageFlags> for ImageUsage {
- #[inline]
- fn from(val: ash::vk::ImageUsageFlags) -> ImageUsage {
- ImageUsage {
- transfer_source: !(val & ash::vk::ImageUsageFlags::TRANSFER_SRC).is_empty(),
- transfer_destination: !(val & ash::vk::ImageUsageFlags::TRANSFER_DST).is_empty(),
- sampled: !(val & ash::vk::ImageUsageFlags::SAMPLED).is_empty(),
- storage: !(val & ash::vk::ImageUsageFlags::STORAGE).is_empty(),
- color_attachment: !(val & ash::vk::ImageUsageFlags::COLOR_ATTACHMENT).is_empty(),
- depth_stencil_attachment: !(val & ash::vk::ImageUsageFlags::DEPTH_STENCIL_ATTACHMENT)
- .is_empty(),
- transient_attachment: !(val & ash::vk::ImageUsageFlags::TRANSIENT_ATTACHMENT)
- .is_empty(),
- input_attachment: !(val & ash::vk::ImageUsageFlags::INPUT_ATTACHMENT).is_empty(),
- }
- }
-}
-
-impl BitOr for ImageUsage {
- type Output = Self;
-
- #[inline]
- fn bitor(self, rhs: Self) -> Self {
- ImageUsage {
- transfer_source: self.transfer_source || rhs.transfer_source,
- transfer_destination: self.transfer_destination || rhs.transfer_destination,
- sampled: self.sampled || rhs.sampled,
- storage: self.storage || rhs.storage,
- color_attachment: self.color_attachment || rhs.color_attachment,
- depth_stencil_attachment: self.depth_stencil_attachment || rhs.depth_stencil_attachment,
- transient_attachment: self.transient_attachment || rhs.transient_attachment,
- input_attachment: self.input_attachment || rhs.input_attachment,
- }
- }
+ /// If `transient_attachment` is true, then only `color_attachment`, `depth_stencil_attachment`
+ /// and `input_attachment` can be true as well. The rest must be false or an error will be
+ /// returned when creating the image.
+ TRANSIENT_ATTACHMENT = TRANSIENT_ATTACHMENT,
+
+ /// The image can be used as an input attachment in a render pass/framebuffer.
+ INPUT_ATTACHMENT = INPUT_ATTACHMENT,
+
+ /* TODO: enable
+ // TODO: document
+ VIDEO_DECODE_DST = VIDEO_DECODE_DST_KHR {
+ device_extensions: [khr_video_decode_queue],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ VIDEO_DECODE_SRC = VIDEO_DECODE_SRC_KHR {
+ device_extensions: [khr_video_decode_queue],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ VIDEO_DECODE_DPB = VIDEO_DECODE_DPB_KHR {
+ device_extensions: [khr_video_decode_queue],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ FRAGMENT_DENSITY_MAP = FRAGMENT_DENSITY_MAP_EXT {
+ device_extensions: [ext_fragment_density_map],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ FRAGMENT_SHADING_RATE_ATTACHMENT = FRAGMENT_SHADING_RATE_ATTACHMENT_KHR {
+ device_extensions: [khr_fragment_shading_rate],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ VIDEO_ENCODE_DST = VIDEO_ENCODE_DST_KHR {
+ device_extensions: [khr_video_encode_queue],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ VIDEO_ENCODE_SRC = VIDEO_ENCODE_SRC_KHR {
+ device_extensions: [khr_video_encode_queue],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ VIDEO_ENCODE_DPB = VIDEO_ENCODE_DPB_KHR {
+ device_extensions: [khr_video_encode_queue],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ ATTACHMENT_FEEDBACK_LOOP = ATTACHMENT_FEEDBACK_LOOP_EXT {
+ device_extensions: [ext_attachment_feedback_loop_layout],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ INVOCATION_MASK = INVOCATION_MASK_HUAWEI {
+ device_extensions: [huawei_invocation_mask],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ SAMPLE_WEIGHT = SAMPLE_WEIGHT_QCOM {
+ device_extensions: [qcom_image_processing],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ SAMPLE_BLOCK_MATCH = SAMPLE_BLOCK_MATCH_QCOM {
+ device_extensions: [qcom_image_processing],
+ },*/
}
diff --git a/src/image/view.rs b/src/image/view.rs
index 894a343..99bed3b 100644
--- a/src/image/view.rs
+++ b/src/image/view.rs
@@ -13,609 +13,1386 @@
//! an image and describes how the GPU should interpret the data. It is needed when an image is
//! to be used in a shader descriptor or as a framebuffer attachment.
-use crate::check_errors;
-use crate::device::Device;
-use crate::format::Format;
-use crate::format::FormatTy;
-use crate::image::sys::UnsafeImage;
-use crate::image::ImageAccess;
-use crate::image::ImageDimensions;
-use crate::memory::DeviceMemoryAllocError;
-use crate::sampler::Sampler;
-use crate::OomError;
-use crate::SafeDeref;
-use crate::VulkanObject;
-use std::error;
-use std::fmt;
-use std::hash::Hash;
-use std::hash::Hasher;
-use std::mem::MaybeUninit;
-use std::ops::Range;
-use std::ptr;
-use std::sync::Arc;
-
-/// A safe image view that checks for validity and keeps its attached image alive.
+use super::{
+ sys::Image, ImageAccess, ImageDimensions, ImageFormatInfo, ImageSubresourceRange, ImageUsage,
+};
+use crate::{
+ device::{Device, DeviceOwned},
+ format::{ChromaSampling, Format, FormatFeatures},
+ image::{ImageAspects, ImageCreateFlags, ImageTiling, ImageType, SampleCount},
+ macros::{impl_id_counter, vulkan_enum},
+ sampler::{ycbcr::SamplerYcbcrConversion, ComponentMapping},
+ OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject,
+};
+use std::{
+ error::Error,
+ fmt::{Debug, Display, Error as FmtError, Formatter},
+ hash::{Hash, Hasher},
+ mem::MaybeUninit,
+ num::NonZeroU64,
+ ptr,
+ sync::Arc,
+};
+
+/// A wrapper around an image that makes it available to shaders or framebuffers.
+#[derive(Debug)]
pub struct ImageView<I>
where
- I: ImageAccess,
+ I: ImageAccess + ?Sized,
{
- image: I,
- inner: UnsafeImageView,
- format: Format,
+ handle: ash::vk::ImageView,
+ image: Arc<I>,
+ id: NonZeroU64,
- ty: ImageViewType,
component_mapping: ComponentMapping,
- array_layers: Range<u32>,
+ format: Option<Format>,
+ format_features: FormatFeatures,
+ sampler_ycbcr_conversion: Option<Arc<SamplerYcbcrConversion>>,
+ subresource_range: ImageSubresourceRange,
+ usage: ImageUsage,
+ view_type: ImageViewType,
+
+ filter_cubic: bool,
+ filter_cubic_minmax: bool,
}
impl<I> ImageView<I>
where
- I: ImageAccess,
+ I: ImageAccess + ?Sized,
{
- /// Creates a default `ImageView`. Equivalent to `ImageView::start(image).build()`.
- #[inline]
- pub fn new(image: I) -> Result<Arc<ImageView<I>>, ImageViewCreationError> {
- Self::start(image).build()
- }
-
- /// Begins building an `ImageView`.
- pub fn start(image: I) -> ImageViewBuilder<I> {
- let ty = match image.dimensions() {
- ImageDimensions::Dim1d {
- array_layers: 1, ..
- } => ImageViewType::Dim1d,
- ImageDimensions::Dim1d { .. } => ImageViewType::Dim1dArray,
- ImageDimensions::Dim2d {
- array_layers: 1, ..
- } => ImageViewType::Dim2d,
- ImageDimensions::Dim2d { .. } => ImageViewType::Dim2dArray,
- ImageDimensions::Dim3d { .. } => ImageViewType::Dim3d,
- };
- let mipmap_levels = 0..image.mipmap_levels();
- let array_layers = 0..image.dimensions().array_layers();
+ /// Creates a new `ImageView`.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `create_info.array_layers` is empty.
+ /// - Panics if `create_info.mip_levels` is empty.
+ /// - Panics if `create_info.aspects` contains any aspects other than `color`, `depth`,
+ /// `stencil`, `plane0`, `plane1` or `plane2`.
+ /// - Panics if `create_info.aspects` contains more more than one aspect, unless `depth` and
+ /// `stencil` are the only aspects selected.
+ pub fn new(
+ image: Arc<I>,
+ create_info: ImageViewCreateInfo,
+ ) -> Result<Arc<ImageView<I>>, ImageViewCreationError> {
+ let format_features = Self::validate_new(&image, &create_info)?;
- ImageViewBuilder {
- image,
- ty,
- component_mapping: ComponentMapping::default(),
- mipmap_levels,
- array_layers,
+ unsafe {
+ Ok(Self::new_unchecked_with_format_features(
+ image,
+ create_info,
+ format_features,
+ )?)
}
}
- /// Returns the wrapped image that this image view was created from.
- pub fn image(&self) -> &I {
- &self.image
- }
-}
+ fn validate_new(
+ image: &I,
+ create_info: &ImageViewCreateInfo,
+ ) -> Result<FormatFeatures, ImageViewCreationError> {
+ let &ImageViewCreateInfo {
+ view_type,
+ format,
+ component_mapping,
+ ref subresource_range,
+ mut usage,
+ ref sampler_ycbcr_conversion,
+ _ne: _,
+ } = create_info;
-#[derive(Debug)]
-pub struct ImageViewBuilder<I> {
- image: I,
- ty: ImageViewType,
- component_mapping: ComponentMapping,
- mipmap_levels: Range<u32>,
- array_layers: Range<u32>,
-}
+ let image_inner = image.inner().image;
+ let device = image_inner.device();
+ let format = format.unwrap();
-impl<I> ImageViewBuilder<I>
-where
- I: ImageAccess,
-{
- /// Sets the image view type.
- ///
- /// By default, this is determined from the image, based on its dimensions and number of layers.
- /// The value of `ty` must be compatible with the dimensions of the image and the selected
- /// array layers.
- #[inline]
- pub fn with_type(mut self, ty: ImageViewType) -> Self {
- self.ty = ty;
- self
- }
+ let level_count = subresource_range.mip_levels.end - subresource_range.mip_levels.start;
+ let layer_count = subresource_range.array_layers.end - subresource_range.array_layers.start;
- /// Sets how to map components of each pixel.
- ///
- /// By default, this is the identity mapping, with every component mapped directly.
- #[inline]
- pub fn with_component_mapping(mut self, component_mapping: ComponentMapping) -> Self {
- self.component_mapping = component_mapping;
- self
- }
+ // VUID-VkImageSubresourceRange-aspectMask-requiredbitmask
+ assert!(!subresource_range.aspects.is_empty());
- /// Sets the range of mipmap levels that the view should cover.
- ///
- /// By default, this is the full range of mipmaps present in the image.
- #[inline]
- pub fn with_mipmap_levels(mut self, mipmap_levels: Range<u32>) -> Self {
- self.mipmap_levels = mipmap_levels;
- self
- }
+ // VUID-VkImageSubresourceRange-levelCount-01720
+ assert!(level_count != 0);
- /// Sets the range of array layers that the view should cover.
- ///
- /// By default, this is the full range of array layers present in the image.
- #[inline]
- pub fn with_array_layers(mut self, array_layers: Range<u32>) -> Self {
- self.array_layers = array_layers;
- self
- }
+ // VUID-VkImageSubresourceRange-layerCount-01721
+ assert!(layer_count != 0);
+
+ let default_usage = Self::get_default_usage(subresource_range.aspects, image_inner);
- /// Builds the `ImageView`.
- pub fn build(self) -> Result<Arc<ImageView<I>>, ImageViewCreationError> {
- let dimensions = self.image.dimensions();
- let format = self.image.format();
- let image_inner = self.image.inner().image;
- let usage = image_inner.usage();
- let flags = image_inner.flags();
+ let has_non_default_usage = if usage.is_empty() {
+ usage = default_usage;
+ false
+ } else {
+ usage == default_usage
+ };
- if self.mipmap_levels.end <= self.mipmap_levels.start
- || self.mipmap_levels.end > image_inner.mipmap_levels()
+ // VUID-VkImageViewCreateInfo-viewType-parameter
+ view_type.validate_device(device)?;
+
+ // VUID-VkImageViewCreateInfo-format-parameter
+ format.validate_device(device)?;
+
+ // VUID-VkComponentMapping-r-parameter
+ component_mapping.r.validate_device(device)?;
+
+ // VUID-VkComponentMapping-g-parameter
+ component_mapping.g.validate_device(device)?;
+
+ // VUID-VkComponentMapping-b-parameter
+ component_mapping.b.validate_device(device)?;
+
+ // VUID-VkComponentMapping-a-parameter
+ component_mapping.a.validate_device(device)?;
+
+ // VUID-VkImageSubresourceRange-aspectMask-parameter
+ subresource_range.aspects.validate_device(device)?;
+
+ assert!(!subresource_range.aspects.intersects(
+ ImageAspects::METADATA
+ | ImageAspects::MEMORY_PLANE_0
+ | ImageAspects::MEMORY_PLANE_1
+ | ImageAspects::MEMORY_PLANE_2
+ ));
+ assert!({
+ subresource_range.aspects.count() == 1
+ || subresource_range
+ .aspects
+ .contains(ImageAspects::DEPTH | ImageAspects::STENCIL)
+ && !subresource_range.aspects.intersects(
+ ImageAspects::COLOR
+ | ImageAspects::PLANE_0
+ | ImageAspects::PLANE_1
+ | ImageAspects::PLANE_2,
+ )
+ });
+
+ // Get format features
+ let format_features = unsafe { Self::get_format_features(format, image_inner) };
+
+ // No VUID apparently, but this seems like something we want to check?
+ if !image_inner
+ .format()
+ .unwrap()
+ .aspects()
+ .contains(subresource_range.aspects)
{
- return Err(ImageViewCreationError::MipMapLevelsOutOfRange);
+ return Err(ImageViewCreationError::ImageAspectsNotCompatible {
+ aspects: subresource_range.aspects,
+ image_aspects: image_inner.format().unwrap().aspects(),
+ });
+ }
+
+ // VUID-VkImageViewCreateInfo-None-02273
+ if format_features == FormatFeatures::default() {
+ return Err(ImageViewCreationError::FormatNotSupported);
+ }
+
+ // Check for compatibility with the image
+ let image_type = image.dimensions().image_type();
+
+ // VUID-VkImageViewCreateInfo-subResourceRange-01021
+ if !view_type.is_compatible_with(image_type) {
+ return Err(ImageViewCreationError::ImageTypeNotCompatible);
}
- if self.array_layers.end <= self.array_layers.start
- || self.array_layers.end > dimensions.array_layers()
+ // VUID-VkImageViewCreateInfo-image-01003
+ if (view_type == ImageViewType::Cube || view_type == ImageViewType::CubeArray)
+ && !image_inner
+ .flags()
+ .intersects(ImageCreateFlags::CUBE_COMPATIBLE)
{
- return Err(ImageViewCreationError::ArrayLayersOutOfRange);
+ return Err(ImageViewCreationError::ImageNotCubeCompatible);
+ }
+
+ // VUID-VkImageViewCreateInfo-viewType-01004
+ if view_type == ImageViewType::CubeArray && !device.enabled_features().image_cube_array {
+ return Err(ImageViewCreationError::RequirementNotMet {
+ required_for: "`create_info.viewtype` is `ImageViewType::CubeArray`",
+ requires_one_of: RequiresOneOf {
+ features: &["image_cube_array"],
+ ..Default::default()
+ },
+ });
}
- if !(usage.sampled
- || usage.storage
- || usage.color_attachment
- || usage.depth_stencil_attachment
- || usage.input_attachment
- || usage.transient_attachment)
+ // VUID-VkImageViewCreateInfo-subresourceRange-01718
+ if subresource_range.mip_levels.end > image_inner.mip_levels() {
+ return Err(ImageViewCreationError::MipLevelsOutOfRange {
+ range_end: subresource_range.mip_levels.end,
+ max: image_inner.mip_levels(),
+ });
+ }
+
+ if image_type == ImageType::Dim3d
+ && (view_type == ImageViewType::Dim2d || view_type == ImageViewType::Dim2dArray)
{
- return Err(ImageViewCreationError::InvalidImageUsage);
+ // VUID-VkImageViewCreateInfo-image-01005
+ if !image_inner
+ .flags()
+ .intersects(ImageCreateFlags::ARRAY_2D_COMPATIBLE)
+ {
+ return Err(ImageViewCreationError::ImageNotArray2dCompatible);
+ }
+
+ // VUID-VkImageViewCreateInfo-image-04970
+ if level_count != 1 {
+ return Err(ImageViewCreationError::Array2dCompatibleMultipleMipLevels);
+ }
+
+ // VUID-VkImageViewCreateInfo-image-02724
+ // VUID-VkImageViewCreateInfo-subresourceRange-02725
+ // We're using the depth dimension as array layers, but because of mip scaling, the
+ // depth, and therefore number of layers available, shrinks as the mip level gets
+ // higher.
+ let max = image_inner
+ .dimensions()
+ .mip_level_dimensions(subresource_range.mip_levels.start)
+ .unwrap()
+ .depth();
+ if subresource_range.array_layers.end > max {
+ return Err(ImageViewCreationError::ArrayLayersOutOfRange {
+ range_end: subresource_range.array_layers.end,
+ max,
+ });
+ }
+ } else {
+ // VUID-VkImageViewCreateInfo-image-01482
+ // VUID-VkImageViewCreateInfo-subresourceRange-01483
+ if subresource_range.array_layers.end > image_inner.dimensions().array_layers() {
+ return Err(ImageViewCreationError::ArrayLayersOutOfRange {
+ range_end: subresource_range.array_layers.end,
+ max: image_inner.dimensions().array_layers(),
+ });
+ }
}
- // Check for compatibility with the image
- match (
- self.ty,
- self.image.dimensions(),
- self.array_layers.end - self.array_layers.start,
- self.mipmap_levels.end - self.mipmap_levels.start,
- ) {
- (ImageViewType::Dim1d, ImageDimensions::Dim1d { .. }, 1, _) => (),
- (ImageViewType::Dim1dArray, ImageDimensions::Dim1d { .. }, _, _) => (),
- (ImageViewType::Dim2d, ImageDimensions::Dim2d { .. }, 1, _) => (),
- (ImageViewType::Dim2dArray, ImageDimensions::Dim2d { .. }, _, _) => (),
- (ImageViewType::Cubemap, ImageDimensions::Dim2d { .. }, 6, _)
- if flags.cube_compatible =>
+ // VUID-VkImageViewCreateInfo-image-04972
+ if image_inner.samples() != SampleCount::Sample1
+ && !(view_type == ImageViewType::Dim2d || view_type == ImageViewType::Dim2dArray)
+ {
+ return Err(ImageViewCreationError::MultisamplingNot2d);
+ }
+
+ /* Check usage requirements */
+
+ if has_non_default_usage {
+ if !(device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_maintenance2)
{
- ()
+ return Err(ImageViewCreationError::RequirementNotMet {
+ required_for: "`create_info.usage` is not the default value",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_1),
+ device_extensions: &["khr_maintenance2"],
+ ..Default::default()
+ },
+ });
}
- (ImageViewType::CubemapArray, ImageDimensions::Dim2d { .. }, n, _)
- if flags.cube_compatible && n % 6 == 0 =>
+
+ // VUID-VkImageViewUsageCreateInfo-usage-parameter
+ usage.validate_device(device)?;
+
+ // VUID-VkImageViewUsageCreateInfo-usage-requiredbitmask
+ assert!(!usage.is_empty());
+
+ // VUID-VkImageViewCreateInfo-pNext-02662
+ // VUID-VkImageViewCreateInfo-pNext-02663
+ // VUID-VkImageViewCreateInfo-pNext-02664
+ if !default_usage.contains(usage) {
+ return Err(ImageViewCreationError::UsageNotSupportedByImage {
+ usage,
+ supported_usage: default_usage,
+ });
+ }
+ }
+
+ // VUID-VkImageViewCreateInfo-image-04441
+ if !image_inner.usage().intersects(
+ ImageUsage::SAMPLED
+ | ImageUsage::STORAGE
+ | ImageUsage::COLOR_ATTACHMENT
+ | ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ | ImageUsage::INPUT_ATTACHMENT
+ | ImageUsage::TRANSIENT_ATTACHMENT,
+ ) {
+ return Err(ImageViewCreationError::ImageMissingUsage);
+ }
+
+ // VUID-VkImageViewCreateInfo-usage-02274
+ if usage.intersects(ImageUsage::SAMPLED)
+ && !format_features.intersects(FormatFeatures::SAMPLED_IMAGE)
+ {
+ return Err(ImageViewCreationError::FormatUsageNotSupported { usage: "sampled" });
+ }
+
+ // VUID-VkImageViewCreateInfo-usage-02275
+ if usage.intersects(ImageUsage::STORAGE)
+ && !format_features.intersects(FormatFeatures::STORAGE_IMAGE)
+ {
+ return Err(ImageViewCreationError::FormatUsageNotSupported { usage: "storage" });
+ }
+
+ // VUID-VkImageViewCreateInfo-usage-02276
+ if usage.intersects(ImageUsage::COLOR_ATTACHMENT)
+ && !format_features.intersects(FormatFeatures::COLOR_ATTACHMENT)
+ {
+ return Err(ImageViewCreationError::FormatUsageNotSupported {
+ usage: "color_attachment",
+ });
+ }
+
+ // VUID-VkImageViewCreateInfo-usage-02277
+ if usage.intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT)
+ && !format_features.intersects(FormatFeatures::DEPTH_STENCIL_ATTACHMENT)
+ {
+ return Err(ImageViewCreationError::FormatUsageNotSupported {
+ usage: "depth_stencil_attachment",
+ });
+ }
+
+ // VUID-VkImageViewCreateInfo-usage-02652
+ if usage.intersects(ImageUsage::INPUT_ATTACHMENT)
+ && !format_features.intersects(
+ FormatFeatures::COLOR_ATTACHMENT | FormatFeatures::DEPTH_STENCIL_ATTACHMENT,
+ )
+ {
+ return Err(ImageViewCreationError::FormatUsageNotSupported {
+ usage: "input_attachment",
+ });
+ }
+
+ /* Check flags requirements */
+
+ if Some(format) != image_inner.format() {
+ // VUID-VkImageViewCreateInfo-image-01762
+ if !image_inner
+ .flags()
+ .intersects(ImageCreateFlags::MUTABLE_FORMAT)
+ || !image_inner.format().unwrap().planes().is_empty()
+ && subresource_range.aspects.intersects(ImageAspects::COLOR)
{
- ()
+ return Err(ImageViewCreationError::FormatNotCompatible);
}
- (ImageViewType::Dim3d, ImageDimensions::Dim3d { .. }, 1, _) => (),
- (ImageViewType::Dim2d, ImageDimensions::Dim3d { .. }, 1, 1)
- if flags.array_2d_compatible =>
+
+ // VUID-VkImageViewCreateInfo-imageViewFormatReinterpretation-04466
+ // TODO: it is unclear what the number of bits is for compressed formats.
+ // See https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/2361
+ if device.enabled_extensions().khr_portability_subset
+ && !device.enabled_features().image_view_format_reinterpretation
+ && format.components() != image_inner.format().unwrap().components()
{
- ()
+ return Err(ImageViewCreationError::RequirementNotMet {
+ required_for: "this device is a portability subset device, and the format of \
+ the image view does not have the same components and number of bits per \
+ component as the parent image",
+ requires_one_of: RequiresOneOf {
+ features: &["image_view_format_reinterpretation"],
+ ..Default::default()
+ },
+ });
}
- (ImageViewType::Dim2dArray, ImageDimensions::Dim3d { .. }, _, 1)
- if flags.array_2d_compatible =>
+
+ if image_inner
+ .flags()
+ .intersects(ImageCreateFlags::BLOCK_TEXEL_VIEW_COMPATIBLE)
{
- ()
+ // VUID-VkImageViewCreateInfo-image-01583
+ if !(format.compatibility() == image_inner.format().unwrap().compatibility()
+ || format.block_size() == image_inner.format().unwrap().block_size())
+ {
+ return Err(ImageViewCreationError::FormatNotCompatible);
+ }
+
+ if format.compression().is_none() {
+ // VUID-VkImageViewCreateInfo-image-01584
+ if layer_count != 1 {
+ return Err(
+ ImageViewCreationError::BlockTexelViewCompatibleMultipleArrayLayers,
+ );
+ }
+
+ // VUID-VkImageViewCreateInfo-image-01584
+ if level_count != 1 {
+ return Err(
+ ImageViewCreationError::BlockTexelViewCompatibleMultipleMipLevels,
+ );
+ }
+ }
+ } else {
+ if image_inner.format().unwrap().planes().is_empty() {
+ // VUID-VkImageViewCreateInfo-image-01761
+ if format.compatibility() != image_inner.format().unwrap().compatibility() {
+ return Err(ImageViewCreationError::FormatNotCompatible);
+ }
+ } else {
+ let plane = if subresource_range.aspects.intersects(ImageAspects::PLANE_0) {
+ 0
+ } else if subresource_range.aspects.intersects(ImageAspects::PLANE_1) {
+ 1
+ } else if subresource_range.aspects.intersects(ImageAspects::PLANE_2) {
+ 2
+ } else {
+ unreachable!()
+ };
+ let plane_format = image_inner.format().unwrap().planes()[plane];
+
+ // VUID-VkImageViewCreateInfo-image-01586
+ if format.compatibility() != plane_format.compatibility() {
+ return Err(ImageViewCreationError::FormatNotCompatible);
+ }
+ }
}
- _ => return Err(ImageViewCreationError::IncompatibleType),
}
- let inner = unsafe {
- UnsafeImageView::new(
- image_inner,
- self.ty,
- self.component_mapping,
- self.mipmap_levels,
- self.array_layers.clone(),
- )?
- };
-
- Ok(Arc::new(ImageView {
- image: self.image,
- inner,
- format,
-
- ty: self.ty,
- component_mapping: self.component_mapping,
- array_layers: self.array_layers,
- }))
- }
-}
+ // VUID-VkImageViewCreateInfo-imageViewType-04973
+ if (view_type == ImageViewType::Dim1d
+ || view_type == ImageViewType::Dim2d
+ || view_type == ImageViewType::Dim3d)
+ && layer_count != 1
+ {
+ return Err(ImageViewCreationError::TypeNonArrayedMultipleArrayLayers);
+ }
+ // VUID-VkImageViewCreateInfo-viewType-02960
+ else if view_type == ImageViewType::Cube && layer_count != 6 {
+ return Err(ImageViewCreationError::TypeCubeNot6ArrayLayers);
+ }
+ // VUID-VkImageViewCreateInfo-viewType-02961
+ else if view_type == ImageViewType::CubeArray && layer_count % 6 != 0 {
+ return Err(ImageViewCreationError::TypeCubeArrayNotMultipleOf6ArrayLayers);
+ }
-/// Error that can happen when creating an image view.
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum ImageViewCreationError {
- /// Allocating memory failed.
- AllocError(DeviceMemoryAllocError),
- /// The specified range of array layers was out of range for the image.
- ArrayLayersOutOfRange,
- /// The specified range of mipmap levels was out of range for the image.
- MipMapLevelsOutOfRange,
- /// The requested [`ImageViewType`] was not compatible with the image, or with the specified ranges of array layers and mipmap levels.
- IncompatibleType,
- /// The image was not created with
- /// [one of the required usages](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#valid-imageview-imageusage)
- /// for image views.
- InvalidImageUsage,
-}
+ // VUID-VkImageViewCreateInfo-imageViewFormatSwizzle-04465
+ if device.enabled_extensions().khr_portability_subset
+ && !device.enabled_features().image_view_format_swizzle
+ && !component_mapping.is_identity()
+ {
+ return Err(ImageViewCreationError::RequirementNotMet {
+ required_for: "this device is a portability subset device, and \
+ `create_info.component_mapping` is not the identity mapping",
+ requires_one_of: RequiresOneOf {
+ features: &["image_view_format_swizzle"],
+ ..Default::default()
+ },
+ });
+ }
-impl error::Error for ImageViewCreationError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- ImageViewCreationError::AllocError(ref err) => Some(err),
- _ => None,
+ // VUID-VkImageViewCreateInfo-format-04714
+ // VUID-VkImageViewCreateInfo-format-04715
+ match format.ycbcr_chroma_sampling() {
+ Some(ChromaSampling::Mode422) => {
+ if image_inner.dimensions().width() % 2 != 0 {
+ return Err(
+ ImageViewCreationError::FormatChromaSubsamplingInvalidImageDimensions,
+ );
+ }
+ }
+ Some(ChromaSampling::Mode420) => {
+ if image_inner.dimensions().width() % 2 != 0
+ || image_inner.dimensions().height() % 2 != 0
+ {
+ return Err(
+ ImageViewCreationError::FormatChromaSubsamplingInvalidImageDimensions,
+ );
+ }
+ }
+ _ => (),
}
- }
-}
-impl fmt::Display for ImageViewCreationError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- ImageViewCreationError::AllocError(err) => "allocating memory failed",
- ImageViewCreationError::ArrayLayersOutOfRange => "array layers are out of range",
- ImageViewCreationError::MipMapLevelsOutOfRange => "mipmap levels are out of range",
- ImageViewCreationError::IncompatibleType =>
- "image view type is not compatible with image, array layers or mipmap levels",
- ImageViewCreationError::InvalidImageUsage =>
- "the usage of the image is not compatible with image views",
+ // Don't need to check features because you can't create a conversion object without the
+ // feature anyway.
+ if let Some(conversion) = &sampler_ycbcr_conversion {
+ assert_eq!(device, conversion.device());
+
+ // VUID-VkImageViewCreateInfo-pNext-01970
+ if !component_mapping.is_identity() {
+ return Err(
+ ImageViewCreationError::SamplerYcbcrConversionComponentMappingNotIdentity {
+ component_mapping,
+ },
+ );
+ }
+ } else {
+ // VUID-VkImageViewCreateInfo-format-06415
+ if format.ycbcr_chroma_sampling().is_some() {
+ return Err(
+ ImageViewCreationError::FormatRequiresSamplerYcbcrConversion { format },
+ );
}
- )
+ }
+
+ Ok(format_features)
}
-}
-impl From<OomError> for ImageViewCreationError {
- #[inline]
- fn from(err: OomError) -> ImageViewCreationError {
- ImageViewCreationError::AllocError(DeviceMemoryAllocError::OomError(err))
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn new_unchecked(
+ image: Arc<I>,
+ create_info: ImageViewCreateInfo,
+ ) -> Result<Arc<Self>, VulkanError> {
+ let format_features =
+ Self::get_format_features(create_info.format.unwrap(), image.inner().image);
+ Self::new_unchecked_with_format_features(image, create_info, format_features)
}
-}
-/// A low-level wrapper around a `vkImageView`.
-pub struct UnsafeImageView {
- view: ash::vk::ImageView,
- device: Arc<Device>,
-}
+ unsafe fn new_unchecked_with_format_features(
+ image: Arc<I>,
+ create_info: ImageViewCreateInfo,
+ format_features: FormatFeatures,
+ ) -> Result<Arc<Self>, VulkanError> {
+ let &ImageViewCreateInfo {
+ view_type,
+ format,
+ component_mapping,
+ ref subresource_range,
+ mut usage,
+ ref sampler_ycbcr_conversion,
+ _ne: _,
+ } = &create_info;
+
+ let image_inner = image.inner().image;
+ let device = image_inner.device();
+
+ let default_usage = Self::get_default_usage(subresource_range.aspects, image_inner);
+
+ let has_non_default_usage = if usage.is_empty() {
+ usage = default_usage;
+ false
+ } else {
+ usage == default_usage
+ };
-impl UnsafeImageView {
- /// Creates a new view from an image.
- ///
- /// # Safety
- /// - The returned `UnsafeImageView` must not outlive `image`.
- /// - `image` must have a usage that is compatible with image views.
- /// - `ty` must be compatible with the dimensions and flags of the image.
- /// - `mipmap_levels` must not be empty, must be within the range of levels of the image, and be compatible with the requested `ty`.
- /// - `array_layers` must not be empty, must be within the range of layers of the image, and be compatible with the requested `ty`.
- ///
- /// # Panics
- /// Panics if the image is a YcbCr image, since the Vulkano API is not yet flexible enough to
- /// specify the aspect of image.
- pub unsafe fn new(
- image: &UnsafeImage,
- ty: ImageViewType,
- component_mapping: ComponentMapping,
- mipmap_levels: Range<u32>,
- array_layers: Range<u32>,
- ) -> Result<UnsafeImageView, OomError> {
- let fns = image.device().fns();
-
- debug_assert!(mipmap_levels.end > mipmap_levels.start);
- debug_assert!(mipmap_levels.end <= image.mipmap_levels());
- debug_assert!(array_layers.end > array_layers.start);
- debug_assert!(array_layers.end <= image.dimensions().array_layers());
-
- if image.format().ty() == FormatTy::Ycbcr {
- unimplemented!();
- }
-
- // TODO: Let user choose
- let aspects = image.format().aspects();
-
- let view = {
- let infos = ash::vk::ImageViewCreateInfo {
- flags: ash::vk::ImageViewCreateFlags::empty(),
- image: image.internal_object(),
- view_type: ty.into(),
- format: image.format().into(),
- components: component_mapping.into(),
- subresource_range: ash::vk::ImageSubresourceRange {
- aspect_mask: aspects.into(),
- base_mip_level: mipmap_levels.start,
- level_count: mipmap_levels.end - mipmap_levels.start,
- base_array_layer: array_layers.start,
- layer_count: array_layers.end - array_layers.start,
- },
+ let mut info_vk = ash::vk::ImageViewCreateInfo {
+ flags: ash::vk::ImageViewCreateFlags::empty(),
+ image: image_inner.handle(),
+ view_type: view_type.into(),
+ format: format.unwrap().into(),
+ components: component_mapping.into(),
+ subresource_range: subresource_range.clone().into(),
+ ..Default::default()
+ };
+ let mut image_view_usage_info_vk = None;
+ let mut sampler_ycbcr_conversion_info_vk = None;
+
+ if has_non_default_usage {
+ let next = image_view_usage_info_vk.insert(ash::vk::ImageViewUsageCreateInfo {
+ usage: usage.into(),
..Default::default()
- };
+ });
+
+ next.p_next = info_vk.p_next;
+ info_vk.p_next = next as *const _ as *const _;
+ }
+
+ if let Some(conversion) = sampler_ycbcr_conversion {
+ let next =
+ sampler_ycbcr_conversion_info_vk.insert(ash::vk::SamplerYcbcrConversionInfo {
+ conversion: conversion.handle(),
+ ..Default::default()
+ });
+ next.p_next = info_vk.p_next;
+ info_vk.p_next = next as *const _ as *const _;
+ }
+
+ let handle = {
+ let fns = device.fns();
let mut output = MaybeUninit::uninit();
- check_errors(fns.v1_0.create_image_view(
- image.device().internal_object(),
- &infos,
+ (fns.v1_0.create_image_view)(
+ device.handle(),
+ &info_vk,
ptr::null(),
output.as_mut_ptr(),
- ))?;
+ )
+ .result()
+ .map_err(VulkanError::from)?;
output.assume_init()
};
- Ok(UnsafeImageView {
- view,
- device: image.device().clone(),
- })
+ Self::from_handle_with_format_features(image, handle, create_info, format_features)
}
-}
-unsafe impl VulkanObject for UnsafeImageView {
- type Object = ash::vk::ImageView;
+ /// Creates a default `ImageView`. Equivalent to
+ /// `ImageView::new(image, ImageViewCreateInfo::from_image(image))`.
+ pub fn new_default(image: Arc<I>) -> Result<Arc<ImageView<I>>, ImageViewCreationError> {
+ let create_info = ImageViewCreateInfo::from_image(&image);
+ Self::new(image, create_info)
+ }
- #[inline]
- fn internal_object(&self) -> ash::vk::ImageView {
- self.view
+ /// Creates a new `ImageView` from a raw object handle.
+ ///
+ /// # Safety
+ ///
+ /// - `handle` must be a valid Vulkan object handle created from `image`.
+ /// - `create_info` must match the info used to create the object.
+ pub unsafe fn from_handle(
+ image: Arc<I>,
+ handle: ash::vk::ImageView,
+ create_info: ImageViewCreateInfo,
+ ) -> Result<Arc<Self>, VulkanError> {
+ let format_features =
+ Self::get_format_features(create_info.format.unwrap(), image.inner().image);
+ Self::from_handle_with_format_features(image, handle, create_info, format_features)
}
-}
-impl fmt::Debug for UnsafeImageView {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(fmt, "<Vulkan image view {:?}>", self.view)
+ unsafe fn from_handle_with_format_features(
+ image: Arc<I>,
+ handle: ash::vk::ImageView,
+ create_info: ImageViewCreateInfo,
+ format_features: FormatFeatures,
+ ) -> Result<Arc<Self>, VulkanError> {
+ let ImageViewCreateInfo {
+ view_type,
+ format,
+ component_mapping,
+ subresource_range,
+ mut usage,
+ sampler_ycbcr_conversion,
+ _ne: _,
+ } = create_info;
+
+ let image_inner = image.inner().image;
+ let device = image_inner.device();
+
+ if usage.is_empty() {
+ usage = Self::get_default_usage(subresource_range.aspects, image_inner);
+ }
+
+ let mut filter_cubic = false;
+ let mut filter_cubic_minmax = false;
+
+ if device
+ .physical_device()
+ .supported_extensions()
+ .ext_filter_cubic
+ {
+ // Use unchecked, because all validation has been done above or is validated by the
+ // image.
+ let properties =
+ device
+ .physical_device()
+ .image_format_properties_unchecked(ImageFormatInfo {
+ flags: image_inner.flags(),
+ format: image_inner.format(),
+ image_type: image.dimensions().image_type(),
+ tiling: image_inner.tiling(),
+ usage: image_inner.usage(),
+ image_view_type: Some(view_type),
+ ..Default::default()
+ })?;
+
+ if let Some(properties) = properties {
+ filter_cubic = properties.filter_cubic;
+ filter_cubic_minmax = properties.filter_cubic_minmax;
+ }
+ }
+
+ Ok(Arc::new(ImageView {
+ handle,
+ image,
+ id: Self::next_id(),
+ view_type,
+ format,
+ format_features,
+ component_mapping,
+ subresource_range,
+ usage,
+ sampler_ycbcr_conversion,
+ filter_cubic,
+ filter_cubic_minmax,
+ }))
+ }
+
+ // https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkImageViewCreateInfo.html#_description
+ fn get_default_usage(aspects: ImageAspects, image: &Image) -> ImageUsage {
+ let has_stencil_aspect = aspects.intersects(ImageAspects::STENCIL);
+ let has_non_stencil_aspect = !(aspects - ImageAspects::STENCIL).is_empty();
+
+ if has_stencil_aspect && has_non_stencil_aspect {
+ image.usage() & image.stencil_usage()
+ } else if has_stencil_aspect {
+ image.stencil_usage()
+ } else if has_non_stencil_aspect {
+ image.usage()
+ } else {
+ unreachable!()
+ }
+ }
+
+ // https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/chap12.html#resources-image-view-format-features
+ unsafe fn get_format_features(format: Format, image: &Image) -> FormatFeatures {
+ let device = image.device();
+
+ let mut format_features = if Some(format) != image.format() {
+ // Use unchecked, because all validation should have been done before calling.
+ let format_properties = device.physical_device().format_properties_unchecked(format);
+
+ match image.tiling() {
+ ImageTiling::Optimal => format_properties.optimal_tiling_features,
+ ImageTiling::Linear => format_properties.linear_tiling_features,
+ ImageTiling::DrmFormatModifier => format_properties.linear_tiling_features,
+ }
+ } else {
+ image.format_features()
+ };
+
+ if !device.enabled_extensions().khr_format_feature_flags2 {
+ if format.type_color().is_none()
+ && format_features.intersects(FormatFeatures::SAMPLED_IMAGE)
+ {
+ format_features |= FormatFeatures::SAMPLED_IMAGE_DEPTH_COMPARISON;
+ }
+
+ if format.shader_storage_image_without_format() {
+ if device
+ .enabled_features()
+ .shader_storage_image_read_without_format
+ {
+ format_features |= FormatFeatures::STORAGE_READ_WITHOUT_FORMAT;
+ }
+
+ if device
+ .enabled_features()
+ .shader_storage_image_write_without_format
+ {
+ format_features |= FormatFeatures::STORAGE_WRITE_WITHOUT_FORMAT;
+ }
+ }
+ }
+
+ format_features
+ }
+
+ /// Returns the wrapped image that this image view was created from.
+ pub fn image(&self) -> &Arc<I> {
+ &self.image
}
}
-impl Drop for UnsafeImageView {
- #[inline]
+impl<I> Drop for ImageView<I>
+where
+ I: ImageAccess + ?Sized,
+{
fn drop(&mut self) {
unsafe {
- let fns = self.device.fns();
- fns.v1_0
- .destroy_image_view(self.device.internal_object(), self.view, ptr::null());
+ let device = self.device();
+ let fns = device.fns();
+ (fns.v1_0.destroy_image_view)(device.handle(), self.handle, ptr::null());
}
}
}
-impl PartialEq for UnsafeImageView {
- #[inline]
- fn eq(&self, other: &Self) -> bool {
- self.view == other.view && self.device == other.device
+unsafe impl<I> VulkanObject for ImageView<I>
+where
+ I: ImageAccess + ?Sized,
+{
+ type Handle = ash::vk::ImageView;
+
+ fn handle(&self) -> Self::Handle {
+ self.handle
}
}
-impl Eq for UnsafeImageView {}
-
-impl Hash for UnsafeImageView {
- #[inline]
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.view.hash(state);
- self.device.hash(state);
+unsafe impl<I> DeviceOwned for ImageView<I>
+where
+ I: ImageAccess + ?Sized,
+{
+ fn device(&self) -> &Arc<Device> {
+ self.image.inner().image.device()
}
}
-/// The geometry type of an image view.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-#[repr(i32)]
-pub enum ImageViewType {
- Dim1d = ash::vk::ImageViewType::TYPE_1D.as_raw(),
- Dim1dArray = ash::vk::ImageViewType::TYPE_1D_ARRAY.as_raw(),
- Dim2d = ash::vk::ImageViewType::TYPE_2D.as_raw(),
- Dim2dArray = ash::vk::ImageViewType::TYPE_2D_ARRAY.as_raw(),
- Dim3d = ash::vk::ImageViewType::TYPE_3D.as_raw(),
- Cubemap = ash::vk::ImageViewType::CUBE.as_raw(),
- CubemapArray = ash::vk::ImageViewType::CUBE_ARRAY.as_raw(),
+impl_id_counter!(ImageView<I: ImageAccess + ?Sized>);
+
+/// Parameters to create a new `ImageView`.
+#[derive(Debug)]
+pub struct ImageViewCreateInfo {
+ /// The image view type.
+ ///
+ /// The view type must be compatible with the dimensions of the image and the selected array
+ /// layers.
+ ///
+ /// The default value is [`ImageViewType::Dim2d`].
+ pub view_type: ImageViewType,
+
+ /// The format of the image view.
+ ///
+ /// If this is set to a format that is different from the image, the image must be created with
+ /// the `mutable_format` flag.
+ ///
+ /// On [portability subset](crate::instance#portability-subset-devices-and-the-enumerate_portability-flag)
+ /// devices, if `format` does not have the same number of components and bits per component as
+ /// the parent image's format, the
+ /// [`image_view_format_reinterpretation`](crate::device::Features::image_view_format_reinterpretation)
+ /// feature must be enabled on the device.
+ ///
+ /// The default value is `None`, which must be overridden.
+ pub format: Option<Format>,
+
+ /// How to map components of each pixel.
+ ///
+ /// On [portability subset](crate::instance#portability-subset-devices-and-the-enumerate_portability-flag)
+ /// devices, if `component_mapping` is not the identity mapping, the
+ /// [`image_view_format_swizzle`](crate::device::Features::image_view_format_swizzle)
+ /// feature must be enabled on the device.
+ ///
+ /// The default value is [`ComponentMapping::identity()`].
+ pub component_mapping: ComponentMapping,
+
+ /// The subresource range of the image that the view should cover.
+ ///
+ /// The default value is empty, which must be overridden.
+ pub subresource_range: ImageSubresourceRange,
+
+ /// How the image view is going to be used.
+ ///
+ /// If `usage` is empty, then a default value is used based on the parent image's usages.
+ /// Depending on the image aspects selected in `subresource_range`,
+ /// the default `usage` will be equal to the parent image's `usage`, its `stencil_usage`,
+ /// or the intersection of the two.
+ ///
+ /// If you set `usage` to a different value from the default, then the device API version must
+ /// be at least 1.1, or the [`khr_maintenance2`](crate::device::DeviceExtensions::khr_maintenance2)
+ /// extension must be enabled on the device. The specified `usage` must be a subset of the
+ /// default value; usages that are not set for the parent image are not allowed.
+ ///
+ /// The default value is [`ImageUsage::empty()`].
+ pub usage: ImageUsage,
+
+ /// The sampler YCbCr conversion to be used with the image view.
+ ///
+ /// If set to `Some`, several restrictions apply:
+ /// - The `component_mapping` must be the identity swizzle for all components.
+ /// - If the image view is to be used in a shader, it must be in a combined image sampler
+ /// descriptor, a separate sampled image descriptor is not allowed.
+ /// - The corresponding sampler must have the same sampler YCbCr object or an identically
+ /// created one, and must be used as an immutable sampler within a descriptor set layout.
+ ///
+ /// The default value is `None`.
+ pub sampler_ycbcr_conversion: Option<Arc<SamplerYcbcrConversion>>,
+
+ pub _ne: crate::NonExhaustive,
}
-impl From<ImageViewType> for ash::vk::ImageViewType {
- fn from(val: ImageViewType) -> Self {
- Self::from_raw(val as i32)
+impl Default for ImageViewCreateInfo {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ view_type: ImageViewType::Dim2d,
+ format: None,
+ component_mapping: ComponentMapping::identity(),
+ subresource_range: ImageSubresourceRange {
+ aspects: ImageAspects::empty(),
+ array_layers: 0..0,
+ mip_levels: 0..0,
+ },
+ usage: ImageUsage::empty(),
+ sampler_ycbcr_conversion: None,
+ _ne: crate::NonExhaustive(()),
+ }
}
}
-/// Specifies how the components of an image must be mapped.
-///
-/// When creating an image view, it is possible to ask the implementation to modify the value
-/// returned when accessing a given component from within a shader.
-#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
-pub struct ComponentMapping {
- /// First component.
- pub r: ComponentSwizzle,
- /// Second component.
- pub g: ComponentSwizzle,
- /// Third component.
- pub b: ComponentSwizzle,
- /// Fourth component.
- pub a: ComponentSwizzle,
+impl ImageViewCreateInfo {
+ /// Returns an `ImageViewCreateInfo` with the `view_type` determined from the image type and
+ /// array layers, and `subresource_range` determined from the image format and covering the
+ /// whole image.
+ pub fn from_image(image: &(impl ImageAccess + ?Sized)) -> Self {
+ Self {
+ view_type: match image.dimensions() {
+ ImageDimensions::Dim1d {
+ array_layers: 1, ..
+ } => ImageViewType::Dim1d,
+ ImageDimensions::Dim1d { .. } => ImageViewType::Dim1dArray,
+ ImageDimensions::Dim2d {
+ array_layers: 1, ..
+ } => ImageViewType::Dim2d,
+ ImageDimensions::Dim2d { .. } => ImageViewType::Dim2dArray,
+ ImageDimensions::Dim3d { .. } => ImageViewType::Dim3d,
+ },
+ format: Some(image.format()),
+ subresource_range: image.subresource_range(),
+ ..Default::default()
+ }
+ }
}
-impl ComponentMapping {
- /// Returns `true` if the component mapping is identity swizzled,
- /// meaning that all the members are `Identity`.
- ///
- /// Certain operations require views that are identity swizzled, and will return an error
- /// otherwise. For example, attaching a view to a framebuffer is only possible if the view is
- /// identity swizzled.
- #[inline]
- pub fn is_identity(&self) -> bool {
- self.r == ComponentSwizzle::Identity
- && self.g == ComponentSwizzle::Identity
- && self.b == ComponentSwizzle::Identity
- && self.a == ComponentSwizzle::Identity
+/// Error that can happen when creating an image view.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum ImageViewCreationError {
+ /// Allocating memory failed.
+ OomError(OomError),
+
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+
+ /// A 2D image view was requested from a 3D image, but a range of multiple mip levels was
+ /// specified.
+ Array2dCompatibleMultipleMipLevels,
+
+ /// The specified range of array layers was not a subset of those in the image.
+ ArrayLayersOutOfRange { range_end: u32, max: u32 },
+
+ /// The image has the `block_texel_view_compatible` flag, but a range of multiple array layers
+ /// was specified.
+ BlockTexelViewCompatibleMultipleArrayLayers,
+
+ /// The image has the `block_texel_view_compatible` flag, but a range of multiple mip levels
+ /// was specified.
+ BlockTexelViewCompatibleMultipleMipLevels,
+
+ /// The requested format has chroma subsampling, but the width and/or height of the image was
+ /// not a multiple of 2.
+ FormatChromaSubsamplingInvalidImageDimensions,
+
+ /// The requested format was not compatible with the image.
+ FormatNotCompatible,
+
+ /// The given format was not supported by the device.
+ FormatNotSupported,
+
+ /// The format requires a sampler YCbCr conversion, but none was provided.
+ FormatRequiresSamplerYcbcrConversion { format: Format },
+
+ /// A requested usage flag was not supported by the given format.
+ FormatUsageNotSupported { usage: &'static str },
+
+ /// An aspect was selected that was not present in the image.
+ ImageAspectsNotCompatible {
+ aspects: ImageAspects,
+ image_aspects: ImageAspects,
+ },
+
+ /// The image was not created with
+ /// [one of the required usages](https://registry.khronos.org/vulkan/specs/1.2-extensions/html/vkspec.html#valid-imageview-imageusage)
+ /// for image views.
+ ImageMissingUsage,
+
+ /// A 2D image view was requested from a 3D image, but the image was not created with the
+ /// `array_2d_compatible` flag.
+ ImageNotArray2dCompatible,
+
+ /// A cube image view type was requested, but the image was not created with the
+ /// `cube_compatible` flag.
+ ImageNotCubeCompatible,
+
+ /// The given image view type was not compatible with the type of the image.
+ ImageTypeNotCompatible,
+
+ /// The requested [`ImageViewType`] was not compatible with the image, or with the specified
+ /// ranges of array layers and mipmap levels.
+ IncompatibleType,
+
+ /// The specified range of mip levels was not a subset of those in the image.
+ MipLevelsOutOfRange { range_end: u32, max: u32 },
+
+ /// The image has multisampling enabled, but the image view type was not `Dim2d` or
+ /// `Dim2dArray`.
+ MultisamplingNot2d,
+
+ /// Sampler YCbCr conversion was enabled, but `component_mapping` was not the identity mapping.
+ SamplerYcbcrConversionComponentMappingNotIdentity { component_mapping: ComponentMapping },
+
+ /// The `CubeArray` image view type was specified, but the range of array layers did not have a
+ /// size that is a multiple 6.
+ TypeCubeArrayNotMultipleOf6ArrayLayers,
+
+ /// The `Cube` image view type was specified, but the range of array layers did not have a size
+ /// of 6.
+ TypeCubeNot6ArrayLayers,
+
+ /// A non-arrayed image view type was specified, but a range of multiple array layers was
+ /// specified.
+ TypeNonArrayedMultipleArrayLayers,
+
+ /// The provided `usage` is not supported by the parent image.
+ UsageNotSupportedByImage {
+ usage: ImageUsage,
+ supported_usage: ImageUsage,
+ },
+}
+
+impl Error for ImageViewCreationError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ ImageViewCreationError::OomError(err) => Some(err),
+ _ => None,
+ }
}
}
-impl From<ComponentMapping> for ash::vk::ComponentMapping {
- #[inline]
- fn from(value: ComponentMapping) -> Self {
- Self {
- r: value.r.into(),
- g: value.g.into(),
- b: value.b.into(),
- a: value.a.into(),
+impl Display for ImageViewCreationError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::OomError(_) => write!(f, "allocating memory failed",),
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ Self::Array2dCompatibleMultipleMipLevels => write!(
+ f,
+ "a 2D image view was requested from a 3D image, but a range of multiple mip levels \
+ was specified",
+ ),
+ Self::ArrayLayersOutOfRange { .. } => write!(
+ f,
+ "the specified range of array layers was not a subset of those in the image",
+ ),
+ Self::BlockTexelViewCompatibleMultipleArrayLayers => write!(
+ f,
+ "the image has the `block_texel_view_compatible` flag, but a range of multiple \
+ array layers was specified",
+ ),
+ Self::BlockTexelViewCompatibleMultipleMipLevels => write!(
+ f,
+ "the image has the `block_texel_view_compatible` flag, but a range of multiple mip \
+ levels was specified",
+ ),
+ Self::FormatChromaSubsamplingInvalidImageDimensions => write!(
+ f,
+ "the requested format has chroma subsampling, but the width and/or height of the \
+ image was not a multiple of 2",
+ ),
+ Self::FormatNotCompatible => {
+ write!(f, "the requested format was not compatible with the image")
+ }
+ Self::FormatNotSupported => {
+ write!(f, "the given format was not supported by the device")
+ }
+ Self::FormatRequiresSamplerYcbcrConversion { .. } => write!(
+ f,
+ "the format requires a sampler YCbCr conversion, but none was provided",
+ ),
+ Self::FormatUsageNotSupported { .. } => write!(
+ f,
+ "a requested usage flag was not supported by the given format",
+ ),
+ Self::ImageAspectsNotCompatible { .. } => write!(
+ f,
+ "an aspect was selected that was not present in the image",
+ ),
+ Self::ImageMissingUsage => write!(
+ f,
+ "the image was not created with one of the required usages for image views",
+ ),
+ Self::ImageNotArray2dCompatible => write!(
+ f,
+ "a 2D image view was requested from a 3D image, but the image was not created with \
+ the `array_2d_compatible` flag",
+ ),
+ Self::ImageNotCubeCompatible => write!(
+ f,
+ "a cube image view type was requested, but the image was not created with the \
+ `cube_compatible` flag",
+ ),
+ Self::ImageTypeNotCompatible => write!(
+ f,
+ "the given image view type was not compatible with the type of the image",
+ ),
+ Self::IncompatibleType => write!(
+ f,
+ "image view type is not compatible with image, array layers or mipmap levels",
+ ),
+ Self::MipLevelsOutOfRange { .. } => write!(
+ f,
+ "the specified range of mip levels was not a subset of those in the image",
+ ),
+ Self::MultisamplingNot2d => write!(
+ f,
+ "the image has multisampling enabled, but the image view type was not `Dim2d` or \
+ `Dim2dArray`",
+ ),
+ Self::SamplerYcbcrConversionComponentMappingNotIdentity { .. } => write!(
+ f,
+ "sampler YCbCr conversion was enabled, but `component_mapping` was not the \
+ identity mapping",
+ ),
+ Self::TypeCubeArrayNotMultipleOf6ArrayLayers => write!(
+ f,
+ "the `CubeArray` image view type was specified, but the range of array layers did \
+ not have a size that is a multiple 6",
+ ),
+ Self::TypeCubeNot6ArrayLayers => write!(
+ f,
+ "the `Cube` image view type was specified, but the range of array layers did not \
+ have a size of 6",
+ ),
+ Self::TypeNonArrayedMultipleArrayLayers => write!(
+ f,
+ "a non-arrayed image view type was specified, but a range of multiple array layers \
+ was specified",
+ ),
+ Self::UsageNotSupportedByImage {
+ usage: _,
+ supported_usage: _,
+ } => write!(
+ f,
+ "the provided `usage` is not supported by the parent image",
+ ),
}
}
}
-/// Describes the value that an individual component must return when being accessed.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-#[repr(i32)]
-pub enum ComponentSwizzle {
- /// Returns the value that this component should normally have.
- ///
- /// This is the `Default` value.
- Identity = ash::vk::ComponentSwizzle::IDENTITY.as_raw(),
- /// Always return zero.
- Zero = ash::vk::ComponentSwizzle::ZERO.as_raw(),
- /// Always return one.
- One = ash::vk::ComponentSwizzle::ONE.as_raw(),
- /// Returns the value of the first component.
- Red = ash::vk::ComponentSwizzle::R.as_raw(),
- /// Returns the value of the second component.
- Green = ash::vk::ComponentSwizzle::G.as_raw(),
- /// Returns the value of the third component.
- Blue = ash::vk::ComponentSwizzle::B.as_raw(),
- /// Returns the value of the fourth component.
- Alpha = ash::vk::ComponentSwizzle::A.as_raw(),
+impl From<OomError> for ImageViewCreationError {
+ fn from(err: OomError) -> ImageViewCreationError {
+ ImageViewCreationError::OomError(err)
+ }
}
-impl From<ComponentSwizzle> for ash::vk::ComponentSwizzle {
- #[inline]
- fn from(val: ComponentSwizzle) -> Self {
- Self::from_raw(val as i32)
+impl From<VulkanError> for ImageViewCreationError {
+ fn from(err: VulkanError) -> ImageViewCreationError {
+ match err {
+ err @ VulkanError::OutOfHostMemory => OomError::from(err).into(),
+ err @ VulkanError::OutOfDeviceMemory => OomError::from(err).into(),
+ _ => panic!("unexpected error: {:?}", err),
+ }
}
}
-impl Default for ComponentSwizzle {
- #[inline]
- fn default() -> ComponentSwizzle {
- ComponentSwizzle::Identity
+impl From<RequirementNotMet> for ImageViewCreationError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
+ }
+ }
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// The geometry type of an image view.
+ ImageViewType impl {
+ /// Returns whether the type is arrayed.
+ #[inline]
+ pub fn is_arrayed(self) -> bool {
+ match self {
+ Self::Dim1d | Self::Dim2d | Self::Dim3d | Self::Cube => false,
+ Self::Dim1dArray | Self::Dim2dArray | Self::CubeArray => true,
+ }
+ }
+
+ /// Returns whether `self` is compatible with the given `image_type`.
+ #[inline]
+ pub fn is_compatible_with(self, image_type: ImageType) -> bool {
+ matches!(
+ (self, image_type,),
+ (
+ ImageViewType::Dim1d | ImageViewType::Dim1dArray,
+ ImageType::Dim1d
+ ) | (
+ ImageViewType::Dim2d | ImageViewType::Dim2dArray,
+ ImageType::Dim2d | ImageType::Dim3d
+ ) | (
+ ImageViewType::Cube | ImageViewType::CubeArray,
+ ImageType::Dim2d
+ ) | (ImageViewType::Dim3d, ImageType::Dim3d)
+ )
+ }
}
+ = ImageViewType(i32);
+
+ // TODO: document
+ Dim1d = TYPE_1D,
+
+ // TODO: document
+ Dim2d = TYPE_2D,
+
+ // TODO: document
+ Dim3d = TYPE_3D,
+
+ // TODO: document
+ Cube = CUBE,
+
+ // TODO: document
+ Dim1dArray = TYPE_1D_ARRAY,
+
+ // TODO: document
+ Dim2dArray = TYPE_2D_ARRAY,
+
+ // TODO: document
+ CubeArray = CUBE_ARRAY,
}
/// Trait for types that represent the GPU can access an image view.
-pub unsafe trait ImageViewAbstract {
+pub unsafe trait ImageViewAbstract:
+ VulkanObject<Handle = ash::vk::ImageView> + DeviceOwned + Debug + Send + Sync
+{
/// Returns the wrapped image that this image view was created from.
- fn image(&self) -> &dyn ImageAccess;
+ fn image(&self) -> Arc<dyn ImageAccess>;
+
+ /// Returns the component mapping of this view.
+ fn component_mapping(&self) -> ComponentMapping;
+
+ /// Returns the dimensions of this view.
+ #[inline]
+ fn dimensions(&self) -> ImageDimensions {
+ let subresource_range = self.subresource_range();
+ let array_layers =
+ subresource_range.array_layers.end - subresource_range.array_layers.start;
+
+ match self.image().dimensions() {
+ ImageDimensions::Dim1d { width, .. } => ImageDimensions::Dim1d {
+ width,
+ array_layers,
+ },
+ ImageDimensions::Dim2d { width, height, .. } => ImageDimensions::Dim2d {
+ width,
+ height,
+ array_layers,
+ },
+ ImageDimensions::Dim3d {
+ width,
+ height,
+ depth,
+ } => ImageDimensions::Dim3d {
+ width,
+ height,
+ depth,
+ },
+ }
+ }
- /// Returns the inner unsafe image view object used by this image view.
- fn inner(&self) -> &UnsafeImageView;
+ /// Returns whether the image view supports sampling with a
+ /// [`Cubic`](crate::sampler::Filter::Cubic) `mag_filter` or `min_filter`.
+ fn filter_cubic(&self) -> bool;
- /// Returns the range of array layers of the wrapped image that this view exposes.
- fn array_layers(&self) -> Range<u32>;
+ /// Returns whether the image view supports sampling with a
+ /// [`Cubic`](crate::sampler::Filter::Cubic) `mag_filter` or `min_filter`, and with a
+ /// [`Min`](crate::sampler::SamplerReductionMode::Min) or
+ /// [`Max`](crate::sampler::SamplerReductionMode::Max) `reduction_mode`.
+ fn filter_cubic_minmax(&self) -> bool;
/// Returns the format of this view. This can be different from the parent's format.
- fn format(&self) -> Format;
+ fn format(&self) -> Option<Format>;
- /// Returns the component mapping of this view.
- fn component_mapping(&self) -> ComponentMapping;
+ /// Returns the features supported by the image view's format.
+ fn format_features(&self) -> FormatFeatures;
- /// Returns the [`ImageViewType`] of this image view.
- fn ty(&self) -> ImageViewType;
+ /// Returns the sampler YCbCr conversion that this image view was created with, if any.
+ fn sampler_ycbcr_conversion(&self) -> Option<&Arc<SamplerYcbcrConversion>>;
- /// Returns true if the given sampler can be used with this image view.
- ///
- /// This method should check whether the sampler's configuration can be used with the format
- /// of the view.
- // TODO: return a Result and propagate it when binding to a descriptor set
- fn can_be_sampled(&self, _sampler: &Sampler) -> bool {
- true /* FIXME */
- }
+ /// Returns the subresource range of the wrapped image that this view exposes.
+ fn subresource_range(&self) -> &ImageSubresourceRange;
+
+ /// Returns the usage of the image view.
+ fn usage(&self) -> ImageUsage;
+
+ /// Returns the [`ImageViewType`] of this image view.
+ fn view_type(&self) -> ImageViewType;
}
unsafe impl<I> ImageViewAbstract for ImageView<I>
where
- I: ImageAccess,
+ I: ImageAccess + Debug + 'static,
{
- #[inline]
- fn image(&self) -> &dyn ImageAccess {
- &self.image
+ fn image(&self) -> Arc<dyn ImageAccess> {
+ self.image.clone()
}
- #[inline]
- fn inner(&self) -> &UnsafeImageView {
- &self.inner
+ fn component_mapping(&self) -> ComponentMapping {
+ self.component_mapping
}
- #[inline]
- fn array_layers(&self) -> Range<u32> {
- self.array_layers.clone()
+ fn filter_cubic(&self) -> bool {
+ self.filter_cubic
}
- #[inline]
- fn format(&self) -> Format {
- // TODO: remove this default impl
+ fn filter_cubic_minmax(&self) -> bool {
+ self.filter_cubic_minmax
+ }
+
+ fn format(&self) -> Option<Format> {
self.format
}
+ fn format_features(&self) -> FormatFeatures {
+ self.format_features
+ }
+
+ fn sampler_ycbcr_conversion(&self) -> Option<&Arc<SamplerYcbcrConversion>> {
+ self.sampler_ycbcr_conversion.as_ref()
+ }
+
+ fn subresource_range(&self) -> &ImageSubresourceRange {
+ &self.subresource_range
+ }
+
+ fn usage(&self) -> ImageUsage {
+ self.usage
+ }
+
+ fn view_type(&self) -> ImageViewType {
+ self.view_type
+ }
+}
+
+unsafe impl ImageViewAbstract for ImageView<dyn ImageAccess> {
+ #[inline]
+ fn image(&self) -> Arc<dyn ImageAccess> {
+ self.image.clone()
+ }
+
#[inline]
fn component_mapping(&self) -> ComponentMapping {
self.component_mapping
}
#[inline]
- fn ty(&self) -> ImageViewType {
- self.ty
+ fn filter_cubic(&self) -> bool {
+ self.filter_cubic
}
-}
-unsafe impl<T> ImageViewAbstract for T
-where
- T: SafeDeref,
- T::Target: ImageViewAbstract,
-{
#[inline]
- fn image(&self) -> &dyn ImageAccess {
- (**self).image()
+ fn filter_cubic_minmax(&self) -> bool {
+ self.filter_cubic_minmax
}
#[inline]
- fn inner(&self) -> &UnsafeImageView {
- (**self).inner()
+ fn format(&self) -> Option<Format> {
+ self.format
}
#[inline]
- fn array_layers(&self) -> Range<u32> {
- (**self).array_layers()
+ fn format_features(&self) -> FormatFeatures {
+ self.format_features
}
#[inline]
- fn format(&self) -> Format {
- (**self).format()
+ fn sampler_ycbcr_conversion(&self) -> Option<&Arc<SamplerYcbcrConversion>> {
+ self.sampler_ycbcr_conversion.as_ref()
}
#[inline]
- fn component_mapping(&self) -> ComponentMapping {
- (**self).component_mapping()
+ fn subresource_range(&self) -> &ImageSubresourceRange {
+ &self.subresource_range
}
#[inline]
- fn ty(&self) -> ImageViewType {
- (**self).ty()
+ fn usage(&self) -> ImageUsage {
+ self.usage
}
#[inline]
- fn can_be_sampled(&self, sampler: &Sampler) -> bool {
- (**self).can_be_sampled(sampler)
+ fn view_type(&self) -> ImageViewType {
+ self.view_type
}
}
-impl PartialEq for dyn ImageViewAbstract + Send + Sync {
+impl PartialEq for dyn ImageViewAbstract {
#[inline]
fn eq(&self, other: &Self) -> bool {
- self.inner() == other.inner()
+ self.handle() == other.handle() && self.device() == other.device()
}
}
-impl Eq for dyn ImageViewAbstract + Send + Sync {}
+impl Eq for dyn ImageViewAbstract {}
-impl Hash for dyn ImageViewAbstract + Send + Sync {
- #[inline]
+impl Hash for dyn ImageViewAbstract {
fn hash<H: Hasher>(&self, state: &mut H) {
- self.inner().hash(state);
+ self.handle().hash(state);
+ self.device().hash(state);
}
}
diff --git a/src/instance/debug.rs b/src/instance/debug.rs
index 2bc0615..7e5a75e 100644
--- a/src/instance/debug.rs
+++ b/src/instance/debug.rs
@@ -7,9 +7,9 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-//! Debug callback called by intermediate layers or by the driver.
+//! Debug messenger called by intermediate layers or by the driver.
//!
-//! When working on an application, it is recommended to register a debug callback. For example if
+//! When working on an application, it is recommended to register a debug messenger. For example if
//! you enable the validation layers provided by the official Vulkan SDK, they will warn you about
//! invalid API usages or performance problems by calling this callback. The callback can also
//! be called by the driver or by whatever intermediate layer is activated.
@@ -17,445 +17,528 @@
//! Note that the vulkano library can also emit messages to warn you about performance issues.
//! TODO: ^ that's not the case yet, need to choose whether we keep this idea
//!
-//! # Example
+//! # Examples
//!
//! ```
//! # use vulkano::instance::Instance;
//! # use std::sync::Arc;
//! # let instance: Arc<Instance> = return;
-//! use vulkano::instance::debug::DebugCallback;
+//! use vulkano::instance::debug::{DebugUtilsMessenger, DebugUtilsMessengerCreateInfo};
//!
-//! let _callback = DebugCallback::errors_and_warnings(&instance, |msg| {
-//! println!("Debug callback: {:?}", msg.description);
-//! }).ok();
+//! let _callback = unsafe {
+//! DebugUtilsMessenger::new(
+//! instance,
+//! DebugUtilsMessengerCreateInfo::user_callback(Arc::new(|msg| {
+//! println!("Debug callback: {:?}", msg.description);
+//! })),
+//! ).ok()
+//! };
//! ```
//!
-//! The type of `msg` in the callback is [`Message`](struct.Message.html).
+//! The type of `msg` in the callback is [`Message`].
//!
//! Note that you must keep the `_callback` object alive for as long as you want your callback to
-//! be callable. If you don't store the return value of `DebugCallback`'s constructor in a
+//! be callable. If you don't store the return value of `DebugUtilsMessenger`'s constructor in a
//! variable, it will be immediately destroyed and your callback will not work.
-//!
-use crate::check_errors;
-use crate::instance::Instance;
-use crate::Error;
-use crate::VulkanObject;
-use std::error;
-use std::ffi::CStr;
-use std::fmt;
-use std::mem::MaybeUninit;
-use std::os::raw::c_void;
-use std::panic;
-use std::ptr;
-use std::sync::Arc;
+use super::Instance;
+use crate::{
+ macros::{vulkan_bitflags, vulkan_enum},
+ RequirementNotMet, RequiresOneOf, VulkanError, VulkanObject,
+};
+use std::{
+ error::Error,
+ ffi::{c_void, CStr},
+ fmt::{Debug, Display, Error as FmtError, Formatter},
+ mem::MaybeUninit,
+ panic::{catch_unwind, AssertUnwindSafe, RefUnwindSafe},
+ ptr,
+ sync::Arc,
+};
+
+pub(super) type UserCallback = Arc<dyn Fn(&Message<'_>) + RefUnwindSafe + Send + Sync>;
/// Registration of a callback called by validation layers.
///
/// The callback can be called as long as this object is alive.
-#[must_use = "The DebugCallback object must be kept alive for as long as you want your callback \
- to be called"]
-pub struct DebugCallback {
+#[must_use = "The DebugUtilsMessenger object must be kept alive for as long as you want your callback to be called"]
+pub struct DebugUtilsMessenger {
+ handle: ash::vk::DebugUtilsMessengerEXT,
instance: Arc<Instance>,
- debug_report_callback: ash::vk::DebugUtilsMessengerEXT,
- user_callback: Box<Box<dyn Fn(&Message) + Send>>,
+ _user_callback: Box<UserCallback>,
}
-impl DebugCallback {
+impl DebugUtilsMessenger {
/// Initializes a debug callback.
///
- /// Panics generated by calling `user_callback` are ignored.
- pub fn new<F>(
- instance: &Arc<Instance>,
- severity: MessageSeverity,
- ty: MessageType,
- user_callback: F,
- ) -> Result<DebugCallback, DebugCallbackCreationError>
- where
- F: Fn(&Message) + 'static + Send + panic::RefUnwindSafe,
- {
+ /// # Panics
+ ///
+ /// - Panics if the `message_severity` or `message_type` members of `create_info` are empty.
+ ///
+ /// # Safety
+ ///
+ /// - `create_info.user_callback` must not make any calls to the Vulkan API.
+ pub unsafe fn new(
+ instance: Arc<Instance>,
+ mut create_info: DebugUtilsMessengerCreateInfo,
+ ) -> Result<Self, DebugUtilsMessengerCreationError> {
+ Self::validate_create(&instance, &mut create_info)?;
+ let (handle, user_callback) = Self::record_create(&instance, create_info)?;
+
+ Ok(DebugUtilsMessenger {
+ handle,
+ instance,
+ _user_callback: user_callback,
+ })
+ }
+
+ fn validate_create(
+ instance: &Instance,
+ create_info: &mut DebugUtilsMessengerCreateInfo,
+ ) -> Result<(), DebugUtilsMessengerCreationError> {
+ let &mut DebugUtilsMessengerCreateInfo {
+ message_type,
+ message_severity,
+ user_callback: _,
+ _ne: _,
+ } = create_info;
+
if !instance.enabled_extensions().ext_debug_utils {
- return Err(DebugCallbackCreationError::MissingExtension);
+ return Err(DebugUtilsMessengerCreationError::RequirementNotMet {
+ required_for: "`DebugUtilsMessenger::new`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["ext_debug_utils"],
+ ..Default::default()
+ },
+ });
}
- // Note that we need to double-box the callback, because a `*const Fn()` is a fat pointer
- // that can't be cast to a `*const c_void`.
- let user_callback = Box::new(Box::new(user_callback) as Box<_>);
-
- unsafe extern "system" fn callback(
- severity: ash::vk::DebugUtilsMessageSeverityFlagsEXT,
- ty: ash::vk::DebugUtilsMessageTypeFlagsEXT,
- callback_data: *const ash::vk::DebugUtilsMessengerCallbackDataEXT,
- user_data: *mut c_void,
- ) -> ash::vk::Bool32 {
- let user_callback = user_data as *mut Box<dyn Fn()> as *const _;
- let user_callback: &Box<dyn Fn(&Message)> = &*user_callback;
-
- let layer_prefix = (*callback_data)
- .p_message_id_name
- .as_ref()
- .map(|msg_id_name| {
- CStr::from_ptr(msg_id_name)
- .to_str()
- .expect("debug callback message not utf-8")
- });
-
- let description = CStr::from_ptr((*callback_data).p_message)
- .to_str()
- .expect("debug callback message not utf-8");
-
- let message = Message {
- severity: MessageSeverity {
- information: !(severity & ash::vk::DebugUtilsMessageSeverityFlagsEXT::INFO)
- .is_empty(),
- warning: !(severity & ash::vk::DebugUtilsMessageSeverityFlagsEXT::WARNING)
- .is_empty(),
- error: !(severity & ash::vk::DebugUtilsMessageSeverityFlagsEXT::ERROR)
- .is_empty(),
- verbose: !(severity & ash::vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE)
- .is_empty(),
- },
- ty: MessageType {
- general: !(ty & ash::vk::DebugUtilsMessageTypeFlagsEXT::GENERAL).is_empty(),
- validation: !(ty & ash::vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION)
- .is_empty(),
- performance: !(ty & ash::vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE)
- .is_empty(),
- },
- layer_prefix,
- description,
- };
+ // VUID-VkDebugUtilsMessengerCreateInfoEXT-messageSeverity-parameter
+ message_severity.validate_instance(instance)?;
- // Since we box the closure, the type system doesn't detect that the `UnwindSafe`
- // bound is enforced. Therefore we enforce it manually.
- let _ = panic::catch_unwind(panic::AssertUnwindSafe(move || {
- user_callback(&message);
- }));
+ // VUID-VkDebugUtilsMessengerCreateInfoEXT-messageSeverity-requiredbitmask
+ assert!(!message_severity.is_empty());
- ash::vk::FALSE
- }
+ // VUID-VkDebugUtilsMessengerCreateInfoEXT-messageType-parameter
+ message_type.validate_instance(instance)?;
- let severity = {
- let mut flags = ash::vk::DebugUtilsMessageSeverityFlagsEXT::empty();
- if severity.information {
- flags |= ash::vk::DebugUtilsMessageSeverityFlagsEXT::INFO;
- }
- if severity.warning {
- flags |= ash::vk::DebugUtilsMessageSeverityFlagsEXT::WARNING;
- }
- if severity.error {
- flags |= ash::vk::DebugUtilsMessageSeverityFlagsEXT::ERROR;
- }
- if severity.verbose {
- flags |= ash::vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE;
- }
- flags
- };
+ // VUID-VkDebugUtilsMessengerCreateInfoEXT-messageType-requiredbitmask
+ assert!(!message_type.is_empty());
- let ty = {
- let mut flags = ash::vk::DebugUtilsMessageTypeFlagsEXT::empty();
- if ty.general {
- flags |= ash::vk::DebugUtilsMessageTypeFlagsEXT::GENERAL;
- }
- if ty.validation {
- flags |= ash::vk::DebugUtilsMessageTypeFlagsEXT::VALIDATION;
- }
- if ty.performance {
- flags |= ash::vk::DebugUtilsMessageTypeFlagsEXT::PERFORMANCE;
- }
- flags
- };
+ // VUID-PFN_vkDebugUtilsMessengerCallbackEXT-None-04769
+ // Can't be checked, creation is unsafe.
+
+ Ok(())
+ }
+
+ unsafe fn record_create(
+ instance: &Instance,
+ create_info: DebugUtilsMessengerCreateInfo,
+ ) -> Result<
+ (ash::vk::DebugUtilsMessengerEXT, Box<UserCallback>),
+ DebugUtilsMessengerCreationError,
+ > {
+ let DebugUtilsMessengerCreateInfo {
+ message_severity,
+ message_type,
+ user_callback,
+ _ne: _,
+ } = create_info;
+
+ // Note that we need to double-box the callback, because a `*const Fn()` is a fat pointer
+ // that can't be cast to a `*const c_void`.
+ let user_callback = Box::new(user_callback);
- let infos = ash::vk::DebugUtilsMessengerCreateInfoEXT {
+ let create_info = ash::vk::DebugUtilsMessengerCreateInfoEXT {
flags: ash::vk::DebugUtilsMessengerCreateFlagsEXT::empty(),
- message_severity: severity,
- message_type: ty,
- pfn_user_callback: Some(callback),
- p_user_data: &*user_callback as &Box<_> as *const Box<_> as *const c_void as *mut _,
+ message_severity: message_severity.into(),
+ message_type: message_type.into(),
+ pfn_user_callback: Some(trampoline),
+ p_user_data: &*user_callback as &Arc<_> as *const Arc<_> as *const c_void as *mut _,
..Default::default()
};
let fns = instance.fns();
- let debug_report_callback = unsafe {
+ let handle = {
let mut output = MaybeUninit::uninit();
- check_errors(fns.ext_debug_utils.create_debug_utils_messenger_ext(
- instance.internal_object(),
- &infos,
+ (fns.ext_debug_utils.create_debug_utils_messenger_ext)(
+ instance.handle(),
+ &create_info,
ptr::null(),
output.as_mut_ptr(),
- ))?;
+ )
+ .result()
+ .map_err(VulkanError::from)?;
output.assume_init()
};
- Ok(DebugCallback {
- instance: instance.clone(),
- debug_report_callback,
- user_callback,
- })
- }
-
- /// Initializes a debug callback with errors and warnings.
- ///
- /// Shortcut for `new(instance, MessageTypes::errors_and_warnings(), user_callback)`.
- #[inline]
- pub fn errors_and_warnings<F>(
- instance: &Arc<Instance>,
- user_callback: F,
- ) -> Result<DebugCallback, DebugCallbackCreationError>
- where
- F: Fn(&Message) + Send + 'static + panic::RefUnwindSafe,
- {
- DebugCallback::new(
- instance,
- MessageSeverity::errors_and_warnings(),
- MessageType::general(),
- user_callback,
- )
+ Ok((handle, user_callback))
}
}
-impl Drop for DebugCallback {
+impl Drop for DebugUtilsMessenger {
#[inline]
fn drop(&mut self) {
unsafe {
let fns = self.instance.fns();
- fns.ext_debug_utils.destroy_debug_utils_messenger_ext(
- self.instance.internal_object(),
- self.debug_report_callback,
+ (fns.ext_debug_utils.destroy_debug_utils_messenger_ext)(
+ self.instance.handle(),
+ self.handle,
ptr::null(),
);
}
}
}
-/// A message received by the callback.
-pub struct Message<'a> {
- /// Severity of message.
- pub severity: MessageSeverity,
- /// Type of message,
- pub ty: MessageType,
- /// Prefix of the layer that reported this message or `None` if unknown.
- pub layer_prefix: Option<&'a str>,
- /// Description of the message.
- pub description: &'a str,
+impl Debug for DebugUtilsMessenger {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ let Self {
+ handle,
+ instance,
+ _user_callback: _,
+ } = self;
+
+ f.debug_struct("DebugUtilsMessenger")
+ .field("handle", handle)
+ .field("instance", instance)
+ .finish_non_exhaustive()
+ }
}
-/// Severity of message.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub struct MessageSeverity {
- /// An error that may cause undefined results, including an application crash.
- pub error: bool,
- /// An unexpected use.
- pub warning: bool,
- /// An informational message that may be handy when debugging an application.
- pub information: bool,
- /// Diagnostic information from the loader and layers.
- pub verbose: bool,
+pub(super) unsafe extern "system" fn trampoline(
+ message_severity: ash::vk::DebugUtilsMessageSeverityFlagsEXT,
+ message_types: ash::vk::DebugUtilsMessageTypeFlagsEXT,
+ callback_data: *const ash::vk::DebugUtilsMessengerCallbackDataEXT,
+ user_data: *mut c_void,
+) -> ash::vk::Bool32 {
+ // Since we box the closure, the type system doesn't detect that the `UnwindSafe`
+ // bound is enforced. Therefore we enforce it manually.
+ let _ = catch_unwind(AssertUnwindSafe(move || {
+ let user_callback = user_data as *mut UserCallback as *const _;
+ let user_callback: &UserCallback = &*user_callback;
+
+ let layer_prefix = (*callback_data)
+ .p_message_id_name
+ .as_ref()
+ .map(|msg_id_name| {
+ CStr::from_ptr(msg_id_name)
+ .to_str()
+ .expect("debug callback message not utf-8")
+ });
+
+ let description = CStr::from_ptr((*callback_data).p_message)
+ .to_str()
+ .expect("debug callback message not utf-8");
+
+ let message = Message {
+ severity: message_severity.into(),
+ ty: message_types.into(),
+ layer_prefix,
+ description,
+ };
+
+ user_callback(&message);
+ }));
+
+ ash::vk::FALSE
}
-impl MessageSeverity {
- /// Builds a `MessageSeverity` with all fields set to `false` expect `error`.
- #[inline]
- pub const fn errors() -> MessageSeverity {
- MessageSeverity {
- error: true,
- ..MessageSeverity::none()
- }
- }
+/// Error that can happen when creating a `DebugUtilsMessenger`.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum DebugUtilsMessengerCreationError {
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+}
- /// Builds a `MessageSeverity` with all fields set to `false` expect `warning`.
- #[inline]
- pub const fn warnings() -> MessageSeverity {
- MessageSeverity {
- warning: true,
- ..MessageSeverity::none()
+impl Error for DebugUtilsMessengerCreationError {}
+
+impl Display for DebugUtilsMessengerCreationError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
}
}
+}
- /// Builds a `MessageSeverity` with all fields set to `false` expect `information`.
- #[inline]
- pub const fn information() -> MessageSeverity {
- MessageSeverity {
- information: true,
- ..MessageSeverity::none()
- }
+impl From<VulkanError> for DebugUtilsMessengerCreationError {
+ fn from(err: VulkanError) -> DebugUtilsMessengerCreationError {
+ panic!("unexpected error: {:?}", err)
}
+}
- /// Builds a `MessageSeverity` with all fields set to `false` expect `verbose`.
- #[inline]
- pub const fn verbose() -> MessageSeverity {
- MessageSeverity {
- verbose: true,
- ..MessageSeverity::none()
+impl From<RequirementNotMet> for DebugUtilsMessengerCreationError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
}
}
+}
- /// Builds a `MessageSeverity` with all fields set to `false` expect `error`, `warning`
- /// and `performance_warning`.
- #[inline]
- pub const fn errors_and_warnings() -> MessageSeverity {
- MessageSeverity {
- error: true,
- warning: true,
- ..MessageSeverity::none()
- }
- }
+/// Parameters to create a `DebugUtilsMessenger`.
+#[derive(Clone)]
+pub struct DebugUtilsMessengerCreateInfo {
+ /// The message severity types that the callback should be called for.
+ ///
+ /// The value must not be empty.
+ ///
+ /// The default value is `MessageSeverity::errors_and_warnings()`.
+ pub message_severity: DebugUtilsMessageSeverity,
- /// Builds a `MessageSeverity` with all fields set to `false`.
- #[inline]
- pub const fn none() -> MessageSeverity {
- MessageSeverity {
- error: false,
- warning: false,
- information: false,
- verbose: false,
- }
- }
+ /// The message types that the callback should be called for.
+ ///
+ /// The value must not be empty.
+ ///
+ /// The default value is `MessageType::general()`.
+ pub message_type: DebugUtilsMessageType,
+
+ /// The closure that should be called.
+ ///
+ /// The closure must not make any calls to the Vulkan API.
+ /// If the closure panics, the panic is caught and ignored.
+ ///
+ /// The callback is provided inside an `Arc` so that it can be shared across multiple
+ /// messengers.
+ pub user_callback: UserCallback,
- /// Builds a `MessageSeverity` with all fields set to `true`.
+ pub _ne: crate::NonExhaustive,
+}
+
+impl DebugUtilsMessengerCreateInfo {
+ /// Returns a `DebugUtilsMessengerCreateInfo` with the specified `user_callback`.
#[inline]
- pub const fn all() -> MessageSeverity {
- MessageSeverity {
- error: true,
- warning: true,
- information: true,
- verbose: true,
+ pub fn user_callback(user_callback: UserCallback) -> Self {
+ Self {
+ message_severity: DebugUtilsMessageSeverity::ERROR | DebugUtilsMessageSeverity::WARNING,
+ message_type: DebugUtilsMessageType::GENERAL,
+ user_callback,
+ _ne: crate::NonExhaustive(()),
}
}
}
-impl std::ops::BitOr for MessageSeverity {
- type Output = Self;
- fn bitor(self, rhs: Self) -> Self::Output {
- MessageSeverity {
- error: self.error | rhs.error,
- warning: self.warning | rhs.warning,
- information: self.information | rhs.information,
- verbose: self.verbose | rhs.verbose,
- }
+impl Debug for DebugUtilsMessengerCreateInfo {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ let Self {
+ message_severity,
+ message_type,
+ user_callback: _,
+ _ne: _,
+ } = self;
+
+ f.debug_struct("DebugUtilsMessengerCreateInfo")
+ .field("message_severity", message_severity)
+ .field("message_type", message_type)
+ .finish_non_exhaustive()
}
}
-/// Type of message.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub struct MessageType {
+/// A message received by the callback.
+pub struct Message<'a> {
+ /// Severity of message.
+ pub severity: DebugUtilsMessageSeverity,
+ /// Type of message,
+ pub ty: DebugUtilsMessageType,
+ /// Prefix of the layer that reported this message or `None` if unknown.
+ pub layer_prefix: Option<&'a str>,
+ /// Description of the message.
+ pub description: &'a str,
+}
+
+vulkan_bitflags! {
+ #[non_exhaustive]
+
+ /// Severity of message.
+ DebugUtilsMessageSeverity = DebugUtilsMessageSeverityFlagsEXT(u32);
+
+ /// An error that may cause undefined results, including an application crash.
+ ERROR = ERROR,
+
+ /// An unexpected use.
+ WARNING = WARNING,
+
+ /// An informational message that may be handy when debugging an application.
+ INFO = INFO,
+
+ /// Diagnostic information from the loader and layers.
+ VERBOSE = VERBOSE,
+}
+
+vulkan_bitflags! {
+ #[non_exhaustive]
+
+ /// Type of message.
+ DebugUtilsMessageType = DebugUtilsMessageTypeFlagsEXT(u32);
+
/// Specifies that some general event has occurred.
- pub general: bool,
+ GENERAL = GENERAL,
+
/// Specifies that something has occurred during validation against the vulkan specification
- pub validation: bool,
+ VALIDATION = VALIDATION,
+
/// Specifies a potentially non-optimal use of Vulkan
- pub performance: bool,
+ PERFORMANCE = PERFORMANCE,
}
-impl MessageType {
- /// Builds a `MessageType` with general field set to `true`.
- #[inline]
- pub const fn general() -> MessageType {
- MessageType {
- general: true,
- validation: false,
- performance: false,
- }
- }
-
- /// Builds a `MessageType` with validation field set to `true`.
- #[inline]
- pub const fn validation() -> MessageType {
- MessageType {
- general: false,
- validation: true,
- performance: false,
- }
- }
+/// A label to associate with a span of work in a queue.
+///
+/// When debugging, labels can be useful to identify which queue, or where in a specific queue,
+/// something happened.
+#[derive(Clone, Debug)]
+pub struct DebugUtilsLabel {
+ /// The name of the label.
+ ///
+ /// The default value is empty.
+ pub label_name: String,
- /// Builds a `MessageType` with performance field set to `true`.
- #[inline]
- pub const fn performance() -> MessageType {
- MessageType {
- general: false,
- validation: false,
- performance: true,
- }
- }
+ /// An RGBA color value that is associated with the label, with values in the range `0.0..=1.0`.
+ ///
+ /// If set to `[0.0; 4]`, the value is ignored.
+ ///
+ /// The default value is `[0.0; 4]`.
+ pub color: [f32; 4],
- /// Builds a `MessageType` with all fields set to `true`.
- #[inline]
- pub const fn all() -> MessageType {
- MessageType {
- general: true,
- validation: true,
- performance: true,
- }
- }
+ pub _ne: crate::NonExhaustive,
+}
- /// Builds a `MessageType` with all fields set to `false`.
+impl Default for DebugUtilsLabel {
#[inline]
- pub const fn none() -> MessageType {
- MessageType {
- general: false,
- validation: false,
- performance: false,
+ fn default() -> Self {
+ Self {
+ label_name: String::new(),
+ color: [0.0; 4],
+ _ne: crate::NonExhaustive(()),
}
}
}
-impl std::ops::BitOr for MessageType {
- type Output = Self;
- fn bitor(self, rhs: Self) -> Self::Output {
- MessageType {
- general: self.general | rhs.general,
- validation: self.validation | rhs.validation,
- performance: self.performance | rhs.performance,
- }
- }
-}
+vulkan_enum! {
+ #[non_exhaustive]
-/// Error that can happen when creating a debug callback.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum DebugCallbackCreationError {
- /// The `EXT_debug_utils` extension was not enabled.
- MissingExtension,
-}
+ /// Features of the validation layer to enable.
+ ValidationFeatureEnable = ValidationFeatureEnableEXT(i32);
-impl error::Error for DebugCallbackCreationError {}
+ /// The validation layer will use shader programs running on the GPU to provide additional
+ /// validation.
+ ///
+ /// This must not be used together with `DebugPrintf`.
+ GpuAssisted = GPU_ASSISTED,
-impl fmt::Display for DebugCallbackCreationError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- DebugCallbackCreationError::MissingExtension => {
- "the `EXT_debug_utils` extension was not enabled"
- }
- }
- )
- }
+ /// The validation layer will reserve and use one descriptor set slot for its own use.
+ /// The limit reported by
+ /// [`max_bound_descriptor_sets`](crate::device::Properties::max_bound_descriptor_sets)
+ /// will be reduced by 1.
+ ///
+ /// `GpuAssisted` must also be enabled.
+ GpuAssistedReserveBindingSlot = GPU_ASSISTED_RESERVE_BINDING_SLOT,
+
+ /// The validation layer will report recommendations that are not strictly errors,
+ /// but that may be considered good Vulkan practice.
+ BestPractices = BEST_PRACTICES,
+
+ /// The validation layer will process `debugPrintfEXT` operations in shaders, and send them
+ /// to the debug callback.
+ ///
+ /// This must not be used together with `GpuAssisted`.
+ DebugPrintf = DEBUG_PRINTF,
+
+ /// The validation layer will report errors relating to synchronization, such as data races and
+ /// the use of synchronization primitives.
+ SynchronizationValidation = SYNCHRONIZATION_VALIDATION,
}
-impl From<Error> for DebugCallbackCreationError {
- #[inline]
- fn from(err: Error) -> DebugCallbackCreationError {
- panic!("unexpected error: {:?}", err)
- }
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// Features of the validation layer to disable.
+ ValidationFeatureDisable = ValidationFeatureDisableEXT(i32);
+
+ /// All validation is disabled.
+ All = ALL,
+
+ /// Shader validation is disabled.
+ Shaders = SHADERS,
+
+ /// Thread safety validation is disabled.
+ ThreadSafety = THREAD_SAFETY,
+
+ /// Stateless parameter validation is disabled.
+ ApiParameters = API_PARAMETERS,
+
+ /// Object lifetime validation is disabled.
+ ObjectLifetimes = OBJECT_LIFETIMES,
+
+ /// Core validation checks are disabled.
+ ///
+ /// This also disables shader validation and GPU-assisted validation.
+ CoreChecks = CORE_CHECKS,
+
+ /// Protection against duplicate non-dispatchable handles is disabled.
+ UniqueHandles = UNIQUE_HANDLES,
+
+ /// Results of shader validation will not be cached, and are validated from scratch each time.
+ ShaderValidationCache = SHADER_VALIDATION_CACHE,
}
#[cfg(test)]
mod tests {
use super::*;
+ use crate::{
+ instance::{InstanceCreateInfo, InstanceExtensions},
+ VulkanLibrary,
+ };
use std::thread;
+
#[test]
fn ensure_sendable() {
- // It's useful to be able to initialize a DebugCallback on one thread
+ // It's useful to be able to initialize a DebugUtilsMessenger on one thread
// and keep it alive on another thread.
- let instance = instance!();
- let severity = MessageSeverity::none();
- let ty = MessageType::all();
- let callback = DebugCallback::new(&instance, severity, ty, |_| {});
+ let instance = {
+ let library = match VulkanLibrary::new() {
+ Ok(x) => x,
+ Err(_) => return,
+ };
+
+ match Instance::new(
+ library,
+ InstanceCreateInfo {
+ enabled_extensions: InstanceExtensions {
+ ext_debug_utils: true,
+ ..InstanceExtensions::empty()
+ },
+ ..Default::default()
+ },
+ ) {
+ Ok(x) => x,
+ Err(_) => return,
+ }
+ };
+
+ let callback = unsafe {
+ DebugUtilsMessenger::new(
+ instance,
+ DebugUtilsMessengerCreateInfo {
+ message_severity: DebugUtilsMessageSeverity::ERROR,
+ message_type: DebugUtilsMessageType::GENERAL
+ | DebugUtilsMessageType::VALIDATION
+ | DebugUtilsMessageType::PERFORMANCE,
+ ..DebugUtilsMessengerCreateInfo::user_callback(Arc::new(|_| {}))
+ },
+ )
+ }
+ .unwrap();
thread::spawn(move || {
- let _ = callback;
+ drop(callback);
});
}
}
diff --git a/src/instance/extensions.rs b/src/instance/extensions.rs
index dab0b12..3aac844 100644
--- a/src/instance/extensions.rs
+++ b/src/instance/extensions.rs
@@ -7,138 +7,10 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use crate::check_errors;
-pub use crate::extensions::{
- ExtensionRestriction, ExtensionRestrictionError, SupportedExtensionsError,
-};
-use crate::instance::loader;
-use crate::instance::loader::LoadingError;
-use std::ffi::CStr;
-use std::ptr;
+pub use crate::extensions::{ExtensionRestriction, ExtensionRestrictionError};
-macro_rules! instance_extensions {
- (
- $($member:ident => {
- doc: $doc:expr,
- raw: $raw:expr,
- requires_core: $requires_core:expr,
- requires_instance_extensions: [$($requires_instance_extension:ident),*]$(,)?
- },)*
- ) => (
- extensions! {
- InstanceExtensions,
- $($member => {
- doc: $doc,
- raw: $raw,
- requires_core: $requires_core,
- requires_device_extensions: [],
- requires_instance_extensions: [$($requires_instance_extension),*],
- },)*
- }
-
- impl InstanceExtensions {
- /// Checks enabled extensions against the instance version and each other.
- pub(super) fn check_requirements(
- &self,
- supported: &InstanceExtensions,
- api_version: crate::Version,
- ) -> Result<(), crate::extensions::ExtensionRestrictionError> {
- $(
- if self.$member {
- if !supported.$member {
- return Err(crate::extensions::ExtensionRestrictionError {
- extension: stringify!($member),
- restriction: crate::extensions::ExtensionRestriction::NotSupported,
- });
- }
-
- if api_version < $requires_core {
- return Err(crate::extensions::ExtensionRestrictionError {
- extension: stringify!($member),
- restriction: crate::extensions::ExtensionRestriction::RequiresCore($requires_core),
- });
- } else {
- $(
- if !self.$requires_instance_extension {
- return Err(crate::extensions::ExtensionRestrictionError {
- extension: stringify!($member),
- restriction: crate::extensions::ExtensionRestriction::RequiresInstanceExtension(stringify!($requires_instance_extension)),
- });
- }
- )*
- }
- }
- )*
- Ok(())
- }
- }
- );
-}
-
-pub use crate::autogen::InstanceExtensions;
-pub(crate) use instance_extensions;
-
-impl InstanceExtensions {
- /// See the docs of supported_by_core().
- pub fn supported_by_core_raw() -> Result<Self, SupportedExtensionsError> {
- InstanceExtensions::supported_by_core_raw_with_loader(loader::auto_loader()?)
- }
-
- /// Returns an `InstanceExtensions` object with extensions supported by the core driver.
- pub fn supported_by_core() -> Result<Self, LoadingError> {
- match InstanceExtensions::supported_by_core_raw() {
- Ok(l) => Ok(l),
- Err(SupportedExtensionsError::LoadingError(e)) => Err(e),
- Err(SupportedExtensionsError::OomError(e)) => panic!("{:?}", e),
- }
- }
-
- /// Same as `supported_by_core`, but allows specifying a loader.
- pub fn supported_by_core_with_loader<L>(
- ptrs: &loader::FunctionPointers<L>,
- ) -> Result<Self, LoadingError>
- where
- L: loader::Loader,
- {
- match InstanceExtensions::supported_by_core_raw_with_loader(ptrs) {
- Ok(l) => Ok(l),
- Err(SupportedExtensionsError::LoadingError(e)) => Err(e),
- Err(SupportedExtensionsError::OomError(e)) => panic!("{:?}", e),
- }
- }
-
- /// See the docs of supported_by_core().
- pub fn supported_by_core_raw_with_loader<L>(
- ptrs: &loader::FunctionPointers<L>,
- ) -> Result<Self, SupportedExtensionsError>
- where
- L: loader::Loader,
- {
- let fns = ptrs.fns();
-
- let properties: Vec<ash::vk::ExtensionProperties> = unsafe {
- let mut num = 0;
- check_errors(fns.v1_0.enumerate_instance_extension_properties(
- ptr::null(),
- &mut num,
- ptr::null_mut(),
- ))?;
-
- let mut properties = Vec::with_capacity(num as usize);
- check_errors(fns.v1_0.enumerate_instance_extension_properties(
- ptr::null(),
- &mut num,
- properties.as_mut_ptr(),
- ))?;
- properties.set_len(num as usize);
- properties
- };
-
- Ok(Self::from(properties.iter().map(|property| unsafe {
- CStr::from_ptr(property.extension_name.as_ptr())
- })))
- }
-}
+// Generated by build.rs
+include!(concat!(env!("OUT_DIR"), "/instance_extensions.rs"));
#[cfg(test)]
mod tests {
@@ -147,7 +19,22 @@ mod tests {
#[test]
fn empty_extensions() {
- let i: Vec<CString> = (&InstanceExtensions::none()).into();
- assert!(i.iter().next().is_none());
+ let i: Vec<CString> = (&InstanceExtensions::empty()).into();
+ assert!(i.get(0).is_none());
+ }
+
+ #[test]
+ fn into_iter() {
+ let extensions = InstanceExtensions {
+ khr_display: true,
+ ..InstanceExtensions::empty()
+ };
+ for (name, enabled) in extensions {
+ if name == "VK_KHR_display" {
+ assert!(enabled);
+ } else {
+ assert!(!enabled);
+ }
+ }
}
}
diff --git a/src/instance/instance.rs b/src/instance/instance.rs
deleted file mode 100644
index 50712d2..0000000
--- a/src/instance/instance.rs
+++ /dev/null
@@ -1,693 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::check_errors;
-use crate::device::physical::{init_physical_devices, PhysicalDeviceInfo};
-use crate::extensions::ExtensionRestrictionError;
-use crate::fns::InstanceFunctions;
-use crate::instance::loader;
-use crate::instance::loader::FunctionPointers;
-use crate::instance::loader::Loader;
-use crate::instance::loader::LoadingError;
-use crate::instance::InstanceExtensions;
-use crate::Error;
-use crate::OomError;
-use crate::Version;
-use crate::VulkanObject;
-use smallvec::SmallVec;
-use std::borrow::Cow;
-use std::convert::TryInto;
-use std::error;
-use std::ffi::CString;
-use std::fmt;
-use std::hash::Hash;
-use std::hash::Hasher;
-use std::mem::MaybeUninit;
-use std::ops::Deref;
-use std::ptr;
-use std::slice;
-use std::sync::Arc;
-
-/// An instance of a Vulkan context. This is the main object that should be created by an
-/// application before everything else.
-///
-/// # Application info
-///
-/// When you create an instance, you have the possibility to pass an `ApplicationInfo` struct as
-/// the first parameter. This struct contains various information about your application, most
-/// notably its name and engine.
-///
-/// Passing such a structure allows for example the driver to let the user configure the driver's
-/// behavior for your application alone through a control panel.
-///
-/// ```no_run
-/// # #[macro_use] extern crate vulkano;
-/// # fn main() {
-/// use vulkano::instance::{Instance, InstanceExtensions};
-/// use vulkano::Version;
-///
-/// // Builds an `ApplicationInfo` by looking at the content of the `Cargo.toml` file at
-/// // compile-time.
-/// let app_infos = app_info_from_cargo_toml!();
-///
-/// let _instance = Instance::new(Some(&app_infos), Version::V1_1, &InstanceExtensions::none(), None).unwrap();
-/// # }
-/// ```
-///
-/// # API versions
-///
-/// Both an `Instance` and a [`Device`](crate::device::Device) have a highest version of the Vulkan
-/// API that they support. This places a limit on what Vulkan functions and features are available
-/// to use when used on a particular instance or device. It is possible for the instance and the
-/// device to support different versions. The supported version for an instance can be queried
-/// before creation with
-/// [`FunctionPointers::api_version`](crate::instance::loader::FunctionPointers::api_version),
-/// while for a device it can be retrieved with
-/// [`PhysicalDevice::api_version`](crate::instance::PhysicalDevice::api_version).
-///
-/// When creating an `Instance`, you have to specify a maximum API version that you will use.
-/// This restricts the API version that is available for the instance and any devices created from
-/// it. For example, if both instance and device potentially support Vulkan 1.2, but you specify
-/// 1.1 as the maximum API version when creating the `Instance`, then you can only use Vulkan 1.1
-/// functions, even though they could theoretically support a higher version. You can think of it
-/// as a promise never to use any functionality from a higher version.
-///
-/// The maximum API version is not a _minimum_, so it is possible to set it to a higher version than
-/// what the instance or device inherently support. The final API version that you are able to use
-/// on an instance or device is the lower of the supported API version and the chosen maximum API
-/// version of the `Instance`.
-///
-/// However, due to a quirk in how the Vulkan 1.0 specification was written, if the instance only
-/// supports Vulkan 1.0, then it is not possible to specify a maximum API version higher than 1.0.
-/// Trying to create an `Instance` will return an `IncompatibleDriver` error. Consequently, it is
-/// not possible to use a higher device API version with an instance that only supports 1.0.
-///
-/// # Extensions
-///
-/// When creating an `Instance`, you must provide a list of extensions that must be enabled on the
-/// newly-created instance. Trying to enable an extension that is not supported by the system will
-/// result in an error.
-///
-/// Contrary to OpenGL, it is not possible to use the features of an extension if it was not
-/// explicitly enabled.
-///
-/// Extensions are especially important to take into account if you want to render images on the
-/// screen, as the only way to do so is to use the `VK_KHR_surface` extension. More information
-/// about this in the `swapchain` module.
-///
-/// For example, here is how we create an instance with the `VK_KHR_surface` and
-/// `VK_KHR_android_surface` extensions enabled, which will allow us to render images to an
-/// Android screen. You can compile and run this code on any system, but it is highly unlikely to
-/// succeed on anything else than an Android-running device.
-///
-/// ```no_run
-/// use vulkano::instance::Instance;
-/// use vulkano::instance::InstanceExtensions;
-/// use vulkano::Version;
-///
-/// let extensions = InstanceExtensions {
-/// khr_surface: true,
-/// khr_android_surface: true,
-/// .. InstanceExtensions::none()
-/// };
-///
-/// let instance = match Instance::new(None, Version::V1_1, &extensions, None) {
-/// Ok(i) => i,
-/// Err(err) => panic!("Couldn't build instance: {:?}", err)
-/// };
-/// ```
-///
-/// # Layers
-///
-/// When creating an `Instance`, you have the possibility to pass a list of **layers** that will
-/// be activated on the newly-created instance. The list of available layers can be retrieved by
-/// calling [the `layers_list` function](fn.layers_list.html).
-///
-/// A layer is a component that will hook and potentially modify the Vulkan function calls.
-/// For example, activating a layer could add a frames-per-second counter on the screen, or it
-/// could send information to a debugger that will debug your application.
-///
-/// > **Note**: From an application's point of view, layers "just exist". In practice, on Windows
-/// > and Linux, layers can be installed by third party installers or by package managers and can
-/// > also be activated by setting the value of the `VK_INSTANCE_LAYERS` environment variable
-/// > before starting the program. See the documentation of the official Vulkan loader for these
-/// > platforms.
-///
-/// > **Note**: In practice, the most common use of layers right now is for debugging purposes.
-/// > To do so, you are encouraged to set the `VK_INSTANCE_LAYERS` environment variable on Windows
-/// > or Linux instead of modifying the source code of your program. For example:
-/// > `export VK_INSTANCE_LAYERS=VK_LAYER_LUNARG_api_dump` on Linux if you installed the Vulkan SDK
-/// > will print the list of raw Vulkan function calls.
-///
-/// ## Example
-///
-/// ```
-/// # use std::sync::Arc;
-/// # use std::error::Error;
-/// # use vulkano::instance;
-/// # use vulkano::instance::Instance;
-/// # use vulkano::instance::InstanceExtensions;
-/// # use vulkano::Version;
-/// # fn test() -> Result<Arc<Instance>, Box<dyn Error>> {
-/// // For the sake of the example, we activate all the layers that
-/// // contain the word "foo" in their description.
-/// let layers: Vec<_> = instance::layers_list()?
-/// .filter(|l| l.description().contains("foo"))
-/// .collect();
-///
-/// let layer_names = layers.iter()
-/// .map(|l| l.name());
-///
-/// let instance = Instance::new(None, Version::V1_1, &InstanceExtensions::none(), layer_names)?;
-/// # Ok(instance)
-/// # }
-/// ```
-// TODO: mention that extensions must be supported by layers as well
-pub struct Instance {
- instance: ash::vk::Instance,
- //alloc: Option<Box<Alloc + Send + Sync>>,
-
- // The highest version that is supported for this instance.
- // This is the minimum of Instance::max_api_version and FunctionPointers::api_version.
- api_version: Version,
-
- // The highest allowed API version for instances and devices created from it.
- max_api_version: Version,
-
- pub(crate) physical_device_infos: Vec<PhysicalDeviceInfo>,
- fns: InstanceFunctions,
- extensions: InstanceExtensions,
- layers: SmallVec<[CString; 16]>,
- function_pointers: OwnedOrRef<FunctionPointers<Box<dyn Loader + Send + Sync>>>,
-}
-
-// TODO: fix the underlying cause instead
-impl ::std::panic::UnwindSafe for Instance {}
-impl ::std::panic::RefUnwindSafe for Instance {}
-
-impl Instance {
- /// Initializes a new instance of Vulkan.
- ///
- /// See the documentation of `Instance` or of [the `instance` module](index.html) for more
- /// details.
- ///
- /// # Example
- ///
- /// ```no_run
- /// use vulkano::instance::Instance;
- /// use vulkano::instance::InstanceExtensions;
- /// use vulkano::Version;
- ///
- /// let instance = match Instance::new(None, Version::V1_1, &InstanceExtensions::none(), None) {
- /// Ok(i) => i,
- /// Err(err) => panic!("Couldn't build instance: {:?}", err)
- /// };
- /// ```
- ///
- /// # Panic
- ///
- /// - Panics if the version numbers passed in `ApplicationInfo` are too large can't be
- /// converted into a Vulkan version number.
- /// - Panics if the application name or engine name contain a null character.
- // TODO: add a test for these ^
- // TODO: if no allocator is specified by the user, use Rust's allocator instead of leaving
- // the choice to Vulkan
- pub fn new<'a, L>(
- app_infos: Option<&ApplicationInfo>,
- max_api_version: Version,
- extensions: &InstanceExtensions,
- layers: L,
- ) -> Result<Arc<Instance>, InstanceCreationError>
- where
- L: IntoIterator<Item = &'a str>,
- {
- let layers = layers
- .into_iter()
- .map(|layer| CString::new(layer).unwrap())
- .collect::<SmallVec<[_; 16]>>();
-
- Instance::new_inner(
- app_infos,
- max_api_version,
- extensions,
- layers,
- OwnedOrRef::Ref(loader::auto_loader()?),
- )
- }
-
- /// Same as `new`, but allows specifying a loader where to load Vulkan from.
- pub fn with_loader<'a, L>(
- loader: FunctionPointers<Box<dyn Loader + Send + Sync>>,
- app_infos: Option<&ApplicationInfo>,
- max_api_version: Version,
- extensions: &InstanceExtensions,
- layers: L,
- ) -> Result<Arc<Instance>, InstanceCreationError>
- where
- L: IntoIterator<Item = &'a str>,
- {
- let layers = layers
- .into_iter()
- .map(|layer| CString::new(layer).unwrap())
- .collect::<SmallVec<[_; 16]>>();
-
- Instance::new_inner(
- app_infos,
- max_api_version,
- extensions,
- layers,
- OwnedOrRef::Owned(loader),
- )
- }
-
- fn new_inner(
- app_infos: Option<&ApplicationInfo>,
- max_api_version: Version,
- extensions: &InstanceExtensions,
- layers: SmallVec<[CString; 16]>,
- function_pointers: OwnedOrRef<FunctionPointers<Box<dyn Loader + Send + Sync>>>,
- ) -> Result<Arc<Instance>, InstanceCreationError> {
- let api_version = std::cmp::min(max_api_version, function_pointers.api_version()?);
-
- // Check if the extensions are correct
- extensions.check_requirements(
- &InstanceExtensions::supported_by_core_with_loader(&function_pointers)?,
- api_version,
- )?;
-
- // TODO: For now there are still buggy drivers that will segfault if you don't pass any
- // appinfos. Therefore for now we ensure that it can't be `None`.
- let def = Default::default();
- let app_infos = match app_infos {
- Some(a) => Some(a),
- None => Some(&def),
- };
-
- // Building the CStrings from the `str`s within `app_infos`.
- // They need to be created ahead of time, since we pass pointers to them.
- let app_infos_strings = if let Some(app_infos) = app_infos {
- Some((
- app_infos
- .application_name
- .clone()
- .map(|n| CString::new(n.as_bytes().to_owned()).unwrap()),
- app_infos
- .engine_name
- .clone()
- .map(|n| CString::new(n.as_bytes().to_owned()).unwrap()),
- ))
- } else {
- None
- };
-
- // Building the `vk::ApplicationInfo` if required.
- let app_infos = if let Some(app_infos) = app_infos {
- Some(ash::vk::ApplicationInfo {
- p_application_name: app_infos_strings
- .as_ref()
- .unwrap()
- .0
- .as_ref()
- .map(|s| s.as_ptr())
- .unwrap_or(ptr::null()),
- application_version: app_infos
- .application_version
- .map(|v| v.try_into().expect("Version out of range"))
- .unwrap_or(0),
- p_engine_name: app_infos_strings
- .as_ref()
- .unwrap()
- .1
- .as_ref()
- .map(|s| s.as_ptr())
- .unwrap_or(ptr::null()),
- engine_version: app_infos
- .engine_version
- .map(|v| v.try_into().expect("Version out of range"))
- .unwrap_or(0),
- api_version: max_api_version.try_into().expect("Version out of range"),
- ..Default::default()
- })
- } else {
- None
- };
-
- // FIXME: check whether each layer is supported
- let layers_ptrs = layers
- .iter()
- .map(|layer| layer.as_ptr())
- .collect::<SmallVec<[_; 16]>>();
-
- let extensions_list: Vec<CString> = extensions.into();
- let extensions_ptrs = extensions_list
- .iter()
- .map(|extension| extension.as_ptr())
- .collect::<SmallVec<[_; 32]>>();
-
- // Creating the Vulkan instance.
- let instance = unsafe {
- let mut output = MaybeUninit::uninit();
- let infos = ash::vk::InstanceCreateInfo {
- flags: ash::vk::InstanceCreateFlags::empty(),
- p_application_info: if let Some(app) = app_infos.as_ref() {
- app as *const _
- } else {
- ptr::null()
- },
- enabled_layer_count: layers_ptrs.len() as u32,
- pp_enabled_layer_names: layers_ptrs.as_ptr(),
- enabled_extension_count: extensions_ptrs.len() as u32,
- pp_enabled_extension_names: extensions_ptrs.as_ptr(),
- ..Default::default()
- };
-
- let fns = function_pointers.fns();
- check_errors(
- fns.v1_0
- .create_instance(&infos, ptr::null(), output.as_mut_ptr()),
- )?;
- output.assume_init()
- };
-
- // Loading the function pointers of the newly-created instance.
- let fns = {
- InstanceFunctions::load(|name| {
- function_pointers.get_instance_proc_addr(instance, name.as_ptr())
- })
- };
-
- let mut instance = Instance {
- instance,
- api_version,
- max_api_version,
- //alloc: None,
- physical_device_infos: Vec::new(),
- fns,
- extensions: extensions.clone(),
- layers,
- function_pointers,
- };
-
- // Enumerating all physical devices.
- instance.physical_device_infos = init_physical_devices(&instance)?;
-
- Ok(Arc::new(instance))
- }
-
- /*/// Same as `new`, but provides an allocator that will be used by the Vulkan library whenever
- /// it needs to allocate memory on the host.
- ///
- /// Note that this allocator can be overridden when you create a `Device`, a `MemoryPool`, etc.
- pub fn with_alloc(app_infos: Option<&ApplicationInfo>, alloc: Box<Alloc + Send + Sync>) -> Arc<Instance> {
- unimplemented!()
- }*/
-
- /// Returns the Vulkan version supported by the instance.
- ///
- /// This is the lower of the
- /// [driver's supported version](crate::instance::loader::FunctionPointers::api_version) and
- /// [`max_api_version`](Instance::max_api_version).
- #[inline]
- pub fn api_version(&self) -> Version {
- self.api_version
- }
-
- /// Returns the maximum Vulkan version that was specified when creating the instance.
- #[inline]
- pub fn max_api_version(&self) -> Version {
- self.max_api_version
- }
-
- /// Grants access to the Vulkan functions of the instance.
- #[inline]
- pub fn fns(&self) -> &InstanceFunctions {
- &self.fns
- }
-
- /// Returns the extensions that have been enabled on the instance.
- #[inline]
- pub fn enabled_extensions(&self) -> &InstanceExtensions {
- &self.extensions
- }
-
- /// Returns the layers that have been enabled on the instance.
- #[doc(hidden)]
- #[inline]
- pub fn enabled_layers(&self) -> slice::Iter<CString> {
- self.layers.iter()
- }
-}
-
-impl fmt::Debug for Instance {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(fmt, "<Vulkan instance {:?}>", self.instance)
- }
-}
-
-unsafe impl VulkanObject for Instance {
- type Object = ash::vk::Instance;
-
- #[inline]
- fn internal_object(&self) -> ash::vk::Instance {
- self.instance
- }
-}
-
-impl Drop for Instance {
- #[inline]
- fn drop(&mut self) {
- unsafe {
- self.fns.v1_0.destroy_instance(self.instance, ptr::null());
- }
- }
-}
-
-impl PartialEq for Instance {
- #[inline]
- fn eq(&self, other: &Self) -> bool {
- self.instance == other.instance
- }
-}
-
-impl Eq for Instance {}
-
-impl Hash for Instance {
- #[inline]
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.instance.hash(state);
- }
-}
-
-// Same as Cow but less annoying.
-enum OwnedOrRef<T: 'static> {
- Owned(T),
- Ref(&'static T),
-}
-
-impl<T> Deref for OwnedOrRef<T> {
- type Target = T;
- #[inline]
- fn deref(&self) -> &T {
- match *self {
- OwnedOrRef::Owned(ref v) => v,
- OwnedOrRef::Ref(v) => v,
- }
- }
-}
-
-/// Information that can be given to the Vulkan driver so that it can identify your application.
-// TODO: better documentation for struct and methods
-#[derive(Debug, Clone)]
-pub struct ApplicationInfo<'a> {
- /// Name of the application.
- pub application_name: Option<Cow<'a, str>>,
- /// An opaque number that contains the version number of the application.
- pub application_version: Option<Version>,
- /// Name of the engine used to power the application.
- pub engine_name: Option<Cow<'a, str>>,
- /// An opaque number that contains the version number of the engine.
- pub engine_version: Option<Version>,
-}
-
-impl<'a> ApplicationInfo<'a> {
- /// Builds an `ApplicationInfo` from the information gathered by Cargo.
- ///
- /// # Panic
- ///
- /// - Panics if the required environment variables are missing, which happens if the project
- /// wasn't built by Cargo.
- ///
- #[deprecated(note = "Please use the `app_info_from_cargo_toml!` macro instead")]
- pub fn from_cargo_toml() -> ApplicationInfo<'a> {
- let version = Version {
- major: 0,
- minor: 0,
- patch: 0,
- };
-
- let name = "";
-
- ApplicationInfo {
- application_name: Some(name.into()),
- application_version: Some(version),
- engine_name: None,
- engine_version: None,
- }
- }
-}
-
-/// Builds an `ApplicationInfo` from the information gathered by Cargo.
-///
-/// # Panic
-///
-/// - Panics if the required environment variables are missing, which happens if the project
-/// wasn't built by Cargo.
-///
-#[macro_export]
-macro_rules! app_info_from_cargo_toml {
- () => {{
- let version = $crate::instance::Version {
- major: 0,
- minor: 0,
- patch: 0,
- };
-
- let name = "";
-
- $crate::instance::ApplicationInfo {
- application_name: Some(name.into()),
- application_version: Some(version),
- engine_name: None,
- engine_version: None,
- }
- }};
-}
-
-impl<'a> Default for ApplicationInfo<'a> {
- fn default() -> ApplicationInfo<'a> {
- ApplicationInfo {
- application_name: None,
- application_version: None,
- engine_name: None,
- engine_version: None,
- }
- }
-}
-
-/// Error that can happen when creating an instance.
-#[derive(Clone, Debug)]
-pub enum InstanceCreationError {
- /// Failed to load the Vulkan shared library.
- LoadingError(LoadingError),
- /// Not enough memory.
- OomError(OomError),
- /// Failed to initialize for an implementation-specific reason.
- InitializationFailed,
- /// One of the requested layers is missing.
- LayerNotPresent,
- /// One of the requested extensions is not supported by the implementation.
- ExtensionNotPresent,
- /// The version requested is not supported by the implementation.
- IncompatibleDriver,
- /// A restriction for an extension was not met.
- ExtensionRestrictionNotMet(ExtensionRestrictionError),
-}
-
-impl error::Error for InstanceCreationError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- InstanceCreationError::LoadingError(ref err) => Some(err),
- InstanceCreationError::OomError(ref err) => Some(err),
- _ => None,
- }
- }
-}
-
-impl fmt::Display for InstanceCreationError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- match *self {
- InstanceCreationError::LoadingError(_) => {
- write!(fmt, "failed to load the Vulkan shared library")
- }
- InstanceCreationError::OomError(_) => write!(fmt, "not enough memory available"),
- InstanceCreationError::InitializationFailed => write!(fmt, "initialization failed"),
- InstanceCreationError::LayerNotPresent => write!(fmt, "layer not present"),
- InstanceCreationError::ExtensionNotPresent => write!(fmt, "extension not present"),
- InstanceCreationError::IncompatibleDriver => write!(fmt, "incompatible driver"),
- InstanceCreationError::ExtensionRestrictionNotMet(err) => err.fmt(fmt),
- }
- }
-}
-
-impl From<OomError> for InstanceCreationError {
- #[inline]
- fn from(err: OomError) -> InstanceCreationError {
- InstanceCreationError::OomError(err)
- }
-}
-
-impl From<LoadingError> for InstanceCreationError {
- #[inline]
- fn from(err: LoadingError) -> InstanceCreationError {
- InstanceCreationError::LoadingError(err)
- }
-}
-
-impl From<ExtensionRestrictionError> for InstanceCreationError {
- #[inline]
- fn from(err: ExtensionRestrictionError) -> Self {
- Self::ExtensionRestrictionNotMet(err)
- }
-}
-
-impl From<Error> for InstanceCreationError {
- #[inline]
- fn from(err: Error) -> InstanceCreationError {
- match err {
- err @ Error::OutOfHostMemory => InstanceCreationError::OomError(OomError::from(err)),
- err @ Error::OutOfDeviceMemory => InstanceCreationError::OomError(OomError::from(err)),
- Error::InitializationFailed => InstanceCreationError::InitializationFailed,
- Error::LayerNotPresent => InstanceCreationError::LayerNotPresent,
- Error::ExtensionNotPresent => InstanceCreationError::ExtensionNotPresent,
- Error::IncompatibleDriver => InstanceCreationError::IncompatibleDriver,
- _ => panic!("unexpected error: {:?}", err),
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use crate::device::physical::PhysicalDevice;
-
- #[test]
- fn create_instance() {
- let _ = instance!();
- }
-
- #[test]
- fn queue_family_by_id() {
- let instance = instance!();
-
- let phys = match PhysicalDevice::enumerate(&instance).next() {
- Some(p) => p,
- None => return,
- };
-
- let queue_family = match phys.queue_families().next() {
- Some(q) => q,
- None => return,
- };
-
- let by_id = phys.queue_family_by_id(queue_family.id()).unwrap();
- assert_eq!(by_id.id(), queue_family.id());
- }
-}
diff --git a/src/instance/layers.rs b/src/instance/layers.rs
index 6c56090..3ea264b 100644
--- a/src/instance/layers.rs
+++ b/src/instance/layers.rs
@@ -7,79 +7,13 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use std::error;
-use std::ffi::CStr;
-use std::fmt;
-use std::ptr;
-use std::vec::IntoIter;
-
-use crate::check_errors;
-use crate::instance::loader;
-use crate::instance::loader::LoadingError;
-use crate::Error;
-use crate::OomError;
use crate::Version;
-
-/// Queries the list of layers that are available when creating an instance.
-///
-/// On success, this function returns an iterator that produces
-/// [`LayerProperties`](struct.LayerProperties.html) objects. In order to enable a layer, you need
-/// to pass its name (returned by `LayerProperties::name()`) when creating the
-/// [`Instance`](struct.Instance.html).
-///
-/// This function returns an error if it failed to load the Vulkan library.
-///
-/// > **Note**: It is possible that one of the layers enumerated here is no longer available when
-/// > you create the `Instance`. This will lead to an error when calling `Instance::new`. The
-/// > author isn't aware of any situation where this would happen, but it is theoretically possible
-/// > according to the specifications.
-///
-/// # Example
-///
-/// ```no_run
-/// use vulkano::instance;
-///
-/// for layer in instance::layers_list().unwrap() {
-/// println!("Available layer: {}", layer.name());
-/// }
-/// ```
-pub fn layers_list() -> Result<LayersIterator, LayersListError> {
- layers_list_from_loader(loader::auto_loader()?)
-}
-
-/// Same as `layers_list()`, but allows specifying a loader.
-pub fn layers_list_from_loader<L>(
- ptrs: &loader::FunctionPointers<L>,
-) -> Result<LayersIterator, LayersListError>
-where
- L: loader::Loader,
-{
- unsafe {
- let fns = ptrs.fns();
-
- let mut num = 0;
- check_errors(
- fns.v1_0
- .enumerate_instance_layer_properties(&mut num, ptr::null_mut()),
- )?;
-
- let mut layers: Vec<ash::vk::LayerProperties> = Vec::with_capacity(num as usize);
- check_errors({
- fns.v1_0
- .enumerate_instance_layer_properties(&mut num, layers.as_mut_ptr())
- })?;
- layers.set_len(num as usize);
-
- Ok(LayersIterator {
- iter: layers.into_iter(),
- })
- }
-}
+use std::ffi::CStr;
/// Properties of a layer.
#[derive(Clone)]
pub struct LayerProperties {
- props: ash::vk::LayerProperties,
+ pub(crate) props: ash::vk::LayerProperties,
}
impl LayerProperties {
@@ -88,12 +22,14 @@ impl LayerProperties {
/// If you want to enable this layer on an instance, you need to pass this value to
/// `Instance::new`.
///
- /// # Example
+ /// # Examples
///
/// ```no_run
- /// use vulkano::instance;
+ /// use vulkano::VulkanLibrary;
///
- /// for layer in instance::layers_list().unwrap() {
+ /// let library = VulkanLibrary::new().unwrap();
+ ///
+ /// for layer in library.layer_properties().unwrap() {
/// println!("Layer name: {}", layer.name());
/// }
/// ```
@@ -110,12 +46,14 @@ impl LayerProperties {
///
/// This description is chosen by the layer itself.
///
- /// # Example
+ /// # Examples
///
/// ```no_run
- /// use vulkano::instance;
+ /// use vulkano::VulkanLibrary;
+ ///
+ /// let library = VulkanLibrary::new().unwrap();
///
- /// for layer in instance::layers_list().unwrap() {
+ /// for layer in library.layer_properties().unwrap() {
/// println!("Layer description: {}", layer.description());
/// }
/// ```
@@ -130,13 +68,14 @@ impl LayerProperties {
/// Returns the version of Vulkan supported by this layer.
///
- /// # Example
+ /// # Examples
///
/// ```no_run
- /// use vulkano::instance;
- /// use vulkano::instance::Version;
+ /// use vulkano::{Version, VulkanLibrary};
+ ///
+ /// let library = VulkanLibrary::new().unwrap();
///
- /// for layer in instance::layers_list().unwrap() {
+ /// for layer in library.layer_properties().unwrap() {
/// if layer.vulkan_version() >= Version::major_minor(2, 0) {
/// println!("Layer {} requires Vulkan 2.0", layer.name());
/// }
@@ -151,12 +90,14 @@ impl LayerProperties {
///
/// The number is chosen by the layer itself. It can be used for bug reports for example.
///
- /// # Example
+ /// # Examples
///
/// ```no_run
- /// use vulkano::instance;
+ /// use vulkano::VulkanLibrary;
///
- /// for layer in instance::layers_list().unwrap() {
+ /// let library = VulkanLibrary::new().unwrap();
+ ///
+ /// for layer in library.layer_properties().unwrap() {
/// println!("Layer {} - Version: {}", layer.name(), layer.implementation_version());
/// }
/// ```
@@ -166,97 +107,22 @@ impl LayerProperties {
}
}
-/// Error that can happen when loading the list of layers.
-#[derive(Clone, Debug)]
-pub enum LayersListError {
- /// Failed to load the Vulkan shared library.
- LoadingError(LoadingError),
- /// Not enough memory.
- OomError(OomError),
-}
-
-impl error::Error for LayersListError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- LayersListError::LoadingError(ref err) => Some(err),
- LayersListError::OomError(ref err) => Some(err),
- }
- }
-}
-
-impl fmt::Display for LayersListError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- LayersListError::LoadingError(_) => "failed to load the Vulkan shared library",
- LayersListError::OomError(_) => "not enough memory available",
- }
- )
- }
-}
-
-impl From<OomError> for LayersListError {
- #[inline]
- fn from(err: OomError) -> LayersListError {
- LayersListError::OomError(err)
- }
-}
-
-impl From<LoadingError> for LayersListError {
- #[inline]
- fn from(err: LoadingError) -> LayersListError {
- LayersListError::LoadingError(err)
- }
-}
-
-impl From<Error> for LayersListError {
- #[inline]
- fn from(err: Error) -> LayersListError {
- match err {
- err @ Error::OutOfHostMemory => LayersListError::OomError(OomError::from(err)),
- err @ Error::OutOfDeviceMemory => LayersListError::OomError(OomError::from(err)),
- _ => panic!("unexpected error: {:?}", err),
- }
- }
-}
-
-/// Iterator that produces the list of layers that are available.
-// TODO: #[derive(Debug, Clone)]
-pub struct LayersIterator {
- iter: IntoIter<ash::vk::LayerProperties>,
-}
-
-impl Iterator for LayersIterator {
- type Item = LayerProperties;
-
- #[inline]
- fn next(&mut self) -> Option<LayerProperties> {
- self.iter.next().map(|p| LayerProperties { props: p })
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.iter.size_hint()
- }
-}
-
-impl ExactSizeIterator for LayersIterator {}
-
#[cfg(test)]
mod tests {
- use crate::instance;
+ use crate::VulkanLibrary;
#[test]
fn layers_list() {
- let mut list = match instance::layers_list() {
+ let library = match VulkanLibrary::new() {
+ Ok(x) => x,
+ Err(_) => return,
+ };
+
+ let list = match library.layer_properties() {
Ok(l) => l,
Err(_) => return,
};
- while let Some(_) = list.next() {}
+ for _ in list {}
}
}
diff --git a/src/instance/loader.rs b/src/instance/loader.rs
deleted file mode 100644
index 7714fd2..0000000
--- a/src/instance/loader.rs
+++ /dev/null
@@ -1,316 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-//! Vulkan implementation loading system.
-//!
-//! Before vulkano can do anything, it first needs to find an implementation of Vulkan. A Vulkan
-//! implementation is defined as a single `vkGetInstanceProcAddr` function, which can be accessed
-//! through the `Loader` trait.
-//!
-//! This module provides various implementations of the `Loader` trait.
-//!
-//! Once you have a struct that implements `Loader`, you can create a `FunctionPointers` struct
-//! from it and use this `FunctionPointers` struct to build an `Instance`.
-//!
-//! By default vulkano will use the `auto_loader()` function, which tries to automatically load
-//! a Vulkan implementation from the system.
-
-use crate::check_errors;
-use crate::fns::EntryFunctions;
-use crate::OomError;
-use crate::SafeDeref;
-use crate::Version;
-use lazy_static::lazy_static;
-use shared_library;
-use std::error;
-use std::ffi::CStr;
-use std::fmt;
-use std::mem;
-use std::ops::Deref;
-use std::os::raw::c_char;
-use std::os::raw::c_void;
-use std::path::Path;
-
-/// Implemented on objects that grant access to a Vulkan implementation.
-pub unsafe trait Loader {
- /// Calls the `vkGetInstanceProcAddr` function. The parameters are the same.
- ///
- /// The returned function must stay valid for as long as `self` is alive.
- fn get_instance_proc_addr(
- &self,
- instance: ash::vk::Instance,
- name: *const c_char,
- ) -> *const c_void;
-}
-
-unsafe impl<T> Loader for T
-where
- T: SafeDeref,
- T::Target: Loader,
-{
- #[inline]
- fn get_instance_proc_addr(
- &self,
- instance: ash::vk::Instance,
- name: *const c_char,
- ) -> *const c_void {
- (**self).get_instance_proc_addr(instance, name)
- }
-}
-
-/// Implementation of `Loader` that loads Vulkan from a dynamic library.
-pub struct DynamicLibraryLoader {
- vk_lib: shared_library::dynamic_library::DynamicLibrary,
- get_proc_addr:
- extern "system" fn(instance: ash::vk::Instance, pName: *const c_char) -> *const c_void,
-}
-
-impl DynamicLibraryLoader {
- /// Tries to load the dynamic library at the given path, and tries to
- /// load `vkGetInstanceProcAddr` in it.
- ///
- /// # Safety
- ///
- /// - The dynamic library must be a valid Vulkan implementation.
- ///
- pub unsafe fn new<P>(path: P) -> Result<DynamicLibraryLoader, LoadingError>
- where
- P: AsRef<Path>,
- {
- let vk_lib = shared_library::dynamic_library::DynamicLibrary::open(Some(path.as_ref()))
- .map_err(LoadingError::LibraryLoadFailure)?;
-
- let get_proc_addr = {
- let ptr: *mut c_void = vk_lib
- .symbol("vkGetInstanceProcAddr")
- .map_err(|_| LoadingError::MissingEntryPoint("vkGetInstanceProcAddr".to_owned()))?;
- mem::transmute(ptr)
- };
-
- Ok(DynamicLibraryLoader {
- vk_lib,
- get_proc_addr,
- })
- }
-}
-
-unsafe impl Loader for DynamicLibraryLoader {
- #[inline]
- fn get_instance_proc_addr(
- &self,
- instance: ash::vk::Instance,
- name: *const c_char,
- ) -> *const c_void {
- (self.get_proc_addr)(instance, name)
- }
-}
-
-/// Wraps around a loader and contains function pointers.
-pub struct FunctionPointers<L> {
- loader: L,
- fns: EntryFunctions,
-}
-
-impl<L> FunctionPointers<L> {
- /// Loads some global function pointer from the loader.
- pub fn new(loader: L) -> FunctionPointers<L>
- where
- L: Loader,
- {
- let fns = EntryFunctions::load(|name| unsafe {
- mem::transmute(loader.get_instance_proc_addr(ash::vk::Instance::null(), name.as_ptr()))
- });
-
- FunctionPointers { loader, fns }
- }
-
- /// Returns the collection of Vulkan entry points from the Vulkan loader.
- #[inline]
- pub fn fns(&self) -> &EntryFunctions {
- &self.fns
- }
-
- /// Returns the highest Vulkan version that is supported for instances.
- pub fn api_version(&self) -> Result<Version, OomError>
- where
- L: Loader,
- {
- // Per the Vulkan spec:
- // If the vkGetInstanceProcAddr returns NULL for vkEnumerateInstanceVersion, it is a
- // Vulkan 1.0 implementation. Otherwise, the application can call vkEnumerateInstanceVersion
- // to determine the version of Vulkan.
- unsafe {
- let name = CStr::from_bytes_with_nul_unchecked(b"vkEnumerateInstanceVersion\0");
- let func = self.get_instance_proc_addr(ash::vk::Instance::null(), name.as_ptr());
-
- if func.is_null() {
- Ok(Version {
- major: 1,
- minor: 0,
- patch: 0,
- })
- } else {
- type Pfn = extern "system" fn(pApiVersion: *mut u32) -> ash::vk::Result;
- let func: Pfn = mem::transmute(func);
- let mut api_version = 0;
- check_errors(func(&mut api_version))?;
- Ok(Version::from(api_version))
- }
- }
- }
-
- /// Calls `get_instance_proc_addr` on the underlying loader.
- #[inline]
- pub fn get_instance_proc_addr(
- &self,
- instance: ash::vk::Instance,
- name: *const c_char,
- ) -> *const c_void
- where
- L: Loader,
- {
- self.loader.get_instance_proc_addr(instance, name)
- }
-}
-
-/// Expression that returns a loader that assumes that Vulkan is linked to the executable you're
-/// compiling.
-///
-/// If you use this macro, you must linked to a library that provides the `vkGetInstanceProcAddr`
-/// symbol.
-///
-/// This is provided as a macro and not as a regular function, because the macro contains an
-/// `extern {}` block.
-// TODO: should this be unsafe?
-#[macro_export]
-macro_rules! statically_linked_vulkan_loader {
- () => {{
- extern "C" {
- fn vkGetInstanceProcAddr(
- instance: ash::vk::Instance,
- pName: *const c_char,
- ) -> ash::vk::PFN_vkVoidFunction;
- }
-
- struct StaticallyLinkedVulkanLoader;
- unsafe impl Loader for StaticallyLinkedVulkanLoader {
- fn get_instance_proc_addr(
- &self,
- instance: ash::vk::Instance,
- name: *const c_char,
- ) -> extern "system" fn() -> () {
- unsafe { vkGetInstanceProcAddr(instance, name) }
- }
- }
-
- StaticallyLinkedVulkanLoader
- }};
-}
-
-/// Returns the default `FunctionPointers` for this system.
-///
-/// This function tries to auto-guess where to find the Vulkan implementation, and loads it in a
-/// `lazy_static!`. The content of the lazy_static is then returned, or an error if we failed to
-/// load Vulkan.
-pub fn auto_loader(
-) -> Result<&'static FunctionPointers<Box<dyn Loader + Send + Sync>>, LoadingError> {
- #[cfg(target_os = "ios")]
- #[allow(non_snake_case)]
- fn def_loader_impl() -> Result<Box<Loader + Send + Sync>, LoadingError> {
- let loader = statically_linked_vulkan_loader!();
- Ok(Box::new(loader))
- }
-
- #[cfg(not(target_os = "ios"))]
- fn def_loader_impl() -> Result<Box<dyn Loader + Send + Sync>, LoadingError> {
- #[cfg(windows)]
- fn get_path() -> &'static Path {
- Path::new("vulkan-1.dll")
- }
- #[cfg(all(unix, not(target_os = "android"), not(target_os = "macos")))]
- fn get_path() -> &'static Path {
- Path::new("libvulkan.so.1")
- }
- #[cfg(target_os = "macos")]
- fn get_path() -> &'static Path {
- Path::new("libvulkan.1.dylib")
- }
- #[cfg(target_os = "android")]
- fn get_path() -> &'static Path {
- Path::new("libvulkan.so")
- }
-
- let loader = unsafe { DynamicLibraryLoader::new(get_path())? };
-
- Ok(Box::new(loader))
- }
-
- lazy_static! {
- static ref DEFAULT_LOADER: Result<FunctionPointers<Box<dyn Loader + Send + Sync>>, LoadingError> =
- def_loader_impl().map(FunctionPointers::new);
- }
-
- match DEFAULT_LOADER.deref() {
- &Ok(ref ptr) => Ok(ptr),
- &Err(ref err) => Err(err.clone()),
- }
-}
-
-/// Error that can happen when loading the Vulkan loader.
-#[derive(Debug, Clone)]
-pub enum LoadingError {
- /// Failed to load the Vulkan shared library.
- LibraryLoadFailure(String), // TODO: meh for error type, but this needs changes in shared_library
-
- /// One of the entry points required to be supported by the Vulkan implementation is missing.
- MissingEntryPoint(String),
-}
-
-impl error::Error for LoadingError {
- /*#[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- LoadingError::LibraryLoadFailure(ref err) => Some(err),
- _ => None
- }
- }*/
-}
-
-impl fmt::Display for LoadingError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- LoadingError::LibraryLoadFailure(_) => "failed to load the Vulkan shared library",
- LoadingError::MissingEntryPoint(_) => {
- "one of the entry points required to be supported by the Vulkan implementation \
- is missing"
- }
- }
- )
- }
-}
-
-#[cfg(test)]
-mod tests {
- use crate::instance::loader::DynamicLibraryLoader;
- use crate::instance::loader::LoadingError;
-
- #[test]
- fn dl_open_error() {
- unsafe {
- match DynamicLibraryLoader::new("_non_existing_library.void") {
- Err(LoadingError::LibraryLoadFailure(_)) => (),
- _ => panic!(),
- }
- }
- }
-}
diff --git a/src/instance/mod.rs b/src/instance/mod.rs
index 5e85e7f..55e0626 100644
--- a/src/instance/mod.rs
+++ b/src/instance/mod.rs
@@ -9,32 +9,35 @@
//! API entry point.
//!
-//! The first thing to do before you start using Vulkan is to create an `Instance` object.
+//! The first thing to do after loading the Vulkan library is to create an `Instance` object.
//!
//! For example:
//!
//! ```no_run
-//! use vulkano::instance::Instance;
-//! use vulkano::instance::InstanceExtensions;
-//! use vulkano::Version;
-//!
-//! let instance = match Instance::new(None, Version::V1_1, &InstanceExtensions::none(), None) {
-//! Ok(i) => i,
-//! Err(err) => panic!("Couldn't build instance: {:?}", err)
+//! use vulkano::{
+//! instance::{Instance, InstanceExtensions},
+//! Version, VulkanLibrary,
//! };
+//!
+//! let library = VulkanLibrary::new()
+//! .unwrap_or_else(|err| panic!("Couldn't load Vulkan library: {:?}", err));
+//! let instance = Instance::new(library, Default::default())
+//! .unwrap_or_else(|err| panic!("Couldn't create instance: {:?}", err));
//! ```
//!
//! Creating an instance initializes everything and allows you to enumerate physical devices,
//! ie. all the Vulkan implementations that are available on the system.
//!
//! ```no_run
-//! # use vulkano::instance::Instance;
-//! # use vulkano::instance::InstanceExtensions;
-//! # use vulkano::Version;
+//! # use vulkano::{
+//! # instance::{Instance, InstanceExtensions},
+//! # Version, VulkanLibrary,
+//! # };
//! use vulkano::device::physical::PhysicalDevice;
//!
-//! # let instance = Instance::new(None, Version::V1_1, &InstanceExtensions::none(), None).unwrap();
-//! for physical_device in PhysicalDevice::enumerate(&instance) {
+//! # let library = VulkanLibrary::new().unwrap();
+//! # let instance = Instance::new(library, Default::default()).unwrap();
+//! for physical_device in instance.enumerate_physical_devices().unwrap() {
//! println!("Available device: {}", physical_device.properties().device_name);
//! }
//! ```
@@ -42,7 +45,7 @@
//! # Enumerating physical devices and creating a device
//!
//! After you have created an instance, the next step is usually to enumerate the physical devices
-//! that are available on the system with `PhysicalDevice::enumerate()` (see above).
+//! that are available on the system with `Instance::enumerate_physical_devices()` (see above).
//!
//! When choosing which physical device to use, keep in mind that physical devices may or may not
//! be able to draw to a certain surface (ie. to a window or a monitor), or may even not be able
@@ -50,23 +53,844 @@
//!
//! Once you have chosen a physical device, you can create a `Device` object from it. See the
//! `device` module for more info.
+//!
+//! # Portability subset devices and the `enumerate_portability` flag
+//!
+//! Certain devices, currently those on MacOS and iOS systems, do not fully conform to the Vulkan
+//! specification. They are usable as normal devices, but they do not implement everything that
+//! is required; some mandatory parts of Vulkan are missing. These are known as
+//! "portability subset" devices.
+//!
+//! A portability subset device will advertise support for the
+//! [`khr_portability_subset`](crate::device::DeviceExtensions::khr_portability_subset) device
+//! extension. This extension must always be enabled when it is supported, and Vulkano will
+//! automatically enable it when creating the device. When it is enabled, some parts of Vulkan that
+//! are available in standard Vulkan will not be available by default, but they can be used by
+//! enabling corresponding features when creating the device, if the device supports them.
+//!
+//! Because these devices are non-conformant, Vulkan programs that rely on full compliance may
+//! not work (crash or have validation errors) when run on them, if they happen to use a part of
+//! Vulkan that is missing from the non-conformant device. Therefore, Vulkan hides them from
+//! the user by default when calling `enumerate_physical_devices` on the instance. If there are no
+//! conformant devices on the system, `Instance::new` will return an `IncompatibleDriver` error.
+//!
+//! In order to enumerate portability subset devices, you must set the
+//! [`InstanceCreateInfo::enumerate_portability`] flag when creating the instance. However, if you
+//! do this, your program must be prepared to handle the non-conformant aspects of these devices,
+//! and must enable the appropriate features when creating the `Device` if you intend to use them.
-pub use self::extensions::InstanceExtensions;
-pub use self::instance::ApplicationInfo;
-pub use self::instance::Instance;
-pub use self::instance::InstanceCreationError;
-pub use self::layers::layers_list;
-pub use self::layers::LayerProperties;
-pub use self::layers::LayersIterator;
-pub use self::layers::LayersListError;
-pub use self::loader::LoadingError;
-pub use crate::extensions::{
- ExtensionRestriction, ExtensionRestrictionError, SupportedExtensionsError,
+use self::debug::{
+ DebugUtilsMessengerCreateInfo, UserCallback, ValidationFeatureDisable, ValidationFeatureEnable,
+};
+pub use self::{extensions::InstanceExtensions, layers::LayerProperties};
+use crate::{
+ device::physical::PhysicalDevice, instance::debug::trampoline, macros::impl_id_counter,
+ OomError, RequiresOneOf, VulkanError, VulkanLibrary, VulkanObject,
+};
+pub use crate::{
+ extensions::{ExtensionRestriction, ExtensionRestrictionError},
+ fns::InstanceFunctions,
+ version::Version,
+};
+use smallvec::SmallVec;
+use std::{
+ error::Error,
+ ffi::{c_void, CString},
+ fmt::{Debug, Display, Error as FmtError, Formatter},
+ mem::MaybeUninit,
+ num::NonZeroU64,
+ panic::{RefUnwindSafe, UnwindSafe},
+ ptr,
+ sync::Arc,
};
-pub use crate::version::Version;
pub mod debug;
pub(crate) mod extensions;
-mod instance;
mod layers;
-pub mod loader;
+
+/// An instance of a Vulkan context. This is the main object that should be created by an
+/// application before everything else.
+///
+/// # Application and engine info
+///
+/// When you create an instance, you have the possibility to set information about your application
+/// and its engine.
+///
+/// Providing this information allows for example the driver to let the user configure the driver's
+/// behavior for your application alone through a control panel.
+///
+/// ```no_run
+/// # #[macro_use] extern crate vulkano;
+/// # fn main() {
+/// use vulkano::{
+/// instance::{Instance, InstanceCreateInfo, InstanceExtensions},
+/// Version, VulkanLibrary,
+/// };
+///
+/// let library = VulkanLibrary::new().unwrap();
+/// let _instance = Instance::new(
+/// library,
+/// InstanceCreateInfo::application_from_cargo_toml(),
+/// ).unwrap();
+/// # }
+/// ```
+///
+/// # API versions
+///
+/// Both an `Instance` and a [`Device`](crate::device::Device) have a highest version of the Vulkan
+/// API that they support. This places a limit on what Vulkan functions and features are available
+/// to use when used on a particular instance or device. It is possible for the instance and the
+/// device to support different versions. The supported version for an instance can be queried
+/// before creation with
+/// [`VulkanLibrary::api_version`](crate::VulkanLibrary::api_version),
+/// while for a device it can be retrieved with
+/// [`PhysicalDevice::api_version`](crate::device::physical::PhysicalDevice::api_version).
+///
+/// When creating an `Instance`, you have to specify a maximum API version that you will use.
+/// This restricts the API version that is available for the instance and any devices created from
+/// it. For example, if both instance and device potentially support Vulkan 1.2, but you specify
+/// 1.1 as the maximum API version when creating the `Instance`, then you can only use Vulkan 1.1
+/// functions, even though they could theoretically support a higher version. You can think of it
+/// as a promise never to use any functionality from a higher version.
+///
+/// The maximum API version is not a _minimum_, so it is possible to set it to a higher version than
+/// what the instance or device inherently support. The final API version that you are able to use
+/// on an instance or device is the lower of the supported API version and the chosen maximum API
+/// version of the `Instance`.
+///
+/// Due to a quirk in how the Vulkan 1.0 specification was written, if the instance only
+/// supports Vulkan 1.0, then it is not possible to specify a maximum API version higher than 1.0.
+/// Trying to create an `Instance` will return an `IncompatibleDriver` error. Consequently, it is
+/// not possible to use a higher device API version with an instance that only supports 1.0.
+///
+/// # Extensions
+///
+/// When creating an `Instance`, you must provide a list of extensions that must be enabled on the
+/// newly-created instance. Trying to enable an extension that is not supported by the system will
+/// result in an error.
+///
+/// Contrary to OpenGL, it is not possible to use the features of an extension if it was not
+/// explicitly enabled.
+///
+/// Extensions are especially important to take into account if you want to render images on the
+/// screen, as the only way to do so is to use the `VK_KHR_surface` extension. More information
+/// about this in the `swapchain` module.
+///
+/// For example, here is how we create an instance with the `VK_KHR_surface` and
+/// `VK_KHR_android_surface` extensions enabled, which will allow us to render images to an
+/// Android screen. You can compile and run this code on any system, but it is highly unlikely to
+/// succeed on anything else than an Android-running device.
+///
+/// ```no_run
+/// use vulkano::{
+/// instance::{Instance, InstanceCreateInfo, InstanceExtensions},
+/// Version, VulkanLibrary,
+/// };
+///
+/// let library = VulkanLibrary::new()
+/// .unwrap_or_else(|err| panic!("Couldn't load Vulkan library: {:?}", err));
+///
+/// let extensions = InstanceExtensions {
+/// khr_surface: true,
+/// khr_android_surface: true,
+/// .. InstanceExtensions::empty()
+/// };
+///
+/// let instance = Instance::new(
+/// library,
+/// InstanceCreateInfo {
+/// enabled_extensions: extensions,
+/// ..Default::default()
+/// },
+/// )
+/// .unwrap_or_else(|err| panic!("Couldn't create instance: {:?}", err));
+/// ```
+///
+/// # Layers
+///
+/// When creating an `Instance`, you have the possibility to pass a list of **layers** that will
+/// be activated on the newly-created instance. The list of available layers can be retrieved by
+/// calling the [`layer_properties`](crate::VulkanLibrary::layer_properties) method of
+/// `VulkanLibrary`.
+///
+/// A layer is a component that will hook and potentially modify the Vulkan function calls.
+/// For example, activating a layer could add a frames-per-second counter on the screen, or it
+/// could send information to a debugger that will debug your application.
+///
+/// > **Note**: From an application's point of view, layers "just exist". In practice, on Windows
+/// > and Linux, layers can be installed by third party installers or by package managers and can
+/// > also be activated by setting the value of the `VK_INSTANCE_LAYERS` environment variable
+/// > before starting the program. See the documentation of the official Vulkan loader for these
+/// > platforms.
+///
+/// > **Note**: In practice, the most common use of layers right now is for debugging purposes.
+/// > To do so, you are encouraged to set the `VK_INSTANCE_LAYERS` environment variable on Windows
+/// > or Linux instead of modifying the source code of your program. For example:
+/// > `export VK_INSTANCE_LAYERS=VK_LAYER_LUNARG_api_dump` on Linux if you installed the Vulkan SDK
+/// > will print the list of raw Vulkan function calls.
+///
+/// ## Examples
+///
+/// ```
+/// # use std::{sync::Arc, error::Error};
+/// # use vulkano::{
+/// # instance::{Instance, InstanceCreateInfo, InstanceExtensions},
+/// # Version, VulkanLibrary,
+/// # };
+/// # fn test() -> Result<Arc<Instance>, Box<dyn Error>> {
+/// let library = VulkanLibrary::new()?;
+///
+/// // For the sake of the example, we activate all the layers that
+/// // contain the word "foo" in their description.
+/// let layers: Vec<_> = library.layer_properties()?
+/// .filter(|l| l.description().contains("foo"))
+/// .collect();
+///
+/// let instance = Instance::new(
+/// library,
+/// InstanceCreateInfo {
+/// enabled_layers: layers.iter().map(|l| l.name().to_owned()).collect(),
+/// ..Default::default()
+/// },
+/// )?;
+/// # Ok(instance)
+/// # }
+/// ```
+// TODO: mention that extensions must be supported by layers as well
+pub struct Instance {
+ handle: ash::vk::Instance,
+ fns: InstanceFunctions,
+ id: NonZeroU64,
+
+ api_version: Version,
+ enabled_extensions: InstanceExtensions,
+ enabled_layers: Vec<String>,
+ library: Arc<VulkanLibrary>,
+ max_api_version: Version,
+ _user_callbacks: Vec<Box<UserCallback>>,
+}
+
+// TODO: fix the underlying cause instead
+impl UnwindSafe for Instance {}
+impl RefUnwindSafe for Instance {}
+
+impl Instance {
+ /// Creates a new `Instance`.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if any version numbers in `create_info` contain a field too large to be converted
+ /// into a Vulkan version number.
+ /// - Panics if `create_info.max_api_version` is not at least `V1_0`.
+ pub fn new(
+ library: Arc<VulkanLibrary>,
+ create_info: InstanceCreateInfo,
+ ) -> Result<Arc<Instance>, InstanceCreationError> {
+ unsafe { Self::with_debug_utils_messengers(library, create_info, []) }
+ }
+
+ /// Creates a new `Instance` with debug messengers to use during the creation and destruction
+ /// of the instance.
+ ///
+ /// The debug messengers are not used at any other time,
+ /// [`DebugUtilsMessenger`](crate::instance::debug::DebugUtilsMessenger) should be used for
+ /// that.
+ ///
+ /// If `debug_utils_messengers` is not empty, the `ext_debug_utils` extension must be set in
+ /// `enabled_extensions`.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the `message_severity` or `message_type` members of any element of
+ /// `debug_utils_messengers` are empty.
+ ///
+ /// # Safety
+ ///
+ /// - The `user_callback` of each element of `debug_utils_messengers` must not make any calls
+ /// to the Vulkan API.
+ pub unsafe fn with_debug_utils_messengers(
+ library: Arc<VulkanLibrary>,
+ create_info: InstanceCreateInfo,
+ debug_utils_messengers: impl IntoIterator<Item = DebugUtilsMessengerCreateInfo>,
+ ) -> Result<Arc<Instance>, InstanceCreationError> {
+ let InstanceCreateInfo {
+ application_name,
+ application_version,
+ mut enabled_extensions,
+ enabled_layers,
+ engine_name,
+ engine_version,
+ max_api_version,
+ enumerate_portability,
+ enabled_validation_features,
+ disabled_validation_features,
+ _ne: _,
+ } = create_info;
+
+ let (api_version, max_api_version) = {
+ let api_version = library.api_version();
+ let max_api_version = if let Some(max_api_version) = max_api_version {
+ max_api_version
+ } else if api_version < Version::V1_1 {
+ api_version
+ } else {
+ Version::HEADER_VERSION
+ };
+
+ (std::cmp::min(max_api_version, api_version), max_api_version)
+ };
+
+ // VUID-VkApplicationInfo-apiVersion-04010
+ assert!(max_api_version >= Version::V1_0);
+ let supported_extensions =
+ library.supported_extensions_with_layers(enabled_layers.iter().map(String::as_str))?;
+ let mut flags = ash::vk::InstanceCreateFlags::empty();
+
+ if enumerate_portability && supported_extensions.khr_portability_enumeration {
+ enabled_extensions.khr_portability_enumeration = true;
+ flags |= ash::vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR;
+ }
+
+ // Check if the extensions are correct
+ enabled_extensions.check_requirements(&supported_extensions, api_version)?;
+
+ // FIXME: check whether each layer is supported
+ let enabled_layers_cstr: Vec<CString> = enabled_layers
+ .iter()
+ .map(|name| CString::new(name.clone()).unwrap())
+ .collect();
+ let enabled_layers_ptrs = enabled_layers_cstr
+ .iter()
+ .map(|layer| layer.as_ptr())
+ .collect::<SmallVec<[_; 2]>>();
+
+ let enabled_extensions_cstr: Vec<CString> = (&enabled_extensions).into();
+ let enabled_extensions_ptrs = enabled_extensions_cstr
+ .iter()
+ .map(|extension| extension.as_ptr())
+ .collect::<SmallVec<[_; 2]>>();
+
+ let application_name_cstr = application_name.map(|name| CString::new(name).unwrap());
+ let engine_name_cstr = engine_name.map(|name| CString::new(name).unwrap());
+ let application_info = ash::vk::ApplicationInfo {
+ p_application_name: application_name_cstr
+ .as_ref()
+ .map(|s| s.as_ptr())
+ .unwrap_or(ptr::null()),
+ application_version: application_version
+ .try_into()
+ .expect("Version out of range"),
+ p_engine_name: engine_name_cstr
+ .as_ref()
+ .map(|s| s.as_ptr())
+ .unwrap_or(ptr::null()),
+ engine_version: engine_version.try_into().expect("Version out of range"),
+ api_version: max_api_version.try_into().expect("Version out of range"),
+ ..Default::default()
+ };
+
+ let enable_validation_features_vk: SmallVec<[_; 5]> = enabled_validation_features
+ .iter()
+ .copied()
+ .map(Into::into)
+ .collect();
+ let disable_validation_features_vk: SmallVec<[_; 8]> = disabled_validation_features
+ .iter()
+ .copied()
+ .map(Into::into)
+ .collect();
+
+ let mut create_info_vk = ash::vk::InstanceCreateInfo {
+ flags,
+ p_application_info: &application_info,
+ enabled_layer_count: enabled_layers_ptrs.len() as u32,
+ pp_enabled_layer_names: enabled_layers_ptrs.as_ptr(),
+ enabled_extension_count: enabled_extensions_ptrs.len() as u32,
+ pp_enabled_extension_names: enabled_extensions_ptrs.as_ptr(),
+ ..Default::default()
+ };
+ let mut validation_features_vk = None;
+
+ if !enabled_validation_features.is_empty() || !disabled_validation_features.is_empty() {
+ if !enabled_extensions.ext_validation_features {
+ return Err(InstanceCreationError::RequirementNotMet {
+ required_for: "`create_info.enabled_validation_features` or \
+ `create_info.disabled_validation_features` are not empty",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["ext_validation_features"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkValidationFeaturesEXT-pEnabledValidationFeatures-02967
+ assert!(
+ !enabled_validation_features
+ .contains(&ValidationFeatureEnable::GpuAssistedReserveBindingSlot)
+ || enabled_validation_features.contains(&ValidationFeatureEnable::GpuAssisted)
+ );
+
+ // VUID-VkValidationFeaturesEXT-pEnabledValidationFeatures-02968
+ assert!(
+ !(enabled_validation_features.contains(&ValidationFeatureEnable::DebugPrintf)
+ && enabled_validation_features.contains(&ValidationFeatureEnable::GpuAssisted))
+ );
+
+ let next = validation_features_vk.insert(ash::vk::ValidationFeaturesEXT {
+ enabled_validation_feature_count: enable_validation_features_vk.len() as u32,
+ p_enabled_validation_features: enable_validation_features_vk.as_ptr(),
+ disabled_validation_feature_count: disable_validation_features_vk.len() as u32,
+ p_disabled_validation_features: disable_validation_features_vk.as_ptr(),
+ ..Default::default()
+ });
+
+ next.p_next = create_info_vk.p_next;
+ create_info_vk.p_next = next as *const _ as *const _;
+ }
+
+ // Handle debug messengers
+ let debug_utils_messengers = debug_utils_messengers.into_iter();
+ let mut debug_utils_messenger_create_infos =
+ Vec::with_capacity(debug_utils_messengers.size_hint().0);
+ let mut user_callbacks = Vec::with_capacity(debug_utils_messengers.size_hint().0);
+
+ for create_info in debug_utils_messengers {
+ let DebugUtilsMessengerCreateInfo {
+ message_type,
+ message_severity,
+ user_callback,
+ _ne: _,
+ } = create_info;
+
+ // VUID-VkInstanceCreateInfo-pNext-04926
+ if !enabled_extensions.ext_debug_utils {
+ return Err(InstanceCreationError::RequirementNotMet {
+ required_for: "`create_info.debug_utils_messengers` is not empty",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["ext_debug_utils"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkDebugUtilsMessengerCreateInfoEXT-messageSeverity-parameter
+ // TODO: message_severity.validate_instance()?;
+
+ // VUID-VkDebugUtilsMessengerCreateInfoEXT-messageSeverity-requiredbitmask
+ assert!(!message_severity.is_empty());
+
+ // VUID-VkDebugUtilsMessengerCreateInfoEXT-messageType-parameter
+ // TODO: message_type.validate_instance()?;
+
+ // VUID-VkDebugUtilsMessengerCreateInfoEXT-messageType-requiredbitmask
+ assert!(!message_type.is_empty());
+
+ // VUID-PFN_vkDebugUtilsMessengerCallbackEXT-None-04769
+ // Can't be checked, creation is unsafe.
+
+ let user_callback = Box::new(user_callback);
+ let create_info = ash::vk::DebugUtilsMessengerCreateInfoEXT {
+ flags: ash::vk::DebugUtilsMessengerCreateFlagsEXT::empty(),
+ message_severity: message_severity.into(),
+ message_type: message_type.into(),
+ pfn_user_callback: Some(trampoline),
+ p_user_data: &*user_callback as &Arc<_> as *const Arc<_> as *const c_void as *mut _,
+ ..Default::default()
+ };
+
+ debug_utils_messenger_create_infos.push(create_info);
+ user_callbacks.push(user_callback);
+ }
+
+ for i in 1..debug_utils_messenger_create_infos.len() {
+ debug_utils_messenger_create_infos[i - 1].p_next =
+ &debug_utils_messenger_create_infos[i] as *const _ as *const _;
+ }
+
+ if let Some(info) = debug_utils_messenger_create_infos.first() {
+ create_info_vk.p_next = info as *const _ as *const _;
+ }
+
+ // Creating the Vulkan instance.
+ let handle = {
+ let mut output = MaybeUninit::uninit();
+ let fns = library.fns();
+ (fns.v1_0.create_instance)(&create_info_vk, ptr::null(), output.as_mut_ptr())
+ .result()
+ .map_err(VulkanError::from)?;
+ output.assume_init()
+ };
+
+ // Loading the function pointers of the newly-created instance.
+ let fns = {
+ InstanceFunctions::load(|name| {
+ library
+ .get_instance_proc_addr(handle, name.as_ptr())
+ .map_or(ptr::null(), |func| func as _)
+ })
+ };
+
+ Ok(Arc::new(Instance {
+ handle,
+ fns,
+ id: Self::next_id(),
+ api_version,
+ enabled_extensions,
+ enabled_layers,
+ library,
+ max_api_version,
+ _user_callbacks: user_callbacks,
+ }))
+ }
+
+ /// Returns the Vulkan library used to create this instance.
+ #[inline]
+ pub fn library(&self) -> &Arc<VulkanLibrary> {
+ &self.library
+ }
+
+ /// Returns the Vulkan version supported by the instance.
+ ///
+ /// This is the lower of the
+ /// [driver's supported version](crate::VulkanLibrary::api_version) and
+ /// [`max_api_version`](Instance::max_api_version).
+ #[inline]
+ pub fn api_version(&self) -> Version {
+ self.api_version
+ }
+
+ /// Returns the maximum Vulkan version that was specified when creating the instance.
+ #[inline]
+ pub fn max_api_version(&self) -> Version {
+ self.max_api_version
+ }
+
+ /// Returns pointers to the raw Vulkan functions of the instance.
+ #[inline]
+ pub fn fns(&self) -> &InstanceFunctions {
+ &self.fns
+ }
+
+ /// Returns the extensions that have been enabled on the instance.
+ #[inline]
+ pub fn enabled_extensions(&self) -> &InstanceExtensions {
+ &self.enabled_extensions
+ }
+
+ /// Returns the layers that have been enabled on the instance.
+ #[inline]
+ pub fn enabled_layers(&self) -> &[String] {
+ &self.enabled_layers
+ }
+
+ /// Returns an iterator that enumerates the physical devices available.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # use vulkano::{
+ /// # instance::{Instance, InstanceExtensions},
+ /// # Version, VulkanLibrary,
+ /// # };
+ ///
+ /// # let library = VulkanLibrary::new().unwrap();
+ /// # let instance = Instance::new(library, Default::default()).unwrap();
+ /// for physical_device in instance.enumerate_physical_devices().unwrap() {
+ /// println!("Available device: {}", physical_device.properties().device_name);
+ /// }
+ /// ```
+ pub fn enumerate_physical_devices(
+ self: &Arc<Self>,
+ ) -> Result<impl ExactSizeIterator<Item = Arc<PhysicalDevice>>, VulkanError> {
+ let fns = self.fns();
+
+ unsafe {
+ let handles = loop {
+ let mut count = 0;
+ (fns.v1_0.enumerate_physical_devices)(self.handle, &mut count, ptr::null_mut())
+ .result()
+ .map_err(VulkanError::from)?;
+
+ let mut handles = Vec::with_capacity(count as usize);
+ let result = (fns.v1_0.enumerate_physical_devices)(
+ self.handle,
+ &mut count,
+ handles.as_mut_ptr(),
+ );
+
+ match result {
+ ash::vk::Result::SUCCESS => {
+ handles.set_len(count as usize);
+ break handles;
+ }
+ ash::vk::Result::INCOMPLETE => (),
+ err => return Err(VulkanError::from(err)),
+ }
+ };
+
+ let physical_devices: SmallVec<[_; 4]> = handles
+ .into_iter()
+ .map(|handle| PhysicalDevice::from_handle(self.clone(), handle))
+ .collect::<Result<_, _>>()?;
+
+ Ok(physical_devices.into_iter())
+ }
+ }
+}
+
+impl Drop for Instance {
+ #[inline]
+ fn drop(&mut self) {
+ let fns = self.fns();
+
+ unsafe {
+ (fns.v1_0.destroy_instance)(self.handle, ptr::null());
+ }
+ }
+}
+
+unsafe impl VulkanObject for Instance {
+ type Handle = ash::vk::Instance;
+
+ #[inline]
+ fn handle(&self) -> Self::Handle {
+ self.handle
+ }
+}
+
+impl_id_counter!(Instance);
+
+impl Debug for Instance {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ let Self {
+ handle,
+ fns,
+ id: _,
+ api_version,
+ enabled_extensions,
+ enabled_layers,
+ library: function_pointers,
+ max_api_version,
+ _user_callbacks: _,
+ } = self;
+
+ f.debug_struct("Instance")
+ .field("handle", handle)
+ .field("fns", fns)
+ .field("api_version", api_version)
+ .field("enabled_extensions", enabled_extensions)
+ .field("enabled_layers", enabled_layers)
+ .field("function_pointers", function_pointers)
+ .field("max_api_version", max_api_version)
+ .finish_non_exhaustive()
+ }
+}
+
+/// Parameters to create a new `Instance`.
+#[derive(Debug)]
+pub struct InstanceCreateInfo {
+ /// A string of your choice stating the name of your application.
+ ///
+ /// The default value is `None`.
+ pub application_name: Option<String>,
+
+ /// A version number of your choice specifying the version of your application.
+ ///
+ /// The default value is zero.
+ pub application_version: Version,
+
+ /// The extensions to enable on the instance.
+ ///
+ /// The default value is [`InstanceExtensions::empty()`].
+ pub enabled_extensions: InstanceExtensions,
+
+ /// The layers to enable on the instance.
+ ///
+ /// The default value is empty.
+ pub enabled_layers: Vec<String>,
+
+ /// A string of your choice stating the name of the engine used to power the application.
+ pub engine_name: Option<String>,
+
+ /// A version number of your choice specifying the version of the engine used to power the
+ /// application.
+ ///
+ /// The default value is zero.
+ pub engine_version: Version,
+
+ /// The highest Vulkan API version that the application will use with the instance.
+ ///
+ /// Usually, you will want to leave this at the default.
+ ///
+ /// The default value is [`Version::HEADER_VERSION`], but if the
+ /// supported instance version is 1.0, then it will be 1.0.
+ pub max_api_version: Option<Version>,
+
+ /// Include [portability subset](crate::instance#portability-subset-devices-and-the-enumerate_portability-flag)
+ /// devices when enumerating physical devices.
+ ///
+ /// If you enable this flag, you must ensure that your program is prepared to handle the
+ /// non-conformant aspects of these devices.
+ ///
+ /// If this flag is not enabled, and there are no fully-conformant devices on the system, then
+ /// [`Instance::new`] will return an `IncompatibleDriver` error.
+ ///
+ /// The default value is `false`.
+ ///
+ /// # Notes
+ ///
+ /// If this flag is enabled, and the
+ /// [`khr_portability_enumeration`](crate::instance::InstanceExtensions::khr_portability_enumeration)
+ /// extension is supported, it will be enabled automatically when creating the instance.
+ /// If the extension is not supported, this flag will be ignored.
+ pub enumerate_portability: bool,
+
+ /// Features of the validation layer to enable.
+ ///
+ /// If not empty, the
+ /// [`ext_validation_features`](crate::instance::InstanceExtensions::ext_validation_features)
+ /// extension must be enabled on the instance.
+ pub enabled_validation_features: Vec<ValidationFeatureEnable>,
+
+ /// Features of the validation layer to disable.
+ ///
+ /// If not empty, the
+ /// [`ext_validation_features`](crate::instance::InstanceExtensions::ext_validation_features)
+ /// extension must be enabled on the instance.
+ pub disabled_validation_features: Vec<ValidationFeatureDisable>,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for InstanceCreateInfo {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ application_name: None,
+ application_version: Version::major_minor(0, 0),
+ enabled_extensions: InstanceExtensions::empty(),
+ enabled_layers: Vec::new(),
+ engine_name: None,
+ engine_version: Version::major_minor(0, 0),
+ max_api_version: None,
+ enumerate_portability: false,
+ enabled_validation_features: Vec::new(),
+ disabled_validation_features: Vec::new(),
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+impl InstanceCreateInfo {
+ /// Returns an `InstanceCreateInfo` with the `application_name` and `application_version` set
+ /// from information in your crate's Cargo.toml file.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the required environment variables are missing, which happens if the project
+ /// wasn't built by Cargo.
+ #[inline]
+ pub fn application_from_cargo_toml() -> Self {
+ Self {
+ application_name: Some("vulkano".to_owned()),
+ application_version: Version {
+ major: env!("CARGO_PKG_VERSION_MAJOR").parse().unwrap(),
+ minor: env!("CARGO_PKG_VERSION_MINOR").parse().unwrap(),
+ patch: env!("CARGO_PKG_VERSION_PATCH").parse().unwrap(),
+ },
+ ..Default::default()
+ }
+ }
+}
+
+/// Error that can happen when creating an instance.
+#[derive(Clone, Debug)]
+pub enum InstanceCreationError {
+ /// Not enough memory.
+ OomError(OomError),
+
+ /// Failed to initialize for an implementation-specific reason.
+ InitializationFailed,
+
+ /// One of the requested layers is missing.
+ LayerNotPresent,
+
+ /// One of the requested extensions is not supported by the implementation.
+ ExtensionNotPresent,
+
+ /// The version requested is not supported by the implementation.
+ IncompatibleDriver,
+
+ /// A restriction for an extension was not met.
+ ExtensionRestrictionNotMet(ExtensionRestrictionError),
+
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+}
+
+impl Error for InstanceCreationError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::OomError(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+impl Display for InstanceCreationError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::OomError(_) => write!(f, "not enough memory available"),
+ Self::InitializationFailed => write!(f, "initialization failed"),
+ Self::LayerNotPresent => write!(f, "layer not present"),
+ Self::ExtensionNotPresent => write!(f, "extension not present"),
+ Self::IncompatibleDriver => write!(f, "incompatible driver"),
+ Self::ExtensionRestrictionNotMet(err) => Display::fmt(err, f),
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ }
+ }
+}
+
+impl From<OomError> for InstanceCreationError {
+ fn from(err: OomError) -> Self {
+ Self::OomError(err)
+ }
+}
+
+impl From<ExtensionRestrictionError> for InstanceCreationError {
+ fn from(err: ExtensionRestrictionError) -> Self {
+ Self::ExtensionRestrictionNotMet(err)
+ }
+}
+
+impl From<VulkanError> for InstanceCreationError {
+ fn from(err: VulkanError) -> Self {
+ match err {
+ err @ VulkanError::OutOfHostMemory => Self::OomError(OomError::from(err)),
+ err @ VulkanError::OutOfDeviceMemory => Self::OomError(OomError::from(err)),
+ VulkanError::InitializationFailed => Self::InitializationFailed,
+ VulkanError::LayerNotPresent => Self::LayerNotPresent,
+ VulkanError::ExtensionNotPresent => Self::ExtensionNotPresent,
+ VulkanError::IncompatibleDriver => Self::IncompatibleDriver,
+ _ => panic!("unexpected error: {:?}", err),
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+
+ #[test]
+ fn create_instance() {
+ let _ = instance!();
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 8c8e7b2..302dedc 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -10,66 +10,160 @@
#![doc(html_logo_url = "https://raw.githubusercontent.com/vulkano-rs/vulkano/master/logo.png")]
//! Safe and rich Rust wrapper around the Vulkan API.
//!
-//! # Brief summary of Vulkan
-//!
-//! - The [`Instance`](instance/struct.Instance.html) object is the API entry point. It is the
-//! first object you must create before starting to use Vulkan.
-//!
-//! - The [`PhysicalDevice`](instance/struct.PhysicalDevice.html) object represents an
-//! implementation of Vulkan available on the system (eg. a graphics card, a software
-//! implementation, etc.). Physical devices can be enumerated from an instance with
-//! [`PhysicalDevice::enumerate()`](instance/struct.PhysicalDevice.html#method.enumerate).
-//!
-//! - Once you have chosen a physical device to use, you can create a
-//! [`Device`](device/index.html) object from it. The `Device` is the most important
-//! object of Vulkan, as it represents an open channel of communication with a physical device.
-//! You always need to have one before you can do interesting things with Vulkan.
-//!
-//! - [*Buffers*](buffer/index.html) and [*images*](image/index.html) can be used to store data on
-//! memory accessible by the GPU (or more generally by the Vulkan implementation). Buffers are
-//! usually used to store information about vertices, lights, etc. or arbitrary data, while
-//! images are used to store textures or multi-dimensional data.
-//!
-//! - In order to show something on the screen, you need a [`Swapchain`](swapchain/index.html).
-//! A `Swapchain` contains special `Image`s that correspond to the content of the window or the
-//! monitor. When you *present* a swapchain, the content of one of these special images is shown
-//! on the screen.
-//!
-//! - In order to ask the GPU to do something, you must create a
-//! [*command buffer*](command_buffer/index.html). A command buffer contains a list of commands
-//! that the GPU must perform. This can include copies between buffers and images, compute
-//! operations, or graphics operations. For the work to start, the command buffer must then be
-//! submitted to a [`Queue`](device/struct.Queue.html), which is obtained when you create the
-//! `Device`.
-//!
-//! - In order to be able to add a compute operation or a graphics operation to a command buffer,
-//! you need to have created a [`ComputePipeline` or a `GraphicsPipeline`
-//! object](pipeline/index.html) that describes the operation you want. These objects are usually
-//! created during your program's initialization. `Shader`s are programs that the GPU will
-//! execute as part of a pipeline. [*Descriptors*](descriptor/index.html) can be used to access
-//! the content of buffers or images from within shaders.
-//!
-//! - For graphical operations, [`RenderPass`es and `Framebuffer`s](framebuffer/index.html)
-//! describe on which images the implementation must draw upon.
-//!
-//! - Once you have built a *command buffer* that contains a list of commands, submitting it to the
-//! GPU will return an object that implements [the `GpuFuture` trait](sync/index.html).
-//! `GpuFuture`s allow you to chain multiple submissions together and are essential to performing
-//! multiple operations on multiple different GPU queues.
+//! # Starting off with Vulkano
//!
+//! The steps for using Vulkan through Vulkano are in principle not any different from using
+//! the raw Vulkan API, but the details may be different for the sake of idiomaticity, safety
+//! and convenience.
+//!
+//! 1. Create a [`VulkanLibrary`]. This represents a Vulkan library on the system, which must be
+//! loaded before you can do anything with Vulkan.
+//!
+//! 2. Create an [`Instance`]. This is the API entry point, and represents an initialised Vulkan
+//! library.
+//!
+//! 3. If you intend to show graphics to the user on a window or a screen, create a [`Surface`].
+//! A `Surface` is created from a window identifier or handle, that is specific to the display or
+//! windowing system being used. The [`vulkano-win`] crate, which is part of the Vulkano
+//! project, can make this step easier.
+//!
+//! 4. [Enumerate the physical devices] that are available on the `Instance`, and choose one that
+//! is suitable for your program. A [`PhysicalDevice`] represents a Vulkan-capable device that
+//! is available on the system, such as a graphics card, a software implementation, etc.
+//!
+//! 6. Create a [`Device`] and accompanying [`Queue`]s from the selected `PhysicalDevice`.
+//! The `Device` is the most important object of Vulkan, and you need one to create almost
+//! every other object. `Queue`s are created together with the `Device`, and are used to submit
+//! work to the device to make it do something.
+//!
+//! 7. If you created a `Surface` earlier, create a [`Swapchain`]. This object contains special
+//! images that correspond to the contents of the surface. Whenever you want to
+//! change the contents (show something new to the user), you must first *acquire* one of these
+//! images from the swapchain, fill it with the new contents (by rendering, copying or any
+//! other means), and then *present* it back to the swapchain.
+//! A swapchain can become outdated if the properties of the surface change, such as when
+//! the size of the window changes. It then becomes necessary to create a new swapchain.
+//!
+//! 8. Record a [*command buffer*](crate::command_buffer), containing commands that the device must
+//! execute. Then build the command buffer and submit it to a `Queue`.
+//!
+//! Many different operations can be recorded to a command buffer, such as *draw*, *compute* and
+//! *transfer* operations. To do any of these things, you will need to create several other objects,
+//! depending on your specific needs. This includes:
+//!
+//! - [*Buffers*] store general-purpose data on memory accessible by the device. This can include
+//! mesh data (vertices, texture coordinates etc.), lighting information, matrices, and anything
+//! else you can think of.
+//!
+//! - [*Images*] store texel data, arranged in a grid of one or more dimensions. They can be used
+//! as textures, depth/stencil buffers, framebuffers and as part of a swapchain.
+//!
+//! - [*Pipelines*] describe operations on the device. They include one or more [*shader*]s, small
+//! programs that the device will execute as part of a pipeline.
+//! Pipelines come in several types:
+//! - A [`ComputePipeline`] describes how *dispatch* commands are to be performed.
+//! - A [`GraphicsPipeline`] describes how *draw* commands are to be performed.
+//!
+//! - [*Descriptor sets*] make buffers, images and other objects available to shaders. The
+//! arrangement of these resources in shaders is described by a [`DescriptorSetLayout`]. One or
+//! more of these layouts in turn forms a [`PipelineLayout`], which is used when creating a
+//! pipeline object.
+//!
+//! - For more complex, multi-stage draw operations, you can create a [`RenderPass`] object.
+//! This object describes the stages, known as subpasses, that draw operations consist of,
+//! how they interact with one another, and which types of images are available in each subpass.
+//! You must also create a [`Framebuffer`], which contains the image objects that are to be used
+//! in a render pass.
+//!
+//! # `_unchecked` functions
+//!
+//! Many functions in Vulkano have two versions: the normal function, which is usually safe to
+//! call, and another function with `_unchecked` added onto the end of the name, which is unsafe
+//! to call. The `_unchecked` functions skip all validation checks, so they are usually more
+//! efficient, but you must ensure that you meet the validity/safety requirements of the function.
+//!
+//! For all `_unchecked` functions, a call to the function is valid, if a call to the
+//! corresponding normal function with the same arguments would return without any error.
+//! This includes following all the valid usage requirements of the Vulkan specification, but may
+//! also include additional requirements specific to Vulkano.
+//! **All other usage of `_unchecked` functions may be undefined behavior.**
+//!
+//! Because there are potentially many `_unchecked` functions, and because their name and operation
+//! can be straightforwardly understood based on the corresponding normal function, they are hidden
+//! from the Vulkano documentation by default. You can unhide them by enabling the
+//! `document_unchecked` cargo feature, and then generating the documentation with the command
+//! `cargo doc --open`.
+//!
+//! # Cargo features
+//!
+//! | Feature | Description |
+//! |----------------------|---------------------------------------------------------------||
+//! | `macros` | Include reexports from [`vulkano-macros`]. Enabled by default. |
+//! | `document_unchecked` | Include `_unchecked` functions in the generated documentation. |
+//! | `serde` | Enables (de)serialization of certain types using [`serde`]. |
+//!
+//! [`VulkanLibrary`]: crate::VulkanLibrary
+//! [`Instance`]: crate::instance::Instance
+//! [`Surface`]: crate::swapchain::Surface
+//! [`vulkano-win`]: https://crates.io/crates/vulkano-win
+//! [Enumerate the physical devices]: crate::instance::Instance::enumerate_physical_devices
+//! [`PhysicalDevice`]: crate::device::physical::PhysicalDevice
+//! [`Device`]: crate::device::Device
+//! [`Queue`]: crate::device::Queue
+//! [`Swapchain`]: crate::swapchain::Swapchain
+//! [*command buffer*]: crate::command_buffer
+//! [*Buffers*]: crate::buffer
+//! [*Images*]: crate::image
+//! [*Pipelines*]: crate::pipeline
+//! [*shader*]: crate::shader
+//! [`ComputePipeline`]: crate::pipeline::ComputePipeline
+//! [`GraphicsPipeline`]: crate::pipeline::GraphicsPipeline
+//! [*Descriptor sets*]: crate::descriptor_set
+//! [`DescriptorSetLayout`]: crate::descriptor_set::layout
+//! [`PipelineLayout`]: crate::pipeline::layout
+//! [`RenderPass`]: crate::render_pass::RenderPass
+//! [`Framebuffer`]: crate::render_pass::Framebuffer
+//! [`vulkano-macros`]: vulkano_macros
+//! [`serde`]: https://crates.io/crates/serde
//#![warn(missing_docs)] // TODO: activate
-#![allow(dead_code)] // TODO: remove
-#![allow(unused_variables)] // TODO: remove
+#![warn(
+ rust_2018_idioms,
+ rust_2021_compatibility,
+ clippy::trivially_copy_pass_by_ref
+)]
+// These lints are a bit too pedantic, so they're disabled here.
+#![allow(
+ clippy::collapsible_else_if,
+ clippy::collapsible_if,
+ clippy::derivable_impls, // TODO: remove
+ clippy::large_enum_variant,
+ clippy::len_without_is_empty,
+ clippy::missing_safety_doc, // TODO: remove
+ clippy::module_inception,
+ clippy::mutable_key_type,
+ clippy::needless_borrowed_reference,
+ clippy::new_without_default,
+ clippy::nonminimal_bool,
+ clippy::op_ref, // Seems to be bugged, the fixed code triggers a compile error
+ clippy::result_large_err,
+ clippy::too_many_arguments,
+ clippy::type_complexity,
+ clippy::vec_box,
+ clippy::wrong_self_convention
+)]
pub use ash::vk::Handle;
pub use half;
-use std::error;
-use std::fmt;
-use std::ops::Deref;
-use std::sync::Arc;
-use std::sync::MutexGuard;
-pub use version::Version;
+pub use library::{LoadingError, VulkanLibrary};
+use std::{
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+ num::NonZeroU64,
+ ops::Deref,
+ sync::Arc,
+};
+pub use {extensions::ExtensionProperties, version::Version};
#[macro_use]
mod tests;
@@ -83,25 +177,37 @@ pub mod format;
mod version;
#[macro_use]
pub mod render_pass;
+mod cache;
mod fns;
pub mod image;
pub mod instance;
+pub mod library;
+mod macros;
pub mod memory;
+pub mod padded;
pub mod pipeline;
pub mod query;
+mod range_map;
+pub mod range_set;
pub mod sampler;
+pub mod shader;
pub mod swapchain;
pub mod sync;
-mod autogen {
- // Generated by build.rs
- include!(concat!(env!("OUT_DIR"), "/autogen.rs"));
-}
-
/// Represents memory size and offset values on a Vulkan device.
/// Analogous to the Rust `usize` type on the host.
pub use ash::vk::DeviceSize;
+/// A [`DeviceSize`] that is known not to equal zero.
+pub type NonZeroDeviceSize = NonZeroU64;
+
+// Allow refering to crate by its name to work around limitations of proc-macros
+// in doctests.
+// See https://github.com/rust-lang/cargo/issues/9886
+// and https://github.com/bkchr/proc-macro-crate/issues/10
+#[allow(unused_extern_crates)]
+extern crate self as vulkano;
+
/// Alternative to the `Deref` trait. Contrary to `Deref`, must always return the same object.
pub unsafe trait SafeDeref: Deref {}
unsafe impl<'a, T: ?Sized> SafeDeref for &'a T {}
@@ -111,20 +217,23 @@ unsafe impl<T: ?Sized> SafeDeref for Box<T> {}
/// Gives access to the internal identifier of an object.
pub unsafe trait VulkanObject {
/// The type of the object.
- type Object: ash::vk::Handle;
+ type Handle: ash::vk::Handle;
- /// Returns a reference to the object.
- fn internal_object(&self) -> Self::Object;
+ /// Returns the raw Vulkan handle of the object.
+ fn handle(&self) -> Self::Handle;
}
-/// Gives access to the internal identifier of an object.
-// TODO: remove ; crappy design
-pub unsafe trait SynchronizedVulkanObject {
- /// The type of the object.
- type Object: ash::vk::Handle;
+unsafe impl<T, U> VulkanObject for T
+where
+ T: SafeDeref<Target = U>,
+ U: VulkanObject + ?Sized,
+{
+ type Handle = U::Handle;
- /// Returns a reference to the object.
- fn internal_object_guard(&self) -> MutexGuard<Self::Object>;
+ #[inline]
+ fn handle(&self) -> Self::Handle {
+ (**self).handle()
+ }
}
/// Error type returned by most Vulkan functions.
@@ -136,15 +245,14 @@ pub enum OomError {
OutOfDeviceMemory,
}
-impl error::Error for OomError {}
+impl Error for OomError {}
-impl fmt::Display for OomError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+impl Display for OomError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
write!(
- fmt,
+ f,
"{}",
- match *self {
+ match self {
OomError::OutOfHostMemory => "no memory available on the host",
OomError::OutOfDeviceMemory => "no memory available on the graphical device",
}
@@ -152,92 +260,225 @@ impl fmt::Display for OomError {
}
}
-impl From<Error> for OomError {
- #[inline]
- fn from(err: Error) -> OomError {
+impl From<VulkanError> for OomError {
+ fn from(err: VulkanError) -> OomError {
match err {
- Error::OutOfHostMemory => OomError::OutOfHostMemory,
- Error::OutOfDeviceMemory => OomError::OutOfDeviceMemory,
+ VulkanError::OutOfHostMemory => OomError::OutOfHostMemory,
+ VulkanError::OutOfDeviceMemory => OomError::OutOfDeviceMemory,
_ => panic!("unexpected error: {:?}", err),
}
}
}
-/// All possible success codes returned by any Vulkan function.
-#[derive(Debug, Copy, Clone)]
-#[repr(i32)]
-enum Success {
- Success = ash::vk::Result::SUCCESS.as_raw(),
- NotReady = ash::vk::Result::NOT_READY.as_raw(),
- Timeout = ash::vk::Result::TIMEOUT.as_raw(),
- EventSet = ash::vk::Result::EVENT_SET.as_raw(),
- EventReset = ash::vk::Result::EVENT_RESET.as_raw(),
- Incomplete = ash::vk::Result::INCOMPLETE.as_raw(),
- Suboptimal = ash::vk::Result::SUBOPTIMAL_KHR.as_raw(),
+// Generated by build.rs
+include!(concat!(env!("OUT_DIR"), "/errors.rs"));
+
+impl Error for VulkanError {}
+
+impl Display for VulkanError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ write!(
+ f,
+ "{}",
+ match self {
+ VulkanError::OutOfHostMemory => "a host memory allocation has failed",
+ VulkanError::OutOfDeviceMemory => "a device memory allocation has failed",
+ VulkanError::InitializationFailed => {
+ "initialization of an object could not be completed for \
+ implementation-specific reasons"
+ }
+ VulkanError::DeviceLost => "the logical or physical device has been lost",
+ VulkanError::MemoryMapFailed => "mapping of a memory object has failed",
+ VulkanError::LayerNotPresent => {
+ "a requested layer is not present or could not be loaded"
+ }
+ VulkanError::ExtensionNotPresent => "a requested extension is not supported",
+ VulkanError::FeatureNotPresent => "a requested feature is not supported",
+ VulkanError::IncompatibleDriver => {
+ "the requested version of Vulkan is not supported by the driver or is \
+ otherwise incompatible for implementation-specific reasons"
+ }
+ VulkanError::TooManyObjects => {
+ "too many objects of the type have already been created"
+ }
+ VulkanError::FormatNotSupported => {
+ "a requested format is not supported on this device"
+ }
+ VulkanError::FragmentedPool => {
+ "a pool allocation has failed due to fragmentation of the pool's memory"
+ }
+ VulkanError::Unknown => {
+ "an unknown error has occurred; either the application has provided invalid \
+ input, or an implementation failure has occurred"
+ }
+ VulkanError::OutOfPoolMemory => "a pool memory allocation has failed",
+ VulkanError::InvalidExternalHandle => {
+ "an external handle is not a valid handle of the specified type"
+ }
+ VulkanError::Fragmentation => {
+ "a descriptor pool creation has failed due to fragmentation"
+ }
+ VulkanError::InvalidOpaqueCaptureAddress => {
+ "a buffer creation or memory allocation failed because the requested address \
+ is not available. A shader group handle assignment failed because the \
+ requested shader group handle information is no longer valid"
+ }
+ VulkanError::IncompatibleDisplay => {
+ "the display used by a swapchain does not use the same presentable image \
+ layout, or is incompatible in a way that prevents sharing an image"
+ }
+ VulkanError::NotPermitted => "a requested operation was not permitted",
+ VulkanError::SurfaceLost => "a surface is no longer available",
+ VulkanError::NativeWindowInUse => {
+ "the requested window is already in use by Vulkan or another API in a manner \
+ which prevents it from being used again"
+ }
+ VulkanError::OutOfDate => {
+ "a surface has changed in such a way that it is no longer compatible with the \
+ swapchain, and further presentation requests using the swapchain will fail"
+ }
+ VulkanError::ValidationFailed => "validation failed",
+ VulkanError::FullScreenExclusiveModeLost => {
+ "an operation on a swapchain created with application controlled full-screen \
+ access failed as it did not have exclusive full-screen access"
+ }
+ VulkanError::InvalidDrmFormatModifierPlaneLayout => {
+ "the requested DRM format modifier plane layout is invalid"
+ }
+ VulkanError::InvalidShader => "one or more shaders failed to compile or link",
+ VulkanError::ImageUsageNotSupported =>
+ "the requested `ImageUsage` are not supported",
+ VulkanError::VideoPictureLayoutNotSupported =>
+ "the requested video picture layout is not supported",
+ VulkanError::VideoProfileOperationNotSupported =>
+ "a video profile operation specified via \
+ `VideoProfileInfo::video_codec_operation` is not supported",
+ VulkanError::VideoProfileFormatNotSupported =>
+ "format parameters in a requested `VideoProfileInfo` chain are not supported",
+ VulkanError::VideoProfileCodecNotSupported =>
+ "codec-specific parameters in a requested `VideoProfileInfo` chain are not \
+ supported",
+ VulkanError::VideoStdVersionNotSupported =>
+ "the specified video Std header version is not supported",
+ VulkanError::CompressionExhausted =>
+ "an image creation failed because internal resources required for compression \
+ are exhausted",
+ VulkanError::Unnamed(result) =>
+ return write!(f, "unnamed error, VkResult value {}", result.as_raw()),
+ }
+ )
+ }
}
-/// All possible errors returned by any Vulkan function.
-///
-/// This type is not public. Instead all public error types should implement `From<Error>` and
-/// panic for error code that aren't supposed to happen.
-#[derive(Debug, Copy, Clone)]
-#[repr(i32)]
-// TODO: being pub is necessary because of the weird visibility rules in rustc
-pub(crate) enum Error {
- OutOfHostMemory = ash::vk::Result::ERROR_OUT_OF_HOST_MEMORY.as_raw(),
- OutOfDeviceMemory = ash::vk::Result::ERROR_OUT_OF_DEVICE_MEMORY.as_raw(),
- InitializationFailed = ash::vk::Result::ERROR_INITIALIZATION_FAILED.as_raw(),
- DeviceLost = ash::vk::Result::ERROR_DEVICE_LOST.as_raw(),
- MemoryMapFailed = ash::vk::Result::ERROR_MEMORY_MAP_FAILED.as_raw(),
- LayerNotPresent = ash::vk::Result::ERROR_LAYER_NOT_PRESENT.as_raw(),
- ExtensionNotPresent = ash::vk::Result::ERROR_EXTENSION_NOT_PRESENT.as_raw(),
- FeatureNotPresent = ash::vk::Result::ERROR_FEATURE_NOT_PRESENT.as_raw(),
- IncompatibleDriver = ash::vk::Result::ERROR_INCOMPATIBLE_DRIVER.as_raw(),
- TooManyObjects = ash::vk::Result::ERROR_TOO_MANY_OBJECTS.as_raw(),
- FormatNotSupported = ash::vk::Result::ERROR_FORMAT_NOT_SUPPORTED.as_raw(),
- SurfaceLost = ash::vk::Result::ERROR_SURFACE_LOST_KHR.as_raw(),
- NativeWindowInUse = ash::vk::Result::ERROR_NATIVE_WINDOW_IN_USE_KHR.as_raw(),
- OutOfDate = ash::vk::Result::ERROR_OUT_OF_DATE_KHR.as_raw(),
- IncompatibleDisplay = ash::vk::Result::ERROR_INCOMPATIBLE_DISPLAY_KHR.as_raw(),
- ValidationFailed = ash::vk::Result::ERROR_VALIDATION_FAILED_EXT.as_raw(),
- OutOfPoolMemory = ash::vk::Result::ERROR_OUT_OF_POOL_MEMORY_KHR.as_raw(),
- FullscreenExclusiveLost = ash::vk::Result::ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT.as_raw(),
+/// Used in errors to indicate a set of alternatives that needs to be available/enabled to allow
+/// a given operation.
+#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
+pub struct RequiresOneOf {
+ /// A minimum Vulkan API version that would allow the operation.
+ pub api_version: Option<Version>,
+
+ /// Enabled features that would allow the operation.
+ pub features: &'static [&'static str],
+
+ /// Available/enabled device extensions that would allow the operation.
+ pub device_extensions: &'static [&'static str],
+
+ /// Available/enabled instance extensions that would allow the operation.
+ pub instance_extensions: &'static [&'static str],
}
-/// Checks whether the result returned correctly.
-fn check_errors(result: ash::vk::Result) -> Result<Success, Error> {
- match result {
- ash::vk::Result::SUCCESS => Ok(Success::Success),
- ash::vk::Result::NOT_READY => Ok(Success::NotReady),
- ash::vk::Result::TIMEOUT => Ok(Success::Timeout),
- ash::vk::Result::EVENT_SET => Ok(Success::EventSet),
- ash::vk::Result::EVENT_RESET => Ok(Success::EventReset),
- ash::vk::Result::INCOMPLETE => Ok(Success::Incomplete),
- ash::vk::Result::ERROR_OUT_OF_HOST_MEMORY => Err(Error::OutOfHostMemory),
- ash::vk::Result::ERROR_OUT_OF_DEVICE_MEMORY => Err(Error::OutOfDeviceMemory),
- ash::vk::Result::ERROR_INITIALIZATION_FAILED => Err(Error::InitializationFailed),
- ash::vk::Result::ERROR_DEVICE_LOST => Err(Error::DeviceLost),
- ash::vk::Result::ERROR_MEMORY_MAP_FAILED => Err(Error::MemoryMapFailed),
- ash::vk::Result::ERROR_LAYER_NOT_PRESENT => Err(Error::LayerNotPresent),
- ash::vk::Result::ERROR_EXTENSION_NOT_PRESENT => Err(Error::ExtensionNotPresent),
- ash::vk::Result::ERROR_FEATURE_NOT_PRESENT => Err(Error::FeatureNotPresent),
- ash::vk::Result::ERROR_INCOMPATIBLE_DRIVER => Err(Error::IncompatibleDriver),
- ash::vk::Result::ERROR_TOO_MANY_OBJECTS => Err(Error::TooManyObjects),
- ash::vk::Result::ERROR_FORMAT_NOT_SUPPORTED => Err(Error::FormatNotSupported),
- ash::vk::Result::ERROR_SURFACE_LOST_KHR => Err(Error::SurfaceLost),
- ash::vk::Result::ERROR_NATIVE_WINDOW_IN_USE_KHR => Err(Error::NativeWindowInUse),
- ash::vk::Result::SUBOPTIMAL_KHR => Ok(Success::Suboptimal),
- ash::vk::Result::ERROR_OUT_OF_DATE_KHR => Err(Error::OutOfDate),
- ash::vk::Result::ERROR_INCOMPATIBLE_DISPLAY_KHR => Err(Error::IncompatibleDisplay),
- ash::vk::Result::ERROR_VALIDATION_FAILED_EXT => Err(Error::ValidationFailed),
- ash::vk::Result::ERROR_OUT_OF_POOL_MEMORY_KHR => Err(Error::OutOfPoolMemory),
- ash::vk::Result::ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT => {
- Err(Error::FullscreenExclusiveLost)
+impl RequiresOneOf {
+ /// Returns whether there is more than one possible requirement.
+ pub fn len(&self) -> usize {
+ self.api_version.map_or(0, |_| 1)
+ + self.features.len()
+ + self.device_extensions.len()
+ + self.instance_extensions.len()
+ }
+}
+
+impl Display for RequiresOneOf {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ let mut members_written = 0;
+
+ if let Some(version) = self.api_version {
+ write!(f, "Vulkan API version {}.{}", version.major, version.minor)?;
+ members_written += 1;
+ }
+
+ if let Some((last, rest)) = self.features.split_last() {
+ if members_written != 0 {
+ write!(f, ", ")?;
+ }
+
+ members_written += 1;
+
+ if rest.is_empty() {
+ write!(f, "feature {}", last)?;
+ } else {
+ write!(f, "features ")?;
+
+ for feature in rest {
+ write!(f, "{}, ", feature)?;
+ }
+
+ write!(f, "{}", last)?;
+ }
+ }
+
+ if let Some((last, rest)) = self.device_extensions.split_last() {
+ if members_written != 0 {
+ write!(f, ", ")?;
+ }
+
+ members_written += 1;
+
+ if rest.is_empty() {
+ write!(f, "device extension {}", last)?;
+ } else {
+ write!(f, "device extensions ")?;
+
+ for feature in rest {
+ write!(f, "{}, ", feature)?;
+ }
+
+ write!(f, "{}", last)?;
+ }
+ }
+
+ if let Some((last, rest)) = self.instance_extensions.split_last() {
+ if members_written != 0 {
+ write!(f, ", ")?;
+ }
+
+ if rest.is_empty() {
+ write!(f, "instance extension {}", last)?;
+ } else {
+ write!(f, "instance extensions ")?;
+
+ for feature in rest {
+ write!(f, "{}, ", feature)?;
+ }
+
+ write!(f, "{}", last)?;
+ }
}
- ash::vk::Result::ERROR_INVALID_SHADER_NV => panic!(
- "Vulkan function returned \
- VK_ERROR_INVALID_SHADER_NV"
- ),
- c => unreachable!("Unexpected error code returned by Vulkan: {}", c),
+
+ Ok(())
}
}
+
+#[derive(Clone, Copy, Debug)]
+pub(crate) struct RequirementNotMet {
+ pub(crate) required_for: &'static str,
+ pub(crate) requires_one_of: RequiresOneOf,
+}
+
+/// A helper type for non-exhaustive structs.
+///
+/// This type cannot be constructed outside Vulkano. Structures with a field of this type can only
+/// be constructed by calling a constructor function or `Default::default()`. The effect is similar
+/// to the standard Rust `#[non_exhaustive]` attribute, except that it does not prevent update
+/// syntax from being used.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] // add traits as needed
+pub struct NonExhaustive(pub(crate) ());
diff --git a/src/library.rs b/src/library.rs
new file mode 100644
index 0000000..d2e3abe
--- /dev/null
+++ b/src/library.rs
@@ -0,0 +1,464 @@
+// Copyright (c) 2016 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+//! Vulkan library loading system.
+//!
+//! Before Vulkano can do anything, it first needs to find a library containing an implementation
+//! of Vulkan. A Vulkan implementation is defined as a single `vkGetInstanceProcAddr` function,
+//! which can be accessed through the `Loader` trait.
+//!
+//! This module provides various implementations of the `Loader` trait.
+//!
+//! Once you have a type that implements `Loader`, you can create a `VulkanLibrary`
+//! from it and use this `VulkanLibrary` struct to build an `Instance`.
+
+pub use crate::fns::EntryFunctions;
+use crate::{
+ instance::{InstanceExtensions, LayerProperties},
+ ExtensionProperties, OomError, SafeDeref, Version, VulkanError,
+};
+use libloading::{Error as LibloadingError, Library};
+use std::{
+ error::Error,
+ ffi::{CStr, CString},
+ fmt::{Debug, Display, Error as FmtError, Formatter},
+ mem::transmute,
+ os::raw::c_char,
+ path::Path,
+ ptr,
+ sync::Arc,
+};
+
+/// A loaded library containing a valid Vulkan implementation.
+#[derive(Debug)]
+pub struct VulkanLibrary {
+ loader: Box<dyn Loader>,
+ fns: EntryFunctions,
+
+ api_version: Version,
+ extension_properties: Vec<ExtensionProperties>,
+ supported_extensions: InstanceExtensions,
+}
+
+impl VulkanLibrary {
+ /// Loads the default Vulkan library for this system.
+ pub fn new() -> Result<Arc<Self>, LoadingError> {
+ #[cfg(target_os = "ios")]
+ #[allow(non_snake_case)]
+ fn def_loader_impl() -> Result<Box<dyn Loader>, LoadingError> {
+ let loader = crate::statically_linked_vulkan_loader!();
+
+ Ok(Box::new(loader))
+ }
+
+ #[cfg(not(target_os = "ios"))]
+ fn def_loader_impl() -> Result<Box<dyn Loader>, LoadingError> {
+ #[cfg(windows)]
+ fn get_path() -> &'static Path {
+ Path::new("vulkan-1.dll")
+ }
+ #[cfg(all(unix, not(target_os = "android"), not(target_os = "macos")))]
+ fn get_path() -> &'static Path {
+ Path::new("libvulkan.so.1")
+ }
+ #[cfg(target_os = "macos")]
+ fn get_path() -> &'static Path {
+ Path::new("libvulkan.1.dylib")
+ }
+ #[cfg(target_os = "android")]
+ fn get_path() -> &'static Path {
+ Path::new("libvulkan.so")
+ }
+
+ let loader = unsafe { DynamicLibraryLoader::new(get_path())? };
+
+ Ok(Box::new(loader))
+ }
+
+ def_loader_impl().and_then(VulkanLibrary::with_loader)
+ }
+
+ /// Loads a custom Vulkan library.
+ pub fn with_loader(loader: impl Loader + 'static) -> Result<Arc<Self>, LoadingError> {
+ let fns = EntryFunctions::load(|name| unsafe {
+ loader
+ .get_instance_proc_addr(ash::vk::Instance::null(), name.as_ptr())
+ .map_or(ptr::null(), |func| func as _)
+ });
+
+ let api_version = unsafe { Self::get_api_version(&loader)? };
+ let extension_properties = unsafe { Self::get_extension_properties(&fns, None)? };
+ let supported_extensions = extension_properties
+ .iter()
+ .map(|property| property.extension_name.as_str())
+ .collect();
+
+ Ok(Arc::new(VulkanLibrary {
+ loader: Box::new(loader),
+ fns,
+ api_version,
+ extension_properties,
+ supported_extensions,
+ }))
+ }
+
+ unsafe fn get_api_version(loader: &impl Loader) -> Result<Version, VulkanError> {
+ // Per the Vulkan spec:
+ // If the vkGetInstanceProcAddr returns NULL for vkEnumerateInstanceVersion, it is a
+ // Vulkan 1.0 implementation. Otherwise, the application can call vkEnumerateInstanceVersion
+ // to determine the version of Vulkan.
+
+ let name = CStr::from_bytes_with_nul_unchecked(b"vkEnumerateInstanceVersion\0");
+ let func = loader.get_instance_proc_addr(ash::vk::Instance::null(), name.as_ptr());
+
+ let version = if let Some(func) = func {
+ let func: ash::vk::PFN_vkEnumerateInstanceVersion = transmute(func);
+ let mut api_version = 0;
+ func(&mut api_version).result().map_err(VulkanError::from)?;
+ Version::from(api_version)
+ } else {
+ Version {
+ major: 1,
+ minor: 0,
+ patch: 0,
+ }
+ };
+
+ Ok(version)
+ }
+
+ unsafe fn get_extension_properties(
+ fns: &EntryFunctions,
+ layer: Option<&str>,
+ ) -> Result<Vec<ExtensionProperties>, VulkanError> {
+ let layer_vk = layer.map(|layer| CString::new(layer).unwrap());
+
+ loop {
+ let mut count = 0;
+ (fns.v1_0.enumerate_instance_extension_properties)(
+ layer_vk
+ .as_ref()
+ .map_or(ptr::null(), |layer| layer.as_ptr()),
+ &mut count,
+ ptr::null_mut(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+
+ let mut output = Vec::with_capacity(count as usize);
+ let result = (fns.v1_0.enumerate_instance_extension_properties)(
+ layer_vk
+ .as_ref()
+ .map_or(ptr::null(), |layer| layer.as_ptr()),
+ &mut count,
+ output.as_mut_ptr(),
+ );
+
+ match result {
+ ash::vk::Result::SUCCESS => {
+ output.set_len(count as usize);
+ return Ok(output.into_iter().map(Into::into).collect());
+ }
+ ash::vk::Result::INCOMPLETE => (),
+ err => return Err(VulkanError::from(err)),
+ }
+ }
+ }
+
+ /// Returns pointers to the raw global Vulkan functions of the library.
+ #[inline]
+ pub fn fns(&self) -> &EntryFunctions {
+ &self.fns
+ }
+
+ /// Returns the highest Vulkan version that is supported for instances.
+ #[inline]
+ pub fn api_version(&self) -> Version {
+ self.api_version
+ }
+
+ /// Returns the extension properties reported by the core library.
+ #[inline]
+ pub fn extension_properties(&self) -> &[ExtensionProperties] {
+ &self.extension_properties
+ }
+
+ /// Returns the extensions that are supported by the core library.
+ #[inline]
+ pub fn supported_extensions(&self) -> &InstanceExtensions {
+ &self.supported_extensions
+ }
+
+ /// Returns the list of layers that are available when creating an instance.
+ ///
+ /// On success, this function returns an iterator that produces
+ /// [`LayerProperties`](crate::instance::LayerProperties) objects. In order to enable a layer,
+ /// you need to pass its name (returned by `LayerProperties::name()`) when creating the
+ /// [`Instance`](crate::instance::Instance).
+ ///
+ /// > **Note**: The available layers may change between successive calls to this function, so
+ /// > each call may return different results. It is possible that one of the layers enumerated
+ /// > here is no longer available when you create the `Instance`. This will lead to an error
+ /// > when calling `Instance::new`.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use vulkano::VulkanLibrary;
+ ///
+ /// let library = VulkanLibrary::new().unwrap();
+ ///
+ /// for layer in library.layer_properties().unwrap() {
+ /// println!("Available layer: {}", layer.name());
+ /// }
+ /// ```
+ pub fn layer_properties(
+ &self,
+ ) -> Result<impl ExactSizeIterator<Item = LayerProperties>, OomError> {
+ let fns = self.fns();
+
+ let layer_properties = unsafe {
+ loop {
+ let mut count = 0;
+ (fns.v1_0.enumerate_instance_layer_properties)(&mut count, ptr::null_mut())
+ .result()
+ .map_err(VulkanError::from)?;
+
+ let mut properties = Vec::with_capacity(count as usize);
+ let result = (fns.v1_0.enumerate_instance_layer_properties)(
+ &mut count,
+ properties.as_mut_ptr(),
+ );
+
+ match result {
+ ash::vk::Result::SUCCESS => {
+ properties.set_len(count as usize);
+ break properties;
+ }
+ ash::vk::Result::INCOMPLETE => (),
+ err => return Err(VulkanError::from(err).into()),
+ }
+ }
+ };
+
+ Ok(layer_properties
+ .into_iter()
+ .map(|p| LayerProperties { props: p }))
+ }
+
+ /// Returns the extension properties that are reported by the given layer.
+ #[inline]
+ pub fn layer_extension_properties(
+ &self,
+ layer: &str,
+ ) -> Result<Vec<ExtensionProperties>, VulkanError> {
+ unsafe { Self::get_extension_properties(&self.fns, Some(layer)) }
+ }
+
+ /// Returns the extensions that are supported by the given layer.
+ #[inline]
+ pub fn supported_layer_extensions(
+ &self,
+ layer: &str,
+ ) -> Result<InstanceExtensions, VulkanError> {
+ Ok(self
+ .layer_extension_properties(layer)?
+ .iter()
+ .map(|property| property.extension_name.as_str())
+ .collect())
+ }
+
+ /// Returns the union of the extensions that are supported by the core library and all
+ /// the given layers.
+ #[inline]
+ pub fn supported_extensions_with_layers<'a>(
+ &self,
+ layers: impl IntoIterator<Item = &'a str>,
+ ) -> Result<InstanceExtensions, VulkanError> {
+ layers
+ .into_iter()
+ .try_fold(self.supported_extensions, |extensions, layer| {
+ self.supported_layer_extensions(layer)
+ .map(|layer_extensions| extensions.union(&layer_extensions))
+ })
+ }
+
+ /// Calls `get_instance_proc_addr` on the underlying loader.
+ #[inline]
+ pub unsafe fn get_instance_proc_addr(
+ &self,
+ instance: ash::vk::Instance,
+ name: *const c_char,
+ ) -> ash::vk::PFN_vkVoidFunction {
+ self.loader.get_instance_proc_addr(instance, name)
+ }
+}
+
+/// Implemented on objects that grant access to a Vulkan implementation.
+pub unsafe trait Loader: Send + Sync {
+ /// Calls the `vkGetInstanceProcAddr` function. The parameters are the same.
+ ///
+ /// The returned function must stay valid for as long as `self` is alive.
+ unsafe fn get_instance_proc_addr(
+ &self,
+ instance: ash::vk::Instance,
+ name: *const c_char,
+ ) -> ash::vk::PFN_vkVoidFunction;
+}
+
+unsafe impl<T> Loader for T
+where
+ T: SafeDeref + Send + Sync,
+ T::Target: Loader,
+{
+ unsafe fn get_instance_proc_addr(
+ &self,
+ instance: ash::vk::Instance,
+ name: *const c_char,
+ ) -> ash::vk::PFN_vkVoidFunction {
+ (**self).get_instance_proc_addr(instance, name)
+ }
+}
+
+impl Debug for dyn Loader {
+ fn fmt(&self, _f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ Ok(())
+ }
+}
+
+/// Implementation of `Loader` that loads Vulkan from a dynamic library.
+pub struct DynamicLibraryLoader {
+ _vk_lib: Library,
+ get_instance_proc_addr: ash::vk::PFN_vkGetInstanceProcAddr,
+}
+
+impl DynamicLibraryLoader {
+ /// Tries to load the dynamic library at the given path, and tries to
+ /// load `vkGetInstanceProcAddr` in it.
+ ///
+ /// # Safety
+ ///
+ /// - The dynamic library must be a valid Vulkan implementation.
+ ///
+ pub unsafe fn new(path: impl AsRef<Path>) -> Result<DynamicLibraryLoader, LoadingError> {
+ let vk_lib = Library::new(path.as_ref()).map_err(LoadingError::LibraryLoadFailure)?;
+
+ let get_instance_proc_addr = *vk_lib
+ .get(b"vkGetInstanceProcAddr")
+ .map_err(LoadingError::LibraryLoadFailure)?;
+
+ Ok(DynamicLibraryLoader {
+ _vk_lib: vk_lib,
+ get_instance_proc_addr,
+ })
+ }
+}
+
+unsafe impl Loader for DynamicLibraryLoader {
+ #[inline]
+ unsafe fn get_instance_proc_addr(
+ &self,
+ instance: ash::vk::Instance,
+ name: *const c_char,
+ ) -> ash::vk::PFN_vkVoidFunction {
+ (self.get_instance_proc_addr)(instance, name)
+ }
+}
+
+/// Expression that returns a loader that assumes that Vulkan is linked to the executable you're
+/// compiling.
+///
+/// If you use this macro, you must linked to a library that provides the `vkGetInstanceProcAddr`
+/// symbol.
+///
+/// This is provided as a macro and not as a regular function, because the macro contains an
+/// `extern {}` block.
+// TODO: should this be unsafe?
+#[macro_export]
+macro_rules! statically_linked_vulkan_loader {
+ () => {{
+ extern "C" {
+ fn vkGetInstanceProcAddr(
+ instance: ash::vk::Instance,
+ pName: *const c_char,
+ ) -> ash::vk::PFN_vkVoidFunction;
+ }
+
+ struct StaticallyLinkedVulkanLoader;
+ unsafe impl Loader for StaticallyLinkedVulkanLoader {
+ unsafe fn get_instance_proc_addr(
+ &self,
+ instance: ash::vk::Instance,
+ name: *const c_char,
+ ) -> ash::vk::PFN_vkVoidFunction {
+ vkGetInstanceProcAddr(instance, name)
+ }
+ }
+
+ StaticallyLinkedVulkanLoader
+ }};
+}
+
+/// Error that can happen when loading a Vulkan library.
+#[derive(Debug)]
+pub enum LoadingError {
+ /// Failed to load the Vulkan shared library.
+ LibraryLoadFailure(LibloadingError),
+
+ /// Not enough memory.
+ OomError(OomError),
+}
+
+impl Error for LoadingError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ //Self::LibraryLoadFailure(err) => Some(err),
+ Self::OomError(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+impl Display for LoadingError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ write!(
+ f,
+ "{}",
+ match self {
+ Self::LibraryLoadFailure(_) => "failed to load the Vulkan shared library",
+ Self::OomError(_) => "not enough memory available",
+ }
+ )
+ }
+}
+
+impl From<VulkanError> for LoadingError {
+ fn from(err: VulkanError) -> Self {
+ match err {
+ err @ VulkanError::OutOfHostMemory => Self::OomError(OomError::from(err)),
+ err @ VulkanError::OutOfDeviceMemory => Self::OomError(OomError::from(err)),
+ _ => panic!("unexpected error: {:?}", err),
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::{DynamicLibraryLoader, LoadingError};
+
+ #[test]
+ fn dl_open_error() {
+ unsafe {
+ match DynamicLibraryLoader::new("_non_existing_library.void") {
+ Err(LoadingError::LibraryLoadFailure(_)) => (),
+ _ => panic!(),
+ }
+ }
+ }
+}
diff --git a/src/macros.rs b/src/macros.rs
new file mode 100644
index 0000000..ee57133
--- /dev/null
+++ b/src/macros.rs
@@ -0,0 +1,947 @@
+// Copyright (c) 2022 The Vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+macro_rules! vulkan_bitflags {
+ {
+ $(#[doc = $ty_doc:literal])*
+ $ty:ident
+ $( impl { $($impls:item)* } )?
+ = $ty_ffi:ident($repr:ty);
+
+ $(
+ $(#[doc = $flag_doc:literal])*
+ $flag_name:ident = $flag_name_ffi:ident,
+ )+
+ } => {
+ $(#[doc = $ty_doc])*
+ #[derive(Clone, Copy, PartialEq, Eq, Hash)]
+ pub struct $ty($repr);
+
+ impl $ty {
+ $(
+ $(#[doc = $flag_doc])*
+ pub const $flag_name: Self = Self(ash::vk::$ty_ffi::$flag_name_ffi.as_raw());
+ )*
+
+ #[doc = concat!("Returns a `", stringify!($ty), "` with none of the flags set.")]
+ #[inline]
+ pub const fn empty() -> Self {
+ Self(0)
+ }
+
+ #[deprecated(since = "0.31.0", note = "Use `empty` instead.")]
+ #[doc = concat!("Returns a `", stringify!($ty), "` with none of the flags set.")]
+ #[inline]
+ pub const fn none() -> Self {
+ Self::empty()
+ }
+
+ #[doc = concat!("Returns a `", stringify!($ty), "` with all of the flags set.")]
+ #[inline]
+ pub const fn all() -> Self {
+ Self(Self::all_raw())
+ }
+
+ const fn all_raw() -> $repr {
+ 0
+ $(
+ | ash::vk::$ty_ffi::$flag_name_ffi.as_raw()
+ )*
+ }
+
+ /// Returns whether no flags are set in `self`.
+ #[inline]
+ pub const fn is_empty(self) -> bool {
+ self.0 == 0
+ }
+
+ /// Returns whether any flags are set in both `self` and `other`.
+ #[inline]
+ pub const fn intersects(self, #[allow(unused_variables)] other: Self) -> bool {
+ self.0 & other.0 != 0
+ }
+
+ /// Returns whether all flags in `other` are set in `self`.
+ #[inline]
+ pub const fn contains(self, #[allow(unused_variables)] other: Self) -> bool {
+ self.0 & other.0 == other.0
+ }
+
+ /// Returns the union of `self` and `other`.
+ #[inline]
+ pub const fn union(self, #[allow(unused_variables)] other: Self) -> Self {
+ Self(self.0 | other.0)
+ }
+
+ /// Returns the intersection of `self` and `other`.
+ #[inline]
+ pub const fn intersection(self, #[allow(unused_variables)] other: Self) -> Self {
+ Self(self.0 & other.0)
+ }
+
+ /// Returns `self` without the flags set in `other`.
+ #[inline]
+ pub const fn difference(self, #[allow(unused_variables)] other: Self) -> Self {
+ Self(self.0 & !other.0)
+ }
+
+ /// Returns the flags that are set in `self` or `other`, but not in both.
+ #[inline]
+ pub const fn symmetric_difference(self, #[allow(unused_variables)] other: Self) -> Self {
+ Self(self.0 ^ other.0)
+ }
+
+ /// Returns the flags not in `self`.
+ #[inline]
+ pub const fn complement(self) -> Self {
+ Self(!self.0 & Self::all_raw())
+ }
+
+ $( $($impls)* )?
+ }
+
+ impl Default for $ty {
+ #[inline]
+ fn default() -> Self {
+ Self::empty()
+ }
+ }
+
+ impl std::fmt::Debug for $ty {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
+ #[allow(unused_mut)]
+ let mut written = false;
+
+ $(
+ if self.intersects(Self::$flag_name) {
+ if written {
+ write!(f, " | ")?;
+ }
+
+ write!(f, stringify!($flag_name))?;
+ written = true;
+ }
+ )*
+
+ if !written {
+ write!(f, "empty()")?;
+ }
+
+ Ok(())
+ }
+ }
+
+ impl From<$ty> for ash::vk::$ty_ffi {
+ #[inline]
+ fn from(val: $ty) -> Self {
+ ash::vk::$ty_ffi::from_raw(val.0)
+ }
+ }
+
+ impl From<ash::vk::$ty_ffi> for $ty {
+ #[inline]
+ fn from(val: ash::vk::$ty_ffi) -> Self {
+ Self(val.as_raw() & Self::all_raw())
+ }
+ }
+
+ impl std::ops::BitAnd for $ty {
+ type Output = Self;
+
+ #[inline]
+ fn bitand(self, rhs: Self) -> Self {
+ self.intersection(rhs)
+ }
+ }
+
+ impl std::ops::BitAndAssign for $ty {
+ #[inline]
+ fn bitand_assign(&mut self, rhs: Self) {
+ *self = self.intersection(rhs);
+ }
+ }
+
+ impl std::ops::BitOr for $ty {
+ type Output = Self;
+
+ #[inline]
+ fn bitor(self, rhs: Self) -> Self {
+ self.union(rhs)
+ }
+ }
+
+ impl std::ops::BitOrAssign for $ty {
+ #[inline]
+ fn bitor_assign(&mut self, rhs: Self) {
+ *self = self.union(rhs);
+ }
+ }
+
+ impl std::ops::BitXor for $ty {
+ type Output = Self;
+
+ #[inline]
+ fn bitxor(self, rhs: Self) -> Self {
+ self.symmetric_difference(rhs)
+ }
+ }
+
+ impl std::ops::BitXorAssign for $ty {
+ #[inline]
+ fn bitxor_assign(&mut self, rhs: Self) {
+ *self = self.symmetric_difference(rhs);
+ }
+ }
+
+ impl std::ops::Sub for $ty {
+ type Output = Self;
+
+ #[inline]
+ fn sub(self, rhs: Self) -> Self {
+ self.difference(rhs)
+ }
+ }
+
+ impl std::ops::SubAssign for $ty {
+ #[inline]
+ fn sub_assign(&mut self, rhs: Self) {
+ *self = self.difference(rhs);
+ }
+ }
+
+ impl std::ops::Not for $ty {
+ type Output = Self;
+
+ #[inline]
+ fn not(self) -> Self {
+ self.complement()
+ }
+ }
+ };
+
+ {
+ #[non_exhaustive]
+
+ $(#[doc = $ty_doc:literal])*
+ $ty:ident
+ $( impl { $($impls:item)* } )?
+ = $ty_ffi:ident($repr:ty);
+
+ $(
+ $(#[doc = $flag_doc:literal])*
+ $flag_name:ident = $flag_name_ffi:ident
+ $({
+ $(api_version: $api_version:ident,)?
+ $(features: [$($feature:ident),+ $(,)?],)?
+ $(device_extensions: [$($device_extension:ident),+ $(,)?],)?
+ $(instance_extensions: [$($instance_extension:ident),+ $(,)?],)?
+ })?
+ ,
+ )*
+ } => {
+ $(#[doc = $ty_doc])*
+ #[derive(Clone, Copy, PartialEq, Eq, Hash)]
+ pub struct $ty($repr);
+
+ impl $ty {
+ $(
+ $(#[doc = $flag_doc])*
+ pub const $flag_name: Self = Self(ash::vk::$ty_ffi::$flag_name_ffi.as_raw());
+ )*
+
+ #[doc = concat!("Returns a `", stringify!($ty), "` with none of the flags set.")]
+ #[inline]
+ pub const fn empty() -> Self {
+ Self(0)
+ }
+
+ #[deprecated(since = "0.31.0", note = "Use `empty` instead.")]
+ #[doc = concat!("Returns a `", stringify!($ty), "` with none of the flags set.")]
+ #[inline]
+ pub const fn none() -> Self {
+ Self::empty()
+ }
+
+ const fn all_raw() -> $repr {
+ 0
+ $(
+ | ash::vk::$ty_ffi::$flag_name_ffi.as_raw()
+ )*
+ }
+
+ /// Returns the number of flags set in self.
+ #[inline]
+ pub const fn count(self) -> u32 {
+ self.0.count_ones()
+ }
+
+ /// Returns whether no flags are set in `self`.
+ #[inline]
+ pub const fn is_empty(self) -> bool {
+ self.0 == 0
+ }
+
+ /// Returns whether any flags are set in both `self` and `other`.
+ #[inline]
+ pub const fn intersects(self, #[allow(unused_variables)] other: Self) -> bool {
+ self.0 & other.0 != 0
+ }
+
+ /// Returns whether all flags in `other` are set in `self`.
+ #[inline]
+ pub const fn contains(self, #[allow(unused_variables)] other: Self) -> bool {
+ self.0 & other.0 == other.0
+ }
+
+ /// Returns the union of `self` and `other`.
+ #[inline]
+ pub const fn union(self, #[allow(unused_variables)] other: Self) -> Self {
+ Self(self.0 | other.0)
+ }
+
+ /// Returns the intersection of `self` and `other`.
+ #[inline]
+ pub const fn intersection(self, #[allow(unused_variables)] other: Self) -> Self {
+ Self(self.0 & other.0)
+ }
+
+ /// Returns `self` without the flags set in `other`.
+ #[inline]
+ pub const fn difference(self, #[allow(unused_variables)] other: Self) -> Self {
+ Self(self.0 & !other.0)
+ }
+
+ /// Returns the flags that are set in `self` or `other`, but not in both.
+ #[inline]
+ pub const fn symmetric_difference(self, #[allow(unused_variables)] other: Self) -> Self {
+ Self(self.0 ^ other.0)
+ }
+
+ #[allow(dead_code)]
+ pub(crate) fn validate_device(
+ self,
+ #[allow(unused_variables)] device: &crate::device::Device,
+ ) -> Result<(), crate::RequirementNotMet> {
+ $(
+ $(
+ if self.intersects(Self::$flag_name) && ![
+ $(
+ device.api_version() >= crate::Version::$api_version,
+ )?
+ $($(
+ device.enabled_features().$feature,
+ )+)?
+ $($(
+ device.enabled_extensions().$device_extension,
+ )+)?
+ $($(
+ device.instance().enabled_extensions().$instance_extension,
+ )+)?
+ ].into_iter().any(|x| x) {
+ return Err(crate::RequirementNotMet {
+ required_for: concat!("`", stringify!($ty), "::", stringify!($flag_name), "`"),
+ requires_one_of: crate::RequiresOneOf {
+ $(api_version: Some(crate::Version::$api_version),)?
+ $(features: &[$(stringify!($feature)),+],)?
+ $(device_extensions: &[$(stringify!($device_extension)),+],)?
+ $(instance_extensions: &[$(stringify!($instance_extension)),+],)?
+ ..Default::default()
+ },
+ });
+ }
+ )?
+ )*
+
+ Ok(())
+ }
+
+ #[allow(dead_code)]
+ pub(crate) fn validate_physical_device(
+ self,
+ #[allow(unused_variables)] physical_device: &crate::device::physical::PhysicalDevice,
+ ) -> Result<(), crate::RequirementNotMet> {
+ $(
+ $(
+ if self.intersects(Self::$flag_name) && ![
+ $(
+ physical_device.api_version() >= crate::Version::$api_version,
+ )?
+ $($(
+ physical_device.supported_features().$feature,
+ )+)?
+ $($(
+ physical_device.supported_extensions().$device_extension,
+ )+)?
+ $($(
+ physical_device.instance().enabled_extensions().$instance_extension,
+ )+)?
+ ].into_iter().any(|x| x) {
+ return Err(crate::RequirementNotMet {
+ required_for: concat!("`", stringify!($ty), "::", stringify!($flag_name), "`"),
+ requires_one_of: crate::RequiresOneOf {
+ $(api_version: Some(crate::Version::$api_version),)?
+ $(features: &[$(stringify!($feature)),+],)?
+ $(device_extensions: &[$(stringify!($device_extension)),+],)?
+ $(instance_extensions: &[$(stringify!($instance_extension)),+],)?
+ ..Default::default()
+ },
+ });
+ }
+ )?
+ )*
+
+ Ok(())
+ }
+
+ #[allow(dead_code)]
+ pub(crate) fn validate_instance(
+ self,
+ #[allow(unused_variables)] instance: &crate::instance::Instance,
+ ) -> Result<(), crate::RequirementNotMet> {
+ $(
+ $(
+ if self.intersects(Self::$flag_name) && ![
+ $(
+ instance.api_version() >= crate::Version::$api_version,
+ )?
+ $($(
+ instance.enabled_extensions().$instance_extension,
+ )+)?
+ ].into_iter().any(|x| x) {
+ return Err(crate::RequirementNotMet {
+ required_for: concat!("`", stringify!($ty), "::", stringify!($flag_name), "`"),
+ requires_one_of: crate::RequiresOneOf {
+ $(api_version: Some(crate::Version::$api_version),)?
+ $(instance_extensions: &[$(stringify!($instance_extension)),+],)?
+ ..Default::default()
+ },
+ });
+ }
+ )?
+ )*
+
+ Ok(())
+ }
+
+ $( $($impls)* )?
+ }
+
+ impl Default for $ty {
+ #[inline]
+ fn default() -> Self {
+ Self::empty()
+ }
+ }
+
+ impl std::fmt::Debug for $ty {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
+ #[allow(unused_mut)]
+ let mut written = false;
+
+ $(
+ if self.intersects(Self::$flag_name) {
+ if written {
+ write!(f, " | ")?;
+ }
+
+ write!(f, stringify!($flag_name))?;
+ written = true;
+ }
+ )*
+
+ if !written {
+ write!(f, "empty()")?;
+ }
+
+ Ok(())
+ }
+ }
+
+ impl From<$ty> for ash::vk::$ty_ffi {
+ #[inline]
+ fn from(val: $ty) -> Self {
+ ash::vk::$ty_ffi::from_raw(val.0)
+ }
+ }
+
+ impl From<ash::vk::$ty_ffi> for $ty {
+ #[inline]
+ fn from(val: ash::vk::$ty_ffi) -> Self {
+ Self(val.as_raw() & Self::all_raw())
+ }
+ }
+
+ impl std::ops::BitAnd for $ty {
+ type Output = Self;
+
+ #[inline]
+ fn bitand(self, rhs: Self) -> Self {
+ self.intersection(rhs)
+ }
+ }
+
+ impl std::ops::BitAndAssign for $ty {
+ #[inline]
+ fn bitand_assign(&mut self, rhs: Self) {
+ *self = self.intersection(rhs);
+ }
+ }
+
+ impl std::ops::BitOr for $ty {
+ type Output = Self;
+
+ #[inline]
+ fn bitor(self, rhs: Self) -> Self {
+ self.union(rhs)
+ }
+ }
+
+ impl std::ops::BitOrAssign for $ty {
+ #[inline]
+ fn bitor_assign(&mut self, rhs: Self) {
+ *self = self.union(rhs);
+ }
+ }
+
+ impl std::ops::BitXor for $ty {
+ type Output = Self;
+
+ #[inline]
+ fn bitxor(self, rhs: Self) -> Self {
+ self.symmetric_difference(rhs)
+ }
+ }
+
+ impl std::ops::BitXorAssign for $ty {
+ #[inline]
+ fn bitxor_assign(&mut self, rhs: Self) {
+ *self = self.symmetric_difference(rhs);
+ }
+ }
+
+ impl std::ops::Sub for $ty {
+ type Output = Self;
+
+ #[inline]
+ fn sub(self, rhs: Self) -> Self {
+ self.difference(rhs)
+ }
+ }
+
+ impl std::ops::SubAssign for $ty {
+ #[inline]
+ fn sub_assign(&mut self, rhs: Self) {
+ *self = self.difference(rhs);
+ }
+ }
+ };
+}
+
+macro_rules! vulkan_enum {
+ {
+ $(#[doc = $ty_doc:literal])*
+ $ty:ident
+ $( impl { $($impls:item)* } )?
+ = $ty_ffi:ident($repr:ty);
+
+ $(
+ $(#[doc = $flag_doc:literal])*
+ $flag_name:ident = $flag_name_ffi:ident,
+ )+
+ } => {
+ $(#[doc = $ty_doc])*
+ #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+ #[repr($repr)]
+ pub enum $ty {
+ $(
+ $(#[doc = $flag_doc])*
+ $flag_name = ash::vk::$ty_ffi::$flag_name_ffi.as_raw(),
+ )+
+ }
+
+ $(
+ impl $ty {
+ $($impls)*
+ }
+ )?
+
+ impl From<$ty> for ash::vk::$ty_ffi {
+ #[inline]
+ fn from(val: $ty) -> Self {
+ ash::vk::$ty_ffi::from_raw(val as $repr)
+ }
+ }
+
+ impl TryFrom<ash::vk::$ty_ffi> for $ty {
+ type Error = ();
+
+ #[inline]
+ fn try_from(val: ash::vk::$ty_ffi) -> Result<Self, Self::Error> {
+ Ok(match val {
+ $(
+ ash::vk::$ty_ffi::$flag_name_ffi => Self::$flag_name,
+ )+
+ _ => return Err(()),
+ })
+ }
+ }
+ };
+
+ {
+ #[non_exhaustive]
+
+ $(#[doc = $ty_doc:literal])*
+ $ty:ident
+ $( impl { $($impls:item)* } )?
+ = $ty_ffi:ident($repr:ty);
+
+ $(
+ $(#[doc = $flag_doc:literal])*
+ $flag_name:ident = $flag_name_ffi:ident
+ $({
+ $(api_version: $api_version:ident,)?
+ $(features: [$($feature:ident),+ $(,)?],)?
+ $(device_extensions: [$($device_extension:ident),+ $(,)?],)?
+ $(instance_extensions: [$($instance_extension:ident),+ $(,)?],)?
+ })?
+ ,
+ )+
+ } => {
+ $(#[doc = $ty_doc])*
+ #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+ #[non_exhaustive]
+ #[repr($repr)]
+ pub enum $ty {
+ $(
+ $(#[doc = $flag_doc])*
+ $flag_name = ash::vk::$ty_ffi::$flag_name_ffi.as_raw(),
+ )+
+ }
+
+ impl $ty {
+ #[allow(dead_code)]
+ pub(crate) fn validate_device(
+ self,
+ #[allow(unused_variables)] device: &crate::device::Device,
+ ) -> Result<(), crate::RequirementNotMet> {
+ match self {
+ $(
+ $(
+ Self::$flag_name => {
+ if ![
+ $(
+ device.api_version() >= crate::Version::$api_version,
+ )?
+ $($(
+ device.enabled_features().$feature,
+ )+)?
+ $($(
+ device.enabled_extensions().$device_extension,
+ )+)?
+ $($(
+ device.instance().enabled_extensions().$instance_extension,
+ )+)?
+ ].into_iter().any(|x| x) {
+ return Err(crate::RequirementNotMet {
+ required_for: concat!("`", stringify!($ty), "::", stringify!($flag_name), "`"),
+ requires_one_of: crate::RequiresOneOf {
+ $(api_version: Some(crate::Version::$api_version),)?
+ $(features: &[$(stringify!($feature)),+],)?
+ $(device_extensions: &[$(stringify!($device_extension)),+],)?
+ $(instance_extensions: &[$(stringify!($instance_extension)),+],)?
+ ..Default::default()
+ },
+ });
+ }
+ },
+ )?
+ )+
+ _ => (),
+ }
+
+ Ok(())
+ }
+
+ #[allow(dead_code)]
+ pub(crate) fn validate_physical_device(
+ self,
+ #[allow(unused_variables)] physical_device: &crate::device::physical::PhysicalDevice,
+ ) -> Result<(), crate::RequirementNotMet> {
+ match self {
+ $(
+ $(
+ Self::$flag_name => {
+ if ![
+ $(
+ physical_device.api_version() >= crate::Version::$api_version,
+ )?
+ $($(
+ physical_device.supported_features().$feature,
+ )+)?
+ $($(
+ physical_device.supported_extensions().$device_extension,
+ )+)?
+ $($(
+ physical_device.instance().enabled_extensions().$instance_extension,
+ )+)?
+ ].into_iter().any(|x| x) {
+ return Err(crate::RequirementNotMet {
+ required_for: concat!("`", stringify!($ty), "::", stringify!($flag_name), "`"),
+ requires_one_of: crate::RequiresOneOf {
+ $(api_version: Some(crate::Version::$api_version),)?
+ $(features: &[$(stringify!($feature)),+],)?
+ $(device_extensions: &[$(stringify!($device_extension)),+],)?
+ $(instance_extensions: &[$(stringify!($instance_extension)),+],)?
+ ..Default::default()
+ },
+ });
+ }
+ },
+ )?
+ )+
+ _ => (),
+ }
+
+ Ok(())
+ }
+
+ #[allow(dead_code)]
+ pub(crate) fn validate_instance(
+ self,
+ #[allow(unused_variables)] instance: &crate::instance::Instance,
+ ) -> Result<(), crate::RequirementNotMet> {
+ match self {
+ $(
+ $(
+ Self::$flag_name => {
+ if ![
+ $(
+ instance.api_version() >= crate::Version::$api_version,
+ )?
+ $($(
+ instance.enabled_extensions().$instance_extension,
+ )+)?
+ ].into_iter().any(|x| x) {
+ return Err(crate::RequirementNotMet {
+ required_for: concat!("`", stringify!($ty), "::", stringify!($flag_name), "`"),
+ requires_one_of: crate::RequiresOneOf {
+ $(api_version: Some(crate::Version::$api_version),)?
+ $(instance_extensions: &[$(stringify!($instance_extension)),+],)?
+ ..Default::default()
+ },
+ });
+ }
+ },
+ )?
+ )+
+ _ => (),
+ }
+
+ Ok(())
+ }
+
+ $(
+ $($impls)*
+ )?
+ }
+
+ impl From<$ty> for ash::vk::$ty_ffi {
+ #[inline]
+ fn from(val: $ty) -> Self {
+ ash::vk::$ty_ffi::from_raw(val as $repr)
+ }
+ }
+
+ impl TryFrom<ash::vk::$ty_ffi> for $ty {
+ type Error = ();
+
+ #[inline]
+ fn try_from(val: ash::vk::$ty_ffi) -> Result<Self, Self::Error> {
+ Ok(match val {
+ $(
+ ash::vk::$ty_ffi::$flag_name_ffi => Self::$flag_name,
+ )+
+ _ => return Err(()),
+ })
+ }
+ }
+ };
+}
+
+macro_rules! vulkan_bitflags_enum {
+ {
+ #[non_exhaustive]
+
+ $(#[doc = $ty_bitflags_doc:literal])*
+ $ty_bitflags:ident
+ $( impl { $($impls_bitflags:item)* } )?
+ ,
+
+ $(#[doc = $ty_enum_doc:literal])*
+ $ty_enum:ident
+ $( impl { $($impls_enum:item)* } )?
+ ,
+
+ = $ty_ffi:ident($repr:ty);
+
+ $(
+ $(#[doc = $flag_doc:literal])*
+ $flag_name_bitflags:ident, $flag_name_enum:ident = $flag_name_ffi:ident
+ $({
+ $(api_version: $api_version:ident,)?
+ $(features: [$($feature:ident),+ $(,)?],)?
+ $(device_extensions: [$($device_extension:ident),+ $(,)?],)?
+ $(instance_extensions: [$($instance_extension:ident),+ $(,)?],)?
+ })?
+ ,
+ )*
+ } => {
+ crate::macros::vulkan_bitflags! {
+ #[non_exhaustive]
+
+ $(#[doc = $ty_bitflags_doc])*
+ $ty_bitflags
+ impl {
+ /// Returns whether `self` contains the flag corresponding to `val`.
+ #[inline]
+ pub fn contains_enum(self, val: $ty_enum) -> bool {
+ self.intersects(val.into())
+ }
+
+ $( $($impls_bitflags)* )?
+ }
+ = $ty_ffi($repr);
+
+ $(
+ $(#[doc = $flag_doc])*
+ $flag_name_bitflags = $flag_name_ffi
+ $({
+ $(api_version: $api_version,)?
+ $(features: [$($feature),+],)?
+ $(device_extensions: [$($device_extension),+],)?
+ $(instance_extensions: [$($instance_extension),+],)?
+ })?
+ ,
+ )*
+ }
+
+ crate::macros::vulkan_enum! {
+ #[non_exhaustive]
+
+ $(#[doc = $ty_enum_doc])*
+ $ty_enum
+ $( impl { $($impls_enum)* } )?
+ = $ty_ffi($repr);
+
+ $(
+ $(#[doc = $flag_doc])*
+ $flag_name_enum = $flag_name_ffi
+ $({
+ $(api_version: $api_version,)?
+ $(features: [$($feature),+],)?
+ $(device_extensions: [$($device_extension),+],)?
+ $(instance_extensions: [$($instance_extension),+],)?
+ })?
+ ,
+ )*
+ }
+
+ impl From<$ty_enum> for $ty_bitflags {
+ #[inline]
+ fn from(val: $ty_enum) -> Self {
+ Self(val as $repr)
+ }
+ }
+
+ impl FromIterator<$ty_enum> for $ty_bitflags {
+ #[inline]
+ fn from_iter<T>(iter: T) -> Self where T: IntoIterator<Item = $ty_enum> {
+ iter.into_iter().map(|item| Self::from(item)).fold(Self::empty(), |r, i| r.union(i))
+ }
+ }
+
+ impl IntoIterator for $ty_bitflags {
+ type Item = $ty_enum;
+ type IntoIter = std::iter::Flatten<
+ std::array::IntoIter<
+ Option<Self::Item>,
+ { $ty_bitflags::all_raw().count_ones() as usize },
+ >
+ >;
+
+ #[inline]
+ fn into_iter(self) -> Self::IntoIter {
+ [
+ $(
+ self.intersects(Self::$flag_name_bitflags)
+ .then_some($ty_enum::$flag_name_enum),
+ )*
+ ].into_iter().flatten()
+ }
+ }
+ }
+}
+
+macro_rules! impl_id_counter {
+ ($type:ident $(< $($param:ident $(: $bound:ident $(+ $bounds:ident)* )?),+ >)?) => {
+ $crate::macros::impl_id_counter!(
+ @inner $type $(< $($param),+ >)?, $( $($param $(: $bound $(+ $bounds)* )?),+)?
+ );
+ };
+ ($type:ident $(< $($param:ident $(: $bound:ident $(+ $bounds:ident)* )? + ?Sized),+ >)?) => {
+ $crate::macros::impl_id_counter!(
+ @inner $type $(< $($param),+ >)?, $( $($param $(: $bound $(+ $bounds)* )? + ?Sized),+)?
+ );
+ };
+ (@inner $type:ident $(< $($param:ident),+ >)?, $($bounds:tt)*) => {
+ impl< $($bounds)* > $type $(< $($param),+ >)? {
+ fn next_id() -> std::num::NonZeroU64 {
+ use std::{
+ num::NonZeroU64,
+ sync::atomic::{AtomicU64, Ordering},
+ };
+
+ static COUNTER: AtomicU64 = AtomicU64::new(1);
+
+ NonZeroU64::new(COUNTER.fetch_add(1, Ordering::Relaxed)).unwrap_or_else(|| {
+ println!("an ID counter has overflown ...somehow");
+ std::process::abort();
+ })
+ }
+ }
+
+ impl< $($bounds)* > PartialEq for $type $(< $($param),+ >)? {
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ self.id == other.id
+ }
+ }
+
+ impl< $($bounds)* > Eq for $type $(< $($param),+ >)? {}
+
+ impl< $($bounds)* > std::hash::Hash for $type $(< $($param),+ >)? {
+ fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+ self.id.hash(state);
+ }
+ }
+ };
+}
+
+// TODO: Replace with the `?` operator once its constness is stabilized.
+macro_rules! try_opt {
+ ($e:expr) => {
+ if let Some(val) = $e {
+ val
+ } else {
+ return None;
+ }
+ };
+}
+
+pub(crate) use {impl_id_counter, try_opt, vulkan_bitflags, vulkan_bitflags_enum, vulkan_enum};
diff --git a/src/memory/alignment.rs b/src/memory/alignment.rs
new file mode 100644
index 0000000..290240b
--- /dev/null
+++ b/src/memory/alignment.rs
@@ -0,0 +1,249 @@
+use crate::{DeviceSize, NonZeroDeviceSize};
+use std::{
+ cmp::Ordering,
+ error::Error,
+ fmt::{Debug, Display, Formatter, Result as FmtResult},
+ hash::{Hash, Hasher},
+ mem::{self, align_of, size_of},
+};
+
+/// Vulkan analog of std's [`Alignment`], stored as a [`DeviceSize`] that is guaranteed to be a
+/// valid Vulkan alignment.
+///
+/// [`Alignment`]: std::ptr::Alignment
+#[derive(Clone, Copy, PartialEq, Eq)]
+#[repr(transparent)]
+pub struct DeviceAlignment(AlignmentEnum);
+
+const _: () = assert!(size_of::<DeviceAlignment>() == size_of::<DeviceSize>());
+const _: () = assert!(align_of::<DeviceAlignment>() == align_of::<DeviceSize>());
+
+impl DeviceAlignment {
+ /// The smallest possible alignment, 1.
+ pub const MIN: Self = Self(AlignmentEnum::_Align1Shl0);
+
+ /// The largest possible alignment, 2<sup>63</sup>.
+ pub const MAX: Self = Self(AlignmentEnum::_Align1Shl63);
+
+ /// Returns the alignment for a type.
+ #[inline]
+ pub const fn of<T>() -> Self {
+ #[cfg(any(
+ target_pointer_width = "64",
+ target_pointer_width = "32",
+ target_pointer_width = "16",
+ ))]
+ {
+ const _: () = assert!(size_of::<DeviceSize>() >= size_of::<usize>());
+
+ // SAFETY: rustc guarantees that the alignment of types is a power of two.
+ unsafe { DeviceAlignment::new_unchecked(align_of::<T>() as DeviceSize) }
+ }
+ }
+
+ /// Tries to create a `DeviceAlignment` from a [`DeviceSize`], returning [`None`] if it's not a
+ /// power of two.
+ #[inline]
+ pub const fn new(alignment: DeviceSize) -> Option<Self> {
+ if alignment.is_power_of_two() {
+ Some(unsafe { DeviceAlignment::new_unchecked(alignment) })
+ } else {
+ None
+ }
+ }
+
+ /// Creates a `DeviceAlignment` from a [`DeviceSize`] without checking if it's a power of two.
+ ///
+ /// # Safety
+ ///
+ /// - `alignment` must be a power of two, which also means it must be non-zero.
+ #[inline]
+ pub const unsafe fn new_unchecked(alignment: DeviceSize) -> Self {
+ debug_assert!(alignment.is_power_of_two());
+
+ unsafe { mem::transmute::<DeviceSize, DeviceAlignment>(alignment) }
+ }
+
+ /// Returns the alignment as a [`DeviceSize`].
+ #[inline]
+ pub const fn as_devicesize(self) -> DeviceSize {
+ self.0 as DeviceSize
+ }
+
+ /// Returns the alignment as a [`NonZeroDeviceSize`].
+ #[inline]
+ pub const fn as_nonzero(self) -> NonZeroDeviceSize {
+ // SAFETY: All the discriminants are non-zero.
+ unsafe { NonZeroDeviceSize::new_unchecked(self.as_devicesize()) }
+ }
+
+ /// Returns the base-2 logarithm of the alignment.
+ #[inline]
+ pub const fn log2(self) -> u32 {
+ self.as_nonzero().trailing_zeros()
+ }
+
+ // TODO: Replace with `Ord::max` once its constness is stabilized.
+ #[inline(always)]
+ pub(crate) const fn max(self, other: Self) -> Self {
+ if self.as_devicesize() >= other.as_devicesize() {
+ self
+ } else {
+ other
+ }
+ }
+}
+
+impl Debug for DeviceAlignment {
+ fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
+ write!(f, "{:?} (1 << {:?})", self.as_nonzero(), self.log2())
+ }
+}
+
+impl Default for DeviceAlignment {
+ #[inline]
+ fn default() -> Self {
+ DeviceAlignment::MIN
+ }
+}
+
+impl TryFrom<NonZeroDeviceSize> for DeviceAlignment {
+ type Error = TryFromIntError;
+
+ #[inline]
+ fn try_from(alignment: NonZeroDeviceSize) -> Result<Self, Self::Error> {
+ if alignment.is_power_of_two() {
+ Ok(unsafe { DeviceAlignment::new_unchecked(alignment.get()) })
+ } else {
+ Err(TryFromIntError)
+ }
+ }
+}
+
+impl TryFrom<DeviceSize> for DeviceAlignment {
+ type Error = TryFromIntError;
+
+ #[inline]
+ fn try_from(alignment: DeviceSize) -> Result<Self, Self::Error> {
+ DeviceAlignment::new(alignment).ok_or(TryFromIntError)
+ }
+}
+
+impl From<DeviceAlignment> for NonZeroDeviceSize {
+ #[inline]
+ fn from(alignment: DeviceAlignment) -> Self {
+ alignment.as_nonzero()
+ }
+}
+
+impl From<DeviceAlignment> for DeviceSize {
+ #[inline]
+ fn from(alignment: DeviceAlignment) -> Self {
+ alignment.as_devicesize()
+ }
+}
+
+// This is a false-positive, the underlying values that this impl and the derived `PartialEq` work
+// with are the same.
+#[allow(clippy::derived_hash_with_manual_eq)]
+impl Hash for DeviceAlignment {
+ #[inline]
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.as_nonzero().hash(state);
+ }
+}
+
+impl PartialOrd for DeviceAlignment {
+ #[inline]
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ self.as_nonzero().partial_cmp(&other.as_nonzero())
+ }
+}
+
+impl Ord for DeviceAlignment {
+ #[inline]
+ fn cmp(&self, other: &Self) -> Ordering {
+ self.as_nonzero().cmp(&other.as_nonzero())
+ }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq)]
+#[repr(u64)]
+enum AlignmentEnum {
+ _Align1Shl0 = 1 << 0,
+ _Align1Shl1 = 1 << 1,
+ _Align1Shl2 = 1 << 2,
+ _Align1Shl3 = 1 << 3,
+ _Align1Shl4 = 1 << 4,
+ _Align1Shl5 = 1 << 5,
+ _Align1Shl6 = 1 << 6,
+ _Align1Shl7 = 1 << 7,
+ _Align1Shl8 = 1 << 8,
+ _Align1Shl9 = 1 << 9,
+ _Align1Shl10 = 1 << 10,
+ _Align1Shl11 = 1 << 11,
+ _Align1Shl12 = 1 << 12,
+ _Align1Shl13 = 1 << 13,
+ _Align1Shl14 = 1 << 14,
+ _Align1Shl15 = 1 << 15,
+ _Align1Shl16 = 1 << 16,
+ _Align1Shl17 = 1 << 17,
+ _Align1Shl18 = 1 << 18,
+ _Align1Shl19 = 1 << 19,
+ _Align1Shl20 = 1 << 20,
+ _Align1Shl21 = 1 << 21,
+ _Align1Shl22 = 1 << 22,
+ _Align1Shl23 = 1 << 23,
+ _Align1Shl24 = 1 << 24,
+ _Align1Shl25 = 1 << 25,
+ _Align1Shl26 = 1 << 26,
+ _Align1Shl27 = 1 << 27,
+ _Align1Shl28 = 1 << 28,
+ _Align1Shl29 = 1 << 29,
+ _Align1Shl30 = 1 << 30,
+ _Align1Shl31 = 1 << 31,
+ _Align1Shl32 = 1 << 32,
+ _Align1Shl33 = 1 << 33,
+ _Align1Shl34 = 1 << 34,
+ _Align1Shl35 = 1 << 35,
+ _Align1Shl36 = 1 << 36,
+ _Align1Shl37 = 1 << 37,
+ _Align1Shl38 = 1 << 38,
+ _Align1Shl39 = 1 << 39,
+ _Align1Shl40 = 1 << 40,
+ _Align1Shl41 = 1 << 41,
+ _Align1Shl42 = 1 << 42,
+ _Align1Shl43 = 1 << 43,
+ _Align1Shl44 = 1 << 44,
+ _Align1Shl45 = 1 << 45,
+ _Align1Shl46 = 1 << 46,
+ _Align1Shl47 = 1 << 47,
+ _Align1Shl48 = 1 << 48,
+ _Align1Shl49 = 1 << 49,
+ _Align1Shl50 = 1 << 50,
+ _Align1Shl51 = 1 << 51,
+ _Align1Shl52 = 1 << 52,
+ _Align1Shl53 = 1 << 53,
+ _Align1Shl54 = 1 << 54,
+ _Align1Shl55 = 1 << 55,
+ _Align1Shl56 = 1 << 56,
+ _Align1Shl57 = 1 << 57,
+ _Align1Shl58 = 1 << 58,
+ _Align1Shl59 = 1 << 59,
+ _Align1Shl60 = 1 << 60,
+ _Align1Shl61 = 1 << 61,
+ _Align1Shl62 = 1 << 62,
+ _Align1Shl63 = 1 << 63,
+}
+
+/// Error that can happen when trying to convert an integer to a `DeviceAlignment`.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct TryFromIntError;
+
+impl Error for TryFromIntError {}
+
+impl Display for TryFromIntError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
+ f.write_str("attempted to convert a non-power-of-two integer to a `DeviceAlignment`")
+ }
+}
diff --git a/src/memory/allocator/layout.rs b/src/memory/allocator/layout.rs
new file mode 100644
index 0000000..bca396a
--- /dev/null
+++ b/src/memory/allocator/layout.rs
@@ -0,0 +1,352 @@
+// Copyright (c) 2016 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use super::align_up;
+use crate::{macros::try_opt, memory::DeviceAlignment, DeviceSize, NonZeroDeviceSize};
+use std::{
+ alloc::Layout,
+ error::Error,
+ fmt::{Debug, Display, Formatter, Result as FmtResult},
+ hash::Hash,
+ mem::size_of,
+};
+
+/// Vulkan analog of std's [`Layout`], represented using [`DeviceSize`]s.
+///
+/// Unlike `Layout`s, `DeviceLayout`s are required to have non-zero size.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct DeviceLayout {
+ size: NonZeroDeviceSize,
+ alignment: DeviceAlignment,
+}
+
+impl DeviceLayout {
+ /// The maximum size of a memory block after its layout's size has been rounded up to the
+ /// nearest multiple of its layout's alignment.
+ ///
+ /// This invariant is enforced to avoid arithmetic overflows when constructing layouts and when
+ /// allocating memory. Any layout that doesn't uphold this invariant will therefore *lead to
+ /// undefined behavior*.
+ pub const MAX_SIZE: DeviceSize = DeviceAlignment::MAX.as_devicesize() - 1;
+
+ /// Creates a new `DeviceLayout` from a [`Layout`], or returns an error if the `Layout` has
+ /// zero size.
+ #[inline]
+ pub const fn from_layout(layout: Layout) -> Result<Self, TryFromLayoutError> {
+ let (size, alignment) = Self::size_alignment_from_layout(&layout);
+
+ #[cfg(any(
+ target_pointer_width = "64",
+ target_pointer_width = "32",
+ target_pointer_width = "16",
+ ))]
+ {
+ const _: () = assert!(size_of::<DeviceSize>() >= size_of::<usize>());
+ const _: () = assert!(DeviceLayout::MAX_SIZE >= isize::MAX as DeviceSize);
+
+ if let Some(size) = NonZeroDeviceSize::new(size) {
+ // SAFETY: Under the precondition that `usize` can't overflow `DeviceSize`, which
+ // we checked above, `Layout`'s overflow-invariant is the same if not stricter than
+ // that of `DeviceLayout`.
+ Ok(unsafe { DeviceLayout::new_unchecked(size, alignment) })
+ } else {
+ Err(TryFromLayoutError)
+ }
+ }
+ }
+
+ /// Converts the `DeviceLayout` into a [`Layout`], or returns an error if the `DeviceLayout`
+ /// doesn't meet the invariants of `Layout`.
+ #[inline]
+ pub const fn into_layout(self) -> Result<Layout, TryFromDeviceLayoutError> {
+ let (size, alignment) = (self.size(), self.alignment().as_devicesize());
+
+ #[cfg(target_pointer_width = "64")]
+ {
+ const _: () = assert!(size_of::<DeviceSize>() <= size_of::<usize>());
+ const _: () = assert!(DeviceLayout::MAX_SIZE as usize <= isize::MAX as usize);
+
+ // SAFETY: Under the precondition that `DeviceSize` can't overflow `usize`, which we
+ // checked above, `DeviceLayout`'s overflow-invariant is the same if not stricter that
+ // of `Layout`.
+ Ok(unsafe { Layout::from_size_align_unchecked(size as usize, alignment as usize) })
+ }
+ #[cfg(any(target_pointer_width = "32", target_pointer_width = "16"))]
+ {
+ const _: () = assert!(size_of::<DeviceSize>() > size_of::<usize>());
+ const _: () = assert!(DeviceLayout::MAX_SIZE > isize::MAX as DeviceSize);
+
+ if size > usize::MAX as DeviceSize || alignment > usize::MAX as DeviceSize {
+ Err(TryFromDeviceLayoutError)
+ } else if let Ok(layout) = Layout::from_size_align(size as usize, alignment as usize) {
+ Ok(layout)
+ } else {
+ Err(TryFromDeviceLayoutError)
+ }
+ }
+ }
+
+ /// Creates a new `DeviceLayout` from the given `size` and `alignment`.
+ ///
+ /// Returns [`None`] if `size` is zero, `alignment` is not a power of two, or if `size` would
+ /// exceed [`DeviceLayout::MAX_SIZE`] when rounded up to the nearest multiple of `alignment`.
+ #[inline]
+ pub const fn from_size_alignment(size: DeviceSize, alignment: DeviceSize) -> Option<Self> {
+ let size = try_opt!(NonZeroDeviceSize::new(size));
+ let alignment = try_opt!(DeviceAlignment::new(alignment));
+
+ DeviceLayout::new(size, alignment)
+ }
+
+ /// Creates a new `DeviceLayout` from the given `size` and `alignment` without doing any
+ /// checks.
+ ///
+ /// # Safety
+ ///
+ /// - `size` must be non-zero.
+ /// - `alignment` must be a power of two, which also means it must be non-zero.
+ /// - `size`, when rounded up to the nearest multiple of `alignment`, must not exceed
+ /// [`DeviceLayout::MAX_SIZE`].
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ #[inline]
+ pub const unsafe fn from_size_alignment_unchecked(
+ size: DeviceSize,
+ alignment: DeviceSize,
+ ) -> Self {
+ DeviceLayout::new_unchecked(
+ NonZeroDeviceSize::new_unchecked(size),
+ DeviceAlignment::new_unchecked(alignment),
+ )
+ }
+
+ /// Creates a new `DeviceLayout` from the given `size` and `alignment`.
+ ///
+ /// Returns [`None`] if `size` would exceed [`DeviceLayout::MAX_SIZE`] when rounded up to the
+ /// nearest multiple of `alignment`.
+ #[inline]
+ pub const fn new(size: NonZeroDeviceSize, alignment: DeviceAlignment) -> Option<Self> {
+ if size.get() > Self::max_size_for_alignment(alignment) {
+ None
+ } else {
+ // SAFETY: We checked that the rounded-up size won't exceed `DeviceLayout::MAX_SIZE`.
+ Some(unsafe { DeviceLayout::new_unchecked(size, alignment) })
+ }
+ }
+
+ #[inline(always)]
+ const fn max_size_for_alignment(alignment: DeviceAlignment) -> DeviceSize {
+ // `DeviceLayout::MAX_SIZE` is `DeviceAlignment::MAX - 1`, so this can't overflow.
+ DeviceLayout::MAX_SIZE - (alignment.as_devicesize() - 1)
+ }
+
+ /// Creates a new `DeviceLayout` from the given `size` and `alignment` without checking for
+ /// potential overflow.
+ ///
+ /// # Safety
+ ///
+ /// - `size`, when rounded up to the nearest multiple of `alignment`, must not exceed
+ /// [`DeviceLayout::MAX_SIZE`].
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ #[inline]
+ pub const unsafe fn new_unchecked(size: NonZeroDeviceSize, alignment: DeviceAlignment) -> Self {
+ debug_assert!(size.get() <= Self::max_size_for_alignment(alignment));
+
+ DeviceLayout { size, alignment }
+ }
+
+ /// Returns the minimum size in bytes for a memory block of this layout.
+ #[inline]
+ pub const fn size(&self) -> DeviceSize {
+ self.size.get()
+ }
+
+ /// Returns the minimum alignment for a memory block of this layout.
+ #[inline]
+ pub const fn alignment(&self) -> DeviceAlignment {
+ self.alignment
+ }
+
+ /// Creates a new `DeviceLayout` from `self` that is also aligned to `alignment` at minimum.
+ ///
+ /// Returns [`None`] if `self.size()` would overflow [`DeviceLayout::MAX_SIZE`] when rounded up
+ /// to the nearest multiple of `alignment`.
+ #[inline]
+ pub const fn align_to(&self, alignment: DeviceAlignment) -> Option<Self> {
+ DeviceLayout::new(self.size, DeviceAlignment::max(self.alignment, alignment))
+ }
+
+ /// Returns the amount of padding that needs to be added to `self.size()` such that the result
+ /// is a multiple of `alignment`.
+ #[inline]
+ pub const fn padding_needed_for(&self, alignment: DeviceAlignment) -> DeviceSize {
+ let size = self.size();
+
+ align_up(size, alignment).wrapping_sub(size)
+ }
+
+ /// Creates a new `DeviceLayout` by rounding up `self.size()` to the nearest multiple of
+ /// `self.alignment()`.
+ #[inline]
+ pub const fn pad_to_alignment(&self) -> Self {
+ // SAFETY: `DeviceLayout`'s invariant guarantees that the rounded up size won't exceed
+ // `DeviceLayout::MAX_SIZE`.
+ unsafe { DeviceLayout::new_unchecked(self.padded_size(), self.alignment) }
+ }
+
+ #[inline(always)]
+ const fn padded_size(&self) -> NonZeroDeviceSize {
+ let size = align_up(self.size(), self.alignment);
+
+ // SAFETY: `DeviceLayout`'s invariant guarantees that the rounded up size won't overflow.
+ unsafe { NonZeroDeviceSize::new_unchecked(size) }
+ }
+
+ /// Creates a new `DeviceLayout` describing the record for `n` instances of `self`, possibly
+ /// with padding at the end of each to ensure correct alignment of all instances.
+ ///
+ /// Returns a tuple consisting of the new layout and the stride, in bytes, of `self`, or
+ /// returns [`None`] on arithmetic overflow or when the total size would exceed
+ /// [`DeviceLayout::MAX_SIZE`].
+ #[inline]
+ pub const fn repeat(&self, n: NonZeroDeviceSize) -> Option<(Self, DeviceSize)> {
+ let stride = self.padded_size();
+ let size = try_opt!(stride.checked_mul(n));
+ let layout = try_opt!(DeviceLayout::new(size, self.alignment));
+
+ Some((layout, stride.get()))
+ }
+
+ /// Creates a new `DeviceLayout` describing the record for `self` followed by `next`, including
+ /// potential padding between them to ensure `next` will be properly aligned, but without any
+ /// trailing padding. You should use [`pad_to_alignment`] after you are done extending the
+ /// layout with all fields to get a valid `#[repr(C)]` layout.
+ ///
+ /// The alignments of the two layouts get combined by picking the maximum between them.
+ ///
+ /// Returns a tuple consisting of the resulting layout as well as the offset, in bytes, of
+ /// `next`.
+ ///
+ /// Returns [`None`] on arithmetic overflow or when the total size rounded up to the nearest
+ /// multiple of the combined alignment would exceed [`DeviceLayout::MAX_SIZE`].
+ ///
+ /// [`pad_to_alignment`]: Self::pad_to_alignment
+ #[inline]
+ pub const fn extend(&self, next: Self) -> Option<(Self, DeviceSize)> {
+ self.extend_inner(next.size(), next.alignment)
+ }
+
+ /// Same as [`extend`], except it extends with a [`Layout`].
+ ///
+ /// [`extend`]: Self::extend
+ #[inline]
+ pub const fn extend_with_layout(&self, next: Layout) -> Option<(Self, DeviceSize)> {
+ let (next_size, next_alignment) = Self::size_alignment_from_layout(&next);
+
+ self.extend_inner(next_size, next_alignment)
+ }
+
+ const fn extend_inner(
+ &self,
+ next_size: DeviceSize,
+ next_alignment: DeviceAlignment,
+ ) -> Option<(Self, DeviceSize)> {
+ let padding = self.padding_needed_for(next_alignment);
+ let offset = try_opt!(self.size.checked_add(padding));
+ let size = try_opt!(offset.checked_add(next_size));
+ let alignment = DeviceAlignment::max(self.alignment, next_alignment);
+ let layout = try_opt!(DeviceLayout::new(size, alignment));
+
+ Some((layout, offset.get()))
+ }
+
+ /// Creates a new `DeviceLayout` describing the record for the `previous` [`Layout`] followed
+ /// by `self`. This function is otherwise the same as [`extend`].
+ ///
+ /// [`extend`]: Self::extend
+ #[inline]
+ pub const fn extend_from_layout(self, previous: &Layout) -> Option<(Self, DeviceSize)> {
+ let (size, alignment) = Self::size_alignment_from_layout(previous);
+
+ let padding = align_up(size, self.alignment).wrapping_sub(size);
+ let offset = try_opt!(size.checked_add(padding));
+ let size = try_opt!(self.size.checked_add(offset));
+ let alignment = DeviceAlignment::max(alignment, self.alignment);
+ let layout = try_opt!(DeviceLayout::new(size, alignment));
+
+ Some((layout, offset))
+ }
+
+ #[inline(always)]
+ const fn size_alignment_from_layout(layout: &Layout) -> (DeviceSize, DeviceAlignment) {
+ #[cfg(any(
+ target_pointer_width = "64",
+ target_pointer_width = "32",
+ target_pointer_width = "16",
+ ))]
+ {
+ const _: () = assert!(size_of::<DeviceSize>() >= size_of::<usize>());
+ const _: () = assert!(DeviceLayout::MAX_SIZE >= isize::MAX as DeviceSize);
+
+ // We checked that `usize` can't overflow `DeviceSize`, so this can't truncate.
+ let (size, alignment) = (layout.size() as DeviceSize, layout.align() as DeviceSize);
+
+ // SAFETY: `Layout`'s alignment-invariant guarantees that it is a power of two.
+ let alignment = unsafe { DeviceAlignment::new_unchecked(alignment) };
+
+ (size, alignment)
+ }
+ }
+}
+
+impl TryFrom<Layout> for DeviceLayout {
+ type Error = TryFromLayoutError;
+
+ #[inline]
+ fn try_from(layout: Layout) -> Result<Self, Self::Error> {
+ DeviceLayout::from_layout(layout)
+ }
+}
+
+impl TryFrom<DeviceLayout> for Layout {
+ type Error = TryFromDeviceLayoutError;
+
+ #[inline]
+ fn try_from(device_layout: DeviceLayout) -> Result<Self, Self::Error> {
+ DeviceLayout::into_layout(device_layout)
+ }
+}
+
+/// Error that can happen when converting a [`Layout`] to a [`DeviceLayout`].
+///
+/// It occurs when the `Layout` has zero size.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct TryFromLayoutError;
+
+impl Error for TryFromLayoutError {}
+
+impl Display for TryFromLayoutError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
+ f.write_str("attempted to convert a zero-size `Layout` to a `DeviceLayout`")
+ }
+}
+
+/// Error that can happen when converting a [`DeviceLayout`] to a [`Layout`].
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct TryFromDeviceLayoutError;
+
+impl Error for TryFromDeviceLayoutError {}
+
+impl Display for TryFromDeviceLayoutError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
+ f.write_str(
+ "attempted to convert a `DeviceLayout` to a `Layout` which would result in a \
+ violation of `Layout`'s overflow-invariant",
+ )
+ }
+}
diff --git a/src/memory/allocator/mod.rs b/src/memory/allocator/mod.rs
new file mode 100644
index 0000000..38c4ffb
--- /dev/null
+++ b/src/memory/allocator/mod.rs
@@ -0,0 +1,1654 @@
+// Copyright (c) 2016 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+//! In Vulkan, suballocation of [`DeviceMemory`] is left to the application, because every
+//! application has slightly different needs and one can not incorporate an allocator into the
+//! driver that would perform well in all cases. Vulkano stays true to this sentiment, but aims to
+//! reduce the burden on the user as much as possible. You have a toolbox of configurable
+//! [suballocators] to choose from that cover all allocation algorithms, which you can compose into
+//! any kind of [hierarchy] you wish. This way you have maximum flexibility while still only using
+//! a few `DeviceMemory` blocks and not writing any of the very error-prone code.
+//!
+//! If you just want to allocate memory and don't have any special needs, look no further than the
+//! [`StandardMemoryAllocator`].
+//!
+//! # Why not just allocate `DeviceMemory`?
+//!
+//! But the driver has an allocator! Otherwise you wouldn't be able to allocate `DeviceMemory`,
+//! right? Indeed, but that allocation is very expensive. Not only that, there is also a pretty low
+//! limit on the number of allocations by the drivers. See, everything in Vulkan tries to keep you
+//! away from allocating `DeviceMemory` too much. These limits are used by the implementation to
+//! optimize on its end, while the application optimizes on the other end.
+//!
+//! # Alignment
+//!
+//! At the end of the day, memory needs to be backed by hardware somehow. A *memory cell* stores a
+//! single *bit*, bits are grouped into *bytes* and bytes are grouped into *words*. Intuitively, it
+//! should make sense that accessing single bits at a time would be very inefficient. That is why
+//! computers always access a whole word of memory at once, at least. That means that if you tried
+//! to do an unaligned access, you would need to access twice the number of memory locations.
+//!
+//! Example aligned access, performing bitwise NOT on the (64-bit) word at offset 0x08:
+//!
+//! ```plain
+//! | 08 | 10 | 18
+//! ----+-------------------------+-------------------------+----
+//! ••• | 35 35 35 35 35 35 35 35 | 01 23 45 67 89 ab cd ef | •••
+//! ----+-------------------------+-------------------------+----
+//! , | ,
+//! +------------|------------+
+//! ' v '
+//! ----+-------------------------+-------------------------+----
+//! ••• | ca ca ca ca ca ca ca ca | 01 23 45 67 89 ab cd ef | •••
+//! ----+-------------------------+-------------------------+----
+//! ```
+//!
+//! Same example as above, but this time unaligned with a word at offset 0x0a:
+//!
+//! ```plain
+//! | 08 0a | 10 | 18
+//! ----+-------------------------+-------------------------+----
+//! ••• | cd ef 35 35 35 35 35 35 | 35 35 01 23 45 67 89 ab | •••
+//! ----+-------------------------+-------------------------+----
+//! , | ,
+//! +------------|------------+
+//! ' v '
+//! ----+-------------------------+-------------------------+----
+//! ••• | cd ef ca ca ca ca ca ca | ca ca 01 23 45 67 89 ab | •••
+//! ----+-------------------------+-------------------------+----
+//! ```
+//!
+//! As you can see, in the unaligned case the hardware would need to read both the word at offset
+//! 0x08 and the word at the offset 0x10 and then shift the bits from one register into the other.
+//! Safe to say it should to be avoided, and this is why we need alignment. This example also goes
+//! to show how inefficient unaligned writes are. Say you pieced together your word as described,
+//! and now you want to perform the bitwise NOT and write the result back. Difficult, isn't it?
+//! That's due to the fact that even though the chunks occupy different ranges in memory, they are
+//! still said to *alias* each other, because if you try to write to one memory location, you would
+//! be overwriting 2 or more different chunks of data.
+//!
+//! ## Pages
+//!
+//! It doesn't stop at the word, though. Words are further grouped into *pages*. These are
+//! typically power-of-two multiples of the word size, much like words are typically powers of two
+//! themselves. You can easily extend the concepts from the previous examples to pages if you think
+//! of the examples as having a page size of 1 word. Two resources are said to alias if they share
+//! a page, and therefore should be aligned to the page size. What the page size is depends on the
+//! context, and a computer might have multiple different ones for different parts of hardware.
+//!
+//! ## Memory requirements
+//!
+//! A Vulkan device might have any number of reasons it would want certain alignments for certain
+//! resources. For example, the device might have different caches for different types of
+//! resources, which have different page sizes. Maybe the device wants to store images in some
+//! other cache compared to buffers which needs different alignment. Or maybe images of different
+//! layouts require different alignment, or buffers with different usage/mapping do. The specifics
+//! don't matter in the end, this just goes to illustrate the point. This is why memory
+//! requirements in Vulkan vary not only with the Vulkan implementation, but also with the type of
+//! resource.
+//!
+//! ## Buffer-image granularity
+//!
+//! This unfortunately named granularity is the page size which a linear resource neighboring a
+//! non-linear resource must be aligned to in order for them not to alias. The difference between
+//! the memory requirements of the individual resources and the [buffer-image granularity] is that
+//! the memory requirements only apply to the resource they are for, while the buffer-image
+//! granularity applies to two neighboring resources. For example, you might create two buffers,
+//! which might have two different memory requirements, but as long as those are satisfied, you can
+//! put these buffers cheek to cheek. On the other hand, if one of them is an (optimal layout)
+//! image, then they must not share any page, whose size is given by this granularity. The Vulkan
+//! implementation can use this for additional optimizations if it needs to, or report a
+//! granularity of 1.
+//!
+//! # Fragmentation
+//!
+//! Memory fragmentation refers to the wastage of memory that results from alignment requirements
+//! and/or dynamic memory allocation. As such, some level of fragmentation is always going to be
+//! inevitable. Different allocation algorithms each have their own characteristics and trade-offs
+//! in relation to fragmentation.
+//!
+//! ## Internal Fragmentation
+//!
+//! This type of fragmentation arises from alignment requirements. These might be imposed by the
+//! Vulkan implementation or the application itself.
+//!
+//! Say for example your allocations need to be aligned to 64B, then any allocation whose size is
+//! not a multiple of the alignment will need padding at the end:
+//!
+//! ```plain
+//! | 0x040 | 0x080 | 0x0c0 | 0x100
+//! ----+------------------+------------------+------------------+--------
+//! | ############ | ################ | ######## | #######
+//! ••• | ### 48 B ### | ##### 64 B ##### | # 32 B # | ### •••
+//! | ############ | ################ | ######## | #######
+//! ----+------------------+------------------+------------------+--------
+//! ```
+//!
+//! If this alignment is imposed by the Vulkan implementation, then there's nothing one can do
+//! about this. Simply put, that space is unusable. One also shouldn't want to do anything about
+//! it, since these requirements have very good reasons, as described in further detail in previous
+//! sections. They prevent resources from aliasing so that performance is optimal.
+//!
+//! It might seem strange that the application would want to cause internal fragmentation itself,
+//! but this is often a good trade-off to reduce or even completely eliminate external
+//! fragmentation. Internal fragmentation is very predictable, which makes it easier to deal with.
+//!
+//! ## External fragmentation
+//!
+//! With external fragmentation, what happens is that while the allocations might be using their
+//! own memory totally efficiently, the way they are arranged in relation to each other would
+//! prevent a new contiguous chunk of memory to be allocated even though there is enough free space
+//! left. That is why this fragmentation is said to be external to the allocations. Also, the
+//! allocations together with the fragments in-between add overhead both in terms of space and time
+//! to the allocator, because it needs to keep track of more things overall.
+//!
+//! As an example, take these 4 allocations within some block, with the rest of the block assumed
+//! to be full:
+//!
+//! ```plain
+//! +-----+-------------------+-------+-----------+-- - - --+
+//! | | | | | |
+//! | A | B | C | D | ••• |
+//! | | | | | |
+//! +-----+-------------------+-------+-----------+-- - - --+
+//! ```
+//!
+//! The allocations were all done in order, and naturally there is no fragmentation at this point.
+//! Now if we free B and D, since these are done out of order, we will be left with holes between
+//! the other allocations, and we won't be able to fit allocation E anywhere:
+//!
+//! ```plain
+//! +-----+-------------------+-------+-----------+-- - - --+ +-------------------------+
+//! | | | | | | ? | |
+//! | A | | C | | ••• | <== | E |
+//! | | | | | | | |
+//! +-----+-------------------+-------+-----------+-- - - --+ +-------------------------+
+//! ```
+//!
+//! So fine, we use a different block for E, and just use this block for allocations that fit:
+//!
+//! ```plain
+//! +-----+---+-----+---------+-------+-----+-----+-- - - --+
+//! | | | | | | | | |
+//! | A | H | I | J | C | F | G | ••• |
+//! | | | | | | | | |
+//! +-----+---+-----+---------+-------+-----+-----+-- - - --+
+//! ```
+//!
+//! Sure, now let's free some shall we? And voilà, the problem just became much worse:
+//!
+//! ```plain
+//! +-----+---+-----+---------+-------+-----+-----+-- - - --+
+//! | | | | | | | | |
+//! | A | | I | J | | F | | ••• |
+//! | | | | | | | | |
+//! +-----+---+-----+---------+-------+-----+-----+-- - - --+
+//! ```
+//!
+//! # Leakage
+//!
+//! Memory leaks happen when allocations are kept alive past their shelf life. This most often
+//! occurs because of [cyclic references]. If you have structures that have cycles, then make sure
+//! you read the documentation for [`Arc`]/[`Rc`] carefully to avoid memory leaks. You can also
+//! introduce memory leaks willingly by using [`mem::forget`] or [`Box::leak`] to name a few. In
+//! all of these examples the memory can never be reclaimed, but that doesn't have to be the case
+//! for something to be considered a leak. Say for example you have a [region] which you
+//! suballocate, and at some point you drop all the suballocations. When that happens, the region
+//! can be returned (freed) to the next level up the hierarchy, or it can be reused by another
+//! suballocator. But if you happen to keep alive just one suballocation for the duration of the
+//! program for instance, then the whole region is also kept as it is for that time (and keep in
+//! mind this bubbles up the hierarchy). Therefore, for the program, that memory might be a leak
+//! depending on the allocator, because some allocators wouldn't be able to reuse the entire rest
+//! of the region. You must always consider the lifetime of your resources when choosing the
+//! appropriate allocator.
+//!
+//! [suballocators]: Suballocator
+//! [hierarchy]: Suballocator#memory-hierarchies
+//! [buffer-image granularity]: crate::device::Properties::buffer_image_granularity
+//! [cyclic references]: Arc#breaking-cycles-with-weak
+//! [`Rc`]: std::rc::Rc
+//! [`mem::forget`]: std::mem::forget
+//! [region]: Suballocator#regions
+
+mod layout;
+pub mod suballocator;
+
+use self::array_vec::ArrayVec;
+pub use self::{
+ layout::DeviceLayout,
+ suballocator::{
+ AllocationType, BuddyAllocator, BumpAllocator, FreeListAllocator, MemoryAlloc,
+ PoolAllocator, SuballocationCreateInfo, SuballocationCreationError, Suballocator,
+ },
+};
+use super::{
+ DedicatedAllocation, DeviceAlignment, DeviceMemory, ExternalMemoryHandleTypes,
+ MemoryAllocateFlags, MemoryAllocateInfo, MemoryProperties, MemoryPropertyFlags,
+ MemoryRequirements, MemoryType,
+};
+use crate::{
+ device::{Device, DeviceOwned},
+ DeviceSize, RequirementNotMet, RequiresOneOf, Version, VulkanError,
+};
+use ash::vk::{MAX_MEMORY_HEAPS, MAX_MEMORY_TYPES};
+use parking_lot::RwLock;
+use std::{
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+ sync::Arc,
+};
+
+const B: DeviceSize = 1;
+const K: DeviceSize = 1024 * B;
+const M: DeviceSize = 1024 * K;
+const G: DeviceSize = 1024 * M;
+
+/// General-purpose memory allocators which allocate from any memory type dynamically as needed.
+pub unsafe trait MemoryAllocator: DeviceOwned {
+ /// Finds the most suitable memory type index in `memory_type_bits` using a filter. Returns
+ /// [`None`] if the requirements are too strict and no memory type is able to satisfy them.
+ fn find_memory_type_index(
+ &self,
+ memory_type_bits: u32,
+ filter: MemoryTypeFilter,
+ ) -> Option<u32>;
+
+ /// Allocates memory from a specific memory type.
+ fn allocate_from_type(
+ &self,
+ memory_type_index: u32,
+ create_info: SuballocationCreateInfo,
+ ) -> Result<MemoryAlloc, AllocationCreationError>;
+
+ /// Allocates memory from a specific memory type without checking the parameters.
+ ///
+ /// # Safety
+ ///
+ /// - If `memory_type_index` refers to a memory type with the [`protected`] flag set, then the
+ /// [`protected_memory`] feature must be enabled on the device.
+ /// - If `memory_type_index` refers to a memory type with the [`device_coherent`] flag set,
+ /// then the [`device_coherent_memory`] feature must be enabled on the device.
+ /// - `create_info.layout.size()` must not exceed the size of the heap that the memory type
+ /// corresponding to `memory_type_index` resides in.
+ ///
+ /// [`protected`]: MemoryPropertyFlags::protected
+ /// [`protected_memory`]: crate::device::Features::protected_memory
+ /// [`device_coherent`]: MemoryPropertyFlags::device_coherent
+ /// [`device_coherent_memory`]: crate::device::Features::device_coherent_memory
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ unsafe fn allocate_from_type_unchecked(
+ &self,
+ memory_type_index: u32,
+ create_info: SuballocationCreateInfo,
+ never_allocate: bool,
+ ) -> Result<MemoryAlloc, AllocationCreationError>;
+
+ /// Allocates memory according to requirements.
+ ///
+ /// # Arguments
+ ///
+ /// - `requirements` - Requirements of the resource you want to allocate memory for.
+ ///
+ /// If you plan to bind this memory directly to a non-sparse resource, then this must
+ /// correspond to the value returned by either [`RawBuffer::memory_requirements`] or
+ /// [`RawImage::memory_requirements`] for the respective buffer or image.
+ ///
+ /// [`memory_type_bits`] must be below 2<sup>*n*</sup> where *n* is the number of available
+ /// memory types.
+ ///
+ /// The default is a layout with size [`DeviceLayout::MAX_SIZE`] and alignment
+ /// [`DeviceAlignment::MIN`] and the rest all zeroes, which must be overridden.
+ ///
+ /// - `allocation_type` - What type of resource this allocation will be used for.
+ ///
+ /// This should be [`Linear`] for buffers and linear images, and [`NonLinear`] for optimal
+ /// images. You can not bind memory allocated with the [`Linear`] type to optimal images or
+ /// bind memory allocated with the [`NonLinear`] type to buffers and linear images. You
+ /// should never use the [`Unknown`] type unless you have to, as that can be less memory
+ /// efficient.
+ ///
+ /// - `dedicated_allocation` - Allows a dedicated allocation to be created.
+ ///
+ /// You should always fill this field in if you are allocating memory for a non-sparse
+ /// resource, otherwise the allocator won't be able to create a dedicated allocation if one
+ /// is recommended.
+ ///
+ /// This option is silently ignored (treated as `None`) if the device API version is below
+ /// 1.1 and the [`khr_dedicated_allocation`] extension is not enabled on the device.
+ ///
+ /// [`alignment`]: MemoryRequirements::alignment
+ /// [`memory_type_bits`]: MemoryRequirements::memory_type_bits
+ /// [`RawBuffer::memory_requirements`]: crate::buffer::sys::RawBuffer::memory_requirements
+ /// [`RawImage::memory_requirements`]: crate::image::sys::RawImage::memory_requirements
+ /// [`Linear`]: AllocationType::Linear
+ /// [`NonLinear`]: AllocationType::NonLinear
+ /// [`Unknown`]: AllocationType::Unknown
+ /// [`khr_dedicated_allocation`]: crate::device::DeviceExtensions::khr_dedicated_allocation
+ fn allocate(
+ &self,
+ requirements: MemoryRequirements,
+ allocation_type: AllocationType,
+ create_info: AllocationCreateInfo,
+ dedicated_allocation: Option<DedicatedAllocation<'_>>,
+ ) -> Result<MemoryAlloc, AllocationCreationError>;
+
+ /// Allocates memory according to requirements without checking the parameters.
+ ///
+ /// # Safety
+ ///
+ /// - If `create_info.dedicated_allocation` is `Some` then `create_info.requirements.size` must
+ /// match the memory requirements of the resource.
+ /// - If `create_info.dedicated_allocation` is `Some` then the device the resource was created
+ /// with must match the device the allocator was created with.
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ unsafe fn allocate_unchecked(
+ &self,
+ requirements: MemoryRequirements,
+ allocation_type: AllocationType,
+ create_info: AllocationCreateInfo,
+ dedicated_allocation: Option<DedicatedAllocation<'_>>,
+ ) -> Result<MemoryAlloc, AllocationCreationError>;
+
+ /// Creates a root allocation/dedicated allocation without checking the parameters.
+ ///
+ /// # Safety
+ ///
+ /// - `allocation_size` must not exceed the size of the heap that the memory type corresponding
+ /// to `memory_type_index` resides in.
+ /// - The handle types in `export_handle_types` must be supported and compatible, as reported by
+ /// [`ExternalBufferProperties`] or [`ImageFormatProperties`].
+ /// - If any of the handle types in `export_handle_types` require a dedicated allocation, as
+ /// reported by [`ExternalBufferProperties::external_memory_properties`] or
+ /// [`ImageFormatProperties::external_memory_properties`], then `dedicated_allocation` must
+ /// not be `None`.
+ ///
+ /// [`ExternalBufferProperties`]: crate::buffer::ExternalBufferProperties
+ /// [`ImageFormatProperties`]: crate::image::ImageFormatProperties
+ /// [`ExternalBufferProperties::external_memory_properties`]: crate::buffer::ExternalBufferProperties
+ /// [`ImageFormatProperties::external_memory_properties`]: crate::image::ImageFormatProperties::external_memory_properties
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ unsafe fn allocate_dedicated_unchecked(
+ &self,
+ memory_type_index: u32,
+ allocation_size: DeviceSize,
+ dedicated_allocation: Option<DedicatedAllocation<'_>>,
+ export_handle_types: ExternalMemoryHandleTypes,
+ ) -> Result<MemoryAlloc, AllocationCreationError>;
+}
+
+/// Describes what memory property flags are required, preferred and not preferred when picking a
+/// memory type index.
+#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
+pub struct MemoryTypeFilter {
+ pub required_flags: MemoryPropertyFlags,
+ pub preferred_flags: MemoryPropertyFlags,
+ pub not_preferred_flags: MemoryPropertyFlags,
+}
+
+impl From<MemoryUsage> for MemoryTypeFilter {
+ #[inline]
+ fn from(usage: MemoryUsage) -> Self {
+ let mut filter = Self::default();
+
+ match usage {
+ MemoryUsage::DeviceOnly => {
+ filter.preferred_flags |= MemoryPropertyFlags::DEVICE_LOCAL;
+ filter.not_preferred_flags |= MemoryPropertyFlags::HOST_VISIBLE;
+ }
+ MemoryUsage::Upload => {
+ filter.required_flags |= MemoryPropertyFlags::HOST_VISIBLE;
+ filter.preferred_flags |= MemoryPropertyFlags::DEVICE_LOCAL;
+ filter.not_preferred_flags |= MemoryPropertyFlags::HOST_CACHED;
+ }
+ MemoryUsage::Download => {
+ filter.required_flags |= MemoryPropertyFlags::HOST_VISIBLE;
+ filter.preferred_flags |= MemoryPropertyFlags::HOST_CACHED;
+ }
+ }
+
+ filter
+ }
+}
+
+/// Parameters to create a new [allocation] using a [memory allocator].
+///
+/// [allocation]: MemoryAlloc
+/// [memory allocator]: MemoryAllocator
+#[derive(Clone, Debug)]
+pub struct AllocationCreateInfo {
+ /// The intended usage for the allocation.
+ ///
+ /// The default value is [`MemoryUsage::DeviceOnly`].
+ pub usage: MemoryUsage,
+
+ /// How eager the allocator should be to allocate [`DeviceMemory`].
+ ///
+ /// The default value is [`MemoryAllocatePreference::Unknown`].
+ pub allocate_preference: MemoryAllocatePreference,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for AllocationCreateInfo {
+ #[inline]
+ fn default() -> Self {
+ AllocationCreateInfo {
+ usage: MemoryUsage::DeviceOnly,
+ allocate_preference: MemoryAllocatePreference::Unknown,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// Describes how a memory allocation is going to be used.
+///
+/// This is mostly an optimization, except for `MemoryUsage::DeviceOnly` which will pick a memory
+/// type that is not host-accessible if such a type exists.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+pub enum MemoryUsage {
+ /// The memory is intended to only be used by the device.
+ ///
+ /// Prefers picking a memory type with the [`DEVICE_LOCAL`] flag and without the
+ /// [`HOST_VISIBLE`] flag.
+ ///
+ /// This option is what you will always want to use unless the memory needs to be accessed by
+ /// the CPU, because a memory type that can only be accessed by the GPU is going to give the
+ /// best performance. Example use cases would be textures and other maps which are written to
+ /// once and then never again, or resources that are only written and read by the GPU, like
+ /// render targets and intermediary buffers.
+ ///
+ /// [`DEVICE_LOCAL`]: MemoryPropertyFlags::DEVICE_LOCAL
+ /// [`HOST_VISIBLE`]: MemoryPropertyFlags::HOST_VISIBLE
+ DeviceOnly,
+
+ /// The memory is intended for upload to the device.
+ ///
+ /// Guarantees picking a memory type with the [`HOST_VISIBLE`] flag. Prefers picking one
+ /// without the [`HOST_CACHED`] flag and with the [`DEVICE_LOCAL`] flag.
+ ///
+ /// This option is best suited for resources that need to be constantly updated by the CPU,
+ /// like vertex and index buffers for example. It is also neccessary for *staging buffers*,
+ /// whose only purpose in life it is to get data into device-local memory or texels into an
+ /// optimal image.
+ ///
+ /// [`HOST_VISIBLE`]: MemoryPropertyFlags::HOST_VISIBLE
+ /// [`HOST_CACHED`]: MemoryPropertyFlags::HOST_CACHED
+ /// [`DEVICE_LOCAL`]: MemoryPropertyFlags::DEVICE_LOCAL
+ Upload,
+
+ /// The memory is intended for download from the device.
+ ///
+ /// Guarantees picking a memory type with the [`HOST_VISIBLE`] flag. Prefers picking one with
+ /// the [`HOST_CACHED`] flag and without the [`DEVICE_LOCAL`] flag.
+ ///
+ /// This option is best suited if you're using the device for things other than rendering and
+ /// you need to get the results back to the host. That might be compute shading, or image or
+ /// video manipulation, or screenshotting for example.
+ ///
+ /// [`HOST_VISIBLE`]: MemoryPropertyFlags::HOST_VISIBLE
+ /// [`HOST_CACHED`]: MemoryPropertyFlags::HOST_CACHED
+ /// [`DEVICE_LOCAL`]: MemoryPropertyFlags::DEVICE_LOCAL
+ Download,
+}
+
+/// Describes whether allocating [`DeviceMemory`] is desired.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+pub enum MemoryAllocatePreference {
+ /// There is no known preference, let the allocator decide.
+ Unknown,
+
+ /// The allocator should never allocate `DeviceMemory` and should instead only suballocate from
+ /// existing blocks.
+ ///
+ /// This option is best suited if you can not afford the overhead of allocating `DeviceMemory`.
+ NeverAllocate,
+
+ /// The allocator should always allocate `DeviceMemory`.
+ ///
+ /// This option is best suited if you are allocating a long-lived resource that you know could
+ /// benefit from having a dedicated allocation.
+ AlwaysAllocate,
+}
+
+/// Error that can be returned when creating an [allocation] using a [memory allocator].
+///
+/// [allocation]: MemoryAlloc
+/// [memory allocator]: MemoryAllocator
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum AllocationCreationError {
+ VulkanError(VulkanError),
+
+ /// There is not enough memory in the pool.
+ ///
+ /// This is returned when using [`MemoryAllocatePreference::NeverAllocate`] and there is not
+ /// enough memory in the pool.
+ OutOfPoolMemory,
+
+ /// A dedicated allocation is required but was explicitly forbidden.
+ ///
+ /// This is returned when using [`MemoryAllocatePreference::NeverAllocate`] and the
+ /// implementation requires a dedicated allocation.
+ DedicatedAllocationRequired,
+
+ /// The block size for the allocator was exceeded.
+ ///
+ /// This is returned when using [`MemoryAllocatePreference::NeverAllocate`] and the allocation
+ /// size exceeded the block size for all heaps of suitable memory types.
+ BlockSizeExceeded,
+
+ /// The block size for the suballocator was exceeded.
+ ///
+ /// This is returned when using [`GenericMemoryAllocator<Arc<PoolAllocator<BLOCK_SIZE>>>`] if
+ /// the allocation size exceeded `BLOCK_SIZE`.
+ SuballocatorBlockSizeExceeded,
+}
+
+impl Error for AllocationCreationError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::VulkanError(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+impl Display for AllocationCreationError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::VulkanError(_) => write!(f, "a runtime error occurred"),
+ Self::OutOfPoolMemory => write!(f, "the pool doesn't have enough free space"),
+ Self::DedicatedAllocationRequired => write!(
+ f,
+ "a dedicated allocation is required but was explicitly forbidden",
+ ),
+ Self::BlockSizeExceeded => write!(
+ f,
+ "the allocation size was greater than the block size for all heaps of suitable \
+ memory types and dedicated allocations were explicitly forbidden",
+ ),
+ Self::SuballocatorBlockSizeExceeded => write!(
+ f,
+ "the allocation size was greater than the suballocator's block size",
+ ),
+ }
+ }
+}
+
+impl From<VulkanError> for AllocationCreationError {
+ fn from(err: VulkanError) -> Self {
+ AllocationCreationError::VulkanError(err)
+ }
+}
+
+/// Standard memory allocator intended as a global and general-purpose allocator.
+///
+/// This type of allocator is what you should always use, unless you know, for a fact, that it is
+/// not suited to the task.
+///
+/// See also [`GenericMemoryAllocator`] for details about the allocation algorithm, and
+/// [`FreeListAllocator`] for details about the suballocation algorithm and example usage.
+pub type StandardMemoryAllocator = GenericMemoryAllocator<Arc<FreeListAllocator>>;
+
+impl StandardMemoryAllocator {
+ /// Creates a new `StandardMemoryAllocator` with default configuration.
+ pub fn new_default(device: Arc<Device>) -> Self {
+ #[allow(clippy::erasing_op, clippy::identity_op)]
+ let create_info = GenericMemoryAllocatorCreateInfo {
+ #[rustfmt::skip]
+ block_sizes: &[
+ (0 * B, 64 * M),
+ (1 * G, 256 * M),
+ ],
+ ..Default::default()
+ };
+
+ unsafe { Self::new_unchecked(device, create_info) }
+ }
+}
+
+/// A generic implementation of a [memory allocator].
+///
+/// The allocator keeps a pool of [`DeviceMemory`] blocks for each memory type and uses the type
+/// parameter `S` to [suballocate] these blocks. You can also configure the sizes of these blocks.
+/// This means that you can have as many `GenericMemoryAllocator`s as you you want for different
+/// needs, or for performance reasons, as long as the block sizes are configured properly so that
+/// too much memory isn't wasted.
+///
+/// See also [the `MemoryAllocator` implementation].
+///
+/// # `DeviceMemory` allocation
+///
+/// If an allocation is created with the [`MemoryAllocatePreference::Unknown`] option, and the
+/// allocator deems the allocation too big for suballocation (larger than half the block size), or
+/// the implementation prefers or requires a dedicated allocation, then that allocation is made a
+/// dedicated allocation. Using [`MemoryAllocatePreference::NeverAllocate`], a dedicated allocation
+/// is never created, even if the allocation is larger than the block size or a dedicated
+/// allocation is required. In such a case an error is returned instead. Using
+/// [`MemoryAllocatePreference::AlwaysAllocate`], a dedicated allocation is always created.
+///
+/// In all other cases, `DeviceMemory` is only allocated if a pool runs out of memory and needs
+/// another block. No `DeviceMemory` is allocated when the allocator is created, the blocks are
+/// only allocated once they are needed.
+///
+/// # Locking behavior
+///
+/// The allocator never needs to lock while suballocating unless `S` needs to lock. The only time
+/// when a pool must be locked is when a new `DeviceMemory` block is allocated for the pool. This
+/// means that the allocator is suited to both locking and lock-free (sub)allocation algorithms.
+///
+/// [memory allocator]: MemoryAllocator
+/// [suballocate]: Suballocator
+/// [the `MemoryAllocator` implementation]: Self#impl-MemoryAllocator-for-GenericMemoryAllocator<S>
+#[derive(Debug)]
+pub struct GenericMemoryAllocator<S: Suballocator> {
+ device: Arc<Device>,
+ // Each memory type has a pool of `DeviceMemory` blocks.
+ pools: ArrayVec<Pool<S>, MAX_MEMORY_TYPES>,
+ // Each memory heap has its own block size.
+ block_sizes: ArrayVec<DeviceSize, MAX_MEMORY_HEAPS>,
+ allocation_type: AllocationType,
+ dedicated_allocation: bool,
+ export_handle_types: ArrayVec<ExternalMemoryHandleTypes, MAX_MEMORY_TYPES>,
+ flags: MemoryAllocateFlags,
+ // Global mask of memory types.
+ memory_type_bits: u32,
+ // How many `DeviceMemory` allocations should be allowed before restricting them.
+ max_allocations: u32,
+}
+
+#[derive(Debug)]
+struct Pool<S> {
+ blocks: RwLock<Vec<S>>,
+ // This is cached here for faster access, so we don't need to hop through 3 pointers.
+ memory_type: ash::vk::MemoryType,
+}
+
+impl<S: Suballocator> GenericMemoryAllocator<S> {
+ // This is a false-positive, we only use this const for static initialization.
+ #[allow(clippy::declare_interior_mutable_const)]
+ const EMPTY_POOL: Pool<S> = Pool {
+ blocks: RwLock::new(Vec::new()),
+ memory_type: ash::vk::MemoryType {
+ property_flags: ash::vk::MemoryPropertyFlags::empty(),
+ heap_index: 0,
+ },
+ };
+
+ /// Creates a new `GenericMemoryAllocator<S>` using the provided suballocator `S` for
+ /// suballocation of [`DeviceMemory`] blocks.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `create_info.block_sizes` is not sorted by threshold.
+ /// - Panics if `create_info.block_sizes` contains duplicate thresholds.
+ /// - Panics if `create_info.block_sizes` does not contain a baseline threshold of `0`.
+ /// - Panics if the block size for a heap exceeds the size of the heap.
+ pub fn new(
+ device: Arc<Device>,
+ create_info: GenericMemoryAllocatorCreateInfo<'_, '_>,
+ ) -> Result<Self, GenericMemoryAllocatorCreationError> {
+ Self::validate_new(&device, &create_info)?;
+
+ Ok(unsafe { Self::new_unchecked(device, create_info) })
+ }
+
+ fn validate_new(
+ device: &Device,
+ create_info: &GenericMemoryAllocatorCreateInfo<'_, '_>,
+ ) -> Result<(), GenericMemoryAllocatorCreationError> {
+ let &GenericMemoryAllocatorCreateInfo {
+ block_sizes,
+ allocation_type: _,
+ dedicated_allocation: _,
+ export_handle_types,
+ device_address: _,
+ _ne: _,
+ } = create_info;
+
+ assert!(
+ block_sizes.windows(2).all(|win| win[0].0 < win[1].0),
+ "`create_info.block_sizes` must be sorted by threshold without duplicates",
+ );
+ assert!(
+ matches!(block_sizes.first(), Some((0, _))),
+ "`create_info.block_sizes` must contain a baseline threshold `0`",
+ );
+
+ if !export_handle_types.is_empty() {
+ if !(device.api_version() >= Version::V1_1
+ && device.enabled_extensions().khr_external_memory)
+ {
+ return Err(GenericMemoryAllocatorCreationError::RequirementNotMet {
+ required_for: "`create_info.export_handle_types` is not empty",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_1),
+ device_extensions: &["khr_external_memory"],
+ ..Default::default()
+ },
+ });
+ }
+
+ assert!(
+ export_handle_types.len()
+ == device
+ .physical_device()
+ .memory_properties()
+ .memory_types
+ .len(),
+ "`create_info.export_handle_types` must contain as many elements as the number of \
+ memory types if not empty",
+ );
+
+ for export_handle_types in export_handle_types {
+ // VUID-VkExportMemoryAllocateInfo-handleTypes-parameter
+ export_handle_types.validate_device(device)?;
+ }
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn new_unchecked(
+ device: Arc<Device>,
+ create_info: GenericMemoryAllocatorCreateInfo<'_, '_>,
+ ) -> Self {
+ let GenericMemoryAllocatorCreateInfo {
+ block_sizes,
+ allocation_type,
+ dedicated_allocation,
+ export_handle_types,
+ mut device_address,
+ _ne: _,
+ } = create_info;
+
+ let MemoryProperties {
+ memory_types,
+ memory_heaps,
+ } = device.physical_device().memory_properties();
+
+ let mut pools = ArrayVec::new(memory_types.len(), [Self::EMPTY_POOL; MAX_MEMORY_TYPES]);
+ for (i, memory_type) in memory_types.iter().enumerate() {
+ pools[i].memory_type = ash::vk::MemoryType {
+ property_flags: memory_type.property_flags.into(),
+ heap_index: memory_type.heap_index,
+ };
+ }
+
+ let block_sizes = {
+ let mut sizes = ArrayVec::new(memory_heaps.len(), [0; MAX_MEMORY_HEAPS]);
+
+ for (i, memory_heap) in memory_heaps.iter().enumerate() {
+ let idx = match block_sizes.binary_search_by_key(&memory_heap.size, |&(t, _)| t) {
+ Ok(idx) => idx,
+ Err(idx) => idx.saturating_sub(1),
+ };
+ sizes[i] = block_sizes[idx].1;
+
+ // VUID-vkAllocateMemory-pAllocateInfo-01713
+ assert!(sizes[i] <= memory_heap.size);
+ }
+
+ sizes
+ };
+
+ let export_handle_types = {
+ let mut types = ArrayVec::new(
+ export_handle_types.len(),
+ [ExternalMemoryHandleTypes::empty(); MAX_MEMORY_TYPES],
+ );
+ types.copy_from_slice(export_handle_types);
+
+ types
+ };
+
+ // VUID-VkMemoryAllocateInfo-flags-03331
+ device_address &= device.enabled_features().buffer_device_address
+ && !device.enabled_extensions().ext_buffer_device_address;
+ // Providers of `VkMemoryAllocateFlags`
+ device_address &=
+ device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_device_group;
+
+ let mut memory_type_bits = u32::MAX;
+ for (index, MemoryType { property_flags, .. }) in memory_types.iter().enumerate() {
+ if property_flags.intersects(
+ MemoryPropertyFlags::LAZILY_ALLOCATED
+ | MemoryPropertyFlags::PROTECTED
+ | MemoryPropertyFlags::DEVICE_COHERENT
+ | MemoryPropertyFlags::DEVICE_UNCACHED
+ | MemoryPropertyFlags::RDMA_CAPABLE,
+ ) {
+ // VUID-VkMemoryAllocateInfo-memoryTypeIndex-01872
+ // VUID-vkAllocateMemory-deviceCoherentMemory-02790
+ // Lazily allocated memory would just cause problems for suballocation in general.
+ memory_type_bits &= !(1 << index);
+ }
+ }
+
+ let flags = if device_address {
+ MemoryAllocateFlags::DEVICE_ADDRESS
+ } else {
+ MemoryAllocateFlags::empty()
+ };
+
+ let max_memory_allocation_count = device
+ .physical_device()
+ .properties()
+ .max_memory_allocation_count;
+ let max_allocations = max_memory_allocation_count / 4 * 3;
+
+ GenericMemoryAllocator {
+ device,
+ pools,
+ block_sizes,
+ allocation_type,
+ dedicated_allocation,
+ export_handle_types,
+ flags,
+ memory_type_bits,
+ max_allocations,
+ }
+ }
+
+ fn validate_allocate_from_type(&self, memory_type_index: u32) {
+ let memory_type = &self.pools[usize::try_from(memory_type_index).unwrap()].memory_type;
+
+ // VUID-VkMemoryAllocateInfo-memoryTypeIndex-01872
+ assert!(
+ memory_type
+ .property_flags
+ .contains(ash::vk::MemoryPropertyFlags::PROTECTED)
+ && !self.device.enabled_features().protected_memory,
+ "attempted to allocate from a protected memory type without the `protected_memory` \
+ feature being enabled on the device",
+ );
+
+ // VUID-vkAllocateMemory-deviceCoherentMemory-02790
+ assert!(
+ memory_type
+ .property_flags
+ .contains(ash::vk::MemoryPropertyFlags::DEVICE_COHERENT_AMD)
+ && !self.device.enabled_features().device_coherent_memory,
+ "attempted to allocate memory from a device-coherent memory type without the \
+ `device_coherent_memory` feature being enabled on the device",
+ );
+ }
+
+ fn validate_allocate(
+ &self,
+ requirements: MemoryRequirements,
+ dedicated_allocation: Option<DedicatedAllocation<'_>>,
+ ) {
+ assert!(requirements.memory_type_bits != 0);
+ assert!(requirements.memory_type_bits < 1 << self.pools.len());
+
+ if let Some(dedicated_allocation) = dedicated_allocation {
+ match dedicated_allocation {
+ DedicatedAllocation::Buffer(buffer) => {
+ // VUID-VkMemoryDedicatedAllocateInfo-commonparent
+ assert_eq!(&self.device, buffer.device());
+
+ let required_size = buffer.memory_requirements().layout.size();
+
+ // VUID-VkMemoryDedicatedAllocateInfo-buffer-02965
+ assert!(requirements.layout.size() != required_size);
+ }
+ DedicatedAllocation::Image(image) => {
+ // VUID-VkMemoryDedicatedAllocateInfo-commonparent
+ assert_eq!(&self.device, image.device());
+
+ let required_size = image.memory_requirements()[0].layout.size();
+
+ // VUID-VkMemoryDedicatedAllocateInfo-image-02964
+ assert!(requirements.layout.size() != required_size);
+ }
+ }
+ }
+
+ // VUID-VkMemoryAllocateInfo-pNext-00639
+ // VUID-VkExportMemoryAllocateInfo-handleTypes-00656
+ // Can't validate, must be ensured by user
+ }
+}
+
+unsafe impl<S: Suballocator> MemoryAllocator for GenericMemoryAllocator<S> {
+ fn find_memory_type_index(
+ &self,
+ memory_type_bits: u32,
+ filter: MemoryTypeFilter,
+ ) -> Option<u32> {
+ let required_flags = filter.required_flags.into();
+ let preferred_flags = filter.preferred_flags.into();
+ let not_preferred_flags = filter.not_preferred_flags.into();
+
+ self.pools
+ .iter()
+ .map(|pool| pool.memory_type.property_flags)
+ .enumerate()
+ // Filter out memory types which are supported by the memory type bits and have the
+ // required flags set.
+ .filter(|&(index, flags)| {
+ memory_type_bits & (1 << index) != 0 && flags & required_flags == required_flags
+ })
+ // Rank memory types with more of the preferred flags higher, and ones with more of the
+ // not preferred flags lower.
+ .min_by_key(|&(_, flags)| {
+ (!flags & preferred_flags).as_raw().count_ones()
+ + (flags & not_preferred_flags).as_raw().count_ones()
+ })
+ .map(|(index, _)| index as u32)
+ }
+
+ /// Allocates memory from a specific memory type.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `memory_type_index` is not less than the number of available memory types.
+ /// - Panics if `memory_type_index` refers to a memory type which has the [`PROTECTED`] flag
+ /// set and the [`protected_memory`] feature is not enabled on the device.
+ /// - Panics if `memory_type_index` refers to a memory type which has the [`DEVICE_COHERENT`]
+ /// flag set and the [`device_coherent_memory`] feature is not enabled on the device.
+ ///
+ /// # Errors
+ ///
+ /// - Returns an error if allocating a new block is required and failed. This can be one of the
+ /// OOM errors or [`TooManyObjects`].
+ /// - Returns [`BlockSizeExceeded`] if `create_info.layout.size()` is greater than the block
+ /// size corresponding to the heap that the memory type corresponding to `memory_type_index`
+ /// resides in.
+ /// - Returns [`SuballocatorBlockSizeExceeded`] if `S` is `PoolAllocator<BLOCK_SIZE>` and
+ /// `create_info.layout.size()` is greater than `BLOCK_SIZE`.
+ ///
+ /// [`PROTECTED`]: MemoryPropertyFlags::PROTECTED
+ /// [`protected_memory`]: crate::device::Features::protected_memory
+ /// [`DEVICE_COHERENT`]: MemoryPropertyFlags::DEVICE_COHERENT
+ /// [`device_coherent_memory`]: crate::device::Features::device_coherent_memory
+ /// [`TooManyObjects`]: VulkanError::TooManyObjects
+ /// [`BlockSizeExceeded`]: AllocationCreationError::BlockSizeExceeded
+ /// [`SuballocatorBlockSizeExceeded`]: AllocationCreationError::SuballocatorBlockSizeExceeded
+ fn allocate_from_type(
+ &self,
+ memory_type_index: u32,
+ create_info: SuballocationCreateInfo,
+ ) -> Result<MemoryAlloc, AllocationCreationError> {
+ self.validate_allocate_from_type(memory_type_index);
+
+ if self.pools[memory_type_index as usize]
+ .memory_type
+ .property_flags
+ .contains(ash::vk::MemoryPropertyFlags::LAZILY_ALLOCATED)
+ {
+ return unsafe {
+ self.allocate_dedicated_unchecked(
+ memory_type_index,
+ create_info.layout.size(),
+ None,
+ if !self.export_handle_types.is_empty() {
+ self.export_handle_types[memory_type_index as usize]
+ } else {
+ ExternalMemoryHandleTypes::empty()
+ },
+ )
+ };
+ }
+
+ unsafe { self.allocate_from_type_unchecked(memory_type_index, create_info, false) }
+ }
+
+ unsafe fn allocate_from_type_unchecked(
+ &self,
+ memory_type_index: u32,
+ create_info: SuballocationCreateInfo,
+ never_allocate: bool,
+ ) -> Result<MemoryAlloc, AllocationCreationError> {
+ let SuballocationCreateInfo {
+ layout,
+ allocation_type: _,
+ _ne: _,
+ } = create_info;
+
+ let size = layout.size();
+ let pool = &self.pools[memory_type_index as usize];
+ let block_size = self.block_sizes[pool.memory_type.heap_index as usize];
+
+ if size > block_size {
+ return Err(AllocationCreationError::BlockSizeExceeded);
+ }
+
+ let mut blocks = if S::IS_BLOCKING {
+ // If the allocation algorithm needs to block, then there's no point in trying to avoid
+ // locks here either. In that case the best strategy is to take full advantage of it by
+ // always taking an exclusive lock, which lets us sort the blocks by free size. If you
+ // as a user want to avoid locks, simply don't share the allocator between threads. You
+ // can create as many allocators as you wish, but keep in mind that that will waste a
+ // huge amount of memory unless you configure your block sizes properly!
+
+ let mut blocks = pool.blocks.write();
+ blocks.sort_by_key(Suballocator::free_size);
+ let (Ok(idx) | Err(idx)) = blocks.binary_search_by_key(&size, Suballocator::free_size);
+ for block in &blocks[idx..] {
+ match block.allocate(create_info.clone()) {
+ Ok(allocation) => return Ok(allocation),
+ Err(SuballocationCreationError::BlockSizeExceeded) => {
+ return Err(AllocationCreationError::SuballocatorBlockSizeExceeded);
+ }
+ Err(_) => {}
+ }
+ }
+
+ blocks
+ } else {
+ // If the allocation algorithm is lock-free, then we should avoid taking an exclusive
+ // lock unless it is absolutely neccessary (meaning, only when allocating a new
+ // `DeviceMemory` block and inserting it into a pool). This has the disadvantage that
+ // traversing the pool is O(n), which is not a problem since the number of blocks is
+ // expected to be small. If there are more than 10 blocks in a pool then that's a
+ // configuration error. Also, sorting the blocks before each allocation would be less
+ // efficient because to get the free size of the `PoolAllocator` and `BumpAllocator`
+ // has the same performance as trying to allocate.
+
+ let blocks = pool.blocks.read();
+ // Search in reverse order because we always append new blocks at the end.
+ for block in blocks.iter().rev() {
+ match block.allocate(create_info.clone()) {
+ Ok(allocation) => return Ok(allocation),
+ // This can happen when using the `PoolAllocator<BLOCK_SIZE>` if the allocation
+ // size is greater than `BLOCK_SIZE`.
+ Err(SuballocationCreationError::BlockSizeExceeded) => {
+ return Err(AllocationCreationError::SuballocatorBlockSizeExceeded);
+ }
+ Err(_) => {}
+ }
+ }
+
+ let len = blocks.len();
+ drop(blocks);
+ let blocks = pool.blocks.write();
+ if blocks.len() > len {
+ // Another thread beat us to it and inserted a fresh block, try to allocate from it.
+ match blocks[len].allocate(create_info.clone()) {
+ Ok(allocation) => return Ok(allocation),
+ // This can happen if this is the first block that was inserted and when using
+ // the `PoolAllocator<BLOCK_SIZE>` if the allocation size is greater than
+ // `BLOCK_SIZE`.
+ Err(SuballocationCreationError::BlockSizeExceeded) => {
+ return Err(AllocationCreationError::SuballocatorBlockSizeExceeded);
+ }
+ Err(_) => {}
+ }
+ }
+
+ blocks
+ };
+
+ // For bump allocators, first do a garbage sweep and try to allocate again.
+ if S::NEEDS_CLEANUP {
+ blocks.iter_mut().for_each(Suballocator::cleanup);
+ blocks.sort_unstable_by_key(Suballocator::free_size);
+
+ if let Some(block) = blocks.last() {
+ if let Ok(allocation) = block.allocate(create_info.clone()) {
+ return Ok(allocation);
+ }
+ }
+ }
+
+ if never_allocate {
+ return Err(AllocationCreationError::OutOfPoolMemory);
+ }
+
+ // The pool doesn't have enough real estate, so we need a new block.
+ let block = {
+ let export_handle_types = if !self.export_handle_types.is_empty() {
+ self.export_handle_types[memory_type_index as usize]
+ } else {
+ ExternalMemoryHandleTypes::empty()
+ };
+ let mut i = 0;
+
+ loop {
+ let allocate_info = MemoryAllocateInfo {
+ allocation_size: block_size >> i,
+ memory_type_index,
+ export_handle_types,
+ dedicated_allocation: None,
+ flags: self.flags,
+ ..Default::default()
+ };
+ match DeviceMemory::allocate_unchecked(self.device.clone(), allocate_info, None) {
+ Ok(device_memory) => {
+ break S::new(MemoryAlloc::new(device_memory)?);
+ }
+ // Retry up to 3 times, halving the allocation size each time.
+ Err(VulkanError::OutOfHostMemory | VulkanError::OutOfDeviceMemory) if i < 3 => {
+ i += 1;
+ }
+ Err(err) => return Err(err.into()),
+ }
+ }
+ };
+
+ blocks.push(block);
+ let block = blocks.last().unwrap();
+
+ match block.allocate(create_info) {
+ Ok(allocation) => Ok(allocation),
+ // This can happen if the block ended up smaller than advertised because there wasn't
+ // enough memory.
+ Err(SuballocationCreationError::OutOfRegionMemory) => Err(
+ AllocationCreationError::VulkanError(VulkanError::OutOfDeviceMemory),
+ ),
+ // This can not happen as the block is fresher than Febreze and we're still holding an
+ // exclusive lock.
+ Err(SuballocationCreationError::FragmentedRegion) => unreachable!(),
+ // This can happen if this is the first block that was inserted and when using the
+ // `PoolAllocator<BLOCK_SIZE>` if the allocation size is greater than `BLOCK_SIZE`.
+ Err(SuballocationCreationError::BlockSizeExceeded) => {
+ Err(AllocationCreationError::SuballocatorBlockSizeExceeded)
+ }
+ }
+ }
+
+ /// Allocates memory according to requirements.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `create_info.requirements.memory_type_bits` is zero.
+ /// - Panics if `create_info.requirements.memory_type_bits` is not less than 2<sup>*n*</sup>
+ /// where *n* is the number of available memory types.
+ /// - Panics if `create_info.dedicated_allocation` is `Some` and
+ /// `create_info.requirements.size` doesn't match the memory requirements of the resource.
+ /// - Panics if finding a suitable memory type failed. This only happens if the
+ /// `create_info.requirements` correspond to those of an optimal image but
+ /// `create_info.usage` is not [`MemoryUsage::DeviceOnly`].
+ ///
+ /// # Errors
+ ///
+ /// - Returns an error if allocating a new block is required and failed. This can be one of the
+ /// OOM errors or [`TooManyObjects`].
+ /// - Returns [`OutOfPoolMemory`] if `create_info.allocate_preference` is
+ /// [`MemoryAllocatePreference::NeverAllocate`] and none of the pools of suitable memory
+ /// types have enough free space.
+ /// - Returns [`DedicatedAllocationRequired`] if `create_info.allocate_preference` is
+ /// [`MemoryAllocatePreference::NeverAllocate`] and
+ /// `create_info.requirements.requires_dedicated_allocation` is `true`.
+ /// - Returns [`BlockSizeExceeded`] if `create_info.allocate_preference` is
+ /// [`MemoryAllocatePreference::NeverAllocate`] and `create_info.requirements.size` is greater
+ /// than the block size for all heaps of suitable memory types.
+ /// - Returns [`SuballocatorBlockSizeExceeded`] if `S` is `PoolAllocator<BLOCK_SIZE>` and
+ /// `create_info.size` is greater than `BLOCK_SIZE` and a dedicated allocation was not
+ /// created.
+ ///
+ /// [`TooManyObjects`]: VulkanError::TooManyObjects
+ /// [`OutOfPoolMemory`]: AllocationCreationError::OutOfPoolMemory
+ /// [`DedicatedAllocationRequired`]: AllocationCreationError::DedicatedAllocationRequired
+ /// [`BlockSizeExceeded`]: AllocationCreationError::BlockSizeExceeded
+ /// [`SuballocatorBlockSizeExceeded`]: AllocationCreationError::SuballocatorBlockSizeExceeded
+ fn allocate(
+ &self,
+ requirements: MemoryRequirements,
+ allocation_type: AllocationType,
+ create_info: AllocationCreateInfo,
+ dedicated_allocation: Option<DedicatedAllocation<'_>>,
+ ) -> Result<MemoryAlloc, AllocationCreationError> {
+ self.validate_allocate(requirements, dedicated_allocation);
+
+ unsafe {
+ self.allocate_unchecked(
+ requirements,
+ allocation_type,
+ create_info,
+ dedicated_allocation,
+ )
+ }
+ }
+
+ unsafe fn allocate_unchecked(
+ &self,
+ requirements: MemoryRequirements,
+ allocation_type: AllocationType,
+ create_info: AllocationCreateInfo,
+ mut dedicated_allocation: Option<DedicatedAllocation<'_>>,
+ ) -> Result<MemoryAlloc, AllocationCreationError> {
+ let MemoryRequirements {
+ layout,
+ mut memory_type_bits,
+ mut prefers_dedicated_allocation,
+ requires_dedicated_allocation,
+ } = requirements;
+ let AllocationCreateInfo {
+ usage,
+ allocate_preference,
+ _ne: _,
+ } = create_info;
+
+ let create_info = SuballocationCreateInfo {
+ layout,
+ allocation_type,
+ _ne: crate::NonExhaustive(()),
+ };
+
+ let size = layout.size();
+ memory_type_bits &= self.memory_type_bits;
+
+ let filter = usage.into();
+ let mut memory_type_index = self
+ .find_memory_type_index(memory_type_bits, filter)
+ .expect("couldn't find a suitable memory type");
+
+ if !self.dedicated_allocation {
+ dedicated_allocation = None;
+ }
+
+ let export_handle_types = if self.export_handle_types.is_empty() {
+ ExternalMemoryHandleTypes::empty()
+ } else {
+ self.export_handle_types[memory_type_index as usize]
+ };
+
+ loop {
+ let memory_type = self.pools[memory_type_index as usize].memory_type;
+ let block_size = self.block_sizes[memory_type.heap_index as usize];
+
+ let res = match allocate_preference {
+ MemoryAllocatePreference::Unknown => {
+ if requires_dedicated_allocation {
+ self.allocate_dedicated_unchecked(
+ memory_type_index,
+ size,
+ dedicated_allocation,
+ export_handle_types,
+ )
+ } else {
+ if size > block_size / 2 {
+ prefers_dedicated_allocation = true;
+ }
+ if self.device.allocation_count() > self.max_allocations
+ && size <= block_size
+ {
+ prefers_dedicated_allocation = false;
+ }
+
+ if prefers_dedicated_allocation {
+ self.allocate_dedicated_unchecked(
+ memory_type_index,
+ size,
+ dedicated_allocation,
+ export_handle_types,
+ )
+ // Fall back to suballocation.
+ .or_else(|err| {
+ if size <= block_size {
+ self.allocate_from_type_unchecked(
+ memory_type_index,
+ create_info.clone(),
+ true, // A dedicated allocation already failed.
+ )
+ .map_err(|_| err)
+ } else {
+ Err(err)
+ }
+ })
+ } else {
+ self.allocate_from_type_unchecked(
+ memory_type_index,
+ create_info.clone(),
+ false,
+ )
+ // Fall back to dedicated allocation. It is possible that the 1/8 block
+ // size tried was greater than the allocation size, so there's hope.
+ .or_else(|_| {
+ self.allocate_dedicated_unchecked(
+ memory_type_index,
+ size,
+ dedicated_allocation,
+ export_handle_types,
+ )
+ })
+ }
+ }
+ }
+ MemoryAllocatePreference::NeverAllocate => {
+ if requires_dedicated_allocation {
+ return Err(AllocationCreationError::DedicatedAllocationRequired);
+ }
+
+ self.allocate_from_type_unchecked(memory_type_index, create_info.clone(), true)
+ }
+ MemoryAllocatePreference::AlwaysAllocate => self.allocate_dedicated_unchecked(
+ memory_type_index,
+ size,
+ dedicated_allocation,
+ export_handle_types,
+ ),
+ };
+
+ match res {
+ Ok(allocation) => return Ok(allocation),
+ // This is not recoverable.
+ Err(AllocationCreationError::SuballocatorBlockSizeExceeded) => {
+ return Err(AllocationCreationError::SuballocatorBlockSizeExceeded);
+ }
+ // Try a different memory type.
+ Err(err) => {
+ memory_type_bits &= !(1 << memory_type_index);
+ memory_type_index = self
+ .find_memory_type_index(memory_type_bits, filter)
+ .ok_or(err)?;
+ }
+ }
+ }
+ }
+
+ unsafe fn allocate_dedicated_unchecked(
+ &self,
+ memory_type_index: u32,
+ allocation_size: DeviceSize,
+ mut dedicated_allocation: Option<DedicatedAllocation<'_>>,
+ export_handle_types: ExternalMemoryHandleTypes,
+ ) -> Result<MemoryAlloc, AllocationCreationError> {
+ // Providers of `VkMemoryDedicatedAllocateInfo`
+ if !(self.device.api_version() >= Version::V1_1
+ || self.device.enabled_extensions().khr_dedicated_allocation)
+ {
+ dedicated_allocation = None;
+ }
+
+ let allocate_info = MemoryAllocateInfo {
+ allocation_size,
+ memory_type_index,
+ dedicated_allocation,
+ export_handle_types,
+ flags: self.flags,
+ ..Default::default()
+ };
+ let mut allocation = MemoryAlloc::new(DeviceMemory::allocate_unchecked(
+ self.device.clone(),
+ allocate_info,
+ None,
+ )?)?;
+ allocation.set_allocation_type(self.allocation_type);
+
+ Ok(allocation)
+ }
+}
+
+unsafe impl<S: Suballocator> MemoryAllocator for Arc<GenericMemoryAllocator<S>> {
+ fn find_memory_type_index(
+ &self,
+ memory_type_bits: u32,
+ filter: MemoryTypeFilter,
+ ) -> Option<u32> {
+ (**self).find_memory_type_index(memory_type_bits, filter)
+ }
+
+ fn allocate_from_type(
+ &self,
+ memory_type_index: u32,
+ create_info: SuballocationCreateInfo,
+ ) -> Result<MemoryAlloc, AllocationCreationError> {
+ (**self).allocate_from_type(memory_type_index, create_info)
+ }
+
+ unsafe fn allocate_from_type_unchecked(
+ &self,
+ memory_type_index: u32,
+ create_info: SuballocationCreateInfo,
+ never_allocate: bool,
+ ) -> Result<MemoryAlloc, AllocationCreationError> {
+ (**self).allocate_from_type_unchecked(memory_type_index, create_info, never_allocate)
+ }
+
+ fn allocate(
+ &self,
+ requirements: MemoryRequirements,
+ allocation_type: AllocationType,
+ create_info: AllocationCreateInfo,
+ dedicated_allocation: Option<DedicatedAllocation<'_>>,
+ ) -> Result<MemoryAlloc, AllocationCreationError> {
+ (**self).allocate(
+ requirements,
+ allocation_type,
+ create_info,
+ dedicated_allocation,
+ )
+ }
+
+ unsafe fn allocate_unchecked(
+ &self,
+ requirements: MemoryRequirements,
+ allocation_type: AllocationType,
+ create_info: AllocationCreateInfo,
+ dedicated_allocation: Option<DedicatedAllocation<'_>>,
+ ) -> Result<MemoryAlloc, AllocationCreationError> {
+ (**self).allocate_unchecked(
+ requirements,
+ allocation_type,
+ create_info,
+ dedicated_allocation,
+ )
+ }
+
+ unsafe fn allocate_dedicated_unchecked(
+ &self,
+ memory_type_index: u32,
+ allocation_size: DeviceSize,
+ dedicated_allocation: Option<DedicatedAllocation<'_>>,
+ export_handle_types: ExternalMemoryHandleTypes,
+ ) -> Result<MemoryAlloc, AllocationCreationError> {
+ (**self).allocate_dedicated_unchecked(
+ memory_type_index,
+ allocation_size,
+ dedicated_allocation,
+ export_handle_types,
+ )
+ }
+}
+
+unsafe impl<S: Suballocator> DeviceOwned for GenericMemoryAllocator<S> {
+ fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+}
+
+/// Parameters to create a new [`GenericMemoryAllocator`].
+#[derive(Clone, Debug)]
+pub struct GenericMemoryAllocatorCreateInfo<'b, 'e> {
+ /// Lets you configure the block sizes for various heap size classes.
+ ///
+ /// Each entry is a pair of the threshold for the heap size and the block size that should be
+ /// used for that heap. Must be sorted by threshold and all thresholds must be unique. Must
+ /// contain a baseline threshold of 0.
+ ///
+ /// The allocator keeps a pool of [`DeviceMemory`] blocks for each memory type, so each memory
+ /// type that resides in a heap whose size crosses one of the thresholds will use the
+ /// corresponding block size. If multiple thresholds apply to a given heap, the block size
+ /// corresponding to the largest threshold is chosen.
+ ///
+ /// The block size is going to be the maximum size of a `DeviceMemory` block that is tried. If
+ /// allocating a block with the size fails, the allocator tries 1/2, 1/4 and 1/8 of the block
+ /// size in that order until one succeeds, else a dedicated allocation is attempted for the
+ /// allocation. If an allocation is created with a size greater than half the block size it is
+ /// always made a dedicated allocation. All of this doesn't apply when using
+ /// [`MemoryAllocatePreference::NeverAllocate`] however.
+ ///
+ /// The default value is `&[]`, which must be overridden.
+ pub block_sizes: &'b [(Threshold, BlockSize)],
+
+ /// The allocation type that should be used for root allocations.
+ ///
+ /// You only need to worry about this if you're using [`PoolAllocator`] as the suballocator, as
+ /// all suballocations that the pool allocator makes inherit their allocation type from the
+ /// parent allocation. For the [`FreeListAllocator`] and the [`BuddyAllocator`] this must be
+ /// [`AllocationType::Unknown`] otherwise you will get panics. It does not matter what this is
+ /// when using the [`BumpAllocator`].
+ ///
+ /// The default value is [`AllocationType::Unknown`].
+ pub allocation_type: AllocationType,
+
+ /// Whether the allocator should use the dedicated allocation APIs.
+ ///
+ /// This means that when the allocator decides that an allocation should not be suballocated,
+ /// but rather have its own block of [`DeviceMemory`], that that allocation will be made a
+ /// dedicated allocation. Otherwise they are still made free-standing ([root]) allocations,
+ /// just not [dedicated] ones.
+ ///
+ /// Dedicated allocations are an optimization which may result in better performance, so there
+ /// really is no reason to disable this option, unless the restrictions that they bring with
+ /// them are a problem. Namely, a dedicated allocation must only be used for the resource it
+ /// was created for. Meaning that [reusing the memory] for something else is not possible,
+ /// [suballocating it] is not possible, and [aliasing it] is also not possible.
+ ///
+ /// This option is silently ignored (treated as `false`) if the device API version is below 1.1
+ /// and the [`khr_dedicated_allocation`] extension is not enabled on the device.
+ ///
+ /// The default value is `true`.
+ ///
+ /// [root]: MemoryAlloc::is_root
+ /// [dedicated]: MemoryAlloc::is_dedicated
+ /// [reusing the memory]: MemoryAlloc::try_unwrap
+ /// [suballocating it]: Suballocator
+ /// [aliasing it]: MemoryAlloc::alias
+ /// [`khr_dedicated_allocation`]: crate::device::DeviceExtensions::khr_dedicated_allocation
+ pub dedicated_allocation: bool,
+
+ /// Lets you configure the external memory handle types that the [`DeviceMemory`] blocks will
+ /// be allocated with.
+ ///
+ /// Must be either empty or contain one element for each memory type. When `DeviceMemory` is
+ /// allocated, the external handle types corresponding to the memory type index are looked up
+ /// here and used for the allocation.
+ ///
+ /// The default value is `&[]`.
+ pub export_handle_types: &'e [ExternalMemoryHandleTypes],
+
+ /// Whether the allocator should allocate the [`DeviceMemory`] blocks with the
+ /// [`DEVICE_ADDRESS`] flag set.
+ ///
+ /// This is required if you want to allocate memory for buffers that have the
+ /// [`SHADER_DEVICE_ADDRESS`] usage set. For this option too, there is no reason to disable it.
+ ///
+ /// This option is silently ignored (treated as `false`) if the [`buffer_device_address`]
+ /// feature is not enabled on the device or if the [`ext_buffer_device_address`] extension is
+ /// enabled on the device. It is also ignored if the device API version is below 1.1 and the
+ /// [`khr_device_group`] extension is not enabled on the device.
+ ///
+ /// The default value is `true`.
+ ///
+ /// [`DEVICE_ADDRESS`]: MemoryAllocateFlags::DEVICE_ADDRESS
+ /// [`SHADER_DEVICE_ADDRESS`]: crate::buffer::BufferUsage::SHADER_DEVICE_ADDRESS
+ /// [`buffer_device_address`]: crate::device::Features::buffer_device_address
+ /// [`ext_buffer_device_address`]: crate::device::DeviceExtensions::ext_buffer_device_address
+ /// [`khr_device_group`]: crate::device::DeviceExtensions::khr_device_group
+ pub device_address: bool,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+pub type Threshold = DeviceSize;
+
+pub type BlockSize = DeviceSize;
+
+impl Default for GenericMemoryAllocatorCreateInfo<'_, '_> {
+ #[inline]
+ fn default() -> Self {
+ GenericMemoryAllocatorCreateInfo {
+ block_sizes: &[],
+ allocation_type: AllocationType::Unknown,
+ dedicated_allocation: true,
+ export_handle_types: &[],
+ device_address: true,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// Error that can be returned when creating a [`GenericMemoryAllocator`].
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum GenericMemoryAllocatorCreationError {
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+}
+
+impl Error for GenericMemoryAllocatorCreationError {}
+
+impl Display for GenericMemoryAllocatorCreationError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ }
+ }
+}
+
+impl From<RequirementNotMet> for GenericMemoryAllocatorCreationError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
+ }
+ }
+}
+
+/// > **Note**: Returns `0` on overflow.
+#[inline(always)]
+pub(crate) const fn align_up(val: DeviceSize, alignment: DeviceAlignment) -> DeviceSize {
+ align_down(val.wrapping_add(alignment.as_devicesize() - 1), alignment)
+}
+
+#[inline(always)]
+pub(crate) const fn align_down(val: DeviceSize, alignment: DeviceAlignment) -> DeviceSize {
+ val & !(alignment.as_devicesize() - 1)
+}
+
+mod array_vec {
+ use std::ops::{Deref, DerefMut};
+
+ /// Minimal implementation of an `ArrayVec`. Useful when a `Vec` is needed but there is a known
+ /// limit on the number of elements, so that it can occupy real estate on the stack.
+ #[derive(Clone, Copy, Debug)]
+ pub(super) struct ArrayVec<T, const N: usize> {
+ len: usize,
+ data: [T; N],
+ }
+
+ impl<T, const N: usize> ArrayVec<T, N> {
+ pub fn new(len: usize, data: [T; N]) -> Self {
+ assert!(len <= N);
+
+ ArrayVec { len, data }
+ }
+ }
+
+ impl<T, const N: usize> Deref for ArrayVec<T, N> {
+ type Target = [T];
+
+ fn deref(&self) -> &Self::Target {
+ // SAFETY: `self.len <= N`.
+ unsafe { self.data.get_unchecked(0..self.len) }
+ }
+ }
+
+ impl<T, const N: usize> DerefMut for ArrayVec<T, N> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ // SAFETY: `self.len <= N`.
+ unsafe { self.data.get_unchecked_mut(0..self.len) }
+ }
+ }
+}
diff --git a/src/memory/allocator/suballocator.rs b/src/memory/allocator/suballocator.rs
new file mode 100644
index 0000000..d48974e
--- /dev/null
+++ b/src/memory/allocator/suballocator.rs
@@ -0,0 +1,3142 @@
+// Copyright (c) 2016 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+//! Suballocators are used to divide a *region* into smaller *suballocations*.
+//!
+//! See also [the parent module] for details about memory allocation in Vulkan.
+//!
+//! [the parent module]: super
+
+use self::host::SlotId;
+use super::{
+ align_down, align_up, array_vec::ArrayVec, AllocationCreationError, DeviceAlignment,
+ DeviceLayout,
+};
+use crate::{
+ device::{Device, DeviceOwned},
+ image::ImageTiling,
+ memory::{is_aligned, DeviceMemory, MemoryPropertyFlags},
+ DeviceSize, NonZeroDeviceSize, VulkanError, VulkanObject,
+};
+use crossbeam_queue::ArrayQueue;
+use parking_lot::Mutex;
+use std::{
+ cell::Cell,
+ cmp,
+ error::Error,
+ ffi::c_void,
+ fmt::{self, Display},
+ mem::{self, ManuallyDrop, MaybeUninit},
+ ops::Range,
+ ptr::{self, NonNull},
+ slice,
+ sync::{
+ atomic::{AtomicU64, Ordering},
+ Arc,
+ },
+};
+
+/// Memory allocations are portions of memory that are reserved for a specific resource or purpose.
+///
+/// There's a few ways you can obtain a `MemoryAlloc` in Vulkano. Most commonly you will probably
+/// want to use a [memory allocator]. If you already have a [`DeviceMemory`] block on hand that you
+/// would like to turn into an allocation, you can use [the constructor]. Lastly, you can use a
+/// [suballocator] if you want to create multiple smaller allocations out of a bigger one.
+///
+/// [memory allocator]: super::MemoryAllocator
+/// [the constructor]: Self::new
+/// [suballocator]: Suballocator
+#[derive(Debug)]
+pub struct MemoryAlloc {
+ offset: DeviceSize,
+ size: DeviceSize,
+ // Needed when binding resources to the allocation in order to avoid aliasing memory.
+ allocation_type: AllocationType,
+ // Mapped pointer to the start of the allocation or `None` is the memory is not host-visible.
+ mapped_ptr: Option<NonNull<c_void>>,
+ // Used by the suballocators to align allocations to the non-coherent atom size when the memory
+ // type is host-visible but not host-coherent. This will be `None` for any other memory type.
+ atom_size: Option<DeviceAlignment>,
+ // Used in the `Drop` impl to free the allocation if required.
+ parent: AllocParent,
+}
+
+#[derive(Debug)]
+enum AllocParent {
+ FreeList {
+ allocator: Arc<FreeListAllocator>,
+ id: SlotId,
+ },
+ Buddy {
+ allocator: Arc<BuddyAllocator>,
+ order: usize,
+ offset: DeviceSize,
+ },
+ Pool {
+ allocator: Arc<PoolAllocatorInner>,
+ index: DeviceSize,
+ },
+ Bump(Arc<BumpAllocator>),
+ Root(Arc<DeviceMemory>),
+ Dedicated(DeviceMemory),
+}
+
+// It is safe to share `mapped_ptr` between threads because the user would have to use unsafe code
+// themself to get UB in the first place.
+unsafe impl Send for MemoryAlloc {}
+unsafe impl Sync for MemoryAlloc {}
+
+impl MemoryAlloc {
+ /// Creates a new `MemoryAlloc`.
+ ///
+ /// The memory is mapped automatically if it's host-visible.
+ #[inline]
+ pub fn new(device_memory: DeviceMemory) -> Result<Self, AllocationCreationError> {
+ // Sanity check: this would lead to UB when suballocating.
+ assert!(device_memory.allocation_size() <= DeviceLayout::MAX_SIZE);
+
+ let device = device_memory.device();
+ let physical_device = device.physical_device();
+ let memory_type_index = device_memory.memory_type_index();
+ let property_flags = &physical_device.memory_properties().memory_types
+ [memory_type_index as usize]
+ .property_flags;
+
+ let mapped_ptr = if property_flags.intersects(MemoryPropertyFlags::HOST_VISIBLE) {
+ // Sanity check: this would lead to UB when calculating pointer offsets.
+ assert!(device_memory.allocation_size() <= isize::MAX.try_into().unwrap());
+
+ let fns = device.fns();
+ let mut output = MaybeUninit::uninit();
+ // This is always valid because we are mapping the whole range.
+ unsafe {
+ (fns.v1_0.map_memory)(
+ device.handle(),
+ device_memory.handle(),
+ 0,
+ ash::vk::WHOLE_SIZE,
+ ash::vk::MemoryMapFlags::empty(),
+ output.as_mut_ptr(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+
+ Some(NonNull::new(output.assume_init()).unwrap())
+ }
+ } else {
+ None
+ };
+
+ let atom_size = (property_flags.intersects(MemoryPropertyFlags::HOST_VISIBLE)
+ && !property_flags.intersects(MemoryPropertyFlags::HOST_COHERENT))
+ .then_some(physical_device.properties().non_coherent_atom_size);
+
+ Ok(MemoryAlloc {
+ offset: 0,
+ size: device_memory.allocation_size(),
+ allocation_type: AllocationType::Unknown,
+ mapped_ptr,
+ atom_size,
+ parent: if device_memory.is_dedicated() {
+ AllocParent::Dedicated(device_memory)
+ } else {
+ AllocParent::Root(Arc::new(device_memory))
+ },
+ })
+ }
+
+ /// Returns the offset of the allocation within the [`DeviceMemory`] block.
+ #[inline]
+ pub fn offset(&self) -> DeviceSize {
+ self.offset
+ }
+
+ /// Returns the size of the allocation.
+ #[inline]
+ pub fn size(&self) -> DeviceSize {
+ self.size
+ }
+
+ /// Returns the type of resources that can be bound to this allocation.
+ #[inline]
+ pub fn allocation_type(&self) -> AllocationType {
+ self.allocation_type
+ }
+
+ /// Returns the mapped pointer to the start of the allocation if the memory is host-visible,
+ /// otherwise returns [`None`].
+ #[inline]
+ pub fn mapped_ptr(&self) -> Option<NonNull<c_void>> {
+ self.mapped_ptr
+ }
+
+ /// Returns a mapped slice to the data within the allocation if the memory is host-visible,
+ /// otherwise returns [`None`].
+ ///
+ /// # Safety
+ ///
+ /// - While the returned slice exists, there must be no operations pending or executing in a
+ /// GPU queue that write to the same memory.
+ #[inline]
+ pub unsafe fn mapped_slice(&self) -> Option<&[u8]> {
+ self.mapped_ptr
+ .map(|ptr| slice::from_raw_parts(ptr.as_ptr().cast(), self.size as usize))
+ }
+
+ /// Returns a mapped mutable slice to the data within the allocation if the memory is
+ /// host-visible, otherwise returns [`None`].
+ ///
+ /// # Safety
+ ///
+ /// - While the returned slice exists, there must be no operations pending or executing in a
+ /// GPU queue that access the same memory.
+ #[inline]
+ pub unsafe fn mapped_slice_mut(&mut self) -> Option<&mut [u8]> {
+ self.mapped_ptr
+ .map(|ptr| slice::from_raw_parts_mut(ptr.as_ptr().cast(), self.size as usize))
+ }
+
+ pub(crate) fn atom_size(&self) -> Option<DeviceAlignment> {
+ self.atom_size
+ }
+
+ /// Invalidates the host (CPU) cache for a range of the allocation.
+ ///
+ /// You must call this method before the memory is read by the host, if the device previously
+ /// wrote to the memory. It has no effect if the memory is not mapped or if the memory is
+ /// [host-coherent].
+ ///
+ /// `range` is specified in bytes relative to the start of the allocation. The start and end of
+ /// `range` must be a multiple of the [`non_coherent_atom_size`] device property, but
+ /// `range.end` can also equal to `self.size()`.
+ ///
+ /// # Safety
+ ///
+ /// - If there are memory writes by the GPU that have not been propagated into the CPU cache,
+ /// then there must not be any references in Rust code to the specified `range` of the memory.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `range` is empty.
+ /// - Panics if `range.end` exceeds `self.size`.
+ /// - Panics if `range.start` or `range.end` are not a multiple of the `non_coherent_atom_size`.
+ ///
+ /// [host-coherent]: crate::memory::MemoryPropertyFlags::HOST_COHERENT
+ /// [`non_coherent_atom_size`]: crate::device::Properties::non_coherent_atom_size
+ #[inline]
+ pub unsafe fn invalidate_range(&self, range: Range<DeviceSize>) -> Result<(), VulkanError> {
+ // VUID-VkMappedMemoryRange-memory-00684
+ if let Some(atom_size) = self.atom_size {
+ let range = self.create_memory_range(range, atom_size);
+ let device = self.device();
+ let fns = device.fns();
+ (fns.v1_0.invalidate_mapped_memory_ranges)(device.handle(), 1, &range)
+ .result()
+ .map_err(VulkanError::from)?;
+ } else {
+ self.debug_validate_memory_range(&range);
+ }
+
+ Ok(())
+ }
+
+ /// Flushes the host (CPU) cache for a range of the allocation.
+ ///
+ /// You must call this method after writing to the memory from the host, if the device is going
+ /// to read the memory. It has no effect if the memory is not mapped or if the memory is
+ /// [host-coherent].
+ ///
+ /// `range` is specified in bytes relative to the start of the allocation. The start and end of
+ /// `range` must be a multiple of the [`non_coherent_atom_size`] device property, but
+ /// `range.end` can also equal to `self.size()`.
+ ///
+ /// # Safety
+ ///
+ /// - There must be no operations pending or executing in a GPU queue that access the specified
+ /// `range` of the memory.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `range` is empty.
+ /// - Panics if `range.end` exceeds `self.size`.
+ /// - Panics if `range.start` or `range.end` are not a multiple of the `non_coherent_atom_size`.
+ ///
+ /// [host-coherent]: crate::memory::MemoryPropertyFlags::HOST_COHERENT
+ /// [`non_coherent_atom_size`]: crate::device::Properties::non_coherent_atom_size
+ #[inline]
+ pub unsafe fn flush_range(&self, range: Range<DeviceSize>) -> Result<(), VulkanError> {
+ // VUID-VkMappedMemoryRange-memory-00684
+ if let Some(atom_size) = self.atom_size {
+ let range = self.create_memory_range(range, atom_size);
+ let device = self.device();
+ let fns = device.fns();
+ (fns.v1_0.flush_mapped_memory_ranges)(device.handle(), 1, &range)
+ .result()
+ .map_err(VulkanError::from)?;
+ } else {
+ self.debug_validate_memory_range(&range);
+ }
+
+ Ok(())
+ }
+
+ fn create_memory_range(
+ &self,
+ range: Range<DeviceSize>,
+ atom_size: DeviceAlignment,
+ ) -> ash::vk::MappedMemoryRange {
+ assert!(!range.is_empty() && range.end <= self.size);
+
+ // VUID-VkMappedMemoryRange-size-00685
+ // Guaranteed because we always map the entire `DeviceMemory`.
+
+ // VUID-VkMappedMemoryRange-offset-00687
+ // VUID-VkMappedMemoryRange-size-01390
+ assert!(
+ is_aligned(range.start, atom_size)
+ && (is_aligned(range.end, atom_size) || range.end == self.size)
+ );
+
+ // VUID-VkMappedMemoryRange-offset-00687
+ // Guaranteed as long as `range.start` is aligned because the suballocators always align
+ // `self.offset` to the non-coherent atom size for non-coherent host-visible memory.
+ let offset = self.offset + range.start;
+
+ let mut size = range.end - range.start;
+ let device_memory = self.device_memory();
+
+ // VUID-VkMappedMemoryRange-size-01390
+ if offset + size < device_memory.allocation_size() {
+ // We align the size in case `range.end == self.size`. We can do this without aliasing
+ // other allocations because the suballocators ensure that all allocations are aligned
+ // to the atom size for non-coherent host-visible memory.
+ size = align_up(size, atom_size);
+ }
+
+ ash::vk::MappedMemoryRange {
+ memory: device_memory.handle(),
+ offset,
+ size,
+ ..Default::default()
+ }
+ }
+
+ /// This exists because even if no cache control is required, the parameters should still be
+ /// valid, otherwise you might have bugs in your code forever just because your memory happens
+ /// to be host-coherent.
+ fn debug_validate_memory_range(&self, range: &Range<DeviceSize>) {
+ debug_assert!(!range.is_empty() && range.end <= self.size);
+
+ let atom_size = self
+ .device()
+ .physical_device()
+ .properties()
+ .non_coherent_atom_size;
+ debug_assert!(
+ is_aligned(range.start, atom_size)
+ && (is_aligned(range.end, atom_size) || range.end == self.size),
+ "attempted to invalidate or flush a memory range that is not aligned to the \
+ non-coherent atom size",
+ );
+ }
+
+ /// Returns the underlying block of [`DeviceMemory`].
+ #[inline]
+ pub fn device_memory(&self) -> &DeviceMemory {
+ match &self.parent {
+ AllocParent::FreeList { allocator, .. } => &allocator.device_memory,
+ AllocParent::Buddy { allocator, .. } => &allocator.device_memory,
+ AllocParent::Pool { allocator, .. } => &allocator.device_memory,
+ AllocParent::Bump(allocator) => &allocator.device_memory,
+ AllocParent::Root(device_memory) => device_memory,
+ AllocParent::Dedicated(device_memory) => device_memory,
+ }
+ }
+
+ /// Returns the parent allocation if this allocation is a [suballocation], otherwise returns
+ /// [`None`].
+ ///
+ /// [suballocation]: Suballocator
+ #[inline]
+ pub fn parent_allocation(&self) -> Option<&Self> {
+ match &self.parent {
+ AllocParent::FreeList { allocator, .. } => Some(&allocator.region),
+ AllocParent::Buddy { allocator, .. } => Some(&allocator.region),
+ AllocParent::Pool { allocator, .. } => Some(&allocator.region),
+ AllocParent::Bump(allocator) => Some(&allocator.region),
+ AllocParent::Root(_) => None,
+ AllocParent::Dedicated(_) => None,
+ }
+ }
+
+ /// Returns `true` if this allocation is the root of the [memory hierarchy].
+ ///
+ /// [memory hierarchy]: Suballocator#memory-hierarchies
+ #[inline]
+ pub fn is_root(&self) -> bool {
+ matches!(&self.parent, AllocParent::Root(_))
+ }
+
+ /// Returns `true` if this allocation is a [dedicated allocation].
+ ///
+ /// [dedicated allocation]: crate::memory::MemoryAllocateInfo#structfield.dedicated_allocation
+ #[inline]
+ pub fn is_dedicated(&self) -> bool {
+ matches!(&self.parent, AllocParent::Dedicated(_))
+ }
+
+ /// Returns the underlying block of [`DeviceMemory`] if this allocation [is the root
+ /// allocation] and is not [aliased], otherwise returns the allocation back wrapped in [`Err`].
+ ///
+ /// [is the root allocation]: Self::is_root
+ /// [aliased]: Self::alias
+ #[inline]
+ pub fn try_unwrap(self) -> Result<DeviceMemory, Self> {
+ let this = ManuallyDrop::new(self);
+
+ // SAFETY: This is safe because even if a panic happens, `self.parent` can not be
+ // double-freed since `self` was wrapped in `ManuallyDrop`. If we fail to unwrap the
+ // `DeviceMemory`, the copy of `self.parent` is forgotten and only then is the
+ // `ManuallyDrop` wrapper removed from `self`.
+ match unsafe { ptr::read(&this.parent) } {
+ AllocParent::Root(device_memory) => {
+ Arc::try_unwrap(device_memory).map_err(|device_memory| {
+ mem::forget(device_memory);
+ ManuallyDrop::into_inner(this)
+ })
+ }
+ parent => {
+ mem::forget(parent);
+ Err(ManuallyDrop::into_inner(this))
+ }
+ }
+ }
+
+ /// Duplicates the allocation, creating aliased memory. Returns [`None`] if the allocation [is
+ /// a dedicated allocation].
+ ///
+ /// You might consider using this method if you want to optimize memory usage by aliasing
+ /// render targets for example, in which case you will have to double and triple check that the
+ /// memory is not used concurrently unless it only involves reading. You are highly discouraged
+ /// from doing this unless you have a reason to.
+ ///
+ /// # Safety
+ ///
+ /// - You must ensure memory accesses are synchronized yourself.
+ ///
+ /// [memory hierarchy]: Suballocator#memory-hierarchies
+ /// [is a dedicated allocation]: Self::is_dedicated
+ #[inline]
+ pub unsafe fn alias(&self) -> Option<Self> {
+ self.root().map(|device_memory| MemoryAlloc {
+ parent: AllocParent::Root(device_memory.clone()),
+ ..*self
+ })
+ }
+
+ fn root(&self) -> Option<&Arc<DeviceMemory>> {
+ match &self.parent {
+ AllocParent::FreeList { allocator, .. } => Some(&allocator.device_memory),
+ AllocParent::Buddy { allocator, .. } => Some(&allocator.device_memory),
+ AllocParent::Pool { allocator, .. } => Some(&allocator.device_memory),
+ AllocParent::Bump(allocator) => Some(&allocator.device_memory),
+ AllocParent::Root(device_memory) => Some(device_memory),
+ AllocParent::Dedicated(_) => None,
+ }
+ }
+
+ /// Increases the offset of the allocation by the specified `amount` and shrinks its size by
+ /// the same amount.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the `amount` exceeds the size of the allocation.
+ #[inline]
+ pub fn shift(&mut self, amount: DeviceSize) {
+ assert!(amount <= self.size);
+
+ unsafe { self.set_offset(self.offset + amount) };
+ self.size -= amount;
+ }
+
+ /// Shrinks the size of the allocation to the specified `new_size`.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the `new_size` exceeds the current size of the allocation.
+ #[inline]
+ pub fn shrink(&mut self, new_size: DeviceSize) {
+ assert!(new_size <= self.size);
+
+ self.size = new_size;
+ }
+
+ /// Sets the offset of the allocation without checking for memory aliasing.
+ ///
+ /// See also [`shift`], which moves the offset safely.
+ ///
+ /// # Safety
+ ///
+ /// - You must ensure that the allocation doesn't alias any other allocations within the
+ /// [`DeviceMemory`] block, and if it does, then you must ensure memory accesses are
+ /// synchronized yourself.
+ /// - You must ensure the allocation still fits inside the `DeviceMemory` block.
+ ///
+ /// [`shift`]: Self::shift
+ #[inline]
+ pub unsafe fn set_offset(&mut self, new_offset: DeviceSize) {
+ if let Some(ptr) = self.mapped_ptr.as_mut() {
+ *ptr = NonNull::new_unchecked(
+ ptr.as_ptr()
+ .offset(new_offset as isize - self.offset as isize),
+ );
+ }
+ self.offset = new_offset;
+ }
+
+ /// Sets the size of the allocation without checking for memory aliasing.
+ ///
+ /// See also [`shrink`], which sets the size safely.
+ ///
+ /// # Safety
+ ///
+ /// - You must ensure that the allocation doesn't alias any other allocations within the
+ /// [`DeviceMemory`] block, and if it does, then you must ensure memory accesses are
+ /// synchronized yourself.
+ /// - You must ensure the allocation still fits inside the `DeviceMemory` block.
+ ///
+ /// [`shrink`]: Self::shrink
+ #[inline]
+ pub unsafe fn set_size(&mut self, new_size: DeviceSize) {
+ self.size = new_size;
+ }
+
+ /// Sets the allocation type.
+ ///
+ /// This might cause memory aliasing due to [buffer-image granularity] conflicts if the
+ /// allocation type is [`Linear`] or [`NonLinear`] and is changed to a different one.
+ ///
+ /// # Safety
+ ///
+ /// - You must ensure that the allocation doesn't alias any other allocations within the
+ /// [`DeviceMemory`] block, and if it does, then you must ensure memory accesses are
+ /// synchronized yourself.
+ ///
+ /// [buffer-image granularity]: super#buffer-image-granularity
+ /// [`Linear`]: AllocationType::Linear
+ /// [`NonLinear`]: AllocationType::NonLinear
+ #[inline]
+ pub unsafe fn set_allocation_type(&mut self, new_type: AllocationType) {
+ self.allocation_type = new_type;
+ }
+}
+
+impl Drop for MemoryAlloc {
+ #[inline]
+ fn drop(&mut self) {
+ match &self.parent {
+ AllocParent::FreeList { allocator, id } => {
+ unsafe { allocator.free(*id) };
+ }
+ AllocParent::Buddy {
+ allocator,
+ order,
+ offset,
+ } => {
+ unsafe { allocator.free(*order, *offset) };
+ }
+ AllocParent::Pool { allocator, index } => {
+ unsafe { allocator.free(*index) };
+ }
+ // The bump allocator can't free individually, but we need to keep a reference to it so
+ // it don't get reset or dropped while in use.
+ AllocParent::Bump(_) => {}
+ // A root allocation frees itself once all references to the `DeviceMemory` are dropped.
+ AllocParent::Root(_) => {}
+ // Dedicated allocations free themselves when the `DeviceMemory` is dropped.
+ AllocParent::Dedicated(_) => {}
+ }
+ }
+}
+
+unsafe impl DeviceOwned for MemoryAlloc {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ self.device_memory().device()
+ }
+}
+
+/// Suballocators are used to divide a *region* into smaller *suballocations*.
+///
+/// # Regions
+///
+/// As the name implies, a region is a contiguous portion of memory. It may be the whole dedicated
+/// block of [`DeviceMemory`], or only a part of it. Regions are just [allocations] like any other,
+/// but we use this term to refer specifically to an allocation that is to be suballocated. Every
+/// suballocator is created with a region to work with.
+///
+/// # Free-lists
+///
+/// A free-list, also kind of predictably, refers to a list of (sub)allocations within a region
+/// that are currently free. Every (sub)allocator that can free allocations dynamically (in any
+/// order) needs to keep a free-list of some sort. This list is then consulted when new allocations
+/// are made, and can be used to coalesce neighboring allocations that are free into bigger ones.
+///
+/// # Memory hierarchies
+///
+/// Different applications have wildly different allocation needs, and there's no way to cover them
+/// all with a single type of allocator. Furthermore, different allocators have different
+/// trade-offs and are best suited to specific tasks. To account for all possible use-cases,
+/// Vulkano offers the ability to create *memory hierarchies*. We refer to the [`DeviceMemory`] as
+/// the root of any such hierarchy, even though technically the driver has levels that are further
+/// up, because those `DeviceMemory` blocks need to be allocated from physical memory [pages]
+/// themselves, but since those levels are not accessible to us we don't need to consider them. You
+/// can create any number of levels/branches from there, bounded only by the amount of available
+/// memory within a `DeviceMemory` block. You can suballocate the root into regions, which are then
+/// suballocated into further regions and so on, creating hierarchies of arbitrary height.
+///
+/// As an added bonus, memory hierarchies lend themselves perfectly to the concept of composability
+/// we all love so much, making them a natural fit for Rust. For one, a region can be allocated any
+/// way, and fed into any suballocator. Also, once you are done with a branch of a hierarchy,
+/// meaning there are no more suballocations in use within the region of that branch, and you would
+/// like to reuse the region, you can do so safely! All suballocators have a `try_into_region`
+/// method for this purpose. This means that you can replace one suballocator with another without
+/// consulting any of the higher levels in the hierarchy.
+///
+/// # Examples
+///
+/// Allocating a region to suballocatate:
+///
+/// ```
+/// use vulkano::memory::{DeviceMemory, MemoryAllocateInfo, MemoryPropertyFlags, MemoryType};
+/// use vulkano::memory::allocator::MemoryAlloc;
+/// # let device: std::sync::Arc<vulkano::device::Device> = return;
+///
+/// // First you need to find a suitable memory type.
+/// let memory_type_index = device
+/// .physical_device()
+/// .memory_properties()
+/// .memory_types
+/// .iter()
+/// .enumerate()
+/// // In a real-world scenario, you would probably want to rank the memory types based on your
+/// // requirements, instead of picking the first one that satisfies them. Also, you have to
+/// // take the requirements of the resources you want to allocate memory for into consideration.
+/// .find_map(|(index, MemoryType { property_flags, .. })| {
+/// property_flags.intersects(MemoryPropertyFlags::DEVICE_LOCAL).then_some(index)
+/// })
+/// .unwrap() as u32;
+///
+/// let region = MemoryAlloc::new(
+/// DeviceMemory::allocate(
+/// device.clone(),
+/// MemoryAllocateInfo {
+/// allocation_size: 64 * 1024 * 1024,
+/// memory_type_index,
+/// ..Default::default()
+/// },
+/// )
+/// .unwrap(),
+/// )
+/// .unwrap();
+///
+/// // You can now feed `region` into any suballocator.
+/// ```
+///
+/// # Implementing the trait
+///
+/// Please don't.
+///
+/// [allocations]: MemoryAlloc
+/// [pages]: super#pages
+pub unsafe trait Suballocator: DeviceOwned {
+ /// Whether this allocator needs to block or not.
+ ///
+ /// This is used by the [`GenericMemoryAllocator`] to specialize the allocation strategy to the
+ /// suballocator at compile time.
+ ///
+ /// [`GenericMemoryAllocator`]: super::GenericMemoryAllocator
+ const IS_BLOCKING: bool;
+
+ /// Whether the allocator needs [`cleanup`] to be called before memory can be released.
+ ///
+ /// This is used by the [`GenericMemoryAllocator`] to specialize the allocation strategy to the
+ /// suballocator at compile time.
+ ///
+ /// [`cleanup`]: Self::cleanup
+ /// [`GenericMemoryAllocator`]: super::GenericMemoryAllocator
+ const NEEDS_CLEANUP: bool;
+
+ /// Creates a new suballocator for the given [region].
+ ///
+ /// [region]: Self#regions
+ fn new(region: MemoryAlloc) -> Self
+ where
+ Self: Sized;
+
+ /// Creates a new suballocation within the [region].
+ ///
+ /// [region]: Self#regions
+ fn allocate(
+ &self,
+ create_info: SuballocationCreateInfo,
+ ) -> Result<MemoryAlloc, SuballocationCreationError>;
+
+ /// Returns a reference to the underlying [region].
+ ///
+ /// [region]: Self#regions
+ fn region(&self) -> &MemoryAlloc;
+
+ /// Returns the underlying [region] if there are no other strong references to the allocator,
+ /// otherwise hands you back the allocator wrapped in [`Err`]. Allocations made with the
+ /// allocator count as references for as long as they are alive.
+ ///
+ /// [region]: Self#regions
+ fn try_into_region(self) -> Result<MemoryAlloc, Self>
+ where
+ Self: Sized;
+
+ /// Returns the total amount of free space that is left in the [region].
+ ///
+ /// [region]: Self#regions
+ fn free_size(&self) -> DeviceSize;
+
+ /// Tries to free some space, if applicable.
+ fn cleanup(&mut self);
+}
+
+/// Parameters to create a new [allocation] using a [suballocator].
+///
+/// [allocation]: MemoryAlloc
+/// [suballocator]: Suballocator
+#[derive(Clone, Debug)]
+pub struct SuballocationCreateInfo {
+ /// Memory layout required for the allocation.
+ ///
+ /// The default value is a layout with size [`DeviceLayout::MAX_SIZE`] and alignment
+ /// [`DeviceAlignment::MIN`], which must be overridden.
+ pub layout: DeviceLayout,
+
+ /// Type of resources that can be bound to the allocation.
+ ///
+ /// The default value is [`AllocationType::Unknown`].
+ pub allocation_type: AllocationType,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for SuballocationCreateInfo {
+ #[inline]
+ fn default() -> Self {
+ SuballocationCreateInfo {
+ layout: DeviceLayout::new(
+ NonZeroDeviceSize::new(DeviceLayout::MAX_SIZE).unwrap(),
+ DeviceAlignment::MIN,
+ )
+ .unwrap(),
+ allocation_type: AllocationType::Unknown,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// Tells the [suballocator] what type of resource will be bound to the allocation, so that it can
+/// optimize memory usage while still respecting the [buffer-image granularity].
+///
+/// [suballocator]: Suballocator
+/// [buffer-image granularity]: super#buffer-image-granularity
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+pub enum AllocationType {
+ /// The type of resource is unknown, it might be either linear or non-linear. What this means is
+ /// that allocations created with this type must always be aligned to the buffer-image
+ /// granularity.
+ Unknown = 0,
+
+ /// The resource is linear, e.g. buffers, linear images. A linear allocation following another
+ /// linear allocation never needs to be aligned to the buffer-image granularity.
+ Linear = 1,
+
+ /// The resource is non-linear, e.g. optimal images. A non-linear allocation following another
+ /// non-linear allocation never needs to be aligned to the buffer-image granularity.
+ NonLinear = 2,
+}
+
+impl From<ImageTiling> for AllocationType {
+ #[inline]
+ fn from(tiling: ImageTiling) -> Self {
+ match tiling {
+ ImageTiling::Optimal => AllocationType::NonLinear,
+ ImageTiling::Linear => AllocationType::Linear,
+ ImageTiling::DrmFormatModifier => AllocationType::Linear, // TODO: improve
+ }
+ }
+}
+
+/// Error that can be returned when using a [suballocator].
+///
+/// [suballocator]: Suballocator
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum SuballocationCreationError {
+ /// There is no more space available in the region.
+ OutOfRegionMemory,
+
+ /// The region has enough free space to satisfy the request but is too fragmented.
+ FragmentedRegion,
+
+ /// The allocation was larger than the allocator's block size, meaning that this error would
+ /// arise with the parameters no matter the state the allocator was in.
+ ///
+ /// This can be used to let the [`GenericMemoryAllocator`] know that allocating a new block of
+ /// [`DeviceMemory`] and trying to suballocate it with the same parameters would not solve the
+ /// issue.
+ ///
+ /// [`GenericMemoryAllocator`]: super::GenericMemoryAllocator
+ BlockSizeExceeded,
+}
+
+impl Error for SuballocationCreationError {}
+
+impl Display for SuballocationCreationError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(
+ f,
+ "{}",
+ match self {
+ Self::OutOfRegionMemory => "out of region memory",
+ Self::FragmentedRegion => "the region is too fragmented",
+ Self::BlockSizeExceeded =>
+ "the allocation size was greater than the suballocator's block size",
+ }
+ )
+ }
+}
+
+/// A [suballocator] that uses the most generic [free-list].
+///
+/// The strength of this allocator is that it can create and free allocations completely
+/// dynamically, which means they can be any size and created/freed in any order. The downside is
+/// that this always leads to horrific [external fragmentation] the more such dynamic allocations
+/// are made. Therefore, this allocator is best suited for long-lived allocations. If you need
+/// to create allocations of various sizes, but can't afford this fragmentation, then the
+/// [`BuddyAllocator`] is your best buddy. If you need to create allocations which share a similar
+/// size, consider the [`PoolAllocator`]. Lastly, if you need to allocate very often, then
+/// [`BumpAllocator`] is best suited.
+///
+/// See also [the `Suballocator` implementation].
+///
+/// # Algorithm
+///
+/// The free-list stores suballocations which can have any offset and size. When an allocation
+/// request is made, the list is searched using the best-fit strategy, meaning that the smallest
+/// suballocation that fits the request is chosen. If required, the chosen suballocation is trimmed
+/// at the ends and the ends are returned to the free-list. As such, no [internal fragmentation]
+/// occurs. The front might need to be trimmed because of [alignment requirements] and the end
+/// because of a larger than required size. When an allocation is freed, the allocator checks if
+/// the adjacent suballocations are free, and if so it coalesces them into a bigger one before
+/// putting it in the free-list.
+///
+/// # Efficiency
+///
+/// The allocator is synchronized internally with a lock, which is held only for a very short
+/// period each time an allocation is created and freed. The free-list is sorted by size, which
+/// means that when allocating, finding a best-fit is always possible in *O*(log(*n*)) time in the
+/// worst case. When freeing, the coalescing requires us to remove the adjacent free suballocations
+/// from the free-list which is *O*(log(*n*)), and insert the possibly coalesced suballocation into
+/// the free-list which has the same time complexity, so in total freeing is *O*(log(*n*)).
+///
+/// There is one notable edge-case: after the allocator finds a best-fit, it is possible that it
+/// needs to align the suballocation's offset to a higher value, after which the requested size
+/// might no longer fit. In such a case, the next free suballocation in sorted order is tried until
+/// a fit is successful. If this issue is encountered with all candidates, then the time complexity
+/// would be *O*(*n*). However, this scenario is extremely unlikely which is why we are not
+/// considering it in the above analysis. Additionally, if your free-list is filled with
+/// allocations that all have the same size then that seems pretty sus. Sounds like you're in dire
+/// need of a `PoolAllocator`.
+///
+/// # Examples
+///
+/// Most commonly you will not want to use this suballocator directly but rather use it within
+/// [`GenericMemoryAllocator`], having one global [`StandardMemoryAllocator`] for most if not all
+/// of your allocation needs.
+///
+/// Basic usage as a global allocator for long-lived resources:
+///
+/// ```
+/// use vulkano::format::Format;
+/// use vulkano::image::{ImageDimensions, ImmutableImage};
+/// use vulkano::memory::allocator::StandardMemoryAllocator;
+/// # let device: std::sync::Arc<vulkano::device::Device> = return;
+///
+/// let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
+///
+/// # fn read_textures() -> Vec<Vec<u8>> { Vec::new() }
+/// # let mut command_buffer_builder: vulkano::command_buffer::AutoCommandBufferBuilder<vulkano::command_buffer::PrimaryAutoCommandBuffer<vulkano::command_buffer::allocator::StandardCommandBufferAlloc>> = return;
+/// // Allocate some resources.
+/// let textures_data: Vec<Vec<u8>> = read_textures();
+/// let textures = textures_data.into_iter().map(|data| {
+/// ImmutableImage::from_iter(
+/// &memory_allocator,
+/// data,
+/// ImageDimensions::Dim2d {
+/// width: 1024,
+/// height: 1024,
+/// array_layers: 1,
+/// },
+/// 1.into(),
+/// Format::R8G8B8A8_UNORM,
+/// &mut command_buffer_builder,
+/// )
+/// .unwrap()
+/// });
+/// ```
+///
+/// For use in allocating arenas for [`SubbufferAllocator`]:
+///
+/// ```
+/// use std::sync::Arc;
+/// use vulkano::buffer::allocator::SubbufferAllocator;
+/// use vulkano::memory::allocator::StandardMemoryAllocator;
+/// # let device: std::sync::Arc<vulkano::device::Device> = return;
+///
+/// // We need to wrap the allocator in an `Arc` so that we can share ownership of it.
+/// let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device.clone()));
+/// let buffer_allocator = SubbufferAllocator::new(memory_allocator.clone(), Default::default());
+///
+/// // You can continue using `memory_allocator` for other things.
+/// ```
+///
+/// Sometimes, it is neccessary to suballocate an allocation. If you don't want to allocate new
+/// [`DeviceMemory`] blocks to suballocate, perhaps because of concerns of memory wastage or
+/// allocation efficiency, you can use your existing global `StandardMemoryAllocator` to allocate
+/// regions for your suballocation needs:
+///
+/// ```
+/// use vulkano::memory::allocator::{
+/// DeviceLayout, MemoryAllocator, StandardMemoryAllocator, SuballocationCreateInfo,
+/// };
+///
+/// # let device: std::sync::Arc<vulkano::device::Device> = return;
+/// let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
+///
+/// # let memory_type_index = 0;
+/// let region = memory_allocator.allocate_from_type(
+/// // When choosing the index, you have to make sure that the memory type is allowed for the
+/// // type of resource that you want to bind the suballocations to.
+/// memory_type_index,
+/// SuballocationCreateInfo {
+/// layout: DeviceLayout::from_size_alignment(
+/// // This will be the size of your region.
+/// 16 * 1024 * 1024,
+/// // It generally does not matter what the alignment is, because you're going to
+/// // suballocate the allocation anyway, and not bind it directly.
+/// 1,
+/// )
+/// .unwrap(),
+/// ..Default::default()
+/// },
+/// )
+/// .unwrap();
+///
+/// // You can now feed the `region` into any suballocator.
+/// ```
+///
+/// [suballocator]: Suballocator
+/// [free-list]: Suballocator#free-lists
+/// [external fragmentation]: super#external-fragmentation
+/// [the `Suballocator` implementation]: Suballocator#impl-Suballocator-for-Arc<FreeListAllocator>
+/// [internal fragmentation]: super#internal-fragmentation
+/// [alignment requirements]: super#alignment
+/// [`GenericMemoryAllocator`]: super::GenericMemoryAllocator
+/// [`StandardMemoryAllocator`]: super::StandardMemoryAllocator
+/// [`SubbufferAllocator`]: crate::buffer::allocator::SubbufferAllocator
+#[derive(Debug)]
+pub struct FreeListAllocator {
+ region: MemoryAlloc,
+ device_memory: Arc<DeviceMemory>,
+ buffer_image_granularity: DeviceAlignment,
+ atom_size: DeviceAlignment,
+ // Total memory remaining in the region.
+ free_size: AtomicU64,
+ state: Mutex<FreeListAllocatorState>,
+}
+
+impl FreeListAllocator {
+ /// Creates a new `FreeListAllocator` for the given [region].
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `region.allocation_type` is not [`AllocationType::Unknown`]. This is done to
+ /// avoid checking for a special case of [buffer-image granularity] conflict.
+ /// - Panics if `region` is a [dedicated allocation].
+ ///
+ /// [region]: Suballocator#regions
+ /// [buffer-image granularity]: super#buffer-image-granularity
+ /// [dedicated allocation]: MemoryAlloc::is_dedicated
+ pub fn new(region: MemoryAlloc) -> Arc<Self> {
+ // NOTE(Marc): This number was pulled straight out of my a-
+ const AVERAGE_ALLOCATION_SIZE: DeviceSize = 64 * 1024;
+
+ assert!(region.allocation_type == AllocationType::Unknown);
+
+ let device_memory = region
+ .root()
+ .expect("dedicated allocations can't be suballocated")
+ .clone();
+ let buffer_image_granularity = device_memory
+ .device()
+ .physical_device()
+ .properties()
+ .buffer_image_granularity;
+
+ let atom_size = region.atom_size.unwrap_or(DeviceAlignment::MIN);
+ let free_size = AtomicU64::new(region.size);
+
+ let capacity = (region.size / AVERAGE_ALLOCATION_SIZE) as usize;
+ let mut nodes = host::PoolAllocator::new(capacity + 64);
+ let mut free_list = Vec::with_capacity(capacity / 16 + 16);
+ let root_id = nodes.allocate(SuballocationListNode {
+ prev: None,
+ next: None,
+ offset: region.offset,
+ size: region.size,
+ ty: SuballocationType::Free,
+ });
+ free_list.push(root_id);
+ let state = Mutex::new(FreeListAllocatorState { nodes, free_list });
+
+ Arc::new(FreeListAllocator {
+ region,
+ device_memory,
+ buffer_image_granularity,
+ atom_size,
+ free_size,
+ state,
+ })
+ }
+
+ /// # Safety
+ ///
+ /// - `node_id` must refer to an occupied suballocation allocated by `self`.
+ unsafe fn free(&self, node_id: SlotId) {
+ let mut state = self.state.lock();
+ let node = state.nodes.get_mut(node_id);
+
+ debug_assert!(node.ty != SuballocationType::Free);
+
+ // Suballocation sizes are constrained by the size of the region, so they can't possibly
+ // overflow when added up.
+ self.free_size.fetch_add(node.size, Ordering::Release);
+
+ node.ty = SuballocationType::Free;
+ state.coalesce(node_id);
+ state.free(node_id);
+ }
+}
+
+unsafe impl Suballocator for Arc<FreeListAllocator> {
+ const IS_BLOCKING: bool = true;
+
+ const NEEDS_CLEANUP: bool = false;
+
+ #[inline]
+ fn new(region: MemoryAlloc) -> Self {
+ FreeListAllocator::new(region)
+ }
+
+ /// Creates a new suballocation within the [region].
+ ///
+ /// # Errors
+ ///
+ /// - Returns [`OutOfRegionMemory`] if there are no free suballocations large enough so satisfy
+ /// the request.
+ /// - Returns [`FragmentedRegion`] if a suballocation large enough to satisfy the request could
+ /// have been formed, but wasn't because of [external fragmentation].
+ ///
+ /// [region]: Suballocator#regions
+ /// [`allocate`]: Suballocator::allocate
+ /// [`OutOfRegionMemory`]: SuballocationCreationError::OutOfRegionMemory
+ /// [`FragmentedRegion`]: SuballocationCreationError::FragmentedRegion
+ /// [external fragmentation]: super#external-fragmentation
+ #[inline]
+ fn allocate(
+ &self,
+ create_info: SuballocationCreateInfo,
+ ) -> Result<MemoryAlloc, SuballocationCreationError> {
+ fn has_granularity_conflict(prev_ty: SuballocationType, ty: AllocationType) -> bool {
+ if prev_ty == SuballocationType::Free {
+ false
+ } else if prev_ty == SuballocationType::Unknown {
+ true
+ } else {
+ prev_ty != ty.into()
+ }
+ }
+
+ let SuballocationCreateInfo {
+ layout,
+ allocation_type,
+ _ne: _,
+ } = create_info;
+
+ let size = layout.size();
+ let alignment = cmp::max(layout.alignment(), self.atom_size);
+ let mut state = self.state.lock();
+
+ unsafe {
+ match state.free_list.last() {
+ Some(&last) if state.nodes.get(last).size >= size => {
+ let index = match state
+ .free_list
+ .binary_search_by_key(&size, |&id| state.nodes.get(id).size)
+ {
+ // Exact fit.
+ Ok(index) => index,
+ // Next-best fit. Note that `index == free_list.len()` can't be because we
+ // checked that the free-list contains a suballocation that is big enough.
+ Err(index) => index,
+ };
+
+ for (index, &id) in state.free_list.iter().enumerate().skip(index) {
+ let suballoc = state.nodes.get(id);
+
+ // This can't overflow because suballocation offsets are constrained by
+ // the size of the root allocation, which can itself not exceed
+ // `DeviceLayout::MAX_SIZE`.
+ let mut offset = align_up(suballoc.offset, alignment);
+
+ if let Some(prev_id) = suballoc.prev {
+ let prev = state.nodes.get(prev_id);
+
+ if are_blocks_on_same_page(
+ prev.offset,
+ prev.size,
+ offset,
+ self.buffer_image_granularity,
+ ) && has_granularity_conflict(prev.ty, allocation_type)
+ {
+ // This is overflow-safe for the same reason as above.
+ offset = align_up(offset, self.buffer_image_granularity);
+ }
+ }
+
+ if offset + size <= suballoc.offset + suballoc.size {
+ state.free_list.remove(index);
+
+ // SAFETY:
+ // - `suballoc` is free.
+ // - `offset` is that of `suballoc`, possibly rounded up.
+ // - We checked that `offset + size` falls within `suballoc`.
+ state.split(id, offset, size);
+ state.nodes.get_mut(id).ty = allocation_type.into();
+
+ // This can't overflow because suballocation sizes in the free-list are
+ // constrained by the remaining size of the region.
+ self.free_size.fetch_sub(size, Ordering::Release);
+
+ let mapped_ptr = self.region.mapped_ptr.map(|ptr| {
+ // This can't overflow because offsets in the free-list are confined
+ // to the range [region.offset, region.offset + region.size).
+ let relative_offset = offset - self.region.offset;
+
+ // SAFETY: Allocation sizes are guaranteed to not exceed
+ // `isize::MAX` when they have a mapped pointer, and the original
+ // pointer was handed to us from the Vulkan implementation,
+ // so the offset better be in range.
+ let ptr = ptr.as_ptr().offset(relative_offset as isize);
+
+ // SAFETY: Same as the previous.
+ NonNull::new_unchecked(ptr)
+ });
+
+ return Ok(MemoryAlloc {
+ offset,
+ size,
+ allocation_type,
+ mapped_ptr,
+ atom_size: self.region.atom_size,
+ parent: AllocParent::FreeList {
+ allocator: self.clone(),
+ id,
+ },
+ });
+ }
+ }
+
+ // There is not enough space due to alignment requirements.
+ Err(SuballocationCreationError::OutOfRegionMemory)
+ }
+ // There would be enough space if the region wasn't so fragmented. :(
+ Some(_) if self.free_size() >= size => {
+ Err(SuballocationCreationError::FragmentedRegion)
+ }
+ // There is not enough space.
+ Some(_) => Err(SuballocationCreationError::OutOfRegionMemory),
+ // There is no space at all.
+ None => Err(SuballocationCreationError::OutOfRegionMemory),
+ }
+ }
+ }
+
+ #[inline]
+ fn region(&self) -> &MemoryAlloc {
+ &self.region
+ }
+
+ #[inline]
+ fn try_into_region(self) -> Result<MemoryAlloc, Self> {
+ Arc::try_unwrap(self).map(|allocator| allocator.region)
+ }
+
+ #[inline]
+ fn free_size(&self) -> DeviceSize {
+ self.free_size.load(Ordering::Acquire)
+ }
+
+ #[inline]
+ fn cleanup(&mut self) {}
+}
+
+unsafe impl DeviceOwned for FreeListAllocator {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ self.device_memory.device()
+ }
+}
+
+#[derive(Debug)]
+struct FreeListAllocatorState {
+ nodes: host::PoolAllocator<SuballocationListNode>,
+ // Free suballocations sorted by size in ascending order. This means we can always find a
+ // best-fit in *O*(log(*n*)) time in the worst case, and iterating in order is very efficient.
+ free_list: Vec<SlotId>,
+}
+
+#[derive(Clone, Copy, Debug)]
+struct SuballocationListNode {
+ prev: Option<SlotId>,
+ next: Option<SlotId>,
+ offset: DeviceSize,
+ size: DeviceSize,
+ ty: SuballocationType,
+}
+
+/// Tells us if a suballocation is free, and if not, whether it is linear or not. This is needed in
+/// order to be able to respect the buffer-image granularity.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+enum SuballocationType {
+ Unknown,
+ Linear,
+ NonLinear,
+ Free,
+}
+
+impl From<AllocationType> for SuballocationType {
+ fn from(ty: AllocationType) -> Self {
+ match ty {
+ AllocationType::Unknown => SuballocationType::Unknown,
+ AllocationType::Linear => SuballocationType::Linear,
+ AllocationType::NonLinear => SuballocationType::NonLinear,
+ }
+ }
+}
+
+impl FreeListAllocatorState {
+ /// Removes the target suballocation from the free-list.
+ ///
+ /// # Safety
+ ///
+ /// - `node_id` must have been allocated by `self`.
+ /// - `node_id` must be in the free-list.
+ unsafe fn allocate(&mut self, node_id: SlotId) {
+ debug_assert!(self.free_list.contains(&node_id));
+
+ let node = self.nodes.get(node_id);
+
+ match self
+ .free_list
+ .binary_search_by_key(&node.size, |&id| self.nodes.get(id).size)
+ {
+ Ok(index) => {
+ // If there are multiple free suballocations with the same size, the search might
+ // have returned any one, so we need to find the one corresponding to the target ID.
+ if self.free_list[index] == node_id {
+ self.free_list.remove(index);
+ return;
+ }
+
+ // Check all previous indices that point to suballocations with the same size.
+ {
+ let mut index = index;
+ loop {
+ index = index.wrapping_sub(1);
+ if let Some(&id) = self.free_list.get(index) {
+ if id == node_id {
+ self.free_list.remove(index);
+ return;
+ }
+ if self.nodes.get(id).size != node.size {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ }
+
+ // Check all next indices that point to suballocations with the same size.
+ {
+ let mut index = index;
+ loop {
+ index += 1;
+ if let Some(&id) = self.free_list.get(index) {
+ if id == node_id {
+ self.free_list.remove(index);
+ return;
+ }
+ if self.nodes.get(id).size != node.size {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ }
+
+ unreachable!();
+ }
+ Err(_) => unreachable!(),
+ }
+ }
+
+ /// Fits a suballocation inside the target one, splitting the target at the ends if required.
+ ///
+ /// # Safety
+ ///
+ /// - `node_id` must have been allocated by `self`.
+ /// - `node_id` must refer to a free suballocation.
+ /// - `offset` and `size` must refer to a subregion of the given suballocation.
+ unsafe fn split(&mut self, node_id: SlotId, offset: DeviceSize, size: DeviceSize) {
+ let node = self.nodes.get(node_id);
+
+ debug_assert!(node.ty == SuballocationType::Free);
+ debug_assert!(offset >= node.offset);
+ debug_assert!(offset + size <= node.offset + node.size);
+
+ // These are guaranteed to not overflow because the caller must uphold that the given
+ // region is contained within that of `node`.
+ let padding_front = offset - node.offset;
+ let padding_back = node.offset + node.size - offset - size;
+
+ if padding_front > 0 {
+ let padding = SuballocationListNode {
+ prev: node.prev,
+ next: Some(node_id),
+ offset: node.offset,
+ size: padding_front,
+ ty: SuballocationType::Free,
+ };
+ let padding_id = self.nodes.allocate(padding);
+
+ if let Some(prev_id) = padding.prev {
+ self.nodes.get_mut(prev_id).next = Some(padding_id);
+ }
+
+ let node = self.nodes.get_mut(node_id);
+ node.prev = Some(padding_id);
+ node.offset = offset;
+ // The caller must uphold that the given region is contained within that of `node`, and
+ // it follows that if there is padding, the size of the node must be larger than that
+ // of the padding, so this can't overflow.
+ node.size -= padding.size;
+
+ self.free(padding_id);
+ }
+
+ if padding_back > 0 {
+ let padding = SuballocationListNode {
+ prev: Some(node_id),
+ next: node.next,
+ offset: offset + size,
+ size: padding_back,
+ ty: SuballocationType::Free,
+ };
+ let padding_id = self.nodes.allocate(padding);
+
+ if let Some(next_id) = padding.next {
+ self.nodes.get_mut(next_id).prev = Some(padding_id);
+ }
+
+ let node = self.nodes.get_mut(node_id);
+ node.next = Some(padding_id);
+ // This is overflow-safe for the same reason as above.
+ node.size -= padding.size;
+
+ self.free(padding_id);
+ }
+ }
+
+ /// Inserts the target suballocation into the free-list.
+ ///
+ /// # Safety
+ ///
+ /// - `node_id` must have been allocated by `self`.
+ /// - The free-list must not contain the given suballocation already, as that would constitude
+ /// a double-free.
+ unsafe fn free(&mut self, node_id: SlotId) {
+ debug_assert!(!self.free_list.contains(&node_id));
+
+ let node = self.nodes.get(node_id);
+ let (Ok(index) | Err(index)) = self
+ .free_list
+ .binary_search_by_key(&node.size, |&id| self.nodes.get(id).size);
+ self.free_list.insert(index, node_id);
+ }
+
+ /// Coalesces the target (free) suballocation with adjacent ones that are also free.
+ ///
+ /// # Safety
+ ///
+ /// - `node_id` must have been allocated by `self`.
+ /// - `node_id` must refer to a free suballocation.
+ unsafe fn coalesce(&mut self, node_id: SlotId) {
+ let node = self.nodes.get(node_id);
+
+ debug_assert!(node.ty == SuballocationType::Free);
+
+ if let Some(prev_id) = node.prev {
+ let prev = self.nodes.get(prev_id);
+
+ if prev.ty == SuballocationType::Free {
+ // SAFETY: We checked that the suballocation is free.
+ self.allocate(prev_id);
+
+ let node = self.nodes.get_mut(node_id);
+ node.prev = prev.prev;
+ node.offset = prev.offset;
+ // The sizes of suballocations are constrained by that of the parent allocation, so
+ // they can't possibly overflow when added up.
+ node.size += prev.size;
+
+ if let Some(prev_id) = node.prev {
+ self.nodes.get_mut(prev_id).next = Some(node_id);
+ }
+
+ // SAFETY:
+ // - The suballocation is free.
+ // - The suballocation was removed from the free-list.
+ // - The next suballocation and possibly a previous suballocation have been updated
+ // such that they no longer reference the suballocation.
+ // All of these conditions combined guarantee that `prev_id` can not be used again.
+ self.nodes.free(prev_id);
+ }
+ }
+
+ if let Some(next_id) = node.next {
+ let next = self.nodes.get(next_id);
+
+ if next.ty == SuballocationType::Free {
+ // SAFETY: Same as above.
+ self.allocate(next_id);
+
+ let node = self.nodes.get_mut(node_id);
+ node.next = next.next;
+ // This is overflow-safe for the same reason as above.
+ node.size += next.size;
+
+ if let Some(next_id) = node.next {
+ self.nodes.get_mut(next_id).prev = Some(node_id);
+ }
+
+ // SAFETY: Same as above.
+ self.nodes.free(next_id);
+ }
+ }
+ }
+}
+
+/// A [suballocator] whose structure forms a binary tree of power-of-two-sized suballocations.
+///
+/// That is, all allocation sizes are rounded up to the next power of two. This helps reduce
+/// [external fragmentation] by a lot, at the expense of possibly severe [internal fragmentation]
+/// if you're not careful. For example, if you needed an allocation size of 64MiB, you would be
+/// wasting no memory. But with an allocation size of 70MiB, you would use a whole 128MiB instead,
+/// wasting 45% of the memory. Use this algorithm if you need to create and free a lot of
+/// allocations, which would cause too much external fragmentation when using
+/// [`FreeListAllocator`]. However, if the sizes of your allocations are more or less the same,
+/// then the [`PoolAllocator`] would be a better choice and would eliminate external fragmentation
+/// completely.
+///
+/// See also [the `Suballocator` implementation].
+///
+/// # Algorithm
+///
+/// Say you have a [region] of size 256MiB, and you want to allocate 14MiB. Assuming there are no
+/// existing allocations, the `BuddyAllocator` would split the 256MiB root *node* into two 128MiB
+/// nodes. These two nodes are called *buddies*. The allocator would then proceed to split the left
+/// node recursively until it wouldn't be able to fit the allocation anymore. In this example, that
+/// would happen after 4 splits and end up with a node size of 16MiB. Since the allocation
+/// requested was 14MiB, 2MiB would become internal fragmentation and be unusable for the lifetime
+/// of the allocation. When an allocation is freed, this process is done backwards, checking if the
+/// buddy of each node on the way up is free and if so they are coalesced.
+///
+/// Each possible node size has an *order*, with the smallest node size being of order 0 and the
+/// largest of the highest order. With this notion, node sizes are proportional to 2<sup>*n*</sup>
+/// where *n* is the order. The highest order is determined from the size of the region and a
+/// constant minimum node size, which we chose to be 16B: log(*region&nbsp;size*&nbsp;/&nbsp;16) or
+/// equiavalently log(*region&nbsp;size*)&nbsp;-&nbsp;4 (assuming
+/// *region&nbsp;size*&nbsp;&ge;&nbsp;16).
+///
+/// It's safe to say that this algorithm works best if you have some level of control over your
+/// allocation sizes, so that you don't end up allocating twice as much memory. An example of this
+/// would be when you need to allocate regions for other allocators, such as the `PoolAllocator` or
+/// the [`BumpAllocator`].
+///
+/// # Efficiency
+///
+/// The allocator is synchronized internally with a lock, which is held only for a very short
+/// period each time an allocation is created and freed. The time complexity of both allocation and
+/// freeing is *O*(*m*) in the worst case where *m* is the highest order, which equates to *O*(log
+/// (*n*)) where *n* is the size of the region.
+///
+/// # Examples
+///
+/// Basic usage together with [`GenericMemoryAllocator`], to allocate resources that have a
+/// moderately low life span (for example if you have a lot of images, each of which needs to be
+/// resized every now and then):
+///
+/// ```
+/// use std::sync::Arc;
+/// use vulkano::memory::allocator::{
+/// BuddyAllocator, GenericMemoryAllocator, GenericMemoryAllocatorCreateInfo,
+/// };
+///
+/// # let device: std::sync::Arc<vulkano::device::Device> = return;
+/// let memory_allocator = GenericMemoryAllocator::<Arc<BuddyAllocator>>::new(
+/// device.clone(),
+/// GenericMemoryAllocatorCreateInfo {
+/// // Your block sizes must be powers of two, because `BuddyAllocator` only accepts
+/// // power-of-two-sized regions.
+/// block_sizes: &[(0, 64 * 1024 * 1024)],
+/// ..Default::default()
+/// },
+/// )
+/// .unwrap();
+///
+/// // Now you can use `memory_allocator` to allocate whatever it is you need.
+/// ```
+///
+/// [suballocator]: Suballocator
+/// [internal fragmentation]: super#internal-fragmentation
+/// [external fragmentation]: super#external-fragmentation
+/// [the `Suballocator` implementation]: Suballocator#impl-Suballocator-for-Arc<BuddyAllocator>
+/// [region]: Suballocator#regions
+/// [`GenericMemoryAllocator`]: super::GenericMemoryAllocator
+#[derive(Debug)]
+pub struct BuddyAllocator {
+ region: MemoryAlloc,
+ device_memory: Arc<DeviceMemory>,
+ buffer_image_granularity: DeviceAlignment,
+ atom_size: DeviceAlignment,
+ // Total memory remaining in the region.
+ free_size: AtomicU64,
+ state: Mutex<BuddyAllocatorState>,
+}
+
+impl BuddyAllocator {
+ const MIN_NODE_SIZE: DeviceSize = 16;
+
+ /// Arbitrary maximum number of orders, used to avoid a 2D `Vec`. Together with a minimum node
+ /// size of 16, this is enough for a 64GiB region.
+ const MAX_ORDERS: usize = 32;
+
+ /// Creates a new `BuddyAllocator` for the given [region].
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `region.allocation_type` is not [`AllocationType::Unknown`]. This is done to
+ /// avoid checking for a special case of [buffer-image granularity] conflict.
+ /// - Panics if `region.size` is not a power of two.
+ /// - Panics if `region.size` is not in the range \[16B,&nbsp;64GiB\].
+ /// - Panics if `region` is a [dedicated allocation].
+ ///
+ /// [region]: Suballocator#regions
+ /// [buffer-image granularity]: super#buffer-image-granularity
+ /// [dedicated allocation]: MemoryAlloc::is_dedicated
+ #[inline]
+ pub fn new(region: MemoryAlloc) -> Arc<Self> {
+ const EMPTY_FREE_LIST: Vec<DeviceSize> = Vec::new();
+
+ assert!(region.allocation_type == AllocationType::Unknown);
+ assert!(region.size.is_power_of_two());
+ assert!(region.size >= BuddyAllocator::MIN_NODE_SIZE);
+
+ let max_order = (region.size / BuddyAllocator::MIN_NODE_SIZE).trailing_zeros() as usize;
+
+ assert!(max_order < BuddyAllocator::MAX_ORDERS);
+
+ let device_memory = region
+ .root()
+ .expect("dedicated allocations can't be suballocated")
+ .clone();
+ let buffer_image_granularity = device_memory
+ .device()
+ .physical_device()
+ .properties()
+ .buffer_image_granularity;
+ let atom_size = region.atom_size.unwrap_or(DeviceAlignment::MIN);
+ let free_size = AtomicU64::new(region.size);
+
+ let mut free_list =
+ ArrayVec::new(max_order + 1, [EMPTY_FREE_LIST; BuddyAllocator::MAX_ORDERS]);
+ // The root node has the lowest offset and highest order, so it's the whole region.
+ free_list[max_order].push(region.offset);
+ let state = Mutex::new(BuddyAllocatorState { free_list });
+
+ Arc::new(BuddyAllocator {
+ region,
+ device_memory,
+ buffer_image_granularity,
+ atom_size,
+ free_size,
+ state,
+ })
+ }
+
+ /// # Safety
+ ///
+ /// - `order` and `offset` must refer to an occupied suballocation allocated by `self`.
+ unsafe fn free(&self, order: usize, mut offset: DeviceSize) {
+ let min_order = order;
+ let mut state = self.state.lock();
+
+ debug_assert!(!state.free_list[order].contains(&offset));
+
+ // Try to coalesce nodes while incrementing the order.
+ for (order, free_list) in state.free_list.iter_mut().enumerate().skip(min_order) {
+ // This can't discard any bits because `order` is confined to the range
+ // [0, log(region.size / BuddyAllocator::MIN_NODE_SIZE)].
+ let size = BuddyAllocator::MIN_NODE_SIZE << order;
+
+ // This can't overflow because the offsets in the free-list are confined to the range
+ // [region.offset, region.offset + region.size).
+ let buddy_offset = ((offset - self.region.offset) ^ size) + self.region.offset;
+
+ match free_list.binary_search(&buddy_offset) {
+ // If the buddy is in the free-list, we can coalesce.
+ Ok(index) => {
+ free_list.remove(index);
+ offset = cmp::min(offset, buddy_offset);
+ }
+ // Otherwise free the node.
+ Err(_) => {
+ let (Ok(index) | Err(index)) = free_list.binary_search(&offset);
+ free_list.insert(index, offset);
+
+ // This can't discard any bits for the same reason as above.
+ let size = BuddyAllocator::MIN_NODE_SIZE << min_order;
+
+ // The sizes of suballocations allocated by `self` are constrained by that of
+ // its region, so they can't possibly overflow when added up.
+ self.free_size.fetch_add(size, Ordering::Release);
+
+ break;
+ }
+ }
+ }
+ }
+}
+
+unsafe impl Suballocator for Arc<BuddyAllocator> {
+ const IS_BLOCKING: bool = true;
+
+ const NEEDS_CLEANUP: bool = false;
+
+ #[inline]
+ fn new(region: MemoryAlloc) -> Self {
+ BuddyAllocator::new(region)
+ }
+
+ /// Creates a new suballocation within the [region].
+ ///
+ /// # Errors
+ ///
+ /// - Returns [`OutOfRegionMemory`] if there are no free nodes large enough so satisfy the
+ /// request.
+ /// - Returns [`FragmentedRegion`] if a node large enough to satisfy the request could have
+ /// been formed, but wasn't because of [external fragmentation].
+ ///
+ /// [region]: Suballocator#regions
+ /// [`allocate`]: Suballocator::allocate
+ /// [`OutOfRegionMemory`]: SuballocationCreationError::OutOfRegionMemory
+ /// [`FragmentedRegion`]: SuballocationCreationError::FragmentedRegion
+ /// [external fragmentation]: super#external-fragmentation
+ #[inline]
+ fn allocate(
+ &self,
+ create_info: SuballocationCreateInfo,
+ ) -> Result<MemoryAlloc, SuballocationCreationError> {
+ /// Returns the largest power of two smaller or equal to the input, or zero if the input is
+ /// zero.
+ fn prev_power_of_two(val: DeviceSize) -> DeviceSize {
+ const MAX_POWER_OF_TWO: DeviceSize = DeviceAlignment::MAX.as_devicesize();
+
+ if let Some(val) = NonZeroDeviceSize::new(val) {
+ // This can't overflow because `val` is non-zero, which means it has fewer leading
+ // zeroes than the total number of bits.
+ MAX_POWER_OF_TWO >> val.leading_zeros()
+ } else {
+ 0
+ }
+ }
+
+ let SuballocationCreateInfo {
+ layout,
+ allocation_type,
+ _ne: _,
+ } = create_info;
+
+ let mut size = layout.size();
+ let mut alignment = cmp::max(layout.alignment(), self.atom_size);
+
+ if allocation_type == AllocationType::Unknown
+ || allocation_type == AllocationType::NonLinear
+ {
+ // This can't overflow because `DeviceLayout` guarantees that `size` doesn't exceed
+ // `DeviceLayout::MAX_SIZE`.
+ size = align_up(size, self.buffer_image_granularity);
+ alignment = cmp::max(alignment, self.buffer_image_granularity);
+ }
+
+ // `DeviceLayout` guarantees that its size does not exceed `DeviceLayout::MAX_SIZE`,
+ // which means it can't overflow when rounded up to the next power of two.
+ let size = cmp::max(size, BuddyAllocator::MIN_NODE_SIZE).next_power_of_two();
+
+ let min_order = (size / BuddyAllocator::MIN_NODE_SIZE).trailing_zeros() as usize;
+ let mut state = self.state.lock();
+
+ // Start searching at the lowest possible order going up.
+ for (order, free_list) in state.free_list.iter_mut().enumerate().skip(min_order) {
+ for (index, &offset) in free_list.iter().enumerate() {
+ if is_aligned(offset, alignment) {
+ free_list.remove(index);
+
+ // Go in the opposite direction, splitting nodes from higher orders. The lowest
+ // order doesn't need any splitting.
+ for (order, free_list) in state
+ .free_list
+ .iter_mut()
+ .enumerate()
+ .skip(min_order)
+ .take(order - min_order)
+ .rev()
+ {
+ // This can't discard any bits because `order` is confined to the range
+ // [0, log(region.size / BuddyAllocator::MIN_NODE_SIZE)].
+ let size = BuddyAllocator::MIN_NODE_SIZE << order;
+
+ // This can't overflow because offsets are confined to the size of the root
+ // allocation, which can itself not exceed `DeviceLayout::MAX_SIZE`.
+ let right_child = offset + size;
+
+ // Insert the right child in sorted order.
+ let (Ok(index) | Err(index)) = free_list.binary_search(&right_child);
+ free_list.insert(index, right_child);
+
+ // Repeat splitting for the left child if required in the next loop turn.
+ }
+
+ // This can't overflow because suballocation sizes in the free-list are
+ // constrained by the remaining size of the region.
+ self.free_size.fetch_sub(size, Ordering::Release);
+
+ let mapped_ptr = self.region.mapped_ptr.map(|ptr| {
+ // This can't overflow because offsets in the free-list are confined to the
+ // range [region.offset, region.offset + region.size).
+ let relative_offset = offset - self.region.offset;
+
+ // SAFETY: Allocation sizes are guaranteed to not exceed `isize::MAX` when
+ // they have a mapped pointer, and the original pointer was handed to us
+ // from the Vulkan implementation, so the offset better be in range.
+ let ptr = unsafe { ptr.as_ptr().offset(relative_offset as isize) };
+
+ // SAFETY: Same as the previous.
+ unsafe { NonNull::new_unchecked(ptr) }
+ });
+
+ return Ok(MemoryAlloc {
+ offset,
+ size: layout.size(),
+ allocation_type,
+ mapped_ptr,
+ atom_size: self.region.atom_size,
+ parent: AllocParent::Buddy {
+ allocator: self.clone(),
+ order: min_order,
+ offset, // The offset in the alloc itself can change.
+ },
+ });
+ }
+ }
+ }
+
+ if prev_power_of_two(self.free_size()) >= layout.size() {
+ // A node large enough could be formed if the region wasn't so fragmented.
+ Err(SuballocationCreationError::FragmentedRegion)
+ } else {
+ Err(SuballocationCreationError::OutOfRegionMemory)
+ }
+ }
+
+ #[inline]
+ fn region(&self) -> &MemoryAlloc {
+ &self.region
+ }
+
+ #[inline]
+ fn try_into_region(self) -> Result<MemoryAlloc, Self> {
+ Arc::try_unwrap(self).map(|allocator| allocator.region)
+ }
+
+ /// Returns the total amount of free space left in the [region] that is available to the
+ /// allocator, which means that [internal fragmentation] is excluded.
+ ///
+ /// [region]: Suballocator#regions
+ /// [internal fragmentation]: super#internal-fragmentation
+ #[inline]
+ fn free_size(&self) -> DeviceSize {
+ self.free_size.load(Ordering::Acquire)
+ }
+
+ #[inline]
+ fn cleanup(&mut self) {}
+}
+
+unsafe impl DeviceOwned for BuddyAllocator {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ self.device_memory.device()
+ }
+}
+
+#[derive(Debug)]
+struct BuddyAllocatorState {
+ // Every order has its own free-list for convenience, so that we don't have to traverse a tree.
+ // Each free-list is sorted by offset because we want to find the first-fit as this strategy
+ // minimizes external fragmentation.
+ free_list: ArrayVec<Vec<DeviceSize>, { BuddyAllocator::MAX_ORDERS }>,
+}
+
+/// A [suballocator] using a pool of fixed-size blocks as a [free-list].
+///
+/// Since the size of the blocks is fixed, you can not create allocations bigger than that. You can
+/// create smaller ones, though, which leads to more and more [internal fragmentation] the smaller
+/// the allocations get. This is generally a good trade-off, as internal fragmentation is nowhere
+/// near as hard to deal with as [external fragmentation].
+///
+/// See also [the `Suballocator` implementation].
+///
+/// # Algorithm
+///
+/// The free-list contains indices of blocks in the region that are available, so allocation
+/// consists merely of popping an index from the free-list. The same goes for freeing, all that is
+/// required is to push the index of the block into the free-list. Note that this is only possible
+/// because the blocks have a fixed size. Due to this one fact, the free-list doesn't need to be
+/// sorted or traversed. As long as there is a free block, it will do, no matter which block it is.
+///
+/// Since the `PoolAllocator` doesn't keep a list of suballocations that are currently in use,
+/// resolving [buffer-image granularity] conflicts on a case-by-case basis is not possible.
+/// Therefore, it is an all or nothing situation:
+///
+/// - you use the allocator for only one type of allocation, [`Linear`] or [`NonLinear`], or
+/// - you allow both but align the blocks to the granularity so that no conflics can happen.
+///
+/// The way this is done is that every suballocation inherits the allocation type of the region.
+/// The latter is done by using a region whose allocation type is [`Unknown`]. You are discouraged
+/// from using this type if you can avoid it.
+///
+/// The block size can end up bigger than specified if the allocator is created with a region whose
+/// allocation type is `Unknown`. In that case all blocks are aligned to the buffer-image
+/// granularity, which may or may not cause signifficant memory usage increase. Say for example
+/// your driver reports a granularity of 4KiB. If you need a block size of 8KiB, you would waste no
+/// memory. On the other hand, if you needed a block size of 6KiB, you would be wasting 25% of the
+/// memory. In such a scenario you are highly encouraged to use a different allocation type.
+///
+/// The reverse is also true: with an allocation type other than `Unknown`, not all memory within a
+/// block may be usable depending on the requested [suballocation]. For instance, with a block size
+/// of 1152B (9 * 128B) and a suballocation with `alignment: 256`, a block at an odd index could
+/// not utilize its first 128B, reducing its effective size to 1024B. This is usually only relevant
+/// with small block sizes, as [alignment requirements] are usually rather small, but it completely
+/// depends on the resource and driver.
+///
+/// In summary, the block size you choose has a signifficant impact on internal fragmentation due
+/// to the two reasons described above. You need to choose your block size carefully, *especially*
+/// if you require small allocations. Some rough guidelines:
+///
+/// - Always [align] your blocks to a sufficiently large power of 2. This does **not** mean your
+/// block size must be a power of two. For example with a block size of 3KiB, your blocks would
+/// be aligned to 1KiB.
+/// - Prefer not using the allocation type `Unknown`. You can always create as many
+/// `PoolAllocator`s as you like for different allocation types and sizes, and they can all work
+/// within the same memory block. You should be safe from fragmentation if your blocks are
+/// aligned to 1KiB.
+/// - If you must use the allocation type `Unknown`, then you should be safe from fragmentation on
+/// pretty much any driver if your blocks are aligned to 64KiB. Keep in mind that this might
+/// change any time as new devices appear or new drivers come out. Always look at the properties
+/// of the devices you want to support before relying on any such data.
+///
+/// # Efficiency
+///
+/// In theory, a pool allocator is the ideal one because it causes no external fragmentation, and
+/// both allocation and freeing is *O*(1). It also never needs to lock and hence also lends itself
+/// perfectly to concurrency. But of course, there is the trade-off that block sizes are not
+/// dynamic.
+///
+/// As you can imagine, the `PoolAllocator` is the perfect fit if you know the sizes of the
+/// allocations you will be making, and they are more or less in the same size class. But this
+/// allocation algorithm really shines when combined with others, as most do. For one, nothing is
+/// stopping you from having multiple `PoolAllocator`s for many different size classes. You could
+/// consider a pool of pools, by layering `PoolAllocator` with itself, but this would have the
+/// downside that the regions of the pools for all size classes would have to match. Usually this
+/// is not desired. If you want pools for different size classes to all have about the same number
+/// of blocks, or you even know that some size classes require more or less blocks (because of how
+/// many resources you will be allocating for each), then you need an allocator that can allocate
+/// regions of different sizes. You can use the [`FreeListAllocator`] for this, if external
+/// fragmentation is not an issue, otherwise you might consider using the [`BuddyAllocator`]. On
+/// the other hand, you might also want to consider having a `PoolAllocator` at the top of a
+/// [hierarchy]. Again, this allocator never needs to lock making it *the* perfect fit for a global
+/// concurrent allocator, which hands out large regions which can then be suballocated locally on a
+/// thread, by the [`BumpAllocator`] for example.
+///
+/// # Examples
+///
+/// Basic usage together with [`GenericMemoryAllocator`]:
+///
+/// ```
+/// use std::sync::Arc;
+/// use vulkano::memory::allocator::{
+/// GenericMemoryAllocator, GenericMemoryAllocatorCreateInfo, PoolAllocator,
+/// };
+///
+/// # let device: std::sync::Arc<vulkano::device::Device> = return;
+/// let memory_allocator = GenericMemoryAllocator::<Arc<PoolAllocator<{ 64 * 1024 }>>>::new(
+/// device.clone(),
+/// GenericMemoryAllocatorCreateInfo {
+/// block_sizes: &[(0, 64 * 1024 * 1024)],
+/// ..Default::default()
+/// },
+/// )
+/// .unwrap();
+///
+/// // Now you can use `memory_allocator` to allocate whatever it is you need.
+/// ```
+///
+/// [suballocator]: Suballocator
+/// [free-list]: Suballocator#free-lists
+/// [internal fragmentation]: super#internal-fragmentation
+/// [external fragmentation]: super#external-fragmentation
+/// [the `Suballocator` implementation]: Suballocator#impl-Suballocator-for-Arc<PoolAllocator<BLOCK_SIZE>>
+/// [region]: Suballocator#regions
+/// [buffer-image granularity]: super#buffer-image-granularity
+/// [`Linear`]: AllocationType::Linear
+/// [`NonLinear`]: AllocationType::NonLinear
+/// [`Unknown`]: AllocationType::Unknown
+/// [suballocation]: SuballocationCreateInfo
+/// [alignment requirements]: super#memory-requirements
+/// [align]: super#alignment
+/// [hierarchy]: Suballocator#memory-hierarchies
+/// [`GenericMemoryAllocator`]: super::GenericMemoryAllocator
+#[derive(Debug)]
+#[repr(transparent)]
+pub struct PoolAllocator<const BLOCK_SIZE: DeviceSize> {
+ inner: PoolAllocatorInner,
+}
+
+impl<const BLOCK_SIZE: DeviceSize> PoolAllocator<BLOCK_SIZE> {
+ /// Creates a new `PoolAllocator` for the given [region].
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `region.size < BLOCK_SIZE`.
+ /// - Panics if `region` is a [dedicated allocation].
+ ///
+ /// [region]: Suballocator#regions
+ /// [dedicated allocation]: MemoryAlloc::is_dedicated
+ #[inline]
+ pub fn new(
+ region: MemoryAlloc,
+ #[cfg(test)] buffer_image_granularity: DeviceAlignment,
+ ) -> Arc<Self> {
+ Arc::new(PoolAllocator {
+ inner: PoolAllocatorInner::new(
+ region,
+ BLOCK_SIZE,
+ #[cfg(test)]
+ buffer_image_granularity,
+ ),
+ })
+ }
+
+ /// Size of a block. Can be bigger than `BLOCK_SIZE` due to alignment requirements.
+ #[inline]
+ pub fn block_size(&self) -> DeviceSize {
+ self.inner.block_size
+ }
+
+ /// Total number of blocks available to the allocator. This is always equal to
+ /// `self.region().size() / self.block_size()`.
+ #[inline]
+ pub fn block_count(&self) -> usize {
+ self.inner.free_list.capacity()
+ }
+
+ /// Number of free blocks.
+ #[inline]
+ pub fn free_count(&self) -> usize {
+ self.inner.free_list.len()
+ }
+}
+
+unsafe impl<const BLOCK_SIZE: DeviceSize> Suballocator for Arc<PoolAllocator<BLOCK_SIZE>> {
+ const IS_BLOCKING: bool = false;
+
+ const NEEDS_CLEANUP: bool = false;
+
+ #[inline]
+ fn new(region: MemoryAlloc) -> Self {
+ PoolAllocator::new(
+ region,
+ #[cfg(test)]
+ DeviceAlignment::MIN,
+ )
+ }
+
+ /// Creates a new suballocation within the [region].
+ ///
+ /// > **Note**: `create_info.allocation_type` is silently ignored because all suballocations
+ /// > inherit the allocation type from the region.
+ ///
+ /// # Errors
+ ///
+ /// - Returns [`OutOfRegionMemory`] if the [free-list] is empty.
+ /// - Returns [`OutOfRegionMemory`] if the allocation can't fit inside a block. Only the first
+ /// block in the free-list is tried, which means that if one block isn't usable due to
+ /// [internal fragmentation] but a different one would be, you still get this error. See the
+ /// [type-level documentation] for details on how to properly configure your allocator.
+ /// - Returns [`BlockSizeExceeded`] if `create_info.size` exceeds `BLOCK_SIZE`.
+ ///
+ /// [region]: Suballocator#regions
+ /// [`allocate`]: Suballocator::allocate
+ /// [`OutOfRegionMemory`]: SuballocationCreationError::OutOfRegionMemory
+ /// [free-list]: Suballocator#free-lists
+ /// [internal fragmentation]: super#internal-fragmentation
+ /// [type-level documentation]: PoolAllocator
+ /// [`BlockSizeExceeded`]: SuballocationCreationError::BlockSizeExceeded
+ #[inline]
+ fn allocate(
+ &self,
+ create_info: SuballocationCreateInfo,
+ ) -> Result<MemoryAlloc, SuballocationCreationError> {
+ // SAFETY: `PoolAllocator<BLOCK_SIZE>` and `PoolAllocatorInner` have the same layout.
+ //
+ // This is not quite optimal, because we are always cloning the `Arc` even if allocation
+ // fails, in which case the `Arc` gets cloned and dropped for no reason. Unfortunately,
+ // there is currently no way to turn `&Arc<T>` into `&Arc<U>` that is sound.
+ unsafe { Arc::from_raw(Arc::into_raw(self.clone()).cast::<PoolAllocatorInner>()) }
+ .allocate(create_info)
+ }
+
+ #[inline]
+ fn region(&self) -> &MemoryAlloc {
+ &self.inner.region
+ }
+
+ #[inline]
+ fn try_into_region(self) -> Result<MemoryAlloc, Self> {
+ Arc::try_unwrap(self).map(|allocator| allocator.inner.region)
+ }
+
+ #[inline]
+ fn free_size(&self) -> DeviceSize {
+ self.free_count() as DeviceSize * self.block_size()
+ }
+
+ #[inline]
+ fn cleanup(&mut self) {}
+}
+
+unsafe impl<const BLOCK_SIZE: DeviceSize> DeviceOwned for PoolAllocator<BLOCK_SIZE> {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ self.inner.device_memory.device()
+ }
+}
+
+#[derive(Debug)]
+struct PoolAllocatorInner {
+ region: MemoryAlloc,
+ device_memory: Arc<DeviceMemory>,
+ atom_size: DeviceAlignment,
+ block_size: DeviceSize,
+ // Unsorted list of free block indices.
+ free_list: ArrayQueue<DeviceSize>,
+}
+
+impl PoolAllocatorInner {
+ fn new(
+ region: MemoryAlloc,
+ mut block_size: DeviceSize,
+ #[cfg(test)] buffer_image_granularity: DeviceAlignment,
+ ) -> Self {
+ let device_memory = region
+ .root()
+ .expect("dedicated allocations can't be suballocated")
+ .clone();
+ #[cfg(not(test))]
+ let buffer_image_granularity = device_memory
+ .device()
+ .physical_device()
+ .properties()
+ .buffer_image_granularity;
+ let atom_size = region.atom_size.unwrap_or(DeviceAlignment::MIN);
+ if region.allocation_type == AllocationType::Unknown {
+ block_size = align_up(block_size, buffer_image_granularity);
+ }
+
+ let block_count = region.size / block_size;
+ let free_list = ArrayQueue::new(block_count as usize);
+ for i in 0..block_count {
+ free_list.push(i).unwrap();
+ }
+
+ PoolAllocatorInner {
+ region,
+ device_memory,
+ atom_size,
+ block_size,
+ free_list,
+ }
+ }
+
+ fn allocate(
+ self: Arc<Self>,
+ create_info: SuballocationCreateInfo,
+ ) -> Result<MemoryAlloc, SuballocationCreationError> {
+ let SuballocationCreateInfo {
+ layout,
+ allocation_type: _,
+ _ne: _,
+ } = create_info;
+
+ let size = layout.size();
+ let alignment = cmp::max(layout.alignment(), self.atom_size);
+ let index = self
+ .free_list
+ .pop()
+ .ok_or(SuballocationCreationError::OutOfRegionMemory)?;
+
+ // Indices in the free-list are confined to the range [0, region.size / block_size], so
+ // this can't overflow.
+ let relative_offset = index * self.block_size;
+ // This can't overflow because offsets are confined to the size of the root allocation,
+ // which can itself not exceed `DeviceLayout::MAX_SIZE`.
+ let offset = align_up(self.region.offset + relative_offset, alignment);
+
+ if offset + size > self.region.offset + relative_offset + self.block_size {
+ let _ = self.free_list.push(index);
+
+ return if size > self.block_size {
+ Err(SuballocationCreationError::BlockSizeExceeded)
+ } else {
+ // There is not enough space due to alignment requirements.
+ Err(SuballocationCreationError::OutOfRegionMemory)
+ };
+ }
+
+ let mapped_ptr = self.region.mapped_ptr.map(|ptr| {
+ // SAFETY: Allocation sizes are guaranteed to not exceed `isize::MAX` when they have a
+ // mapped pointer, and the original pointer was handed to us from the Vulkan
+ // implementation, so the offset better be in range.
+ let ptr = unsafe { ptr.as_ptr().offset(relative_offset as isize) };
+
+ // SAFETY: Same as the previous.
+ unsafe { NonNull::new_unchecked(ptr) }
+ });
+
+ Ok(MemoryAlloc {
+ offset,
+ size,
+ allocation_type: self.region.allocation_type,
+ mapped_ptr,
+ atom_size: self.region.atom_size,
+ parent: AllocParent::Pool {
+ allocator: self,
+ index,
+ },
+ })
+ }
+
+ /// # Safety
+ ///
+ /// - `index` must refer to an occupied suballocation allocated by `self`.
+ unsafe fn free(&self, index: DeviceSize) {
+ let _ = self.free_list.push(index);
+ }
+}
+
+/// A [suballocator] which can allocate dynamically, but can only free all allocations at once.
+///
+/// With bump allocation, the used up space increases linearly as allocations are made and
+/// allocations can never be freed individually, which is why this algorithm is also called *linear
+/// allocation*. It is also known as *arena allocation*.
+///
+/// `BumpAllocator`s are best suited for very short-lived (say a few frames at best) resources that
+/// need to be allocated often (say each frame), to really take advantage of the performance gains.
+/// For creating long-lived allocations, [`FreeListAllocator`] is best suited. The way you would
+/// typically use this allocator is to have one for each frame in flight. At the start of a frame,
+/// you reset it and allocate your resources with it. You write to the resources, render with them,
+/// and drop them at the end of the frame.
+///
+/// See also [the `Suballocator` implementation].
+///
+/// # Algorithm
+///
+/// What happens is that every time you make an allocation, you receive one with an offset
+/// corresponding to the *free start* within the [region], and then the free start is *bumped*, so
+/// that following allocations wouldn't alias it. As you can imagine, this is **extremely fast**,
+/// because it doesn't need to keep a [free-list]. It only needs to do a few additions and
+/// comparisons. But beware, **fast is about all this is**. It is horribly memory inefficient when
+/// used wrong, and is very susceptible to [memory leaks].
+///
+/// Once you know that you are done with the allocations, meaning you know they have all been
+/// dropped, you can safely reset the allocator using the [`try_reset`] method as long as the
+/// allocator is not shared between threads. It is hard to safely reset a bump allocator that is
+/// used concurrently. In such a scenario it's best not to reset it at all and instead drop it once
+/// it reaches the end of the [region], freeing the region to a higher level in the [hierarchy]
+/// once all threads have dropped their reference to the allocator. This is one of the reasons you
+/// are generally advised to use one `BumpAllocator` per thread if you can.
+///
+/// # Efficiency
+///
+/// Allocation is *O*(1), and so is resetting the allocator (freeing all allocations). Allocation
+/// is always lock-free, and most of the time even wait-free. The only case in which it is not
+/// wait-free is if a lot of allocations are made concurrently, which results in CPU-level
+/// contention. Therefore, if you for example need to allocate a lot of buffers each frame from
+/// multiple threads, you might get better performance by using one `BumpAllocator` per thread.
+///
+/// The reason synchronization can be avoided entirely is that the created allocations can be
+/// dropped without needing to talk back to the allocator to free anything. The other allocation
+/// algorithms all have a free-list which needs to be modified once an allocation is dropped. Since
+/// Vulkano's buffers and images are `Sync`, that means that even if the allocator only allocates
+/// from one thread, it can still be used to free from multiple threads.
+///
+/// [suballocator]: Suballocator
+/// [the `Suballocator` implementation]: Suballocator#impl-Suballocator-for-Arc<BumpAllocator>
+/// [region]: Suballocator#regions
+/// [free-list]: Suballocator#free-lists
+/// [memory leaks]: super#leakage
+/// [`try_reset`]: Self::try_reset
+/// [hierarchy]: Suballocator#memory-hierarchies
+#[derive(Debug)]
+pub struct BumpAllocator {
+ region: MemoryAlloc,
+ device_memory: Arc<DeviceMemory>,
+ buffer_image_granularity: DeviceAlignment,
+ atom_size: DeviceAlignment,
+ // Encodes the previous allocation type in the 2 least signifficant bits and the free start in
+ // the rest.
+ state: AtomicU64,
+}
+
+impl BumpAllocator {
+ /// Creates a new `BumpAllocator` for the given [region].
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `region` is a [dedicated allocation].
+ /// - Panics if `region.size` exceeds `DeviceLayout::MAX_SIZE >> 2`.
+ ///
+ /// [region]: Suballocator#regions
+ /// [dedicated allocation]: MemoryAlloc::is_dedicated
+ pub fn new(region: MemoryAlloc) -> Arc<Self> {
+ // Sanity check: this would lead to UB because of the left-shifting by 2 needed to encode
+ // the free-start into the state.
+ assert!(region.size <= (DeviceLayout::MAX_SIZE >> 2));
+
+ let device_memory = region
+ .root()
+ .expect("dedicated allocations can't be suballocated")
+ .clone();
+ let buffer_image_granularity = device_memory
+ .device()
+ .physical_device()
+ .properties()
+ .buffer_image_granularity;
+ let atom_size = region.atom_size.unwrap_or(DeviceAlignment::MIN);
+ let state = AtomicU64::new(region.allocation_type as DeviceSize);
+
+ Arc::new(BumpAllocator {
+ region,
+ device_memory,
+ buffer_image_granularity,
+ atom_size,
+ state,
+ })
+ }
+
+ /// Resets the free-start back to the beginning of the [region] if there are no other strong
+ /// references to the allocator.
+ ///
+ /// [region]: Suballocator#regions
+ #[inline]
+ pub fn try_reset(self: &mut Arc<Self>) -> Result<(), BumpAllocatorResetError> {
+ Arc::get_mut(self)
+ .map(|allocator| {
+ *allocator.state.get_mut() = allocator.region.allocation_type as DeviceSize;
+ })
+ .ok_or(BumpAllocatorResetError)
+ }
+
+ /// Resets the free-start to the beginning of the [region] without checking if there are other
+ /// strong references to the allocator.
+ ///
+ /// This could be useful if you cloned the [`Arc`] yourself, and can guarantee that no
+ /// allocations currently hold a reference to it.
+ ///
+ /// As a safe alternative, you can let the `Arc` do all the work. Simply drop it once it
+ /// reaches the end of the region. After all threads do that, the region will be freed to the
+ /// next level up the [hierarchy]. If you only use the allocator on one thread and need shared
+ /// ownership, you can use `Rc<RefCell<Arc<BumpAllocator>>>` together with [`try_reset`] for a
+ /// safe alternative as well.
+ ///
+ /// # Safety
+ ///
+ /// - All allocations made with the allocator must have been dropped.
+ ///
+ /// [region]: Suballocator#regions
+ /// [hierarchy]: Suballocator#memory-hierarchies
+ /// [`try_reset`]: Self::try_reset
+ #[inline]
+ pub unsafe fn reset_unchecked(&self) {
+ self.state
+ .store(self.region.allocation_type as DeviceSize, Ordering::Release);
+ }
+}
+
+unsafe impl Suballocator for Arc<BumpAllocator> {
+ const IS_BLOCKING: bool = false;
+
+ const NEEDS_CLEANUP: bool = true;
+
+ #[inline]
+ fn new(region: MemoryAlloc) -> Self {
+ BumpAllocator::new(region)
+ }
+
+ /// Creates a new suballocation within the [region].
+ ///
+ /// # Errors
+ ///
+ /// - Returns [`OutOfRegionMemory`] if the requested allocation can't fit in the free space
+ /// remaining in the region.
+ ///
+ /// [region]: Suballocator#regions
+ /// [`allocate`]: Suballocator::allocate
+ /// [`OutOfRegionMemory`]: SuballocationCreationError::OutOfRegionMemory
+ #[inline]
+ fn allocate(
+ &self,
+ create_info: SuballocationCreateInfo,
+ ) -> Result<MemoryAlloc, SuballocationCreationError> {
+ const SPIN_LIMIT: u32 = 6;
+
+ // NOTE(Marc): The following code is a minimal version `Backoff` taken from
+ // crossbeam_utils v0.8.11, because we didn't want to add a dependency for a couple lines
+ // that are used in one place only.
+ /// Original documentation:
+ /// https://docs.rs/crossbeam-utils/0.8.11/crossbeam_utils/struct.Backoff.html
+ struct Backoff {
+ step: Cell<u32>,
+ }
+
+ impl Backoff {
+ fn new() -> Self {
+ Backoff { step: Cell::new(0) }
+ }
+
+ fn spin(&self) {
+ for _ in 0..1 << self.step.get().min(SPIN_LIMIT) {
+ core::hint::spin_loop();
+ }
+
+ if self.step.get() <= SPIN_LIMIT {
+ self.step.set(self.step.get() + 1);
+ }
+ }
+ }
+
+ fn has_granularity_conflict(prev_ty: AllocationType, ty: AllocationType) -> bool {
+ prev_ty == AllocationType::Unknown || prev_ty != ty
+ }
+
+ let SuballocationCreateInfo {
+ layout,
+ allocation_type,
+ _ne: _,
+ } = create_info;
+
+ let size = layout.size();
+ let alignment = cmp::max(layout.alignment(), self.atom_size);
+ let backoff = Backoff::new();
+ let mut state = self.state.load(Ordering::Relaxed);
+
+ loop {
+ let free_start = state >> 2;
+ let prev_alloc_type = match state & 0b11 {
+ 0 => AllocationType::Unknown,
+ 1 => AllocationType::Linear,
+ 2 => AllocationType::NonLinear,
+ _ => unreachable!(),
+ };
+
+ // These can't overflow because offsets are constrained by the size of the root
+ // allocation, which can itself not exceed `DeviceLayout::MAX_SIZE`.
+ let prev_end = self.region.offset + free_start;
+ let mut offset = align_up(prev_end, alignment);
+
+ if prev_end > 0
+ && are_blocks_on_same_page(0, prev_end, offset, self.buffer_image_granularity)
+ && has_granularity_conflict(prev_alloc_type, allocation_type)
+ {
+ offset = align_up(offset, self.buffer_image_granularity);
+ }
+
+ let relative_offset = offset - self.region.offset;
+
+ let free_start = relative_offset + size;
+
+ if free_start > self.region.size {
+ return Err(SuballocationCreationError::OutOfRegionMemory);
+ }
+
+ // This can't discard any bits because we checked that `region.size` does not exceed
+ // `DeviceLayout::MAX_SIZE >> 2`.
+ let new_state = free_start << 2 | allocation_type as DeviceSize;
+
+ match self.state.compare_exchange_weak(
+ state,
+ new_state,
+ Ordering::Release,
+ Ordering::Relaxed,
+ ) {
+ Ok(_) => {
+ let mapped_ptr = self.region.mapped_ptr.map(|ptr| {
+ // SAFETY: Allocation sizes are guaranteed to not exceed `isize::MAX` when
+ // they have a mapped pointer, and the original pointer was handed to us
+ // from the Vulkan implementation, so the offset better be in range.
+ let ptr = unsafe { ptr.as_ptr().offset(relative_offset as isize) };
+
+ // SAFETY: Same as the previous.
+ unsafe { NonNull::new_unchecked(ptr) }
+ });
+
+ return Ok(MemoryAlloc {
+ offset,
+ size,
+ allocation_type,
+ mapped_ptr,
+ atom_size: self.region.atom_size,
+ parent: AllocParent::Bump(self.clone()),
+ });
+ }
+ Err(new_state) => {
+ state = new_state;
+ backoff.spin();
+ }
+ }
+ }
+ }
+
+ #[inline]
+ fn region(&self) -> &MemoryAlloc {
+ &self.region
+ }
+
+ #[inline]
+ fn try_into_region(self) -> Result<MemoryAlloc, Self> {
+ Arc::try_unwrap(self).map(|allocator| allocator.region)
+ }
+
+ #[inline]
+ fn free_size(&self) -> DeviceSize {
+ self.region.size - (self.state.load(Ordering::Acquire) >> 2)
+ }
+
+ #[inline]
+ fn cleanup(&mut self) {
+ let _ = self.try_reset();
+ }
+}
+
+unsafe impl DeviceOwned for BumpAllocator {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ self.device_memory.device()
+ }
+}
+
+/// Error that can be returned when resetting the [`BumpAllocator`].
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct BumpAllocatorResetError;
+
+impl Error for BumpAllocatorResetError {}
+
+impl Display for BumpAllocatorResetError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("the allocator is still in use")
+ }
+}
+
+/// Checks if resouces A and B share a page.
+///
+/// > **Note**: Assumes `a_offset + a_size > 0` and `a_offset + a_size <= b_offset`.
+fn are_blocks_on_same_page(
+ a_offset: DeviceSize,
+ a_size: DeviceSize,
+ b_offset: DeviceSize,
+ page_size: DeviceAlignment,
+) -> bool {
+ debug_assert!(a_offset + a_size > 0);
+ debug_assert!(a_offset + a_size <= b_offset);
+
+ let a_end = a_offset + a_size - 1;
+ let a_end_page = align_down(a_end, page_size);
+ let b_start_page = align_down(b_offset, page_size);
+
+ a_end_page == b_start_page
+}
+
+/// Allocators for memory on the host, used to speed up the allocators for the device.
+mod host {
+ use std::num::NonZeroUsize;
+
+ /// Allocates objects from a pool on the host, which has the following benefits:
+ ///
+ /// - Allocation is much faster because there is no need to consult the global allocator or even
+ /// worse, the operating system, each time a small object needs to be created.
+ /// - Freeing is extremely fast, because the whole pool can be dropped at once. This is
+ /// particularily useful for linked structures, whose nodes need to be freed one-by-one by
+ /// traversing the whole structure otherwise.
+ /// - Cache locality is somewhat improved for linked structures with few nodes.
+ ///
+ /// The allocator doesn't hand out pointers but rather IDs that are relative to the pool. This
+ /// simplifies the logic because the pool can easily be moved and hence also resized, but the
+ /// downside is that the whole pool must be copied when it runs out of memory. It is therefore
+ /// best to start out with a safely large capacity.
+ #[derive(Debug)]
+ pub(super) struct PoolAllocator<T> {
+ pool: Vec<T>,
+ // Unsorted list of free slots.
+ free_list: Vec<SlotId>,
+ }
+
+ impl<T> PoolAllocator<T> {
+ pub fn new(capacity: usize) -> Self {
+ debug_assert!(capacity > 0);
+
+ PoolAllocator {
+ pool: Vec::with_capacity(capacity),
+ free_list: Vec::new(),
+ }
+ }
+
+ /// Allocates a slot and initializes it with the provided value. Returns the ID of the slot.
+ pub fn allocate(&mut self, val: T) -> SlotId {
+ if let Some(id) = self.free_list.pop() {
+ *unsafe { self.get_mut(id) } = val;
+
+ id
+ } else {
+ self.pool.push(val);
+
+ // SAFETY: `self.pool` is guaranteed to be non-empty.
+ SlotId(unsafe { NonZeroUsize::new_unchecked(self.pool.len()) })
+ }
+ }
+
+ /// Returns the slot with the given ID to the allocator to be reused.
+ ///
+ /// # Safety
+ ///
+ /// - `id` must not be freed again, as that would constitute a double-free.
+ /// - `id` must not be used to to access the slot again afterward, as that would constitute
+ /// a use-after-free.
+ pub unsafe fn free(&mut self, id: SlotId) {
+ debug_assert!(!self.free_list.contains(&id));
+ self.free_list.push(id);
+ }
+
+ /// Returns a mutable reference to the slot with the given ID.
+ ///
+ /// # Safety
+ ///
+ /// - `SlotId` must have been allocated by `self`.
+ pub unsafe fn get_mut(&mut self, id: SlotId) -> &mut T {
+ debug_assert!(!self.free_list.contains(&id));
+ debug_assert!(id.0.get() <= self.pool.len());
+
+ // SAFETY:
+ // - The caller must uphold that the `SlotId` was allocated with this allocator.
+ // - The only way to obtain a `SlotId` is through `Self::allocate`.
+ // - `Self::allocate` returns `SlotId`s in the range [1, self.pool.len()].
+ // - `self.pool` only grows and never shrinks.
+ self.pool.get_unchecked_mut(id.0.get() - 1)
+ }
+ }
+
+ impl<T: Copy> PoolAllocator<T> {
+ /// Returns a copy of the slot with the given ID.
+ ///
+ /// # Safety
+ ///
+ /// - `SlotId` must have been allocated by `self`.
+ pub unsafe fn get(&self, id: SlotId) -> T {
+ debug_assert!(!self.free_list.contains(&id));
+ debug_assert!(id.0.get() <= self.pool.len());
+
+ // SAFETY: Same as the `get_unchecked_mut` above.
+ *self.pool.get_unchecked(id.0.get() - 1)
+ }
+ }
+
+ /// ID of a slot in the pool of the `host::PoolAllocator`. This is used to limit the visibility
+ /// of the actual ID to this `host` module, making it easier to reason about unsafe code.
+ #[derive(Clone, Copy, Debug, PartialEq, Eq)]
+ pub(super) struct SlotId(NonZeroUsize);
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::memory::MemoryAllocateInfo;
+ use std::thread;
+
+ #[test]
+ fn memory_alloc_set_offset() {
+ let (device, _) = gfx_dev_and_queue!();
+ let memory_type_index = device
+ .physical_device()
+ .memory_properties()
+ .memory_types
+ .iter()
+ .position(|memory_type| {
+ memory_type
+ .property_flags
+ .contains(MemoryPropertyFlags::HOST_VISIBLE)
+ })
+ .unwrap() as u32;
+ let mut alloc = MemoryAlloc::new(
+ DeviceMemory::allocate(
+ device,
+ MemoryAllocateInfo {
+ memory_type_index,
+ allocation_size: 1024,
+ ..Default::default()
+ },
+ )
+ .unwrap(),
+ )
+ .unwrap();
+ let ptr = alloc.mapped_ptr().unwrap().as_ptr();
+
+ unsafe {
+ alloc.set_offset(16);
+ assert_eq!(alloc.mapped_ptr().unwrap().as_ptr(), ptr.offset(16));
+ alloc.set_offset(0);
+ assert_eq!(alloc.mapped_ptr().unwrap().as_ptr(), ptr.offset(0));
+ alloc.set_offset(32);
+ assert_eq!(alloc.mapped_ptr().unwrap().as_ptr(), ptr.offset(32));
+ }
+ }
+
+ #[test]
+ fn free_list_allocator_capacity() {
+ const THREADS: DeviceSize = 12;
+ const ALLOCATIONS_PER_THREAD: DeviceSize = 100;
+ const ALLOCATION_STEP: DeviceSize = 117;
+ const REGION_SIZE: DeviceSize =
+ (ALLOCATION_STEP * (THREADS + 1) * THREADS / 2) * ALLOCATIONS_PER_THREAD;
+
+ let allocator = dummy_allocator!(FreeListAllocator, REGION_SIZE);
+ let allocs = ArrayQueue::new((ALLOCATIONS_PER_THREAD * THREADS) as usize);
+
+ // Using threads to randomize allocation order.
+ thread::scope(|scope| {
+ for i in 1..=THREADS {
+ let (allocator, allocs) = (&allocator, &allocs);
+
+ scope.spawn(move || {
+ let info = dummy_info!(i * ALLOCATION_STEP);
+
+ for _ in 0..ALLOCATIONS_PER_THREAD {
+ allocs
+ .push(allocator.allocate(info.clone()).unwrap())
+ .unwrap();
+ }
+ });
+ }
+ });
+
+ assert!(allocator.allocate(dummy_info!()).is_err());
+ assert!(allocator.free_size() == 0);
+
+ drop(allocs);
+ assert!(allocator.free_size() == REGION_SIZE);
+ assert!(allocator.allocate(dummy_info!(REGION_SIZE)).is_ok());
+ }
+
+ #[test]
+ fn free_list_allocator_respects_alignment() {
+ const REGION_SIZE: DeviceSize = 10 * 256;
+
+ let info = dummy_info!(1, 256);
+
+ let allocator = dummy_allocator!(FreeListAllocator, REGION_SIZE);
+ let mut allocs = Vec::with_capacity(10);
+
+ for _ in 0..10 {
+ allocs.push(allocator.allocate(info.clone()).unwrap());
+ }
+
+ assert!(allocator.allocate(info).is_err());
+ assert!(allocator.free_size() == REGION_SIZE - 10);
+ }
+
+ #[test]
+ fn free_list_allocator_respects_granularity() {
+ const GRANULARITY: DeviceSize = 16;
+ const REGION_SIZE: DeviceSize = 2 * GRANULARITY;
+
+ let allocator = dummy_allocator!(FreeListAllocator, REGION_SIZE, GRANULARITY);
+ let mut linear_allocs = Vec::with_capacity(GRANULARITY as usize);
+ let mut nonlinear_allocs = Vec::with_capacity(GRANULARITY as usize);
+
+ for i in 0..REGION_SIZE {
+ if i % 2 == 0 {
+ linear_allocs.push(allocator.allocate(dummy_info_linear!()).unwrap());
+ } else {
+ nonlinear_allocs.push(allocator.allocate(dummy_info_nonlinear!()).unwrap());
+ }
+ }
+
+ assert!(allocator.allocate(dummy_info_linear!()).is_err());
+ assert!(allocator.free_size() == 0);
+
+ drop(linear_allocs);
+ assert!(allocator.allocate(dummy_info!(GRANULARITY)).is_ok());
+
+ let _alloc = allocator.allocate(dummy_info!()).unwrap();
+ assert!(allocator.allocate(dummy_info!()).is_err());
+ assert!(allocator.allocate(dummy_info_linear!()).is_err());
+ }
+
+ #[test]
+ fn pool_allocator_capacity() {
+ const BLOCK_SIZE: DeviceSize = 1024;
+
+ fn dummy_allocator(
+ device: Arc<Device>,
+ allocation_size: DeviceSize,
+ ) -> Arc<PoolAllocator<BLOCK_SIZE>> {
+ let device_memory = DeviceMemory::allocate(
+ device,
+ MemoryAllocateInfo {
+ allocation_size,
+ memory_type_index: 0,
+ ..Default::default()
+ },
+ )
+ .unwrap();
+
+ PoolAllocator::new(
+ MemoryAlloc::new(device_memory).unwrap(),
+ DeviceAlignment::new(1).unwrap(),
+ )
+ }
+
+ let (device, _) = gfx_dev_and_queue!();
+
+ assert_should_panic!({ dummy_allocator(device.clone(), BLOCK_SIZE - 1) });
+
+ let allocator = dummy_allocator(device.clone(), 2 * BLOCK_SIZE - 1);
+ {
+ let alloc = allocator.allocate(dummy_info!()).unwrap();
+ assert!(allocator.allocate(dummy_info!()).is_err());
+
+ drop(alloc);
+ let _alloc = allocator.allocate(dummy_info!()).unwrap();
+ }
+
+ let allocator = dummy_allocator(device, 2 * BLOCK_SIZE);
+ {
+ let alloc1 = allocator.allocate(dummy_info!()).unwrap();
+ let alloc2 = allocator.allocate(dummy_info!()).unwrap();
+ assert!(allocator.allocate(dummy_info!()).is_err());
+
+ drop(alloc1);
+ let alloc1 = allocator.allocate(dummy_info!()).unwrap();
+ assert!(allocator.allocate(dummy_info!()).is_err());
+
+ drop(alloc1);
+ drop(alloc2);
+ let _alloc1 = allocator.allocate(dummy_info!()).unwrap();
+ let _alloc2 = allocator.allocate(dummy_info!()).unwrap();
+ }
+ }
+
+ #[test]
+ fn pool_allocator_respects_alignment() {
+ const BLOCK_SIZE: DeviceSize = 1024 + 128;
+
+ let info_a = dummy_info!(BLOCK_SIZE, 256);
+ let info_b = dummy_info!(1024, 256);
+
+ let allocator = {
+ let (device, _) = gfx_dev_and_queue!();
+ let device_memory = DeviceMemory::allocate(
+ device,
+ MemoryAllocateInfo {
+ allocation_size: 10 * BLOCK_SIZE,
+ memory_type_index: 0,
+ ..Default::default()
+ },
+ )
+ .unwrap();
+
+ PoolAllocator::<BLOCK_SIZE>::new(
+ MemoryAlloc::new(device_memory).unwrap(),
+ DeviceAlignment::new(1).unwrap(),
+ )
+ };
+
+ // This uses the fact that block indices are inserted into the free-list in order, so
+ // the first allocation succeeds because the block has an even index, while the second
+ // has an odd index.
+ allocator.allocate(info_a.clone()).unwrap();
+ assert!(allocator.allocate(info_a.clone()).is_err());
+ allocator.allocate(info_a.clone()).unwrap();
+ assert!(allocator.allocate(info_a).is_err());
+
+ for _ in 0..10 {
+ allocator.allocate(info_b.clone()).unwrap();
+ }
+ }
+
+ #[test]
+ fn pool_allocator_respects_granularity() {
+ const BLOCK_SIZE: DeviceSize = 128;
+
+ fn dummy_allocator(
+ device: Arc<Device>,
+ allocation_type: AllocationType,
+ ) -> Arc<PoolAllocator<BLOCK_SIZE>> {
+ let device_memory = DeviceMemory::allocate(
+ device,
+ MemoryAllocateInfo {
+ allocation_size: 1024,
+ memory_type_index: 0,
+ ..Default::default()
+ },
+ )
+ .unwrap();
+ let mut region = MemoryAlloc::new(device_memory).unwrap();
+ unsafe { region.set_allocation_type(allocation_type) };
+
+ PoolAllocator::new(region, DeviceAlignment::new(256).unwrap())
+ }
+
+ let (device, _) = gfx_dev_and_queue!();
+
+ let allocator = dummy_allocator(device.clone(), AllocationType::Unknown);
+ assert!(allocator.block_count() == 4);
+
+ let allocator = dummy_allocator(device.clone(), AllocationType::Linear);
+ assert!(allocator.block_count() == 8);
+
+ let allocator = dummy_allocator(device, AllocationType::NonLinear);
+ assert!(allocator.block_count() == 8);
+ }
+
+ #[test]
+ fn buddy_allocator_capacity() {
+ const MAX_ORDER: usize = 10;
+ const REGION_SIZE: DeviceSize = BuddyAllocator::MIN_NODE_SIZE << MAX_ORDER;
+
+ let allocator = dummy_allocator!(BuddyAllocator, REGION_SIZE);
+ let mut allocs = Vec::with_capacity(1 << MAX_ORDER);
+
+ for order in 0..=MAX_ORDER {
+ let size = BuddyAllocator::MIN_NODE_SIZE << order;
+
+ for _ in 0..1 << (MAX_ORDER - order) {
+ allocs.push(allocator.allocate(dummy_info!(size)).unwrap());
+ }
+
+ assert!(allocator.allocate(dummy_info!()).is_err());
+ assert!(allocator.free_size() == 0);
+ allocs.clear();
+ }
+
+ let mut orders = (0..MAX_ORDER).collect::<Vec<_>>();
+
+ for mid in 0..MAX_ORDER {
+ orders.rotate_left(mid);
+
+ for &order in &orders {
+ let size = BuddyAllocator::MIN_NODE_SIZE << order;
+ allocs.push(allocator.allocate(dummy_info!(size)).unwrap());
+ }
+
+ let _alloc = allocator.allocate(dummy_info!()).unwrap();
+ assert!(allocator.allocate(dummy_info!()).is_err());
+ assert!(allocator.free_size() == 0);
+ allocs.clear();
+ }
+ }
+
+ #[test]
+ fn buddy_allocator_respects_alignment() {
+ const REGION_SIZE: DeviceSize = 4096;
+
+ let allocator = dummy_allocator!(BuddyAllocator, REGION_SIZE);
+
+ {
+ let info = dummy_info!(1, 4096);
+
+ let _alloc = allocator.allocate(info.clone()).unwrap();
+ assert!(allocator.allocate(info).is_err());
+ assert!(allocator.free_size() == REGION_SIZE - BuddyAllocator::MIN_NODE_SIZE);
+ }
+
+ {
+ let info_a = dummy_info!(1, 256);
+ let allocations_a = REGION_SIZE / info_a.layout.alignment().as_devicesize();
+ let info_b = dummy_info!(1, 16);
+ let allocations_b =
+ REGION_SIZE / info_b.layout.alignment().as_devicesize() - allocations_a;
+
+ let mut allocs =
+ Vec::with_capacity((REGION_SIZE / BuddyAllocator::MIN_NODE_SIZE) as usize);
+
+ for _ in 0..allocations_a {
+ allocs.push(allocator.allocate(info_a.clone()).unwrap());
+ }
+
+ assert!(allocator.allocate(info_a).is_err());
+ assert!(
+ allocator.free_size()
+ == REGION_SIZE - allocations_a * BuddyAllocator::MIN_NODE_SIZE
+ );
+
+ for _ in 0..allocations_b {
+ allocs.push(allocator.allocate(info_b.clone()).unwrap());
+ }
+
+ assert!(allocator.allocate(dummy_info!()).is_err());
+ assert!(allocator.free_size() == 0);
+ }
+ }
+
+ #[test]
+ fn buddy_allocator_respects_granularity() {
+ const GRANULARITY: DeviceSize = 256;
+ const REGION_SIZE: DeviceSize = 2 * GRANULARITY;
+
+ let allocator = dummy_allocator!(BuddyAllocator, REGION_SIZE, GRANULARITY);
+
+ {
+ const ALLOCATIONS: DeviceSize = REGION_SIZE / BuddyAllocator::MIN_NODE_SIZE;
+
+ let mut allocs = Vec::with_capacity(ALLOCATIONS as usize);
+ for _ in 0..ALLOCATIONS {
+ allocs.push(allocator.allocate(dummy_info_linear!()).unwrap());
+ }
+
+ assert!(allocator.allocate(dummy_info_linear!()).is_err());
+ assert!(allocator.free_size() == 0);
+ }
+
+ {
+ let _alloc1 = allocator.allocate(dummy_info!()).unwrap();
+ let _alloc2 = allocator.allocate(dummy_info!()).unwrap();
+ assert!(allocator.allocate(dummy_info!()).is_err());
+ assert!(allocator.free_size() == 0);
+ }
+ }
+
+ #[test]
+ fn bump_allocator_respects_alignment() {
+ const ALIGNMENT: DeviceSize = 16;
+
+ let info = dummy_info!(1, ALIGNMENT);
+ let allocator = dummy_allocator!(BumpAllocator, ALIGNMENT * 10);
+
+ for _ in 0..10 {
+ allocator.allocate(info.clone()).unwrap();
+ }
+
+ assert!(allocator.allocate(info.clone()).is_err());
+
+ for _ in 0..ALIGNMENT - 1 {
+ allocator.allocate(dummy_info!()).unwrap();
+ }
+
+ assert!(allocator.allocate(info).is_err());
+ assert!(allocator.free_size() == 0);
+ }
+
+ #[test]
+ fn bump_allocator_respects_granularity() {
+ const ALLOCATIONS: DeviceSize = 10;
+ const GRANULARITY: DeviceSize = 1024;
+
+ let mut allocator = dummy_allocator!(BumpAllocator, GRANULARITY * ALLOCATIONS, GRANULARITY);
+
+ for i in 0..ALLOCATIONS {
+ for _ in 0..GRANULARITY {
+ allocator
+ .allocate(SuballocationCreateInfo {
+ allocation_type: if i % 2 == 0 {
+ AllocationType::NonLinear
+ } else {
+ AllocationType::Linear
+ },
+ ..dummy_info!()
+ })
+ .unwrap();
+ }
+ }
+
+ assert!(allocator.allocate(dummy_info_linear!()).is_err());
+ assert!(allocator.free_size() == 0);
+
+ allocator.try_reset().unwrap();
+
+ for i in 0..ALLOCATIONS {
+ allocator
+ .allocate(SuballocationCreateInfo {
+ allocation_type: if i % 2 == 0 {
+ AllocationType::Linear
+ } else {
+ AllocationType::NonLinear
+ },
+ ..dummy_info!()
+ })
+ .unwrap();
+ }
+
+ assert!(allocator.allocate(dummy_info_linear!()).is_err());
+ assert!(allocator.free_size() == GRANULARITY - 1);
+ }
+
+ #[test]
+ fn bump_allocator_syncness() {
+ const THREADS: DeviceSize = 12;
+ const ALLOCATIONS_PER_THREAD: DeviceSize = 100_000;
+ const ALLOCATION_STEP: DeviceSize = 117;
+ const REGION_SIZE: DeviceSize =
+ (ALLOCATION_STEP * (THREADS + 1) * THREADS / 2) * ALLOCATIONS_PER_THREAD;
+
+ let mut allocator = dummy_allocator!(BumpAllocator, REGION_SIZE);
+
+ thread::scope(|scope| {
+ for i in 1..=THREADS {
+ let allocator = &allocator;
+
+ scope.spawn(move || {
+ let info = dummy_info!(i * ALLOCATION_STEP);
+
+ for _ in 0..ALLOCATIONS_PER_THREAD {
+ allocator.allocate(info.clone()).unwrap();
+ }
+ });
+ }
+ });
+
+ assert!(allocator.allocate(dummy_info!()).is_err());
+ assert!(allocator.free_size() == 0);
+
+ allocator.try_reset().unwrap();
+ assert!(allocator.free_size() == REGION_SIZE);
+ }
+
+ macro_rules! dummy_allocator {
+ ($type:ty, $size:expr) => {
+ dummy_allocator!($type, $size, 1)
+ };
+ ($type:ty, $size:expr, $granularity:expr) => {{
+ let (device, _) = gfx_dev_and_queue!();
+ let device_memory = DeviceMemory::allocate(
+ device,
+ MemoryAllocateInfo {
+ allocation_size: $size,
+ memory_type_index: 0,
+ ..Default::default()
+ },
+ )
+ .unwrap();
+ let mut allocator = <$type>::new(MemoryAlloc::new(device_memory).unwrap());
+ Arc::get_mut(&mut allocator)
+ .unwrap()
+ .buffer_image_granularity = DeviceAlignment::new($granularity).unwrap();
+
+ allocator
+ }};
+ }
+
+ macro_rules! dummy_info {
+ () => {
+ dummy_info!(1)
+ };
+ ($size:expr) => {
+ dummy_info!($size, 1)
+ };
+ ($size:expr, $alignment:expr) => {
+ SuballocationCreateInfo {
+ layout: DeviceLayout::new(
+ NonZeroDeviceSize::new($size).unwrap(),
+ DeviceAlignment::new($alignment).unwrap(),
+ )
+ .unwrap(),
+ allocation_type: AllocationType::Unknown,
+ ..Default::default()
+ }
+ };
+ }
+
+ macro_rules! dummy_info_linear {
+ ($($args:tt)*) => {
+ SuballocationCreateInfo {
+ allocation_type: AllocationType::Linear,
+ ..dummy_info!($($args)*)
+ }
+ };
+ }
+
+ macro_rules! dummy_info_nonlinear {
+ ($($args:tt)*) => {
+ SuballocationCreateInfo {
+ allocation_type: AllocationType::NonLinear,
+ ..dummy_info!($($args)*)
+ }
+ };
+ }
+
+ pub(self) use {dummy_allocator, dummy_info, dummy_info_linear, dummy_info_nonlinear};
+}
diff --git a/src/memory/device_memory.rs b/src/memory/device_memory.rs
index 5f2bf0e..8a0de85 100644
--- a/src/memory/device_memory.rs
+++ b/src/memory/device_memory.rs
@@ -7,615 +7,737 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use crate::check_errors;
-use crate::device::physical::MemoryType;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::memory::Content;
-use crate::memory::DedicatedAlloc;
-use crate::memory::ExternalMemoryHandleType;
-use crate::DeviceSize;
-use crate::Error;
-use crate::OomError;
-use crate::Version;
-use crate::VulkanObject;
-use std::error;
-use std::fmt;
-#[cfg(any(target_os = "android", target_os = "linux"))]
-use std::fs::File;
-use std::marker::PhantomData;
-use std::mem::MaybeUninit;
-use std::ops::Deref;
-use std::ops::DerefMut;
-use std::ops::Range;
-use std::os::raw::c_void;
-#[cfg(any(target_os = "android", target_os = "linux"))]
-use std::os::unix::io::{FromRawFd, IntoRawFd};
-use std::ptr;
-use std::sync::Arc;
-use std::sync::Mutex;
-
-#[repr(C)]
-pub struct BaseOutStructure {
- pub s_type: i32,
- pub p_next: *mut BaseOutStructure,
-}
-
-pub(crate) unsafe fn ptr_chain_iter<T>(ptr: &mut T) -> impl Iterator<Item = *mut BaseOutStructure> {
- let ptr: *mut BaseOutStructure = ptr as *mut T as _;
- (0..).scan(ptr, |p_ptr, _| {
- if p_ptr.is_null() {
- return None;
- }
- let n_ptr = (**p_ptr).p_next as *mut BaseOutStructure;
- let old = *p_ptr;
- *p_ptr = n_ptr;
- Some(old)
- })
-}
-
-pub unsafe trait ExtendsMemoryAllocateInfo {}
-unsafe impl ExtendsMemoryAllocateInfo for ash::vk::MemoryDedicatedAllocateInfoKHR {}
-unsafe impl ExtendsMemoryAllocateInfo for ash::vk::ExportMemoryAllocateInfo {}
-unsafe impl ExtendsMemoryAllocateInfo for ash::vk::ImportMemoryFdInfoKHR {}
-
-/// Represents memory that has been allocated.
+use super::{DedicatedAllocation, DedicatedTo, DeviceAlignment};
+use crate::{
+ device::{Device, DeviceOwned},
+ macros::{impl_id_counter, vulkan_bitflags, vulkan_bitflags_enum},
+ memory::{is_aligned, MemoryPropertyFlags},
+ DeviceSize, OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject,
+};
+use std::{
+ error::Error,
+ ffi::c_void,
+ fmt::{Display, Error as FmtError, Formatter},
+ fs::File,
+ mem::MaybeUninit,
+ num::NonZeroU64,
+ ops::Range,
+ ptr, slice,
+ sync::{atomic::Ordering, Arc},
+};
+
+/// Represents memory that has been allocated from the device.
///
/// The destructor of `DeviceMemory` automatically frees the memory.
///
-/// # Example
+/// # Examples
///
/// ```
-/// use vulkano::memory::DeviceMemory;
+/// use vulkano::memory::{DeviceMemory, MemoryAllocateInfo};
///
/// # let device: std::sync::Arc<vulkano::device::Device> = return;
-/// let mem_ty = device.physical_device().memory_types().next().unwrap();
+/// let memory_type_index = 0;
///
/// // Allocates 1KB of memory.
-/// let memory = DeviceMemory::alloc(device.clone(), mem_ty, 1024).unwrap();
+/// let memory = DeviceMemory::allocate(
+/// device.clone(),
+/// MemoryAllocateInfo {
+/// allocation_size: 1024,
+/// memory_type_index,
+/// ..Default::default()
+/// },
+/// )
+/// .unwrap();
/// ```
+#[derive(Debug)]
pub struct DeviceMemory {
- memory: ash::vk::DeviceMemory,
+ handle: ash::vk::DeviceMemory,
device: Arc<Device>,
- size: DeviceSize,
- memory_type_index: u32,
- handle_types: ExternalMemoryHandleType,
- mapped: Mutex<bool>,
-}
+ id: NonZeroU64,
-/// Represents a builder for the device memory object.
-///
-/// # Example
-///
-/// ```
-/// use vulkano::memory::DeviceMemoryBuilder;
-///
-/// # let device: std::sync::Arc<vulkano::device::Device> = return;
-/// let mem_ty = device.physical_device().memory_types().next().unwrap();
-///
-/// // Allocates 1KB of memory.
-/// let memory = DeviceMemoryBuilder::new(device, mem_ty.id(), 1024).build().unwrap();
-/// ```
-pub struct DeviceMemoryBuilder<'a> {
- device: Arc<Device>,
- allocate: ash::vk::MemoryAllocateInfo,
- dedicated_info: Option<ash::vk::MemoryDedicatedAllocateInfoKHR>,
- export_info: Option<ash::vk::ExportMemoryAllocateInfo>,
- import_info: Option<ash::vk::ImportMemoryFdInfoKHR>,
- marker: PhantomData<&'a ()>,
+ allocation_size: DeviceSize,
+ memory_type_index: u32,
+ dedicated_to: Option<DedicatedTo>,
+ export_handle_types: ExternalMemoryHandleTypes,
+ imported_handle_type: Option<ExternalMemoryHandleType>,
+ flags: MemoryAllocateFlags,
}
-impl<'a> DeviceMemoryBuilder<'a> {
- /// Returns a new `DeviceMemoryBuilder` given the required device, memory type and size fields.
- /// Validation of parameters is done when the builder is built.
- pub fn new(
+impl DeviceMemory {
+ /// Allocates a block of memory from the device.
+ ///
+ /// Some platforms may have a limit on the maximum size of a single allocation. For example,
+ /// certain systems may fail to create allocations with a size greater than or equal to 4GB.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `allocate_info.allocation_size` is 0.
+ /// - Panics if `allocate_info.dedicated_allocation` is `Some` and the contained buffer or
+ /// image does not belong to `device`.
+ #[inline]
+ pub fn allocate(
device: Arc<Device>,
- memory_index: u32,
- size: DeviceSize,
- ) -> DeviceMemoryBuilder<'a> {
- let allocate = ash::vk::MemoryAllocateInfo {
- allocation_size: size,
- memory_type_index: memory_index,
- ..Default::default()
- };
+ mut allocate_info: MemoryAllocateInfo<'_>,
+ ) -> Result<Self, DeviceMemoryError> {
+ Self::validate(&device, &mut allocate_info, None)?;
- DeviceMemoryBuilder {
- device,
- allocate,
- dedicated_info: None,
- export_info: None,
- import_info: None,
- marker: PhantomData,
- }
+ unsafe { Self::allocate_unchecked(device, allocate_info, None) }.map_err(Into::into)
}
- /// Sets an optional field for dedicated allocations in the `DeviceMemoryBuilder`. To maintain
- /// backwards compatibility, this function does nothing when dedicated allocation has not been
- /// enabled on the device.
+ /// Creates a new `DeviceMemory` from a raw object handle.
///
- /// # Panic
+ /// # Safety
///
- /// - Panics if the dedicated allocation info has already been set.
- pub fn dedicated_info(mut self, dedicated: DedicatedAlloc<'a>) -> DeviceMemoryBuilder {
- assert!(self.dedicated_info.is_none());
-
- if !(self.device.api_version() >= Version::V1_1
- || self.device.enabled_extensions().khr_dedicated_allocation)
- {
- return self;
+ /// - `handle` must be a valid Vulkan object handle created from `device`.
+ /// - `allocate_info` must match the info used to create the object.
+ #[inline]
+ pub unsafe fn from_handle(
+ device: Arc<Device>,
+ handle: ash::vk::DeviceMemory,
+ allocate_info: MemoryAllocateInfo<'_>,
+ ) -> Self {
+ let MemoryAllocateInfo {
+ allocation_size,
+ memory_type_index,
+ dedicated_allocation,
+ export_handle_types,
+ flags,
+ _ne: _,
+ } = allocate_info;
+
+ DeviceMemory {
+ handle,
+ device,
+ id: Self::next_id(),
+ allocation_size,
+ memory_type_index,
+ dedicated_to: dedicated_allocation.map(Into::into),
+ export_handle_types,
+ imported_handle_type: None,
+ flags,
}
-
- let mut dedicated_info = match dedicated {
- DedicatedAlloc::Buffer(buffer) => ash::vk::MemoryDedicatedAllocateInfoKHR {
- image: ash::vk::Image::null(),
- buffer: buffer.internal_object(),
- ..Default::default()
- },
- DedicatedAlloc::Image(image) => ash::vk::MemoryDedicatedAllocateInfoKHR {
- image: image.internal_object(),
- buffer: ash::vk::Buffer::null(),
- ..Default::default()
- },
- DedicatedAlloc::None => return self,
- };
-
- self = self.push_next(&mut dedicated_info);
- self.dedicated_info = Some(dedicated_info);
- self
}
- /// Sets an optional field for exportable allocations in the `DeviceMemoryBuilder`.
+ /// Imports a block of memory from an external source.
///
- /// # Panic
+ /// # Safety
///
- /// - Panics if the export info has already been set.
- pub fn export_info(
- mut self,
- handle_types: ExternalMemoryHandleType,
- ) -> DeviceMemoryBuilder<'a> {
- assert!(self.export_info.is_none());
-
- let mut export_info = ash::vk::ExportMemoryAllocateInfo {
- handle_types: handle_types.into(),
- ..Default::default()
- };
-
- self = self.push_next(&mut export_info);
- self.export_info = Some(export_info);
- self
- }
-
- /// Sets an optional field for importable DeviceMemory in the `DeviceMemoryBuilder`.
+ /// - See the documentation of the variants of [`MemoryImportInfo`].
///
- /// # Panic
+ /// # Panics
///
- /// - Panics if the import info has already been set.
- #[cfg(any(target_os = "android", target_os = "linux"))]
- pub fn import_info(
- mut self,
- fd: File,
- handle_types: ExternalMemoryHandleType,
- ) -> DeviceMemoryBuilder<'a> {
- assert!(self.import_info.is_none());
-
- let mut import_info = ash::vk::ImportMemoryFdInfoKHR {
- handle_type: handle_types.into(),
- fd: fd.into_raw_fd(),
- ..Default::default()
- };
+ /// - Panics if `allocate_info.allocation_size` is 0.
+ /// - Panics if `allocate_info.dedicated_allocation` is `Some` and the contained buffer or
+ /// image does not belong to `device`.
+ #[inline]
+ pub unsafe fn import(
+ device: Arc<Device>,
+ mut allocate_info: MemoryAllocateInfo<'_>,
+ import_info: MemoryImportInfo,
+ ) -> Result<Self, DeviceMemoryError> {
+ Self::validate(&device, &mut allocate_info, Some(&import_info))?;
- self = self.push_next(&mut import_info);
- self.import_info = Some(import_info);
- self
+ Self::allocate_unchecked(device, allocate_info, Some(import_info)).map_err(Into::into)
}
- // Private function copied shamelessly from Ash.
- // https://github.com/MaikKlein/ash/blob/4ba8637d018fec6d6e3a90d7fa47d11c085f6b4a/generator/src/lib.rs
- #[allow(unused_assignments)]
- fn push_next<T: ExtendsMemoryAllocateInfo>(self, next: &mut T) -> DeviceMemoryBuilder<'a> {
- unsafe {
- // `next` here can contain a pointer chain. This means that we must correctly
- // attach he head to the root and the tail to the rest of the chain
- // For example:
- //
- // next = A -> B
- // Before: `Root -> C -> D -> E`
- // After: `Root -> A -> B -> C -> D -> E`
-
- // Convert next to our ptr structure
- let next_ptr = next as *mut T as *mut BaseOutStructure;
- // Previous head (can be null)
- let mut prev_head = self.allocate.p_next as *mut BaseOutStructure;
- // Retrieve end of next chain
- let last_next = ptr_chain_iter(next).last().unwrap();
- // Set end of next chain's next to be previous head only if previous head's next'
- if !prev_head.is_null() {
- (*last_next).p_next = (*prev_head).p_next;
- }
- // Set next ptr to be first one
- prev_head = next_ptr;
+ #[inline(never)]
+ fn validate(
+ device: &Device,
+ allocate_info: &mut MemoryAllocateInfo<'_>,
+ import_info: Option<&MemoryImportInfo>,
+ ) -> Result<(), DeviceMemoryError> {
+ let &mut MemoryAllocateInfo {
+ allocation_size,
+ memory_type_index,
+ ref mut dedicated_allocation,
+ export_handle_types,
+ flags,
+ _ne: _,
+ } = allocate_info;
+
+ if !(device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_dedicated_allocation)
+ {
+ // Fall back instead of erroring out
+ *dedicated_allocation = None;
}
- self
- }
-
- /// Creates a `DeviceMemory` object on success, consuming the `DeviceMemoryBuilder`. An error
- /// is returned if the requested allocation is too large or if the total number of allocations
- /// would exceed per-device limits.
- pub fn build(self) -> Result<Arc<DeviceMemory>, DeviceMemoryAllocError> {
- if self.allocate.allocation_size == 0 {
- return Err(DeviceMemoryAllocError::InvalidSize)?;
+ let memory_properties = device.physical_device().memory_properties();
+
+ // VUID-vkAllocateMemory-pAllocateInfo-01714
+ let memory_type = memory_properties
+ .memory_types
+ .get(memory_type_index as usize)
+ .ok_or(DeviceMemoryError::MemoryTypeIndexOutOfRange {
+ memory_type_index,
+ memory_type_count: memory_properties.memory_types.len() as u32,
+ })?;
+
+ // VUID-VkMemoryAllocateInfo-memoryTypeIndex-01872
+ if memory_type
+ .property_flags
+ .intersects(MemoryPropertyFlags::PROTECTED)
+ && !device.enabled_features().protected_memory
+ {
+ return Err(DeviceMemoryError::RequirementNotMet {
+ required_for: "`allocate_info.memory_type_index` refers to a memory type where \
+ `property_flags` contains `MemoryPropertyFlags::PROTECTED`",
+ requires_one_of: RequiresOneOf {
+ features: &["protected_memory"],
+ ..Default::default()
+ },
+ });
}
- // VUID-vkAllocateMemory-pAllocateInfo-01714: "pAllocateInfo->memoryTypeIndex must be less
- // than VkPhysicalDeviceMemoryProperties::memoryTypeCount as returned by
- // vkGetPhysicalDeviceMemoryProperties for the VkPhysicalDevice that device was created
- // from."
- let memory_type = self
- .device
- .physical_device()
- .memory_type_by_id(self.allocate.memory_type_index)
- .ok_or(DeviceMemoryAllocError::SpecViolation(1714))?;
+ // VUID-VkMemoryAllocateInfo-pNext-01874
+ assert!(allocation_size != 0);
- if self.device.physical_device().internal_object()
- != memory_type.physical_device().internal_object()
- {
- return Err(DeviceMemoryAllocError::SpecViolation(1714));
+ // VUID-vkAllocateMemory-pAllocateInfo-01713
+ let heap_size = memory_properties.memory_heaps[memory_type.heap_index as usize].size;
+ if heap_size != 0 && allocation_size > heap_size {
+ return Err(DeviceMemoryError::MemoryTypeHeapSizeExceeded {
+ allocation_size,
+ heap_size,
+ });
}
- // Note: This check is disabled because MoltenVK doesn't report correct heap sizes yet.
- // This check was re-enabled because Mesa aborts if `size` is Very Large.
- //
- // Conversions won't panic since it's based on `vkDeviceSize`, which is a u64 in the VK
- // header. Not sure why we bother with usizes.
-
- // VUID-vkAllocateMemory-pAllocateInfo-01713: "pAllocateInfo->allocationSize must be less than
- // or equal to VkPhysicalDeviceMemoryProperties::memoryHeaps[memindex].size where memindex =
- // VkPhysicalDeviceMemoryProperties::memoryTypes[pAllocateInfo->memoryTypeIndex].heapIndex as
- // returned by vkGetPhysicalDeviceMemoryProperties for the VkPhysicalDevice that device was created
- // from".
- let reported_heap_size = memory_type.heap().size();
- if reported_heap_size != 0 && self.allocate.allocation_size > reported_heap_size {
- return Err(DeviceMemoryAllocError::SpecViolation(1713));
+ // VUID-vkAllocateMemory-deviceCoherentMemory-02790
+ if memory_type
+ .property_flags
+ .intersects(MemoryPropertyFlags::DEVICE_COHERENT)
+ && !device.enabled_features().device_coherent_memory
+ {
+ return Err(DeviceMemoryError::RequirementNotMet {
+ required_for: "`allocate_info.memory_type_index` refers to a memory type where \
+ `property_flags` contains `MemoryPropertyFlags::DEVICE_COHERENT`",
+ requires_one_of: RequiresOneOf {
+ features: &["device_coherent_memory"],
+ ..Default::default()
+ },
+ });
}
- let mut export_handle_bits = ash::vk::ExternalMemoryHandleTypeFlags::empty();
-
- if self.export_info.is_some() || self.import_info.is_some() {
- // TODO: check exportFromImportedHandleTypes
- export_handle_bits = match self.export_info {
- Some(export_info) => export_info.handle_types,
- None => ash::vk::ExternalMemoryHandleTypeFlags::empty(),
- };
-
- let import_handle_bits = match self.import_info {
- Some(import_info) => import_info.handle_type,
- None => ash::vk::ExternalMemoryHandleTypeFlags::empty(),
- };
+ if let Some(dedicated_allocation) = dedicated_allocation {
+ match dedicated_allocation {
+ DedicatedAllocation::Buffer(buffer) => {
+ // VUID-VkMemoryDedicatedAllocateInfo-commonparent
+ assert_eq!(device, buffer.device().as_ref());
+
+ let required_size = buffer.memory_requirements().layout.size();
+
+ // VUID-VkMemoryDedicatedAllocateInfo-buffer-02965
+ if allocation_size != required_size {
+ return Err(DeviceMemoryError::DedicatedAllocationSizeMismatch {
+ allocation_size,
+ required_size,
+ });
+ }
+ }
+ DedicatedAllocation::Image(image) => {
+ // VUID-VkMemoryDedicatedAllocateInfo-commonparent
+ assert_eq!(device, image.device().as_ref());
+
+ let required_size = image.memory_requirements()[0].layout.size();
+
+ // VUID-VkMemoryDedicatedAllocateInfo-image-02964
+ if allocation_size != required_size {
+ return Err(DeviceMemoryError::DedicatedAllocationSizeMismatch {
+ allocation_size,
+ required_size,
+ });
+ }
+ }
+ }
+ }
- if !(export_handle_bits & ash::vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT)
- .is_empty()
+ if !export_handle_types.is_empty() {
+ if !(device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_external_memory)
{
- if !self.device.enabled_extensions().ext_external_memory_dma_buf {
- return Err(DeviceMemoryAllocError::MissingExtension(
- "ext_external_memory_dmabuf",
- ));
- };
+ return Err(DeviceMemoryError::RequirementNotMet {
+ required_for: "`allocate_info.export_handle_types` is not empty",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_1),
+ device_extensions: &["khr_external_memory"],
+ ..Default::default()
+ },
+ });
}
- if !(export_handle_bits & ash::vk::ExternalMemoryHandleTypeFlags::OPAQUE_FD).is_empty()
- {
- if !self.device.enabled_extensions().khr_external_memory_fd {
- return Err(DeviceMemoryAllocError::MissingExtension(
- "khr_external_memory_fd",
- ));
+ // VUID-VkExportMemoryAllocateInfo-handleTypes-parameter
+ export_handle_types.validate_device(device)?;
+
+ // VUID-VkMemoryAllocateInfo-pNext-00639
+ // VUID-VkExportMemoryAllocateInfo-handleTypes-00656
+ // TODO: how do you fullfill this when you don't know the image or buffer parameters?
+ // Does exporting memory require specifying these parameters up front, and does it tie
+ // the allocation to only images or buffers of that type?
+ }
+
+ if let Some(import_info) = import_info {
+ match *import_info {
+ MemoryImportInfo::Fd {
+ #[cfg(unix)]
+ handle_type,
+ #[cfg(not(unix))]
+ handle_type: _,
+ file: _,
+ } => {
+ if !device.enabled_extensions().khr_external_memory_fd {
+ return Err(DeviceMemoryError::RequirementNotMet {
+ required_for: "`allocate_info.import_info` is \
+ `Some(MemoryImportInfo::Fd)`",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["khr_external_memory_fd"],
+ ..Default::default()
+ },
+ });
+ }
+
+ #[cfg(not(unix))]
+ unreachable!(
+ "`khr_external_memory_fd` was somehow enabled on a non-Unix system"
+ );
+
+ #[cfg(unix)]
+ {
+ // VUID-VkImportMemoryFdInfoKHR-handleType-parameter
+ handle_type.validate_device(device)?;
+
+ // VUID-VkImportMemoryFdInfoKHR-handleType-00669
+ match handle_type {
+ ExternalMemoryHandleType::OpaqueFd => {
+ // VUID-VkMemoryAllocateInfo-allocationSize-01742
+ // Can't validate, must be ensured by user
+
+ // VUID-VkMemoryDedicatedAllocateInfo-buffer-01879
+ // Can't validate, must be ensured by user
+
+ // VUID-VkMemoryDedicatedAllocateInfo-image-01878
+ // Can't validate, must be ensured by user
+ }
+ ExternalMemoryHandleType::DmaBuf => {}
+ _ => {
+ return Err(DeviceMemoryError::ImportFdHandleTypeNotSupported {
+ handle_type,
+ })
+ }
+ }
+
+ // VUID-VkMemoryAllocateInfo-memoryTypeIndex-00648
+ // Can't validate, must be ensured by user
+ }
+ }
+ MemoryImportInfo::Win32 {
+ #[cfg(windows)]
+ handle_type,
+ #[cfg(not(windows))]
+ handle_type: _,
+ handle: _,
+ } => {
+ if !device.enabled_extensions().khr_external_memory_win32 {
+ return Err(DeviceMemoryError::RequirementNotMet {
+ required_for: "`allocate_info.import_info` is \
+ `Some(MemoryImportInfo::Win32)`",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["khr_external_memory_win32"],
+ ..Default::default()
+ },
+ });
+ }
+
+ #[cfg(not(windows))]
+ unreachable!(
+ "`khr_external_memory_win32` was somehow enabled on a non-Windows system"
+ );
+
+ #[cfg(windows)]
+ {
+ // VUID-VkImportMemoryWin32HandleInfoKHR-handleType-parameter
+ handle_type.validate_device(device)?;
+
+ // VUID-VkImportMemoryWin32HandleInfoKHR-handleType-00660
+ match handle_type {
+ ExternalMemoryHandleType::OpaqueWin32
+ | ExternalMemoryHandleType::OpaqueWin32Kmt => {
+ // VUID-VkMemoryAllocateInfo-allocationSize-01742
+ // Can't validate, must be ensured by user
+
+ // VUID-VkMemoryDedicatedAllocateInfo-buffer-01879
+ // Can't validate, must be ensured by user
+
+ // VUID-VkMemoryDedicatedAllocateInfo-image-01878
+ // Can't validate, must be ensured by user
+ }
+ _ => {
+ return Err(DeviceMemoryError::ImportWin32HandleTypeNotSupported {
+ handle_type,
+ })
+ }
+ }
+
+ // VUID-VkMemoryAllocateInfo-memoryTypeIndex-00645
+ // Can't validate, must be ensured by user
+ }
}
}
+ }
- if !(import_handle_bits & ash::vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT)
- .is_empty()
- {
- if !self.device.enabled_extensions().ext_external_memory_dma_buf {
- return Err(DeviceMemoryAllocError::MissingExtension(
- "ext_external_memory_dmabuf",
- ));
- }
+ if !flags.is_empty()
+ && device.physical_device().api_version() < Version::V1_1
+ && !device.enabled_extensions().khr_device_group
+ {
+ return Err(DeviceMemoryError::RequirementNotMet {
+ required_for: "`allocate_info.flags` is not empty",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_1),
+ device_extensions: &["khr_device_group"],
+ ..Default::default()
+ },
+ });
+ }
+
+ if flags.intersects(MemoryAllocateFlags::DEVICE_ADDRESS) {
+ // VUID-VkMemoryAllocateInfo-flags-03331
+ if !device.enabled_features().buffer_device_address {
+ return Err(DeviceMemoryError::RequirementNotMet {
+ required_for: "`allocate_info.flags` contains \
+ `MemoryAllocateFlags::DEVICE_ADDRESS`",
+ requires_one_of: RequiresOneOf {
+ features: &["buffer_device_address"],
+ ..Default::default()
+ },
+ });
}
- if !(import_handle_bits & ash::vk::ExternalMemoryHandleTypeFlags::OPAQUE_FD).is_empty()
- {
- if !self.device.enabled_extensions().khr_external_memory_fd {
- return Err(DeviceMemoryAllocError::MissingExtension(
- "khr_external_memory_fd",
- ));
- }
+ if device.enabled_extensions().ext_buffer_device_address {
+ return Err(DeviceMemoryError::RequirementNotMet {
+ required_for: "`allocate_info.flags` contains \
+ `MemoryAllocateFlags::DEVICE_ADDRESS`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_2),
+ device_extensions: &["khr_buffer_device_address"],
+ ..Default::default()
+ },
+ });
}
}
- let memory = unsafe {
- let physical_device = self.device.physical_device();
- let mut allocation_count = self
- .device
- .allocation_count()
- .lock()
- .expect("Poisoned mutex");
-
- if *allocation_count
- >= physical_device
- .properties()
- .max_memory_allocation_count
- {
- return Err(DeviceMemoryAllocError::TooManyObjects);
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ #[inline(never)]
+ pub unsafe fn allocate_unchecked(
+ device: Arc<Device>,
+ allocate_info: MemoryAllocateInfo<'_>,
+ import_info: Option<MemoryImportInfo>,
+ ) -> Result<Self, VulkanError> {
+ let MemoryAllocateInfo {
+ allocation_size,
+ memory_type_index,
+ dedicated_allocation,
+ export_handle_types,
+ flags,
+ _ne: _,
+ } = allocate_info;
+
+ let mut allocate_info = ash::vk::MemoryAllocateInfo::builder()
+ .allocation_size(allocation_size)
+ .memory_type_index(memory_type_index);
+
+ // VUID-VkMemoryDedicatedAllocateInfo-image-01432
+ let mut dedicated_allocate_info =
+ dedicated_allocation.map(|dedicated_allocation| match dedicated_allocation {
+ DedicatedAllocation::Buffer(buffer) => ash::vk::MemoryDedicatedAllocateInfo {
+ buffer: buffer.handle(),
+ ..Default::default()
+ },
+ DedicatedAllocation::Image(image) => ash::vk::MemoryDedicatedAllocateInfo {
+ image: image.handle(),
+ ..Default::default()
+ },
+ });
+
+ if let Some(info) = dedicated_allocate_info.as_mut() {
+ allocate_info = allocate_info.push_next(info);
+ }
+
+ let mut export_allocate_info = if !export_handle_types.is_empty() {
+ Some(ash::vk::ExportMemoryAllocateInfo {
+ handle_types: export_handle_types.into(),
+ ..Default::default()
+ })
+ } else {
+ None
+ };
+
+ if let Some(info) = export_allocate_info.as_mut() {
+ allocate_info = allocate_info.push_next(info);
+ }
+
+ let imported_handle_type = import_info.as_ref().map(|import_info| match import_info {
+ MemoryImportInfo::Fd { handle_type, .. } => *handle_type,
+ MemoryImportInfo::Win32 { handle_type, .. } => *handle_type,
+ });
+
+ #[cfg(unix)]
+ let mut import_fd_info = match import_info {
+ Some(MemoryImportInfo::Fd { handle_type, file }) => {
+ use std::os::unix::io::IntoRawFd;
+
+ Some(ash::vk::ImportMemoryFdInfoKHR {
+ handle_type: handle_type.into(),
+ fd: file.into_raw_fd(),
+ ..Default::default()
+ })
}
- let fns = self.device.fns();
+ _ => None,
+ };
+
+ #[cfg(unix)]
+ if let Some(info) = import_fd_info.as_mut() {
+ allocate_info = allocate_info.push_next(info);
+ }
+
+ #[cfg(windows)]
+ let mut import_win32_handle_info = match import_info {
+ Some(MemoryImportInfo::Win32 {
+ handle_type,
+ handle,
+ }) => Some(ash::vk::ImportMemoryWin32HandleInfoKHR {
+ handle_type: handle_type.into(),
+ handle,
+ ..Default::default()
+ }),
+ _ => None,
+ };
+
+ #[cfg(windows)]
+ if let Some(info) = import_win32_handle_info.as_mut() {
+ allocate_info = allocate_info.push_next(info);
+ }
+ let mut flags_info = ash::vk::MemoryAllocateFlagsInfo {
+ flags: flags.into(),
+ ..Default::default()
+ };
+
+ if !flags.is_empty() {
+ allocate_info = allocate_info.push_next(&mut flags_info);
+ }
+
+ // VUID-vkAllocateMemory-maxMemoryAllocationCount-04101
+ let max_allocations = device
+ .physical_device()
+ .properties()
+ .max_memory_allocation_count;
+ device
+ .allocation_count
+ .fetch_update(Ordering::Acquire, Ordering::Relaxed, move |count| {
+ (count < max_allocations).then_some(count + 1)
+ })
+ .map_err(|_| VulkanError::TooManyObjects)?;
+
+ let handle = {
+ let fns = device.fns();
let mut output = MaybeUninit::uninit();
- check_errors(fns.v1_0.allocate_memory(
- self.device.internal_object(),
- &self.allocate,
+ (fns.v1_0.allocate_memory)(
+ device.handle(),
+ &allocate_info.build(),
ptr::null(),
output.as_mut_ptr(),
- ))?;
- *allocation_count += 1;
+ )
+ .result()
+ .map_err(|e| {
+ device.allocation_count.fetch_sub(1, Ordering::Release);
+ VulkanError::from(e)
+ })?;
+
output.assume_init()
};
- Ok(Arc::new(DeviceMemory {
- memory: memory,
- device: self.device,
- size: self.allocate.allocation_size,
- memory_type_index: self.allocate.memory_type_index,
- handle_types: ExternalMemoryHandleType::from(export_handle_bits),
- mapped: Mutex::new(false),
- }))
+ Ok(DeviceMemory {
+ handle,
+ device,
+ id: Self::next_id(),
+ allocation_size,
+ memory_type_index,
+ dedicated_to: dedicated_allocation.map(Into::into),
+ export_handle_types,
+ imported_handle_type,
+ flags,
+ })
}
-}
-impl DeviceMemory {
- /// Allocates a chunk of memory from the device.
- ///
- /// Some platforms may have a limit on the maximum size of a single allocation. For example,
- /// certain systems may fail to create allocations with a size greater than or equal to 4GB.
- ///
- /// # Panic
- ///
- /// - Panics if `size` is 0.
- /// - Panics if `memory_type` doesn't belong to the same physical device as `device`.
- ///
+ /// Returns the index of the memory type that this memory was allocated from.
#[inline]
- pub fn alloc(
- device: Arc<Device>,
- memory_type: MemoryType,
- size: DeviceSize,
- ) -> Result<DeviceMemory, DeviceMemoryAllocError> {
- let memory = DeviceMemoryBuilder::new(device, memory_type.id(), size).build()?;
- // Will never panic because we call the DeviceMemoryBuilder internally, and that only
- // returns an atomically refcounted DeviceMemory object on success.
- Ok(Arc::try_unwrap(memory).unwrap())
+ pub fn memory_type_index(&self) -> u32 {
+ self.memory_type_index
}
- /// Same as `alloc`, but allows specifying a resource that will be bound to the memory.
- ///
- /// If a buffer or an image is specified in `resource`, then the returned memory must not be
- /// bound to a different buffer or image.
- ///
- /// If the `VK_KHR_dedicated_allocation` extension is enabled on the device, then it will be
- /// used by this method. Otherwise the `resource` parameter will be ignored.
+ /// Returns the size in bytes of the memory allocation.
#[inline]
- pub fn dedicated_alloc(
- device: Arc<Device>,
- memory_type: MemoryType,
- size: DeviceSize,
- resource: DedicatedAlloc,
- ) -> Result<DeviceMemory, DeviceMemoryAllocError> {
- let memory = DeviceMemoryBuilder::new(device, memory_type.id(), size)
- .dedicated_info(resource)
- .build()?;
-
- // Will never panic because we call the DeviceMemoryBuilder internally, and that only
- // returns an atomically refcounted DeviceMemory object on success.
- Ok(Arc::try_unwrap(memory).unwrap())
+ pub fn allocation_size(&self) -> DeviceSize {
+ self.allocation_size
}
- /// Allocates a chunk of memory and maps it.
- ///
- /// # Panic
- ///
- /// - Panics if `memory_type` doesn't belong to the same physical device as `device`.
- /// - Panics if the memory type is not host-visible.
+ /// Returns `true` if the memory is a [dedicated] to a resource.
///
+ /// [dedicated]: MemoryAllocateInfo#structfield.dedicated_allocation
#[inline]
- pub fn alloc_and_map(
- device: Arc<Device>,
- memory_type: MemoryType,
- size: DeviceSize,
- ) -> Result<MappedDeviceMemory, DeviceMemoryAllocError> {
- DeviceMemory::dedicated_alloc_and_map(device, memory_type, size, DedicatedAlloc::None)
+ pub fn is_dedicated(&self) -> bool {
+ self.dedicated_to.is_some()
}
- /// Equivalent of `dedicated_alloc` for `alloc_and_map`.
- pub fn dedicated_alloc_and_map(
- device: Arc<Device>,
- memory_type: MemoryType,
- size: DeviceSize,
- resource: DedicatedAlloc,
- ) -> Result<MappedDeviceMemory, DeviceMemoryAllocError> {
- let fns = device.fns();
-
- assert!(memory_type.is_host_visible());
- let mem = DeviceMemory::dedicated_alloc(device.clone(), memory_type, size, resource)?;
-
- Self::map_allocation(device.clone(), mem)
+ pub(crate) fn dedicated_to(&self) -> Option<DedicatedTo> {
+ self.dedicated_to
}
- /// Same as `alloc`, but allows exportable file descriptor on Linux.
+ /// Returns the handle types that can be exported from the memory allocation.
#[inline]
- #[cfg(target_os = "linux")]
- pub fn alloc_with_exportable_fd(
- device: Arc<Device>,
- memory_type: MemoryType,
- size: DeviceSize,
- ) -> Result<DeviceMemory, DeviceMemoryAllocError> {
- let memory = DeviceMemoryBuilder::new(device, memory_type.id(), size)
- .export_info(ExternalMemoryHandleType {
- opaque_fd: true,
- ..ExternalMemoryHandleType::none()
- })
- .build()?;
-
- // Will never panic because we call the DeviceMemoryBuilder internally, and that only
- // returns an atomically refcounted DeviceMemory object on success.
- Ok(Arc::try_unwrap(memory).unwrap())
+ pub fn export_handle_types(&self) -> ExternalMemoryHandleTypes {
+ self.export_handle_types
}
- /// Same as `dedicated_alloc`, but allows exportable file descriptor on Linux.
+ /// Returns the handle type that the memory allocation was imported from, if any.
#[inline]
- #[cfg(target_os = "linux")]
- pub fn dedicated_alloc_with_exportable_fd(
- device: Arc<Device>,
- memory_type: MemoryType,
- size: DeviceSize,
- resource: DedicatedAlloc,
- ) -> Result<DeviceMemory, DeviceMemoryAllocError> {
- let memory = DeviceMemoryBuilder::new(device, memory_type.id(), size)
- .export_info(ExternalMemoryHandleType {
- opaque_fd: true,
- ..ExternalMemoryHandleType::none()
- })
- .dedicated_info(resource)
- .build()?;
-
- // Will never panic because we call the DeviceMemoryBuilder internally, and that only
- // returns an atomically refcounted DeviceMemory object on success.
- Ok(Arc::try_unwrap(memory).unwrap())
+ pub fn imported_handle_type(&self) -> Option<ExternalMemoryHandleType> {
+ self.imported_handle_type
}
- /// Same as `alloc_and_map`, but allows exportable file descriptor on Linux.
+ /// Returns the flags the memory was allocated with.
#[inline]
- #[cfg(target_os = "linux")]
- pub fn alloc_and_map_with_exportable_fd(
- device: Arc<Device>,
- memory_type: MemoryType,
- size: DeviceSize,
- ) -> Result<MappedDeviceMemory, DeviceMemoryAllocError> {
- DeviceMemory::dedicated_alloc_and_map_with_exportable_fd(
- device,
- memory_type,
- size,
- DedicatedAlloc::None,
- )
+ pub fn flags(&self) -> MemoryAllocateFlags {
+ self.flags
}
- /// Same as `dedicated_alloc_and_map`, but allows exportable file descriptor on Linux.
+ /// Retrieves the amount of lazily-allocated memory that is currently commited to this
+ /// memory object.
+ ///
+ /// The device may change this value at any time, and the returned value may be
+ /// already out-of-date.
+ ///
+ /// `self` must have been allocated from a memory type that has the [`LAZILY_ALLOCATED`] flag
+ /// set.
+ ///
+ /// [`LAZILY_ALLOCATED`]: crate::memory::MemoryPropertyFlags::LAZILY_ALLOCATED
#[inline]
- #[cfg(target_os = "linux")]
- pub fn dedicated_alloc_and_map_with_exportable_fd(
- device: Arc<Device>,
- memory_type: MemoryType,
- size: DeviceSize,
- resource: DedicatedAlloc,
- ) -> Result<MappedDeviceMemory, DeviceMemoryAllocError> {
- let fns = device.fns();
-
- assert!(memory_type.is_host_visible());
- let mem = DeviceMemory::dedicated_alloc_with_exportable_fd(
- device.clone(),
- memory_type,
- size,
- resource,
- )?;
+ pub fn commitment(&self) -> Result<DeviceSize, DeviceMemoryError> {
+ self.validate_commitment()?;
- Self::map_allocation(device.clone(), mem)
+ unsafe { Ok(self.commitment_unchecked()) }
}
- fn map_allocation(
- device: Arc<Device>,
- mem: DeviceMemory,
- ) -> Result<MappedDeviceMemory, DeviceMemoryAllocError> {
- let fns = device.fns();
- let coherent = mem.memory_type().is_host_coherent();
- let ptr = unsafe {
- let mut output = MaybeUninit::uninit();
- check_errors(fns.v1_0.map_memory(
- device.internal_object(),
- mem.memory,
- 0,
- mem.size,
- ash::vk::MemoryMapFlags::empty(),
- output.as_mut_ptr(),
- ))?;
- output.assume_init()
- };
+ fn validate_commitment(&self) -> Result<(), DeviceMemoryError> {
+ let memory_type = &self
+ .device
+ .physical_device()
+ .memory_properties()
+ .memory_types[self.memory_type_index as usize];
- Ok(MappedDeviceMemory {
- memory: mem,
- pointer: ptr,
- coherent,
- })
- }
+ // VUID-vkGetDeviceMemoryCommitment-memory-00690
+ if !memory_type
+ .property_flags
+ .intersects(MemoryPropertyFlags::LAZILY_ALLOCATED)
+ {
+ return Err(DeviceMemoryError::NotLazilyAllocated);
+ }
- /// Returns the memory type this chunk was allocated on.
- #[inline]
- pub fn memory_type(&self) -> MemoryType {
- self.device
- .physical_device()
- .memory_type_by_id(self.memory_type_index)
- .unwrap()
+ Ok(())
}
- /// Returns the size in bytes of that memory chunk.
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
#[inline]
- pub fn size(&self) -> DeviceSize {
- self.size
+ pub unsafe fn commitment_unchecked(&self) -> DeviceSize {
+ let mut output: DeviceSize = 0;
+
+ let fns = self.device.fns();
+ (fns.v1_0.get_device_memory_commitment)(self.device.handle(), self.handle, &mut output);
+
+ output
}
- /// Exports the device memory into a Unix file descriptor. The caller retains ownership of the
- /// file, as per the Vulkan spec.
+ /// Exports the device memory into a Unix file descriptor. The caller owns the returned `File`.
///
- /// # Panic
+ /// # Panics
///
/// - Panics if the user requests an invalid handle type for this device memory object.
#[inline]
- #[cfg(any(target_os = "android", target_os = "linux"))]
pub fn export_fd(
&self,
handle_type: ExternalMemoryHandleType,
- ) -> Result<File, DeviceMemoryAllocError> {
- let fns = self.device.fns();
+ ) -> Result<std::fs::File, DeviceMemoryError> {
+ // VUID-VkMemoryGetFdInfoKHR-handleType-parameter
+ handle_type.validate_device(&self.device)?;
+
+ // VUID-VkMemoryGetFdInfoKHR-handleType-00672
+ if !matches!(
+ handle_type,
+ ExternalMemoryHandleType::OpaqueFd | ExternalMemoryHandleType::DmaBuf
+ ) {
+ return Err(DeviceMemoryError::HandleTypeNotSupported { handle_type });
+ }
- // VUID-VkMemoryGetFdInfoKHR-handleType-00672: "handleType must be defined as a POSIX file
- // descriptor handle".
- let bits = ash::vk::ExternalMemoryHandleTypeFlags::from(handle_type);
- if bits != ash::vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT
- && bits != ash::vk::ExternalMemoryHandleTypeFlags::OPAQUE_FD
+ // VUID-VkMemoryGetFdInfoKHR-handleType-00671
+ if !ash::vk::ExternalMemoryHandleTypeFlags::from(self.export_handle_types)
+ .intersects(ash::vk::ExternalMemoryHandleTypeFlags::from(handle_type))
{
- return Err(DeviceMemoryAllocError::SpecViolation(672))?;
+ return Err(DeviceMemoryError::HandleTypeNotSupported { handle_type });
}
- // VUID-VkMemoryGetFdInfoKHR-handleType-00671: "handleType must have been included in
- // VkExportMemoryAllocateInfo::handleTypes when memory was created".
- if (bits & ash::vk::ExternalMemoryHandleTypeFlags::from(self.handle_types)).is_empty() {
- return Err(DeviceMemoryAllocError::SpecViolation(671))?;
- }
+ debug_assert!(self.device().enabled_extensions().khr_external_memory_fd);
- let fd = unsafe {
- let info = ash::vk::MemoryGetFdInfoKHR {
- memory: self.memory,
- handle_type: handle_type.into(),
- ..Default::default()
+ #[cfg(not(unix))]
+ unreachable!("`khr_external_memory_fd` was somehow enabled on a non-Unix system");
+
+ #[cfg(unix)]
+ {
+ use std::os::unix::io::FromRawFd;
+
+ let fd = unsafe {
+ let fns = self.device.fns();
+ let info = ash::vk::MemoryGetFdInfoKHR {
+ memory: self.handle,
+ handle_type: handle_type.into(),
+ ..Default::default()
+ };
+
+ let mut output = MaybeUninit::uninit();
+ (fns.khr_external_memory_fd.get_memory_fd_khr)(
+ self.device.handle(),
+ &info,
+ output.as_mut_ptr(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+ output.assume_init()
};
- let mut output = MaybeUninit::uninit();
- check_errors(fns.khr_external_memory_fd.get_memory_fd_khr(
- self.device.internal_object(),
- &info,
- output.as_mut_ptr(),
- ))?;
- output.assume_init()
- };
+ let file = unsafe { std::fs::File::from_raw_fd(fd) };
+
+ Ok(file)
+ }
+ }
+}
+
+impl Drop for DeviceMemory {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ let fns = self.device.fns();
+ (fns.v1_0.free_memory)(self.device.handle(), self.handle, ptr::null());
+ self.device.allocation_count.fetch_sub(1, Ordering::Release);
+ }
+ }
+}
+
+unsafe impl VulkanObject for DeviceMemory {
+ type Handle = ash::vk::DeviceMemory;
- let file = unsafe { File::from_raw_fd(fd) };
- Ok(file)
+ #[inline]
+ fn handle(&self) -> Self::Handle {
+ self.handle
}
}
@@ -626,74 +748,447 @@ unsafe impl DeviceOwned for DeviceMemory {
}
}
-impl fmt::Debug for DeviceMemory {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- fmt.debug_struct("DeviceMemory")
- .field("device", &*self.device)
- .field("memory_type", &self.memory_type())
- .field("size", &self.size)
- .finish()
- }
-}
+impl_id_counter!(DeviceMemory);
-unsafe impl VulkanObject for DeviceMemory {
- type Object = ash::vk::DeviceMemory;
+/// Parameters to allocate a new `DeviceMemory`.
+#[derive(Clone, Debug)]
+pub struct MemoryAllocateInfo<'d> {
+ /// The number of bytes to allocate.
+ ///
+ /// The default value is `0`, which must be overridden.
+ pub allocation_size: DeviceSize,
+
+ /// The index of the memory type that should be allocated.
+ ///
+ /// The default value is [`u32::MAX`], which must be overridden.
+ pub memory_type_index: u32,
+
+ /// Allocates memory for a specific buffer or image.
+ ///
+ /// This value is silently ignored (treated as `None`) if the device API version is less than
+ /// 1.1 and the
+ /// [`khr_dedicated_allocation`](crate::device::DeviceExtensions::khr_dedicated_allocation)
+ /// extension is not enabled on the device.
+ pub dedicated_allocation: Option<DedicatedAllocation<'d>>,
+
+ /// The handle types that can be exported from the allocated memory.
+ pub export_handle_types: ExternalMemoryHandleTypes,
+
+ /// Additional flags for the memory allocation.
+ ///
+ /// If not empty, the device API version must be at least 1.1, or the
+ /// [`khr_device_group`](crate::device::DeviceExtensions::khr_device_group) extension must be
+ /// enabled on the device.
+ ///
+ /// The default value is [`MemoryAllocateFlags::empty()`].
+ pub flags: MemoryAllocateFlags,
+
+ pub _ne: crate::NonExhaustive,
+}
+impl Default for MemoryAllocateInfo<'static> {
#[inline]
- fn internal_object(&self) -> ash::vk::DeviceMemory {
- self.memory
+ fn default() -> Self {
+ Self {
+ allocation_size: 0,
+ memory_type_index: u32::MAX,
+ dedicated_allocation: None,
+ export_handle_types: ExternalMemoryHandleTypes::empty(),
+ flags: MemoryAllocateFlags::empty(),
+ _ne: crate::NonExhaustive(()),
+ }
}
}
-impl Drop for DeviceMemory {
+impl<'d> MemoryAllocateInfo<'d> {
+ /// Returns a `MemoryAllocateInfo` with the specified `dedicated_allocation`.
#[inline]
- fn drop(&mut self) {
- unsafe {
- let fns = self.device.fns();
- fns.v1_0
- .free_memory(self.device.internal_object(), self.memory, ptr::null());
- let mut allocation_count = self
- .device
- .allocation_count()
- .lock()
- .expect("Poisoned mutex");
- *allocation_count -= 1;
+ pub fn dedicated_allocation(dedicated_allocation: DedicatedAllocation<'d>) -> Self {
+ Self {
+ allocation_size: 0,
+ memory_type_index: u32::MAX,
+ dedicated_allocation: Some(dedicated_allocation),
+ export_handle_types: ExternalMemoryHandleTypes::empty(),
+ flags: MemoryAllocateFlags::empty(),
+ _ne: crate::NonExhaustive(()),
}
}
}
-/// Represents memory that has been allocated and mapped in CPU accessible space.
-///
-/// Can be obtained with `DeviceMemory::alloc_and_map`. The function will panic if the memory type
-/// is not host-accessible.
+/// Parameters to import memory from an external source.
+#[derive(Debug)]
+#[non_exhaustive]
+pub enum MemoryImportInfo {
+ /// Import memory from a Unix file descriptor.
+ ///
+ /// `handle_type` must be either [`ExternalMemoryHandleType::OpaqueFd`] or
+ /// [`ExternalMemoryHandleType::DmaBuf`].
+ ///
+ /// # Safety
+ ///
+ /// - `file` must be a valid Unix file descriptor.
+ /// - Vulkan will take ownership of `file`, and once the memory is imported, you must not
+ /// perform any operations on `file` nor on any of its clones/duplicates.
+ /// - If `file` was created by the Vulkan API, and `handle_type` is
+ /// [`ExternalMemoryHandleType::OpaqueFd`]:
+ /// - [`MemoryAllocateInfo::allocation_size`] and [`MemoryAllocateInfo::memory_type_index`]
+ /// must match those of the original memory allocation.
+ /// - If the original memory allocation used [`MemoryAllocateInfo::dedicated_allocation`],
+ /// the imported one must also use it, and the associated buffer or image must be defined
+ /// identically to the original.
+ /// - If `file` was not created by the Vulkan API, then
+ /// [`MemoryAllocateInfo::memory_type_index`] must be one of the memory types returned by
+ /// [`Device::memory_fd_properties`].
+ Fd {
+ handle_type: ExternalMemoryHandleType,
+ file: File,
+ },
+
+ /// Import memory from a Windows handle.
+ ///
+ /// `handle_type` must be either [`ExternalMemoryHandleType::OpaqueWin32`] or
+ /// [`ExternalMemoryHandleType::OpaqueWin32Kmt`].
+ ///
+ /// # Safety
+ ///
+ /// - `handle` must be a valid Windows handle.
+ /// - Vulkan will not take ownership of `handle`.
+ /// - If `handle_type` is [`ExternalMemoryHandleType::OpaqueWin32`], it owns a reference
+ /// to the underlying resource and must eventually be closed by the caller.
+ /// - If `handle_type` is [`ExternalMemoryHandleType::OpaqueWin32Kmt`], it does not own a
+ /// reference to the underlying resource.
+ /// - `handle` must be created by the Vulkan API.
+ /// - [`MemoryAllocateInfo::allocation_size`] and [`MemoryAllocateInfo::memory_type_index`]
+ /// must match those of the original memory allocation.
+ /// - If the original memory allocation used [`MemoryAllocateInfo::dedicated_allocation`],
+ /// the imported one must also use it, and the associated buffer or image must be defined
+ /// identically to the original.
+ Win32 {
+ handle_type: ExternalMemoryHandleType,
+ handle: ash::vk::HANDLE,
+ },
+}
+
+vulkan_bitflags_enum! {
+ #[non_exhaustive]
+
+ /// A set of [`ExternalMemoryHandleType`] values.
+ ExternalMemoryHandleTypes,
+
+ /// A handle type used to export or import memory to/from an external source.
+ ExternalMemoryHandleType,
+
+ = ExternalMemoryHandleTypeFlags(u32);
+
+ /// A POSIX file descriptor handle that is only usable with Vulkan and compatible APIs.
+ OPAQUE_FD, OpaqueFd = OPAQUE_FD,
+
+ /// A Windows NT handle that is only usable with Vulkan and compatible APIs.
+ OPAQUE_WIN32, OpaqueWin32 = OPAQUE_WIN32,
+
+ /// A Windows global share handle that is only usable with Vulkan and compatible APIs.
+ OPAQUE_WIN32_KMT, OpaqueWin32Kmt = OPAQUE_WIN32_KMT,
+
+ /// A Windows NT handle that refers to a Direct3D 10 or 11 texture resource.
+ D3D11_TEXTURE, D3D11Texture = D3D11_TEXTURE,
+
+ /// A Windows global share handle that refers to a Direct3D 10 or 11 texture resource.
+ D3D11_TEXTURE_KMT, D3D11TextureKmt = D3D11_TEXTURE_KMT,
+
+ /// A Windows NT handle that refers to a Direct3D 12 heap resource.
+ D3D12_HEAP, D3D12Heap = D3D12_HEAP,
+
+ /// A Windows NT handle that refers to a Direct3D 12 committed resource.
+ D3D12_RESOURCE, D3D12Resource = D3D12_RESOURCE,
+
+ /// A POSIX file descriptor handle that refers to a Linux dma-buf.
+ DMA_BUF, DmaBuf = DMA_BUF_EXT {
+ device_extensions: [ext_external_memory_dma_buf],
+ },
+
+ /// A handle for an Android `AHardwareBuffer` object.
+ ANDROID_HARDWARE_BUFFER, AndroidHardwareBuffer = ANDROID_HARDWARE_BUFFER_ANDROID {
+ device_extensions: [android_external_memory_android_hardware_buffer],
+ },
+
+ /// A pointer to memory that was allocated by the host.
+ HOST_ALLOCATION, HostAllocation = HOST_ALLOCATION_EXT {
+ device_extensions: [ext_external_memory_host],
+ },
+
+ /// A pointer to a memory mapping on the host that maps non-host memory.
+ HOST_MAPPED_FOREIGN_MEMORY, HostMappedForeignMemory = HOST_MAPPED_FOREIGN_MEMORY_EXT {
+ device_extensions: [ext_external_memory_host],
+ },
+
+ /// A Zircon handle to a virtual memory object.
+ ZIRCON_VMO, ZirconVmo = ZIRCON_VMO_FUCHSIA {
+ device_extensions: [fuchsia_external_memory],
+ },
+
+ /// A Remote Direct Memory Address handle to an allocation that is accessible by remote devices.
+ RDMA_ADDRESS, RdmaAddress = RDMA_ADDRESS_NV {
+ device_extensions: [nv_external_memory_rdma],
+ },
+}
+
+vulkan_bitflags! {
+ #[non_exhaustive]
+
+ /// A mask specifying flags for device memory allocation.
+ MemoryAllocateFlags = MemoryAllocateFlags(u32);
+
+ /* TODO: enable
+ DEVICE_MASK = DEVICE_MASK,*/
+
+ /// Specifies that the allocated device memory can be bound to a buffer created with the
+ /// [`SHADER_DEVICE_ADDRESS`] usage. This requires that the [`buffer_device_address`] feature
+ /// is enabled on the device and the [`ext_buffer_device_address`] extension is not enabled on
+ /// the device.
+ ///
+ /// [`SHADER_DEVICE_ADDRESS`]: crate::buffer::BufferUsage::SHADER_DEVICE_ADDRESS
+ /// [`buffer_device_address`]: crate::device::Features::buffer_device_address
+ /// [`ext_buffer_device_address`]: crate::device::DeviceExtensions::ext_buffer_device_address
+ DEVICE_ADDRESS = DEVICE_ADDRESS,
+
+ /* TODO: enable
+ DEVICE_ADDRESS_CAPTURE_REPLAY = DEVICE_ADDRESS_CAPTURE_REPLAY,*/
+}
+
+/// Error type returned by functions related to `DeviceMemory`.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum DeviceMemoryError {
+ /// Not enough memory available.
+ OomError(OomError),
+
+ /// The maximum number of allocations has been exceeded.
+ TooManyObjects,
+
+ /// An error occurred when mapping the memory.
+ MemoryMapError(MemoryMapError),
+
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+
+ /// `dedicated_allocation` was `Some`, but the provided `allocation_size` was different from
+ /// the required size of the buffer or image.
+ DedicatedAllocationSizeMismatch {
+ allocation_size: DeviceSize,
+ required_size: DeviceSize,
+ },
+
+ /// The requested export handle type is not supported for this operation, or was not provided in
+ /// `export_handle_types` when allocating the memory.
+ HandleTypeNotSupported {
+ handle_type: ExternalMemoryHandleType,
+ },
+
+ /// The provided `MemoryImportInfo::Fd::handle_type` is not supported for file descriptors.
+ ImportFdHandleTypeNotSupported {
+ handle_type: ExternalMemoryHandleType,
+ },
+
+ /// The provided `MemoryImportInfo::Win32::handle_type` is not supported.
+ ImportWin32HandleTypeNotSupported {
+ handle_type: ExternalMemoryHandleType,
+ },
+
+ /// The provided `allocation_size` was greater than the memory type's heap size.
+ MemoryTypeHeapSizeExceeded {
+ allocation_size: DeviceSize,
+ heap_size: DeviceSize,
+ },
+
+ /// The provided `memory_type_index` was not less than the number of memory types in the
+ /// physical device.
+ MemoryTypeIndexOutOfRange {
+ memory_type_index: u32,
+ memory_type_count: u32,
+ },
+
+ /// The memory type from which this memory was allocated does not have the [`LAZILY_ALLOCATED`]
+ /// flag set.
+ ///
+ /// [`LAZILY_ALLOCATED`]: crate::memory::MemoryPropertyFlags::LAZILY_ALLOCATED
+ NotLazilyAllocated,
+
+ /// Spec violation, containing the Valid Usage ID (VUID) from the Vulkan spec.
+ // TODO: Remove
+ SpecViolation(u32),
+
+ /// An implicit violation that's convered in the Vulkan spec.
+ // TODO: Remove
+ ImplicitSpecViolation(&'static str),
+}
+
+impl Error for DeviceMemoryError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::OomError(err) => Some(err),
+ Self::MemoryMapError(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+impl Display for DeviceMemoryError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::OomError(_) => write!(f, "not enough memory available"),
+ Self::TooManyObjects => {
+ write!(f, "the maximum number of allocations has been exceeded")
+ }
+ Self::MemoryMapError(_) => write!(f, "error occurred when mapping the memory"),
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ Self::DedicatedAllocationSizeMismatch {
+ allocation_size,
+ required_size,
+ } => write!(
+ f,
+ "`dedicated_allocation` was `Some`, but the provided `allocation_size` ({}) was \
+ different from the required size of the buffer or image ({})",
+ allocation_size, required_size,
+ ),
+ Self::HandleTypeNotSupported { handle_type } => write!(
+ f,
+ "the requested export handle type ({:?}) is not supported for this operation, or \
+ was not provided in `export_handle_types` when allocating the memory",
+ handle_type,
+ ),
+ Self::ImportFdHandleTypeNotSupported { handle_type } => write!(
+ f,
+ "the provided `MemoryImportInfo::Fd::handle_type` ({:?}) is not supported for file \
+ descriptors",
+ handle_type,
+ ),
+ Self::ImportWin32HandleTypeNotSupported { handle_type } => write!(
+ f,
+ "the provided `MemoryImportInfo::Win32::handle_type` ({:?}) is not supported",
+ handle_type,
+ ),
+ Self::MemoryTypeHeapSizeExceeded {
+ allocation_size,
+ heap_size,
+ } => write!(
+ f,
+ "the provided `allocation_size` ({}) was greater than the memory type's heap size \
+ ({})",
+ allocation_size, heap_size,
+ ),
+ Self::MemoryTypeIndexOutOfRange {
+ memory_type_index,
+ memory_type_count,
+ } => write!(
+ f,
+ "the provided `memory_type_index` ({}) was not less than the number of memory \
+ types in the physical device ({})",
+ memory_type_index, memory_type_count,
+ ),
+ Self::NotLazilyAllocated => write!(
+ f,
+ "the memory type from which this memory was allocated does not have the \
+ `lazily_allocated` flag set",
+ ),
+
+ Self::SpecViolation(u) => {
+ write!(f, "valid usage ID check {} failed", u)
+ }
+ Self::ImplicitSpecViolation(e) => {
+ write!(f, "Implicit spec violation failed {}", e)
+ }
+ }
+ }
+}
+
+impl From<VulkanError> for DeviceMemoryError {
+ fn from(err: VulkanError) -> Self {
+ match err {
+ e @ VulkanError::OutOfHostMemory | e @ VulkanError::OutOfDeviceMemory => {
+ Self::OomError(e.into())
+ }
+ VulkanError::TooManyObjects => Self::TooManyObjects,
+ _ => panic!("unexpected error: {:?}", err),
+ }
+ }
+}
+
+impl From<OomError> for DeviceMemoryError {
+ fn from(err: OomError) -> Self {
+ Self::OomError(err)
+ }
+}
+
+impl From<MemoryMapError> for DeviceMemoryError {
+ fn from(err: MemoryMapError) -> Self {
+ Self::MemoryMapError(err)
+ }
+}
+
+impl From<RequirementNotMet> for DeviceMemoryError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
+ }
+ }
+}
+
+/// Represents device memory that has been mapped in a CPU-accessible space.
///
-/// In order to access the content of the allocated memory, you can use the `read_write` method.
-/// This method returns a guard object that derefs to the content.
+/// In order to access the contents of the allocated memory, you can use the `read` and `write`
+/// methods.
///
-/// # Example
+/// # Examples
///
/// ```
-/// use vulkano::memory::DeviceMemory;
+/// use vulkano::memory::{DeviceMemory, MappedDeviceMemory, MemoryAllocateInfo, MemoryPropertyFlags};
///
/// # let device: std::sync::Arc<vulkano::device::Device> = return;
/// // The memory type must be mappable.
-/// let mem_ty = device.physical_device().memory_types()
-/// .filter(|t| t.is_host_visible())
-/// .next().unwrap(); // Vk specs guarantee that this can't fail
+/// let memory_type_index = device
+/// .physical_device()
+/// .memory_properties()
+/// .memory_types
+/// .iter()
+/// .position(|t| t.property_flags.intersects(MemoryPropertyFlags::HOST_VISIBLE))
+/// .map(|i| i as u32)
+/// .unwrap(); // Vk specs guarantee that this can't fail
///
/// // Allocates 1KB of memory.
-/// let memory = DeviceMemory::alloc_and_map(device.clone(), mem_ty, 1024).unwrap();
+/// let memory = DeviceMemory::allocate(
+/// device.clone(),
+/// MemoryAllocateInfo {
+/// allocation_size: 1024,
+/// memory_type_index,
+/// ..Default::default()
+/// },
+/// )
+/// .unwrap();
+/// let mapped_memory = MappedDeviceMemory::new(memory, 0..1024).unwrap();
///
-/// // Get access to the content. Note that this is very unsafe for two reasons: 1) the content is
-/// // uninitialized, and 2) the access is unsynchronized.
+/// // Get access to the content.
+/// // Note that this is very unsafe because the access is unsynchronized.
/// unsafe {
-/// let mut content = memory.read_write::<[u8]>(0 .. 1024);
-/// content[12] = 54; // `content` derefs to a `&[u8]` or a `&mut [u8]`
+/// let content = mapped_memory.write(0..1024).unwrap();
+/// content[12] = 54;
/// }
/// ```
+#[derive(Debug)]
pub struct MappedDeviceMemory {
memory: DeviceMemory,
- pointer: *mut c_void,
+ pointer: *mut c_void, // points to `range.start`
+ range: Range<DeviceSize>,
+
+ atom_size: DeviceAlignment,
coherent: bool,
}
@@ -702,405 +1197,423 @@ pub struct MappedDeviceMemory {
//
// Vulkan specs, documentation of `vkFreeMemory`:
// > If a memory object is mapped at the time it is freed, it is implicitly unmapped.
-//
impl MappedDeviceMemory {
- /// Unmaps the memory. It will no longer be accessible from the CPU.
- pub fn unmap(self) -> DeviceMemory {
- unsafe {
- let device = self.memory.device();
- let fns = device.fns();
- fns.v1_0
- .unmap_memory(device.internal_object(), self.memory.memory);
- }
-
- self.memory
- }
-
- /// Gives access to the content of the memory.
+ /// Maps a range of memory to be accessed by the CPU.
///
- /// This function takes care of calling `vkInvalidateMappedMemoryRanges` and
- /// `vkFlushMappedMemoryRanges` on the given range. You are therefore encouraged to use the
- /// smallest range as possible, and to not call this function multiple times in a row for
- /// several small changes.
+ /// `memory` must be allocated from host-visible memory.
///
- /// # Safety
+ /// `range` is specified in bytes relative to the start of the memory allocation, and must fall
+ /// within the range of the allocation (`0..allocation_size`). If `memory` was not allocated
+ /// from host-coherent memory, then the start and end of `range` must be a multiple of the
+ /// [`non_coherent_atom_size`](crate::device::Properties::non_coherent_atom_size) device
+ /// property, but `range.end` can also the memory's `allocation_size`.
///
- /// - Type safety is not checked. You must ensure that `T` corresponds to the content of the
- /// buffer.
- /// - Accesses are not synchronized. Synchronization must be handled outside of
- /// the `MappedDeviceMemory`.
+ /// # Panics
///
- #[inline]
- pub unsafe fn read_write<T: ?Sized>(&self, range: Range<DeviceSize>) -> CpuAccess<T>
- where
- T: Content,
- {
- let fns = self.memory.device().fns();
- let pointer = T::ref_from_ptr(
- (self.pointer as usize + range.start as usize) as *mut _,
- (range.end - range.start) as usize,
- )
- .unwrap(); // TODO: error
+ /// - Panics if `range` is empty.
+ pub fn new(memory: DeviceMemory, range: Range<DeviceSize>) -> Result<Self, MemoryMapError> {
+ // VUID-vkMapMemory-size-00680
+ assert!(!range.is_empty());
+
+ // VUID-vkMapMemory-memory-00678
+ // Guaranteed because we take ownership of `memory`, no other mapping can exist.
+
+ // VUID-vkMapMemory-offset-00679
+ // VUID-vkMapMemory-size-00681
+ if range.end > memory.allocation_size {
+ return Err(MemoryMapError::OutOfRange {
+ provided_range: range,
+ allowed_range: 0..memory.allocation_size,
+ });
+ }
- if !self.coherent {
- let range = ash::vk::MappedMemoryRange {
- memory: self.memory.internal_object(),
- offset: range.start,
- size: range.end - range.start,
- ..Default::default()
- };
+ let device = memory.device();
+ let memory_type = &device.physical_device().memory_properties().memory_types
+ [memory.memory_type_index() as usize];
- // TODO: return result instead?
- check_errors(fns.v1_0.invalidate_mapped_memory_ranges(
- self.memory.device().internal_object(),
- 1,
- &range,
- ))
- .unwrap();
+ // VUID-vkMapMemory-memory-00682
+ if !memory_type
+ .property_flags
+ .intersects(MemoryPropertyFlags::HOST_VISIBLE)
+ {
+ return Err(MemoryMapError::NotHostVisible);
}
- CpuAccess {
- pointer: pointer,
- mem: self,
- coherent: self.coherent,
- range,
+ let coherent = memory_type
+ .property_flags
+ .intersects(MemoryPropertyFlags::HOST_COHERENT);
+ let atom_size = device.physical_device().properties().non_coherent_atom_size;
+
+ // Not required for merely mapping, but without this check the user can end up with
+ // parts of the mapped memory at the start and end that they're not able to
+ // invalidate/flush, which is probably unintended.
+ if !coherent
+ && (!is_aligned(range.start, atom_size)
+ || (!is_aligned(range.end, atom_size) && range.end != memory.allocation_size))
+ {
+ return Err(MemoryMapError::RangeNotAlignedToAtomSize { range, atom_size });
}
- }
-}
-impl AsRef<DeviceMemory> for MappedDeviceMemory {
- #[inline]
- fn as_ref(&self) -> &DeviceMemory {
- &self.memory
- }
-}
+ let pointer = unsafe {
+ let fns = device.fns();
+ let mut output = MaybeUninit::uninit();
+ (fns.v1_0.map_memory)(
+ device.handle(),
+ memory.handle,
+ range.start,
+ range.end - range.start,
+ ash::vk::MemoryMapFlags::empty(),
+ output.as_mut_ptr(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+ output.assume_init()
+ };
-impl AsMut<DeviceMemory> for MappedDeviceMemory {
- #[inline]
- fn as_mut(&mut self) -> &mut DeviceMemory {
- &mut self.memory
+ Ok(MappedDeviceMemory {
+ memory,
+ pointer,
+ range,
+ atom_size,
+ coherent,
+ })
}
-}
-unsafe impl DeviceOwned for MappedDeviceMemory {
+ /// Unmaps the memory. It will no longer be accessible from the CPU.
#[inline]
- fn device(&self) -> &Arc<Device> {
- self.memory.device()
- }
-}
-
-unsafe impl Send for MappedDeviceMemory {}
-unsafe impl Sync for MappedDeviceMemory {}
+ pub fn unmap(self) -> DeviceMemory {
+ unsafe {
+ let device = self.memory.device();
+ let fns = device.fns();
+ (fns.v1_0.unmap_memory)(device.handle(), self.memory.handle);
+ }
-impl fmt::Debug for MappedDeviceMemory {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- fmt.debug_tuple("MappedDeviceMemory")
- .field(&self.memory)
- .finish()
+ self.memory
}
-}
-
-unsafe impl Send for DeviceMemoryMapping {}
-unsafe impl Sync for DeviceMemoryMapping {}
-
-/// Represents memory mapped in CPU accessible space.
-///
-/// Takes an additional reference on the underlying device memory and device.
-pub struct DeviceMemoryMapping {
- device: Arc<Device>,
- memory: Arc<DeviceMemory>,
- pointer: *mut c_void,
- coherent: bool,
-}
-impl DeviceMemoryMapping {
- /// Creates a new `DeviceMemoryMapping` object given the previously allocated `device` and `memory`.
- pub fn new(
- device: Arc<Device>,
- memory: Arc<DeviceMemory>,
- offset: DeviceSize,
- size: DeviceSize,
- flags: u32,
- ) -> Result<DeviceMemoryMapping, DeviceMemoryAllocError> {
- // VUID-vkMapMemory-memory-00678: "memory must not be currently host mapped".
- let mut mapped = memory.mapped.lock().expect("Poisoned mutex");
-
- if *mapped {
- return Err(DeviceMemoryAllocError::SpecViolation(678));
+ /// Invalidates the host (CPU) cache for a range of mapped memory.
+ ///
+ /// If the mapped memory is not host-coherent, you must call this function before the memory is
+ /// read by the host, if the device previously wrote to the memory. It has no effect if the
+ /// mapped memory is host-coherent.
+ ///
+ /// `range` is specified in bytes relative to the start of the memory allocation, and must fall
+ /// within the range of the memory mapping given to `new`. If the memory was not allocated
+ /// from host-coherent memory, then the start and end of `range` must be a multiple of the
+ /// [`non_coherent_atom_size`](crate::device::Properties::non_coherent_atom_size) device
+ /// property, but `range.end` can also equal the memory's `allocation_size`.
+ ///
+ /// # Safety
+ ///
+ /// - If there are memory writes by the GPU that have not been propagated into the CPU cache,
+ /// then there must not be any references in Rust code to the specified `range` of the memory.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `range` is empty.
+ #[inline]
+ pub unsafe fn invalidate_range(&self, range: Range<DeviceSize>) -> Result<(), MemoryMapError> {
+ if self.coherent {
+ return Ok(());
}
- // VUID-vkMapMemory-offset-00679: "offset must be less than the size of memory"
- if size != ash::vk::WHOLE_SIZE && offset >= memory.size() {
- return Err(DeviceMemoryAllocError::SpecViolation(679));
- }
+ self.check_range(range.clone())?;
- // VUID-vkMapMemory-size-00680: "If size is not equal to VK_WHOLE_SIZE, size must be
- // greater than 0".
- if size != ash::vk::WHOLE_SIZE && size == 0 {
- return Err(DeviceMemoryAllocError::SpecViolation(680));
- }
+ // VUID-VkMappedMemoryRange-memory-00684
+ // Guaranteed because `self` owns the memory and it's mapped during our lifetime.
- // VUID-vkMapMemory-size-00681: "If size is not equal to VK_WHOLE_SIZE, size must be less
- // than or equal to the size of the memory minus offset".
- if size != ash::vk::WHOLE_SIZE && size > memory.size() - offset {
- return Err(DeviceMemoryAllocError::SpecViolation(681));
- }
+ let range = ash::vk::MappedMemoryRange {
+ memory: self.memory.handle(),
+ offset: range.start,
+ size: range.end - range.start,
+ ..Default::default()
+ };
- // VUID-vkMapMemory-memory-00682: "memory must have been created with a memory type
- // that reports VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT"
- let coherent = memory.memory_type().is_host_coherent();
- if !coherent {
- return Err(DeviceMemoryAllocError::SpecViolation(682));
- }
+ let fns = self.memory.device().fns();
+ (fns.v1_0.invalidate_mapped_memory_ranges)(self.memory.device().handle(), 1, &range)
+ .result()
+ .map_err(VulkanError::from)?;
- // VUID-vkMapMemory-memory-00683: "memory must not have been allocated with multiple instances".
- // Confused about this one, so not implemented.
+ Ok(())
+ }
- // VUID-vkMapMemory-memory-parent: "memory must have been created, allocated or retrieved
- // from device"
- if device.internal_object() != memory.device().internal_object() {
- return Err(DeviceMemoryAllocError::ImplicitSpecViolation(
- "VUID-vkMapMemory-memory-parent",
- ));
- }
+ /// Flushes the host (CPU) cache for a range of mapped memory.
+ ///
+ /// If the mapped memory is not host-coherent, you must call this function after writing to the
+ /// memory, if the device is going to read the memory. It has no effect if the
+ /// mapped memory is host-coherent.
+ ///
+ /// `range` is specified in bytes relative to the start of the memory allocation, and must fall
+ /// within the range of the memory mapping given to `map`. If the memory was not allocated
+ /// from host-coherent memory, then the start and end of `range` must be a multiple of the
+ /// [`non_coherent_atom_size`](crate::device::Properties::non_coherent_atom_size) device
+ /// property, but `range.end` can also equal the memory's `allocation_size`.
+ ///
+ /// # Safety
+ ///
+ /// - There must be no operations pending or executing in a GPU queue, that access the specified
+ /// `range` of the memory.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `range` is empty.
+ #[inline]
+ pub unsafe fn flush_range(&self, range: Range<DeviceSize>) -> Result<(), MemoryMapError> {
+ self.check_range(range.clone())?;
- // VUID-vkMapMemory-flags-zerobitmask: "flags must be 0".
- if flags != 0 {
- return Err(DeviceMemoryAllocError::ImplicitSpecViolation(
- "VUID-vkMapMemory-flags-zerobitmask",
- ));
+ if self.coherent {
+ return Ok(());
}
- // VUID-vkMapMemory-device-parameter, VUID-vkMapMemory-memory-parameter and
- // VUID-vkMapMemory-ppData-parameter satisfied via Vulkano internally.
+ // VUID-VkMappedMemoryRange-memory-00684
+ // Guaranteed because `self` owns the memory and it's mapped during our lifetime.
- let fns = device.fns();
- let ptr = unsafe {
- let mut output = MaybeUninit::uninit();
- check_errors(fns.v1_0.map_memory(
- device.internal_object(),
- memory.memory,
- 0,
- memory.size,
- ash::vk::MemoryMapFlags::empty(),
- output.as_mut_ptr(),
- ))?;
- output.assume_init()
+ let range = ash::vk::MappedMemoryRange {
+ memory: self.memory.handle(),
+ offset: range.start,
+ size: range.end - range.start,
+ ..Default::default()
};
- *mapped = true;
+ let fns = self.device().fns();
+ (fns.v1_0.flush_mapped_memory_ranges)(self.memory.device().handle(), 1, &range)
+ .result()
+ .map_err(VulkanError::from)?;
- Ok(DeviceMemoryMapping {
- device: device.clone(),
- memory: memory.clone(),
- pointer: ptr,
- coherent,
- })
+ Ok(())
}
- /// Returns the raw pointer associated with the `DeviceMemoryMapping`.
+ /// Returns a reference to bytes in the mapped memory.
+ ///
+ /// `range` is specified in bytes relative to the start of the memory allocation, and must fall
+ /// within the range of the memory mapping given to `map`. If the memory was not allocated
+ /// from host-coherent memory, then the start and end of `range` must be a multiple of the
+ /// [`non_coherent_atom_size`](crate::device::Properties::non_coherent_atom_size) device
+ /// property, but `range.end` can also equal the memory's `allocation_size`.
///
/// # Safety
///
- /// The caller of this function must ensure that the use of the raw pointer does not outlive
- /// the associated `DeviceMemoryMapping`.
- pub unsafe fn as_ptr(&self) -> *mut u8 {
- self.pointer as *mut u8
+ /// - While the returned reference exists, there must not be any mutable references in Rust code
+ /// to the same memory.
+ /// - While the returned reference exists, there must be no operations pending or executing in
+ /// a GPU queue, that write to the same memory.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `range` is empty.
+ #[inline]
+ pub unsafe fn read(&self, range: Range<DeviceSize>) -> Result<&[u8], MemoryMapError> {
+ self.check_range(range.clone())?;
+
+ let bytes = slice::from_raw_parts(
+ self.pointer.add((range.start - self.range.start) as usize) as *const u8,
+ (range.end - range.start) as usize,
+ );
+
+ Ok(bytes)
}
-}
-impl Drop for DeviceMemoryMapping {
+ /// Returns a mutable reference to bytes in the mapped memory.
+ ///
+ /// `range` is specified in bytes relative to the start of the memory allocation, and must fall
+ /// within the range of the memory mapping given to `map`. If the memory was not allocated
+ /// from host-coherent memory, then the start and end of `range` must be a multiple of the
+ /// [`non_coherent_atom_size`](crate::device::Properties::non_coherent_atom_size) device
+ /// property, but `range.end` can also equal the memory's `allocation_size`.
+ ///
+ /// # Safety
+ ///
+ /// - While the returned reference exists, there must not be any other references in Rust code
+ /// to the same memory.
+ /// - While the returned reference exists, there must be no operations pending or executing in
+ /// a GPU queue, that access the same memory.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `range` is empty.
#[inline]
- fn drop(&mut self) {
- let mut mapped = self.memory.mapped.lock().expect("Poisoned mutex");
+ pub unsafe fn write(&self, range: Range<DeviceSize>) -> Result<&mut [u8], MemoryMapError> {
+ self.check_range(range.clone())?;
- unsafe {
- let fns = self.device.fns();
- fns.v1_0
- .unmap_memory(self.device.internal_object(), self.memory.memory);
- }
+ let bytes = slice::from_raw_parts_mut(
+ self.pointer.add((range.start - self.range.start) as usize) as *mut u8,
+ (range.end - range.start) as usize,
+ );
- *mapped = false;
+ Ok(bytes)
}
-}
-
-/// Object that can be used to read or write the content of a `MappedDeviceMemory`.
-///
-/// This object derefs to the content, just like a `MutexGuard` for example.
-pub struct CpuAccess<'a, T: ?Sized + 'a> {
- pointer: *mut T,
- mem: &'a MappedDeviceMemory,
- coherent: bool,
- range: Range<DeviceSize>,
-}
-impl<'a, T: ?Sized + 'a> CpuAccess<'a, T> {
- /// Builds a new `CpuAccess` to access a sub-part of the current `CpuAccess`.
- ///
- /// This function is unstable. Don't use it directly.
- // TODO: unsafe?
- // TODO: decide what to do with this
- #[doc(hidden)]
#[inline]
- pub fn map<U: ?Sized + 'a, F>(self, f: F) -> CpuAccess<'a, U>
- where
- F: FnOnce(*mut T) -> *mut U,
- {
- CpuAccess {
- pointer: f(self.pointer),
- mem: self.mem,
- coherent: self.coherent,
- range: self.range.clone(), // TODO: ?
+ fn check_range(&self, range: Range<DeviceSize>) -> Result<(), MemoryMapError> {
+ assert!(!range.is_empty());
+
+ // VUID-VkMappedMemoryRange-size-00685
+ if range.start < self.range.start || range.end > self.range.end {
+ return Err(MemoryMapError::OutOfRange {
+ provided_range: range,
+ allowed_range: self.range.clone(),
+ });
}
- }
-}
-unsafe impl<'a, T: ?Sized + 'a> Send for CpuAccess<'a, T> {}
-unsafe impl<'a, T: ?Sized + 'a> Sync for CpuAccess<'a, T> {}
+ if !self.coherent {
+ // VUID-VkMappedMemoryRange-offset-00687
+ // VUID-VkMappedMemoryRange-size-01390
+ if !is_aligned(range.start, self.atom_size)
+ || (!is_aligned(range.end, self.atom_size)
+ && range.end != self.memory.allocation_size)
+ {
+ return Err(MemoryMapError::RangeNotAlignedToAtomSize {
+ range,
+ atom_size: self.atom_size,
+ });
+ }
+ }
-impl<'a, T: ?Sized + 'a> Deref for CpuAccess<'a, T> {
- type Target = T;
+ Ok(())
+ }
+}
+impl AsRef<DeviceMemory> for MappedDeviceMemory {
#[inline]
- fn deref(&self) -> &T {
- unsafe { &*self.pointer }
+ fn as_ref(&self) -> &DeviceMemory {
+ &self.memory
}
}
-impl<'a, T: ?Sized + 'a> DerefMut for CpuAccess<'a, T> {
+impl AsMut<DeviceMemory> for MappedDeviceMemory {
#[inline]
- fn deref_mut(&mut self) -> &mut T {
- unsafe { &mut *self.pointer }
+ fn as_mut(&mut self) -> &mut DeviceMemory {
+ &mut self.memory
}
}
-impl<'a, T: ?Sized + 'a> Drop for CpuAccess<'a, T> {
+unsafe impl DeviceOwned for MappedDeviceMemory {
#[inline]
- fn drop(&mut self) {
- // If the memory doesn't have the `coherent` flag, we need to flush the data.
- if !self.coherent {
- let fns = self.mem.as_ref().device().fns();
-
- let range = ash::vk::MappedMemoryRange {
- memory: self.mem.as_ref().internal_object(),
- offset: self.range.start,
- size: self.range.end - self.range.start,
- ..Default::default()
- };
-
- unsafe {
- check_errors(fns.v1_0.flush_mapped_memory_ranges(
- self.mem.as_ref().device().internal_object(),
- 1,
- &range,
- ))
- .unwrap();
- }
- }
+ fn device(&self) -> &Arc<Device> {
+ self.memory.device()
}
}
+unsafe impl Send for MappedDeviceMemory {}
+unsafe impl Sync for MappedDeviceMemory {}
+
/// Error type returned by functions related to `DeviceMemory`.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum DeviceMemoryAllocError {
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum MemoryMapError {
/// Not enough memory available.
OomError(OomError),
- /// The maximum number of allocations has been exceeded.
- TooManyObjects,
+
/// Memory map failed.
MemoryMapFailed,
- /// Invalid Memory Index
- MemoryIndexInvalid,
- /// Invalid Structure Type
- StructureTypeAlreadyPresent,
- /// Spec violation, containing the Valid Usage ID (VUID) from the Vulkan spec.
- SpecViolation(u32),
- /// An implicit violation that's convered in the Vulkan spec.
- ImplicitSpecViolation(&'static str),
- /// An extension is missing.
- MissingExtension(&'static str),
- /// Invalid Size
- InvalidSize,
+
+ /// Tried to map memory whose type is not host-visible.
+ NotHostVisible,
+
+ /// The specified `range` is not contained within the allocated or mapped memory range.
+ OutOfRange {
+ provided_range: Range<DeviceSize>,
+ allowed_range: Range<DeviceSize>,
+ },
+
+ /// The memory is not host-coherent, and the specified `range` bounds are not a multiple of the
+ /// [`non_coherent_atom_size`](crate::device::Properties::non_coherent_atom_size) device
+ /// property.
+ RangeNotAlignedToAtomSize {
+ range: Range<DeviceSize>,
+ atom_size: DeviceAlignment,
+ },
}
-impl error::Error for DeviceMemoryAllocError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- DeviceMemoryAllocError::OomError(ref err) => Some(err),
+impl Error for MemoryMapError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::OomError(err) => Some(err),
_ => None,
}
}
}
-impl fmt::Display for DeviceMemoryAllocError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- match *self {
- DeviceMemoryAllocError::OomError(_) => write!(fmt, "not enough memory available"),
- DeviceMemoryAllocError::TooManyObjects => {
- write!(fmt, "the maximum number of allocations has been exceeded")
- }
- DeviceMemoryAllocError::MemoryMapFailed => write!(fmt, "memory map failed"),
- DeviceMemoryAllocError::MemoryIndexInvalid => write!(fmt, "memory index invalid"),
- DeviceMemoryAllocError::StructureTypeAlreadyPresent => {
- write!(fmt, "structure type already present")
- }
- DeviceMemoryAllocError::SpecViolation(u) => {
- write!(fmt, "valid usage ID check {} failed", u)
+impl Display for MemoryMapError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::OomError(_) => write!(f, "not enough memory available"),
+ Self::MemoryMapFailed => write!(f, "memory map failed"),
+ Self::NotHostVisible => {
+ write!(f, "tried to map memory whose type is not host-visible")
}
- DeviceMemoryAllocError::MissingExtension(s) => {
- write!(fmt, "Missing the following extension: {}", s)
- }
- DeviceMemoryAllocError::ImplicitSpecViolation(e) => {
- write!(fmt, "Implicit spec violation failed {}", e)
- }
- DeviceMemoryAllocError::InvalidSize => write!(fmt, "invalid size"),
+ Self::OutOfRange {
+ provided_range,
+ allowed_range,
+ } => write!(
+ f,
+ "the specified `range` ({:?}) was not contained within the allocated or mapped \
+ memory range ({:?})",
+ provided_range, allowed_range,
+ ),
+ Self::RangeNotAlignedToAtomSize { range, atom_size } => write!(
+ f,
+ "the memory is not host-coherent, and the specified `range` bounds ({:?}) are not \
+ a multiple of the `non_coherent_atom_size` device property ({:?})",
+ range, atom_size,
+ ),
}
}
}
-impl From<Error> for DeviceMemoryAllocError {
- #[inline]
- fn from(err: Error) -> DeviceMemoryAllocError {
+impl From<VulkanError> for MemoryMapError {
+ fn from(err: VulkanError) -> Self {
match err {
- e @ Error::OutOfHostMemory | e @ Error::OutOfDeviceMemory => {
- DeviceMemoryAllocError::OomError(e.into())
+ e @ VulkanError::OutOfHostMemory | e @ VulkanError::OutOfDeviceMemory => {
+ Self::OomError(e.into())
}
- Error::TooManyObjects => DeviceMemoryAllocError::TooManyObjects,
- Error::MemoryMapFailed => DeviceMemoryAllocError::MemoryMapFailed,
+ VulkanError::MemoryMapFailed => Self::MemoryMapFailed,
_ => panic!("unexpected error: {:?}", err),
}
}
}
-impl From<OomError> for DeviceMemoryAllocError {
- #[inline]
- fn from(err: OomError) -> DeviceMemoryAllocError {
- DeviceMemoryAllocError::OomError(err)
+impl From<OomError> for MemoryMapError {
+ fn from(err: OomError) -> Self {
+ Self::OomError(err)
}
}
#[cfg(test)]
mod tests {
- use crate::memory::DeviceMemory;
- use crate::memory::DeviceMemoryAllocError;
- use crate::OomError;
+ use super::MemoryAllocateInfo;
+ use crate::{
+ memory::{DeviceMemory, DeviceMemoryError, MemoryPropertyFlags},
+ OomError,
+ };
#[test]
fn create() {
let (device, _) = gfx_dev_and_queue!();
- let mem_ty = device.physical_device().memory_types().next().unwrap();
- let _ = DeviceMemory::alloc(device.clone(), mem_ty, 256).unwrap();
+ let _ = DeviceMemory::allocate(
+ device,
+ MemoryAllocateInfo {
+ allocation_size: 256,
+ memory_type_index: 0,
+ ..Default::default()
+ },
+ )
+ .unwrap();
}
#[test]
fn zero_size() {
let (device, _) = gfx_dev_and_queue!();
- let mem_ty = device.physical_device().memory_types().next().unwrap();
assert_should_panic!({
- let _ = DeviceMemory::alloc(device.clone(), mem_ty, 0).unwrap();
+ let _ = DeviceMemory::allocate(
+ device.clone(),
+ MemoryAllocateInfo {
+ allocation_size: 0,
+ memory_type_index: 0,
+ ..Default::default()
+ },
+ )
+ .unwrap();
});
}
@@ -1108,15 +1621,28 @@ mod tests {
#[cfg(target_pointer_width = "64")]
fn oom_single() {
let (device, _) = gfx_dev_and_queue!();
- let mem_ty = device
+ let memory_type_index = device
.physical_device()
- .memory_types()
- .filter(|m| !m.is_lazily_allocated())
- .next()
+ .memory_properties()
+ .memory_types
+ .iter()
+ .enumerate()
+ .find_map(|(i, m)| {
+ (!m.property_flags
+ .intersects(MemoryPropertyFlags::LAZILY_ALLOCATED))
+ .then_some(i as u32)
+ })
.unwrap();
- match DeviceMemory::alloc(device.clone(), mem_ty, 0xffffffffffffffff) {
- Err(DeviceMemoryAllocError::SpecViolation(u)) => (),
+ match DeviceMemory::allocate(
+ device,
+ MemoryAllocateInfo {
+ allocation_size: 0xffffffffffffffff,
+ memory_type_index,
+ ..Default::default()
+ },
+ ) {
+ Err(DeviceMemoryError::MemoryTypeHeapSizeExceeded { .. }) => (),
_ => panic!(),
}
}
@@ -1125,19 +1651,34 @@ mod tests {
#[ignore] // TODO: test fails for now on Mesa+Intel
fn oom_multi() {
let (device, _) = gfx_dev_and_queue!();
- let mem_ty = device
+ let (memory_type_index, memory_type) = device
.physical_device()
- .memory_types()
- .filter(|m| !m.is_lazily_allocated())
- .next()
+ .memory_properties()
+ .memory_types
+ .iter()
+ .enumerate()
+ .find_map(|(i, m)| {
+ (!m.property_flags
+ .intersects(MemoryPropertyFlags::LAZILY_ALLOCATED))
+ .then_some((i as u32, m))
+ })
.unwrap();
- let heap_size = mem_ty.heap().size();
+ let heap_size = device.physical_device().memory_properties().memory_heaps
+ [memory_type.heap_index as usize]
+ .size;
let mut allocs = Vec::new();
for _ in 0..4 {
- match DeviceMemory::alloc(device.clone(), mem_ty, heap_size / 3) {
- Err(DeviceMemoryAllocError::OomError(OomError::OutOfDeviceMemory)) => return, // test succeeded
+ match DeviceMemory::allocate(
+ device.clone(),
+ MemoryAllocateInfo {
+ allocation_size: heap_size / 3,
+ memory_type_index,
+ ..Default::default()
+ },
+ ) {
+ Err(DeviceMemoryError::OomError(OomError::OutOfDeviceMemory)) => return, // test succeeded
Ok(a) => allocs.push(a),
_ => (),
}
@@ -1149,14 +1690,29 @@ mod tests {
#[test]
fn allocation_count() {
let (device, _) = gfx_dev_and_queue!();
- let mem_ty = device.physical_device().memory_types().next().unwrap();
- assert_eq!(*device.allocation_count().lock().unwrap(), 0);
- let mem1 = DeviceMemory::alloc(device.clone(), mem_ty, 256).unwrap();
- assert_eq!(*device.allocation_count().lock().unwrap(), 1);
+ assert_eq!(device.allocation_count(), 0);
+ let _mem1 = DeviceMemory::allocate(
+ device.clone(),
+ MemoryAllocateInfo {
+ allocation_size: 256,
+ memory_type_index: 0,
+ ..Default::default()
+ },
+ )
+ .unwrap();
+ assert_eq!(device.allocation_count(), 1);
{
- let mem2 = DeviceMemory::alloc(device.clone(), mem_ty, 256).unwrap();
- assert_eq!(*device.allocation_count().lock().unwrap(), 2);
+ let _mem2 = DeviceMemory::allocate(
+ device.clone(),
+ MemoryAllocateInfo {
+ allocation_size: 256,
+ memory_type_index: 0,
+ ..Default::default()
+ },
+ )
+ .unwrap();
+ assert_eq!(device.allocation_count(), 2);
}
- assert_eq!(*device.allocation_count().lock().unwrap(), 1);
+ assert_eq!(device.allocation_count(), 1);
}
}
diff --git a/src/memory/external_memory_handle_type.rs b/src/memory/external_memory_handle_type.rs
deleted file mode 100644
index 39dee03..0000000
--- a/src/memory/external_memory_handle_type.rs
+++ /dev/null
@@ -1,168 +0,0 @@
-// Copyright (c) 2020 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use std::ops::BitOr;
-
-/// Describes the handle type used for Vulkan external memory apis. This is **not** just a
-/// suggestion. Check out vkExternalMemoryHandleTypeFlagBits in the Vulkan spec.
-///
-/// If you specify an handle type that doesnt make sense (for example, using a dma-buf handle type
-/// on Windows) when using this handle, a panic will happen.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub struct ExternalMemoryHandleType {
- pub opaque_fd: bool,
- pub opaque_win32: bool,
- pub opaque_win32_kmt: bool,
- pub d3d11_texture: bool,
- pub d3d11_texture_kmt: bool,
- pub d3d12_heap: bool,
- pub d3d12_resource: bool,
- pub dma_buf: bool,
- pub android_hardware_buffer: bool,
- pub host_allocation: bool,
- pub host_mapped_foreign_memory: bool,
-}
-
-impl ExternalMemoryHandleType {
- /// Builds a `ExternalMemoryHandleType` with all values set to false. Useful as a default value.
- ///
- /// # Example
- ///
- /// ```rust
- /// use vulkano::memory::ExternalMemoryHandleType as ExternalMemoryHandleType;
- ///
- /// let _handle_type = ExternalMemoryHandleType {
- /// opaque_fd: true,
- /// .. ExternalMemoryHandleType::none()
- /// };
- /// ```
- #[inline]
- pub fn none() -> ExternalMemoryHandleType {
- ExternalMemoryHandleType {
- opaque_fd: false,
- opaque_win32: false,
- opaque_win32_kmt: false,
- d3d11_texture: false,
- d3d11_texture_kmt: false,
- d3d12_heap: false,
- d3d12_resource: false,
- dma_buf: false,
- android_hardware_buffer: false,
- host_allocation: false,
- host_mapped_foreign_memory: false,
- }
- }
-
- /// Builds an `ExternalMemoryHandleType` for a posix file descriptor.
- ///
- /// # Example
- ///
- /// ```rust
- /// use vulkano::memory::ExternalMemoryHandleType as ExternalMemoryHandleType;
- ///
- /// let _handle_type = ExternalMemoryHandleType::posix();
- /// ```
- #[inline]
- pub fn posix() -> ExternalMemoryHandleType {
- ExternalMemoryHandleType {
- opaque_fd: true,
- ..ExternalMemoryHandleType::none()
- }
- }
-}
-
-impl From<ExternalMemoryHandleType> for ash::vk::ExternalMemoryHandleTypeFlags {
- #[inline]
- fn from(val: ExternalMemoryHandleType) -> Self {
- let mut result = ash::vk::ExternalMemoryHandleTypeFlags::empty();
- if val.opaque_fd {
- result |= ash::vk::ExternalMemoryHandleTypeFlags::OPAQUE_FD;
- }
- if val.opaque_win32 {
- result |= ash::vk::ExternalMemoryHandleTypeFlags::OPAQUE_WIN32;
- }
- if val.opaque_win32_kmt {
- result |= ash::vk::ExternalMemoryHandleTypeFlags::OPAQUE_WIN32_KMT;
- }
- if val.d3d11_texture {
- result |= ash::vk::ExternalMemoryHandleTypeFlags::D3D11_TEXTURE;
- }
- if val.d3d11_texture_kmt {
- result |= ash::vk::ExternalMemoryHandleTypeFlags::D3D11_TEXTURE_KMT;
- }
- if val.d3d12_heap {
- result |= ash::vk::ExternalMemoryHandleTypeFlags::D3D12_HEAP;
- }
- if val.d3d12_resource {
- result |= ash::vk::ExternalMemoryHandleTypeFlags::D3D12_RESOURCE;
- }
- if val.dma_buf {
- result |= ash::vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT;
- }
- if val.android_hardware_buffer {
- result |= ash::vk::ExternalMemoryHandleTypeFlags::ANDROID_HARDWARE_BUFFER_ANDROID;
- }
- if val.host_allocation {
- result |= ash::vk::ExternalMemoryHandleTypeFlags::HOST_ALLOCATION_EXT;
- }
- if val.host_mapped_foreign_memory {
- result |= ash::vk::ExternalMemoryHandleTypeFlags::HOST_MAPPED_FOREIGN_MEMORY_EXT
- }
- result
- }
-}
-
-impl From<ash::vk::ExternalMemoryHandleTypeFlags> for ExternalMemoryHandleType {
- fn from(val: ash::vk::ExternalMemoryHandleTypeFlags) -> Self {
- ExternalMemoryHandleType {
- opaque_fd: !(val & ash::vk::ExternalMemoryHandleTypeFlags::OPAQUE_FD).is_empty(),
- opaque_win32: !(val & ash::vk::ExternalMemoryHandleTypeFlags::OPAQUE_WIN32).is_empty(),
- opaque_win32_kmt: !(val & ash::vk::ExternalMemoryHandleTypeFlags::OPAQUE_WIN32_KMT)
- .is_empty(),
- d3d11_texture: !(val & ash::vk::ExternalMemoryHandleTypeFlags::D3D11_TEXTURE)
- .is_empty(),
- d3d11_texture_kmt: !(val & ash::vk::ExternalMemoryHandleTypeFlags::D3D11_TEXTURE_KMT)
- .is_empty(),
- d3d12_heap: !(val & ash::vk::ExternalMemoryHandleTypeFlags::D3D12_HEAP).is_empty(),
- d3d12_resource: !(val & ash::vk::ExternalMemoryHandleTypeFlags::D3D12_RESOURCE)
- .is_empty(),
- dma_buf: !(val & ash::vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT).is_empty(),
- android_hardware_buffer: !(val
- & ash::vk::ExternalMemoryHandleTypeFlags::ANDROID_HARDWARE_BUFFER_ANDROID)
- .is_empty(),
- host_allocation: !(val & ash::vk::ExternalMemoryHandleTypeFlags::HOST_ALLOCATION_EXT)
- .is_empty(),
- host_mapped_foreign_memory: !(val
- & ash::vk::ExternalMemoryHandleTypeFlags::HOST_MAPPED_FOREIGN_MEMORY_EXT)
- .is_empty(),
- }
- }
-}
-
-impl BitOr for ExternalMemoryHandleType {
- type Output = Self;
-
- #[inline]
- fn bitor(self, rhs: Self) -> Self {
- ExternalMemoryHandleType {
- opaque_fd: self.opaque_fd || rhs.opaque_fd,
- opaque_win32: self.opaque_win32 || rhs.opaque_win32,
- opaque_win32_kmt: self.opaque_win32_kmt || rhs.opaque_win32_kmt,
- d3d11_texture: self.d3d11_texture || rhs.d3d11_texture,
- d3d11_texture_kmt: self.d3d11_texture_kmt || rhs.d3d11_texture_kmt,
- d3d12_heap: self.d3d12_heap || rhs.d3d12_heap,
- d3d12_resource: self.d3d12_resource || rhs.d3d12_resource,
- dma_buf: self.dma_buf || rhs.dma_buf,
- android_hardware_buffer: self.android_hardware_buffer || rhs.android_hardware_buffer,
- host_allocation: self.host_allocation || rhs.host_allocation,
- host_mapped_foreign_memory: self.host_mapped_foreign_memory
- || rhs.host_mapped_foreign_memory,
- }
- }
-}
diff --git a/src/memory/mod.rs b/src/memory/mod.rs
index 8797d38..94b6a1a 100644
--- a/src/memory/mod.rs
+++ b/src/memory/mod.rs
@@ -21,8 +21,8 @@
//! ```
//! // Enumerating memory heaps.
//! # let physical_device: vulkano::device::physical::PhysicalDevice = return;
-//! for heap in physical_device.memory_heaps() {
-//! println!("Heap #{:?} has a capacity of {:?} bytes", heap.id(), heap.size());
+//! for (index, heap) in physical_device.memory_properties().memory_heaps.iter().enumerate() {
+//! println!("Heap #{:?} has a capacity of {:?} bytes", index, heap.size);
//! }
//! ```
//!
@@ -38,10 +38,9 @@
//! ```
//! // Enumerating memory types.
//! # let physical_device: vulkano::device::physical::PhysicalDevice = return;
-//! for ty in physical_device.memory_types() {
-//! println!("Memory type belongs to heap #{:?}", ty.heap().id());
-//! println!("Host-accessible: {:?}", ty.is_host_visible());
-//! println!("Device-local: {:?}", ty.is_device_local());
+//! for ty in physical_device.memory_properties().memory_types.iter() {
+//! println!("Memory type belongs to heap #{:?}", ty.heap_index);
+//! println!("Property flags: {:?}", ty.property_flags);
//! }
//! ```
//!
@@ -60,20 +59,27 @@
//!
//! # Allocating memory and memory pools
//!
-//! Allocating memory can be done by calling `DeviceMemory::alloc()`.
+//! Allocating memory can be done by calling `DeviceMemory::allocate()`.
//!
//! Here is an example:
//!
//! ```
-//! use vulkano::memory::DeviceMemory;
+//! use vulkano::memory::{DeviceMemory, MemoryAllocateInfo};
//!
//! # let device: std::sync::Arc<vulkano::device::Device> = return;
//! // Taking the first memory type for the sake of this example.
-//! let ty = device.physical_device().memory_types().next().unwrap();
+//! let memory_type_index = 0;
//!
-//! let alloc = DeviceMemory::alloc(device.clone(), ty, 1024).expect("Failed to allocate memory");
+//! let memory = DeviceMemory::allocate(
+//! device.clone(),
+//! MemoryAllocateInfo {
+//! allocation_size: 1024,
+//! memory_type_index,
+//! ..Default::default()
+//! },
+//! ).expect("Failed to allocate memory");
//!
-//! // The memory is automatically free'd when `alloc` is destroyed.
+//! // The memory is automatically freed when `memory` is destroyed.
//! ```
//!
//! However allocating and freeing memory is very slow (up to several hundred milliseconds
@@ -83,143 +89,503 @@
//! A memory pool is any object that implements the `MemoryPool` trait. You can implement that
//! trait on your own structure and then use it when you create buffers and images so that they
//! get memory from that pool. By default if you don't specify any pool when creating a buffer or
-//! an image, an instance of `StdMemoryPool` that is shared by the `Device` object is used.
+//! an image, an instance of `StandardMemoryPool` that is shared by the `Device` object is used.
-use std::mem;
-use std::os::raw::c_void;
-use std::slice;
+pub use self::alignment::DeviceAlignment;
+use self::allocator::DeviceLayout;
+pub use self::device_memory::{
+ DeviceMemory, DeviceMemoryError, ExternalMemoryHandleType, ExternalMemoryHandleTypes,
+ MappedDeviceMemory, MemoryAllocateFlags, MemoryAllocateInfo, MemoryImportInfo, MemoryMapError,
+};
+use crate::{
+ buffer::{sys::RawBuffer, Subbuffer},
+ image::{sys::RawImage, ImageAccess, ImageAspects},
+ macros::vulkan_bitflags,
+ sync::semaphore::Semaphore,
+ DeviceSize,
+};
+use std::{
+ num::NonZeroU64,
+ ops::{Bound, Range, RangeBounds, RangeTo},
+ sync::Arc,
+};
-use crate::buffer::sys::UnsafeBuffer;
-use crate::image::sys::UnsafeImage;
+mod alignment;
+pub mod allocator;
+mod device_memory;
-pub use self::device_memory::CpuAccess;
-pub use self::device_memory::DeviceMemory;
-pub use self::device_memory::DeviceMemoryAllocError;
-pub use self::device_memory::DeviceMemoryBuilder;
-pub use self::device_memory::DeviceMemoryMapping;
-pub use self::device_memory::MappedDeviceMemory;
-pub use self::external_memory_handle_type::ExternalMemoryHandleType;
-pub use self::pool::MemoryPool;
-use crate::DeviceSize;
+/// Properties of the memory in a physical device.
+#[derive(Clone, Debug)]
+#[non_exhaustive]
+pub struct MemoryProperties {
+ /// The available memory types.
+ pub memory_types: Vec<MemoryType>,
-mod device_memory;
-mod external_memory_handle_type;
-pub mod pool;
+ /// The available memory heaps.
+ pub memory_heaps: Vec<MemoryHeap>,
+}
+
+impl From<ash::vk::PhysicalDeviceMemoryProperties> for MemoryProperties {
+ #[inline]
+ fn from(val: ash::vk::PhysicalDeviceMemoryProperties) -> Self {
+ Self {
+ memory_types: val.memory_types[0..val.memory_type_count as usize]
+ .iter()
+ .map(|vk_memory_type| MemoryType {
+ property_flags: vk_memory_type.property_flags.into(),
+ heap_index: vk_memory_type.heap_index,
+ })
+ .collect(),
+ memory_heaps: val.memory_heaps[0..val.memory_heap_count as usize]
+ .iter()
+ .map(|vk_memory_heap| MemoryHeap {
+ size: vk_memory_heap.size,
+ flags: vk_memory_heap.flags.into(),
+ })
+ .collect(),
+ }
+ }
+}
+
+/// A memory type in a physical device.
+#[derive(Clone, Debug)]
+#[non_exhaustive]
+pub struct MemoryType {
+ /// The properties of this memory type.
+ pub property_flags: MemoryPropertyFlags,
+
+ /// The index of the memory heap that this memory type corresponds to.
+ pub heap_index: u32,
+}
+
+vulkan_bitflags! {
+ #[non_exhaustive]
+
+ /// Properties of a memory type.
+ MemoryPropertyFlags = MemoryPropertyFlags(u32);
+
+ /// The memory is located on the device, and is allocated from a heap that also has the
+ /// [`DEVICE_LOCAL`] flag set.
+ ///
+ /// For some devices, particularly integrated GPUs, the device shares memory with the host and
+ /// all memory may be device-local, so the distinction is moot. However, if the device has
+ /// non-device-local memory, it is usually faster for the device to access device-local memory.
+ /// Therefore, device-local memory is preferred for data that will only be accessed by
+ /// the device.
+ ///
+ /// If the device and host do not share memory, data transfer between host and device may
+ /// involve sending the data over the data bus that connects the two. Accesses are faster if
+ /// they do not have to cross this barrier: device-local memory is fast for the device to
+ /// access, but slower to access by the host. However, there are devices that share memory with
+ /// the host, yet have distinct device-local and non-device local memory types. In that case,
+ /// the speed difference may not be large.
+ ///
+ /// For data transfer between host and device, it is most efficient if the memory is located
+ /// at the destination of the transfer. Thus, if [`HOST_VISIBLE`] versions of both are
+ /// available, device-local memory is preferred for host-to-device data transfer, while
+ /// non-device-local memory is preferred for device-to-host data transfer. This is because data
+ /// is usually written only once but potentially read several times, and because reads can take
+ /// advantage of caching while writes cannot.
+ ///
+ /// Devices may have memory types that are neither `DEVICE_LOCAL` nor [`HOST_VISIBLE`]. This
+ /// is regular host memory that is made available to the device exclusively. Although it will be
+ /// slower to access from the device than `DEVICE_LOCAL` memory, it can be faster than
+ /// [`HOST_VISIBLE`] memory. It can be used as overflow space if the device is out of memory.
+ ///
+ /// [`DEVICE_LOCAL`]: MemoryHeapFlags::DEVICE_LOCAL
+ /// [`HOST_VISIBLE`]: MemoryPropertyFlags::HOST_VISIBLE
+ DEVICE_LOCAL = DEVICE_LOCAL,
+
+ /// The memory can be mapped into the memory space of the host and accessed as regular RAM.
+ ///
+ /// Memory of this type is required to transfer data between the host and the device. If
+ /// the memory is going to be accessed by the device more than a few times, it is recommended
+ /// to copy the data to non-`HOST_VISIBLE` memory first if it is available.
+ ///
+ /// `HOST_VISIBLE` memory is always at least either [`HOST_COHERENT`] or [`HOST_CACHED`],
+ /// but it can be both.
+ ///
+ /// [`HOST_COHERENT`]: MemoryPropertyFlags::HOST_COHERENT
+ /// [`HOST_CACHED`]: MemoryPropertyFlags::HOST_CACHED
+ HOST_VISIBLE = HOST_VISIBLE,
+
+ /// Host access to the memory does not require calling [`invalidate_range`] to make device
+ /// writes visible to the host, nor [`flush_range`] to flush host writes back to the device.
+ ///
+ /// [`invalidate_range`]: MappedDeviceMemory::invalidate_range
+ /// [`flush_range`]: MappedDeviceMemory::flush_range
+ HOST_COHERENT = HOST_COHERENT,
+
+ /// The memory is cached by the host.
+ ///
+ /// `HOST_CACHED` memory is fast for reads and random access from the host, so it is preferred
+ /// for device-to-host data transfer. Memory that is [`HOST_VISIBLE`] but not `HOST_CACHED` is
+ /// often slow for all accesses other than sequential writing, so it is more suited for
+ /// host-to-device transfer, and it is often beneficial to write the data in sequence.
+ ///
+ /// [`HOST_VISIBLE`]: MemoryPropertyFlags::HOST_VISIBLE
+ HOST_CACHED = HOST_CACHED,
+
+ /// Allocations made from the memory are lazy.
+ ///
+ /// This means that no actual allocation is performed. Instead memory is automatically
+ /// allocated by the Vulkan implementation based on need. You can call
+ /// [`DeviceMemory::commitment`] to query how much memory is currently committed to an
+ /// allocation.
+ ///
+ /// Memory of this type can only be used on images created with a certain flag, and is never
+ /// [`HOST_VISIBLE`].
+ ///
+ /// [`HOST_VISIBLE`]: MemoryPropertyFlags::HOST_VISIBLE
+ LAZILY_ALLOCATED = LAZILY_ALLOCATED,
+
+ /// The memory can only be accessed by the device, and allows protected queue access.
+ ///
+ /// Memory of this type is never [`HOST_VISIBLE`], [`HOST_COHERENT`] or [`HOST_CACHED`].
+ ///
+ /// [`HOST_VISIBLE`]: MemoryPropertyFlags::HOST_VISIBLE
+ /// [`HOST_COHERENT`]: MemoryPropertyFlags::HOST_COHERENT
+ /// [`HOST_CACHED`]: MemoryPropertyFlags::HOST_CACHED
+ PROTECTED = PROTECTED {
+ api_version: V1_1,
+ },
+
+ /// Device accesses to the memory are automatically made available and visible to other device
+ /// accesses.
+ ///
+ /// Memory of this type is slower to access by the device, so it is best avoided for general
+ /// purpose use. Because of its coherence properties, however, it may be useful for debugging.
+ DEVICE_COHERENT = DEVICE_COHERENT_AMD {
+ device_extensions: [amd_device_coherent_memory],
+ },
+
+ /// The memory is not cached on the device.
+ ///
+ /// `DEVICE_UNCACHED` memory is always also [`DEVICE_COHERENT`].
+ ///
+ /// [`DEVICE_COHERENT`]: MemoryPropertyFlags::DEVICE_COHERENT
+ DEVICE_UNCACHED = DEVICE_UNCACHED_AMD {
+ device_extensions: [amd_device_coherent_memory],
+ },
+
+ /// Other devices can access the memory via remote direct memory access (RDMA).
+ RDMA_CAPABLE = RDMA_CAPABLE_NV {
+ device_extensions: [nv_external_memory_rdma],
+ },
+}
+
+/// A memory heap in a physical device.
+#[derive(Clone, Debug)]
+#[non_exhaustive]
+pub struct MemoryHeap {
+ /// The size of the heap in bytes.
+ pub size: DeviceSize,
+
+ /// Attributes of the heap.
+ pub flags: MemoryHeapFlags,
+}
+
+vulkan_bitflags! {
+ #[non_exhaustive]
+
+ /// Attributes of a memory heap.
+ MemoryHeapFlags = MemoryHeapFlags(u32);
+
+ /// The heap corresponds to device-local memory.
+ DEVICE_LOCAL = DEVICE_LOCAL,
+
+ /// If used on a logical device that represents more than one physical device, allocations are
+ /// replicated across each physical device's instance of this heap.
+ MULTI_INSTANCE = MULTI_INSTANCE {
+ api_version: V1_1,
+ instance_extensions: [khr_device_group_creation],
+ },
+}
/// Represents requirements expressed by the Vulkan implementation when it comes to binding memory
/// to a resource.
-#[derive(Debug, Copy, Clone)]
+#[derive(Clone, Copy, Debug)]
pub struct MemoryRequirements {
- /// Number of bytes of memory required.
- pub size: DeviceSize,
-
- /// Alignment of the requirement buffer. The base memory address must be a multiple
- /// of this value.
- pub alignment: DeviceSize,
+ /// Memory layout required for the resource.
+ pub layout: DeviceLayout,
/// Indicates which memory types can be used. Each bit that is set to 1 means that the memory
/// type whose index is the same as the position of the bit can be used.
pub memory_type_bits: u32,
- /// True if the implementation prefers to use dedicated allocations (in other words, allocate
- /// a whole block of memory dedicated to this resource alone). If the
- /// `khr_get_memory_requirements2` extension isn't enabled, then this will be false.
- ///
- /// > **Note**: As its name says, using a dedicated allocation is an optimization and not a
- /// > requirement.
- pub prefer_dedicated: bool,
-}
+ /// Whether implementation prefers to use dedicated allocations (in other words, allocate
+ /// a whole block of memory dedicated to this resource alone).
+ /// This will be `false` if the device API version is less than 1.1 and the
+ /// [`khr_get_memory_requirements2`](crate::device::DeviceExtensions::khr_get_memory_requirements2)
+ /// extension is not enabled on the device.
+ pub prefers_dedicated_allocation: bool,
-impl From<ash::vk::MemoryRequirements> for MemoryRequirements {
- #[inline]
- fn from(val: ash::vk::MemoryRequirements) -> Self {
- MemoryRequirements {
- size: val.size,
- alignment: val.alignment,
- memory_type_bits: val.memory_type_bits,
- prefer_dedicated: false,
- }
- }
+ /// Whether implementation requires the use of a dedicated allocation (in other words, allocate
+ /// a whole block of memory dedicated to this resource alone).
+ /// This will be `false` if the device API version is less than 1.1 and the
+ /// [`khr_get_memory_requirements2`](crate::device::DeviceExtensions::khr_get_memory_requirements2)
+ /// extension is not enabled on the device.
+ pub requires_dedicated_allocation: bool,
}
-/// Indicates whether we want to allocate memory for a specific resource, or in a generic way.
+/// Indicates a specific resource to allocate memory for.
///
/// Using dedicated allocations can yield better performance, but requires the
-/// `VK_KHR_dedicated_allocation` extension to be enabled on the device.
+/// [`khr_dedicated_allocation`](crate::device::DeviceExtensions::khr_dedicated_allocation)
+/// extension to be enabled on the device.
///
-/// If a dedicated allocation is performed, it must only be bound to any resource other than the
+/// If a dedicated allocation is performed, it must not be bound to any resource other than the
/// one that was passed with the enumeration.
-#[derive(Debug, Copy, Clone)]
-pub enum DedicatedAlloc<'a> {
- /// Generic allocation.
- None,
+#[derive(Clone, Copy, Debug)]
+pub enum DedicatedAllocation<'a> {
/// Allocation dedicated to a buffer.
- Buffer(&'a UnsafeBuffer),
+ Buffer(&'a RawBuffer),
/// Allocation dedicated to an image.
- Image(&'a UnsafeImage),
+ Image(&'a RawImage),
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub(crate) enum DedicatedTo {
+ Buffer(NonZeroU64),
+ Image(NonZeroU64),
+}
+
+impl From<DedicatedAllocation<'_>> for DedicatedTo {
+ fn from(dedicated_allocation: DedicatedAllocation<'_>) -> Self {
+ match dedicated_allocation {
+ DedicatedAllocation::Buffer(buffer) => Self::Buffer(buffer.id()),
+ DedicatedAllocation::Image(image) => Self::Image(image.id()),
+ }
+ }
}
-/// Trait for types of data that can be mapped.
-// TODO: move to `buffer` module
-pub unsafe trait Content {
- /// Builds a pointer to this type from a raw pointer.
- fn ref_from_ptr<'a>(ptr: *mut c_void, size: usize) -> Option<*mut Self>;
+/// The properties for exporting or importing external memory, when a buffer or image is created
+/// with a specific configuration.
+#[derive(Clone, Debug, Default)]
+#[non_exhaustive]
+pub struct ExternalMemoryProperties {
+ /// Whether a dedicated memory allocation is required for the queried external handle type.
+ pub dedicated_only: bool,
+
+ /// Whether memory can be exported to an external source with the queried
+ /// external handle type.
+ pub exportable: bool,
- /// Returns true if the size is suitable to store a type like this.
- fn is_size_suitable(size: DeviceSize) -> bool;
+ /// Whether memory can be imported from an external source with the queried
+ /// external handle type.
+ pub importable: bool,
- /// Returns the size of an individual element.
- fn indiv_size() -> DeviceSize;
+ /// Which external handle types can be re-exported after the queried external handle type has
+ /// been imported.
+ pub export_from_imported_handle_types: ExternalMemoryHandleTypes,
+
+ /// Which external handle types can be enabled along with the queried external handle type
+ /// when creating the buffer or image.
+ pub compatible_handle_types: ExternalMemoryHandleTypes,
}
-unsafe impl<T> Content for T {
+impl From<ash::vk::ExternalMemoryProperties> for ExternalMemoryProperties {
#[inline]
- fn ref_from_ptr<'a>(ptr: *mut c_void, size: usize) -> Option<*mut T> {
- if size < mem::size_of::<T>() {
- return None;
+ fn from(val: ash::vk::ExternalMemoryProperties) -> Self {
+ Self {
+ dedicated_only: val
+ .external_memory_features
+ .intersects(ash::vk::ExternalMemoryFeatureFlags::DEDICATED_ONLY),
+ exportable: val
+ .external_memory_features
+ .intersects(ash::vk::ExternalMemoryFeatureFlags::EXPORTABLE),
+ importable: val
+ .external_memory_features
+ .intersects(ash::vk::ExternalMemoryFeatureFlags::IMPORTABLE),
+ export_from_imported_handle_types: val.export_from_imported_handle_types.into(),
+ compatible_handle_types: val.compatible_handle_types.into(),
}
-
- Some(ptr as *mut T)
}
+}
- #[inline]
- fn is_size_suitable(size: DeviceSize) -> bool {
- size == mem::size_of::<T>() as DeviceSize
- }
+/// Parameters to execute sparse bind operations on a queue.
+#[derive(Clone, Debug)]
+pub struct BindSparseInfo {
+ /// The semaphores to wait for before beginning the execution of this batch of
+ /// sparse bind operations.
+ ///
+ /// The default value is empty.
+ pub wait_semaphores: Vec<Arc<Semaphore>>,
- #[inline]
- fn indiv_size() -> DeviceSize {
- mem::size_of::<T>() as DeviceSize
- }
+ /// The bind operations to perform for buffers.
+ ///
+ /// The default value is empty.
+ pub buffer_binds: Vec<(Subbuffer<[u8]>, Vec<SparseBufferMemoryBind>)>,
+
+ /// The bind operations to perform for images with an opaque memory layout.
+ ///
+ /// This should be used for mip tail regions, the metadata aspect, and for the normal regions
+ /// of images that do not have the `sparse_residency` flag set.
+ ///
+ /// The default value is empty.
+ pub image_opaque_binds: Vec<(Arc<dyn ImageAccess>, Vec<SparseImageOpaqueMemoryBind>)>,
+
+ /// The bind operations to perform for images with a known memory layout.
+ ///
+ /// This type of sparse bind can only be used for images that have the `sparse_residency`
+ /// flag set.
+ /// Only the normal texel regions can be bound this way, not the mip tail regions or metadata
+ /// aspect.
+ ///
+ /// The default value is empty.
+ pub image_binds: Vec<(Arc<dyn ImageAccess>, Vec<SparseImageMemoryBind>)>,
+
+ /// The semaphores to signal after the execution of this batch of sparse bind operations
+ /// has completed.
+ ///
+ /// The default value is empty.
+ pub signal_semaphores: Vec<Arc<Semaphore>>,
+
+ pub _ne: crate::NonExhaustive,
}
-unsafe impl<T> Content for [T] {
+impl Default for BindSparseInfo {
#[inline]
- fn ref_from_ptr<'a>(ptr: *mut c_void, size: usize) -> Option<*mut [T]> {
- let ptr = ptr as *mut T;
- let size = size / mem::size_of::<T>();
- Some(unsafe { slice::from_raw_parts_mut(&mut *ptr, size) as *mut [T] })
+ fn default() -> Self {
+ Self {
+ wait_semaphores: Vec::new(),
+ buffer_binds: Vec::new(),
+ image_opaque_binds: Vec::new(),
+ image_binds: Vec::new(),
+ signal_semaphores: Vec::new(),
+ _ne: crate::NonExhaustive(()),
+ }
}
+}
- #[inline]
- fn is_size_suitable(size: DeviceSize) -> bool {
- size % mem::size_of::<T>() as DeviceSize == 0
- }
+/// Parameters for a single sparse bind operation on a buffer.
+#[derive(Clone, Debug, Default)]
+pub struct SparseBufferMemoryBind {
+ /// The offset in bytes from the start of the buffer's memory, where memory is to be (un)bound.
+ ///
+ /// The default value is `0`.
+ pub offset: DeviceSize,
- #[inline]
- fn indiv_size() -> DeviceSize {
- mem::size_of::<T>() as DeviceSize
- }
+ /// The size in bytes of the memory to be (un)bound.
+ ///
+ /// The default value is `0`, which must be overridden.
+ pub size: DeviceSize,
+
+ /// If `Some`, specifies the memory and an offset into that memory that is to be bound.
+ /// The provided memory must match the buffer's memory requirements.
+ ///
+ /// If `None`, specifies that existing memory at the specified location is to be unbound.
+ ///
+ /// The default value is `None`.
+ pub memory: Option<(Arc<DeviceMemory>, DeviceSize)>,
+}
+
+/// Parameters for a single sparse bind operation on parts of an image with an opaque memory layout.
+///
+/// This type of sparse bind should be used for mip tail regions, the metadata aspect, and for the
+/// normal regions of images that do not have the `sparse_residency` flag set.
+#[derive(Clone, Debug, Default)]
+pub struct SparseImageOpaqueMemoryBind {
+ /// The offset in bytes from the start of the image's memory, where memory is to be (un)bound.
+ ///
+ /// The default value is `0`.
+ pub offset: DeviceSize,
+
+ /// The size in bytes of the memory to be (un)bound.
+ ///
+ /// The default value is `0`, which must be overridden.
+ pub size: DeviceSize,
+
+ /// If `Some`, specifies the memory and an offset into that memory that is to be bound.
+ /// The provided memory must match the image's memory requirements.
+ ///
+ /// If `None`, specifies that existing memory at the specified location is to be unbound.
+ ///
+ /// The default value is `None`.
+ pub memory: Option<(Arc<DeviceMemory>, DeviceSize)>,
+
+ /// Sets whether the binding should apply to the metadata aspect of the image, or to the
+ /// normal texel data.
+ ///
+ /// The default value is `false`.
+ pub metadata: bool,
+}
+
+/// Parameters for a single sparse bind operation on parts of an image with a known memory layout.
+///
+/// This type of sparse bind can only be used for images that have the `sparse_residency` flag set.
+/// Only the normal texel regions can be bound this way, not the mip tail regions or metadata
+/// aspect.
+#[derive(Clone, Debug, Default)]
+pub struct SparseImageMemoryBind {
+ /// The aspects of the image where memory is to be (un)bound.
+ ///
+ /// The default value is `ImageAspects::empty()`, which must be overridden.
+ pub aspects: ImageAspects,
+
+ /// The mip level of the image where memory is to be (un)bound.
+ ///
+ /// The default value is `0`.
+ pub mip_level: u32,
+
+ /// The array layer of the image where memory is to be (un)bound.
+ ///
+ /// The default value is `0`.
+ pub array_layer: u32,
+
+ /// The offset in texels (or for compressed images, texel blocks) from the origin of the image,
+ /// where memory is to be (un)bound.
+ ///
+ /// This must be a multiple of the
+ /// [`SparseImageFormatProperties::image_granularity`](crate::image::SparseImageFormatProperties::image_granularity)
+ /// value of the image.
+ ///
+ /// The default value is `[0; 3]`.
+ pub offset: [u32; 3],
+
+ /// The extent in texels (or for compressed images, texel blocks) of the image where
+ /// memory is to be (un)bound.
+ ///
+ /// This must be a multiple of the
+ /// [`SparseImageFormatProperties::image_granularity`](crate::image::SparseImageFormatProperties::image_granularity)
+ /// value of the image, or `offset + extent` for that dimension must equal the image's total
+ /// extent.
+ ///
+ /// The default value is `[0; 3]`, which must be overridden.
+ pub extent: [u32; 3],
+
+ /// If `Some`, specifies the memory and an offset into that memory that is to be bound.
+ /// The provided memory must match the image's memory requirements.
+ ///
+ /// If `None`, specifies that existing memory at the specified location is to be unbound.
+ ///
+ /// The default value is `None`.
+ pub memory: Option<(Arc<DeviceMemory>, DeviceSize)>,
+}
+
+#[inline(always)]
+pub(crate) fn is_aligned(offset: DeviceSize, alignment: DeviceAlignment) -> bool {
+ offset & (alignment.as_devicesize() - 1) == 0
}
-/*
-TODO: do this when it's possible
-unsafe impl Content for .. {}
-impl<'a, T> !Content for &'a T {}
-impl<'a, T> !Content for &'a mut T {}
-impl<T> !Content for *const T {}
-impl<T> !Content for *mut T {}
-impl<T> !Content for Box<T> {}
-impl<T> !Content for UnsafeCell<T> {}
+/// Performs bounds-checking of a Vulkan memory range. Analog of `std::slice::range`.
+pub(crate) fn range(
+ range: impl RangeBounds<DeviceSize>,
+ bounds: RangeTo<DeviceSize>,
+) -> Option<Range<DeviceSize>> {
+ let len = bounds.end;
+
+ let start = match range.start_bound() {
+ Bound::Included(&start) => start,
+ Bound::Excluded(start) => start.checked_add(1)?,
+ Bound::Unbounded => 0,
+ };
-*/
+ let end = match range.end_bound() {
+ Bound::Included(end) => end.checked_add(1)?,
+ Bound::Excluded(&end) => end,
+ Bound::Unbounded => len,
+ };
+
+ (start <= end && end <= len).then_some(Range { start, end })
+}
diff --git a/src/memory/pool/host_visible.rs b/src/memory/pool/host_visible.rs
deleted file mode 100644
index 0060618..0000000
--- a/src/memory/pool/host_visible.rs
+++ /dev/null
@@ -1,252 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::device::physical::MemoryType;
-use crate::device::Device;
-use crate::instance::Instance;
-use crate::memory::DeviceMemory;
-use crate::memory::DeviceMemoryAllocError;
-use crate::memory::MappedDeviceMemory;
-use crate::DeviceSize;
-use std::cmp;
-use std::ops::Range;
-use std::sync::Arc;
-use std::sync::Mutex;
-
-/// Memory pool that operates on a given memory type.
-#[derive(Debug)]
-pub struct StdHostVisibleMemoryTypePool {
- device: Arc<Device>,
- memory_type: u32,
- // TODO: obviously very inefficient
- occupied: Mutex<Vec<(Arc<MappedDeviceMemory>, Vec<Range<DeviceSize>>)>>,
-}
-
-impl StdHostVisibleMemoryTypePool {
- /// Creates a new pool that will operate on the given memory type.
- ///
- /// # Panic
- ///
- /// - Panics if the `device` and `memory_type` don't belong to the same physical device.
- /// - Panics if the memory type is not host-visible.
- ///
- #[inline]
- pub fn new(device: Arc<Device>, memory_type: MemoryType) -> Arc<StdHostVisibleMemoryTypePool> {
- assert_eq!(
- &**device.physical_device().instance() as *const Instance,
- &**memory_type.physical_device().instance() as *const Instance
- );
- assert_eq!(
- device.physical_device().index(),
- memory_type.physical_device().index()
- );
- assert!(memory_type.is_host_visible());
-
- Arc::new(StdHostVisibleMemoryTypePool {
- device: device.clone(),
- memory_type: memory_type.id(),
- occupied: Mutex::new(Vec::new()),
- })
- }
-
- /// Allocates memory from the pool.
- ///
- /// # Panic
- ///
- /// - Panics if `size` is 0.
- /// - Panics if `alignment` is 0.
- ///
- pub fn alloc(
- me: &Arc<Self>,
- size: DeviceSize,
- alignment: DeviceSize,
- ) -> Result<StdHostVisibleMemoryTypePoolAlloc, DeviceMemoryAllocError> {
- assert!(size != 0);
- assert!(alignment != 0);
-
- #[inline]
- fn align(val: DeviceSize, al: DeviceSize) -> DeviceSize {
- al * (1 + (val - 1) / al)
- }
-
- // Find a location.
- let mut occupied = me.occupied.lock().unwrap();
-
- // Try finding an entry in already-allocated chunks.
- for &mut (ref dev_mem, ref mut entries) in occupied.iter_mut() {
- // Try find some free space in-between two entries.
- for i in 0..entries.len().saturating_sub(1) {
- let entry1 = entries[i].clone();
- let entry1_end = align(entry1.end, alignment);
- let entry2 = entries[i + 1].clone();
- if entry1_end + size <= entry2.start {
- entries.insert(i + 1, entry1_end..entry1_end + size);
- return Ok(StdHostVisibleMemoryTypePoolAlloc {
- pool: me.clone(),
- memory: dev_mem.clone(),
- offset: entry1_end,
- size: size,
- });
- }
- }
-
- // Try append at the end.
- let last_end = entries.last().map(|e| align(e.end, alignment)).unwrap_or(0);
- if last_end + size <= (**dev_mem).as_ref().size() {
- entries.push(last_end..last_end + size);
- return Ok(StdHostVisibleMemoryTypePoolAlloc {
- pool: me.clone(),
- memory: dev_mem.clone(),
- offset: last_end,
- size: size,
- });
- }
- }
-
- // We need to allocate a new block.
- let new_block = {
- const MIN_BLOCK_SIZE: DeviceSize = 8 * 1024 * 1024; // 8 MB
- let to_alloc = cmp::max(MIN_BLOCK_SIZE, size.next_power_of_two());
- let new_block =
- DeviceMemory::alloc_and_map(me.device.clone(), me.memory_type(), to_alloc)?;
- Arc::new(new_block)
- };
-
- occupied.push((new_block.clone(), vec![0..size]));
- Ok(StdHostVisibleMemoryTypePoolAlloc {
- pool: me.clone(),
- memory: new_block,
- offset: 0,
- size,
- })
- }
-
- /// Same as `alloc` but with exportable memory fd on Linux.
- #[cfg(target_os = "linux")]
- pub fn alloc_with_exportable_fd(
- me: &Arc<Self>,
- size: DeviceSize,
- alignment: DeviceSize,
- ) -> Result<StdHostVisibleMemoryTypePoolAlloc, DeviceMemoryAllocError> {
- assert!(size != 0);
- assert!(alignment != 0);
-
- #[inline]
- fn align(val: DeviceSize, al: DeviceSize) -> DeviceSize {
- al * (1 + (val - 1) / al)
- }
-
- // Find a location.
- let mut occupied = me.occupied.lock().unwrap();
-
- // Try finding an entry in already-allocated chunks.
- for &mut (ref dev_mem, ref mut entries) in occupied.iter_mut() {
- // Try find some free space in-between two entries.
- for i in 0..entries.len().saturating_sub(1) {
- let entry1 = entries[i].clone();
- let entry1_end = align(entry1.end, alignment);
- let entry2 = entries[i + 1].clone();
- if entry1_end + size <= entry2.start {
- entries.insert(i + 1, entry1_end..entry1_end + size);
- return Ok(StdHostVisibleMemoryTypePoolAlloc {
- pool: me.clone(),
- memory: dev_mem.clone(),
- offset: entry1_end,
- size,
- });
- }
- }
-
- // Try append at the end.
- let last_end = entries.last().map(|e| align(e.end, alignment)).unwrap_or(0);
- if last_end + size <= (**dev_mem).as_ref().size() {
- entries.push(last_end..last_end + size);
- return Ok(StdHostVisibleMemoryTypePoolAlloc {
- pool: me.clone(),
- memory: dev_mem.clone(),
- offset: last_end,
- size,
- });
- }
- }
-
- // We need to allocate a new block.
- let new_block = {
- const MIN_BLOCK_SIZE: DeviceSize = 8 * 1024 * 1024; // 8 MB
- let to_alloc = cmp::max(MIN_BLOCK_SIZE, size.next_power_of_two());
- let new_block = DeviceMemory::alloc_and_map_with_exportable_fd(
- me.device.clone(),
- me.memory_type(),
- to_alloc,
- )?;
- Arc::new(new_block)
- };
-
- occupied.push((new_block.clone(), vec![0..size]));
- Ok(StdHostVisibleMemoryTypePoolAlloc {
- pool: me.clone(),
- memory: new_block,
- offset: 0,
- size,
- })
- }
-
- /// Returns the device this pool operates on.
- #[inline]
- pub fn device(&self) -> &Arc<Device> {
- &self.device
- }
-
- /// Returns the memory type this pool operates on.
- #[inline]
- pub fn memory_type(&self) -> MemoryType {
- self.device
- .physical_device()
- .memory_type_by_id(self.memory_type)
- .unwrap()
- }
-}
-
-#[derive(Debug)]
-pub struct StdHostVisibleMemoryTypePoolAlloc {
- pool: Arc<StdHostVisibleMemoryTypePool>,
- memory: Arc<MappedDeviceMemory>,
- offset: DeviceSize,
- size: DeviceSize,
-}
-
-impl StdHostVisibleMemoryTypePoolAlloc {
- #[inline]
- pub fn memory(&self) -> &MappedDeviceMemory {
- &self.memory
- }
-
- #[inline]
- pub fn offset(&self) -> DeviceSize {
- self.offset
- }
-
- #[inline]
- pub fn size(&self) -> DeviceSize {
- self.size
- }
-}
-
-impl Drop for StdHostVisibleMemoryTypePoolAlloc {
- fn drop(&mut self) {
- let mut occupied = self.pool.occupied.lock().unwrap();
-
- let entries = occupied
- .iter_mut()
- .find(|e| &*e.0 as *const MappedDeviceMemory == &*self.memory)
- .unwrap();
-
- entries.1.retain(|e| e.start != self.offset);
- }
-}
diff --git a/src/memory/pool/mod.rs b/src/memory/pool/mod.rs
deleted file mode 100644
index 4c5ad7c..0000000
--- a/src/memory/pool/mod.rs
+++ /dev/null
@@ -1,352 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-pub use self::host_visible::StdHostVisibleMemoryTypePool;
-pub use self::host_visible::StdHostVisibleMemoryTypePoolAlloc;
-pub use self::non_host_visible::StdNonHostVisibleMemoryTypePool;
-pub use self::non_host_visible::StdNonHostVisibleMemoryTypePoolAlloc;
-pub use self::pool::StdMemoryPool;
-pub use self::pool::StdMemoryPoolAlloc;
-use crate::device::physical::MemoryType;
-use crate::device::{Device, DeviceOwned};
-use crate::memory::DedicatedAlloc;
-use crate::memory::DeviceMemory;
-use crate::memory::DeviceMemoryAllocError;
-use crate::memory::MappedDeviceMemory;
-use crate::memory::MemoryRequirements;
-use crate::DeviceSize;
-use std::sync::Arc;
-
-mod host_visible;
-mod non_host_visible;
-mod pool;
-
-// If the allocation size goes beyond this, then we perform a dedicated allocation which bypasses
-// the pool. This prevents the pool from overallocating a significant amount of memory.
-const MAX_POOL_ALLOC: DeviceSize = 256 * 1024 * 1024;
-
-fn choose_allocation_memory_type<'s, F>(
- device: &'s Arc<Device>,
- requirements: &MemoryRequirements,
- mut filter: F,
- map: MappingRequirement,
-) -> MemoryType<'s>
-where
- F: FnMut(MemoryType) -> AllocFromRequirementsFilter,
-{
- let mem_ty = {
- let mut filter = |ty: MemoryType| {
- if map == MappingRequirement::Map && !ty.is_host_visible() {
- return AllocFromRequirementsFilter::Forbidden;
- }
- filter(ty)
- };
- let first_loop = device
- .physical_device()
- .memory_types()
- .map(|t| (t, AllocFromRequirementsFilter::Preferred));
- let second_loop = device
- .physical_device()
- .memory_types()
- .map(|t| (t, AllocFromRequirementsFilter::Allowed));
- first_loop
- .chain(second_loop)
- .filter(|&(t, _)| (requirements.memory_type_bits & (1 << t.id())) != 0)
- .filter(|&(t, rq)| filter(t) == rq)
- .next()
- .expect("Couldn't find a memory type to allocate from")
- .0
- };
- mem_ty
-}
-
-/// Pool of GPU-visible memory that can be allocated from.
-pub unsafe trait MemoryPool: DeviceOwned {
- /// Object that represents a single allocation. Its destructor should free the chunk.
- type Alloc: MemoryPoolAlloc;
-
- /// Allocates memory from the pool.
- ///
- /// # Safety
- ///
- /// Implementation safety:
- ///
- /// - The returned object must match the requirements.
- /// - When a linear object is allocated next to an optimal object, it is mandatory that
- /// the boundary is aligned to the value of the `buffer_image_granularity` limit.
- ///
- /// Note that it is not unsafe to *call* this function, but it is unsafe to bind the memory
- /// returned by this function to a resource.
- ///
- /// # Panic
- ///
- /// - Panics if `memory_type` doesn't belong to the same physical device as the device which
- /// was used to create this pool.
- /// - Panics if the memory type is not host-visible and `map` is `MappingRequirement::Map`.
- /// - Panics if `size` is 0.
- /// - Panics if `alignment` is 0.
- ///
- fn alloc_generic(
- &self,
- ty: MemoryType,
- size: DeviceSize,
- alignment: DeviceSize,
- layout: AllocLayout,
- map: MappingRequirement,
- ) -> Result<Self::Alloc, DeviceMemoryAllocError>;
-
- /// Same as `alloc_generic` but with exportable memory option.
- #[cfg(target_os = "linux")]
- fn alloc_generic_with_exportable_fd(
- &self,
- ty: MemoryType,
- size: DeviceSize,
- alignment: DeviceSize,
- layout: AllocLayout,
- map: MappingRequirement,
- ) -> Result<Self::Alloc, DeviceMemoryAllocError>;
-
- /// Chooses a memory type and allocates memory from it.
- ///
- /// Contrary to `alloc_generic`, this function may allocate a whole new block of memory
- /// dedicated to a resource based on `requirements.prefer_dedicated`.
- ///
- /// `filter` can be used to restrict the memory types and to indicate which are preferred.
- /// If `map` is `MappingRequirement::Map`, then non-host-visible memory types will
- /// automatically be filtered out.
- ///
- /// # Safety
- ///
- /// Implementation safety:
- ///
- /// - The returned object must match the requirements.
- /// - When a linear object is allocated next to an optimal object, it is mandatory that
- /// the boundary is aligned to the value of the `buffer_image_granularity` limit.
- /// - If `dedicated` is not `None`, the returned memory must either not be dedicated or be
- /// dedicated to the resource that was passed.
- ///
- /// Note that it is not unsafe to *call* this function, but it is unsafe to bind the memory
- /// returned by this function to a resource.
- ///
- /// # Panic
- ///
- /// - Panics if no memory type could be found, which can happen if `filter` is too restrictive.
- // TODO: ^ is this a good idea?
- /// - Panics if `size` is 0.
- /// - Panics if `alignment` is 0.
- ///
- fn alloc_from_requirements<F>(
- &self,
- requirements: &MemoryRequirements,
- layout: AllocLayout,
- map: MappingRequirement,
- dedicated: DedicatedAlloc,
- filter: F,
- ) -> Result<PotentialDedicatedAllocation<Self::Alloc>, DeviceMemoryAllocError>
- where
- F: FnMut(MemoryType) -> AllocFromRequirementsFilter,
- {
- // Choose a suitable memory type.
- let mem_ty = choose_allocation_memory_type(self.device(), requirements, filter, map);
-
- // Redirect to `self.alloc_generic` if we don't perform a dedicated allocation.
- if !requirements.prefer_dedicated && requirements.size <= MAX_POOL_ALLOC {
- let alloc = self.alloc_generic(
- mem_ty,
- requirements.size,
- requirements.alignment,
- layout,
- map,
- )?;
- return Ok(alloc.into());
- }
- if let DedicatedAlloc::None = dedicated {
- let alloc = self.alloc_generic(
- mem_ty,
- requirements.size,
- requirements.alignment,
- layout,
- map,
- )?;
- return Ok(alloc.into());
- }
-
- // If we reach here, then we perform a dedicated alloc.
- match map {
- MappingRequirement::Map => {
- let mem = DeviceMemory::dedicated_alloc_and_map(
- self.device().clone(),
- mem_ty,
- requirements.size,
- dedicated,
- )?;
- Ok(PotentialDedicatedAllocation::DedicatedMapped(mem))
- }
- MappingRequirement::DoNotMap => {
- let mem = DeviceMemory::dedicated_alloc(
- self.device().clone(),
- mem_ty,
- requirements.size,
- dedicated,
- )?;
- Ok(PotentialDedicatedAllocation::Dedicated(mem))
- }
- }
- }
-
- /// Same as `alloc_from_requirements` but with exportable fd option on Linux.
- #[cfg(target_os = "linux")]
- fn alloc_from_requirements_with_exportable_fd<F>(
- &self,
- requirements: &MemoryRequirements,
- layout: AllocLayout,
- map: MappingRequirement,
- dedicated: DedicatedAlloc,
- filter: F,
- ) -> Result<PotentialDedicatedAllocation<Self::Alloc>, DeviceMemoryAllocError>
- where
- F: FnMut(MemoryType) -> AllocFromRequirementsFilter,
- {
- assert!(self.device().enabled_extensions().khr_external_memory_fd);
- assert!(self.device().enabled_extensions().khr_external_memory);
-
- let mem_ty = choose_allocation_memory_type(self.device(), requirements, filter, map);
-
- if !requirements.prefer_dedicated
- || !self.device().enabled_extensions().khr_dedicated_allocation
- {
- let alloc = self.alloc_generic_with_exportable_fd(
- mem_ty,
- requirements.size,
- requirements.alignment,
- layout,
- map,
- )?;
- return Ok(alloc.into());
- }
- if let DedicatedAlloc::None = dedicated {
- let alloc = self.alloc_generic_with_exportable_fd(
- mem_ty,
- requirements.size,
- requirements.alignment,
- layout,
- map,
- )?;
- return Ok(alloc.into());
- }
-
- match map {
- MappingRequirement::Map => {
- let mem = DeviceMemory::dedicated_alloc_and_map_with_exportable_fd(
- self.device().clone(),
- mem_ty,
- requirements.size,
- dedicated,
- )?;
- Ok(PotentialDedicatedAllocation::DedicatedMapped(mem))
- }
- MappingRequirement::DoNotMap => {
- let mem = DeviceMemory::dedicated_alloc_with_exportable_fd(
- self.device().clone(),
- mem_ty,
- requirements.size,
- dedicated,
- )?;
- Ok(PotentialDedicatedAllocation::Dedicated(mem))
- }
- }
- }
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum AllocFromRequirementsFilter {
- Preferred,
- Allowed,
- Forbidden,
-}
-
-/// Object that represents a single allocation. Its destructor should free the chunk.
-pub unsafe trait MemoryPoolAlloc {
- /// Returns the memory object from which this is allocated. Returns `None` if the memory is
- /// not mapped.
- fn mapped_memory(&self) -> Option<&MappedDeviceMemory>;
-
- /// Returns the memory object from which this is allocated.
- fn memory(&self) -> &DeviceMemory;
-
- /// Returns the offset at the start of the memory where the first byte of this allocation
- /// resides.
- fn offset(&self) -> DeviceSize;
-}
-
-/// Whether an allocation should map the memory or not.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub enum MappingRequirement {
- /// Should map.
- Map,
- /// Shouldn't map.
- DoNotMap,
-}
-
-/// Layout of the object being allocated.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub enum AllocLayout {
- /// The object has a linear layout.
- Linear,
- /// The object has an optimal layout.
- Optimal,
-}
-
-/// Enumeration that can contain either a generic allocation coming from a pool, or a dedicated
-/// allocation for one specific resource.
-#[derive(Debug)]
-pub enum PotentialDedicatedAllocation<A> {
- Generic(A),
- Dedicated(DeviceMemory),
- DedicatedMapped(MappedDeviceMemory),
-}
-
-unsafe impl<A> MemoryPoolAlloc for PotentialDedicatedAllocation<A>
-where
- A: MemoryPoolAlloc,
-{
- #[inline]
- fn mapped_memory(&self) -> Option<&MappedDeviceMemory> {
- match *self {
- PotentialDedicatedAllocation::Generic(ref alloc) => alloc.mapped_memory(),
- PotentialDedicatedAllocation::Dedicated(_) => None,
- PotentialDedicatedAllocation::DedicatedMapped(ref mem) => Some(mem),
- }
- }
-
- #[inline]
- fn memory(&self) -> &DeviceMemory {
- match *self {
- PotentialDedicatedAllocation::Generic(ref alloc) => alloc.memory(),
- PotentialDedicatedAllocation::Dedicated(ref mem) => mem,
- PotentialDedicatedAllocation::DedicatedMapped(ref mem) => mem.as_ref(),
- }
- }
-
- #[inline]
- fn offset(&self) -> DeviceSize {
- match *self {
- PotentialDedicatedAllocation::Generic(ref alloc) => alloc.offset(),
- PotentialDedicatedAllocation::Dedicated(_) => 0,
- PotentialDedicatedAllocation::DedicatedMapped(_) => 0,
- }
- }
-}
-
-impl<A> From<A> for PotentialDedicatedAllocation<A> {
- #[inline]
- fn from(alloc: A) -> PotentialDedicatedAllocation<A> {
- PotentialDedicatedAllocation::Generic(alloc)
- }
-}
diff --git a/src/memory/pool/non_host_visible.rs b/src/memory/pool/non_host_visible.rs
deleted file mode 100644
index e9cf12e..0000000
--- a/src/memory/pool/non_host_visible.rs
+++ /dev/null
@@ -1,251 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::device::physical::MemoryType;
-use crate::device::Device;
-use crate::instance::Instance;
-use crate::memory::DeviceMemory;
-use crate::memory::DeviceMemoryAllocError;
-use crate::DeviceSize;
-use std::cmp;
-use std::ops::Range;
-use std::sync::Arc;
-use std::sync::Mutex;
-
-/// Memory pool that operates on a given memory type.
-#[derive(Debug)]
-pub struct StdNonHostVisibleMemoryTypePool {
- device: Arc<Device>,
- memory_type: u32,
- // TODO: obviously very inefficient
- occupied: Mutex<Vec<(Arc<DeviceMemory>, Vec<Range<DeviceSize>>)>>,
-}
-
-impl StdNonHostVisibleMemoryTypePool {
- /// Creates a new pool that will operate on the given memory type.
- ///
- /// # Panic
- ///
- /// - Panics if the `device` and `memory_type` don't belong to the same physical device.
- ///
- #[inline]
- pub fn new(
- device: Arc<Device>,
- memory_type: MemoryType,
- ) -> Arc<StdNonHostVisibleMemoryTypePool> {
- assert_eq!(
- &**device.physical_device().instance() as *const Instance,
- &**memory_type.physical_device().instance() as *const Instance
- );
- assert_eq!(
- device.physical_device().index(),
- memory_type.physical_device().index()
- );
-
- Arc::new(StdNonHostVisibleMemoryTypePool {
- device: device.clone(),
- memory_type: memory_type.id(),
- occupied: Mutex::new(Vec::new()),
- })
- }
-
- /// Allocates memory from the pool.
- ///
- /// # Panic
- ///
- /// - Panics if `size` is 0.
- /// - Panics if `alignment` is 0.
- ///
- pub fn alloc(
- me: &Arc<Self>,
- size: DeviceSize,
- alignment: DeviceSize,
- ) -> Result<StdNonHostVisibleMemoryTypePoolAlloc, DeviceMemoryAllocError> {
- assert!(size != 0);
- assert!(alignment != 0);
-
- #[inline]
- fn align(val: DeviceSize, al: DeviceSize) -> DeviceSize {
- al * (1 + (val - 1) / al)
- }
-
- // Find a location.
- let mut occupied = me.occupied.lock().unwrap();
-
- // Try finding an entry in already-allocated chunks.
- for &mut (ref dev_mem, ref mut entries) in occupied.iter_mut() {
- // Try find some free space in-between two entries.
- for i in 0..entries.len().saturating_sub(1) {
- let entry1 = entries[i].clone();
- let entry1_end = align(entry1.end, alignment);
- let entry2 = entries[i + 1].clone();
- if entry1_end + size <= entry2.start {
- entries.insert(i + 1, entry1_end..entry1_end + size);
- return Ok(StdNonHostVisibleMemoryTypePoolAlloc {
- pool: me.clone(),
- memory: dev_mem.clone(),
- offset: entry1_end,
- size: size,
- });
- }
- }
-
- // Try append at the end.
- let last_end = entries.last().map(|e| align(e.end, alignment)).unwrap_or(0);
- if last_end + size <= dev_mem.size() {
- entries.push(last_end..last_end + size);
- return Ok(StdNonHostVisibleMemoryTypePoolAlloc {
- pool: me.clone(),
- memory: dev_mem.clone(),
- offset: last_end,
- size: size,
- });
- }
- }
-
- // We need to allocate a new block.
- let new_block = {
- const MIN_BLOCK_SIZE: DeviceSize = 8 * 1024 * 1024; // 8 MB
- let to_alloc = cmp::max(MIN_BLOCK_SIZE, size.next_power_of_two());
- let new_block = DeviceMemory::alloc(me.device.clone(), me.memory_type(), to_alloc)?;
- Arc::new(new_block)
- };
-
- occupied.push((new_block.clone(), vec![0..size]));
- Ok(StdNonHostVisibleMemoryTypePoolAlloc {
- pool: me.clone(),
- memory: new_block,
- offset: 0,
- size: size,
- })
- }
-
- /// Same as `alloc` but with exportable memory fd on Linux.
- #[cfg(target_os = "linux")]
- pub fn alloc_with_exportable_fd(
- me: &Arc<Self>,
- size: DeviceSize,
- alignment: DeviceSize,
- ) -> Result<StdNonHostVisibleMemoryTypePoolAlloc, DeviceMemoryAllocError> {
- assert!(size != 0);
- assert!(alignment != 0);
-
- #[inline]
- fn align(val: DeviceSize, al: DeviceSize) -> DeviceSize {
- al * (1 + (val - 1) / al)
- }
-
- // Find a location.
- let mut occupied = me.occupied.lock().unwrap();
-
- // Try finding an entry in already-allocated chunks.
- for &mut (ref dev_mem, ref mut entries) in occupied.iter_mut() {
- // Try find some free space in-between two entries.
- for i in 0..entries.len().saturating_sub(1) {
- let entry1 = entries[i].clone();
- let entry1_end = align(entry1.end, alignment);
- let entry2 = entries[i + 1].clone();
- if entry1_end + size <= entry2.start {
- entries.insert(i + 1, entry1_end..entry1_end + size);
- return Ok(StdNonHostVisibleMemoryTypePoolAlloc {
- pool: me.clone(),
- memory: dev_mem.clone(),
- offset: entry1_end,
- size,
- });
- }
- }
-
- // Try append at the end.
- let last_end = entries.last().map(|e| align(e.end, alignment)).unwrap_or(0);
- if last_end + size <= dev_mem.size() {
- entries.push(last_end..last_end + size);
- return Ok(StdNonHostVisibleMemoryTypePoolAlloc {
- pool: me.clone(),
- memory: dev_mem.clone(),
- offset: last_end,
- size,
- });
- }
- }
-
- // We need to allocate a new block.
- let new_block = {
- const MIN_BLOCK_SIZE: DeviceSize = 8 * 1024 * 1024; // 8 MB
- let to_alloc = cmp::max(MIN_BLOCK_SIZE, size.next_power_of_two());
- let new_block = DeviceMemory::alloc_with_exportable_fd(
- me.device.clone(),
- me.memory_type(),
- to_alloc,
- )?;
- Arc::new(new_block)
- };
-
- occupied.push((new_block.clone(), vec![0..size]));
- Ok(StdNonHostVisibleMemoryTypePoolAlloc {
- pool: me.clone(),
- memory: new_block,
- offset: 0,
- size,
- })
- }
-
- /// Returns the device this pool operates on.
- #[inline]
- pub fn device(&self) -> &Arc<Device> {
- &self.device
- }
-
- /// Returns the memory type this pool operates on.
- #[inline]
- pub fn memory_type(&self) -> MemoryType {
- self.device
- .physical_device()
- .memory_type_by_id(self.memory_type)
- .unwrap()
- }
-}
-
-#[derive(Debug)]
-pub struct StdNonHostVisibleMemoryTypePoolAlloc {
- pool: Arc<StdNonHostVisibleMemoryTypePool>,
- memory: Arc<DeviceMemory>,
- offset: DeviceSize,
- size: DeviceSize,
-}
-
-impl StdNonHostVisibleMemoryTypePoolAlloc {
- #[inline]
- pub fn memory(&self) -> &DeviceMemory {
- &self.memory
- }
-
- #[inline]
- pub fn offset(&self) -> DeviceSize {
- self.offset
- }
-
- #[inline]
- pub fn size(&self) -> DeviceSize {
- self.size
- }
-}
-
-impl Drop for StdNonHostVisibleMemoryTypePoolAlloc {
- fn drop(&mut self) {
- let mut occupied = self.pool.occupied.lock().unwrap();
-
- let entries = occupied
- .iter_mut()
- .find(|e| &*e.0 as *const DeviceMemory == &*self.memory)
- .unwrap();
-
- entries.1.retain(|e| e.start != self.offset);
- }
-}
diff --git a/src/memory/pool/pool.rs b/src/memory/pool/pool.rs
deleted file mode 100644
index 0681716..0000000
--- a/src/memory/pool/pool.rs
+++ /dev/null
@@ -1,273 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::device::physical::MemoryType;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::memory::pool::AllocLayout;
-use crate::memory::pool::MappingRequirement;
-use crate::memory::pool::MemoryPool;
-use crate::memory::pool::MemoryPoolAlloc;
-use crate::memory::pool::StdHostVisibleMemoryTypePool;
-use crate::memory::pool::StdHostVisibleMemoryTypePoolAlloc;
-use crate::memory::pool::StdNonHostVisibleMemoryTypePool;
-use crate::memory::pool::StdNonHostVisibleMemoryTypePoolAlloc;
-use crate::memory::DeviceMemory;
-use crate::memory::DeviceMemoryAllocError;
-use crate::memory::MappedDeviceMemory;
-use crate::DeviceSize;
-use fnv::FnvHasher;
-use std::collections::hash_map::Entry;
-use std::collections::HashMap;
-use std::hash::BuildHasherDefault;
-use std::sync::Arc;
-use std::sync::Mutex;
-
-#[derive(Debug)]
-pub struct StdMemoryPool {
- device: Arc<Device>,
-
- // For each memory type index, stores the associated pool.
- pools:
- Mutex<HashMap<(u32, AllocLayout, MappingRequirement), Pool, BuildHasherDefault<FnvHasher>>>,
-}
-
-impl StdMemoryPool {
- /// Creates a new pool.
- #[inline]
- pub fn new(device: Arc<Device>) -> Arc<StdMemoryPool> {
- let cap = device.physical_device().memory_types().len();
- let hasher = BuildHasherDefault::<FnvHasher>::default();
-
- Arc::new(StdMemoryPool {
- device: device.clone(),
- pools: Mutex::new(HashMap::with_capacity_and_hasher(cap, hasher)),
- })
- }
-}
-
-fn generic_allocation(
- mem_pool: Arc<StdMemoryPool>,
- memory_type: MemoryType,
- size: DeviceSize,
- alignment: DeviceSize,
- layout: AllocLayout,
- map: MappingRequirement,
-) -> Result<StdMemoryPoolAlloc, DeviceMemoryAllocError> {
- let mut pools = mem_pool.pools.lock().unwrap();
-
- let memory_type_host_visible = memory_type.is_host_visible();
- assert!(memory_type_host_visible || map == MappingRequirement::DoNotMap);
-
- match pools.entry((memory_type.id(), layout, map)) {
- Entry::Occupied(entry) => match entry.get() {
- &Pool::HostVisible(ref pool) => {
- let alloc = StdHostVisibleMemoryTypePool::alloc(&pool, size, alignment)?;
- let inner = StdMemoryPoolAllocInner::HostVisible(alloc);
- Ok(StdMemoryPoolAlloc {
- inner,
- pool: mem_pool.clone(),
- })
- }
- &Pool::NonHostVisible(ref pool) => {
- let alloc = StdNonHostVisibleMemoryTypePool::alloc(&pool, size, alignment)?;
- let inner = StdMemoryPoolAllocInner::NonHostVisible(alloc);
- Ok(StdMemoryPoolAlloc {
- inner,
- pool: mem_pool.clone(),
- })
- }
- },
-
- Entry::Vacant(entry) => {
- if memory_type_host_visible {
- let pool = StdHostVisibleMemoryTypePool::new(mem_pool.device.clone(), memory_type);
- entry.insert(Pool::HostVisible(pool.clone()));
- let alloc = StdHostVisibleMemoryTypePool::alloc(&pool, size, alignment)?;
- let inner = StdMemoryPoolAllocInner::HostVisible(alloc);
- Ok(StdMemoryPoolAlloc {
- inner,
- pool: mem_pool.clone(),
- })
- } else {
- let pool =
- StdNonHostVisibleMemoryTypePool::new(mem_pool.device.clone(), memory_type);
- entry.insert(Pool::NonHostVisible(pool.clone()));
- let alloc = StdNonHostVisibleMemoryTypePool::alloc(&pool, size, alignment)?;
- let inner = StdMemoryPoolAllocInner::NonHostVisible(alloc);
- Ok(StdMemoryPoolAlloc {
- inner,
- pool: mem_pool.clone(),
- })
- }
- }
- }
-}
-
-/// Same as `generic_allocation` but with exportable memory fd on Linux.
-#[cfg(target_os = "linux")]
-fn generit_allocation_with_exportable_fd(
- mem_pool: Arc<StdMemoryPool>,
- memory_type: MemoryType,
- size: DeviceSize,
- alignment: DeviceSize,
- layout: AllocLayout,
- map: MappingRequirement,
-) -> Result<StdMemoryPoolAlloc, DeviceMemoryAllocError> {
- let mut pools = mem_pool.pools.lock().unwrap();
-
- let memory_type_host_visible = memory_type.is_host_visible();
- assert!(memory_type_host_visible || map == MappingRequirement::DoNotMap);
-
- match pools.entry((memory_type.id(), layout, map)) {
- Entry::Occupied(entry) => match entry.get() {
- &Pool::HostVisible(ref pool) => {
- let alloc =
- StdHostVisibleMemoryTypePool::alloc_with_exportable_fd(&pool, size, alignment)?;
- let inner = StdMemoryPoolAllocInner::HostVisible(alloc);
- Ok(StdMemoryPoolAlloc {
- inner,
- pool: mem_pool.clone(),
- })
- }
- &Pool::NonHostVisible(ref pool) => {
- let alloc = StdNonHostVisibleMemoryTypePool::alloc_with_exportable_fd(
- &pool, size, alignment,
- )?;
- let inner = StdMemoryPoolAllocInner::NonHostVisible(alloc);
- Ok(StdMemoryPoolAlloc {
- inner,
- pool: mem_pool.clone(),
- })
- }
- },
-
- Entry::Vacant(entry) => {
- if memory_type_host_visible {
- let pool = StdHostVisibleMemoryTypePool::new(mem_pool.device.clone(), memory_type);
- entry.insert(Pool::HostVisible(pool.clone()));
- let alloc =
- StdHostVisibleMemoryTypePool::alloc_with_exportable_fd(&pool, size, alignment)?;
- let inner = StdMemoryPoolAllocInner::HostVisible(alloc);
- Ok(StdMemoryPoolAlloc {
- inner,
- pool: mem_pool.clone(),
- })
- } else {
- let pool =
- StdNonHostVisibleMemoryTypePool::new(mem_pool.device.clone(), memory_type);
- entry.insert(Pool::NonHostVisible(pool.clone()));
- let alloc = StdNonHostVisibleMemoryTypePool::alloc_with_exportable_fd(
- &pool, size, alignment,
- )?;
- let inner = StdMemoryPoolAllocInner::NonHostVisible(alloc);
- Ok(StdMemoryPoolAlloc {
- inner,
- pool: mem_pool.clone(),
- })
- }
- }
- }
-}
-
-unsafe impl MemoryPool for Arc<StdMemoryPool> {
- type Alloc = StdMemoryPoolAlloc;
-
- fn alloc_generic(
- &self,
- memory_type: MemoryType,
- size: DeviceSize,
- alignment: DeviceSize,
- layout: AllocLayout,
- map: MappingRequirement,
- ) -> Result<StdMemoryPoolAlloc, DeviceMemoryAllocError> {
- generic_allocation(self.clone(), memory_type, size, alignment, layout, map)
- }
-
- /// Same as `alloc_generic` but with exportable fd option on Linux.
- #[cfg(target_os = "linux")]
- fn alloc_generic_with_exportable_fd(
- &self,
- memory_type: MemoryType,
- size: DeviceSize,
- alignment: DeviceSize,
- layout: AllocLayout,
- map: MappingRequirement,
- ) -> Result<StdMemoryPoolAlloc, DeviceMemoryAllocError> {
- generit_allocation_with_exportable_fd(
- self.clone(),
- memory_type,
- size,
- alignment,
- layout,
- map,
- )
- }
-}
-
-unsafe impl DeviceOwned for StdMemoryPool {
- #[inline]
- fn device(&self) -> &Arc<Device> {
- &self.device
- }
-}
-
-#[derive(Debug)]
-enum Pool {
- HostVisible(Arc<StdHostVisibleMemoryTypePool>),
- NonHostVisible(Arc<StdNonHostVisibleMemoryTypePool>),
-}
-
-#[derive(Debug)]
-pub struct StdMemoryPoolAlloc {
- inner: StdMemoryPoolAllocInner,
- pool: Arc<StdMemoryPool>,
-}
-
-impl StdMemoryPoolAlloc {
- #[inline]
- pub fn size(&self) -> DeviceSize {
- match self.inner {
- StdMemoryPoolAllocInner::NonHostVisible(ref mem) => mem.size(),
- StdMemoryPoolAllocInner::HostVisible(ref mem) => mem.size(),
- }
- }
-}
-
-unsafe impl MemoryPoolAlloc for StdMemoryPoolAlloc {
- #[inline]
- fn memory(&self) -> &DeviceMemory {
- match self.inner {
- StdMemoryPoolAllocInner::NonHostVisible(ref mem) => mem.memory(),
- StdMemoryPoolAllocInner::HostVisible(ref mem) => mem.memory().as_ref(),
- }
- }
-
- #[inline]
- fn mapped_memory(&self) -> Option<&MappedDeviceMemory> {
- match self.inner {
- StdMemoryPoolAllocInner::NonHostVisible(_) => None,
- StdMemoryPoolAllocInner::HostVisible(ref mem) => Some(mem.memory()),
- }
- }
-
- #[inline]
- fn offset(&self) -> DeviceSize {
- match self.inner {
- StdMemoryPoolAllocInner::NonHostVisible(ref mem) => mem.offset(),
- StdMemoryPoolAllocInner::HostVisible(ref mem) => mem.offset(),
- }
- }
-}
-
-#[derive(Debug)]
-enum StdMemoryPoolAllocInner {
- NonHostVisible(StdNonHostVisibleMemoryTypePoolAlloc),
- HostVisible(StdHostVisibleMemoryTypePoolAlloc),
-}
diff --git a/src/padded.rs b/src/padded.rs
new file mode 100644
index 0000000..dbf18f1
--- /dev/null
+++ b/src/padded.rs
@@ -0,0 +1,338 @@
+// Copyright (c) 2016 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+//! A newtype wrapper for enforcing correct alignment for external types.
+
+use crate::buffer::{BufferContents, BufferContentsLayout};
+#[cfg(feature = "serde")]
+use serde::{Deserialize, Deserializer, Serialize, Serializer};
+use std::{
+ alloc::Layout,
+ cmp::Ordering,
+ ffi::c_void,
+ fmt::{Debug, Display, Formatter, Result as FmtResult},
+ hash::{Hash, Hasher},
+ mem::{align_of, size_of, MaybeUninit},
+ ops::{Deref, DerefMut},
+};
+
+/// A newtype wrapper around `T`, with `N` bytes of trailing padding.
+///
+/// In Vulkan, the layout of buffer contents is not necessarily as one would expect from the type
+/// signature in the shader code. For example, the *extended layout* or *std140 layout* in GLSL,
+/// which is used for uniform buffers by default, requires that array elements are aligned to 16
+/// bytes at minimum. That means that even if the array contains a scalar type like `u32` for
+/// example, it must be aligned to 16 bytes. We can not enforce that with primitive Rust types
+/// alone. In such cases, we can use `Padded` to enforce correct alignment on the Rust side.
+///
+/// See also [the `shader` module documentation] for more information about layout in shaders.
+///
+/// # Examples
+///
+/// ## Aligning struct members
+///
+/// Consider this GLSL code:
+///
+/// ```glsl
+/// layout(binding = 0) uniform MyData {
+/// int x;
+/// vec3 y;
+/// vec4 z;
+/// };
+/// ```
+///
+/// By default, the alignment rules require that `y` and `z` are placed at an offset that is an
+/// integer multiple of 16. However, `x` is only 4 bytes, which means that there must be 12 bytes
+/// of padding between `x` and `y`. Furthermore, `y` is only 12 bytes, which means that there must
+/// be 4 bytes of padding between `y` and `z`.
+///
+/// We can model this in Rust using `Padded`:
+///
+/// ```
+/// # use vulkano::{buffer::BufferContents, padded::Padded};
+/// #[derive(BufferContents)]
+/// #[repr(C)]
+/// struct MyData {
+/// x: Padded<i32, 12>,
+/// y: Padded<[f32; 3], 4>,
+/// z: [f32; 4],
+/// }
+///
+/// let data = MyData {
+/// x: Padded(42),
+/// y: Padded([1.0, 2.0, 3.0]),
+/// z: [10.0; 4],
+/// };
+/// ```
+///
+/// **But note that this layout is extremely suboptimal.** What you should do instead is reorder
+/// your fields such that you don't need any padding:
+///
+/// ```glsl
+/// layout(binding = 0) uniform MyData {
+/// vec3 y;
+/// int x;
+/// vec4 z;
+/// };
+/// ```
+///
+/// ```
+/// # use vulkano::buffer::BufferContents;
+/// #[derive(BufferContents)]
+/// #[repr(C)]
+/// struct MyData {
+/// y: [f32; 3],
+/// x: i32,
+/// z: [f32; 4],
+/// }
+/// ```
+///
+/// This way, the fields are aligned naturally. But reordering fields is not always an option: the
+/// notable case being when your structure only contains `vec3`s and `vec4`s, or `vec3`s and
+/// `vec2`s, so that there are no scalar fields to fill the gaps with.
+///
+/// ## Aligning array elements
+///
+/// If you need an array of `vec3`s, then that necessitates that each array element has 4 bytes of
+/// trailing padding. The same goes for a matrix with 3 rows, each column will have to have 4 bytes
+/// of trailing padding (assuming its column-major).
+///
+/// We can model those using `Padded` too:
+///
+/// ```glsl
+/// layout(binding = 0) uniform MyData {
+/// vec3 x[10];
+/// mat3 y;
+/// };
+/// ```
+///
+/// ```
+/// # use vulkano::{buffer::BufferContents, padded::Padded};
+/// #[derive(BufferContents)]
+/// #[repr(C)]
+/// struct MyData {
+/// x: [Padded<[f32; 3], 4>; 10],
+/// y: [Padded<[f32; 3], 4>; 3],
+/// }
+/// ```
+///
+/// Another example would be if you have an array of scalars or `vec2`s inside a uniform block:
+///
+/// ```glsl
+/// layout(binding = 0) uniform MyData {
+/// int x[10];
+/// vec2 y[10];
+/// };
+/// ```
+///
+/// By default, arrays inside uniform blocks must have their elements aligned to 16 bytes at
+/// minimum, which would look like this in Rust:
+///
+/// ```
+/// # use vulkano::{buffer::BufferContents, padded::Padded};
+/// #[derive(BufferContents)]
+/// #[repr(C)]
+/// struct MyData {
+/// x: [Padded<i32, 12>; 10],
+/// y: [Padded<[f32; 2], 8>; 10],
+/// }
+/// ```
+///
+/// **But note again, that this layout is suboptimal.** You can instead use a buffer block instead
+/// of the uniform block, if memory usage could become an issue:
+///
+/// ```glsl
+/// layout(binding = 0) buffer MyData {
+/// int x[10];
+/// vec2 y[10];
+/// };
+/// ```
+///
+/// ```
+/// # use vulkano::buffer::BufferContents;
+/// #[derive(BufferContents)]
+/// #[repr(C)]
+/// struct MyData {
+/// x: [i32; 10],
+/// y: [[f32; 2]; 10],
+/// }
+/// ```
+///
+/// You may also want to consider using [the `uniform_buffer_standard_layout` feature].
+///
+/// [the `shader` module documentation]: crate::shader
+/// [the `uniform_buffer_standard_layout` feature]: crate::device::Features::uniform_buffer_standard_layout
+#[repr(C)]
+pub struct Padded<T, const N: usize> {
+ value: T,
+ _padding: [MaybeUninit<u8>; N],
+}
+
+#[allow(non_snake_case)]
+#[doc(hidden)]
+#[inline(always)]
+pub const fn Padded<T, const N: usize>(value: T) -> Padded<T, N> {
+ Padded {
+ value,
+ _padding: [MaybeUninit::uninit(); N],
+ }
+}
+
+impl<T, const N: usize> AsRef<T> for Padded<T, N> {
+ fn as_ref(&self) -> &T {
+ &self.value
+ }
+}
+
+impl<T, const N: usize> AsMut<T> for Padded<T, N> {
+ fn as_mut(&mut self) -> &mut T {
+ &mut self.value
+ }
+}
+
+impl<T, const N: usize> Clone for Padded<T, N>
+where
+ T: Clone,
+{
+ fn clone(&self) -> Self {
+ Padded(self.value.clone())
+ }
+}
+
+impl<T, const N: usize> Copy for Padded<T, N> where T: Copy {}
+
+impl<T, const N: usize> Debug for Padded<T, N>
+where
+ T: Debug,
+{
+ fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
+ self.value.fmt(f)
+ }
+}
+
+impl<T, const N: usize> Default for Padded<T, N>
+where
+ T: Default,
+{
+ fn default() -> Self {
+ Padded(T::default())
+ }
+}
+
+impl<T, const N: usize> Deref for Padded<T, N> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ &self.value
+ }
+}
+
+impl<T, const N: usize> DerefMut for Padded<T, N> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.value
+ }
+}
+
+impl<T, const N: usize> Display for Padded<T, N>
+where
+ T: Display,
+{
+ fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
+ self.value.fmt(f)
+ }
+}
+
+impl<T, const N: usize> From<T> for Padded<T, N> {
+ fn from(value: T) -> Self {
+ Padded(value)
+ }
+}
+
+impl<T, const N: usize> PartialEq for Padded<T, N>
+where
+ T: PartialEq,
+{
+ fn eq(&self, other: &Self) -> bool {
+ self.value == other.value
+ }
+}
+
+impl<T, const N: usize> Eq for Padded<T, N> where T: Eq {}
+
+impl<T, const N: usize> Hash for Padded<T, N>
+where
+ T: Hash,
+{
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.value.hash(state);
+ }
+}
+
+impl<T, const N: usize> PartialOrd for Padded<T, N>
+where
+ T: PartialOrd,
+{
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ self.value.partial_cmp(&other.value)
+ }
+}
+
+impl<T, const N: usize> Ord for Padded<T, N>
+where
+ T: Ord,
+{
+ fn cmp(&self, other: &Self) -> Ordering {
+ self.value.cmp(&other.value)
+ }
+}
+
+unsafe impl<T, const N: usize> BufferContents for Padded<T, N>
+where
+ T: BufferContents,
+{
+ const LAYOUT: BufferContentsLayout =
+ if let Some(layout) = BufferContentsLayout::from_sized(Layout::new::<Self>()) {
+ layout
+ } else {
+ panic!("zero-sized types are not valid buffer contents");
+ };
+
+ unsafe fn from_ffi(data: *mut c_void, range: usize) -> *mut Self {
+ debug_assert!(range == size_of::<Self>());
+ debug_assert!(data as usize % align_of::<Self>() == 0);
+
+ data.cast()
+ }
+}
+
+#[cfg(feature = "serde")]
+impl<T, const N: usize> Serialize for Padded<T, N>
+where
+ T: Serialize,
+{
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ self.value.serialize(serializer)
+ }
+}
+
+#[cfg(feature = "serde")]
+impl<'de, T, const N: usize> Deserialize<'de> for Padded<T, N>
+where
+ T: Deserialize<'de>,
+{
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ T::deserialize(deserializer).map(Padded)
+ }
+}
diff --git a/src/pipeline/blend.rs b/src/pipeline/blend.rs
deleted file mode 100644
index 7863b8a..0000000
--- a/src/pipeline/blend.rs
+++ /dev/null
@@ -1,291 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-//! Defines how the color output of the fragment shader is written to the attachment.
-//!
-//! # Blending in details
-//!
-//! There are three kinds of color attachments for the purpose of blending:
-//!
-//! - Attachments with a floating-point, fixed point format.
-//! - Attachments with a (non-normalized) integer format.
-//! - Attachments with a normalized integer format.
-//!
-//! For floating-point and fixed-point formats, the blending operation is applied. For integer
-//! formats, the logic operation is applied. For normalized integer formats, the logic operation
-//! will take precedence if it is activated, otherwise the blending operation is applied.
-//!
-
-/// Describes how the color output of the fragment shader is written to the attachment. See the
-/// documentation of the `blend` module for more info.
-#[derive(Debug, Clone, PartialEq)]
-pub struct Blend {
- pub logic_op: Option<LogicOp>,
-
- pub attachments: AttachmentsBlend,
-
- /// The constant color to use for the `Constant*` blending operation.
- ///
- /// If you pass `None`, then this state will be considered as dynamic and the blend constants
- /// will need to be set when you build the command buffer.
- pub blend_constants: Option<[f32; 4]>,
-}
-
-impl Blend {
- /// Returns a `Blend` object that directly writes colors and alpha on the surface.
- #[inline]
- pub fn pass_through() -> Blend {
- Blend {
- logic_op: None,
- attachments: AttachmentsBlend::Collective(AttachmentBlend::pass_through()),
- blend_constants: Some([0.0, 0.0, 0.0, 0.0]),
- }
- }
-
- /// Returns a `Blend` object that adds transparent objects over others.
- #[inline]
- pub fn alpha_blending() -> Blend {
- Blend {
- logic_op: None,
- attachments: AttachmentsBlend::Collective(AttachmentBlend::alpha_blending()),
- blend_constants: Some([0.0, 0.0, 0.0, 0.0]),
- }
- }
-}
-
-/// Describes how the blending system should behave.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum AttachmentsBlend {
- /// All the framebuffer attachments will use the same blending.
- Collective(AttachmentBlend),
-
- /// Each attachment will behave differently. Note that this requires enabling the
- /// `independent_blend` feature.
- Individual(Vec<AttachmentBlend>),
-}
-
-/// Describes how the blending system should behave for an individual attachment.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct AttachmentBlend {
- // TODO: could be automatically determined from the other params
- /// If false, blending is ignored and the output is directly written to the attachment.
- pub enabled: bool,
-
- pub color_op: BlendOp,
- pub color_source: BlendFactor,
- pub color_destination: BlendFactor,
-
- pub alpha_op: BlendOp,
- pub alpha_source: BlendFactor,
- pub alpha_destination: BlendFactor,
-
- pub mask_red: bool,
- pub mask_green: bool,
- pub mask_blue: bool,
- pub mask_alpha: bool,
-}
-
-impl AttachmentBlend {
- /// Builds an `AttachmentBlend` where blending is disabled.
- #[inline]
- pub fn pass_through() -> AttachmentBlend {
- AttachmentBlend {
- enabled: false,
- color_op: BlendOp::Add,
- color_source: BlendFactor::Zero,
- color_destination: BlendFactor::One,
- alpha_op: BlendOp::Add,
- alpha_source: BlendFactor::Zero,
- alpha_destination: BlendFactor::One,
- mask_red: true,
- mask_green: true,
- mask_blue: true,
- mask_alpha: true,
- }
- }
-
- /// Builds an `AttachmentBlend` where the output of the fragment shader is ignored and the
- /// destination is untouched.
- #[inline]
- pub fn ignore_source() -> AttachmentBlend {
- AttachmentBlend {
- enabled: true,
- color_op: BlendOp::Add,
- color_source: BlendFactor::Zero,
- color_destination: BlendFactor::DstColor,
- alpha_op: BlendOp::Add,
- alpha_source: BlendFactor::Zero,
- alpha_destination: BlendFactor::DstColor,
- mask_red: true,
- mask_green: true,
- mask_blue: true,
- mask_alpha: true,
- }
- }
-
- /// Builds an `AttachmentBlend` where the output will be merged with the existing value
- /// based on the alpha of the source.
- #[inline]
- pub fn alpha_blending() -> AttachmentBlend {
- AttachmentBlend {
- enabled: true,
- color_op: BlendOp::Add,
- color_source: BlendFactor::SrcAlpha,
- color_destination: BlendFactor::OneMinusSrcAlpha,
- alpha_op: BlendOp::Add,
- alpha_source: BlendFactor::SrcAlpha,
- alpha_destination: BlendFactor::OneMinusSrcAlpha,
- mask_red: true,
- mask_green: true,
- mask_blue: true,
- mask_alpha: true,
- }
- }
-}
-
-impl From<AttachmentBlend> for ash::vk::PipelineColorBlendAttachmentState {
- #[inline]
- fn from(val: AttachmentBlend) -> Self {
- ash::vk::PipelineColorBlendAttachmentState {
- blend_enable: if val.enabled {
- ash::vk::TRUE
- } else {
- ash::vk::FALSE
- },
- src_color_blend_factor: val.color_source.into(),
- dst_color_blend_factor: val.color_destination.into(),
- color_blend_op: val.color_op.into(),
- src_alpha_blend_factor: val.alpha_source.into(),
- dst_alpha_blend_factor: val.alpha_destination.into(),
- alpha_blend_op: val.alpha_op.into(),
- color_write_mask: {
- let mut mask = ash::vk::ColorComponentFlags::empty();
- if val.mask_red {
- mask |= ash::vk::ColorComponentFlags::R;
- }
- if val.mask_green {
- mask |= ash::vk::ColorComponentFlags::G;
- }
- if val.mask_blue {
- mask |= ash::vk::ColorComponentFlags::B;
- }
- if val.mask_alpha {
- mask |= ash::vk::ColorComponentFlags::A;
- }
- mask
- },
- }
- }
-}
-
-/// Which logical operation to apply to the output values.
-///
-/// The operation is applied individually for each channel (red, green, blue and alpha).
-///
-/// Only relevant for integer or unsigned attachments.
-///
-/// Also note that some implementations don't support logic operations.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-#[repr(i32)]
-pub enum LogicOp {
- /// Returns `0`.
- Clear = ash::vk::LogicOp::CLEAR.as_raw(),
- /// Returns `source & destination`.
- And = ash::vk::LogicOp::AND.as_raw(),
- /// Returns `source & !destination`.
- AndReverse = ash::vk::LogicOp::AND_REVERSE.as_raw(),
- /// Returns `source`.
- Copy = ash::vk::LogicOp::COPY.as_raw(),
- /// Returns `!source & destination`.
- AndInverted = ash::vk::LogicOp::AND_INVERTED.as_raw(),
- /// Returns `destination`.
- Noop = ash::vk::LogicOp::NO_OP.as_raw(),
- /// Returns `source ^ destination`.
- Xor = ash::vk::LogicOp::XOR.as_raw(),
- /// Returns `source | destination`.
- Or = ash::vk::LogicOp::OR.as_raw(),
- /// Returns `!(source | destination)`.
- Nor = ash::vk::LogicOp::NOR.as_raw(),
- /// Returns `!(source ^ destination)`.
- Equivalent = ash::vk::LogicOp::EQUIVALENT.as_raw(),
- /// Returns `!destination`.
- Invert = ash::vk::LogicOp::INVERT.as_raw(),
- /// Returns `source | !destination.
- OrReverse = ash::vk::LogicOp::OR_REVERSE.as_raw(),
- /// Returns `!source`.
- CopyInverted = ash::vk::LogicOp::COPY_INVERTED.as_raw(),
- /// Returns `!source | destination`.
- OrInverted = ash::vk::LogicOp::OR_INVERTED.as_raw(),
- /// Returns `!(source & destination)`.
- Nand = ash::vk::LogicOp::NAND.as_raw(),
- /// Returns `!0` (all bits set to 1).
- Set = ash::vk::LogicOp::SET.as_raw(),
-}
-
-impl From<LogicOp> for ash::vk::LogicOp {
- #[inline]
- fn from(val: LogicOp) -> Self {
- Self::from_raw(val as i32)
- }
-}
-
-impl Default for LogicOp {
- #[inline]
- fn default() -> LogicOp {
- LogicOp::Noop
- }
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-#[repr(i32)]
-pub enum BlendOp {
- Add = ash::vk::BlendOp::ADD.as_raw(),
- Subtract = ash::vk::BlendOp::SUBTRACT.as_raw(),
- ReverseSubtract = ash::vk::BlendOp::REVERSE_SUBTRACT.as_raw(),
- Min = ash::vk::BlendOp::MIN.as_raw(),
- Max = ash::vk::BlendOp::MAX.as_raw(),
-}
-
-impl From<BlendOp> for ash::vk::BlendOp {
- #[inline]
- fn from(val: BlendOp) -> Self {
- Self::from_raw(val as i32)
- }
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-#[repr(i32)]
-pub enum BlendFactor {
- Zero = ash::vk::BlendFactor::ZERO.as_raw(),
- One = ash::vk::BlendFactor::ONE.as_raw(),
- SrcColor = ash::vk::BlendFactor::SRC_COLOR.as_raw(),
- OneMinusSrcColor = ash::vk::BlendFactor::ONE_MINUS_SRC_COLOR.as_raw(),
- DstColor = ash::vk::BlendFactor::DST_COLOR.as_raw(),
- OneMinusDstColor = ash::vk::BlendFactor::ONE_MINUS_DST_COLOR.as_raw(),
- SrcAlpha = ash::vk::BlendFactor::SRC_ALPHA.as_raw(),
- OneMinusSrcAlpha = ash::vk::BlendFactor::ONE_MINUS_SRC_ALPHA.as_raw(),
- DstAlpha = ash::vk::BlendFactor::DST_ALPHA.as_raw(),
- OneMinusDstAlpha = ash::vk::BlendFactor::ONE_MINUS_DST_ALPHA.as_raw(),
- ConstantColor = ash::vk::BlendFactor::CONSTANT_COLOR.as_raw(),
- OneMinusConstantColor = ash::vk::BlendFactor::ONE_MINUS_CONSTANT_COLOR.as_raw(),
- ConstantAlpha = ash::vk::BlendFactor::CONSTANT_ALPHA.as_raw(),
- OneMinusConstantAlpha = ash::vk::BlendFactor::ONE_MINUS_CONSTANT_ALPHA.as_raw(),
- SrcAlphaSaturate = ash::vk::BlendFactor::SRC_ALPHA_SATURATE.as_raw(),
- Src1Color = ash::vk::BlendFactor::SRC1_COLOR.as_raw(),
- OneMinusSrc1Color = ash::vk::BlendFactor::ONE_MINUS_SRC1_COLOR.as_raw(),
- Src1Alpha = ash::vk::BlendFactor::SRC1_ALPHA.as_raw(),
- OneMinusSrc1Alpha = ash::vk::BlendFactor::ONE_MINUS_SRC1_ALPHA.as_raw(),
-}
-
-impl From<BlendFactor> for ash::vk::BlendFactor {
- #[inline]
- fn from(val: BlendFactor) -> Self {
- Self::from_raw(val as i32)
- }
-}
diff --git a/src/pipeline/cache.rs b/src/pipeline/cache.rs
index 9b3ac77..a33321a 100644
--- a/src/pipeline/cache.rs
+++ b/src/pipeline/cache.rs
@@ -18,20 +18,16 @@
//! doesn't exist.
//!
//! Once that is done, you can extract the data from the cache and store it. See the documentation
-//! of [`get_data`](struct.PipelineCache.html#method.get_data) for example of how to store the data
-//! on the disk, and [`with_data`](struct.PipelineCache.html#method.with_data) for how to reload it.
+//! of [`get_data`](crate::pipeline::cache::PipelineCache::get_data) for example of how to store the data
+//! on the disk, and [`with_data`](crate::pipeline::cache::PipelineCache::with_data) for how to reload it.
-use crate::check_errors;
-use crate::device::Device;
-use crate::OomError;
-use crate::VulkanObject;
-use std::mem::MaybeUninit;
-use std::ptr;
-use std::sync::Arc;
+use crate::{device::Device, OomError, VulkanError, VulkanObject};
+use std::{mem::MaybeUninit, ptr, sync::Arc};
/// Opaque cache that contains pipeline objects.
///
-/// See [the documentation of the module](index.html) for more info.
+/// See [the documentation of the module](crate::pipeline::cache) for more info.
+#[derive(Debug)]
pub struct PipelineCache {
device: Arc<Device>,
cache: ash::vk::PipelineCache,
@@ -45,7 +41,7 @@ impl PipelineCache {
/// implementation. Therefore you can easily crash your application or the system by passing
/// wrong data. Hence why this function is unsafe.
///
- /// # Example
+ /// # Examples
///
/// This example loads a cache from a file, if it exists.
/// See [`get_data`](#method.get_data) for how to store the data in a file.
@@ -65,8 +61,12 @@ impl PipelineCache {
/// let mut data = Vec::new();
/// if let Ok(_) = file.read_to_end(&mut data) {
/// Some(data)
- /// } else { None }
- /// } else { None }
+ /// } else {
+ /// None
+ /// }
+ /// } else {
+ /// None
+ /// }
/// };
///
/// let cache = if let Some(data) = data {
@@ -86,7 +86,7 @@ impl PipelineCache {
/// Builds a new empty pipeline cache.
///
- /// # Example
+ /// # Examples
///
/// ```
/// # use std::sync::Arc;
@@ -118,18 +118,20 @@ impl PipelineCache {
};
let mut output = MaybeUninit::uninit();
- check_errors(fns.v1_0.create_pipeline_cache(
- device.internal_object(),
+ (fns.v1_0.create_pipeline_cache)(
+ device.handle(),
&infos,
ptr::null(),
output.as_mut_ptr(),
- ))?;
+ )
+ .result()
+ .map_err(VulkanError::from)?;
output.assume_init()
};
Ok(Arc::new(PipelineCache {
device: device.clone(),
- cache: cache,
+ cache,
}))
}
@@ -137,33 +139,35 @@ impl PipelineCache {
///
/// It is `self` that is modified here. The pipeline caches passed as parameter are untouched.
///
- /// # Panic
+ /// # Panics
///
/// - Panics if `self` is included in the list of other pipelines.
///
// FIXME: vkMergePipelineCaches is not thread safe for the destination cache
// TODO: write example
- pub fn merge<'a, I>(&self, pipelines: I) -> Result<(), OomError>
- where
- I: IntoIterator<Item = &'a &'a Arc<PipelineCache>>,
- {
+ pub fn merge<'a>(
+ &self,
+ pipelines: impl IntoIterator<Item = &'a &'a Arc<PipelineCache>>,
+ ) -> Result<(), OomError> {
unsafe {
let fns = self.device.fns();
let pipelines = pipelines
.into_iter()
.map(|pipeline| {
- assert!(&***pipeline as *const _ != &*self as *const _);
+ assert!(&***pipeline as *const _ != self as *const _);
pipeline.cache
})
.collect::<Vec<_>>();
- check_errors(fns.v1_0.merge_pipeline_caches(
- self.device.internal_object(),
+ (fns.v1_0.merge_pipeline_caches)(
+ self.device.handle(),
self.cache,
pipelines.len() as u32,
pipelines.as_ptr(),
- ))?;
+ )
+ .result()
+ .map_err(VulkanError::from)?;
Ok(())
}
@@ -173,7 +177,7 @@ impl PipelineCache {
///
/// This data can be stored and then reloaded and passed to `PipelineCache::with_data`.
///
- /// # Example
+ /// # Examples
///
/// This example stores the data of a pipeline cache on the disk.
/// See [`with_data`](#method.with_data) for how to reload it.
@@ -197,37 +201,50 @@ impl PipelineCache {
/// }
/// }
/// ```
+ #[inline]
pub fn get_data(&self) -> Result<Vec<u8>, OomError> {
- unsafe {
- let fns = self.device.fns();
-
- let mut num = 0;
- check_errors(fns.v1_0.get_pipeline_cache_data(
- self.device.internal_object(),
- self.cache,
- &mut num,
- ptr::null_mut(),
- ))?;
-
- let mut data: Vec<u8> = Vec::with_capacity(num as usize);
- check_errors(fns.v1_0.get_pipeline_cache_data(
- self.device.internal_object(),
- self.cache,
- &mut num,
- data.as_mut_ptr() as *mut _,
- ))?;
- data.set_len(num as usize);
+ let fns = self.device.fns();
+
+ let data = unsafe {
+ loop {
+ let mut count = 0;
+ (fns.v1_0.get_pipeline_cache_data)(
+ self.device.handle(),
+ self.cache,
+ &mut count,
+ ptr::null_mut(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+
+ let mut data: Vec<u8> = Vec::with_capacity(count);
+ let result = (fns.v1_0.get_pipeline_cache_data)(
+ self.device.handle(),
+ self.cache,
+ &mut count,
+ data.as_mut_ptr() as *mut _,
+ );
+
+ match result {
+ ash::vk::Result::SUCCESS => {
+ data.set_len(count);
+ break data;
+ }
+ ash::vk::Result::INCOMPLETE => (),
+ err => return Err(VulkanError::from(err).into()),
+ }
+ }
+ };
- Ok(data)
- }
+ Ok(data)
}
}
unsafe impl VulkanObject for PipelineCache {
- type Object = ash::vk::PipelineCache;
+ type Handle = ash::vk::PipelineCache;
#[inline]
- fn internal_object(&self) -> ash::vk::PipelineCache {
+ fn handle(&self) -> Self::Handle {
self.cache
}
}
@@ -237,23 +254,21 @@ impl Drop for PipelineCache {
fn drop(&mut self) {
unsafe {
let fns = self.device.fns();
- fns.v1_0
- .destroy_pipeline_cache(self.device.internal_object(), self.cache, ptr::null());
+ (fns.v1_0.destroy_pipeline_cache)(self.device.handle(), self.cache, ptr::null());
}
}
}
#[cfg(test)]
mod tests {
- use crate::pipeline::cache::PipelineCache;
- use crate::pipeline::shader::ShaderModule;
- use crate::pipeline::shader::SpecializationConstants;
- use crate::pipeline::ComputePipeline;
- use std::{ffi::CStr, sync::Arc};
+ use crate::{
+ pipeline::{cache::PipelineCache, ComputePipeline},
+ shader::ShaderModule,
+ };
#[test]
fn merge_self_forbidden() {
- let (device, queue) = gfx_dev_and_queue!();
+ let (device, _queue) = gfx_dev_and_queue!();
let pipeline = PipelineCache::empty(device).unwrap();
assert_should_panic!({
pipeline.merge(&[&pipeline]).unwrap();
@@ -262,7 +277,7 @@ mod tests {
#[test]
fn cache_returns_same_data() {
- let (device, queue) = gfx_dev_and_queue!();
+ let (device, _queue) = gfx_dev_and_queue!();
let cache = PipelineCache::empty(device.clone()).unwrap();
@@ -282,22 +297,17 @@ mod tests {
0, 0, 0, 54, 0, 5, 0, 2, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 248, 0, 2, 0,
5, 0, 0, 0, 253, 0, 1, 0, 56, 0, 1, 0,
];
- ShaderModule::new(device.clone(), &MODULE).unwrap()
- };
-
- let shader = unsafe {
- static NAME: [u8; 5] = [109, 97, 105, 110, 0]; // "main"
- module.compute_entry_point(
- CStr::from_ptr(NAME.as_ptr() as *const _),
- [],
- None,
- <()>::descriptors(),
- )
+ ShaderModule::from_bytes(device.clone(), &MODULE).unwrap()
};
- let pipeline = Arc::new(
- ComputePipeline::new(device.clone(), &shader, &(), Some(cache.clone())).unwrap(),
- );
+ let _pipeline = ComputePipeline::new(
+ device,
+ module.entry_point("main").unwrap(),
+ &(),
+ Some(cache.clone()),
+ |_| {},
+ )
+ .unwrap();
let cache_data = cache.get_data().unwrap();
let second_data = cache.get_data().unwrap();
@@ -307,7 +317,7 @@ mod tests {
#[test]
fn cache_returns_different_data() {
- let (device, queue) = gfx_dev_and_queue!();
+ let (device, _queue) = gfx_dev_and_queue!();
let cache = PipelineCache::empty(device.clone()).unwrap();
@@ -327,17 +337,7 @@ mod tests {
0, 0, 0, 54, 0, 5, 0, 2, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 248, 0, 2, 0,
5, 0, 0, 0, 253, 0, 1, 0, 56, 0, 1, 0,
];
- ShaderModule::new(device.clone(), &MODULE).unwrap()
- };
-
- let first_shader = unsafe {
- static NAME: [u8; 5] = [109, 97, 105, 110, 0]; // "main"
- first_module.compute_entry_point(
- CStr::from_ptr(NAME.as_ptr() as *const _),
- [],
- None,
- <()>::descriptors(),
- )
+ ShaderModule::from_bytes(device.clone(), &MODULE).unwrap()
};
let second_module = unsafe {
@@ -368,28 +368,28 @@ mod tests {
0, 15, 0, 0, 0, 14, 0, 0, 0, 62, 0, 3, 0, 8, 0, 0, 0, 15, 0, 0, 0, 253, 0, 1, 0,
56, 0, 1, 0,
];
- ShaderModule::new(device.clone(), &SECOND_MODULE).unwrap()
+ ShaderModule::from_bytes(device.clone(), &SECOND_MODULE).unwrap()
};
- let second_shader = unsafe {
- static NAME: [u8; 5] = [109, 97, 105, 110, 0]; // "main"
- second_module.compute_entry_point(
- CStr::from_ptr(NAME.as_ptr() as *const _),
- [],
- None,
- <()>::descriptors(),
- )
- };
-
- let pipeline = Arc::new(
- ComputePipeline::new(device.clone(), &first_shader, &(), Some(cache.clone())).unwrap(),
- );
+ let _pipeline = ComputePipeline::new(
+ device.clone(),
+ first_module.entry_point("main").unwrap(),
+ &(),
+ Some(cache.clone()),
+ |_| {},
+ )
+ .unwrap();
let cache_data = cache.get_data().unwrap();
- let second_pipeline = Arc::new(
- ComputePipeline::new(device.clone(), &second_shader, &(), Some(cache.clone())).unwrap(),
- );
+ let _second_pipeline = ComputePipeline::new(
+ device,
+ second_module.entry_point("main").unwrap(),
+ &(),
+ Some(cache.clone()),
+ |_| {},
+ )
+ .unwrap();
let second_data = cache.get_data().unwrap();
@@ -402,7 +402,7 @@ mod tests {
#[test]
fn cache_data_does_not_change() {
- let (device, queue) = gfx_dev_and_queue!();
+ let (device, _queue) = gfx_dev_and_queue!();
let cache = PipelineCache::empty(device.clone()).unwrap();
@@ -422,28 +422,28 @@ mod tests {
0, 0, 0, 54, 0, 5, 0, 2, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 248, 0, 2, 0,
5, 0, 0, 0, 253, 0, 1, 0, 56, 0, 1, 0,
];
- ShaderModule::new(device.clone(), &MODULE).unwrap()
- };
-
- let shader = unsafe {
- static NAME: [u8; 5] = [109, 97, 105, 110, 0]; // "main"
- module.compute_entry_point(
- CStr::from_ptr(NAME.as_ptr() as *const _),
- [],
- None,
- <()>::descriptors(),
- )
+ ShaderModule::from_bytes(device.clone(), &MODULE).unwrap()
};
- let pipeline = Arc::new(
- ComputePipeline::new(device.clone(), &shader, &(), Some(cache.clone())).unwrap(),
- );
+ let _pipeline = ComputePipeline::new(
+ device.clone(),
+ module.entry_point("main").unwrap(),
+ &(),
+ Some(cache.clone()),
+ |_| {},
+ )
+ .unwrap();
let cache_data = cache.get_data().unwrap();
- let second_pipeline = Arc::new(
- ComputePipeline::new(device.clone(), &shader, &(), Some(cache.clone())).unwrap(),
- );
+ let _second_pipeline = ComputePipeline::new(
+ device,
+ module.entry_point("main").unwrap(),
+ &(),
+ Some(cache.clone()),
+ |_| {},
+ )
+ .unwrap();
let second_data = cache.get_data().unwrap();
diff --git a/src/pipeline/compute.rs b/src/pipeline/compute.rs
new file mode 100644
index 0000000..eb1549a
--- /dev/null
+++ b/src/pipeline/compute.rs
@@ -0,0 +1,541 @@
+// Copyright (c) 2016 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+//! A pipeline that performs general-purpose operations.
+//!
+//! A compute pipeline takes buffers and/or images as both inputs and outputs. It operates
+//! "standalone", with no additional infrastructure such as render passes or vertex input. Compute
+//! pipelines can be used by themselves for performing work on the Vulkan device, but they can also
+//! assist graphics operations by precalculating or postprocessing the operations from another kind
+//! of pipeline. While it theoretically possible to perform graphics operations entirely in a
+//! compute pipeline, a graphics pipeline is better suited to that task.
+//!
+//! A compute pipeline is relatively simple to create, requiring only a pipeline layout and a single
+//! shader, the *compute shader*. The compute shader is the actual program that performs the work.
+//! Once created, you can execute a compute pipeline by *binding* it in a command buffer, binding
+//! any descriptor sets and/or push constants that the pipeline needs, and then issuing a `dispatch`
+//! command on the command buffer.
+
+use super::layout::PipelineLayoutCreateInfo;
+use crate::{
+ descriptor_set::layout::{
+ DescriptorSetLayout, DescriptorSetLayoutCreateInfo, DescriptorSetLayoutCreationError,
+ },
+ device::{Device, DeviceOwned},
+ macros::impl_id_counter,
+ pipeline::{
+ cache::PipelineCache,
+ layout::{PipelineLayout, PipelineLayoutCreationError, PipelineLayoutSupersetError},
+ Pipeline, PipelineBindPoint,
+ },
+ shader::{DescriptorBindingRequirements, EntryPoint, SpecializationConstants},
+ DeviceSize, OomError, VulkanError, VulkanObject,
+};
+use ahash::HashMap;
+use std::{
+ error::Error,
+ fmt::{Debug, Display, Error as FmtError, Formatter},
+ mem,
+ mem::MaybeUninit,
+ num::NonZeroU64,
+ ptr,
+ sync::Arc,
+};
+
+/// A pipeline object that describes to the Vulkan implementation how it should perform compute
+/// operations.
+///
+/// The template parameter contains the descriptor set to use with this pipeline.
+///
+/// Pass an optional `Arc` to a `PipelineCache` to enable pipeline caching. The vulkan
+/// implementation will handle the `PipelineCache` and check if it is available.
+/// Check the documentation of the `PipelineCache` for more information.
+pub struct ComputePipeline {
+ handle: ash::vk::Pipeline,
+ device: Arc<Device>,
+ id: NonZeroU64,
+ layout: Arc<PipelineLayout>,
+ descriptor_binding_requirements: HashMap<(u32, u32), DescriptorBindingRequirements>,
+ num_used_descriptor_sets: u32,
+}
+
+impl ComputePipeline {
+ /// Builds a new `ComputePipeline`.
+ ///
+ /// `func` is a closure that is given a mutable reference to the inferred descriptor set
+ /// definitions. This can be used to make changes to the layout before it's created, for example
+ /// to add dynamic buffers or immutable samplers.
+ pub fn new<Css, F>(
+ device: Arc<Device>,
+ shader: EntryPoint<'_>,
+ specialization_constants: &Css,
+ cache: Option<Arc<PipelineCache>>,
+ func: F,
+ ) -> Result<Arc<ComputePipeline>, ComputePipelineCreationError>
+ where
+ Css: SpecializationConstants,
+ F: FnOnce(&mut [DescriptorSetLayoutCreateInfo]),
+ {
+ let mut set_layout_create_infos = DescriptorSetLayoutCreateInfo::from_requirements(
+ shader.descriptor_binding_requirements(),
+ );
+ func(&mut set_layout_create_infos);
+ let set_layouts = set_layout_create_infos
+ .iter()
+ .map(|desc| DescriptorSetLayout::new(device.clone(), desc.clone()))
+ .collect::<Result<Vec<_>, _>>()?;
+
+ let layout = PipelineLayout::new(
+ device.clone(),
+ PipelineLayoutCreateInfo {
+ set_layouts,
+ push_constant_ranges: shader
+ .push_constant_requirements()
+ .cloned()
+ .into_iter()
+ .collect(),
+ ..Default::default()
+ },
+ )?;
+
+ unsafe {
+ ComputePipeline::with_unchecked_pipeline_layout(
+ device,
+ shader,
+ specialization_constants,
+ layout,
+ cache,
+ )
+ }
+ }
+
+ /// Builds a new `ComputePipeline` with a specific pipeline layout.
+ ///
+ /// An error will be returned if the pipeline layout isn't a superset of what the shader
+ /// uses.
+ pub fn with_pipeline_layout<Css>(
+ device: Arc<Device>,
+ shader: EntryPoint<'_>,
+ specialization_constants: &Css,
+ layout: Arc<PipelineLayout>,
+ cache: Option<Arc<PipelineCache>>,
+ ) -> Result<Arc<ComputePipeline>, ComputePipelineCreationError>
+ where
+ Css: SpecializationConstants,
+ {
+ let spec_descriptors = Css::descriptors();
+
+ for (constant_id, reqs) in shader.specialization_constant_requirements() {
+ let map_entry = spec_descriptors
+ .iter()
+ .find(|desc| desc.constant_id == constant_id)
+ .ok_or(ComputePipelineCreationError::IncompatibleSpecializationConstants)?;
+
+ if map_entry.size as DeviceSize != reqs.size {
+ return Err(ComputePipelineCreationError::IncompatibleSpecializationConstants);
+ }
+ }
+
+ layout.ensure_compatible_with_shader(
+ shader.descriptor_binding_requirements(),
+ shader.push_constant_requirements(),
+ )?;
+
+ unsafe {
+ ComputePipeline::with_unchecked_pipeline_layout(
+ device,
+ shader,
+ specialization_constants,
+ layout,
+ cache,
+ )
+ }
+ }
+
+ /// Same as `with_pipeline_layout`, but doesn't check whether the pipeline layout is a
+ /// superset of what the shader expects.
+ pub unsafe fn with_unchecked_pipeline_layout<Css>(
+ device: Arc<Device>,
+ shader: EntryPoint<'_>,
+ specialization_constants: &Css,
+ layout: Arc<PipelineLayout>,
+ cache: Option<Arc<PipelineCache>>,
+ ) -> Result<Arc<ComputePipeline>, ComputePipelineCreationError>
+ where
+ Css: SpecializationConstants,
+ {
+ let fns = device.fns();
+
+ let handle = {
+ let spec_descriptors = Css::descriptors();
+ let specialization = ash::vk::SpecializationInfo {
+ map_entry_count: spec_descriptors.len() as u32,
+ p_map_entries: spec_descriptors.as_ptr() as *const _,
+ data_size: mem::size_of_val(specialization_constants),
+ p_data: specialization_constants as *const Css as *const _,
+ };
+
+ let stage = ash::vk::PipelineShaderStageCreateInfo {
+ flags: ash::vk::PipelineShaderStageCreateFlags::empty(),
+ stage: ash::vk::ShaderStageFlags::COMPUTE,
+ module: shader.module().handle(),
+ p_name: shader.name().as_ptr(),
+ p_specialization_info: if specialization.data_size == 0 {
+ ptr::null()
+ } else {
+ &specialization
+ },
+ ..Default::default()
+ };
+
+ let infos = ash::vk::ComputePipelineCreateInfo {
+ flags: ash::vk::PipelineCreateFlags::empty(),
+ stage,
+ layout: layout.handle(),
+ base_pipeline_handle: ash::vk::Pipeline::null(),
+ base_pipeline_index: 0,
+ ..Default::default()
+ };
+
+ let cache_handle = match cache {
+ Some(ref cache) => cache.handle(),
+ None => ash::vk::PipelineCache::null(),
+ };
+
+ let mut output = MaybeUninit::uninit();
+ (fns.v1_0.create_compute_pipelines)(
+ device.handle(),
+ cache_handle,
+ 1,
+ &infos,
+ ptr::null(),
+ output.as_mut_ptr(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+ output.assume_init()
+ };
+
+ let descriptor_binding_requirements: HashMap<_, _> = shader
+ .descriptor_binding_requirements()
+ .map(|(loc, reqs)| (loc, reqs.clone()))
+ .collect();
+ let num_used_descriptor_sets = descriptor_binding_requirements
+ .keys()
+ .map(|loc| loc.0)
+ .max()
+ .map(|x| x + 1)
+ .unwrap_or(0);
+
+ Ok(Arc::new(ComputePipeline {
+ handle,
+ device: device.clone(),
+ id: Self::next_id(),
+ layout,
+ descriptor_binding_requirements,
+ num_used_descriptor_sets,
+ }))
+ }
+
+ /// Returns the `Device` this compute pipeline was created with.
+ #[inline]
+ pub fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+}
+
+impl Pipeline for ComputePipeline {
+ #[inline]
+ fn bind_point(&self) -> PipelineBindPoint {
+ PipelineBindPoint::Compute
+ }
+
+ #[inline]
+ fn layout(&self) -> &Arc<PipelineLayout> {
+ &self.layout
+ }
+
+ #[inline]
+ fn num_used_descriptor_sets(&self) -> u32 {
+ self.num_used_descriptor_sets
+ }
+
+ #[inline]
+ fn descriptor_binding_requirements(
+ &self,
+ ) -> &HashMap<(u32, u32), DescriptorBindingRequirements> {
+ &self.descriptor_binding_requirements
+ }
+}
+
+impl Debug for ComputePipeline {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ write!(f, "<Vulkan compute pipeline {:?}>", self.handle)
+ }
+}
+
+impl_id_counter!(ComputePipeline);
+
+unsafe impl VulkanObject for ComputePipeline {
+ type Handle = ash::vk::Pipeline;
+
+ #[inline]
+ fn handle(&self) -> Self::Handle {
+ self.handle
+ }
+}
+
+unsafe impl DeviceOwned for ComputePipeline {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ self.device()
+ }
+}
+
+impl Drop for ComputePipeline {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ let fns = self.device.fns();
+ (fns.v1_0.destroy_pipeline)(self.device.handle(), self.handle, ptr::null());
+ }
+ }
+}
+
+/// Error that can happen when creating a compute pipeline.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum ComputePipelineCreationError {
+ /// Not enough memory.
+ OomError(OomError),
+ /// Error while creating a descriptor set layout object.
+ DescriptorSetLayoutCreationError(DescriptorSetLayoutCreationError),
+ /// Error while creating the pipeline layout object.
+ PipelineLayoutCreationError(PipelineLayoutCreationError),
+ /// The pipeline layout is not compatible with what the shader expects.
+ IncompatiblePipelineLayout(PipelineLayoutSupersetError),
+ /// The provided specialization constants are not compatible with what the shader expects.
+ IncompatibleSpecializationConstants,
+}
+
+impl Error for ComputePipelineCreationError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::OomError(err) => Some(err),
+ Self::DescriptorSetLayoutCreationError(err) => Some(err),
+ Self::PipelineLayoutCreationError(err) => Some(err),
+ Self::IncompatiblePipelineLayout(err) => Some(err),
+ Self::IncompatibleSpecializationConstants => None,
+ }
+ }
+}
+
+impl Display for ComputePipelineCreationError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ write!(
+ f,
+ "{}",
+ match self {
+ ComputePipelineCreationError::OomError(_) => "not enough memory available",
+ ComputePipelineCreationError::DescriptorSetLayoutCreationError(_) => {
+ "error while creating a descriptor set layout object"
+ }
+ ComputePipelineCreationError::PipelineLayoutCreationError(_) => {
+ "error while creating the pipeline layout object"
+ }
+ ComputePipelineCreationError::IncompatiblePipelineLayout(_) => {
+ "the pipeline layout is not compatible with what the shader expects"
+ }
+ ComputePipelineCreationError::IncompatibleSpecializationConstants => {
+ "the provided specialization constants are not compatible with what the shader \
+ expects"
+ }
+ }
+ )
+ }
+}
+
+impl From<OomError> for ComputePipelineCreationError {
+ fn from(err: OomError) -> ComputePipelineCreationError {
+ Self::OomError(err)
+ }
+}
+
+impl From<DescriptorSetLayoutCreationError> for ComputePipelineCreationError {
+ fn from(err: DescriptorSetLayoutCreationError) -> Self {
+ Self::DescriptorSetLayoutCreationError(err)
+ }
+}
+
+impl From<PipelineLayoutCreationError> for ComputePipelineCreationError {
+ fn from(err: PipelineLayoutCreationError) -> Self {
+ Self::PipelineLayoutCreationError(err)
+ }
+}
+
+impl From<PipelineLayoutSupersetError> for ComputePipelineCreationError {
+ fn from(err: PipelineLayoutSupersetError) -> Self {
+ Self::IncompatiblePipelineLayout(err)
+ }
+}
+
+impl From<VulkanError> for ComputePipelineCreationError {
+ fn from(err: VulkanError) -> ComputePipelineCreationError {
+ match err {
+ err @ VulkanError::OutOfHostMemory => Self::OomError(OomError::from(err)),
+ err @ VulkanError::OutOfDeviceMemory => Self::OomError(OomError::from(err)),
+ _ => panic!("unexpected error: {:?}", err),
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::{
+ buffer::{Buffer, BufferCreateInfo, BufferUsage},
+ command_buffer::{
+ allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage,
+ },
+ descriptor_set::{
+ allocator::StandardDescriptorSetAllocator, PersistentDescriptorSet, WriteDescriptorSet,
+ },
+ memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
+ pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
+ shader::{ShaderModule, SpecializationConstants, SpecializationMapEntry},
+ sync::{now, GpuFuture},
+ };
+
+ // TODO: test for basic creation
+ // TODO: test for pipeline layout error
+
+ #[test]
+ fn specialization_constants() {
+ // This test checks whether specialization constants work.
+ // It executes a single compute shader (one invocation) that writes the value of a spec.
+ // constant to a buffer. The buffer content is then checked for the right value.
+
+ let (device, queue) = gfx_dev_and_queue!();
+
+ let module = unsafe {
+ /*
+ #version 450
+
+ layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+
+ layout(constant_id = 83) const int VALUE = 0xdeadbeef;
+
+ layout(set = 0, binding = 0) buffer Output {
+ int write;
+ } write;
+
+ void main() {
+ write.write = VALUE;
+ }
+ */
+ const MODULE: [u8; 480] = [
+ 3, 2, 35, 7, 0, 0, 1, 0, 1, 0, 8, 0, 14, 0, 0, 0, 0, 0, 0, 0, 17, 0, 2, 0, 1, 0, 0,
+ 0, 11, 0, 6, 0, 1, 0, 0, 0, 71, 76, 83, 76, 46, 115, 116, 100, 46, 52, 53, 48, 0,
+ 0, 0, 0, 14, 0, 3, 0, 0, 0, 0, 0, 1, 0, 0, 0, 15, 0, 5, 0, 5, 0, 0, 0, 4, 0, 0, 0,
+ 109, 97, 105, 110, 0, 0, 0, 0, 16, 0, 6, 0, 4, 0, 0, 0, 17, 0, 0, 0, 1, 0, 0, 0, 1,
+ 0, 0, 0, 1, 0, 0, 0, 3, 0, 3, 0, 2, 0, 0, 0, 194, 1, 0, 0, 5, 0, 4, 0, 4, 0, 0, 0,
+ 109, 97, 105, 110, 0, 0, 0, 0, 5, 0, 4, 0, 7, 0, 0, 0, 79, 117, 116, 112, 117, 116,
+ 0, 0, 6, 0, 5, 0, 7, 0, 0, 0, 0, 0, 0, 0, 119, 114, 105, 116, 101, 0, 0, 0, 5, 0,
+ 4, 0, 9, 0, 0, 0, 119, 114, 105, 116, 101, 0, 0, 0, 5, 0, 4, 0, 11, 0, 0, 0, 86,
+ 65, 76, 85, 69, 0, 0, 0, 72, 0, 5, 0, 7, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0,
+ 0, 71, 0, 3, 0, 7, 0, 0, 0, 3, 0, 0, 0, 71, 0, 4, 0, 9, 0, 0, 0, 34, 0, 0, 0, 0, 0,
+ 0, 0, 71, 0, 4, 0, 9, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 71, 0, 4, 0, 11, 0, 0, 0,
+ 1, 0, 0, 0, 83, 0, 0, 0, 19, 0, 2, 0, 2, 0, 0, 0, 33, 0, 3, 0, 3, 0, 0, 0, 2, 0, 0,
+ 0, 21, 0, 4, 0, 6, 0, 0, 0, 32, 0, 0, 0, 1, 0, 0, 0, 30, 0, 3, 0, 7, 0, 0, 0, 6, 0,
+ 0, 0, 32, 0, 4, 0, 8, 0, 0, 0, 2, 0, 0, 0, 7, 0, 0, 0, 59, 0, 4, 0, 8, 0, 0, 0, 9,
+ 0, 0, 0, 2, 0, 0, 0, 43, 0, 4, 0, 6, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 50, 0, 4, 0,
+ 6, 0, 0, 0, 11, 0, 0, 0, 239, 190, 173, 222, 32, 0, 4, 0, 12, 0, 0, 0, 2, 0, 0, 0,
+ 6, 0, 0, 0, 54, 0, 5, 0, 2, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 248, 0, 2,
+ 0, 5, 0, 0, 0, 65, 0, 5, 0, 12, 0, 0, 0, 13, 0, 0, 0, 9, 0, 0, 0, 10, 0, 0, 0, 62,
+ 0, 3, 0, 13, 0, 0, 0, 11, 0, 0, 0, 253, 0, 1, 0, 56, 0, 1, 0,
+ ];
+ ShaderModule::from_bytes(device.clone(), &MODULE).unwrap()
+ };
+
+ #[derive(Debug, Copy, Clone)]
+ #[allow(non_snake_case)]
+ #[repr(C)]
+ struct SpecConsts {
+ VALUE: i32,
+ }
+ unsafe impl SpecializationConstants for SpecConsts {
+ fn descriptors() -> &'static [SpecializationMapEntry] {
+ static DESCRIPTORS: [SpecializationMapEntry; 1] = [SpecializationMapEntry {
+ constant_id: 83,
+ offset: 0,
+ size: 4,
+ }];
+ &DESCRIPTORS
+ }
+ }
+
+ let pipeline = ComputePipeline::new(
+ device.clone(),
+ module.entry_point("main").unwrap(),
+ &SpecConsts { VALUE: 0x12345678 },
+ None,
+ |_| {},
+ )
+ .unwrap();
+
+ let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
+ let data_buffer = Buffer::from_data(
+ &memory_allocator,
+ BufferCreateInfo {
+ usage: BufferUsage::STORAGE_BUFFER,
+ ..Default::default()
+ },
+ AllocationCreateInfo {
+ usage: MemoryUsage::Upload,
+ ..Default::default()
+ },
+ 0,
+ )
+ .unwrap();
+
+ let ds_allocator = StandardDescriptorSetAllocator::new(device.clone());
+ let set = PersistentDescriptorSet::new(
+ &ds_allocator,
+ pipeline.layout().set_layouts().get(0).unwrap().clone(),
+ [WriteDescriptorSet::buffer(0, data_buffer.clone())],
+ )
+ .unwrap();
+
+ let cb_allocator = StandardCommandBufferAllocator::new(device.clone(), Default::default());
+ let mut cbb = AutoCommandBufferBuilder::primary(
+ &cb_allocator,
+ queue.queue_family_index(),
+ CommandBufferUsage::OneTimeSubmit,
+ )
+ .unwrap();
+ cbb.bind_pipeline_compute(pipeline.clone())
+ .bind_descriptor_sets(
+ PipelineBindPoint::Compute,
+ pipeline.layout().clone(),
+ 0,
+ set,
+ )
+ .dispatch([1, 1, 1])
+ .unwrap();
+ let cb = cbb.build().unwrap();
+
+ let future = now(device)
+ .then_execute(queue, cb)
+ .unwrap()
+ .then_signal_fence_and_flush()
+ .unwrap();
+ future.wait(None).unwrap();
+
+ let data_buffer_content = data_buffer.read().unwrap();
+ assert_eq!(*data_buffer_content, 0x12345678);
+ }
+}
diff --git a/src/pipeline/compute_pipeline.rs b/src/pipeline/compute_pipeline.rs
deleted file mode 100644
index 0601374..0000000
--- a/src/pipeline/compute_pipeline.rs
+++ /dev/null
@@ -1,523 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::check_errors;
-use crate::descriptor_set::layout::DescriptorSetLayout;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::pipeline::cache::PipelineCache;
-use crate::pipeline::layout::PipelineLayout;
-use crate::pipeline::layout::PipelineLayoutCreationError;
-use crate::pipeline::layout::PipelineLayoutSupersetError;
-use crate::pipeline::shader::EntryPointAbstract;
-use crate::pipeline::shader::SpecializationConstants;
-use crate::Error;
-use crate::OomError;
-use crate::SafeDeref;
-use crate::VulkanObject;
-use std::error;
-use std::fmt;
-use std::marker::PhantomData;
-use std::mem;
-use std::mem::MaybeUninit;
-use std::ptr;
-use std::sync::Arc;
-
-/// A pipeline object that describes to the Vulkan implementation how it should perform compute
-/// operations.
-///
-/// The template parameter contains the descriptor set to use with this pipeline.
-///
-/// All compute pipeline objects implement the `ComputePipelineAbstract` trait. You can turn any
-/// `Arc<ComputePipeline>` into an `Arc<ComputePipelineAbstract>` if necessary.
-///
-/// Pass an optional `Arc` to a `PipelineCache` to enable pipeline caching. The vulkan
-/// implementation will handle the `PipelineCache` and check if it is available.
-/// Check the documentation of the `PipelineCache` for more information.
-pub struct ComputePipeline {
- inner: Inner,
- pipeline_layout: Arc<PipelineLayout>,
-}
-
-struct Inner {
- pipeline: ash::vk::Pipeline,
- device: Arc<Device>,
-}
-
-impl ComputePipeline {
- /// Builds a new `ComputePipeline`.
- pub fn new<Cs, Css>(
- device: Arc<Device>,
- shader: &Cs,
- spec_constants: &Css,
- cache: Option<Arc<PipelineCache>>,
- ) -> Result<ComputePipeline, ComputePipelineCreationError>
- where
- Cs: EntryPointAbstract,
- Css: SpecializationConstants,
- {
- unsafe {
- let descriptor_set_layouts = shader
- .descriptor_set_layout_descs()
- .iter()
- .map(|desc| {
- Ok(Arc::new(DescriptorSetLayout::new(
- device.clone(),
- desc.clone(),
- )?))
- })
- .collect::<Result<Vec<_>, OomError>>()?;
- let pipeline_layout = Arc::new(PipelineLayout::new(
- device.clone(),
- descriptor_set_layouts,
- shader.push_constant_range().iter().cloned(),
- )?);
- ComputePipeline::with_unchecked_pipeline_layout(
- device,
- shader,
- spec_constants,
- pipeline_layout,
- cache,
- )
- }
- }
-
- /// Builds a new `ComputePipeline` with a specific pipeline layout.
- ///
- /// An error will be returned if the pipeline layout isn't a superset of what the shader
- /// uses.
- pub fn with_pipeline_layout<Cs, Css>(
- device: Arc<Device>,
- shader: &Cs,
- spec_constants: &Css,
- pipeline_layout: Arc<PipelineLayout>,
- cache: Option<Arc<PipelineCache>>,
- ) -> Result<ComputePipeline, ComputePipelineCreationError>
- where
- Cs: EntryPointAbstract,
- Css: SpecializationConstants,
- {
- if Css::descriptors() != shader.spec_constants() {
- return Err(ComputePipelineCreationError::IncompatibleSpecializationConstants);
- }
-
- unsafe {
- pipeline_layout.ensure_superset_of(
- shader.descriptor_set_layout_descs(),
- shader.push_constant_range(),
- )?;
- ComputePipeline::with_unchecked_pipeline_layout(
- device,
- shader,
- spec_constants,
- pipeline_layout,
- cache,
- )
- }
- }
-
- /// Same as `with_pipeline_layout`, but doesn't check whether the pipeline layout is a
- /// superset of what the shader expects.
- pub unsafe fn with_unchecked_pipeline_layout<Cs, Css>(
- device: Arc<Device>,
- shader: &Cs,
- spec_constants: &Css,
- pipeline_layout: Arc<PipelineLayout>,
- cache: Option<Arc<PipelineCache>>,
- ) -> Result<ComputePipeline, ComputePipelineCreationError>
- where
- Cs: EntryPointAbstract,
- Css: SpecializationConstants,
- {
- let fns = device.fns();
-
- let pipeline = {
- let spec_descriptors = Css::descriptors();
- let specialization = ash::vk::SpecializationInfo {
- map_entry_count: spec_descriptors.len() as u32,
- p_map_entries: spec_descriptors.as_ptr() as *const _,
- data_size: mem::size_of_val(spec_constants),
- p_data: spec_constants as *const Css as *const _,
- };
-
- let stage = ash::vk::PipelineShaderStageCreateInfo {
- flags: ash::vk::PipelineShaderStageCreateFlags::empty(),
- stage: ash::vk::ShaderStageFlags::COMPUTE,
- module: shader.module().internal_object(),
- p_name: shader.name().as_ptr(),
- p_specialization_info: if specialization.data_size == 0 {
- ptr::null()
- } else {
- &specialization
- },
- ..Default::default()
- };
-
- let infos = ash::vk::ComputePipelineCreateInfo {
- flags: ash::vk::PipelineCreateFlags::empty(),
- stage,
- layout: pipeline_layout.internal_object(),
- base_pipeline_handle: ash::vk::Pipeline::null(),
- base_pipeline_index: 0,
- ..Default::default()
- };
-
- let cache_handle = match cache {
- Some(ref cache) => cache.internal_object(),
- None => ash::vk::PipelineCache::null(),
- };
-
- let mut output = MaybeUninit::uninit();
- check_errors(fns.v1_0.create_compute_pipelines(
- device.internal_object(),
- cache_handle,
- 1,
- &infos,
- ptr::null(),
- output.as_mut_ptr(),
- ))?;
- output.assume_init()
- };
-
- Ok(ComputePipeline {
- inner: Inner {
- device: device.clone(),
- pipeline: pipeline,
- },
- pipeline_layout: pipeline_layout,
- })
- }
-}
-
-impl fmt::Debug for ComputePipeline {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(fmt, "<Vulkan compute pipeline {:?}>", self.inner.pipeline)
- }
-}
-
-impl ComputePipeline {
- /// Returns the `Device` this compute pipeline was created with.
- #[inline]
- pub fn device(&self) -> &Arc<Device> {
- &self.inner.device
- }
-}
-
-/// Trait implemented on all compute pipelines.
-pub unsafe trait ComputePipelineAbstract: DeviceOwned {
- /// Returns an opaque object that represents the inside of the compute pipeline.
- fn inner(&self) -> ComputePipelineSys;
-
- /// Returns the pipeline layout used in this compute pipeline.
- fn layout(&self) -> &Arc<PipelineLayout>;
-}
-
-unsafe impl ComputePipelineAbstract for ComputePipeline {
- #[inline]
- fn inner(&self) -> ComputePipelineSys {
- ComputePipelineSys(self.inner.pipeline, PhantomData)
- }
-
- #[inline]
- fn layout(&self) -> &Arc<PipelineLayout> {
- &self.pipeline_layout
- }
-}
-
-unsafe impl<T> ComputePipelineAbstract for T
-where
- T: SafeDeref,
- T::Target: ComputePipelineAbstract,
-{
- #[inline]
- fn inner(&self) -> ComputePipelineSys {
- (**self).inner()
- }
-
- #[inline]
- fn layout(&self) -> &Arc<PipelineLayout> {
- (**self).layout()
- }
-}
-
-/// Opaque object that represents the inside of the compute pipeline. Can be made into a trait
-/// object.
-#[derive(Debug, Copy, Clone)]
-pub struct ComputePipelineSys<'a>(ash::vk::Pipeline, PhantomData<&'a ()>);
-
-unsafe impl<'a> VulkanObject for ComputePipelineSys<'a> {
- type Object = ash::vk::Pipeline;
-
- #[inline]
- fn internal_object(&self) -> ash::vk::Pipeline {
- self.0
- }
-}
-
-unsafe impl DeviceOwned for ComputePipeline {
- #[inline]
- fn device(&self) -> &Arc<Device> {
- self.device()
- }
-}
-
-unsafe impl VulkanObject for ComputePipeline {
- type Object = ash::vk::Pipeline;
-
- #[inline]
- fn internal_object(&self) -> ash::vk::Pipeline {
- self.inner.pipeline
- }
-}
-
-impl Drop for Inner {
- #[inline]
- fn drop(&mut self) {
- unsafe {
- let fns = self.device.fns();
- fns.v1_0
- .destroy_pipeline(self.device.internal_object(), self.pipeline, ptr::null());
- }
- }
-}
-
-/// Error that can happen when creating a compute pipeline.
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum ComputePipelineCreationError {
- /// Not enough memory.
- OomError(OomError),
- /// Error while creating the pipeline layout object.
- PipelineLayoutCreationError(PipelineLayoutCreationError),
- /// The pipeline layout is not compatible with what the shader expects.
- IncompatiblePipelineLayout(PipelineLayoutSupersetError),
- /// The provided specialization constants are not compatible with what the shader expects.
- IncompatibleSpecializationConstants,
-}
-
-impl error::Error for ComputePipelineCreationError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- ComputePipelineCreationError::OomError(ref err) => Some(err),
- ComputePipelineCreationError::PipelineLayoutCreationError(ref err) => Some(err),
- ComputePipelineCreationError::IncompatiblePipelineLayout(ref err) => Some(err),
- ComputePipelineCreationError::IncompatibleSpecializationConstants => None,
- }
- }
-}
-
-impl fmt::Display for ComputePipelineCreationError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- ComputePipelineCreationError::OomError(_) => "not enough memory available",
- ComputePipelineCreationError::PipelineLayoutCreationError(_) => {
- "error while creating the pipeline layout object"
- }
- ComputePipelineCreationError::IncompatiblePipelineLayout(_) => {
- "the pipeline layout is not compatible with what the shader expects"
- }
- ComputePipelineCreationError::IncompatibleSpecializationConstants => {
- "the provided specialization constants are not compatible with what the shader expects"
- }
- }
- )
- }
-}
-
-impl From<OomError> for ComputePipelineCreationError {
- #[inline]
- fn from(err: OomError) -> ComputePipelineCreationError {
- ComputePipelineCreationError::OomError(err)
- }
-}
-
-impl From<PipelineLayoutCreationError> for ComputePipelineCreationError {
- #[inline]
- fn from(err: PipelineLayoutCreationError) -> ComputePipelineCreationError {
- ComputePipelineCreationError::PipelineLayoutCreationError(err)
- }
-}
-
-impl From<PipelineLayoutSupersetError> for ComputePipelineCreationError {
- #[inline]
- fn from(err: PipelineLayoutSupersetError) -> ComputePipelineCreationError {
- ComputePipelineCreationError::IncompatiblePipelineLayout(err)
- }
-}
-
-impl From<Error> for ComputePipelineCreationError {
- #[inline]
- fn from(err: Error) -> ComputePipelineCreationError {
- match err {
- err @ Error::OutOfHostMemory => {
- ComputePipelineCreationError::OomError(OomError::from(err))
- }
- err @ Error::OutOfDeviceMemory => {
- ComputePipelineCreationError::OomError(OomError::from(err))
- }
- _ => panic!("unexpected error: {:?}", err),
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use crate::buffer::BufferUsage;
- use crate::buffer::CpuAccessibleBuffer;
- use crate::command_buffer::AutoCommandBufferBuilder;
- use crate::command_buffer::CommandBufferUsage;
- use crate::descriptor_set::layout::DescriptorBufferDesc;
- use crate::descriptor_set::layout::DescriptorDesc;
- use crate::descriptor_set::layout::DescriptorDescTy;
- use crate::descriptor_set::layout::DescriptorSetDesc;
- use crate::descriptor_set::PersistentDescriptorSet;
- use crate::pipeline::shader::ShaderModule;
- use crate::pipeline::shader::ShaderStages;
- use crate::pipeline::shader::SpecializationConstants;
- use crate::pipeline::shader::SpecializationMapEntry;
- use crate::pipeline::ComputePipeline;
- use crate::pipeline::ComputePipelineAbstract;
- use crate::sync::now;
- use crate::sync::GpuFuture;
- use std::ffi::CStr;
- use std::sync::Arc;
-
- // TODO: test for basic creation
- // TODO: test for pipeline layout error
-
- #[test]
- fn spec_constants() {
- // This test checks whether specialization constants work.
- // It executes a single compute shader (one invocation) that writes the value of a spec.
- // constant to a buffer. The buffer content is then checked for the right value.
-
- let (device, queue) = gfx_dev_and_queue!();
-
- let module = unsafe {
- /*
- #version 450
-
- layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-
- layout(constant_id = 83) const int VALUE = 0xdeadbeef;
-
- layout(set = 0, binding = 0) buffer Output {
- int write;
- } write;
-
- void main() {
- write.write = VALUE;
- }
- */
- const MODULE: [u8; 480] = [
- 3, 2, 35, 7, 0, 0, 1, 0, 1, 0, 8, 0, 14, 0, 0, 0, 0, 0, 0, 0, 17, 0, 2, 0, 1, 0, 0,
- 0, 11, 0, 6, 0, 1, 0, 0, 0, 71, 76, 83, 76, 46, 115, 116, 100, 46, 52, 53, 48, 0,
- 0, 0, 0, 14, 0, 3, 0, 0, 0, 0, 0, 1, 0, 0, 0, 15, 0, 5, 0, 5, 0, 0, 0, 4, 0, 0, 0,
- 109, 97, 105, 110, 0, 0, 0, 0, 16, 0, 6, 0, 4, 0, 0, 0, 17, 0, 0, 0, 1, 0, 0, 0, 1,
- 0, 0, 0, 1, 0, 0, 0, 3, 0, 3, 0, 2, 0, 0, 0, 194, 1, 0, 0, 5, 0, 4, 0, 4, 0, 0, 0,
- 109, 97, 105, 110, 0, 0, 0, 0, 5, 0, 4, 0, 7, 0, 0, 0, 79, 117, 116, 112, 117, 116,
- 0, 0, 6, 0, 5, 0, 7, 0, 0, 0, 0, 0, 0, 0, 119, 114, 105, 116, 101, 0, 0, 0, 5, 0,
- 4, 0, 9, 0, 0, 0, 119, 114, 105, 116, 101, 0, 0, 0, 5, 0, 4, 0, 11, 0, 0, 0, 86,
- 65, 76, 85, 69, 0, 0, 0, 72, 0, 5, 0, 7, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0,
- 0, 71, 0, 3, 0, 7, 0, 0, 0, 3, 0, 0, 0, 71, 0, 4, 0, 9, 0, 0, 0, 34, 0, 0, 0, 0, 0,
- 0, 0, 71, 0, 4, 0, 9, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 71, 0, 4, 0, 11, 0, 0, 0,
- 1, 0, 0, 0, 83, 0, 0, 0, 19, 0, 2, 0, 2, 0, 0, 0, 33, 0, 3, 0, 3, 0, 0, 0, 2, 0, 0,
- 0, 21, 0, 4, 0, 6, 0, 0, 0, 32, 0, 0, 0, 1, 0, 0, 0, 30, 0, 3, 0, 7, 0, 0, 0, 6, 0,
- 0, 0, 32, 0, 4, 0, 8, 0, 0, 0, 2, 0, 0, 0, 7, 0, 0, 0, 59, 0, 4, 0, 8, 0, 0, 0, 9,
- 0, 0, 0, 2, 0, 0, 0, 43, 0, 4, 0, 6, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 50, 0, 4, 0,
- 6, 0, 0, 0, 11, 0, 0, 0, 239, 190, 173, 222, 32, 0, 4, 0, 12, 0, 0, 0, 2, 0, 0, 0,
- 6, 0, 0, 0, 54, 0, 5, 0, 2, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 248, 0, 2,
- 0, 5, 0, 0, 0, 65, 0, 5, 0, 12, 0, 0, 0, 13, 0, 0, 0, 9, 0, 0, 0, 10, 0, 0, 0, 62,
- 0, 3, 0, 13, 0, 0, 0, 11, 0, 0, 0, 253, 0, 1, 0, 56, 0, 1, 0,
- ];
- ShaderModule::new(device.clone(), &MODULE).unwrap()
- };
-
- let shader = unsafe {
- static NAME: [u8; 5] = [109, 97, 105, 110, 0]; // "main"
- module.compute_entry_point(
- CStr::from_ptr(NAME.as_ptr() as *const _),
- [DescriptorSetDesc::new([Some(DescriptorDesc {
- ty: DescriptorDescTy::Buffer(DescriptorBufferDesc {
- dynamic: Some(false),
- storage: true,
- }),
- array_count: 1,
- stages: ShaderStages {
- compute: true,
- ..ShaderStages::none()
- },
- readonly: true,
- })])],
- None,
- SpecConsts::descriptors(),
- )
- };
-
- #[derive(Debug, Copy, Clone)]
- #[allow(non_snake_case)]
- #[repr(C)]
- struct SpecConsts {
- VALUE: i32,
- }
- unsafe impl SpecializationConstants for SpecConsts {
- fn descriptors() -> &'static [SpecializationMapEntry] {
- static DESCRIPTORS: [SpecializationMapEntry; 1] = [SpecializationMapEntry {
- constant_id: 83,
- offset: 0,
- size: 4,
- }];
- &DESCRIPTORS
- }
- }
-
- let pipeline = Arc::new(
- ComputePipeline::new(
- device.clone(),
- &shader,
- &SpecConsts { VALUE: 0x12345678 },
- None,
- )
- .unwrap(),
- );
-
- let data_buffer =
- CpuAccessibleBuffer::from_data(device.clone(), BufferUsage::all(), false, 0).unwrap();
- let layout = pipeline.layout().descriptor_set_layouts().get(0).unwrap();
- let set = PersistentDescriptorSet::start(layout.clone())
- .add_buffer(data_buffer.clone())
- .unwrap()
- .build()
- .unwrap();
-
- let mut cbb = AutoCommandBufferBuilder::primary(
- device.clone(),
- queue.family(),
- CommandBufferUsage::OneTimeSubmit,
- )
- .unwrap();
- cbb.dispatch([1, 1, 1], pipeline.clone(), set, ()).unwrap();
- let cb = cbb.build().unwrap();
-
- let future = now(device.clone())
- .then_execute(queue.clone(), cb)
- .unwrap()
- .then_signal_fence_and_flush()
- .unwrap();
- future.wait(None).unwrap();
-
- let data_buffer_content = data_buffer.read().unwrap();
- assert_eq!(*data_buffer_content, 0x12345678);
- }
-}
diff --git a/src/pipeline/depth_stencil.rs b/src/pipeline/depth_stencil.rs
deleted file mode 100644
index 84d1e03..0000000
--- a/src/pipeline/depth_stencil.rs
+++ /dev/null
@@ -1,263 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-//! Depth and stencil operations description.
-//!
-//! After the fragment shader has finished running, each fragment goes through the depth
-//! and stencil tests.
-//!
-//! The depth test passes of fails depending on how the depth value of each fragment compares
-//! to the existing depth value in the depth buffer at that fragment's location. Depth values
-//! are always between 0.0 and 1.0.
-//!
-//! The stencil test passes or fails depending on how a reference value compares to the existing
-//! value in the stencil buffer at each fragment's location. Depending on the outcome of the
-//! depth and stencil tests, the value of the stencil buffer at that location can be updated.
-
-use std::ops::Range;
-use std::u32;
-
-/// Configuration of the depth and stencil tests.
-#[derive(Debug, Clone)]
-pub struct DepthStencil {
- /// Comparison to use between the depth value of each fragment and the depth value currently
- /// in the depth buffer.
- pub depth_compare: Compare,
-
- /// If `true`, then the value in the depth buffer will be updated when the depth test succeeds.
- pub depth_write: bool,
-
- /// Allows you to ask the GPU to exclude fragments that are outside of a certain range. This is
- /// done in addition to the regular depth test.
- pub depth_bounds_test: DepthBounds,
-
- /// Stencil operations to use for points, lines and triangles whose front is facing the user.
- pub stencil_front: Stencil,
-
- /// Stencil operations to use for triangles whose back is facing the user.
- pub stencil_back: Stencil,
-}
-
-impl DepthStencil {
- /// Creates a `DepthStencil` where both the depth and stencil tests are disabled and have
- /// no effect.
- #[inline]
- pub fn disabled() -> DepthStencil {
- DepthStencil {
- depth_write: false,
- depth_compare: Compare::Always,
- depth_bounds_test: DepthBounds::Disabled,
- stencil_front: Default::default(),
- stencil_back: Default::default(),
- }
- }
-
- /// Creates a `DepthStencil` with a `Less` depth test, `depth_write` set to true, and stencil
- /// testing disabled.
- #[inline]
- pub fn simple_depth_test() -> DepthStencil {
- DepthStencil {
- depth_write: true,
- depth_compare: Compare::Less,
- depth_bounds_test: DepthBounds::Disabled,
- stencil_front: Default::default(),
- stencil_back: Default::default(),
- }
- }
-}
-
-impl Default for DepthStencil {
- #[inline]
- fn default() -> DepthStencil {
- DepthStencil::disabled()
- }
-}
-
-/// Configuration of a stencil test.
-#[derive(Debug, Copy, Clone)]
-pub struct Stencil {
- /// The comparison to perform between the existing stencil value in the stencil buffer, and
- /// the reference value (given by `reference`).
- pub compare: Compare,
-
- /// The operation to perform when both the depth test and the stencil test passed.
- pub pass_op: StencilOp,
-
- /// The operation to perform when the stencil test failed.
- pub fail_op: StencilOp,
-
- /// The operation to perform when the stencil test passed but the depth test failed.
- pub depth_fail_op: StencilOp,
-
- /// Selects the bits of the unsigned integer stencil values participating in the stencil test.
- ///
- /// Ignored if `compare` is `Never` or `Always`.
- ///
- /// If `None`, then this value is dynamic and will need to be set when drawing. Doesn't apply
- /// if `compare` is `Never` or `Always`.
- ///
- /// Note that if this value is `Some` in `stencil_front`, it must also be `Some` in
- /// `stencil_back` (but the content can be different). If this value is `None` in
- /// `stencil_front`, then it must also be `None` in `stencil_back`. This rule doesn't apply
- /// if `compare` is `Never` or `Always`.
- pub compare_mask: Option<u32>,
-
- /// Selects the bits of the unsigned integer stencil values updated by the stencil test in the
- /// stencil framebuffer attachment.
- ///
- /// If `None`, then this value is dynamic and will need to be set when drawing.
- ///
- /// Note that if this value is `Some` in `stencil_front`, it must also be `Some` in
- /// `stencil_back` (but the content can be different). If this value is `None` in
- /// `stencil_front`, then it must also be `None` in `stencil_back`.
- pub write_mask: Option<u32>,
-
- /// Reference value that is used in the unsigned stencil comparison.
- ///
- /// If `None`, then this value is dynamic and will need to be set when drawing.
- ///
- /// Note that if this value is `Some` in `stencil_front`, it must also be `Some` in
- /// `stencil_back` (but the content can be different). If this value is `None` in
- /// `stencil_front`, then it must also be `None` in `stencil_back`.
- pub reference: Option<u32>,
-}
-
-impl Stencil {
- /// Returns true if the stencil operation will always result in `Keep`.
- #[inline]
- pub fn always_keep(&self) -> bool {
- match self.compare {
- Compare::Always => {
- self.pass_op == StencilOp::Keep && self.depth_fail_op == StencilOp::Keep
- }
- Compare::Never => self.fail_op == StencilOp::Keep,
- _ => {
- self.pass_op == StencilOp::Keep
- && self.fail_op == StencilOp::Keep
- && self.depth_fail_op == StencilOp::Keep
- }
- }
- }
-}
-
-impl Default for Stencil {
- #[inline]
- fn default() -> Stencil {
- Stencil {
- compare: Compare::Never,
- pass_op: StencilOp::Keep,
- fail_op: StencilOp::Keep,
- depth_fail_op: StencilOp::Keep,
- compare_mask: Some(u32::MAX),
- write_mask: Some(u32::MAX),
- reference: Some(u32::MAX),
- }
- }
-}
-
-/// Operation to perform after the depth and stencil tests.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-#[repr(i32)]
-pub enum StencilOp {
- Keep = ash::vk::StencilOp::KEEP.as_raw(),
- Zero = ash::vk::StencilOp::ZERO.as_raw(),
- Replace = ash::vk::StencilOp::REPLACE.as_raw(),
- IncrementAndClamp = ash::vk::StencilOp::INCREMENT_AND_CLAMP.as_raw(),
- DecrementAndClamp = ash::vk::StencilOp::DECREMENT_AND_CLAMP.as_raw(),
- Invert = ash::vk::StencilOp::INVERT.as_raw(),
- IncrementAndWrap = ash::vk::StencilOp::INCREMENT_AND_WRAP.as_raw(),
- DecrementAndWrap = ash::vk::StencilOp::DECREMENT_AND_WRAP.as_raw(),
-}
-
-impl From<StencilOp> for ash::vk::StencilOp {
- #[inline]
- fn from(val: StencilOp) -> Self {
- Self::from_raw(val as i32)
- }
-}
-
-/// Specifies a face for stencil operations.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-#[repr(u32)]
-pub enum StencilFaces {
- Front = ash::vk::StencilFaceFlags::FRONT.as_raw(),
- Back = ash::vk::StencilFaceFlags::BACK.as_raw(),
- FrontAndBack = ash::vk::StencilFaceFlags::FRONT_AND_BACK.as_raw(),
-}
-
-impl From<StencilFaces> for ash::vk::StencilFaceFlags {
- #[inline]
- fn from(val: StencilFaces) -> Self {
- Self::from_raw(val as u32)
- }
-}
-
-/// Specifies a dynamic state value for the front and back faces.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct DynamicStencilValue {
- pub front: u32,
- pub back: u32,
-}
-
-/// Allows you to ask the GPU to exclude fragments that are outside of a certain range.
-#[derive(Debug, Clone, PartialEq)]
-pub enum DepthBounds {
- /// The test is disabled. All fragments pass the depth bounds test.
- Disabled,
-
- /// Fragments that are within the given range do pass the test. Values are depth values
- /// between 0.0 and 1.0.
- Fixed(Range<f32>),
-
- /// The depth bounds test is enabled, but the range will need to specified when you submit
- /// a draw command.
- Dynamic,
-}
-
-impl DepthBounds {
- /// Returns true if equal to `DepthBounds::Dynamic`.
- #[inline]
- pub fn is_dynamic(&self) -> bool {
- match self {
- &DepthBounds::Dynamic => true,
- _ => false,
- }
- }
-}
-
-/// Specifies how two values should be compared to decide whether a test passes or fails.
-///
-/// Used for both depth testing and stencil testing.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-#[repr(i32)]
-pub enum Compare {
- /// The test never passes.
- Never = ash::vk::CompareOp::NEVER.as_raw(),
- /// The test passes if `value < reference_value`.
- Less = ash::vk::CompareOp::LESS.as_raw(),
- /// The test passes if `value == reference_value`.
- Equal = ash::vk::CompareOp::EQUAL.as_raw(),
- /// The test passes if `value <= reference_value`.
- LessOrEqual = ash::vk::CompareOp::LESS_OR_EQUAL.as_raw(),
- /// The test passes if `value > reference_value`.
- Greater = ash::vk::CompareOp::GREATER.as_raw(),
- /// The test passes if `value != reference_value`.
- NotEqual = ash::vk::CompareOp::NOT_EQUAL.as_raw(),
- /// The test passes if `value >= reference_value`.
- GreaterOrEqual = ash::vk::CompareOp::GREATER_OR_EQUAL.as_raw(),
- /// The test always passes.
- Always = ash::vk::CompareOp::ALWAYS.as_raw(),
-}
-
-impl From<Compare> for ash::vk::CompareOp {
- #[inline]
- fn from(val: Compare) -> Self {
- Self::from_raw(val as i32)
- }
-}
diff --git a/src/pipeline/graphics/builder.rs b/src/pipeline/graphics/builder.rs
new file mode 100644
index 0000000..3ef98da
--- /dev/null
+++ b/src/pipeline/graphics/builder.rs
@@ -0,0 +1,4585 @@
+// Copyright (c) 2017 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+// TODO: graphics pipeline params are deprecated, but are still the primary implementation in order
+// to avoid duplicating code, so we hide the warnings for now
+#![allow(deprecated)]
+
+use super::{
+ color_blend::{
+ AttachmentBlend, ColorBlendAttachmentState, ColorBlendState, ColorComponents, LogicOp,
+ },
+ depth_stencil::{DepthStencilState, StencilOps},
+ discard_rectangle::DiscardRectangleState,
+ input_assembly::{InputAssemblyState, PrimitiveTopology, PrimitiveTopologyClass},
+ multisample::MultisampleState,
+ rasterization::{
+ CullMode, DepthBiasState, FrontFace, LineRasterizationMode, PolygonMode, RasterizationState,
+ },
+ render_pass::{PipelineRenderPassType, PipelineRenderingCreateInfo},
+ tessellation::TessellationState,
+ vertex_input::{
+ VertexDefinition, VertexInputAttributeDescription, VertexInputBindingDescription,
+ VertexInputState,
+ },
+ viewport::{Scissor, Viewport, ViewportState},
+ GraphicsPipeline, GraphicsPipelineCreationError,
+};
+use crate::{
+ descriptor_set::layout::{DescriptorSetLayout, DescriptorSetLayoutCreateInfo},
+ device::{Device, DeviceOwned},
+ format::{FormatFeatures, NumericType},
+ image::ImageAspects,
+ pipeline::{
+ cache::PipelineCache,
+ graphics::{
+ color_blend::BlendFactor,
+ depth_stencil::{DepthBoundsState, DepthState, StencilOpState, StencilState},
+ vertex_input::VertexInputRate,
+ },
+ layout::{PipelineLayoutCreateInfo, PushConstantRange},
+ DynamicState, PartialStateMode, PipelineLayout, StateMode,
+ },
+ shader::{
+ DescriptorBindingRequirements, EntryPoint, FragmentShaderExecution, FragmentTestsStages,
+ ShaderExecution, ShaderScalarType, ShaderStage, SpecializationConstants,
+ SpecializationMapEntry,
+ },
+ DeviceSize, RequiresOneOf, Version, VulkanError, VulkanObject,
+};
+use ahash::HashMap;
+use smallvec::SmallVec;
+use std::{
+ collections::hash_map::Entry,
+ mem::{size_of_val, MaybeUninit},
+ ptr, slice,
+ sync::Arc,
+};
+
+/// Prototype for a `GraphicsPipeline`.
+#[derive(Debug)]
+pub struct GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss> {
+ render_pass: Option<PipelineRenderPassType>,
+ cache: Option<Arc<PipelineCache>>,
+
+ vertex_shader: Option<(EntryPoint<'vs>, Vss)>,
+ tessellation_shaders: Option<TessellationShaders<'tcs, 'tes, Tcss, Tess>>,
+ geometry_shader: Option<(EntryPoint<'gs>, Gss)>,
+ fragment_shader: Option<(EntryPoint<'fs>, Fss)>,
+
+ vertex_input_state: Vdef,
+ input_assembly_state: InputAssemblyState,
+ tessellation_state: TessellationState,
+ viewport_state: ViewportState,
+ discard_rectangle_state: DiscardRectangleState,
+ rasterization_state: RasterizationState,
+ multisample_state: MultisampleState,
+ depth_stencil_state: DepthStencilState,
+ color_blend_state: ColorBlendState,
+}
+
+// Additional parameters if tessellation is used.
+#[derive(Clone, Debug)]
+struct TessellationShaders<'tcs, 'tes, Tcss, Tess> {
+ control: (EntryPoint<'tcs>, Tcss),
+ evaluation: (EntryPoint<'tes>, Tess),
+}
+
+impl
+ GraphicsPipelineBuilder<
+ 'static,
+ 'static,
+ 'static,
+ 'static,
+ 'static,
+ VertexInputState,
+ (),
+ (),
+ (),
+ (),
+ (),
+ >
+{
+ /// Builds a new empty builder.
+ pub(super) fn new() -> Self {
+ GraphicsPipelineBuilder {
+ render_pass: None,
+ cache: None,
+
+ vertex_shader: None,
+ tessellation_shaders: None,
+ geometry_shader: None,
+ fragment_shader: None,
+
+ vertex_input_state: Default::default(),
+ input_assembly_state: Default::default(),
+ tessellation_state: Default::default(),
+ viewport_state: Default::default(),
+ discard_rectangle_state: Default::default(),
+ rasterization_state: Default::default(),
+ multisample_state: Default::default(),
+ depth_stencil_state: Default::default(),
+ color_blend_state: Default::default(),
+ }
+ }
+}
+
+#[derive(Clone, Copy, Debug)]
+struct Has {
+ vertex_input_state: bool,
+ pre_rasterization_shader_state: bool,
+ tessellation_state: bool,
+ viewport_state: bool,
+ fragment_shader_state: bool,
+ depth_stencil_state: bool,
+ fragment_output_state: bool,
+ color_blend_state: bool,
+}
+
+impl<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss>
+ GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss>
+where
+ Vdef: VertexDefinition,
+ Vss: SpecializationConstants,
+ Tcss: SpecializationConstants,
+ Tess: SpecializationConstants,
+ Gss: SpecializationConstants,
+ Fss: SpecializationConstants,
+{
+ /// Builds the graphics pipeline, using an inferred a pipeline layout.
+ #[inline]
+ pub fn build(
+ self,
+ device: Arc<Device>,
+ ) -> Result<Arc<GraphicsPipeline>, GraphicsPipelineCreationError> {
+ self.with_auto_layout(device, |_| {})
+ }
+
+ /// The same as `new`, but allows you to provide a closure that is given a mutable reference to
+ /// the inferred descriptor set definitions. This can be used to make changes to the layout
+ /// before it's created, for example to add dynamic buffers or immutable samplers.
+ pub fn with_auto_layout<F>(
+ self,
+ device: Arc<Device>,
+ func: F,
+ ) -> Result<Arc<GraphicsPipeline>, GraphicsPipelineCreationError>
+ where
+ F: FnOnce(&mut [DescriptorSetLayoutCreateInfo]),
+ {
+ let (set_layout_create_infos, push_constant_ranges) = {
+ let stages: SmallVec<[&EntryPoint<'_>; 5]> = [
+ self.vertex_shader.as_ref().map(|s| &s.0),
+ self.tessellation_shaders.as_ref().map(|s| &s.control.0),
+ self.tessellation_shaders.as_ref().map(|s| &s.evaluation.0),
+ self.geometry_shader.as_ref().map(|s| &s.0),
+ self.fragment_shader.as_ref().map(|s| &s.0),
+ ]
+ .into_iter()
+ .flatten()
+ .collect();
+
+ // Produce `DescriptorBindingRequirements` for each binding, by iterating over all
+ // shaders and adding the requirements of each.
+ let mut descriptor_binding_requirements: HashMap<
+ (u32, u32),
+ DescriptorBindingRequirements,
+ > = HashMap::default();
+
+ for (loc, reqs) in stages
+ .iter()
+ .flat_map(|shader| shader.descriptor_binding_requirements())
+ {
+ match descriptor_binding_requirements.entry(loc) {
+ Entry::Occupied(entry) => {
+ // Previous shaders already added requirements, so we merge requirements of
+ // the current shader into the requirements of the previous one.
+ entry.into_mut().merge(reqs).expect("Could not produce an intersection of the shader descriptor requirements");
+ }
+ Entry::Vacant(entry) => {
+ // No previous shader had this descriptor yet, so we just insert the
+ // requirements.
+ entry.insert(reqs.clone());
+ }
+ }
+ }
+
+ // Build a description of a descriptor set layout from the shader requirements, then
+ // feed it to the user-provided closure to allow tweaking.
+ let mut set_layout_create_infos = DescriptorSetLayoutCreateInfo::from_requirements(
+ descriptor_binding_requirements
+ .iter()
+ .map(|(&loc, reqs)| (loc, reqs)),
+ );
+ func(&mut set_layout_create_infos);
+
+ // We want to union each push constant range into a set of ranges that do not have intersecting stage flags.
+ // e.g. The range [0, 16) is either made available to Vertex | Fragment or we only make [0, 16) available to
+ // Vertex and a subrange available to Fragment, like [0, 8)
+ let mut range_map = HashMap::default();
+ for stage in stages.iter() {
+ if let Some(range) = stage.push_constant_requirements() {
+ match range_map.entry((range.offset, range.size)) {
+ Entry::Vacant(entry) => {
+ entry.insert(range.stages);
+ }
+ Entry::Occupied(mut entry) => {
+ *entry.get_mut() = *entry.get() | range.stages;
+ }
+ }
+ }
+ }
+ let push_constant_ranges: Vec<_> = range_map
+ .iter()
+ .map(|((offset, size), stages)| PushConstantRange {
+ stages: *stages,
+ offset: *offset,
+ size: *size,
+ })
+ .collect();
+
+ (set_layout_create_infos, push_constant_ranges)
+ };
+
+ let set_layouts = set_layout_create_infos
+ .into_iter()
+ .map(|desc| DescriptorSetLayout::new(device.clone(), desc))
+ .collect::<Result<Vec<_>, _>>()?;
+ let pipeline_layout = PipelineLayout::new(
+ device.clone(),
+ PipelineLayoutCreateInfo {
+ set_layouts,
+ push_constant_ranges,
+ ..Default::default()
+ },
+ )
+ .unwrap();
+ self.with_pipeline_layout(device, pipeline_layout)
+ }
+
+ /// Builds the graphics pipeline.
+ ///
+ /// Does the same as `build`, except that `build` automatically builds the pipeline layout
+ /// object corresponding to the union of your shaders while this function allows you to specify
+ /// the pipeline layout.
+ #[inline]
+ pub fn with_pipeline_layout(
+ mut self,
+ device: Arc<Device>,
+ pipeline_layout: Arc<PipelineLayout>,
+ ) -> Result<Arc<GraphicsPipeline>, GraphicsPipelineCreationError> {
+ let vertex_input_state = self
+ .vertex_input_state
+ .definition(self.vertex_shader.as_ref().unwrap().0.input_interface())?;
+
+ // If there is one element, duplicate it for all attachments.
+ // TODO: this is undocumented and only exists for compatibility with some of the
+ // deprecated builder methods. Remove it when those methods are gone.
+ if self.color_blend_state.attachments.len() == 1 {
+ let color_attachment_count =
+ match self.render_pass.as_ref().expect("Missing render pass") {
+ PipelineRenderPassType::BeginRenderPass(subpass) => {
+ subpass.subpass_desc().color_attachments.len()
+ }
+ PipelineRenderPassType::BeginRendering(rendering_info) => {
+ rendering_info.color_attachment_formats.len()
+ }
+ };
+ let element = self.color_blend_state.attachments.pop().unwrap();
+ self.color_blend_state
+ .attachments
+ .extend(std::iter::repeat(element).take(color_attachment_count));
+ }
+
+ let has = {
+ let Self {
+ render_pass,
+ cache: _,
+
+ vertex_shader,
+ tessellation_shaders,
+ geometry_shader: _,
+ fragment_shader: _,
+
+ vertex_input_state: _,
+ input_assembly_state: _,
+ tessellation_state: _,
+ viewport_state: _,
+ discard_rectangle_state: _,
+ rasterization_state,
+ multisample_state: _,
+ depth_stencil_state: _,
+ color_blend_state: _,
+ } = &self;
+
+ let render_pass = render_pass.as_ref().expect("Missing render pass");
+
+ let has_pre_rasterization_shader_state = true;
+ let has_vertex_input_state = vertex_shader.is_some();
+ let has_fragment_shader_state =
+ rasterization_state.rasterizer_discard_enable != StateMode::Fixed(true);
+ let has_fragment_output_state =
+ rasterization_state.rasterizer_discard_enable != StateMode::Fixed(true);
+
+ let has_tessellation_state =
+ has_pre_rasterization_shader_state && tessellation_shaders.is_some();
+ let has_viewport_state =
+ has_pre_rasterization_shader_state && has_fragment_shader_state;
+ let has_depth_stencil_state = has_fragment_shader_state
+ && match render_pass {
+ PipelineRenderPassType::BeginRenderPass(subpass) => {
+ subpass.subpass_desc().depth_stencil_attachment.is_some()
+ }
+ PipelineRenderPassType::BeginRendering(rendering_info) => {
+ !has_fragment_output_state
+ || rendering_info.depth_attachment_format.is_some()
+ || rendering_info.stencil_attachment_format.is_some()
+ }
+ };
+ let has_color_blend_state = has_fragment_output_state
+ && match render_pass {
+ PipelineRenderPassType::BeginRenderPass(subpass) => {
+ !subpass.subpass_desc().color_attachments.is_empty()
+ }
+ PipelineRenderPassType::BeginRendering(rendering_info) => {
+ !rendering_info.color_attachment_formats.is_empty()
+ }
+ };
+
+ Has {
+ vertex_input_state: has_vertex_input_state,
+ pre_rasterization_shader_state: has_pre_rasterization_shader_state,
+ tessellation_state: has_tessellation_state,
+ viewport_state: has_viewport_state,
+ fragment_shader_state: has_fragment_shader_state,
+ depth_stencil_state: has_depth_stencil_state,
+ fragment_output_state: has_fragment_output_state,
+ color_blend_state: has_color_blend_state,
+ }
+ };
+
+ self.validate_create(&device, &pipeline_layout, &vertex_input_state, has)?;
+
+ let (handle, descriptor_requirements, dynamic_state, shaders, fragment_tests_stages) =
+ unsafe { self.record_create(&device, &pipeline_layout, &vertex_input_state, has)? };
+
+ let Self {
+ mut render_pass,
+ cache: _,
+
+ vertex_shader: _,
+ tessellation_shaders: _,
+ geometry_shader: _,
+ fragment_shader: _,
+
+ vertex_input_state: _,
+ input_assembly_state,
+ tessellation_state,
+ viewport_state,
+ discard_rectangle_state,
+ rasterization_state,
+ multisample_state,
+ depth_stencil_state,
+ color_blend_state,
+ } = self;
+
+ let num_used_descriptor_sets = descriptor_requirements
+ .keys()
+ .map(|loc| loc.0)
+ .max()
+ .map(|x| x + 1)
+ .unwrap_or(0);
+
+ Ok(Arc::new(GraphicsPipeline {
+ handle,
+ device,
+ id: GraphicsPipeline::next_id(),
+ layout: pipeline_layout,
+ render_pass: render_pass.take().expect("Missing render pass"),
+
+ shaders,
+ descriptor_binding_requirements: descriptor_requirements,
+ num_used_descriptor_sets,
+ fragment_tests_stages,
+
+ vertex_input_state, // Can be None if there's a mesh shader, but we don't support that yet
+ input_assembly_state, // Can be None if there's a mesh shader, but we don't support that yet
+ tessellation_state: has.tessellation_state.then_some(tessellation_state),
+ viewport_state: has.viewport_state.then_some(viewport_state),
+ discard_rectangle_state: has
+ .pre_rasterization_shader_state
+ .then_some(discard_rectangle_state),
+ rasterization_state,
+ multisample_state: has.fragment_output_state.then_some(multisample_state),
+ depth_stencil_state: has.depth_stencil_state.then_some(depth_stencil_state),
+ color_blend_state: has.color_blend_state.then_some(color_blend_state),
+ dynamic_state,
+ }))
+ }
+
+ fn validate_create(
+ &self,
+ device: &Device,
+ pipeline_layout: &PipelineLayout,
+ vertex_input_state: &VertexInputState,
+ has: Has,
+ ) -> Result<(), GraphicsPipelineCreationError> {
+ let physical_device = device.physical_device();
+ let properties = physical_device.properties();
+
+ let Self {
+ render_pass,
+ cache: _,
+
+ vertex_shader,
+ tessellation_shaders,
+ geometry_shader,
+ fragment_shader,
+
+ vertex_input_state: _,
+ input_assembly_state,
+ tessellation_state,
+ viewport_state,
+ discard_rectangle_state,
+ rasterization_state,
+ multisample_state,
+ depth_stencil_state,
+ color_blend_state,
+ } = self;
+
+ let render_pass = render_pass.as_ref().expect("Missing render pass");
+
+ let mut shader_stages: SmallVec<[_; 5]> = SmallVec::new();
+
+ // VUID-VkGraphicsPipelineCreateInfo-layout-01688
+ // Checked at pipeline layout creation time.
+
+ /*
+ Render pass
+ */
+
+ match render_pass {
+ PipelineRenderPassType::BeginRenderPass(subpass) => {
+ // VUID-VkGraphicsPipelineCreateInfo-commonparent
+ assert_eq!(device, subpass.render_pass().device().as_ref());
+ }
+ PipelineRenderPassType::BeginRendering(rendering_info) => {
+ let &PipelineRenderingCreateInfo {
+ view_mask,
+ ref color_attachment_formats,
+ depth_attachment_format,
+ stencil_attachment_format,
+ _ne: _,
+ } = rendering_info;
+
+ // VUID-VkGraphicsPipelineCreateInfo-dynamicRendering-06576
+ if !device.enabled_features().dynamic_rendering {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`render_pass` is `PipelineRenderPassType::BeginRendering`",
+ requires_one_of: RequiresOneOf {
+ features: &["dynamic_rendering"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkGraphicsPipelineCreateInfo-multiview-06577
+ if view_mask != 0 && !device.enabled_features().multiview {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`render_pass` is `PipelineRenderPassType::BeginRendering` \
+ where `view_mask` is not `0`",
+ requires_one_of: RequiresOneOf {
+ features: &["multiview"],
+ ..Default::default()
+ },
+ });
+ }
+
+ let view_count = u32::BITS - view_mask.leading_zeros();
+
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06578
+ if view_count > properties.max_multiview_view_count.unwrap_or(0) {
+ return Err(
+ GraphicsPipelineCreationError::MaxMultiviewViewCountExceeded {
+ view_count,
+ max: properties.max_multiview_view_count.unwrap_or(0),
+ },
+ );
+ }
+
+ if has.fragment_output_state {
+ for (attachment_index, format) in color_attachment_formats
+ .iter()
+ .enumerate()
+ .flat_map(|(i, f)| f.map(|f| (i, f)))
+ {
+ let attachment_index = attachment_index as u32;
+
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06580
+ format.validate_device(device)?;
+
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06582
+ // Use unchecked, because all validation has been done above.
+ if !unsafe { physical_device.format_properties_unchecked(format) }
+ .potential_format_features()
+ .intersects(FormatFeatures::COLOR_ATTACHMENT)
+ {
+ return Err(
+ GraphicsPipelineCreationError::ColorAttachmentFormatUsageNotSupported {
+ attachment_index,
+ },
+ );
+ }
+ }
+
+ if let Some(format) = depth_attachment_format {
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06583
+ format.validate_device(device)?;
+
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06585
+ // Use unchecked, because all validation has been done above.
+ if !unsafe { physical_device.format_properties_unchecked(format) }
+ .potential_format_features()
+ .intersects(FormatFeatures::DEPTH_STENCIL_ATTACHMENT)
+ {
+ return Err(
+ GraphicsPipelineCreationError::DepthAttachmentFormatUsageNotSupported,
+ );
+ }
+
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06587
+ if !format.aspects().intersects(ImageAspects::DEPTH) {
+ return Err(
+ GraphicsPipelineCreationError::DepthAttachmentFormatUsageNotSupported,
+ );
+ }
+ }
+
+ if let Some(format) = stencil_attachment_format {
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06584
+ format.validate_device(device)?;
+
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06586
+ // Use unchecked, because all validation has been done above.
+ if !unsafe { physical_device.format_properties_unchecked(format) }
+ .potential_format_features()
+ .intersects(FormatFeatures::DEPTH_STENCIL_ATTACHMENT)
+ {
+ return Err(
+ GraphicsPipelineCreationError::StencilAttachmentFormatUsageNotSupported,
+ );
+ }
+
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06588
+ if !format.aspects().intersects(ImageAspects::STENCIL) {
+ return Err(
+ GraphicsPipelineCreationError::StencilAttachmentFormatUsageNotSupported,
+ );
+ }
+ }
+
+ if let (Some(depth_format), Some(stencil_format)) =
+ (depth_attachment_format, stencil_attachment_format)
+ {
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06589
+ if depth_format != stencil_format {
+ return Err(
+ GraphicsPipelineCreationError::DepthStencilAttachmentFormatMismatch,
+ );
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ Vertex input state
+ */
+
+ if has.vertex_input_state {
+ // Vertex input state
+ // VUID-VkGraphicsPipelineCreateInfo-pVertexInputState-04910
+ {
+ let VertexInputState {
+ bindings,
+ attributes,
+ } = vertex_input_state;
+
+ // VUID-VkPipelineVertexInputStateCreateInfo-vertexBindingDescriptionCount-00613
+ if bindings.len() > properties.max_vertex_input_bindings as usize {
+ return Err(
+ GraphicsPipelineCreationError::MaxVertexInputBindingsExceeded {
+ max: properties.max_vertex_input_bindings,
+ obtained: bindings.len() as u32,
+ },
+ );
+ }
+
+ // VUID-VkPipelineVertexInputStateCreateInfo-pVertexBindingDescriptions-00616
+ // Ensured by HashMap.
+
+ for (&binding, binding_desc) in bindings {
+ let &VertexInputBindingDescription { stride, input_rate } = binding_desc;
+
+ // VUID-VkVertexInputBindingDescription-binding-00618
+ if binding >= properties.max_vertex_input_bindings {
+ return Err(
+ GraphicsPipelineCreationError::MaxVertexInputBindingsExceeded {
+ max: properties.max_vertex_input_bindings,
+ obtained: binding,
+ },
+ );
+ }
+
+ // VUID-VkVertexInputBindingDescription-stride-00619
+ if stride > properties.max_vertex_input_binding_stride {
+ return Err(
+ GraphicsPipelineCreationError::MaxVertexInputBindingStrideExceeded {
+ binding,
+ max: properties.max_vertex_input_binding_stride,
+ obtained: stride,
+ },
+ );
+ }
+
+ // VUID-VkVertexInputBindingDescription-stride-04456
+ if device.enabled_extensions().khr_portability_subset
+ && (stride == 0
+ || stride
+ % properties
+ .min_vertex_input_binding_stride_alignment
+ .unwrap()
+ != 0)
+ {
+ return Err(GraphicsPipelineCreationError::MinVertexInputBindingStrideAlignmentExceeded {
+ binding,
+ max: properties.min_vertex_input_binding_stride_alignment.unwrap(),
+ obtained: binding,
+ });
+ }
+
+ match input_rate {
+ VertexInputRate::Instance { divisor } if divisor != 1 => {
+ // VUID-VkVertexInputBindingDivisorDescriptionEXT-vertexAttributeInstanceRateDivisor-02229
+ if !device
+ .enabled_features()
+ .vertex_attribute_instance_rate_divisor
+ {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`vertex_input_state.bindings` has an element \
+ where `input_rate` is `VertexInputRate::Instance`, where \
+ `divisor` is not `1`",
+ requires_one_of: RequiresOneOf {
+ features: &["vertex_attribute_instance_rate_divisor"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkVertexInputBindingDivisorDescriptionEXT-vertexAttributeInstanceRateZeroDivisor-02228
+ if divisor == 0
+ && !device
+ .enabled_features()
+ .vertex_attribute_instance_rate_zero_divisor
+ {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`vertex_input_state.bindings` has an element \
+ where `input_rate` is `VertexInputRate::Instance`, where \
+ `divisor` is `0`",
+ requires_one_of: RequiresOneOf {
+ features: &["vertex_attribute_instance_rate_zero_divisor"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkVertexInputBindingDivisorDescriptionEXT-divisor-01870
+ if divisor > properties.max_vertex_attrib_divisor.unwrap() {
+ return Err(
+ GraphicsPipelineCreationError::MaxVertexAttribDivisorExceeded {
+ binding,
+ max: properties.max_vertex_attrib_divisor.unwrap(),
+ obtained: divisor,
+ },
+ );
+ }
+ }
+ _ => (),
+ }
+ }
+
+ // VUID-VkPipelineVertexInputStateCreateInfo-vertexAttributeDescriptionCount-00614
+ if attributes.len() > properties.max_vertex_input_attributes as usize {
+ return Err(
+ GraphicsPipelineCreationError::MaxVertexInputAttributesExceeded {
+ max: properties.max_vertex_input_attributes,
+ obtained: attributes.len(),
+ },
+ );
+ }
+
+ // VUID-VkPipelineVertexInputStateCreateInfo-pVertexAttributeDescriptions-00617
+ // Ensured by HashMap with the exception of formats exceeding a single location.
+ // When a format exceeds a single location the location following it (e.g.
+ // R64B64G64_SFLOAT) needs to be unassigned.
+ let unassigned_locations = attributes
+ .iter()
+ .filter(|&(_, attribute_desc)| attribute_desc.format.block_size().unwrap() > 16)
+ .map(|(location, _)| location + 1);
+ for location in unassigned_locations {
+ if !attributes.get(&location).is_none() {
+ return Err(
+ GraphicsPipelineCreationError::VertexInputAttributeInvalidAssignedLocation {
+ location,
+ },
+ );
+ }
+ }
+
+ for (&location, attribute_desc) in attributes {
+ let &VertexInputAttributeDescription {
+ binding,
+ format,
+ offset,
+ } = attribute_desc;
+
+ // VUID-VkVertexInputAttributeDescription-format-parameter
+ format.validate_device(device)?;
+
+ // TODO:
+ // VUID-VkVertexInputAttributeDescription-location-00620
+
+ // VUID-VkPipelineVertexInputStateCreateInfo-binding-00615
+ let binding_desc = bindings.get(&binding).ok_or(
+ GraphicsPipelineCreationError::VertexInputAttributeInvalidBinding {
+ location,
+ binding,
+ },
+ )?;
+
+ // VUID-VkVertexInputAttributeDescription-offset-00622
+ if offset > properties.max_vertex_input_attribute_offset {
+ return Err(
+ GraphicsPipelineCreationError::MaxVertexInputAttributeOffsetExceeded {
+ max: properties.max_vertex_input_attribute_offset,
+ obtained: offset,
+ },
+ );
+ }
+
+ // Use unchecked, because all validation has been done above.
+ let format_features = unsafe {
+ device
+ .physical_device()
+ .format_properties_unchecked(format)
+ .buffer_features
+ };
+
+ // VUID-VkVertexInputAttributeDescription-format-00623
+ if !format_features.intersects(FormatFeatures::VERTEX_BUFFER) {
+ return Err(
+ GraphicsPipelineCreationError::VertexInputAttributeUnsupportedFormat {
+ location,
+ format,
+ },
+ );
+ }
+
+ // VUID-VkVertexInputAttributeDescription-vertexAttributeAccessBeyondStride-04457
+ if device.enabled_extensions().khr_portability_subset
+ && !device
+ .enabled_features()
+ .vertex_attribute_access_beyond_stride
+ && offset as DeviceSize + format.block_size().unwrap()
+ > binding_desc.stride as DeviceSize
+ {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "this device is a portability subset device, and \
+ `vertex_input_state.attributes` has an element where \
+ `offset + format.block_size()` is greater than the `stride` of \
+ `binding`",
+ requires_one_of: RequiresOneOf {
+ features: &["vertex_attribute_access_beyond_stride"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ }
+
+ // Input assembly state
+ // VUID-VkGraphicsPipelineCreateInfo-pStages-02098
+ {
+ let &InputAssemblyState {
+ topology,
+ primitive_restart_enable,
+ } = input_assembly_state;
+
+ match topology {
+ PartialStateMode::Fixed(topology) => {
+ // VUID-VkPipelineInputAssemblyStateCreateInfo-topology-parameter
+ topology.validate_device(device)?;
+
+ match topology {
+ PrimitiveTopology::TriangleFan => {
+ // VUID-VkPipelineInputAssemblyStateCreateInfo-triangleFans-04452
+ if device.enabled_extensions().khr_portability_subset
+ && !device.enabled_features().triangle_fans
+ {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "this device is a portability subset \
+ device, and `input_assembly_state.topology` is \
+ `StateMode::Fixed(PrimitiveTopology::TriangleFan)`",
+ requires_one_of: RequiresOneOf {
+ features: &["triangle_fans"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ PrimitiveTopology::LineListWithAdjacency
+ | PrimitiveTopology::LineStripWithAdjacency
+ | PrimitiveTopology::TriangleListWithAdjacency
+ | PrimitiveTopology::TriangleStripWithAdjacency => {
+ // VUID-VkPipelineInputAssemblyStateCreateInfo-topology-00429
+ if !device.enabled_features().geometry_shader {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`input_assembly_state.topology` is \
+ `StateMode::Fixed(PrimitiveTopology::*WithAdjacency)`",
+ requires_one_of: RequiresOneOf {
+ features: &["geometry_shader"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ PrimitiveTopology::PatchList => {
+ // VUID-VkPipelineInputAssemblyStateCreateInfo-topology-00430
+ if !device.enabled_features().tessellation_shader {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`input_assembly_state.topology` is \
+ `StateMode::Fixed(PrimitiveTopology::PatchList)`",
+ requires_one_of: RequiresOneOf {
+ features: &["tessellation_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // TODO:
+ // VUID-VkGraphicsPipelineCreateInfo-topology-00737
+ }
+ _ => (),
+ }
+ }
+ PartialStateMode::Dynamic(topology_class) => {
+ // VUID-VkPipelineInputAssemblyStateCreateInfo-topology-parameter
+ topology_class.example().validate_device(device)?;
+
+ // VUID?
+ if !(device.api_version() >= Version::V1_3
+ || device.enabled_features().extended_dynamic_state)
+ {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`input_assembly_state.topology` is \
+ `PartialStateMode::Dynamic`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ }
+
+ match primitive_restart_enable {
+ StateMode::Fixed(primitive_restart_enable) => {
+ if primitive_restart_enable {
+ match topology {
+ PartialStateMode::Fixed(
+ PrimitiveTopology::PointList
+ | PrimitiveTopology::LineList
+ | PrimitiveTopology::TriangleList
+ | PrimitiveTopology::LineListWithAdjacency
+ | PrimitiveTopology::TriangleListWithAdjacency,
+ ) => {
+ // VUID-VkPipelineInputAssemblyStateCreateInfo-topology-06252
+ if !device.enabled_features().primitive_topology_list_restart {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`input_assembly_state.primitive_restart_enable` \
+ is `StateMode::Fixed(true)` and \
+ `input_assembly_state.topology` is \
+ `StateMode::Fixed(PrimitiveTopology::*List)`",
+ requires_one_of: RequiresOneOf {
+ features: &["primitive_topology_list_restart"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ PartialStateMode::Fixed(PrimitiveTopology::PatchList) => {
+ // VUID-VkPipelineInputAssemblyStateCreateInfo-topology-06253
+ if !device
+ .enabled_features()
+ .primitive_topology_patch_list_restart
+ {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`input_assembly_state.primitive_restart_enable` \
+ is `StateMode::Fixed(true)` and \
+ `input_assembly_state.topology` is \
+ `StateMode::Fixed(PrimitiveTopology::PatchList)`",
+ requires_one_of: RequiresOneOf {
+ features: &["primitive_topology_patch_list_restart"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ _ => (),
+ }
+ }
+ }
+ StateMode::Dynamic => {
+ // VUID?
+ if !(device.api_version() >= Version::V1_3
+ || device.enabled_features().extended_dynamic_state2)
+ {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`input_assembly_state.primitive_restart_enable` is \
+ `StateMode::Dynamic`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state2"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ };
+ }
+ }
+
+ /*
+ Pre-rasterization shader state
+ */
+
+ if has.pre_rasterization_shader_state {
+ // Vertex shader
+ if let Some((entry_point, specialization_data)) = vertex_shader {
+ shader_stages.push(ShaderStageInfo {
+ entry_point,
+ specialization_map_entries: Vss::descriptors(),
+ _specialization_data: unsafe {
+ std::slice::from_raw_parts(
+ specialization_data as *const _ as *const u8,
+ size_of_val(specialization_data),
+ )
+ },
+ });
+
+ match entry_point.execution() {
+ ShaderExecution::Vertex => (),
+ _ => return Err(GraphicsPipelineCreationError::WrongShaderType),
+ }
+
+ // VUID?
+ // Check that the vertex input state contains attributes for all the shader's input
+ // variables.
+ for element in entry_point.input_interface().elements() {
+ assert!(!element.ty.is_64bit); // TODO: implement
+ let location_range =
+ element.location..element.location + element.ty.num_locations();
+
+ for location in location_range {
+ let attribute_desc =
+ match vertex_input_state.attributes.get(&location) {
+ Some(attribute_desc) => attribute_desc,
+ None => return Err(
+ GraphicsPipelineCreationError::VertexInputAttributeMissing {
+ location,
+ },
+ ),
+ };
+
+ // TODO: Check component assignments too. Multiple variables can occupy the same
+ // location but in different components.
+
+ let shader_type = element.ty.base_type;
+ let attribute_type = attribute_desc.format.type_color().unwrap();
+
+ if !matches!(
+ (shader_type, attribute_type),
+ (
+ ShaderScalarType::Float,
+ NumericType::SFLOAT
+ | NumericType::UFLOAT
+ | NumericType::SNORM
+ | NumericType::UNORM
+ | NumericType::SSCALED
+ | NumericType::USCALED
+ | NumericType::SRGB,
+ ) | (ShaderScalarType::Sint, NumericType::SINT)
+ | (ShaderScalarType::Uint, NumericType::UINT)
+ ) {
+ return Err(
+ GraphicsPipelineCreationError::VertexInputAttributeIncompatibleFormat {
+ location,
+ shader_type,
+ attribute_type,
+ },
+ );
+ }
+ }
+ }
+
+ // TODO:
+ // VUID-VkPipelineShaderStageCreateInfo-stage-00712
+ } else {
+ // VUID-VkGraphicsPipelineCreateInfo-stage-02096
+ panic!("Missing vertex shader"); // TODO: return error
+ }
+
+ // Tessellation shaders & tessellation state
+ if let Some(tessellation_shaders) = tessellation_shaders {
+ // VUID-VkGraphicsPipelineCreateInfo-pStages-00729
+ // VUID-VkGraphicsPipelineCreateInfo-pStages-00730
+ // Ensured by the definition of TessellationShaders.
+
+ // FIXME: must check that the control shader and evaluation shader are compatible
+
+ // VUID-VkPipelineShaderStageCreateInfo-stage-00705
+ if !device.enabled_features().tessellation_shader {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`tessellation_shaders` are provided",
+ requires_one_of: RequiresOneOf {
+ features: &["tessellation_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ {
+ let (entry_point, specialization_data) = &tessellation_shaders.control;
+
+ shader_stages.push(ShaderStageInfo {
+ entry_point,
+ specialization_map_entries: Tcss::descriptors(),
+ _specialization_data: unsafe {
+ std::slice::from_raw_parts(
+ specialization_data as *const _ as *const u8,
+ size_of_val(specialization_data),
+ )
+ },
+ });
+
+ match entry_point.execution() {
+ ShaderExecution::TessellationControl => (),
+ _ => return Err(GraphicsPipelineCreationError::WrongShaderType),
+ }
+ }
+
+ {
+ let (entry_point, specialization_data) = &tessellation_shaders.evaluation;
+
+ shader_stages.push(ShaderStageInfo {
+ entry_point,
+ specialization_map_entries: Tess::descriptors(),
+ _specialization_data: unsafe {
+ std::slice::from_raw_parts(
+ specialization_data as *const _ as *const u8,
+ size_of_val(specialization_data),
+ )
+ },
+ });
+
+ match entry_point.execution() {
+ ShaderExecution::TessellationEvaluation => (),
+ _ => return Err(GraphicsPipelineCreationError::WrongShaderType),
+ }
+ }
+
+ if !device.enabled_features().multiview_tessellation_shader {
+ let view_mask = match render_pass {
+ PipelineRenderPassType::BeginRenderPass(subpass) => {
+ subpass.render_pass().views_used()
+ }
+ PipelineRenderPassType::BeginRendering(rendering_info) => {
+ rendering_info.view_mask
+ }
+ };
+
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06047
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06057
+ if view_mask != 0 {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`tessellation_shaders` are provided and `render_pass` \
+ has a subpass where `view_mask` is not `0`",
+ requires_one_of: RequiresOneOf {
+ features: &["multiview_tessellation_shader"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+
+ // TODO:
+ // VUID-VkPipelineShaderStageCreateInfo-stage-00713
+ // VUID-VkGraphicsPipelineCreateInfo-pStages-00732
+ // VUID-VkGraphicsPipelineCreateInfo-pStages-00733
+ // VUID-VkGraphicsPipelineCreateInfo-pStages-00734
+ // VUID-VkGraphicsPipelineCreateInfo-pStages-00735
+ }
+
+ // Geometry shader
+ if let Some((entry_point, specialization_data)) = geometry_shader {
+ shader_stages.push(ShaderStageInfo {
+ entry_point,
+ specialization_map_entries: Gss::descriptors(),
+ _specialization_data: unsafe {
+ std::slice::from_raw_parts(
+ specialization_data as *const _ as *const u8,
+ size_of_val(specialization_data),
+ )
+ },
+ });
+
+ // VUID-VkPipelineShaderStageCreateInfo-stage-00704
+ if !device.enabled_features().geometry_shader {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`geometry_shader` is provided",
+ requires_one_of: RequiresOneOf {
+ features: &["geometry_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ let input = match entry_point.execution() {
+ ShaderExecution::Geometry(execution) => execution.input,
+ _ => return Err(GraphicsPipelineCreationError::WrongShaderType),
+ };
+
+ if let PartialStateMode::Fixed(topology) = input_assembly_state.topology {
+ // VUID-VkGraphicsPipelineCreateInfo-pStages-00738
+ if !input.is_compatible_with(topology) {
+ return Err(
+ GraphicsPipelineCreationError::TopologyNotMatchingGeometryShader,
+ );
+ }
+ }
+
+ if !device.enabled_features().multiview_geometry_shader {
+ let view_mask = match render_pass {
+ PipelineRenderPassType::BeginRenderPass(subpass) => {
+ subpass.render_pass().views_used()
+ }
+ PipelineRenderPassType::BeginRendering(rendering_info) => {
+ rendering_info.view_mask
+ }
+ };
+
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06048
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06058
+ if view_mask != 0 {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`geometry_shader` is provided and `render_pass` has a \
+ subpass where `view_mask` is not `0`",
+ requires_one_of: RequiresOneOf {
+ features: &["multiview_geometry_shader"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+
+ // TODO:
+ // VUID-VkPipelineShaderStageCreateInfo-stage-00714
+ // VUID-VkPipelineShaderStageCreateInfo-stage-00715
+ // VUID-VkGraphicsPipelineCreateInfo-pStages-00739
+ }
+
+ // Rasterization state
+ // VUID?
+ {
+ let &RasterizationState {
+ depth_clamp_enable,
+ rasterizer_discard_enable,
+ polygon_mode,
+ cull_mode,
+ front_face,
+ depth_bias,
+ line_width,
+ line_rasterization_mode,
+ line_stipple,
+ } = rasterization_state;
+
+ // VUID-VkPipelineRasterizationStateCreateInfo-polygonMode-parameter
+ polygon_mode.validate_device(device)?;
+
+ // VUID-VkPipelineRasterizationStateCreateInfo-depthClampEnable-00782
+ if depth_clamp_enable && !device.enabled_features().depth_clamp {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`rasterization_state.depth_clamp_enable` is set",
+ requires_one_of: RequiresOneOf {
+ features: &["depth_clamp"],
+ ..Default::default()
+ },
+ });
+ }
+
+ match rasterizer_discard_enable {
+ StateMode::Dynamic => {
+ // VUID?
+ if !(device.api_version() >= Version::V1_3
+ || device.enabled_features().extended_dynamic_state2)
+ {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`rasterization_state.rasterizer_discard_enable` is \
+ `StateMode::Dynamic`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ StateMode::Fixed(false) => {
+ // VUID-VkPipelineRasterizationStateCreateInfo-pointPolygons-04458
+ if device.enabled_extensions().khr_portability_subset
+ && !device.enabled_features().point_polygons
+ && polygon_mode == PolygonMode::Point
+ {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "this device is a portability subset device, \
+ `rasterization_state.rasterizer_discard_enable` is \
+ `StateMode::Fixed(false)` and \
+ `rasterization_state.polygon_mode` is `PolygonMode::Point`",
+ requires_one_of: RequiresOneOf {
+ features: &["point_polygons"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ _ => (),
+ }
+
+ // VUID-VkPipelineRasterizationStateCreateInfo-polygonMode-01507
+ if polygon_mode != PolygonMode::Fill
+ && !device.enabled_features().fill_mode_non_solid
+ {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`rasterization_state.polygon_mode` is not \
+ `PolygonMode::Fill`",
+ requires_one_of: RequiresOneOf {
+ features: &["fill_mode_non_solid"],
+ ..Default::default()
+ },
+ });
+ }
+
+ match cull_mode {
+ StateMode::Fixed(cull_mode) => {
+ // VUID-VkPipelineRasterizationStateCreateInfo-cullMode-parameter
+ cull_mode.validate_device(device)?;
+ }
+ StateMode::Dynamic => {
+ // VUID?
+ if !(device.api_version() >= Version::V1_3
+ || device.enabled_features().extended_dynamic_state)
+ {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`rasterization_state.cull_mode` is \
+ `StateMode::Dynamic`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ }
+
+ match front_face {
+ StateMode::Fixed(front_face) => {
+ // VUID-VkPipelineRasterizationStateCreateInfo-frontFace-parameter
+ front_face.validate_device(device)?;
+ }
+ StateMode::Dynamic => {
+ // VUID?
+ if !(device.api_version() >= Version::V1_3
+ || device.enabled_features().extended_dynamic_state)
+ {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`rasterization_state.front_face` is \
+ `StateMode::Dynamic`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ }
+
+ if let Some(depth_bias_state) = depth_bias {
+ let DepthBiasState {
+ enable_dynamic,
+ bias,
+ } = depth_bias_state;
+
+ // VUID?
+ if enable_dynamic
+ && !(device.api_version() >= Version::V1_3
+ || device.enabled_features().extended_dynamic_state2)
+ {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`rasterization_state.depth_bias` is \
+ `Some(depth_bias_state)`, where `depth_bias_state.enable_dynamic` \
+ is set",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state2"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-00754
+ if matches!(bias, StateMode::Fixed(bias) if bias.clamp != 0.0)
+ && !device.enabled_features().depth_bias_clamp
+ {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`rasterization_state.depth_bias` is \
+ `Some(depth_bias_state)`, where `depth_bias_state.bias` is \
+ `StateMode::Fixed(bias)`, where `bias.clamp` is not `0.0`",
+ requires_one_of: RequiresOneOf {
+ features: &["depth_bias_clamp"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+
+ // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-00749
+ if matches!(line_width, StateMode::Fixed(line_width) if line_width != 1.0)
+ && !device.enabled_features().wide_lines
+ {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`rasterization_state.line_width` is \
+ `StateMode::Fixed(line_width)`, where `line_width` is not `1.0`",
+ requires_one_of: RequiresOneOf {
+ features: &["wide_lines"],
+ ..Default::default()
+ },
+ });
+ }
+
+ if device.enabled_extensions().ext_line_rasterization {
+ // VUID-VkPipelineRasterizationLineStateCreateInfoEXT-lineRasterizationMode-parameter
+ line_rasterization_mode.validate_device(device)?;
+
+ match line_rasterization_mode {
+ LineRasterizationMode::Default => (),
+ LineRasterizationMode::Rectangular => {
+ // VUID-VkPipelineRasterizationLineStateCreateInfoEXT-lineRasterizationMode-02768
+ if !device.enabled_features().rectangular_lines {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`rasterization_state.line_rasterization_mode` \
+ is `LineRasterizationMode::Rectangular`",
+ requires_one_of: RequiresOneOf {
+ features: &["rectangular_lines"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ LineRasterizationMode::Bresenham => {
+ // VUID-VkPipelineRasterizationLineStateCreateInfoEXT-lineRasterizationMode-02769
+ if !device.enabled_features().bresenham_lines {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`rasterization_state.line_rasterization_mode` \
+ is `LineRasterizationMode::Bresenham`",
+ requires_one_of: RequiresOneOf {
+ features: &["bresenham_lines"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ LineRasterizationMode::RectangularSmooth => {
+ // VUID-VkPipelineRasterizationLineStateCreateInfoEXT-lineRasterizationMode-02770
+ if !device.enabled_features().smooth_lines {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`rasterization_state.line_rasterization_mode` \
+ is `LineRasterizationMode::RectangularSmooth`",
+ requires_one_of: RequiresOneOf {
+ features: &["smooth_lines"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ }
+
+ if let Some(line_stipple) = line_stipple {
+ match line_rasterization_mode {
+ LineRasterizationMode::Default => {
+ // VUID-VkPipelineRasterizationLineStateCreateInfoEXT-stippledLineEnable-02774
+ if !device.enabled_features().stippled_rectangular_lines {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`rasterization_state.line_stipple` is \
+ `Some` and \
+ `rasterization_state.line_rasterization_mode` \
+ is `LineRasterizationMode::Default`",
+ requires_one_of: RequiresOneOf {
+ features: &["stippled_rectangular_lines"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkPipelineRasterizationLineStateCreateInfoEXT-stippledLineEnable-02774
+ if !properties.strict_lines {
+ return Err(
+ GraphicsPipelineCreationError::StrictLinesNotSupported,
+ );
+ }
+ }
+ LineRasterizationMode::Rectangular => {
+ // VUID-VkPipelineRasterizationLineStateCreateInfoEXT-stippledLineEnable-02771
+ if !device.enabled_features().stippled_rectangular_lines {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`rasterization_state.line_stipple` is \
+ `Some` and \
+ `rasterization_state.line_rasterization_mode` \
+ is `LineRasterizationMode::Rectangular`",
+ requires_one_of: RequiresOneOf {
+ features: &["stippled_rectangular_lines"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ LineRasterizationMode::Bresenham => {
+ // VUID-VkPipelineRasterizationLineStateCreateInfoEXT-stippledLineEnable-02772
+ if !device.enabled_features().stippled_bresenham_lines {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`rasterization_state.line_stipple` is \
+ `Some` and \
+ `rasterization_state.line_rasterization_mode` \
+ is `LineRasterizationMode::Bresenham`",
+ requires_one_of: RequiresOneOf {
+ features: &["stippled_bresenham_lines"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ LineRasterizationMode::RectangularSmooth => {
+ // VUID-VkPipelineRasterizationLineStateCreateInfoEXT-stippledLineEnable-02773
+ if !device.enabled_features().stippled_smooth_lines {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`rasterization_state.line_stipple` is \
+ `Some` and \
+ `rasterization_state.line_rasterization_mode` \
+ is `LineRasterizationMode::RectangularSmooth`",
+ requires_one_of: RequiresOneOf {
+ features: &["stippled_smooth_lines"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ }
+
+ if let StateMode::Fixed(line_stipple) = line_stipple {
+ // VUID-VkGraphicsPipelineCreateInfo-stippledLineEnable-02767
+ assert!(line_stipple.factor >= 1 && line_stipple.factor <= 256);
+ // TODO: return error?
+ }
+ }
+ } else {
+ if line_rasterization_mode != LineRasterizationMode::Default {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`rasterization_state.line_rasterization_mode` is not \
+ `LineRasterizationMode::Default`",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["ext_line_rasterization"],
+ ..Default::default()
+ },
+ });
+ }
+
+ if line_stipple.is_some() {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`rasterization_state.line_stipple` is `Some`",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["ext_line_rasterization"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ }
+
+ // Discard rectangle state
+ {
+ let DiscardRectangleState { mode, rectangles } = discard_rectangle_state;
+
+ if device.enabled_extensions().ext_discard_rectangles {
+ // VUID-VkPipelineDiscardRectangleStateCreateInfoEXT-discardRectangleMode-parameter
+ mode.validate_device(device)?;
+
+ let discard_rectangle_count = match rectangles {
+ PartialStateMode::Dynamic(count) => *count,
+ PartialStateMode::Fixed(rectangles) => rectangles.len() as u32,
+ };
+
+ // VUID-VkPipelineDiscardRectangleStateCreateInfoEXT-discardRectangleCount-00582
+ if discard_rectangle_count > properties.max_discard_rectangles.unwrap() {
+ return Err(
+ GraphicsPipelineCreationError::MaxDiscardRectanglesExceeded {
+ max: properties.max_discard_rectangles.unwrap(),
+ obtained: discard_rectangle_count,
+ },
+ );
+ }
+ } else {
+ let error = match rectangles {
+ PartialStateMode::Dynamic(_) => true,
+ PartialStateMode::Fixed(rectangles) => !rectangles.is_empty(),
+ };
+
+ if error {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`discard_rectangle_state.rectangles` is not \
+ `PartialStateMode::Fixed(vec![])`",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["ext_discard_rectangles"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ }
+
+ // TODO:
+ // VUID-VkPipelineShaderStageCreateInfo-stage-02596
+ // VUID-VkPipelineShaderStageCreateInfo-stage-02597
+ // VUID-VkGraphicsPipelineCreateInfo-pStages-00740
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06049
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06050
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06059
+ }
+
+ // VUID-VkGraphicsPipelineCreateInfo-pStages-00731
+ if has.tessellation_state {
+ let &TessellationState {
+ patch_control_points,
+ } = tessellation_state;
+
+ // VUID-VkGraphicsPipelineCreateInfo-pStages-00736
+ if !matches!(
+ input_assembly_state.topology,
+ PartialStateMode::Dynamic(PrimitiveTopologyClass::Patch)
+ | PartialStateMode::Fixed(PrimitiveTopology::PatchList)
+ ) {
+ return Err(GraphicsPipelineCreationError::InvalidPrimitiveTopology);
+ }
+
+ match patch_control_points {
+ StateMode::Fixed(patch_control_points) => {
+ // VUID-VkPipelineTessellationStateCreateInfo-patchControlPoints-01214
+ if patch_control_points == 0
+ || patch_control_points > properties.max_tessellation_patch_size
+ {
+ return Err(GraphicsPipelineCreationError::InvalidNumPatchControlPoints);
+ }
+ }
+ StateMode::Dynamic => {
+ // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-04870
+ if !device
+ .enabled_features()
+ .extended_dynamic_state2_patch_control_points
+ {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`tessellation_state.patch_control_points` is \
+ `StateMode::Dynamic`",
+ requires_one_of: RequiresOneOf {
+ features: &["extended_dynamic_state2_patch_control_points"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ };
+ }
+
+ // Viewport state
+ // VUID-VkGraphicsPipelineCreateInfo-rasterizerDiscardEnable-00750
+ // VUID-VkGraphicsPipelineCreateInfo-pViewportState-04892
+ if has.viewport_state {
+ let (viewport_count, scissor_count) = match viewport_state {
+ ViewportState::Fixed { data } => {
+ let count = data.len() as u32;
+ assert!(count != 0); // TODO: return error?
+
+ for (viewport, _) in data {
+ for i in 0..2 {
+ if viewport.dimensions[i] > properties.max_viewport_dimensions[i] as f32
+ {
+ return Err(
+ GraphicsPipelineCreationError::MaxViewportDimensionsExceeded,
+ );
+ }
+
+ if viewport.origin[i] < properties.viewport_bounds_range[0]
+ || viewport.origin[i] + viewport.dimensions[i]
+ > properties.viewport_bounds_range[1]
+ {
+ return Err(GraphicsPipelineCreationError::ViewportBoundsExceeded);
+ }
+ }
+ }
+
+ // TODO:
+ // VUID-VkPipelineViewportStateCreateInfo-offset-02822
+ // VUID-VkPipelineViewportStateCreateInfo-offset-02823
+
+ (count, count)
+ }
+ ViewportState::FixedViewport {
+ viewports,
+ scissor_count_dynamic,
+ } => {
+ let viewport_count = viewports.len() as u32;
+
+ // VUID-VkPipelineViewportStateCreateInfo-scissorCount-04136
+ assert!(viewport_count != 0); // TODO: return error?
+
+ for viewport in viewports {
+ for i in 0..2 {
+ if viewport.dimensions[i] > properties.max_viewport_dimensions[i] as f32
+ {
+ return Err(
+ GraphicsPipelineCreationError::MaxViewportDimensionsExceeded,
+ );
+ }
+
+ if viewport.origin[i] < properties.viewport_bounds_range[0]
+ || viewport.origin[i] + viewport.dimensions[i]
+ > properties.viewport_bounds_range[1]
+ {
+ return Err(GraphicsPipelineCreationError::ViewportBoundsExceeded);
+ }
+ }
+ }
+
+ // VUID-VkPipelineViewportStateCreateInfo-scissorCount-04136
+ let scissor_count = if *scissor_count_dynamic {
+ if !(device.api_version() >= Version::V1_3
+ || device.enabled_features().extended_dynamic_state)
+ {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`viewport_state` is \
+ `ViewportState::FixedViewport`, where `scissor_count_dynamic` \
+ is set",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-03380
+ 0
+ } else {
+ viewport_count
+ };
+
+ (viewport_count, scissor_count)
+ }
+ ViewportState::FixedScissor {
+ scissors,
+ viewport_count_dynamic,
+ } => {
+ let scissor_count = scissors.len() as u32;
+
+ // VUID-VkPipelineViewportStateCreateInfo-viewportCount-04135
+ assert!(scissor_count != 0); // TODO: return error?
+
+ // VUID-VkPipelineViewportStateCreateInfo-viewportCount-04135
+ let viewport_count = if *viewport_count_dynamic {
+ if !(device.api_version() >= Version::V1_3
+ || device.enabled_features().extended_dynamic_state)
+ {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`viewport_state` is \
+ `ViewportState::FixedScissor`, where `viewport_count_dynamic` \
+ is set",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-03379
+ 0
+ } else {
+ scissor_count
+ };
+
+ // TODO:
+ // VUID-VkPipelineViewportStateCreateInfo-offset-02822
+ // VUID-VkPipelineViewportStateCreateInfo-offset-02823
+
+ (viewport_count, scissor_count)
+ }
+ &ViewportState::Dynamic {
+ count,
+ viewport_count_dynamic,
+ scissor_count_dynamic,
+ } => {
+ // VUID-VkPipelineViewportStateCreateInfo-viewportCount-04135
+ // VUID-VkPipelineViewportStateCreateInfo-scissorCount-04136
+ if !(viewport_count_dynamic && scissor_count_dynamic) {
+ assert!(count != 0); // TODO: return error?
+ }
+
+ // VUID-VkPipelineViewportStateCreateInfo-viewportCount-04135
+ let viewport_count = if viewport_count_dynamic {
+ if !(device.api_version() >= Version::V1_3
+ || device.enabled_features().extended_dynamic_state)
+ {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`viewport_state` is \
+ `ViewportState::Dynamic`, where `viewport_count_dynamic` \
+ is set",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-03379
+ 0
+ } else {
+ count
+ };
+
+ // VUID-VkPipelineViewportStateCreateInfo-scissorCount-04136
+ let scissor_count = if scissor_count_dynamic {
+ if !(device.api_version() >= Version::V1_3
+ || device.enabled_features().extended_dynamic_state)
+ {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`viewport_state` is \
+ `ViewportState::Dynamic`, where `scissor_count_dynamic` \
+ is set",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-03380
+ 0
+ } else {
+ count
+ };
+
+ (viewport_count, scissor_count)
+ }
+ };
+
+ // VUID-VkPipelineViewportStateCreateInfo-scissorCount-04134
+ // Ensured by the definition of `ViewportState`.
+
+ let viewport_scissor_count = u32::max(viewport_count, scissor_count);
+
+ // VUID-VkPipelineViewportStateCreateInfo-viewportCount-01216
+ // VUID-VkPipelineViewportStateCreateInfo-scissorCount-01217
+ if viewport_scissor_count > 1 && !device.enabled_features().multi_viewport {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`viewport_state` has a fixed viewport/scissor count that is \
+ greater than `1`",
+ requires_one_of: RequiresOneOf {
+ features: &["multi_viewport"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkPipelineViewportStateCreateInfo-viewportCount-01218
+ // VUID-VkPipelineViewportStateCreateInfo-scissorCount-01219
+ if viewport_scissor_count > properties.max_viewports {
+ return Err(GraphicsPipelineCreationError::MaxViewportsExceeded {
+ obtained: viewport_scissor_count,
+ max: properties.max_viewports,
+ });
+ }
+
+ // TODO:
+ // VUID-VkGraphicsPipelineCreateInfo-primitiveFragmentShadingRateWithMultipleViewports-04503
+ // VUID-VkGraphicsPipelineCreateInfo-primitiveFragmentShadingRateWithMultipleViewports-04504
+ }
+
+ /*
+ Fragment shader state
+ */
+
+ if has.fragment_shader_state {
+ // Fragment shader
+ if let Some((entry_point, specialization_data)) = fragment_shader {
+ shader_stages.push(ShaderStageInfo {
+ entry_point,
+ specialization_map_entries: Fss::descriptors(),
+ _specialization_data: unsafe {
+ std::slice::from_raw_parts(
+ specialization_data as *const _ as *const u8,
+ size_of_val(specialization_data),
+ )
+ },
+ });
+
+ match entry_point.execution() {
+ ShaderExecution::Fragment(_) => (),
+ _ => return Err(GraphicsPipelineCreationError::WrongShaderType),
+ }
+
+ // Check that the subpass can accept the output of the fragment shader.
+ match render_pass {
+ PipelineRenderPassType::BeginRenderPass(subpass) => {
+ if !subpass.is_compatible_with(entry_point.output_interface()) {
+ return Err(
+ GraphicsPipelineCreationError::FragmentShaderRenderPassIncompatible,
+ );
+ }
+ }
+ PipelineRenderPassType::BeginRendering(_) => {
+ // TODO:
+ }
+ }
+
+ // TODO:
+ // VUID-VkPipelineShaderStageCreateInfo-stage-00718
+ // VUID-VkPipelineShaderStageCreateInfo-stage-06685
+ // VUID-VkPipelineShaderStageCreateInfo-stage-06686
+ // VUID-VkGraphicsPipelineCreateInfo-pStages-01565
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06056
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06061
+ } else {
+ // TODO: should probably error out here at least under some circumstances?
+ // VUID?
+ }
+
+ // TODO:
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06038
+ }
+
+ // Depth/stencil state
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06043
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06053
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06590
+ if has.depth_stencil_state {
+ let DepthStencilState {
+ depth,
+ depth_bounds,
+ stencil,
+ } = depth_stencil_state;
+
+ if let Some(depth_state) = depth {
+ let &DepthState {
+ enable_dynamic,
+ write_enable,
+ compare_op,
+ } = depth_state;
+
+ let has_depth_attachment = match render_pass {
+ PipelineRenderPassType::BeginRenderPass(subpass) => subpass.has_depth(),
+ PipelineRenderPassType::BeginRendering(rendering_info) => {
+ rendering_info.depth_attachment_format.is_some()
+ }
+ };
+
+ // VUID?
+ if !has_depth_attachment {
+ return Err(GraphicsPipelineCreationError::NoDepthAttachment);
+ }
+
+ // VUID?
+ if enable_dynamic
+ && !(device.api_version() >= Version::V1_3
+ || device.enabled_features().extended_dynamic_state)
+ {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`depth_stencil_state.depth` is `Some(depth_state)`, where \
+ `depth_state.enable_dynamic` is set",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+
+ match write_enable {
+ StateMode::Fixed(write_enable) => {
+ match render_pass {
+ PipelineRenderPassType::BeginRenderPass(subpass) => {
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06039
+ if write_enable && !subpass.has_writable_depth() {
+ return Err(GraphicsPipelineCreationError::NoDepthAttachment);
+ }
+ }
+ PipelineRenderPassType::BeginRendering(_) => {
+ // No VUID?
+ }
+ }
+ }
+ StateMode::Dynamic => {
+ // VUID?
+ if !(device.api_version() >= Version::V1_3
+ || device.enabled_features().extended_dynamic_state)
+ {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`depth_stencil_state.depth` is \
+ `Some(depth_state)`, where `depth_state.write_enable` is \
+ `StateMode::Dynamic`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ }
+
+ match compare_op {
+ StateMode::Fixed(compare_op) => {
+ // VUID-VkPipelineDepthStencilStateCreateInfo-depthCompareOp-parameter
+ compare_op.validate_device(device)?;
+ }
+ StateMode::Dynamic => {
+ // VUID?
+ if !(device.api_version() >= Version::V1_3
+ || device.enabled_features().extended_dynamic_state)
+ {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`depth_stencil_state.depth` is \
+ `Some(depth_state)`, where `depth_state.compare_op` is \
+ `StateMode::Dynamic`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ }
+ }
+
+ if let Some(depth_bounds_state) = depth_bounds {
+ let DepthBoundsState {
+ enable_dynamic,
+ bounds,
+ } = depth_bounds_state;
+
+ // VUID-VkPipelineDepthStencilStateCreateInfo-depthBoundsTestEnable-00598
+ if !device.enabled_features().depth_bounds {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`depth_stencil_state.depth_bounds` is `Some`",
+ requires_one_of: RequiresOneOf {
+ features: &["depth_bounds"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID?
+ if *enable_dynamic
+ && !(device.api_version() >= Version::V1_3
+ || device.enabled_features().extended_dynamic_state)
+ {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`depth_stencil_state.depth_bounds` is \
+ `Some(depth_bounds_state)`, where `depth_bounds_state.enable_dynamic` \
+ is set",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+
+ if let StateMode::Fixed(bounds) = bounds {
+ // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-02510
+ if !device.enabled_extensions().ext_depth_range_unrestricted
+ && !(0.0..1.0).contains(bounds.start())
+ && !(0.0..1.0).contains(bounds.end())
+ {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`depth_stencil_state.depth_bounds` is \
+ `Some(depth_bounds_state)`, where `depth_bounds_state.bounds` is \
+ not between `0.0` and `1.0` inclusive",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["ext_depth_range_unrestricted"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ }
+
+ if let Some(stencil_state) = stencil {
+ let StencilState {
+ enable_dynamic,
+ front,
+ back,
+ } = stencil_state;
+
+ let has_stencil_attachment = match render_pass {
+ PipelineRenderPassType::BeginRenderPass(subpass) => subpass.has_stencil(),
+ PipelineRenderPassType::BeginRendering(rendering_info) => {
+ rendering_info.stencil_attachment_format.is_some()
+ }
+ };
+
+ if !has_stencil_attachment {
+ return Err(GraphicsPipelineCreationError::NoStencilAttachment);
+ }
+
+ // VUID?
+ if *enable_dynamic
+ && !(device.api_version() >= Version::V1_3
+ || device.enabled_features().extended_dynamic_state)
+ {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`depth_stencil_state.stencil` is `Some(stencil_state)`, \
+ where `stencil_state.enable_dynamic` is set",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+
+ match (front.ops, back.ops) {
+ (StateMode::Fixed(front_ops), StateMode::Fixed(back_ops)) => {
+ for ops in [front_ops, back_ops] {
+ let StencilOps {
+ fail_op,
+ pass_op,
+ depth_fail_op,
+ compare_op,
+ } = ops;
+
+ // VUID-VkStencilOpState-failOp-parameter
+ fail_op.validate_device(device)?;
+
+ // VUID-VkStencilOpState-passOp-parameter
+ pass_op.validate_device(device)?;
+
+ // VUID-VkStencilOpState-depthFailOp-parameter
+ depth_fail_op.validate_device(device)?;
+
+ // VUID-VkStencilOpState-compareOp-parameter
+ compare_op.validate_device(device)?;
+ }
+ }
+ (StateMode::Dynamic, StateMode::Dynamic) => {
+ // VUID?
+ if !(device.api_version() >= Version::V1_3
+ || device.enabled_features().extended_dynamic_state)
+ {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`depth_stencil_state.stencil` is \
+ `Some(stencil_state)`, where `stencil_state.front.ops` and \
+ `stencil_state.back.ops` are `StateMode::Dynamic`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_3),
+ features: &["extended_dynamic_state"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ _ => return Err(GraphicsPipelineCreationError::WrongStencilState),
+ }
+
+ if !matches!(
+ (front.compare_mask, back.compare_mask),
+ (StateMode::Fixed(_), StateMode::Fixed(_))
+ | (StateMode::Dynamic, StateMode::Dynamic)
+ ) {
+ return Err(GraphicsPipelineCreationError::WrongStencilState);
+ }
+
+ if !matches!(
+ (front.write_mask, back.write_mask),
+ (StateMode::Fixed(_), StateMode::Fixed(_))
+ | (StateMode::Dynamic, StateMode::Dynamic)
+ ) {
+ return Err(GraphicsPipelineCreationError::WrongStencilState);
+ }
+
+ match (front.reference, back.reference) {
+ (StateMode::Fixed(front_reference), StateMode::Fixed(back_reference)) => {
+ // VUID-VkPipelineDepthStencilStateCreateInfo-separateStencilMaskRef-04453
+ if device.enabled_extensions().khr_portability_subset
+ && !device.enabled_features().separate_stencil_mask_ref
+ && matches!(
+ rasterization_state.cull_mode,
+ StateMode::Fixed(CullMode::None)
+ )
+ && front_reference != back_reference
+ {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "this device is a portability subset device, \
+ `rasterization_state.cull_mode` is \
+ `StateMode::Fixed(CullMode::None)`, and \
+ `depth_stencil_state.stencil` is `Some(stencil_state)`, \
+ where `stencil_state.front.reference` does not equal \
+ `stencil_state.back.reference`",
+ requires_one_of: RequiresOneOf {
+ features: &["separate_stencil_mask_ref"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ (StateMode::Dynamic, StateMode::Dynamic) => (),
+ _ => return Err(GraphicsPipelineCreationError::WrongStencilState),
+ }
+
+ // TODO:
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06040
+ }
+ }
+
+ /*
+ Fragment output state
+ */
+
+ if has.fragment_output_state {
+ // Multisample state
+ // VUID-VkGraphicsPipelineCreateInfo-rasterizerDiscardEnable-00751
+ {
+ let &MultisampleState {
+ rasterization_samples,
+ sample_shading,
+ sample_mask: _,
+ alpha_to_coverage_enable: _,
+ alpha_to_one_enable,
+ } = multisample_state;
+
+ // VUID-VkPipelineMultisampleStateCreateInfo-rasterizationSamples-parameter
+ rasterization_samples.validate_device(device)?;
+
+ match render_pass {
+ PipelineRenderPassType::BeginRenderPass(subpass) => {
+ if let Some(samples) = subpass.num_samples() {
+ // VUID-VkGraphicsPipelineCreateInfo-subpass-00757
+ if rasterization_samples != samples {
+ return Err(GraphicsPipelineCreationError::MultisampleRasterizationSamplesMismatch);
+ }
+ }
+
+ // TODO:
+ // VUID-VkGraphicsPipelineCreateInfo-subpass-00758
+ // VUID-VkGraphicsPipelineCreateInfo-subpass-01505
+ // VUID-VkGraphicsPipelineCreateInfo-subpass-01411
+ // VUID-VkGraphicsPipelineCreateInfo-subpass-01412
+ }
+ PipelineRenderPassType::BeginRendering(_) => {
+ // No equivalent VUIDs for dynamic rendering, as no sample count information
+ // is provided until `begin_rendering`.
+ }
+ }
+
+ if let Some(min_sample_shading) = sample_shading {
+ // VUID-VkPipelineMultisampleStateCreateInfo-sampleShadingEnable-00784
+ if !device.enabled_features().sample_rate_shading {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`multisample_state.sample_shading` is `Some`",
+ requires_one_of: RequiresOneOf {
+ features: &["sample_rate_shading"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkPipelineMultisampleStateCreateInfo-minSampleShading-00786
+ // TODO: return error?
+ assert!((0.0..=1.0).contains(&min_sample_shading));
+ }
+
+ // VUID-VkPipelineMultisampleStateCreateInfo-alphaToOneEnable-00785
+ if alpha_to_one_enable && !device.enabled_features().alpha_to_one {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`multisample_state.alpha_to_one_enable` is set",
+ requires_one_of: RequiresOneOf {
+ features: &["alpha_to_one"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // TODO:
+ // VUID-VkGraphicsPipelineCreateInfo-lineRasterizationMode-02766
+ }
+ }
+
+ // Color blend state
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06044
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06054
+ if has.color_blend_state {
+ let ColorBlendState {
+ logic_op,
+ attachments,
+ blend_constants: _,
+ } = color_blend_state;
+
+ if let Some(logic_op) = logic_op {
+ // VUID-VkPipelineColorBlendStateCreateInfo-logicOpEnable-00606
+ if !device.enabled_features().logic_op {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`color_blend_state.logic_op` is `Some`",
+ requires_one_of: RequiresOneOf {
+ features: &["logic_op"],
+ ..Default::default()
+ },
+ });
+ }
+
+ match logic_op {
+ StateMode::Fixed(logic_op) => {
+ // VUID-VkPipelineColorBlendStateCreateInfo-logicOpEnable-00607
+ logic_op.validate_device(device)?
+ }
+ StateMode::Dynamic => {
+ // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-04869
+ if !device.enabled_features().extended_dynamic_state2_logic_op {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`color_blend_state.logic_op` is \
+ `Some(StateMode::Dynamic)`",
+ requires_one_of: RequiresOneOf {
+ features: &["extended_dynamic_state2_logic_op"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ }
+ }
+
+ let color_attachment_count = match render_pass {
+ PipelineRenderPassType::BeginRenderPass(subpass) => {
+ subpass.subpass_desc().color_attachments.len()
+ }
+ PipelineRenderPassType::BeginRendering(rendering_info) => {
+ rendering_info.color_attachment_formats.len()
+ }
+ };
+
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06042
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06055
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06060
+ if color_attachment_count != attachments.len() {
+ return Err(GraphicsPipelineCreationError::MismatchBlendingAttachmentsCount);
+ }
+
+ if attachments.len() > 1 && !device.enabled_features().independent_blend {
+ // Ensure that all `blend` and `color_write_mask` are identical.
+ let mut iter = attachments
+ .iter()
+ .map(|state| (&state.blend, &state.color_write_mask));
+ let first = iter.next().unwrap();
+
+ // VUID-VkPipelineColorBlendStateCreateInfo-pAttachments-00605
+ if !iter.all(|state| state == first) {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`color_blend_state.attachments` has elements where \
+ `blend` and `color_write_mask` do not match the other elements",
+ requires_one_of: RequiresOneOf {
+ features: &["independent_blend"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+
+ for (attachment_index, state) in attachments.iter().enumerate() {
+ let &ColorBlendAttachmentState {
+ blend,
+ color_write_mask: _,
+ color_write_enable,
+ } = state;
+
+ if let Some(blend) = blend {
+ let AttachmentBlend {
+ color_op,
+ color_source,
+ color_destination,
+ alpha_op,
+ alpha_source,
+ alpha_destination,
+ } = blend;
+
+ // VUID-VkPipelineColorBlendAttachmentState-colorBlendOp-parameter
+ color_op.validate_device(device)?;
+
+ // VUID-VkPipelineColorBlendAttachmentState-srcColorBlendFactor-parameter
+ color_source.validate_device(device)?;
+
+ // VUID-VkPipelineColorBlendAttachmentState-dstColorBlendFactor-parameter
+ color_destination.validate_device(device)?;
+
+ // VUID-VkPipelineColorBlendAttachmentState-alphaBlendOp-parameter
+ alpha_op.validate_device(device)?;
+
+ // VUID-VkPipelineColorBlendAttachmentState-srcAlphaBlendFactor-parameter
+ alpha_source.validate_device(device)?;
+
+ // VUID-VkPipelineColorBlendAttachmentState-dstAlphaBlendFactor-parameter
+ alpha_destination.validate_device(device)?;
+
+ // VUID?
+ if !device.enabled_features().dual_src_blend
+ && [
+ color_source,
+ color_destination,
+ alpha_source,
+ alpha_destination,
+ ]
+ .into_iter()
+ .any(|blend_factor| {
+ matches!(
+ blend_factor,
+ BlendFactor::Src1Color
+ | BlendFactor::OneMinusSrc1Color
+ | BlendFactor::Src1Alpha
+ | BlendFactor::OneMinusSrc1Alpha
+ )
+ })
+ {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`color_blend_state.attachments` has an element where \
+ `blend` is `Some(blend)`, where `blend.color_source`, \
+ `blend.color_destination`, `blend.alpha_source` or \
+ `blend.alpha_destination` is `BlendFactor::Src1*`",
+ requires_one_of: RequiresOneOf {
+ features: &["dual_src_blend"],
+ ..Default::default()
+ },
+ });
+ }
+
+ let attachment_format = match render_pass {
+ PipelineRenderPassType::BeginRenderPass(subpass) => subpass
+ .subpass_desc()
+ .color_attachments[attachment_index]
+ .as_ref()
+ .and_then(|atch_ref| {
+ subpass.render_pass().attachments()[atch_ref.attachment as usize]
+ .format
+ }),
+ PipelineRenderPassType::BeginRendering(rendering_info) => {
+ rendering_info.color_attachment_formats[attachment_index]
+ }
+ };
+
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06041
+ // VUID-VkGraphicsPipelineCreateInfo-renderPass-06062
+ // Use unchecked, because all validation has been done above or by the
+ // render pass creation.
+ if !attachment_format.map_or(false, |format| unsafe {
+ physical_device
+ .format_properties_unchecked(format)
+ .potential_format_features()
+ .intersects(FormatFeatures::COLOR_ATTACHMENT_BLEND)
+ }) {
+ return Err(
+ GraphicsPipelineCreationError::ColorAttachmentFormatBlendNotSupported {
+ attachment_index: attachment_index as u32,
+ },
+ );
+ }
+
+ // VUID-VkPipelineColorBlendAttachmentState-constantAlphaColorBlendFactors-04454
+ // VUID-VkPipelineColorBlendAttachmentState-constantAlphaColorBlendFactors-04455
+ if device.enabled_extensions().khr_portability_subset
+ && !device.enabled_features().constant_alpha_color_blend_factors
+ && (matches!(
+ color_source,
+ BlendFactor::ConstantAlpha | BlendFactor::OneMinusConstantAlpha
+ ) || matches!(
+ color_destination,
+ BlendFactor::ConstantAlpha | BlendFactor::OneMinusConstantAlpha
+ ))
+ {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "this device is a portability subset device, and \
+ `color_blend_state.attachments` has an element where `blend` is \
+ `Some(blend)`, where \
+ `blend.color_source` or `blend.color_destination` is \
+ `BlendFactor::ConstantAlpha` or \
+ `BlendFactor::OneMinusConstantAlpha`",
+ requires_one_of: RequiresOneOf {
+ features: &["constant_alpha_color_blend_factors"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+
+ match color_write_enable {
+ StateMode::Fixed(enable) => {
+ // VUID-VkPipelineColorWriteCreateInfoEXT-pAttachments-04801
+ if !enable && !device.enabled_features().color_write_enable {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`color_blend_state.attachments` has an element \
+ where `color_write_enable` is `StateMode::Fixed(false)`",
+ requires_one_of: RequiresOneOf {
+ features: &["color_write_enable"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ StateMode::Dynamic => {
+ // VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-04800
+ if !device.enabled_features().color_write_enable {
+ return Err(GraphicsPipelineCreationError::RequirementNotMet {
+ required_for: "`color_blend_state.attachments` has an element \
+ where `color_write_enable` is `StateMode::Dynamic`",
+ requires_one_of: RequiresOneOf {
+ features: &["color_write_enable"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ Generic shader checks
+ */
+
+ for stage_info in &shader_stages {
+ // VUID-VkGraphicsPipelineCreateInfo-layout-00756
+ pipeline_layout.ensure_compatible_with_shader(
+ stage_info.entry_point.descriptor_binding_requirements(),
+ stage_info.entry_point.push_constant_requirements(),
+ )?;
+
+ for (constant_id, reqs) in stage_info
+ .entry_point
+ .specialization_constant_requirements()
+ {
+ let map_entry = stage_info
+ .specialization_map_entries
+ .iter()
+ .find(|desc| desc.constant_id == constant_id)
+ .ok_or(GraphicsPipelineCreationError::IncompatibleSpecializationConstants)?;
+
+ if map_entry.size as DeviceSize != reqs.size {
+ return Err(GraphicsPipelineCreationError::IncompatibleSpecializationConstants);
+ }
+ }
+ }
+
+ // VUID-VkGraphicsPipelineCreateInfo-pStages-00742
+ // VUID-VkGraphicsPipelineCreateInfo-None-04889
+ // TODO: this check is too strict; the output only has to be a superset, any variables
+ // not used in the input of the next shader are just ignored.
+ for (output, input) in shader_stages.iter().zip(shader_stages.iter().skip(1)) {
+ if let Err(err) = input
+ .entry_point
+ .input_interface()
+ .matches(output.entry_point.output_interface())
+ {
+ return Err(GraphicsPipelineCreationError::ShaderStagesMismatch(err));
+ }
+ }
+
+ // TODO:
+ // VUID-VkPipelineShaderStageCreateInfo-maxClipDistances-00708
+ // VUID-VkPipelineShaderStageCreateInfo-maxCullDistances-00709
+ // VUID-VkPipelineShaderStageCreateInfo-maxCombinedClipAndCullDistances-00710
+ // VUID-VkPipelineShaderStageCreateInfo-maxSampleMaskWords-00711
+
+ // Dynamic states not handled yet:
+ // - ViewportWScaling (VkPipelineViewportWScalingStateCreateInfoNV)
+ // - SampleLocations (VkPipelineSampleLocationsStateCreateInfoEXT)
+ // - ViewportShadingRatePalette (VkPipelineViewportShadingRateImageStateCreateInfoNV)
+ // - ViewportCoarseSampleOrder (VkPipelineViewportCoarseSampleOrderStateCreateInfoNV)
+ // - ExclusiveScissor (VkPipelineViewportExclusiveScissorStateCreateInfoNV)
+ // - FragmentShadingRate (VkPipelineFragmentShadingRateStateCreateInfoKHR)
+
+ Ok(())
+ }
+
+ unsafe fn record_create(
+ &self,
+ device: &Device,
+ pipeline_layout: &PipelineLayout,
+ vertex_input_state: &VertexInputState,
+ has: Has,
+ ) -> Result<
+ (
+ ash::vk::Pipeline,
+ HashMap<(u32, u32), DescriptorBindingRequirements>,
+ HashMap<DynamicState, bool>,
+ HashMap<ShaderStage, ()>,
+ Option<FragmentTestsStages>,
+ ),
+ GraphicsPipelineCreationError,
+ > {
+ let Self {
+ render_pass,
+ cache,
+
+ vertex_shader,
+ tessellation_shaders,
+ geometry_shader,
+ fragment_shader,
+
+ vertex_input_state: _,
+ input_assembly_state,
+ tessellation_state,
+ viewport_state,
+ discard_rectangle_state,
+ rasterization_state,
+ multisample_state,
+ depth_stencil_state,
+ color_blend_state,
+ } = self;
+
+ let render_pass = render_pass.as_ref().unwrap();
+
+ let mut descriptor_binding_requirements: HashMap<
+ (u32, u32),
+ DescriptorBindingRequirements,
+ > = HashMap::default();
+ let mut dynamic_state: HashMap<DynamicState, bool> = HashMap::default();
+ let mut stages = HashMap::default();
+ let mut stages_vk: SmallVec<[_; 5]> = SmallVec::new();
+ let mut fragment_tests_stages = None;
+
+ /*
+ Render pass
+ */
+
+ let mut render_pass_vk = ash::vk::RenderPass::null();
+ let mut subpass_vk = 0;
+ let mut color_attachment_formats_vk: SmallVec<[_; 4]> = SmallVec::new();
+ let mut rendering_create_info_vk = None;
+
+ match render_pass {
+ PipelineRenderPassType::BeginRenderPass(subpass) => {
+ render_pass_vk = subpass.render_pass().handle();
+ subpass_vk = subpass.index();
+ }
+ PipelineRenderPassType::BeginRendering(rendering_info) => {
+ let &PipelineRenderingCreateInfo {
+ view_mask,
+ ref color_attachment_formats,
+ depth_attachment_format,
+ stencil_attachment_format,
+ _ne: _,
+ } = rendering_info;
+
+ color_attachment_formats_vk.extend(
+ color_attachment_formats
+ .iter()
+ .map(|format| format.map_or(ash::vk::Format::UNDEFINED, Into::into)),
+ );
+
+ let _ = rendering_create_info_vk.insert(ash::vk::PipelineRenderingCreateInfo {
+ view_mask,
+ color_attachment_count: color_attachment_formats_vk.len() as u32,
+ p_color_attachment_formats: color_attachment_formats_vk.as_ptr(),
+ depth_attachment_format: depth_attachment_format
+ .map_or(ash::vk::Format::UNDEFINED, Into::into),
+ stencil_attachment_format: stencil_attachment_format
+ .map_or(ash::vk::Format::UNDEFINED, Into::into),
+ ..Default::default()
+ });
+ }
+ }
+
+ /*
+ Vertex input state
+ */
+
+ let mut vertex_binding_descriptions_vk: SmallVec<[_; 8]> = SmallVec::new();
+ let mut vertex_attribute_descriptions_vk: SmallVec<[_; 8]> = SmallVec::new();
+ let mut vertex_binding_divisor_descriptions_vk: SmallVec<[_; 8]> = SmallVec::new();
+ let mut vertex_binding_divisor_state_vk = None;
+ let mut vertex_input_state_vk = None;
+ let mut input_assembly_state_vk = None;
+
+ if has.vertex_input_state {
+ // Vertex input state
+ {
+ dynamic_state.insert(DynamicState::VertexInput, false);
+
+ let VertexInputState {
+ bindings,
+ attributes,
+ } = vertex_input_state;
+
+ vertex_binding_descriptions_vk.extend(bindings.iter().map(
+ |(&binding, binding_desc)| ash::vk::VertexInputBindingDescription {
+ binding,
+ stride: binding_desc.stride,
+ input_rate: binding_desc.input_rate.into(),
+ },
+ ));
+
+ vertex_attribute_descriptions_vk.extend(attributes.iter().map(
+ |(&location, attribute_desc)| ash::vk::VertexInputAttributeDescription {
+ location,
+ binding: attribute_desc.binding,
+ format: attribute_desc.format.into(),
+ offset: attribute_desc.offset,
+ },
+ ));
+
+ let vertex_input_state =
+ vertex_input_state_vk.insert(ash::vk::PipelineVertexInputStateCreateInfo {
+ flags: ash::vk::PipelineVertexInputStateCreateFlags::empty(),
+ vertex_binding_description_count: vertex_binding_descriptions_vk.len()
+ as u32,
+ p_vertex_binding_descriptions: vertex_binding_descriptions_vk.as_ptr(),
+ vertex_attribute_description_count: vertex_attribute_descriptions_vk.len()
+ as u32,
+ p_vertex_attribute_descriptions: vertex_attribute_descriptions_vk.as_ptr(),
+ ..Default::default()
+ });
+
+ {
+ vertex_binding_divisor_descriptions_vk.extend(
+ bindings
+ .iter()
+ .filter_map(|(&binding, binding_desc)| match binding_desc.input_rate {
+ VertexInputRate::Instance { divisor } if divisor != 1 => {
+ Some((binding, divisor))
+ }
+ _ => None,
+ })
+ .map(|(binding, divisor)| {
+ ash::vk::VertexInputBindingDivisorDescriptionEXT {
+ binding,
+ divisor,
+ }
+ }),
+ );
+
+ // VUID-VkPipelineVertexInputDivisorStateCreateInfoEXT-vertexBindingDivisorCount-arraylength
+ if !vertex_binding_divisor_descriptions_vk.is_empty() {
+ vertex_input_state.p_next =
+ vertex_binding_divisor_state_vk.insert(
+ ash::vk::PipelineVertexInputDivisorStateCreateInfoEXT {
+ vertex_binding_divisor_count:
+ vertex_binding_divisor_descriptions_vk.len() as u32,
+ p_vertex_binding_divisors:
+ vertex_binding_divisor_descriptions_vk.as_ptr(),
+ ..Default::default()
+ },
+ ) as *const _ as *const _;
+ }
+ }
+ }
+
+ // Input assembly state
+ {
+ let &InputAssemblyState {
+ topology,
+ primitive_restart_enable,
+ } = input_assembly_state;
+
+ let topology = match topology {
+ PartialStateMode::Fixed(topology) => {
+ dynamic_state.insert(DynamicState::PrimitiveTopology, false);
+ topology.into()
+ }
+ PartialStateMode::Dynamic(topology_class) => {
+ dynamic_state.insert(DynamicState::PrimitiveTopology, true);
+ topology_class.example().into()
+ }
+ };
+
+ let primitive_restart_enable = match primitive_restart_enable {
+ StateMode::Fixed(primitive_restart_enable) => {
+ dynamic_state.insert(DynamicState::PrimitiveRestartEnable, false);
+ primitive_restart_enable as ash::vk::Bool32
+ }
+ StateMode::Dynamic => {
+ dynamic_state.insert(DynamicState::PrimitiveRestartEnable, true);
+ Default::default()
+ }
+ };
+
+ let _ =
+ input_assembly_state_vk.insert(ash::vk::PipelineInputAssemblyStateCreateInfo {
+ flags: ash::vk::PipelineInputAssemblyStateCreateFlags::empty(),
+ topology,
+ primitive_restart_enable,
+ ..Default::default()
+ });
+ }
+ }
+
+ /*
+ Pre-rasterization shader state
+ */
+
+ let mut vertex_shader_specialization_vk = None;
+ let mut tessellation_control_shader_specialization_vk = None;
+ let mut tessellation_evaluation_shader_specialization_vk = None;
+ let mut tessellation_state_vk = None;
+ let mut geometry_shader_specialization_vk = None;
+ let mut viewports_vk: SmallVec<[_; 2]> = SmallVec::new();
+ let mut scissors_vk: SmallVec<[_; 2]> = SmallVec::new();
+ let mut viewport_state_vk = None;
+ let mut rasterization_line_state_vk = None;
+ let mut rasterization_state_vk = None;
+ let mut discard_rectangles: SmallVec<[_; 2]> = SmallVec::new();
+ let mut discard_rectangle_state_vk = None;
+
+ if has.pre_rasterization_shader_state {
+ // Vertex shader
+ if let Some((entry_point, specialization_data)) = vertex_shader {
+ let specialization_map_entries = Vss::descriptors();
+ let specialization_data = slice::from_raw_parts(
+ specialization_data as *const _ as *const u8,
+ size_of_val(specialization_data),
+ );
+
+ let specialization_info_vk =
+ vertex_shader_specialization_vk.insert(ash::vk::SpecializationInfo {
+ map_entry_count: specialization_map_entries.len() as u32,
+ p_map_entries: specialization_map_entries.as_ptr() as *const _,
+ data_size: specialization_data.len(),
+ p_data: specialization_data.as_ptr() as *const _,
+ });
+
+ for (loc, reqs) in entry_point.descriptor_binding_requirements() {
+ match descriptor_binding_requirements.entry(loc) {
+ Entry::Occupied(entry) => {
+ entry.into_mut().merge(reqs).expect("Could not produce an intersection of the shader descriptor requirements");
+ }
+ Entry::Vacant(entry) => {
+ entry.insert(reqs.clone());
+ }
+ }
+ }
+
+ stages.insert(ShaderStage::Vertex, ());
+ stages_vk.push(ash::vk::PipelineShaderStageCreateInfo {
+ flags: ash::vk::PipelineShaderStageCreateFlags::empty(),
+ stage: ash::vk::ShaderStageFlags::VERTEX,
+ module: entry_point.module().handle(),
+ p_name: entry_point.name().as_ptr(),
+ p_specialization_info: specialization_info_vk as *const _,
+ ..Default::default()
+ });
+ }
+
+ // Tessellation shaders
+ if let Some(tessellation_shaders) = tessellation_shaders {
+ {
+ let (entry_point, specialization_data) = &tessellation_shaders.control;
+ let specialization_map_entries = Tcss::descriptors();
+ let specialization_data = slice::from_raw_parts(
+ specialization_data as *const _ as *const u8,
+ size_of_val(specialization_data),
+ );
+
+ let specialization_info_vk = tessellation_control_shader_specialization_vk
+ .insert(ash::vk::SpecializationInfo {
+ map_entry_count: specialization_map_entries.len() as u32,
+ p_map_entries: specialization_map_entries.as_ptr() as *const _,
+ data_size: specialization_data.len(),
+ p_data: specialization_data.as_ptr() as *const _,
+ });
+
+ for (loc, reqs) in entry_point.descriptor_binding_requirements() {
+ match descriptor_binding_requirements.entry(loc) {
+ Entry::Occupied(entry) => {
+ entry.into_mut().merge(reqs).expect("Could not produce an intersection of the shader descriptor requirements");
+ }
+ Entry::Vacant(entry) => {
+ entry.insert(reqs.clone());
+ }
+ }
+ }
+
+ stages.insert(ShaderStage::TessellationControl, ());
+ stages_vk.push(ash::vk::PipelineShaderStageCreateInfo {
+ flags: ash::vk::PipelineShaderStageCreateFlags::empty(),
+ stage: ash::vk::ShaderStageFlags::TESSELLATION_CONTROL,
+ module: entry_point.module().handle(),
+ p_name: entry_point.name().as_ptr(),
+ p_specialization_info: specialization_info_vk as *const _,
+ ..Default::default()
+ });
+ }
+
+ {
+ let (entry_point, specialization_data) = &tessellation_shaders.evaluation;
+ let specialization_map_entries = Tess::descriptors();
+ let specialization_data = slice::from_raw_parts(
+ specialization_data as *const _ as *const u8,
+ size_of_val(specialization_data),
+ );
+
+ let specialization_info_vk = tessellation_evaluation_shader_specialization_vk
+ .insert(ash::vk::SpecializationInfo {
+ map_entry_count: specialization_map_entries.len() as u32,
+ p_map_entries: specialization_map_entries.as_ptr() as *const _,
+ data_size: specialization_data.len(),
+ p_data: specialization_data.as_ptr() as *const _,
+ });
+
+ for (loc, reqs) in entry_point.descriptor_binding_requirements() {
+ match descriptor_binding_requirements.entry(loc) {
+ Entry::Occupied(entry) => {
+ entry.into_mut().merge(reqs).expect("Could not produce an intersection of the shader descriptor requirements");
+ }
+ Entry::Vacant(entry) => {
+ entry.insert(reqs.clone());
+ }
+ }
+ }
+
+ stages.insert(ShaderStage::TessellationEvaluation, ());
+ stages_vk.push(ash::vk::PipelineShaderStageCreateInfo {
+ flags: ash::vk::PipelineShaderStageCreateFlags::empty(),
+ stage: ash::vk::ShaderStageFlags::TESSELLATION_EVALUATION,
+ module: entry_point.module().handle(),
+ p_name: entry_point.name().as_ptr(),
+ p_specialization_info: specialization_info_vk as *const _,
+ ..Default::default()
+ });
+ }
+ }
+
+ // Geometry shader
+ if let Some((entry_point, specialization_data)) = geometry_shader {
+ let specialization_map_entries = Gss::descriptors();
+ let specialization_data = slice::from_raw_parts(
+ specialization_data as *const _ as *const u8,
+ size_of_val(specialization_data),
+ );
+
+ let specialization_info_vk =
+ geometry_shader_specialization_vk.insert(ash::vk::SpecializationInfo {
+ map_entry_count: specialization_map_entries.len() as u32,
+ p_map_entries: specialization_map_entries.as_ptr() as *const _,
+ data_size: specialization_data.len(),
+ p_data: specialization_data.as_ptr() as *const _,
+ });
+
+ for (loc, reqs) in entry_point.descriptor_binding_requirements() {
+ match descriptor_binding_requirements.entry(loc) {
+ Entry::Occupied(entry) => {
+ entry.into_mut().merge(reqs).expect("Could not produce an intersection of the shader descriptor requirements");
+ }
+ Entry::Vacant(entry) => {
+ entry.insert(reqs.clone());
+ }
+ }
+ }
+
+ stages.insert(ShaderStage::Geometry, ());
+ stages_vk.push(ash::vk::PipelineShaderStageCreateInfo {
+ flags: ash::vk::PipelineShaderStageCreateFlags::empty(),
+ stage: ash::vk::ShaderStageFlags::GEOMETRY,
+ module: entry_point.module().handle(),
+ p_name: entry_point.name().as_ptr(),
+ p_specialization_info: specialization_info_vk as *const _,
+ ..Default::default()
+ });
+ }
+
+ // Rasterization state
+ {
+ let &RasterizationState {
+ depth_clamp_enable,
+ rasterizer_discard_enable,
+ polygon_mode,
+ cull_mode,
+ front_face,
+ depth_bias,
+ line_width,
+ line_rasterization_mode,
+ line_stipple,
+ } = rasterization_state;
+
+ let rasterizer_discard_enable = match rasterizer_discard_enable {
+ StateMode::Fixed(rasterizer_discard_enable) => {
+ dynamic_state.insert(DynamicState::RasterizerDiscardEnable, false);
+ rasterizer_discard_enable as ash::vk::Bool32
+ }
+ StateMode::Dynamic => {
+ dynamic_state.insert(DynamicState::RasterizerDiscardEnable, true);
+ ash::vk::FALSE
+ }
+ };
+
+ let cull_mode = match cull_mode {
+ StateMode::Fixed(cull_mode) => {
+ dynamic_state.insert(DynamicState::CullMode, false);
+ cull_mode.into()
+ }
+ StateMode::Dynamic => {
+ dynamic_state.insert(DynamicState::CullMode, true);
+ CullMode::default().into()
+ }
+ };
+
+ let front_face = match front_face {
+ StateMode::Fixed(front_face) => {
+ dynamic_state.insert(DynamicState::FrontFace, false);
+ front_face.into()
+ }
+ StateMode::Dynamic => {
+ dynamic_state.insert(DynamicState::FrontFace, true);
+ FrontFace::default().into()
+ }
+ };
+
+ let (
+ depth_bias_enable,
+ depth_bias_constant_factor,
+ depth_bias_clamp,
+ depth_bias_slope_factor,
+ ) = if let Some(depth_bias_state) = depth_bias {
+ if depth_bias_state.enable_dynamic {
+ dynamic_state.insert(DynamicState::DepthBiasEnable, true);
+ } else {
+ dynamic_state.insert(DynamicState::DepthBiasEnable, false);
+ }
+
+ let (constant_factor, clamp, slope_factor) = match depth_bias_state.bias {
+ StateMode::Fixed(bias) => {
+ dynamic_state.insert(DynamicState::DepthBias, false);
+ (bias.constant_factor, bias.clamp, bias.slope_factor)
+ }
+ StateMode::Dynamic => {
+ dynamic_state.insert(DynamicState::DepthBias, true);
+ (0.0, 0.0, 0.0)
+ }
+ };
+
+ (ash::vk::TRUE, constant_factor, clamp, slope_factor)
+ } else {
+ (ash::vk::FALSE, 0.0, 0.0, 0.0)
+ };
+
+ let line_width = match line_width {
+ StateMode::Fixed(line_width) => {
+ dynamic_state.insert(DynamicState::LineWidth, false);
+ line_width
+ }
+ StateMode::Dynamic => {
+ dynamic_state.insert(DynamicState::LineWidth, true);
+ 1.0
+ }
+ };
+
+ let rasterization_state =
+ rasterization_state_vk.insert(ash::vk::PipelineRasterizationStateCreateInfo {
+ flags: ash::vk::PipelineRasterizationStateCreateFlags::empty(),
+ depth_clamp_enable: depth_clamp_enable as ash::vk::Bool32,
+ rasterizer_discard_enable,
+ polygon_mode: polygon_mode.into(),
+ cull_mode,
+ front_face,
+ depth_bias_enable,
+ depth_bias_constant_factor,
+ depth_bias_clamp,
+ depth_bias_slope_factor,
+ line_width,
+ ..Default::default()
+ });
+
+ if device.enabled_extensions().ext_line_rasterization {
+ let (stippled_line_enable, line_stipple_factor, line_stipple_pattern) =
+ if let Some(line_stipple) = line_stipple {
+ let (factor, pattern) = match line_stipple {
+ StateMode::Fixed(line_stipple) => {
+ dynamic_state.insert(DynamicState::LineStipple, false);
+ (line_stipple.factor, line_stipple.pattern)
+ }
+ StateMode::Dynamic => {
+ dynamic_state.insert(DynamicState::LineStipple, true);
+ (1, 0)
+ }
+ };
+
+ (ash::vk::TRUE, factor, pattern)
+ } else {
+ (ash::vk::FALSE, 1, 0)
+ };
+
+ rasterization_state.p_next = rasterization_line_state_vk.insert(
+ ash::vk::PipelineRasterizationLineStateCreateInfoEXT {
+ line_rasterization_mode: line_rasterization_mode.into(),
+ stippled_line_enable,
+ line_stipple_factor,
+ line_stipple_pattern,
+ ..Default::default()
+ },
+ ) as *const _ as *const _;
+ }
+ }
+
+ // Discard rectangle state
+ if device.enabled_extensions().ext_discard_rectangles {
+ let DiscardRectangleState { mode, rectangles } = discard_rectangle_state;
+
+ let discard_rectangle_count = match rectangles {
+ PartialStateMode::Fixed(rectangles) => {
+ dynamic_state.insert(DynamicState::DiscardRectangle, false);
+ discard_rectangles.extend(rectangles.iter().map(|&rect| rect.into()));
+
+ discard_rectangles.len() as u32
+ }
+ PartialStateMode::Dynamic(count) => {
+ dynamic_state.insert(DynamicState::DiscardRectangle, true);
+
+ *count
+ }
+ };
+
+ let _ = discard_rectangle_state_vk.insert(
+ ash::vk::PipelineDiscardRectangleStateCreateInfoEXT {
+ flags: ash::vk::PipelineDiscardRectangleStateCreateFlagsEXT::empty(),
+ discard_rectangle_mode: (*mode).into(),
+ discard_rectangle_count,
+ p_discard_rectangles: discard_rectangles.as_ptr(),
+ ..Default::default()
+ },
+ );
+ }
+ }
+
+ // Tessellation state
+ if has.tessellation_state {
+ let &TessellationState {
+ patch_control_points,
+ } = tessellation_state;
+
+ let patch_control_points = match patch_control_points {
+ StateMode::Fixed(patch_control_points) => {
+ dynamic_state.insert(DynamicState::PatchControlPoints, false);
+ patch_control_points
+ }
+ StateMode::Dynamic => {
+ dynamic_state.insert(DynamicState::PatchControlPoints, true);
+ Default::default()
+ }
+ };
+
+ let _ = tessellation_state_vk.insert(ash::vk::PipelineTessellationStateCreateInfo {
+ flags: ash::vk::PipelineTessellationStateCreateFlags::empty(),
+ patch_control_points,
+ ..Default::default()
+ });
+ }
+
+ // Viewport state
+ if has.viewport_state {
+ let (viewport_count, scissor_count) = match viewport_state {
+ ViewportState::Fixed { data } => {
+ let count = data.len() as u32;
+ viewports_vk.extend(data.iter().map(|e| e.0.clone().into()));
+ dynamic_state.insert(DynamicState::Viewport, false);
+ dynamic_state.insert(DynamicState::ViewportWithCount, false);
+
+ scissors_vk.extend(data.iter().map(|e| e.1.into()));
+ dynamic_state.insert(DynamicState::Scissor, false);
+ dynamic_state.insert(DynamicState::ScissorWithCount, false);
+
+ (count, count)
+ }
+ ViewportState::FixedViewport {
+ viewports,
+ scissor_count_dynamic,
+ } => {
+ let viewport_count = viewports.len() as u32;
+ viewports_vk.extend(viewports.iter().map(|e| e.clone().into()));
+ dynamic_state.insert(DynamicState::Viewport, false);
+ dynamic_state.insert(DynamicState::ViewportWithCount, false);
+
+ let scissor_count = if *scissor_count_dynamic {
+ dynamic_state.insert(DynamicState::Scissor, false);
+ dynamic_state.insert(DynamicState::ScissorWithCount, true);
+ 0
+ } else {
+ dynamic_state.insert(DynamicState::Scissor, true);
+ dynamic_state.insert(DynamicState::ScissorWithCount, false);
+ viewport_count
+ };
+
+ (viewport_count, scissor_count)
+ }
+ ViewportState::FixedScissor {
+ scissors,
+ viewport_count_dynamic,
+ } => {
+ let scissor_count = scissors.len() as u32;
+ scissors_vk.extend(scissors.iter().map(|&e| e.into()));
+ dynamic_state.insert(DynamicState::Scissor, false);
+ dynamic_state.insert(DynamicState::ScissorWithCount, false);
+
+ let viewport_count = if *viewport_count_dynamic {
+ dynamic_state.insert(DynamicState::Viewport, false);
+ dynamic_state.insert(DynamicState::ViewportWithCount, true);
+ 0
+ } else {
+ dynamic_state.insert(DynamicState::Viewport, true);
+ dynamic_state.insert(DynamicState::ViewportWithCount, false);
+ scissor_count
+ };
+
+ (viewport_count, scissor_count)
+ }
+ &ViewportState::Dynamic {
+ count,
+ viewport_count_dynamic,
+ scissor_count_dynamic,
+ } => {
+ let viewport_count = if viewport_count_dynamic {
+ dynamic_state.insert(DynamicState::Viewport, false);
+ dynamic_state.insert(DynamicState::ViewportWithCount, true);
+
+ 0
+ } else {
+ dynamic_state.insert(DynamicState::Viewport, true);
+ dynamic_state.insert(DynamicState::ViewportWithCount, false);
+
+ count
+ };
+ let scissor_count = if scissor_count_dynamic {
+ dynamic_state.insert(DynamicState::Scissor, false);
+ dynamic_state.insert(DynamicState::ScissorWithCount, true);
+
+ 0
+ } else {
+ dynamic_state.insert(DynamicState::Scissor, true);
+ dynamic_state.insert(DynamicState::ScissorWithCount, false);
+
+ count
+ };
+
+ (viewport_count, scissor_count)
+ }
+ };
+
+ let _ = viewport_state_vk.insert(ash::vk::PipelineViewportStateCreateInfo {
+ flags: ash::vk::PipelineViewportStateCreateFlags::empty(),
+ viewport_count,
+ p_viewports: if viewports_vk.is_empty() {
+ ptr::null()
+ } else {
+ viewports_vk.as_ptr()
+ }, // validation layer crashes if you just pass the pointer
+ scissor_count,
+ p_scissors: if scissors_vk.is_empty() {
+ ptr::null()
+ } else {
+ scissors_vk.as_ptr()
+ }, // validation layer crashes if you just pass the pointer
+ ..Default::default()
+ });
+ }
+
+ /*
+ Fragment shader state
+ */
+
+ let mut fragment_shader_specialization_vk = None;
+ let mut depth_stencil_state_vk = None;
+
+ if has.fragment_shader_state {
+ // Fragment shader
+ if let Some((entry_point, specialization_data)) = fragment_shader {
+ let specialization_map_entries = Fss::descriptors();
+ let specialization_data = slice::from_raw_parts(
+ specialization_data as *const _ as *const u8,
+ size_of_val(specialization_data),
+ );
+
+ let specialization_info_vk =
+ fragment_shader_specialization_vk.insert(ash::vk::SpecializationInfo {
+ map_entry_count: specialization_map_entries.len() as u32,
+ p_map_entries: specialization_map_entries.as_ptr() as *const _,
+ data_size: specialization_data.len(),
+ p_data: specialization_data.as_ptr() as *const _,
+ });
+
+ for (loc, reqs) in entry_point.descriptor_binding_requirements() {
+ match descriptor_binding_requirements.entry(loc) {
+ Entry::Occupied(entry) => {
+ entry.into_mut().merge(reqs).expect("Could not produce an intersection of the shader descriptor requirements");
+ }
+ Entry::Vacant(entry) => {
+ entry.insert(reqs.clone());
+ }
+ }
+ }
+
+ stages.insert(ShaderStage::Fragment, ());
+ stages_vk.push(ash::vk::PipelineShaderStageCreateInfo {
+ flags: ash::vk::PipelineShaderStageCreateFlags::empty(),
+ stage: ash::vk::ShaderStageFlags::FRAGMENT,
+ module: entry_point.module().handle(),
+ p_name: entry_point.name().as_ptr(),
+ p_specialization_info: specialization_info_vk as *const _,
+ ..Default::default()
+ });
+ fragment_tests_stages = match entry_point.execution() {
+ ShaderExecution::Fragment(FragmentShaderExecution {
+ fragment_tests_stages,
+ ..
+ }) => Some(*fragment_tests_stages),
+ _ => unreachable!(),
+ };
+ }
+ }
+
+ // Depth/stencil state
+ if has.depth_stencil_state {
+ let DepthStencilState {
+ depth,
+ depth_bounds,
+ stencil,
+ } = depth_stencil_state;
+
+ let (depth_test_enable, depth_write_enable, depth_compare_op) =
+ if let Some(depth_state) = depth {
+ let &DepthState {
+ enable_dynamic,
+ write_enable,
+ compare_op,
+ } = depth_state;
+
+ if enable_dynamic {
+ dynamic_state.insert(DynamicState::DepthTestEnable, true);
+ } else {
+ dynamic_state.insert(DynamicState::DepthTestEnable, false);
+ }
+
+ let write_enable = match write_enable {
+ StateMode::Fixed(write_enable) => {
+ dynamic_state.insert(DynamicState::DepthWriteEnable, false);
+ write_enable as ash::vk::Bool32
+ }
+ StateMode::Dynamic => {
+ dynamic_state.insert(DynamicState::DepthWriteEnable, true);
+ ash::vk::TRUE
+ }
+ };
+
+ let compare_op = match compare_op {
+ StateMode::Fixed(compare_op) => {
+ dynamic_state.insert(DynamicState::DepthCompareOp, false);
+ compare_op.into()
+ }
+ StateMode::Dynamic => {
+ dynamic_state.insert(DynamicState::DepthCompareOp, true);
+ ash::vk::CompareOp::ALWAYS
+ }
+ };
+
+ (ash::vk::TRUE, write_enable, compare_op)
+ } else {
+ (ash::vk::FALSE, ash::vk::FALSE, ash::vk::CompareOp::ALWAYS)
+ };
+
+ let (depth_bounds_test_enable, min_depth_bounds, max_depth_bounds) =
+ if let Some(depth_bounds_state) = depth_bounds {
+ let DepthBoundsState {
+ enable_dynamic,
+ bounds,
+ } = depth_bounds_state;
+
+ if *enable_dynamic {
+ dynamic_state.insert(DynamicState::DepthBoundsTestEnable, true);
+ } else {
+ dynamic_state.insert(DynamicState::DepthBoundsTestEnable, false);
+ }
+
+ let (min_bounds, max_bounds) = match bounds.clone() {
+ StateMode::Fixed(bounds) => {
+ dynamic_state.insert(DynamicState::DepthBounds, false);
+ bounds.into_inner()
+ }
+ StateMode::Dynamic => {
+ dynamic_state.insert(DynamicState::DepthBounds, true);
+ (0.0, 1.0)
+ }
+ };
+
+ (ash::vk::TRUE, min_bounds, max_bounds)
+ } else {
+ (ash::vk::FALSE, 0.0, 1.0)
+ };
+
+ let (stencil_test_enable, front, back) = if let Some(stencil_state) = stencil {
+ let StencilState {
+ enable_dynamic,
+ front,
+ back,
+ } = stencil_state;
+
+ if *enable_dynamic {
+ dynamic_state.insert(DynamicState::StencilTestEnable, true);
+ } else {
+ dynamic_state.insert(DynamicState::StencilTestEnable, false);
+ }
+
+ match (front.ops, back.ops) {
+ (StateMode::Fixed(_), StateMode::Fixed(_)) => {
+ dynamic_state.insert(DynamicState::StencilOp, false);
+ }
+ (StateMode::Dynamic, StateMode::Dynamic) => {
+ dynamic_state.insert(DynamicState::StencilOp, true);
+ }
+ _ => unreachable!(),
+ };
+
+ match (front.compare_mask, back.compare_mask) {
+ (StateMode::Fixed(_), StateMode::Fixed(_)) => {
+ dynamic_state.insert(DynamicState::StencilCompareMask, false);
+ }
+ (StateMode::Dynamic, StateMode::Dynamic) => {
+ dynamic_state.insert(DynamicState::StencilCompareMask, true);
+ }
+ _ => unreachable!(),
+ };
+
+ match (front.write_mask, back.write_mask) {
+ (StateMode::Fixed(_), StateMode::Fixed(_)) => {
+ dynamic_state.insert(DynamicState::StencilWriteMask, false);
+ }
+ (StateMode::Dynamic, StateMode::Dynamic) => {
+ dynamic_state.insert(DynamicState::StencilWriteMask, true);
+ }
+ _ => unreachable!(),
+ };
+
+ match (front.reference, back.reference) {
+ (StateMode::Fixed(_), StateMode::Fixed(_)) => {
+ dynamic_state.insert(DynamicState::StencilReference, false);
+ }
+ (StateMode::Dynamic, StateMode::Dynamic) => {
+ dynamic_state.insert(DynamicState::StencilReference, true);
+ }
+ _ => unreachable!(),
+ };
+
+ let [front, back] = [front, back].map(|stencil_op_state| {
+ let &StencilOpState {
+ ops,
+ compare_mask,
+ write_mask,
+ reference,
+ } = stencil_op_state;
+
+ let ops = match ops {
+ StateMode::Fixed(x) => x,
+ StateMode::Dynamic => Default::default(),
+ };
+ let compare_mask = match compare_mask {
+ StateMode::Fixed(x) => x,
+ StateMode::Dynamic => Default::default(),
+ };
+ let write_mask = match write_mask {
+ StateMode::Fixed(x) => x,
+ StateMode::Dynamic => Default::default(),
+ };
+ let reference = match reference {
+ StateMode::Fixed(x) => x,
+ StateMode::Dynamic => Default::default(),
+ };
+
+ ash::vk::StencilOpState {
+ fail_op: ops.fail_op.into(),
+ pass_op: ops.pass_op.into(),
+ depth_fail_op: ops.depth_fail_op.into(),
+ compare_op: ops.compare_op.into(),
+ compare_mask,
+ write_mask,
+ reference,
+ }
+ });
+
+ (ash::vk::TRUE, front, back)
+ } else {
+ (ash::vk::FALSE, Default::default(), Default::default())
+ };
+
+ let _ = depth_stencil_state_vk.insert(ash::vk::PipelineDepthStencilStateCreateInfo {
+ flags: ash::vk::PipelineDepthStencilStateCreateFlags::empty(),
+ depth_test_enable,
+ depth_write_enable,
+ depth_compare_op,
+ depth_bounds_test_enable,
+ stencil_test_enable,
+ front,
+ back,
+ min_depth_bounds,
+ max_depth_bounds,
+ ..Default::default()
+ });
+ }
+
+ /*
+ Fragment output state
+ */
+
+ let mut multisample_state_vk = None;
+ let mut color_blend_attachments_vk: SmallVec<[_; 4]> = SmallVec::new();
+ let mut color_write_enables_vk: SmallVec<[_; 4]> = SmallVec::new();
+ let mut color_write_vk = None;
+ let mut color_blend_state_vk = None;
+
+ if has.fragment_output_state {
+ // Multisample state
+ {
+ let &MultisampleState {
+ rasterization_samples,
+ sample_shading,
+ ref sample_mask,
+ alpha_to_coverage_enable,
+ alpha_to_one_enable,
+ } = multisample_state;
+
+ let (sample_shading_enable, min_sample_shading) =
+ if let Some(min_sample_shading) = sample_shading {
+ (ash::vk::TRUE, min_sample_shading)
+ } else {
+ (ash::vk::FALSE, 0.0)
+ };
+
+ let _ = multisample_state_vk.insert(ash::vk::PipelineMultisampleStateCreateInfo {
+ flags: ash::vk::PipelineMultisampleStateCreateFlags::empty(),
+ rasterization_samples: rasterization_samples.into(),
+ sample_shading_enable,
+ min_sample_shading,
+ p_sample_mask: sample_mask as _,
+ alpha_to_coverage_enable: alpha_to_coverage_enable as ash::vk::Bool32,
+ alpha_to_one_enable: alpha_to_one_enable as ash::vk::Bool32,
+ ..Default::default()
+ });
+ }
+ }
+
+ // Color blend state
+ if has.color_blend_state {
+ let &ColorBlendState {
+ logic_op,
+ ref attachments,
+ blend_constants,
+ } = color_blend_state;
+
+ color_blend_attachments_vk.extend(attachments.iter().map(
+ |color_blend_attachment_state| {
+ let &ColorBlendAttachmentState {
+ blend,
+ color_write_mask,
+ color_write_enable: _,
+ } = color_blend_attachment_state;
+
+ let blend = if let Some(blend) = blend {
+ blend.into()
+ } else {
+ Default::default()
+ };
+
+ ash::vk::PipelineColorBlendAttachmentState {
+ color_write_mask: color_write_mask.into(),
+ ..blend
+ }
+ },
+ ));
+
+ let (logic_op_enable, logic_op) = if let Some(logic_op) = logic_op {
+ let logic_op = match logic_op {
+ StateMode::Fixed(logic_op) => {
+ dynamic_state.insert(DynamicState::LogicOp, false);
+ logic_op.into()
+ }
+ StateMode::Dynamic => {
+ dynamic_state.insert(DynamicState::LogicOp, true);
+ Default::default()
+ }
+ };
+
+ (ash::vk::TRUE, logic_op)
+ } else {
+ (ash::vk::FALSE, Default::default())
+ };
+
+ let blend_constants = match blend_constants {
+ StateMode::Fixed(blend_constants) => {
+ dynamic_state.insert(DynamicState::BlendConstants, false);
+ blend_constants
+ }
+ StateMode::Dynamic => {
+ dynamic_state.insert(DynamicState::BlendConstants, true);
+ Default::default()
+ }
+ };
+
+ let mut color_blend_state_vk =
+ color_blend_state_vk.insert(ash::vk::PipelineColorBlendStateCreateInfo {
+ flags: ash::vk::PipelineColorBlendStateCreateFlags::empty(),
+ logic_op_enable,
+ logic_op,
+ attachment_count: color_blend_attachments_vk.len() as u32,
+ p_attachments: color_blend_attachments_vk.as_ptr(),
+ blend_constants,
+ ..Default::default()
+ });
+
+ if device.enabled_extensions().ext_color_write_enable {
+ color_write_enables_vk.extend(attachments.iter().map(
+ |color_blend_attachment_state| {
+ let &ColorBlendAttachmentState {
+ blend: _,
+ color_write_mask: _,
+ color_write_enable,
+ } = color_blend_attachment_state;
+
+ match color_write_enable {
+ StateMode::Fixed(enable) => {
+ dynamic_state.insert(DynamicState::ColorWriteEnable, false);
+ enable as ash::vk::Bool32
+ }
+ StateMode::Dynamic => {
+ dynamic_state.insert(DynamicState::ColorWriteEnable, true);
+ ash::vk::TRUE
+ }
+ }
+ },
+ ));
+
+ color_blend_state_vk.p_next =
+ color_write_vk.insert(ash::vk::PipelineColorWriteCreateInfoEXT {
+ attachment_count: color_write_enables_vk.len() as u32,
+ p_color_write_enables: color_write_enables_vk.as_ptr(),
+ ..Default::default()
+ }) as *const _ as *const _;
+ }
+ }
+
+ /*
+ Dynamic state
+ */
+
+ let mut dynamic_state_list: SmallVec<[_; 4]> = SmallVec::new();
+ let mut dynamic_state_vk = None;
+
+ {
+ dynamic_state_list.extend(
+ dynamic_state
+ .iter()
+ .filter(|(_, d)| **d)
+ .map(|(&state, _)| state.into()),
+ );
+
+ if !dynamic_state_list.is_empty() {
+ let _ = dynamic_state_vk.insert(ash::vk::PipelineDynamicStateCreateInfo {
+ flags: ash::vk::PipelineDynamicStateCreateFlags::empty(),
+ dynamic_state_count: dynamic_state_list.len() as u32,
+ p_dynamic_states: dynamic_state_list.as_ptr(),
+ ..Default::default()
+ });
+ }
+ }
+
+ /*
+ Create
+ */
+
+ let mut create_info = ash::vk::GraphicsPipelineCreateInfo {
+ flags: ash::vk::PipelineCreateFlags::empty(), // TODO: some flags are available but none are critical
+ stage_count: stages_vk.len() as u32,
+ p_stages: stages_vk.as_ptr(),
+ p_vertex_input_state: vertex_input_state_vk
+ .as_ref()
+ .map(|p| p as *const _)
+ .unwrap_or(ptr::null()),
+ p_input_assembly_state: input_assembly_state_vk
+ .as_ref()
+ .map(|p| p as *const _)
+ .unwrap_or(ptr::null()),
+ p_tessellation_state: tessellation_state_vk
+ .as_ref()
+ .map(|p| p as *const _)
+ .unwrap_or(ptr::null()),
+ p_viewport_state: viewport_state_vk
+ .as_ref()
+ .map(|p| p as *const _)
+ .unwrap_or(ptr::null()),
+ p_rasterization_state: rasterization_state_vk
+ .as_ref()
+ .map(|p| p as *const _)
+ .unwrap_or(ptr::null()),
+ p_multisample_state: multisample_state_vk
+ .as_ref()
+ .map(|p| p as *const _)
+ .unwrap_or(ptr::null()),
+ p_depth_stencil_state: depth_stencil_state_vk
+ .as_ref()
+ .map(|p| p as *const _)
+ .unwrap_or(ptr::null()),
+ p_color_blend_state: color_blend_state_vk
+ .as_ref()
+ .map(|p| p as *const _)
+ .unwrap_or(ptr::null()),
+ p_dynamic_state: dynamic_state_vk
+ .as_ref()
+ .map(|s| s as *const _)
+ .unwrap_or(ptr::null()),
+ layout: pipeline_layout.handle(),
+ render_pass: render_pass_vk,
+ subpass: subpass_vk,
+ base_pipeline_handle: ash::vk::Pipeline::null(), // TODO:
+ base_pipeline_index: -1, // TODO:
+ ..Default::default()
+ };
+
+ if let Some(info) = discard_rectangle_state_vk.as_mut() {
+ info.p_next = create_info.p_next;
+ create_info.p_next = info as *const _ as *const _;
+ }
+
+ if let Some(info) = rendering_create_info_vk.as_mut() {
+ info.p_next = create_info.p_next;
+ create_info.p_next = info as *const _ as *const _;
+ }
+
+ let cache_handle = match cache.as_ref() {
+ Some(cache) => cache.handle(),
+ None => ash::vk::PipelineCache::null(),
+ };
+
+ let handle = {
+ let fns = device.fns();
+ let mut output = MaybeUninit::uninit();
+ (fns.v1_0.create_graphics_pipelines)(
+ device.handle(),
+ cache_handle,
+ 1,
+ &create_info,
+ ptr::null(),
+ output.as_mut_ptr(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+
+ output.assume_init()
+ };
+
+ // Some drivers return `VK_SUCCESS` but provide a null handle if they
+ // fail to create the pipeline (due to invalid shaders, etc)
+ // This check ensures that we don't create an invalid `GraphicsPipeline` instance
+ if handle == ash::vk::Pipeline::null() {
+ panic!("vkCreateGraphicsPipelines provided a NULL handle");
+ }
+
+ Ok((
+ handle,
+ descriptor_binding_requirements,
+ dynamic_state,
+ stages,
+ fragment_tests_stages,
+ ))
+ }
+
+ // TODO: add build_with_cache method
+}
+
+struct ShaderStageInfo<'a> {
+ entry_point: &'a EntryPoint<'a>,
+ specialization_map_entries: &'a [SpecializationMapEntry],
+ _specialization_data: &'a [u8],
+}
+
+impl<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss>
+ GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss>
+{
+ // TODO: add pipeline derivate system
+
+ /// Sets the vertex shader to use.
+ // TODO: correct specialization constants
+ pub fn vertex_shader<'vs2, Vss2>(
+ self,
+ shader: EntryPoint<'vs2>,
+ specialization_constants: Vss2,
+ ) -> GraphicsPipelineBuilder<'vs2, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss2, Tcss, Tess, Gss, Fss>
+ where
+ Vss2: SpecializationConstants,
+ {
+ GraphicsPipelineBuilder {
+ render_pass: self.render_pass,
+ cache: self.cache,
+
+ vertex_shader: Some((shader, specialization_constants)),
+ tessellation_shaders: self.tessellation_shaders,
+ geometry_shader: self.geometry_shader,
+ fragment_shader: self.fragment_shader,
+
+ vertex_input_state: self.vertex_input_state,
+ input_assembly_state: self.input_assembly_state,
+ tessellation_state: self.tessellation_state,
+ viewport_state: self.viewport_state,
+ discard_rectangle_state: self.discard_rectangle_state,
+ rasterization_state: self.rasterization_state,
+ multisample_state: self.multisample_state,
+ depth_stencil_state: self.depth_stencil_state,
+ color_blend_state: self.color_blend_state,
+ }
+ }
+
+ /// Sets the tessellation shaders to use.
+ // TODO: correct specialization constants
+ pub fn tessellation_shaders<'tcs2, 'tes2, Tcss2, Tess2>(
+ self,
+ control_shader: EntryPoint<'tcs2>,
+ control_specialization_constants: Tcss2,
+ evaluation_shader: EntryPoint<'tes2>,
+ evaluation_specialization_constants: Tess2,
+ ) -> GraphicsPipelineBuilder<'vs, 'tcs2, 'tes2, 'gs, 'fs, Vdef, Vss, Tcss2, Tess2, Gss, Fss>
+ where
+ Tcss2: SpecializationConstants,
+ Tess2: SpecializationConstants,
+ {
+ GraphicsPipelineBuilder {
+ render_pass: self.render_pass,
+ cache: self.cache,
+
+ vertex_shader: self.vertex_shader,
+ tessellation_shaders: Some(TessellationShaders {
+ control: (control_shader, control_specialization_constants),
+ evaluation: (evaluation_shader, evaluation_specialization_constants),
+ }),
+ geometry_shader: self.geometry_shader,
+ fragment_shader: self.fragment_shader,
+
+ vertex_input_state: self.vertex_input_state,
+ input_assembly_state: self.input_assembly_state,
+ tessellation_state: self.tessellation_state,
+ viewport_state: self.viewport_state,
+ discard_rectangle_state: self.discard_rectangle_state,
+ rasterization_state: self.rasterization_state,
+ multisample_state: self.multisample_state,
+ depth_stencil_state: self.depth_stencil_state,
+ color_blend_state: self.color_blend_state,
+ }
+ }
+
+ /// Sets the geometry shader to use.
+ // TODO: correct specialization constants
+ pub fn geometry_shader<'gs2, Gss2>(
+ self,
+ shader: EntryPoint<'gs2>,
+ specialization_constants: Gss2,
+ ) -> GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs2, 'fs, Vdef, Vss, Tcss, Tess, Gss2, Fss>
+ where
+ Gss2: SpecializationConstants,
+ {
+ GraphicsPipelineBuilder {
+ render_pass: self.render_pass,
+ cache: self.cache,
+
+ vertex_shader: self.vertex_shader,
+ tessellation_shaders: self.tessellation_shaders,
+ geometry_shader: Some((shader, specialization_constants)),
+ fragment_shader: self.fragment_shader,
+
+ vertex_input_state: self.vertex_input_state,
+ input_assembly_state: self.input_assembly_state,
+ tessellation_state: self.tessellation_state,
+ viewport_state: self.viewport_state,
+ discard_rectangle_state: self.discard_rectangle_state,
+ rasterization_state: self.rasterization_state,
+ multisample_state: self.multisample_state,
+ depth_stencil_state: self.depth_stencil_state,
+ color_blend_state: self.color_blend_state,
+ }
+ }
+
+ /// Sets the fragment shader to use.
+ ///
+ /// The fragment shader is run once for each pixel that is covered by each primitive.
+ // TODO: correct specialization constants
+ pub fn fragment_shader<'fs2, Fss2>(
+ self,
+ shader: EntryPoint<'fs2>,
+ specialization_constants: Fss2,
+ ) -> GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs2, Vdef, Vss, Tcss, Tess, Gss, Fss2>
+ where
+ Fss2: SpecializationConstants,
+ {
+ GraphicsPipelineBuilder {
+ render_pass: self.render_pass,
+ cache: self.cache,
+
+ vertex_shader: self.vertex_shader,
+ tessellation_shaders: self.tessellation_shaders,
+ geometry_shader: self.geometry_shader,
+ fragment_shader: Some((shader, specialization_constants)),
+
+ vertex_input_state: self.vertex_input_state,
+ input_assembly_state: self.input_assembly_state,
+ tessellation_state: self.tessellation_state,
+ viewport_state: self.viewport_state,
+ discard_rectangle_state: self.discard_rectangle_state,
+ rasterization_state: self.rasterization_state,
+ multisample_state: self.multisample_state,
+ depth_stencil_state: self.depth_stencil_state,
+ color_blend_state: self.color_blend_state,
+ }
+ }
+
+ /// Sets the vertex input state.
+ ///
+ /// The default value is [`VertexInputState::default()`].
+ pub fn vertex_input_state<T>(
+ self,
+ vertex_input_state: T,
+ ) -> GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs, T, Vss, Tcss, Tess, Gss, Fss>
+ where
+ T: VertexDefinition,
+ {
+ GraphicsPipelineBuilder {
+ render_pass: self.render_pass,
+ cache: self.cache,
+
+ vertex_shader: self.vertex_shader,
+ tessellation_shaders: self.tessellation_shaders,
+ geometry_shader: self.geometry_shader,
+ fragment_shader: self.fragment_shader,
+
+ vertex_input_state,
+ input_assembly_state: self.input_assembly_state,
+ tessellation_state: self.tessellation_state,
+ viewport_state: self.viewport_state,
+ discard_rectangle_state: self.discard_rectangle_state,
+ rasterization_state: self.rasterization_state,
+ multisample_state: self.multisample_state,
+ depth_stencil_state: self.depth_stencil_state,
+ color_blend_state: self.color_blend_state,
+ }
+ }
+
+ /// Sets the input assembly state.
+ ///
+ /// The default value is [`InputAssemblyState::default()`].
+ #[inline]
+ pub fn input_assembly_state(mut self, input_assembly_state: InputAssemblyState) -> Self {
+ self.input_assembly_state = input_assembly_state;
+ self
+ }
+
+ /// Sets the tessellation state. This is required if the pipeline contains tessellation shaders,
+ /// and ignored otherwise.
+ ///
+ /// The default value is [`TessellationState::default()`].
+ #[inline]
+ pub fn tessellation_state(mut self, tessellation_state: TessellationState) -> Self {
+ self.tessellation_state = tessellation_state;
+ self
+ }
+
+ /// Sets the viewport state.
+ ///
+ /// The default value is [`ViewportState::default()`].
+ #[inline]
+ pub fn viewport_state(mut self, viewport_state: ViewportState) -> Self {
+ self.viewport_state = viewport_state;
+ self
+ }
+
+ /// Sets the discard rectangle state.
+ ///
+ /// The default value is [`DiscardRectangleState::default()`].
+ #[inline]
+ pub fn discard_rectangle_state(
+ mut self,
+ discard_rectangle_state: DiscardRectangleState,
+ ) -> Self {
+ self.discard_rectangle_state = discard_rectangle_state;
+ self
+ }
+
+ /// Sets the rasterization state.
+ ///
+ /// The default value is [`RasterizationState::default()`].
+ #[inline]
+ pub fn rasterization_state(mut self, rasterization_state: RasterizationState) -> Self {
+ self.rasterization_state = rasterization_state;
+ self
+ }
+
+ /// Sets the multisample state.
+ ///
+ /// The default value is [`MultisampleState::default()`].
+ #[inline]
+ pub fn multisample_state(mut self, multisample_state: MultisampleState) -> Self {
+ self.multisample_state = multisample_state;
+ self
+ }
+
+ /// Sets the depth/stencil state.
+ ///
+ /// The default value is [`DepthStencilState::default()`].
+ #[inline]
+ pub fn depth_stencil_state(mut self, depth_stencil_state: DepthStencilState) -> Self {
+ self.depth_stencil_state = depth_stencil_state;
+ self
+ }
+
+ /// Sets the color blend state.
+ ///
+ /// The default value is [`ColorBlendState::default()`].
+ #[inline]
+ pub fn color_blend_state(mut self, color_blend_state: ColorBlendState) -> Self {
+ self.color_blend_state = color_blend_state;
+ self
+ }
+
+ /// Sets the tessellation shaders stage as disabled. This is the default.
+ #[deprecated(since = "0.27.0")]
+ #[inline]
+ pub fn tessellation_shaders_disabled(mut self) -> Self {
+ self.tessellation_shaders = None;
+ self
+ }
+
+ /// Sets the geometry shader stage as disabled. This is the default.
+ #[deprecated(since = "0.27.0")]
+ #[inline]
+ pub fn geometry_shader_disabled(mut self) -> Self {
+ self.geometry_shader = None;
+ self
+ }
+
+ /// Sets whether primitive restart is enabled.
+ #[deprecated(since = "0.27.0", note = "Use `input_assembly_state` instead")]
+ #[inline]
+ pub fn primitive_restart(mut self, enabled: bool) -> Self {
+ self.input_assembly_state.primitive_restart_enable = StateMode::Fixed(enabled);
+ self
+ }
+
+ /// Sets the topology of the primitives that are expected by the pipeline.
+ #[deprecated(since = "0.27.0", note = "Use `input_assembly_state` instead")]
+ #[inline]
+ pub fn primitive_topology(mut self, topology: PrimitiveTopology) -> Self {
+ self.input_assembly_state.topology = PartialStateMode::Fixed(topology);
+ self
+ }
+
+ /// Sets the topology of the primitives to a list of points.
+ ///
+ /// > **Note**: This is equivalent to
+ /// > `self.primitive_topology(PrimitiveTopology::PointList)`.
+ #[deprecated(since = "0.27.0", note = "Use `input_assembly_state` instead")]
+ #[inline]
+ pub fn point_list(self) -> Self {
+ self.primitive_topology(PrimitiveTopology::PointList)
+ }
+
+ /// Sets the topology of the primitives to a list of lines.
+ ///
+ /// > **Note**: This is equivalent to
+ /// > `self.primitive_topology(PrimitiveTopology::LineList)`.
+ #[deprecated(since = "0.27.0", note = "Use `input_assembly_state` instead")]
+ #[inline]
+ pub fn line_list(self) -> Self {
+ self.primitive_topology(PrimitiveTopology::LineList)
+ }
+
+ /// Sets the topology of the primitives to a line strip.
+ ///
+ /// > **Note**: This is equivalent to
+ /// > `self.primitive_topology(PrimitiveTopology::LineStrip)`.
+ #[deprecated(since = "0.27.0", note = "Use `input_assembly_state` instead")]
+ #[inline]
+ pub fn line_strip(self) -> Self {
+ self.primitive_topology(PrimitiveTopology::LineStrip)
+ }
+
+ /// Sets the topology of the primitives to a list of triangles. Note that this is the default.
+ ///
+ /// > **Note**: This is equivalent to
+ /// > `self.primitive_topology(PrimitiveTopology::TriangleList)`.
+ #[deprecated(since = "0.27.0", note = "Use `input_assembly_state` instead")]
+ #[inline]
+ pub fn triangle_list(self) -> Self {
+ self.primitive_topology(PrimitiveTopology::TriangleList)
+ }
+
+ /// Sets the topology of the primitives to a triangle strip.
+ ///
+ /// > **Note**: This is equivalent to
+ /// > `self.primitive_topology(PrimitiveTopology::TriangleStrip)`.
+ #[deprecated(since = "0.27.0", note = "Use `input_assembly_state` instead")]
+ #[inline]
+ pub fn triangle_strip(self) -> Self {
+ self.primitive_topology(PrimitiveTopology::TriangleStrip)
+ }
+
+ /// Sets the topology of the primitives to a fan of triangles.
+ ///
+ /// > **Note**: This is equivalent to
+ /// > `self.primitive_topology(PrimitiveTopology::TriangleFan)`.
+ #[deprecated(since = "0.27.0", note = "Use `input_assembly_state` instead")]
+ #[inline]
+ pub fn triangle_fan(self) -> Self {
+ self.primitive_topology(PrimitiveTopology::TriangleFan)
+ }
+
+ /// Sets the topology of the primitives to a list of lines with adjacency information.
+ ///
+ /// > **Note**: This is equivalent to
+ /// > `self.primitive_topology(PrimitiveTopology::LineListWithAdjacency)`.
+ #[deprecated(since = "0.27.0", note = "Use `input_assembly_state` instead")]
+ #[inline]
+ pub fn line_list_with_adjacency(self) -> Self {
+ self.primitive_topology(PrimitiveTopology::LineListWithAdjacency)
+ }
+
+ /// Sets the topology of the primitives to a line strip with adjacency information.
+ ///
+ /// > **Note**: This is equivalent to
+ /// > `self.primitive_topology(PrimitiveTopology::LineStripWithAdjacency)`.
+ #[deprecated(since = "0.27.0", note = "Use `input_assembly_state` instead")]
+ #[inline]
+ pub fn line_strip_with_adjacency(self) -> Self {
+ self.primitive_topology(PrimitiveTopology::LineStripWithAdjacency)
+ }
+
+ /// Sets the topology of the primitives to a list of triangles with adjacency information.
+ ///
+ /// > **Note**: This is equivalent to
+ /// > `self.primitive_topology(PrimitiveTopology::TriangleListWithAdjacency)`.
+ #[deprecated(since = "0.27.0", note = "Use `input_assembly_state` instead")]
+ #[inline]
+ pub fn triangle_list_with_adjacency(self) -> Self {
+ self.primitive_topology(PrimitiveTopology::TriangleListWithAdjacency)
+ }
+
+ /// Sets the topology of the primitives to a triangle strip with adjacency information`
+ ///
+ /// > **Note**: This is equivalent to
+ /// > `self.primitive_topology(PrimitiveTopology::TriangleStripWithAdjacency)`.
+ #[deprecated(since = "0.27.0", note = "Use `input_assembly_state` instead")]
+ #[inline]
+ pub fn triangle_strip_with_adjacency(self) -> Self {
+ self.primitive_topology(PrimitiveTopology::TriangleStripWithAdjacency)
+ }
+
+ /// Sets the topology of the primitives to a list of patches. Can only be used and must be used
+ /// with a tessellation shader.
+ ///
+ /// > **Note**: This is equivalent to
+ /// > `self.primitive_topology(PrimitiveTopology::PatchList)`.
+ #[deprecated(since = "0.27.0", note = "Use `input_assembly_state` instead")]
+ #[inline]
+ pub fn patch_list(self) -> Self {
+ self.primitive_topology(PrimitiveTopology::PatchList)
+ }
+
+ /// Sets the viewports to some value, and the scissor boxes to boxes that always cover the
+ /// whole viewport.
+ #[deprecated(since = "0.27.0", note = "Use `viewport_state` instead")]
+ pub fn viewports<I>(self, viewports: I) -> Self
+ where
+ I: IntoIterator<Item = Viewport>,
+ {
+ self.viewports_scissors(viewports.into_iter().map(|v| (v, Scissor::irrelevant())))
+ }
+
+ /// Sets the characteristics of viewports and scissor boxes in advance.
+ #[deprecated(since = "0.27.0", note = "Use `viewport_state` instead")]
+ pub fn viewports_scissors<I>(mut self, viewports: I) -> Self
+ where
+ I: IntoIterator<Item = (Viewport, Scissor)>,
+ {
+ self.viewport_state = ViewportState::Fixed {
+ data: viewports.into_iter().collect(),
+ };
+ self
+ }
+
+ /// Sets the scissor boxes to some values, and viewports to dynamic. The viewports will
+ /// need to be set before drawing.
+ #[deprecated(since = "0.27.0", note = "Use `viewport_state` instead")]
+ pub fn viewports_dynamic_scissors_fixed<I>(mut self, scissors: I) -> Self
+ where
+ I: IntoIterator<Item = Scissor>,
+ {
+ self.viewport_state = ViewportState::FixedScissor {
+ scissors: scissors.into_iter().collect(),
+ viewport_count_dynamic: false,
+ };
+ self
+ }
+
+ /// Sets the viewports to dynamic, and the scissor boxes to boxes that always cover the whole
+ /// viewport. The viewports will need to be set before drawing.
+ #[deprecated(since = "0.27.0", note = "Use `viewport_state` instead")]
+ #[inline]
+ pub fn viewports_dynamic_scissors_irrelevant(mut self, num: u32) -> Self {
+ self.viewport_state = ViewportState::FixedScissor {
+ scissors: (0..num).map(|_| Scissor::irrelevant()).collect(),
+ viewport_count_dynamic: false,
+ };
+ self
+ }
+
+ /// Sets the viewports to some values, and scissor boxes to dynamic. The scissor boxes will
+ /// need to be set before drawing.
+ #[deprecated(since = "0.27.0", note = "Use `viewport_state` instead")]
+ pub fn viewports_fixed_scissors_dynamic<I>(mut self, viewports: I) -> Self
+ where
+ I: IntoIterator<Item = Viewport>,
+ {
+ self.viewport_state = ViewportState::FixedViewport {
+ viewports: viewports.into_iter().collect(),
+ scissor_count_dynamic: false,
+ };
+ self
+ }
+
+ /// Sets the viewports and scissor boxes to dynamic. They will both need to be set before
+ /// drawing.
+ #[deprecated(since = "0.27.0", note = "Use `viewport_state` instead")]
+ #[inline]
+ pub fn viewports_scissors_dynamic(mut self, count: u32) -> Self {
+ self.viewport_state = ViewportState::Dynamic {
+ count,
+ viewport_count_dynamic: false,
+ scissor_count_dynamic: false,
+ };
+ self
+ }
+
+ /// If true, then the depth value of the vertices will be clamped to the range `[0.0 ; 1.0]`.
+ /// If false, fragments whose depth is outside of this range will be discarded before the
+ /// fragment shader even runs.
+ #[deprecated(since = "0.27.0", note = "Use `rasterization_state` instead")]
+ #[inline]
+ pub fn depth_clamp(mut self, clamp: bool) -> Self {
+ self.rasterization_state.depth_clamp_enable = clamp;
+ self
+ }
+
+ /// Sets the front-facing faces to counter-clockwise faces. This is the default.
+ ///
+ /// Triangles whose vertices are oriented counter-clockwise on the screen will be considered
+ /// as facing their front. Otherwise they will be considered as facing their back.
+ #[deprecated(since = "0.27.0", note = "Use `rasterization_state` instead")]
+ #[inline]
+ pub fn front_face_counter_clockwise(mut self) -> Self {
+ self.rasterization_state.front_face = StateMode::Fixed(FrontFace::CounterClockwise);
+ self
+ }
+
+ /// Sets the front-facing faces to clockwise faces.
+ ///
+ /// Triangles whose vertices are oriented clockwise on the screen will be considered
+ /// as facing their front. Otherwise they will be considered as facing their back.
+ #[deprecated(since = "0.27.0", note = "Use `rasterization_state` instead")]
+ #[inline]
+ pub fn front_face_clockwise(mut self) -> Self {
+ self.rasterization_state.front_face = StateMode::Fixed(FrontFace::Clockwise);
+ self
+ }
+
+ /// Sets backface culling as disabled. This is the default.
+ #[deprecated(since = "0.27.0", note = "Use `rasterization_state` instead")]
+ #[inline]
+ pub fn cull_mode_disabled(mut self) -> Self {
+ self.rasterization_state.cull_mode = StateMode::Fixed(CullMode::None);
+ self
+ }
+
+ /// Sets backface culling to front faces. The front faces (as chosen with the `front_face_*`
+ /// methods) will be discarded by the GPU when drawing.
+ #[deprecated(since = "0.27.0", note = "Use `rasterization_state` instead")]
+ #[inline]
+ pub fn cull_mode_front(mut self) -> Self {
+ self.rasterization_state.cull_mode = StateMode::Fixed(CullMode::Front);
+ self
+ }
+
+ /// Sets backface culling to back faces. Faces that are not facing the front (as chosen with
+ /// the `front_face_*` methods) will be discarded by the GPU when drawing.
+ #[deprecated(since = "0.27.0", note = "Use `rasterization_state` instead")]
+ #[inline]
+ pub fn cull_mode_back(mut self) -> Self {
+ self.rasterization_state.cull_mode = StateMode::Fixed(CullMode::Back);
+ self
+ }
+
+ /// Sets backface culling to both front and back faces. All the faces will be discarded.
+ ///
+ /// > **Note**: This option exists for the sake of completeness. It has no known practical
+ /// > usage.
+ #[deprecated(since = "0.27.0", note = "Use `rasterization_state` instead")]
+ #[inline]
+ pub fn cull_mode_front_and_back(mut self) -> Self {
+ self.rasterization_state.cull_mode = StateMode::Fixed(CullMode::FrontAndBack);
+ self
+ }
+
+ /// Sets the polygon mode to "fill". This is the default.
+ #[deprecated(since = "0.27.0", note = "Use `rasterization_state` instead")]
+ #[inline]
+ pub fn polygon_mode_fill(mut self) -> Self {
+ self.rasterization_state.polygon_mode = PolygonMode::Fill;
+ self
+ }
+
+ /// Sets the polygon mode to "line". Triangles will each be turned into three lines.
+ #[deprecated(since = "0.27.0", note = "Use `rasterization_state` instead")]
+ #[inline]
+ pub fn polygon_mode_line(mut self) -> Self {
+ self.rasterization_state.polygon_mode = PolygonMode::Line;
+ self
+ }
+
+ /// Sets the polygon mode to "point". Triangles and lines will each be turned into three points.
+ #[deprecated(since = "0.27.0", note = "Use `rasterization_state` instead")]
+ #[inline]
+ pub fn polygon_mode_point(mut self) -> Self {
+ self.rasterization_state.polygon_mode = PolygonMode::Point;
+ self
+ }
+
+ /// Sets the width of the lines, if the GPU needs to draw lines. The default is `1.0`.
+ #[deprecated(since = "0.27.0", note = "Use `rasterization_state` instead")]
+ #[inline]
+ pub fn line_width(mut self, value: f32) -> Self {
+ self.rasterization_state.line_width = StateMode::Fixed(value);
+ self
+ }
+
+ /// Sets the width of the lines as dynamic, which means that you will need to set this value
+ /// when drawing.
+ #[deprecated(since = "0.27.0", note = "Use `rasterization_state` instead")]
+ #[inline]
+ pub fn line_width_dynamic(mut self) -> Self {
+ self.rasterization_state.line_width = StateMode::Dynamic;
+ self
+ }
+
+ /// Disables sample shading. The fragment shader will only be run once per fragment (ie. per
+ /// pixel) and not once by sample. The output will then be copied in all of the covered
+ /// samples.
+ ///
+ /// Sample shading is disabled by default.
+ #[deprecated(since = "0.27.0", note = "Use `multisample_state` instead")]
+ #[inline]
+ pub fn sample_shading_disabled(mut self) -> Self {
+ self.multisample_state.sample_shading = None;
+ self
+ }
+
+ /// Enables sample shading. The fragment shader will be run once per sample at the borders of
+ /// the object you're drawing.
+ ///
+ /// Enabling sampling shading requires the `sample_rate_shading` feature to be enabled on the
+ /// device.
+ ///
+ /// The `min_fract` parameter is the minimum fraction of samples shading. For example if its
+ /// value is 0.5, then the fragment shader will run for at least half of the samples. The other
+ /// half of the samples will get their values determined automatically.
+ ///
+ /// Sample shading is disabled by default.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `min_fract` is not between 0.0 and 1.0.
+ #[deprecated(since = "0.27.0", note = "Use `multisample_state` instead")]
+ #[inline]
+ pub fn sample_shading_enabled(mut self, min_fract: f32) -> Self {
+ assert!((0.0..=1.0).contains(&min_fract));
+ self.multisample_state.sample_shading = Some(min_fract);
+ self
+ }
+
+ // TODO: doc
+ #[deprecated(since = "0.27.0", note = "Use `multisample_state` instead")]
+ pub fn alpha_to_coverage_disabled(mut self) -> Self {
+ self.multisample_state.alpha_to_coverage_enable = false;
+ self
+ }
+
+ // TODO: doc
+ #[deprecated(since = "0.27.0", note = "Use `multisample_state` instead")]
+ pub fn alpha_to_coverage_enabled(mut self) -> Self {
+ self.multisample_state.alpha_to_coverage_enable = true;
+ self
+ }
+
+ /// Disables alpha-to-one.
+ ///
+ /// Alpha-to-one is disabled by default.
+ #[deprecated(since = "0.27.0", note = "Use `multisample_state` instead")]
+ #[inline]
+ pub fn alpha_to_one_disabled(mut self) -> Self {
+ self.multisample_state.alpha_to_one_enable = false;
+ self
+ }
+
+ /// Enables alpha-to-one. The alpha component of the first color output of the fragment shader
+ /// will be replaced by the value `1.0`.
+ ///
+ /// Enabling alpha-to-one requires the `alpha_to_one` feature to be enabled on the device.
+ ///
+ /// Alpha-to-one is disabled by default.
+ #[deprecated(since = "0.27.0", note = "Use `multisample_state` instead")]
+ #[inline]
+ pub fn alpha_to_one_enabled(mut self) -> Self {
+ self.multisample_state.alpha_to_one_enable = true;
+ self
+ }
+
+ /// Sets the depth/stencil state.
+ #[deprecated(since = "0.27.0", note = "Use `depth_stencil_state` instead")]
+ #[inline]
+ pub fn depth_stencil(self, depth_stencil_state: DepthStencilState) -> Self {
+ self.depth_stencil_state(depth_stencil_state)
+ }
+
+ /// Sets the depth/stencil tests as disabled.
+ ///
+ /// > **Note**: This is a shortcut for all the other `depth_*` and `depth_stencil_*` methods
+ /// > of the builder.
+ #[deprecated(since = "0.27.0", note = "Use `depth_stencil_state` instead")]
+ #[inline]
+ pub fn depth_stencil_disabled(mut self) -> Self {
+ self.depth_stencil_state = DepthStencilState::disabled();
+ self
+ }
+
+ /// Sets the depth/stencil tests as a simple depth test and no stencil test.
+ ///
+ /// > **Note**: This is a shortcut for setting the depth test to `Less`, the depth write Into
+ /// > ` true` and disable the stencil test.
+ #[deprecated(since = "0.27.0", note = "Use `depth_stencil_state` instead")]
+ #[inline]
+ pub fn depth_stencil_simple_depth(mut self) -> Self {
+ self.depth_stencil_state = DepthStencilState::simple_depth_test();
+ self
+ }
+
+ /// Sets whether the depth buffer will be written.
+ #[deprecated(since = "0.27.0", note = "Use `depth_stencil_state` instead")]
+ #[inline]
+ pub fn depth_write(mut self, write: bool) -> Self {
+ let depth_state = self
+ .depth_stencil_state
+ .depth
+ .get_or_insert(Default::default());
+ depth_state.write_enable = StateMode::Fixed(write);
+ self
+ }
+
+ #[deprecated(since = "0.27.0", note = "Use `color_blend_state` instead")]
+ // TODO: When this method is removed, also remove the special casing in `with_pipeline_layout`
+ // for self.color_blend_state.attachments.len() == 1
+ #[inline]
+ pub fn blend_collective(mut self, blend: AttachmentBlend) -> Self {
+ self.color_blend_state.attachments = vec![ColorBlendAttachmentState {
+ blend: Some(blend),
+ color_write_mask: ColorComponents::all(),
+ color_write_enable: StateMode::Fixed(true),
+ }];
+ self
+ }
+
+ #[deprecated(since = "0.27.0", note = "Use `color_blend_state` instead")]
+ pub fn blend_individual<I>(mut self, blend: I) -> Self
+ where
+ I: IntoIterator<Item = AttachmentBlend>,
+ {
+ self.color_blend_state.attachments = blend
+ .into_iter()
+ .map(|x| ColorBlendAttachmentState {
+ blend: Some(x),
+ color_write_mask: ColorComponents::all(),
+ color_write_enable: StateMode::Fixed(true),
+ })
+ .collect();
+ self
+ }
+
+ /// Each fragment shader output will have its value directly written to the framebuffer
+ /// attachment. This is the default.
+ #[deprecated(since = "0.27.0", note = "Use `color_blend_state` instead")]
+ // TODO: When this method is removed, also remove the special casing in `with_pipeline_layout`
+ // for self.color_blend_state.attachments.len() == 1
+ #[inline]
+ pub fn blend_pass_through(mut self) -> Self {
+ self.color_blend_state.attachments = vec![ColorBlendAttachmentState {
+ blend: None,
+ color_write_mask: ColorComponents::all(),
+ color_write_enable: StateMode::Fixed(true),
+ }];
+ self
+ }
+
+ #[deprecated(since = "0.27.0", note = "Use `color_blend_state` instead")]
+ // TODO: When this method is removed, also remove the special casing in `with_pipeline_layout`
+ // for self.color_blend_state.attachments.len() == 1
+ #[inline]
+ pub fn blend_alpha_blending(mut self) -> Self {
+ self.color_blend_state.attachments = vec![ColorBlendAttachmentState {
+ blend: Some(AttachmentBlend::alpha()),
+ color_write_mask: ColorComponents::all(),
+ color_write_enable: StateMode::Fixed(true),
+ }];
+ self
+ }
+
+ #[deprecated(since = "0.27.0", note = "Use `color_blend_state` instead")]
+ #[inline]
+ pub fn blend_logic_op(mut self, logic_op: LogicOp) -> Self {
+ self.color_blend_state.logic_op = Some(StateMode::Fixed(logic_op));
+ self
+ }
+
+ /// Sets the logic operation as disabled. This is the default.
+ #[deprecated(since = "0.27.0", note = "Use `color_blend_state` instead")]
+ #[inline]
+ pub fn blend_logic_op_disabled(mut self) -> Self {
+ self.color_blend_state.logic_op = None;
+ self
+ }
+
+ /// Sets the blend constant. The default is `[0.0, 0.0, 0.0, 0.0]`.
+ ///
+ /// The blend constant is used for some blending calculations. It is irrelevant otherwise.
+ #[deprecated(since = "0.27.0", note = "Use `color_blend_state` instead")]
+ #[inline]
+ pub fn blend_constants(mut self, constants: [f32; 4]) -> Self {
+ self.color_blend_state.blend_constants = StateMode::Fixed(constants);
+ self
+ }
+
+ /// Sets the blend constant value as dynamic. Its value will need to be set before drawing.
+ ///
+ /// The blend constant is used for some blending calculations. It is irrelevant otherwise.
+ #[deprecated(since = "0.27.0", note = "Use `color_blend_state` instead")]
+ #[inline]
+ pub fn blend_constants_dynamic(mut self) -> Self {
+ self.color_blend_state.blend_constants = StateMode::Dynamic;
+ self
+ }
+
+ /// Sets the render pass subpass to use.
+ pub fn render_pass(self, render_pass: impl Into<PipelineRenderPassType>) -> Self {
+ GraphicsPipelineBuilder {
+ render_pass: Some(render_pass.into()),
+ cache: self.cache,
+
+ vertex_shader: self.vertex_shader,
+ tessellation_shaders: self.tessellation_shaders,
+ geometry_shader: self.geometry_shader,
+ fragment_shader: self.fragment_shader,
+
+ vertex_input_state: self.vertex_input_state,
+ input_assembly_state: self.input_assembly_state,
+ tessellation_state: self.tessellation_state,
+ viewport_state: self.viewport_state,
+ rasterization_state: self.rasterization_state,
+ multisample_state: self.multisample_state,
+ depth_stencil_state: self.depth_stencil_state,
+ color_blend_state: self.color_blend_state,
+
+ discard_rectangle_state: self.discard_rectangle_state,
+ }
+ }
+
+ /// Enable caching of this pipeline via a PipelineCache object.
+ ///
+ /// If this pipeline already exists in the cache it will be used, if this is a new
+ /// pipeline it will be inserted into the cache. The implementation handles the
+ /// PipelineCache.
+ #[inline]
+ pub fn build_with_cache(mut self, pipeline_cache: Arc<PipelineCache>) -> Self {
+ self.cache = Some(pipeline_cache);
+ self
+ }
+}
+
+impl<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss> Clone
+ for GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss>
+where
+ Vdef: Clone,
+ Vss: Clone,
+ Tcss: Clone,
+ Tess: Clone,
+ Gss: Clone,
+ Fss: Clone,
+{
+ fn clone(&self) -> Self {
+ GraphicsPipelineBuilder {
+ render_pass: self.render_pass.clone(),
+ cache: self.cache.clone(),
+
+ vertex_shader: self.vertex_shader.clone(),
+ tessellation_shaders: self.tessellation_shaders.clone(),
+ geometry_shader: self.geometry_shader.clone(),
+ fragment_shader: self.fragment_shader.clone(),
+
+ vertex_input_state: self.vertex_input_state.clone(),
+ input_assembly_state: self.input_assembly_state,
+ tessellation_state: self.tessellation_state,
+ viewport_state: self.viewport_state.clone(),
+ rasterization_state: self.rasterization_state.clone(),
+ multisample_state: self.multisample_state,
+ depth_stencil_state: self.depth_stencil_state.clone(),
+ color_blend_state: self.color_blend_state.clone(),
+
+ discard_rectangle_state: self.discard_rectangle_state.clone(),
+ }
+ }
+}
diff --git a/src/pipeline/graphics/color_blend.rs b/src/pipeline/graphics/color_blend.rs
new file mode 100644
index 0000000..8acc342
--- /dev/null
+++ b/src/pipeline/graphics/color_blend.rs
@@ -0,0 +1,717 @@
+// Copyright (c) 2016 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+//! Configures how the color output of the fragment shader is written to the attachment.
+//!
+//! # Blending in details
+//!
+//! There are three kinds of color attachments for the purpose of blending:
+//!
+//! - Attachments with a floating-point or fixed point format.
+//! - Attachments with a (non-normalized) integer format.
+//! - Attachments with a normalized integer format.
+//!
+//! For floating-point and fixed-point formats, the blending operation is applied. For integer
+//! formats, the logic operation is applied. For normalized integer formats, the logic operation
+//! will take precedence if it is activated, otherwise the blending operation is applied.
+
+use crate::{
+ macros::{vulkan_bitflags, vulkan_enum},
+ pipeline::StateMode,
+};
+
+/// Describes how the color output of the fragment shader is written to the attachment. See the
+/// documentation of the `blend` module for more info.
+#[derive(Clone, Debug)]
+pub struct ColorBlendState {
+ /// Sets the logical operation to perform between the incoming fragment color and the existing
+ /// fragment in the framebuffer attachment.
+ ///
+ /// If set to `Some`, the [`logic_op`](crate::device::Features::logic_op) feature must be
+ /// enabled on the device. If set to `Some(Dynamic)`, then the
+ /// [`extended_dynamic_state2_logic_op`](crate::device::Features::extended_dynamic_state2_logic_op)
+ /// feature must also be enabled on the device.
+ pub logic_op: Option<StateMode<LogicOp>>,
+
+ /// Sets the blend and output state for each color attachment. The number of elements must match
+ /// the number of color attachments in the framebuffer.
+ ///
+ /// If there are multiple elements, and the `blend` and `color_write_mask` members of each
+ /// element differ, then the [`independent_blend`](crate::device::Features::independent_blend)
+ /// feature must be enabled on the device.
+ pub attachments: Vec<ColorBlendAttachmentState>,
+
+ /// The constant color to use for some of the `BlendFactor` variants.
+ pub blend_constants: StateMode<[f32; 4]>,
+}
+
+impl ColorBlendState {
+ /// Creates a `ColorBlendState` with logical operations disabled, blend constants set to zero,
+ /// and `num` attachment entries that have blending disabled, and color write and all color
+ /// components enabled.
+ #[inline]
+ pub fn new(num: u32) -> Self {
+ Self {
+ logic_op: None,
+ attachments: (0..num)
+ .map(|_| ColorBlendAttachmentState {
+ blend: None,
+ color_write_mask: ColorComponents::all(),
+ color_write_enable: StateMode::Fixed(true),
+ })
+ .collect(),
+ blend_constants: StateMode::Fixed([0.0, 0.0, 0.0, 0.0]),
+ }
+ }
+
+ /// Enables logical operations with the given logical operation.
+ #[inline]
+ pub fn logic_op(mut self, logic_op: LogicOp) -> Self {
+ self.logic_op = Some(StateMode::Fixed(logic_op));
+ self
+ }
+
+ /// Enables logical operations with a dynamic logical operation.
+ #[inline]
+ pub fn logic_op_dynamic(mut self) -> Self {
+ self.logic_op = Some(StateMode::Dynamic);
+ self
+ }
+
+ /// Enables blending for all attachments, with the given parameters.
+ #[inline]
+ pub fn blend(mut self, blend: AttachmentBlend) -> Self {
+ self.attachments
+ .iter_mut()
+ .for_each(|attachment_state| attachment_state.blend = Some(blend));
+ self
+ }
+
+ /// Enables blending for all attachments, with alpha blending.
+ #[inline]
+ pub fn blend_alpha(mut self) -> Self {
+ self.attachments
+ .iter_mut()
+ .for_each(|attachment_state| attachment_state.blend = Some(AttachmentBlend::alpha()));
+ self
+ }
+
+ /// Enables blending for all attachments, with additive blending.
+ #[inline]
+ pub fn blend_additive(mut self) -> Self {
+ self.attachments.iter_mut().for_each(|attachment_state| {
+ attachment_state.blend = Some(AttachmentBlend::additive())
+ });
+ self
+ }
+
+ /// Sets the color write mask for all attachments.
+ #[inline]
+ pub fn color_write_mask(mut self, color_write_mask: ColorComponents) -> Self {
+ self.attachments
+ .iter_mut()
+ .for_each(|attachment_state| attachment_state.color_write_mask = color_write_mask);
+ self
+ }
+
+ /// Sets the blend constants.
+ #[inline]
+ pub fn blend_constants(mut self, constants: [f32; 4]) -> Self {
+ self.blend_constants = StateMode::Fixed(constants);
+ self
+ }
+
+ /// Sets the blend constants as dynamic.
+ #[inline]
+ pub fn blend_constants_dynamic(mut self) -> Self {
+ self.blend_constants = StateMode::Dynamic;
+ self
+ }
+}
+
+impl Default for ColorBlendState {
+ /// Returns [`ColorBlendState::new(1)`].
+ #[inline]
+ fn default() -> Self {
+ Self::new(1)
+ }
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+ /// Which logical operation to apply to the output values.
+ ///
+ /// The operation is applied individually for each channel (red, green, blue and alpha).
+ ///
+ /// Only relevant for integer or unsigned attachments.
+ ///
+ /// Also note that some implementations don't support logic operations.
+ LogicOp = LogicOp(i32);
+
+ /// Returns `0`.
+ Clear = CLEAR,
+
+ /// Returns `source & destination`.
+ And = AND,
+
+ /// Returns `source & !destination`.
+ AndReverse = AND_REVERSE,
+
+ /// Returns `source`.
+ Copy = COPY,
+
+ /// Returns `!source & destination`.
+ AndInverted = AND_INVERTED,
+
+ /// Returns `destination`.
+ Noop = NO_OP,
+
+ /// Returns `source ^ destination`.
+ Xor = XOR,
+
+ /// Returns `source | destination`.
+ Or = OR,
+
+ /// Returns `!(source | destination)`.
+ Nor = NOR,
+
+ /// Returns `!(source ^ destination)`.
+ Equivalent = EQUIVALENT,
+
+ /// Returns `!destination`.
+ Invert = INVERT,
+
+ /// Returns `source | !destination.
+ OrReverse = OR_REVERSE,
+
+ /// Returns `!source`.
+ CopyInverted = COPY_INVERTED,
+
+ /// Returns `!source | destination`.
+ OrInverted = OR_INVERTED,
+
+ /// Returns `!(source & destination)`.
+ Nand = NAND,
+
+ /// Returns `!0` (all bits set to 1).
+ Set = SET,
+
+}
+
+impl Default for LogicOp {
+ #[inline]
+ fn default() -> LogicOp {
+ LogicOp::Noop
+ }
+}
+
+/// Describes how a framebuffer color attachment is handled in the pipeline during the color
+/// blend stage.
+#[derive(Clone, Debug)]
+pub struct ColorBlendAttachmentState {
+ /// The blend parameters for the attachment.
+ ///
+ /// If set to `None`, blending is disabled, and all incoming pixels will be used directly.
+ pub blend: Option<AttachmentBlend>,
+
+ /// Sets which components of the final pixel value are written to the attachment.
+ pub color_write_mask: ColorComponents,
+
+ /// Sets whether anything at all is written to the attachment. If enabled, the pixel data
+ /// that is written is determined by the `color_write_mask`. If disabled, the mask is ignored
+ /// and nothing is written.
+ ///
+ /// If set to anything other than `Fixed(true)`, the
+ /// [`color_write_enable`](crate::device::Features::color_write_enable) feature must be enabled
+ /// on the device.
+ pub color_write_enable: StateMode<bool>,
+}
+
+/// Describes how the blending system should behave for an attachment.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub struct AttachmentBlend {
+ /// The operation to apply between the color components of the source and destination pixels,
+ /// to produce the final pixel value.
+ pub color_op: BlendOp,
+
+ /// The operation to apply to the source color component before applying `color_op`.
+ pub color_source: BlendFactor,
+
+ /// The operation to apply to the destination color component before applying `color_op`.
+ pub color_destination: BlendFactor,
+
+ /// The operation to apply between the alpha component of the source and destination pixels,
+ /// to produce the final pixel value.
+ pub alpha_op: BlendOp,
+
+ /// The operation to apply to the source alpha component before applying `alpha_op`.
+ pub alpha_source: BlendFactor,
+
+ /// The operation to apply to the destination alpha component before applying `alpha_op`.
+ pub alpha_destination: BlendFactor,
+}
+
+impl AttachmentBlend {
+ /// Builds an `AttachmentBlend` where the output of the fragment shader is ignored and the
+ /// destination is untouched.
+ #[inline]
+ pub fn ignore_source() -> Self {
+ Self {
+ color_op: BlendOp::Add,
+ color_source: BlendFactor::Zero,
+ color_destination: BlendFactor::DstColor,
+ alpha_op: BlendOp::Add,
+ alpha_source: BlendFactor::Zero,
+ alpha_destination: BlendFactor::DstColor,
+ }
+ }
+
+ /// Builds an `AttachmentBlend` where the output will be merged with the existing value
+ /// based on the alpha of the source.
+ #[inline]
+ pub fn alpha() -> Self {
+ Self {
+ color_op: BlendOp::Add,
+ color_source: BlendFactor::SrcAlpha,
+ color_destination: BlendFactor::OneMinusSrcAlpha,
+ alpha_op: BlendOp::Add,
+ alpha_source: BlendFactor::SrcAlpha,
+ alpha_destination: BlendFactor::OneMinusSrcAlpha,
+ }
+ }
+
+ /// Builds an `AttachmentBlend` where the colors are added, and alpha is set to the maximum of
+ /// the two.
+ #[inline]
+ pub fn additive() -> Self {
+ Self {
+ color_op: BlendOp::Add,
+ color_source: BlendFactor::One,
+ color_destination: BlendFactor::One,
+ alpha_op: BlendOp::Max,
+ alpha_source: BlendFactor::One,
+ alpha_destination: BlendFactor::One,
+ }
+ }
+}
+
+impl From<AttachmentBlend> for ash::vk::PipelineColorBlendAttachmentState {
+ #[inline]
+ fn from(val: AttachmentBlend) -> Self {
+ ash::vk::PipelineColorBlendAttachmentState {
+ blend_enable: ash::vk::TRUE,
+ src_color_blend_factor: val.color_source.into(),
+ dst_color_blend_factor: val.color_destination.into(),
+ color_blend_op: val.color_op.into(),
+ src_alpha_blend_factor: val.alpha_source.into(),
+ dst_alpha_blend_factor: val.alpha_destination.into(),
+ alpha_blend_op: val.alpha_op.into(),
+ color_write_mask: ash::vk::ColorComponentFlags::empty(), // Overwritten by GraphicsPipelineBuilder
+ }
+ }
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// The operation that takes `source` (output from the fragment shader), `destination` (value
+ /// currently in the framebuffer attachment) and `blend_constant` input values,
+ /// and produces new inputs to be fed to `BlendOp`.
+ ///
+ /// Some operations take `source1` as an input, representing the second source value. The
+ /// [`dual_src_blend`](crate::device::Features::dual_src_blend) feature must be enabled on the
+ /// device when these are used.
+ BlendFactor = BlendFactor(i32);
+
+ /// Always `0`.
+ Zero = ZERO,
+
+ /// Always `1`.
+ One = ONE,
+
+ /// `source` component-wise.
+ SrcColor = SRC_COLOR,
+
+ /// `1 - source` component-wise.
+ OneMinusSrcColor = ONE_MINUS_SRC_COLOR,
+
+ /// `destination` component-wise.
+ DstColor = DST_COLOR,
+
+ /// `1 - destination` component-wise.
+ OneMinusDstColor = ONE_MINUS_DST_COLOR,
+
+ /// `source.a` for all components.
+ SrcAlpha = SRC_ALPHA,
+
+ /// `1 - source.a` for all components.
+ OneMinusSrcAlpha = ONE_MINUS_SRC_ALPHA,
+
+ /// `destination.a` for all components.
+ DstAlpha = DST_ALPHA,
+
+ /// `1 - destination.a` for all components.
+ OneMinusDstAlpha = ONE_MINUS_DST_ALPHA,
+
+ /// `blend_constants` component-wise.
+ ConstantColor = CONSTANT_COLOR,
+
+ /// `1 - blend_constants` component-wise.
+ OneMinusConstantColor = ONE_MINUS_CONSTANT_COLOR,
+
+ /// `blend_constants.a` for all components.
+ ///
+ /// On [portability subset](crate::instance#portability-subset-devices-and-the-enumerate_portability-flag)
+ /// devices, if this value is used for the `color_source` or `color_destination` blend factors,
+ /// then the
+ /// [`constant_alpha_color_blend_factors`](crate::device::Features::constant_alpha_color_blend_factors)
+ /// feature must be enabled on the device.
+ ConstantAlpha = CONSTANT_ALPHA,
+
+ /// `1 - blend_constants.a` for all components.
+ ///
+ /// On [portability subset](crate::instance#portability-subset-devices-and-the-enumerate_portability-flag)
+ /// devices, if this value is used for the `color_source` or `color_destination` blend factors,
+ /// then the
+ /// [`constant_alpha_color_blend_factors`](crate::device::Features::constant_alpha_color_blend_factors)
+ /// feature must be enabled on the device.
+ OneMinusConstantAlpha = ONE_MINUS_CONSTANT_ALPHA,
+
+ /// For the alpha component, always `1`. For the color components,
+ /// `min(source.a, 1 - destination.a)` for all components.
+ SrcAlphaSaturate = SRC_ALPHA_SATURATE,
+
+ /// `source1` component-wise.
+ Src1Color = SRC1_COLOR,
+
+ /// `1 - source1` component-wise.
+ OneMinusSrc1Color = ONE_MINUS_SRC1_COLOR,
+
+ /// `source1.a` for all components.
+ Src1Alpha = SRC1_ALPHA,
+
+ /// `1 - source1.a` for all components.
+ OneMinusSrc1Alpha = ONE_MINUS_SRC1_ALPHA,
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// The arithmetic operation that is applied between the `source` and `destination` component
+ /// values, after the appropriate `BlendFactor` is applied to both.
+ BlendOp = BlendOp(i32);
+
+ /// `source + destination`.
+ Add = ADD,
+
+ /// `source - destination`.
+ Subtract = SUBTRACT,
+
+ /// `destination - source`.
+ ReverseSubtract = REVERSE_SUBTRACT,
+
+ /// `min(source, destination)`.
+ Min = MIN,
+
+ /// `max(source, destination)`.
+ Max = MAX,
+
+ /* TODO: enable
+ // TODO: document
+ Zero = ZERO_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ Src = SRC_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ Dst = DST_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ SrcOver = SRC_OVER_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ DstOver = DST_OVER_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ SrcIn = SRC_IN_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ DstIn = DST_IN_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ SrcOut = SRC_OUT_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ DstOut = DST_OUT_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ SrcAtop = SRC_ATOP_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ DstAtop = DST_ATOP_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ Xor = XOR_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ Multiply = MULTIPLY_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ Screen = SCREEN_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ Overlay = OVERLAY_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ Darken = DARKEN_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ Lighten = LIGHTEN_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ Colordodge = COLORDODGE_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ Colorburn = COLORBURN_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ Hardlight = HARDLIGHT_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ Softlight = SOFTLIGHT_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ Difference = DIFFERENCE_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ Exclusion = EXCLUSION_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ Invert = INVERT_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ InvertRgb = INVERT_RGB_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ Lineardodge = LINEARDODGE_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ Linearburn = LINEARBURN_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ Vividlight = VIVIDLIGHT_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ Linearlight = LINEARLIGHT_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ Pinlight = PINLIGHT_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ Hardmix = HARDMIX_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ HslHue = HSL_HUE_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ HslSaturation = HSL_SATURATION_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ HslColor = HSL_COLOR_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ HslLuminosity = HSL_LUMINOSITY_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ Plus = PLUS_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ PlusClamped = PLUS_CLAMPED_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ PlusClampedAlpha = PLUS_CLAMPED_ALPHA_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ PlusDarker = PLUS_DARKER_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ Minus = MINUS_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ MinusClamped = MINUS_CLAMPED_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ Contrast = CONTRAST_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ InvertOvg = INVERT_OVG_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ Red = RED_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ Green = GREEN_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ Blue = BLUE_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },*/
+}
+
+vulkan_bitflags! {
+ /// A mask specifying color components that can be written to a framebuffer attachment.
+ ColorComponents = ColorComponentFlags(u32);
+
+ /// The red component.
+ R = R,
+
+ /// The green component.
+ G = G,
+
+ /// The blue component.
+ B = B,
+
+ /// The alpha component.
+ A = A,
+}
diff --git a/src/pipeline/graphics/creation_error.rs b/src/pipeline/graphics/creation_error.rs
new file mode 100644
index 0000000..50a8b36
--- /dev/null
+++ b/src/pipeline/graphics/creation_error.rs
@@ -0,0 +1,451 @@
+// Copyright (c) 2017 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use super::vertex_input::IncompatibleVertexDefinitionError;
+use crate::{
+ descriptor_set::layout::DescriptorSetLayoutCreationError,
+ format::{Format, NumericType},
+ pipeline::layout::{PipelineLayoutCreationError, PipelineLayoutSupersetError},
+ shader::{ShaderInterfaceMismatchError, ShaderScalarType},
+ OomError, RequirementNotMet, RequiresOneOf, VulkanError,
+};
+use std::{
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+};
+
+/// Error that can happen when creating a graphics pipeline.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum GraphicsPipelineCreationError {
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+
+ /// A color attachment has a format that does not support blending.
+ ColorAttachmentFormatBlendNotSupported { attachment_index: u32 },
+
+ /// A color attachment has a format that does not support that usage.
+ ColorAttachmentFormatUsageNotSupported { attachment_index: u32 },
+
+ /// The depth attachment has a format that does not support that usage.
+ DepthAttachmentFormatUsageNotSupported,
+
+ /// The depth and stencil attachments have different formats.
+ DepthStencilAttachmentFormatMismatch,
+
+ /// The output of the fragment shader is not compatible with what the render pass subpass
+ /// expects.
+ FragmentShaderRenderPassIncompatible,
+
+ /// The pipeline layout is not compatible with what the shaders expect.
+ IncompatiblePipelineLayout(PipelineLayoutSupersetError),
+
+ /// The provided specialization constants are not compatible with what the shader expects.
+ IncompatibleSpecializationConstants,
+
+ /// The vertex definition is not compatible with the input of the vertex shader.
+ IncompatibleVertexDefinition(IncompatibleVertexDefinitionError),
+
+ /// Tried to use a patch list without a tessellation shader, or a non-patch-list with a
+ /// tessellation shader.
+ InvalidPrimitiveTopology,
+
+ /// `patch_control_points` was not greater than 0 and less than or equal to the `max_tessellation_patch_size` limit.
+ InvalidNumPatchControlPoints,
+
+ /// The maximum number of discard rectangles has been exceeded.
+ MaxDiscardRectanglesExceeded {
+ /// Maximum allowed value.
+ max: u32,
+ /// Value that was passed.
+ obtained: u32,
+ },
+
+ /// The `max_multiview_view_count` limit has been exceeded.
+ MaxMultiviewViewCountExceeded { view_count: u32, max: u32 },
+
+ /// The maximum value for the instance rate divisor has been exceeded.
+ MaxVertexAttribDivisorExceeded {
+ /// Index of the faulty binding.
+ binding: u32,
+ /// Maximum allowed value.
+ max: u32,
+ /// Value that was passed.
+ obtained: u32,
+ },
+
+ /// The maximum number of vertex attributes has been exceeded.
+ MaxVertexInputAttributesExceeded {
+ /// Maximum allowed value.
+ max: u32,
+ /// Value that was passed.
+ obtained: usize,
+ },
+
+ /// The maximum offset for a vertex attribute has been exceeded. This means that your vertex
+ /// struct is too large.
+ MaxVertexInputAttributeOffsetExceeded {
+ /// Maximum allowed value.
+ max: u32,
+ /// Value that was passed.
+ obtained: u32,
+ },
+
+ /// The maximum number of vertex sources has been exceeded.
+ MaxVertexInputBindingsExceeded {
+ /// Maximum allowed value.
+ max: u32,
+ /// Value that was passed.
+ obtained: u32,
+ },
+
+ /// The maximum stride value for vertex input (ie. the distance between two vertex elements)
+ /// has been exceeded.
+ MaxVertexInputBindingStrideExceeded {
+ /// Index of the faulty binding.
+ binding: u32,
+ /// Maximum allowed value.
+ max: u32,
+ /// Value that was passed.
+ obtained: u32,
+ },
+
+ /// The maximum number of viewports has been exceeded.
+ MaxViewportsExceeded {
+ /// Maximum allowed value.
+ max: u32,
+ /// Value that was passed.
+ obtained: u32,
+ },
+
+ /// The `min_vertex_input_binding_stride_alignment` limit was exceeded.
+ MinVertexInputBindingStrideAlignmentExceeded {
+ /// Index of the faulty binding.
+ binding: u32,
+ /// Maximum allowed value.
+ max: u32,
+ /// Value that was passed.
+ obtained: u32,
+ },
+
+ /// The maximum dimensions of viewports has been exceeded.
+ MaxViewportDimensionsExceeded,
+
+ /// The number of attachments specified in the blending does not match the number of
+ /// attachments in the subpass.
+ MismatchBlendingAttachmentsCount,
+
+ /// The provided `rasterization_samples` does not match the number of samples of the render
+ /// subpass.
+ MultisampleRasterizationSamplesMismatch,
+
+ /// The depth test requires a depth attachment but render pass has no depth attachment, or
+ /// depth writing is enabled and the depth attachment is read-only.
+ NoDepthAttachment,
+
+ /// The stencil test requires a stencil attachment but render pass has no stencil attachment, or
+ /// stencil writing is enabled and the stencil attachment is read-only.
+ NoStencilAttachment,
+
+ /// Not enough memory.
+ OomError(OomError),
+
+ /// Error while creating a descriptor set layout object.
+ DescriptorSetLayoutCreationError(DescriptorSetLayoutCreationError),
+
+ /// Error while creating the pipeline layout object.
+ PipelineLayoutCreationError(PipelineLayoutCreationError),
+
+ /// The output interface of one shader and the input interface of the next shader do not match.
+ ShaderStagesMismatch(ShaderInterfaceMismatchError),
+
+ /// The stencil attachment has a format that does not support that usage.
+ StencilAttachmentFormatUsageNotSupported,
+
+ /// The [`strict_lines`](crate::device::Properties::strict_lines) device property was `false`.
+ StrictLinesNotSupported,
+
+ /// The primitives topology does not match what the geometry shader expects.
+ TopologyNotMatchingGeometryShader,
+
+ /// The type of the shader input variable at the given location is not compatible with the
+ /// format of the corresponding vertex input attribute.
+ VertexInputAttributeIncompatibleFormat {
+ location: u32,
+ shader_type: ShaderScalarType,
+ attribute_type: NumericType,
+ },
+
+ /// The location provided is assigned, but expected to unassigned due to the format of the
+ /// prior location.
+ VertexInputAttributeInvalidAssignedLocation { location: u32 },
+
+ /// The binding number specified by a vertex input attribute does not exist in the provided list
+ /// of binding descriptions.
+ VertexInputAttributeInvalidBinding { location: u32, binding: u32 },
+
+ /// The vertex shader expects an input variable at the given location, but no vertex input
+ /// attribute exists for that location.
+ VertexInputAttributeMissing { location: u32 },
+
+ /// The format specified by a vertex input attribute is not supported for vertex buffers.
+ VertexInputAttributeUnsupportedFormat { location: u32, format: Format },
+
+ /// The minimum or maximum bounds of viewports have been exceeded.
+ ViewportBoundsExceeded,
+
+ /// The wrong type of shader has been passed.
+ ///
+ /// For example you passed a vertex shader as the fragment shader.
+ WrongShaderType,
+
+ /// The requested stencil test is invalid.
+ WrongStencilState,
+}
+
+impl Error for GraphicsPipelineCreationError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::OomError(err) => Some(err),
+ Self::PipelineLayoutCreationError(err) => Some(err),
+ Self::IncompatiblePipelineLayout(err) => Some(err),
+ Self::ShaderStagesMismatch(err) => Some(err),
+ Self::IncompatibleVertexDefinition(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+impl Display for GraphicsPipelineCreationError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ Self::ColorAttachmentFormatBlendNotSupported { attachment_index } => write!(
+ f,
+ "color attachment {} has a format that does not support blending",
+ attachment_index,
+ ),
+ Self::ColorAttachmentFormatUsageNotSupported { attachment_index } => write!(
+ f,
+ "color attachment {} has a format that does not support that usage",
+ attachment_index,
+ ),
+ Self::DepthAttachmentFormatUsageNotSupported => write!(
+ f,
+ "the depth attachment has a format that does not support that usage",
+ ),
+ Self::DepthStencilAttachmentFormatMismatch => write!(
+ f,
+ "the depth and stencil attachments have different formats",
+ ),
+ Self::FragmentShaderRenderPassIncompatible => write!(
+ f,
+ "the output of the fragment shader is not compatible with what the render pass \
+ subpass expects",
+ ),
+ Self::IncompatiblePipelineLayout(_) => write!(
+ f,
+ "the pipeline layout is not compatible with what the shaders expect",
+ ),
+ Self::IncompatibleSpecializationConstants => write!(
+ f,
+ "the provided specialization constants are not compatible with what the shader \
+ expects",
+ ),
+ Self::IncompatibleVertexDefinition(_) => write!(
+ f,
+ "the vertex definition is not compatible with the input of the vertex shader",
+ ),
+ Self::InvalidPrimitiveTopology => write!(
+ f,
+ "trying to use a patch list without a tessellation shader, or a non-patch-list \
+ with a tessellation shader",
+ ),
+ Self::InvalidNumPatchControlPoints => write!(
+ f,
+ "patch_control_points was not greater than 0 and less than or equal to the \
+ max_tessellation_patch_size limit",
+ ),
+ Self::MaxDiscardRectanglesExceeded { .. } => write!(
+ f,
+ "the maximum number of discard rectangles has been exceeded",
+ ),
+ Self::MaxMultiviewViewCountExceeded { .. } => {
+ write!(f, "the `max_multiview_view_count` limit has been exceeded")
+ }
+ Self::MaxVertexAttribDivisorExceeded { .. } => write!(
+ f,
+ "the maximum value for the instance rate divisor has been exceeded",
+ ),
+ Self::MaxVertexInputAttributesExceeded { .. } => write!(
+ f,
+ "the maximum number of vertex attributes has been exceeded",
+ ),
+ Self::MaxVertexInputAttributeOffsetExceeded { .. } => write!(
+ f,
+ "the maximum offset for a vertex attribute has been exceeded",
+ ),
+ Self::MaxVertexInputBindingsExceeded { .. } => {
+ write!(f, "the maximum number of vertex sources has been exceeded")
+ }
+ Self::MaxVertexInputBindingStrideExceeded { .. } => write!(
+ f,
+ "the maximum stride value for vertex input (ie. the distance between two vertex \
+ elements) has been exceeded",
+ ),
+ Self::MaxViewportsExceeded { .. } => {
+ write!(f, "the maximum number of viewports has been exceeded")
+ }
+ Self::MaxViewportDimensionsExceeded => {
+ write!(f, "the maximum dimensions of viewports has been exceeded")
+ }
+ Self::MinVertexInputBindingStrideAlignmentExceeded { .. } => write!(
+ f,
+ "the `min_vertex_input_binding_stride_alignment` limit has been exceeded",
+ ),
+ Self::MismatchBlendingAttachmentsCount => write!(
+ f,
+ "the number of attachments specified in the blending does not match the number of \
+ attachments in the subpass",
+ ),
+ Self::MultisampleRasterizationSamplesMismatch => write!(
+ f,
+ "the provided `rasterization_samples` does not match the number of samples of the \
+ render subpass",
+ ),
+ Self::NoDepthAttachment => write!(
+ f,
+ "the depth attachment of the render pass does not match the depth test",
+ ),
+ Self::NoStencilAttachment => write!(
+ f,
+ "the stencil attachment of the render pass does not match the stencil test",
+ ),
+ Self::OomError(_) => write!(f, "not enough memory available"),
+ Self::DescriptorSetLayoutCreationError(_) => {
+ write!(f, "error while creating a descriptor set layout object")
+ }
+ Self::PipelineLayoutCreationError(_) => {
+ write!(f, "error while creating the pipeline layout object")
+ }
+ Self::ShaderStagesMismatch(_) => write!(
+ f,
+ "the output interface of one shader and the input interface of the next shader do \
+ not match",
+ ),
+ Self::StencilAttachmentFormatUsageNotSupported => write!(
+ f,
+ "the stencil attachment has a format that does not support that usage",
+ ),
+ Self::StrictLinesNotSupported => {
+ write!(f, "the strict_lines device property was false")
+ }
+ Self::TopologyNotMatchingGeometryShader => write!(
+ f,
+ "the primitives topology does not match what the geometry shader expects",
+ ),
+ Self::VertexInputAttributeIncompatibleFormat {
+ location,
+ shader_type,
+ attribute_type,
+ } => write!(
+ f,
+ "the type of the shader input variable at location {} ({:?}) is not compatible \
+ with the format of the corresponding vertex input attribute ({:?})",
+ location, shader_type, attribute_type,
+ ),
+ Self::VertexInputAttributeInvalidAssignedLocation { location } => write!(
+ f,
+ "input attribute location {} is expected to be unassigned due to the format of the prior location",
+ location,
+ ),
+ Self::VertexInputAttributeInvalidBinding { location, binding } => write!(
+ f,
+ "the binding number {} specified by vertex input attribute location {} does not \
+ exist in the provided list of binding descriptions",
+ binding, location,
+ ),
+ Self::VertexInputAttributeMissing { location } => write!(
+ f,
+ "the vertex shader expects an input variable at location {}, but no vertex input \
+ attribute exists for that location",
+ location,
+ ),
+ Self::VertexInputAttributeUnsupportedFormat { location, format } => write!(
+ f,
+ "the format {:?} specified by vertex input attribute location {} is not supported \
+ for vertex buffers",
+ format, location,
+ ),
+ Self::ViewportBoundsExceeded => write!(
+ f,
+ "the minimum or maximum bounds of viewports have been exceeded",
+ ),
+ Self::WrongShaderType => write!(f, "the wrong type of shader has been passed"),
+ Self::WrongStencilState => write!(f, "the requested stencil test is invalid"),
+ }
+ }
+}
+
+impl From<OomError> for GraphicsPipelineCreationError {
+ fn from(err: OomError) -> GraphicsPipelineCreationError {
+ Self::OomError(err)
+ }
+}
+
+impl From<DescriptorSetLayoutCreationError> for GraphicsPipelineCreationError {
+ fn from(err: DescriptorSetLayoutCreationError) -> Self {
+ Self::DescriptorSetLayoutCreationError(err)
+ }
+}
+
+impl From<PipelineLayoutCreationError> for GraphicsPipelineCreationError {
+ fn from(err: PipelineLayoutCreationError) -> Self {
+ Self::PipelineLayoutCreationError(err)
+ }
+}
+
+impl From<PipelineLayoutSupersetError> for GraphicsPipelineCreationError {
+ fn from(err: PipelineLayoutSupersetError) -> Self {
+ Self::IncompatiblePipelineLayout(err)
+ }
+}
+
+impl From<IncompatibleVertexDefinitionError> for GraphicsPipelineCreationError {
+ fn from(err: IncompatibleVertexDefinitionError) -> Self {
+ Self::IncompatibleVertexDefinition(err)
+ }
+}
+
+impl From<VulkanError> for GraphicsPipelineCreationError {
+ fn from(err: VulkanError) -> Self {
+ match err {
+ err @ VulkanError::OutOfHostMemory => Self::OomError(OomError::from(err)),
+ err @ VulkanError::OutOfDeviceMemory => Self::OomError(OomError::from(err)),
+ _ => panic!("unexpected error: {:?}", err),
+ }
+ }
+}
+
+impl From<RequirementNotMet> for GraphicsPipelineCreationError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
+ }
+ }
+}
diff --git a/src/pipeline/graphics/depth_stencil.rs b/src/pipeline/graphics/depth_stencil.rs
new file mode 100644
index 0000000..650be60
--- /dev/null
+++ b/src/pipeline/graphics/depth_stencil.rs
@@ -0,0 +1,338 @@
+// Copyright (c) 2016 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+//! Configures the operation of the depth, stencil and depth bounds tests.
+//!
+//! The depth test passes of fails depending on how the depth value of each fragment compares
+//! to the existing depth value in the depth buffer at that fragment's location. Depth values
+//! are always between 0.0 and 1.0.
+//!
+//! The depth bounds test allows you to ask the GPU to exclude fragments that are outside of a
+//! certain range. This is done in addition to the regular depth test.
+//!
+//! The stencil test passes or fails depending on how a reference value compares to the existing
+//! value in the stencil buffer at each fragment's location. Depending on the outcome of the
+//! depth and stencil tests, the value of the stencil buffer at that location can be updated.
+
+use crate::{macros::vulkan_enum, pipeline::StateMode};
+use std::ops::RangeInclusive;
+
+/// The state in a graphics pipeline describing how the depth, depth bounds and stencil tests
+/// should behave.
+#[derive(Clone, Debug)]
+pub struct DepthStencilState {
+ /// The state of the depth test.
+ ///
+ /// If set to `None`, the depth test is disabled, all fragments will pass and no depth writes
+ /// are performed.
+ pub depth: Option<DepthState>,
+
+ /// The state of the depth bounds test.
+ ///
+ /// If set to `None`, the depth bounds test is disabled, all fragments will pass.
+ pub depth_bounds: Option<DepthBoundsState>,
+
+ /// The state of the stencil test.
+ ///
+ /// If set to `None`, the stencil test is disabled, all fragments will pass and no stencil
+ /// writes are performed.
+ pub stencil: Option<StencilState>,
+}
+
+impl DepthStencilState {
+ /// Creates a `DepthStencilState` where all tests are disabled and have no effect.
+ #[inline]
+ pub fn disabled() -> Self {
+ Self {
+ depth: Default::default(),
+ depth_bounds: Default::default(),
+ stencil: Default::default(),
+ }
+ }
+
+ /// Creates a `DepthStencilState` with a `Less` depth test, `depth_write` set to true, and other
+ /// tests disabled.
+ #[inline]
+ pub fn simple_depth_test() -> Self {
+ Self {
+ depth: Some(DepthState {
+ enable_dynamic: false,
+ compare_op: StateMode::Fixed(CompareOp::Less),
+ write_enable: StateMode::Fixed(true),
+ }),
+ depth_bounds: Default::default(),
+ stencil: Default::default(),
+ }
+ }
+}
+
+impl Default for DepthStencilState {
+ /// Returns [`DepthStencilState::disabled()`].
+ #[inline]
+ fn default() -> Self {
+ DepthStencilState::disabled()
+ }
+}
+
+/// The state in a graphics pipeline describing how the depth test should behave when enabled.
+#[derive(Clone, Copy, Debug)]
+pub struct DepthState {
+ /// Sets whether depth testing should be enabled and disabled dynamically. If set to `false`,
+ /// depth testing is always enabled.
+ ///
+ /// If set to `true`, the device API version must be at least 1.3, or the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must be
+ /// enabled on the device.
+ pub enable_dynamic: bool,
+
+ /// Sets whether the value in the depth buffer will be updated when the depth test succeeds.
+ ///
+ /// If set to `Dynamic`, the device API version must be at least 1.3, or the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must be
+ /// enabled on the device.
+ pub write_enable: StateMode<bool>,
+
+ /// Comparison operation to use between the depth value of each incoming fragment and the depth
+ /// value currently in the depth buffer.
+ ///
+ /// If set to `Dynamic`, the device API version must be at least 1.3, or the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must be
+ /// enabled on the device.
+ pub compare_op: StateMode<CompareOp>,
+}
+
+impl Default for DepthState {
+ /// Creates a `DepthState` with no dynamic state, depth writes disabled and `compare_op` set
+ /// to always pass.
+ #[inline]
+ fn default() -> Self {
+ Self {
+ enable_dynamic: false,
+ write_enable: StateMode::Fixed(false),
+ compare_op: StateMode::Fixed(CompareOp::Always),
+ }
+ }
+}
+
+/// The state in a graphics pipeline describing how the depth bounds test should behave when
+/// enabled.
+#[derive(Clone, Debug)]
+pub struct DepthBoundsState {
+ /// Sets whether depth bounds testing should be enabled and disabled dynamically. If set to
+ /// `false`, depth bounds testing is always enabled.
+ ///
+ /// If set to `true`, the device API version must be at least 1.3, or the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must be
+ /// enabled on the device.
+ pub enable_dynamic: bool,
+
+ /// The minimum and maximum depth values to use for the test. Fragments with values outside this
+ /// range are discarded.
+ ///
+ /// If set to `Dynamic`, the device API version must be at least 1.3, or the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must be
+ /// enabled on the device.
+ pub bounds: StateMode<RangeInclusive<f32>>,
+}
+
+impl Default for DepthBoundsState {
+ /// Creates a `DepthBoundsState` with no dynamic state and the bounds set to `0.0..=1.0`.
+ #[inline]
+ fn default() -> Self {
+ Self {
+ enable_dynamic: false,
+ bounds: StateMode::Fixed(0.0..=1.0),
+ }
+ }
+}
+
+/// The state in a graphics pipeline describing how the stencil test should behave when enabled.
+///
+/// Dynamic state can only be enabled or disabled for both faces at once. Therefore, the dynamic
+/// state values in `StencilOpState`, must match: the values for `front` and `back` must either both
+/// be `Fixed` or both be `Dynamic`.
+#[derive(Clone, Debug)]
+pub struct StencilState {
+ /// Sets whether stencil testing should be enabled and disabled dynamically. If set to
+ /// `false`, stencil testing is always enabled.
+ ///
+ /// If set to `true`, the device API version must be at least 1.3, or the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must be
+ /// enabled on the device.
+ pub enable_dynamic: bool,
+
+ /// The stencil operation state to use for points and lines, and for triangles whose front is
+ /// facing the user.
+ pub front: StencilOpState,
+
+ /// The stencil operation state to use for triangles whose back is facing the user.
+ pub back: StencilOpState,
+}
+
+/// Stencil test operations for a single face.
+#[derive(Clone, Copy, Debug)]
+pub struct StencilOpState {
+ /// The stencil operations to perform.
+ ///
+ /// If set to `Dynamic`, the device API version must be at least 1.3, or the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must be
+ /// enabled on the device.
+ pub ops: StateMode<StencilOps>,
+
+ /// A bitmask that selects the bits of the unsigned integer stencil values participating in the
+ /// stencil test. Ignored if `compare_op` is `Never` or `Always`.
+ pub compare_mask: StateMode<u32>,
+
+ /// A bitmask that selects the bits of the unsigned integer stencil values updated by the
+ /// stencil test in the stencil framebuffer attachment. Ignored if the relevant operation is
+ /// `Keep`.
+ pub write_mask: StateMode<u32>,
+
+ /// Reference value that is used in the unsigned stencil comparison. The stencil test is
+ /// considered to pass if the `compare_op` between the stencil buffer value and this reference
+ /// value yields true.
+ ///
+ /// On [portability subset](crate::instance#portability-subset-devices-and-the-enumerate_portability-flag)
+ /// devices, if culling is disabled, and the `reference` values of the front and back face
+ /// are not equal, then the
+ /// [`separate_stencil_mask_ref`](crate::device::Features::separate_stencil_mask_ref)
+ /// feature must be enabled on the device.
+ pub reference: StateMode<u32>,
+}
+
+impl Default for StencilOpState {
+ /// Creates a `StencilOpState` with no dynamic state, `compare_op` set to `Never`, the stencil
+ /// operations set to `Keep`, and the masks and reference values set to `u32::MAX`.
+ #[inline]
+ fn default() -> StencilOpState {
+ StencilOpState {
+ ops: StateMode::Fixed(Default::default()),
+ compare_mask: StateMode::Fixed(u32::MAX),
+ write_mask: StateMode::Fixed(u32::MAX),
+ reference: StateMode::Fixed(u32::MAX),
+ }
+ }
+}
+
+#[derive(Clone, Copy, Debug)]
+pub struct StencilOps {
+ /// The operation to perform when the stencil test failed.
+ pub fail_op: StencilOp,
+
+ /// The operation to perform when both the depth test and the stencil test passed.
+ pub pass_op: StencilOp,
+
+ /// The operation to perform when the stencil test passed but the depth test failed.
+ pub depth_fail_op: StencilOp,
+
+ /// The comparison to perform between the existing stencil value in the stencil buffer, and
+ /// the reference value (given by `reference`).
+ pub compare_op: CompareOp,
+}
+
+impl Default for StencilOps {
+ /// Creates a `StencilOps` with no dynamic state, `compare_op` set to `Never` and the stencil
+ /// operations set to `Keep`.
+ #[inline]
+ fn default() -> Self {
+ Self {
+ pass_op: StencilOp::Keep,
+ fail_op: StencilOp::Keep,
+ depth_fail_op: StencilOp::Keep,
+ compare_op: CompareOp::Never,
+ }
+ }
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// Operation to perform after the depth and stencil tests.
+ StencilOp = StencilOp(i32);
+
+ // TODO: document
+ Keep = KEEP,
+
+ // TODO: document
+ Zero = ZERO,
+
+ // TODO: document
+ Replace = REPLACE,
+
+ // TODO: document
+ IncrementAndClamp = INCREMENT_AND_CLAMP,
+
+ // TODO: document
+ DecrementAndClamp = DECREMENT_AND_CLAMP,
+
+ // TODO: document
+ Invert = INVERT,
+
+ // TODO: document
+ IncrementAndWrap = INCREMENT_AND_WRAP,
+
+ // TODO: document
+ DecrementAndWrap = DECREMENT_AND_WRAP,
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// Specifies a face for stencil operations.
+ StencilFaces = StencilFaceFlags(u32);
+
+ // TODO: document
+ Front = FRONT,
+
+ // TODO: document
+ Back = BACK,
+
+ // TODO: document
+ FrontAndBack = FRONT_AND_BACK,
+}
+
+/// Specifies a dynamic state value for the front and back faces.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct DynamicStencilValue {
+ pub front: u32,
+ pub back: u32,
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// Specifies how two values should be compared to decide whether a test passes or fails.
+ ///
+ /// Used for both depth testing and stencil testing.
+ CompareOp = CompareOp(i32);
+
+ /// The test never passes.
+ Never = NEVER,
+
+ /// The test passes if `value < reference_value`.
+ Less = LESS,
+
+ /// The test passes if `value == reference_value`.
+ Equal = EQUAL,
+
+ /// The test passes if `value <= reference_value`.
+ LessOrEqual = LESS_OR_EQUAL,
+
+ /// The test passes if `value > reference_value`.
+ Greater = GREATER,
+
+ /// The test passes if `value != reference_value`.
+ NotEqual = NOT_EQUAL,
+
+ /// The test passes if `value >= reference_value`.
+ GreaterOrEqual = GREATER_OR_EQUAL,
+
+ /// The test always passes.
+ Always = ALWAYS,
+}
diff --git a/src/pipeline/graphics/discard_rectangle.rs b/src/pipeline/graphics/discard_rectangle.rs
new file mode 100644
index 0000000..3548870
--- /dev/null
+++ b/src/pipeline/graphics/discard_rectangle.rs
@@ -0,0 +1,66 @@
+// Copyright (c) 2016 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+//! A test to discard pixels that would be written to certain areas of a framebuffer.
+//!
+//! The discard rectangle test is similar to, but separate from the scissor test.
+
+use crate::{
+ macros::vulkan_enum,
+ pipeline::{graphics::viewport::Scissor, PartialStateMode},
+};
+
+/// The state in a graphics pipeline describing how the discard rectangle test should behave.
+#[derive(Clone, Debug)]
+pub struct DiscardRectangleState {
+ /// Sets whether the discard rectangle test operates inclusively or exclusively.
+ pub mode: DiscardRectangleMode,
+
+ /// Specifies the discard rectangles. If set to `Dynamic`, it specifies only the number of
+ /// rectangles used from the dynamic state.
+ ///
+ /// If set to `Dynamic` or to `Fixed` with a non-empty list, the
+ /// [`ext_discard_rectangles`](crate::device::DeviceExtensions::ext_discard_rectangles)
+ /// extension must be enabled on the device.
+ pub rectangles: PartialStateMode<Vec<Scissor>, u32>,
+}
+
+impl DiscardRectangleState {
+ /// Creates a `DiscardRectangleState` in exclusive mode with zero rectangles.
+ #[inline]
+ pub fn new() -> Self {
+ Self {
+ mode: DiscardRectangleMode::Exclusive,
+ rectangles: PartialStateMode::Fixed(Vec::new()),
+ }
+ }
+}
+
+impl Default for DiscardRectangleState {
+ /// Returns [`DiscardRectangleState::new`].
+ #[inline]
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// The mode in which the discard rectangle test operates.
+ DiscardRectangleMode = DiscardRectangleModeEXT(i32);
+
+ /// Samples that are inside a rectangle are kept, samples that are outside all rectangles
+ /// are discarded.
+ Inclusive = INCLUSIVE,
+
+ /// Samples that are inside a rectangle are discarded, samples that are outside all rectangles
+ /// are kept.
+ Exclusive = EXCLUSIVE,
+}
diff --git a/src/pipeline/graphics/input_assembly.rs b/src/pipeline/graphics/input_assembly.rs
new file mode 100644
index 0000000..0e4feda
--- /dev/null
+++ b/src/pipeline/graphics/input_assembly.rs
@@ -0,0 +1,262 @@
+// Copyright (c) 2016 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+//! Configures how input vertices are assembled into primitives.
+
+use crate::{
+ buffer::BufferContents,
+ macros::vulkan_enum,
+ pipeline::{PartialStateMode, StateMode},
+ DeviceSize,
+};
+
+/// The state in a graphics pipeline describing how the input assembly stage should behave.
+#[derive(Clone, Copy, Debug)]
+pub struct InputAssemblyState {
+ /// The type of primitives.
+ ///
+ /// Note that some topologies require a feature to be enabled on the device.
+ ///
+ /// If set to `Dynamic`, the device API version must be at least 1.3, or the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must be
+ /// enabled on the device.
+ pub topology: PartialStateMode<PrimitiveTopology, PrimitiveTopologyClass>,
+
+ /// If true, then when drawing with an index buffer, the special index value consisting of the
+ /// maximum unsigned value (`0xff`, `0xffff` or `0xffffffff`) will tell the GPU that it is the
+ /// end of the current primitive. A new primitive will restart at the next index.
+ ///
+ /// Primitive restart is mostly useful in combination with "strip" and "fan" topologies. "List"
+ /// topologies require a feature to be enabled on the device when combined with primitive
+ /// restart.
+ ///
+ /// If set to `Dynamic`, the device API version must be at least 1.3, or the
+ /// [`extended_dynamic_state2`](crate::device::Features::extended_dynamic_state2) feature must
+ /// be enabled on the device.
+ pub primitive_restart_enable: StateMode<bool>,
+}
+
+impl InputAssemblyState {
+ /// Creates an `InputAssemblyState` with the `TriangleList` topology and primitive restart
+ /// disabled.
+ #[inline]
+ pub fn new() -> Self {
+ Self {
+ topology: PartialStateMode::Fixed(PrimitiveTopology::TriangleList),
+ primitive_restart_enable: StateMode::Fixed(false),
+ }
+ }
+
+ /// Sets the primitive topology.
+ #[inline]
+ pub fn topology(mut self, topology: PrimitiveTopology) -> Self {
+ self.topology = PartialStateMode::Fixed(topology);
+ self
+ }
+
+ /// Sets the primitive topology to dynamic.
+ #[inline]
+ pub fn topology_dynamic(mut self, topology_class: PrimitiveTopologyClass) -> Self {
+ self.topology = PartialStateMode::Dynamic(topology_class);
+ self
+ }
+
+ /// Enables primitive restart.
+ #[inline]
+ pub fn primitive_restart_enable(mut self) -> Self {
+ self.primitive_restart_enable = StateMode::Fixed(true);
+ self
+ }
+
+ /// Sets primitive restart enable to dynmamic.
+ #[inline]
+ pub fn primitive_restart_enable_dynamic(mut self) -> Self {
+ self.primitive_restart_enable = StateMode::Dynamic;
+ self
+ }
+}
+
+impl Default for InputAssemblyState {
+ /// Returns [`InputAssemblyState::new()`].
+ #[inline]
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// Describes how vertices must be grouped together to form primitives.
+ ///
+ /// When enabling primitive restart, "list" topologies require a feature to be enabled on the
+ /// device:
+ /// - The `PatchList` topology requires the
+ /// [`primitive_topology_patch_list_restart`](crate::device::Features::primitive_topology_patch_list_restart)
+ /// feature.
+ /// - All other "list" topologies require the
+ /// [`primitive_topology_list_restart`](crate::device::Features::primitive_topology_list_restart)
+ /// feature.
+ PrimitiveTopology impl {
+ /// Returns the topology class of this topology.
+ #[inline]
+ pub fn class(self) -> PrimitiveTopologyClass {
+ match self {
+ Self::PointList => PrimitiveTopologyClass::Point,
+ Self::LineList
+ | Self::LineStrip
+ | Self::LineListWithAdjacency
+ | Self::LineStripWithAdjacency => PrimitiveTopologyClass::Line,
+ Self::TriangleList
+ | Self::TriangleStrip
+ | Self::TriangleFan
+ | Self::TriangleListWithAdjacency
+ | Self::TriangleStripWithAdjacency => PrimitiveTopologyClass::Triangle,
+ Self::PatchList => PrimitiveTopologyClass::Patch,
+ }
+ }
+ }
+ = PrimitiveTopology(i32);
+
+ /// A series of separate point primitives.
+ PointList = POINT_LIST,
+
+ /// A series of separate line primitives.
+ LineList = LINE_LIST,
+
+ /// A series of consecutive line primitives, with consecutive lines sharing a vertex.
+ LineStrip = LINE_STRIP,
+
+ /// A series of separate triangle primitives.
+ TriangleList = TRIANGLE_LIST,
+
+ /// A series of consecutive triangle primitives, with consecutive triangles sharing an edge (two vertices).
+ TriangleStrip = TRIANGLE_STRIP,
+
+ /// A series of consecutive triangle primitives, with all triangles sharing a common vertex (the first).
+ ///
+ /// On [portability subset](crate::instance#portability-subset-devices-and-the-enumerate_portability-flag)
+ /// devices, the [`triangle_fans`](crate::device::Features::triangle_fans)
+ /// feature must be enabled on the device.
+ TriangleFan = TRIANGLE_FAN,
+
+ /// As `LineList, but with adjacency, used in combination with geometry shaders. Requires the
+ /// [`geometry_shader`](crate::device::Features::geometry_shader) feature.
+ LineListWithAdjacency = LINE_LIST_WITH_ADJACENCY,
+
+ /// As `LineStrip`, but with adjacency, used in combination with geometry shaders. Requires the
+ /// [`geometry_shader`](crate::device::Features::geometry_shader) feature.
+ LineStripWithAdjacency = LINE_STRIP_WITH_ADJACENCY,
+
+ /// As `TriangleList`, but with adjacency, used in combination with geometry shaders. Requires
+ /// the [`geometry_shader`](crate::device::Features::geometry_shader) feature.
+ TriangleListWithAdjacency = TRIANGLE_LIST_WITH_ADJACENCY,
+
+ /// As `TriangleStrip`, but with adjacency, used in combination with geometry shaders. Requires
+ /// the [`geometry_shader`](crate::device::Features::geometry_shader) feature.
+ TriangleStripWithAdjacency = TRIANGLE_STRIP_WITH_ADJACENCY,
+
+ /// Separate patch primitives, used in combination with tessellation shaders. Requires the
+ /// [`tessellation_shader`](crate::device::Features::tessellation_shader) feature.
+ PatchList = PATCH_LIST,
+
+}
+
+// TODO: use the #[default] attribute once it's stable.
+// See: https://github.com/rust-lang/rust/issues/87517
+impl Default for PrimitiveTopology {
+ #[inline]
+ fn default() -> Self {
+ PrimitiveTopology::TriangleList
+ }
+}
+
+/// Describes the shape of a primitive topology.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub enum PrimitiveTopologyClass {
+ Point,
+ Line,
+ Triangle,
+ Patch,
+}
+
+impl PrimitiveTopologyClass {
+ /// Returns a representative example of this topology class.
+ pub(crate) fn example(self) -> PrimitiveTopology {
+ match self {
+ Self::Point => PrimitiveTopology::PointList,
+ Self::Line => PrimitiveTopology::LineList,
+ Self::Triangle => PrimitiveTopology::TriangleList,
+ Self::Patch => PrimitiveTopology::PatchList,
+ }
+ }
+}
+
+/// Trait for types that can be used as indices by the GPU.
+pub unsafe trait Index: BufferContents + Sized {
+ /// Returns the type of data.
+ fn ty() -> IndexType;
+}
+
+unsafe impl Index for u8 {
+ #[inline(always)]
+ fn ty() -> IndexType {
+ IndexType::U8
+ }
+}
+
+unsafe impl Index for u16 {
+ #[inline(always)]
+ fn ty() -> IndexType {
+ IndexType::U16
+ }
+}
+
+unsafe impl Index for u32 {
+ #[inline(always)]
+ fn ty() -> IndexType {
+ IndexType::U32
+ }
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// An enumeration of all valid index types.
+ IndexType = IndexType(i32);
+
+ // TODO: document
+ U8 = UINT8_EXT {
+ device_extensions: [ext_index_type_uint8],
+ },
+
+ // TODO: document
+ U16 = UINT16,
+
+ // TODO: document
+ U32 = UINT32,
+
+ /* TODO: enable
+ // TODO: document
+ None = NONE_KHR {
+ device_extensions: [khr_acceleration_structure, nv_ray_tracing],
+ },*/
+}
+
+impl IndexType {
+ /// Returns the size in bytes of indices of this type.
+ #[inline]
+ pub fn size(self) -> DeviceSize {
+ match self {
+ IndexType::U8 => 1,
+ IndexType::U16 => 2,
+ IndexType::U32 => 4,
+ }
+ }
+}
diff --git a/src/pipeline/graphics/mod.rs b/src/pipeline/graphics/mod.rs
new file mode 100644
index 0000000..a85e8b5
--- /dev/null
+++ b/src/pipeline/graphics/mod.rs
@@ -0,0 +1,302 @@
+// Copyright (c) 2017 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+//! A pipeline that performs graphics processing operations.
+//!
+//! Unlike a compute pipeline, which performs general-purpose work, a graphics pipeline is geared
+//! specifically towards doing graphical processing. To that end, it consists of several shaders,
+//! with additional state and glue logic in between.
+//!
+//! A graphics pipeline performs many separate steps, that execute more or less in sequence.
+//! Due to the parallel nature of a GPU, no strict ordering guarantees may exist.
+//!
+//! 1. Vertex input and assembly: vertex input data is read from data buffers and then assembled
+//! into primitives (points, lines, triangles etc.).
+//! 2. Vertex shader invocations: the vertex data of each primitive is fed as input to the vertex
+//! shader, which performs transformations on the data and generates new data as output.
+//! 3. (Optional) Tessellation: primitives are subdivided by the operations of two shaders, the
+//! tessellation control and tessellation evaluation shaders. The control shader produces the
+//! tessellation level to apply for the primitive, while the evaluation shader postprocesses the
+//! newly created vertices.
+//! 4. (Optional) Geometry shading: whole primitives are fed as input and processed into a new set
+//! of output primitives.
+//! 5. Vertex post-processing, including:
+//! - Clipping primitives to the view frustum and user-defined clipping planes.
+//! - Perspective division.
+//! - Viewport mapping.
+//! 6. Rasterization: converting primitives into a two-dimensional representation. Primitives may be
+//! discarded depending on their orientation, and are then converted into a collection of
+//! fragments that are processed further.
+//! 7. Fragment operations. These include invocations of the fragment shader, which generates the
+//! values to be written to the color attachment. Various testing and discarding operations can
+//! be performed both before and after the fragment shader ("early" and "late" fragment tests),
+//! including:
+//! - Discard rectangle test
+//! - Scissor test
+//! - Sample mask test
+//! - Depth bounds test
+//! - Stencil test
+//! - Depth test
+//! 8. Color attachment output: the final pixel data is written to a framebuffer. Blending and
+//! logical operations can be applied to combine incoming pixel data with data already present
+//! in the framebuffer.
+//!
+//! A graphics pipeline contains many configuration options, which are grouped into collections of
+//! "state". Often, these directly correspond to one or more steps in the graphics pipeline. Each
+//! state collection has a dedicated submodule.
+//!
+//! Once a graphics pipeline has been created, you can execute it by first *binding* it in a command
+//! buffer, binding the necessary vertex buffers, binding any descriptor sets, setting push
+//! constants, and setting any dynamic state that the pipeline may need. Then you issue a `draw`
+//! command.
+
+pub use self::{builder::GraphicsPipelineBuilder, creation_error::GraphicsPipelineCreationError};
+use self::{
+ color_blend::ColorBlendState, depth_stencil::DepthStencilState,
+ discard_rectangle::DiscardRectangleState, input_assembly::InputAssemblyState,
+ multisample::MultisampleState, rasterization::RasterizationState,
+ render_pass::PipelineRenderPassType, tessellation::TessellationState,
+ vertex_input::VertexInputState, viewport::ViewportState,
+};
+use super::{DynamicState, Pipeline, PipelineBindPoint, PipelineLayout};
+use crate::{
+ device::{Device, DeviceOwned},
+ macros::impl_id_counter,
+ shader::{DescriptorBindingRequirements, FragmentTestsStages, ShaderStage},
+ VulkanObject,
+};
+use ahash::HashMap;
+use std::{
+ fmt::{Debug, Error as FmtError, Formatter},
+ num::NonZeroU64,
+ ptr,
+ sync::Arc,
+};
+
+mod builder;
+pub mod color_blend;
+mod creation_error;
+pub mod depth_stencil;
+pub mod discard_rectangle;
+pub mod input_assembly;
+pub mod multisample;
+pub mod rasterization;
+pub mod render_pass;
+pub mod tessellation;
+pub mod vertex_input;
+pub mod viewport;
+// FIXME: restore
+//mod tests;
+
+/// Defines how the implementation should perform a draw operation.
+///
+/// This object contains the shaders and the various fixed states that describe how the
+/// implementation should perform the various operations needed by a draw command.
+pub struct GraphicsPipeline {
+ handle: ash::vk::Pipeline,
+ device: Arc<Device>,
+ id: NonZeroU64,
+ layout: Arc<PipelineLayout>,
+ render_pass: PipelineRenderPassType,
+
+ // TODO: replace () with an object that describes the shaders in some way.
+ shaders: HashMap<ShaderStage, ()>,
+ descriptor_binding_requirements: HashMap<(u32, u32), DescriptorBindingRequirements>,
+ num_used_descriptor_sets: u32,
+ fragment_tests_stages: Option<FragmentTestsStages>,
+
+ vertex_input_state: VertexInputState,
+ input_assembly_state: InputAssemblyState,
+ tessellation_state: Option<TessellationState>,
+ viewport_state: Option<ViewportState>,
+ discard_rectangle_state: Option<DiscardRectangleState>,
+ rasterization_state: RasterizationState,
+ multisample_state: Option<MultisampleState>,
+ depth_stencil_state: Option<DepthStencilState>,
+ color_blend_state: Option<ColorBlendState>,
+ dynamic_state: HashMap<DynamicState, bool>,
+}
+
+impl GraphicsPipeline {
+ /// Starts the building process of a graphics pipeline. Returns a builder object that you can
+ /// fill with the various parameters.
+ #[inline]
+ pub fn start() -> GraphicsPipelineBuilder<
+ 'static,
+ 'static,
+ 'static,
+ 'static,
+ 'static,
+ VertexInputState,
+ (),
+ (),
+ (),
+ (),
+ (),
+ > {
+ GraphicsPipelineBuilder::new()
+ }
+
+ /// Returns the device used to create this pipeline.
+ #[inline]
+ pub fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+
+ /// Returns the render pass this graphics pipeline is rendering to.
+ #[inline]
+ pub fn render_pass(&self) -> &PipelineRenderPassType {
+ &self.render_pass
+ }
+
+ /// Returns information about a particular shader.
+ ///
+ /// `None` is returned if the pipeline does not contain this shader.
+ ///
+ /// Compatibility note: `()` is temporary, it will be replaced with something else in the
+ /// future.
+ // TODO: ^ implement and make this public
+ #[inline]
+ pub(crate) fn shader(&self, stage: ShaderStage) -> Option<()> {
+ self.shaders.get(&stage).copied()
+ }
+
+ /// Returns the vertex input state used to create this pipeline.
+ #[inline]
+ pub fn vertex_input_state(&self) -> &VertexInputState {
+ &self.vertex_input_state
+ }
+
+ /// Returns the input assembly state used to create this pipeline.
+ #[inline]
+ pub fn input_assembly_state(&self) -> &InputAssemblyState {
+ &self.input_assembly_state
+ }
+
+ /// Returns the tessellation state used to create this pipeline.
+ #[inline]
+ pub fn tessellation_state(&self) -> Option<&TessellationState> {
+ self.tessellation_state.as_ref()
+ }
+
+ /// Returns the viewport state used to create this pipeline.
+ #[inline]
+ pub fn viewport_state(&self) -> Option<&ViewportState> {
+ self.viewport_state.as_ref()
+ }
+
+ /// Returns the discard rectangle state used to create this pipeline.
+ #[inline]
+ pub fn discard_rectangle_state(&self) -> Option<&DiscardRectangleState> {
+ self.discard_rectangle_state.as_ref()
+ }
+
+ /// Returns the rasterization state used to create this pipeline.
+ #[inline]
+ pub fn rasterization_state(&self) -> &RasterizationState {
+ &self.rasterization_state
+ }
+
+ /// Returns the multisample state used to create this pipeline.
+ #[inline]
+ pub fn multisample_state(&self) -> Option<&MultisampleState> {
+ self.multisample_state.as_ref()
+ }
+
+ /// Returns the depth/stencil state used to create this pipeline.
+ #[inline]
+ pub fn depth_stencil_state(&self) -> Option<&DepthStencilState> {
+ self.depth_stencil_state.as_ref()
+ }
+
+ /// Returns the color blend state used to create this pipeline.
+ #[inline]
+ pub fn color_blend_state(&self) -> Option<&ColorBlendState> {
+ self.color_blend_state.as_ref()
+ }
+
+ /// Returns whether a particular state is must be dynamically set.
+ ///
+ /// `None` is returned if the pipeline does not contain this state. Previously set dynamic
+ /// state is not disturbed when binding it.
+ #[inline]
+ pub fn dynamic_state(&self, state: DynamicState) -> Option<bool> {
+ self.dynamic_state.get(&state).copied()
+ }
+
+ /// Returns all potentially dynamic states in the pipeline, and whether they are dynamic or not.
+ #[inline]
+ pub fn dynamic_states(&self) -> impl ExactSizeIterator<Item = (DynamicState, bool)> + '_ {
+ self.dynamic_state.iter().map(|(k, v)| (*k, *v))
+ }
+
+ /// If the pipeline has a fragment shader, returns the fragment tests stages used.
+ #[inline]
+ pub fn fragment_tests_stages(&self) -> Option<FragmentTestsStages> {
+ self.fragment_tests_stages
+ }
+}
+
+impl Pipeline for GraphicsPipeline {
+ #[inline]
+ fn bind_point(&self) -> PipelineBindPoint {
+ PipelineBindPoint::Graphics
+ }
+
+ #[inline]
+ fn layout(&self) -> &Arc<PipelineLayout> {
+ &self.layout
+ }
+
+ #[inline]
+ fn num_used_descriptor_sets(&self) -> u32 {
+ self.num_used_descriptor_sets
+ }
+
+ #[inline]
+ fn descriptor_binding_requirements(
+ &self,
+ ) -> &HashMap<(u32, u32), DescriptorBindingRequirements> {
+ &self.descriptor_binding_requirements
+ }
+}
+
+unsafe impl DeviceOwned for GraphicsPipeline {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+}
+
+impl Debug for GraphicsPipeline {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ write!(f, "<Vulkan graphics pipeline {:?}>", self.handle)
+ }
+}
+
+unsafe impl VulkanObject for GraphicsPipeline {
+ type Handle = ash::vk::Pipeline;
+
+ #[inline]
+ fn handle(&self) -> Self::Handle {
+ self.handle
+ }
+}
+
+impl Drop for GraphicsPipeline {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ let fns = self.device.fns();
+ (fns.v1_0.destroy_pipeline)(self.device.handle(), self.handle, ptr::null());
+ }
+ }
+}
+
+impl_id_counter!(GraphicsPipeline);
diff --git a/src/pipeline/graphics/multisample.rs b/src/pipeline/graphics/multisample.rs
new file mode 100644
index 0000000..67476cc
--- /dev/null
+++ b/src/pipeline/graphics/multisample.rs
@@ -0,0 +1,80 @@
+// Copyright (c) 2016 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+//! Generates multiple fragments per framebuffer pixel when rasterizing. This can be used for
+//! anti-aliasing.
+
+use crate::image::SampleCount;
+
+// TODO: handle some weird behaviors with non-floating-point targets
+
+/// State of the multisampling.
+#[derive(Copy, Clone, Debug)]
+pub struct MultisampleState {
+ /// The number of rasterization samples to take per pixel. The GPU will pick this many different
+ /// locations within each pixel and assign to each of these locations a different depth value.
+ /// The depth and stencil test will then be run for each sample.
+ ///
+ /// The default value is [`SampleCount::Sample1`].
+ pub rasterization_samples: SampleCount,
+
+ /// Controls the proportion (between 0.0 and 1.0) of the samples that will be run through the
+ /// fragment shader.
+ ///
+ /// If the value is 1.0, then all sub-pixel samples will run
+ /// through the shader and get a different value. If the value is 0.5, about half of the samples
+ /// will run through the shader and the other half will get their values from the ones which
+ /// went through the shader.
+ ///
+ /// If set to `Some`, the [`sample_rate_shading`](crate::device::Features::sample_rate_shading)
+ /// feature must be enabled on the device.
+ pub sample_shading: Option<f32>,
+
+ /// A mask of bits that is ANDed with the coverage mask of each set of `rasterization_samples`
+ /// samples. Only the first `rasterization_samples / 32` bits are used, the rest is ignored.
+ ///
+ /// The default value is `[0xFFFFFFFF; 2]`.
+ pub sample_mask: [u32; 2], // 64 bits for needed for 64 SampleCount
+
+ /// Controls whether the alpha value of the fragment will be used in an implementation-defined
+ /// way to determine which samples get disabled or not. For example if the alpha value is 0.5,
+ /// then about half of the samples will be discarded. If you render to a multisample image, this
+ /// means that the color will end up being mixed with whatever color was underneath, which gives
+ /// the same effect as alpha blending.
+ pub alpha_to_coverage_enable: bool,
+
+ /// Controls whether the alpha value of all the samples will be forced to 1.0 (or the
+ /// maximum possible value) after the effects of `alpha_to_coverage` have been applied.
+ ///
+ /// If set to `true`, the [`alpha_to_one`](crate::device::Features::alpha_to_one)
+ /// feature must be enabled on the device.
+ pub alpha_to_one_enable: bool,
+}
+
+impl MultisampleState {
+ /// Creates a `MultisampleState` with multisampling disabled.
+ #[inline]
+ pub fn new() -> MultisampleState {
+ MultisampleState {
+ rasterization_samples: SampleCount::Sample1,
+ sample_shading: None,
+ sample_mask: [0xFFFFFFFF; 2],
+ alpha_to_coverage_enable: false,
+ alpha_to_one_enable: false,
+ }
+ }
+}
+
+impl Default for MultisampleState {
+ /// Returns [`MultisampleState::new()`].
+ #[inline]
+ fn default() -> Self {
+ Self::new()
+ }
+}
diff --git a/src/pipeline/graphics/rasterization.rs b/src/pipeline/graphics/rasterization.rs
new file mode 100644
index 0000000..185110a
--- /dev/null
+++ b/src/pipeline/graphics/rasterization.rs
@@ -0,0 +1,320 @@
+// Copyright (c) 2016 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+//! Configures how primitives should be converted into collections of fragments.
+
+use crate::{macros::vulkan_enum, pipeline::StateMode};
+
+/// The state in a graphics pipeline describing how the rasterization stage should behave.
+#[derive(Clone, Debug)]
+pub struct RasterizationState {
+ /// If true, then the depth value of the vertices will be clamped to the range [0.0, 1.0]. If
+ /// false, fragments whose depth is outside of this range will be discarded.
+ ///
+ /// If enabled, the [`depth_clamp`](crate::device::Features::depth_clamp) feature must be
+ /// enabled on the device.
+ pub depth_clamp_enable: bool,
+
+ /// If true, all the fragments will be discarded, and the fragment shader will not be run. This
+ /// is usually used when your vertex shader has some side effects and you don't need to run the
+ /// fragment shader.
+ ///
+ /// If set to `Dynamic`, the device API version must be at least 1.3, or the
+ /// [`extended_dynamic_state2`](crate::device::Features::extended_dynamic_state2) feature must
+ /// be enabled on the device.
+ pub rasterizer_discard_enable: StateMode<bool>,
+
+ /// This setting can ask the rasterizer to downgrade triangles into lines or points, or lines
+ /// into points.
+ ///
+ /// If set to a value other than `Fill`, the
+ /// [`fill_mode_non_solid`](crate::device::Features::fill_mode_non_solid) feature must be
+ /// enabled on the device.
+ pub polygon_mode: PolygonMode,
+
+ /// Specifies whether front faces or back faces should be discarded, or none, or both.
+ ///
+ /// If set to `Dynamic`, the device API version must be at least 1.3, or the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must be
+ /// enabled on the device.
+ pub cull_mode: StateMode<CullMode>,
+
+ /// Specifies which triangle orientation is considered to be the front of the triangle.
+ ///
+ /// If set to `Dynamic`, the device API version must be at least 1.3, or the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must be
+ /// enabled on the device.
+ pub front_face: StateMode<FrontFace>,
+
+ /// Sets how to modify depth values in the rasterization stage.
+ ///
+ /// If set to `None`, depth biasing is disabled, the depth values will pass to the fragment
+ /// shader unmodified.
+ pub depth_bias: Option<DepthBiasState>,
+
+ /// Width, in pixels, of lines when drawing lines.
+ ///
+ /// Setting this to a value other than 1.0 requires the
+ /// [`wide_lines`](crate::device::Features::wide_lines) feature to be enabled on
+ /// the device.
+ pub line_width: StateMode<f32>,
+
+ /// The rasterization mode for lines.
+ ///
+ /// If this is not set to `Default`, the
+ /// [`ext_line_rasterization`](crate::device::DeviceExtensions::ext_line_rasterization)
+ /// extension and an additional feature must be enabled on the device.
+ pub line_rasterization_mode: LineRasterizationMode,
+
+ /// Enables and sets the parameters for line stippling.
+ ///
+ /// If this is set to `Some`, the
+ /// [`ext_line_rasterization`](crate::device::DeviceExtensions::ext_line_rasterization)
+ /// extension and an additional feature must be enabled on the device.
+ pub line_stipple: Option<StateMode<LineStipple>>,
+}
+
+impl RasterizationState {
+ /// Creates a `RasterizationState` with depth clamping, discard, depth biasing and line
+ /// stippling disabled, filled polygons, no culling, counterclockwise front face, and the
+ /// default line width and line rasterization mode.
+ #[inline]
+ pub fn new() -> Self {
+ Self {
+ depth_clamp_enable: false,
+ rasterizer_discard_enable: StateMode::Fixed(false),
+ polygon_mode: Default::default(),
+ cull_mode: StateMode::Fixed(Default::default()),
+ front_face: StateMode::Fixed(Default::default()),
+ depth_bias: None,
+ line_width: StateMode::Fixed(1.0),
+ line_rasterization_mode: Default::default(),
+ line_stipple: None,
+ }
+ }
+
+ /// Sets the polygon mode.
+ #[inline]
+ pub fn polygon_mode(mut self, polygon_mode: PolygonMode) -> Self {
+ self.polygon_mode = polygon_mode;
+ self
+ }
+
+ /// Sets the cull mode.
+ #[inline]
+ pub fn cull_mode(mut self, cull_mode: CullMode) -> Self {
+ self.cull_mode = StateMode::Fixed(cull_mode);
+ self
+ }
+
+ /// Sets the cull mode to dynamic.
+ #[inline]
+ pub fn cull_mode_dynamic(mut self) -> Self {
+ self.cull_mode = StateMode::Dynamic;
+ self
+ }
+
+ /// Sets the front face.
+ #[inline]
+ pub fn front_face(mut self, front_face: FrontFace) -> Self {
+ self.front_face = StateMode::Fixed(front_face);
+ self
+ }
+
+ /// Sets the front face to dynamic.
+ #[inline]
+ pub fn front_face_dynamic(mut self) -> Self {
+ self.front_face = StateMode::Dynamic;
+ self
+ }
+}
+
+impl Default for RasterizationState {
+ /// Returns [`RasterizationState::new()`].
+ #[inline]
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+/// The state in a graphics pipeline describing how depth biasing should behave when enabled.
+#[derive(Clone, Copy, Debug)]
+pub struct DepthBiasState {
+ /// Sets whether depth biasing should be enabled and disabled dynamically. If set to `false`,
+ /// depth biasing is always enabled.
+ ///
+ /// If set to `true`, the
+ /// [`extended_dynamic_state2`](crate::device::Features::extended_dynamic_state2) feature must
+ /// be enabled on the device.
+ pub enable_dynamic: bool,
+
+ /// The values to use when depth biasing is enabled.
+ pub bias: StateMode<DepthBias>,
+}
+
+/// The values to use for depth biasing.
+#[derive(Clone, Copy, Debug)]
+pub struct DepthBias {
+ /// Specifies a constant factor to be added to every depth value.
+ pub constant_factor: f32,
+
+ /// The maximum (or minimum) depth bias of a fragment.
+ ///
+ /// Setting this to a value other than 0.0 requires the
+ /// [`depth_bias_clamp`](crate::device::Features::depth_bias_clamp) feature to be enabled on
+ /// the device.
+ pub clamp: f32,
+
+ /// A scalar factor applied to a fragment's slope in depth bias calculations.
+ pub slope_factor: f32,
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// Specifies the culling mode.
+ ///
+ /// This setting works in pair with `front_face`. The `front_face` setting tells the GPU whether
+ /// clockwise or counter-clockwise correspond to the front and the back of each triangle. Then
+ /// `cull_mode` lets you specify whether front faces should be discarded, back faces should be
+ /// discarded, or none, or both.
+ CullMode = CullModeFlags(u32);
+
+ /// No culling.
+ None = NONE,
+
+ /// The faces facing the front of the screen (ie. facing the user) will be removed.
+ Front = FRONT,
+
+ /// The faces facing the back of the screen will be removed.
+ Back = BACK,
+
+ /// All faces will be removed.
+ FrontAndBack = FRONT_AND_BACK,
+}
+
+impl Default for CullMode {
+ #[inline]
+ fn default() -> CullMode {
+ CullMode::None
+ }
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// Specifies which triangle orientation corresponds to the front or the triangle.
+ FrontFace = FrontFace(i32);
+
+ /// Triangles whose vertices are oriented counter-clockwise on the screen will be considered
+ /// as facing their front. Otherwise they will be considered as facing their back.
+ CounterClockwise = COUNTER_CLOCKWISE,
+
+
+ /// Triangles whose vertices are oriented clockwise on the screen will be considered
+ /// as facing their front. Otherwise they will be considered as facing their back.
+ Clockwise = CLOCKWISE,
+}
+
+impl Default for FrontFace {
+ #[inline]
+ fn default() -> FrontFace {
+ FrontFace::CounterClockwise
+ }
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ // TODO: document
+ PolygonMode = PolygonMode(i32);
+
+ // TODO: document
+ Fill = FILL,
+
+ // TODO: document
+ Line = LINE,
+
+ // TODO: document further
+ /// On [portability subset](crate::instance#portability-subset-devices-and-the-enumerate_portability-flag)
+ /// devices, unless `rasterizer_discard_enable` is active, the
+ /// [`point_polygons`](crate::device::Features::point_polygons)
+ /// feature must be enabled on the device.
+ Point = POINT,
+
+ /* TODO: enable
+ // TODO: document
+ FillRectangle = FILL_RECTANGLE_NV {
+ device_extensions: [nv_fill_rectangle],
+ },*/
+}
+
+impl Default for PolygonMode {
+ #[inline]
+ fn default() -> PolygonMode {
+ PolygonMode::Fill
+ }
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// The rasterization mode to use for lines.
+ LineRasterizationMode = LineRasterizationModeEXT(i32);
+
+ /// If the [`strict_lines`](crate::device::Properties::strict_lines) device property is `true`,
+ /// then this is the same as `Rectangular`. Otherwise, lines are drawn as parallelograms.
+ ///
+ /// If [`RasterizationState::line_stipple`] is `Some`, then the
+ /// [`strict_lines`](crate::device::Properties::strict_lines) property must be `true` and the
+ /// [`stippled_rectangular_lines`](crate::device::Features::stippled_rectangular_lines) feature
+ /// must be enabled on the device.
+ Default = DEFAULT,
+
+ /// Lines are drawn as if they were rectangles extruded from the line.
+ ///
+ /// The [`rectangular_lines`](crate::device::Features::rectangular_lines) feature must be
+ /// enabled on the device. If [`RasterizationState::line_stipple`] is `Some`, then the
+ /// [`stippled_rectangular_lines`](crate::device::Features::stippled_rectangular_lines) must
+ /// also be enabled.
+ Rectangular = RECTANGULAR,
+
+ /// Lines are drawn by determining which pixel diamonds the line intersects and exits.
+ ///
+ /// The [`bresenham_lines`](crate::device::Features::bresenham_lines) feature must be
+ /// enabled on the device. If [`RasterizationState::line_stipple`] is `Some`, then the
+ /// [`stippled_bresenham_lines`](crate::device::Features::stippled_bresenham_lines) must
+ /// also be enabled.
+ Bresenham = BRESENHAM,
+
+ /// As `Rectangular`, but with alpha falloff.
+ ///
+ /// The [`smooth_lines`](crate::device::Features::smooth_lines) feature must be
+ /// enabled on the device. If [`RasterizationState::line_stipple`] is `Some`, then the
+ /// [`stippled_smooth_lines`](crate::device::Features::stippled_smooth_lines) must
+ /// also be enabled.
+ RectangularSmooth = RECTANGULAR_SMOOTH,
+}
+
+impl Default for LineRasterizationMode {
+ /// Returns `LineRasterizationMode::Default`.
+ #[inline]
+ fn default() -> Self {
+ Self::Default
+ }
+}
+
+/// The parameters of a stippled line.
+#[derive(Clone, Copy, Debug)]
+pub struct LineStipple {
+ /// The repeat factor used in stippled line rasterization. Must be between 1 and 256 inclusive.
+ pub factor: u32,
+ /// The bit pattern used in stippled line rasterization.
+ pub pattern: u16,
+}
diff --git a/src/pipeline/graphics/render_pass.rs b/src/pipeline/graphics/render_pass.rs
new file mode 100644
index 0000000..fd6a5ea
--- /dev/null
+++ b/src/pipeline/graphics/render_pass.rs
@@ -0,0 +1,141 @@
+// Copyright (c) 2022 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use crate::{
+ command_buffer::{CommandBufferInheritanceRenderingInfo, RenderingInfo},
+ format::Format,
+ image::ImageAspects,
+ render_pass::Subpass,
+};
+
+/// Selects the type of render pass that a graphics pipeline is created for.
+#[derive(Clone, Debug)]
+pub enum PipelineRenderPassType {
+ BeginRenderPass(Subpass),
+ BeginRendering(PipelineRenderingCreateInfo),
+}
+
+impl From<Subpass> for PipelineRenderPassType {
+ #[inline]
+ fn from(val: Subpass) -> Self {
+ Self::BeginRenderPass(val)
+ }
+}
+
+impl From<PipelineRenderingCreateInfo> for PipelineRenderPassType {
+ #[inline]
+ fn from(val: PipelineRenderingCreateInfo) -> Self {
+ Self::BeginRendering(val)
+ }
+}
+
+/// The dynamic rendering parameters to create a graphics pipeline.
+#[derive(Clone, Debug)]
+pub struct PipelineRenderingCreateInfo {
+ /// If not `0`, indicates that multiview rendering will be enabled, and specifies the view
+ /// indices that are rendered to. The value is a bitmask, so that that for example `0b11` will
+ /// draw to the first two views and `0b101` will draw to the first and third view.
+ ///
+ /// If set to a nonzero value, the [`multiview`](crate::device::Features::multiview) feature
+ /// must be enabled on the device.
+ ///
+ /// The default value is `0`.
+ pub view_mask: u32,
+
+ /// The formats of the color attachments that will be used during rendering.
+ ///
+ /// If an element is `None`, it indicates that the attachment will not be used.
+ ///
+ /// The default value is empty.
+ pub color_attachment_formats: Vec<Option<Format>>,
+
+ /// The format of the depth attachment that will be used during rendering.
+ ///
+ /// If set to `None`, it indicates that no depth attachment will be used.
+ ///
+ /// The default value is `None`.
+ pub depth_attachment_format: Option<Format>,
+
+ /// The format of the stencil attachment that will be used during rendering.
+ ///
+ /// If set to `None`, it indicates that no stencil attachment will be used.
+ ///
+ /// The default value is `None`.
+ pub stencil_attachment_format: Option<Format>,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for PipelineRenderingCreateInfo {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ view_mask: 0,
+ color_attachment_formats: Vec::new(),
+ depth_attachment_format: None,
+ stencil_attachment_format: None,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+impl PipelineRenderingCreateInfo {
+ pub(crate) fn from_subpass(subpass: &Subpass) -> Self {
+ let subpass_desc = subpass.subpass_desc();
+ let rp_attachments = subpass.render_pass().attachments();
+
+ Self {
+ view_mask: subpass_desc.view_mask,
+ color_attachment_formats: (subpass_desc.color_attachments.iter())
+ .map(|atch_ref| {
+ atch_ref.as_ref().map(|atch_ref| {
+ rp_attachments[atch_ref.attachment as usize].format.unwrap()
+ })
+ })
+ .collect(),
+ depth_attachment_format: (subpass_desc.depth_stencil_attachment.as_ref())
+ .map(|atch_ref| rp_attachments[atch_ref.attachment as usize].format.unwrap())
+ .filter(|format| format.aspects().intersects(ImageAspects::DEPTH)),
+ stencil_attachment_format: (subpass_desc.depth_stencil_attachment.as_ref())
+ .map(|atch_ref| rp_attachments[atch_ref.attachment as usize].format.unwrap())
+ .filter(|format| format.aspects().intersects(ImageAspects::STENCIL)),
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+
+ pub(crate) fn from_rendering_info(info: &RenderingInfo) -> Self {
+ Self {
+ view_mask: info.view_mask,
+ color_attachment_formats: (info.color_attachments.iter())
+ .map(|atch_info| {
+ atch_info
+ .as_ref()
+ .map(|atch_info| atch_info.image_view.format().unwrap())
+ })
+ .collect(),
+ depth_attachment_format: (info.depth_attachment.as_ref())
+ .map(|atch_info| atch_info.image_view.format().unwrap()),
+ stencil_attachment_format: (info.stencil_attachment.as_ref())
+ .map(|atch_info| atch_info.image_view.format().unwrap()),
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+
+ pub(crate) fn from_inheritance_rendering_info(
+ info: &CommandBufferInheritanceRenderingInfo,
+ ) -> Self {
+ Self {
+ view_mask: info.view_mask,
+ color_attachment_formats: info.color_attachment_formats.clone(),
+ depth_attachment_format: info.depth_attachment_format,
+ stencil_attachment_format: info.stencil_attachment_format,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
diff --git a/src/pipeline/graphics/tessellation.rs b/src/pipeline/graphics/tessellation.rs
new file mode 100644
index 0000000..e3c5e74
--- /dev/null
+++ b/src/pipeline/graphics/tessellation.rs
@@ -0,0 +1,56 @@
+// Copyright (c) 2021 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+//! Subdivides primitives into smaller primitives.
+
+use crate::pipeline::StateMode;
+
+/// The state in a graphics pipeline describing the tessellation shader execution of a graphics
+/// pipeline.
+#[derive(Clone, Copy, Debug)]
+pub struct TessellationState {
+ /// The number of patch control points to use.
+ ///
+ /// If set to `Dynamic`, the
+ /// [`extended_dynamic_state2_patch_control_points`](crate::device::Features::extended_dynamic_state2_patch_control_points)
+ /// feature must be enabled on the device.
+ pub patch_control_points: StateMode<u32>,
+}
+
+impl TessellationState {
+ /// Creates a new `TessellationState` with 3 patch control points.
+ #[inline]
+ pub fn new() -> Self {
+ Self {
+ patch_control_points: StateMode::Fixed(3),
+ }
+ }
+
+ /// Sets the number of patch control points.
+ #[inline]
+ pub fn patch_control_points(mut self, num: u32) -> Self {
+ self.patch_control_points = StateMode::Fixed(num);
+ self
+ }
+
+ /// Sets the number of patch control points to dynamic.
+ #[inline]
+ pub fn patch_control_points_dynamic(mut self) -> Self {
+ self.patch_control_points = StateMode::Dynamic;
+ self
+ }
+}
+
+impl Default for TessellationState {
+ /// Returns [`TessellationState::new()`].
+ #[inline]
+ fn default() -> Self {
+ Self::new()
+ }
+}
diff --git a/src/pipeline/graphics_pipeline/tests.rs b/src/pipeline/graphics/tests.rs
index 53ef2eb..ebe8395 100644
--- a/src/pipeline/graphics_pipeline/tests.rs
+++ b/src/pipeline/graphics/tests.rs
@@ -66,7 +66,7 @@ fn create() {
render_pass: Subpass::from(
simple_rp::CustomRenderPass::new(&device, &{
simple_rp::Formats {
- color: (Format::R8G8B8A8Unorm, 1),
+ color: (Format::R8G8B8A8_UNORM, 1),
}
})
.unwrap(),
@@ -119,7 +119,7 @@ fn bad_primitive_restart() {
render_pass: Subpass::from(
simple_rp::CustomRenderPass::new(&device, &{
simple_rp::Formats {
- color: (Format::R8G8B8A8Unorm, 1),
+ color: (Format::R8G8B8A8_UNORM, 1),
}
})
.unwrap(),
@@ -130,7 +130,7 @@ fn bad_primitive_restart() {
);
match result {
- Err(GraphicsPipelineCreationError::PrimitiveDoesntSupportPrimitiveRestart { .. }) => (),
+ Err(GraphicsPipelineCreationError::RequirementNotMet { .. }) => (),
_ => panic!(),
}
}
@@ -173,7 +173,7 @@ fn multi_viewport_feature() {
render_pass: Subpass::from(
simple_rp::CustomRenderPass::new(&device, &{
simple_rp::Formats {
- color: (Format::R8G8B8A8Unorm, 1),
+ color: (Format::R8G8B8A8_UNORM, 1),
}
})
.unwrap(),
@@ -227,7 +227,7 @@ fn max_viewports() {
render_pass: Subpass::from(
simple_rp::CustomRenderPass::new(&device, &{
simple_rp::Formats {
- color: (Format::R8G8B8A8Unorm, 1),
+ color: (Format::R8G8B8A8_UNORM, 1),
}
})
.unwrap(),
@@ -281,7 +281,7 @@ fn no_depth_attachment() {
render_pass: Subpass::from(
simple_rp::CustomRenderPass::new(&device, &{
simple_rp::Formats {
- color: (Format::R8G8B8A8Unorm, 1),
+ color: (Format::R8G8B8A8_UNORM, 1),
}
})
.unwrap(),
@@ -306,12 +306,12 @@ mod simple_rp {
load: Clear,
store: Store,
format: Format,
- }
+ },
},
pass: {
color: [color],
- depth_stencil: {}
- }
+ depth_stencil: {},
+ },
}
}
diff --git a/src/pipeline/graphics/vertex_input/buffers.rs b/src/pipeline/graphics/vertex_input/buffers.rs
new file mode 100644
index 0000000..b7637e6
--- /dev/null
+++ b/src/pipeline/graphics/vertex_input/buffers.rs
@@ -0,0 +1,72 @@
+// Copyright (c) 2016 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use super::VertexBufferDescription;
+use crate::{
+ pipeline::graphics::vertex_input::{
+ IncompatibleVertexDefinitionError, Vertex, VertexDefinition, VertexInputState,
+ },
+ shader::ShaderInterface,
+};
+
+/// A vertex definition for any number of vertex and instance buffers.
+#[deprecated(
+ since = "0.33.0",
+ note = "Use `VertexBufferDescription` directly instead as returned by `Vertex::per_vertex` or `Vertex::per_instance`"
+)]
+#[derive(Clone, Debug, Default)]
+pub struct BuffersDefinition(Vec<VertexBufferDescription>);
+
+#[allow(deprecated)]
+impl BuffersDefinition {
+ /// Constructs a new definition.
+ #[inline]
+ pub fn new() -> Self {
+ BuffersDefinition(Vec::new())
+ }
+
+ /// Adds a new vertex buffer containing elements of type `V` to the definition.
+ pub fn vertex<V: Vertex>(mut self) -> Self {
+ self.0.push(V::per_vertex());
+ self
+ }
+
+ /// Adds a new instance buffer containing elements of type `V` to the definition.
+ pub fn instance<V: Vertex>(mut self) -> Self {
+ self.0.push(V::per_instance());
+ self
+ }
+
+ /// Adds a new instance buffer containing elements of type `V` to the definition, with the
+ /// specified input rate divisor.
+ ///
+ /// This requires the [`vertex_attribute_instance_rate_divisor`] feature has been enabled on
+ /// the device, unless `divisor` is 1.
+ ///
+ /// `divisor` can be 0 if the [`vertex_attribute_instance_rate_zero_divisor`] feature is also
+ /// enabled. This means that every vertex will use the same vertex and instance data.
+ ///
+ /// [`vertex_attribute_instance_rate_divisor`]: crate::device::Features::vertex_attribute_instance_rate_divisor
+ /// [`vertex_attribute_instance_rate_zero_divisor`]: crate::device::Features::vertex_attribute_instance_rate_zero_divisor
+ pub fn instance_with_divisor<V: Vertex>(mut self, divisor: u32) -> Self {
+ self.0.push(V::per_instance_with_divisor(divisor));
+ self
+ }
+}
+
+#[allow(deprecated)]
+unsafe impl VertexDefinition for BuffersDefinition {
+ #[inline]
+ fn definition(
+ &self,
+ interface: &ShaderInterface,
+ ) -> Result<VertexInputState, IncompatibleVertexDefinitionError> {
+ self.0.definition(interface)
+ }
+}
diff --git a/src/pipeline/graphics/vertex_input/collection.rs b/src/pipeline/graphics/vertex_input/collection.rs
new file mode 100644
index 0000000..cb209f4
--- /dev/null
+++ b/src/pipeline/graphics/vertex_input/collection.rs
@@ -0,0 +1,67 @@
+// Copyright (c) 2021 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use crate::buffer::Subbuffer;
+use std::mem;
+
+/// A collection of vertex buffers.
+pub trait VertexBuffersCollection {
+ /// Converts `self` into a list of buffers.
+ // TODO: better than a Vec
+ fn into_vec(self) -> Vec<Subbuffer<[u8]>>;
+}
+
+impl VertexBuffersCollection for () {
+ #[inline]
+ fn into_vec(self) -> Vec<Subbuffer<[u8]>> {
+ Vec::new()
+ }
+}
+
+impl<T: ?Sized> VertexBuffersCollection for Subbuffer<T> {
+ fn into_vec(self) -> Vec<Subbuffer<[u8]>> {
+ vec![self.into_bytes()]
+ }
+}
+
+impl<T: ?Sized> VertexBuffersCollection for Vec<Subbuffer<T>> {
+ fn into_vec(self) -> Vec<Subbuffer<[u8]>> {
+ assert!(mem::size_of::<Subbuffer<T>>() == mem::size_of::<Subbuffer<[u8]>>());
+ assert!(mem::align_of::<Subbuffer<T>>() == mem::align_of::<Subbuffer<[u8]>>());
+
+ // SAFETY: All `Subbuffer`s share the same layout.
+ unsafe { mem::transmute::<Vec<Subbuffer<T>>, Vec<Subbuffer<[u8]>>>(self) }
+ }
+}
+
+impl<T: ?Sized, const N: usize> VertexBuffersCollection for [Subbuffer<T>; N] {
+ fn into_vec(self) -> Vec<Subbuffer<[u8]>> {
+ self.into_iter().map(Subbuffer::into_bytes).collect()
+ }
+}
+
+macro_rules! impl_collection {
+ ($first:ident $(, $others:ident)*) => (
+ impl<$first: ?Sized $(, $others: ?Sized)*> VertexBuffersCollection
+ for (Subbuffer<$first>, $(Subbuffer<$others>),*)
+ {
+ #[inline]
+ #[allow(non_snake_case)]
+ fn into_vec(self) -> Vec<Subbuffer<[u8]>> {
+ let ($first, $($others,)*) = self;
+ vec![$first.into_bytes() $(, $others.into_bytes())*]
+ }
+ }
+
+ impl_collection!($($others),*);
+ );
+ () => {}
+}
+
+impl_collection!(Z, Y, X, W, V, U, T, S, R, Q, P, O, N, M, L, K, J, I, H, G, F, E, D, C, B, A);
diff --git a/src/pipeline/graphics/vertex_input/definition.rs b/src/pipeline/graphics/vertex_input/definition.rs
new file mode 100644
index 0000000..2372670
--- /dev/null
+++ b/src/pipeline/graphics/vertex_input/definition.rs
@@ -0,0 +1,226 @@
+// Copyright (c) 2016 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+//! Definition for creating a [`VertexInputState`] based on a [`ShaderInterface`].
+//!
+//! # Implementing `Vertex`
+//!
+//! The implementations of the `VertexDefinition` trait that are provided by vulkano require you to
+//! use a buffer whose content is `[V]` where `V` implements the `Vertex` trait.
+//!
+//! The `Vertex` trait is unsafe, but can be implemented on a struct with the `impl_vertex!`
+//! macro.
+//!
+//! # Examples
+//!
+//! ```ignore // TODO:
+//! # #[macro_use] extern crate vulkano
+//! # fn main() {
+//! # use std::sync::Arc;
+//! # use vulkano::device::Device;
+//! # use vulkano::device::Queue;
+//! use vulkano::buffer::BufferAccess;
+//! use vulkano::buffer::BufferUsage;
+//! use vulkano::memory::HostVisible;
+//! use vulkano::pipeline::vertex::;
+//! # let device: Arc<Device> = return;
+//! # let queue: Arc<Queue> = return;
+//!
+//! struct Vertex {
+//! position: [f32; 2]
+//! }
+//!
+//! impl_vertex!(Vertex, position);
+//!
+//! let usage = BufferUsage {
+//! vertex_buffer: true,
+//! ..BufferUsage::empty()
+//! };
+//!
+//! let vertex_buffer = BufferAccess::<[Vertex], _>::array(&device, 128, &usage, HostVisible, &queue)
+//! .expect("failed to create buffer");
+//!
+//! // TODO: finish example
+//! # }
+//! ```
+
+use super::{
+ VertexBufferDescription, VertexInputAttributeDescription, VertexInputBindingDescription,
+};
+use crate::{
+ pipeline::graphics::vertex_input::{VertexInputState, VertexMemberInfo},
+ shader::{ShaderInterface, ShaderInterfaceEntryType},
+ DeviceSize,
+};
+use std::{
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+};
+
+/// Trait for types that can create a [`VertexInputState`] from a [`ShaderInterface`].
+pub unsafe trait VertexDefinition {
+ /// Builds the vertex definition to use to link this definition to a vertex shader's input
+ /// interface.
+ // TODO: remove error return, move checks to GraphicsPipelineBuilder
+ fn definition(
+ &self,
+ interface: &ShaderInterface,
+ ) -> Result<VertexInputState, IncompatibleVertexDefinitionError>;
+}
+
+unsafe impl VertexDefinition for VertexInputState {
+ fn definition(
+ &self,
+ _interface: &ShaderInterface,
+ ) -> Result<VertexInputState, IncompatibleVertexDefinitionError> {
+ Ok(self.clone())
+ }
+}
+
+/// Error that can happen when the vertex definition doesn't match the input of the vertex shader.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum IncompatibleVertexDefinitionError {
+ /// An attribute of the vertex shader is missing in the vertex source.
+ MissingAttribute {
+ /// Name of the missing attribute.
+ attribute: String,
+ },
+
+ /// The format of an attribute does not match.
+ FormatMismatch {
+ /// Name of the attribute.
+ attribute: String,
+ /// The format in the vertex shader.
+ shader: ShaderInterfaceEntryType,
+ /// The format in the vertex definition.
+ definition: VertexMemberInfo,
+ },
+}
+
+impl Error for IncompatibleVertexDefinitionError {}
+
+impl Display for IncompatibleVertexDefinitionError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ IncompatibleVertexDefinitionError::MissingAttribute { .. } => {
+ write!(f, "an attribute is missing")
+ }
+ IncompatibleVertexDefinitionError::FormatMismatch { .. } => {
+ write!(f, "the format of an attribute does not match")
+ }
+ }
+ }
+}
+
+unsafe impl VertexDefinition for &[VertexBufferDescription] {
+ #[inline]
+ fn definition(
+ &self,
+ interface: &ShaderInterface,
+ ) -> Result<VertexInputState, IncompatibleVertexDefinitionError> {
+ let bindings = self.iter().enumerate().map(|(binding, buffer)| {
+ (
+ binding as u32,
+ VertexInputBindingDescription {
+ stride: buffer.stride,
+ input_rate: buffer.input_rate,
+ },
+ )
+ });
+ let mut attributes: Vec<(u32, VertexInputAttributeDescription)> = Vec::new();
+
+ for element in interface.elements() {
+ let name = element.name.as_ref().unwrap().clone().into_owned();
+
+ let (infos, binding) = self
+ .iter()
+ .enumerate()
+ .find_map(|(binding, buffer)| {
+ buffer
+ .members
+ .get(&name)
+ .map(|infos| (infos.clone(), binding as u32))
+ })
+ .ok_or_else(||
+ // TODO: move this check to GraphicsPipelineBuilder
+ IncompatibleVertexDefinitionError::MissingAttribute {
+ attribute: name.clone(),
+ })?;
+
+ // TODO: ShaderInterfaceEntryType does not properly support 64bit.
+ // Once it does the below logic around num_elements and num_locations
+ // might have to be updated.
+ if infos.num_components() != element.ty.num_components
+ || infos.num_elements != element.ty.num_locations()
+ {
+ return Err(IncompatibleVertexDefinitionError::FormatMismatch {
+ attribute: name,
+ shader: element.ty,
+ definition: infos,
+ });
+ }
+
+ let mut offset = infos.offset as DeviceSize;
+ let block_size = infos.format.block_size().unwrap();
+ // Double precision formats can exceed a single location.
+ // R64B64G64A64_SFLOAT requires two locations, so we need to adapt how we bind
+ let location_range = if block_size > 16 {
+ (element.location..element.location + 2 * element.ty.num_locations()).step_by(2)
+ } else {
+ (element.location..element.location + element.ty.num_locations()).step_by(1)
+ };
+
+ for location in location_range {
+ attributes.push((
+ location,
+ VertexInputAttributeDescription {
+ binding,
+ format: infos.format,
+ offset: offset as u32,
+ },
+ ));
+ offset += block_size;
+ }
+ }
+
+ Ok(VertexInputState::new()
+ .bindings(bindings)
+ .attributes(attributes))
+ }
+}
+
+unsafe impl<const N: usize> VertexDefinition for [VertexBufferDescription; N] {
+ #[inline]
+ fn definition(
+ &self,
+ interface: &ShaderInterface,
+ ) -> Result<VertexInputState, IncompatibleVertexDefinitionError> {
+ self.as_slice().definition(interface)
+ }
+}
+
+unsafe impl VertexDefinition for Vec<VertexBufferDescription> {
+ #[inline]
+ fn definition(
+ &self,
+ interface: &ShaderInterface,
+ ) -> Result<VertexInputState, IncompatibleVertexDefinitionError> {
+ self.as_slice().definition(interface)
+ }
+}
+
+unsafe impl VertexDefinition for VertexBufferDescription {
+ #[inline]
+ fn definition(
+ &self,
+ interface: &ShaderInterface,
+ ) -> Result<VertexInputState, IncompatibleVertexDefinitionError> {
+ std::slice::from_ref(self).definition(interface)
+ }
+}
diff --git a/src/pipeline/graphics/vertex_input/impl_vertex.rs b/src/pipeline/graphics/vertex_input/impl_vertex.rs
new file mode 100644
index 0000000..f8e5246
--- /dev/null
+++ b/src/pipeline/graphics/vertex_input/impl_vertex.rs
@@ -0,0 +1,200 @@
+// Copyright (c) 2017 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use crate::format::Format;
+
+/// Implements the `Vertex` trait on a struct.
+///
+/// # Examples
+///
+/// ```
+/// # use vulkano::buffer::BufferContents;
+/// #[derive(BufferContents, Default)]
+/// #[repr(C)]
+/// struct Vertex {
+/// position: [f32; 3],
+/// color: [f32; 4],
+/// }
+///
+/// vulkano::impl_vertex!(Vertex, position, color);
+/// ```
+#[deprecated(
+ since = "0.33.0",
+ note = "derive `Vertex` instead and use field-level attributes to specify format"
+)]
+#[macro_export]
+macro_rules! impl_vertex {
+ ($out:ty $(, $member:ident)*) => (
+ #[allow(unsafe_code)]
+ unsafe impl $crate::pipeline::graphics::vertex_input::Vertex for $out {
+ #[inline(always)]
+ #[allow(deprecated)]
+ fn per_vertex() -> $crate::pipeline::graphics::vertex_input::VertexBufferDescription {
+ #[allow(unused_imports)]
+ use std::collections::HashMap;
+ use $crate::format::Format;
+ use $crate::pipeline::graphics::vertex_input::VertexMember;
+ use $crate::pipeline::graphics::vertex_input::{VertexInputRate, VertexMemberInfo};
+
+ let mut members = HashMap::default();
+ $(
+ {
+ let dummy = <$out>::default();
+ #[inline] fn f<T: VertexMember>(_: &T) -> Format { T::format() }
+ let format = f(&dummy.$member);
+ let field_size = {
+ let p = unsafe {
+ core::ptr::addr_of!((*(&dummy as *const _ as *const $out)).$member)
+ };
+ const fn size_of_raw<T>(_: *const T) -> usize {
+ core::mem::size_of::<T>()
+ }
+ size_of_raw(p)
+ } as u32;
+ let format_size = format.block_size().expect("no block size for format") as u32;
+ let num_elements = field_size / format_size;
+ let remainder = field_size % format_size;
+ assert!(remainder == 0, "struct field `{}` size does not fit multiple of format size", stringify!($member));
+
+ let dummy_ptr = (&dummy) as *const _;
+ let member_ptr = (&dummy.$member) as *const _;
+
+ members.insert(stringify!($member).to_string(), VertexMemberInfo {
+ offset: member_ptr as usize - dummy_ptr as usize,
+ format,
+ num_elements,
+ });
+ }
+ )*
+
+ $crate::pipeline::graphics::vertex_input::VertexBufferDescription {
+ members,
+ stride: std::mem::size_of::<$out>() as u32,
+ input_rate: VertexInputRate::Vertex,
+ }
+ }
+ #[inline(always)]
+ #[allow(deprecated)]
+ fn per_instance() -> $crate::pipeline::graphics::vertex_input::VertexBufferDescription {
+ <$out as $crate::pipeline::graphics::vertex_input::Vertex>::per_vertex().per_instance()
+ }
+ #[inline(always)]
+ #[allow(deprecated)]
+ fn per_instance_with_divisor(divisor: u32) -> $crate::pipeline::graphics::vertex_input::VertexBufferDescription {
+ <$out as $crate::pipeline::graphics::vertex_input::Vertex>::per_vertex().per_instance_with_divisor(divisor)
+ }
+
+ }
+ )
+}
+
+/// Trait for data types that can be used as vertex members. Used by the `impl_vertex!` macro.
+#[deprecated(
+ since = "0.33.0",
+ note = "Derive `Vertex` instead and use field-level attributes to specify format"
+)]
+pub unsafe trait VertexMember {
+ /// Returns the format and array size of the member.
+ fn format() -> Format;
+}
+
+#[macro_export]
+macro_rules! impl_vertex_member {
+ ($out:ty, $format:ident) => {
+ #[allow(deprecated)]
+ unsafe impl VertexMember for $out {
+ #[inline]
+ fn format() -> Format {
+ Format::$format
+ }
+ }
+ };
+}
+
+impl_vertex_member!(i8, R8_SINT);
+impl_vertex_member!(u8, R8_UINT);
+impl_vertex_member!(i16, R16_SINT);
+impl_vertex_member!(u16, R16_UINT);
+impl_vertex_member!(i32, R32_SINT);
+impl_vertex_member!(u32, R32_UINT);
+impl_vertex_member!(f32, R32_SFLOAT);
+impl_vertex_member!(f64, R64_SFLOAT);
+impl_vertex_member!([i8; 2], R8G8_SINT);
+impl_vertex_member!([u8; 2], R8G8_UINT);
+impl_vertex_member!([i16; 2], R16G16_SINT);
+impl_vertex_member!([u16; 2], R16G16_UINT);
+impl_vertex_member!([i32; 2], R32G32_SINT);
+impl_vertex_member!([u32; 2], R32G32_UINT);
+impl_vertex_member!([f32; 2], R32G32_SFLOAT);
+impl_vertex_member!([f64; 2], R64G64_SFLOAT);
+impl_vertex_member!([i8; 3], R8G8B8_SINT);
+impl_vertex_member!([u8; 3], R8G8B8_UINT);
+impl_vertex_member!([i16; 3], R16G16B16_SINT);
+impl_vertex_member!([u16; 3], R16G16B16_UINT);
+impl_vertex_member!([i32; 3], R32G32B32_SINT);
+impl_vertex_member!([u32; 3], R32G32B32_UINT);
+impl_vertex_member!([f32; 3], R32G32B32_SFLOAT);
+impl_vertex_member!([f64; 3], R64G64B64_SFLOAT);
+impl_vertex_member!([i8; 4], R8G8B8A8_SINT);
+impl_vertex_member!([u8; 4], R8G8B8A8_UINT);
+impl_vertex_member!([i16; 4], R16G16B16A16_SINT);
+impl_vertex_member!([u16; 4], R16G16B16A16_UINT);
+impl_vertex_member!([i32; 4], R32G32B32A32_SINT);
+impl_vertex_member!([u32; 4], R32G32B32A32_UINT);
+impl_vertex_member!([f32; 4], R32G32B32A32_SFLOAT);
+impl_vertex_member!([f64; 4], R64G64B64A64_SFLOAT);
+impl_vertex_member!([f32; 9], R32G32B32_SFLOAT);
+impl_vertex_member!([f32; 16], R32G32B32A32_SFLOAT);
+
+#[allow(deprecated)]
+unsafe impl<T> VertexMember for [T; 1]
+where
+ T: VertexMember,
+{
+ fn format() -> Format {
+ <T as VertexMember>::format()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::format::Format;
+ #[allow(deprecated)]
+ use crate::pipeline::graphics::vertex_input::Vertex;
+
+ use bytemuck::{Pod, Zeroable};
+
+ #[test]
+ #[allow(deprecated)]
+ fn impl_vertex() {
+ #[repr(C)]
+ #[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
+ struct TestVertex {
+ matrix: [f32; 16],
+ vector: [f32; 4],
+ scalar: u16,
+ _padding: u16,
+ }
+ impl_vertex!(TestVertex, scalar, vector, matrix);
+
+ let info = TestVertex::per_vertex();
+ let matrix = info.members.get("matrix").unwrap();
+ let vector = info.members.get("vector").unwrap();
+ let scalar = info.members.get("scalar").unwrap();
+ assert_eq!(matrix.format, Format::R32G32B32A32_SFLOAT);
+ assert_eq!(matrix.offset, 0);
+ assert_eq!(matrix.num_elements, 4);
+ assert_eq!(vector.format, Format::R32G32B32A32_SFLOAT);
+ assert_eq!(vector.offset, 16 * 4);
+ assert_eq!(vector.num_elements, 1);
+ assert_eq!(scalar.format, Format::R16_UINT);
+ assert_eq!(scalar.offset, 16 * 5);
+ assert_eq!(scalar.num_elements, 1);
+ }
+}
diff --git a/src/pipeline/graphics/vertex_input/mod.rs b/src/pipeline/graphics/vertex_input/mod.rs
new file mode 100644
index 0000000..2ccc73d
--- /dev/null
+++ b/src/pipeline/graphics/vertex_input/mod.rs
@@ -0,0 +1,235 @@
+// Copyright (c) 2016 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+//! Configures how data from vertex buffers is read into vertex shader input locations.
+//!
+//! The vertex input stage is the stage where data is read from a buffer and fed into the vertex
+//! shader. After each invocation of the vertex shader, the pipeline then proceeds to the input
+//! assembly stage.
+//!
+//! # Input locations and components
+//!
+//! Input data is assigned per shader input location. Locations are set by adding the `location`
+//! layout qualifier to an input variable in GLSL. A single location contains four data elements,
+//! named "components", which are each 32 bits in size. These correspond to the `x`, `y`, `z` and
+//! `w` (or equivalently `r`, `g`, `b`, `a`) components of a `vec4` inside the shader.
+//! A component can contain at most one value, and data types that are smaller than 32 bits will
+//! still take up a whole component, so a single `i8vec4` variable will still take up all four
+//! components in a location, even if not all bits are actually used.
+//!
+//! A variable may take up fewer than four components. For example, a single `float` takes up only
+//! one component, a `vec2` takes up two, and so on. Using the `component` layout qualifier in GLSL,
+//! it is possible to fit multiple variables into a single four-component location slot, as long
+//! as the components of each variable don't overlap.
+//!
+//! If the input variable is an array, then it takes up a series of consecutive locations. Each
+//! element of the array always starts at a new location, regardless of whether there is still room
+//! in the previous one. So, for example, an array of three `vec2` takes three locations, since
+//! `vec2` alone needs one location. An array can be decorated with the `component` qualifier as
+//! well; this is equivalent to applying the qualifier to every element of the array. If elements do
+//! not use all components in their locations, those free components can be filled with additional
+//! variables, just like for non-array types.
+//!
+//! Matrices are laid out as if they were an array of column vectors. Thus, a `mat4x3` is laid out
+//! as an array of four `vec3`s, `mat2x4` as two `vec4`s. As with individual vectors, each column of
+//! the matrix uses up as many components of its location as there are rows in the matrix, and the
+//! remaining components are available for additional variables as described above. However, it is
+//! not possible to use the `component` qualifier on a matrix.
+//!
+//! If a 64-bit value is to be passed to a shader, it will take up two adjacent components. Vectors
+//! of 64-bit values are correspondingly twice as large: `dvec2` takes up all four components of a
+//! location, `dvec4` takes two full locations, while `dvec3` takes one full location and the first
+//! two components of the next. An array or matrix of a 64-bit type is made up of multiple adjacent
+//! 64-bit elements, just like for smaller types: each new element starts at a fresh location.
+//!
+//! # Input attributes
+//!
+//! An input attribute is a mapping between data in a vertex buffer and the locations and components
+//! of the vertex shader.
+//!
+//! Input attributes are assigned on a per-location basis; it is not possible to assign attributes
+//! to individual components. Instead, each attribute specifies up to four values to be read from
+//! the vertex buffer at once, which are then mapped to the four components of the given location.
+//! Like the texels in an image, each attribute's data format in a vertex buffer is described by a
+//! [`Format`]. The input data doesn't have to be an actual color, the format simply describes the
+//! type, size and layout of the data for the four input components. For example,
+//! `Format::R32G32B32A32_SFLOAT` will read four `f32` values from the vertex buffer and assigns
+//! them to the four components of the attribute's location.
+//!
+//! It is possible to specify a `Format` that contains less than four components. In this case, the
+//! missing components are given default values: the first three components default to 0, while the
+//! fourth defaults to 1. This means that you can, for example, store only the `x`, `y` and `z`
+//! components of a vertex position in a vertex buffer, and have the vertex input state
+//! automatically set the `w` value to 1 for you. An exception to this are 64-bit values: these do
+//! *not* receive default values, meaning that components that are missing from the format are
+//! assigned no value and must not be used in the shader at all.
+//!
+//! When matching attribute formats to shader input types, the following rules apply:
+//! - Signed integers in the shader must have an attribute format with a `SINT` type.
+//! - Unsigned integers in the shader must have an attribute format with a `UINT` type.
+//! - Floating point values in the shader must have an attribute format with a type other than
+//! `SINT` or `UINT`. This includes `SFLOAT`, `UFLOAT` and `SRGB`, but also `SNORM`, `UNORM`,
+//! `SSCALED` and `USCALED`.
+//! - 64-bit values in the shader must have a 64-bit attribute format.
+//! - 32-bit and smaller values in the shader must have a 32-bit or smaller attribute format, but
+//! the exact number of bits doesn't matter. For example, `Format::R8G8B8A8_UNORM` can be used
+//! with a `vec4` in the shader.
+//!
+//! # Input bindings
+//!
+//! An input binding is a definition of a Vulkan buffer that contains the actual data from which
+//! each input attribute is to be read. The buffer itself is referred to as a "vertex buffer", and
+//! is set during drawing with the
+//! [`bind_vertex_buffers`](crate::command_buffer::AutoCommandBufferBuilder::bind_vertex_buffers)
+//! command.
+//!
+//! The data in a vertex buffer is typically arranged into an array, where each array element
+//! contains the data for a single vertex shader invocation. When deciding which element read from
+//! the vertex buffer for a given vertex and instance number, each binding has an "input rate".
+//! If the input rate is `Vertex`, then the vertex input state advances to the next element of that
+//! buffer each time a new vertex number is processed. Likewise, if the input rate is `Instance`,
+//! it advances to the next element for each new instance number. Different bindings can have
+//! different input rates, and it's also possible to have multiple bindings with the same input
+//! rate.
+
+#[allow(deprecated)]
+pub use self::{
+ buffers::BuffersDefinition,
+ collection::VertexBuffersCollection,
+ definition::{IncompatibleVertexDefinitionError, VertexDefinition},
+ impl_vertex::VertexMember,
+ vertex::{Vertex, VertexBufferDescription, VertexMemberInfo},
+};
+use crate::format::Format;
+use ahash::HashMap;
+
+mod buffers;
+mod collection;
+mod definition;
+mod impl_vertex;
+mod vertex;
+
+/// The state in a graphics pipeline describing how the vertex input stage should behave.
+#[derive(Clone, Debug, Default)]
+pub struct VertexInputState {
+ /// A description of the vertex buffers that the vertex input stage will read from.
+ pub bindings: HashMap<u32, VertexInputBindingDescription>,
+
+ /// Describes, for each shader input location, the mapping between elements in a vertex buffer
+ /// and the components of that location in the shader.
+ pub attributes: HashMap<u32, VertexInputAttributeDescription>,
+}
+
+impl VertexInputState {
+ /// Constructs a new `VertexInputState` with no bindings or attributes.
+ #[inline]
+ pub fn new() -> VertexInputState {
+ VertexInputState {
+ bindings: Default::default(),
+ attributes: Default::default(),
+ }
+ }
+
+ /// Adds a single binding.
+ #[inline]
+ pub fn binding(mut self, binding: u32, description: VertexInputBindingDescription) -> Self {
+ self.bindings.insert(binding, description);
+ self
+ }
+
+ /// Sets all bindings.
+ pub fn bindings(
+ mut self,
+ bindings: impl IntoIterator<Item = (u32, VertexInputBindingDescription)>,
+ ) -> Self {
+ self.bindings = bindings.into_iter().collect();
+ self
+ }
+
+ /// Adds a single attribute.
+ #[inline]
+ pub fn attribute(
+ mut self,
+ location: u32,
+ description: VertexInputAttributeDescription,
+ ) -> Self {
+ self.attributes.insert(location, description);
+ self
+ }
+
+ /// Sets all attributes.
+ pub fn attributes(
+ mut self,
+ attributes: impl IntoIterator<Item = (u32, VertexInputAttributeDescription)>,
+ ) -> Self {
+ self.attributes = attributes.into_iter().collect();
+ self
+ }
+}
+
+/// Describes a single vertex buffer binding.
+#[derive(Clone, Debug)]
+pub struct VertexInputBindingDescription {
+ /// The number of bytes from the start of one element in the vertex buffer to the start of the
+ /// next element. This can be simply the size of the data in each element, but larger strides
+ /// are possible.
+ pub stride: u32,
+
+ /// How often the vertex input should advance to the next element.
+ pub input_rate: VertexInputRate,
+}
+
+/// Describes a single vertex buffer attribute mapping.
+#[derive(Clone, Copy, Debug)]
+pub struct VertexInputAttributeDescription {
+ /// The vertex buffer binding number that this attribute should take its data from.
+ pub binding: u32,
+
+ /// The size and type of the vertex data.
+ pub format: Format,
+
+ /// Number of bytes between the start of a vertex buffer element and the location of attribute.
+ ///
+ /// On [portability subset](crate::instance#portability-subset-devices-and-the-enumerate_portability-flag)
+ /// devices, if the sum of `offset + format.block_size()` is greater than the `stride` of
+ /// `binding`, the
+ /// [`vertex_attribute_access_beyond_stride`](crate::device::Features::vertex_attribute_access_beyond_stride)
+ /// feature must be enabled on the device.
+ pub offset: u32,
+}
+
+/// How the vertex source should be unrolled.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum VertexInputRate {
+ /// Each element of the source corresponds to a vertex.
+ Vertex,
+
+ /// Each element of the source corresponds to an instance.
+ ///
+ /// `divisor` indicates how many consecutive instances will use the same instance buffer data.
+ /// This value must be 1, unless the [`vertex_attribute_instance_rate_divisor`] feature has
+ /// been enabled on the device.
+ ///
+ /// `divisor` can be 0 if the [`vertex_attribute_instance_rate_zero_divisor`] feature is also
+ /// enabled. This means that every vertex will use the same vertex and instance data.
+ ///
+ /// [`vertex_attribute_instance_rate_divisor`]: crate::device::Features::vertex_attribute_instance_rate_divisor
+ /// [`vertex_attribute_instance_rate_zero_divisor`]: crate::device::Features::vertex_attribute_instance_rate_zero_divisor
+ Instance { divisor: u32 },
+}
+
+impl From<VertexInputRate> for ash::vk::VertexInputRate {
+ #[inline]
+ fn from(val: VertexInputRate) -> Self {
+ match val {
+ VertexInputRate::Vertex => ash::vk::VertexInputRate::VERTEX,
+ VertexInputRate::Instance { .. } => ash::vk::VertexInputRate::INSTANCE,
+ }
+ }
+}
diff --git a/src/pipeline/graphics/vertex_input/vertex.rs b/src/pipeline/graphics/vertex_input/vertex.rs
new file mode 100644
index 0000000..fb500aa
--- /dev/null
+++ b/src/pipeline/graphics/vertex_input/vertex.rs
@@ -0,0 +1,155 @@
+// Copyright (c) 2017 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use super::VertexInputRate;
+use crate::{buffer::BufferContents, format::Format};
+use std::collections::HashMap;
+#[cfg(feature = "macros")]
+pub use vulkano_macros::Vertex;
+
+/// Describes an individual `Vertex`. In other words a collection of attributes that can be read
+/// from a vertex shader.
+///
+/// At this stage, the vertex is in a "raw" format. For example a `[f32; 4]` can match both a
+/// `vec4` or a `float[4]`. The way the things are bound depends on the shader.
+///
+/// The vertex trait can be derived and the format has to be specified using the `format`
+/// field-level attribute:
+///
+/// ```
+/// use vulkano::{buffer::BufferContents, pipeline::graphics::vertex_input::Vertex};
+///
+/// #[derive(BufferContents, Vertex)]
+/// #[repr(C)]
+/// struct MyVertex {
+/// // Every field needs to explicitly state the desired shader input format
+/// #[format(R32G32B32_SFLOAT)]
+/// pos: [f32; 3],
+/// // The `name` attribute can be used to specify shader input names to match.
+/// // By default the field-name is used.
+/// #[name("in_proj", "cam_proj")]
+/// #[format(R32G32B32_SFLOAT)]
+/// proj: [f32; 16],
+/// }
+/// ```
+pub unsafe trait Vertex: BufferContents + Sized {
+ /// Returns the information about this Vertex type.
+ fn per_vertex() -> VertexBufferDescription;
+
+ fn per_instance() -> VertexBufferDescription;
+
+ fn per_instance_with_divisor(divisor: u32) -> VertexBufferDescription;
+}
+
+/// Describes the contents of a VertexBuffer.
+#[derive(Clone, Debug)]
+pub struct VertexBufferDescription {
+ /// List of member names with their detailed information.
+ pub members: HashMap<String, VertexMemberInfo>,
+ /// Stride of the vertex type in a buffer.
+ pub stride: u32,
+ /// How the vertex buffer is unrolled in the shader.
+ pub input_rate: VertexInputRate,
+}
+
+impl VertexBufferDescription {
+ #[inline]
+ pub fn per_vertex(self) -> VertexBufferDescription {
+ let VertexBufferDescription {
+ members, stride, ..
+ } = self;
+ VertexBufferDescription {
+ members,
+ stride,
+ input_rate: VertexInputRate::Vertex,
+ }
+ }
+
+ #[inline]
+ pub fn per_instance(self) -> VertexBufferDescription {
+ self.per_instance_with_divisor(1)
+ }
+
+ #[inline]
+ pub fn per_instance_with_divisor(self, divisor: u32) -> VertexBufferDescription {
+ let VertexBufferDescription {
+ members, stride, ..
+ } = self;
+ VertexBufferDescription {
+ members,
+ stride,
+ input_rate: VertexInputRate::Instance { divisor },
+ }
+ }
+}
+
+/// Information about a member of a vertex struct.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct VertexMemberInfo {
+ /// Offset of the member in bytes from the start of the struct.
+ pub offset: usize,
+ /// Attribute format of the member. Implicitly provides number of components.
+ pub format: Format,
+ /// Number of consecutive array elements or matrix columns using format. The corresponding
+ /// number of locations might defer depending on the size of the format.
+ pub num_elements: u32,
+}
+
+impl VertexMemberInfo {
+ #[inline]
+ pub fn num_components(&self) -> u32 {
+ self.format
+ .components()
+ .iter()
+ .filter(|&bits| *bits > 0)
+ .count() as u32
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::format::Format;
+ use crate::pipeline::graphics::vertex_input::Vertex;
+
+ use bytemuck::{Pod, Zeroable};
+
+ #[test]
+ fn derive_vertex_multiple_names() {
+ #[repr(C)]
+ #[derive(Clone, Copy, Debug, Default, Zeroable, Pod, Vertex)]
+ struct TestVertex {
+ #[name("b", "c")]
+ #[format(R32G32B32A32_SFLOAT)]
+ a: [f32; 16],
+ }
+
+ let info = TestVertex::per_vertex();
+ let b = info.members.get("b").unwrap();
+ let c = info.members.get("c").unwrap();
+ assert_eq!(b.format, Format::R32G32B32A32_SFLOAT);
+ assert_eq!(c.format, Format::R32G32B32A32_SFLOAT);
+ assert_eq!(b.num_elements, 4);
+ assert_eq!(c.num_elements, 4);
+ }
+
+ #[test]
+ fn derive_vertex_format() {
+ #[repr(C)]
+ #[derive(Clone, Copy, Debug, Default, Zeroable, Pod, Vertex)]
+ struct TestVertex {
+ #[format(R8_UNORM)]
+ unorm: u8,
+ }
+
+ let info = TestVertex::per_instance();
+ let unorm = info.members.get("unorm").unwrap();
+ assert_eq!(unorm.format, Format::R8_UNORM);
+ assert_eq!(unorm.num_elements, 1);
+ }
+}
diff --git a/src/pipeline/viewport.rs b/src/pipeline/graphics/viewport.rs
index e899369..aeb3810 100644
--- a/src/pipeline/viewport.rs
+++ b/src/pipeline/graphics/viewport.rs
@@ -7,15 +7,15 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-//! Viewports and scissor boxes.
+//! Configures the area of the framebuffer that pixels will be written to.
//!
//! There are two different concepts to determine where things will be drawn:
//!
-//! - The viewport is the region of the image which corresponds to the
-//! vertex coordinates `-1.0` to `1.0`.
+//! - The viewport is the region of the image which corresponds to the vertex coordinates `-1.0` to
+//! `1.0`.
//! - Any pixel outside of the scissor box will be discarded.
//!
-//! In other words modifying the viewport will stretch the image, while modifying the scissor
+//! In other words, modifying the viewport will stretch the image, while modifying the scissor
//! box acts like a filter.
//!
//! It is legal and sensible to use a viewport that is larger than the target image or that
@@ -54,68 +54,146 @@ use std::ops::Range;
///
/// Note that the number of viewports and scissors must be the same.
#[derive(Debug, Clone)]
-pub enum ViewportsState {
+pub enum ViewportState {
/// The state is known in advance.
Fixed {
/// State of the viewports and scissors.
data: Vec<(Viewport, Scissor)>,
},
+ /// The state of viewports is known in advance, but the state of scissors is dynamic and will
+ /// be set when drawing.
+ FixedViewport {
+ /// State of the viewports.
+ viewports: Vec<Viewport>,
+
+ /// Sets whether the scissor count is also dynamic, or only the scissors themselves.
+ ///
+ /// If set to `true`, the device API version must be at least 1.3, or the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must
+ /// be enabled on the device.
+ scissor_count_dynamic: bool,
+ },
+
/// The state of scissors is known in advance, but the state of viewports is dynamic and will
- /// bet set when drawing.
- ///
- /// Note that the number of viewports and scissors must be the same.
- DynamicViewports {
+ /// be set when drawing.
+ FixedScissor {
/// State of the scissors.
scissors: Vec<Scissor>,
- },
- /// The state of viewports is known in advance, but the state of scissors is dynamic and will
- /// bet set when drawing.
- ///
- /// Note that the number of viewports and scissors must be the same.
- DynamicScissors {
- /// State of the viewports
- viewports: Vec<Viewport>,
+ /// Sets whether the viewport count is also dynamic, or only the viewports themselves.
+ ///
+ /// If set to `true`, the device API version must be at least 1.3, or the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must
+ /// be enabled on the device.
+ viewport_count_dynamic: bool,
},
/// The state of both the viewports and scissors is dynamic and will be set when drawing.
Dynamic {
/// Number of viewports and scissors.
- num: u32,
+ ///
+ /// This is ignored if both `viewport_count_dynamic` and `scissor_count_dynamic` are `true`.
+ count: u32,
+
+ /// Sets whether the viewport count is also dynamic, or only the viewports themselves.
+ ///
+ /// If set to `true`, the device API version must be at least 1.3, or the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must
+ /// be enabled on the device.
+ viewport_count_dynamic: bool,
+
+ /// Sets whether the scissor count is also dynamic, or only the scissors themselves.
+ ///
+ /// If set to `true`, the device API version must be at least 1.3, or the
+ /// [`extended_dynamic_state`](crate::device::Features::extended_dynamic_state) feature must
+ /// be enabled on the device.
+ scissor_count_dynamic: bool,
},
}
-impl ViewportsState {
- /// Returns true if the state of the viewports is dynamic.
- pub fn dynamic_viewports(&self) -> bool {
- match *self {
- ViewportsState::Fixed { .. } => false,
- ViewportsState::DynamicViewports { .. } => true,
- ViewportsState::DynamicScissors { .. } => false,
- ViewportsState::Dynamic { .. } => true,
+impl ViewportState {
+ /// Creates a `ViewportState` with fixed state and no viewports or scissors.
+ #[inline]
+ pub fn new() -> Self {
+ Self::Fixed { data: Vec::new() }
+ }
+
+ /// Creates a `ViewportState` with fixed state from the given viewports and scissors.
+ pub fn viewport_fixed_scissor_fixed(
+ data: impl IntoIterator<Item = (Viewport, Scissor)>,
+ ) -> Self {
+ Self::Fixed {
+ data: data.into_iter().collect(),
}
}
- /// Returns true if the state of the scissors is dynamic.
- pub fn dynamic_scissors(&self) -> bool {
- match *self {
- ViewportsState::Fixed { .. } => false,
- ViewportsState::DynamicViewports { .. } => false,
- ViewportsState::DynamicScissors { .. } => true,
- ViewportsState::Dynamic { .. } => true,
+ /// Creates a `ViewportState` with fixed state from the given viewports, and matching scissors
+ /// that cover the whole viewport.
+ pub fn viewport_fixed_scissor_irrelevant(data: impl IntoIterator<Item = Viewport>) -> Self {
+ Self::Fixed {
+ data: data
+ .into_iter()
+ .map(|viewport| (viewport, Scissor::irrelevant()))
+ .collect(),
}
}
- /// Returns the number of viewports and scissors.
- pub fn num_viewports(&self) -> u32 {
- match *self {
- ViewportsState::Fixed { ref data } => data.len() as u32,
- ViewportsState::DynamicViewports { ref scissors } => scissors.len() as u32,
- ViewportsState::DynamicScissors { ref viewports } => viewports.len() as u32,
- ViewportsState::Dynamic { num } => num,
+ /// Creates a `ViewportState` with dynamic viewport, and a single scissor that always covers
+ /// the whole viewport.
+ #[inline]
+ pub fn viewport_dynamic_scissor_irrelevant() -> Self {
+ Self::FixedScissor {
+ scissors: vec![Scissor::irrelevant()],
+ viewport_count_dynamic: false,
}
}
+
+ /// Creates a `ViewportState` with dynamic viewports and scissors, but a fixed count.
+ #[inline]
+ pub fn viewport_dynamic_scissor_dynamic(count: u32) -> Self {
+ Self::Dynamic {
+ count,
+ viewport_count_dynamic: false,
+ scissor_count_dynamic: false,
+ }
+ }
+
+ /// Creates a `ViewportState` with dynamic viewport count and scissor count.
+ #[inline]
+ pub fn viewport_count_dynamic_scissor_count_dynamic() -> Self {
+ Self::Dynamic {
+ count: 0,
+ viewport_count_dynamic: true,
+ scissor_count_dynamic: true,
+ }
+ }
+
+ /// Returns the number of viewports and scissors.
+ ///
+ /// `None` is returned if both `viewport_count_dynamic` and `scissor_count_dynamic` are `true`.
+ #[inline]
+ pub fn count(&self) -> Option<u32> {
+ Some(match *self {
+ ViewportState::Fixed { ref data } => data.len() as u32,
+ ViewportState::FixedViewport { ref viewports, .. } => viewports.len() as u32,
+ ViewportState::FixedScissor { ref scissors, .. } => scissors.len() as u32,
+ ViewportState::Dynamic {
+ viewport_count_dynamic: true,
+ scissor_count_dynamic: true,
+ ..
+ } => return None,
+ ViewportState::Dynamic { count, .. } => count,
+ })
+ }
+}
+
+impl Default for ViewportState {
+ /// Returns [`ViewportState::new()`].
+ #[inline]
+ fn default() -> Self {
+ Self::new()
+ }
}
/// State of a single viewport.
@@ -161,14 +239,15 @@ impl From<Viewport> for ash::vk::Viewport {
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct Scissor {
/// Coordinates in pixels of the top-left hand corner of the box.
- pub origin: [i32; 2],
+ pub origin: [u32; 2],
/// Dimensions in pixels of the box.
pub dimensions: [u32; 2],
}
impl Scissor {
- /// Returns a scissor that, when used, will instruct the pipeline to draw to the entire framebuffer.
+ /// Returns a scissor that, when used, will instruct the pipeline to draw to the entire
+ /// framebuffer no matter its size.
#[inline]
pub fn irrelevant() -> Scissor {
Scissor {
@@ -190,8 +269,8 @@ impl From<Scissor> for ash::vk::Rect2D {
fn from(val: Scissor) -> Self {
ash::vk::Rect2D {
offset: ash::vk::Offset2D {
- x: val.origin[0],
- y: val.origin[1],
+ x: val.origin[0] as i32,
+ y: val.origin[1] as i32,
},
extent: ash::vk::Extent2D {
width: val.dimensions[0],
diff --git a/src/pipeline/graphics_pipeline/builder.rs b/src/pipeline/graphics_pipeline/builder.rs
deleted file mode 100644
index 5f9a770..0000000
--- a/src/pipeline/graphics_pipeline/builder.rs
+++ /dev/null
@@ -1,1952 +0,0 @@
-// Copyright (c) 2017 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-// TODO: graphics pipeline params are deprecated, but are still the primary implementation in order
-// to avoid duplicating code, so we hide the warnings for now
-#![allow(deprecated)]
-
-use crate::check_errors;
-use crate::descriptor_set::layout::DescriptorSetDesc;
-use crate::descriptor_set::layout::DescriptorSetLayout;
-use crate::device::Device;
-use crate::image::SampleCount;
-use crate::pipeline::blend::AttachmentBlend;
-use crate::pipeline::blend::AttachmentsBlend;
-use crate::pipeline::blend::Blend;
-use crate::pipeline::blend::LogicOp;
-use crate::pipeline::cache::PipelineCache;
-use crate::pipeline::depth_stencil::Compare;
-use crate::pipeline::depth_stencil::DepthBounds;
-use crate::pipeline::depth_stencil::DepthStencil;
-use crate::pipeline::graphics_pipeline::GraphicsPipeline;
-use crate::pipeline::graphics_pipeline::GraphicsPipelineCreationError;
-use crate::pipeline::graphics_pipeline::Inner as GraphicsPipelineInner;
-use crate::pipeline::input_assembly::PrimitiveTopology;
-use crate::pipeline::layout::PipelineLayout;
-use crate::pipeline::layout::PipelineLayoutPcRange;
-use crate::pipeline::raster::CullMode;
-use crate::pipeline::raster::DepthBiasControl;
-use crate::pipeline::raster::FrontFace;
-use crate::pipeline::raster::PolygonMode;
-use crate::pipeline::raster::Rasterization;
-use crate::pipeline::shader::EntryPointAbstract;
-use crate::pipeline::shader::GraphicsEntryPoint;
-use crate::pipeline::shader::GraphicsShaderType;
-use crate::pipeline::shader::SpecializationConstants;
-use crate::pipeline::vertex::BufferlessDefinition;
-use crate::pipeline::vertex::BuffersDefinition;
-use crate::pipeline::vertex::Vertex;
-use crate::pipeline::vertex::VertexDefinition;
-use crate::pipeline::vertex::VertexInputRate;
-use crate::pipeline::viewport::Scissor;
-use crate::pipeline::viewport::Viewport;
-use crate::pipeline::viewport::ViewportsState;
-use crate::render_pass::Subpass;
-use crate::OomError;
-use crate::VulkanObject;
-use smallvec::SmallVec;
-use std::collections::hash_map::{Entry, HashMap};
-use std::mem;
-use std::mem::MaybeUninit;
-use std::ptr;
-use std::sync::Arc;
-use std::u32;
-
-/// Prototype for a `GraphicsPipeline`.
-// TODO: we can optimize this by filling directly the raw vk structs
-pub struct GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss> {
- vertex_definition: Vdef,
- vertex_shader: Option<(GraphicsEntryPoint<'vs>, Vss)>,
- input_assembly: ash::vk::PipelineInputAssemblyStateCreateInfo,
- // Note: the `input_assembly_topology` member is temporary in order to not lose information
- // about the number of patches per primitive.
- input_assembly_topology: PrimitiveTopology,
- tessellation: Option<TessInfo<'tcs, 'tes, Tcss, Tess>>,
- geometry_shader: Option<(GraphicsEntryPoint<'gs>, Gss)>,
- viewport: Option<ViewportsState>,
- raster: Rasterization,
- multisample: ash::vk::PipelineMultisampleStateCreateInfo,
- fragment_shader: Option<(GraphicsEntryPoint<'fs>, Fss)>,
- depth_stencil: DepthStencil,
- blend: Blend,
- subpass: Option<Subpass>,
- cache: Option<Arc<PipelineCache>>,
-}
-
-// Additional parameters if tessellation is used.
-#[derive(Clone, Debug)]
-struct TessInfo<'tcs, 'tes, Tcss, Tess> {
- tessellation_control_shader: (GraphicsEntryPoint<'tcs>, Tcss),
- tessellation_evaluation_shader: (GraphicsEntryPoint<'tes>, Tess),
-}
-
-impl
- GraphicsPipelineBuilder<
- 'static,
- 'static,
- 'static,
- 'static,
- 'static,
- BufferlessDefinition,
- (),
- (),
- (),
- (),
- (),
- >
-{
- /// Builds a new empty builder.
- pub(super) fn new() -> Self {
- GraphicsPipelineBuilder {
- vertex_definition: BufferlessDefinition,
- vertex_shader: None,
- input_assembly: ash::vk::PipelineInputAssemblyStateCreateInfo {
- topology: PrimitiveTopology::TriangleList.into(),
- ..Default::default()
- },
- input_assembly_topology: PrimitiveTopology::TriangleList,
- tessellation: None,
- geometry_shader: None,
- viewport: None,
- raster: Default::default(),
- multisample: ash::vk::PipelineMultisampleStateCreateInfo::default(),
- fragment_shader: None,
- depth_stencil: DepthStencil::disabled(),
- blend: Blend::pass_through(),
- subpass: None,
- cache: None,
- }
- }
-}
-
-impl<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss>
- GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss>
-where
- Vdef: VertexDefinition,
- Vss: SpecializationConstants,
- Tcss: SpecializationConstants,
- Tess: SpecializationConstants,
- Gss: SpecializationConstants,
- Fss: SpecializationConstants,
-{
- /// Builds the graphics pipeline, using an inferred a pipeline layout.
- pub fn build(
- self,
- device: Arc<Device>,
- ) -> Result<GraphicsPipeline<Vdef>, GraphicsPipelineCreationError> {
- self.with_auto_layout(device, &[])
- }
-
- /// Builds the graphics pipeline, using an inferred pipeline layout with some dynamic buffers.
- ///
- /// Configures the inferred layout for each descriptor `(set, binding)` in `dynamic_buffers` to accept dynamic
- /// buffers.
- pub fn with_auto_layout(
- self,
- device: Arc<Device>,
- dynamic_buffers: &[(usize, usize)],
- ) -> Result<GraphicsPipeline<Vdef>, GraphicsPipelineCreationError> {
- let (descriptor_set_layout_descs, push_constant_ranges) = {
- let stages: SmallVec<[&GraphicsEntryPoint; 5]> = std::array::IntoIter::new([
- self.vertex_shader.as_ref().map(|s| &s.0),
- self.tessellation
- .as_ref()
- .map(|s| &s.tessellation_control_shader.0),
- self.tessellation
- .as_ref()
- .map(|s| &s.tessellation_evaluation_shader.0),
- self.geometry_shader.as_ref().map(|s| &s.0),
- self.fragment_shader.as_ref().map(|s| &s.0),
- ])
- .flatten()
- .collect();
-
- for (output, input) in stages.iter().zip(stages.iter().skip(1)) {
- if let Err(err) = input.input().matches(output.output()) {
- return Err(GraphicsPipelineCreationError::ShaderStagesMismatch(err));
- }
- }
-
- let mut descriptor_set_layout_descs = stages
- .iter()
- .try_fold(vec![], |total, shader| -> Result<_, ()> {
- DescriptorSetDesc::union_multiple(&total, shader.descriptor_set_layout_descs())
- })
- .expect("Can't be union'd");
- DescriptorSetDesc::tweak_multiple(
- &mut descriptor_set_layout_descs,
- dynamic_buffers.into_iter().cloned(),
- );
-
- // We want to union each push constant range into a set of ranges that do not have intersecting stage flags.
- // e.g. The range [0, 16) is either made available to Vertex | Fragment or we only make [0, 16) available to
- // Vertex and a subrange available to Fragment, like [0, 8)
- let mut range_map = HashMap::new();
- for stage in stages.iter() {
- if let Some(range) = stage.push_constant_range() {
- match range_map.entry((range.offset, range.size)) {
- Entry::Vacant(entry) => {
- entry.insert(range.stages);
- },
- Entry::Occupied(mut entry) => {
- *entry.get_mut() = *entry.get() | range.stages;
- },
- }
- }
- }
- let push_constant_ranges: Vec<_> = range_map
- .iter()
- .map(|((offset, size), stages)| {
- PipelineLayoutPcRange { offset: *offset, size: *size, stages: *stages }
- })
- .collect();
-
- (descriptor_set_layout_descs, push_constant_ranges)
- };
-
- let descriptor_set_layouts = descriptor_set_layout_descs
- .into_iter()
- .map(|desc| Ok(Arc::new(DescriptorSetLayout::new(device.clone(), desc)?)))
- .collect::<Result<Vec<_>, OomError>>()?;
- let pipeline_layout = Arc::new(
- PipelineLayout::new(device.clone(), descriptor_set_layouts, push_constant_ranges)
- .unwrap(),
- );
- self.with_pipeline_layout(device, pipeline_layout)
- }
-
- /// Builds the graphics pipeline.
- ///
- /// Does the same as `build`, except that `build` automatically builds the pipeline layout
- /// object corresponding to the union of your shaders while this function allows you to specify
- /// the pipeline layout.
- pub fn with_pipeline_layout(
- mut self,
- device: Arc<Device>,
- pipeline_layout: Arc<PipelineLayout>,
- ) -> Result<GraphicsPipeline<Vdef>, GraphicsPipelineCreationError> {
- // TODO: return errors instead of panicking if missing param
-
- let fns = device.fns();
-
- // Checking that the pipeline layout matches the shader stages.
- // TODO: more details in the errors
-
- {
- let shader = &self.vertex_shader.as_ref().unwrap().0;
- pipeline_layout.ensure_superset_of(
- shader.descriptor_set_layout_descs(),
- shader.push_constant_range(),
- )?;
- }
-
- if let Some(ref geometry_shader) = self.geometry_shader {
- let shader = &geometry_shader.0;
- pipeline_layout.ensure_superset_of(
- shader.descriptor_set_layout_descs(),
- shader.push_constant_range(),
- )?;
- }
-
- if let Some(ref tess) = self.tessellation {
- {
- let shader = &tess.tessellation_control_shader.0;
- pipeline_layout.ensure_superset_of(
- shader.descriptor_set_layout_descs(),
- shader.push_constant_range(),
- )?;
- }
-
- {
- let shader = &tess.tessellation_evaluation_shader.0;
- pipeline_layout.ensure_superset_of(
- shader.descriptor_set_layout_descs(),
- shader.push_constant_range(),
- )?;
- }
- }
-
- if let Some(ref fragment_shader) = self.fragment_shader {
- let shader = &fragment_shader.0;
- pipeline_layout.ensure_superset_of(
- shader.descriptor_set_layout_descs(),
- shader.push_constant_range(),
- )?;
-
- // Check that the subpass can accept the output of the fragment shader.
- // TODO: If there is no fragment shader, what should be checked then? The previous stage?
- if !self
- .subpass
- .as_ref()
- .unwrap()
- .is_compatible_with(shader.output())
- {
- return Err(GraphicsPipelineCreationError::FragmentShaderRenderPassIncompatible);
- }
- }
-
- // Will contain the list of dynamic states. Filled throughout this function.
- let mut dynamic_states: SmallVec<[ash::vk::DynamicState; 8]> = SmallVec::new();
-
- // Creating the specialization constants of the various stages.
- let vertex_shader_specialization = {
- let shader = self.vertex_shader.as_ref().unwrap();
- let spec_descriptors = Vss::descriptors();
- if spec_descriptors != shader.0.spec_constants() {
- return Err(GraphicsPipelineCreationError::IncompatibleSpecializationConstants);
- }
-
- let constants = &shader.1;
- ash::vk::SpecializationInfo {
- map_entry_count: spec_descriptors.len() as u32,
- p_map_entries: spec_descriptors.as_ptr() as *const _,
- data_size: mem::size_of_val(constants),
- p_data: constants as *const Vss as *const _,
- }
- };
-
- let tess_shader_specialization = if let Some(ref tess) = self.tessellation {
- let tcs_spec = {
- let shader = &tess.tessellation_control_shader;
- let spec_descriptors = Tcss::descriptors();
- if spec_descriptors != shader.0.spec_constants() {
- return Err(GraphicsPipelineCreationError::IncompatibleSpecializationConstants);
- }
-
- let constants = &shader.1;
- ash::vk::SpecializationInfo {
- map_entry_count: spec_descriptors.len() as u32,
- p_map_entries: spec_descriptors.as_ptr() as *const _,
- data_size: mem::size_of_val(constants),
- p_data: constants as *const Tcss as *const _,
- }
- };
- let tes_spec = {
- let shader = &tess.tessellation_evaluation_shader;
- let spec_descriptors = Tess::descriptors();
- if spec_descriptors != shader.0.spec_constants() {
- return Err(GraphicsPipelineCreationError::IncompatibleSpecializationConstants);
- }
-
- let constants = &shader.1;
- ash::vk::SpecializationInfo {
- map_entry_count: spec_descriptors.len() as u32,
- p_map_entries: spec_descriptors.as_ptr() as *const _,
- data_size: mem::size_of_val(constants),
- p_data: constants as *const Tess as *const _,
- }
- };
- Some((tcs_spec, tes_spec))
- } else {
- None
- };
-
- let geometry_shader_specialization = if let Some(ref shader) = self.geometry_shader {
- let spec_descriptors = Gss::descriptors();
- if spec_descriptors != shader.0.spec_constants() {
- return Err(GraphicsPipelineCreationError::IncompatibleSpecializationConstants);
- }
-
- let constants = &shader.1;
- Some(ash::vk::SpecializationInfo {
- map_entry_count: spec_descriptors.len() as u32,
- p_map_entries: spec_descriptors.as_ptr() as *const _,
- data_size: mem::size_of_val(constants),
- p_data: constants as *const Gss as *const _,
- })
- } else {
- None
- };
-
- let fragment_shader_specialization = if let Some(ref shader) = self.fragment_shader {
- let spec_descriptors = Fss::descriptors();
- if spec_descriptors != shader.0.spec_constants() {
- return Err(GraphicsPipelineCreationError::IncompatibleSpecializationConstants);
- }
-
- let constants = &shader.1;
- Some(ash::vk::SpecializationInfo {
- map_entry_count: spec_descriptors.len() as u32,
- p_map_entries: spec_descriptors.as_ptr() as *const _,
- data_size: mem::size_of_val(constants),
- p_data: constants as *const Fss as *const _,
- })
- } else {
- None
- };
-
- // List of shader stages.
- let stages = {
- let mut stages = SmallVec::<[_; 5]>::new();
-
- match self.vertex_shader.as_ref().unwrap().0.ty() {
- GraphicsShaderType::Vertex => {}
- _ => return Err(GraphicsPipelineCreationError::WrongShaderType),
- };
-
- stages.push(ash::vk::PipelineShaderStageCreateInfo {
- flags: ash::vk::PipelineShaderStageCreateFlags::empty(),
- stage: ash::vk::ShaderStageFlags::VERTEX,
- module: self
- .vertex_shader
- .as_ref()
- .unwrap()
- .0
- .module()
- .internal_object(),
- p_name: self.vertex_shader.as_ref().unwrap().0.name().as_ptr(),
- p_specialization_info: &vertex_shader_specialization as *const _,
- ..Default::default()
- });
-
- if let Some(ref tess) = self.tessellation {
- // FIXME: must check that the control shader and evaluation shader are compatible
-
- if !device.enabled_features().tessellation_shader {
- return Err(GraphicsPipelineCreationError::TessellationShaderFeatureNotEnabled);
- }
-
- match tess.tessellation_control_shader.0.ty() {
- GraphicsShaderType::TessellationControl => {}
- _ => return Err(GraphicsPipelineCreationError::WrongShaderType),
- };
-
- match tess.tessellation_evaluation_shader.0.ty() {
- GraphicsShaderType::TessellationEvaluation => {}
- _ => return Err(GraphicsPipelineCreationError::WrongShaderType),
- };
-
- stages.push(ash::vk::PipelineShaderStageCreateInfo {
- flags: ash::vk::PipelineShaderStageCreateFlags::empty(),
- stage: ash::vk::ShaderStageFlags::TESSELLATION_CONTROL,
- module: tess
- .tessellation_control_shader
- .0
- .module()
- .internal_object(),
- p_name: tess.tessellation_control_shader.0.name().as_ptr(),
- p_specialization_info: &tess_shader_specialization.as_ref().unwrap().0
- as *const _,
- ..Default::default()
- });
-
- stages.push(ash::vk::PipelineShaderStageCreateInfo {
- flags: ash::vk::PipelineShaderStageCreateFlags::empty(),
- stage: ash::vk::ShaderStageFlags::TESSELLATION_EVALUATION,
- module: tess
- .tessellation_evaluation_shader
- .0
- .module()
- .internal_object(),
- p_name: tess.tessellation_evaluation_shader.0.name().as_ptr(),
- p_specialization_info: &tess_shader_specialization.as_ref().unwrap().1
- as *const _,
- ..Default::default()
- });
- }
-
- if let Some(ref geometry_shader) = self.geometry_shader {
- if !device.enabled_features().geometry_shader {
- return Err(GraphicsPipelineCreationError::GeometryShaderFeatureNotEnabled);
- }
-
- match geometry_shader.0.ty() {
- GraphicsShaderType::Geometry(_) => {}
- _ => return Err(GraphicsPipelineCreationError::WrongShaderType),
- };
-
- stages.push(ash::vk::PipelineShaderStageCreateInfo {
- flags: ash::vk::PipelineShaderStageCreateFlags::empty(),
- stage: ash::vk::ShaderStageFlags::GEOMETRY,
- module: geometry_shader.0.module().internal_object(),
- p_name: geometry_shader.0.name().as_ptr(),
- p_specialization_info: geometry_shader_specialization.as_ref().unwrap()
- as *const _,
- ..Default::default()
- });
- }
-
- if let Some(ref fragment_shader) = self.fragment_shader {
- match fragment_shader.0.ty() {
- GraphicsShaderType::Fragment => {}
- _ => return Err(GraphicsPipelineCreationError::WrongShaderType),
- };
-
- stages.push(ash::vk::PipelineShaderStageCreateInfo {
- flags: ash::vk::PipelineShaderStageCreateFlags::empty(),
- stage: ash::vk::ShaderStageFlags::FRAGMENT,
- module: fragment_shader.0.module().internal_object(),
- p_name: fragment_shader.0.name().as_ptr(),
- p_specialization_info: fragment_shader_specialization.as_ref().unwrap()
- as *const _,
- ..Default::default()
- });
- }
-
- stages
- };
-
- // Vertex input.
- let vertex_input = self
- .vertex_definition
- .definition(self.vertex_shader.as_ref().unwrap().0.input())?;
-
- let (binding_descriptions, binding_divisor_descriptions) = {
- let mut binding_descriptions = SmallVec::<[_; 8]>::new();
- let mut binding_divisor_descriptions = SmallVec::<[_; 8]>::new();
-
- for (binding, binding_desc) in vertex_input.bindings() {
- if binding
- >= device
- .physical_device()
- .properties()
- .max_vertex_input_bindings
- {
- return Err(
- GraphicsPipelineCreationError::MaxVertexInputBindingsExceeded {
- max: device
- .physical_device()
- .properties()
- .max_vertex_input_bindings,
- obtained: binding,
- },
- );
- }
-
- if binding_desc.stride
- > device
- .physical_device()
- .properties()
- .max_vertex_input_binding_stride
- {
- return Err(
- GraphicsPipelineCreationError::MaxVertexInputBindingStrideExceeded {
- binding,
- max: device
- .physical_device()
- .properties()
- .max_vertex_input_binding_stride,
- obtained: binding_desc.stride,
- },
- );
- }
-
- binding_descriptions.push(ash::vk::VertexInputBindingDescription {
- binding,
- stride: binding_desc.stride,
- input_rate: binding_desc.input_rate.into(),
- });
-
- if let VertexInputRate::Instance { divisor } = binding_desc.input_rate {
- if divisor != 1 {
- if !device
- .enabled_features()
- .vertex_attribute_instance_rate_divisor
- {
- return Err(GraphicsPipelineCreationError::VertexAttributeInstanceRateDivisorFeatureNotEnabled);
- }
-
- if divisor == 0
- && !device
- .enabled_features()
- .vertex_attribute_instance_rate_zero_divisor
- {
- return Err(GraphicsPipelineCreationError::VertexAttributeInstanceRateZeroDivisorFeatureNotEnabled);
- }
-
- if divisor
- > device
- .physical_device()
- .properties()
- .max_vertex_attrib_divisor
- .unwrap()
- {
- return Err(
- GraphicsPipelineCreationError::MaxVertexAttribDivisorExceeded {
- binding,
- max: device
- .physical_device()
- .properties()
- .max_vertex_attrib_divisor
- .unwrap(),
- obtained: divisor,
- },
- );
- }
-
- binding_divisor_descriptions.push(
- ash::vk::VertexInputBindingDivisorDescriptionEXT { binding, divisor },
- )
- }
- }
- }
-
- if binding_descriptions.len()
- > device
- .physical_device()
- .properties()
- .max_vertex_input_bindings as usize
- {
- return Err(
- GraphicsPipelineCreationError::MaxVertexInputBindingsExceeded {
- max: device
- .physical_device()
- .properties()
- .max_vertex_input_bindings,
- obtained: binding_descriptions.len() as u32,
- },
- );
- }
-
- (binding_descriptions, binding_divisor_descriptions)
- };
-
- let attribute_descriptions = {
- let mut attribute_descriptions = SmallVec::<[_; 8]>::new();
-
- for (location, attribute_desc) in vertex_input.attributes() {
- // TODO: check attribute format support
-
- if attribute_desc.offset
- > device
- .physical_device()
- .properties()
- .max_vertex_input_attribute_offset
- {
- return Err(
- GraphicsPipelineCreationError::MaxVertexInputAttributeOffsetExceeded {
- max: device
- .physical_device()
- .properties()
- .max_vertex_input_attribute_offset,
- obtained: attribute_desc.offset,
- },
- );
- }
-
- attribute_descriptions.push(ash::vk::VertexInputAttributeDescription {
- location,
- binding: attribute_desc.binding,
- format: attribute_desc.format.into(),
- offset: attribute_desc.offset,
- });
- }
-
- if attribute_descriptions.len()
- > device
- .physical_device()
- .properties()
- .max_vertex_input_attributes as usize
- {
- return Err(
- GraphicsPipelineCreationError::MaxVertexInputAttributesExceeded {
- max: device
- .physical_device()
- .properties()
- .max_vertex_input_attributes,
- obtained: attribute_descriptions.len(),
- },
- );
- }
-
- attribute_descriptions
- };
-
- let vertex_input_divisor_state = if !binding_divisor_descriptions.is_empty() {
- Some(ash::vk::PipelineVertexInputDivisorStateCreateInfoEXT {
- vertex_binding_divisor_count: binding_divisor_descriptions.len() as u32,
- p_vertex_binding_divisors: binding_divisor_descriptions.as_ptr(),
- ..Default::default()
- })
- } else {
- None
- };
-
- let vertex_input_state = ash::vk::PipelineVertexInputStateCreateInfo {
- p_next: if let Some(next) = vertex_input_divisor_state.as_ref() {
- next as *const _ as *const _
- } else {
- ptr::null()
- },
- flags: ash::vk::PipelineVertexInputStateCreateFlags::empty(),
- vertex_binding_description_count: binding_descriptions.len() as u32,
- p_vertex_binding_descriptions: binding_descriptions.as_ptr(),
- vertex_attribute_description_count: attribute_descriptions.len() as u32,
- p_vertex_attribute_descriptions: attribute_descriptions.as_ptr(),
- ..Default::default()
- };
-
- if self.input_assembly.primitive_restart_enable != ash::vk::FALSE
- && !self.input_assembly_topology.supports_primitive_restart()
- {
- return Err(
- GraphicsPipelineCreationError::PrimitiveDoesntSupportPrimitiveRestart {
- primitive: self.input_assembly_topology,
- },
- );
- }
-
- // TODO: should check from the tess eval shader instead of the input assembly
- if let Some(ref gs) = self.geometry_shader {
- match gs.0.ty() {
- GraphicsShaderType::Geometry(primitives) => {
- if !primitives.matches(self.input_assembly_topology) {
- return Err(
- GraphicsPipelineCreationError::TopologyNotMatchingGeometryShader,
- );
- }
- }
- _ => return Err(GraphicsPipelineCreationError::WrongShaderType),
- }
- }
-
- let tessellation = match self.input_assembly_topology {
- PrimitiveTopology::PatchList { vertices_per_patch } => {
- if self.tessellation.is_none() {
- return Err(GraphicsPipelineCreationError::InvalidPrimitiveTopology);
- }
- if vertices_per_patch
- > device
- .physical_device()
- .properties()
- .max_tessellation_patch_size
- {
- return Err(GraphicsPipelineCreationError::MaxTessellationPatchSizeExceeded);
- }
-
- Some(ash::vk::PipelineTessellationStateCreateInfo {
- flags: ash::vk::PipelineTessellationStateCreateFlags::empty(),
- patch_control_points: vertices_per_patch,
- ..Default::default()
- })
- }
- _ => {
- if self.tessellation.is_some() {
- return Err(GraphicsPipelineCreationError::InvalidPrimitiveTopology);
- }
-
- None
- }
- };
-
- let (vp_vp, vp_sc, vp_num) = match *self.viewport.as_ref().unwrap() {
- ViewportsState::Fixed { ref data } => (
- data.iter()
- .map(|e| e.0.clone().into())
- .collect::<SmallVec<[ash::vk::Viewport; 4]>>(),
- data.iter()
- .map(|e| e.1.clone().into())
- .collect::<SmallVec<[ash::vk::Rect2D; 4]>>(),
- data.len() as u32,
- ),
- ViewportsState::DynamicViewports { ref scissors } => {
- let num = scissors.len() as u32;
- let scissors = scissors
- .iter()
- .map(|e| e.clone().into())
- .collect::<SmallVec<[ash::vk::Rect2D; 4]>>();
- dynamic_states.push(ash::vk::DynamicState::VIEWPORT);
- (SmallVec::new(), scissors, num)
- }
- ViewportsState::DynamicScissors { ref viewports } => {
- let num = viewports.len() as u32;
- let viewports = viewports
- .iter()
- .map(|e| e.clone().into())
- .collect::<SmallVec<[ash::vk::Viewport; 4]>>();
- dynamic_states.push(ash::vk::DynamicState::SCISSOR);
- (viewports, SmallVec::new(), num)
- }
- ViewportsState::Dynamic { num } => {
- dynamic_states.push(ash::vk::DynamicState::VIEWPORT);
- dynamic_states.push(ash::vk::DynamicState::SCISSOR);
- (SmallVec::new(), SmallVec::new(), num)
- }
- };
-
- if vp_num > 1 && !device.enabled_features().multi_viewport {
- return Err(GraphicsPipelineCreationError::MultiViewportFeatureNotEnabled);
- }
-
- if vp_num > device.physical_device().properties().max_viewports {
- return Err(GraphicsPipelineCreationError::MaxViewportsExceeded {
- obtained: vp_num,
- max: device.physical_device().properties().max_viewports,
- });
- }
-
- for vp in vp_vp.iter() {
- if vp.width
- > device
- .physical_device()
- .properties()
- .max_viewport_dimensions[0] as f32
- || vp.height
- > device
- .physical_device()
- .properties()
- .max_viewport_dimensions[1] as f32
- {
- return Err(GraphicsPipelineCreationError::MaxViewportDimensionsExceeded);
- }
-
- if vp.x
- < device
- .physical_device()
- .properties()
- .viewport_bounds_range[0]
- || vp.x + vp.width
- > device
- .physical_device()
- .properties()
- .viewport_bounds_range[1]
- || vp.y
- < device
- .physical_device()
- .properties()
- .viewport_bounds_range[0]
- || vp.y + vp.height
- > device
- .physical_device()
- .properties()
- .viewport_bounds_range[1]
- {
- return Err(GraphicsPipelineCreationError::ViewportBoundsExceeded);
- }
- }
-
- let viewport_info = ash::vk::PipelineViewportStateCreateInfo {
- flags: ash::vk::PipelineViewportStateCreateFlags::empty(),
- viewport_count: vp_num,
- p_viewports: if vp_vp.is_empty() {
- ptr::null()
- } else {
- vp_vp.as_ptr()
- }, // validation layer crashes if you just pass the pointer
- scissor_count: vp_num,
- p_scissors: if vp_sc.is_empty() {
- ptr::null()
- } else {
- vp_sc.as_ptr()
- }, // validation layer crashes if you just pass the pointer
- ..Default::default()
- };
-
- if let Some(line_width) = self.raster.line_width {
- if line_width != 1.0 && !device.enabled_features().wide_lines {
- return Err(GraphicsPipelineCreationError::WideLinesFeatureNotEnabled);
- }
- } else {
- dynamic_states.push(ash::vk::DynamicState::LINE_WIDTH);
- }
-
- let (db_enable, db_const, db_clamp, db_slope) = match self.raster.depth_bias {
- DepthBiasControl::Dynamic => {
- dynamic_states.push(ash::vk::DynamicState::DEPTH_BIAS);
- (ash::vk::TRUE, 0.0, 0.0, 0.0)
- }
- DepthBiasControl::Disabled => (ash::vk::FALSE, 0.0, 0.0, 0.0),
- DepthBiasControl::Static(bias) => {
- if bias.clamp != 0.0 && !device.enabled_features().depth_bias_clamp {
- return Err(GraphicsPipelineCreationError::DepthBiasClampFeatureNotEnabled);
- }
-
- (
- ash::vk::TRUE,
- bias.constant_factor,
- bias.clamp,
- bias.slope_factor,
- )
- }
- };
-
- if self.raster.depth_clamp && !device.enabled_features().depth_clamp {
- return Err(GraphicsPipelineCreationError::DepthClampFeatureNotEnabled);
- }
-
- if self.raster.polygon_mode != PolygonMode::Fill
- && !device.enabled_features().fill_mode_non_solid
- {
- return Err(GraphicsPipelineCreationError::FillModeNonSolidFeatureNotEnabled);
- }
-
- let rasterization = ash::vk::PipelineRasterizationStateCreateInfo {
- flags: ash::vk::PipelineRasterizationStateCreateFlags::empty(),
- depth_clamp_enable: if self.raster.depth_clamp {
- ash::vk::TRUE
- } else {
- ash::vk::FALSE
- },
- rasterizer_discard_enable: if self.raster.rasterizer_discard {
- ash::vk::TRUE
- } else {
- ash::vk::FALSE
- },
- polygon_mode: self.raster.polygon_mode.into(),
- cull_mode: self.raster.cull_mode.into(),
- front_face: self.raster.front_face.into(),
- depth_bias_enable: db_enable,
- depth_bias_constant_factor: db_const,
- depth_bias_clamp: db_clamp,
- depth_bias_slope_factor: db_slope,
- line_width: self.raster.line_width.unwrap_or(1.0),
- ..Default::default()
- };
-
- self.multisample.rasterization_samples = self
- .subpass
- .as_ref()
- .unwrap()
- .num_samples()
- .unwrap_or(SampleCount::Sample1)
- .into();
- if self.multisample.sample_shading_enable != ash::vk::FALSE {
- debug_assert!(
- self.multisample.min_sample_shading >= 0.0
- && self.multisample.min_sample_shading <= 1.0
- );
- if !device.enabled_features().sample_rate_shading {
- return Err(GraphicsPipelineCreationError::SampleRateShadingFeatureNotEnabled);
- }
- }
- if self.multisample.alpha_to_one_enable != ash::vk::FALSE {
- if !device.enabled_features().alpha_to_one {
- return Err(GraphicsPipelineCreationError::AlphaToOneFeatureNotEnabled);
- }
- }
-
- let depth_stencil = {
- let db = match self.depth_stencil.depth_bounds_test {
- DepthBounds::Disabled => (ash::vk::FALSE, 0.0, 0.0),
- DepthBounds::Fixed(ref range) => {
- if !device.enabled_features().depth_bounds {
- return Err(GraphicsPipelineCreationError::DepthBoundsFeatureNotEnabled);
- }
-
- (ash::vk::TRUE, range.start, range.end)
- }
- DepthBounds::Dynamic => {
- if !device.enabled_features().depth_bounds {
- return Err(GraphicsPipelineCreationError::DepthBoundsFeatureNotEnabled);
- }
-
- dynamic_states.push(ash::vk::DynamicState::DEPTH_BOUNDS);
-
- (ash::vk::TRUE, 0.0, 1.0)
- }
- };
-
- match (
- self.depth_stencil.stencil_front.compare_mask,
- self.depth_stencil.stencil_back.compare_mask,
- ) {
- (Some(_), Some(_)) => (),
- (None, None) => {
- dynamic_states.push(ash::vk::DynamicState::STENCIL_COMPARE_MASK);
- }
- _ => return Err(GraphicsPipelineCreationError::WrongStencilState),
- };
-
- match (
- self.depth_stencil.stencil_front.write_mask,
- self.depth_stencil.stencil_back.write_mask,
- ) {
- (Some(_), Some(_)) => (),
- (None, None) => {
- dynamic_states.push(ash::vk::DynamicState::STENCIL_WRITE_MASK);
- }
- _ => return Err(GraphicsPipelineCreationError::WrongStencilState),
- };
-
- match (
- self.depth_stencil.stencil_front.reference,
- self.depth_stencil.stencil_back.reference,
- ) {
- (Some(_), Some(_)) => (),
- (None, None) => {
- dynamic_states.push(ash::vk::DynamicState::STENCIL_REFERENCE);
- }
- _ => return Err(GraphicsPipelineCreationError::WrongStencilState),
- };
-
- if self.depth_stencil.depth_write
- && !self.subpass.as_ref().unwrap().has_writable_depth()
- {
- return Err(GraphicsPipelineCreationError::NoDepthAttachment);
- }
-
- if self.depth_stencil.depth_compare != Compare::Always
- && !self.subpass.as_ref().unwrap().has_depth()
- {
- return Err(GraphicsPipelineCreationError::NoDepthAttachment);
- }
-
- if (!self.depth_stencil.stencil_front.always_keep()
- || !self.depth_stencil.stencil_back.always_keep())
- && !self.subpass.as_ref().unwrap().has_stencil()
- {
- return Err(GraphicsPipelineCreationError::NoStencilAttachment);
- }
-
- // FIXME: stencil writability
-
- ash::vk::PipelineDepthStencilStateCreateInfo {
- flags: ash::vk::PipelineDepthStencilStateCreateFlags::empty(),
- depth_test_enable: if !self.depth_stencil.depth_write
- && self.depth_stencil.depth_compare == Compare::Always
- {
- ash::vk::FALSE
- } else {
- ash::vk::TRUE
- },
- depth_write_enable: if self.depth_stencil.depth_write {
- ash::vk::TRUE
- } else {
- ash::vk::FALSE
- },
- depth_compare_op: self.depth_stencil.depth_compare.into(),
- depth_bounds_test_enable: db.0,
- stencil_test_enable: if self.depth_stencil.stencil_front.always_keep()
- && self.depth_stencil.stencil_back.always_keep()
- {
- ash::vk::FALSE
- } else {
- ash::vk::TRUE
- },
- front: ash::vk::StencilOpState {
- fail_op: self.depth_stencil.stencil_front.fail_op.into(),
- pass_op: self.depth_stencil.stencil_front.pass_op.into(),
- depth_fail_op: self.depth_stencil.stencil_front.depth_fail_op.into(),
- compare_op: self.depth_stencil.stencil_front.compare.into(),
- compare_mask: self
- .depth_stencil
- .stencil_front
- .compare_mask
- .unwrap_or(u32::MAX),
- write_mask: self
- .depth_stencil
- .stencil_front
- .write_mask
- .unwrap_or(u32::MAX),
- reference: self.depth_stencil.stencil_front.reference.unwrap_or(0),
- },
- back: ash::vk::StencilOpState {
- fail_op: self.depth_stencil.stencil_back.fail_op.into(),
- pass_op: self.depth_stencil.stencil_back.pass_op.into(),
- depth_fail_op: self.depth_stencil.stencil_back.depth_fail_op.into(),
- compare_op: self.depth_stencil.stencil_back.compare.into(),
- compare_mask: self
- .depth_stencil
- .stencil_back
- .compare_mask
- .unwrap_or(u32::MAX),
- write_mask: self
- .depth_stencil
- .stencil_back
- .write_mask
- .unwrap_or(u32::MAX),
- reference: self.depth_stencil.stencil_back.reference.unwrap_or(0),
- },
- min_depth_bounds: db.1,
- max_depth_bounds: db.2,
- ..Default::default()
- }
- };
-
- let blend_atch: SmallVec<[ash::vk::PipelineColorBlendAttachmentState; 8]> = {
- let num_atch = self.subpass.as_ref().unwrap().num_color_attachments();
-
- match self.blend.attachments {
- AttachmentsBlend::Collective(blend) => {
- (0..num_atch).map(|_| blend.clone().into()).collect()
- }
- AttachmentsBlend::Individual(blend) => {
- if blend.len() != num_atch as usize {
- return Err(
- GraphicsPipelineCreationError::MismatchBlendingAttachmentsCount,
- );
- }
-
- if !device.enabled_features().independent_blend {
- return Err(
- GraphicsPipelineCreationError::IndependentBlendFeatureNotEnabled,
- );
- }
-
- blend.iter().map(|b| b.clone().into()).collect()
- }
- }
- };
-
- let blend = ash::vk::PipelineColorBlendStateCreateInfo {
- flags: ash::vk::PipelineColorBlendStateCreateFlags::empty(),
- logic_op_enable: if self.blend.logic_op.is_some() {
- if !device.enabled_features().logic_op {
- return Err(GraphicsPipelineCreationError::LogicOpFeatureNotEnabled);
- }
- ash::vk::TRUE
- } else {
- ash::vk::FALSE
- },
- logic_op: self.blend.logic_op.unwrap_or(Default::default()).into(),
- attachment_count: blend_atch.len() as u32,
- p_attachments: blend_atch.as_ptr(),
- blend_constants: if let Some(c) = self.blend.blend_constants {
- c
- } else {
- dynamic_states.push(ash::vk::DynamicState::BLEND_CONSTANTS);
- [0.0, 0.0, 0.0, 0.0]
- },
- ..Default::default()
- };
-
- let dynamic_states = if !dynamic_states.is_empty() {
- Some(ash::vk::PipelineDynamicStateCreateInfo {
- flags: ash::vk::PipelineDynamicStateCreateFlags::empty(),
- dynamic_state_count: dynamic_states.len() as u32,
- p_dynamic_states: dynamic_states.as_ptr(),
- ..Default::default()
- })
- } else {
- None
- };
-
- if let Some(multiview) = self
- .subpass
- .as_ref()
- .unwrap()
- .render_pass()
- .desc()
- .multiview()
- .as_ref()
- {
- if multiview.used_layer_count() > 0 {
- if self.geometry_shader.is_some()
- && !device
- .physical_device()
- .supported_features()
- .multiview_geometry_shader
- {
- return Err(GraphicsPipelineCreationError::MultiviewGeometryShaderNotSupported);
- }
-
- if self.tessellation.is_some()
- && !device
- .physical_device()
- .supported_features()
- .multiview_tessellation_shader
- {
- return Err(
- GraphicsPipelineCreationError::MultiviewTessellationShaderNotSupported,
- );
- }
- }
- }
-
- let pipeline = unsafe {
- let infos = ash::vk::GraphicsPipelineCreateInfo {
- flags: ash::vk::PipelineCreateFlags::empty(), // TODO: some flags are available but none are critical
- stage_count: stages.len() as u32,
- p_stages: stages.as_ptr(),
- p_vertex_input_state: &vertex_input_state,
- p_input_assembly_state: &self.input_assembly,
- p_tessellation_state: tessellation
- .as_ref()
- .map(|t| t as *const _)
- .unwrap_or(ptr::null()),
- p_viewport_state: &viewport_info,
- p_rasterization_state: &rasterization,
- p_multisample_state: &self.multisample,
- p_depth_stencil_state: &depth_stencil,
- p_color_blend_state: &blend,
- p_dynamic_state: dynamic_states
- .as_ref()
- .map(|s| s as *const _)
- .unwrap_or(ptr::null()),
- layout: pipeline_layout.internal_object(),
- render_pass: self
- .subpass
- .as_ref()
- .unwrap()
- .render_pass()
- .inner()
- .internal_object(),
- subpass: self.subpass.as_ref().unwrap().index(),
- base_pipeline_handle: ash::vk::Pipeline::null(), // TODO:
- base_pipeline_index: -1, // TODO:
- ..Default::default()
- };
-
- let cache_handle = match self.cache {
- Some(cache) => cache.internal_object(),
- None => ash::vk::PipelineCache::null(),
- };
-
- let mut output = MaybeUninit::uninit();
- check_errors(fns.v1_0.create_graphics_pipelines(
- device.internal_object(),
- cache_handle,
- 1,
- &infos,
- ptr::null(),
- output.as_mut_ptr(),
- ))?;
- output.assume_init()
- };
-
- // Some drivers return `VK_SUCCESS` but provide a null handle if they
- // fail to create the pipeline (due to invalid shaders, etc)
- // This check ensures that we don't create an invalid `GraphicsPipeline` instance
- if pipeline == ash::vk::Pipeline::null() {
- panic!("vkCreateGraphicsPipelines provided a NULL handle");
- }
-
- Ok(GraphicsPipeline {
- inner: GraphicsPipelineInner {
- device: device.clone(),
- pipeline,
- },
- layout: pipeline_layout,
- subpass: self.subpass.take().unwrap(),
- vertex_definition: self.vertex_definition,
- vertex_input,
-
- dynamic_line_width: self.raster.line_width.is_none(),
- dynamic_viewport: self.viewport.as_ref().unwrap().dynamic_viewports(),
- dynamic_scissor: self.viewport.as_ref().unwrap().dynamic_scissors(),
- dynamic_depth_bias: self.raster.depth_bias.is_dynamic(),
- dynamic_depth_bounds: self.depth_stencil.depth_bounds_test.is_dynamic(),
- dynamic_stencil_compare_mask: self.depth_stencil.stencil_back.compare_mask.is_none(),
- dynamic_stencil_write_mask: self.depth_stencil.stencil_back.write_mask.is_none(),
- dynamic_stencil_reference: self.depth_stencil.stencil_back.reference.is_none(),
- dynamic_blend_constants: self.blend.blend_constants.is_none(),
-
- num_viewports: self.viewport.as_ref().unwrap().num_viewports(),
- })
- }
-
- // TODO: add build_with_cache method
-}
-
-impl<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss>
- GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss>
-{
- // TODO: add pipeline derivate system
-
- /// Sets the vertex input.
- #[inline]
- pub fn vertex_input<T>(
- self,
- vertex_definition: T,
- ) -> GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs, T, Vss, Tcss, Tess, Gss, Fss> {
- GraphicsPipelineBuilder {
- vertex_definition,
- vertex_shader: self.vertex_shader,
- input_assembly: self.input_assembly,
- input_assembly_topology: self.input_assembly_topology,
- tessellation: self.tessellation,
- geometry_shader: self.geometry_shader,
- viewport: self.viewport,
- raster: self.raster,
- multisample: self.multisample,
- fragment_shader: self.fragment_shader,
- depth_stencil: self.depth_stencil,
- blend: self.blend,
- subpass: self.subpass,
- cache: self.cache,
- }
- }
-
- /// Sets the vertex input to a single vertex buffer.
- ///
- /// You will most likely need to explicitly specify the template parameter to the type of a
- /// vertex.
- #[inline]
- pub fn vertex_input_single_buffer<V: Vertex>(
- self,
- ) -> GraphicsPipelineBuilder<
- 'vs,
- 'tcs,
- 'tes,
- 'gs,
- 'fs,
- BuffersDefinition,
- Vss,
- Tcss,
- Tess,
- Gss,
- Fss,
- > {
- self.vertex_input(BuffersDefinition::new().vertex::<V>())
- }
-
- /// Sets the vertex shader to use.
- // TODO: correct specialization constants
- #[inline]
- pub fn vertex_shader<'vs2, Vss2>(
- self,
- shader: GraphicsEntryPoint<'vs2>,
- specialization_constants: Vss2,
- ) -> GraphicsPipelineBuilder<'vs2, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss2, Tcss, Tess, Gss, Fss>
- where
- Vss2: SpecializationConstants,
- {
- GraphicsPipelineBuilder {
- vertex_definition: self.vertex_definition,
- vertex_shader: Some((shader, specialization_constants)),
- input_assembly: self.input_assembly,
- input_assembly_topology: self.input_assembly_topology,
- tessellation: self.tessellation,
- geometry_shader: self.geometry_shader,
- viewport: self.viewport,
- raster: self.raster,
- multisample: self.multisample,
- fragment_shader: self.fragment_shader,
- depth_stencil: self.depth_stencil,
- blend: self.blend,
- subpass: self.subpass,
- cache: self.cache,
- }
- }
-
- /// Sets whether primitive restart if enabled.
- #[inline]
- pub fn primitive_restart(mut self, enabled: bool) -> Self {
- self.input_assembly.primitive_restart_enable = if enabled {
- ash::vk::TRUE
- } else {
- ash::vk::FALSE
- };
-
- self
- }
-
- /// Sets the topology of the primitives that are expected by the pipeline.
- #[inline]
- pub fn primitive_topology(mut self, topology: PrimitiveTopology) -> Self {
- self.input_assembly_topology = topology;
- self.input_assembly.topology = topology.into();
- self
- }
-
- /// Sets the topology of the primitives to a list of points.
- ///
- /// > **Note**: This is equivalent to
- /// > `self.primitive_topology(PrimitiveTopology::PointList)`.
- #[inline]
- pub fn point_list(self) -> Self {
- self.primitive_topology(PrimitiveTopology::PointList)
- }
-
- /// Sets the topology of the primitives to a list of lines.
- ///
- /// > **Note**: This is equivalent to
- /// > `self.primitive_topology(PrimitiveTopology::LineList)`.
- #[inline]
- pub fn line_list(self) -> Self {
- self.primitive_topology(PrimitiveTopology::LineList)
- }
-
- /// Sets the topology of the primitives to a line strip.
- ///
- /// > **Note**: This is equivalent to
- /// > `self.primitive_topology(PrimitiveTopology::LineStrip)`.
- #[inline]
- pub fn line_strip(self) -> Self {
- self.primitive_topology(PrimitiveTopology::LineStrip)
- }
-
- /// Sets the topology of the primitives to a list of triangles. Note that this is the default.
- ///
- /// > **Note**: This is equivalent to
- /// > `self.primitive_topology(PrimitiveTopology::TriangleList)`.
- #[inline]
- pub fn triangle_list(self) -> Self {
- self.primitive_topology(PrimitiveTopology::TriangleList)
- }
-
- /// Sets the topology of the primitives to a triangle strip.
- ///
- /// > **Note**: This is equivalent to
- /// > `self.primitive_topology(PrimitiveTopology::TriangleStrip)`.
- #[inline]
- pub fn triangle_strip(self) -> Self {
- self.primitive_topology(PrimitiveTopology::TriangleStrip)
- }
-
- /// Sets the topology of the primitives to a fan of triangles.
- ///
- /// > **Note**: This is equivalent to
- /// > `self.primitive_topology(PrimitiveTopology::TriangleFan)`.
- #[inline]
- pub fn triangle_fan(self) -> Self {
- self.primitive_topology(PrimitiveTopology::TriangleFan)
- }
-
- /// Sets the topology of the primitives to a list of lines with adjacency information.
- ///
- /// > **Note**: This is equivalent to
- /// > `self.primitive_topology(PrimitiveTopology::LineListWithAdjacency)`.
- #[inline]
- pub fn line_list_with_adjacency(self) -> Self {
- self.primitive_topology(PrimitiveTopology::LineListWithAdjacency)
- }
-
- /// Sets the topology of the primitives to a line strip with adjacency information.
- ///
- /// > **Note**: This is equivalent to
- /// > `self.primitive_topology(PrimitiveTopology::LineStripWithAdjacency)`.
- #[inline]
- pub fn line_strip_with_adjacency(self) -> Self {
- self.primitive_topology(PrimitiveTopology::LineStripWithAdjacency)
- }
-
- /// Sets the topology of the primitives to a list of triangles with adjacency information.
- ///
- /// > **Note**: This is equivalent to
- /// > `self.primitive_topology(PrimitiveTopology::TriangleListWithAdjacency)`.
- #[inline]
- pub fn triangle_list_with_adjacency(self) -> Self {
- self.primitive_topology(PrimitiveTopology::TriangleListWithAdjacency)
- }
-
- /// Sets the topology of the primitives to a triangle strip with adjacency information`
- ///
- /// > **Note**: This is equivalent to
- /// > `self.primitive_topology(PrimitiveTopology::TriangleStripWithAdjacency)`.
- #[inline]
- pub fn triangle_strip_with_adjacency(self) -> Self {
- self.primitive_topology(PrimitiveTopology::TriangleStripWithAdjacency)
- }
-
- /// Sets the topology of the primitives to a list of patches. Can only be used and must be used
- /// with a tessellation shader.
- ///
- /// > **Note**: This is equivalent to
- /// > `self.primitive_topology(PrimitiveTopology::PatchList { vertices_per_patch })`.
- #[inline]
- pub fn patch_list(self, vertices_per_patch: u32) -> Self {
- self.primitive_topology(PrimitiveTopology::PatchList { vertices_per_patch })
- }
-
- /// Sets the tessellation shaders to use.
- // TODO: correct specialization constants
- #[inline]
- pub fn tessellation_shaders<'tcs2, 'tes2, Tcss2, Tess2>(
- self,
- tessellation_control_shader: GraphicsEntryPoint<'tcs2>,
- tessellation_control_shader_spec_constants: Tcss2,
- tessellation_evaluation_shader: GraphicsEntryPoint<'tes2>,
- tessellation_evaluation_shader_spec_constants: Tess2,
- ) -> GraphicsPipelineBuilder<'vs, 'tcs2, 'tes2, 'gs, 'fs, Vdef, Vss, Tcss2, Tess2, Gss, Fss>
- where
- Tcss2: SpecializationConstants,
- Tess2: SpecializationConstants,
- {
- GraphicsPipelineBuilder {
- vertex_definition: self.vertex_definition,
- vertex_shader: self.vertex_shader,
- input_assembly: self.input_assembly,
- input_assembly_topology: self.input_assembly_topology,
- tessellation: Some(TessInfo {
- tessellation_control_shader: (
- tessellation_control_shader,
- tessellation_control_shader_spec_constants,
- ),
- tessellation_evaluation_shader: (
- tessellation_evaluation_shader,
- tessellation_evaluation_shader_spec_constants,
- ),
- }),
- geometry_shader: self.geometry_shader,
- viewport: self.viewport,
- raster: self.raster,
- multisample: self.multisample,
- fragment_shader: self.fragment_shader,
- depth_stencil: self.depth_stencil,
- blend: self.blend,
- subpass: self.subpass,
- cache: self.cache,
- }
- }
-
- /// Sets the tessellation shaders stage as disabled. This is the default.
- #[inline]
- pub fn tessellation_shaders_disabled(mut self) -> Self {
- self.tessellation = None;
- self
- }
-
- /// Sets the geometry shader to use.
- // TODO: correct specialization constants
- #[inline]
- pub fn geometry_shader<'gs2, Gss2>(
- self,
- shader: GraphicsEntryPoint<'gs2>,
- specialization_constants: Gss2,
- ) -> GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs2, 'fs, Vdef, Vss, Tcss, Tess, Gss2, Fss>
- where
- Gss2: SpecializationConstants,
- {
- GraphicsPipelineBuilder {
- vertex_definition: self.vertex_definition,
- vertex_shader: self.vertex_shader,
- input_assembly: self.input_assembly,
- input_assembly_topology: self.input_assembly_topology,
- tessellation: self.tessellation,
- geometry_shader: Some((shader, specialization_constants)),
- viewport: self.viewport,
- raster: self.raster,
- multisample: self.multisample,
- fragment_shader: self.fragment_shader,
- depth_stencil: self.depth_stencil,
- blend: self.blend,
- subpass: self.subpass,
- cache: self.cache,
- }
- }
-
- /// Sets the geometry shader stage as disabled. This is the default.
- #[inline]
- pub fn geometry_shader_disabled(mut self) -> Self {
- self.geometry_shader = None;
- self
- }
-
- /// Sets the viewports to some value, and the scissor boxes to boxes that always cover the
- /// whole viewport.
- #[inline]
- pub fn viewports<I>(self, viewports: I) -> Self
- where
- I: IntoIterator<Item = Viewport>,
- {
- self.viewports_scissors(viewports.into_iter().map(|v| (v, Scissor::irrelevant())))
- }
-
- /// Sets the characteristics of viewports and scissor boxes in advance.
- #[inline]
- pub fn viewports_scissors<I>(mut self, viewports: I) -> Self
- where
- I: IntoIterator<Item = (Viewport, Scissor)>,
- {
- self.viewport = Some(ViewportsState::Fixed {
- data: viewports.into_iter().collect(),
- });
- self
- }
-
- /// Sets the scissor boxes to some values, and viewports to dynamic. The viewports will
- /// need to be set before drawing.
- #[inline]
- pub fn viewports_dynamic_scissors_fixed<I>(mut self, scissors: I) -> Self
- where
- I: IntoIterator<Item = Scissor>,
- {
- self.viewport = Some(ViewportsState::DynamicViewports {
- scissors: scissors.into_iter().collect(),
- });
- self
- }
-
- /// Sets the viewports to dynamic, and the scissor boxes to boxes that always cover the whole
- /// viewport. The viewports will need to be set before drawing.
- #[inline]
- pub fn viewports_dynamic_scissors_irrelevant(mut self, num: u32) -> Self {
- self.viewport = Some(ViewportsState::DynamicViewports {
- scissors: (0..num).map(|_| Scissor::irrelevant()).collect(),
- });
- self
- }
-
- /// Sets the viewports to some values, and scissor boxes to dynamic. The scissor boxes will
- /// need to be set before drawing.
- #[inline]
- pub fn viewports_fixed_scissors_dynamic<I>(mut self, viewports: I) -> Self
- where
- I: IntoIterator<Item = Viewport>,
- {
- self.viewport = Some(ViewportsState::DynamicScissors {
- viewports: viewports.into_iter().collect(),
- });
- self
- }
-
- /// Sets the viewports and scissor boxes to dynamic. They will both need to be set before
- /// drawing.
- #[inline]
- pub fn viewports_scissors_dynamic(mut self, num: u32) -> Self {
- self.viewport = Some(ViewportsState::Dynamic { num });
- self
- }
-
- /// If true, then the depth value of the vertices will be clamped to the range `[0.0 ; 1.0]`.
- /// If false, fragments whose depth is outside of this range will be discarded before the
- /// fragment shader even runs.
- #[inline]
- pub fn depth_clamp(mut self, clamp: bool) -> Self {
- self.raster.depth_clamp = clamp;
- self
- }
-
- // TODO: this won't work correctly
- /*/// Disables the fragment shader stage.
- #[inline]
- pub fn rasterizer_discard(mut self) -> Self {
- self.rasterization.rasterizer_discard. = true;
- self
- }*/
-
- /// Sets the front-facing faces to counter-clockwise faces. This is the default.
- ///
- /// Triangles whose vertices are oriented counter-clockwise on the screen will be considered
- /// as facing their front. Otherwise they will be considered as facing their back.
- #[inline]
- pub fn front_face_counter_clockwise(mut self) -> Self {
- self.raster.front_face = FrontFace::CounterClockwise;
- self
- }
-
- /// Sets the front-facing faces to clockwise faces.
- ///
- /// Triangles whose vertices are oriented clockwise on the screen will be considered
- /// as facing their front. Otherwise they will be considered as facing their back.
- #[inline]
- pub fn front_face_clockwise(mut self) -> Self {
- self.raster.front_face = FrontFace::Clockwise;
- self
- }
-
- /// Sets backface culling as disabled. This is the default.
- #[inline]
- pub fn cull_mode_disabled(mut self) -> Self {
- self.raster.cull_mode = CullMode::None;
- self
- }
-
- /// Sets backface culling to front faces. The front faces (as chosen with the `front_face_*`
- /// methods) will be discarded by the GPU when drawing.
- #[inline]
- pub fn cull_mode_front(mut self) -> Self {
- self.raster.cull_mode = CullMode::Front;
- self
- }
-
- /// Sets backface culling to back faces. Faces that are not facing the front (as chosen with
- /// the `front_face_*` methods) will be discarded by the GPU when drawing.
- #[inline]
- pub fn cull_mode_back(mut self) -> Self {
- self.raster.cull_mode = CullMode::Back;
- self
- }
-
- /// Sets backface culling to both front and back faces. All the faces will be discarded.
- ///
- /// > **Note**: This option exists for the sake of completeness. It has no known practical
- /// > usage.
- #[inline]
- pub fn cull_mode_front_and_back(mut self) -> Self {
- self.raster.cull_mode = CullMode::FrontAndBack;
- self
- }
-
- /// Sets the polygon mode to "fill". This is the default.
- #[inline]
- pub fn polygon_mode_fill(mut self) -> Self {
- self.raster.polygon_mode = PolygonMode::Fill;
- self
- }
-
- /// Sets the polygon mode to "line". Triangles will each be turned into three lines.
- #[inline]
- pub fn polygon_mode_line(mut self) -> Self {
- self.raster.polygon_mode = PolygonMode::Line;
- self
- }
-
- /// Sets the polygon mode to "point". Triangles and lines will each be turned into three points.
- #[inline]
- pub fn polygon_mode_point(mut self) -> Self {
- self.raster.polygon_mode = PolygonMode::Point;
- self
- }
-
- /// Sets the width of the lines, if the GPU needs to draw lines. The default is `1.0`.
- #[inline]
- pub fn line_width(mut self, value: f32) -> Self {
- self.raster.line_width = Some(value);
- self
- }
-
- /// Sets the width of the lines as dynamic, which means that you will need to set this value
- /// when drawing.
- #[inline]
- pub fn line_width_dynamic(mut self) -> Self {
- self.raster.line_width = None;
- self
- }
-
- // TODO: missing DepthBiasControl
-
- /// Disables sample shading. The fragment shader will only be run once per fragment (ie. per
- /// pixel) and not once by sample. The output will then be copied in all of the covered
- /// samples.
- ///
- /// Sample shading is disabled by default.
- #[inline]
- pub fn sample_shading_disabled(mut self) -> Self {
- self.multisample.sample_shading_enable = ash::vk::FALSE;
- self
- }
-
- /// Enables sample shading. The fragment shader will be run once per sample at the borders of
- /// the object you're drawing.
- ///
- /// Enabling sampling shading requires the `sample_rate_shading` feature to be enabled on the
- /// device.
- ///
- /// The `min_fract` parameter is the minimum fraction of samples shading. For example if its
- /// value is 0.5, then the fragment shader will run for at least half of the samples. The other
- /// half of the samples will get their values determined automatically.
- ///
- /// Sample shading is disabled by default.
- ///
- /// # Panic
- ///
- /// - Panics if `min_fract` is not between 0.0 and 1.0.
- ///
- #[inline]
- pub fn sample_shading_enabled(mut self, min_fract: f32) -> Self {
- assert!(min_fract >= 0.0 && min_fract <= 1.0);
- self.multisample.sample_shading_enable = ash::vk::TRUE;
- self.multisample.min_sample_shading = min_fract;
- self
- }
-
- // TODO: doc
- pub fn alpha_to_coverage_disabled(mut self) -> Self {
- self.multisample.alpha_to_coverage_enable = ash::vk::FALSE;
- self
- }
-
- // TODO: doc
- pub fn alpha_to_coverage_enabled(mut self) -> Self {
- self.multisample.alpha_to_coverage_enable = ash::vk::TRUE;
- self
- }
-
- /// Disables alpha-to-one.
- ///
- /// Alpha-to-one is disabled by default.
- #[inline]
- pub fn alpha_to_one_disabled(mut self) -> Self {
- self.multisample.alpha_to_one_enable = ash::vk::FALSE;
- self
- }
-
- /// Enables alpha-to-one. The alpha component of the first color output of the fragment shader
- /// will be replaced by the value `1.0`.
- ///
- /// Enabling alpha-to-one requires the `alpha_to_one` feature to be enabled on the device.
- ///
- /// Alpha-to-one is disabled by default.
- #[inline]
- pub fn alpha_to_one_enabled(mut self) -> Self {
- self.multisample.alpha_to_one_enable = ash::vk::TRUE;
- self
- }
-
- // TODO: rasterizationSamples and pSampleMask
-
- /// Sets the fragment shader to use.
- ///
- /// The fragment shader is run once for each pixel that is covered by each primitive.
- // TODO: correct specialization constants
- #[inline]
- pub fn fragment_shader<'fs2, Fss2>(
- self,
- shader: GraphicsEntryPoint<'fs2>,
- specialization_constants: Fss2,
- ) -> GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs2, Vdef, Vss, Tcss, Tess, Gss, Fss2>
- where
- Fss2: SpecializationConstants,
- {
- GraphicsPipelineBuilder {
- vertex_definition: self.vertex_definition,
- vertex_shader: self.vertex_shader,
- input_assembly: self.input_assembly,
- input_assembly_topology: self.input_assembly_topology,
- tessellation: self.tessellation,
- geometry_shader: self.geometry_shader,
- viewport: self.viewport,
- raster: self.raster,
- multisample: self.multisample,
- fragment_shader: Some((shader, specialization_constants)),
- depth_stencil: self.depth_stencil,
- blend: self.blend,
- subpass: self.subpass,
- cache: self.cache,
- }
- }
-
- /// Sets the depth/stencil configuration. This function may be removed in the future.
- #[inline]
- pub fn depth_stencil(mut self, depth_stencil: DepthStencil) -> Self {
- self.depth_stencil = depth_stencil;
- self
- }
-
- /// Sets the depth/stencil tests as disabled.
- ///
- /// > **Note**: This is a shortcut for all the other `depth_*` and `depth_stencil_*` methods
- /// > of the builder.
- #[inline]
- pub fn depth_stencil_disabled(mut self) -> Self {
- self.depth_stencil = DepthStencil::disabled();
- self
- }
-
- /// Sets the depth/stencil tests as a simple depth test and no stencil test.
- ///
- /// > **Note**: This is a shortcut for setting the depth test to `Less`, the depth write Into
- /// > ` true` and disable the stencil test.
- #[inline]
- pub fn depth_stencil_simple_depth(mut self) -> Self {
- self.depth_stencil = DepthStencil::simple_depth_test();
- self
- }
-
- /// Sets whether the depth buffer will be written.
- #[inline]
- pub fn depth_write(mut self, write: bool) -> Self {
- self.depth_stencil.depth_write = write;
- self
- }
-
- // TODO: missing tons of depth-stencil stuff
-
- #[inline]
- pub fn blend_collective(mut self, blend: AttachmentBlend) -> Self {
- self.blend.attachments = AttachmentsBlend::Collective(blend);
- self
- }
-
- #[inline]
- pub fn blend_individual<I>(mut self, blend: I) -> Self
- where
- I: IntoIterator<Item = AttachmentBlend>,
- {
- self.blend.attachments = AttachmentsBlend::Individual(blend.into_iter().collect());
- self
- }
-
- /// Each fragment shader output will have its value directly written to the framebuffer
- /// attachment. This is the default.
- #[inline]
- pub fn blend_pass_through(self) -> Self {
- self.blend_collective(AttachmentBlend::pass_through())
- }
-
- #[inline]
- pub fn blend_alpha_blending(self) -> Self {
- self.blend_collective(AttachmentBlend::alpha_blending())
- }
-
- #[inline]
- pub fn blend_logic_op(mut self, logic_op: LogicOp) -> Self {
- self.blend.logic_op = Some(logic_op);
- self
- }
-
- /// Sets the logic operation as disabled. This is the default.
- #[inline]
- pub fn blend_logic_op_disabled(mut self) -> Self {
- self.blend.logic_op = None;
- self
- }
-
- /// Sets the blend constant. The default is `[0.0, 0.0, 0.0, 0.0]`.
- ///
- /// The blend constant is used for some blending calculations. It is irrelevant otherwise.
- #[inline]
- pub fn blend_constants(mut self, constants: [f32; 4]) -> Self {
- self.blend.blend_constants = Some(constants);
- self
- }
-
- /// Sets the blend constant value as dynamic. Its value will need to be set before drawing.
- ///
- /// The blend constant is used for some blending calculations. It is irrelevant otherwise.
- #[inline]
- pub fn blend_constants_dynamic(mut self) -> Self {
- self.blend.blend_constants = None;
- self
- }
-
- /// Sets the render pass subpass to use.
- #[inline]
- pub fn render_pass(self, subpass: Subpass) -> Self {
- GraphicsPipelineBuilder {
- vertex_definition: self.vertex_definition,
- vertex_shader: self.vertex_shader,
- input_assembly: self.input_assembly,
- input_assembly_topology: self.input_assembly_topology,
- tessellation: self.tessellation,
- geometry_shader: self.geometry_shader,
- viewport: self.viewport,
- raster: self.raster,
- multisample: self.multisample,
- fragment_shader: self.fragment_shader,
- depth_stencil: self.depth_stencil,
- blend: self.blend,
- subpass: Some(subpass),
- cache: self.cache,
- }
- }
-
- /// Enable caching of this pipeline via a PipelineCache object.
- ///
- /// If this pipeline already exists in the cache it will be used, if this is a new
- /// pipeline it will be inserted into the cache. The implementation handles the
- /// PipelineCache.
- #[inline]
- pub fn build_with_cache(mut self, pipeline_cache: Arc<PipelineCache>) -> Self {
- self.cache = Some(pipeline_cache);
- self
- }
-}
-
-impl<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss> Clone
- for GraphicsPipelineBuilder<'vs, 'tcs, 'tes, 'gs, 'fs, Vdef, Vss, Tcss, Tess, Gss, Fss>
-where
- Vdef: Clone,
- Vss: Clone,
- Tcss: Clone,
- Tess: Clone,
- Gss: Clone,
- Fss: Clone,
-{
- fn clone(&self) -> Self {
- GraphicsPipelineBuilder {
- vertex_definition: self.vertex_definition.clone(),
- vertex_shader: self.vertex_shader.clone(),
- input_assembly: unsafe { ptr::read(&self.input_assembly) },
- input_assembly_topology: self.input_assembly_topology,
- tessellation: self.tessellation.clone(),
- geometry_shader: self.geometry_shader.clone(),
- viewport: self.viewport.clone(),
- raster: self.raster.clone(),
- multisample: self.multisample,
- fragment_shader: self.fragment_shader.clone(),
- depth_stencil: self.depth_stencil.clone(),
- blend: self.blend.clone(),
- subpass: self.subpass.clone(),
- cache: self.cache.clone(),
- }
- }
-}
diff --git a/src/pipeline/graphics_pipeline/creation_error.rs b/src/pipeline/graphics_pipeline/creation_error.rs
deleted file mode 100644
index 434426e..0000000
--- a/src/pipeline/graphics_pipeline/creation_error.rs
+++ /dev/null
@@ -1,380 +0,0 @@
-// Copyright (c) 2017 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::pipeline::input_assembly::PrimitiveTopology;
-use crate::pipeline::layout::PipelineLayoutSupersetError;
-use crate::pipeline::shader::ShaderInterfaceMismatchError;
-use crate::pipeline::vertex::IncompatibleVertexDefinitionError;
-use crate::Error;
-use crate::OomError;
-use std::error;
-use std::fmt;
-use std::u32;
-
-/// Error that can happen when creating a graphics pipeline.
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum GraphicsPipelineCreationError {
- /// Not enough memory.
- OomError(OomError),
-
- /// The pipeline layout is not compatible with what the shaders expect.
- IncompatiblePipelineLayout(PipelineLayoutSupersetError),
-
- /// The provided specialization constants are not compatible with what the shader expects.
- IncompatibleSpecializationConstants,
-
- /// The output interface of one shader and the input interface of the next shader does not match.
- ShaderStagesMismatch(ShaderInterfaceMismatchError),
-
- /// The output of the fragment shader is not compatible with what the render pass subpass
- /// expects.
- FragmentShaderRenderPassIncompatible,
-
- /// The vertex definition is not compatible with the input of the vertex shader.
- IncompatibleVertexDefinition(IncompatibleVertexDefinitionError),
-
- /// The maximum stride value for vertex input (ie. the distance between two vertex elements)
- /// has been exceeded.
- MaxVertexInputBindingStrideExceeded {
- /// Index of the faulty binding.
- binding: u32,
- /// Maximum allowed value.
- max: u32,
- /// Value that was passed.
- obtained: u32,
- },
-
- /// The maximum number of vertex sources has been exceeded.
- MaxVertexInputBindingsExceeded {
- /// Maximum allowed value.
- max: u32,
- /// Value that was passed.
- obtained: u32,
- },
-
- /// The maximum offset for a vertex attribute has been exceeded. This means that your vertex
- /// struct is too large.
- MaxVertexInputAttributeOffsetExceeded {
- /// Maximum allowed value.
- max: u32,
- /// Value that was passed.
- obtained: u32,
- },
-
- /// The maximum number of vertex attributes has been exceeded.
- MaxVertexInputAttributesExceeded {
- /// Maximum allowed value.
- max: u32,
- /// Value that was passed.
- obtained: usize,
- },
-
- /// The `vertex_attribute_instance_rate_divisor` feature must be enabled in order to use
- /// instance rate divisors.
- VertexAttributeInstanceRateDivisorFeatureNotEnabled,
-
- /// The `vertex_attribute_instance_rate_zero_divisor` feature must be enabled in order to use
- /// an instance rate divisor of zero.
- VertexAttributeInstanceRateZeroDivisorFeatureNotEnabled,
-
- /// The maximum value for the instance rate divisor has been exceeded.
- MaxVertexAttribDivisorExceeded {
- /// Index of the faulty binding.
- binding: u32,
- /// Maximum allowed value.
- max: u32,
- /// Value that was passed.
- obtained: u32,
- },
-
- /// The user requested to use primitive restart, but the primitive topology doesn't support it.
- PrimitiveDoesntSupportPrimitiveRestart {
- /// The topology that doesn't support primitive restart.
- primitive: PrimitiveTopology,
- },
-
- /// The `multi_viewport` feature must be enabled in order to use multiple viewports at once.
- MultiViewportFeatureNotEnabled,
-
- /// The maximum number of viewports has been exceeded.
- MaxViewportsExceeded {
- /// Maximum allowed value.
- max: u32,
- /// Value that was passed.
- obtained: u32,
- },
-
- /// The maximum dimensions of viewports has been exceeded.
- MaxViewportDimensionsExceeded,
-
- /// The minimum or maximum bounds of viewports have been exceeded.
- ViewportBoundsExceeded,
-
- /// The `wide_lines` feature must be enabled in order to use a line width greater than 1.0.
- WideLinesFeatureNotEnabled,
-
- /// The `depth_clamp` feature must be enabled in order to use depth clamping.
- DepthClampFeatureNotEnabled,
-
- /// The `depth_bias_clamp` feature must be enabled in order to use a depth bias clamp different
- /// from 0.0.
- DepthBiasClampFeatureNotEnabled,
-
- /// The `fill_mode_non_solid` feature must be enabled in order to use a polygon mode different
- /// from `Fill`.
- FillModeNonSolidFeatureNotEnabled,
-
- /// The `depth_bounds` feature must be enabled in order to use depth bounds testing.
- DepthBoundsFeatureNotEnabled,
-
- /// The requested stencil test is invalid.
- WrongStencilState,
-
- /// The primitives topology does not match what the geometry shader expects.
- TopologyNotMatchingGeometryShader,
-
- /// The `geometry_shader` feature must be enabled in order to use geometry shaders.
- GeometryShaderFeatureNotEnabled,
-
- /// The `tessellation_shader` feature must be enabled in order to use tessellation shaders.
- TessellationShaderFeatureNotEnabled,
-
- /// The number of attachments specified in the blending does not match the number of
- /// attachments in the subpass.
- MismatchBlendingAttachmentsCount,
-
- /// The `independent_blend` feature must be enabled in order to use different blending
- /// operations per attachment.
- IndependentBlendFeatureNotEnabled,
-
- /// The `logic_op` feature must be enabled in order to use logic operations.
- LogicOpFeatureNotEnabled,
-
- /// The depth test requires a depth attachment but render pass has no depth attachment, or
- /// depth writing is enabled and the depth attachment is read-only.
- NoDepthAttachment,
-
- /// The stencil test requires a stencil attachment but render pass has no stencil attachment, or
- /// stencil writing is enabled and the stencil attachment is read-only.
- NoStencilAttachment,
-
- /// Tried to use a patch list without a tessellation shader, or a non-patch-list with a
- /// tessellation shader.
- InvalidPrimitiveTopology,
-
- /// The `maxTessellationPatchSize` limit was exceeded.
- MaxTessellationPatchSizeExceeded,
-
- /// The wrong type of shader has been passed.
- ///
- /// For example you passed a vertex shader as the fragment shader.
- WrongShaderType,
-
- /// The `sample_rate_shading` feature must be enabled in order to use sample shading.
- SampleRateShadingFeatureNotEnabled,
-
- /// The `alpha_to_one` feature must be enabled in order to use alpha-to-one.
- AlphaToOneFeatureNotEnabled,
-
- /// The device doesn't support using the `multiview´ feature with geometry shaders.
- MultiviewGeometryShaderNotSupported,
-
- /// The device doesn't support using the `multiview´ feature with tessellation shaders.
- MultiviewTessellationShaderNotSupported,
-}
-
-impl error::Error for GraphicsPipelineCreationError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- GraphicsPipelineCreationError::OomError(ref err) => Some(err),
- GraphicsPipelineCreationError::IncompatiblePipelineLayout(ref err) => Some(err),
- GraphicsPipelineCreationError::ShaderStagesMismatch(ref err) => Some(err),
- GraphicsPipelineCreationError::IncompatibleVertexDefinition(ref err) => Some(err),
- _ => None,
- }
- }
-}
-
-impl fmt::Display for GraphicsPipelineCreationError {
- // TODO: finish
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- GraphicsPipelineCreationError::OomError(_) => "not enough memory available",
- GraphicsPipelineCreationError::ShaderStagesMismatch(_) => {
- "the output interface of one shader and the input interface of the next shader does not match"
- }
- GraphicsPipelineCreationError::IncompatiblePipelineLayout(_) => {
- "the pipeline layout is not compatible with what the shaders expect"
- }
- GraphicsPipelineCreationError::IncompatibleSpecializationConstants => {
- "the provided specialization constants are not compatible with what the shader expects"
- }
- GraphicsPipelineCreationError::FragmentShaderRenderPassIncompatible => {
- "the output of the fragment shader is not compatible with what the render pass \
- subpass expects"
- }
- GraphicsPipelineCreationError::IncompatibleVertexDefinition(_) => {
- "the vertex definition is not compatible with the input of the vertex shader"
- }
- GraphicsPipelineCreationError::MaxVertexInputBindingStrideExceeded { .. } => {
- "the maximum stride value for vertex input (ie. the distance between two vertex \
- elements) has been exceeded"
- }
- GraphicsPipelineCreationError::MaxVertexInputBindingsExceeded { .. } => {
- "the maximum number of vertex sources has been exceeded"
- }
- GraphicsPipelineCreationError::MaxVertexInputAttributeOffsetExceeded { .. } => {
- "the maximum offset for a vertex attribute has been exceeded"
- }
- GraphicsPipelineCreationError::MaxVertexInputAttributesExceeded { .. } => {
- "the maximum number of vertex attributes has been exceeded"
- }
- GraphicsPipelineCreationError::VertexAttributeInstanceRateDivisorFeatureNotEnabled => {
- "the `vertex_attribute_instance_rate_divisor` feature must be enabled in order to use instance rate divisors"
- }
- GraphicsPipelineCreationError::VertexAttributeInstanceRateZeroDivisorFeatureNotEnabled => {
- "the `vertex_attribute_instance_rate_zero_divisor` feature must be enabled in order to use an instance rate divisor of zero"
- }
- GraphicsPipelineCreationError::MaxVertexAttribDivisorExceeded { .. } => {
- "the maximum value for the instance rate divisor has been exceeded"
- }
- GraphicsPipelineCreationError::PrimitiveDoesntSupportPrimitiveRestart {
- ..
- } => {
- "the user requested to use primitive restart, but the primitive topology \
- doesn't support it"
- }
- GraphicsPipelineCreationError::MultiViewportFeatureNotEnabled => {
- "the `multi_viewport` feature must be enabled in order to use multiple viewports \
- at once"
- }
- GraphicsPipelineCreationError::MaxViewportsExceeded { .. } => {
- "the maximum number of viewports has been exceeded"
- }
- GraphicsPipelineCreationError::MaxViewportDimensionsExceeded => {
- "the maximum dimensions of viewports has been exceeded"
- }
- GraphicsPipelineCreationError::ViewportBoundsExceeded => {
- "the minimum or maximum bounds of viewports have been exceeded"
- }
- GraphicsPipelineCreationError::WideLinesFeatureNotEnabled => {
- "the `wide_lines` feature must be enabled in order to use a line width \
- greater than 1.0"
- }
- GraphicsPipelineCreationError::DepthClampFeatureNotEnabled => {
- "the `depth_clamp` feature must be enabled in order to use depth clamping"
- }
- GraphicsPipelineCreationError::DepthBiasClampFeatureNotEnabled => {
- "the `depth_bias_clamp` feature must be enabled in order to use a depth bias \
- clamp different from 0.0."
- }
- GraphicsPipelineCreationError::FillModeNonSolidFeatureNotEnabled => {
- "the `fill_mode_non_solid` feature must be enabled in order to use a polygon mode \
- different from `Fill`"
- }
- GraphicsPipelineCreationError::DepthBoundsFeatureNotEnabled => {
- "the `depth_bounds` feature must be enabled in order to use depth bounds testing"
- }
- GraphicsPipelineCreationError::WrongStencilState => {
- "the requested stencil test is invalid"
- }
- GraphicsPipelineCreationError::TopologyNotMatchingGeometryShader => {
- "the primitives topology does not match what the geometry shader expects"
- }
- GraphicsPipelineCreationError::GeometryShaderFeatureNotEnabled => {
- "the `geometry_shader` feature must be enabled in order to use geometry shaders"
- }
- GraphicsPipelineCreationError::TessellationShaderFeatureNotEnabled => {
- "the `tessellation_shader` feature must be enabled in order to use tessellation \
- shaders"
- }
- GraphicsPipelineCreationError::MismatchBlendingAttachmentsCount => {
- "the number of attachments specified in the blending does not match the number of \
- attachments in the subpass"
- }
- GraphicsPipelineCreationError::IndependentBlendFeatureNotEnabled => {
- "the `independent_blend` feature must be enabled in order to use different \
- blending operations per attachment"
- }
- GraphicsPipelineCreationError::LogicOpFeatureNotEnabled => {
- "the `logic_op` feature must be enabled in order to use logic operations"
- }
- GraphicsPipelineCreationError::NoDepthAttachment => {
- "the depth attachment of the render pass does not match the depth test"
- }
- GraphicsPipelineCreationError::NoStencilAttachment => {
- "the stencil attachment of the render pass does not match the stencil test"
- }
- GraphicsPipelineCreationError::InvalidPrimitiveTopology => {
- "trying to use a patch list without a tessellation shader, or a non-patch-list \
- with a tessellation shader"
- }
- GraphicsPipelineCreationError::MaxTessellationPatchSizeExceeded => {
- "the maximum tessellation patch size was exceeded"
- }
- GraphicsPipelineCreationError::WrongShaderType => {
- "the wrong type of shader has been passed"
- }
- GraphicsPipelineCreationError::SampleRateShadingFeatureNotEnabled => {
- "the `sample_rate_shading` feature must be enabled in order to use sample shading"
- }
- GraphicsPipelineCreationError::AlphaToOneFeatureNotEnabled => {
- "the `alpha_to_one` feature must be enabled in order to use alpha-to-one"
- }
- GraphicsPipelineCreationError::MultiviewGeometryShaderNotSupported => {
- "the device doesn't support using the `multiview´ feature with geometry shaders"
- }
- GraphicsPipelineCreationError::MultiviewTessellationShaderNotSupported => {
- "the device doesn't support using the `multiview´ feature with tessellation shaders"
- }
- }
- )
- }
-}
-
-impl From<OomError> for GraphicsPipelineCreationError {
- #[inline]
- fn from(err: OomError) -> GraphicsPipelineCreationError {
- GraphicsPipelineCreationError::OomError(err)
- }
-}
-
-impl From<PipelineLayoutSupersetError> for GraphicsPipelineCreationError {
- #[inline]
- fn from(err: PipelineLayoutSupersetError) -> GraphicsPipelineCreationError {
- GraphicsPipelineCreationError::IncompatiblePipelineLayout(err)
- }
-}
-
-impl From<IncompatibleVertexDefinitionError> for GraphicsPipelineCreationError {
- #[inline]
- fn from(err: IncompatibleVertexDefinitionError) -> GraphicsPipelineCreationError {
- GraphicsPipelineCreationError::IncompatibleVertexDefinition(err)
- }
-}
-
-impl From<Error> for GraphicsPipelineCreationError {
- #[inline]
- fn from(err: Error) -> GraphicsPipelineCreationError {
- match err {
- err @ Error::OutOfHostMemory => {
- GraphicsPipelineCreationError::OomError(OomError::from(err))
- }
- err @ Error::OutOfDeviceMemory => {
- GraphicsPipelineCreationError::OomError(OomError::from(err))
- }
- _ => panic!("unexpected error: {:?}", err),
- }
- }
-}
diff --git a/src/pipeline/graphics_pipeline/mod.rs b/src/pipeline/graphics_pipeline/mod.rs
deleted file mode 100644
index 2082830..0000000
--- a/src/pipeline/graphics_pipeline/mod.rs
+++ /dev/null
@@ -1,448 +0,0 @@
-// Copyright (c) 2017 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-pub use self::builder::GraphicsPipelineBuilder;
-pub use self::creation_error::GraphicsPipelineCreationError;
-use crate::buffer::BufferAccess;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::pipeline::layout::PipelineLayout;
-use crate::pipeline::shader::ShaderInterface;
-use crate::pipeline::vertex::BufferlessDefinition;
-use crate::pipeline::vertex::IncompatibleVertexDefinitionError;
-use crate::pipeline::vertex::VertexDefinition;
-use crate::pipeline::vertex::VertexInput;
-use crate::pipeline::vertex::VertexSource;
-use crate::render_pass::RenderPass;
-use crate::render_pass::Subpass;
-use crate::SafeDeref;
-use crate::VulkanObject;
-use std::fmt;
-use std::hash::Hash;
-use std::hash::Hasher;
-use std::marker::PhantomData;
-use std::ptr;
-use std::sync::Arc;
-use std::u32;
-
-mod builder;
-mod creation_error;
-// FIXME: restore
-//mod tests;
-
-/// Defines how the implementation should perform a draw operation.
-///
-/// This object contains the shaders and the various fixed states that describe how the
-/// implementation should perform the various operations needed by a draw command.
-pub struct GraphicsPipeline<VertexDefinition> {
- inner: Inner,
- layout: Arc<PipelineLayout>,
- subpass: Subpass,
- vertex_definition: VertexDefinition,
- vertex_input: VertexInput,
-
- dynamic_line_width: bool,
- dynamic_viewport: bool,
- dynamic_scissor: bool,
- dynamic_depth_bias: bool,
- dynamic_depth_bounds: bool,
- dynamic_stencil_compare_mask: bool,
- dynamic_stencil_write_mask: bool,
- dynamic_stencil_reference: bool,
- dynamic_blend_constants: bool,
-
- num_viewports: u32,
-}
-
-#[derive(PartialEq, Eq, Hash)]
-struct Inner {
- pipeline: ash::vk::Pipeline,
- device: Arc<Device>,
-}
-
-impl GraphicsPipeline<()> {
- /// Starts the building process of a graphics pipeline. Returns a builder object that you can
- /// fill with the various parameters.
- pub fn start<'a>() -> GraphicsPipelineBuilder<
- 'static,
- 'static,
- 'static,
- 'static,
- 'static,
- BufferlessDefinition,
- (),
- (),
- (),
- (),
- (),
- > {
- GraphicsPipelineBuilder::new()
- }
-}
-
-impl<Mv> GraphicsPipeline<Mv> {
- /// Returns the vertex definition used in the constructor.
- #[inline]
- pub fn vertex_definition(&self) -> &Mv {
- &self.vertex_definition
- }
-
- /// Returns the device used to create this pipeline.
- #[inline]
- pub fn device(&self) -> &Arc<Device> {
- &self.inner.device
- }
-
- /// Returns the pass used in the constructor.
- #[inline]
- pub fn subpass(&self) -> Subpass {
- self.subpass.clone()
- }
-
- /// Returns the render pass used in the constructor.
- #[inline]
- pub fn render_pass(&self) -> &Arc<RenderPass> {
- self.subpass.render_pass()
- }
-
- /// Returns true if the line width used by this pipeline is dynamic.
- #[inline]
- pub fn has_dynamic_line_width(&self) -> bool {
- self.dynamic_line_width
- }
-
- /// Returns the number of viewports and scissors of this pipeline.
- #[inline]
- pub fn num_viewports(&self) -> u32 {
- self.num_viewports
- }
-
- /// Returns true if the viewports used by this pipeline are dynamic.
- #[inline]
- pub fn has_dynamic_viewports(&self) -> bool {
- self.dynamic_viewport
- }
-
- /// Returns true if the scissors used by this pipeline are dynamic.
- #[inline]
- pub fn has_dynamic_scissors(&self) -> bool {
- self.dynamic_scissor
- }
-
- /// Returns true if the depth bounds used by this pipeline are dynamic.
- #[inline]
- pub fn has_dynamic_depth_bounds(&self) -> bool {
- self.dynamic_depth_bounds
- }
-
- /// Returns true if the stencil compare masks used by this pipeline are dynamic.
- #[inline]
- pub fn has_dynamic_stencil_compare_mask(&self) -> bool {
- self.dynamic_stencil_compare_mask
- }
-
- /// Returns true if the stencil write masks used by this pipeline are dynamic.
- #[inline]
- pub fn has_dynamic_stencil_write_mask(&self) -> bool {
- self.dynamic_stencil_write_mask
- }
-
- /// Returns true if the stencil references used by this pipeline are dynamic.
- #[inline]
- pub fn has_dynamic_stencil_reference(&self) -> bool {
- self.dynamic_stencil_reference
- }
-}
-
-unsafe impl<Mv> DeviceOwned for GraphicsPipeline<Mv> {
- #[inline]
- fn device(&self) -> &Arc<Device> {
- &self.inner.device
- }
-}
-
-impl<Mv> fmt::Debug for GraphicsPipeline<Mv> {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(fmt, "<Vulkan graphics pipeline {:?}>", self.inner.pipeline)
- }
-}
-
-unsafe impl<Mv> VulkanObject for GraphicsPipeline<Mv> {
- type Object = ash::vk::Pipeline;
-
- #[inline]
- fn internal_object(&self) -> ash::vk::Pipeline {
- self.inner.pipeline
- }
-}
-
-impl Drop for Inner {
- #[inline]
- fn drop(&mut self) {
- unsafe {
- let fns = self.device.fns();
- fns.v1_0
- .destroy_pipeline(self.device.internal_object(), self.pipeline, ptr::null());
- }
- }
-}
-
-/// Trait implemented on objects that reference a graphics pipeline. Can be made into a trait
-/// object.
-/// When using this trait `AutoCommandBufferBuilder::draw*` calls will need the buffers to be
-/// wrapped in a `vec!()`.
-pub unsafe trait GraphicsPipelineAbstract:
- VertexSource<Vec<Arc<dyn BufferAccess + Send + Sync>>> + DeviceOwned
-{
- /// Returns an opaque object that represents the inside of the graphics pipeline.
- fn inner(&self) -> GraphicsPipelineSys;
-
- /// Returns the pipeline layout used in the constructor.
- fn layout(&self) -> &Arc<PipelineLayout>;
-
- /// Returns the subpass this graphics pipeline is rendering to.
- fn subpass(&self) -> &Subpass;
-
- /// Returns the vertex input description of the graphics pipeline.
- fn vertex_input(&self) -> &VertexInput;
-
- /// Returns true if the line width used by this pipeline is dynamic.
- fn has_dynamic_line_width(&self) -> bool;
-
- /// Returns the number of viewports and scissors of this pipeline.
- fn num_viewports(&self) -> u32;
-
- /// Returns true if the viewports used by this pipeline are dynamic.
- fn has_dynamic_viewports(&self) -> bool;
-
- /// Returns true if the scissors used by this pipeline are dynamic.
- fn has_dynamic_scissors(&self) -> bool;
-
- /// Returns true if the depth bounds used by this pipeline are dynamic.
- fn has_dynamic_depth_bounds(&self) -> bool;
-
- /// Returns true if the stencil compare masks used by this pipeline are dynamic.
- fn has_dynamic_stencil_compare_mask(&self) -> bool;
-
- /// Returns true if the stencil write masks used by this pipeline are dynamic.
- fn has_dynamic_stencil_write_mask(&self) -> bool;
-
- /// Returns true if the stencil references used by this pipeline are dynamic.
- fn has_dynamic_stencil_reference(&self) -> bool;
-}
-
-unsafe impl<Mv> GraphicsPipelineAbstract for GraphicsPipeline<Mv>
-where
- Mv: VertexSource<Vec<Arc<dyn BufferAccess + Send + Sync>>>,
-{
- #[inline]
- fn inner(&self) -> GraphicsPipelineSys {
- GraphicsPipelineSys(self.inner.pipeline, PhantomData)
- }
-
- /// Returns the pipeline layout used in the constructor.
- #[inline]
- fn layout(&self) -> &Arc<PipelineLayout> {
- &self.layout
- }
-
- #[inline]
- fn subpass(&self) -> &Subpass {
- &self.subpass
- }
-
- #[inline]
- fn vertex_input(&self) -> &VertexInput {
- &self.vertex_input
- }
-
- #[inline]
- fn has_dynamic_line_width(&self) -> bool {
- self.dynamic_line_width
- }
-
- #[inline]
- fn num_viewports(&self) -> u32 {
- self.num_viewports
- }
-
- #[inline]
- fn has_dynamic_viewports(&self) -> bool {
- self.dynamic_viewport
- }
-
- #[inline]
- fn has_dynamic_scissors(&self) -> bool {
- self.dynamic_scissor
- }
-
- #[inline]
- fn has_dynamic_depth_bounds(&self) -> bool {
- self.dynamic_depth_bounds
- }
-
- #[inline]
- fn has_dynamic_stencil_compare_mask(&self) -> bool {
- self.dynamic_stencil_compare_mask
- }
-
- #[inline]
- fn has_dynamic_stencil_write_mask(&self) -> bool {
- self.dynamic_stencil_write_mask
- }
-
- #[inline]
- fn has_dynamic_stencil_reference(&self) -> bool {
- self.dynamic_stencil_reference
- }
-}
-
-unsafe impl<T> GraphicsPipelineAbstract for T
-where
- T: SafeDeref,
- T::Target: GraphicsPipelineAbstract,
-{
- #[inline]
- fn inner(&self) -> GraphicsPipelineSys {
- GraphicsPipelineAbstract::inner(&**self)
- }
-
- #[inline]
- fn layout(&self) -> &Arc<PipelineLayout> {
- (**self).layout()
- }
-
- #[inline]
- fn subpass(&self) -> &Subpass {
- (**self).subpass()
- }
-
- #[inline]
- fn vertex_input(&self) -> &VertexInput {
- (**self).vertex_input()
- }
-
- #[inline]
- fn has_dynamic_line_width(&self) -> bool {
- (**self).has_dynamic_line_width()
- }
-
- #[inline]
- fn num_viewports(&self) -> u32 {
- (**self).num_viewports()
- }
-
- #[inline]
- fn has_dynamic_viewports(&self) -> bool {
- (**self).has_dynamic_viewports()
- }
-
- #[inline]
- fn has_dynamic_scissors(&self) -> bool {
- (**self).has_dynamic_scissors()
- }
-
- #[inline]
- fn has_dynamic_depth_bounds(&self) -> bool {
- (**self).has_dynamic_depth_bounds()
- }
-
- #[inline]
- fn has_dynamic_stencil_compare_mask(&self) -> bool {
- (**self).has_dynamic_stencil_compare_mask()
- }
-
- #[inline]
- fn has_dynamic_stencil_write_mask(&self) -> bool {
- (**self).has_dynamic_stencil_write_mask()
- }
-
- #[inline]
- fn has_dynamic_stencil_reference(&self) -> bool {
- (**self).has_dynamic_stencil_reference()
- }
-}
-
-impl<Mv> PartialEq for GraphicsPipeline<Mv>
-where
- Mv: VertexSource<Vec<Arc<dyn BufferAccess + Send + Sync>>>,
-{
- #[inline]
- fn eq(&self, other: &Self) -> bool {
- self.inner == other.inner
- }
-}
-
-impl<Mv> Eq for GraphicsPipeline<Mv> where Mv: VertexSource<Vec<Arc<dyn BufferAccess + Send + Sync>>>
-{}
-
-impl<Mv> Hash for GraphicsPipeline<Mv>
-where
- Mv: VertexSource<Vec<Arc<dyn BufferAccess + Send + Sync>>>,
-{
- #[inline]
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.inner.hash(state);
- }
-}
-
-impl PartialEq for dyn GraphicsPipelineAbstract + Send + Sync {
- #[inline]
- fn eq(&self, other: &Self) -> bool {
- GraphicsPipelineAbstract::inner(self).0 == GraphicsPipelineAbstract::inner(other).0
- && DeviceOwned::device(self) == DeviceOwned::device(other)
- }
-}
-
-impl Eq for dyn GraphicsPipelineAbstract + Send + Sync {}
-
-impl Hash for dyn GraphicsPipelineAbstract + Send + Sync {
- #[inline]
- fn hash<H: Hasher>(&self, state: &mut H) {
- GraphicsPipelineAbstract::inner(self).0.hash(state);
- DeviceOwned::device(self).hash(state);
- }
-}
-
-/// Opaque object that represents the inside of the graphics pipeline.
-#[derive(Debug, Copy, Clone)]
-pub struct GraphicsPipelineSys<'a>(ash::vk::Pipeline, PhantomData<&'a ()>);
-
-unsafe impl<'a> VulkanObject for GraphicsPipelineSys<'a> {
- type Object = ash::vk::Pipeline;
-
- #[inline]
- fn internal_object(&self) -> ash::vk::Pipeline {
- self.0
- }
-}
-
-unsafe impl<Mv> VertexDefinition for GraphicsPipeline<Mv>
-where
- Mv: VertexDefinition,
-{
- #[inline]
- fn definition(
- &self,
- interface: &ShaderInterface,
- ) -> Result<VertexInput, IncompatibleVertexDefinitionError> {
- self.vertex_definition.definition(interface)
- }
-}
-
-unsafe impl<Mv, S> VertexSource<S> for GraphicsPipeline<Mv>
-where
- Mv: VertexSource<S>,
-{
- #[inline]
- fn decode(&self, s: S) -> (Vec<Box<dyn BufferAccess + Send + Sync>>, usize, usize) {
- self.vertex_definition.decode(s)
- }
-}
diff --git a/src/pipeline/input_assembly.rs b/src/pipeline/input_assembly.rs
deleted file mode 100644
index d797d0d..0000000
--- a/src/pipeline/input_assembly.rs
+++ /dev/null
@@ -1,136 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-//! Assembling vertices into primitives.
-//!
-//! The input assembly is the stage where lists of vertices are turned into primitives.
-//!
-
-/// How the input assembly stage should behave.
-#[derive(Copy, Clone, Debug)]
-#[deprecated]
-pub struct InputAssembly {
- /// The type of primitives.
- ///
- /// Note that some topologies don't support primitive restart.
- pub topology: PrimitiveTopology,
-
- /// If true, then the special index value `0xffff` or `0xffffffff` will tell the GPU that it is
- /// the end of the current primitive. A new primitive will restart at the next index.
- ///
- /// Note that some topologies don't support primitive restart.
- pub primitive_restart_enable: bool,
-}
-
-impl InputAssembly {
- /// Builds an `InputAssembly` struct with the `TriangleList` topology.
- #[inline]
- pub fn triangle_list() -> InputAssembly {
- InputAssembly {
- topology: PrimitiveTopology::TriangleList,
- primitive_restart_enable: false,
- }
- }
-}
-
-/// Describes how vertices must be grouped together to form primitives.
-///
-/// Note that some topologies don't support primitive restart.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum PrimitiveTopology {
- PointList,
- LineList,
- LineStrip,
- TriangleList,
- TriangleStrip,
- TriangleFan,
- LineListWithAdjacency,
- LineStripWithAdjacency,
- TriangleListWithAdjacency,
- TriangleStripWithAdjacency,
- PatchList { vertices_per_patch: u32 },
-}
-
-impl From<PrimitiveTopology> for ash::vk::PrimitiveTopology {
- #[inline]
- fn from(val: PrimitiveTopology) -> ash::vk::PrimitiveTopology {
- match val {
- PrimitiveTopology::PointList => ash::vk::PrimitiveTopology::POINT_LIST,
- PrimitiveTopology::LineList => ash::vk::PrimitiveTopology::LINE_LIST,
- PrimitiveTopology::LineStrip => ash::vk::PrimitiveTopology::LINE_STRIP,
- PrimitiveTopology::TriangleList => ash::vk::PrimitiveTopology::TRIANGLE_LIST,
- PrimitiveTopology::TriangleStrip => ash::vk::PrimitiveTopology::TRIANGLE_STRIP,
- PrimitiveTopology::TriangleFan => ash::vk::PrimitiveTopology::TRIANGLE_FAN,
- PrimitiveTopology::LineListWithAdjacency => {
- ash::vk::PrimitiveTopology::LINE_LIST_WITH_ADJACENCY
- }
- PrimitiveTopology::LineStripWithAdjacency => {
- ash::vk::PrimitiveTopology::LINE_STRIP_WITH_ADJACENCY
- }
- PrimitiveTopology::TriangleListWithAdjacency => {
- ash::vk::PrimitiveTopology::TRIANGLE_LIST_WITH_ADJACENCY
- }
- PrimitiveTopology::TriangleStripWithAdjacency => {
- ash::vk::PrimitiveTopology::TRIANGLE_STRIP_WITH_ADJACENCY
- }
- PrimitiveTopology::PatchList { .. } => ash::vk::PrimitiveTopology::PATCH_LIST,
- }
- }
-}
-
-impl PrimitiveTopology {
- /// Returns true if this primitive topology supports using primitives restart.
- #[inline]
- pub fn supports_primitive_restart(&self) -> bool {
- match *self {
- PrimitiveTopology::LineStrip => true,
- PrimitiveTopology::TriangleStrip => true,
- PrimitiveTopology::TriangleFan => true,
- PrimitiveTopology::LineStripWithAdjacency => true,
- PrimitiveTopology::TriangleStripWithAdjacency => true,
- _ => false,
- }
- }
-}
-
-/// Trait for types that can be used as indices by the GPU.
-pub unsafe trait Index {
- /// Returns the type of data.
- fn ty() -> IndexType;
-}
-
-unsafe impl Index for u16 {
- #[inline(always)]
- fn ty() -> IndexType {
- IndexType::U16
- }
-}
-
-unsafe impl Index for u32 {
- #[inline(always)]
- fn ty() -> IndexType {
- IndexType::U32
- }
-}
-
-/// An enumeration of all valid index types.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
-#[allow(missing_docs)]
-#[repr(i32)]
-pub enum IndexType {
- U16 = ash::vk::IndexType::UINT16.as_raw(),
- U32 = ash::vk::IndexType::UINT32.as_raw(),
-}
-
-impl From<IndexType> for ash::vk::IndexType {
- #[inline]
- fn from(val: IndexType) -> Self {
- Self::from_raw(val as i32)
- }
-}
diff --git a/src/pipeline/layout.rs b/src/pipeline/layout.rs
new file mode 100644
index 0000000..8fc7bcf
--- /dev/null
+++ b/src/pipeline/layout.rs
@@ -0,0 +1,1468 @@
+// Copyright (c) 2016 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+//! The layout of descriptor sets and push constants used by a pipeline.
+//!
+//! # Overview
+//!
+//! The layout itself only *describes* the descriptors and push constants, and does not contain
+//! their content itself. Instead, you can think of it as a `struct` definition that states which
+//! members there are, what types they have, and in what order.
+//! One could imagine a Rust definition somewhat like this:
+//!
+//! ```text
+//! #[repr(C)]
+//! struct MyPipelineLayout {
+//! push_constants: Pc,
+//! descriptor_set0: Ds0,
+//! descriptor_set1: Ds1,
+//! descriptor_set2: Ds2,
+//! descriptor_set3: Ds3,
+//! }
+//! ```
+//!
+//! Of course, a pipeline layout is created at runtime, unlike a Rust type.
+//!
+//! # Layout compatibility
+//!
+//! When binding descriptor sets or setting push constants, you must provide a pipeline layout.
+//! This layout is used to decide where in memory Vulkan should write the new data. The
+//! descriptor sets and push constants can later be read by dispatch or draw calls, but only if
+//! the bound pipeline being used for the command has a layout that is *compatible* with the layout
+//! that was used to bind the resources.
+//!
+//! *Compatible* means that the pipeline layout must be the same object, or a different layout in
+//! which the push constant ranges and descriptor set layouts were be identically defined.
+//! However, Vulkan allows for partial compatibility as well. In the `struct` analogy used above,
+//! one could imagine that using a different definition would leave some members with the same
+//! offset and size within the struct as in the old definition, while others are no longer
+//! positioned correctly. For example, if a new, incompatible type were used for `Ds1`, then the
+//! `descriptor_set1`, `descriptor_set2` and `descriptor_set3` members would no longer be correct,
+//! but `descriptor_set0` and `push_constants` would remain accessible in the new layout.
+//! Because of this behaviour, the following rules apply to compatibility between the layouts used
+//! in subsequent descriptor set binding calls:
+//!
+//! - An incompatible definition of `Pc` invalidates all bound descriptor sets.
+//! - An incompatible definition of `DsN` invalidates all bound descriptor sets *N* and higher.
+//! - If *N* is the highest set being assigned in a bind command, and it and all lower sets
+//! have compatible definitions, including the push constants, then descriptor sets above *N*
+//! remain valid.
+//!
+//! [`SyncCommandBufferBuilder`](crate::command_buffer::synced::SyncCommandBufferBuilder) keeps
+//! track of this state and will automatically remove descriptor sets that have been invalidated
+//! by incompatible layouts in subsequent binding commands.
+//!
+//! # Creating pipeline layouts
+//!
+//! A pipeline layout is a Vulkan object type, represented in Vulkano with the `PipelineLayout`
+//! type. Each pipeline that you create holds a pipeline layout object.
+
+use crate::{
+ descriptor_set::layout::{DescriptorRequirementsNotMet, DescriptorSetLayout, DescriptorType},
+ device::{Device, DeviceOwned},
+ macros::impl_id_counter,
+ shader::{DescriptorBindingRequirements, ShaderStages},
+ OomError, RequirementNotMet, RequiresOneOf, VulkanError, VulkanObject,
+};
+use smallvec::SmallVec;
+use std::{
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+ mem::MaybeUninit,
+ num::NonZeroU64,
+ ptr,
+ sync::Arc,
+};
+
+/// Describes the layout of descriptor sets and push constants that are made available to shaders.
+#[derive(Debug)]
+pub struct PipelineLayout {
+ handle: ash::vk::PipelineLayout,
+ device: Arc<Device>,
+ id: NonZeroU64,
+
+ set_layouts: Vec<Arc<DescriptorSetLayout>>,
+ push_constant_ranges: Vec<PushConstantRange>,
+
+ push_constant_ranges_disjoint: Vec<PushConstantRange>,
+}
+
+impl PipelineLayout {
+ /// Creates a new `PipelineLayout`.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if an element of `create_info.push_constant_ranges` has an empty `stages` value.
+ /// - Panics if an element of `create_info.push_constant_ranges` has an `offset` or `size`
+ /// that's not divisible by 4.
+ /// - Panics if an element of `create_info.push_constant_ranges` has an `size` of zero.
+ pub fn new(
+ device: Arc<Device>,
+ mut create_info: PipelineLayoutCreateInfo,
+ ) -> Result<Arc<PipelineLayout>, PipelineLayoutCreationError> {
+ Self::validate(&device, &mut create_info)?;
+ let handle = unsafe { Self::create(&device, &create_info)? };
+
+ let PipelineLayoutCreateInfo {
+ set_layouts,
+ mut push_constant_ranges,
+ _ne: _,
+ } = create_info;
+
+ // Sort the ranges for the purpose of comparing for equality.
+ // The stage mask is guaranteed to be unique, so it's a suitable sorting key.
+ push_constant_ranges.sort_unstable_by_key(|range| {
+ (
+ range.offset,
+ range.size,
+ ash::vk::ShaderStageFlags::from(range.stages),
+ )
+ });
+
+ let push_constant_ranges_disjoint =
+ Self::create_push_constant_ranges_disjoint(&push_constant_ranges);
+
+ Ok(Arc::new(PipelineLayout {
+ handle,
+ device,
+ id: Self::next_id(),
+ set_layouts,
+ push_constant_ranges,
+ push_constant_ranges_disjoint,
+ }))
+ }
+
+ fn create_push_constant_ranges_disjoint(
+ push_constant_ranges: &Vec<PushConstantRange>,
+ ) -> Vec<PushConstantRange> {
+ let mut push_constant_ranges_disjoint: Vec<PushConstantRange> =
+ Vec::with_capacity(push_constant_ranges.len());
+
+ if !push_constant_ranges.is_empty() {
+ let mut min_offset = push_constant_ranges[0].offset;
+ loop {
+ let mut max_offset = u32::MAX;
+ let mut stages = ShaderStages::empty();
+
+ for range in push_constant_ranges.iter() {
+ // new start (begin next time from it)
+ if range.offset > min_offset {
+ max_offset = max_offset.min(range.offset);
+ break;
+ } else if range.offset + range.size > min_offset {
+ // inside the range, include the stage
+ // use the minimum of the end of all ranges that are overlapping
+ max_offset = max_offset.min(range.offset + range.size);
+ stages |= range.stages;
+ }
+ }
+ // finished all stages
+ if stages.is_empty() {
+ break;
+ }
+
+ push_constant_ranges_disjoint.push(PushConstantRange {
+ stages,
+ offset: min_offset,
+ size: max_offset - min_offset,
+ });
+ // prepare for next range
+ min_offset = max_offset;
+ }
+ }
+ push_constant_ranges_disjoint
+ }
+
+ fn validate(
+ device: &Device,
+ create_info: &mut PipelineLayoutCreateInfo,
+ ) -> Result<(), PipelineLayoutCreationError> {
+ let &mut PipelineLayoutCreateInfo {
+ ref set_layouts,
+ ref push_constant_ranges,
+ _ne: _,
+ } = create_info;
+
+ let properties = device.physical_device().properties();
+
+ /* Check descriptor set layouts */
+
+ // VUID-VkPipelineLayoutCreateInfo-setLayoutCount-00286
+ if set_layouts.len() > properties.max_bound_descriptor_sets as usize {
+ return Err(
+ PipelineLayoutCreationError::MaxBoundDescriptorSetsExceeded {
+ provided: set_layouts.len() as u32,
+ max_supported: properties.max_bound_descriptor_sets,
+ },
+ );
+ }
+
+ {
+ let mut num_resources = Counter::default();
+ let mut num_samplers = Counter::default();
+ let mut num_uniform_buffers = Counter::default();
+ let mut num_uniform_buffers_dynamic = 0;
+ let mut num_storage_buffers = Counter::default();
+ let mut num_storage_buffers_dynamic = 0;
+ let mut num_sampled_images = Counter::default();
+ let mut num_storage_images = Counter::default();
+ let mut num_input_attachments = Counter::default();
+ let mut push_descriptor_set = None;
+
+ for (set_num, set_layout) in set_layouts.iter().enumerate() {
+ let set_num = set_num as u32;
+
+ if set_layout.push_descriptor() {
+ // VUID-VkPipelineLayoutCreateInfo-pSetLayouts-00293
+ if push_descriptor_set.is_some() {
+ return Err(PipelineLayoutCreationError::SetLayoutsPushDescriptorMultiple);
+ } else {
+ push_descriptor_set = Some(set_num);
+ }
+ }
+
+ for layout_binding in set_layout.bindings().values() {
+ num_resources.increment(layout_binding.descriptor_count, layout_binding.stages);
+
+ match layout_binding.descriptor_type {
+ DescriptorType::Sampler => {
+ num_samplers
+ .increment(layout_binding.descriptor_count, layout_binding.stages);
+ }
+ DescriptorType::CombinedImageSampler => {
+ num_samplers
+ .increment(layout_binding.descriptor_count, layout_binding.stages);
+ num_sampled_images
+ .increment(layout_binding.descriptor_count, layout_binding.stages);
+ }
+ DescriptorType::SampledImage | DescriptorType::UniformTexelBuffer => {
+ num_sampled_images
+ .increment(layout_binding.descriptor_count, layout_binding.stages);
+ }
+ DescriptorType::StorageImage | DescriptorType::StorageTexelBuffer => {
+ num_storage_images
+ .increment(layout_binding.descriptor_count, layout_binding.stages);
+ }
+ DescriptorType::UniformBuffer => {
+ num_uniform_buffers
+ .increment(layout_binding.descriptor_count, layout_binding.stages);
+ }
+ DescriptorType::UniformBufferDynamic => {
+ num_uniform_buffers
+ .increment(layout_binding.descriptor_count, layout_binding.stages);
+ num_uniform_buffers_dynamic += 1;
+ }
+ DescriptorType::StorageBuffer => {
+ num_storage_buffers
+ .increment(layout_binding.descriptor_count, layout_binding.stages);
+ }
+ DescriptorType::StorageBufferDynamic => {
+ num_storage_buffers
+ .increment(layout_binding.descriptor_count, layout_binding.stages);
+ num_storage_buffers_dynamic += 1;
+ }
+ DescriptorType::InputAttachment => {
+ num_input_attachments
+ .increment(layout_binding.descriptor_count, layout_binding.stages);
+ }
+ }
+ }
+ }
+
+ if num_resources.max_per_stage() > properties.max_per_stage_resources {
+ return Err(PipelineLayoutCreationError::MaxPerStageResourcesExceeded {
+ provided: num_resources.max_per_stage(),
+ max_supported: properties.max_per_stage_resources,
+ });
+ }
+
+ // VUID-VkPipelineLayoutCreateInfo-descriptorType-03016
+ if num_samplers.max_per_stage() > properties.max_per_stage_descriptor_samplers {
+ return Err(
+ PipelineLayoutCreationError::MaxPerStageDescriptorSamplersExceeded {
+ provided: num_samplers.max_per_stage(),
+ max_supported: properties.max_per_stage_descriptor_samplers,
+ },
+ );
+ }
+
+ // VUID-VkPipelineLayoutCreateInfo-descriptorType-03017
+ if num_uniform_buffers.max_per_stage()
+ > properties.max_per_stage_descriptor_uniform_buffers
+ {
+ return Err(
+ PipelineLayoutCreationError::MaxPerStageDescriptorUniformBuffersExceeded {
+ provided: num_uniform_buffers.max_per_stage(),
+ max_supported: properties.max_per_stage_descriptor_uniform_buffers,
+ },
+ );
+ }
+
+ // VUID-VkPipelineLayoutCreateInfo-descriptorType-03018
+ if num_storage_buffers.max_per_stage()
+ > properties.max_per_stage_descriptor_storage_buffers
+ {
+ return Err(
+ PipelineLayoutCreationError::MaxPerStageDescriptorStorageBuffersExceeded {
+ provided: num_storage_buffers.max_per_stage(),
+ max_supported: properties.max_per_stage_descriptor_storage_buffers,
+ },
+ );
+ }
+
+ // VUID-VkPipelineLayoutCreateInfo-descriptorType-03019
+ if num_sampled_images.max_per_stage()
+ > properties.max_per_stage_descriptor_sampled_images
+ {
+ return Err(
+ PipelineLayoutCreationError::MaxPerStageDescriptorSampledImagesExceeded {
+ provided: num_sampled_images.max_per_stage(),
+ max_supported: properties.max_per_stage_descriptor_sampled_images,
+ },
+ );
+ }
+
+ // VUID-VkPipelineLayoutCreateInfo-descriptorType-03020
+ if num_storage_images.max_per_stage()
+ > properties.max_per_stage_descriptor_storage_images
+ {
+ return Err(
+ PipelineLayoutCreationError::MaxPerStageDescriptorStorageImagesExceeded {
+ provided: num_storage_images.max_per_stage(),
+ max_supported: properties.max_per_stage_descriptor_storage_images,
+ },
+ );
+ }
+
+ // VUID-VkPipelineLayoutCreateInfo-descriptorType-03021
+ if num_input_attachments.max_per_stage()
+ > properties.max_per_stage_descriptor_input_attachments
+ {
+ return Err(
+ PipelineLayoutCreationError::MaxPerStageDescriptorInputAttachmentsExceeded {
+ provided: num_input_attachments.max_per_stage(),
+ max_supported: properties.max_per_stage_descriptor_input_attachments,
+ },
+ );
+ }
+
+ // VUID-VkPipelineLayoutCreateInfo-descriptorType-03028
+ if num_samplers.total > properties.max_descriptor_set_samplers {
+ return Err(
+ PipelineLayoutCreationError::MaxDescriptorSetSamplersExceeded {
+ provided: num_samplers.total,
+ max_supported: properties.max_descriptor_set_samplers,
+ },
+ );
+ }
+
+ // VUID-VkPipelineLayoutCreateInfo-descriptorType-03029
+ if num_uniform_buffers.total > properties.max_descriptor_set_uniform_buffers {
+ return Err(
+ PipelineLayoutCreationError::MaxDescriptorSetUniformBuffersExceeded {
+ provided: num_uniform_buffers.total,
+ max_supported: properties.max_descriptor_set_uniform_buffers,
+ },
+ );
+ }
+
+ // VUID-VkPipelineLayoutCreateInfo-descriptorType-03030
+ if num_uniform_buffers_dynamic > properties.max_descriptor_set_uniform_buffers_dynamic {
+ return Err(
+ PipelineLayoutCreationError::MaxDescriptorSetUniformBuffersDynamicExceeded {
+ provided: num_uniform_buffers_dynamic,
+ max_supported: properties.max_descriptor_set_uniform_buffers_dynamic,
+ },
+ );
+ }
+
+ // VUID-VkPipelineLayoutCreateInfo-descriptorType-03031
+ if num_storage_buffers.total > properties.max_descriptor_set_storage_buffers {
+ return Err(
+ PipelineLayoutCreationError::MaxDescriptorSetStorageBuffersExceeded {
+ provided: num_storage_buffers.total,
+ max_supported: properties.max_descriptor_set_storage_buffers,
+ },
+ );
+ }
+
+ // VUID-VkPipelineLayoutCreateInfo-descriptorType-03032
+ if num_storage_buffers_dynamic > properties.max_descriptor_set_storage_buffers_dynamic {
+ return Err(
+ PipelineLayoutCreationError::MaxDescriptorSetStorageBuffersDynamicExceeded {
+ provided: num_storage_buffers_dynamic,
+ max_supported: properties.max_descriptor_set_storage_buffers_dynamic,
+ },
+ );
+ }
+
+ // VUID-VkPipelineLayoutCreateInfo-descriptorType-03033
+ if num_sampled_images.total > properties.max_descriptor_set_sampled_images {
+ return Err(
+ PipelineLayoutCreationError::MaxDescriptorSetSampledImagesExceeded {
+ provided: num_sampled_images.total,
+ max_supported: properties.max_descriptor_set_sampled_images,
+ },
+ );
+ }
+
+ // VUID-VkPipelineLayoutCreateInfo-descriptorType-03034
+ if num_storage_images.total > properties.max_descriptor_set_storage_images {
+ return Err(
+ PipelineLayoutCreationError::MaxDescriptorSetStorageImagesExceeded {
+ provided: num_storage_images.total,
+ max_supported: properties.max_descriptor_set_storage_images,
+ },
+ );
+ }
+
+ // VUID-VkPipelineLayoutCreateInfo-descriptorType-03035
+ if num_input_attachments.total > properties.max_descriptor_set_input_attachments {
+ return Err(
+ PipelineLayoutCreationError::MaxDescriptorSetInputAttachmentsExceeded {
+ provided: num_input_attachments.total,
+ max_supported: properties.max_descriptor_set_input_attachments,
+ },
+ );
+ }
+ }
+
+ /* Check push constant ranges */
+
+ push_constant_ranges
+ .iter()
+ .try_fold(ShaderStages::empty(), |total, range| {
+ let &PushConstantRange {
+ stages,
+ offset,
+ size,
+ } = range;
+
+ // VUID-VkPushConstantRange-stageFlags-parameter
+ stages.validate_device(device)?;
+
+ // VUID-VkPushConstantRange-stageFlags-requiredbitmask
+ assert!(!stages.is_empty());
+
+ // VUID-VkPushConstantRange-offset-00295
+ assert!(offset % 4 == 0);
+
+ // VUID-VkPushConstantRange-size-00296
+ assert!(size != 0);
+
+ // VUID-VkPushConstantRange-size-00297
+ assert!(size % 4 == 0);
+
+ // VUID-VkPushConstantRange-offset-00294
+ // VUID-VkPushConstantRange-size-00298
+ if offset + size > properties.max_push_constants_size {
+ return Err(PipelineLayoutCreationError::MaxPushConstantsSizeExceeded {
+ provided: offset + size,
+ max_supported: properties.max_push_constants_size,
+ });
+ }
+
+ // VUID-VkPipelineLayoutCreateInfo-pPushConstantRanges-00292
+ if !(total & stages).is_empty() {
+ return Err(PipelineLayoutCreationError::PushConstantRangesStageMultiple);
+ }
+
+ Ok(total | stages)
+ })?;
+
+ Ok(())
+ }
+
+ unsafe fn create(
+ device: &Device,
+ create_info: &PipelineLayoutCreateInfo,
+ ) -> Result<ash::vk::PipelineLayout, PipelineLayoutCreationError> {
+ let PipelineLayoutCreateInfo {
+ set_layouts,
+ push_constant_ranges,
+ _ne: _,
+ } = create_info;
+
+ let set_layouts: SmallVec<[_; 4]> = set_layouts.iter().map(|l| l.handle()).collect();
+
+ let push_constant_ranges: SmallVec<[_; 4]> = push_constant_ranges
+ .iter()
+ .map(|range| ash::vk::PushConstantRange {
+ stage_flags: range.stages.into(),
+ offset: range.offset,
+ size: range.size,
+ })
+ .collect();
+
+ let create_info = ash::vk::PipelineLayoutCreateInfo {
+ flags: ash::vk::PipelineLayoutCreateFlags::empty(),
+ set_layout_count: set_layouts.len() as u32,
+ p_set_layouts: set_layouts.as_ptr(),
+ push_constant_range_count: push_constant_ranges.len() as u32,
+ p_push_constant_ranges: push_constant_ranges.as_ptr(),
+ ..Default::default()
+ };
+
+ let handle = {
+ let fns = device.fns();
+ let mut output = MaybeUninit::uninit();
+ (fns.v1_0.create_pipeline_layout)(
+ device.handle(),
+ &create_info,
+ ptr::null(),
+ output.as_mut_ptr(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+ output.assume_init()
+ };
+
+ Ok(handle)
+ }
+
+ /// Creates a new `PipelineLayout` from a raw object handle.
+ ///
+ /// # Safety
+ ///
+ /// - `handle` must be a valid Vulkan object handle created from `device`.
+ /// - `create_info` must match the info used to create the object.
+ #[inline]
+ pub unsafe fn from_handle(
+ device: Arc<Device>,
+ handle: ash::vk::PipelineLayout,
+ create_info: PipelineLayoutCreateInfo,
+ ) -> Arc<PipelineLayout> {
+ let PipelineLayoutCreateInfo {
+ set_layouts,
+ push_constant_ranges,
+ _ne: _,
+ } = create_info;
+
+ let push_constant_ranges_disjoint =
+ Self::create_push_constant_ranges_disjoint(&push_constant_ranges);
+
+ Arc::new(PipelineLayout {
+ handle,
+ device,
+ id: Self::next_id(),
+ set_layouts,
+ push_constant_ranges,
+ push_constant_ranges_disjoint,
+ })
+ }
+
+ /// Returns the descriptor set layouts this pipeline layout was created from.
+ #[inline]
+ pub fn set_layouts(&self) -> &[Arc<DescriptorSetLayout>] {
+ &self.set_layouts
+ }
+
+ /// Returns a slice containing the push constant ranges this pipeline layout was created from.
+ ///
+ /// The ranges are guaranteed to be sorted deterministically by offset, size, then stages.
+ /// This means that two slices containing the same elements will always have the same order.
+ #[inline]
+ pub fn push_constant_ranges(&self) -> &[PushConstantRange] {
+ &self.push_constant_ranges
+ }
+
+ /// Returns a slice containing the push constant ranges in with all disjoint stages.
+ ///
+ /// For example, if we have these `push_constant_ranges`:
+ /// - `offset=0, size=4, stages=vertex`
+ /// - `offset=0, size=12, stages=fragment`
+ ///
+ /// The returned value will be:
+ /// - `offset=0, size=4, stages=vertex|fragment`
+ /// - `offset=4, size=8, stages=fragment`
+ ///
+ /// The ranges are guaranteed to be sorted deterministically by offset, and
+ /// guaranteed to be disjoint, meaning that there is no overlap between the ranges.
+ #[inline]
+ pub(crate) fn push_constant_ranges_disjoint(&self) -> &[PushConstantRange] {
+ &self.push_constant_ranges_disjoint
+ }
+
+ /// Returns whether `self` is compatible with `other` for the given number of sets.
+ #[inline]
+ pub fn is_compatible_with(&self, other: &PipelineLayout, num_sets: u32) -> bool {
+ let num_sets = num_sets as usize;
+ assert!(num_sets >= self.set_layouts.len());
+
+ if self == other {
+ return true;
+ }
+
+ if self.push_constant_ranges != other.push_constant_ranges {
+ return false;
+ }
+
+ let other_sets = match other.set_layouts.get(0..num_sets) {
+ Some(x) => x,
+ None => return false,
+ };
+
+ self.set_layouts
+ .iter()
+ .zip(other_sets)
+ .all(|(self_set_layout, other_set_layout)| {
+ self_set_layout.is_compatible_with(other_set_layout)
+ })
+ }
+
+ /// Makes sure that `self` is a superset of the provided descriptor set layouts and push
+ /// constant ranges. Returns an `Err` if this is not the case.
+ pub fn ensure_compatible_with_shader<'a>(
+ &self,
+ descriptor_requirements: impl IntoIterator<
+ Item = ((u32, u32), &'a DescriptorBindingRequirements),
+ >,
+ push_constant_range: Option<&PushConstantRange>,
+ ) -> Result<(), PipelineLayoutSupersetError> {
+ for ((set_num, binding_num), reqs) in descriptor_requirements.into_iter() {
+ let layout_binding = self
+ .set_layouts
+ .get(set_num as usize)
+ .and_then(|set_layout| set_layout.bindings().get(&binding_num));
+
+ let layout_binding = match layout_binding {
+ Some(x) => x,
+ None => {
+ return Err(PipelineLayoutSupersetError::DescriptorMissing {
+ set_num,
+ binding_num,
+ })
+ }
+ };
+
+ if let Err(error) = layout_binding.ensure_compatible_with_shader(reqs) {
+ return Err(PipelineLayoutSupersetError::DescriptorRequirementsNotMet {
+ set_num,
+ binding_num,
+ error,
+ });
+ }
+ }
+
+ // FIXME: check push constants
+ if let Some(range) = push_constant_range {
+ for own_range in self.push_constant_ranges.iter() {
+ if range.stages.intersects(own_range.stages) && // check if it shares any stages
+ (range.offset < own_range.offset || // our range must start before and end after the given range
+ own_range.offset + own_range.size < range.offset + range.size)
+ {
+ return Err(PipelineLayoutSupersetError::PushConstantRange {
+ first_range: *own_range,
+ second_range: *range,
+ });
+ }
+ }
+ }
+
+ Ok(())
+ }
+}
+
+impl Drop for PipelineLayout {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ let fns = self.device.fns();
+ (fns.v1_0.destroy_pipeline_layout)(self.device.handle(), self.handle, ptr::null());
+ }
+ }
+}
+
+unsafe impl VulkanObject for PipelineLayout {
+ type Handle = ash::vk::PipelineLayout;
+
+ #[inline]
+ fn handle(&self) -> Self::Handle {
+ self.handle
+ }
+}
+
+unsafe impl DeviceOwned for PipelineLayout {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+}
+
+impl_id_counter!(PipelineLayout);
+
+/// Error that can happen when creating a pipeline layout.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum PipelineLayoutCreationError {
+ /// Not enough memory.
+ OomError(OomError),
+
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+
+ /// The number of elements in `set_layouts` is greater than the
+ /// [`max_bound_descriptor_sets`](crate::device::Properties::max_bound_descriptor_sets) limit.
+ MaxBoundDescriptorSetsExceeded { provided: u32, max_supported: u32 },
+
+ /// The `set_layouts` contain more [`DescriptorType::Sampler`],
+ /// [`DescriptorType::CombinedImageSampler`] and [`DescriptorType::UniformTexelBuffer`]
+ /// descriptors than the
+ /// [`max_descriptor_set_samplers`](crate::device::Properties::max_descriptor_set_samplers)
+ /// limit.
+ MaxDescriptorSetSamplersExceeded { provided: u32, max_supported: u32 },
+
+ /// The `set_layouts` contain more [`DescriptorType::UniformBuffer`] descriptors than the
+ /// [`max_descriptor_set_uniform_buffers`](crate::device::Properties::max_descriptor_set_uniform_buffers)
+ /// limit.
+ MaxDescriptorSetUniformBuffersExceeded { provided: u32, max_supported: u32 },
+
+ /// The `set_layouts` contain more [`DescriptorType::UniformBufferDynamic`] descriptors than the
+ /// [`max_descriptor_set_uniform_buffers_dynamic`](crate::device::Properties::max_descriptor_set_uniform_buffers_dynamic)
+ /// limit.
+ MaxDescriptorSetUniformBuffersDynamicExceeded { provided: u32, max_supported: u32 },
+
+ /// The `set_layouts` contain more [`DescriptorType::StorageBuffer`] descriptors than the
+ /// [`max_descriptor_set_storage_buffers`](crate::device::Properties::max_descriptor_set_storage_buffers)
+ /// limit.
+ MaxDescriptorSetStorageBuffersExceeded { provided: u32, max_supported: u32 },
+
+ /// The `set_layouts` contain more [`DescriptorType::StorageBufferDynamic`] descriptors than the
+ /// [`max_descriptor_set_storage_buffers_dynamic`](crate::device::Properties::max_descriptor_set_storage_buffers_dynamic)
+ /// limit.
+ MaxDescriptorSetStorageBuffersDynamicExceeded { provided: u32, max_supported: u32 },
+
+ /// The `set_layouts` contain more [`DescriptorType::SampledImage`] and
+ /// [`DescriptorType::CombinedImageSampler`] descriptors than the
+ /// [`max_descriptor_set_sampled_images`](crate::device::Properties::max_descriptor_set_sampled_images)
+ /// limit.
+ MaxDescriptorSetSampledImagesExceeded { provided: u32, max_supported: u32 },
+
+ /// The `set_layouts` contain more [`DescriptorType::StorageImage`] and
+ /// [`DescriptorType::StorageTexelBuffer`] descriptors than the
+ /// [`max_descriptor_set_storage_images`](crate::device::Properties::max_descriptor_set_storage_images)
+ /// limit.
+ MaxDescriptorSetStorageImagesExceeded { provided: u32, max_supported: u32 },
+
+ /// The `set_layouts` contain more [`DescriptorType::InputAttachment`] descriptors than the
+ /// [`max_descriptor_set_input_attachments`](crate::device::Properties::max_descriptor_set_input_attachments)
+ /// limit.
+ MaxDescriptorSetInputAttachmentsExceeded { provided: u32, max_supported: u32 },
+
+ /// The `set_layouts` contain more bound resources in a single stage than the
+ /// [`max_per_stage_resources`](crate::device::Properties::max_per_stage_resources)
+ /// limit.
+ MaxPerStageResourcesExceeded { provided: u32, max_supported: u32 },
+
+ /// The `set_layouts` contain more [`DescriptorType::Sampler`] and
+ /// [`DescriptorType::CombinedImageSampler`] descriptors in a single stage than the
+ /// [`max_per_stage_descriptor_samplers`](crate::device::Properties::max_per_stage_descriptor_samplers)
+ /// limit.
+ MaxPerStageDescriptorSamplersExceeded { provided: u32, max_supported: u32 },
+
+ /// The `set_layouts` contain more [`DescriptorType::UniformBuffer`] and
+ /// [`DescriptorType::UniformBufferDynamic`] descriptors in a single stage than the
+ /// [`max_per_stage_descriptor_uniform_buffers`](crate::device::Properties::max_per_stage_descriptor_uniform_buffers)
+ /// limit.
+ MaxPerStageDescriptorUniformBuffersExceeded { provided: u32, max_supported: u32 },
+
+ /// The `set_layouts` contain more [`DescriptorType::StorageBuffer`] and
+ /// [`DescriptorType::StorageBufferDynamic`] descriptors in a single stage than the
+ /// [`max_per_stage_descriptor_storage_buffers`](crate::device::Properties::max_per_stage_descriptor_storage_buffers)
+ /// limit.
+ MaxPerStageDescriptorStorageBuffersExceeded { provided: u32, max_supported: u32 },
+
+ /// The `set_layouts` contain more [`DescriptorType::SampledImage`],
+ /// [`DescriptorType::CombinedImageSampler`] and [`DescriptorType::UniformTexelBuffer`]
+ /// descriptors in a single stage than the
+ /// [`max_per_stage_descriptor_sampled_images`](crate::device::Properties::max_per_stage_descriptor_sampled_images)
+ /// limit.
+ MaxPerStageDescriptorSampledImagesExceeded { provided: u32, max_supported: u32 },
+
+ /// The `set_layouts` contain more [`DescriptorType::StorageImage`] and
+ /// [`DescriptorType::StorageTexelBuffer`] descriptors in a single stage than the
+ /// [`max_per_stage_descriptor_storage_images`](crate::device::Properties::max_per_stage_descriptor_storage_images)
+ /// limit.
+ MaxPerStageDescriptorStorageImagesExceeded { provided: u32, max_supported: u32 },
+
+ /// The `set_layouts` contain more [`DescriptorType::InputAttachment`] descriptors in a single
+ /// stage than the
+ /// [`max_per_stage_descriptor_input_attachments`](crate::device::Properties::max_per_stage_descriptor_input_attachments)
+ /// limit.
+ MaxPerStageDescriptorInputAttachmentsExceeded { provided: u32, max_supported: u32 },
+
+ /// An element in `push_constant_ranges` has an `offset + size` greater than the
+ /// [`max_push_constants_size`](crate::device::Properties::max_push_constants_size) limit.
+ MaxPushConstantsSizeExceeded { provided: u32, max_supported: u32 },
+
+ /// A shader stage appears in multiple elements of `push_constant_ranges`.
+ PushConstantRangesStageMultiple,
+
+ /// Multiple elements of `set_layouts` have `push_descriptor` enabled.
+ SetLayoutsPushDescriptorMultiple,
+}
+
+impl Error for PipelineLayoutCreationError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::OomError(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+impl Display for PipelineLayoutCreationError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::OomError(_) => write!(f, "not enough memory available"),
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ Self::MaxBoundDescriptorSetsExceeded {
+ provided,
+ max_supported,
+ } => write!(
+ f,
+ "the number of elements in `set_layouts` ({}) is greater than the \
+ `max_bound_descriptor_sets` limit ({})",
+ provided, max_supported,
+ ),
+ Self::MaxDescriptorSetSamplersExceeded {
+ provided,
+ max_supported,
+ } => write!(
+ f,
+ "the `set_layouts` contain more `DescriptorType::Sampler` and \
+ `DescriptorType::CombinedImageSampler` descriptors ({}) than the \
+ `max_descriptor_set_samplers` limit ({})",
+ provided, max_supported,
+ ),
+ Self::MaxDescriptorSetUniformBuffersExceeded {
+ provided,
+ max_supported,
+ } => write!(
+ f,
+ "the `set_layouts` contain more `DescriptorType::UniformBuffer` descriptors ({}) \
+ than the `max_descriptor_set_uniform_buffers` limit ({})",
+ provided, max_supported,
+ ),
+ Self::MaxDescriptorSetUniformBuffersDynamicExceeded {
+ provided,
+ max_supported,
+ } => write!(
+ f,
+ "the `set_layouts` contain more `DescriptorType::UniformBufferDynamic` descriptors \
+ ({}) than the `max_descriptor_set_uniform_buffers_dynamic` limit ({})",
+ provided, max_supported,
+ ),
+ Self::MaxDescriptorSetStorageBuffersExceeded {
+ provided,
+ max_supported,
+ } => write!(
+ f,
+ "the `set_layouts` contain more `DescriptorType::StorageBuffer` descriptors ({}) \
+ than the `max_descriptor_set_storage_buffers` limit ({})",
+ provided, max_supported,
+ ),
+ Self::MaxDescriptorSetStorageBuffersDynamicExceeded {
+ provided,
+ max_supported,
+ } => write!(
+ f,
+ "the `set_layouts` contain more `DescriptorType::StorageBufferDynamic` descriptors \
+ ({}) than the `max_descriptor_set_storage_buffers_dynamic` limit ({})",
+ provided, max_supported,
+ ),
+ Self::MaxDescriptorSetSampledImagesExceeded {
+ provided,
+ max_supported,
+ } => write!(
+ f,
+ "the `set_layouts` contain more `DescriptorType::SampledImage`, \
+ `DescriptorType::CombinedImageSampler` and `DescriptorType::UniformTexelBuffer` \
+ descriptors ({}) than the `max_descriptor_set_sampled_images` limit ({})",
+ provided, max_supported,
+ ),
+ Self::MaxDescriptorSetStorageImagesExceeded {
+ provided,
+ max_supported,
+ } => write!(
+ f,
+ "the `set_layouts` contain more `DescriptorType::StorageImage` and \
+ `DescriptorType::StorageTexelBuffer` descriptors ({}) than the \
+ `max_descriptor_set_storage_images` limit ({})",
+ provided, max_supported,
+ ),
+ Self::MaxDescriptorSetInputAttachmentsExceeded {
+ provided,
+ max_supported,
+ } => write!(
+ f,
+ "the `set_layouts` contain more `DescriptorType::InputAttachment` descriptors ({}) \
+ than the `max_descriptor_set_input_attachments` limit ({})",
+ provided, max_supported,
+ ),
+ Self::MaxPerStageResourcesExceeded {
+ provided,
+ max_supported,
+ } => write!(
+ f,
+ "the `set_layouts` contain more bound resources ({}) in a single stage than the \
+ `max_per_stage_resources` limit ({})",
+ provided, max_supported,
+ ),
+ Self::MaxPerStageDescriptorSamplersExceeded {
+ provided,
+ max_supported,
+ } => write!(
+ f,
+ "the `set_layouts` contain more `DescriptorType::Sampler` and \
+ `DescriptorType::CombinedImageSampler` descriptors ({}) in a single stage than the \
+ `max_per_stage_descriptor_set_samplers` limit ({})",
+ provided, max_supported,
+ ),
+ Self::MaxPerStageDescriptorUniformBuffersExceeded {
+ provided,
+ max_supported,
+ } => write!(
+ f,
+ "the `set_layouts` contain more `DescriptorType::UniformBuffer` and \
+ `DescriptorType::UniformBufferDynamic` descriptors ({}) in a single stage than the \
+ `max_per_stage_descriptor_set_uniform_buffers` limit ({})",
+ provided, max_supported,
+ ),
+ Self::MaxPerStageDescriptorStorageBuffersExceeded {
+ provided,
+ max_supported,
+ } => write!(
+ f,
+ "the `set_layouts` contain more `DescriptorType::StorageBuffer` and \
+ `DescriptorType::StorageBufferDynamic` descriptors ({}) in a single stage than the \
+ `max_per_stage_descriptor_set_storage_buffers` limit ({})",
+ provided, max_supported,
+ ),
+ Self::MaxPerStageDescriptorSampledImagesExceeded {
+ provided,
+ max_supported,
+ } => write!(
+ f,
+ "the `set_layouts` contain more `DescriptorType::SampledImage`, \
+ `DescriptorType::CombinedImageSampler` and `DescriptorType::UniformTexelBuffer` \
+ descriptors ({}) in a single stage than the \
+ `max_per_stage_descriptor_set_sampled_images` limit ({})",
+ provided, max_supported,
+ ),
+ Self::MaxPerStageDescriptorStorageImagesExceeded {
+ provided,
+ max_supported,
+ } => write!(
+ f,
+ "the `set_layouts` contain more `DescriptorType::StorageImage` and \
+ `DescriptorType::StorageTexelBuffer` descriptors ({}) in a single stage than the \
+ `max_per_stage_descriptor_set_storage_images` limit ({})",
+ provided, max_supported,
+ ),
+ Self::MaxPerStageDescriptorInputAttachmentsExceeded {
+ provided,
+ max_supported,
+ } => write!(
+ f,
+ "the `set_layouts` contain more `DescriptorType::InputAttachment` descriptors ({}) \
+ in a single stage than the `max_per_stage_descriptor_set_input_attachments` limit \
+ ({})",
+ provided, max_supported,
+ ),
+ Self::MaxPushConstantsSizeExceeded {
+ provided,
+ max_supported,
+ } => write!(
+ f,
+ "an element in `push_constant_ranges` has an `offset + size` ({}) greater than the \
+ `max_push_constants_size` limit ({})",
+ provided, max_supported,
+ ),
+ Self::PushConstantRangesStageMultiple => write!(
+ f,
+ "a shader stage appears in multiple elements of `push_constant_ranges`",
+ ),
+ Self::SetLayoutsPushDescriptorMultiple => write!(
+ f,
+ "multiple elements of `set_layouts` have `push_descriptor` enabled",
+ ),
+ }
+ }
+}
+
+impl From<OomError> for PipelineLayoutCreationError {
+ fn from(err: OomError) -> PipelineLayoutCreationError {
+ PipelineLayoutCreationError::OomError(err)
+ }
+}
+
+impl From<VulkanError> for PipelineLayoutCreationError {
+ fn from(err: VulkanError) -> PipelineLayoutCreationError {
+ match err {
+ err @ VulkanError::OutOfHostMemory => {
+ PipelineLayoutCreationError::OomError(OomError::from(err))
+ }
+ err @ VulkanError::OutOfDeviceMemory => {
+ PipelineLayoutCreationError::OomError(OomError::from(err))
+ }
+ _ => panic!("unexpected error: {:?}", err),
+ }
+ }
+}
+
+impl From<RequirementNotMet> for PipelineLayoutCreationError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
+ }
+ }
+}
+
+/// Error when checking whether a pipeline layout is a superset of another one.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum PipelineLayoutSupersetError {
+ DescriptorMissing {
+ set_num: u32,
+ binding_num: u32,
+ },
+ DescriptorRequirementsNotMet {
+ set_num: u32,
+ binding_num: u32,
+ error: DescriptorRequirementsNotMet,
+ },
+ PushConstantRange {
+ first_range: PushConstantRange,
+ second_range: PushConstantRange,
+ },
+}
+
+impl Error for PipelineLayoutSupersetError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ PipelineLayoutSupersetError::DescriptorRequirementsNotMet { error, .. } => Some(error),
+ _ => None,
+ }
+ }
+}
+
+impl Display for PipelineLayoutSupersetError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ PipelineLayoutSupersetError::DescriptorRequirementsNotMet {
+ set_num,
+ binding_num,
+ ..
+ } => write!(
+ f,
+ "the descriptor at set {} binding {} does not meet the requirements",
+ set_num, binding_num,
+ ),
+ PipelineLayoutSupersetError::DescriptorMissing {
+ set_num,
+ binding_num,
+ } => write!(
+ f,
+ "a descriptor at set {} binding {} is required by the shaders, but is missing from \
+ the pipeline layout",
+ set_num, binding_num,
+ ),
+ PipelineLayoutSupersetError::PushConstantRange {
+ first_range,
+ second_range,
+ } => {
+ writeln!(f, "our range did not completely encompass the other range")?;
+ writeln!(f, " our stages: {:?}", first_range.stages)?;
+ writeln!(
+ f,
+ " our range: {} - {}",
+ first_range.offset,
+ first_range.offset + first_range.size,
+ )?;
+ writeln!(f, " other stages: {:?}", second_range.stages)?;
+ write!(
+ f,
+ " other range: {} - {}",
+ second_range.offset,
+ second_range.offset + second_range.size,
+ )
+ }
+ }
+ }
+}
+
+/// Parameters to create a new `PipelineLayout`.
+#[derive(Clone, Debug)]
+pub struct PipelineLayoutCreateInfo {
+ /// The descriptor set layouts that should be part of the pipeline layout.
+ ///
+ /// They are provided in order of set number.
+ ///
+ /// The default value is empty.
+ pub set_layouts: Vec<Arc<DescriptorSetLayout>>,
+
+ /// The ranges of push constants that the pipeline will access.
+ ///
+ /// A shader stage can only appear in one element of the list, but it is possible to combine
+ /// ranges for multiple shader stages if they are the same.
+ ///
+ /// The default value is empty.
+ pub push_constant_ranges: Vec<PushConstantRange>,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for PipelineLayoutCreateInfo {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ set_layouts: Vec::new(),
+ push_constant_ranges: Vec::new(),
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// Description of a range of the push constants of a pipeline layout.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub struct PushConstantRange {
+ /// The stages which can access this range. A stage can access at most one push constant range.
+ ///
+ /// The default value is [`ShaderStages::empty()`], which must be overridden.
+ pub stages: ShaderStages,
+
+ /// Offset in bytes from the start of the push constants to this range.
+ ///
+ /// The value must be a multiple of 4.
+ ///
+ /// The default value is `0`.
+ pub offset: u32,
+
+ /// Size in bytes of the range.
+ ///
+ /// The value must be a multiple of 4, and not 0.
+ ///
+ /// The default value is `0`, which must be overridden.
+ pub size: u32,
+}
+
+impl Default for PushConstantRange {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ stages: ShaderStages::empty(),
+ offset: 0,
+ size: 0,
+ }
+ }
+}
+
+// Helper struct for the main function.
+#[derive(Default)]
+struct Counter {
+ total: u32,
+ compute: u32,
+ vertex: u32,
+ geometry: u32,
+ tess_ctl: u32,
+ tess_eval: u32,
+ frag: u32,
+}
+
+impl Counter {
+ fn increment(&mut self, num: u32, stages: ShaderStages) {
+ self.total += num;
+ if stages.intersects(ShaderStages::COMPUTE) {
+ self.compute += num;
+ }
+ if stages.intersects(ShaderStages::VERTEX) {
+ self.vertex += num;
+ }
+ if stages.intersects(ShaderStages::TESSELLATION_CONTROL) {
+ self.tess_ctl += num;
+ }
+ if stages.intersects(ShaderStages::TESSELLATION_EVALUATION) {
+ self.tess_eval += num;
+ }
+ if stages.intersects(ShaderStages::GEOMETRY) {
+ self.geometry += num;
+ }
+ if stages.intersects(ShaderStages::FRAGMENT) {
+ self.frag += num;
+ }
+ }
+
+ fn max_per_stage(&self) -> u32 {
+ [
+ self.compute,
+ self.vertex,
+ self.tess_ctl,
+ self.tess_eval,
+ self.geometry,
+ self.frag,
+ ]
+ .into_iter()
+ .max()
+ .unwrap_or(0)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+
+ use super::PipelineLayout;
+ use crate::{
+ pipeline::layout::{PipelineLayoutCreateInfo, PushConstantRange},
+ shader::ShaderStages,
+ };
+
+ #[test]
+ fn push_constant_ranges_disjoint() {
+ let test_cases = [
+ // input:
+ // - `0..12`, stage=fragment
+ // - `0..40`, stage=vertex
+ //
+ // output:
+ // - `0..12`, stage=fragment|vertex
+ // - `12..40`, stage=vertex
+ (
+ &[
+ PushConstantRange {
+ stages: ShaderStages::FRAGMENT,
+ offset: 0,
+ size: 12,
+ },
+ PushConstantRange {
+ stages: ShaderStages::VERTEX,
+ offset: 0,
+ size: 40,
+ },
+ ][..],
+ &[
+ PushConstantRange {
+ stages: ShaderStages::VERTEX | ShaderStages::FRAGMENT,
+ offset: 0,
+ size: 12,
+ },
+ PushConstantRange {
+ stages: ShaderStages::VERTEX,
+ offset: 12,
+ size: 28,
+ },
+ ][..],
+ ),
+ // input:
+ // - `0..12`, stage=fragment
+ // - `4..40`, stage=vertex
+ //
+ // output:
+ // - `0..4`, stage=fragment
+ // - `4..12`, stage=fragment|vertex
+ // - `12..40`, stage=vertex
+ (
+ &[
+ PushConstantRange {
+ stages: ShaderStages::FRAGMENT,
+ offset: 0,
+ size: 12,
+ },
+ PushConstantRange {
+ stages: ShaderStages::VERTEX,
+ offset: 4,
+ size: 36,
+ },
+ ][..],
+ &[
+ PushConstantRange {
+ stages: ShaderStages::FRAGMENT,
+ offset: 0,
+ size: 4,
+ },
+ PushConstantRange {
+ stages: ShaderStages::FRAGMENT | ShaderStages::VERTEX,
+ offset: 4,
+ size: 8,
+ },
+ PushConstantRange {
+ stages: ShaderStages::VERTEX,
+ offset: 12,
+ size: 28,
+ },
+ ][..],
+ ),
+ // input:
+ // - `0..12`, stage=fragment
+ // - `8..20`, stage=compute
+ // - `4..16`, stage=vertex
+ // - `8..32`, stage=tess_ctl
+ //
+ // output:
+ // - `0..4`, stage=fragment
+ // - `4..8`, stage=fragment|vertex
+ // - `8..16`, stage=fragment|vertex|compute|tess_ctl
+ // - `16..20`, stage=compute|tess_ctl
+ // - `20..32` stage=tess_ctl
+ (
+ &[
+ PushConstantRange {
+ stages: ShaderStages::FRAGMENT,
+ offset: 0,
+ size: 12,
+ },
+ PushConstantRange {
+ stages: ShaderStages::COMPUTE,
+ offset: 8,
+ size: 12,
+ },
+ PushConstantRange {
+ stages: ShaderStages::VERTEX,
+ offset: 4,
+ size: 12,
+ },
+ PushConstantRange {
+ stages: ShaderStages::TESSELLATION_CONTROL,
+ offset: 8,
+ size: 24,
+ },
+ ][..],
+ &[
+ PushConstantRange {
+ stages: ShaderStages::FRAGMENT,
+ offset: 0,
+ size: 4,
+ },
+ PushConstantRange {
+ stages: ShaderStages::FRAGMENT | ShaderStages::VERTEX,
+ offset: 4,
+ size: 4,
+ },
+ PushConstantRange {
+ stages: ShaderStages::VERTEX
+ | ShaderStages::FRAGMENT
+ | ShaderStages::COMPUTE
+ | ShaderStages::TESSELLATION_CONTROL,
+ offset: 8,
+ size: 4,
+ },
+ PushConstantRange {
+ stages: ShaderStages::VERTEX
+ | ShaderStages::COMPUTE
+ | ShaderStages::TESSELLATION_CONTROL,
+ offset: 12,
+ size: 4,
+ },
+ PushConstantRange {
+ stages: ShaderStages::COMPUTE | ShaderStages::TESSELLATION_CONTROL,
+ offset: 16,
+ size: 4,
+ },
+ PushConstantRange {
+ stages: ShaderStages::TESSELLATION_CONTROL,
+ offset: 20,
+ size: 12,
+ },
+ ][..],
+ ),
+ ];
+
+ let (device, _) = gfx_dev_and_queue!();
+
+ for (input, expected) in test_cases {
+ let layout = PipelineLayout::new(
+ device.clone(),
+ PipelineLayoutCreateInfo {
+ push_constant_ranges: input.into(),
+ ..Default::default()
+ },
+ )
+ .unwrap();
+
+ assert_eq!(layout.push_constant_ranges_disjoint.as_slice(), expected);
+ }
+ }
+}
+
+/* TODO: restore
+#[cfg(test)]
+mod tests {
+ use std::iter;
+ use std::sync::Arc;
+ use descriptor::descriptor::ShaderStages;
+ use descriptor::descriptor_set::DescriptorSetLayout;
+ use descriptor::pipeline_layout::sys::PipelineLayout;
+ use descriptor::pipeline_layout::sys::PipelineLayoutCreationError;
+
+ #[test]
+ fn empty() {
+ let (device, _) = gfx_dev_and_queue!();
+ let _layout = PipelineLayout::new(&device, iter::empty(), iter::empty()).unwrap();
+ }
+
+ #[test]
+ fn wrong_device_panic() {
+ let (device1, _) = gfx_dev_and_queue!();
+ let (device2, _) = gfx_dev_and_queue!();
+
+ let set = match DescriptorSetLayout::raw(device1, iter::empty()) {
+ Ok(s) => Arc::new(s),
+ Err(_) => return
+ };
+
+ assert_should_panic!({
+ let _ = PipelineLayout::new(&device2, Some(&set), iter::empty());
+ });
+ }
+
+ #[test]
+ fn invalid_push_constant_stages() {
+ let (device, _) = gfx_dev_and_queue!();
+
+ let push_constant = (0, 8, ShaderStages::empty());
+
+ match PipelineLayout::new(&device, iter::empty(), Some(push_constant)) {
+ Err(PipelineLayoutCreationError::InvalidPushConstant) => (),
+ _ => panic!()
+ }
+ }
+
+ #[test]
+ fn invalid_push_constant_size1() {
+ let (device, _) = gfx_dev_and_queue!();
+
+ let push_constant = (0, 0, ShaderStages::all_graphics());
+
+ match PipelineLayout::new(&device, iter::empty(), Some(push_constant)) {
+ Err(PipelineLayoutCreationError::InvalidPushConstant) => (),
+ _ => panic!()
+ }
+ }
+
+ #[test]
+ fn invalid_push_constant_size2() {
+ let (device, _) = gfx_dev_and_queue!();
+
+ let push_constant = (0, 11, ShaderStages::all_graphics());
+
+ match PipelineLayout::new(&device, iter::empty(), Some(push_constant)) {
+ Err(PipelineLayoutCreationError::InvalidPushConstant) => (),
+ _ => panic!()
+ }
+ }
+}
+*/
diff --git a/src/pipeline/layout/limits_check.rs b/src/pipeline/layout/limits_check.rs
deleted file mode 100644
index 8f98f26..0000000
--- a/src/pipeline/layout/limits_check.rs
+++ /dev/null
@@ -1,513 +0,0 @@
-// Copyright (c) 2017 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-//! Contains the `check_desc_against_limits` function and the `PipelineLayoutLimitsError` error.
-
-use crate::descriptor_set::layout::DescriptorSetLayout;
-use crate::descriptor_set::layout::DescriptorType;
-use crate::device::Properties;
-use crate::pipeline::layout::PipelineLayoutPcRange;
-use crate::pipeline::shader::ShaderStages;
-use std::error;
-use std::fmt;
-use std::sync::Arc;
-
-/// Checks whether the pipeline layout description fulfills the device limits requirements.
-pub fn check_desc_against_limits(
- properties: &Properties,
- descriptor_set_layouts: &[Arc<DescriptorSetLayout>],
- push_constants_ranges: &[PipelineLayoutPcRange],
-) -> Result<(), PipelineLayoutLimitsError> {
- let mut num_resources = Counter::default();
- let mut num_samplers = Counter::default();
- let mut num_uniform_buffers = Counter::default();
- let mut num_uniform_buffers_dynamic = 0;
- let mut num_storage_buffers = Counter::default();
- let mut num_storage_buffers_dynamic = 0;
- let mut num_sampled_images = Counter::default();
- let mut num_storage_images = Counter::default();
- let mut num_input_attachments = Counter::default();
-
- for set in descriptor_set_layouts {
- for descriptor in (0..set.num_bindings()).filter_map(|i| set.descriptor(i).map(|d| d)) {
- num_resources.increment(descriptor.array_count, &descriptor.stages);
-
- match descriptor.ty.ty() {
- // TODO:
- DescriptorType::Sampler => {
- num_samplers.increment(descriptor.array_count, &descriptor.stages);
- }
- DescriptorType::CombinedImageSampler => {
- num_samplers.increment(descriptor.array_count, &descriptor.stages);
- num_sampled_images.increment(descriptor.array_count, &descriptor.stages);
- }
- DescriptorType::SampledImage | DescriptorType::UniformTexelBuffer => {
- num_sampled_images.increment(descriptor.array_count, &descriptor.stages);
- }
- DescriptorType::StorageImage | DescriptorType::StorageTexelBuffer => {
- num_storage_images.increment(descriptor.array_count, &descriptor.stages);
- }
- DescriptorType::UniformBuffer => {
- num_uniform_buffers.increment(descriptor.array_count, &descriptor.stages);
- }
- DescriptorType::UniformBufferDynamic => {
- num_uniform_buffers.increment(descriptor.array_count, &descriptor.stages);
- num_uniform_buffers_dynamic += 1;
- }
- DescriptorType::StorageBuffer => {
- num_storage_buffers.increment(descriptor.array_count, &descriptor.stages);
- }
- DescriptorType::StorageBufferDynamic => {
- num_storage_buffers.increment(descriptor.array_count, &descriptor.stages);
- num_storage_buffers_dynamic += 1;
- }
- DescriptorType::InputAttachment => {
- num_input_attachments.increment(descriptor.array_count, &descriptor.stages);
- }
- }
- }
- }
-
- if descriptor_set_layouts.len() > properties.max_bound_descriptor_sets as usize {
- return Err(PipelineLayoutLimitsError::MaxDescriptorSetsLimitExceeded {
- limit: properties.max_bound_descriptor_sets as usize,
- requested: descriptor_set_layouts.len(),
- });
- }
-
- if num_resources.max_per_stage() > properties.max_per_stage_resources {
- return Err(
- PipelineLayoutLimitsError::MaxPerStageResourcesLimitExceeded {
- limit: properties.max_per_stage_resources,
- requested: num_resources.max_per_stage(),
- },
- );
- }
-
- if num_samplers.max_per_stage() > properties.max_per_stage_descriptor_samplers {
- return Err(
- PipelineLayoutLimitsError::MaxPerStageDescriptorSamplersLimitExceeded {
- limit: properties.max_per_stage_descriptor_samplers,
- requested: num_samplers.max_per_stage(),
- },
- );
- }
- if num_uniform_buffers.max_per_stage()
- > properties.max_per_stage_descriptor_uniform_buffers
- {
- return Err(
- PipelineLayoutLimitsError::MaxPerStageDescriptorUniformBuffersLimitExceeded {
- limit: properties.max_per_stage_descriptor_uniform_buffers,
- requested: num_uniform_buffers.max_per_stage(),
- },
- );
- }
- if num_storage_buffers.max_per_stage()
- > properties.max_per_stage_descriptor_storage_buffers
- {
- return Err(
- PipelineLayoutLimitsError::MaxPerStageDescriptorStorageBuffersLimitExceeded {
- limit: properties.max_per_stage_descriptor_storage_buffers,
- requested: num_storage_buffers.max_per_stage(),
- },
- );
- }
- if num_sampled_images.max_per_stage()
- > properties.max_per_stage_descriptor_sampled_images
- {
- return Err(
- PipelineLayoutLimitsError::MaxPerStageDescriptorSampledImagesLimitExceeded {
- limit: properties.max_per_stage_descriptor_sampled_images,
- requested: num_sampled_images.max_per_stage(),
- },
- );
- }
- if num_storage_images.max_per_stage()
- > properties.max_per_stage_descriptor_storage_images
- {
- return Err(
- PipelineLayoutLimitsError::MaxPerStageDescriptorStorageImagesLimitExceeded {
- limit: properties.max_per_stage_descriptor_storage_images,
- requested: num_storage_images.max_per_stage(),
- },
- );
- }
- if num_input_attachments.max_per_stage()
- > properties
- .max_per_stage_descriptor_input_attachments
- {
- return Err(
- PipelineLayoutLimitsError::MaxPerStageDescriptorInputAttachmentsLimitExceeded {
- limit: properties
- .max_per_stage_descriptor_input_attachments,
- requested: num_input_attachments.max_per_stage(),
- },
- );
- }
-
- if num_samplers.total > properties.max_descriptor_set_samplers {
- return Err(
- PipelineLayoutLimitsError::MaxDescriptorSetSamplersLimitExceeded {
- limit: properties.max_descriptor_set_samplers,
- requested: num_samplers.total,
- },
- );
- }
- if num_uniform_buffers.total > properties.max_descriptor_set_uniform_buffers {
- return Err(
- PipelineLayoutLimitsError::MaxDescriptorSetUniformBuffersLimitExceeded {
- limit: properties.max_descriptor_set_uniform_buffers,
- requested: num_uniform_buffers.total,
- },
- );
- }
- if num_uniform_buffers_dynamic
- > properties
- .max_descriptor_set_uniform_buffers_dynamic
- {
- return Err(
- PipelineLayoutLimitsError::MaxDescriptorSetUniformBuffersDynamicLimitExceeded {
- limit: properties
- .max_descriptor_set_uniform_buffers_dynamic,
- requested: num_uniform_buffers_dynamic,
- },
- );
- }
- if num_storage_buffers.total > properties.max_descriptor_set_storage_buffers {
- return Err(
- PipelineLayoutLimitsError::MaxDescriptorSetStorageBuffersLimitExceeded {
- limit: properties.max_descriptor_set_storage_buffers,
- requested: num_storage_buffers.total,
- },
- );
- }
- if num_storage_buffers_dynamic
- > properties
- .max_descriptor_set_storage_buffers_dynamic
- {
- return Err(
- PipelineLayoutLimitsError::MaxDescriptorSetStorageBuffersDynamicLimitExceeded {
- limit: properties
- .max_descriptor_set_storage_buffers_dynamic,
- requested: num_storage_buffers_dynamic,
- },
- );
- }
- if num_sampled_images.total > properties.max_descriptor_set_sampled_images {
- return Err(
- PipelineLayoutLimitsError::MaxDescriptorSetSampledImagesLimitExceeded {
- limit: properties.max_descriptor_set_sampled_images,
- requested: num_sampled_images.total,
- },
- );
- }
- if num_storage_images.total > properties.max_descriptor_set_storage_images {
- return Err(
- PipelineLayoutLimitsError::MaxDescriptorSetStorageImagesLimitExceeded {
- limit: properties.max_descriptor_set_storage_images,
- requested: num_storage_images.total,
- },
- );
- }
- if num_input_attachments.total > properties.max_descriptor_set_input_attachments {
- return Err(
- PipelineLayoutLimitsError::MaxDescriptorSetInputAttachmentsLimitExceeded {
- limit: properties.max_descriptor_set_input_attachments,
- requested: num_input_attachments.total,
- },
- );
- }
-
- for &PipelineLayoutPcRange { offset, size, .. } in push_constants_ranges {
- if offset + size > properties.max_push_constants_size as usize {
- return Err(PipelineLayoutLimitsError::MaxPushConstantsSizeExceeded {
- limit: properties.max_push_constants_size as usize,
- requested: offset + size,
- });
- }
- }
-
- Ok(())
-}
-
-/// The pipeline layout description isn't compatible with the hardware limits.
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum PipelineLayoutLimitsError {
- /// The maximum number of descriptor sets has been exceeded.
- MaxDescriptorSetsLimitExceeded {
- /// The limit that must be fulfilled.
- limit: usize,
- /// What was requested.
- requested: usize,
- },
-
- /// The maximum size of push constants has been exceeded.
- MaxPushConstantsSizeExceeded {
- /// The limit that must be fulfilled.
- limit: usize,
- /// What was requested.
- requested: usize,
- },
-
- /// The `max_per_stage_resources()` limit has been exceeded.
- MaxPerStageResourcesLimitExceeded {
- /// The limit that must be fulfilled.
- limit: u32,
- /// What was requested.
- requested: u32,
- },
-
- /// The `max_per_stage_descriptor_samplers()` limit has been exceeded.
- MaxPerStageDescriptorSamplersLimitExceeded {
- /// The limit that must be fulfilled.
- limit: u32,
- /// What was requested.
- requested: u32,
- },
-
- /// The `max_per_stage_descriptor_uniform_buffers()` limit has been exceeded.
- MaxPerStageDescriptorUniformBuffersLimitExceeded {
- /// The limit that must be fulfilled.
- limit: u32,
- /// What was requested.
- requested: u32,
- },
-
- /// The `max_per_stage_descriptor_storage_buffers()` limit has been exceeded.
- MaxPerStageDescriptorStorageBuffersLimitExceeded {
- /// The limit that must be fulfilled.
- limit: u32,
- /// What was requested.
- requested: u32,
- },
-
- /// The `max_per_stage_descriptor_sampled_images()` limit has been exceeded.
- MaxPerStageDescriptorSampledImagesLimitExceeded {
- /// The limit that must be fulfilled.
- limit: u32,
- /// What was requested.
- requested: u32,
- },
-
- /// The `max_per_stage_descriptor_storage_images()` limit has been exceeded.
- MaxPerStageDescriptorStorageImagesLimitExceeded {
- /// The limit that must be fulfilled.
- limit: u32,
- /// What was requested.
- requested: u32,
- },
-
- /// The `max_per_stage_descriptor_input_attachments()` limit has been exceeded.
- MaxPerStageDescriptorInputAttachmentsLimitExceeded {
- /// The limit that must be fulfilled.
- limit: u32,
- /// What was requested.
- requested: u32,
- },
-
- /// The `max_descriptor_set_samplers()` limit has been exceeded.
- MaxDescriptorSetSamplersLimitExceeded {
- /// The limit that must be fulfilled.
- limit: u32,
- /// What was requested.
- requested: u32,
- },
-
- /// The `max_descriptor_set_uniform_buffers()` limit has been exceeded.
- MaxDescriptorSetUniformBuffersLimitExceeded {
- /// The limit that must be fulfilled.
- limit: u32,
- /// What was requested.
- requested: u32,
- },
-
- /// The `max_descriptor_set_uniform_buffers_dynamic()` limit has been exceeded.
- MaxDescriptorSetUniformBuffersDynamicLimitExceeded {
- /// The limit that must be fulfilled.
- limit: u32,
- /// What was requested.
- requested: u32,
- },
-
- /// The `max_descriptor_set_storage_buffers()` limit has been exceeded.
- MaxDescriptorSetStorageBuffersLimitExceeded {
- /// The limit that must be fulfilled.
- limit: u32,
- /// What was requested.
- requested: u32,
- },
-
- /// The `max_descriptor_set_storage_buffers_dynamic()` limit has been exceeded.
- MaxDescriptorSetStorageBuffersDynamicLimitExceeded {
- /// The limit that must be fulfilled.
- limit: u32,
- /// What was requested.
- requested: u32,
- },
-
- /// The `max_descriptor_set_sampled_images()` limit has been exceeded.
- MaxDescriptorSetSampledImagesLimitExceeded {
- /// The limit that must be fulfilled.
- limit: u32,
- /// What was requested.
- requested: u32,
- },
-
- /// The `max_descriptor_set_storage_images()` limit has been exceeded.
- MaxDescriptorSetStorageImagesLimitExceeded {
- /// The limit that must be fulfilled.
- limit: u32,
- /// What was requested.
- requested: u32,
- },
-
- /// The `max_descriptor_set_input_attachments()` limit has been exceeded.
- MaxDescriptorSetInputAttachmentsLimitExceeded {
- /// The limit that must be fulfilled.
- limit: u32,
- /// What was requested.
- requested: u32,
- },
-}
-
-impl error::Error for PipelineLayoutLimitsError {}
-
-impl fmt::Display for PipelineLayoutLimitsError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- PipelineLayoutLimitsError::MaxDescriptorSetsLimitExceeded { .. } => {
- "the maximum number of descriptor sets has been exceeded"
- }
- PipelineLayoutLimitsError::MaxPushConstantsSizeExceeded { .. } => {
- "the maximum size of push constants has been exceeded"
- }
- PipelineLayoutLimitsError::MaxPerStageResourcesLimitExceeded { .. } => {
- "the `max_per_stage_resources()` limit has been exceeded"
- }
- PipelineLayoutLimitsError::MaxPerStageDescriptorSamplersLimitExceeded {
- ..
- } => {
- "the `max_per_stage_descriptor_samplers()` limit has been exceeded"
- }
- PipelineLayoutLimitsError::MaxPerStageDescriptorUniformBuffersLimitExceeded {
- ..
- } => "the `max_per_stage_descriptor_uniform_buffers()` limit has been exceeded",
- PipelineLayoutLimitsError::MaxPerStageDescriptorStorageBuffersLimitExceeded {
- ..
- } => "the `max_per_stage_descriptor_storage_buffers()` limit has been exceeded",
- PipelineLayoutLimitsError::MaxPerStageDescriptorSampledImagesLimitExceeded {
- ..
- } => "the `max_per_stage_descriptor_sampled_images()` limit has been exceeded",
- PipelineLayoutLimitsError::MaxPerStageDescriptorStorageImagesLimitExceeded {
- ..
- } => "the `max_per_stage_descriptor_storage_images()` limit has been exceeded",
- PipelineLayoutLimitsError::MaxPerStageDescriptorInputAttachmentsLimitExceeded {
- ..
- } => "the `max_per_stage_descriptor_input_attachments()` limit has been exceeded",
- PipelineLayoutLimitsError::MaxDescriptorSetSamplersLimitExceeded { .. } => {
- "the `max_descriptor_set_samplers()` limit has been exceeded"
- }
- PipelineLayoutLimitsError::MaxDescriptorSetUniformBuffersLimitExceeded {
- ..
- } => {
- "the `max_descriptor_set_uniform_buffers()` limit has been exceeded"
- }
- PipelineLayoutLimitsError::MaxDescriptorSetUniformBuffersDynamicLimitExceeded {
- ..
- } => "the `max_descriptor_set_uniform_buffers_dynamic()` limit has been exceeded",
- PipelineLayoutLimitsError::MaxDescriptorSetStorageBuffersLimitExceeded {
- ..
- } => {
- "the `max_descriptor_set_storage_buffers()` limit has been exceeded"
- }
- PipelineLayoutLimitsError::MaxDescriptorSetStorageBuffersDynamicLimitExceeded {
- ..
- } => "the `max_descriptor_set_storage_buffers_dynamic()` limit has been exceeded",
- PipelineLayoutLimitsError::MaxDescriptorSetSampledImagesLimitExceeded {
- ..
- } => {
- "the `max_descriptor_set_sampled_images()` limit has been exceeded"
- }
- PipelineLayoutLimitsError::MaxDescriptorSetStorageImagesLimitExceeded {
- ..
- } => {
- "the `max_descriptor_set_storage_images()` limit has been exceeded"
- }
- PipelineLayoutLimitsError::MaxDescriptorSetInputAttachmentsLimitExceeded {
- ..
- } => {
- "the `max_descriptor_set_input_attachments()` limit has been exceeded"
- }
- }
- )
- }
-}
-
-// Helper struct for the main function.
-#[derive(Default)]
-struct Counter {
- total: u32,
- compute: u32,
- vertex: u32,
- geometry: u32,
- tess_ctl: u32,
- tess_eval: u32,
- frag: u32,
-}
-
-impl Counter {
- fn increment(&mut self, num: u32, stages: &ShaderStages) {
- self.total += num;
- if stages.compute {
- self.compute += num;
- }
- if stages.vertex {
- self.vertex += num;
- }
- if stages.tessellation_control {
- self.tess_ctl += num;
- }
- if stages.tessellation_evaluation {
- self.tess_eval += num;
- }
- if stages.geometry {
- self.geometry += num;
- }
- if stages.fragment {
- self.frag += num;
- }
- }
-
- fn max_per_stage(&self) -> u32 {
- let mut max = 0;
- if self.compute > max {
- max = self.compute;
- }
- if self.vertex > max {
- max = self.vertex;
- }
- if self.geometry > max {
- max = self.geometry;
- }
- if self.tess_ctl > max {
- max = self.tess_ctl;
- }
- if self.tess_eval > max {
- max = self.tess_eval;
- }
- if self.frag > max {
- max = self.frag;
- }
- max
- }
-}
diff --git a/src/pipeline/layout/mod.rs b/src/pipeline/layout/mod.rs
deleted file mode 100644
index c475d0a..0000000
--- a/src/pipeline/layout/mod.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-//! A pipeline layout describes the layout of descriptors and push constants used by a graphics
-//! pipeline or a compute pipeline.
-//!
-//! The layout itself only *describes* the descriptors and push constants, and does not contain
-//! the content of the push constants or the actual list of resources that are going to be
-//! available through the descriptors. Push constants are set when you submit a draw command, and
-//! the list of resources is set by creating *descriptor set* objects and passing these sets when
-//! you submit a draw command.
-//!
-//! # Pipeline layout objects
-//!
-//! A pipeline layout is something that you must describe to the Vulkan implementation by creating
-//! a **pipeline layout object**, represented by the `PipelineLayout` struct in vulkano.
-//!
-//! Each graphics pipeline or compute pipeline that you create therefore holds a
-//! **pipeline layout object** By default, creating a pipeline automatically builds a new pipeline
-//! layout object describing the union of all the descriptors and push constants of all the shaders
-//! used by the pipeline.
-//!
-//! The `PipelineLayout` struct describes the pipeline layout to both the Vulkan implementation and
-//! to vulkano. It holds a `PipelineLayoutDesc` value.
-//!
-//! # Custom pipeline layouts
-//!
-//! In some situations, it is better (as in, faster) to share the same descriptor set or sets
-//! between multiple pipelines that each use different descriptors. To do so, you have to create a
-//! pipeline layout object in advance and pass it when you create the pipelines.
-//!
-//! TODO: write this section
-
-pub use self::limits_check::PipelineLayoutLimitsError;
-pub use self::sys::PipelineLayout;
-pub use self::sys::PipelineLayoutCreationError;
-pub use self::sys::PipelineLayoutPcRange;
-pub use self::sys::PipelineLayoutSupersetError;
-
-mod limits_check;
-mod sys;
diff --git a/src/pipeline/layout/sys.rs b/src/pipeline/layout/sys.rs
deleted file mode 100644
index 7d6d33b..0000000
--- a/src/pipeline/layout/sys.rs
+++ /dev/null
@@ -1,469 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use super::limits_check;
-use crate::check_errors;
-use crate::descriptor_set::layout::DescriptorSetDesc;
-use crate::descriptor_set::layout::DescriptorSetDescSupersetError;
-use crate::descriptor_set::layout::DescriptorSetLayout;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::pipeline::layout::PipelineLayoutLimitsError;
-use crate::pipeline::shader::ShaderStages;
-use crate::Error;
-use crate::OomError;
-use crate::VulkanObject;
-use smallvec::SmallVec;
-use std::cmp;
-use std::error;
-use std::fmt;
-use std::mem::MaybeUninit;
-use std::ptr;
-use std::sync::Arc;
-
-/// Wrapper around the `PipelineLayout` Vulkan object. Describes to the Vulkan implementation the
-/// descriptor sets and push constants available to your shaders.
-pub struct PipelineLayout {
- handle: ash::vk::PipelineLayout,
- device: Arc<Device>,
- descriptor_set_layouts: SmallVec<[Arc<DescriptorSetLayout>; 16]>,
- push_constant_ranges: SmallVec<[PipelineLayoutPcRange; 8]>,
-}
-
-impl PipelineLayout {
- /// Creates a new `PipelineLayout`.
- #[inline]
- pub fn new<D, P>(
- device: Arc<Device>,
- descriptor_set_layouts: D,
- push_constant_ranges: P,
- ) -> Result<PipelineLayout, PipelineLayoutCreationError>
- where
- D: IntoIterator<Item = Arc<DescriptorSetLayout>>,
- P: IntoIterator<Item = PipelineLayoutPcRange>,
- {
- let fns = device.fns();
- let descriptor_set_layouts: SmallVec<[Arc<DescriptorSetLayout>; 16]> =
- descriptor_set_layouts.into_iter().collect();
- let push_constant_ranges: SmallVec<[PipelineLayoutPcRange; 8]> =
- push_constant_ranges.into_iter().collect();
-
- // Check for overlapping stages
- for (a_id, a) in push_constant_ranges.iter().enumerate() {
- for b in push_constant_ranges.iter().skip(a_id + 1) {
- if a.stages.intersects(&b.stages) {
- return Err(PipelineLayoutCreationError::PushConstantsConflict {
- first_range: *a,
- second_range: *b,
- });
- }
- }
- }
-
- // Check against device limits
- limits_check::check_desc_against_limits(
- device.physical_device().properties(),
- &descriptor_set_layouts,
- &push_constant_ranges,
- )?;
-
- // Grab the list of `vkDescriptorSetLayout` objects from `layouts`.
- let layouts_ids = descriptor_set_layouts
- .iter()
- .map(|l| l.internal_object())
- .collect::<SmallVec<[_; 16]>>();
-
- // Builds a list of `vkPushConstantRange` that describe the push constants.
- let push_constants = {
- let mut out: SmallVec<[_; 8]> = SmallVec::new();
-
- for &PipelineLayoutPcRange {
- offset,
- size,
- stages,
- } in &push_constant_ranges
- {
- if stages == ShaderStages::none() || size == 0 || (size % 4) != 0 {
- return Err(PipelineLayoutCreationError::InvalidPushConstant);
- }
-
- out.push(ash::vk::PushConstantRange {
- stage_flags: stages.into(),
- offset: offset as u32,
- size: size as u32,
- });
- }
-
- out
- };
-
- // Each bit of `stageFlags` must only be present in a single push constants range.
- // We check that with a debug_assert because it's supposed to be enforced by the
- // `PipelineLayoutDesc`.
- debug_assert!({
- let mut stages = ash::vk::ShaderStageFlags::empty();
- let mut outcome = true;
- for pc in push_constants.iter() {
- if !(stages & pc.stage_flags).is_empty() {
- outcome = false;
- break;
- }
- stages &= pc.stage_flags;
- }
- outcome
- });
-
- // FIXME: it is not legal to pass eg. the TESSELLATION_SHADER bit when the device doesn't
- // have tess shaders enabled
-
- // Build the final object.
- let handle = unsafe {
- let infos = ash::vk::PipelineLayoutCreateInfo {
- flags: ash::vk::PipelineLayoutCreateFlags::empty(),
- set_layout_count: layouts_ids.len() as u32,
- p_set_layouts: layouts_ids.as_ptr(),
- push_constant_range_count: push_constants.len() as u32,
- p_push_constant_ranges: push_constants.as_ptr(),
- ..Default::default()
- };
-
- let mut output = MaybeUninit::uninit();
- check_errors(fns.v1_0.create_pipeline_layout(
- device.internal_object(),
- &infos,
- ptr::null(),
- output.as_mut_ptr(),
- ))?;
- output.assume_init()
- };
-
- Ok(PipelineLayout {
- handle,
- device: device.clone(),
- descriptor_set_layouts,
- push_constant_ranges,
- })
- }
-}
-
-impl PipelineLayout {
- /// Returns the descriptor set layouts this pipeline layout was created from.
- #[inline]
- pub fn descriptor_set_layouts(&self) -> &[Arc<DescriptorSetLayout>] {
- &self.descriptor_set_layouts
- }
-
- /// Returns a slice containing the push constant ranges this pipeline layout was created from.
- #[inline]
- pub fn push_constant_ranges(&self) -> &[PipelineLayoutPcRange] {
- &self.push_constant_ranges
- }
-
- /// Makes sure that `self` is a superset of the provided descriptor set layouts and push
- /// constant ranges. Returns an `Err` if this is not the case.
- pub fn ensure_superset_of(
- &self,
- descriptor_set_layout_descs: &[DescriptorSetDesc],
- push_constant_range: &Option<PipelineLayoutPcRange>,
- ) -> Result<(), PipelineLayoutSupersetError> {
- // Ewwwwwww
- let empty = DescriptorSetDesc::empty();
- let num_sets = cmp::max(
- self.descriptor_set_layouts.len(),
- descriptor_set_layout_descs.len(),
- );
-
- for set_num in 0..num_sets {
- let first = self
- .descriptor_set_layouts
- .get(set_num)
- .map(|set| set.desc())
- .unwrap_or_else(|| &empty);
- let second = descriptor_set_layout_descs
- .get(set_num)
- .unwrap_or_else(|| &empty);
-
- if let Err(error) = first.ensure_superset_of(second) {
- return Err(PipelineLayoutSupersetError::DescriptorSet {
- error,
- set_num: set_num as u32,
- });
- }
- }
-
- // FIXME: check push constants
- if let Some(range) = push_constant_range {
- for own_range in self.push_constant_ranges.as_ref().into_iter() {
- if range.stages.intersects(&own_range.stages) && // check if it shares any stages
- (range.offset < own_range.offset || // our range must start before and end after the given range
- own_range.offset + own_range.size < range.offset + range.size) {
- return Err(PipelineLayoutSupersetError::PushConstantRange {
- first_range: *own_range,
- second_range: *range,
- });
- }
- }
- }
-
- Ok(())
- }
-}
-
-unsafe impl DeviceOwned for PipelineLayout {
- #[inline]
- fn device(&self) -> &Arc<Device> {
- &self.device
- }
-}
-
-unsafe impl VulkanObject for PipelineLayout {
- type Object = ash::vk::PipelineLayout;
-
- fn internal_object(&self) -> Self::Object {
- self.handle
- }
-}
-
-impl fmt::Debug for PipelineLayout {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- fmt.debug_struct("PipelineLayout")
- .field("raw", &self.handle)
- .field("device", &self.device)
- .field("descriptor_set_layouts", &self.descriptor_set_layouts)
- .field("push_constant_ranges", &self.push_constant_ranges)
- .finish()
- }
-}
-
-impl Drop for PipelineLayout {
- #[inline]
- fn drop(&mut self) {
- unsafe {
- let fns = self.device.fns();
- fns.v1_0.destroy_pipeline_layout(
- self.device.internal_object(),
- self.handle,
- ptr::null(),
- );
- }
- }
-}
-
-/// Error that can happen when creating a pipeline layout.
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum PipelineLayoutCreationError {
- /// Not enough memory.
- OomError(OomError),
- /// The pipeline layout description doesn't fulfill the limit requirements.
- LimitsError(PipelineLayoutLimitsError),
- /// One of the push constants range didn't obey the rules. The list of stages must not be
- /// empty, the size must not be 0, and the size must be a multiple or 4.
- InvalidPushConstant,
- /// Conflict between different push constants ranges.
- PushConstantsConflict {
- first_range: PipelineLayoutPcRange,
- second_range: PipelineLayoutPcRange,
- },
-}
-
-impl error::Error for PipelineLayoutCreationError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- PipelineLayoutCreationError::OomError(ref err) => Some(err),
- PipelineLayoutCreationError::LimitsError(ref err) => Some(err),
- _ => None,
- }
- }
-}
-
-impl fmt::Display for PipelineLayoutCreationError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- PipelineLayoutCreationError::OomError(_) => "not enough memory available",
- PipelineLayoutCreationError::LimitsError(_) => {
- "the pipeline layout description doesn't fulfill the limit requirements"
- }
- PipelineLayoutCreationError::InvalidPushConstant => {
- "one of the push constants range didn't obey the rules"
- }
- PipelineLayoutCreationError::PushConstantsConflict { .. } => {
- "conflict between different push constants ranges"
- }
- }
- )
- }
-}
-
-impl From<OomError> for PipelineLayoutCreationError {
- #[inline]
- fn from(err: OomError) -> PipelineLayoutCreationError {
- PipelineLayoutCreationError::OomError(err)
- }
-}
-
-impl From<PipelineLayoutLimitsError> for PipelineLayoutCreationError {
- #[inline]
- fn from(err: PipelineLayoutLimitsError) -> PipelineLayoutCreationError {
- PipelineLayoutCreationError::LimitsError(err)
- }
-}
-
-impl From<Error> for PipelineLayoutCreationError {
- #[inline]
- fn from(err: Error) -> PipelineLayoutCreationError {
- match err {
- err @ Error::OutOfHostMemory => {
- PipelineLayoutCreationError::OomError(OomError::from(err))
- }
- err @ Error::OutOfDeviceMemory => {
- PipelineLayoutCreationError::OomError(OomError::from(err))
- }
- _ => panic!("unexpected error: {:?}", err),
- }
- }
-}
-
-/// Error when checking whether a pipeline layout is a superset of another one.
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum PipelineLayoutSupersetError {
- DescriptorSet {
- error: DescriptorSetDescSupersetError,
- set_num: u32,
- },
- PushConstantRange {
- first_range: PipelineLayoutPcRange,
- second_range: PipelineLayoutPcRange,
- },
-}
-
-impl error::Error for PipelineLayoutSupersetError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- PipelineLayoutSupersetError::DescriptorSet { ref error, .. } => Some(error),
- ref error @ PipelineLayoutSupersetError::PushConstantRange { .. } => Some(error),
- }
- }
-}
-
-impl fmt::Display for PipelineLayoutSupersetError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- match *self {
- PipelineLayoutSupersetError::DescriptorSet { .. } => {
- write!(
- fmt,
- "the descriptor set was not a superset of the other"
- )
- },
- PipelineLayoutSupersetError::PushConstantRange { first_range, second_range } => {
- writeln!(fmt, "our range did not completely encompass the other range")?;
- writeln!(fmt, " our stages: {:?}", first_range.stages)?;
- writeln!(
- fmt,
- " our range: {} - {}",
- first_range.offset,
- first_range.offset + first_range.size
- )?;
- writeln!(fmt, " other stages: {:?}", second_range.stages)?;
- write!(fmt,
- " other range: {} - {}",
- second_range.offset,
- second_range.offset + second_range.size
- )
- },
- }
- }
-}
-
-/// Description of a range of the push constants of a pipeline layout.
-// TODO: should contain the layout as well
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-pub struct PipelineLayoutPcRange {
- /// Offset in bytes from the start of the push constants to this range.
- pub offset: usize,
- /// Size in bytes of the range.
- pub size: usize,
- /// The stages which can access this range. Note that the same shader stage can't access two
- /// different ranges.
- pub stages: ShaderStages,
-}
-
-/* TODO: restore
-#[cfg(test)]
-mod tests {
- use std::iter;
- use std::sync::Arc;
- use descriptor::descriptor::ShaderStages;
- use descriptor::descriptor_set::DescriptorSetLayout;
- use descriptor::pipeline_layout::sys::PipelineLayout;
- use descriptor::pipeline_layout::sys::PipelineLayoutCreationError;
-
- #[test]
- fn empty() {
- let (device, _) = gfx_dev_and_queue!();
- let _layout = PipelineLayout::new(&device, iter::empty(), iter::empty()).unwrap();
- }
-
- #[test]
- fn wrong_device_panic() {
- let (device1, _) = gfx_dev_and_queue!();
- let (device2, _) = gfx_dev_and_queue!();
-
- let set = match DescriptorSetLayout::raw(device1, iter::empty()) {
- Ok(s) => Arc::new(s),
- Err(_) => return
- };
-
- assert_should_panic!({
- let _ = PipelineLayout::new(&device2, Some(&set), iter::empty());
- });
- }
-
- #[test]
- fn invalid_push_constant_stages() {
- let (device, _) = gfx_dev_and_queue!();
-
- let push_constant = (0, 8, ShaderStages::none());
-
- match PipelineLayout::new(&device, iter::empty(), Some(push_constant)) {
- Err(PipelineLayoutCreationError::InvalidPushConstant) => (),
- _ => panic!()
- }
- }
-
- #[test]
- fn invalid_push_constant_size1() {
- let (device, _) = gfx_dev_and_queue!();
-
- let push_constant = (0, 0, ShaderStages::all_graphics());
-
- match PipelineLayout::new(&device, iter::empty(), Some(push_constant)) {
- Err(PipelineLayoutCreationError::InvalidPushConstant) => (),
- _ => panic!()
- }
- }
-
- #[test]
- fn invalid_push_constant_size2() {
- let (device, _) = gfx_dev_and_queue!();
-
- let push_constant = (0, 11, ShaderStages::all_graphics());
-
- match PipelineLayout::new(&device, iter::empty(), Some(push_constant)) {
- Err(PipelineLayoutCreationError::InvalidPushConstant) => (),
- _ => panic!()
- }
- }
-}*/
diff --git a/src/pipeline/mod.rs b/src/pipeline/mod.rs
index e87cbfd..9ec6492 100644
--- a/src/pipeline/mod.rs
+++ b/src/pipeline/mod.rs
@@ -7,7 +7,7 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-//! Describes a graphical or compute operation.
+//! Describes a processing operation that will execute on the Vulkan device.
//!
//! In Vulkan, before you can add a draw or a compute command to a command buffer you have to
//! create a *pipeline object* that describes this command.
@@ -16,98 +16,444 @@
//! code that will execute the operation (similar to a compiler that generates an executable for
//! the CPU). Consequently it is a CPU-intensive operation that should be performed at
//! initialization or during a loading screen.
-//!
-//! There are two kinds of pipelines:
-//!
-//! - `ComputePipeline`s, for compute operations (general-purpose operations that read/write data
-//! in buffers or raw pixels in images).
-//! - `GraphicsPipeline`s, for graphical operations (operations that take vertices as input and
-//! write pixels to a framebuffer).
-//!
-//! # Creating a compute pipeline.
-//!
-//! In order to create a compute pipeline, you first need a *shader entry point*.
-//!
-//! TODO: write the rest
-//! For now vulkano has no "clean" way to create shaders ; everything's a bit hacky
-//!
-//! # Creating a graphics pipeline
-//!
-//! A graphics operation takes vertices or vertices and indices as input, and writes pixels to a
-//! framebuffer. It consists of multiple steps:
-//!
-//! - A *shader* named the *vertex shader* is run once for each vertex of the input.
-//! - Vertices are assembled into primitives.
-//! - Optionally, a shader named the *tessellation control shader* is run once for each primitive
-//! and indicates the tessellation level to apply for this primitive.
-//! - Optionally, a shader named the *tessellation evaluation shader* is run once for each vertex,
-//! including the ones newly created by the tessellation.
-//! - Optionally, a shader named the *geometry shader* is run once for each line or triangle.
-//! - The vertex coordinates (as outputted by the geometry shader, or by the tessellation
-//! evaluation shader if there's no geometry shader, or by the vertex shader if there's no
-//! geometry shader nor tessellation evaluation shader) are turned into screen-space coordinates.
-//! - The list of pixels that cover each triangle are determined.
-//! - A shader named the fragment shader is run once for each pixel that covers one of the
-//! triangles.
-//! - The depth test and/or the stencil test are performed.
-//! - The output of the fragment shader is written to the framebuffer attachments, possibly by
-//! mixing it with the existing values.
-//!
-//! All the sub-modules of this module (with the exception of `cache`) correspond to the various
-//! stages of graphical pipelines.
-//!
-//! > **Note**: With the exception of the addition of the tessellation shaders and the geometry
-//! > shader, these steps haven't changed in the past decade. If you are familiar with shaders in
-//! > OpenGL 2 for example, don't worry as it works in the same in Vulkan.
-//!
-//! > **Note**: All the stages that consist in executing a shader are performed by a microprocessor
-//! > (unless you happen to use a software implementation of Vulkan). As for the other stages,
-//! > some hardware (usually desktop graphics cards) have dedicated chips that will execute them
-//! > while some other hardware (usually mobile) perform them with the microprocessor as well. In
-//! > the latter situation, the implementation will usually glue these steps to your shaders.
-//!
-//! Creating a graphics pipeline follows the same principle as a compute pipeline, except that
-//! you must pass multiple shaders alongside with configuration for the other steps.
-//!
-//! TODO: add an example
-
-// TODO: graphics pipeline params are deprecated, but are still the primary implementation in order
-// to avoid duplicating code, so we hide the warnings for now
-#![allow(deprecated)]
-
-pub use self::compute_pipeline::ComputePipeline;
-pub use self::compute_pipeline::ComputePipelineAbstract;
-pub use self::compute_pipeline::ComputePipelineCreationError;
-pub use self::compute_pipeline::ComputePipelineSys;
-pub use self::graphics_pipeline::GraphicsPipeline;
-pub use self::graphics_pipeline::GraphicsPipelineAbstract;
-pub use self::graphics_pipeline::GraphicsPipelineBuilder;
-pub use self::graphics_pipeline::GraphicsPipelineCreationError;
-pub use self::graphics_pipeline::GraphicsPipelineSys;
-
-pub mod blend;
+
+pub use self::{compute::ComputePipeline, graphics::GraphicsPipeline, layout::PipelineLayout};
+use crate::{device::DeviceOwned, macros::vulkan_enum, shader::DescriptorBindingRequirements};
+use ahash::HashMap;
+use std::sync::Arc;
+
pub mod cache;
-mod compute_pipeline;
-pub mod depth_stencil;
-mod graphics_pipeline;
-pub mod input_assembly;
+pub mod compute;
+pub mod graphics;
pub mod layout;
-pub mod multisample;
-pub mod raster;
-pub mod shader;
-pub mod vertex;
-pub mod viewport;
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-#[repr(i32)]
-pub enum PipelineBindPoint {
- Compute = ash::vk::PipelineBindPoint::COMPUTE.as_raw(),
- Graphics = ash::vk::PipelineBindPoint::GRAPHICS.as_raw(),
+
+/// A trait for operations shared between pipeline types.
+pub trait Pipeline: DeviceOwned {
+ /// Returns the bind point of this pipeline.
+ fn bind_point(&self) -> PipelineBindPoint;
+
+ /// Returns the pipeline layout used in this pipeline.
+ fn layout(&self) -> &Arc<PipelineLayout>;
+
+ /// Returns the number of descriptor sets actually accessed by this pipeline. This may be less
+ /// than the number of sets in the pipeline layout.
+ fn num_used_descriptor_sets(&self) -> u32;
+
+ /// Returns a reference to the descriptor binding requirements for this pipeline.
+ fn descriptor_binding_requirements(
+ &self,
+ ) -> &HashMap<(u32, u32), DescriptorBindingRequirements>;
}
-impl From<PipelineBindPoint> for ash::vk::PipelineBindPoint {
- #[inline]
- fn from(val: PipelineBindPoint) -> Self {
- Self::from_raw(val as i32)
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// The type of a pipeline.
+ ///
+ /// When binding a pipeline or descriptor sets in a command buffer, the state for each bind point
+ /// is independent from the others. This means that it is possible, for example, to bind a graphics
+ /// pipeline without disturbing any bound compute pipeline. Likewise, binding descriptor sets for
+ /// the `Compute` bind point does not affect sets that were bound to the `Graphics` bind point.
+ PipelineBindPoint = PipelineBindPoint(i32);
+
+ // TODO: document
+ Compute = COMPUTE,
+
+ // TODO: document
+ Graphics = GRAPHICS,
+
+ /* TODO: enable
+ // TODO: document
+ RayTracing = RAY_TRACING_KHR {
+ device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ SubpassShading = SUBPASS_SHADING_HUAWEI {
+ device_extensions: [huawei_subpass_shading],
+ },*/
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// A particular state value within a graphics pipeline that can be dynamically set by a command
+ /// buffer.
+ DynamicState = DynamicState(i32);
+
+ // TODO: document
+ Viewport = VIEWPORT,
+
+ // TODO: document
+ Scissor = SCISSOR,
+
+ // TODO: document
+ LineWidth = LINE_WIDTH,
+
+ // TODO: document
+ DepthBias = DEPTH_BIAS,
+
+ // TODO: document
+ BlendConstants = BLEND_CONSTANTS,
+
+ // TODO: document
+ DepthBounds = DEPTH_BOUNDS,
+
+ // TODO: document
+ StencilCompareMask = STENCIL_COMPARE_MASK,
+
+ // TODO: document
+ StencilWriteMask = STENCIL_WRITE_MASK,
+
+ // TODO: document
+ StencilReference = STENCIL_REFERENCE,
+
+ // TODO: document
+ CullMode = CULL_MODE {
+ api_version: V1_3,
+ device_extensions: [ext_extended_dynamic_state],
+ },
+
+ // TODO: document
+ FrontFace = FRONT_FACE {
+ api_version: V1_3,
+ device_extensions: [ext_extended_dynamic_state],
+ },
+
+ // TODO: document
+ PrimitiveTopology = PRIMITIVE_TOPOLOGY {
+ api_version: V1_3,
+ device_extensions: [ext_extended_dynamic_state],
+ },
+
+ // TODO: document
+ ViewportWithCount = VIEWPORT_WITH_COUNT {
+ api_version: V1_3,
+ device_extensions: [ext_extended_dynamic_state],
+ },
+
+ // TODO: document
+ ScissorWithCount = SCISSOR_WITH_COUNT {
+ api_version: V1_3,
+ device_extensions: [ext_extended_dynamic_state],
+ },
+
+ // TODO: document
+ VertexInputBindingStride = VERTEX_INPUT_BINDING_STRIDE {
+ api_version: V1_3,
+ device_extensions: [ext_extended_dynamic_state],
+ },
+
+ // TODO: document
+ DepthTestEnable = DEPTH_TEST_ENABLE {
+ api_version: V1_3,
+ device_extensions: [ext_extended_dynamic_state],
+ },
+
+ // TODO: document
+ DepthWriteEnable = DEPTH_WRITE_ENABLE {
+ api_version: V1_3,
+ device_extensions: [ext_extended_dynamic_state],
+ },
+
+ // TODO: document
+ DepthCompareOp = DEPTH_COMPARE_OP {
+ api_version: V1_3,
+ device_extensions: [ext_extended_dynamic_state],
+ },
+
+ // TODO: document
+ DepthBoundsTestEnable = DEPTH_BOUNDS_TEST_ENABLE {
+ api_version: V1_3,
+ device_extensions: [ext_extended_dynamic_state],
+ },
+
+ // TODO: document
+ StencilTestEnable = STENCIL_TEST_ENABLE {
+ api_version: V1_3,
+ device_extensions: [ext_extended_dynamic_state],
+ },
+
+ // TODO: document
+ StencilOp = STENCIL_OP {
+ api_version: V1_3,
+ device_extensions: [ext_extended_dynamic_state],
+ },
+
+ // TODO: document
+ RasterizerDiscardEnable = RASTERIZER_DISCARD_ENABLE {
+ api_version: V1_3,
+ device_extensions: [ext_extended_dynamic_state2],
+ },
+
+ // TODO: document
+ DepthBiasEnable = DEPTH_BIAS_ENABLE {
+ api_version: V1_3,
+ device_extensions: [ext_extended_dynamic_state2],
+ },
+
+ // TODO: document
+ PrimitiveRestartEnable = PRIMITIVE_RESTART_ENABLE {
+ api_version: V1_3,
+ device_extensions: [ext_extended_dynamic_state2],
+ },
+
+ // TODO: document
+ ViewportWScaling = VIEWPORT_W_SCALING_NV {
+ device_extensions: [nv_clip_space_w_scaling],
+ },
+
+ // TODO: document
+ DiscardRectangle = DISCARD_RECTANGLE_EXT {
+ device_extensions: [ext_discard_rectangles],
+ },
+
+ // TODO: document
+ SampleLocations = SAMPLE_LOCATIONS_EXT {
+ device_extensions: [ext_sample_locations],
+ },
+
+ // TODO: document
+ RayTracingPipelineStackSize = RAY_TRACING_PIPELINE_STACK_SIZE_KHR {
+ device_extensions: [khr_ray_tracing_pipeline],
+ },
+
+ // TODO: document
+ ViewportShadingRatePalette = VIEWPORT_SHADING_RATE_PALETTE_NV {
+ device_extensions: [nv_shading_rate_image],
+ },
+
+ // TODO: document
+ ViewportCoarseSampleOrder = VIEWPORT_COARSE_SAMPLE_ORDER_NV {
+ device_extensions: [nv_shading_rate_image],
+ },
+
+ // TODO: document
+ ExclusiveScissor = EXCLUSIVE_SCISSOR_NV {
+ device_extensions: [nv_scissor_exclusive],
+ },
+
+ // TODO: document
+ FragmentShadingRate = FRAGMENT_SHADING_RATE_KHR {
+ device_extensions: [khr_fragment_shading_rate],
+ },
+
+ // TODO: document
+ LineStipple = LINE_STIPPLE_EXT {
+ device_extensions: [ext_line_rasterization],
+ },
+
+ // TODO: document
+ VertexInput = VERTEX_INPUT_EXT {
+ device_extensions: [ext_vertex_input_dynamic_state],
+ },
+
+ // TODO: document
+ PatchControlPoints = PATCH_CONTROL_POINTS_EXT {
+ device_extensions: [ext_extended_dynamic_state2],
+ },
+
+ // TODO: document
+ LogicOp = LOGIC_OP_EXT {
+ device_extensions: [ext_extended_dynamic_state2],
+ },
+
+ // TODO: document
+ ColorWriteEnable = COLOR_WRITE_ENABLE_EXT {
+ device_extensions: [ext_color_write_enable],
+ },
+
+ // TODO: document
+ TessellationDomainOrigin = TESSELLATION_DOMAIN_ORIGIN_EXT {
+ device_extensions: [ext_extended_dynamic_state3],
+ },
+
+ // TODO: document
+ DepthClampEnable = DEPTH_CLAMP_ENABLE_EXT {
+ device_extensions: [ext_extended_dynamic_state3],
+ },
+
+ // TODO: document
+ PolygonMode = POLYGON_MODE_EXT {
+ device_extensions: [ext_extended_dynamic_state3],
+ },
+
+ // TODO: document
+ RasterizationSamples = RASTERIZATION_SAMPLES_EXT {
+ device_extensions: [ext_extended_dynamic_state3],
+ },
+
+ // TODO: document
+ SampleMask = SAMPLE_MASK_EXT {
+ device_extensions: [ext_extended_dynamic_state3],
+ },
+
+ // TODO: document
+ AlphaToCoverageEnable = ALPHA_TO_COVERAGE_ENABLE_EXT {
+ device_extensions: [ext_extended_dynamic_state3],
+ },
+
+ // TODO: document
+ AlphaToOneEnable = ALPHA_TO_ONE_ENABLE_EXT {
+ device_extensions: [ext_extended_dynamic_state3],
+ },
+
+ // TODO: document
+ LogicOpEnable = LOGIC_OP_ENABLE_EXT {
+ device_extensions: [ext_extended_dynamic_state3],
+ },
+
+ // TODO: document
+ ColorBlendEnable = COLOR_BLEND_ENABLE_EXT {
+ device_extensions: [ext_extended_dynamic_state3],
+ },
+
+ // TODO: document
+ ColorBlendEquation = COLOR_BLEND_EQUATION_EXT {
+ device_extensions: [ext_extended_dynamic_state3],
+ },
+
+ // TODO: document
+ ColorWriteMask = COLOR_WRITE_MASK_EXT {
+ device_extensions: [ext_extended_dynamic_state3],
+ },
+
+ // TODO: document
+ RasterizationStream = RASTERIZATION_STREAM_EXT {
+ device_extensions: [ext_extended_dynamic_state3],
+ },
+
+ // TODO: document
+ ConservativeRasterizationMode = CONSERVATIVE_RASTERIZATION_MODE_EXT {
+ device_extensions: [ext_extended_dynamic_state3],
+ },
+
+ // TODO: document
+ ExtraPrimitiveOverestimationSize = EXTRA_PRIMITIVE_OVERESTIMATION_SIZE_EXT {
+ device_extensions: [ext_extended_dynamic_state3],
+ },
+
+ // TODO: document
+ DepthClipEnable = DEPTH_CLIP_ENABLE_EXT {
+ device_extensions: [ext_extended_dynamic_state3],
+ },
+
+ // TODO: document
+ SampleLocationsEnable = SAMPLE_LOCATIONS_ENABLE_EXT {
+ device_extensions: [ext_extended_dynamic_state3],
+ },
+
+ // TODO: document
+ ColorBlendAdvanced = COLOR_BLEND_ADVANCED_EXT {
+ device_extensions: [ext_extended_dynamic_state3],
+ },
+
+ // TODO: document
+ ProvokingVertexMode = PROVOKING_VERTEX_MODE_EXT {
+ device_extensions: [ext_extended_dynamic_state3],
+ },
+
+ // TODO: document
+ LineRasterizationMode = LINE_RASTERIZATION_MODE_EXT {
+ device_extensions: [ext_extended_dynamic_state3],
+ },
+
+ // TODO: document
+ LineStippleEnable = LINE_STIPPLE_ENABLE_EXT {
+ device_extensions: [ext_extended_dynamic_state3],
+ },
+
+ // TODO: document
+ DepthClipNegativeOneToOne = DEPTH_CLIP_NEGATIVE_ONE_TO_ONE_EXT {
+ device_extensions: [ext_extended_dynamic_state3],
+ },
+
+ // TODO: document
+ ViewportWScalingEnable = VIEWPORT_W_SCALING_ENABLE_NV {
+ device_extensions: [ext_extended_dynamic_state3],
+ },
+
+ // TODO: document
+ ViewportSwizzle = VIEWPORT_SWIZZLE_NV {
+ device_extensions: [ext_extended_dynamic_state3],
+ },
+
+ // TODO: document
+ CoverageToColorEnable = COVERAGE_TO_COLOR_ENABLE_NV {
+ device_extensions: [ext_extended_dynamic_state3],
+ },
+
+ // TODO: document
+ CoverageToColorLocation = COVERAGE_TO_COLOR_LOCATION_NV {
+ device_extensions: [ext_extended_dynamic_state3],
+ },
+
+ // TODO: document
+ CoverageModulationMode = COVERAGE_MODULATION_MODE_NV {
+ device_extensions: [ext_extended_dynamic_state3],
+ },
+
+ // TODO: document
+ CoverageModulationTableEnable = COVERAGE_MODULATION_TABLE_ENABLE_NV {
+ device_extensions: [ext_extended_dynamic_state3],
+ },
+
+ // TODO: document
+ CoverageModulationTable = COVERAGE_MODULATION_TABLE_NV {
+ device_extensions: [ext_extended_dynamic_state3],
+ },
+
+ // TODO: document
+ ShadingRateImageEnable = SHADING_RATE_IMAGE_ENABLE_NV {
+ device_extensions: [ext_extended_dynamic_state3],
+ },
+
+ // TODO: document
+ RepresentativeFragmentTestEnable = REPRESENTATIVE_FRAGMENT_TEST_ENABLE_NV {
+ device_extensions: [ext_extended_dynamic_state3],
+ },
+
+ // TODO: document
+ CoverageReductionMode = COVERAGE_REDUCTION_MODE_NV {
+ device_extensions: [ext_extended_dynamic_state3],
+ },
+}
+
+/// Specifies how a dynamic state is handled by a graphics pipeline.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum StateMode<F> {
+ /// The pipeline has a fixed value for this state. Previously set dynamic state will be lost
+ /// when binding it, and will have to be re-set after binding a pipeline that uses it.
+ Fixed(F),
+
+ /// The pipeline expects a dynamic value to be set by a command buffer. Previously set dynamic
+ /// state is not disturbed when binding it.
+ Dynamic,
+}
+
+impl<T> From<Option<T>> for StateMode<T> {
+ fn from(val: Option<T>) -> Self {
+ match val {
+ Some(x) => StateMode::Fixed(x),
+ None => StateMode::Dynamic,
+ }
+ }
+}
+
+impl<T> From<StateMode<T>> for Option<T> {
+ fn from(val: StateMode<T>) -> Self {
+ match val {
+ StateMode::Fixed(x) => Some(x),
+ StateMode::Dynamic => None,
+ }
}
}
+
+/// A variant of `StateMode` that is used for cases where some value is still needed when the state
+/// is dynamic.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum PartialStateMode<F, D> {
+ Fixed(F),
+ Dynamic(D),
+}
diff --git a/src/pipeline/multisample.rs b/src/pipeline/multisample.rs
deleted file mode 100644
index dcb3362..0000000
--- a/src/pipeline/multisample.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-//! State of multisampling.
-//!
-//! Multisampling allows you to ask the GPU to run the rasterizer to generate more than one
-//! sample per pixel.
-//!
-//! For example, if `rasterization_samples` is 1 then the fragment shader, depth test and stencil
-//! test will be run once for each pixel. However if `rasterization_samples` is `n`, then the
-//! GPU will pick `n` different locations within each pixel and assign to each of these locations
-//! a different depth value. Depth and stencil test will then be run `n` times.
-//!
-//! In addition to this, the `sample_shading` parameter is the proportion (between 0.0 and 1.0) or
-//! the samples that will be run through the fragment shader. For example if you set this to 1.0,
-//! then all the sub-pixel samples will run through the shader and get a different value. If you
-//! set this to 0.5, about half of the samples will run through the shader and the other half will
-//! get their values from the ones which went through the shader.
-//!
-//! If `alpha_to_coverage` is true, then the alpha value of the fragment will be used in
-//! an implementation-defined way to determine which samples get disabled or not. For example if
-//! the alpha value is 0.5, then about half of the samples will be discarded. If you render to a
-//! multisample image, this means that the color will end up being mixed with whatever color was
-//! underneath, which gives the same effect as alpha blending.
-//!
-//! If `alpha_to_one` is true, the alpha value of all the samples will be forced to 1.0 (or the
-//! maximum possible value) after the effects of `alpha_to_coverage` have been applied.
-
-// TODO: handle some weird behaviors with non-floating-point targets
-
-/// State of the multisampling.
-///
-/// See the documentation in this module.
-#[deprecated(note = "No longer needed")]
-#[derive(Debug, Copy, Clone)]
-pub struct Multisample {
- pub rasterization_samples: u32,
- pub sample_mask: [u32; 4],
- pub sample_shading: Option<f32>,
- pub alpha_to_coverage: bool,
- pub alpha_to_one: bool,
-}
-
-impl Multisample {
- #[inline]
- pub fn disabled() -> Multisample {
- Multisample {
- rasterization_samples: 1,
- sample_mask: [0xffffffff; 4],
- sample_shading: None,
- alpha_to_coverage: false,
- alpha_to_one: false,
- }
- }
-}
diff --git a/src/pipeline/raster.rs b/src/pipeline/raster.rs
deleted file mode 100644
index 337ef94..0000000
--- a/src/pipeline/raster.rs
+++ /dev/null
@@ -1,166 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-//! Stage when triangles are turned into pixels.
-//!
-//! The rasterization is the stage when collections of triangles are turned into collections
-//! of pixels or samples.
-//!
-
-/// State of the rasterizer.
-#[derive(Clone, Debug)]
-pub struct Rasterization {
- /// If true, then the depth value of the vertices will be clamped to [0.0 ; 1.0]. If false,
- /// fragments whose depth is outside of this range will be discarded.
- pub depth_clamp: bool,
-
- /// If true, all the fragments will be discarded. This is usually used when your vertex shader
- /// has some side effects and you don't need to run the fragment shader.
- pub rasterizer_discard: bool,
-
- /// This setting can ask the rasterizer to downgrade triangles into lines or points, or lines
- /// into points.
- pub polygon_mode: PolygonMode,
-
- /// Specifies whether front faces or back faces should be discarded, or none, or both.
- pub cull_mode: CullMode,
-
- /// Specifies which triangle orientation corresponds to the front or the triangle.
- pub front_face: FrontFace,
-
- /// Width, in pixels, of lines when drawing lines.
- ///
- /// If you pass `None`, then this state will be considered as dynamic and the line width will
- /// need to be set when you build the command buffer.
- pub line_width: Option<f32>,
-
- pub depth_bias: DepthBiasControl,
-}
-
-impl Default for Rasterization {
- #[inline]
- fn default() -> Rasterization {
- Rasterization {
- depth_clamp: false,
- rasterizer_discard: false,
- polygon_mode: Default::default(),
- cull_mode: Default::default(),
- front_face: Default::default(),
- line_width: Some(1.0),
- depth_bias: DepthBiasControl::Disabled,
- }
- }
-}
-
-#[derive(Copy, Clone, Debug)]
-pub enum DepthBiasControl {
- Disabled,
- Dynamic,
- Static(DepthBias),
-}
-
-impl DepthBiasControl {
- #[inline]
- pub fn is_dynamic(&self) -> bool {
- match *self {
- DepthBiasControl::Dynamic => true,
- _ => false,
- }
- }
-}
-
-#[derive(Copy, Clone, Debug)]
-pub struct DepthBias {
- pub constant_factor: f32,
- /// Requires the `depth_bias_clamp` feature to be enabled.
- pub clamp: f32,
- pub slope_factor: f32,
-}
-
-/// Specifies the culling mode.
-///
-/// This setting works in pair with `front_face`. The `front_face` setting tells the GPU whether
-/// clockwise or counter-clockwise correspond to the front and the back of each triangle. Then
-/// `cull_mode` lets you specify whether front faces should be discarded, back faces should be
-/// discarded, or none, or both.
-#[derive(Copy, Clone, Debug)]
-#[repr(u32)]
-pub enum CullMode {
- /// No culling.
- None = ash::vk::CullModeFlags::NONE.as_raw(),
- /// The faces facing the front of the screen (ie. facing the user) will be removed.
- Front = ash::vk::CullModeFlags::FRONT.as_raw(),
- /// The faces facing the back of the screen will be removed.
- Back = ash::vk::CullModeFlags::BACK.as_raw(),
- /// All faces will be removed.
- FrontAndBack = ash::vk::CullModeFlags::FRONT_AND_BACK.as_raw(),
-}
-
-impl From<CullMode> for ash::vk::CullModeFlags {
- #[inline]
- fn from(val: CullMode) -> Self {
- Self::from_raw(val as u32)
- }
-}
-
-impl Default for CullMode {
- #[inline]
- fn default() -> CullMode {
- CullMode::None
- }
-}
-
-/// Specifies which triangle orientation corresponds to the front or the triangle.
-#[derive(Copy, Clone, Debug)]
-#[repr(i32)]
-pub enum FrontFace {
- /// Triangles whose vertices are oriented counter-clockwise on the screen will be considered
- /// as facing their front. Otherwise they will be considered as facing their back.
- CounterClockwise = ash::vk::FrontFace::COUNTER_CLOCKWISE.as_raw(),
-
- /// Triangles whose vertices are oriented clockwise on the screen will be considered
- /// as facing their front. Otherwise they will be considered as facing their back.
- Clockwise = ash::vk::FrontFace::CLOCKWISE.as_raw(),
-}
-
-impl From<FrontFace> for ash::vk::FrontFace {
- #[inline]
- fn from(val: FrontFace) -> Self {
- Self::from_raw(val as i32)
- }
-}
-
-impl Default for FrontFace {
- #[inline]
- fn default() -> FrontFace {
- FrontFace::CounterClockwise
- }
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-#[repr(i32)]
-pub enum PolygonMode {
- Fill = ash::vk::PolygonMode::FILL.as_raw(),
- Line = ash::vk::PolygonMode::LINE.as_raw(),
- Point = ash::vk::PolygonMode::POINT.as_raw(),
-}
-
-impl From<PolygonMode> for ash::vk::PolygonMode {
- #[inline]
- fn from(val: PolygonMode) -> Self {
- Self::from_raw(val as i32)
- }
-}
-
-impl Default for PolygonMode {
- #[inline]
- fn default() -> PolygonMode {
- PolygonMode::Fill
- }
-}
diff --git a/src/pipeline/shader.rs b/src/pipeline/shader.rs
deleted file mode 100644
index c5ba1e3..0000000
--- a/src/pipeline/shader.rs
+++ /dev/null
@@ -1,808 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-//! Stage of a graphics pipeline.
-//!
-//! In Vulkan, shaders are grouped in *shader modules*. Each shader module is built from SPIR-V
-//! code and can contain one or more entry points. Note that for the moment the official
-//! GLSL-to-SPIR-V compiler does not support multiple entry points.
-//!
-//! The vulkano library does not provide any functionality that checks and introspects the SPIR-V
-//! code, therefore the whole shader-related API is unsafe. You are encouraged to use the
-//! `vulkano-shaders` crate that will generate Rust code that wraps around vulkano's shaders API.
-
-use crate::check_errors;
-use crate::descriptor_set::layout::DescriptorSetDesc;
-use crate::device::Device;
-use crate::format::Format;
-use crate::pipeline::input_assembly::PrimitiveTopology;
-use crate::pipeline::layout::PipelineLayoutPcRange;
-use crate::sync::PipelineStages;
-use crate::OomError;
-use crate::VulkanObject;
-use smallvec::SmallVec;
-use std::borrow::Cow;
-use std::error;
-use std::ffi::CStr;
-use std::fmt;
-use std::mem;
-use std::mem::MaybeUninit;
-use std::ops::BitOr;
-use std::ops::Range;
-use std::ptr;
-use std::sync::Arc;
-
-/// Contains SPIR-V code with one or more entry points.
-///
-/// Note that it is advised to wrap around a `ShaderModule` with a struct that is different for
-/// each shader.
-#[derive(Debug)]
-pub struct ShaderModule {
- // The module.
- module: ash::vk::ShaderModule,
- // Pointer to the device.
- device: Arc<Device>,
-}
-
-impl ShaderModule {
- /// Builds a new shader module from SPIR-V bytes.
- ///
- /// # Safety
- ///
- /// - The SPIR-V code is not validated.
- /// - The SPIR-V code may require some features that are not enabled. This isn't checked by
- /// this function either.
- ///
- pub unsafe fn new(device: Arc<Device>, spirv: &[u8]) -> Result<Arc<ShaderModule>, OomError> {
- debug_assert!((spirv.len() % 4) == 0);
- Self::from_ptr(device, spirv.as_ptr() as *const _, spirv.len())
- }
-
- /// Builds a new shader module from SPIR-V 32-bit words.
- ///
- /// # Safety
- ///
- /// - The SPIR-V code is not validated.
- /// - The SPIR-V code may require some features that are not enabled. This isn't checked by
- /// this function either.
- ///
- pub unsafe fn from_words(
- device: Arc<Device>,
- spirv: &[u32],
- ) -> Result<Arc<ShaderModule>, OomError> {
- Self::from_ptr(device, spirv.as_ptr(), spirv.len() * mem::size_of::<u32>())
- }
-
- /// Builds a new shader module from SPIR-V.
- ///
- /// # Safety
- ///
- /// - The SPIR-V code is not validated.
- /// - The SPIR-V code may require some features that are not enabled. This isn't checked by
- /// this function either.
- ///
- unsafe fn from_ptr(
- device: Arc<Device>,
- spirv: *const u32,
- spirv_len: usize,
- ) -> Result<Arc<ShaderModule>, OomError> {
- let module = {
- let infos = ash::vk::ShaderModuleCreateInfo {
- flags: ash::vk::ShaderModuleCreateFlags::empty(),
- code_size: spirv_len,
- p_code: spirv,
- ..Default::default()
- };
-
- let fns = device.fns();
- let mut output = MaybeUninit::uninit();
- check_errors(fns.v1_0.create_shader_module(
- device.internal_object(),
- &infos,
- ptr::null(),
- output.as_mut_ptr(),
- ))?;
- output.assume_init()
- };
-
- Ok(Arc::new(ShaderModule {
- module: module,
- device: device,
- }))
- }
-
- /// Gets access to an entry point contained in this module.
- ///
- /// This is purely a *logical* operation. It returns a struct that *represents* the entry
- /// point but doesn't actually do anything.
- ///
- /// # Safety
- ///
- /// - The user must check that the entry point exists in the module, as this is not checked
- /// by Vulkan.
- /// - The input, output and layout must correctly describe the input, output and layout used
- /// by this stage.
- ///
- pub unsafe fn graphics_entry_point<'a, D>(
- &'a self,
- name: &'a CStr,
- descriptor_set_layout_descs: D,
- push_constant_range: Option<PipelineLayoutPcRange>,
- spec_constants: &'static [SpecializationMapEntry],
- input: ShaderInterface,
- output: ShaderInterface,
- ty: GraphicsShaderType,
- ) -> GraphicsEntryPoint<'a>
- where
- D: IntoIterator<Item = DescriptorSetDesc>,
- {
- GraphicsEntryPoint {
- module: self,
- name,
- descriptor_set_layout_descs: descriptor_set_layout_descs.into_iter().collect(),
- push_constant_range,
- spec_constants,
- input,
- output,
- ty,
- }
- }
-
- /// Gets access to an entry point contained in this module.
- ///
- /// This is purely a *logical* operation. It returns a struct that *represents* the entry
- /// point but doesn't actually do anything.
- ///
- /// # Safety
- ///
- /// - The user must check that the entry point exists in the module, as this is not checked
- /// by Vulkan.
- /// - The layout must correctly describe the layout used by this stage.
- ///
- #[inline]
- pub unsafe fn compute_entry_point<'a, D>(
- &'a self,
- name: &'a CStr,
- descriptor_set_layout_descs: D,
- push_constant_range: Option<PipelineLayoutPcRange>,
- spec_constants: &'static [SpecializationMapEntry],
- ) -> ComputeEntryPoint<'a>
- where
- D: IntoIterator<Item = DescriptorSetDesc>,
- {
- ComputeEntryPoint {
- module: self,
- name,
- descriptor_set_layout_descs: descriptor_set_layout_descs.into_iter().collect(),
- push_constant_range,
- spec_constants,
- }
- }
-}
-
-unsafe impl VulkanObject for ShaderModule {
- type Object = ash::vk::ShaderModule;
-
- #[inline]
- fn internal_object(&self) -> ash::vk::ShaderModule {
- self.module
- }
-}
-
-impl Drop for ShaderModule {
- #[inline]
- fn drop(&mut self) {
- unsafe {
- let fns = self.device.fns();
- fns.v1_0
- .destroy_shader_module(self.device.internal_object(), self.module, ptr::null());
- }
- }
-}
-
-pub unsafe trait EntryPointAbstract {
- /// Returns the module this entry point comes from.
- fn module(&self) -> &ShaderModule;
-
- /// Returns the name of the entry point.
- fn name(&self) -> &CStr;
-
- /// Returns a description of the descriptor set layouts.
- fn descriptor_set_layout_descs(&self) -> &[DescriptorSetDesc];
-
- /// Returns the push constant ranges.
- fn push_constant_range(&self) -> &Option<PipelineLayoutPcRange>;
-
- /// Returns the layout of the specialization constants.
- fn spec_constants(&self) -> &[SpecializationMapEntry];
-}
-
-/// Represents a shader entry point in a shader module.
-///
-/// Can be obtained by calling `entry_point()` on the shader module.
-#[derive(Clone, Debug)]
-pub struct GraphicsEntryPoint<'a> {
- module: &'a ShaderModule,
- name: &'a CStr,
-
- descriptor_set_layout_descs: SmallVec<[DescriptorSetDesc; 16]>,
- push_constant_range: Option<PipelineLayoutPcRange>,
- spec_constants: &'static [SpecializationMapEntry],
- input: ShaderInterface,
- output: ShaderInterface,
- ty: GraphicsShaderType,
-}
-
-impl<'a> GraphicsEntryPoint<'a> {
- /// Returns the input attributes used by the shader stage.
- #[inline]
- pub fn input(&self) -> &ShaderInterface {
- &self.input
- }
-
- /// Returns the output attributes used by the shader stage.
- #[inline]
- pub fn output(&self) -> &ShaderInterface {
- &self.output
- }
-
- /// Returns the type of shader.
- #[inline]
- pub fn ty(&self) -> GraphicsShaderType {
- self.ty
- }
-}
-
-unsafe impl<'a> EntryPointAbstract for GraphicsEntryPoint<'a> {
- #[inline]
- fn module(&self) -> &ShaderModule {
- self.module
- }
-
- #[inline]
- fn name(&self) -> &CStr {
- self.name
- }
-
- #[inline]
- fn descriptor_set_layout_descs(&self) -> &[DescriptorSetDesc] {
- &self.descriptor_set_layout_descs
- }
-
- #[inline]
- fn push_constant_range(&self) -> &Option<PipelineLayoutPcRange> {
- &self.push_constant_range
- }
-
- #[inline]
- fn spec_constants(&self) -> &[SpecializationMapEntry] {
- self.spec_constants
- }
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum GraphicsShaderType {
- Vertex,
- TessellationControl,
- TessellationEvaluation,
- Geometry(GeometryShaderExecutionMode),
- Fragment,
-}
-
-/// Declares which type of primitives are expected by the geometry shader.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum GeometryShaderExecutionMode {
- Points,
- Lines,
- LinesWithAdjacency,
- Triangles,
- TrianglesWithAdjacency,
-}
-
-impl GeometryShaderExecutionMode {
- /// Returns true if the given primitive topology can be used with this execution mode.
- #[inline]
- pub fn matches(&self, input: PrimitiveTopology) -> bool {
- match (*self, input) {
- (GeometryShaderExecutionMode::Points, PrimitiveTopology::PointList) => true,
- (GeometryShaderExecutionMode::Lines, PrimitiveTopology::LineList) => true,
- (GeometryShaderExecutionMode::Lines, PrimitiveTopology::LineStrip) => true,
- (
- GeometryShaderExecutionMode::LinesWithAdjacency,
- PrimitiveTopology::LineListWithAdjacency,
- ) => true,
- (
- GeometryShaderExecutionMode::LinesWithAdjacency,
- PrimitiveTopology::LineStripWithAdjacency,
- ) => true,
- (GeometryShaderExecutionMode::Triangles, PrimitiveTopology::TriangleList) => true,
- (GeometryShaderExecutionMode::Triangles, PrimitiveTopology::TriangleStrip) => true,
- (GeometryShaderExecutionMode::Triangles, PrimitiveTopology::TriangleFan) => true,
- (
- GeometryShaderExecutionMode::TrianglesWithAdjacency,
- PrimitiveTopology::TriangleListWithAdjacency,
- ) => true,
- (
- GeometryShaderExecutionMode::TrianglesWithAdjacency,
- PrimitiveTopology::TriangleStripWithAdjacency,
- ) => true,
- _ => false,
- }
- }
-}
-
-/// Represents the entry point of a compute shader in a shader module.
-///
-/// Can be obtained by calling `compute_shader_entry_point()` on the shader module.
-#[derive(Debug, Clone)]
-pub struct ComputeEntryPoint<'a> {
- module: &'a ShaderModule,
- name: &'a CStr,
- descriptor_set_layout_descs: SmallVec<[DescriptorSetDesc; 16]>,
- push_constant_range: Option<PipelineLayoutPcRange>,
- spec_constants: &'static [SpecializationMapEntry],
-}
-
-unsafe impl<'a> EntryPointAbstract for ComputeEntryPoint<'a> {
- #[inline]
- fn module(&self) -> &ShaderModule {
- self.module
- }
-
- #[inline]
- fn name(&self) -> &CStr {
- self.name
- }
-
- #[inline]
- fn descriptor_set_layout_descs(&self) -> &[DescriptorSetDesc] {
- &self.descriptor_set_layout_descs
- }
-
- #[inline]
- fn push_constant_range(&self) -> &Option<PipelineLayoutPcRange> {
- &self.push_constant_range
- }
-
- #[inline]
- fn spec_constants(&self) -> &[SpecializationMapEntry] {
- self.spec_constants
- }
-}
-
-/// Type that contains the definition of an interface between two shader stages, or between
-/// the outside and a shader stage.
-#[derive(Clone, Debug)]
-pub struct ShaderInterface {
- elements: Vec<ShaderInterfaceEntry>,
-}
-
-impl ShaderInterface {
- /// Constructs a new `ShaderInterface`.
- ///
- /// # Safety
- ///
- /// - Must only provide one entry per location.
- /// - The format of each element must not be larger than 128 bits.
- // TODO: could this be made safe?
- #[inline]
- pub unsafe fn new_unchecked(elements: Vec<ShaderInterfaceEntry>) -> ShaderInterface {
- ShaderInterface { elements }
- }
-
- /// Creates a description of an empty shader interface.
- pub const fn empty() -> ShaderInterface {
- ShaderInterface {
- elements: Vec::new(),
- }
- }
-
- /// Returns a slice containing the elements of the interface.
- #[inline]
- pub fn elements(&self) -> &[ShaderInterfaceEntry] {
- self.elements.as_ref()
- }
-
- /// Checks whether the interface is potentially compatible with another one.
- ///
- /// Returns `Ok` if the two interfaces are compatible.
- pub fn matches(&self, other: &ShaderInterface) -> Result<(), ShaderInterfaceMismatchError> {
- if self.elements().len() != other.elements().len() {
- return Err(ShaderInterfaceMismatchError::ElementsCountMismatch {
- self_elements: self.elements().len() as u32,
- other_elements: other.elements().len() as u32,
- });
- }
-
- for a in self.elements() {
- for loc in a.location.clone() {
- let b = match other
- .elements()
- .iter()
- .find(|e| loc >= e.location.start && loc < e.location.end)
- {
- None => {
- return Err(ShaderInterfaceMismatchError::MissingElement { location: loc })
- }
- Some(b) => b,
- };
-
- if a.format != b.format {
- return Err(ShaderInterfaceMismatchError::FormatMismatch {
- location: loc,
- self_format: a.format,
- other_format: b.format,
- });
- }
-
- // TODO: enforce this?
- /*match (a.name, b.name) {
- (Some(ref an), Some(ref bn)) => if an != bn { return false },
- _ => ()
- };*/
- }
- }
-
- // Note: since we check that the number of elements is the same, we don't need to iterate
- // over b's elements.
-
- Ok(())
- }
-}
-
-/// Entry of a shader interface definition.
-#[derive(Debug, Clone)]
-pub struct ShaderInterfaceEntry {
- /// Range of locations covered by the element.
- pub location: Range<u32>,
- /// Format of a each location of the element.
- pub format: Format,
- /// Name of the element, or `None` if the name is unknown.
- pub name: Option<Cow<'static, str>>,
-}
-
-/// Error that can happen when the interface mismatches between two shader stages.
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum ShaderInterfaceMismatchError {
- /// The number of elements is not the same between the two shader interfaces.
- ElementsCountMismatch {
- /// Number of elements in the first interface.
- self_elements: u32,
- /// Number of elements in the second interface.
- other_elements: u32,
- },
-
- /// An element is missing from one of the interfaces.
- MissingElement {
- /// Location of the missing element.
- location: u32,
- },
-
- /// The format of an element does not match.
- FormatMismatch {
- /// Location of the element that mismatches.
- location: u32,
- /// Format in the first interface.
- self_format: Format,
- /// Format in the second interface.
- other_format: Format,
- },
-}
-
-impl error::Error for ShaderInterfaceMismatchError {}
-
-impl fmt::Display for ShaderInterfaceMismatchError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- ShaderInterfaceMismatchError::ElementsCountMismatch { .. } => {
- "the number of elements mismatches"
- }
- ShaderInterfaceMismatchError::MissingElement { .. } => "an element is missing",
- ShaderInterfaceMismatchError::FormatMismatch { .. } => {
- "the format of an element does not match"
- }
- }
- )
- }
-}
-
-/// Trait for types that contain specialization data for shaders.
-///
-/// Shader modules can contain what is called *specialization constants*. They are the same as
-/// constants except that their values can be defined when you create a compute pipeline or a
-/// graphics pipeline. Doing so is done by passing a type that implements the
-/// `SpecializationConstants` trait and that stores the values in question. The `descriptors()`
-/// method of this trait indicates how to grab them.
-///
-/// Boolean specialization constants must be stored as 32bits integers, where `0` means `false` and
-/// any non-zero value means `true`. Integer and floating-point specialization constants are
-/// stored as their Rust equivalent.
-///
-/// This trait is implemented on `()` for shaders that don't have any specialization constant.
-///
-/// Note that it is the shader module that chooses which type that implements
-/// `SpecializationConstants` it is possible to pass when creating the pipeline, through [the
-/// `EntryPointAbstract` trait](trait.EntryPointAbstract.html). Therefore there is generally no
-/// point to implement this trait yourself, unless you are also writing your own implementation of
-/// `EntryPointAbstract`.
-///
-/// # Example
-///
-/// ```rust
-/// use vulkano::pipeline::shader::SpecializationConstants;
-/// use vulkano::pipeline::shader::SpecializationMapEntry;
-///
-/// #[repr(C)] // `#[repr(C)]` guarantees that the struct has a specific layout
-/// struct MySpecConstants {
-/// my_integer_constant: i32,
-/// a_boolean: u32,
-/// floating_point: f32,
-/// }
-///
-/// unsafe impl SpecializationConstants for MySpecConstants {
-/// fn descriptors() -> &'static [SpecializationMapEntry] {
-/// static DESCRIPTORS: [SpecializationMapEntry; 3] = [
-/// SpecializationMapEntry {
-/// constant_id: 0,
-/// offset: 0,
-/// size: 4,
-/// },
-/// SpecializationMapEntry {
-/// constant_id: 1,
-/// offset: 4,
-/// size: 4,
-/// },
-/// SpecializationMapEntry {
-/// constant_id: 2,
-/// offset: 8,
-/// size: 4,
-/// },
-/// ];
-///
-/// &DESCRIPTORS
-/// }
-/// }
-/// ```
-///
-/// # Safety
-///
-/// - The `SpecializationMapEntry` returned must contain valid offsets and sizes.
-/// - The size of each `SpecializationMapEntry` must match the size of the corresponding constant
-/// (`4` for booleans).
-///
-pub unsafe trait SpecializationConstants {
- /// Returns descriptors of the struct's layout.
- fn descriptors() -> &'static [SpecializationMapEntry];
-}
-
-unsafe impl SpecializationConstants for () {
- #[inline]
- fn descriptors() -> &'static [SpecializationMapEntry] {
- &[]
- }
-}
-
-/// Describes an individual constant to set in the shader. Also a field in the struct.
-// Implementation note: has the same memory representation as a `VkSpecializationMapEntry`.
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-#[repr(C)]
-pub struct SpecializationMapEntry {
- /// Identifier of the constant in the shader that corresponds to this field.
- ///
- /// For SPIR-V, this must be the value of the `SpecId` decoration applied to the specialization
- /// constant.
- /// For GLSL, this must be the value of `N` in the `layout(constant_id = N)` attribute applied
- /// to a constant.
- pub constant_id: u32,
-
- /// Offset within the struct where the data can be found.
- pub offset: u32,
-
- /// Size of the data in bytes. Must match the size of the constant (`4` for booleans).
- pub size: usize,
-}
-
-/// Describes a set of shader stages.
-// TODO: add example with BitOr
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct ShaderStages {
- pub vertex: bool,
- pub tessellation_control: bool,
- pub tessellation_evaluation: bool,
- pub geometry: bool,
- pub fragment: bool,
- pub compute: bool,
-}
-
-impl ShaderStages {
- /// Creates a `ShaderStages` struct will all stages set to `true`.
- // TODO: add example
- #[inline]
- pub const fn all() -> ShaderStages {
- ShaderStages {
- vertex: true,
- tessellation_control: true,
- tessellation_evaluation: true,
- geometry: true,
- fragment: true,
- compute: true,
- }
- }
-
- /// Creates a `ShaderStages` struct will all stages set to `false`.
- // TODO: add example
- #[inline]
- pub const fn none() -> ShaderStages {
- ShaderStages {
- vertex: false,
- tessellation_control: false,
- tessellation_evaluation: false,
- geometry: false,
- fragment: false,
- compute: false,
- }
- }
-
- /// Creates a `ShaderStages` struct with all graphics stages set to `true`.
- // TODO: add example
- #[inline]
- pub const fn all_graphics() -> ShaderStages {
- ShaderStages {
- vertex: true,
- tessellation_control: true,
- tessellation_evaluation: true,
- geometry: true,
- fragment: true,
- compute: false,
- }
- }
-
- /// Creates a `ShaderStages` struct with the compute stage set to `true`.
- // TODO: add example
- #[inline]
- pub const fn compute() -> ShaderStages {
- ShaderStages {
- vertex: false,
- tessellation_control: false,
- tessellation_evaluation: false,
- geometry: false,
- fragment: false,
- compute: true,
- }
- }
-
- /// Checks whether we have more stages enabled than `other`.
- // TODO: add example
- #[inline]
- pub const fn ensure_superset_of(
- &self,
- other: &ShaderStages,
- ) -> Result<(), ShaderStagesSupersetError> {
- if (self.vertex || !other.vertex)
- && (self.tessellation_control || !other.tessellation_control)
- && (self.tessellation_evaluation || !other.tessellation_evaluation)
- && (self.geometry || !other.geometry)
- && (self.fragment || !other.fragment)
- && (self.compute || !other.compute)
- {
- Ok(())
- } else {
- Err(ShaderStagesSupersetError::NotSuperset)
- }
- }
-
- /// Checks whether any of the stages in `self` are also present in `other`.
- // TODO: add example
- #[inline]
- pub const fn intersects(&self, other: &ShaderStages) -> bool {
- (self.vertex && other.vertex)
- || (self.tessellation_control && other.tessellation_control)
- || (self.tessellation_evaluation && other.tessellation_evaluation)
- || (self.geometry && other.geometry)
- || (self.fragment && other.fragment)
- || (self.compute && other.compute)
- }
-}
-
-impl From<ShaderStages> for ash::vk::ShaderStageFlags {
- #[inline]
- fn from(val: ShaderStages) -> Self {
- let mut result = ash::vk::ShaderStageFlags::empty();
- if val.vertex {
- result |= ash::vk::ShaderStageFlags::VERTEX;
- }
- if val.tessellation_control {
- result |= ash::vk::ShaderStageFlags::TESSELLATION_CONTROL;
- }
- if val.tessellation_evaluation {
- result |= ash::vk::ShaderStageFlags::TESSELLATION_EVALUATION;
- }
- if val.geometry {
- result |= ash::vk::ShaderStageFlags::GEOMETRY;
- }
- if val.fragment {
- result |= ash::vk::ShaderStageFlags::FRAGMENT;
- }
- if val.compute {
- result |= ash::vk::ShaderStageFlags::COMPUTE;
- }
- result
- }
-}
-
-impl From<ash::vk::ShaderStageFlags> for ShaderStages {
- #[inline]
- fn from(val: ash::vk::ShaderStageFlags) -> Self {
- Self {
- vertex: val.intersects(ash::vk::ShaderStageFlags::VERTEX),
- tessellation_control: val.intersects(ash::vk::ShaderStageFlags::TESSELLATION_CONTROL),
- tessellation_evaluation: val
- .intersects(ash::vk::ShaderStageFlags::TESSELLATION_EVALUATION),
- geometry: val.intersects(ash::vk::ShaderStageFlags::GEOMETRY),
- fragment: val.intersects(ash::vk::ShaderStageFlags::FRAGMENT),
- compute: val.intersects(ash::vk::ShaderStageFlags::COMPUTE),
- }
- }
-}
-
-impl BitOr for ShaderStages {
- type Output = ShaderStages;
-
- #[inline]
- fn bitor(self, other: ShaderStages) -> ShaderStages {
- ShaderStages {
- vertex: self.vertex || other.vertex,
- tessellation_control: self.tessellation_control || other.tessellation_control,
- tessellation_evaluation: self.tessellation_evaluation || other.tessellation_evaluation,
- geometry: self.geometry || other.geometry,
- fragment: self.fragment || other.fragment,
- compute: self.compute || other.compute,
- }
- }
-}
-
-impl From<ShaderStages> for PipelineStages {
- #[inline]
- fn from(stages: ShaderStages) -> PipelineStages {
- PipelineStages {
- vertex_shader: stages.vertex,
- tessellation_control_shader: stages.tessellation_control,
- tessellation_evaluation_shader: stages.tessellation_evaluation,
- geometry_shader: stages.geometry,
- fragment_shader: stages.fragment,
- compute_shader: stages.compute,
- ..PipelineStages::none()
- }
- }
-}
-
-/// Error when checking that a `ShaderStages` object is a superset of another.
-#[derive(Debug, Clone)]
-pub enum ShaderStagesSupersetError {
- NotSuperset,
-}
-
-impl error::Error for ShaderStagesSupersetError {}
-
-impl fmt::Display for ShaderStagesSupersetError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- ShaderStagesSupersetError::NotSuperset => "shader stages not a superset",
- }
- )
- }
-}
diff --git a/src/pipeline/vertex/bufferless.rs b/src/pipeline/vertex/bufferless.rs
deleted file mode 100644
index 7bb8cd4..0000000
--- a/src/pipeline/vertex/bufferless.rs
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright (c) 2017 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::buffer::BufferAccess;
-use crate::pipeline::shader::ShaderInterface;
-use crate::pipeline::vertex::IncompatibleVertexDefinitionError;
-use crate::pipeline::vertex::VertexDefinition;
-use crate::pipeline::vertex::VertexInput;
-use crate::pipeline::vertex::VertexSource;
-
-/// Implementation of `VertexDefinition` for drawing with no buffers at all.
-///
-/// This is only useful if your shaders come up with vertex data on their own, e.g. by inspecting
-/// `gl_VertexIndex`
-#[derive(Copy, Clone)]
-pub struct BufferlessDefinition;
-
-/// Value to be passed as the vertex source for bufferless draw commands.
-///
-/// Note that the concrete type of the graphics pipeline using `BufferlessDefinition` must be
-/// visible to the command buffer builder for this to be usable.
-#[derive(Copy, Clone)]
-pub struct BufferlessVertices {
- pub vertices: usize,
- pub instances: usize,
-}
-
-unsafe impl VertexSource<BufferlessVertices> for BufferlessDefinition {
- fn decode(
- &self,
- n: BufferlessVertices,
- ) -> (
- Vec<Box<dyn BufferAccess + Sync + Send + 'static>>,
- usize,
- usize,
- ) {
- (Vec::new(), n.vertices, n.instances)
- }
-}
-
-unsafe impl<T> VertexSource<Vec<T>> for BufferlessDefinition {
- fn decode<'l>(
- &self,
- _: Vec<T>,
- ) -> (
- Vec<Box<dyn BufferAccess + Sync + Send + 'static>>,
- usize,
- usize,
- ) {
- panic!("bufferless drawing should not be supplied with buffers")
- }
-}
-
-unsafe impl VertexDefinition for BufferlessDefinition {
- fn definition(
- &self,
- _: &ShaderInterface,
- ) -> Result<VertexInput, IncompatibleVertexDefinitionError> {
- Ok(VertexInput::empty())
- }
-}
diff --git a/src/pipeline/vertex/buffers.rs b/src/pipeline/vertex/buffers.rs
deleted file mode 100644
index 1ef9d40..0000000
--- a/src/pipeline/vertex/buffers.rs
+++ /dev/null
@@ -1,234 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use super::VertexMemberInfo;
-use crate::buffer::BufferAccess;
-use crate::pipeline::shader::ShaderInterface;
-use crate::pipeline::vertex::IncompatibleVertexDefinitionError;
-use crate::pipeline::vertex::Vertex;
-use crate::pipeline::vertex::VertexDefinition;
-use crate::pipeline::vertex::VertexInput;
-use crate::pipeline::vertex::VertexInputAttribute;
-use crate::pipeline::vertex::VertexInputBinding;
-use crate::pipeline::vertex::VertexInputRate;
-use crate::pipeline::vertex::VertexSource;
-use crate::DeviceSize;
-use std::mem;
-use std::sync::Arc;
-
-/// A vertex definition for any number of vertex and instance buffers.
-#[derive(Clone, Default)]
-pub struct BuffersDefinition(Vec<VertexBuffer>);
-
-#[derive(Clone, Copy)]
-struct VertexBuffer {
- info_fn: fn(&str) -> Option<VertexMemberInfo>,
- stride: u32,
- input_rate: VertexInputRate,
-}
-
-impl From<VertexBuffer> for VertexInputBinding {
- #[inline]
- fn from(val: VertexBuffer) -> Self {
- Self {
- stride: val.stride,
- input_rate: val.input_rate,
- }
- }
-}
-
-impl BuffersDefinition {
- /// Constructs a new definition.
- pub fn new() -> Self {
- BuffersDefinition(Vec::new())
- }
-
- /// Adds a new vertex buffer containing elements of type `V` to the definition.
- pub fn vertex<V: Vertex>(mut self) -> Self {
- self.0.push(VertexBuffer {
- info_fn: V::member,
- stride: mem::size_of::<V>() as u32,
- input_rate: VertexInputRate::Vertex,
- });
- self
- }
-
- /// Adds a new instance buffer containing elements of type `V` to the definition.
- pub fn instance<V: Vertex>(mut self) -> Self {
- self.0.push(VertexBuffer {
- info_fn: V::member,
- stride: mem::size_of::<V>() as u32,
- input_rate: VertexInputRate::Instance { divisor: 1 },
- });
- self
- }
-
- /// Adds a new instance buffer containing elements of type `V` to the definition, with the
- /// specified input rate divisor.
- ///
- /// This requires the
- /// [`vertex_attribute_instance_rate_divisor`](crate::device::Features::vertex_attribute_instance_rate_divisor)
- /// feature has been enabled on the device, unless `divisor` is 1.
- ///
- /// `divisor` can be 0 if the
- /// [`vertex_attribute_instance_rate_zero_divisor`](crate::device::Features::vertex_attribute_instance_rate_zero_divisor)
- /// feature is also enabled. This means that every vertex will use the same vertex and instance
- /// data.
- pub fn instance_with_divisor<V: Vertex>(mut self, divisor: u32) -> Self {
- self.0.push(VertexBuffer {
- info_fn: V::member,
- stride: mem::size_of::<V>() as u32,
- input_rate: VertexInputRate::Instance { divisor },
- });
- self
- }
-}
-
-unsafe impl VertexDefinition for BuffersDefinition {
- fn definition(
- &self,
- interface: &ShaderInterface,
- ) -> Result<VertexInput, IncompatibleVertexDefinitionError> {
- let bindings = self
- .0
- .iter()
- .enumerate()
- .map(|(binding, &buffer)| (binding as u32, buffer.into()));
- let mut attributes: Vec<(u32, VertexInputAttribute)> = Vec::new();
-
- for element in interface.elements() {
- let name = element.name.as_ref().unwrap();
-
- let (infos, binding) = self
- .0
- .iter()
- .enumerate()
- .find_map(|(binding, buffer)| {
- (buffer.info_fn)(name).map(|infos| (infos, binding as u32))
- })
- .ok_or_else(||
- // TODO: move this check to GraphicsPipelineBuilder
- IncompatibleVertexDefinitionError::MissingAttribute {
- attribute: name.clone().into_owned(),
- })?;
-
- if !infos.ty.matches(
- infos.array_size,
- element.format,
- element.location.end - element.location.start,
- ) {
- // TODO: move this check to GraphicsPipelineBuilder
- return Err(IncompatibleVertexDefinitionError::FormatMismatch {
- attribute: name.clone().into_owned(),
- shader: (
- element.format,
- (element.location.end - element.location.start) as usize,
- ),
- definition: (infos.ty, infos.array_size),
- });
- }
-
- let mut offset = infos.offset as DeviceSize;
- for location in element.location.clone() {
- attributes.push((
- location,
- VertexInputAttribute {
- binding,
- format: element.format,
- offset: offset as u32,
- },
- ));
- offset += element.format.size().unwrap();
- }
- }
-
- Ok(VertexInput::new(bindings, attributes))
- }
-}
-
-unsafe impl VertexSource<Vec<Arc<dyn BufferAccess + Send + Sync>>> for BuffersDefinition {
- #[inline]
- fn decode(
- &self,
- source: Vec<Arc<dyn BufferAccess + Send + Sync>>,
- ) -> (Vec<Box<dyn BufferAccess + Send + Sync>>, usize, usize) {
- let result = source
- .into_iter()
- .map(|source| Box::new(source) as Box<_>)
- .collect::<Vec<_>>();
- let (vertices, instances) = self.vertices_instances(&result);
- (result, vertices, instances)
- }
-}
-
-unsafe impl<B> VertexSource<B> for BuffersDefinition
-where
- B: BufferAccess + Send + Sync + 'static,
-{
- #[inline]
- fn decode(&self, source: B) -> (Vec<Box<dyn BufferAccess + Send + Sync>>, usize, usize) {
- let result = vec![Box::new(source) as Box<_>];
- let (vertices, instances) = self.vertices_instances(&result);
- (result, vertices, instances)
- }
-}
-
-unsafe impl<B1, B2> VertexSource<(B1, B2)> for BuffersDefinition
-where
- B1: BufferAccess + Send + Sync + 'static,
- B2: BufferAccess + Send + Sync + 'static,
-{
- #[inline]
- fn decode(&self, source: (B1, B2)) -> (Vec<Box<dyn BufferAccess + Send + Sync>>, usize, usize) {
- let result = vec![Box::new(source.0) as Box<_>, Box::new(source.1) as Box<_>];
- let (vertices, instances) = self.vertices_instances(&result);
- (result, vertices, instances)
- }
-}
-
-impl BuffersDefinition {
- fn vertices_instances(&self, source: &[Box<dyn BufferAccess + Send + Sync>]) -> (usize, usize) {
- assert_eq!(source.len(), self.0.len());
- let mut vertices = None;
- let mut instances = None;
-
- for (buffer, source) in self.0.iter().zip(source) {
- let items = (source.size() / buffer.stride as DeviceSize) as usize;
- let (items, count) = match buffer.input_rate {
- VertexInputRate::Vertex => (items, &mut vertices),
- VertexInputRate::Instance { divisor } => (
- if divisor == 0 {
- // A divisor of 0 means the same instance data is used for all instances,
- // so we can draw any number of instances from a single element.
- // The buffer must contain at least one element though.
- if items == 0 {
- 0
- } else {
- usize::MAX
- }
- } else {
- // If divisor is 2, we use only half the amount of data from the source buffer,
- // so the number of instances that can be drawn is twice as large.
- items * divisor as usize
- },
- &mut instances,
- ),
- };
-
- if let Some(count) = count {
- *count = std::cmp::min(*count, items);
- } else {
- *count = Some(items);
- }
- }
-
- // TODO: find some way to let the user specify these when drawing
- (vertices.unwrap_or(1), instances.unwrap_or(1))
- }
-}
diff --git a/src/pipeline/vertex/definition.rs b/src/pipeline/vertex/definition.rs
deleted file mode 100644
index 966feda..0000000
--- a/src/pipeline/vertex/definition.rs
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::buffer::BufferAccess;
-use crate::format::Format;
-use crate::pipeline::shader::ShaderInterface;
-use crate::pipeline::vertex::VertexInput;
-use crate::pipeline::vertex::VertexMemberTy;
-use crate::SafeDeref;
-use std::error;
-use std::fmt;
-use std::sync::Arc;
-
-/// Trait for types that describe the definition of the vertex input used by a graphics pipeline.
-pub unsafe trait VertexDefinition:
- VertexSource<Vec<Arc<dyn BufferAccess + Send + Sync>>>
-{
- /// Builds the vertex definition to use to link this definition to a vertex shader's input
- /// interface.
- // TODO: remove error return, move checks to GraphicsPipelineBuilder
- fn definition(
- &self,
- interface: &ShaderInterface,
- ) -> Result<VertexInput, IncompatibleVertexDefinitionError>;
-}
-
-unsafe impl<T> VertexDefinition for T
-where
- T: SafeDeref,
- T::Target: VertexDefinition,
-{
- #[inline]
- fn definition(
- &self,
- interface: &ShaderInterface,
- ) -> Result<VertexInput, IncompatibleVertexDefinitionError> {
- (**self).definition(interface)
- }
-}
-
-/// Error that can happen when the vertex definition doesn't match the input of the vertex shader.
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum IncompatibleVertexDefinitionError {
- /// An attribute of the vertex shader is missing in the vertex source.
- MissingAttribute {
- /// Name of the missing attribute.
- attribute: String,
- },
-
- /// The format of an attribute does not match.
- FormatMismatch {
- /// Name of the attribute.
- attribute: String,
- /// The format in the vertex shader.
- shader: (Format, usize),
- /// The format in the vertex definition.
- definition: (VertexMemberTy, usize),
- },
-}
-
-impl error::Error for IncompatibleVertexDefinitionError {}
-
-impl fmt::Display for IncompatibleVertexDefinitionError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- IncompatibleVertexDefinitionError::MissingAttribute { .. } =>
- "an attribute is missing",
- IncompatibleVertexDefinitionError::FormatMismatch { .. } => {
- "the format of an attribute does not match"
- }
- }
- )
- }
-}
-
-/// Extension trait of `VertexDefinition`. The `L` parameter is an acceptable vertex source for this
-/// vertex definition.
-pub unsafe trait VertexSource<L> {
- /// Checks and returns the list of buffers with offsets, number of vertices and number of instances.
- // TODO: return error if problem
- // TODO: better than a Vec
- // TODO: return a struct instead
- fn decode(&self, list: L) -> (Vec<Box<dyn BufferAccess + Send + Sync>>, usize, usize);
-}
-
-unsafe impl<L, T> VertexSource<L> for T
-where
- T: SafeDeref,
- T::Target: VertexSource<L>,
-{
- #[inline]
- fn decode(&self, list: L) -> (Vec<Box<dyn BufferAccess + Send + Sync>>, usize, usize) {
- (**self).decode(list)
- }
-}
diff --git a/src/pipeline/vertex/impl_vertex.rs b/src/pipeline/vertex/impl_vertex.rs
deleted file mode 100644
index 7694b96..0000000
--- a/src/pipeline/vertex/impl_vertex.rs
+++ /dev/null
@@ -1,199 +0,0 @@
-// Copyright (c) 2017 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::pipeline::vertex::VertexMemberTy;
-
-/// Implements the `Vertex` trait on a struct.
-///# Example
-///
-///```
-///#[derive(Default, Copy, Clone)]
-///struct Vertex{
-/// position: [f32; 3],
-/// color: [f32; 4]
-///}
-///
-///vulkano::impl_vertex!(Vertex, position, color);
-///
-///```
-#[macro_export]
-macro_rules! impl_vertex {
- ($out:ty $(, $member:ident)*) => (
- #[allow(unsafe_code)]
- unsafe impl $crate::pipeline::vertex::Vertex for $out {
- #[inline(always)]
- fn member(name: &str) -> Option<$crate::pipeline::vertex::VertexMemberInfo> {
- use std::ptr;
- #[allow(unused_imports)]
- use $crate::format::Format;
- use $crate::pipeline::vertex::VertexMemberInfo;
- use $crate::pipeline::vertex::VertexMemberTy;
- use $crate::pipeline::vertex::VertexMember;
-
- $(
- if name == stringify!($member) {
- let dummy = <$out>::default();
- #[inline] fn f<T: VertexMember>(_: &T) -> (VertexMemberTy, usize) { T::format() }
- let (ty, array_size) = f(&dummy.$member);
-
- let dummy_ptr = (&dummy) as *const _;
- let member_ptr = (&dummy.$member) as *const _;
-
- return Some(VertexMemberInfo {
- offset: member_ptr as usize - dummy_ptr as usize,
- ty: ty,
- array_size: array_size,
- });
- }
- )*
-
- None
- }
- }
- )
-}
-
-/// Trait for data types that can be used as vertex members. Used by the `impl_vertex!` macro.
-pub unsafe trait VertexMember {
- /// Returns the format and array size of the member.
- fn format() -> (VertexMemberTy, usize);
-}
-
-unsafe impl VertexMember for i8 {
- #[inline]
- fn format() -> (VertexMemberTy, usize) {
- (VertexMemberTy::I8, 1)
- }
-}
-
-unsafe impl VertexMember for u8 {
- #[inline]
- fn format() -> (VertexMemberTy, usize) {
- (VertexMemberTy::U8, 1)
- }
-}
-
-unsafe impl VertexMember for i16 {
- #[inline]
- fn format() -> (VertexMemberTy, usize) {
- (VertexMemberTy::I16, 1)
- }
-}
-
-unsafe impl VertexMember for u16 {
- #[inline]
- fn format() -> (VertexMemberTy, usize) {
- (VertexMemberTy::U16, 1)
- }
-}
-
-unsafe impl VertexMember for i32 {
- #[inline]
- fn format() -> (VertexMemberTy, usize) {
- (VertexMemberTy::I32, 1)
- }
-}
-
-unsafe impl VertexMember for u32 {
- #[inline]
- fn format() -> (VertexMemberTy, usize) {
- (VertexMemberTy::U32, 1)
- }
-}
-
-unsafe impl VertexMember for f32 {
- #[inline]
- fn format() -> (VertexMemberTy, usize) {
- (VertexMemberTy::F32, 1)
- }
-}
-
-unsafe impl VertexMember for f64 {
- #[inline]
- fn format() -> (VertexMemberTy, usize) {
- (VertexMemberTy::F64, 1)
- }
-}
-
-unsafe impl<T> VertexMember for (T,)
-where
- T: VertexMember,
-{
- #[inline]
- fn format() -> (VertexMemberTy, usize) {
- <T as VertexMember>::format()
- }
-}
-
-unsafe impl<T> VertexMember for (T, T)
-where
- T: VertexMember,
-{
- #[inline]
- fn format() -> (VertexMemberTy, usize) {
- let (ty, sz) = <T as VertexMember>::format();
- (ty, sz * 2)
- }
-}
-
-unsafe impl<T> VertexMember for (T, T, T)
-where
- T: VertexMember,
-{
- #[inline]
- fn format() -> (VertexMemberTy, usize) {
- let (ty, sz) = <T as VertexMember>::format();
- (ty, sz * 3)
- }
-}
-
-unsafe impl<T> VertexMember for (T, T, T, T)
-where
- T: VertexMember,
-{
- #[inline]
- fn format() -> (VertexMemberTy, usize) {
- let (ty, sz) = <T as VertexMember>::format();
- (ty, sz * 4)
- }
-}
-
-macro_rules! impl_vm_array {
- ($sz:expr) => {
- unsafe impl<T> VertexMember for [T; $sz]
- where
- T: VertexMember,
- {
- #[inline]
- fn format() -> (VertexMemberTy, usize) {
- let (ty, sz) = <T as VertexMember>::format();
- (ty, sz * $sz)
- }
- }
- };
-}
-
-impl_vm_array!(1);
-impl_vm_array!(2);
-impl_vm_array!(3);
-impl_vm_array!(4);
-impl_vm_array!(5);
-impl_vm_array!(6);
-impl_vm_array!(7);
-impl_vm_array!(8);
-impl_vm_array!(9);
-impl_vm_array!(10);
-impl_vm_array!(11);
-impl_vm_array!(12);
-impl_vm_array!(13);
-impl_vm_array!(14);
-impl_vm_array!(15);
-impl_vm_array!(16);
-impl_vm_array!(32);
-impl_vm_array!(64);
diff --git a/src/pipeline/vertex/mod.rs b/src/pipeline/vertex/mod.rs
deleted file mode 100644
index a8886a8..0000000
--- a/src/pipeline/vertex/mod.rs
+++ /dev/null
@@ -1,244 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-//! # Vertex sources definition
-//!
-//! When you create a graphics pipeline object, you need to pass an object which indicates the
-//! layout of the vertex buffer(s) that will serve as input for the vertex shader. This is done
-//! by passing an implementation of the `VertexDefinition` trait.
-//!
-//! In addition to this, the object that you pass when you create the graphics pipeline must also
-//! implement the `VertexSource` trait. This trait has a template parameter which corresponds to the
-//! list of vertex buffers.
-//!
-//! The vulkano library provides some structs that already implement these traits.
-//! The most common situation is a single vertex buffer and no instancing, in which case you can
-//! pass a `SingleBufferDefinition` when you create the pipeline.
-//!
-//! # Implementing `Vertex`
-//!
-//! The implementations of the `VertexDefinition` trait that are provided by vulkano (like
-//! `SingleBufferDefinition`) require you to use a buffer whose content is `[V]` where `V`
-//! implements the `Vertex` trait.
-//!
-//! The `Vertex` trait is unsafe, but can be implemented on a struct with the `impl_vertex!`
-//! macro.
-//!
-//! # Example
-//!
-//! ```ignore // TODO:
-//! # #[macro_use] extern crate vulkano
-//! # fn main() {
-//! # use std::sync::Arc;
-//! # use vulkano::device::Device;
-//! # use vulkano::device::Queue;
-//! use vulkano::buffer::BufferAccess;
-//! use vulkano::buffer::BufferUsage;
-//! use vulkano::memory::HostVisible;
-//! use vulkano::pipeline::vertex::;
-//! # let device: Arc<Device> = return;
-//! # let queue: Arc<Queue> = return;
-//!
-//! struct Vertex {
-//! position: [f32; 2]
-//! }
-//!
-//! impl_vertex!(Vertex, position);
-//!
-//! let usage = BufferUsage {
-//! vertex_buffer: true,
-//! .. BufferUsage::none()
-//! };
-//!
-//! let vertex_buffer = BufferAccess::<[Vertex], _>::array(&device, 128, &usage, HostVisible, &queue)
-//! .expect("failed to create buffer");
-//!
-//! // TODO: finish example
-//! # }
-//! ```
-
-pub use self::bufferless::BufferlessDefinition;
-pub use self::bufferless::BufferlessVertices;
-pub use self::buffers::BuffersDefinition;
-pub use self::definition::IncompatibleVertexDefinitionError;
-pub use self::definition::VertexDefinition;
-pub use self::definition::VertexSource;
-pub use self::impl_vertex::VertexMember;
-pub use self::vertex::Vertex;
-pub use self::vertex::VertexMemberInfo;
-pub use self::vertex::VertexMemberTy;
-use crate::buffer::BufferAccess;
-use crate::format::Format;
-use crate::DeviceSize;
-use fnv::FnvHashMap;
-use std::convert::TryInto;
-
-mod bufferless;
-mod buffers;
-mod definition;
-mod impl_vertex;
-mod vertex;
-
-/// A description of the vertex input of a graphics pipeline.
-#[derive(Clone, Debug, Default)]
-pub struct VertexInput {
- bindings: FnvHashMap<u32, VertexInputBinding>,
- attributes: FnvHashMap<u32, VertexInputAttribute>,
-}
-
-impl VertexInput {
- /// Constructs a new `VertexInput` from the given bindings and attributes.
- ///
- /// # Panics
- ///
- /// Panics if any element of `attributes` refers to a binding number that is not provided in
- /// `bindings`.
- #[inline]
- pub fn new(
- bindings: impl IntoIterator<Item = (u32, VertexInputBinding)>,
- attributes: impl IntoIterator<Item = (u32, VertexInputAttribute)>,
- ) -> VertexInput {
- let bindings: FnvHashMap<_, _> = bindings.into_iter().collect();
- let attributes: FnvHashMap<_, _> = attributes.into_iter().collect();
-
- assert!(attributes
- .iter()
- .all(|(_, attr)| bindings.contains_key(&attr.binding)));
-
- VertexInput {
- bindings,
- attributes,
- }
- }
-
- /// Constructs a new empty `VertexInput`.
- #[inline]
- pub fn empty() -> VertexInput {
- VertexInput {
- bindings: Default::default(),
- attributes: Default::default(),
- }
- }
-
- /// Returns an iterator of the binding numbers and their descriptions.
- #[inline]
- pub fn bindings(&self) -> impl ExactSizeIterator<Item = (u32, &VertexInputBinding)> {
- self.bindings.iter().map(|(&key, val)| (key, val))
- }
-
- /// Returns an iterator of the attribute numbers and their descriptions.
- #[inline]
- pub fn attributes(&self) -> impl ExactSizeIterator<Item = (u32, &VertexInputAttribute)> {
- self.attributes.iter().map(|(&key, val)| (key, val))
- }
-
- /// Given an iterator of vertex buffers and their binding numbers, returns the maximum number
- /// of vertices and instances that can be drawn with them.
- ///
- /// # Panics
- ///
- /// Panics if the binding number of a provided vertex buffer does not exist in `self`.
- pub fn max_vertices_instances<'a>(
- &self,
- buffers: impl IntoIterator<Item = (u32, &'a dyn BufferAccess)>,
- ) -> (u32, u32) {
- let buffers = buffers.into_iter();
- let mut max_vertices = u32::MAX;
- let mut max_instances = u32::MAX;
-
- for (binding, buffer) in buffers {
- let binding_desc = &self.bindings[&binding];
- let mut num_elements = (buffer.size() / binding_desc.stride as DeviceSize)
- .try_into()
- .unwrap_or(u32::MAX);
-
- match binding_desc.input_rate {
- VertexInputRate::Vertex => {
- max_vertices = max_vertices.min(num_elements);
- }
- VertexInputRate::Instance { divisor } => {
- if divisor == 0 {
- // A divisor of 0 means the same instance data is used for all instances,
- // so we can draw any number of instances from a single element.
- // The buffer must contain at least one element though.
- if num_elements != 0 {
- num_elements = u32::MAX;
- }
- } else {
- // If divisor is 2, we use only half the amount of data from the source buffer,
- // so the number of instances that can be drawn is twice as large.
- num_elements = num_elements.saturating_mul(divisor);
- }
-
- max_instances = max_instances.min(num_elements);
- }
- };
- }
-
- (max_vertices, max_instances)
- }
-}
-
-/// Describes a single vertex buffer binding in a graphics pipeline.
-#[derive(Clone, Debug)]
-pub struct VertexInputBinding {
- /// The size of each element in the vertex buffer.
- pub stride: u32,
- /// How often the vertex input should advance to the next element.
- pub input_rate: VertexInputRate,
-}
-
-/// Describes how each vertex shader input attribute should be read from a vertex buffer.
-///
-/// An attribute can contain a maximum of four data elements, described by a particular `Format`.
-/// For shader inputs that are larger than this, such as matrices or arrays, multiple separate
-/// attributes should be used, with increasing offsets.
-///
-/// For example, to pass a `mat4` to the shader using sixteen `f32` as input, you would include four
-/// attributes with `Format::R32G32B32A32Sfloat`, using the offset of the matrix from the start of
-/// the vertex buffer element, plus 0, 16, 32, 48 respectively.
-#[derive(Clone, Copy, Debug)]
-pub struct VertexInputAttribute {
- /// The vertex buffer binding number that this attribute should take its data from.
- pub binding: u32,
- /// The size and type of the vertex data.
- pub format: Format,
- /// Number of bytes between the start of a vertex buffer element and the location of attribute.
- pub offset: u32,
-}
-
-/// How the vertex source should be unrolled.
-#[derive(Clone, Copy, Debug)]
-pub enum VertexInputRate {
- /// Each element of the source corresponds to a vertex.
- Vertex,
-
- /// Each element of the source corresponds to an instance.
- ///
- /// `divisor` indicates how many consecutive instances will use the same instance buffer data.
- /// This value must be 1, unless the
- /// [`vertex_attribute_instance_rate_divisor`](crate::device::Features::vertex_attribute_instance_rate_divisor)
- /// feature has been enabled on the device.
- ///
- /// `divisor` can be 0 if the
- /// [`vertex_attribute_instance_rate_zero_divisor`](crate::device::Features::vertex_attribute_instance_rate_zero_divisor)
- /// feature is also enabled. This means that every vertex will use the same vertex and instance
- /// data.
- Instance { divisor: u32 },
-}
-
-impl From<VertexInputRate> for ash::vk::VertexInputRate {
- #[inline]
- fn from(val: VertexInputRate) -> Self {
- match val {
- VertexInputRate::Vertex => ash::vk::VertexInputRate::VERTEX,
- VertexInputRate::Instance { .. } => ash::vk::VertexInputRate::INSTANCE,
- }
- }
-}
diff --git a/src/pipeline/vertex/vertex.rs b/src/pipeline/vertex/vertex.rs
deleted file mode 100644
index 728fcaa..0000000
--- a/src/pipeline/vertex/vertex.rs
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright (c) 2017 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::format::Format;
-
-/// Describes an individual `Vertex`. In other words a collection of attributes that can be read
-/// from a vertex shader.
-///
-/// At this stage, the vertex is in a "raw" format. For example a `[f32; 4]` can match both a
-/// `vec4` or a `float[4]`. The way the things are bound depends on the shader.
-pub unsafe trait Vertex: 'static + Send + Sync {
- /// Returns the characteristics of a vertex member by its name.
- fn member(name: &str) -> Option<VertexMemberInfo>;
-}
-
-unsafe impl Vertex for () {
- #[inline]
- fn member(_: &str) -> Option<VertexMemberInfo> {
- None
- }
-}
-
-/// Information about a member of a vertex struct.
-pub struct VertexMemberInfo {
- /// Offset of the member in bytes from the start of the struct.
- pub offset: usize,
- /// Type of data. This is used to check that the interface is matching.
- pub ty: VertexMemberTy,
- /// Number of consecutive elements of that type.
- pub array_size: usize,
-}
-
-/// Type of a member of a vertex struct.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-#[allow(missing_docs)]
-pub enum VertexMemberTy {
- I8,
- U8,
- I16,
- U16,
- I32,
- U32,
- F32,
- F64,
-}
-
-impl VertexMemberTy {
- /// Returns true if a combination of `(type, array_size)` matches a format.
- #[inline]
- pub fn matches(&self, array_size: usize, format: Format, num_locs: u32) -> bool {
- // TODO: implement correctly
- let my_size = match *self {
- VertexMemberTy::I8 => 1,
- VertexMemberTy::U8 => 1,
- VertexMemberTy::I16 => 2,
- VertexMemberTy::U16 => 2,
- VertexMemberTy::I32 => 4,
- VertexMemberTy::U32 => 4,
- VertexMemberTy::F32 => 4,
- VertexMemberTy::F64 => 8,
- };
-
- let format_size = match format.size() {
- None => return false,
- Some(s) => s,
- } as usize;
-
- array_size * my_size == format_size * num_locs as usize
- }
-}
diff --git a/src/query.rs b/src/query.rs
index 44caada..bb4b885 100644
--- a/src/query.rs
+++ b/src/query.rs
@@ -13,44 +13,61 @@
//! represent a collection of queries. Whenever you use a query, you have to specify both the query
//! pool and the slot id within that query pool.
-use crate::check_errors;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::DeviceSize;
-use crate::Error;
-use crate::OomError;
-use crate::Success;
-use crate::VulkanObject;
-use std::error;
-use std::ffi::c_void;
-use std::fmt;
-use std::mem::MaybeUninit;
-use std::ops::Range;
-use std::ptr;
-use std::sync::Arc;
+use crate::{
+ buffer::BufferContents,
+ device::{Device, DeviceOwned},
+ macros::{impl_id_counter, vulkan_bitflags},
+ DeviceSize, OomError, RequirementNotMet, RequiresOneOf, VulkanError, VulkanObject,
+};
+use std::{
+ error::Error,
+ ffi::c_void,
+ fmt::{Display, Error as FmtError, Formatter},
+ mem::{size_of_val, MaybeUninit},
+ num::NonZeroU64,
+ ops::Range,
+ ptr,
+ sync::Arc,
+};
/// A collection of one or more queries of a particular type.
#[derive(Debug)]
pub struct QueryPool {
- pool: ash::vk::QueryPool,
+ handle: ash::vk::QueryPool,
device: Arc<Device>,
- num_slots: u32,
- ty: QueryType,
+ id: NonZeroU64,
+
+ query_type: QueryType,
+ query_count: u32,
}
impl QueryPool {
- /// Builds a new query pool.
+ /// Creates a new `QueryPool`.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `create_info.query_count` is `0`.
pub fn new(
device: Arc<Device>,
- ty: QueryType,
- num_slots: u32,
- ) -> Result<QueryPool, QueryPoolCreationError> {
- let statistics = match ty {
+ create_info: QueryPoolCreateInfo,
+ ) -> Result<Arc<QueryPool>, QueryPoolCreationError> {
+ let QueryPoolCreateInfo {
+ query_type,
+ query_count,
+ _ne: _,
+ } = create_info;
+
+ // VUID-VkQueryPoolCreateInfo-queryCount-02763
+ assert!(query_count != 0);
+
+ let pipeline_statistics = match query_type {
QueryType::PipelineStatistics(flags) => {
+ // VUID-VkQueryPoolCreateInfo-queryType-00791
if !device.enabled_features().pipeline_statistics_query {
return Err(QueryPoolCreationError::PipelineStatisticsQueryFeatureNotEnabled);
}
+ // VUID-VkQueryPoolCreateInfo-queryType-00792
flags.into()
}
QueryType::Occlusion | QueryType::Timestamp => {
@@ -58,50 +75,80 @@ impl QueryPool {
}
};
- let pool = unsafe {
- let infos = ash::vk::QueryPoolCreateInfo {
- flags: ash::vk::QueryPoolCreateFlags::empty(),
- query_type: ty.into(),
- query_count: num_slots,
- pipeline_statistics: statistics,
- ..Default::default()
- };
+ let create_info = ash::vk::QueryPoolCreateInfo {
+ flags: ash::vk::QueryPoolCreateFlags::empty(),
+ query_type: query_type.into(),
+ query_count,
+ pipeline_statistics,
+ ..Default::default()
+ };
- let mut output = MaybeUninit::uninit();
+ let handle = unsafe {
let fns = device.fns();
- check_errors(fns.v1_0.create_query_pool(
- device.internal_object(),
- &infos,
+ let mut output = MaybeUninit::uninit();
+ (fns.v1_0.create_query_pool)(
+ device.handle(),
+ &create_info,
ptr::null(),
output.as_mut_ptr(),
- ))?;
+ )
+ .result()
+ .map_err(VulkanError::from)?;
output.assume_init()
};
- Ok(QueryPool {
- pool,
+ Ok(Arc::new(QueryPool {
+ handle,
+ device,
+ id: Self::next_id(),
+ query_type,
+ query_count,
+ }))
+ }
+
+ /// Creates a new `QueryPool` from a raw object handle.
+ ///
+ /// # Safety
+ ///
+ /// - `handle` must be a valid Vulkan object handle created from `device`.
+ /// - `create_info` must match the info used to create the object.
+ #[inline]
+ pub unsafe fn from_handle(
+ device: Arc<Device>,
+ handle: ash::vk::QueryPool,
+ create_info: QueryPoolCreateInfo,
+ ) -> Arc<QueryPool> {
+ let QueryPoolCreateInfo {
+ query_type,
+ query_count,
+ _ne: _,
+ } = create_info;
+
+ Arc::new(QueryPool {
+ handle,
device,
- num_slots,
- ty,
+ id: Self::next_id(),
+ query_type,
+ query_count,
})
}
- /// Returns the [`QueryType`] that this query pool was created with.
+ /// Returns the query type of the pool.
#[inline]
- pub fn ty(&self) -> QueryType {
- self.ty
+ pub fn query_type(&self) -> QueryType {
+ self.query_type
}
/// Returns the number of query slots of this query pool.
#[inline]
- pub fn num_slots(&self) -> u32 {
- self.num_slots
+ pub fn query_count(&self) -> u32 {
+ self.query_count
}
/// Returns a reference to a single query slot, or `None` if the index is out of range.
#[inline]
- pub fn query(&self, index: u32) -> Option<Query> {
- if index < self.num_slots() {
+ pub fn query(&self, index: u32) -> Option<Query<'_>> {
+ if index < self.query_count {
Some(Query { pool: self, index })
} else {
None
@@ -110,14 +157,14 @@ impl QueryPool {
/// Returns a reference to a range of queries, or `None` if out of range.
///
- /// # Panic
+ /// # Panics
///
- /// Panics if the range is empty.
+ /// - Panics if the range is empty.
#[inline]
- pub fn queries_range(&self, range: Range<u32>) -> Option<QueriesRange> {
+ pub fn queries_range(&self, range: Range<u32>) -> Option<QueriesRange<'_>> {
assert!(!range.is_empty());
- if range.end <= self.num_slots() {
+ if range.end <= self.query_count {
Some(QueriesRange { pool: self, range })
} else {
None
@@ -125,12 +172,22 @@ impl QueryPool {
}
}
+impl Drop for QueryPool {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ let fns = self.device.fns();
+ (fns.v1_0.destroy_query_pool)(self.device.handle(), self.handle, ptr::null());
+ }
+ }
+}
+
unsafe impl VulkanObject for QueryPool {
- type Object = ash::vk::QueryPool;
+ type Handle = ash::vk::QueryPool;
#[inline]
- fn internal_object(&self) -> ash::vk::QueryPool {
- self.pool
+ fn handle(&self) -> Self::Handle {
+ self.handle
}
}
@@ -141,13 +198,32 @@ unsafe impl DeviceOwned for QueryPool {
}
}
-impl Drop for QueryPool {
+impl_id_counter!(QueryPool);
+
+/// Parameters to create a new `QueryPool`.
+#[derive(Clone, Debug)]
+pub struct QueryPoolCreateInfo {
+ /// The type of query that the pool should be for.
+ ///
+ /// There is no default value.
+ pub query_type: QueryType,
+
+ /// The number of queries to create in the pool.
+ ///
+ /// The default value is `0`, which must be overridden.
+ pub query_count: u32,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl QueryPoolCreateInfo {
+ /// Returns a `QueryPoolCreateInfo` with the specified `query_type`.
#[inline]
- fn drop(&mut self) {
- unsafe {
- let fns = self.device.fns();
- fns.v1_0
- .destroy_query_pool(self.device.internal_object(), self.pool, ptr::null());
+ pub fn query_type(query_type: QueryType) -> Self {
+ Self {
+ query_type,
+ query_count: 0,
+ _ne: crate::NonExhaustive(()),
}
}
}
@@ -161,27 +237,25 @@ pub enum QueryPoolCreationError {
PipelineStatisticsQueryFeatureNotEnabled,
}
-impl error::Error for QueryPoolCreationError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- QueryPoolCreationError::OomError(ref err) => Some(err),
+impl Error for QueryPoolCreationError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ QueryPoolCreationError::OomError(err) => Some(err),
_ => None,
}
}
}
-impl fmt::Display for QueryPoolCreationError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+impl Display for QueryPoolCreationError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
write!(
- fmt,
+ f,
"{}",
- match *self {
+ match self {
QueryPoolCreationError::OomError(_) => "not enough memory available",
QueryPoolCreationError::PipelineStatisticsQueryFeatureNotEnabled => {
"a pipeline statistics pool was requested but the corresponding feature \
- wasn't enabled"
+ wasn't enabled"
}
}
)
@@ -189,18 +263,20 @@ impl fmt::Display for QueryPoolCreationError {
}
impl From<OomError> for QueryPoolCreationError {
- #[inline]
fn from(err: OomError) -> QueryPoolCreationError {
QueryPoolCreationError::OomError(err)
}
}
-impl From<Error> for QueryPoolCreationError {
- #[inline]
- fn from(err: Error) -> QueryPoolCreationError {
+impl From<VulkanError> for QueryPoolCreationError {
+ fn from(err: VulkanError) -> QueryPoolCreationError {
match err {
- err @ Error::OutOfHostMemory => QueryPoolCreationError::OomError(OomError::from(err)),
- err @ Error::OutOfDeviceMemory => QueryPoolCreationError::OomError(OomError::from(err)),
+ err @ VulkanError::OutOfHostMemory => {
+ QueryPoolCreationError::OomError(OomError::from(err))
+ }
+ err @ VulkanError::OutOfDeviceMemory => {
+ QueryPoolCreationError::OomError(OomError::from(err))
+ }
_ => panic!("unexpected error: {:?}", err),
}
}
@@ -219,7 +295,7 @@ impl<'a> Query<'a> {
/// Returns a reference to the query pool.
#[inline]
pub fn pool(&self) -> &'a QueryPool {
- &self.pool
+ self.pool
}
/// Returns the index of the query represented.
@@ -242,7 +318,7 @@ impl<'a> QueriesRange<'a> {
/// Returns a reference to the query pool.
#[inline]
pub fn pool(&self) -> &'a QueryPool {
- &self.pool
+ self.pool
}
/// Returns the range of queries represented.
@@ -253,15 +329,19 @@ impl<'a> QueriesRange<'a> {
/// Copies the results of this range of queries to a buffer on the CPU.
///
- /// [`self.pool().ty().result_size()`](QueryType::result_size) elements
- /// will be written for each query in the range, plus 1 extra element per query if
- /// [`QueryResultFlags::with_availability`] is enabled.
- /// The provided buffer must be large enough to hold the data.
+ /// [`self.pool().ty().result_len()`] will be written for each query in the range, plus 1 extra
+ /// element per query if [`WITH_AVAILABILITY`] is enabled. The provided buffer must be large
+ /// enough to hold the data.
///
/// `true` is returned if every result was available and written to the buffer. `false`
/// is returned if some results were not yet available; these will not be written to the buffer.
///
- /// See also [`copy_query_pool_results`](crate::command_buffer::AutoCommandBufferBuilder::copy_query_pool_results).
+ /// See also [`copy_query_pool_results`].
+ ///
+ /// [`self.pool().ty().result_len()`]: QueryType::result_len
+ /// [`WITH_AVAILABILITY`]: QueryResultFlags::WITH_AVAILABILITY
+ /// [`copy_query_pool_results`]: crate::command_buffer::AutoCommandBufferBuilder::copy_query_pool_results
+ #[inline]
pub fn get_results<T>(
&self,
destination: &mut [T],
@@ -278,23 +358,23 @@ impl<'a> QueriesRange<'a> {
let result = unsafe {
let fns = self.pool.device.fns();
- check_errors(fns.v1_0.get_query_pool_results(
- self.pool.device.internal_object(),
- self.pool.internal_object(),
+ (fns.v1_0.get_query_pool_results)(
+ self.pool.device.handle(),
+ self.pool.handle(),
self.range.start,
self.range.end - self.range.start,
- std::mem::size_of_val(destination),
+ size_of_val(destination),
destination.as_mut_ptr() as *mut c_void,
stride,
ash::vk::QueryResultFlags::from(flags) | T::FLAG,
- ))?
+ )
};
- Ok(match result {
- Success::Success => true,
- Success::NotReady => false,
- s => panic!("unexpected success value: {:?}", s),
- })
+ match result {
+ ash::vk::Result::SUCCESS => Ok(true),
+ ash::vk::Result::NOT_READY => Ok(false),
+ err => Err(VulkanError::from(err).into()),
+ }
}
pub(crate) fn check_query_pool_results<T>(
@@ -306,13 +386,22 @@ impl<'a> QueriesRange<'a> {
where
T: QueryResultElement,
{
+ // VUID-vkGetQueryPoolResults-flags-parameter
+ // VUID-vkCmdCopyQueryPoolResults-flags-parameter
+ flags.validate_device(&self.pool.device)?;
+
assert!(buffer_len > 0);
+
+ // VUID-vkGetQueryPoolResults-flags-02828
+ // VUID-vkGetQueryPoolResults-flags-00815
debug_assert!(buffer_start % std::mem::size_of::<T>() as DeviceSize == 0);
let count = self.range.end - self.range.start;
- let per_query_len = self.pool.ty.result_size() + flags.with_availability as DeviceSize;
+ let per_query_len = self.pool.query_type.result_len()
+ + flags.intersects(QueryResultFlags::WITH_AVAILABILITY) as DeviceSize;
let required_len = per_query_len * count as DeviceSize;
+ // VUID-vkGetQueryPoolResults-dataSize-00817
if buffer_len < required_len {
return Err(GetResultsError::BufferTooSmall {
required_len: required_len as DeviceSize,
@@ -320,11 +409,12 @@ impl<'a> QueriesRange<'a> {
});
}
- match self.pool.ty {
+ match self.pool.query_type {
QueryType::Occlusion => (),
QueryType::PipelineStatistics(_) => (),
QueryType::Timestamp => {
- if flags.partial {
+ // VUID-vkGetQueryPoolResults-queryType-00818
+ if flags.intersects(QueryResultFlags::PARTIAL) {
return Err(GetResultsError::InvalidFlags);
}
}
@@ -337,6 +427,17 @@ impl<'a> QueriesRange<'a> {
/// Error that can happen when calling [`QueriesRange::get_results`].
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum GetResultsError {
+ /// The connection to the device has been lost.
+ DeviceLost,
+
+ /// Not enough memory.
+ OomError(OomError),
+
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+
/// The buffer is too small for the operation.
BufferTooSmall {
/// Required number of elements in the buffer.
@@ -344,60 +445,65 @@ pub enum GetResultsError {
/// Actual number of elements in the buffer.
actual_len: DeviceSize,
},
- /// The connection to the device has been lost.
- DeviceLost,
+
/// The provided flags are not allowed for this type of query.
InvalidFlags,
- /// Not enough memory.
- OomError(OomError),
}
-impl From<Error> for GetResultsError {
- #[inline]
- fn from(err: Error) -> Self {
+impl Error for GetResultsError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::OomError(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+impl Display for GetResultsError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::OomError(_) => write!(f, "not enough memory available"),
+ Self::DeviceLost => write!(f, "the connection to the device has been lost"),
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ Self::BufferTooSmall { .. } => write!(f, "the buffer is too small for the operation"),
+ Self::InvalidFlags => write!(
+ f,
+ "the provided flags are not allowed for this type of query"
+ ),
+ }
+ }
+}
+
+impl From<VulkanError> for GetResultsError {
+ fn from(err: VulkanError) -> Self {
match err {
- Error::OutOfHostMemory | Error::OutOfDeviceMemory => {
+ VulkanError::OutOfHostMemory | VulkanError::OutOfDeviceMemory => {
Self::OomError(OomError::from(err))
}
- Error::DeviceLost => Self::DeviceLost,
+ VulkanError::DeviceLost => Self::DeviceLost,
_ => panic!("unexpected error: {:?}", err),
}
}
}
impl From<OomError> for GetResultsError {
- #[inline]
fn from(err: OomError) -> Self {
Self::OomError(err)
}
}
-impl fmt::Display for GetResultsError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- Self::BufferTooSmall { .. } => {
- "the buffer is too small for the operation"
- }
- Self::DeviceLost => "the connection to the device has been lost",
- Self::InvalidFlags => {
- "the provided flags are not allowed for this type of query"
- }
- Self::OomError(_) => "not enough memory available",
- }
- )
- }
-}
-
-impl error::Error for GetResultsError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- Self::OomError(ref err) => Some(err),
- _ => None,
+impl From<RequirementNotMet> for GetResultsError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
}
}
}
@@ -407,7 +513,7 @@ impl error::Error for GetResultsError {
/// # Safety
/// This is implemented for `u32` and `u64`. Unless you really know what you're doing, you should
/// not implement this trait for any other type.
-pub unsafe trait QueryResultElement {
+pub unsafe trait QueryResultElement: BufferContents + Sized {
const FLAG: ash::vk::QueryResultFlags;
}
@@ -434,16 +540,21 @@ impl QueryType {
/// Returns the number of [`QueryResultElement`]s that are needed to hold the result of a
/// single query of this type.
///
- /// - For `Occlusion` and `Timestamp` queries, this returns 1.
- /// - For `PipelineStatistics` queries, this returns the number of statistics flags enabled.
+ /// - For [`Occlusion`] and [`Timestamp`] queries, this returns 1.
+ /// - For [`PipelineStatistics`] queries, this returns the number of statistics flags enabled.
///
- /// If the results are retrieved with [`QueryResultFlags::with_availability`] enabled, then
- /// an additional element is required per query.
+ /// If the results are retrieved with [`WITH_AVAILABILITY`] enabled, then an additional element
+ /// is required per query.
+ ///
+ /// [`Occlusion`]: QueryType::Occlusion
+ /// [`Timestamp`]: QueryType::Timestamp
+ /// [`PipelineStatistics`]: QueryType::PipelineStatistics
+ /// [`WITH_AVAILABILITY`]: QueryResultFlags::WITH_AVAILABILITY
#[inline]
- pub const fn result_size(&self) -> DeviceSize {
+ pub const fn result_len(self) -> DeviceSize {
match self {
Self::Occlusion | Self::Timestamp => 1,
- Self::PipelineStatistics(flags) => flags.count(),
+ Self::PipelineStatistics(flags) => flags.count() as DeviceSize,
}
}
}
@@ -459,228 +570,139 @@ impl From<QueryType> for ash::vk::QueryType {
}
}
-/// Flags that control how a query is to be executed.
-#[derive(Clone, Copy, Debug, Default)]
-pub struct QueryControlFlags {
+vulkan_bitflags! {
+ #[non_exhaustive]
+
+ /// Flags that control how a query is to be executed.
+ QueryControlFlags = QueryControlFlags(u32);
+
/// For occlusion queries, specifies that the result must reflect the exact number of
/// tests passed. If not enabled, the query may return a result of 1 even if more fragments
/// passed the test.
- pub precise: bool,
+ PRECISE = PRECISE,
}
-impl From<QueryControlFlags> for ash::vk::QueryControlFlags {
- #[inline]
- fn from(value: QueryControlFlags) -> Self {
- let mut result = ash::vk::QueryControlFlags::empty();
- if value.precise {
- result |= ash::vk::QueryControlFlags::PRECISE;
+vulkan_bitflags! {
+ #[non_exhaustive]
+
+ /// For pipeline statistics queries, the statistics that should be gathered.
+ QueryPipelineStatisticFlags impl {
+ /// Returns `true` if `self` contains any flags referring to compute operations.
+ #[inline]
+ pub const fn is_compute(self) -> bool {
+ self.intersects(QueryPipelineStatisticFlags::COMPUTE_SHADER_INVOCATIONS)
+ }
+
+ /// Returns `true` if `self` contains any flags referring to graphics operations.
+ #[inline]
+ pub const fn is_graphics(self) -> bool {
+ self.intersects(
+ (QueryPipelineStatisticFlags::INPUT_ASSEMBLY_VERTICES)
+ .union(QueryPipelineStatisticFlags::INPUT_ASSEMBLY_PRIMITIVES)
+ .union(QueryPipelineStatisticFlags::VERTEX_SHADER_INVOCATIONS)
+ .union(QueryPipelineStatisticFlags::GEOMETRY_SHADER_INVOCATIONS)
+ .union(QueryPipelineStatisticFlags::GEOMETRY_SHADER_PRIMITIVES)
+ .union(QueryPipelineStatisticFlags::CLIPPING_INVOCATIONS)
+ .union(QueryPipelineStatisticFlags::CLIPPING_PRIMITIVES)
+ .union(QueryPipelineStatisticFlags::FRAGMENT_SHADER_INVOCATIONS)
+ .union(QueryPipelineStatisticFlags::TESSELLATION_CONTROL_SHADER_PATCHES)
+ .union(QueryPipelineStatisticFlags::TESSELLATION_EVALUATION_SHADER_INVOCATIONS),
+ )
}
- result
}
-}
+ = QueryPipelineStatisticFlags(u32);
-/// For pipeline statistics queries, the statistics that should be gathered.
-#[derive(Clone, Copy, Debug, Default)]
-pub struct QueryPipelineStatisticFlags {
/// Count the number of vertices processed by the input assembly.
- pub input_assembly_vertices: bool,
+ INPUT_ASSEMBLY_VERTICES = INPUT_ASSEMBLY_VERTICES,
+
/// Count the number of primitives processed by the input assembly.
- pub input_assembly_primitives: bool,
+ INPUT_ASSEMBLY_PRIMITIVES = INPUT_ASSEMBLY_PRIMITIVES,
+
/// Count the number of times a vertex shader is invoked.
- pub vertex_shader_invocations: bool,
+ VERTEX_SHADER_INVOCATIONS = VERTEX_SHADER_INVOCATIONS,
+
/// Count the number of times a geometry shader is invoked.
- pub geometry_shader_invocations: bool,
+ GEOMETRY_SHADER_INVOCATIONS = GEOMETRY_SHADER_INVOCATIONS,
+
/// Count the number of primitives generated by geometry shaders.
- pub geometry_shader_primitives: bool,
+ GEOMETRY_SHADER_PRIMITIVES = GEOMETRY_SHADER_PRIMITIVES,
+
/// Count the number of times the clipping stage is invoked on a primitive.
- pub clipping_invocations: bool,
+ CLIPPING_INVOCATIONS = CLIPPING_INVOCATIONS,
+
/// Count the number of primitives that are output by the clipping stage.
- pub clipping_primitives: bool,
+ CLIPPING_PRIMITIVES = CLIPPING_PRIMITIVES,
+
/// Count the number of times a fragment shader is invoked.
- pub fragment_shader_invocations: bool,
+ FRAGMENT_SHADER_INVOCATIONS = FRAGMENT_SHADER_INVOCATIONS,
+
/// Count the number of patches processed by a tessellation control shader.
- pub tessellation_control_shader_patches: bool,
- /// Count the number of times a tessellation evaluation shader is invoked.
- pub tessellation_evaluation_shader_invocations: bool,
- /// Count the number of times a compute shader is invoked.
- pub compute_shader_invocations: bool,
-}
+ TESSELLATION_CONTROL_SHADER_PATCHES = TESSELLATION_CONTROL_SHADER_PATCHES,
-impl QueryPipelineStatisticFlags {
- #[inline]
- pub fn none() -> QueryPipelineStatisticFlags {
- QueryPipelineStatisticFlags {
- input_assembly_vertices: false,
- input_assembly_primitives: false,
- vertex_shader_invocations: false,
- geometry_shader_invocations: false,
- geometry_shader_primitives: false,
- clipping_invocations: false,
- clipping_primitives: false,
- fragment_shader_invocations: false,
- tessellation_control_shader_patches: false,
- tessellation_evaluation_shader_invocations: false,
- compute_shader_invocations: false,
- }
- }
+ /// Count the number of times a tessellation evaluation shader is invoked.
+ TESSELLATION_EVALUATION_SHADER_INVOCATIONS = TESSELLATION_EVALUATION_SHADER_INVOCATIONS,
- /// Returns the number of flags that are set to `true`.
- #[inline]
- pub const fn count(&self) -> DeviceSize {
- let &Self {
- input_assembly_vertices,
- input_assembly_primitives,
- vertex_shader_invocations,
- geometry_shader_invocations,
- geometry_shader_primitives,
- clipping_invocations,
- clipping_primitives,
- fragment_shader_invocations,
- tessellation_control_shader_patches,
- tessellation_evaluation_shader_invocations,
- compute_shader_invocations,
- } = self;
- input_assembly_vertices as DeviceSize
- + input_assembly_primitives as DeviceSize
- + vertex_shader_invocations as DeviceSize
- + geometry_shader_invocations as DeviceSize
- + geometry_shader_primitives as DeviceSize
- + clipping_invocations as DeviceSize
- + clipping_primitives as DeviceSize
- + fragment_shader_invocations as DeviceSize
- + tessellation_control_shader_patches as DeviceSize
- + tessellation_evaluation_shader_invocations as DeviceSize
- + compute_shader_invocations as DeviceSize
- }
+ /// Count the number of times a compute shader is invoked.
+ COMPUTE_SHADER_INVOCATIONS = COMPUTE_SHADER_INVOCATIONS,
- /// Returns `true` if any flags referring to compute operations are set to `true`.
- #[inline]
- pub const fn is_compute(&self) -> bool {
- let &Self {
- compute_shader_invocations,
- ..
- } = self;
- compute_shader_invocations
- }
+ /* TODO: enable
+ // TODO: document
+ TASK_SHADER_INVOCATIONS = TASK_SHADER_INVOCATIONS_NV {
+ device_extensions: [nv_mesh_shader],
+ },*/
- /// Returns `true` if any flags referring to graphics operations are set to `true`.
- #[inline]
- pub const fn is_graphics(&self) -> bool {
- let &Self {
- input_assembly_vertices,
- input_assembly_primitives,
- vertex_shader_invocations,
- geometry_shader_invocations,
- geometry_shader_primitives,
- clipping_invocations,
- clipping_primitives,
- fragment_shader_invocations,
- tessellation_control_shader_patches,
- tessellation_evaluation_shader_invocations,
- ..
- } = self;
- input_assembly_vertices
- || input_assembly_primitives
- || vertex_shader_invocations
- || geometry_shader_invocations
- || geometry_shader_primitives
- || clipping_invocations
- || clipping_primitives
- || fragment_shader_invocations
- || tessellation_control_shader_patches
- || tessellation_evaluation_shader_invocations
- }
+ /* TODO: enable
+ // TODO: document
+ MESH_SHADER_INVOCATIONS = MESH_SHADER_INVOCATIONS_NV {
+ device_extensions: [nv_mesh_shader],
+ },*/
}
-impl From<QueryPipelineStatisticFlags> for ash::vk::QueryPipelineStatisticFlags {
- fn from(value: QueryPipelineStatisticFlags) -> ash::vk::QueryPipelineStatisticFlags {
- let mut result = ash::vk::QueryPipelineStatisticFlags::empty();
- if value.input_assembly_vertices {
- result |= ash::vk::QueryPipelineStatisticFlags::INPUT_ASSEMBLY_VERTICES;
- }
- if value.input_assembly_primitives {
- result |= ash::vk::QueryPipelineStatisticFlags::INPUT_ASSEMBLY_PRIMITIVES;
- }
- if value.vertex_shader_invocations {
- result |= ash::vk::QueryPipelineStatisticFlags::VERTEX_SHADER_INVOCATIONS;
- }
- if value.geometry_shader_invocations {
- result |= ash::vk::QueryPipelineStatisticFlags::GEOMETRY_SHADER_INVOCATIONS;
- }
- if value.geometry_shader_primitives {
- result |= ash::vk::QueryPipelineStatisticFlags::GEOMETRY_SHADER_PRIMITIVES;
- }
- if value.clipping_invocations {
- result |= ash::vk::QueryPipelineStatisticFlags::CLIPPING_INVOCATIONS;
- }
- if value.clipping_primitives {
- result |= ash::vk::QueryPipelineStatisticFlags::CLIPPING_PRIMITIVES;
- }
- if value.fragment_shader_invocations {
- result |= ash::vk::QueryPipelineStatisticFlags::FRAGMENT_SHADER_INVOCATIONS;
- }
- if value.tessellation_control_shader_patches {
- result |= ash::vk::QueryPipelineStatisticFlags::TESSELLATION_CONTROL_SHADER_PATCHES;
- }
- if value.tessellation_evaluation_shader_invocations {
- result |=
- ash::vk::QueryPipelineStatisticFlags::TESSELLATION_EVALUATION_SHADER_INVOCATIONS;
- }
- if value.compute_shader_invocations {
- result |= ash::vk::QueryPipelineStatisticFlags::COMPUTE_SHADER_INVOCATIONS;
- }
- result
- }
-}
+vulkan_bitflags! {
+ #[non_exhaustive]
+
+ /// Flags to control how the results of a query should be retrieved.
+ ///
+ /// `VK_QUERY_RESULT_64_BIT` is not included, as it is determined automatically via the
+ /// [`QueryResultElement`] trait.
+ QueryResultFlags = QueryResultFlags(u32);
-/// Flags to control how the results of a query should be retrieved.
-///
-/// `VK_QUERY_RESULT_64_BIT` is not included, as it is determined automatically via the
-/// [`QueryResultElement`] trait.
-#[derive(Clone, Copy, Debug, Default)]
-pub struct QueryResultFlags {
/// Wait for the results to become available before writing the results.
- pub wait: bool,
+ WAIT = WAIT,
+
/// Write an additional element to the end of each query's results, indicating the availability
/// of the results:
/// - Nonzero: The results are available, and have been written to the element(s) preceding.
/// - Zero: The results are not yet available, and have not been written.
- pub with_availability: bool,
+ WITH_AVAILABILITY = WITH_AVAILABILITY,
+
/// Allow writing partial results to the buffer, instead of waiting until they are fully
/// available.
- pub partial: bool,
-}
+ PARTIAL = PARTIAL,
-impl From<QueryResultFlags> for ash::vk::QueryResultFlags {
- #[inline]
- fn from(value: QueryResultFlags) -> Self {
- let mut result = ash::vk::QueryResultFlags::empty();
- if value.wait {
- result |= ash::vk::QueryResultFlags::WAIT;
- }
- if value.with_availability {
- result |= ash::vk::QueryResultFlags::WITH_AVAILABILITY;
- }
- if value.partial {
- result |= ash::vk::QueryResultFlags::PARTIAL;
- }
- result
- }
+ /* TODO: enable
+ // TODO: document
+ WITH_STATUS = WITH_STATUS_KHR {
+ device_extensions: [khr_video_queue],
+ },*/
}
#[cfg(test)]
mod tests {
- use crate::query::QueryPipelineStatisticFlags;
- use crate::query::QueryPool;
- use crate::query::QueryPoolCreationError;
- use crate::query::QueryType;
+ use super::QueryPoolCreateInfo;
+ use crate::query::{QueryPipelineStatisticFlags, QueryPool, QueryPoolCreationError, QueryType};
#[test]
fn pipeline_statistics_feature() {
let (device, _) = gfx_dev_and_queue!();
-
- let ty = QueryType::PipelineStatistics(QueryPipelineStatisticFlags::none());
- match QueryPool::new(device, ty, 256) {
+ let query_type = QueryType::PipelineStatistics(QueryPipelineStatisticFlags::empty());
+ match QueryPool::new(
+ device,
+ QueryPoolCreateInfo {
+ query_count: 256,
+ ..QueryPoolCreateInfo::query_type(query_type)
+ },
+ ) {
Err(QueryPoolCreationError::PipelineStatisticsQueryFeatureNotEnabled) => (),
_ => panic!(),
};
diff --git a/src/range_map.rs b/src/range_map.rs
new file mode 100644
index 0000000..b09433c
--- /dev/null
+++ b/src/range_map.rs
@@ -0,0 +1,1527 @@
+#![allow(dead_code)]
+
+use std::{
+ cmp,
+ cmp::Ordering,
+ collections::{btree_map, BTreeMap},
+ fmt::{Debug, Error as FmtError, Formatter},
+ iter::{FromIterator, FusedIterator, Peekable},
+ ops::{Add, Bound, Range, Sub},
+};
+
+/// A map whose keys are stored as (half-open) ranges bounded
+/// inclusively below and exclusively above `(start..end)`.
+///
+/// Contiguous and overlapping ranges that map to the same value
+/// are coalesced into a single range.
+#[derive(Clone)]
+pub struct RangeMap<K, V> {
+ // Wrap ranges so that they are `Ord`.
+ // See `range_wrapper.rs` for explanation.
+ btm: BTreeMap<RangeStartWrapper<K>, V>,
+}
+
+impl<K, V> Default for RangeMap<K, V>
+where
+ K: Ord + Clone,
+ V: Eq + Clone,
+{
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl<K, V> RangeMap<K, V>
+where
+ K: Ord + Clone,
+ V: Eq + Clone,
+{
+ /// Makes a new empty `RangeMap`.
+ #[inline]
+ pub fn new() -> Self {
+ RangeMap {
+ btm: BTreeMap::new(),
+ }
+ }
+
+ /// Returns a reference to the value corresponding to the given key,
+ /// if the key is covered by any range in the map.
+ #[inline]
+ pub fn get(&self, key: &K) -> Option<&V> {
+ self.get_key_value(key).map(|(_range, value)| value)
+ }
+
+ /// Returns the range-value pair (as a pair of references) corresponding
+ /// to the given key, if the key is covered by any range in the map.
+ #[inline]
+ pub fn get_key_value(&self, key: &K) -> Option<(&Range<K>, &V)> {
+ // The only stored range that could contain the given key is the
+ // last stored range whose start is less than or equal to this key.
+ let key_as_start = RangeStartWrapper::new(key.clone()..key.clone());
+
+ self.btm
+ .range((Bound::Unbounded, Bound::Included(key_as_start)))
+ .next_back()
+ .filter(|(range_start_wrapper, _value)| {
+ // Does the only candidate range contain
+ // the requested key?
+ range_start_wrapper.range.contains(key)
+ })
+ .map(|(range_start_wrapper, value)| (&range_start_wrapper.range, value))
+ }
+
+ /// Returns `true` if any range in the map covers the specified key.
+ #[inline]
+ pub fn contains_key(&self, key: &K) -> bool {
+ self.get(key).is_some()
+ }
+
+ /// Returns `true` if any part of the provided range overlaps with a range in the map.
+ #[inline]
+ pub fn contains_any(&self, range: &Range<K>) -> bool {
+ self.range(range).next().is_some()
+ }
+
+ /// Returns `true` if all of the provided range is covered by ranges in the map.
+ #[inline]
+ pub fn contains_all(&self, range: &Range<K>) -> bool {
+ self.gaps(range).next().is_none()
+ }
+
+ /// Gets an iterator over all pairs of key range and value,
+ /// ordered by key range.
+ ///
+ /// The iterator element type is `(&'a Range<K>, &'a V)`.
+ #[inline]
+ pub fn iter(&self) -> Iter<'_, K, V> {
+ Iter {
+ inner: self.btm.iter(),
+ }
+ }
+
+ /// Gets a mutable iterator over all pairs of key range and value,
+ /// ordered by key range.
+ ///
+ /// The iterator element type is `(&'a Range<K>, &'a mut V)`.
+ #[inline]
+ pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
+ IterMut {
+ inner: self.btm.iter_mut(),
+ }
+ }
+
+ /// Insert a pair of key range and value into the map.
+ ///
+ /// If the inserted range partially or completely overlaps any
+ /// existing range in the map, then the existing range (or ranges) will be
+ /// partially or completely replaced by the inserted range.
+ ///
+ /// If the inserted range either overlaps or is immediately adjacent
+ /// any existing range _mapping to the same value_, then the ranges
+ /// will be coalesced into a single contiguous range.
+ ///
+ /// # Panics
+ ///
+ /// Panics if range `start >= end`.
+ pub fn insert(&mut self, range: Range<K>, value: V) {
+ // We don't want to have to make empty ranges make sense;
+ // they don't represent anything meaningful in this structure.
+ assert!(range.start < range.end);
+
+ // Wrap up the given range so that we can "borrow"
+ // it as a wrapper reference to either its start or end.
+ // See `range_wrapper.rs` for explanation of these hacks.
+ let mut new_range_start_wrapper: RangeStartWrapper<K> = RangeStartWrapper::new(range);
+ let new_value = value;
+
+ // Is there a stored range either overlapping the start of
+ // the range to insert or immediately preceding it?
+ //
+ // If there is any such stored range, it will be the last
+ // whose start is less than or equal to the start of the range to insert,
+ // or the one before that if both of the above cases exist.
+ let mut candidates = self
+ .btm
+ .range((Bound::Unbounded, Bound::Included(&new_range_start_wrapper)))
+ .rev()
+ .take(2)
+ .filter(|(stored_range_start_wrapper, _stored_value)| {
+ // Does the candidate range either overlap
+ // or immediately precede the range to insert?
+ // (Remember that it might actually cover the _whole_
+ // range to insert and then some.)
+ stored_range_start_wrapper
+ .range
+ .touches(&new_range_start_wrapper.range)
+ });
+
+ if let Some(mut candidate) = candidates.next() {
+ // Or the one before it if both cases described above exist.
+ if let Some(another_candidate) = candidates.next() {
+ candidate = another_candidate;
+ }
+
+ let (stored_range_start_wrapper, stored_value) =
+ (candidate.0.clone(), candidate.1.clone());
+
+ self.adjust_touching_ranges_for_insert(
+ stored_range_start_wrapper,
+ stored_value,
+ &mut new_range_start_wrapper.range,
+ &new_value,
+ );
+ }
+
+ // Are there any stored ranges whose heads overlap or immediately
+ // follow the range to insert?
+ //
+ // If there are any such stored ranges (that weren't already caught above),
+ // their starts will fall somewhere after the start of the range to insert,
+ // and on or before its end.
+ //
+ // This time around, if the latter holds, it also implies
+ // the former so we don't need to check here if they touch.
+ //
+ // REVISIT: Possible micro-optimisation: `impl Borrow<T> for RangeStartWrapper<T>`
+ // and use that to search here, to avoid constructing another `RangeStartWrapper`.
+ let new_range_end_as_start = RangeStartWrapper::new(
+ new_range_start_wrapper.range.end.clone()..new_range_start_wrapper.range.end.clone(),
+ );
+
+ while let Some((stored_range_start_wrapper, stored_value)) = self
+ .btm
+ .range((
+ Bound::Included(&new_range_start_wrapper),
+ Bound::Included(&new_range_end_as_start),
+ ))
+ .next()
+ {
+ // One extra exception: if we have different values,
+ // and the stored range starts at the end of the range to insert,
+ // then we don't want to keep looping forever trying to find more!
+ #[allow(clippy::suspicious_operation_groupings)]
+ if stored_range_start_wrapper.range.start == new_range_start_wrapper.range.end
+ && *stored_value != new_value
+ {
+ // We're beyond the last stored range that could be relevant.
+ // Avoid wasting time on irrelevant ranges, or even worse, looping forever.
+ // (`adjust_touching_ranges_for_insert` below assumes that the given range
+ // is relevant, and behaves very poorly if it is handed a range that it
+ // shouldn't be touching.)
+ break;
+ }
+
+ let stored_range_start_wrapper = stored_range_start_wrapper.clone();
+ let stored_value = stored_value.clone();
+
+ self.adjust_touching_ranges_for_insert(
+ stored_range_start_wrapper,
+ stored_value,
+ &mut new_range_start_wrapper.range,
+ &new_value,
+ );
+ }
+
+ // Insert the (possibly expanded) new range, and we're done!
+ self.btm.insert(new_range_start_wrapper, new_value);
+ }
+
+ /// Removes a range from the map, if all or any of it was present.
+ ///
+ /// If the range to be removed _partially_ overlaps any ranges
+ /// in the map, then those ranges will be contracted to no
+ /// longer cover the removed range.
+ ///
+ ///
+ /// # Panics
+ ///
+ /// Panics if range `start >= end`.
+ pub fn remove(&mut self, range: Range<K>) {
+ // We don't want to have to make empty ranges make sense;
+ // they don't represent anything meaningful in this structure.
+ assert!(range.start < range.end);
+
+ let range_start_wrapper: RangeStartWrapper<K> = RangeStartWrapper::new(range);
+ let range = &range_start_wrapper.range;
+
+ // Is there a stored range overlapping the start of
+ // the range to insert?
+ //
+ // If there is any such stored range, it will be the last
+ // whose start is less than or equal to the start of the range to insert.
+ if let Some((stored_range_start_wrapper, stored_value)) = self
+ .btm
+ .range((Bound::Unbounded, Bound::Included(&range_start_wrapper)))
+ .next_back()
+ .filter(|(stored_range_start_wrapper, _stored_value)| {
+ // Does the only candidate range overlap
+ // the range to insert?
+ stored_range_start_wrapper.range.overlaps(range)
+ })
+ .map(|(stored_range_start_wrapper, stored_value)| {
+ (stored_range_start_wrapper.clone(), stored_value.clone())
+ })
+ {
+ self.adjust_overlapping_ranges_for_remove(
+ stored_range_start_wrapper,
+ stored_value,
+ range,
+ );
+ }
+
+ // Are there any stored ranges whose heads overlap the range to insert?
+ //
+ // If there are any such stored ranges (that weren't already caught above),
+ // their starts will fall somewhere after the start of the range to insert,
+ // and before its end.
+ //
+ // REVISIT: Possible micro-optimisation: `impl Borrow<T> for RangeStartWrapper<T>`
+ // and use that to search here, to avoid constructing another `RangeStartWrapper`.
+ let new_range_end_as_start = RangeStartWrapper::new(range.end.clone()..range.end.clone());
+
+ while let Some((stored_range_start_wrapper, stored_value)) = self
+ .btm
+ .range((
+ Bound::Excluded(&range_start_wrapper),
+ Bound::Excluded(&new_range_end_as_start),
+ ))
+ .next()
+ .map(|(stored_range_start_wrapper, stored_value)| {
+ (stored_range_start_wrapper.clone(), stored_value.clone())
+ })
+ {
+ self.adjust_overlapping_ranges_for_remove(
+ stored_range_start_wrapper,
+ stored_value,
+ range,
+ );
+ }
+ }
+
+ fn adjust_touching_ranges_for_insert(
+ &mut self,
+ stored_range_start_wrapper: RangeStartWrapper<K>,
+ stored_value: V,
+ new_range: &mut Range<K>,
+ new_value: &V,
+ ) {
+ if stored_value == *new_value {
+ // The ranges have the same value, so we can "adopt"
+ // the stored range.
+ //
+ // This means that no matter how big or where the stored range is,
+ // we will expand the new range's bounds to subsume it,
+ // and then delete the stored range.
+ new_range.start =
+ cmp::min(&new_range.start, &stored_range_start_wrapper.range.start).clone();
+ new_range.end = cmp::max(&new_range.end, &stored_range_start_wrapper.range.end).clone();
+ self.btm.remove(&stored_range_start_wrapper);
+ } else {
+ // The ranges have different values.
+ if new_range.overlaps(&stored_range_start_wrapper.range) {
+ // The ranges overlap. This is a little bit more complicated.
+ // Delete the stored range, and then add back between
+ // 0 and 2 subranges at the ends of the range to insert.
+ self.btm.remove(&stored_range_start_wrapper);
+ if stored_range_start_wrapper.range.start < new_range.start {
+ // Insert the piece left of the range to insert.
+ self.btm.insert(
+ RangeStartWrapper::new(
+ stored_range_start_wrapper.range.start..new_range.start.clone(),
+ ),
+ stored_value.clone(),
+ );
+ }
+ if stored_range_start_wrapper.range.end > new_range.end {
+ // Insert the piece right of the range to insert.
+ self.btm.insert(
+ RangeStartWrapper::new(
+ new_range.end.clone()..stored_range_start_wrapper.range.end,
+ ),
+ stored_value,
+ );
+ }
+ } else {
+ // No-op; they're not overlapping,
+ // so we can just keep both ranges as they are.
+ }
+ }
+ }
+
+ fn adjust_overlapping_ranges_for_remove(
+ &mut self,
+ stored_range_start_wrapper: RangeStartWrapper<K>,
+ stored_value: V,
+ range_to_remove: &Range<K>,
+ ) {
+ // Delete the stored range, and then add back between
+ // 0 and 2 subranges at the ends of the range to insert.
+ self.btm.remove(&stored_range_start_wrapper);
+ let stored_range = stored_range_start_wrapper.range;
+
+ if stored_range.start < range_to_remove.start {
+ // Insert the piece left of the range to insert.
+ self.btm.insert(
+ RangeStartWrapper::new(stored_range.start..range_to_remove.start.clone()),
+ stored_value.clone(),
+ );
+ }
+
+ if stored_range.end > range_to_remove.end {
+ // Insert the piece right of the range to insert.
+ self.btm.insert(
+ RangeStartWrapper::new(range_to_remove.end.clone()..stored_range.end),
+ stored_value,
+ );
+ }
+ }
+
+ /// Splits a range in two at the provided key.
+ ///
+ /// Does nothing if no range exists at the key, or if the key is at a range boundary.
+ pub fn split_at(&mut self, key: &K) {
+ // Find a range that contains the key, but doesn't start or end with the key.
+ let bounds = (
+ Bound::Unbounded,
+ Bound::Excluded(RangeStartWrapper::new(key.clone()..key.clone())),
+ );
+
+ let range_to_remove = match self
+ .btm
+ .range(bounds)
+ .next_back()
+ .filter(|(range_start_wrapper, _value)| range_start_wrapper.range.contains(key))
+ {
+ Some((k, _v)) => k.clone(),
+ None => return,
+ };
+
+ // Remove the range, and re-insert two new ranges with the same value, separated by the key.
+ let value = self.btm.remove(&range_to_remove).unwrap();
+ self.btm.insert(
+ RangeStartWrapper::new(range_to_remove.range.start..key.clone()),
+ value.clone(),
+ );
+ self.btm.insert(
+ RangeStartWrapper::new(key.clone()..range_to_remove.range.end),
+ value,
+ );
+ }
+
+ /// Gets an iterator over all pairs of key range and value, where the key range overlaps with
+ /// the provided range.
+ ///
+ /// The iterator element type is `(&Range<K>, &V)`.
+ pub fn range(&self, range: &Range<K>) -> RangeIter<'_, K, V> {
+ let start = self
+ .get_key_value(&range.start)
+ .map_or(&range.start, |(k, _v)| &k.start);
+ let end = &range.end;
+
+ RangeIter {
+ inner: self.btm.range((
+ Bound::Included(RangeStartWrapper::new(start.clone()..start.clone())),
+ Bound::Excluded(RangeStartWrapper::new(end.clone()..end.clone())),
+ )),
+ }
+ }
+
+ /// Gets a mutable iterator over all pairs of key range and value, where the key range overlaps
+ /// with the provided range.
+ ///
+ /// The iterator element type is `(&Range<K>, &mut V)`.
+ pub fn range_mut(&mut self, range: &Range<K>) -> RangeMutIter<'_, K, V> {
+ let start = self
+ .get_key_value(&range.start)
+ .map_or(&range.start, |(k, _v)| &k.start);
+ let end = &range.end;
+ let bounds = (
+ Bound::Included(RangeStartWrapper::new(start.clone()..start.clone())),
+ Bound::Excluded(RangeStartWrapper::new(end.clone()..end.clone())),
+ );
+
+ RangeMutIter {
+ inner: self.btm.range_mut(bounds),
+ }
+ }
+
+ /// Gets an iterator over all the maximally-sized ranges
+ /// contained in `outer_range` that are not covered by
+ /// any range stored in the map.
+ ///
+ /// The iterator element type is `Range<K>`.
+ ///
+ /// NOTE: Calling `gaps` eagerly finds the first gap,
+ /// even if the iterator is never consumed.
+ pub fn gaps<'a>(&'a self, outer_range: &'a Range<K>) -> Gaps<'a, K, V> {
+ let mut keys = self.btm.keys().peekable();
+ // Find the first potential gap.
+ let mut candidate_start = &outer_range.start;
+
+ while let Some(item) = keys.peek() {
+ if item.range.end <= outer_range.start {
+ // This range sits entirely before the start of
+ // the outer range; just skip it.
+ let _ = keys.next();
+ } else if item.range.start <= outer_range.start {
+ // This range overlaps the start of the
+ // outer range, so the first possible candidate
+ // range begins at its end.
+ candidate_start = &item.range.end;
+ let _ = keys.next();
+ } else {
+ // The rest of the items might contribute to gaps.
+ break;
+ }
+ }
+
+ Gaps {
+ outer_range,
+ keys,
+ candidate_start,
+ }
+ }
+}
+
+/// An iterator over the entries of a `RangeMap`, ordered by key range.
+///
+/// The iterator element type is `(&'a Range<K>, &'a V)`.
+///
+/// This `struct` is created by the [`iter`] method on [`RangeMap`]. See its
+/// documentation for more.
+///
+/// [`iter`]: RangeMap::iter
+pub struct Iter<'a, K, V> {
+ inner: btree_map::Iter<'a, RangeStartWrapper<K>, V>,
+}
+
+impl<'a, K, V> Iterator for Iter<'a, K, V>
+where
+ K: 'a,
+ V: 'a,
+{
+ type Item = (&'a Range<K>, &'a V);
+
+ fn next(&mut self) -> Option<(&'a Range<K>, &'a V)> {
+ self.inner.next().map(|(by_start, v)| (&by_start.range, v))
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.inner.size_hint()
+ }
+}
+
+impl<'a, K, V> FusedIterator for Iter<'a, K, V> where K: Ord + Clone {}
+impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> where K: Ord + Clone {}
+
+/// An iterator over the entries of a `RangeMap`, ordered by key range.
+///
+/// The iterator element type is `(&'a Range<K>, &'a V)`.
+///
+/// This `struct` is created by the [`iter`] method on [`RangeMap`]. See its
+/// documentation for more.
+///
+/// [`iter`]: RangeMap::iter
+pub struct IterMut<'a, K, V> {
+ inner: btree_map::IterMut<'a, RangeStartWrapper<K>, V>,
+}
+
+impl<'a, K, V> Iterator for IterMut<'a, K, V>
+where
+ K: 'a,
+ V: 'a,
+{
+ type Item = (&'a Range<K>, &'a mut V);
+
+ fn next(&mut self) -> Option<(&'a Range<K>, &'a mut V)> {
+ self.inner.next().map(|(by_start, v)| (&by_start.range, v))
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.inner.size_hint()
+ }
+}
+
+impl<'a, K, V> FusedIterator for IterMut<'a, K, V> where K: Ord + Clone {}
+impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> where K: Ord + Clone {}
+
+/// An owning iterator over the entries of a `RangeMap`, ordered by key range.
+///
+/// The iterator element type is `(Range<K>, V)`.
+///
+/// This `struct` is created by the [`into_iter`] method on [`RangeMap`]
+/// (provided by the `IntoIterator` trait). See its documentation for more.
+///
+/// [`into_iter`]: IntoIterator::into_iter
+pub struct IntoIter<K, V> {
+ inner: btree_map::IntoIter<RangeStartWrapper<K>, V>,
+}
+
+impl<K, V> IntoIterator for RangeMap<K, V> {
+ type Item = (Range<K>, V);
+ type IntoIter = IntoIter<K, V>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ IntoIter {
+ inner: self.btm.into_iter(),
+ }
+ }
+}
+
+impl<K, V> Iterator for IntoIter<K, V> {
+ type Item = (Range<K>, V);
+
+ fn next(&mut self) -> Option<(Range<K>, V)> {
+ self.inner.next().map(|(by_start, v)| (by_start.range, v))
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.inner.size_hint()
+ }
+}
+
+impl<K, V> FusedIterator for IntoIter<K, V> where K: Ord + Clone {}
+impl<K, V> ExactSizeIterator for IntoIter<K, V> where K: Ord + Clone {}
+
+// We can't just derive this automatically, because that would
+// expose irrelevant (and private) implementation details.
+// Instead implement it in the same way that the underlying BTreeMap does.
+impl<K: Debug, V: Debug> Debug for RangeMap<K, V>
+where
+ K: Ord + Clone,
+ V: Eq + Clone,
+{
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ f.debug_map().entries(self.iter()).finish()
+ }
+}
+
+impl<K, V> FromIterator<(Range<K>, V)> for RangeMap<K, V>
+where
+ K: Ord + Clone,
+ V: Eq + Clone,
+{
+ fn from_iter<T: IntoIterator<Item = (Range<K>, V)>>(iter: T) -> Self {
+ let mut range_map = RangeMap::new();
+ range_map.extend(iter);
+ range_map
+ }
+}
+
+impl<K, V> Extend<(Range<K>, V)> for RangeMap<K, V>
+where
+ K: Ord + Clone,
+ V: Eq + Clone,
+{
+ fn extend<T: IntoIterator<Item = (Range<K>, V)>>(&mut self, iter: T) {
+ iter.into_iter().for_each(move |(k, v)| {
+ self.insert(k, v);
+ })
+ }
+}
+
+/// An iterator over entries of a `RangeMap` whose range overlaps with a specified range.
+///
+/// The iterator element type is `(&'a Range<K>, &'a V)`.
+///
+/// This `struct` is created by the [`range`] method on [`RangeMap`]. See its
+/// documentation for more.
+///
+/// [`range`]: RangeMap::range
+pub struct RangeIter<'a, K, V> {
+ inner: btree_map::Range<'a, RangeStartWrapper<K>, V>,
+}
+
+impl<'a, K, V> FusedIterator for RangeIter<'a, K, V> where K: Ord + Clone {}
+
+impl<'a, K, V> Iterator for RangeIter<'a, K, V>
+where
+ K: 'a,
+ V: 'a,
+{
+ type Item = (&'a Range<K>, &'a V);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.inner.next().map(|(by_start, v)| (&by_start.range, v))
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.inner.size_hint()
+ }
+}
+
+/// A mutable iterator over entries of a `RangeMap` whose range overlaps with a specified range.
+///
+/// The iterator element type is `(&'a Range<K>, &'a mut V)`.
+///
+/// This `struct` is created by the [`range_mut`] method on [`RangeMap`]. See its
+/// documentation for more.
+///
+/// [`range_mut`]: RangeMap::range_mut
+pub struct RangeMutIter<'a, K, V> {
+ inner: btree_map::RangeMut<'a, RangeStartWrapper<K>, V>,
+}
+
+impl<'a, K, V> FusedIterator for RangeMutIter<'a, K, V> where K: Ord + Clone {}
+
+impl<'a, K, V> Iterator for RangeMutIter<'a, K, V>
+where
+ K: 'a,
+ V: 'a,
+{
+ type Item = (&'a Range<K>, &'a mut V);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.inner.next().map(|(by_start, v)| (&by_start.range, v))
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.inner.size_hint()
+ }
+}
+
+/// An iterator over all ranges not covered by a `RangeMap`.
+///
+/// The iterator element type is `Range<K>`.
+///
+/// This `struct` is created by the [`gaps`] method on [`RangeMap`]. See its
+/// documentation for more.
+///
+/// [`gaps`]: RangeMap::gaps
+pub struct Gaps<'a, K, V> {
+ outer_range: &'a Range<K>,
+ keys: Peekable<btree_map::Keys<'a, RangeStartWrapper<K>, V>>,
+ candidate_start: &'a K,
+}
+
+// `Gaps` is always fused. (See definition of `next` below.)
+impl<'a, K, V> FusedIterator for Gaps<'a, K, V> where K: Ord + Clone {}
+
+impl<'a, K, V> Iterator for Gaps<'a, K, V>
+where
+ K: Ord + Clone,
+{
+ type Item = Range<K>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if *self.candidate_start >= self.outer_range.end {
+ // We've already passed the end of the outer range;
+ // there are no more gaps to find.
+ return None;
+ }
+
+ // Figure out where this gap ends.
+ let (gap_end, mut next_candidate_start) = if let Some(next_item) = self.keys.next() {
+ if next_item.range.start < self.outer_range.end {
+ // The gap goes up until the start of the next item,
+ // and the next candidate starts after it.
+ (&next_item.range.start, &next_item.range.end)
+ } else {
+ // The item sits after the end of the outer range,
+ // so this gap ends at the end of the outer range.
+ // This also means there will be no more gaps.
+ (&self.outer_range.end, &self.outer_range.end)
+ }
+ } else {
+ // There's no next item; the end is at the
+ // end of the outer range.
+ // This also means there will be no more gaps.
+ (&self.outer_range.end, &self.outer_range.end)
+ };
+
+ // Find the start of the next gap.
+ while let Some(next_item) = self.keys.peek() {
+ if next_item.range.start == *next_candidate_start {
+ // There's another item at the start of our candidate range.
+ // Gaps can't have zero width, so skip to the end of this
+ // item and try again.
+ next_candidate_start = &next_item.range.end;
+ self.keys.next().expect("We just checked that this exists");
+ } else {
+ // We found an item that actually has a gap before it.
+ break;
+ }
+ }
+
+ // Move the next candidate gap start past the end
+ // of this gap, and yield the gap we found.
+ let gap = self.candidate_start.clone()..gap_end.clone();
+ self.candidate_start = next_candidate_start;
+ Some(gap)
+ }
+}
+
+// Wrappers to allow storing (and sorting/searching)
+// ranges as the keys of a `BTreeMap`.
+//
+// We can do this because we maintain the invariants
+// that the order of range starts is the same as the order
+// of range ends, and that no two stored ranges have the
+// same start or end as each other.
+//
+// NOTE: Be very careful not to accidentally use these
+// if you really do want to compare equality of the
+// inner range!
+
+//
+// Range start wrapper
+//
+
+#[derive(Eq, Debug, Clone)]
+pub struct RangeStartWrapper<T> {
+ pub range: Range<T>,
+}
+
+impl<T> RangeStartWrapper<T> {
+ #[inline]
+ pub fn new(range: Range<T>) -> RangeStartWrapper<T> {
+ RangeStartWrapper { range }
+ }
+}
+
+impl<T> PartialEq for RangeStartWrapper<T>
+where
+ T: Eq,
+{
+ fn eq(&self, other: &RangeStartWrapper<T>) -> bool {
+ self.range.start == other.range.start
+ }
+}
+
+impl<T> Ord for RangeStartWrapper<T>
+where
+ T: Ord,
+{
+ fn cmp(&self, other: &RangeStartWrapper<T>) -> Ordering {
+ self.range.start.cmp(&other.range.start)
+ }
+}
+
+impl<T> PartialOrd for RangeStartWrapper<T>
+where
+ T: Ord,
+{
+ fn partial_cmp(&self, other: &RangeStartWrapper<T>) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+pub trait RangeExt<T> {
+ fn overlaps(&self, other: &Self) -> bool;
+ fn touches(&self, other: &Self) -> bool;
+}
+
+impl<T> RangeExt<T> for Range<T>
+where
+ T: Ord,
+{
+ fn overlaps(&self, other: &Self) -> bool {
+ // Strictly less than, because ends are excluded.
+ cmp::max(&self.start, &other.start) < cmp::min(&self.end, &other.end)
+ }
+
+ fn touches(&self, other: &Self) -> bool {
+ // Less-than-or-equal-to because if one end is excluded, the other is included.
+ // I.e. the two could be joined into a single range, because they're overlapping
+ // or immediately adjacent.
+ cmp::max(&self.start, &other.start) <= cmp::min(&self.end, &other.end)
+ }
+}
+
+/// Minimal version of unstable [`Step`](std::iter::Step) trait
+/// from the Rust standard library.
+///
+/// This is needed for [`RangeInclusiveMap`](crate::RangeInclusiveMap)
+/// because ranges stored as its keys interact with each other
+/// when the start of one is _adjacent_ the end of another.
+/// I.e. we need a concept of successor values rather than just
+/// equality, and that is what `Step` will
+/// eventually provide once it is stabilized.
+///
+/// **NOTE:** This will likely be deprecated and then eventually
+/// removed once the standard library's `Step`
+/// trait is stabilised, as most crates will then likely implement `Step`
+/// for their types where appropriate.
+///
+/// See [this issue](https://github.com/rust-lang/rust/issues/42168)
+/// for details about that stabilization process.
+pub trait StepLite {
+ /// Returns the _successor_ of `self`.
+ ///
+ /// If this would overflow the range of values supported by `Self`,
+ /// this function is allowed to panic, wrap, or saturate.
+ /// The suggested behavior is to panic when debug assertions are enabled,
+ /// and to wrap or saturate otherwise.
+ fn add_one(&self) -> Self;
+
+ /// Returns the _predecessor_ of `self`.
+ ///
+ /// If this would overflow the range of values supported by `Self`,
+ /// this function is allowed to panic, wrap, or saturate.
+ /// The suggested behavior is to panic when debug assertions are enabled,
+ /// and to wrap or saturate otherwise.
+ fn sub_one(&self) -> Self;
+}
+
+// Implement for all common integer types.
+macro_rules! impl_step_lite {
+ ($($t:ty)*) => ($(
+ impl StepLite for $t {
+ #[inline]
+ fn add_one(&self) -> Self {
+ Add::add(*self, 1)
+ }
+
+ #[inline]
+ fn sub_one(&self) -> Self {
+ Sub::sub(*self, 1)
+ }
+ }
+ )*)
+}
+
+impl_step_lite!(usize u8 u16 u32 u64 u128 i8 i16 i32 i64 i128);
+
+// TODO: When on nightly, a blanket implementation for
+// all types that implement `std::iter::Step` instead
+// of the auto-impl above.
+
+/// Successor and predecessor functions defined for `T`,
+/// but as free functions rather than methods on `T` itself.
+///
+/// This is useful as a workaround for Rust's "orphan rules",
+/// which prevent you from implementing [`StepLite`](crate::StepLite) for `T` if `T`
+/// is a foreign type.
+///
+/// **NOTE:** This will likely be deprecated and then eventually
+/// removed once the standard library's [`Step`](std::iter::Step)
+/// trait is stabilised, as most crates will then likely implement `Step`
+/// for their types where appropriate.
+///
+/// See [this issue](https://github.com/rust-lang/rust/issues/42168)
+/// for details about that stabilization process.
+///
+/// There is also a blanket implementation of `StepFns` for all
+/// types implementing `StepLite`. Consumers of this crate should
+/// prefer to implement `StepLite` for their own types, and only
+/// fall back to `StepFns` when dealing with foreign types.
+pub trait StepFns<T> {
+ /// Returns the _successor_ of value `start`.
+ ///
+ /// If this would overflow the range of values supported by `Self`,
+ /// this function is allowed to panic, wrap, or saturate.
+ /// The suggested behavior is to panic when debug assertions are enabled,
+ /// and to wrap or saturate otherwise.
+ fn add_one(start: &T) -> T;
+
+ /// Returns the _predecessor_ of value `start`.
+ ///
+ /// If this would overflow the range of values supported by `Self`,
+ /// this function is allowed to panic, wrap, or saturate.
+ /// The suggested behavior is to panic when debug assertions are enabled,
+ /// and to wrap or saturate otherwise.
+ fn sub_one(start: &T) -> T;
+}
+
+impl<T> StepFns<T> for T
+where
+ T: StepLite,
+{
+ fn add_one(start: &T) -> T {
+ start.add_one()
+ }
+
+ fn sub_one(start: &T) -> T {
+ start.sub_one()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use std::{format, vec, vec::Vec};
+
+ trait RangeMapExt<K, V> {
+ fn to_vec(&self) -> Vec<(Range<K>, V)>;
+ }
+
+ impl<K, V> RangeMapExt<K, V> for RangeMap<K, V>
+ where
+ K: Ord + Clone,
+ V: Eq + Clone,
+ {
+ fn to_vec(&self) -> Vec<(Range<K>, V)> {
+ self.iter().map(|(kr, v)| (kr.clone(), v.clone())).collect()
+ }
+ }
+
+ //
+ // Insertion tests
+ //
+
+ #[test]
+ fn empty_map_is_empty() {
+ let range_map: RangeMap<u32, bool> = RangeMap::new();
+ assert_eq!(range_map.to_vec(), vec![]);
+ }
+
+ #[test]
+ fn insert_into_empty_map() {
+ let mut range_map: RangeMap<u32, bool> = RangeMap::new();
+ range_map.insert(0..50, false);
+ assert_eq!(range_map.to_vec(), vec![(0..50, false)]);
+ }
+
+ #[test]
+ fn new_same_value_immediately_following_stored() {
+ let mut range_map: RangeMap<u32, bool> = RangeMap::new();
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ●---◌ ◌ ◌ ◌ ◌ ◌ ◌
+ range_map.insert(1..3, false);
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ◌ ●---◌ ◌ ◌ ◌ ◌
+ range_map.insert(3..5, false);
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ●-------◌ ◌ ◌ ◌ ◌
+ assert_eq!(range_map.to_vec(), vec![(1..5, false)]);
+ }
+
+ #[test]
+ fn new_different_value_immediately_following_stored() {
+ let mut range_map: RangeMap<u32, bool> = RangeMap::new();
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ●---◌ ◌ ◌ ◌ ◌ ◌ ◌
+ range_map.insert(1..3, false);
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ◌ ◆---◇ ◌ ◌ ◌ ◌
+ range_map.insert(3..5, true);
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ●---◌ ◌ ◌ ◌ ◌ ◌ ◌
+ // ◌ ◌ ◌ ◆---◇ ◌ ◌ ◌ ◌
+ assert_eq!(range_map.to_vec(), vec![(1..3, false), (3..5, true)]);
+ }
+
+ #[test]
+ fn new_same_value_overlapping_end_of_stored() {
+ let mut range_map: RangeMap<u32, bool> = RangeMap::new();
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ●-----◌ ◌ ◌ ◌ ◌ ◌
+ range_map.insert(1..4, false);
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ◌ ●---◌ ◌ ◌ ◌ ◌
+ range_map.insert(3..5, false);
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ●-------◌ ◌ ◌ ◌ ◌
+ assert_eq!(range_map.to_vec(), vec![(1..5, false)]);
+ }
+
+ #[test]
+ fn new_different_value_overlapping_end_of_stored() {
+ let mut range_map: RangeMap<u32, bool> = RangeMap::new();
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ●-----◌ ◌ ◌ ◌ ◌ ◌
+ range_map.insert(1..4, false);
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ◌ ◆---◇ ◌ ◌ ◌ ◌
+ range_map.insert(3..5, true);
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ●---◌ ◌ ◌ ◌ ◌ ◌ ◌
+ // ◌ ◌ ◌ ◆---◇ ◌ ◌ ◌ ◌
+ assert_eq!(range_map.to_vec(), vec![(1..3, false), (3..5, true)]);
+ }
+
+ #[test]
+ fn new_same_value_immediately_preceding_stored() {
+ let mut range_map: RangeMap<u32, bool> = RangeMap::new();
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ◌ ●---◌ ◌ ◌ ◌ ◌
+ range_map.insert(3..5, false);
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ●---◌ ◌ ◌ ◌ ◌ ◌ ◌
+ range_map.insert(1..3, false);
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ●-------◌ ◌ ◌ ◌ ◌
+ assert_eq!(range_map.to_vec(), vec![(1..5, false)]);
+ }
+
+ #[test]
+ fn new_different_value_immediately_preceding_stored() {
+ let mut range_map: RangeMap<u32, bool> = RangeMap::new();
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ◌ ◆---◇ ◌ ◌ ◌ ◌
+ range_map.insert(3..5, true);
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ●---◌ ◌ ◌ ◌ ◌ ◌ ◌
+ range_map.insert(1..3, false);
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ●---◌ ◌ ◌ ◌ ◌ ◌ ◌
+ // ◌ ◌ ◌ ◆---◇ ◌ ◌ ◌ ◌
+ assert_eq!(range_map.to_vec(), vec![(1..3, false), (3..5, true)]);
+ }
+
+ #[test]
+ fn new_same_value_wholly_inside_stored() {
+ let mut range_map: RangeMap<u32, bool> = RangeMap::new();
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ●-------◌ ◌ ◌ ◌ ◌
+ range_map.insert(1..5, false);
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ●---◌ ◌ ◌ ◌ ◌ ◌ ◌
+ range_map.insert(2..4, false);
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ●-------◌ ◌ ◌ ◌ ◌
+ assert_eq!(range_map.to_vec(), vec![(1..5, false)]);
+ }
+
+ #[test]
+ fn new_different_value_wholly_inside_stored() {
+ let mut range_map: RangeMap<u32, bool> = RangeMap::new();
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◆-------◇ ◌ ◌ ◌ ◌
+ range_map.insert(1..5, true);
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ●---◌ ◌ ◌ ◌ ◌ ◌ ◌
+ range_map.insert(2..4, false);
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ●-◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌
+ // ◌ ◌ ◆---◇ ◌ ◌ ◌ ◌ ◌
+ // ◌ ◌ ◌ ◌ ●-◌ ◌ ◌ ◌ ◌
+ assert_eq!(
+ range_map.to_vec(),
+ vec![(1..2, true), (2..4, false), (4..5, true)]
+ );
+ }
+
+ #[test]
+ fn replace_at_end_of_existing_range_should_coalesce() {
+ let mut range_map: RangeMap<u32, bool> = RangeMap::new();
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ●---◌ ◌ ◌ ◌ ◌ ◌ ◌
+ range_map.insert(1..3, false);
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ◌ ●---◌ ◌ ◌ ◌ ◌
+ range_map.insert(3..5, true);
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ◌ ●---◌ ◌ ◌ ◌ ◌
+ range_map.insert(3..5, false);
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ●-------◌ ◌ ◌ ◌ ◌
+ assert_eq!(range_map.to_vec(), vec![(1..5, false)]);
+ }
+
+ //
+ // Get* tests
+ //
+
+ #[test]
+ fn get() {
+ let mut range_map: RangeMap<u32, bool> = RangeMap::new();
+ range_map.insert(0..50, false);
+ assert_eq!(range_map.get(&49), Some(&false));
+ assert_eq!(range_map.get(&50), None);
+ }
+
+ #[test]
+ fn get_key_value() {
+ let mut range_map: RangeMap<u32, bool> = RangeMap::new();
+ range_map.insert(0..50, false);
+ assert_eq!(range_map.get_key_value(&49), Some((&(0..50), &false)));
+ assert_eq!(range_map.get_key_value(&50), None);
+ }
+
+ //
+ // Removal tests
+ //
+
+ #[test]
+ fn remove_from_empty_map() {
+ let mut range_map: RangeMap<u32, bool> = RangeMap::new();
+ range_map.remove(0..50);
+ assert_eq!(range_map.to_vec(), vec![]);
+ }
+
+ #[test]
+ fn remove_non_covered_range_before_stored() {
+ let mut range_map: RangeMap<u32, bool> = RangeMap::new();
+ range_map.insert(25..75, false);
+ range_map.remove(0..25);
+ assert_eq!(range_map.to_vec(), vec![(25..75, false)]);
+ }
+
+ #[test]
+ fn remove_non_covered_range_after_stored() {
+ let mut range_map: RangeMap<u32, bool> = RangeMap::new();
+ range_map.insert(25..75, false);
+ range_map.remove(75..100);
+ assert_eq!(range_map.to_vec(), vec![(25..75, false)]);
+ }
+
+ #[test]
+ fn remove_overlapping_start_of_stored() {
+ let mut range_map: RangeMap<u32, bool> = RangeMap::new();
+ range_map.insert(25..75, false);
+ range_map.remove(0..30);
+ assert_eq!(range_map.to_vec(), vec![(30..75, false)]);
+ }
+
+ #[test]
+ fn remove_middle_of_stored() {
+ let mut range_map: RangeMap<u32, bool> = RangeMap::new();
+ range_map.insert(25..75, false);
+ range_map.remove(30..70);
+ assert_eq!(range_map.to_vec(), vec![(25..30, false), (70..75, false)]);
+ }
+
+ #[test]
+ fn remove_overlapping_end_of_stored() {
+ let mut range_map: RangeMap<u32, bool> = RangeMap::new();
+ range_map.insert(25..75, false);
+ range_map.remove(70..100);
+ assert_eq!(range_map.to_vec(), vec![(25..70, false)]);
+ }
+
+ #[test]
+ fn remove_exactly_stored() {
+ let mut range_map: RangeMap<u32, bool> = RangeMap::new();
+ range_map.insert(25..75, false);
+ range_map.remove(25..75);
+ assert_eq!(range_map.to_vec(), vec![]);
+ }
+
+ #[test]
+ fn remove_superset_of_stored() {
+ let mut range_map: RangeMap<u32, bool> = RangeMap::new();
+ range_map.insert(25..75, false);
+ range_map.remove(0..100);
+ assert_eq!(range_map.to_vec(), vec![]);
+ }
+
+ // Gaps tests
+
+ #[test]
+ fn whole_range_is_a_gap() {
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌ ◌
+ let range_map: RangeMap<u32, ()> = RangeMap::new();
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◆-------------◇ ◌
+ let outer_range = 1..8;
+ let mut gaps = range_map.gaps(&outer_range);
+ // Should yield the entire outer range.
+ assert_eq!(gaps.next(), Some(1..8));
+ assert_eq!(gaps.next(), None);
+ // Gaps iterator should be fused.
+ assert_eq!(gaps.next(), None);
+ assert_eq!(gaps.next(), None);
+ }
+
+ #[test]
+ fn whole_range_is_covered_exactly() {
+ let mut range_map: RangeMap<u32, ()> = RangeMap::new();
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ●---------◌ ◌ ◌ ◌
+ range_map.insert(1..6, ());
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◆---------◇ ◌ ◌ ◌
+ let outer_range = 1..6;
+ let mut gaps = range_map.gaps(&outer_range);
+ // Should yield no gaps.
+ assert_eq!(gaps.next(), None);
+ // Gaps iterator should be fused.
+ assert_eq!(gaps.next(), None);
+ assert_eq!(gaps.next(), None);
+ }
+
+ #[test]
+ fn item_before_outer_range() {
+ let mut range_map: RangeMap<u32, ()> = RangeMap::new();
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ●---◌ ◌ ◌ ◌ ◌ ◌ ◌
+ range_map.insert(1..3, ());
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ◌ ◌ ◌ ◆-----◇ ◌
+ let outer_range = 5..8;
+ let mut gaps = range_map.gaps(&outer_range);
+ // Should yield the entire outer range.
+ assert_eq!(gaps.next(), Some(5..8));
+ assert_eq!(gaps.next(), None);
+ // Gaps iterator should be fused.
+ assert_eq!(gaps.next(), None);
+ assert_eq!(gaps.next(), None);
+ }
+
+ #[test]
+ fn item_touching_start_of_outer_range() {
+ let mut range_map: RangeMap<u32, ()> = RangeMap::new();
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ●-------◌ ◌ ◌ ◌ ◌
+ range_map.insert(1..5, ());
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ◌ ◌ ◌ ◆-----◇ ◌
+ let outer_range = 5..8;
+ let mut gaps = range_map.gaps(&outer_range);
+ // Should yield the entire outer range.
+ assert_eq!(gaps.next(), Some(5..8));
+ assert_eq!(gaps.next(), None);
+ // Gaps iterator should be fused.
+ assert_eq!(gaps.next(), None);
+ assert_eq!(gaps.next(), None);
+ }
+
+ #[test]
+ fn item_overlapping_start_of_outer_range() {
+ let mut range_map: RangeMap<u32, ()> = RangeMap::new();
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ●---------◌ ◌ ◌ ◌
+ range_map.insert(1..6, ());
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ◌ ◌ ◌ ◆-----◇ ◌
+ let outer_range = 5..8;
+ let mut gaps = range_map.gaps(&outer_range);
+ // Should yield from the end of the stored item
+ // to the end of the outer range.
+ assert_eq!(gaps.next(), Some(6..8));
+ assert_eq!(gaps.next(), None);
+ // Gaps iterator should be fused.
+ assert_eq!(gaps.next(), None);
+ assert_eq!(gaps.next(), None);
+ }
+
+ #[test]
+ fn item_starting_at_start_of_outer_range() {
+ let mut range_map: RangeMap<u32, ()> = RangeMap::new();
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ◌ ◌ ◌ ●-◌ ◌ ◌ ◌
+ range_map.insert(5..6, ());
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ◌ ◌ ◌ ◆-----◇ ◌
+ let outer_range = 5..8;
+ let mut gaps = range_map.gaps(&outer_range);
+ // Should yield from the item onwards.
+ assert_eq!(gaps.next(), Some(6..8));
+ assert_eq!(gaps.next(), None);
+ // Gaps iterator should be fused.
+ assert_eq!(gaps.next(), None);
+ assert_eq!(gaps.next(), None);
+ }
+
+ #[test]
+ fn items_floating_inside_outer_range() {
+ let mut range_map: RangeMap<u32, ()> = RangeMap::new();
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ◌ ◌ ◌ ●-◌ ◌ ◌ ◌
+ range_map.insert(5..6, ());
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ◌ ●-◌ ◌ ◌ ◌ ◌ ◌
+ range_map.insert(3..4, ());
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◆-------------◇ ◌
+ let outer_range = 1..8;
+ let mut gaps = range_map.gaps(&outer_range);
+ // Should yield gaps at start, between items,
+ // and at end.
+ assert_eq!(gaps.next(), Some(1..3));
+ assert_eq!(gaps.next(), Some(4..5));
+ assert_eq!(gaps.next(), Some(6..8));
+ assert_eq!(gaps.next(), None);
+ // Gaps iterator should be fused.
+ assert_eq!(gaps.next(), None);
+ assert_eq!(gaps.next(), None);
+ }
+
+ #[test]
+ fn item_ending_at_end_of_outer_range() {
+ let mut range_map: RangeMap<u32, ()> = RangeMap::new();
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ◌ ◌ ◌ ◌ ◌ ●-◌ ◌
+ range_map.insert(7..8, ());
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ◌ ◌ ◌ ◆-----◇ ◌
+ let outer_range = 5..8;
+ let mut gaps = range_map.gaps(&outer_range);
+ // Should yield from the start of the outer range
+ // up to the start of the stored item.
+ assert_eq!(gaps.next(), Some(5..7));
+ assert_eq!(gaps.next(), None);
+ // Gaps iterator should be fused.
+ assert_eq!(gaps.next(), None);
+ assert_eq!(gaps.next(), None);
+ }
+
+ #[test]
+ fn item_overlapping_end_of_outer_range() {
+ let mut range_map: RangeMap<u32, ()> = RangeMap::new();
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ◌ ◌ ●---◌ ◌ ◌ ◌
+ range_map.insert(4..6, ());
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ◆-----◇ ◌ ◌ ◌ ◌
+ let outer_range = 2..5;
+ let mut gaps = range_map.gaps(&outer_range);
+ // Should yield from the start of the outer range
+ // up to the start of the stored item.
+ assert_eq!(gaps.next(), Some(2..4));
+ assert_eq!(gaps.next(), None);
+ // Gaps iterator should be fused.
+ assert_eq!(gaps.next(), None);
+ assert_eq!(gaps.next(), None);
+ }
+
+ #[test]
+ fn item_touching_end_of_outer_range() {
+ let mut range_map: RangeMap<u32, ()> = RangeMap::new();
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ◌ ◌ ●-------◌ ◌
+ range_map.insert(4..8, ());
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◆-----◇ ◌ ◌ ◌ ◌ ◌
+ let outer_range = 1..4;
+ let mut gaps = range_map.gaps(&outer_range);
+ // Should yield the entire outer range.
+ assert_eq!(gaps.next(), Some(1..4));
+ assert_eq!(gaps.next(), None);
+ // Gaps iterator should be fused.
+ assert_eq!(gaps.next(), None);
+ assert_eq!(gaps.next(), None);
+ }
+
+ #[test]
+ fn item_after_outer_range() {
+ let mut range_map: RangeMap<u32, ()> = RangeMap::new();
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ◌ ◌ ◌ ◌ ●---◌ ◌
+ range_map.insert(6..7, ());
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◆-----◇ ◌ ◌ ◌ ◌ ◌
+ let outer_range = 1..4;
+ let mut gaps = range_map.gaps(&outer_range);
+ // Should yield the entire outer range.
+ assert_eq!(gaps.next(), Some(1..4));
+ assert_eq!(gaps.next(), None);
+ // Gaps iterator should be fused.
+ assert_eq!(gaps.next(), None);
+ assert_eq!(gaps.next(), None);
+ }
+
+ #[test]
+ fn empty_outer_range_with_items_away_from_both_sides() {
+ let mut range_map: RangeMap<u32, ()> = RangeMap::new();
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◆---◇ ◌ ◌ ◌ ◌ ◌ ◌
+ range_map.insert(1..3, ());
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ◌ ◌ ◌ ◆---◇ ◌ ◌
+ range_map.insert(5..7, ());
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ◌ ◌ ◆ ◌ ◌ ◌ ◌ ◌
+ let outer_range = 4..4;
+ let mut gaps = range_map.gaps(&outer_range);
+ // Should yield no gaps.
+ assert_eq!(gaps.next(), None);
+ // Gaps iterator should be fused.
+ assert_eq!(gaps.next(), None);
+ assert_eq!(gaps.next(), None);
+ }
+
+ #[test]
+ fn empty_outer_range_with_items_touching_both_sides() {
+ let mut range_map: RangeMap<u32, ()> = RangeMap::new();
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ◆---◇ ◌ ◌ ◌ ◌ ◌ ◌
+ range_map.insert(2..4, ());
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ◌ ◌ ◆---◇ ◌ ◌ ◌
+ range_map.insert(4..6, ());
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ◌ ◌ ◆ ◌ ◌ ◌ ◌ ◌
+ let outer_range = 4..4;
+ let mut gaps = range_map.gaps(&outer_range);
+ // Should yield no gaps.
+ assert_eq!(gaps.next(), None);
+ // Gaps iterator should be fused.
+ assert_eq!(gaps.next(), None);
+ assert_eq!(gaps.next(), None);
+ }
+
+ #[test]
+ fn empty_outer_range_with_item_straddling() {
+ let mut range_map: RangeMap<u32, ()> = RangeMap::new();
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ◆-----◇ ◌ ◌ ◌ ◌ ◌
+ range_map.insert(2..5, ());
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ◌ ◌ ◆ ◌ ◌ ◌ ◌ ◌
+ let outer_range = 4..4;
+ let mut gaps = range_map.gaps(&outer_range);
+ // Should yield no gaps.
+ assert_eq!(gaps.next(), None);
+ // Gaps iterator should be fused.
+ assert_eq!(gaps.next(), None);
+ assert_eq!(gaps.next(), None);
+ }
+
+ #[test]
+ fn no_empty_gaps() {
+ // Make two ranges different values so they don't
+ // get coalesced.
+ let mut range_map: RangeMap<u32, bool> = RangeMap::new();
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ◌ ◌ ●-◌ ◌ ◌ ◌ ◌
+ range_map.insert(4..5, true);
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◌ ◌ ●-◌ ◌ ◌ ◌ ◌ ◌
+ range_map.insert(3..4, false);
+ // 0 1 2 3 4 5 6 7 8 9
+ // ◌ ◆-------------◇ ◌
+ let outer_range = 1..8;
+ let mut gaps = range_map.gaps(&outer_range);
+ // Should yield gaps at start and end, but not between the
+ // two touching items. (4 is covered, so there should be no gap.)
+ assert_eq!(gaps.next(), Some(1..3));
+ assert_eq!(gaps.next(), Some(5..8));
+ assert_eq!(gaps.next(), None);
+ // Gaps iterator should be fused.
+ assert_eq!(gaps.next(), None);
+ assert_eq!(gaps.next(), None);
+ }
+
+ ///
+ /// impl Debug
+ ///
+
+ #[test]
+ fn map_debug_repr_looks_right() {
+ let mut map: RangeMap<u32, ()> = RangeMap::new();
+
+ // Empty
+ assert_eq!(format!("{:?}", map), "{}");
+
+ // One entry
+ map.insert(2..5, ());
+ assert_eq!(format!("{:?}", map), "{2..5: ()}");
+
+ // Many entries
+ map.insert(6..7, ());
+ map.insert(8..9, ());
+ assert_eq!(format!("{:?}", map), "{2..5: (), 6..7: (), 8..9: ()}");
+ }
+
+ // Iterator Tests
+
+ #[test]
+ fn into_iter_matches_iter() {
+ // Just use vec since that's the same implementation we'd expect
+ let mut range_map: RangeMap<u32, bool> = RangeMap::new();
+ range_map.insert(1..3, false);
+ range_map.insert(3..5, true);
+
+ let cloned = range_map.to_vec();
+ let consumed = range_map.into_iter().collect::<Vec<_>>();
+
+ // Correct value
+ assert_eq!(cloned, vec![(1..3, false), (3..5, true)]);
+
+ // Equality
+ assert_eq!(cloned, consumed);
+ }
+}
diff --git a/src/range_set.rs b/src/range_set.rs
new file mode 100644
index 0000000..d5f9154
--- /dev/null
+++ b/src/range_set.rs
@@ -0,0 +1,68 @@
+// Copyright (c) 2021 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use std::ops::Range;
+
+/// A set of ordered types.
+///
+/// Implemented as an ordered list of ranges that do not touch or overlap.
+#[derive(Clone, Debug, Default)]
+pub struct RangeSet<T>(Vec<Range<T>>);
+
+impl<T: Ord + Copy> RangeSet<T> {
+ /// Returns a new empty `RangeSet`.
+ #[inline]
+ pub fn new() -> Self {
+ RangeSet(Vec::new())
+ }
+
+ /// Returns whether all elements of `range` are contained in the set.
+ #[inline]
+ pub fn contains(&self, elements: Range<T>) -> bool {
+ self.0
+ .iter()
+ .any(|range| range.start <= elements.end && range.end >= elements.end)
+ }
+
+ /// Removes all ranges from the set.
+ #[inline]
+ pub fn clear(&mut self) {
+ self.0.clear();
+ }
+
+ /// Inserts the elements of `range` into the set.
+ pub fn insert(&mut self, elements: Range<T>) {
+ // Find the first range that is not less than `elements`, and the first range that is greater.
+ let index_start = self
+ .0
+ .iter()
+ .position(|range| range.end >= elements.start)
+ .unwrap_or(self.0.len());
+ let index_end = self
+ .0
+ .iter()
+ .position(|range| range.start > elements.end)
+ .unwrap_or(self.0.len());
+
+ if index_start == index_end {
+ // `elements` fits in between index_start - 1 and index_start.
+ self.0.insert(index_start, elements);
+ } else {
+ // `elements` touches the ranges between index_start and index_end.
+ // Expand `elements` with the touched ranges, then store it in the first.
+ self.0[index_start] = self.0[index_start..index_end]
+ .iter()
+ .fold(elements, |Range { start, end }, range| {
+ start.min(range.start)..end.max(range.end)
+ });
+ // Delete the remaining elements.
+ self.0.drain(index_start + 1..index_end);
+ }
+ }
+}
diff --git a/src/render_pass/attachments_list.rs b/src/render_pass/attachments_list.rs
deleted file mode 100644
index 2b1fe23..0000000
--- a/src/render_pass/attachments_list.rs
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::image::view::ImageViewAbstract;
-use crate::SafeDeref;
-use std::sync::Arc;
-//use sync::AccessFlags;
-//use sync::PipelineStages;
-
-/// A list of attachments.
-// TODO: rework this trait
-pub unsafe trait AttachmentsList {
- fn num_attachments(&self) -> usize;
-
- fn as_image_view_access(&self, index: usize) -> Option<&dyn ImageViewAbstract>;
-}
-
-unsafe impl<T> AttachmentsList for T
-where
- T: SafeDeref,
- T::Target: AttachmentsList,
-{
- #[inline]
- fn num_attachments(&self) -> usize {
- (**self).num_attachments()
- }
-
- #[inline]
- fn as_image_view_access(&self, index: usize) -> Option<&dyn ImageViewAbstract> {
- (**self).as_image_view_access(index)
- }
-}
-
-unsafe impl AttachmentsList for () {
- #[inline]
- fn num_attachments(&self) -> usize {
- 0
- }
-
- #[inline]
- fn as_image_view_access(&self, _: usize) -> Option<&dyn ImageViewAbstract> {
- None
- }
-}
-
-unsafe impl AttachmentsList for Vec<Arc<dyn ImageViewAbstract + Send + Sync>> {
- #[inline]
- fn num_attachments(&self) -> usize {
- self.len()
- }
-
- #[inline]
- fn as_image_view_access(&self, index: usize) -> Option<&dyn ImageViewAbstract> {
- self.get(index).map(|v| &**v as &_)
- }
-}
-
-unsafe impl<A, B> AttachmentsList for (A, B)
-where
- A: AttachmentsList,
- B: ImageViewAbstract,
-{
- #[inline]
- fn num_attachments(&self) -> usize {
- self.0.num_attachments() + 1
- }
-
- #[inline]
- fn as_image_view_access(&self, index: usize) -> Option<&dyn ImageViewAbstract> {
- if index == self.0.num_attachments() {
- Some(&self.1)
- } else {
- self.0.as_image_view_access(index)
- }
- }
-}
diff --git a/src/render_pass/compat_atch.rs b/src/render_pass/compat_atch.rs
deleted file mode 100644
index 381f4f3..0000000
--- a/src/render_pass/compat_atch.rs
+++ /dev/null
@@ -1,263 +0,0 @@
-// Copyright (c) 2017 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-//! This module contains the `ensure_image_view_compatible` function, which verifies whether
-//! an image view can be used as a render pass attachment.
-
-use crate::image::view::ImageViewAbstract;
-use crate::render_pass::RenderPassDesc;
-use crate::{format::Format, image::SampleCount};
-use std::error;
-use std::fmt;
-
-/// Checks whether the given image view is allowed to be the nth attachment of the given render
-/// pass.
-///
-/// # Panic
-///
-/// Panics if the attachment number is out of range.
-// TODO: add a specializable trait instead, that uses this function
-// TODO: ImageView instead of ImageViewAbstract?
-pub fn ensure_image_view_compatible<I>(
- render_pass_desc: &RenderPassDesc,
- attachment_num: usize,
- image_view: &I,
-) -> Result<(), IncompatibleRenderPassAttachmentError>
-where
- I: ?Sized + ImageViewAbstract,
-{
- let attachment_desc = render_pass_desc
- .attachments()
- .get(attachment_num)
- .expect("Attachment num out of range");
-
- if image_view.format() != attachment_desc.format {
- return Err(IncompatibleRenderPassAttachmentError::FormatMismatch {
- expected: attachment_desc.format,
- obtained: image_view.format(),
- });
- }
-
- if image_view.image().samples() != attachment_desc.samples {
- return Err(IncompatibleRenderPassAttachmentError::SamplesMismatch {
- expected: attachment_desc.samples,
- obtained: image_view.image().samples(),
- });
- }
-
- if !image_view.component_mapping().is_identity() {
- return Err(IncompatibleRenderPassAttachmentError::NotIdentitySwizzled);
- }
-
- for subpass in render_pass_desc.subpasses() {
- if subpass
- .color_attachments
- .iter()
- .any(|&(n, _)| n == attachment_num)
- {
- debug_assert!(image_view.image().has_color()); // Was normally checked by the render pass.
- if !image_view.image().inner().image.usage().color_attachment {
- return Err(IncompatibleRenderPassAttachmentError::MissingColorAttachmentUsage);
- }
- }
-
- if let Some((ds, _)) = subpass.depth_stencil {
- if ds == attachment_num {
- // Was normally checked by the render pass.
- debug_assert!(image_view.image().has_depth() || image_view.image().has_stencil());
- if !image_view
- .image()
- .inner()
- .image
- .usage()
- .depth_stencil_attachment
- {
- return Err(
- IncompatibleRenderPassAttachmentError::MissingDepthStencilAttachmentUsage,
- );
- }
- }
- }
-
- if subpass
- .input_attachments
- .iter()
- .any(|&(n, _)| n == attachment_num)
- {
- if !image_view.image().inner().image.usage().input_attachment {
- return Err(IncompatibleRenderPassAttachmentError::MissingInputAttachmentUsage);
- }
- }
- }
-
- // TODO: consider forbidding LoadOp::Load if image is transient
-
- // TODO: are all image layouts allowed? check this
-
- Ok(())
-}
-
-/// Error that can happen when an image is not compatible with a render pass attachment slot.
-#[derive(Copy, Clone, Debug)]
-pub enum IncompatibleRenderPassAttachmentError {
- /// The image format expected by the render pass doesn't match the actual format of
- /// the image.
- FormatMismatch {
- /// Format expected by the render pass.
- expected: Format,
- /// Format of the image.
- obtained: Format,
- },
-
- /// The number of samples expected by the render pass doesn't match the number of samples of
- /// the image.
- SamplesMismatch {
- /// Number of samples expected by the render pass.
- expected: SampleCount,
- /// Number of samples of the image.
- obtained: SampleCount,
- },
-
- /// The image view has a component swizzle that is different from identity.
- NotIdentitySwizzled,
-
- /// The image is used as a color attachment but is missing the color attachment usage.
- MissingColorAttachmentUsage,
-
- /// The image is used as a depth/stencil attachment but is missing the depth-stencil attachment
- /// usage.
- MissingDepthStencilAttachmentUsage,
-
- /// The image is used as an input attachment but is missing the input attachment usage.
- MissingInputAttachmentUsage,
-}
-
-impl error::Error for IncompatibleRenderPassAttachmentError {}
-
-impl fmt::Display for IncompatibleRenderPassAttachmentError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- IncompatibleRenderPassAttachmentError::FormatMismatch { .. } => {
- "mismatch between the format expected by the render pass and the actual format"
- }
- IncompatibleRenderPassAttachmentError::SamplesMismatch { .. } => {
- "mismatch between the number of samples expected by the render pass and the actual \
- number of samples"
- }
- IncompatibleRenderPassAttachmentError::NotIdentitySwizzled => {
- "the image view's component mapping is not identity swizzled"
- }
- IncompatibleRenderPassAttachmentError::MissingColorAttachmentUsage => {
- "the image is used as a color attachment but is missing the color attachment usage"
- }
- IncompatibleRenderPassAttachmentError::MissingDepthStencilAttachmentUsage => {
- "the image is used as a depth/stencil attachment but is missing the depth-stencil \
- attachment usage"
- }
- IncompatibleRenderPassAttachmentError::MissingInputAttachmentUsage => {
- "the image is used as an input attachment but is missing the input \
- attachment usage"
- }
- }
- )
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::ensure_image_view_compatible;
- use super::IncompatibleRenderPassAttachmentError;
- use crate::format::Format;
- use crate::image::view::ImageView;
- use crate::image::AttachmentImage;
- use crate::render_pass::RenderPassDesc;
-
- #[test]
- fn basic_ok() {
- let (device, _) = gfx_dev_and_queue!();
-
- let rp = single_pass_renderpass!(device.clone(),
- attachments: {
- color: {
- load: Clear,
- store: Store,
- format: Format::R8G8B8A8Unorm,
- samples: 1,
- }
- },
- pass: {
- color: [color],
- depth_stencil: {}
- }
- )
- .unwrap();
-
- let view = ImageView::new(
- AttachmentImage::new(device, [128, 128], Format::R8G8B8A8Unorm).unwrap(),
- )
- .unwrap();
-
- ensure_image_view_compatible(rp.desc(), 0, &view).unwrap();
- }
-
- #[test]
- fn format_mismatch() {
- let (device, _) = gfx_dev_and_queue!();
-
- let rp = single_pass_renderpass!(device.clone(),
- attachments: {
- color: {
- load: Clear,
- store: Store,
- format: Format::R16G16Sfloat,
- samples: 1,
- }
- },
- pass: {
- color: [color],
- depth_stencil: {}
- }
- )
- .unwrap();
-
- let view = ImageView::new(
- AttachmentImage::new(device, [128, 128], Format::R8G8B8A8Unorm).unwrap(),
- )
- .unwrap();
-
- match ensure_image_view_compatible(rp.desc(), 0, &view) {
- Err(IncompatibleRenderPassAttachmentError::FormatMismatch {
- expected: Format::R16G16Sfloat,
- obtained: Format::R8G8B8A8Unorm,
- }) => (),
- e => panic!("{:?}", e),
- }
- }
-
- #[test]
- fn attachment_out_of_range() {
- let (device, _) = gfx_dev_and_queue!();
-
- let rp = RenderPassDesc::empty();
- let view = ImageView::new(
- AttachmentImage::new(device, [128, 128], Format::R8G8B8A8Unorm).unwrap(),
- )
- .unwrap();
-
- assert_should_panic!("Attachment num out of range", {
- let _ = ensure_image_view_compatible(&rp, 0, &view);
- });
- }
-
- // TODO: more tests
-}
diff --git a/src/render_pass/create.rs b/src/render_pass/create.rs
new file mode 100644
index 0000000..07c4506
--- /dev/null
+++ b/src/render_pass/create.rs
@@ -0,0 +1,1979 @@
+// Copyright (c) 2022 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use super::{
+ AttachmentDescription, AttachmentReference, LoadOp, RenderPass, RenderPassCreateInfo,
+ SubpassDependency, SubpassDescription,
+};
+use crate::{
+ device::Device,
+ format::FormatFeatures,
+ image::{ImageAspects, ImageLayout, SampleCount},
+ sync::{AccessFlags, DependencyFlags, PipelineStages},
+ OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject,
+};
+use smallvec::SmallVec;
+use std::{
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+ mem::MaybeUninit,
+ ptr,
+};
+
+impl RenderPass {
+ pub(super) fn validate(
+ device: &Device,
+ create_info: &mut RenderPassCreateInfo,
+ ) -> Result<(), RenderPassCreationError> {
+ let properties = device.physical_device().properties();
+
+ let RenderPassCreateInfo {
+ attachments,
+ subpasses,
+ dependencies,
+ correlated_view_masks,
+ _ne: _,
+ } = create_info;
+
+ /*
+ Attachments
+ */
+
+ let mut attachment_potential_format_features = Vec::with_capacity(attachments.len());
+
+ for (atch_num, attachment) in attachments.iter().enumerate() {
+ let &AttachmentDescription {
+ format,
+ samples,
+ load_op,
+ store_op,
+ stencil_load_op,
+ stencil_store_op,
+ initial_layout,
+ final_layout,
+ _ne: _,
+ } = attachment;
+ let atch_num = atch_num as u32;
+
+ // VUID-VkAttachmentDescription2-finalLayout-03061
+ if matches!(
+ final_layout,
+ ImageLayout::Undefined | ImageLayout::Preinitialized
+ ) {
+ return Err(RenderPassCreationError::AttachmentLayoutInvalid {
+ attachment: atch_num,
+ });
+ }
+
+ let format = format.unwrap();
+ let aspects = format.aspects();
+
+ // VUID-VkAttachmentDescription2-format-parameter
+ format.validate_device(device)?;
+
+ // VUID-VkAttachmentDescription2-samples-parameter
+ samples.validate_device(device)?;
+
+ for load_op in [load_op, stencil_load_op] {
+ // VUID-VkAttachmentDescription2-loadOp-parameter
+ // VUID-VkAttachmentDescription2-stencilLoadOp-parameter
+ load_op.validate_device(device)?;
+ }
+
+ for store_op in [store_op, stencil_store_op] {
+ // VUID-VkAttachmentDescription2-storeOp-parameter
+ // VUID-VkAttachmentDescription2-stencilStoreOp-parameter
+ store_op.validate_device(device)?;
+ }
+
+ for layout in [initial_layout, final_layout] {
+ // VUID-VkAttachmentDescription2-initialLayout-parameter
+ // VUID-VkAttachmentDescription2-finalLayout-parameter
+ layout.validate_device(device)?;
+
+ if aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL) {
+ // VUID-VkAttachmentDescription2-format-03281
+ // VUID-VkAttachmentDescription2-format-03283
+ if matches!(layout, ImageLayout::ColorAttachmentOptimal) {
+ return Err(RenderPassCreationError::AttachmentLayoutInvalid {
+ attachment: atch_num,
+ });
+ }
+ } else {
+ // VUID-VkAttachmentDescription2-format-03280
+ // VUID-VkAttachmentDescription2-format-03282
+ // VUID-VkAttachmentDescription2-format-06487
+ // VUID-VkAttachmentDescription2-format-06488
+ if matches!(
+ layout,
+ ImageLayout::DepthStencilAttachmentOptimal
+ | ImageLayout::DepthStencilReadOnlyOptimal
+ | ImageLayout::DepthAttachmentStencilReadOnlyOptimal
+ | ImageLayout::DepthReadOnlyStencilAttachmentOptimal
+ ) {
+ return Err(RenderPassCreationError::AttachmentLayoutInvalid {
+ attachment: atch_num,
+ });
+ }
+ }
+ }
+
+ // Use unchecked, because all validation has been done above.
+ attachment_potential_format_features.push(unsafe {
+ device
+ .physical_device()
+ .format_properties_unchecked(format)
+ .potential_format_features()
+ });
+ }
+
+ /*
+ Subpasses
+ */
+
+ // VUID-VkRenderPassCreateInfo2-subpassCount-arraylength
+ assert!(!subpasses.is_empty());
+
+ let is_multiview = subpasses[0].view_mask != 0;
+
+ // VUID-VkSubpassDescription2-multiview-06558
+ if is_multiview && !device.enabled_features().multiview {
+ return Err(RenderPassCreationError::RequirementNotMet {
+ required_for: "`create_info.subpasses[0].view_mask` is not `0`",
+ requires_one_of: RequiresOneOf {
+ features: &["multiview"],
+ ..Default::default()
+ },
+ });
+ }
+
+ let mut attachment_used = vec![false; attachments.len()];
+
+ for (subpass_num, subpass) in subpasses.iter_mut().enumerate() {
+ let &mut SubpassDescription {
+ view_mask,
+ ref mut input_attachments,
+ ref color_attachments,
+ ref resolve_attachments,
+ ref depth_stencil_attachment,
+ ref preserve_attachments,
+ _ne: _,
+ } = subpass;
+ let subpass_num = subpass_num as u32;
+
+ // VUID-VkRenderPassCreateInfo2-viewMask-03058
+ if (view_mask != 0) != is_multiview {
+ return Err(RenderPassCreationError::SubpassMultiviewMismatch {
+ subpass: subpass_num,
+ multiview: subpass.view_mask != 0,
+ first_subpass_multiview: is_multiview,
+ });
+ }
+
+ let view_count = u32::BITS - view_mask.leading_zeros();
+
+ // VUID-VkSubpassDescription2-viewMask-06706
+ if view_count > properties.max_multiview_view_count.unwrap_or(0) {
+ return Err(
+ RenderPassCreationError::SubpassMaxMultiviewViewCountExceeded {
+ subpass: subpass_num,
+ view_count,
+ max: properties.max_multiview_view_count.unwrap_or(0),
+ },
+ );
+ }
+
+ // VUID-VkSubpassDescription2-colorAttachmentCount-03063
+ if color_attachments.len() as u32 > properties.max_color_attachments {
+ return Err(
+ RenderPassCreationError::SubpassMaxColorAttachmentsExceeded {
+ subpass: subpass_num,
+ color_attachment_count: color_attachments.len() as u32,
+ max: properties.max_color_attachments,
+ },
+ );
+ }
+
+ // Track the layout of each attachment used in this subpass
+ let mut layouts = vec![None; attachments.len()];
+
+ // Common checks for all attachment types
+ let mut check_attachment = |atch_ref: &AttachmentReference| {
+ // VUID-VkAttachmentReference2-layout-parameter
+ atch_ref.layout.validate_device(device)?;
+
+ // VUID?
+ atch_ref.aspects.validate_device(device)?;
+
+ // VUID-VkRenderPassCreateInfo2-attachment-03051
+ let atch = attachments.get(atch_ref.attachment as usize).ok_or(
+ RenderPassCreationError::SubpassAttachmentOutOfRange {
+ subpass: subpass_num,
+ attachment: atch_ref.attachment,
+ },
+ )?;
+
+ // VUID-VkSubpassDescription2-layout-02528
+ match &mut layouts[atch_ref.attachment as usize] {
+ Some(layout) if *layout == atch_ref.layout => (),
+ Some(_) => {
+ return Err(RenderPassCreationError::SubpassAttachmentLayoutMismatch {
+ subpass: subpass_num,
+ attachment: atch_ref.attachment,
+ })
+ }
+ layout @ None => *layout = Some(atch_ref.layout),
+ }
+
+ let first_use =
+ !std::mem::replace(&mut attachment_used[atch_ref.attachment as usize], true);
+
+ if first_use {
+ // VUID-VkRenderPassCreateInfo2-pAttachments-02522
+ if atch.load_op == LoadOp::Clear
+ && matches!(
+ atch_ref.layout,
+ ImageLayout::ShaderReadOnlyOptimal
+ | ImageLayout::DepthStencilReadOnlyOptimal
+ | ImageLayout::DepthReadOnlyStencilAttachmentOptimal
+ )
+ {
+ return Err(RenderPassCreationError::AttachmentFirstUseLoadOpInvalid {
+ attachment: atch_ref.attachment,
+ first_use_subpass: subpass_num,
+ });
+ }
+
+ // VUID-VkRenderPassCreateInfo2-pAttachments-02523
+ if atch.stencil_load_op == LoadOp::Clear
+ && matches!(
+ atch_ref.layout,
+ ImageLayout::ShaderReadOnlyOptimal
+ | ImageLayout::DepthStencilReadOnlyOptimal
+ | ImageLayout::DepthAttachmentStencilReadOnlyOptimal
+ )
+ {
+ return Err(RenderPassCreationError::AttachmentFirstUseLoadOpInvalid {
+ attachment: atch_ref.attachment,
+ first_use_subpass: subpass_num,
+ });
+ }
+ }
+
+ let potential_format_features =
+ &attachment_potential_format_features[atch_ref.attachment as usize];
+
+ Ok((atch, potential_format_features, first_use))
+ };
+
+ /*
+ Check color attachments
+ */
+
+ let mut color_samples = None;
+
+ for atch_ref in color_attachments.iter().flatten() {
+ let (atch, features, _first_use) = check_attachment(atch_ref)?;
+
+ // VUID-VkSubpassDescription2-pColorAttachments-02898
+ if !features.intersects(FormatFeatures::COLOR_ATTACHMENT) {
+ return Err(
+ RenderPassCreationError::SubpassAttachmentFormatUsageNotSupported {
+ subpass: subpass_num,
+ attachment: atch_ref.attachment,
+ usage: "color",
+ },
+ );
+ }
+
+ // VUID-VkAttachmentReference2-layout-03077
+ // VUID-VkSubpassDescription2-attachment-06913
+ // VUID-VkSubpassDescription2-attachment-06916
+ if matches!(
+ atch_ref.layout,
+ ImageLayout::Undefined
+ | ImageLayout::Preinitialized
+ | ImageLayout::PresentSrc
+ | ImageLayout::DepthStencilAttachmentOptimal
+ | ImageLayout::ShaderReadOnlyOptimal
+ | ImageLayout::DepthAttachmentStencilReadOnlyOptimal
+ | ImageLayout::DepthReadOnlyStencilAttachmentOptimal
+ ) {
+ return Err(RenderPassCreationError::SubpassAttachmentLayoutInvalid {
+ subpass: subpass_num,
+ attachment: atch_ref.attachment,
+ usage: "color",
+ });
+ }
+
+ // Not required by spec, but enforced by Vulkano for sanity.
+ if !atch_ref.aspects.is_empty() {
+ return Err(RenderPassCreationError::SubpassAttachmentAspectsNotEmpty {
+ subpass: subpass_num,
+ attachment: atch_ref.attachment,
+ });
+ }
+
+ // VUID-VkSubpassDescription2-pColorAttachments-03069
+ match &mut color_samples {
+ Some(samples) if *samples == atch.samples => (),
+ Some(samples) => {
+ return Err(
+ RenderPassCreationError::SubpassColorDepthStencilAttachmentSamplesMismatch {
+ subpass: subpass_num,
+ attachment: atch_ref.attachment,
+ samples: atch.samples,
+ first_samples: *samples,
+ },
+ )
+ }
+ samples @ None => *samples = Some(atch.samples),
+ }
+ }
+
+ /*
+ Check depth/stencil attachment
+ */
+
+ if let Some(atch_ref) = depth_stencil_attachment.as_ref() {
+ let (atch, features, _first_use) = check_attachment(atch_ref)?;
+
+ // VUID-VkSubpassDescription2-pDepthStencilAttachment-02900
+ if !features.intersects(FormatFeatures::DEPTH_STENCIL_ATTACHMENT) {
+ return Err(
+ RenderPassCreationError::SubpassAttachmentFormatUsageNotSupported {
+ subpass: subpass_num,
+ attachment: atch_ref.attachment,
+ usage: "depth/stencil",
+ },
+ );
+ }
+
+ // VUID-VkAttachmentReference2-layout-03077
+ // VUID-VkSubpassDescription2-attachment-06915
+ if matches!(
+ atch_ref.layout,
+ ImageLayout::Undefined
+ | ImageLayout::Preinitialized
+ | ImageLayout::PresentSrc
+ | ImageLayout::ColorAttachmentOptimal
+ | ImageLayout::ShaderReadOnlyOptimal
+ ) {
+ return Err(RenderPassCreationError::SubpassAttachmentLayoutInvalid {
+ subpass: subpass_num,
+ attachment: atch_ref.attachment,
+ usage: "depth/stencil",
+ });
+ }
+
+ // Not required by spec, but enforced by Vulkano for sanity.
+ if !atch_ref.aspects.is_empty() {
+ return Err(RenderPassCreationError::SubpassAttachmentAspectsNotEmpty {
+ subpass: subpass_num,
+ attachment: atch_ref.attachment,
+ });
+ }
+
+ // VUID-VkSubpassDescription2-pDepthStencilAttachment-04440
+ if color_attachments
+ .iter()
+ .flatten()
+ .any(|color_atch_ref| color_atch_ref.attachment == atch_ref.attachment)
+ {
+ return Err(
+ RenderPassCreationError::SubpassAttachmentUsageColorDepthStencil {
+ subpass: subpass_num,
+ attachment: atch_ref.attachment,
+ },
+ );
+ }
+
+ // VUID-VkSubpassDescription2-pDepthStencilAttachment-03071
+ if let Some(samples) = color_samples.filter(|samples| *samples != atch.samples) {
+ return Err(
+ RenderPassCreationError::SubpassColorDepthStencilAttachmentSamplesMismatch {
+ subpass: subpass_num,
+ attachment: atch_ref.attachment,
+ samples: atch.samples,
+ first_samples: samples,
+ },
+ );
+ }
+ }
+
+ /*
+ Check input attachments
+ This must be placed after color and depth/stencil checks so that `first_use`
+ will be true for VUID-VkSubpassDescription2-loadOp-03064.
+ */
+
+ for atch_ref in input_attachments.iter_mut().flatten() {
+ let (atch, features, first_use) = check_attachment(atch_ref)?;
+
+ // VUID-VkSubpassDescription2-pInputAttachments-02897
+ if !features.intersects(
+ FormatFeatures::COLOR_ATTACHMENT | FormatFeatures::DEPTH_STENCIL_ATTACHMENT,
+ ) {
+ return Err(
+ RenderPassCreationError::SubpassAttachmentFormatUsageNotSupported {
+ subpass: subpass_num,
+ attachment: atch_ref.attachment,
+ usage: "input",
+ },
+ );
+ }
+
+ // VUID-VkAttachmentReference2-layout-03077
+ // VUID-VkSubpassDescription2-attachment-06912
+ if matches!(
+ atch_ref.layout,
+ ImageLayout::Undefined
+ | ImageLayout::Preinitialized
+ | ImageLayout::PresentSrc
+ | ImageLayout::ColorAttachmentOptimal
+ | ImageLayout::DepthStencilAttachmentOptimal
+ ) {
+ return Err(RenderPassCreationError::SubpassAttachmentLayoutInvalid {
+ subpass: subpass_num,
+ attachment: atch_ref.attachment,
+ usage: "input",
+ });
+ }
+
+ let atch_aspects = atch.format.unwrap().aspects();
+
+ if atch_ref.aspects.is_empty() {
+ // VUID-VkSubpassDescription2-attachment-02800
+ atch_ref.aspects = atch_aspects;
+ } else if atch_ref.aspects != atch_aspects {
+ if !(device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_create_renderpass2
+ || device.enabled_extensions().khr_maintenance2)
+ {
+ return Err(RenderPassCreationError::RequirementNotMet {
+ required_for: "`create_info.subpasses` has an element, where \
+ `input_attachments` has an element that is `Some(atch_ref)`, \
+ where `atch_ref.aspects` does not match the aspects of the \
+ attachment itself",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_1),
+ device_extensions: &["khr_create_renderpass2", "khr_maintenance2"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkSubpassDescription2-attachment-02801
+ // VUID-VkSubpassDescription2-attachment-04563
+ // VUID-VkRenderPassCreateInfo2-attachment-02525
+ if !atch_aspects.contains(atch_ref.aspects) {
+ return Err(
+ RenderPassCreationError::SubpassInputAttachmentAspectsNotCompatible {
+ subpass: subpass_num,
+ attachment: atch_ref.attachment,
+ },
+ );
+ }
+ }
+
+ // VUID-VkSubpassDescription2-loadOp-03064
+ if first_use && atch.load_op == LoadOp::Clear {
+ return Err(RenderPassCreationError::AttachmentFirstUseLoadOpInvalid {
+ attachment: atch_ref.attachment,
+ first_use_subpass: subpass_num,
+ });
+ }
+ }
+
+ /*
+ Check resolve attachments
+ */
+
+ // VUID-VkSubpassDescription2-pResolveAttachments-parameter
+ if !(resolve_attachments.is_empty()
+ || resolve_attachments.len() == color_attachments.len())
+ {
+ return Err(
+ RenderPassCreationError::SubpassResolveAttachmentsColorAttachmentsLenMismatch {
+ subpass: subpass_num,
+ },
+ );
+ }
+
+ for (atch_ref, color_atch_ref) in resolve_attachments
+ .iter()
+ .zip(subpass.color_attachments.iter())
+ .filter_map(|(r, c)| r.as_ref().map(|r| (r, c.as_ref())))
+ {
+ let (atch, features, _first_use) = check_attachment(atch_ref)?;
+
+ // VUID-VkSubpassDescription2-pResolveAttachments-02899
+ if !features.intersects(FormatFeatures::COLOR_ATTACHMENT) {
+ return Err(
+ RenderPassCreationError::SubpassAttachmentFormatUsageNotSupported {
+ subpass: subpass_num,
+ attachment: atch_ref.attachment,
+ usage: "resolve",
+ },
+ );
+ }
+
+ // VUID-VkAttachmentReference2-layout-03077
+ // VUID-VkSubpassDescription2-attachment-06914
+ // VUID-VkSubpassDescription2-attachment-06917
+ if matches!(
+ atch_ref.layout,
+ ImageLayout::Undefined
+ | ImageLayout::Preinitialized
+ | ImageLayout::PresentSrc
+ | ImageLayout::DepthStencilAttachmentOptimal
+ | ImageLayout::ShaderReadOnlyOptimal
+ | ImageLayout::DepthAttachmentStencilReadOnlyOptimal
+ | ImageLayout::DepthReadOnlyStencilAttachmentOptimal
+ ) {
+ return Err(RenderPassCreationError::SubpassAttachmentLayoutInvalid {
+ subpass: subpass_num,
+ attachment: atch_ref.attachment,
+ usage: "resolve",
+ });
+ }
+
+ // Not required by spec, but enforced by Vulkano for sanity.
+ if !atch_ref.aspects.is_empty() {
+ return Err(RenderPassCreationError::SubpassAttachmentAspectsNotEmpty {
+ subpass: subpass_num,
+ attachment: atch_ref.attachment,
+ });
+ }
+
+ // VUID-VkSubpassDescription2-pResolveAttachments-03065
+ let color_atch_ref = color_atch_ref.ok_or({
+ RenderPassCreationError::SubpassResolveAttachmentWithoutColorAttachment {
+ subpass: subpass_num,
+ }
+ })?;
+ let color_atch = &attachments[color_atch_ref.attachment as usize];
+
+ // VUID-VkSubpassDescription2-pResolveAttachments-03067
+ if atch.samples != SampleCount::Sample1 {
+ return Err(
+ RenderPassCreationError::SubpassResolveAttachmentMultisampled {
+ subpass: subpass_num,
+ attachment: atch_ref.attachment,
+ },
+ );
+ }
+
+ // VUID-VkSubpassDescription2-pResolveAttachments-03066
+ if color_atch.samples == SampleCount::Sample1 {
+ return Err(
+ RenderPassCreationError::SubpassColorAttachmentWithResolveNotMultisampled {
+ subpass: subpass_num,
+ attachment: atch_ref.attachment,
+ },
+ );
+ }
+
+ // VUID-VkSubpassDescription2-pResolveAttachments-03068
+ if atch.format != color_atch.format {
+ return Err(
+ RenderPassCreationError::SubpassResolveAttachmentFormatMismatch {
+ subpass: subpass_num,
+ resolve_attachment: atch_ref.attachment,
+ color_attachment: color_atch_ref.attachment,
+ },
+ );
+ }
+ }
+
+ /*
+ Check preserve attachments
+ */
+
+ for &atch in preserve_attachments {
+ // VUID-VkRenderPassCreateInfo2-attachment-03051
+ if atch as usize >= attachments.len() {
+ return Err(RenderPassCreationError::SubpassAttachmentOutOfRange {
+ subpass: subpass_num,
+ attachment: atch,
+ });
+ }
+
+ // VUID-VkSubpassDescription2-pPreserveAttachments-03074
+ if layouts[atch as usize].is_some() {
+ return Err(
+ RenderPassCreationError::SubpassPreserveAttachmentUsedElsewhere {
+ subpass: subpass_num,
+ attachment: atch,
+ },
+ );
+ }
+ }
+ }
+
+ /*
+ Dependencies
+ */
+
+ for (dependency_num, dependency) in dependencies.iter().enumerate() {
+ let &SubpassDependency {
+ src_subpass,
+ dst_subpass,
+ src_stages,
+ dst_stages,
+ src_access,
+ dst_access,
+ dependency_flags,
+ view_offset,
+ _ne: _,
+ } = dependency;
+ let dependency_num = dependency_num as u32;
+
+ for (stages, access) in [(src_stages, src_access), (dst_stages, dst_access)] {
+ if !device.enabled_features().synchronization2 {
+ if stages.is_2() {
+ return Err(RenderPassCreationError::RequirementNotMet {
+ required_for: "`create_info.dependencies` has an element where \
+ `src_stages` or `dst_stages` contains flags from \
+ `VkPipelineStageFlagBits2`",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }
+
+ if access.is_2() {
+ return Err(RenderPassCreationError::RequirementNotMet {
+ required_for: "`create_info.dependencies` has an element where \
+ `src_access` or `dst_access` contains flags from \
+ `VkAccessFlagBits2`",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }
+ } else if !(device.api_version() >= Version::V1_2
+ || device.enabled_extensions().khr_create_renderpass2)
+ {
+ // If synchronization2 is enabled but we don't have create_renderpass2,
+ // we are unable to use extension structs, so we can't use the
+ // extra flag bits.
+
+ if stages.is_2() {
+ return Err(RenderPassCreationError::RequirementNotMet {
+ required_for: "`create_info.dependencies` has an element where \
+ `src_stages` or `dst_stages` contains flags from \
+ `VkPipelineStageFlagBits2`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_2),
+ device_extensions: &["khr_create_renderpass2"],
+ ..Default::default()
+ },
+ });
+ }
+
+ if access.is_2() {
+ return Err(RenderPassCreationError::RequirementNotMet {
+ required_for: "`create_info.dependencies` has an element where \
+ `src_access` or `dst_access` contains flags from \
+ `VkAccessFlagBits2`",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_2),
+ device_extensions: &["khr_create_renderpass2"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-parameter
+ // VUID-VkMemoryBarrier2-dstStageMask-parameter
+ stages.validate_device(device)?;
+
+ // VUID-VkMemoryBarrier2-srcAccessMask-parameter
+ // VUID-VkMemoryBarrier2-dstAccessMask-parameter
+ access.validate_device(device)?;
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03929
+ // VUID-VkMemoryBarrier2-dstStageMask-03929
+ if stages.intersects(PipelineStages::GEOMETRY_SHADER)
+ && !device.enabled_features().geometry_shader
+ {
+ return Err(RenderPassCreationError::RequirementNotMet {
+ required_for: "`create_info.dependencies` has an element where `stages` \
+ contains `PipelineStages::GEOMETRY_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["geometry_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03930
+ // VUID-VkMemoryBarrier2-dstStageMask-03930
+ if stages.intersects(
+ PipelineStages::TESSELLATION_CONTROL_SHADER
+ | PipelineStages::TESSELLATION_EVALUATION_SHADER,
+ ) && !device.enabled_features().tessellation_shader
+ {
+ return Err(RenderPassCreationError::RequirementNotMet {
+ required_for: "`create_info.dependencies` has an element where `stages` \
+ contains `PipelineStages::TESSELLATION_CONTROL_SHADER` or \
+ `PipelineStages::TESSELLATION_EVALUATION_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["tessellation_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03931
+ // VUID-VkMemoryBarrier2-dstStageMask-03931
+ if stages.intersects(PipelineStages::CONDITIONAL_RENDERING)
+ && !device.enabled_features().conditional_rendering
+ {
+ return Err(RenderPassCreationError::RequirementNotMet {
+ required_for: "`create_info.dependencies` has an element where `stages` \
+ contains `PipelineStages::CONDITIONAL_RENDERING`",
+ requires_one_of: RequiresOneOf {
+ features: &["conditional_rendering"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03932
+ // VUID-VkMemoryBarrier2-dstStageMask-03932
+ if stages.intersects(PipelineStages::FRAGMENT_DENSITY_PROCESS)
+ && !device.enabled_features().fragment_density_map
+ {
+ return Err(RenderPassCreationError::RequirementNotMet {
+ required_for: "`create_info.dependencies` has an element where `stages` \
+ contains `PipelineStages::FRAGMENT_DENSITY_PROCESS`",
+ requires_one_of: RequiresOneOf {
+ features: &["fragment_density_map"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03933
+ // VUID-VkMemoryBarrier2-dstStageMask-03933
+ if stages.intersects(PipelineStages::TRANSFORM_FEEDBACK)
+ && !device.enabled_features().transform_feedback
+ {
+ return Err(RenderPassCreationError::RequirementNotMet {
+ required_for: "`create_info.dependencies` has an element where `stages` \
+ contains `PipelineStages::TRANSFORM_FEEDBACK`",
+ requires_one_of: RequiresOneOf {
+ features: &["transform_feedback"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03934
+ // VUID-VkMemoryBarrier2-dstStageMask-03934
+ if stages.intersects(PipelineStages::MESH_SHADER)
+ && !device.enabled_features().mesh_shader
+ {
+ return Err(RenderPassCreationError::RequirementNotMet {
+ required_for: "`create_info.dependencies` has an element where `stages` \
+ contains `PipelineStages::MESH_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["mesh_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03935
+ // VUID-VkMemoryBarrier2-dstStageMask-03935
+ if stages.intersects(PipelineStages::TASK_SHADER)
+ && !device.enabled_features().task_shader
+ {
+ return Err(RenderPassCreationError::RequirementNotMet {
+ required_for: "`create_info.dependencies` has an element where `stages` \
+ contains `PipelineStages::TASK_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["task_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-shadingRateImage-07316
+ // VUID-VkMemoryBarrier2-shadingRateImage-07316
+ if stages.intersects(PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT)
+ && !(device.enabled_features().attachment_fragment_shading_rate
+ || device.enabled_features().shading_rate_image)
+ {
+ return Err(RenderPassCreationError::RequirementNotMet {
+ required_for: "`create_info.dependencies` has an element where `stages` \
+ contains `PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT`",
+ requires_one_of: RequiresOneOf {
+ features: &["attachment_fragment_shading_rate", "shading_rate_image"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-04957
+ // VUID-VkMemoryBarrier2-dstStageMask-04957
+ if stages.intersects(PipelineStages::SUBPASS_SHADING)
+ && !device.enabled_features().subpass_shading
+ {
+ return Err(RenderPassCreationError::RequirementNotMet {
+ required_for: "`create_info.dependencies` has an element where `stages` \
+ contains `PipelineStages::SUBPASS_SHADING`",
+ requires_one_of: RequiresOneOf {
+ features: &["subpass_shading"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-04995
+ // VUID-VkMemoryBarrier2-dstStageMask-04995
+ if stages.intersects(PipelineStages::INVOCATION_MASK)
+ && !device.enabled_features().invocation_mask
+ {
+ return Err(RenderPassCreationError::RequirementNotMet {
+ required_for: "`create_info.dependencies` has an element where `stages` \
+ contains `PipelineStages::INVOCATION_MASK`",
+ requires_one_of: RequiresOneOf {
+ features: &["invocation_mask"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkSubpassDependency2-srcStageMask-03937
+ // VUID-VkSubpassDependency2-dstStageMask-03937
+ if stages.is_empty() && !device.enabled_features().synchronization2 {
+ return Err(RenderPassCreationError::RequirementNotMet {
+ required_for: "`create_info.dependencies` has an element where `stages` \
+ is empty",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkSubpassDependency2-srcAccessMask-03088
+ // VUID-VkSubpassDependency2-dstAccessMask-03089
+ if !AccessFlags::from(stages).contains(access) {
+ return Err(
+ RenderPassCreationError::DependencyAccessNotSupportedByStages {
+ dependency: dependency_num,
+ },
+ );
+ }
+ }
+
+ if dependency_flags.intersects(DependencyFlags::VIEW_LOCAL) {
+ // VUID-VkRenderPassCreateInfo2-viewMask-03059
+ if !is_multiview {
+ return Err(
+ RenderPassCreationError::DependencyViewLocalMultiviewNotEnabled {
+ dependency: dependency_num,
+ },
+ );
+ }
+ } else {
+ // VUID-VkSubpassDependency2-dependencyFlags-03092
+ if view_offset != 0 {
+ return Err(
+ RenderPassCreationError::DependencyViewOffzetNonzeroWithoutViewLocal {
+ dependency: dependency_num,
+ },
+ );
+ }
+ }
+
+ // VUID-VkSubpassDependency2-srcSubpass-03085
+ if src_subpass.is_none() && dst_subpass.is_none() {
+ return Err(RenderPassCreationError::DependencyBothSubpassesExternal {
+ dependency: dependency_num,
+ });
+ }
+
+ for (subpass, stages) in [(src_subpass, src_stages), (dst_subpass, dst_stages)] {
+ if let Some(subpass) = subpass {
+ // VUID-VkRenderPassCreateInfo2-srcSubpass-02526
+ // VUID-VkRenderPassCreateInfo2-dstSubpass-02527
+ if subpass as usize >= subpasses.len() {
+ return Err(RenderPassCreationError::DependencySubpassOutOfRange {
+ dependency: dependency_num,
+ subpass,
+ });
+ }
+
+ let remaining_stages = stages
+ - (PipelineStages::DRAW_INDIRECT
+ | PipelineStages::INDEX_INPUT
+ | PipelineStages::VERTEX_ATTRIBUTE_INPUT
+ | PipelineStages::VERTEX_SHADER
+ | PipelineStages::TESSELLATION_CONTROL_SHADER
+ | PipelineStages::TESSELLATION_EVALUATION_SHADER
+ | PipelineStages::GEOMETRY_SHADER
+ | PipelineStages::TRANSFORM_FEEDBACK
+ | PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT
+ | PipelineStages::EARLY_FRAGMENT_TESTS
+ | PipelineStages::FRAGMENT_SHADER
+ | PipelineStages::LATE_FRAGMENT_TESTS
+ | PipelineStages::COLOR_ATTACHMENT_OUTPUT
+ | PipelineStages::ALL_GRAPHICS);
+
+ // VUID-VkRenderPassCreateInfo2-pDependencies-03054
+ // VUID-VkRenderPassCreateInfo2-pDependencies-03055
+ if !remaining_stages.is_empty() {
+ return Err(RenderPassCreationError::DependencyStageNotSupported {
+ dependency: dependency_num,
+ });
+ }
+ } else {
+ // VUID-VkSubpassDependency2-dependencyFlags-03090
+ // VUID-VkSubpassDependency2-dependencyFlags-03091
+ if dependency_flags.intersects(DependencyFlags::VIEW_LOCAL) {
+ return Err(
+ RenderPassCreationError::DependencyViewLocalExternalDependency {
+ dependency: dependency_num,
+ },
+ );
+ }
+ }
+ }
+
+ if let (Some(src_subpass), Some(dst_subpass)) = (src_subpass, dst_subpass) {
+ // VUID-VkSubpassDependency2-srcSubpass-03084
+ if src_subpass > dst_subpass {
+ return Err(
+ RenderPassCreationError::DependencySourceSubpassAfterDestinationSubpass {
+ dependency: dependency_num,
+ },
+ );
+ }
+
+ if src_subpass == dst_subpass {
+ let framebuffer_stages = PipelineStages::EARLY_FRAGMENT_TESTS
+ | PipelineStages::FRAGMENT_SHADER
+ | PipelineStages::LATE_FRAGMENT_TESTS
+ | PipelineStages::COLOR_ATTACHMENT_OUTPUT;
+
+ // VUID-VkSubpassDependency2-srcSubpass-06810
+ if src_stages.intersects(framebuffer_stages)
+ && !(dst_stages - framebuffer_stages).is_empty()
+ {
+ return Err(
+ RenderPassCreationError::DependencySelfDependencySourceStageAfterDestinationStage {
+ dependency: dependency_num,
+ },
+ );
+ }
+
+ // VUID-VkSubpassDependency2-srcSubpass-02245
+ if src_stages.intersects(framebuffer_stages)
+ && dst_stages.intersects(framebuffer_stages)
+ && !dependency_flags.intersects(DependencyFlags::BY_REGION)
+ {
+ return Err(
+ RenderPassCreationError::DependencySelfDependencyFramebufferStagesWithoutByRegion {
+ dependency: dependency_num,
+ },
+ );
+ }
+
+ if dependency_flags.intersects(DependencyFlags::VIEW_LOCAL) {
+ // VUID-VkSubpassDependency2-viewOffset-02530
+ if view_offset != 0 {
+ return Err(
+ RenderPassCreationError::DependencySelfDependencyViewLocalNonzeroViewOffset {
+ dependency: dependency_num,
+ },
+ );
+ }
+ } else {
+ // VUID-VkRenderPassCreateInfo2-pDependencies-03060
+ if subpasses[src_subpass as usize].view_mask.count_ones() > 1 {
+ return Err(
+ RenderPassCreationError::DependencySelfDependencyViewMaskMultiple {
+ dependency: dependency_num,
+ subpass: src_subpass,
+ },
+ );
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ Correlated view masks
+ */
+
+ // VUID-VkRenderPassCreateInfo2-viewMask-03057
+ if !correlated_view_masks.is_empty() {
+ if !is_multiview {
+ return Err(RenderPassCreationError::CorrelatedViewMasksMultiviewNotEnabled);
+ }
+
+ // VUID-VkRenderPassCreateInfo2-pCorrelatedViewMasks-03056
+ correlated_view_masks.iter().try_fold(0, |total, &mask| {
+ if total & mask != 0 {
+ Err(RenderPassCreationError::CorrelatedViewMasksOverlapping)
+ } else {
+ Ok(total | mask)
+ }
+ })?;
+ }
+
+ Ok(())
+ }
+
+ pub(super) unsafe fn create_v2(
+ device: &Device,
+ create_info: &RenderPassCreateInfo,
+ ) -> Result<ash::vk::RenderPass, RenderPassCreationError> {
+ let RenderPassCreateInfo {
+ attachments,
+ subpasses,
+ dependencies,
+ correlated_view_masks,
+ _ne: _,
+ } = create_info;
+
+ let attachments_vk = attachments
+ .iter()
+ .map(|attachment| ash::vk::AttachmentDescription2 {
+ flags: ash::vk::AttachmentDescriptionFlags::empty(),
+ format: attachment
+ .format
+ .map_or(ash::vk::Format::UNDEFINED, |f| f.into()),
+ samples: attachment.samples.into(),
+ load_op: attachment.load_op.into(),
+ store_op: attachment.store_op.into(),
+ stencil_load_op: attachment.stencil_load_op.into(),
+ stencil_store_op: attachment.stencil_store_op.into(),
+ initial_layout: attachment.initial_layout.into(),
+ final_layout: attachment.final_layout.into(),
+ ..Default::default()
+ })
+ .collect::<SmallVec<[_; 4]>>();
+
+ let attachment_references_vk = subpasses
+ .iter()
+ .flat_map(|subpass| {
+ (subpass.input_attachments.iter())
+ .chain(subpass.color_attachments.iter())
+ .chain(subpass.resolve_attachments.iter())
+ .map(Option::as_ref)
+ .chain(subpass.depth_stencil_attachment.iter().map(Some))
+ .map(|atch_ref| {
+ if let Some(atch_ref) = atch_ref {
+ ash::vk::AttachmentReference2 {
+ attachment: atch_ref.attachment,
+ layout: atch_ref.layout.into(),
+ aspect_mask: atch_ref.aspects.into(),
+ ..Default::default()
+ }
+ } else {
+ ash::vk::AttachmentReference2 {
+ attachment: ash::vk::ATTACHMENT_UNUSED,
+ ..Default::default()
+ }
+ }
+ })
+ })
+ .collect::<SmallVec<[_; 8]>>();
+
+ let subpasses_vk = {
+ // `ref_index` is increased during the loop and points to the next element to use
+ // in `attachment_references_vk`.
+ let mut ref_index = 0usize;
+ let out: SmallVec<[_; 4]> = subpasses
+ .iter()
+ .map(|subpass| {
+ let input_attachments = attachment_references_vk.as_ptr().add(ref_index);
+ ref_index += subpass.input_attachments.len();
+ let color_attachments = attachment_references_vk.as_ptr().add(ref_index);
+ ref_index += subpass.color_attachments.len();
+ let resolve_attachments = attachment_references_vk.as_ptr().add(ref_index);
+ ref_index += subpass.resolve_attachments.len();
+ let depth_stencil = if subpass.depth_stencil_attachment.is_some() {
+ let a = attachment_references_vk.as_ptr().add(ref_index);
+ ref_index += 1;
+ a
+ } else {
+ ptr::null()
+ };
+
+ ash::vk::SubpassDescription2 {
+ flags: ash::vk::SubpassDescriptionFlags::empty(),
+ pipeline_bind_point: ash::vk::PipelineBindPoint::GRAPHICS, // TODO: any need to make this user-specifiable?
+ view_mask: subpass.view_mask,
+ input_attachment_count: subpass.input_attachments.len() as u32,
+ p_input_attachments: if subpass.input_attachments.is_empty() {
+ ptr::null()
+ } else {
+ input_attachments
+ },
+ color_attachment_count: subpass.color_attachments.len() as u32,
+ p_color_attachments: if subpass.color_attachments.is_empty() {
+ ptr::null()
+ } else {
+ color_attachments
+ },
+ p_resolve_attachments: if subpass.resolve_attachments.is_empty() {
+ ptr::null()
+ } else {
+ resolve_attachments
+ },
+ p_depth_stencil_attachment: depth_stencil,
+ preserve_attachment_count: subpass.preserve_attachments.len() as u32,
+ p_preserve_attachments: if subpass.preserve_attachments.is_empty() {
+ ptr::null()
+ } else {
+ subpass.preserve_attachments.as_ptr()
+ },
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ // If this assertion fails, there's a serious bug in the code above ^.
+ debug_assert!(ref_index == attachment_references_vk.len());
+
+ out
+ };
+
+ let memory_barriers_vk: SmallVec<[_; 4]> = if device.enabled_features().synchronization2 {
+ debug_assert!(
+ device.api_version() >= Version::V1_3
+ || device.enabled_extensions().khr_synchronization2
+ );
+ dependencies
+ .iter()
+ .map(|dependency| ash::vk::MemoryBarrier2 {
+ src_stage_mask: dependency.src_stages.into(),
+ src_access_mask: dependency.src_access.into(),
+ dst_stage_mask: dependency.dst_stages.into(),
+ dst_access_mask: dependency.dst_access.into(),
+ ..Default::default()
+ })
+ .collect()
+ } else {
+ SmallVec::new()
+ };
+
+ let dependencies_vk = dependencies
+ .iter()
+ .enumerate()
+ .map(|(index, dependency)| {
+ ash::vk::SubpassDependency2 {
+ p_next: memory_barriers_vk
+ .get(index)
+ .map_or(ptr::null(), |mb| mb as *const _ as *const _),
+ src_subpass: dependency.src_subpass.unwrap_or(ash::vk::SUBPASS_EXTERNAL),
+ dst_subpass: dependency.dst_subpass.unwrap_or(ash::vk::SUBPASS_EXTERNAL),
+ src_stage_mask: dependency.src_stages.into(),
+ dst_stage_mask: dependency.dst_stages.into(),
+ src_access_mask: dependency.src_access.into(),
+ dst_access_mask: dependency.dst_access.into(),
+ dependency_flags: dependency.dependency_flags.into(),
+ // VUID-VkSubpassDependency2-dependencyFlags-03092
+ view_offset: dependency.view_offset,
+ ..Default::default()
+ }
+ })
+ .collect::<SmallVec<[_; 4]>>();
+
+ let create_info = ash::vk::RenderPassCreateInfo2 {
+ flags: ash::vk::RenderPassCreateFlags::empty(),
+ attachment_count: attachments_vk.len() as u32,
+ p_attachments: if attachments_vk.is_empty() {
+ ptr::null()
+ } else {
+ attachments_vk.as_ptr()
+ },
+ subpass_count: subpasses_vk.len() as u32,
+ p_subpasses: if subpasses_vk.is_empty() {
+ ptr::null()
+ } else {
+ subpasses_vk.as_ptr()
+ },
+ dependency_count: dependencies_vk.len() as u32,
+ p_dependencies: if dependencies_vk.is_empty() {
+ ptr::null()
+ } else {
+ dependencies_vk.as_ptr()
+ },
+ correlated_view_mask_count: correlated_view_masks.len() as u32,
+ p_correlated_view_masks: correlated_view_masks.as_ptr(),
+ ..Default::default()
+ };
+
+ Ok({
+ let fns = device.fns();
+ let mut output = MaybeUninit::uninit();
+
+ if device.api_version() >= Version::V1_2 {
+ (fns.v1_2.create_render_pass2)(
+ device.handle(),
+ &create_info,
+ ptr::null(),
+ output.as_mut_ptr(),
+ )
+ } else {
+ (fns.khr_create_renderpass2.create_render_pass2_khr)(
+ device.handle(),
+ &create_info,
+ ptr::null(),
+ output.as_mut_ptr(),
+ )
+ }
+ .result()
+ .map_err(VulkanError::from)?;
+
+ output.assume_init()
+ })
+ }
+
+ pub(super) unsafe fn create_v1(
+ device: &Device,
+ create_info: &RenderPassCreateInfo,
+ ) -> Result<ash::vk::RenderPass, RenderPassCreationError> {
+ let RenderPassCreateInfo {
+ attachments,
+ subpasses,
+ dependencies,
+ correlated_view_masks,
+ _ne: _,
+ } = create_info;
+
+ let attachments_vk = attachments
+ .iter()
+ .map(|attachment| ash::vk::AttachmentDescription {
+ flags: ash::vk::AttachmentDescriptionFlags::empty(),
+ format: attachment
+ .format
+ .map_or(ash::vk::Format::UNDEFINED, |f| f.into()),
+ samples: attachment.samples.into(),
+ load_op: attachment.load_op.into(),
+ store_op: attachment.store_op.into(),
+ stencil_load_op: attachment.stencil_load_op.into(),
+ stencil_store_op: attachment.stencil_store_op.into(),
+ initial_layout: attachment.initial_layout.into(),
+ final_layout: attachment.final_layout.into(),
+ })
+ .collect::<SmallVec<[_; 4]>>();
+
+ let attachment_references_vk = subpasses
+ .iter()
+ .flat_map(|subpass| {
+ (subpass.input_attachments.iter())
+ .chain(subpass.color_attachments.iter())
+ .chain(subpass.resolve_attachments.iter())
+ .map(Option::as_ref)
+ .chain(subpass.depth_stencil_attachment.iter().map(Some))
+ .map(|atch_ref| {
+ if let Some(atch_ref) = atch_ref {
+ ash::vk::AttachmentReference {
+ attachment: atch_ref.attachment,
+ layout: atch_ref.layout.into(),
+ }
+ } else {
+ ash::vk::AttachmentReference {
+ attachment: ash::vk::ATTACHMENT_UNUSED,
+ layout: Default::default(),
+ }
+ }
+ })
+ })
+ .collect::<SmallVec<[_; 8]>>();
+
+ let subpasses_vk = {
+ // `ref_index` is increased during the loop and points to the next element to use
+ // in `attachment_references_vk`.
+ let mut ref_index = 0usize;
+ let out: SmallVec<[_; 4]> = subpasses
+ .iter()
+ .map(|subpass| {
+ let input_attachments = attachment_references_vk.as_ptr().add(ref_index);
+ ref_index += subpass.input_attachments.len();
+ let color_attachments = attachment_references_vk.as_ptr().add(ref_index);
+ ref_index += subpass.color_attachments.len();
+ let resolve_attachments = attachment_references_vk.as_ptr().add(ref_index);
+ ref_index += subpass.resolve_attachments.len();
+ let depth_stencil = if subpass.depth_stencil_attachment.is_some() {
+ let a = attachment_references_vk.as_ptr().add(ref_index);
+ ref_index += 1;
+ a
+ } else {
+ ptr::null()
+ };
+
+ ash::vk::SubpassDescription {
+ flags: ash::vk::SubpassDescriptionFlags::empty(),
+ pipeline_bind_point: ash::vk::PipelineBindPoint::GRAPHICS,
+ input_attachment_count: subpass.input_attachments.len() as u32,
+ p_input_attachments: if subpass.input_attachments.is_empty() {
+ ptr::null()
+ } else {
+ input_attachments
+ },
+ color_attachment_count: subpass.color_attachments.len() as u32,
+ p_color_attachments: if subpass.color_attachments.is_empty() {
+ ptr::null()
+ } else {
+ color_attachments
+ },
+ p_resolve_attachments: if subpass.resolve_attachments.is_empty() {
+ ptr::null()
+ } else {
+ resolve_attachments
+ },
+ p_depth_stencil_attachment: depth_stencil,
+ preserve_attachment_count: subpass.preserve_attachments.len() as u32,
+ p_preserve_attachments: if subpass.preserve_attachments.is_empty() {
+ ptr::null()
+ } else {
+ subpass.preserve_attachments.as_ptr()
+ },
+ }
+ })
+ .collect();
+
+ // If this assertion fails, there's a serious bug in the code above ^.
+ debug_assert!(ref_index == attachment_references_vk.len());
+
+ out
+ };
+
+ let dependencies_vk = dependencies
+ .iter()
+ .map(|dependency| ash::vk::SubpassDependency {
+ src_subpass: dependency.src_subpass.unwrap_or(ash::vk::SUBPASS_EXTERNAL),
+ dst_subpass: dependency.dst_subpass.unwrap_or(ash::vk::SUBPASS_EXTERNAL),
+ src_stage_mask: dependency.src_stages.into(),
+ dst_stage_mask: dependency.dst_stages.into(),
+ src_access_mask: dependency.src_access.into(),
+ dst_access_mask: dependency.dst_access.into(),
+ dependency_flags: dependency.dependency_flags.into(),
+ })
+ .collect::<SmallVec<[_; 4]>>();
+
+ /* Input attachment aspect */
+
+ let input_attachment_aspect_references: SmallVec<[_; 8]> = if device.api_version()
+ >= Version::V1_1
+ || device.enabled_extensions().khr_maintenance2
+ {
+ subpasses
+ .iter()
+ .enumerate()
+ .flat_map(|(subpass_num, subpass)| {
+ subpass.input_attachments.iter().enumerate().flat_map(
+ move |(atch_num, atch_ref)| {
+ atch_ref.as_ref().map(|atch_ref| {
+ ash::vk::InputAttachmentAspectReference {
+ subpass: subpass_num as u32,
+ input_attachment_index: atch_num as u32,
+ aspect_mask: atch_ref.aspects.into(),
+ }
+ })
+ },
+ )
+ })
+ .collect()
+ } else {
+ SmallVec::new()
+ };
+
+ let mut input_attachment_aspect_create_info =
+ if !input_attachment_aspect_references.is_empty() {
+ Some(ash::vk::RenderPassInputAttachmentAspectCreateInfo {
+ aspect_reference_count: input_attachment_aspect_references.len() as u32,
+ p_aspect_references: input_attachment_aspect_references.as_ptr(),
+ ..Default::default()
+ })
+ } else {
+ None
+ };
+
+ /* Multiview */
+
+ let is_multiview = subpasses[0].view_mask != 0;
+
+ let (multiview_view_masks, multiview_view_offsets): (SmallVec<[_; 4]>, SmallVec<[_; 4]>) =
+ if is_multiview {
+ (
+ subpasses.iter().map(|subpass| subpass.view_mask).collect(),
+ dependencies
+ .iter()
+ .map(|dependency| dependency.view_offset)
+ .collect(),
+ )
+ } else {
+ (SmallVec::new(), SmallVec::new())
+ };
+
+ let mut multiview_create_info = if is_multiview {
+ debug_assert!(multiview_view_masks.len() == subpasses.len());
+ debug_assert!(multiview_view_offsets.len() == dependencies.len());
+
+ Some(ash::vk::RenderPassMultiviewCreateInfo {
+ subpass_count: multiview_view_masks.len() as u32,
+ p_view_masks: multiview_view_masks.as_ptr(),
+ dependency_count: multiview_view_offsets.len() as u32,
+ p_view_offsets: multiview_view_offsets.as_ptr(),
+ correlation_mask_count: correlated_view_masks.len() as u32,
+ p_correlation_masks: correlated_view_masks.as_ptr(),
+ ..Default::default()
+ })
+ } else {
+ None
+ };
+
+ /* Create */
+
+ let mut create_info = ash::vk::RenderPassCreateInfo {
+ flags: ash::vk::RenderPassCreateFlags::empty(),
+ attachment_count: attachments_vk.len() as u32,
+ p_attachments: if attachments_vk.is_empty() {
+ ptr::null()
+ } else {
+ attachments_vk.as_ptr()
+ },
+ subpass_count: subpasses_vk.len() as u32,
+ p_subpasses: if subpasses_vk.is_empty() {
+ ptr::null()
+ } else {
+ subpasses_vk.as_ptr()
+ },
+ dependency_count: dependencies_vk.len() as u32,
+ p_dependencies: if dependencies_vk.is_empty() {
+ ptr::null()
+ } else {
+ dependencies_vk.as_ptr()
+ },
+ ..Default::default()
+ };
+
+ if let Some(input_attachment_aspect_create_info) =
+ input_attachment_aspect_create_info.as_mut()
+ {
+ input_attachment_aspect_create_info.p_next = create_info.p_next;
+ create_info.p_next = input_attachment_aspect_create_info as *const _ as *const _;
+ }
+
+ if let Some(multiview_create_info) = multiview_create_info.as_mut() {
+ multiview_create_info.p_next = create_info.p_next;
+ create_info.p_next = multiview_create_info as *const _ as *const _;
+ }
+
+ Ok({
+ let fns = device.fns();
+ let mut output = MaybeUninit::uninit();
+ (fns.v1_0.create_render_pass)(
+ device.handle(),
+ &create_info,
+ ptr::null(),
+ output.as_mut_ptr(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+ output.assume_init()
+ })
+ }
+}
+
+/// Error that can happen when creating a `RenderPass`.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum RenderPassCreationError {
+ /// Not enough memory.
+ OomError(OomError),
+
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+
+ /// An attachment is first used in the render pass with a read-only layout or as an input
+ /// attachment, but its `load_op` or `stencil_load_op` is [`LoadOp::Clear`].
+ AttachmentFirstUseLoadOpInvalid {
+ attachment: u32,
+ first_use_subpass: u32,
+ },
+
+ /// An attachment has an `initial_layout` or `final_layout` value that is invalid for the
+ /// provided `format`.
+ AttachmentLayoutInvalid { attachment: u32 },
+
+ /// Correlated view masks were included, but multiview is not enabled on the render pass.
+ CorrelatedViewMasksMultiviewNotEnabled,
+
+ /// The provided correlated view masks contain a bit that is set in more than one element.
+ CorrelatedViewMasksOverlapping,
+
+ /// A subpass dependency specified an access type that was not supported by the given stages.
+ DependencyAccessNotSupportedByStages { dependency: u32 },
+
+ /// A subpass dependency has both `src_subpass` and `dst_subpass` set to `None`.
+ DependencyBothSubpassesExternal { dependency: u32 },
+
+ /// A subpass dependency specifies a subpass self-dependency and includes framebuffer stages in
+ /// both `src_stages` and `dst_stages`, but the `by_region` dependency was not enabled.
+ DependencySelfDependencyFramebufferStagesWithoutByRegion { dependency: u32 },
+
+ /// A subpass dependency specifies a subpass self-dependency and includes
+ /// non-framebuffer stages, but the latest stage in `src_stages` is after the earliest stage
+ /// in `dst_stages`.
+ DependencySelfDependencySourceStageAfterDestinationStage { dependency: u32 },
+
+ /// A subpass dependency specifies a subpass self-dependency and has the `view_local` dependency
+ /// enabled, but the inner offset value was not 0.
+ DependencySelfDependencyViewLocalNonzeroViewOffset { dependency: u32 },
+
+ /// A subpass dependency specifies a subpass self-dependency without the `view_local`
+ /// dependency, but the referenced subpass has more than one bit set in its `view_mask`.
+ DependencySelfDependencyViewMaskMultiple { dependency: u32, subpass: u32 },
+
+ /// A subpass dependency has a `src_subpass` that is later than the `dst_subpass`.
+ DependencySourceSubpassAfterDestinationSubpass { dependency: u32 },
+
+ /// A subpass dependency has a bit set in the `src_stages` or `dst_stages` that is
+ /// not supported for graphics pipelines.
+ DependencyStageNotSupported { dependency: u32 },
+
+ /// A subpass index in a subpass dependency is not less than the number of subpasses in the
+ /// render pass.
+ DependencySubpassOutOfRange { dependency: u32, subpass: u32 },
+
+ /// In a subpass dependency, `dependency_flags` contains [`VIEW_LOCAL`], but `src_subpass` or
+ /// `dst_subpass` were set to `None`.
+ ///
+ /// [`VIEW_LOCAL`]: crate::sync::DependencyFlags::VIEW_LOCAL
+ DependencyViewLocalExternalDependency { dependency: u32 },
+
+ /// In a subpass dependency, `dependency_flags` contains [`VIEW_LOCAL`], but multiview is not
+ /// enabled on the render pass.
+ ///
+ /// [`VIEW_LOCAL`]: crate::sync::DependencyFlags::VIEW_LOCAL
+ DependencyViewLocalMultiviewNotEnabled { dependency: u32 },
+
+ /// In a subpass dependency, `view_offset` is not zero, but `dependency_flags` does not contain
+ /// [`VIEW_LOCAL`].
+ ///
+ /// [`VIEW_LOCAL`]: crate::sync::DependencyFlags::VIEW_LOCAL
+ DependencyViewOffzetNonzeroWithoutViewLocal { dependency: u32 },
+
+ /// A reference to an attachment used other than as an input attachment in a subpass has
+ /// one or more aspects selected.
+ SubpassAttachmentAspectsNotEmpty { subpass: u32, attachment: u32 },
+
+ /// An attachment used as an attachment in a subpass has a layout that is not supported for
+ /// that usage.
+ SubpassAttachmentLayoutInvalid {
+ subpass: u32,
+ attachment: u32,
+ usage: &'static str,
+ },
+
+ /// The layouts of all uses of an attachment in a subpass do not match.
+ SubpassAttachmentLayoutMismatch { subpass: u32, attachment: u32 },
+
+ /// An attachment index in a subpass is not less than the number of attachments in the render
+ /// pass.
+ SubpassAttachmentOutOfRange { subpass: u32, attachment: u32 },
+
+ /// An attachment is used as both a color attachment and a depth/stencil attachment in a
+ /// subpass.
+ SubpassAttachmentUsageColorDepthStencil { subpass: u32, attachment: u32 },
+
+ /// An attachment used as an attachment in a subpass has a format that does not support that
+ /// usage.
+ SubpassAttachmentFormatUsageNotSupported {
+ subpass: u32,
+ attachment: u32,
+ usage: &'static str,
+ },
+
+ /// An attachment used as a color attachment in a subpass with resolve attachments has a
+ /// `samples` value of [`SampleCount::Sample1`].
+ SubpassColorAttachmentWithResolveNotMultisampled { subpass: u32, attachment: u32 },
+
+ /// An attachment used as a color or depth/stencil attachment in a subpass has a `samples` value
+ /// that is different from the first color attachment.
+ SubpassColorDepthStencilAttachmentSamplesMismatch {
+ subpass: u32,
+ attachment: u32,
+ samples: SampleCount,
+ first_samples: SampleCount,
+ },
+
+ /// A reference to an attachment used as an input attachment in a subpass selects aspects that
+ /// are not present in the format of the attachment.
+ SubpassInputAttachmentAspectsNotCompatible { subpass: u32, attachment: u32 },
+
+ /// The `max_color_attachments` limit has been exceeded for a subpass.
+ SubpassMaxColorAttachmentsExceeded {
+ subpass: u32,
+ color_attachment_count: u32,
+ max: u32,
+ },
+
+ /// The `max_multiview_view_count` limit has been exceeded for a subpass.
+ SubpassMaxMultiviewViewCountExceeded {
+ subpass: u32,
+ view_count: u32,
+ max: u32,
+ },
+
+ /// The multiview state (whether `view_mask` is nonzero) of a subpass is different from the
+ /// first subpass.
+ SubpassMultiviewMismatch {
+ subpass: u32,
+ multiview: bool,
+ first_subpass_multiview: bool,
+ },
+
+ /// An attachment marked as a preserve attachment in a subpass is also used as an attachment
+ /// in that subpass.
+ SubpassPreserveAttachmentUsedElsewhere { subpass: u32, attachment: u32 },
+
+ /// The `resolve_attachments` field of a subpass was not empty, but its length did not match
+ /// the length of `color_attachments`.
+ SubpassResolveAttachmentsColorAttachmentsLenMismatch { subpass: u32 },
+
+ /// An attachment used as a resolve attachment in a subpass has a `format` value different from
+ /// the corresponding color attachment.
+ SubpassResolveAttachmentFormatMismatch {
+ subpass: u32,
+ resolve_attachment: u32,
+ color_attachment: u32,
+ },
+
+ /// An attachment used as a resolve attachment in a subpass has a `samples` value other than
+ /// [`SampleCount::Sample1`].
+ SubpassResolveAttachmentMultisampled { subpass: u32, attachment: u32 },
+
+ /// A resolve attachment in a subpass is `Some`, but the corresponding color attachment is
+ /// `None`.
+ SubpassResolveAttachmentWithoutColorAttachment { subpass: u32 },
+}
+
+impl Error for RenderPassCreationError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ RenderPassCreationError::OomError(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+impl Display for RenderPassCreationError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::OomError(_) => write!(f, "not enough memory available"),
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ Self::AttachmentFirstUseLoadOpInvalid {
+ attachment,
+ first_use_subpass,
+ } => write!(
+ f,
+ "attachment {} is first used in the render pass in subpass {} with a read-only \
+ layout or as an input attachment, but its `load_op` or `stencil_load_op` is \
+ `LoadOp::Clear`",
+ attachment, first_use_subpass,
+ ),
+ Self::AttachmentLayoutInvalid { attachment } => write!(
+ f,
+ "attachment {} has an `initial_layout` or `final_layout` value that is invalid for \
+ the provided `format`",
+ attachment,
+ ),
+ Self::CorrelatedViewMasksMultiviewNotEnabled => write!(
+ f,
+ "correlated view masks were included, but multiview is not enabled on the render \
+ pass",
+ ),
+ Self::CorrelatedViewMasksOverlapping => write!(
+ f,
+ "the provided correlated view masks contain a bit that is set in more than one \
+ element",
+ ),
+ Self::DependencyAccessNotSupportedByStages { dependency } => write!(
+ f,
+ "subpass dependency {} specified an access type that was not supported by the \
+ given stages",
+ dependency,
+ ),
+ Self::DependencySelfDependencyFramebufferStagesWithoutByRegion { dependency } => {
+ write!(
+ f,
+ "subpass dependency {} specifies a subpass self-dependency and includes \
+ framebuffer stages in both `src_stages` and `dst_stages`, but the \
+ `by_region` dependency was not enabled",
+ dependency,
+ )
+ }
+ Self::DependencySelfDependencySourceStageAfterDestinationStage { dependency } => {
+ write!(
+ f,
+ "subpass dependency {} specifies a subpass self-dependency and includes \
+ non-framebuffer stages, but the latest stage in `src_stages` is after the \
+ earliest stage in `dst_stages`",
+ dependency,
+ )
+ }
+ Self::DependencySelfDependencyViewLocalNonzeroViewOffset { dependency } => write!(
+ f,
+ "subpass dependency {} specifies a subpass self-dependency and has the \
+ `view_local` dependency enabled, but the inner offset value was not 0",
+ dependency,
+ ),
+ Self::DependencySelfDependencyViewMaskMultiple {
+ dependency,
+ subpass,
+ } => write!(
+ f,
+ "subpass dependency {} specifies a subpass self-dependency without the \
+ `view_local` dependency, but the referenced subpass {} has more than one bit set \
+ in its `view_mask`",
+ dependency, subpass,
+ ),
+ Self::DependencySourceSubpassAfterDestinationSubpass { dependency } => write!(
+ f,
+ "subpass dependency {} has a `src_subpass` that is later than the \
+ `dst_subpass`",
+ dependency,
+ ),
+ Self::DependencyStageNotSupported { dependency } => write!(
+ f,
+ "subpass dependency {} has a bit set in the `src_stages` or \
+ `dst_stages` that is not supported for graphics pipelines",
+ dependency,
+ ),
+ Self::DependencyBothSubpassesExternal { dependency } => write!(
+ f,
+ "subpass dependency {} has both `src_subpass` and `dst_subpass` set to \
+ `None`",
+ dependency,
+ ),
+ Self::DependencySubpassOutOfRange {
+ dependency,
+ subpass,
+ } => write!(
+ f,
+ "the subpass index {} in subpass dependency {} is not less than the number of \
+ subpasses in the render pass",
+ subpass, dependency,
+ ),
+ Self::DependencyViewLocalExternalDependency { dependency } => write!(
+ f,
+ "in subpass dependency {}, `dependency_flags` contains `VIEW_LOCAL`, but \
+ `src_subpass` or `dst_subpass` were set to `None`",
+ dependency,
+ ),
+ Self::DependencyViewLocalMultiviewNotEnabled { dependency } => write!(
+ f,
+ "in subpass dependency {}, `dependency_flags` contains `VIEW_LOCAL`, but \
+ multiview is not enabled on the render pass",
+ dependency,
+ ),
+ Self::DependencyViewOffzetNonzeroWithoutViewLocal { dependency } => write!(
+ f,
+ "in subpass dependency {}, `view_offset` is not zero, but `dependency_flags` does \
+ not contain `VIEW_LOCAL`",
+ dependency,
+ ),
+ Self::SubpassAttachmentAspectsNotEmpty {
+ subpass,
+ attachment,
+ } => write!(
+ f,
+ "a reference to attachment {} used other than as an input attachment in subpass {} \
+ has one or more aspects selected",
+ attachment, subpass,
+ ),
+ Self::SubpassAttachmentLayoutMismatch {
+ subpass,
+ attachment,
+ } => write!(
+ f,
+ "the layouts of all uses of attachment {} in subpass {} do not match.",
+ attachment, subpass,
+ ),
+ Self::SubpassAttachmentLayoutInvalid {
+ subpass,
+ attachment,
+ usage,
+ } => write!(
+ f,
+ "attachment {} used as {} attachment in subpass {} has a layout that is not \
+ supported for that usage",
+ attachment, usage, subpass,
+ ),
+ Self::SubpassAttachmentOutOfRange {
+ subpass,
+ attachment,
+ } => write!(
+ f,
+ "the attachment index {} in subpass {} is not less than the number of attachments \
+ in the render pass",
+ attachment, subpass,
+ ),
+ Self::SubpassAttachmentUsageColorDepthStencil {
+ subpass,
+ attachment,
+ } => write!(
+ f,
+ "attachment {} is used as both a color attachment and a depth/stencil attachment \
+ in subpass {}",
+ attachment, subpass,
+ ),
+ Self::SubpassAttachmentFormatUsageNotSupported {
+ subpass,
+ attachment,
+ usage,
+ } => write!(
+ f,
+ "attachment {} used as {} attachment in subpass {} has a format that does not \
+ support that usage",
+ attachment, usage, subpass,
+ ),
+ Self::SubpassColorAttachmentWithResolveNotMultisampled {
+ subpass,
+ attachment,
+ } => write!(
+ f,
+ "attachment {} used as a color attachment in subpass {} with resolve attachments \
+ has a `samples` value of `SampleCount::Sample1`",
+ attachment, subpass,
+ ),
+ Self::SubpassColorDepthStencilAttachmentSamplesMismatch {
+ subpass,
+ attachment,
+ samples,
+ first_samples,
+ } => write!(
+ f,
+ "attachment {} used as a color or depth/stencil attachment in subpass {} has a \
+ `samples` value {:?} that is different from the first color attachment ({:?})",
+ attachment, subpass, samples, first_samples,
+ ),
+ Self::SubpassInputAttachmentAspectsNotCompatible {
+ subpass,
+ attachment,
+ } => write!(
+ f,
+ "a reference to attachment {} used as an input attachment in subpass {} selects \
+ aspects that are not present in the format of the attachment",
+ attachment, subpass,
+ ),
+ Self::SubpassMaxColorAttachmentsExceeded { .. } => {
+ write!(f, "the `max_color_attachments` limit has been exceeded")
+ }
+ Self::SubpassMaxMultiviewViewCountExceeded { .. } => write!(
+ f,
+ "the `max_multiview_view_count` limit has been exceeded for a subpass",
+ ),
+ Self::SubpassMultiviewMismatch {
+ subpass,
+ multiview,
+ first_subpass_multiview,
+ } => write!(
+ f,
+ "the multiview state (whether `view_mask` is nonzero) of subpass {} is {}, which \
+ is different from the first subpass ({})",
+ subpass, multiview, first_subpass_multiview,
+ ),
+ Self::SubpassPreserveAttachmentUsedElsewhere {
+ subpass,
+ attachment,
+ } => write!(
+ f,
+ "attachment {} marked as a preserve attachment in subpass {} is also used as an \
+ attachment in that subpass",
+ attachment, subpass,
+ ),
+ Self::SubpassResolveAttachmentsColorAttachmentsLenMismatch { subpass } => write!(
+ f,
+ "the `resolve_attachments` field of subpass {} was not empty, but its length did \
+ not match the length of `color_attachments`",
+ subpass,
+ ),
+ Self::SubpassResolveAttachmentFormatMismatch {
+ subpass,
+ resolve_attachment,
+ color_attachment,
+ } => write!(
+ f,
+ "attachment {} used as a resolve attachment in subpass {} has a `format` value \
+ different from the corresponding color attachment {}",
+ subpass, resolve_attachment, color_attachment,
+ ),
+ Self::SubpassResolveAttachmentMultisampled {
+ subpass,
+ attachment,
+ } => write!(
+ f,
+ "attachment {} used as a resolve attachment in subpass {} has a `samples` value \
+ other than `SampleCount::Sample1`",
+ attachment, subpass,
+ ),
+ Self::SubpassResolveAttachmentWithoutColorAttachment { subpass } => write!(
+ f,
+ "a resolve attachment in subpass {} is `Some`, but the corresponding color \
+ attachment is `None`",
+ subpass,
+ ),
+ }
+ }
+}
+
+impl From<OomError> for RenderPassCreationError {
+ fn from(err: OomError) -> RenderPassCreationError {
+ RenderPassCreationError::OomError(err)
+ }
+}
+
+impl From<VulkanError> for RenderPassCreationError {
+ fn from(err: VulkanError) -> RenderPassCreationError {
+ match err {
+ err @ VulkanError::OutOfHostMemory => {
+ RenderPassCreationError::OomError(OomError::from(err))
+ }
+ err @ VulkanError::OutOfDeviceMemory => {
+ RenderPassCreationError::OomError(OomError::from(err))
+ }
+ _ => panic!("unexpected error: {:?}", err),
+ }
+ }
+}
+
+impl From<RequirementNotMet> for RenderPassCreationError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
+ }
+ }
+}
diff --git a/src/render_pass/desc.rs b/src/render_pass/desc.rs
deleted file mode 100644
index 8d8928d..0000000
--- a/src/render_pass/desc.rs
+++ /dev/null
@@ -1,434 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::format::ClearValue;
-use crate::format::Format;
-use crate::image::ImageLayout;
-use crate::image::SampleCount;
-use crate::pipeline::shader::ShaderInterface;
-use crate::sync::AccessFlags;
-use crate::sync::PipelineStages;
-
-/// The description of a render pass.
-#[derive(Clone, Debug)]
-pub struct RenderPassDesc {
- attachments: Vec<AttachmentDesc>,
- subpasses: Vec<SubpassDesc>,
- dependencies: Vec<SubpassDependencyDesc>,
- multiview: Option<MultiviewDesc>,
-}
-
-impl RenderPassDesc {
- /// Creates a description of a render pass.
- pub fn new(
- attachments: Vec<AttachmentDesc>,
- subpasses: Vec<SubpassDesc>,
- dependencies: Vec<SubpassDependencyDesc>,
- ) -> RenderPassDesc {
- RenderPassDesc {
- attachments,
- subpasses,
- dependencies,
- multiview: None,
- }
- }
-
- /// Creates a description of a render pass that uses the multiview feature.
- /// See [`MultiviewDesc`] for an explanation of possible configuration options.
- pub fn with_multiview(
- attachments: Vec<AttachmentDesc>,
- subpasses: Vec<SubpassDesc>,
- dependencies: Vec<SubpassDependencyDesc>,
- multiview: MultiviewDesc,
- ) -> RenderPassDesc {
- RenderPassDesc {
- attachments,
- subpasses,
- dependencies,
- multiview: Some(multiview),
- }
- }
-
- /// Creates a description of an empty render pass, with one subpass and no attachments.
- pub fn empty() -> RenderPassDesc {
- RenderPassDesc {
- attachments: vec![],
- subpasses: vec![SubpassDesc {
- color_attachments: vec![],
- depth_stencil: None,
- input_attachments: vec![],
- resolve_attachments: vec![],
- preserve_attachments: vec![],
- }],
- dependencies: vec![],
- multiview: None,
- }
- }
-
- // Returns the attachments of the description.
- #[inline]
- pub fn attachments(&self) -> &[AttachmentDesc] {
- &self.attachments
- }
-
- // Returns the subpasses of the description.
- #[inline]
- pub fn subpasses(&self) -> &[SubpassDesc] {
- &self.subpasses
- }
-
- // Returns the dependencies of the description.
- #[inline]
- pub fn dependencies(&self) -> &[SubpassDependencyDesc] {
- &self.dependencies
- }
-
- // Returns the multiview configuration of the description.
- #[inline]
- pub fn multiview(&self) -> &Option<MultiviewDesc> {
- &self.multiview
- }
-
- /// Decodes `I` into a list of clear values where each element corresponds
- /// to an attachment. The size of the returned iterator must be the same as the number of
- /// attachments.
- ///
- /// When the user enters a render pass, they need to pass a list of clear values to apply to
- /// the attachments of the framebuffer. This method is then responsible for checking the
- /// correctness of these values and turning them into a list that can be processed by vulkano.
- ///
- /// The format of the clear value **must** match the format of the attachment. Attachments
- /// that are not loaded with `LoadOp::Clear` must have an entry equal to `ClearValue::None`.
- pub fn convert_clear_values<I>(&self, values: I) -> impl Iterator<Item = ClearValue>
- where
- I: IntoIterator<Item = ClearValue>,
- {
- // FIXME: safety checks
- values.into_iter()
- }
-
- /// Returns `true` if the subpass of this description is compatible with the shader's fragment
- /// output definition.
- pub fn is_compatible_with_shader(
- &self,
- subpass: u32,
- shader_interface: &ShaderInterface,
- ) -> bool {
- let pass_descr = match self.subpasses.get(subpass as usize) {
- Some(s) => s,
- None => return false,
- };
-
- for element in shader_interface.elements() {
- for location in element.location.clone() {
- let attachment_id = match pass_descr.color_attachments.get(location as usize) {
- Some(a) => a.0,
- None => return false,
- };
-
- let attachment_desc = &self.attachments[attachment_id];
-
- // FIXME: compare formats depending on the number of components and data type
- /*if attachment_desc.format != element.format {
- return false;
- }*/
- }
- }
-
- true
- }
-
- /// Returns `true` if this description is compatible with the other description,
- /// as defined in the `Render Pass Compatibility` section of the Vulkan specs.
- // TODO: return proper error
- pub fn is_compatible_with_desc(&self, other: &RenderPassDesc) -> bool {
- if self.attachments().len() != other.attachments().len() {
- return false;
- }
-
- for (my_atch, other_atch) in self.attachments.iter().zip(other.attachments.iter()) {
- if !my_atch.is_compatible_with(&other_atch) {
- return false;
- }
- }
-
- return true;
-
- // FIXME: finish
- }
-}
-
-impl Default for RenderPassDesc {
- fn default() -> Self {
- Self::empty()
- }
-}
-
-/// Describes an attachment that will be used in a render pass.
-#[derive(Debug, Clone, Copy)]
-pub struct AttachmentDesc {
- /// Format of the image that is going to be bound.
- pub format: Format,
- /// Number of samples of the image that is going to be bound.
- pub samples: SampleCount,
-
- /// What the implementation should do with that attachment at the start of the render pass.
- pub load: LoadOp,
- /// What the implementation should do with that attachment at the end of the render pass.
- pub store: StoreOp,
-
- /// Equivalent of `load` for the stencil component of the attachment, if any. Irrelevant if
- /// there is no stencil component.
- pub stencil_load: LoadOp,
- /// Equivalent of `store` for the stencil component of the attachment, if any. Irrelevant if
- /// there is no stencil component.
- pub stencil_store: StoreOp,
-
- /// Layout that the image is going to be in at the start of the renderpass.
- ///
- /// The vulkano library will automatically switch to the correct layout if necessary, but it
- /// is more efficient to set this to the correct value.
- pub initial_layout: ImageLayout,
-
- /// Layout that the image will be transitioned to at the end of the renderpass.
- pub final_layout: ImageLayout,
-}
-
-impl AttachmentDesc {
- /// Returns true if this attachment is compatible with another attachment, as defined in the
- /// `Render Pass Compatibility` section of the Vulkan specs.
- #[inline]
- pub fn is_compatible_with(&self, other: &AttachmentDesc) -> bool {
- self.format == other.format && self.samples == other.samples
- }
-}
-
-/// Describes one of the subpasses of a render pass.
-///
-/// # Restrictions
-///
-/// All these restrictions are checked when the `RenderPass` object is created.
-/// TODO: that's not the case ^
-///
-/// - The number of color attachments must be less than the limit of the physical device.
-/// - All the attachments in `color_attachments` and `depth_stencil` must have the same
-/// samples count.
-/// - If any attachment is used as both an input attachment and a color or
-/// depth/stencil attachment, then each use must use the same layout.
-/// - Elements of `preserve_attachments` must not be used in any of the other members.
-/// - If `resolve_attachments` is not empty, then all the resolve attachments must be attachments
-/// with 1 sample and all the color attachments must have more than 1 sample.
-/// - If `resolve_attachments` is not empty, all the resolve attachments must have the same format
-/// as the color attachments.
-/// - If the first use of an attachment in this renderpass is as an input attachment and the
-/// attachment is not also used as a color or depth/stencil attachment in the same subpass,
-/// then the loading operation must not be `Clear`.
-///
-// TODO: add tests for all these restrictions
-// TODO: allow unused attachments (for example attachment 0 and 2 are used, 1 is unused)
-#[derive(Debug, Clone)]
-pub struct SubpassDesc {
- /// Indices and layouts of attachments to use as color attachments.
- pub color_attachments: Vec<(usize, ImageLayout)>, // TODO: Vec is slow
-
- /// Index and layout of the attachment to use as depth-stencil attachment.
- pub depth_stencil: Option<(usize, ImageLayout)>,
-
- /// Indices and layouts of attachments to use as input attachments.
- pub input_attachments: Vec<(usize, ImageLayout)>, // TODO: Vec is slow
-
- /// If not empty, each color attachment will be resolved into each corresponding entry of
- /// this list.
- ///
- /// If this value is not empty, it **must** be the same length as `color_attachments`.
- pub resolve_attachments: Vec<(usize, ImageLayout)>, // TODO: Vec is slow
-
- /// Indices of attachments that will be preserved during this pass.
- pub preserve_attachments: Vec<usize>, // TODO: Vec is slow
-}
-
-/// Describes a dependency between two subpasses of a render pass.
-///
-/// The implementation is allowed to change the order of the subpasses within a render pass, unless
-/// you specify that there exists a dependency between two subpasses (ie. the result of one will be
-/// used as the input of another one).
-#[derive(Debug, Clone, Copy)]
-pub struct SubpassDependencyDesc {
- /// Index of the subpass that writes the data that `destination_subpass` is going to use.
- pub source_subpass: usize,
-
- /// Index of the subpass that reads the data that `source_subpass` wrote.
- pub destination_subpass: usize,
-
- /// The pipeline stages that must be finished on the previous subpass before the destination
- /// subpass can start.
- pub source_stages: PipelineStages,
-
- /// The pipeline stages of the destination subpass that must wait for the source to be finished.
- /// Stages that are earlier of the stages specified here can start before the source is
- /// finished.
- pub destination_stages: PipelineStages,
-
- /// The way the source subpass accesses the attachments on which we depend.
- pub source_access: AccessFlags,
-
- /// The way the destination subpass accesses the attachments on which we depend.
- pub destination_access: AccessFlags,
-
- /// If false, then the whole subpass must be finished for the next one to start. If true, then
- /// the implementation can start the new subpass for some given pixels as long as the previous
- /// subpass is finished for these given pixels.
- ///
- /// In other words, if the previous subpass has some side effects on other parts of an
- /// attachment, then you should set it to false.
- ///
- /// Passing `false` is always safer than passing `true`, but in practice you rarely need to
- /// pass `false`.
- pub by_region: bool,
-}
-
-/// Describes what the implementation should do with an attachment after all the subpasses have
-/// completed.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-#[repr(i32)]
-pub enum StoreOp {
- /// The attachment will be stored. This is what you usually want.
- ///
- /// While this is the most intuitive option, it is also slower than `DontCare` because it can
- /// take time to write the data back to memory.
- Store = ash::vk::AttachmentStoreOp::STORE.as_raw(),
-
- /// What happens is implementation-specific.
- ///
- /// This is purely an optimization compared to `Store`. The implementation doesn't need to copy
- /// from the internal cache to the memory, which saves memory bandwidth.
- ///
- /// This doesn't mean that the data won't be copied, as an implementation is also free to not
- /// use a cache and write the output directly in memory. In other words, the content of the
- /// image will be undefined.
- DontCare = ash::vk::AttachmentStoreOp::DONT_CARE.as_raw(),
-}
-
-impl From<StoreOp> for ash::vk::AttachmentStoreOp {
- #[inline]
- fn from(val: StoreOp) -> Self {
- Self::from_raw(val as i32)
- }
-}
-
-/// Describes what the implementation should do with an attachment at the start of the subpass.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-#[repr(i32)]
-pub enum LoadOp {
- /// The content of the attachment will be loaded from memory. This is what you want if you want
- /// to draw over something existing.
- ///
- /// While this is the most intuitive option, it is also the slowest because it uses a lot of
- /// memory bandwidth.
- Load = ash::vk::AttachmentLoadOp::LOAD.as_raw(),
-
- /// The content of the attachment will be filled by the implementation with a uniform value
- /// that you must provide when you start drawing.
- ///
- /// This is what you usually use at the start of a frame, in order to reset the content of
- /// the color, depth and/or stencil buffers.
- ///
- /// See the `draw_inline` and `draw_secondary` methods of `PrimaryComputeBufferBuilder`.
- Clear = ash::vk::AttachmentLoadOp::CLEAR.as_raw(),
-
- /// The attachment will have undefined content.
- ///
- /// This is what you should use for attachments that you intend to entirely cover with draw
- /// commands.
- /// If you are going to fill the attachment with a uniform value, it is better to use `Clear`
- /// instead.
- DontCare = ash::vk::AttachmentLoadOp::DONT_CARE.as_raw(),
-}
-
-impl From<LoadOp> for ash::vk::AttachmentLoadOp {
- #[inline]
- fn from(val: LoadOp) -> Self {
- Self::from_raw(val as i32)
- }
-}
-
-/// Describes the `multiview` configuration for the render pass which is used to draw
-/// to multiple layers of a framebuffer inside of a single render pass.
-#[derive(Debug, Clone)]
-pub struct MultiviewDesc {
- /// The view masks indicate which layers of the framebuffer should be rendered for each subpass.
- /// Values are bit masks which means that for example `0b11` will draw to the first two layers
- /// and `0b101` will draw to the first and third layer.
- pub view_masks: Vec<u32>,
-
- /// The correlation masks indicate sets of views that may be more efficient to render
- /// concurrently (usually because they show the same geometry from almost the same perspective).
- /// Values are bit masks which means that for example `0b11` means the first two layers are
- /// highly correlated and `0b101` means the first and third layer are highly correlated.
- pub correlation_masks: Vec<u32>,
-
- /// The view offsets contain additional information for each subpass dependency that indicate
- /// which views in the source subpass the views of the destination subpass depend on.
- pub view_offsets: Vec<i32>,
-}
-
-impl MultiviewDesc {
- /// Returns the index of the layer with the biggest index that is
- /// referred to by a mask in the multiview description.
- pub fn highest_used_layer(&self) -> u32 {
- self.view_masks
- .iter()
- .chain(self.correlation_masks.iter())
- .map(|&mask| 32 - mask.leading_zeros()) // the highest set bit corresponds to the highest used layer
- .max()
- .unwrap_or(0)
- }
-
- /// Returns the amount of layers that are used in the multiview description.
- pub fn used_layer_count(&self) -> u32 {
- self.view_masks
- .iter()
- .chain(self.correlation_masks.iter())
- .fold(0, |acc, &mask| acc | mask)
- .count_ones()
- }
-}
-
-/// Possible resolve modes for depth and stencil attachments.
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-#[repr(u32)]
-pub enum ResolveMode {
- None = ash::vk::ResolveModeFlags::NONE.as_raw(),
- SampleZero = ash::vk::ResolveModeFlags::SAMPLE_ZERO.as_raw(),
- Average = ash::vk::ResolveModeFlags::AVERAGE.as_raw(),
- Min = ash::vk::ResolveModeFlags::MIN.as_raw(),
- Max = ash::vk::ResolveModeFlags::MAX.as_raw(),
-}
-
-#[derive(Clone, Copy, Debug)]
-pub struct ResolveModes {
- pub none: bool,
- pub sample_zero: bool,
- pub average: bool,
- pub min: bool,
- pub max: bool,
-}
-
-impl From<ash::vk::ResolveModeFlags> for ResolveModes {
- #[inline]
- fn from(val: ash::vk::ResolveModeFlags) -> Self {
- Self {
- none: val.intersects(ash::vk::ResolveModeFlags::NONE),
- sample_zero: val.intersects(ash::vk::ResolveModeFlags::SAMPLE_ZERO),
- average: val.intersects(ash::vk::ResolveModeFlags::AVERAGE),
- min: val.intersects(ash::vk::ResolveModeFlags::MIN),
- max: val.intersects(ash::vk::ResolveModeFlags::MAX),
- }
- }
-}
diff --git a/src/render_pass/framebuffer.rs b/src/render_pass/framebuffer.rs
index b55be4d..5a2df6c 100644
--- a/src/render_pass/framebuffer.rs
+++ b/src/render_pass/framebuffer.rs
@@ -7,649 +7,779 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use crate::check_errors;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::image::view::ImageViewAbstract;
-use crate::render_pass::ensure_image_view_compatible;
-use crate::render_pass::AttachmentsList;
-use crate::render_pass::IncompatibleRenderPassAttachmentError;
-use crate::render_pass::RenderPass;
-use crate::Error;
-use crate::OomError;
-use crate::SafeDeref;
-use crate::VulkanObject;
+use super::RenderPass;
+use crate::{
+ device::{Device, DeviceOwned},
+ format::Format,
+ image::{view::ImageViewType, ImageDimensions, ImageUsage, ImageViewAbstract, SampleCount},
+ macros::impl_id_counter,
+ OomError, VulkanError, VulkanObject,
+};
use smallvec::SmallVec;
-use std::cmp;
-use std::error;
-use std::fmt;
-use std::marker::PhantomData;
-use std::mem::MaybeUninit;
-use std::ptr;
-use std::sync::Arc;
+use std::{
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+ mem::MaybeUninit,
+ num::NonZeroU64,
+ ops::Range,
+ ptr,
+ sync::Arc,
+};
/// The image views that are attached to a render pass during drawing.
///
/// A framebuffer is a collection of images, and supplies the actual inputs and outputs of each
-/// subpass within a render pass. It is created from a subpass and must match it: each attachment
-/// point in the subpass must have a matching image in the framebuffer.
-///
-/// Creating a framebuffer is done by calling `Framebuffer::start`, which returns a
-/// `FramebufferBuilder` object. You can then add the framebuffer attachments one by one by
-/// calling `add(image)`. When you are done, call `build()`.
-///
-/// Both the `add` and the `build` functions perform various checks to make sure that the number
-/// of images is correct and that each image is compatible with the attachment definition in the
-/// render pass.
+/// attachment within a render pass. Each attachment point in the render pass must have a matching
+/// image in the framebuffer.
///
/// ```
/// # use std::sync::Arc;
/// # use vulkano::render_pass::RenderPass;
-/// use vulkano::render_pass::Framebuffer;
+/// # use vulkano::image::AttachmentImage;
+/// # use vulkano::image::view::ImageView;
+/// use vulkano::render_pass::{Framebuffer, FramebufferCreateInfo};
///
/// # let render_pass: Arc<RenderPass> = return;
-/// # let view: Arc<vulkano::image::view::ImageView<Arc<vulkano::image::AttachmentImage<vulkano::format::Format>>>> = return;
+/// # let view: Arc<ImageView<AttachmentImage>> = return;
/// // let render_pass: Arc<_> = ...;
-/// let framebuffer = Framebuffer::start(render_pass.clone())
-/// .add(view).unwrap()
-/// .build().unwrap();
+/// let framebuffer = Framebuffer::new(
+/// render_pass.clone(),
+/// FramebufferCreateInfo {
+/// attachments: vec![view],
+/// ..Default::default()
+/// },
+/// ).unwrap();
/// ```
-///
-/// All framebuffer objects implement the `FramebufferAbstract` trait. This means that you can cast
-/// any `Arc<Framebuffer<..>>` into an `Arc<FramebufferAbstract + Send + Sync>` for easier storage.
-///
-/// ## Framebuffer dimensions
-///
-/// If you use `Framebuffer::start()` to create a framebuffer then vulkano will automatically
-/// make sure that all the attachments have the same dimensions, as this is the most common
-/// situation.
-///
-/// Alternatively you can also use `with_intersecting_dimensions`, in which case the dimensions of
-/// the framebuffer will be the intersection of the dimensions of all attachments, or
-/// `with_dimensions` if you want to specify exact dimensions. If you use `with_dimensions`, you
-/// are allowed to attach images that are larger than these dimensions.
-///
-/// If the dimensions of the framebuffer don't match the dimensions of one of its attachment, then
-/// only the top-left hand corner of the image will be drawn to.
-///
#[derive(Debug)]
-pub struct Framebuffer<A> {
- device: Arc<Device>,
+pub struct Framebuffer {
+ handle: ash::vk::Framebuffer,
render_pass: Arc<RenderPass>,
- framebuffer: ash::vk::Framebuffer,
- dimensions: [u32; 3],
- resources: A,
-}
+ id: NonZeroU64,
-impl Framebuffer<()> {
- /// Starts building a framebuffer.
- pub fn start(render_pass: Arc<RenderPass>) -> FramebufferBuilder<()> {
- FramebufferBuilder {
- render_pass,
- raw_ids: SmallVec::new(),
- dimensions: FramebufferBuilderDimensions::AutoIdentical(None),
- attachments: (),
- }
- }
-
- /// Starts building a framebuffer. The dimensions of the framebuffer will automatically be
- /// the intersection of the dimensions of all the attachments.
- pub fn with_intersecting_dimensions(render_pass: Arc<RenderPass>) -> FramebufferBuilder<()> {
- FramebufferBuilder {
- render_pass,
- raw_ids: SmallVec::new(),
- dimensions: FramebufferBuilderDimensions::AutoSmaller(None),
- attachments: (),
- }
- }
+ attachments: Vec<Arc<dyn ImageViewAbstract>>,
+ extent: [u32; 2],
+ layers: u32,
+}
- /// Starts building a framebuffer.
- pub fn with_dimensions(
+impl Framebuffer {
+ /// Creates a new `Framebuffer`.
+ pub fn new(
render_pass: Arc<RenderPass>,
- dimensions: [u32; 3],
- ) -> FramebufferBuilder<()> {
- FramebufferBuilder {
- render_pass,
- raw_ids: SmallVec::new(),
- dimensions: FramebufferBuilderDimensions::Specific(dimensions),
- attachments: (),
+ create_info: FramebufferCreateInfo,
+ ) -> Result<Arc<Framebuffer>, FramebufferCreationError> {
+ let FramebufferCreateInfo {
+ attachments,
+ mut extent,
+ mut layers,
+ _ne: _,
+ } = create_info;
+
+ let device = render_pass.device();
+
+ // VUID-VkFramebufferCreateInfo-attachmentCount-00876
+ if attachments.len() != render_pass.attachments().len() {
+ return Err(FramebufferCreationError::AttachmentCountMismatch {
+ provided: attachments.len() as u32,
+ required: render_pass.attachments().len() as u32,
+ });
}
- }
-}
-/// Prototype of a framebuffer.
-pub struct FramebufferBuilder<A> {
- render_pass: Arc<RenderPass>,
- raw_ids: SmallVec<[ash::vk::ImageView; 8]>,
- dimensions: FramebufferBuilderDimensions,
- attachments: A,
-}
+ let auto_extent = extent[0] == 0 || extent[1] == 0;
+ let auto_layers = layers == 0;
-impl<A> fmt::Debug for FramebufferBuilder<A>
-where
- A: fmt::Debug,
-{
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- fmt.debug_struct("FramebufferBuilder")
- .field("render_pass", &self.render_pass)
- .field("dimensions", &self.dimensions)
- .field("attachments", &self.attachments)
- .finish()
- }
-}
+ // VUID-VkFramebufferCreateInfo-width-00885
+ // VUID-VkFramebufferCreateInfo-height-00887
+ if auto_extent {
+ if attachments.is_empty() {
+ return Err(FramebufferCreationError::AutoExtentAttachmentsEmpty);
+ }
-#[derive(Debug)]
-enum FramebufferBuilderDimensions {
- AutoIdentical(Option<[u32; 3]>),
- AutoSmaller(Option<[u32; 3]>),
- Specific([u32; 3]),
-}
+ extent = [u32::MAX, u32::MAX];
+ }
-impl<A> FramebufferBuilder<A>
-where
- A: AttachmentsList,
-{
- /// Appends an attachment to the prototype of the framebuffer.
- ///
- /// Attachments must be added in the same order as the one defined in the render pass.
- pub fn add<T>(
- self,
- attachment: T,
- ) -> Result<FramebufferBuilder<(A, T)>, FramebufferCreationError>
- where
- T: ImageViewAbstract,
- {
- if self.raw_ids.len() >= self.render_pass.desc().attachments().len() {
- return Err(FramebufferCreationError::AttachmentsCountMismatch {
- expected: self.render_pass.desc().attachments().len(),
- obtained: self.raw_ids.len() + 1,
- });
+ // VUID-VkFramebufferCreateInfo-layers-00889
+ if auto_layers {
+ if attachments.is_empty() {
+ return Err(FramebufferCreationError::AutoLayersAttachmentsEmpty);
+ }
+
+ if render_pass.views_used() != 0 {
+ // VUID-VkFramebufferCreateInfo-renderPass-02531
+ layers = 1;
+ } else {
+ layers = u32::MAX;
+ }
+ } else {
+ // VUID-VkFramebufferCreateInfo-renderPass-02531
+ if render_pass.views_used() != 0 && layers != 1 {
+ return Err(FramebufferCreationError::MultiviewLayersInvalid);
+ }
}
- match ensure_image_view_compatible(self.render_pass.desc(), self.raw_ids.len(), &attachment)
- {
- Ok(()) => (),
- Err(err) => return Err(FramebufferCreationError::IncompatibleAttachment(err)),
- };
+ let attachments_vk = attachments
+ .iter()
+ .zip(render_pass.attachments())
+ .enumerate()
+ .map(|(attachment_num, (image_view, attachment_desc))| {
+ let attachment_num = attachment_num as u32;
+ assert_eq!(device, image_view.device());
+
+ for subpass in render_pass.subpasses() {
+ // VUID-VkFramebufferCreateInfo-pAttachments-00877
+ if subpass
+ .color_attachments
+ .iter()
+ .flatten()
+ .any(|atch_ref| atch_ref.attachment == attachment_num)
+ {
+ if !image_view.usage().intersects(ImageUsage::COLOR_ATTACHMENT) {
+ return Err(FramebufferCreationError::AttachmentMissingUsage {
+ attachment: attachment_num,
+ usage: "color_attachment",
+ });
+ }
+ }
- let image_dimensions = attachment.image().dimensions();
- let array_layers = attachment.array_layers();
- debug_assert_eq!(image_dimensions.depth(), 1);
+ // VUID-VkFramebufferCreateInfo-pAttachments-02633
+ if let Some(atch_ref) = &subpass.depth_stencil_attachment {
+ if atch_ref.attachment == attachment_num {
+ if !image_view
+ .usage()
+ .intersects(ImageUsage::DEPTH_STENCIL_ATTACHMENT)
+ {
+ return Err(FramebufferCreationError::AttachmentMissingUsage {
+ attachment: attachment_num,
+ usage: "depth_stencil",
+ });
+ }
+ }
+ }
- let view_dimensions = [
- image_dimensions.width(),
- image_dimensions.height(),
- array_layers.end - array_layers.start,
- ];
+ // VUID-VkFramebufferCreateInfo-pAttachments-00879
+ if subpass
+ .input_attachments
+ .iter()
+ .flatten()
+ .any(|atch_ref| atch_ref.attachment == attachment_num)
+ {
+ if !image_view.usage().intersects(ImageUsage::INPUT_ATTACHMENT) {
+ return Err(FramebufferCreationError::AttachmentMissingUsage {
+ attachment: attachment_num,
+ usage: "input_attachment",
+ });
+ }
+ }
+ }
- let dimensions = match self.dimensions {
- FramebufferBuilderDimensions::AutoIdentical(None) => {
- FramebufferBuilderDimensions::AutoIdentical(Some(view_dimensions))
- }
- FramebufferBuilderDimensions::AutoIdentical(Some(current)) => {
- if view_dimensions != current {
- return Err(FramebufferCreationError::AttachmentDimensionsIncompatible {
- expected: current,
- obtained: view_dimensions,
+ // VUID-VkFramebufferCreateInfo-pAttachments-00880
+ if image_view.format() != attachment_desc.format {
+ return Err(FramebufferCreationError::AttachmentFormatMismatch {
+ attachment: attachment_num,
+ provided: image_view.format(),
+ required: attachment_desc.format,
});
}
- FramebufferBuilderDimensions::AutoIdentical(Some(current))
- }
- FramebufferBuilderDimensions::AutoSmaller(None) => {
- FramebufferBuilderDimensions::AutoSmaller(Some(view_dimensions))
- }
- FramebufferBuilderDimensions::AutoSmaller(Some(current)) => {
- let new_dims = [
- cmp::min(current[0], view_dimensions[0]),
- cmp::min(current[1], view_dimensions[1]),
- cmp::min(current[2], view_dimensions[2]),
- ];
-
- FramebufferBuilderDimensions::AutoSmaller(Some(new_dims))
- }
- FramebufferBuilderDimensions::Specific(current) => {
- if view_dimensions[0] < current[0]
- || view_dimensions[1] < current[1]
- || view_dimensions[2] < current[2]
- {
- return Err(FramebufferCreationError::AttachmentDimensionsIncompatible {
- expected: current,
- obtained: view_dimensions,
+ // VUID-VkFramebufferCreateInfo-pAttachments-00881
+ if image_view.image().samples() != attachment_desc.samples {
+ return Err(FramebufferCreationError::AttachmentSamplesMismatch {
+ attachment: attachment_num,
+ provided: image_view.image().samples(),
+ required: attachment_desc.samples,
});
}
- FramebufferBuilderDimensions::Specific(view_dimensions)
- }
- };
+ let image_view_extent = image_view.image().dimensions().width_height();
+ let image_view_array_layers = image_view.subresource_range().array_layers.end
+ - image_view.subresource_range().array_layers.start;
+
+ // VUID-VkFramebufferCreateInfo-renderPass-04536
+ if image_view_array_layers < render_pass.views_used() {
+ return Err(
+ FramebufferCreationError::MultiviewAttachmentNotEnoughLayers {
+ attachment: attachment_num,
+ provided: image_view_array_layers,
+ min: render_pass.views_used(),
+ },
+ );
+ }
- let mut raw_ids = self.raw_ids;
- raw_ids.push(attachment.inner().internal_object());
+ // VUID-VkFramebufferCreateInfo-flags-04533
+ // VUID-VkFramebufferCreateInfo-flags-04534
+ if auto_extent {
+ extent[0] = extent[0].min(image_view_extent[0]);
+ extent[1] = extent[1].min(image_view_extent[1]);
+ } else if image_view_extent[0] < extent[0] || image_view_extent[1] < extent[1] {
+ return Err(FramebufferCreationError::AttachmentExtentTooSmall {
+ attachment: attachment_num,
+ provided: image_view_extent,
+ min: extent,
+ });
+ }
- Ok(FramebufferBuilder {
- render_pass: self.render_pass,
- raw_ids,
- dimensions,
- attachments: (self.attachments, attachment),
- })
- }
+ // VUID-VkFramebufferCreateInfo-flags-04535
+ if auto_layers {
+ layers = layers.min(image_view_array_layers);
+ } else if image_view_array_layers < layers {
+ return Err(FramebufferCreationError::AttachmentNotEnoughLayers {
+ attachment: attachment_num,
+ provided: image_view_array_layers,
+ min: layers,
+ });
+ }
- /// Turns this builder into a `FramebufferBuilder<Rp, Box<AttachmentsList>>`.
- ///
- /// This allows you to store the builder in situations where you don't know in advance the
- /// number of attachments.
- ///
- /// > **Note**: This is a very rare corner case and you shouldn't have to use this function
- /// > in most situations.
- #[inline]
- pub fn boxed(self) -> FramebufferBuilder<Box<dyn AttachmentsList>>
- where
- A: 'static,
- {
- FramebufferBuilder {
- render_pass: self.render_pass,
- raw_ids: self.raw_ids,
- dimensions: self.dimensions,
- attachments: Box::new(self.attachments) as Box<_>,
- }
- }
+ // VUID-VkFramebufferCreateInfo-pAttachments-00883
+ if image_view.subresource_range().mip_levels.end
+ - image_view.subresource_range().mip_levels.start
+ != 1
+ {
+ return Err(FramebufferCreationError::AttachmentMultipleMipLevels {
+ attachment: attachment_num,
+ });
+ }
- /// Builds the framebuffer.
- pub fn build(self) -> Result<Framebuffer<A>, FramebufferCreationError> {
- let device = self.render_pass.device().clone();
+ // VUID-VkFramebufferCreateInfo-pAttachments-00884
+ if !image_view.component_mapping().is_identity() {
+ return Err(
+ FramebufferCreationError::AttachmentComponentMappingNotIdentity {
+ attachment: attachment_num,
+ },
+ );
+ }
- // Check the number of attachments.
- if self.raw_ids.len() != self.render_pass.desc().attachments().len() {
- return Err(FramebufferCreationError::AttachmentsCountMismatch {
- expected: self.render_pass.desc().attachments().len(),
- obtained: self.raw_ids.len(),
- });
- }
+ // VUID-VkFramebufferCreateInfo-pAttachments-00891
+ if matches!(
+ image_view.view_type(),
+ ImageViewType::Dim2d | ImageViewType::Dim2dArray
+ ) && matches!(
+ image_view.image().dimensions(),
+ ImageDimensions::Dim3d { .. }
+ ) && image_view.format().unwrap().type_color().is_none()
+ {
+ return Err(
+ FramebufferCreationError::Attachment2dArrayCompatibleDepthStencil {
+ attachment: attachment_num,
+ },
+ );
+ }
- // Compute the dimensions.
- let dimensions = match self.dimensions {
- FramebufferBuilderDimensions::Specific(dims)
- | FramebufferBuilderDimensions::AutoIdentical(Some(dims))
- | FramebufferBuilderDimensions::AutoSmaller(Some(dims)) => dims,
- FramebufferBuilderDimensions::AutoIdentical(None)
- | FramebufferBuilderDimensions::AutoSmaller(None) => {
- return Err(FramebufferCreationError::CantDetermineDimensions);
- }
- };
+ // VUID-VkFramebufferCreateInfo-flags-04113
+ if image_view.view_type() == ImageViewType::Dim3d {
+ return Err(FramebufferCreationError::AttachmentViewType3d {
+ attachment: attachment_num,
+ });
+ }
+
+ Ok(image_view.handle())
+ })
+ .collect::<Result<SmallVec<[_; 4]>, _>>()?;
- // Checking the dimensions against the limits.
{
let properties = device.physical_device().properties();
- let limits = [
- properties.max_framebuffer_width,
- properties.max_framebuffer_height,
- properties.max_framebuffer_layers,
- ];
- if dimensions[0] > limits[0] || dimensions[1] > limits[1] || dimensions[2] > limits[2] {
- return Err(FramebufferCreationError::DimensionsTooLarge);
- }
- }
- let mut layers = 1;
-
- if let Some(multiview) = self.render_pass.desc().multiview() {
- // There needs to be at least as many layers in the framebuffer
- // as the highest layer that gets referenced by the multiview masking.
- if multiview.highest_used_layer() > dimensions[2] {
- return Err(FramebufferCreationError::InsufficientLayerCount {
- minimum: multiview.highest_used_layer(),
- current: dimensions[2],
+ // VUID-VkFramebufferCreateInfo-width-00886
+ // VUID-VkFramebufferCreateInfo-height-00888
+ if extent[0] > properties.max_framebuffer_width
+ || extent[1] > properties.max_framebuffer_height
+ {
+ return Err(FramebufferCreationError::MaxFramebufferExtentExceeded {
+ provided: extent,
+ max: [
+ properties.max_framebuffer_width,
+ properties.max_framebuffer_height,
+ ],
});
}
- // VUID-VkFramebufferCreateInfo-renderPass-02531
- // The framebuffer has to be created with one layer if multiview is enabled even though
- // the underlying images generally have more layers
- // but these layers get used by the multiview functionality.
- if multiview.view_masks.iter().any(|&mask| mask != 0) {
- layers = 1;
+ // VUID-VkFramebufferCreateInfo-layers-00890
+ if layers > properties.max_framebuffer_layers {
+ return Err(FramebufferCreationError::MaxFramebufferLayersExceeded {
+ provided: layers,
+ max: properties.max_framebuffer_layers,
+ });
}
}
- let framebuffer = unsafe {
- let fns = device.fns();
-
- let infos = ash::vk::FramebufferCreateInfo {
- flags: ash::vk::FramebufferCreateFlags::empty(),
- render_pass: self.render_pass.inner().internal_object(),
- attachment_count: self.raw_ids.len() as u32,
- p_attachments: self.raw_ids.as_ptr(),
- width: dimensions[0],
- height: dimensions[1],
- layers,
- ..Default::default()
- };
+ let create_info = ash::vk::FramebufferCreateInfo {
+ flags: ash::vk::FramebufferCreateFlags::empty(),
+ render_pass: render_pass.handle(),
+ attachment_count: attachments_vk.len() as u32,
+ p_attachments: attachments_vk.as_ptr(),
+ width: extent[0],
+ height: extent[1],
+ layers,
+ ..Default::default()
+ };
+ let handle = unsafe {
+ let fns = device.fns();
let mut output = MaybeUninit::uninit();
- check_errors(fns.v1_0.create_framebuffer(
- device.internal_object(),
- &infos,
+ (fns.v1_0.create_framebuffer)(
+ device.handle(),
+ &create_info,
ptr::null(),
output.as_mut_ptr(),
- ))?;
+ )
+ .result()
+ .map_err(VulkanError::from)?;
output.assume_init()
};
- Ok(Framebuffer {
- device,
- render_pass: self.render_pass,
- framebuffer,
- dimensions,
- resources: self.attachments,
- })
- }
-}
-
-impl<A> Framebuffer<A> {
- /// Returns the width, height and layers of this framebuffer.
- #[inline]
- pub fn dimensions(&self) -> [u32; 3] {
- self.dimensions
- }
-
- /// Returns the width of the framebuffer in pixels.
- #[inline]
- pub fn width(&self) -> u32 {
- self.dimensions[0]
- }
-
- /// Returns the height of the framebuffer in pixels.
- #[inline]
- pub fn height(&self) -> u32 {
- self.dimensions[1]
- }
-
- /// Returns the number of layers (or depth) of the framebuffer.
- #[inline]
- pub fn layers(&self) -> u32 {
- self.dimensions[2]
+ Ok(Arc::new(Framebuffer {
+ handle,
+ render_pass,
+ id: Self::next_id(),
+ attachments,
+ extent,
+ layers,
+ }))
}
- /// Returns the device that was used to create this framebuffer.
+ /// Creates a new `Framebuffer` from a raw object handle.
+ ///
+ /// # Safety
+ ///
+ /// - `handle` must be a valid Vulkan object handle created from `render_pass`.
+ /// - `create_info` must match the info used to create the object.
#[inline]
- pub fn device(&self) -> &Arc<Device> {
- &self.device
+ pub unsafe fn from_handle(
+ render_pass: Arc<RenderPass>,
+ handle: ash::vk::Framebuffer,
+ create_info: FramebufferCreateInfo,
+ ) -> Arc<Framebuffer> {
+ let FramebufferCreateInfo {
+ attachments,
+ extent,
+ layers,
+ _ne: _,
+ } = create_info;
+
+ Arc::new(Framebuffer {
+ handle,
+ render_pass,
+ id: Self::next_id(),
+ attachments,
+ extent,
+ layers,
+ })
}
-
/// Returns the renderpass that was used to create this framebuffer.
#[inline]
pub fn render_pass(&self) -> &Arc<RenderPass> {
&self.render_pass
}
-}
-
-/// Trait for objects that contain a Vulkan framebuffer object.
-///
-/// Any `Framebuffer` object implements this trait. You can therefore turn a `Arc<Framebuffer<_>>`
-/// into a `Arc<FramebufferAbstract + Send + Sync>` for easier storage.
-pub unsafe trait FramebufferAbstract {
- /// Returns an opaque struct that represents the framebuffer's internals.
- fn inner(&self) -> FramebufferSys;
-
- /// Returns the width, height and array layers of the framebuffer.
- fn dimensions(&self) -> [u32; 3];
-
- /// Returns the render pass this framebuffer was created for.
- fn render_pass(&self) -> &Arc<RenderPass>;
-
- /// Returns the attachment of the framebuffer with the given index.
- ///
- /// If the `index` is not between `0` and `num_attachments`, then `None` should be returned.
- fn attached_image_view(&self, index: usize) -> Option<&dyn ImageViewAbstract>;
-
- /// Returns the width of the framebuffer in pixels.
- #[inline]
- fn width(&self) -> u32 {
- self.dimensions()[0]
- }
- /// Returns the height of the framebuffer in pixels.
+ /// Returns the attachments of the framebuffer.
#[inline]
- fn height(&self) -> u32 {
- self.dimensions()[1]
+ pub fn attachments(&self) -> &[Arc<dyn ImageViewAbstract>] {
+ &self.attachments
}
- /// Returns the number of layers (or depth) of the framebuffer.
+ /// Returns the extent (width and height) of the framebuffer.
#[inline]
- fn layers(&self) -> u32 {
- self.dimensions()[2]
+ pub fn extent(&self) -> [u32; 2] {
+ self.extent
}
-}
-unsafe impl<T> FramebufferAbstract for T
-where
- T: SafeDeref,
- T::Target: FramebufferAbstract,
-{
+ /// Returns the number of layers of the framebuffer.
#[inline]
- fn inner(&self) -> FramebufferSys {
- FramebufferAbstract::inner(&**self)
- }
-
- #[inline]
- fn dimensions(&self) -> [u32; 3] {
- (**self).dimensions()
- }
-
- #[inline]
- fn render_pass(&self) -> &Arc<RenderPass> {
- (**self).render_pass()
+ pub fn layers(&self) -> u32 {
+ self.layers
}
+ /// Returns the layer ranges for all attachments.
#[inline]
- fn attached_image_view(&self, index: usize) -> Option<&dyn ImageViewAbstract> {
- (**self).attached_image_view(index)
+ pub fn attached_layers_ranges(&self) -> SmallVec<[Range<u32>; 4]> {
+ self.attachments
+ .iter()
+ .map(|img| img.subresource_range().array_layers.clone())
+ .collect()
}
}
-unsafe impl<A> FramebufferAbstract for Framebuffer<A>
-where
- A: AttachmentsList,
-{
- #[inline]
- fn inner(&self) -> FramebufferSys {
- FramebufferSys(self.framebuffer, PhantomData)
- }
-
+impl Drop for Framebuffer {
#[inline]
- fn dimensions(&self) -> [u32; 3] {
- self.dimensions
+ fn drop(&mut self) {
+ unsafe {
+ let fns = self.device().fns();
+ (fns.v1_0.destroy_framebuffer)(self.device().handle(), self.handle, ptr::null());
+ }
}
+}
- #[inline]
- fn render_pass(&self) -> &Arc<RenderPass> {
- &self.render_pass
- }
+unsafe impl VulkanObject for Framebuffer {
+ type Handle = ash::vk::Framebuffer;
#[inline]
- fn attached_image_view(&self, index: usize) -> Option<&dyn ImageViewAbstract> {
- self.resources.as_image_view_access(index)
+ fn handle(&self) -> Self::Handle {
+ self.handle
}
}
-unsafe impl<A> DeviceOwned for Framebuffer<A> {
+unsafe impl DeviceOwned for Framebuffer {
#[inline]
fn device(&self) -> &Arc<Device> {
- &self.device
+ self.render_pass.device()
}
}
-impl<A> Drop for Framebuffer<A> {
- #[inline]
- fn drop(&mut self) {
- unsafe {
- let fns = self.device.fns();
- fns.v1_0.destroy_framebuffer(
- self.device.internal_object(),
- self.framebuffer,
- ptr::null(),
- );
- }
- }
-}
+impl_id_counter!(Framebuffer);
-/// Opaque object that represents the internals of a framebuffer.
-#[derive(Debug, Copy, Clone)]
-pub struct FramebufferSys<'a>(ash::vk::Framebuffer, PhantomData<&'a ()>);
+/// Parameters to create a new `Framebuffer`.
+#[derive(Clone, Debug)]
+pub struct FramebufferCreateInfo {
+ /// The attachment images that are to be used in the framebuffer.
+ ///
+ /// Attachments are specified in the same order as they are defined in the render pass, and
+ /// there must be exactly as many. This implies that the list must be empty if the render pass
+ /// specifies no attachments. Each image must have the correct usages set to be used for the
+ /// types of attachment that the render pass will use it as.
+ ///
+ /// The attachment images must not be smaller than `extent` and `layers`, but can be larger and
+ /// have different sizes from each other. Any leftover parts of an image will be left untouched
+ /// during rendering.
+ ///
+ /// If the render pass has multiview enabled (`views_used` does not return 0), then each
+ /// image must have at least `views_used` array layers.
+ ///
+ /// The default value is empty.
+ pub attachments: Vec<Arc<dyn ImageViewAbstract>>,
-unsafe impl<'a> VulkanObject for FramebufferSys<'a> {
- type Object = ash::vk::Framebuffer;
+ /// The extent (width and height) of the framebuffer.
+ ///
+ /// This must be no larger than the smallest width and height of the images in `attachments`.
+ /// If one of the elements is set to 0, the extent will be calculated automatically from the
+ /// extents of the attachment images to be the largest allowed. At least one attachment image
+ /// must be specified in that case.
+ ///
+ /// The extent, whether automatically calculated or specified explicitly, must not be larger
+ /// than the [`max_framebuffer_width`](crate::device::Properties::max_framebuffer_width) and
+ /// [`max_framebuffer_height`](crate::device::Properties::max_framebuffer_height) limits.
+ ///
+ /// The default value is `[0, 0]`.
+ pub extent: [u32; 2],
+
+ /// The number of layers of the framebuffer.
+ ///
+ /// This must be no larger than the smallest number of array layers of the images in
+ /// `attachments`. If set to 0, the number of layers will be calculated automatically from the
+ /// layer ranges of the attachment images to be the largest allowed. At least one attachment
+ /// image must be specified in that case.
+ ///
+ /// The number of layers, whether automatically calculated or specified explicitly, must not be
+ /// larger than the
+ /// [`max_framebuffer_layers`](crate::device::Properties::max_framebuffer_layers) limit.
+ ///
+ /// If the render pass has multiview enabled (`views_used` does not return 0), then this value
+ /// must be 0 or 1.
+ ///
+ /// The default value is `0`.
+ pub layers: u32,
+
+ pub _ne: crate::NonExhaustive,
+}
+impl Default for FramebufferCreateInfo {
#[inline]
- fn internal_object(&self) -> ash::vk::Framebuffer {
- self.0
+ fn default() -> Self {
+ Self {
+ attachments: Vec::new(),
+ extent: [0, 0],
+ layers: 0,
+ _ne: crate::NonExhaustive(()),
+ }
}
}
-/// Error that can happen when creating a framebuffer object.
+/// Error that can happen when creating a `Framebuffer`.
#[derive(Copy, Clone, Debug)]
pub enum FramebufferCreationError {
/// Out of memory.
OomError(OomError),
- /// The requested dimensions exceed the device's limits.
- DimensionsTooLarge,
- /// The number of minimum layers expected by the render pass exceed the framebuffer layers.
- /// This can happen when the multiview feature is enabled and the specified view or correlation
- /// masks refer to more layers than the framebuffer has.
- InsufficientLayerCount {
- /// Minimum number of layers.
- minimum: u32,
- /// Number of framebuffer layers.
- current: u32,
+
+ /// An attachment image is a 2D image view created from a 3D image, and has a depth/stencil
+ /// format.
+ Attachment2dArrayCompatibleDepthStencil { attachment: u32 },
+
+ /// An attachment image has a non-identity component mapping.
+ AttachmentComponentMappingNotIdentity { attachment: u32 },
+
+ /// The number of attachments doesn't match the number expected by the render pass.
+ AttachmentCountMismatch { provided: u32, required: u32 },
+
+ /// An attachment image has an extent smaller than the provided `extent`.
+ AttachmentExtentTooSmall {
+ attachment: u32,
+ provided: [u32; 2],
+ min: [u32; 2],
},
- /// The attachment has a size that isn't compatible with the requested framebuffer dimensions.
- AttachmentDimensionsIncompatible {
- /// Expected dimensions.
- expected: [u32; 3],
- /// Attachment dimensions.
- obtained: [u32; 3],
+
+ /// An attachment image has a `format` different from what the render pass requires.
+ AttachmentFormatMismatch {
+ attachment: u32,
+ provided: Option<Format>,
+ required: Option<Format>,
},
- /// The number of attachments doesn't match the number expected by the render pass.
- AttachmentsCountMismatch {
- /// Expected number of attachments.
- expected: usize,
- /// Number of attachments that were given.
- obtained: usize,
+
+ /// An attachment image is missing a usage that the render pass requires it to have.
+ AttachmentMissingUsage {
+ attachment: u32,
+ usage: &'static str,
},
- /// One of the images cannot be used as the requested attachment.
- IncompatibleAttachment(IncompatibleRenderPassAttachmentError),
- /// The framebuffer has no attachment and no dimension was specified.
- CantDetermineDimensions,
+
+ /// An attachment image has multiple mip levels.
+ AttachmentMultipleMipLevels { attachment: u32 },
+
+ /// An attachment image has less array layers than the provided `layers`.
+ AttachmentNotEnoughLayers {
+ attachment: u32,
+ provided: u32,
+ min: u32,
+ },
+
+ /// An attachment image has a `samples` different from what the render pass requires.
+ AttachmentSamplesMismatch {
+ attachment: u32,
+ provided: SampleCount,
+ required: SampleCount,
+ },
+
+ /// An attachment image has a `ty` of [`ImageViewType::Dim3d`].
+ AttachmentViewType3d { attachment: u32 },
+
+ /// One of the elements of `extent` is zero, but no attachment images were given to calculate
+ /// the extent from.
+ AutoExtentAttachmentsEmpty,
+
+ /// `layers` is zero, but no attachment images were given to calculate the number of layers
+ /// from.
+ AutoLayersAttachmentsEmpty,
+
+ /// The provided `extent` exceeds the `max_framebuffer_width` or `max_framebuffer_height`
+ /// limits.
+ MaxFramebufferExtentExceeded { provided: [u32; 2], max: [u32; 2] },
+
+ /// The provided `layers` exceeds the `max_framebuffer_layers` limit.
+ MaxFramebufferLayersExceeded { provided: u32, max: u32 },
+
+ /// The render pass has multiview enabled, and an attachment image has less layers than the
+ /// number of views in the render pass.
+ MultiviewAttachmentNotEnoughLayers {
+ attachment: u32,
+ provided: u32,
+ min: u32,
+ },
+
+ /// The render pass has multiview enabled, but `layers` was not 0 or 1.
+ MultiviewLayersInvalid,
}
impl From<OomError> for FramebufferCreationError {
- #[inline]
- fn from(err: OomError) -> FramebufferCreationError {
- FramebufferCreationError::OomError(err)
+ fn from(err: OomError) -> Self {
+ Self::OomError(err)
}
}
-impl error::Error for FramebufferCreationError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- FramebufferCreationError::OomError(ref err) => Some(err),
- FramebufferCreationError::IncompatibleAttachment(ref err) => Some(err),
+impl Error for FramebufferCreationError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::OomError(err) => Some(err),
_ => None,
}
}
}
-impl fmt::Display for FramebufferCreationError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- FramebufferCreationError::OomError(_) => "no memory available",
- FramebufferCreationError::DimensionsTooLarge => {
- "the dimensions of the framebuffer are too large"
- }
- FramebufferCreationError::InsufficientLayerCount { .. } => {
- "the number of minimum layers expected by the render pass exceed the framebuffer layers"
- }
- FramebufferCreationError::AttachmentDimensionsIncompatible { .. } => {
- "the attachment has a size that isn't compatible with the framebuffer dimensions"
- }
- FramebufferCreationError::AttachmentsCountMismatch { .. } => {
- "the number of attachments doesn't match the number expected by the render pass"
- }
- FramebufferCreationError::IncompatibleAttachment(_) => {
- "one of the images cannot be used as the requested attachment"
- }
- FramebufferCreationError::CantDetermineDimensions => {
- "the framebuffer has no attachment and no dimension was specified"
- }
+impl Display for FramebufferCreationError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::OomError(_) => write!(f, "no memory available",),
+ Self::Attachment2dArrayCompatibleDepthStencil { attachment } => write!(
+ f,
+ "attachment image {} is a 2D image view created from a 3D image, and has a \
+ depth/stencil format",
+ attachment,
+ ),
+ Self::AttachmentComponentMappingNotIdentity { attachment } => write!(
+ f,
+ "attachment image {} has a non-identity component mapping",
+ attachment,
+ ),
+ Self::AttachmentCountMismatch { .. } => write!(
+ f,
+ "the number of attachments doesn't match the number expected by the render pass",
+ ),
+ Self::AttachmentExtentTooSmall {
+ attachment,
+ provided,
+ min,
+ } => write!(
+ f,
+ "attachment image {} has an extent ({:?}) smaller than the provided `extent` \
+ ({:?})",
+ attachment, provided, min,
+ ),
+ Self::AttachmentFormatMismatch {
+ attachment,
+ provided,
+ required,
+ } => write!(
+ f,
+ "attachment image {} has a `format` ({:?}) different from what the render pass \
+ requires ({:?})",
+ attachment, provided, required,
+ ),
+ Self::AttachmentMissingUsage { attachment, usage } => write!(
+ f,
+ "attachment image {} is missing usage `{}` that the render pass requires it to \
+ have",
+ attachment, usage,
+ ),
+ Self::AttachmentMultipleMipLevels { attachment } => {
+ write!(f, "attachment image {} has multiple mip levels", attachment)
}
- )
+ Self::AttachmentNotEnoughLayers {
+ attachment,
+ provided,
+ min,
+ } => write!(
+ f,
+ "attachment image {} has less layers ({}) than the provided `layers` ({})",
+ attachment, provided, min,
+ ),
+ Self::AttachmentSamplesMismatch {
+ attachment,
+ provided,
+ required,
+ } => write!(
+ f,
+ "attachment image {} has a `samples` ({:?}) different from what the render pass \
+ requires ({:?})",
+ attachment, provided, required,
+ ),
+ Self::AttachmentViewType3d { attachment } => write!(
+ f,
+ "attachment image {} has a `ty` of `ImageViewType::Dim3d`",
+ attachment,
+ ),
+ Self::AutoExtentAttachmentsEmpty => write!(
+ f,
+ "one of the elements of `extent` is zero, but no attachment images were given to \
+ calculate the extent from",
+ ),
+ Self::AutoLayersAttachmentsEmpty => write!(
+ f,
+ "`layers` is zero, but no attachment images were given to calculate the number of \
+ layers from",
+ ),
+ Self::MaxFramebufferExtentExceeded { provided, max } => write!(
+ f,
+ "the provided `extent` ({:?}) exceeds the `max_framebuffer_width` or \
+ `max_framebuffer_height` limits ({:?})",
+ provided, max,
+ ),
+ Self::MaxFramebufferLayersExceeded { provided, max } => write!(
+ f,
+ "the provided `layers` ({}) exceeds the `max_framebuffer_layers` limit ({})",
+ provided, max,
+ ),
+ Self::MultiviewAttachmentNotEnoughLayers {
+ attachment,
+ provided,
+ min,
+ } => write!(
+ f,
+ "the render pass has multiview enabled, and attachment image {} has less layers \
+ ({}) than the number of views in the render pass ({})",
+ attachment, provided, min,
+ ),
+ Self::MultiviewLayersInvalid => write!(
+ f,
+ "the render pass has multiview enabled, but `layers` was not 0 or 1",
+ ),
+ }
}
}
-impl From<Error> for FramebufferCreationError {
- #[inline]
- fn from(err: Error) -> FramebufferCreationError {
- FramebufferCreationError::from(OomError::from(err))
+impl From<VulkanError> for FramebufferCreationError {
+ fn from(err: VulkanError) -> Self {
+ Self::from(OomError::from(err))
}
}
#[cfg(test)]
mod tests {
- use crate::format::Format;
- use crate::image::attachment::AttachmentImage;
- use crate::image::view::ImageView;
- use crate::render_pass::Framebuffer;
- use crate::render_pass::FramebufferCreationError;
- use crate::render_pass::RenderPass;
- use std::sync::Arc;
+ use crate::{
+ format::Format,
+ image::{attachment::AttachmentImage, view::ImageView},
+ memory::allocator::StandardMemoryAllocator,
+ render_pass::{Framebuffer, FramebufferCreateInfo, FramebufferCreationError, RenderPass},
+ };
#[test]
fn simple_create() {
let (device, _) = gfx_dev_and_queue!();
- let render_pass = Arc::new(
- single_pass_renderpass!(device.clone(),
- attachments: {
- color: {
- load: Clear,
- store: DontCare,
- format: Format::R8G8B8A8Unorm,
- samples: 1,
- }
+ let render_pass = single_pass_renderpass!(
+ device.clone(),
+ attachments: {
+ color: {
+ load: Clear,
+ store: DontCare,
+ format: Format::R8G8B8A8_UNORM,
+ samples: 1,
},
- pass: {
- color: [color],
- depth_stencil: {}
- }
- )
- .unwrap(),
- );
+ },
+ pass: {
+ color: [color],
+ depth_stencil: {},
+ },
+ )
+ .unwrap();
- let view = ImageView::new(
- AttachmentImage::new(device.clone(), [1024, 768], Format::R8G8B8A8Unorm).unwrap(),
+ let memory_allocator = StandardMemoryAllocator::new_default(device);
+ let view = ImageView::new_default(
+ AttachmentImage::new(&memory_allocator, [1024, 768], Format::R8G8B8A8_UNORM).unwrap(),
+ )
+ .unwrap();
+ let _ = Framebuffer::new(
+ render_pass,
+ FramebufferCreateInfo {
+ attachments: vec![view],
+ ..Default::default()
+ },
)
.unwrap();
- let _ = Framebuffer::start(render_pass)
- .add(view)
- .unwrap()
- .build()
- .unwrap();
}
#[test]
fn check_device_limits() {
let (device, _) = gfx_dev_and_queue!();
- let rp = Arc::new(RenderPass::empty_single_pass(device).unwrap());
- let res = Framebuffer::with_dimensions(rp, [0xffffffff, 0xffffffff, 0xffffffff]).build();
+ let render_pass = RenderPass::empty_single_pass(device).unwrap();
+ let res = Framebuffer::new(
+ render_pass.clone(),
+ FramebufferCreateInfo {
+ extent: [0xffffffff, 0xffffffff],
+ layers: 1,
+ ..Default::default()
+ },
+ );
match res {
- Err(FramebufferCreationError::DimensionsTooLarge) => (),
+ Err(FramebufferCreationError::MaxFramebufferExtentExceeded { .. }) => (),
+ _ => panic!(),
+ }
+
+ let res = Framebuffer::new(
+ render_pass,
+ FramebufferCreateInfo {
+ extent: [1, 1],
+ layers: 0xffffffff,
+ ..Default::default()
+ },
+ );
+
+ match res {
+ Err(FramebufferCreationError::MaxFramebufferLayersExceeded { .. }) => (),
_ => panic!(),
}
}
@@ -658,31 +788,37 @@ mod tests {
fn attachment_format_mismatch() {
let (device, _) = gfx_dev_and_queue!();
- let render_pass = Arc::new(
- single_pass_renderpass!(device.clone(),
- attachments: {
- color: {
- load: Clear,
- store: DontCare,
- format: Format::R8G8B8A8Unorm,
- samples: 1,
- }
+ let render_pass = single_pass_renderpass!(
+ device.clone(),
+ attachments: {
+ color: {
+ load: Clear,
+ store: DontCare,
+ format: Format::R8G8B8A8_UNORM,
+ samples: 1,
},
- pass: {
- color: [color],
- depth_stencil: {}
- }
- )
- .unwrap(),
- );
+ },
+ pass: {
+ color: [color],
+ depth_stencil: {},
+ },
+ )
+ .unwrap();
- let view = ImageView::new(
- AttachmentImage::new(device.clone(), [1024, 768], Format::R8Unorm).unwrap(),
+ let memory_allocator = StandardMemoryAllocator::new_default(device);
+ let view = ImageView::new_default(
+ AttachmentImage::new(&memory_allocator, [1024, 768], Format::R8_UNORM).unwrap(),
)
.unwrap();
- match Framebuffer::start(render_pass).add(view) {
- Err(FramebufferCreationError::IncompatibleAttachment(_)) => (),
+ match Framebuffer::new(
+ render_pass,
+ FramebufferCreateInfo {
+ attachments: vec![view],
+ ..Default::default()
+ },
+ ) {
+ Err(FramebufferCreationError::AttachmentFormatMismatch { .. }) => (),
_ => panic!(),
}
}
@@ -693,120 +829,78 @@ mod tests {
fn attachment_dims_larger_than_specified_valid() {
let (device, _) = gfx_dev_and_queue!();
- let render_pass = Arc::new(
- single_pass_renderpass!(device.clone(),
- attachments: {
- color: {
- load: Clear,
- store: DontCare,
- format: Format::R8G8B8A8Unorm,
- samples: 1,
- }
+ let render_pass = single_pass_renderpass!(
+ device.clone(),
+ attachments: {
+ color: {
+ load: Clear,
+ store: DontCare,
+ format: Format::R8G8B8A8_UNORM,
+ samples: 1,
},
- pass: {
- color: [color],
- depth_stencil: {}
- }
- )
- .unwrap(),
- );
-
- let view = ImageView::new(
- AttachmentImage::new(device.clone(), [600, 600], Format::R8G8B8A8Unorm).unwrap(),
+ },
+ pass: {
+ color: [color],
+ depth_stencil: {},
+ },
)
.unwrap();
- let _ = Framebuffer::with_dimensions(render_pass, [512, 512, 1])
- .add(view)
- .unwrap()
- .build()
- .unwrap();
- }
-
- #[test]
- fn attachment_dims_smaller_than_specified() {
- let (device, _) = gfx_dev_and_queue!();
-
- let render_pass = Arc::new(
- single_pass_renderpass!(device.clone(),
- attachments: {
- color: {
- load: Clear,
- store: DontCare,
- format: Format::R8G8B8A8Unorm,
- samples: 1,
- }
- },
- pass: {
- color: [color],
- depth_stencil: {}
- }
- )
- .unwrap(),
- );
-
- let view = ImageView::new(
- AttachmentImage::new(device.clone(), [512, 700], Format::R8G8B8A8Unorm).unwrap(),
+ let memory_allocator = StandardMemoryAllocator::new_default(device);
+ let view = ImageView::new_default(
+ AttachmentImage::new(&memory_allocator, [600, 600], Format::R8G8B8A8_UNORM).unwrap(),
)
.unwrap();
- match Framebuffer::with_dimensions(render_pass, [600, 600, 1]).add(view) {
- Err(FramebufferCreationError::AttachmentDimensionsIncompatible {
- expected,
- obtained,
- }) => {
- assert_eq!(expected, [600, 600, 1]);
- assert_eq!(obtained, [512, 700, 1]);
- }
- _ => panic!(),
- }
+ let _ = Framebuffer::new(
+ render_pass,
+ FramebufferCreateInfo {
+ attachments: vec![view],
+ extent: [512, 512],
+ layers: 1,
+ ..Default::default()
+ },
+ )
+ .unwrap();
}
#[test]
- fn multi_attachments_dims_not_identical() {
+ fn attachment_dims_smaller_than_specified() {
let (device, _) = gfx_dev_and_queue!();
- let render_pass = Arc::new(
- single_pass_renderpass!(device.clone(),
- attachments: {
- a: {
- load: Clear,
- store: DontCare,
- format: Format::R8G8B8A8Unorm,
- samples: 1,
- },
- b: {
- load: Clear,
- store: DontCare,
- format: Format::R8G8B8A8Unorm,
- samples: 1,
- }
+ let render_pass = single_pass_renderpass!(
+ device.clone(),
+ attachments: {
+ color: {
+ load: Clear,
+ store: DontCare,
+ format: Format::R8G8B8A8_UNORM,
+ samples: 1,
},
- pass: {
- color: [a, b],
- depth_stencil: {}
- }
- )
- .unwrap(),
- );
-
- let a = ImageView::new(
- AttachmentImage::new(device.clone(), [512, 512], Format::R8G8B8A8Unorm).unwrap(),
+ },
+ pass: {
+ color: [color],
+ depth_stencil: {},
+ },
)
.unwrap();
- let b = ImageView::new(
- AttachmentImage::new(device.clone(), [512, 513], Format::R8G8B8A8Unorm).unwrap(),
+
+ let memory_allocator = StandardMemoryAllocator::new_default(device);
+ let view = ImageView::new_default(
+ AttachmentImage::new(&memory_allocator, [512, 700], Format::R8G8B8A8_UNORM).unwrap(),
)
.unwrap();
- match Framebuffer::start(render_pass).add(a).unwrap().add(b) {
- Err(FramebufferCreationError::AttachmentDimensionsIncompatible {
- expected,
- obtained,
- }) => {
- assert_eq!(expected, [512, 512, 1]);
- assert_eq!(obtained, [512, 513, 1]);
- }
+ match Framebuffer::new(
+ render_pass,
+ FramebufferCreateInfo {
+ attachments: vec![view],
+ extent: [600, 600],
+ layers: 1,
+ ..Default::default()
+ },
+ ) {
+ Err(FramebufferCreationError::AttachmentExtentTooSmall { .. }) => (),
_ => panic!(),
}
}
@@ -815,49 +909,50 @@ mod tests {
fn multi_attachments_auto_smaller() {
let (device, _) = gfx_dev_and_queue!();
- let render_pass = Arc::new(
- single_pass_renderpass!(device.clone(),
- attachments: {
- a: {
- load: Clear,
- store: DontCare,
- format: Format::R8G8B8A8Unorm,
- samples: 1,
- },
- b: {
- load: Clear,
- store: DontCare,
- format: Format::R8G8B8A8Unorm,
- samples: 1,
- }
+ let render_pass = single_pass_renderpass!(
+ device.clone(),
+ attachments: {
+ a: {
+ load: Clear,
+ store: DontCare,
+ format: Format::R8G8B8A8_UNORM,
+ samples: 1,
},
- pass: {
- color: [a, b],
- depth_stencil: {}
- }
- )
- .unwrap(),
- );
+ b: {
+ load: Clear,
+ store: DontCare,
+ format: Format::R8G8B8A8_UNORM,
+ samples: 1,
+ },
+ },
+ pass: {
+ color: [a, b],
+ depth_stencil: {},
+ },
+ )
+ .unwrap();
- let a = ImageView::new(
- AttachmentImage::new(device.clone(), [256, 512], Format::R8G8B8A8Unorm).unwrap(),
+ let memory_allocator = StandardMemoryAllocator::new_default(device);
+ let a = ImageView::new_default(
+ AttachmentImage::new(&memory_allocator, [256, 512], Format::R8G8B8A8_UNORM).unwrap(),
)
.unwrap();
- let b = ImageView::new(
- AttachmentImage::new(device.clone(), [512, 128], Format::R8G8B8A8Unorm).unwrap(),
+ let b = ImageView::new_default(
+ AttachmentImage::new(&memory_allocator, [512, 128], Format::R8G8B8A8_UNORM).unwrap(),
)
.unwrap();
- let fb = Framebuffer::with_intersecting_dimensions(render_pass)
- .add(a)
- .unwrap()
- .add(b)
- .unwrap()
- .build()
- .unwrap();
+ let framebuffer = Framebuffer::new(
+ render_pass,
+ FramebufferCreateInfo {
+ attachments: vec![a, b],
+ ..Default::default()
+ },
+ )
+ .unwrap();
- match (fb.width(), fb.height(), fb.layers()) {
- (256, 128, 1) => (),
+ match (framebuffer.extent(), framebuffer.layers()) {
+ ([256, 128], 1) => (),
_ => panic!(),
}
}
@@ -866,44 +961,47 @@ mod tests {
fn not_enough_attachments() {
let (device, _) = gfx_dev_and_queue!();
- let render_pass = Arc::new(
- single_pass_renderpass!(device.clone(),
- attachments: {
- a: {
- load: Clear,
- store: DontCare,
- format: Format::R8G8B8A8Unorm,
- samples: 1,
- },
- b: {
- load: Clear,
- store: DontCare,
- format: Format::R8G8B8A8Unorm,
- samples: 1,
- }
+ let render_pass = single_pass_renderpass!(
+ device.clone(),
+ attachments: {
+ a: {
+ load: Clear,
+ store: DontCare,
+ format: Format::R8G8B8A8_UNORM,
+ samples: 1,
},
- pass: {
- color: [a, b],
- depth_stencil: {}
- }
- )
- .unwrap(),
- );
+ b: {
+ load: Clear,
+ store: DontCare,
+ format: Format::R8G8B8A8_UNORM,
+ samples: 1,
+ },
+ },
+ pass: {
+ color: [a, b],
+ depth_stencil: {},
+ },
+ )
+ .unwrap();
- let view = ImageView::new(
- AttachmentImage::new(device.clone(), [256, 512], Format::R8G8B8A8Unorm).unwrap(),
+ let memory_allocator = StandardMemoryAllocator::new_default(device);
+ let view = ImageView::new_default(
+ AttachmentImage::new(&memory_allocator, [256, 512], Format::R8G8B8A8_UNORM).unwrap(),
)
.unwrap();
- let res = Framebuffer::with_intersecting_dimensions(render_pass)
- .add(view)
- .unwrap()
- .build();
+ let res = Framebuffer::new(
+ render_pass,
+ FramebufferCreateInfo {
+ attachments: vec![view],
+ ..Default::default()
+ },
+ );
match res {
- Err(FramebufferCreationError::AttachmentsCountMismatch {
- expected: 2,
- obtained: 1,
+ Err(FramebufferCreationError::AttachmentCountMismatch {
+ required: 2,
+ provided: 1,
}) => (),
_ => panic!(),
}
@@ -913,42 +1011,45 @@ mod tests {
fn too_many_attachments() {
let (device, _) = gfx_dev_and_queue!();
- let render_pass = Arc::new(
- single_pass_renderpass!(device.clone(),
- attachments: {
- a: {
- load: Clear,
- store: DontCare,
- format: Format::R8G8B8A8Unorm,
- samples: 1,
- }
+ let render_pass = single_pass_renderpass!(
+ device.clone(),
+ attachments: {
+ a: {
+ load: Clear,
+ store: DontCare,
+ format: Format::R8G8B8A8_UNORM,
+ samples: 1,
},
- pass: {
- color: [a],
- depth_stencil: {}
- }
- )
- .unwrap(),
- );
+ },
+ pass: {
+ color: [a],
+ depth_stencil: {},
+ },
+ )
+ .unwrap();
- let a = ImageView::new(
- AttachmentImage::new(device.clone(), [256, 512], Format::R8G8B8A8Unorm).unwrap(),
+ let memory_allocator = StandardMemoryAllocator::new_default(device);
+ let a = ImageView::new_default(
+ AttachmentImage::new(&memory_allocator, [256, 512], Format::R8G8B8A8_UNORM).unwrap(),
)
.unwrap();
- let b = ImageView::new(
- AttachmentImage::new(device.clone(), [256, 512], Format::R8G8B8A8Unorm).unwrap(),
+ let b = ImageView::new_default(
+ AttachmentImage::new(&memory_allocator, [256, 512], Format::R8G8B8A8_UNORM).unwrap(),
)
.unwrap();
- let res = Framebuffer::with_intersecting_dimensions(render_pass)
- .add(a)
- .unwrap()
- .add(b);
+ let res = Framebuffer::new(
+ render_pass,
+ FramebufferCreateInfo {
+ attachments: vec![a, b],
+ ..Default::default()
+ },
+ );
match res {
- Err(FramebufferCreationError::AttachmentsCountMismatch {
- expected: 1,
- obtained: 2,
+ Err(FramebufferCreationError::AttachmentCountMismatch {
+ required: 1,
+ provided: 2,
}) => (),
_ => panic!(),
}
@@ -958,32 +1059,26 @@ mod tests {
fn empty_working() {
let (device, _) = gfx_dev_and_queue!();
- let rp = Arc::new(RenderPass::empty_single_pass(device).unwrap());
- let _ = Framebuffer::with_dimensions(rp, [512, 512, 1])
- .build()
- .unwrap();
+ let render_pass = RenderPass::empty_single_pass(device).unwrap();
+ let _ = Framebuffer::new(
+ render_pass,
+ FramebufferCreateInfo {
+ extent: [512, 512],
+ layers: 1,
+ ..Default::default()
+ },
+ )
+ .unwrap();
}
#[test]
fn cant_determine_dimensions_auto() {
let (device, _) = gfx_dev_and_queue!();
- let rp = Arc::new(RenderPass::empty_single_pass(device).unwrap());
- let res = Framebuffer::start(rp).build();
- match res {
- Err(FramebufferCreationError::CantDetermineDimensions) => (),
- _ => panic!(),
- }
- }
-
- #[test]
- fn cant_determine_dimensions_intersect() {
- let (device, _) = gfx_dev_and_queue!();
-
- let rp = Arc::new(RenderPass::empty_single_pass(device).unwrap());
- let res = Framebuffer::with_intersecting_dimensions(rp).build();
+ let render_pass = RenderPass::empty_single_pass(device).unwrap();
+ let res = Framebuffer::new(render_pass, FramebufferCreateInfo::default());
match res {
- Err(FramebufferCreationError::CantDetermineDimensions) => (),
+ Err(FramebufferCreationError::AutoExtentAttachmentsEmpty) => (),
_ => panic!(),
}
}
diff --git a/src/render_pass/macros.rs b/src/render_pass/macros.rs
index d73a204..86f6631 100644
--- a/src/render_pass/macros.rs
+++ b/src/render_pass/macros.rs
@@ -14,10 +14,11 @@ macro_rules! single_pass_renderpass {
$device:expr,
attachments: { $($a:tt)* },
pass: {
- color: [$($color_atch:ident),*],
- depth_stencil: {$($depth_atch:ident)*}$(,)*
- $(resolve: [$($resolve_atch:ident),*])*$(,)*
- }
+ color: [$($color_atch:ident),* $(,)?],
+ depth_stencil: {$($depth_atch:ident)?}
+ $(,resolve: [$($resolve_atch:ident),* $(,)?])*
+ $(,)*
+ } $(,)?
) => (
$crate::ordered_passes_renderpass!(
$device,
@@ -45,82 +46,96 @@ macro_rules! ordered_passes_renderpass {
load: $load:ident,
store: $store:ident,
format: $format:expr,
- samples: $samples:expr,
- $(initial_layout: $init_layout:expr,)*
- $(final_layout: $final_layout:expr,)*
+ samples: $samples:expr
+ $(,initial_layout: $init_layout:expr)?
+ $(,final_layout: $final_layout:expr)?
+ $(,)?
}
- ),*
+ ),* $(,)?
},
passes: [
$(
{
- color: [$($color_atch:ident),*],
- depth_stencil: {$($depth_atch:ident)*},
- input: [$($input_atch:ident),*]$(,)*
- $(resolve: [$($resolve_atch:ident),*])*$(,)*
+ color: [$($color_atch:ident),* $(,)?],
+ depth_stencil: {$($depth_atch:ident)* $(,)?},
+ input: [$($input_atch:ident),* $(,)?]
+ $(,resolve: [$($resolve_atch:ident),* $(,)?])?
+ $(,)*
}
- ),*
- ]
+ ),* $(,)?
+ ] $(,)?
) => ({
use $crate::render_pass::RenderPass;
- let desc = {
- use $crate::render_pass::AttachmentDesc;
- use $crate::render_pass::RenderPassDesc;
- use $crate::render_pass::SubpassDependencyDesc;
- use $crate::render_pass::SubpassDesc;
- use $crate::image::ImageLayout;
- use $crate::sync::AccessFlags;
- use $crate::sync::PipelineStages;
- use std::convert::TryInto;
-
+ let create_info = {
+ #[allow(unused)]
let mut attachment_num = 0;
$(
let $atch_name = attachment_num;
attachment_num += 1;
)*
- let mut layouts: Vec<(Option<ImageLayout>, Option<ImageLayout>)> = vec![(None, None); attachment_num];
+ #[allow(unused)]
+ let mut layouts: Vec<(
+ Option<$crate::image::ImageLayout>,
+ Option<$crate::image::ImageLayout>
+ )> = vec![(None, None); attachment_num as usize];
let subpasses = vec![
$({
- let desc = SubpassDesc {
+ let desc = $crate::render_pass::SubpassDescription {
color_attachments: vec![
$({
- let layout = &mut layouts[$color_atch];
- layout.0 = layout.0.or(Some(ImageLayout::ColorAttachmentOptimal));
- layout.1 = Some(ImageLayout::ColorAttachmentOptimal);
+ let layout = &mut layouts[$color_atch as usize];
+ layout.0 = layout.0.or(Some($crate::image::ImageLayout::ColorAttachmentOptimal));
+ layout.1 = Some($crate::image::ImageLayout::ColorAttachmentOptimal);
- ($color_atch, ImageLayout::ColorAttachmentOptimal)
+ Some($crate::render_pass::AttachmentReference {
+ attachment: $color_atch,
+ layout: $crate::image::ImageLayout::ColorAttachmentOptimal,
+ ..Default::default()
+ })
}),*
],
- depth_stencil: {
- let depth: Option<(usize, ImageLayout)> = None;
+ depth_stencil_attachment: {
+ let depth: Option<$crate::render_pass::AttachmentReference> = None;
$(
- let layout = &mut layouts[$depth_atch];
- layout.1 = Some(ImageLayout::DepthStencilAttachmentOptimal);
+ let layout = &mut layouts[$depth_atch as usize];
+ layout.1 = Some($crate::image::ImageLayout::DepthStencilAttachmentOptimal);
layout.0 = layout.0.or(layout.1);
- let depth = Some(($depth_atch, ImageLayout::DepthStencilAttachmentOptimal));
+ let depth = Some($crate::render_pass::AttachmentReference {
+ attachment: $depth_atch,
+ layout: $crate::image::ImageLayout::DepthStencilAttachmentOptimal,
+ ..Default::default()
+ });
)*
depth
},
input_attachments: vec![
$({
- let layout = &mut layouts[$input_atch];
- layout.1 = Some(ImageLayout::ShaderReadOnlyOptimal);
+ let layout = &mut layouts[$input_atch as usize];
+ layout.1 = Some($crate::image::ImageLayout::ShaderReadOnlyOptimal);
layout.0 = layout.0.or(layout.1);
- ($input_atch, ImageLayout::ShaderReadOnlyOptimal)
+ Some($crate::render_pass::AttachmentReference {
+ attachment: $input_atch,
+ layout: $crate::image::ImageLayout::ShaderReadOnlyOptimal,
+ ..Default::default()
+ })
}),*
],
resolve_attachments: vec![
$($({
- let layout = &mut layouts[$resolve_atch];
- layout.1 = Some(ImageLayout::TransferDstOptimal);
+ let layout = &mut layouts[$resolve_atch as usize];
+ layout.1 = Some($crate::image::ImageLayout::TransferDstOptimal);
layout.0 = layout.0.or(layout.1);
- ($resolve_atch, ImageLayout::TransferDstOptimal)
+ Some($crate::render_pass::AttachmentReference {
+ attachment: $resolve_atch,
+ layout: $crate::image::ImageLayout::TransferDstOptimal,
+ ..Default::default()
+ })
}),*)*
],
preserve_attachments: (0 .. attachment_num).filter(|&a| {
@@ -129,7 +144,8 @@ macro_rules! ordered_passes_renderpass {
$(if a == $input_atch { return false; })*
$($(if a == $resolve_atch { return false; })*)*
true
- }).collect()
+ }).collect(),
+ ..Default::default()
};
assert!(desc.resolve_attachments.is_empty() ||
@@ -138,39 +154,43 @@ macro_rules! ordered_passes_renderpass {
}),*
];
- let dependencies = (0..subpasses.len().saturating_sub(1))
+ let dependencies: Vec<_> = (0..subpasses.len().saturating_sub(1) as u32)
.map(|id| {
- SubpassDependencyDesc {
- source_subpass: id,
- destination_subpass: id + 1,
- source_stages: PipelineStages {
- all_graphics: true,
- ..PipelineStages::none()
- }, // TODO: correct values
- destination_stages: PipelineStages {
- all_graphics: true,
- ..PipelineStages::none()
- }, // TODO: correct values
- source_access: AccessFlags::all(), // TODO: correct values
- destination_access: AccessFlags::all(), // TODO: correct values
- by_region: true, // TODO: correct values
+ // TODO: correct values
+ let src_stages = $crate::sync::PipelineStages::ALL_GRAPHICS;
+ let dst_stages = $crate::sync::PipelineStages::ALL_GRAPHICS;
+ let src_access = $crate::sync::AccessFlags::MEMORY_READ
+ | $crate::sync::AccessFlags::MEMORY_WRITE;
+ let dst_access = $crate::sync::AccessFlags::MEMORY_READ
+ | $crate::sync::AccessFlags::MEMORY_WRITE;
+
+ $crate::render_pass::SubpassDependency {
+ src_subpass: id.into(),
+ dst_subpass: (id + 1).into(),
+ src_stages,
+ dst_stages,
+ src_access,
+ dst_access,
+ // TODO: correct values
+ dependency_flags: $crate::sync::DependencyFlags::BY_REGION,
+ ..Default::default()
}
})
.collect();
let attachments = vec![
$({
- let layout = &mut layouts[$atch_name];
+ let layout = &mut layouts[$atch_name as usize];
$(layout.0 = Some($init_layout);)*
$(layout.1 = Some($final_layout);)*
- AttachmentDesc {
- format: $format,
- samples: $samples.try_into().unwrap(),
- load: $crate::render_pass::LoadOp::$load,
- store: $crate::render_pass::StoreOp::$store,
- stencil_load: $crate::render_pass::LoadOp::$load,
- stencil_store: $crate::render_pass::StoreOp::$store,
+ $crate::render_pass::AttachmentDescription {
+ format: Some($format),
+ samples: $crate::image::SampleCount::try_from($samples).unwrap(),
+ load_op: $crate::render_pass::LoadOp::$load,
+ store_op: $crate::render_pass::StoreOp::$store,
+ stencil_load_op: $crate::render_pass::LoadOp::$load,
+ stencil_store_op: $crate::render_pass::StoreOp::$store,
initial_layout: layout.0.expect(
format!(
"Attachment {} is missing initial_layout, this is normally \
@@ -189,18 +209,20 @@ macro_rules! ordered_passes_renderpass {
)
.as_ref(),
),
+ ..Default::default()
}
}),*
];
- RenderPassDesc::new(
+ $crate::render_pass::RenderPassCreateInfo {
attachments,
subpasses,
dependencies,
- )
+ ..Default::default()
+ }
};
- RenderPass::new($device, desc)
+ RenderPass::new($device, create_info)
});
}
@@ -211,26 +233,27 @@ mod tests {
#[test]
fn single_pass_resolve() {
let (device, _) = gfx_dev_and_queue!();
- let _ = single_pass_renderpass!(device.clone(),
+ let _ = single_pass_renderpass!(
+ device,
attachments: {
a: {
load: Clear,
store: DontCare,
- format: Format::R8G8B8A8Unorm,
+ format: Format::R8G8B8A8_UNORM,
samples: 4,
},
b: {
load: DontCare,
store: Store,
- format: Format::R8G8B8A8Unorm,
+ format: Format::R8G8B8A8_UNORM,
samples: 1,
- }
+ },
},
pass: {
color: [a],
depth_stencil: {},
resolve: [b],
- }
+ },
)
.unwrap();
}
diff --git a/src/render_pass/mod.rs b/src/render_pass/mod.rs
index 62fedaa..35f5786 100644
--- a/src/render_pass/mod.rs
+++ b/src/render_pass/mod.rs
@@ -25,32 +25,1288 @@
//! Consequently you can create graphics pipelines from a render pass object alone.
//! A `Framebuffer` object is only needed when you actually add draw commands to a command buffer.
-pub use self::attachments_list::AttachmentsList;
-pub use self::compat_atch::ensure_image_view_compatible;
-pub use self::compat_atch::IncompatibleRenderPassAttachmentError;
-pub use self::desc::AttachmentDesc;
-pub use self::desc::LoadOp;
-pub use self::desc::MultiviewDesc;
-pub use self::desc::RenderPassDesc;
-pub use self::desc::ResolveMode;
-pub use self::desc::ResolveModes;
-pub use self::desc::StoreOp;
-pub use self::desc::SubpassDependencyDesc;
-pub use self::desc::SubpassDesc;
-pub use self::framebuffer::Framebuffer;
-pub use self::framebuffer::FramebufferAbstract;
-pub use self::framebuffer::FramebufferBuilder;
-pub use self::framebuffer::FramebufferCreationError;
-pub use self::framebuffer::FramebufferSys;
-pub use self::render_pass::RenderPass;
-pub use self::render_pass::RenderPassCreationError;
-pub use self::render_pass::RenderPassSys;
-pub use self::render_pass::Subpass;
+pub use self::{
+ create::RenderPassCreationError,
+ framebuffer::{Framebuffer, FramebufferCreateInfo, FramebufferCreationError},
+};
+use crate::{
+ device::{Device, DeviceOwned},
+ format::Format,
+ image::{ImageAspects, ImageLayout, SampleCount},
+ macros::{impl_id_counter, vulkan_bitflags_enum, vulkan_enum},
+ shader::ShaderInterface,
+ sync::{AccessFlags, DependencyFlags, PipelineStages},
+ Version, VulkanObject,
+};
+use std::{cmp::max, mem::MaybeUninit, num::NonZeroU64, ptr, sync::Arc};
#[macro_use]
mod macros;
-mod attachments_list;
-mod compat_atch;
-mod desc;
+mod create;
mod framebuffer;
-mod render_pass;
+
+/// An object representing the discrete steps in which rendering is done.
+///
+/// A render pass in Vulkan is made up of three parts:
+/// - A list of attachments, which are image views that are inputs, outputs or intermediate stages
+/// in the rendering process.
+/// - One or more subpasses, which are the steps in which the rendering process, takes place,
+/// and the attachments that are used for each step.
+/// - Dependencies, which describe how the input and output data of each subpass is to be passed
+/// from one subpass to the next.
+///
+/// ```
+/// use vulkano::render_pass::{RenderPass, RenderPassCreateInfo, SubpassDescription};
+///
+/// # let device: std::sync::Arc<vulkano::device::Device> = return;
+/// let render_pass = RenderPass::new(
+/// device.clone(),
+/// RenderPassCreateInfo {
+/// subpasses: vec![SubpassDescription::default()],
+/// ..Default::default()
+/// },
+/// ).unwrap();
+/// ```
+///
+/// This example creates a render pass with no attachment and one single subpass that doesn't draw
+/// on anything. While it's sometimes useful, most of the time it's not what you want.
+///
+/// The easiest way to create a "real" render pass is to use the `single_pass_renderpass!` macro.
+///
+/// ```
+/// # #[macro_use] extern crate vulkano;
+/// # fn main() {
+/// # let device: std::sync::Arc<vulkano::device::Device> = return;
+/// use vulkano::format::Format;
+///
+/// let render_pass = single_pass_renderpass!(
+/// device.clone(),
+/// attachments: {
+/// // `foo` is a custom name we give to the first and only attachment.
+/// foo: {
+/// load: Clear,
+/// store: Store,
+/// format: Format::R8G8B8A8_UNORM,
+/// samples: 1,
+/// },
+/// },
+/// pass: {
+/// color: [foo], // Repeat the attachment name here.
+/// depth_stencil: {},
+/// },
+/// )
+/// .unwrap();
+/// # }
+/// ```
+///
+/// See the documentation of the macro for more details. TODO: put link here
+#[derive(Debug)]
+pub struct RenderPass {
+ handle: ash::vk::RenderPass,
+ device: Arc<Device>,
+ id: NonZeroU64,
+
+ attachments: Vec<AttachmentDescription>,
+ subpasses: Vec<SubpassDescription>,
+ dependencies: Vec<SubpassDependency>,
+ correlated_view_masks: Vec<u32>,
+
+ attachment_uses: Vec<Option<AttachmentUse>>,
+ granularity: [u32; 2],
+ views_used: u32,
+}
+
+impl RenderPass {
+ /// Creates a new `RenderPass`.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `create_info.subpasses` is empty.
+ /// - Panics if any element of `create_info.attachments` has a `format` of `None`.
+ pub fn new(
+ device: Arc<Device>,
+ mut create_info: RenderPassCreateInfo,
+ ) -> Result<Arc<RenderPass>, RenderPassCreationError> {
+ Self::validate(&device, &mut create_info)?;
+
+ let handle = unsafe {
+ if device.api_version() >= Version::V1_2
+ || device.enabled_extensions().khr_create_renderpass2
+ {
+ Self::create_v2(&device, &create_info)?
+ } else {
+ Self::create_v1(&device, &create_info)?
+ }
+ };
+
+ unsafe { Ok(Self::from_handle(device, handle, create_info)) }
+ }
+
+ /// Builds a render pass with one subpass and no attachment.
+ ///
+ /// This method is useful for quick tests.
+ #[inline]
+ pub fn empty_single_pass(
+ device: Arc<Device>,
+ ) -> Result<Arc<RenderPass>, RenderPassCreationError> {
+ RenderPass::new(
+ device,
+ RenderPassCreateInfo {
+ subpasses: vec![SubpassDescription::default()],
+ ..Default::default()
+ },
+ )
+ }
+
+ /// Creates a new `RenderPass` from a raw object handle.
+ ///
+ /// # Safety
+ ///
+ /// - `handle` must be a valid Vulkan object handle created from `device`.
+ /// - `create_info` must match the info used to create the object.
+ #[inline]
+ pub unsafe fn from_handle(
+ device: Arc<Device>,
+ handle: ash::vk::RenderPass,
+ create_info: RenderPassCreateInfo,
+ ) -> Arc<RenderPass> {
+ let RenderPassCreateInfo {
+ attachments,
+ subpasses,
+ dependencies,
+ correlated_view_masks,
+ _ne: _,
+ } = create_info;
+
+ let granularity = Self::get_granularity(&device, handle);
+ let mut attachment_uses: Vec<Option<AttachmentUse>> = vec![None; attachments.len()];
+ let mut views_used = 0;
+
+ for (index, subpass_desc) in subpasses.iter().enumerate() {
+ let index = index as u32;
+ let &SubpassDescription {
+ view_mask,
+ ref input_attachments,
+ ref color_attachments,
+ ref resolve_attachments,
+ ref depth_stencil_attachment,
+ ..
+ } = subpass_desc;
+
+ for atch_ref in (input_attachments.iter().flatten())
+ .chain(color_attachments.iter().flatten())
+ .chain(resolve_attachments.iter().flatten())
+ .chain(depth_stencil_attachment.iter())
+ {
+ match &mut attachment_uses[atch_ref.attachment as usize] {
+ Some(attachment_use) => attachment_use.last_use_subpass = index,
+ attachment_use @ None => {
+ *attachment_use = Some(AttachmentUse {
+ first_use_subpass: index,
+ last_use_subpass: index,
+ })
+ }
+ }
+ }
+
+ views_used = max(views_used, u32::BITS - view_mask.leading_zeros());
+ }
+
+ Arc::new(RenderPass {
+ handle,
+ device,
+ id: Self::next_id(),
+
+ attachments,
+ subpasses,
+ dependencies,
+ correlated_view_masks,
+
+ attachment_uses,
+ granularity,
+ views_used,
+ })
+ }
+
+ unsafe fn get_granularity(device: &Arc<Device>, handle: ash::vk::RenderPass) -> [u32; 2] {
+ let fns = device.fns();
+ let mut out = MaybeUninit::uninit();
+ (fns.v1_0.get_render_area_granularity)(device.handle(), handle, out.as_mut_ptr());
+
+ let out = out.assume_init();
+ debug_assert_ne!(out.width, 0);
+ debug_assert_ne!(out.height, 0);
+ [out.width, out.height]
+ }
+
+ /// Returns the attachments of the render pass.
+ #[inline]
+ pub fn attachments(&self) -> &[AttachmentDescription] {
+ &self.attachments
+ }
+
+ /// Returns the subpasses of the render pass.
+ #[inline]
+ pub fn subpasses(&self) -> &[SubpassDescription] {
+ &self.subpasses
+ }
+
+ /// Returns the dependencies of the render pass.
+ #[inline]
+ pub fn dependencies(&self) -> &[SubpassDependency] {
+ &self.dependencies
+ }
+
+ /// Returns the correlated view masks of the render pass.
+ #[inline]
+ pub fn correlated_view_masks(&self) -> &[u32] {
+ &self.correlated_view_masks
+ }
+
+ /// If the render pass has multiview enabled, returns the number of views used by the render
+ /// pass. Returns 0 if multiview is not enabled.
+ #[inline]
+ pub fn views_used(&self) -> u32 {
+ self.views_used
+ }
+
+ /// Returns the granularity of this render pass.
+ ///
+ /// If the render area of a render pass in a command buffer is a multiple of this granularity,
+ /// then the performance will be optimal. Performances are always optimal for render areas
+ /// that cover the whole framebuffer.
+ #[inline]
+ pub fn granularity(&self) -> [u32; 2] {
+ self.granularity
+ }
+
+ /// Returns the first subpass of the render pass.
+ #[inline]
+ pub fn first_subpass(self: Arc<Self>) -> Subpass {
+ Subpass {
+ render_pass: self,
+ subpass_id: 0, // Guaranteed to exist
+ }
+ }
+
+ /// Returns `true` if this render pass is compatible with the other render pass,
+ /// as defined in the [`Render Pass Compatibility` section of the Vulkan specs](https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap8.html#renderpass-compatibility).
+ pub fn is_compatible_with(&self, other: &RenderPass) -> bool {
+ if self == other {
+ return true;
+ }
+
+ let Self {
+ handle: _,
+ device: _,
+ id: _,
+ attachments: attachments1,
+ subpasses: subpasses1,
+ dependencies: dependencies1,
+ correlated_view_masks: correlated_view_masks1,
+ attachment_uses: _,
+ granularity: _,
+ views_used: _,
+ } = self;
+ let Self {
+ handle: _,
+ device: _,
+ id: _,
+ attachments: attachments2,
+ subpasses: subpasses2,
+ dependencies: dependencies2,
+ attachment_uses: _,
+ correlated_view_masks: correlated_view_masks2,
+ granularity: _,
+ views_used: _,
+ } = other;
+
+ if attachments1.len() != attachments2.len() {
+ return false;
+ }
+
+ if !attachments1
+ .iter()
+ .zip(attachments2)
+ .all(|(attachment_desc1, attachment_desc2)| {
+ let AttachmentDescription {
+ format: format1,
+ samples: samples1,
+ load_op: _,
+ store_op: _,
+ stencil_load_op: _,
+ stencil_store_op: _,
+ initial_layout: _,
+ final_layout: _,
+ _ne: _,
+ } = attachment_desc1;
+ let AttachmentDescription {
+ format: format2,
+ samples: samples2,
+ load_op: _,
+ store_op: _,
+ stencil_load_op: _,
+ stencil_store_op: _,
+ initial_layout: _,
+ final_layout: _,
+ _ne: _,
+ } = attachment_desc2;
+
+ format1 == format2 && samples1 == samples2
+ })
+ {
+ return false;
+ }
+
+ let are_atch_refs_compatible = |atch_ref1, atch_ref2| match (atch_ref1, atch_ref2) {
+ (None, None) => true,
+ (Some(atch_ref1), Some(atch_ref2)) => {
+ let &AttachmentReference {
+ attachment: attachment1,
+ layout: _,
+ aspects: aspects1,
+ _ne: _,
+ } = atch_ref1;
+ let AttachmentDescription {
+ format: format1,
+ samples: samples1,
+ load_op: _,
+ store_op: _,
+ stencil_load_op: _,
+ stencil_store_op: _,
+ initial_layout: _,
+ final_layout: _,
+ _ne: _,
+ } = &attachments1[attachment1 as usize];
+
+ let &AttachmentReference {
+ attachment: attachment2,
+ layout: _,
+ aspects: aspects2,
+ _ne: _,
+ } = atch_ref2;
+ let AttachmentDescription {
+ format: format2,
+ samples: samples2,
+ load_op: _,
+ store_op: _,
+ stencil_load_op: _,
+ stencil_store_op: _,
+ initial_layout: _,
+ final_layout: _,
+ _ne: _,
+ } = &attachments2[attachment2 as usize];
+
+ format1 == format2 && samples1 == samples2 && aspects1 == aspects2
+ }
+ _ => false,
+ };
+
+ if subpasses1.len() != subpasses2.len() {
+ return false;
+ }
+
+ if !(subpasses1.iter())
+ .zip(subpasses2.iter())
+ .all(|(subpass1, subpass2)| {
+ let SubpassDescription {
+ view_mask: view_mask1,
+ input_attachments: input_attachments1,
+ color_attachments: color_attachments1,
+ resolve_attachments: resolve_attachments1,
+ depth_stencil_attachment: depth_stencil_attachment1,
+ preserve_attachments: _,
+ _ne: _,
+ } = subpass1;
+ let SubpassDescription {
+ view_mask: view_mask2,
+ input_attachments: input_attachments2,
+ color_attachments: color_attachments2,
+ resolve_attachments: resolve_attachments2,
+ depth_stencil_attachment: depth_stencil_attachment2,
+ preserve_attachments: _,
+ _ne: _,
+ } = subpass2;
+
+ if !(0..max(input_attachments1.len(), input_attachments2.len())).all(|i| {
+ are_atch_refs_compatible(
+ input_attachments1.get(i).and_then(|x| x.as_ref()),
+ input_attachments2.get(i).and_then(|x| x.as_ref()),
+ )
+ }) {
+ return false;
+ }
+
+ if !(0..max(color_attachments1.len(), color_attachments2.len())).all(|i| {
+ are_atch_refs_compatible(
+ color_attachments1.get(i).and_then(|x| x.as_ref()),
+ color_attachments2.get(i).and_then(|x| x.as_ref()),
+ )
+ }) {
+ return false;
+ }
+
+ if subpasses1.len() > 1
+ && !(0..max(resolve_attachments1.len(), resolve_attachments2.len())).all(|i| {
+ are_atch_refs_compatible(
+ resolve_attachments1.get(i).and_then(|x| x.as_ref()),
+ resolve_attachments2.get(i).and_then(|x| x.as_ref()),
+ )
+ })
+ {
+ return false;
+ }
+
+ if !are_atch_refs_compatible(
+ depth_stencil_attachment1.as_ref(),
+ depth_stencil_attachment2.as_ref(),
+ ) {
+ return false;
+ }
+
+ if view_mask1 != view_mask2 {
+ return false;
+ }
+
+ true
+ })
+ {
+ return false;
+ }
+
+ if dependencies1 != dependencies2 {
+ return false;
+ }
+
+ if correlated_view_masks1 != correlated_view_masks2 {
+ return false;
+ }
+
+ true
+ }
+
+ /// Returns `true` if the subpass of this description is compatible with the shader's fragment
+ /// output definition.
+ pub fn is_compatible_with_shader(
+ &self,
+ subpass: u32,
+ shader_interface: &ShaderInterface,
+ ) -> bool {
+ let subpass_descr = match self.subpasses.get(subpass as usize) {
+ Some(s) => s,
+ None => return false,
+ };
+
+ for element in shader_interface.elements() {
+ assert!(!element.ty.is_64bit); // TODO: implement
+ let location_range = element.location..element.location + element.ty.num_locations();
+
+ for location in location_range {
+ let attachment_id = match subpass_descr.color_attachments.get(location as usize) {
+ Some(Some(atch_ref)) => atch_ref.attachment,
+ _ => return false,
+ };
+
+ let _attachment_desc = &self.attachments[attachment_id as usize];
+
+ // FIXME: compare formats depending on the number of components and data type
+ /*if attachment_desc.format != element.format {
+ return false;
+ }*/
+ }
+ }
+
+ true
+ }
+}
+
+impl Drop for RenderPass {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ let fns = self.device.fns();
+ (fns.v1_0.destroy_render_pass)(self.device.handle(), self.handle, ptr::null());
+ }
+ }
+}
+
+unsafe impl VulkanObject for RenderPass {
+ type Handle = ash::vk::RenderPass;
+
+ #[inline]
+ fn handle(&self) -> Self::Handle {
+ self.handle
+ }
+}
+
+unsafe impl DeviceOwned for RenderPass {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+}
+
+impl_id_counter!(RenderPass);
+
+/// Represents a subpass within a `RenderPass` object.
+///
+/// This struct doesn't correspond to anything in Vulkan. It is simply an equivalent to a
+/// tuple of a render pass and subpass index. Contrary to a tuple, however, the existence of the
+/// subpass is checked when the object is created. When you have a `Subpass` you are guaranteed
+/// that the given subpass does exist.
+#[derive(Debug, Clone)]
+pub struct Subpass {
+ render_pass: Arc<RenderPass>,
+ subpass_id: u32,
+}
+
+impl Subpass {
+ /// Returns a handle that represents a subpass of a render pass.
+ #[inline]
+ pub fn from(render_pass: Arc<RenderPass>, id: u32) -> Option<Subpass> {
+ if (id as usize) < render_pass.subpasses().len() {
+ Some(Subpass {
+ render_pass,
+ subpass_id: id,
+ })
+ } else {
+ None
+ }
+ }
+
+ /// Returns the render pass of this subpass.
+ #[inline]
+ pub fn render_pass(&self) -> &Arc<RenderPass> {
+ &self.render_pass
+ }
+
+ /// Returns the index of this subpass within the renderpass.
+ #[inline]
+ pub fn index(&self) -> u32 {
+ self.subpass_id
+ }
+
+ /// Returns the subpass description for this subpass.
+ #[inline]
+ pub fn subpass_desc(&self) -> &SubpassDescription {
+ &self.render_pass.subpasses()[self.subpass_id as usize]
+ }
+
+ /// Returns whether this subpass is the last one in the render pass. If `true` is returned,
+ /// calling `next_subpass` will panic.
+ #[inline]
+ pub fn is_last_subpass(&self) -> bool {
+ self.subpass_id as usize == self.render_pass.subpasses().len() - 1
+ }
+
+ /// Advances to the next subpass after this one.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if there are no more render passes.
+ #[inline]
+ pub fn next_subpass(&mut self) {
+ let next_id = self.subpass_id + 1;
+ assert!((next_id as usize) < self.render_pass.subpasses().len());
+ self.subpass_id = next_id;
+ }
+
+ #[inline]
+ fn attachment_desc(&self, atch_num: u32) -> &AttachmentDescription {
+ &self.render_pass.attachments()[atch_num as usize]
+ }
+
+ /// Returns the number of color attachments in this subpass.
+ #[inline]
+ pub fn num_color_attachments(&self) -> u32 {
+ self.subpass_desc().color_attachments.len() as u32
+ }
+
+ /// Returns true if the subpass has a depth attachment or a depth-stencil attachment.
+ #[inline]
+ pub fn has_depth(&self) -> bool {
+ let subpass_desc = self.subpass_desc();
+ let atch_num = match &subpass_desc.depth_stencil_attachment {
+ Some(atch_ref) => atch_ref.attachment,
+ None => return false,
+ };
+
+ self.attachment_desc(atch_num)
+ .format
+ .map_or(false, |f| f.aspects().intersects(ImageAspects::DEPTH))
+ }
+
+ /// Returns true if the subpass has a depth attachment or a depth-stencil attachment whose
+ /// layout does not have a read-only depth layout.
+ #[inline]
+ pub fn has_writable_depth(&self) -> bool {
+ let subpass_desc = self.subpass_desc();
+ let atch_num = match &subpass_desc.depth_stencil_attachment {
+ Some(atch_ref) => {
+ if matches!(
+ atch_ref.layout,
+ ImageLayout::DepthStencilReadOnlyOptimal
+ | ImageLayout::DepthReadOnlyStencilAttachmentOptimal
+ ) {
+ return false;
+ }
+ atch_ref.attachment
+ }
+ None => return false,
+ };
+
+ self.attachment_desc(atch_num)
+ .format
+ .map_or(false, |f| f.aspects().intersects(ImageAspects::DEPTH))
+ }
+
+ /// Returns true if the subpass has a stencil attachment or a depth-stencil attachment.
+ #[inline]
+ pub fn has_stencil(&self) -> bool {
+ let subpass_desc = self.subpass_desc();
+ let atch_num = match &subpass_desc.depth_stencil_attachment {
+ Some(atch_ref) => atch_ref.attachment,
+ None => return false,
+ };
+
+ self.attachment_desc(atch_num)
+ .format
+ .map_or(false, |f| f.aspects().intersects(ImageAspects::STENCIL))
+ }
+
+ /// Returns true if the subpass has a stencil attachment or a depth-stencil attachment whose
+ /// layout does not have a read-only stencil layout.
+ #[inline]
+ pub fn has_writable_stencil(&self) -> bool {
+ let subpass_desc = self.subpass_desc();
+
+ let atch_num = match &subpass_desc.depth_stencil_attachment {
+ Some(atch_ref) => {
+ if matches!(
+ atch_ref.layout,
+ ImageLayout::DepthStencilReadOnlyOptimal
+ | ImageLayout::DepthAttachmentStencilReadOnlyOptimal
+ ) {
+ return false;
+ }
+ atch_ref.attachment
+ }
+ None => return false,
+ };
+
+ self.attachment_desc(atch_num)
+ .format
+ .map_or(false, |f| f.aspects().intersects(ImageAspects::STENCIL))
+ }
+
+ /// Returns the number of samples in the color and/or depth/stencil attachments. Returns `None`
+ /// if there is no such attachment in this subpass.
+ #[inline]
+ pub fn num_samples(&self) -> Option<SampleCount> {
+ let subpass_desc = self.subpass_desc();
+
+ // TODO: chain input attachments as well?
+ subpass_desc
+ .color_attachments
+ .iter()
+ .flatten()
+ .chain(subpass_desc.depth_stencil_attachment.iter())
+ .filter_map(|atch_ref| {
+ self.render_pass
+ .attachments()
+ .get(atch_ref.attachment as usize)
+ })
+ .next()
+ .map(|atch_desc| atch_desc.samples)
+ }
+
+ /// Returns `true` if this subpass is compatible with the fragment output definition.
+ // TODO: return proper error
+ #[inline]
+ pub fn is_compatible_with(&self, shader_interface: &ShaderInterface) -> bool {
+ self.render_pass
+ .is_compatible_with_shader(self.subpass_id, shader_interface)
+ }
+
+ pub(crate) fn load_op(&self, attachment_index: u32) -> Option<LoadOp> {
+ self.render_pass.attachment_uses[attachment_index as usize]
+ .as_ref()
+ .and_then(|attachment_use| {
+ (attachment_use.first_use_subpass == self.subpass_id)
+ .then(|| self.render_pass.attachments[attachment_index as usize].load_op)
+ })
+ }
+
+ pub(crate) fn store_op(&self, attachment_index: u32) -> Option<StoreOp> {
+ self.render_pass.attachment_uses[attachment_index as usize]
+ .as_ref()
+ .and_then(|attachment_use| {
+ (attachment_use.last_use_subpass == self.subpass_id)
+ .then(|| self.render_pass.attachments[attachment_index as usize].store_op)
+ })
+ }
+
+ pub(crate) fn stencil_load_op(&self, attachment_index: u32) -> Option<LoadOp> {
+ self.render_pass.attachment_uses[attachment_index as usize]
+ .as_ref()
+ .and_then(|attachment_use| {
+ (attachment_use.first_use_subpass == self.subpass_id).then(|| {
+ self.render_pass.attachments[attachment_index as usize].stencil_load_op
+ })
+ })
+ }
+
+ pub(crate) fn stencil_store_op(&self, attachment_index: u32) -> Option<StoreOp> {
+ self.render_pass.attachment_uses[attachment_index as usize]
+ .as_ref()
+ .and_then(|attachment_use| {
+ (attachment_use.last_use_subpass == self.subpass_id).then(|| {
+ self.render_pass.attachments[attachment_index as usize].stencil_store_op
+ })
+ })
+ }
+}
+
+impl From<Subpass> for (Arc<RenderPass>, u32) {
+ #[inline]
+ fn from(value: Subpass) -> (Arc<RenderPass>, u32) {
+ (value.render_pass, value.subpass_id)
+ }
+}
+
+/// Parameters to create a new `RenderPass`.
+#[derive(Clone, Debug)]
+pub struct RenderPassCreateInfo {
+ /// The attachments available for the render pass.
+ ///
+ /// The default value is empty.
+ pub attachments: Vec<AttachmentDescription>,
+
+ /// The subpasses that make up this render pass.
+ ///
+ /// A render pass must contain at least one subpass.
+ ///
+ /// The default value is empty, which must be overridden.
+ pub subpasses: Vec<SubpassDescription>,
+
+ /// The dependencies between subpasses.
+ ///
+ /// The default value is empty.
+ pub dependencies: Vec<SubpassDependency>,
+
+ /// If multiview rendering is being used (the subpasses have a nonzero `view_mask`),
+ /// this specifies sets of views that may be more efficient to render concurrently, for example
+ /// because they show the same geometry from almost the same perspective. This is an
+ /// optimization hint to the implementation, and does not affect the final result.
+ ///
+ /// The value is a bitmask, so that that for example `0b11` means that the first two views are
+ /// highly correlated, and `0b101` means the first and third view are highly correlated. Each
+ /// view bit must appear in at most one element of the list.
+ ///
+ /// If multiview rendering is not being used, the value must be empty.
+ ///
+ /// The default value is empty.
+ pub correlated_view_masks: Vec<u32>,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for RenderPassCreateInfo {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ attachments: Vec::new(),
+ subpasses: Vec::new(),
+ dependencies: Vec::new(),
+ correlated_view_masks: Vec::new(),
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// Describes an attachment that will be used in a render pass.
+#[derive(Clone, Copy, Debug)]
+pub struct AttachmentDescription {
+ /// The format of the image that is going to be bound.
+ ///
+ /// The default value is `None`, which must be overridden.
+ pub format: Option<Format>,
+
+ /// The number of samples of the image that is going to be bound.
+ ///
+ /// The default value is [`SampleCount::Sample1`].
+ pub samples: SampleCount,
+
+ /// What the implementation should do with the attachment at the start of the subpass that first
+ /// uses it.
+ ///
+ /// The default value is [`LoadOp::DontCare`].
+ pub load_op: LoadOp,
+
+ /// What the implementation should do with the attachment at the end of the subpass that last
+ /// uses it.
+ ///
+ /// The default value is [`StoreOp::DontCare`].
+ pub store_op: StoreOp,
+
+ /// The equivalent of `load_op` for the stencil component of the attachment, if any. Irrelevant
+ /// if there is no stencil component.
+ ///
+ /// The default value is [`LoadOp::DontCare`].
+ pub stencil_load_op: LoadOp,
+
+ /// The equivalent of `store_op` for the stencil component of the attachment, if any. Irrelevant
+ /// if there is no stencil component.
+ ///
+ /// The default value is [`StoreOp::DontCare`].
+ pub stencil_store_op: StoreOp,
+
+ /// The layout that the image must in at the start of the render pass.
+ ///
+ /// The vulkano library will automatically switch to the correct layout if necessary, but it
+ /// is more efficient to set this to the correct value.
+ ///
+ /// The default value is [`ImageLayout::Undefined`], which must be overridden.
+ pub initial_layout: ImageLayout,
+
+ /// The layout that the image will be transitioned to at the end of the render pass.
+ ///
+ /// The default value is [`ImageLayout::Undefined`], which must be overridden.
+ pub final_layout: ImageLayout,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for AttachmentDescription {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ format: None,
+ samples: SampleCount::Sample1,
+ load_op: LoadOp::DontCare,
+ store_op: StoreOp::DontCare,
+ stencil_load_op: LoadOp::DontCare,
+ stencil_store_op: StoreOp::DontCare,
+ initial_layout: ImageLayout::Undefined,
+ final_layout: ImageLayout::Undefined,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// Describes one of the subpasses of a render pass.
+///
+/// A subpass can use zero or more attachments of various types. Attachment types of which there can
+/// be multiple are listed in a `Vec` in this structure. The index in these `Vec`s corresponds to
+/// the index used for that attachment type in the shader.
+///
+/// If a particular index is not used in the shader, it can be set to `None` in this structure.
+/// This is useful if an unused index needs to be skipped but a higher index needs to be specified.
+///
+/// If an attachment is used more than once, i.e. a given `AttachmentReference::attachment` occurs
+/// more than once in the `SubpassDescription`, then their `AttachmentReference::layout` must be
+/// the same as well.
+#[derive(Debug, Clone)]
+pub struct SubpassDescription {
+ /// If not `0`, enables multiview rendering, and specifies the view indices that are rendered to
+ /// in this subpass. The value is a bitmask, so that that for example `0b11` will draw to the
+ /// first two views and `0b101` will draw to the first and third view.
+ ///
+ /// If set to a nonzero value, it must be nonzero for all subpasses in the render pass, and the
+ /// [`multiview`](crate::device::Features::multiview) feature must be enabled on the device.
+ ///
+ /// The default value is `0`.
+ pub view_mask: u32,
+
+ /// The attachments of the render pass that are to be used as input attachments in this subpass.
+ ///
+ /// If an attachment is used here for the first time in this render pass, and it's is not also
+ /// used as a color or depth/stencil attachment in this subpass, then the attachment's `load_op`
+ /// must not be [`LoadOp::Clear`].
+ ///
+ /// The default value is empty.
+ pub input_attachments: Vec<Option<AttachmentReference>>,
+
+ /// The attachments of the render pass that are to be used as color attachments in this subpass.
+ ///
+ /// The number of color attachments must be less than the
+ /// [`max_color_attachments`](crate::device::Properties::max_color_attachments) limit of the
+ /// physical device. All color attachments must have the same `samples` value.
+ ///
+ /// The default value is empty.
+ pub color_attachments: Vec<Option<AttachmentReference>>,
+
+ /// The attachments of the render pass that are to be used as resolve attachments in this
+ /// subpass.
+ ///
+ /// This list must either be empty or have the same length as `color_attachments`. If it's not
+ /// empty, then each resolve attachment is paired with the color attachment of the same index.
+ /// The resolve attachments must all have a `samples` value of [`SampleCount::Sample1`], while
+ /// the color attachments must have a `samples` value other than [`SampleCount::Sample1`].
+ /// Each resolve attachment must have the same `format` as the corresponding color attachment.
+ ///
+ /// The default value is empty.
+ pub resolve_attachments: Vec<Option<AttachmentReference>>,
+
+ /// The single attachment of the render pass that is to be used as depth-stencil attachment in
+ /// this subpass.
+ ///
+ /// If set to `Some`, the referenced attachment must have the same `samples` value as those in
+ /// `color_attachments`.
+ ///
+ /// The default value is `None`.
+ pub depth_stencil_attachment: Option<AttachmentReference>,
+
+ /// The indices of attachments of the render pass that will be preserved during this subpass.
+ ///
+ /// The referenced attachments must not be used as any other attachment type in the subpass.
+ ///
+ /// The default value is empty.
+ pub preserve_attachments: Vec<u32>,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for SubpassDescription {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ view_mask: 0,
+ color_attachments: Vec::new(),
+ depth_stencil_attachment: None,
+ input_attachments: Vec::new(),
+ resolve_attachments: Vec::new(),
+ preserve_attachments: Vec::new(),
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// A reference in a subpass description to a particular attachment of the render pass.
+#[derive(Clone, Debug)]
+pub struct AttachmentReference {
+ /// The number of the attachment being referred to.
+ ///
+ /// The default value is `0`.
+ pub attachment: u32,
+
+ /// The image layout that the attachment should be transitioned to at the start of the subpass.
+ ///
+ /// The layout is restricted by the type of attachment that an attachment is being used as. A
+ /// full listing of allowed layouts per type can be found in
+ /// [the Vulkan specification](https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap8.html#attachment-type-imagelayout).
+ ///
+ /// The default value is [`ImageLayout::Undefined`], which must be overridden.
+ pub layout: ImageLayout,
+
+ /// For references to input attachments, the aspects of the image that should be selected.
+ /// For attachment types other than input attachments, the value must be empty.
+ ///
+ /// If empty, all aspects available in the input attachment's `format` will be selected.
+ /// If any fields are set, they must be aspects that are available in the `format` of the
+ /// attachment.
+ ///
+ /// If the value is neither empty nor identical to the aspects of the `format`, the device API
+ /// version must be at least 1.1, or either the
+ /// [`khr_create_renderpass2`](crate::device::DeviceExtensions::khr_create_renderpass2) or the
+ /// [`khr_maintenance2`](crate::device::DeviceExtensions::khr_maintenance2) extensions must be
+ /// enabled on the device.
+ ///
+ /// The default value is [`ImageAspects::empty()`].
+ pub aspects: ImageAspects,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for AttachmentReference {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ attachment: 0,
+ layout: ImageLayout::Undefined,
+ aspects: ImageAspects::empty(),
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// A dependency between two subpasses of a render pass.
+///
+/// The implementation is allowed to change the order of the subpasses within a render pass, unless
+/// you specify that there exists a dependency between two subpasses (ie. the result of one will be
+/// used as the input of another one). Subpass dependencies work similar to pipeline barriers,
+/// except that they operate on whole subpasses instead of individual images.
+///
+/// If `src_subpass` and `dst_subpass` are equal, then this specifies a
+/// [subpass self-dependency](https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap7.html#synchronization-pipeline-barriers-subpass-self-dependencies).
+/// The `src_stages` must all be
+/// [logically earlier in the pipeline](https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap7.html#synchronization-pipeline-stages-order)
+/// than the `dst_stages`, and if they both contain a
+/// [framebuffer-space stage](https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap7.html#synchronization-framebuffer-regions),
+/// then `by_region` must be activated.
+///
+/// If `src_subpass` or `dst_subpass` are set to `None`, this specifies an external
+/// dependency. An external dependency specifies a dependency on commands that were submitted before
+/// the render pass instance began (for `src_subpass`), or on commands that will be submitted
+/// after the render pass instance ends (for `dst_subpass`). The values must not both be
+/// `None`.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct SubpassDependency {
+ /// The index of the subpass that writes the data that `dst_subpass` is going to use.
+ ///
+ /// `None` specifies an external dependency.
+ ///
+ /// The default value is `None`.
+ pub src_subpass: Option<u32>,
+
+ /// The index of the subpass that reads the data that `src_subpass` wrote.
+ ///
+ /// `None` specifies an external dependency.
+ ///
+ /// The default value is `None`.
+ pub dst_subpass: Option<u32>,
+
+ /// The pipeline stages that must be finished on `src_subpass` before the
+ /// `dst_stages` of `dst_subpass` can start.
+ ///
+ /// The default value is [`PipelineStages::empty()`].
+ pub src_stages: PipelineStages,
+
+ /// The pipeline stages of `dst_subpass` that must wait for the `src_stages` of
+ /// `src_subpass` to be finished. Stages that are earlier than the stages specified here can
+ /// start before the `src_stages` are finished.
+ ///
+ /// The default value is [`PipelineStages::empty()`].
+ pub dst_stages: PipelineStages,
+
+ /// The way `src_subpass` accesses the attachments on which we depend.
+ ///
+ /// The default value is [`AccessFlags::empty()`].
+ pub src_access: AccessFlags,
+
+ /// The way `dst_subpass` accesses the attachments on which we depend.
+ ///
+ /// The default value is [`AccessFlags::empty()`].
+ pub dst_access: AccessFlags,
+
+ /// Dependency flags that modify behavior of the subpass dependency.
+ ///
+ /// If a `src_subpass` equals `dst_subpass`, then:
+ /// - If `src_stages` and `dst_stages` both contain framebuffer-space stages,
+ /// this must include [`BY_REGION`].
+ /// - If the subpass's `view_mask` has more than one view,
+ /// this must include [`VIEW_LOCAL`].
+ ///
+ /// The default value is [`DependencyFlags::empty()`].
+ ///
+ /// [`BY_REGION`]: crate::sync::DependencyFlags::BY_REGION
+ /// [`VIEW_LOCAL`]: crate::sync::DependencyFlags::VIEW_LOCAL
+ pub dependency_flags: DependencyFlags,
+
+ /// If multiview rendering is being used (the subpasses have a nonzero `view_mask`), and
+ /// `dependency_flags` includes [`VIEW_LOCAL`], specifies an offset relative to the view index
+ /// of `dst_subpass`: each view `d` in `dst_subpass` depends on view `d + view_offset` in
+ /// `src_subpass`. If the source view index does not exist, the dependency is ignored for
+ /// that view.
+ ///
+ /// If `dependency_flags` does not include [`VIEW_LOCAL`], or if `src_subpass` and
+ /// `dst_subpass` are the same, the value must be `0`.
+ ///
+ /// The default value is `0`.
+ ///
+ /// [`VIEW_LOCAL`]: crate::sync::DependencyFlags::VIEW_LOCAL
+ pub view_offset: i32,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for SubpassDependency {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ src_subpass: None,
+ dst_subpass: None,
+ src_stages: PipelineStages::empty(),
+ dst_stages: PipelineStages::empty(),
+ src_access: AccessFlags::empty(),
+ dst_access: AccessFlags::empty(),
+ dependency_flags: DependencyFlags::empty(),
+ view_offset: 0,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// Describes what the implementation should do with an attachment at the start of the subpass.
+ LoadOp = AttachmentLoadOp(i32);
+
+ /// The content of the attachment will be loaded from memory. This is what you want if you want
+ /// to draw over something existing.
+ ///
+ /// While this is the most intuitive option, it is also the slowest because it uses a lot of
+ /// memory bandwidth.
+ Load = LOAD,
+
+ /// The content of the attachment will be filled by the implementation with a uniform value
+ /// that you must provide when you start drawing.
+ ///
+ /// This is what you usually use at the start of a frame, in order to reset the content of
+ /// the color, depth and/or stencil buffers.
+ Clear = CLEAR,
+
+ /// The attachment will have undefined content.
+ ///
+ /// This is what you should use for attachments that you intend to entirely cover with draw
+ /// commands.
+ /// If you are going to fill the attachment with a uniform value, it is better to use `Clear`
+ /// instead.
+ DontCare = DONT_CARE,
+
+ /* TODO: enable
+ // TODO: document
+ None = NONE_EXT {
+ device_extensions: [ext_load_store_op_none],
+ },*/
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// Describes what the implementation should do with an attachment after all the subpasses have
+ /// completed.
+ StoreOp = AttachmentStoreOp(i32);
+
+ /// The attachment will be stored. This is what you usually want.
+ ///
+ /// While this is the most intuitive option, it is also slower than `DontCare` because it can
+ /// take time to write the data back to memory.
+ Store = STORE,
+
+ /// What happens is implementation-specific.
+ ///
+ /// This is purely an optimization compared to `Store`. The implementation doesn't need to copy
+ /// from the internal cache to the memory, which saves memory bandwidth.
+ ///
+ /// This doesn't mean that the data won't be copied, as an implementation is also free to not
+ /// use a cache and write the output directly in memory. In other words, the content of the
+ /// image will be undefined.
+ DontCare = DONT_CARE,
+
+ /* TODO: enable
+ // TODO: document
+ None = NONE {
+ api_version: V1_3,
+ device_extensions: [khr_dynamic_rendering, ext_load_store_op_none, qcom_render_pass_store_ops],
+ },*/
+}
+
+vulkan_bitflags_enum! {
+ #[non_exhaustive]
+
+ /// A set of [`ResolveMode`] values.
+ ResolveModes,
+
+ /// Possible resolve modes for attachments.
+ ResolveMode,
+
+ = ResolveModeFlags(u32);
+
+ /// The resolved sample is taken from sample number zero, the other samples are ignored.
+ ///
+ /// This mode is supported for depth and stencil formats, and for color images with an integer
+ /// format.
+ SAMPLE_ZERO, SampleZero = SAMPLE_ZERO,
+
+ /// The resolved sample is calculated from the average of the samples.
+ ///
+ /// This mode is supported for depth formats, and for color images with a non-integer format.
+ AVERAGE, Average = AVERAGE,
+
+ /// The resolved sample is calculated from the minimum of the samples.
+ ///
+ /// This mode is supported for depth and stencil formats only.
+ MIN, Min = MIN,
+
+ /// The resolved sample is calculated from the maximum of the samples.
+ ///
+ /// This mode is supported for depth and stencil formats only.
+ MAX, Max = MAX,
+}
+
+#[derive(Clone, Copy, Debug)]
+pub(crate) struct AttachmentUse {
+ first_use_subpass: u32,
+ last_use_subpass: u32,
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::{
+ format::Format,
+ render_pass::{RenderPass, RenderPassCreationError},
+ };
+
+ #[test]
+ fn empty() {
+ let (device, _) = gfx_dev_and_queue!();
+ let _ = RenderPass::empty_single_pass(device).unwrap();
+ }
+
+ #[test]
+ fn too_many_color_atch() {
+ let (device, _) = gfx_dev_and_queue!();
+
+ if device.physical_device().properties().max_color_attachments >= 10 {
+ return; // test ignored
+ }
+
+ let rp = single_pass_renderpass!(
+ device,
+ attachments: {
+ a1: { load: Clear, store: DontCare, format: Format::R8G8B8A8_UNORM, samples: 1, },
+ a2: { load: Clear, store: DontCare, format: Format::R8G8B8A8_UNORM, samples: 1, },
+ a3: { load: Clear, store: DontCare, format: Format::R8G8B8A8_UNORM, samples: 1, },
+ a4: { load: Clear, store: DontCare, format: Format::R8G8B8A8_UNORM, samples: 1, },
+ a5: { load: Clear, store: DontCare, format: Format::R8G8B8A8_UNORM, samples: 1, },
+ a6: { load: Clear, store: DontCare, format: Format::R8G8B8A8_UNORM, samples: 1, },
+ a7: { load: Clear, store: DontCare, format: Format::R8G8B8A8_UNORM, samples: 1, },
+ a8: { load: Clear, store: DontCare, format: Format::R8G8B8A8_UNORM, samples: 1, },
+ a9: { load: Clear, store: DontCare, format: Format::R8G8B8A8_UNORM, samples: 1, },
+ a10: { load: Clear, store: DontCare, format: Format::R8G8B8A8_UNORM, samples: 1, },
+ },
+ pass: {
+ color: [a1, a2, a3, a4, a5, a6, a7, a8, a9, a10],
+ depth_stencil: {},
+ },
+ );
+
+ match rp {
+ Err(RenderPassCreationError::SubpassMaxColorAttachmentsExceeded { .. }) => (),
+ _ => panic!(),
+ }
+ }
+
+ #[test]
+ fn non_zero_granularity() {
+ let (device, _) = gfx_dev_and_queue!();
+
+ let rp = single_pass_renderpass!(
+ device,
+ attachments: {
+ a: { load: Clear, store: DontCare, format: Format::R8G8B8A8_UNORM, samples: 1, },
+ },
+ pass: {
+ color: [a],
+ depth_stencil: {},
+ },
+ )
+ .unwrap();
+
+ let granularity = rp.granularity();
+ assert_ne!(granularity[0], 0);
+ assert_ne!(granularity[1], 0);
+ }
+}
diff --git a/src/render_pass/render_pass.rs b/src/render_pass/render_pass.rs
deleted file mode 100644
index 629dc8e..0000000
--- a/src/render_pass/render_pass.rs
+++ /dev/null
@@ -1,911 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::check_errors;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::format::FormatTy;
-use crate::image::ImageLayout;
-use crate::image::SampleCount;
-use crate::pipeline::shader::ShaderInterface;
-use crate::render_pass::AttachmentDesc;
-use crate::render_pass::LoadOp;
-use crate::render_pass::RenderPassDesc;
-use crate::render_pass::SubpassDesc;
-use crate::Error;
-use crate::OomError;
-use crate::VulkanObject;
-use smallvec::SmallVec;
-use std::error;
-use std::fmt;
-use std::marker::PhantomData;
-use std::mem::MaybeUninit;
-use std::ptr;
-use std::sync::Arc;
-use std::sync::Mutex;
-
-/// An object representing the discrete steps in which rendering is done.
-///
-/// A render pass in Vulkan is made up of three parts:
-/// - A list of attachments, which are image views that are inputs, outputs or intermediate stages
-/// in the rendering process.
-/// - One or more subpasses, which are the steps in which the rendering process, takes place,
-/// and the attachments that are used for each step.
-/// - Dependencies, which describe how the input and output data of each subpass is to be passed
-/// from one subpass to the next.
-///
-/// In order to create a render pass, you must create a `RenderPassDesc` object that describes the
-/// render pass, then pass it to `RenderPass::new`.
-///
-/// ```
-/// use vulkano::render_pass::RenderPass;
-/// use vulkano::render_pass::RenderPassDesc;
-///
-/// # let device: std::sync::Arc<vulkano::device::Device> = return;
-/// let desc = RenderPassDesc::empty();
-/// let render_pass = RenderPass::new(device.clone(), desc).unwrap();
-/// ```
-///
-/// This example creates a render pass with no attachment and one single subpass that doesn't draw
-/// on anything. While it's sometimes useful, most of the time it's not what you want.
-///
-/// The easiest way to create a "real" render pass is to use the `single_pass_renderpass!` macro.
-///
-/// ```
-/// # #[macro_use] extern crate vulkano;
-/// # fn main() {
-/// # let device: std::sync::Arc<vulkano::device::Device> = return;
-/// use vulkano::format::Format;
-///
-/// let render_pass = single_pass_renderpass!(device.clone(),
-/// attachments: {
-/// // `foo` is a custom name we give to the first and only attachment.
-/// foo: {
-/// load: Clear,
-/// store: Store,
-/// format: Format::R8G8B8A8Unorm,
-/// samples: 1,
-/// }
-/// },
-/// pass: {
-/// color: [foo], // Repeat the attachment name here.
-/// depth_stencil: {}
-/// }
-/// ).unwrap();
-/// # }
-/// ```
-///
-/// See the documentation of the macro for more details. TODO: put link here
-pub struct RenderPass {
- // The internal Vulkan object.
- render_pass: ash::vk::RenderPass,
-
- // Device this render pass was created from.
- device: Arc<Device>,
-
- // Description of the render pass.
- desc: RenderPassDesc,
-
- // Cache of the granularity of the render pass.
- granularity: Mutex<Option<[u32; 2]>>,
-}
-
-impl RenderPass {
- /// Builds a new render pass.
- ///
- /// # Panic
- ///
- /// - Can panic if it detects some violations in the restrictions. Only inexpensive checks are
- /// performed. `debug_assert!` is used, so some restrictions are only checked in debug
- /// mode.
- ///
- pub fn new(
- device: Arc<Device>,
- description: RenderPassDesc,
- ) -> Result<RenderPass, RenderPassCreationError> {
- let fns = device.fns();
-
- // If the first use of an attachment in this render pass is as an input attachment, and
- // the attachment is not also used as a color or depth/stencil attachment in the same
- // subpass, then loadOp must not be VK_ATTACHMENT_LOAD_OP_CLEAR
- debug_assert!(description.attachments().into_iter().enumerate().all(
- |(atch_num, attachment)| {
- if attachment.load != LoadOp::Clear {
- return true;
- }
-
- for p in description.subpasses() {
- if p.color_attachments
- .iter()
- .find(|&&(a, _)| a == atch_num)
- .is_some()
- {
- return true;
- }
- if let Some((a, _)) = p.depth_stencil {
- if a == atch_num {
- return true;
- }
- }
- if p.input_attachments
- .iter()
- .find(|&&(a, _)| a == atch_num)
- .is_some()
- {
- return false;
- }
- }
-
- true
- }
- ));
-
- let attachments = description
- .attachments()
- .iter()
- .map(|attachment| {
- ash::vk::AttachmentDescription {
- flags: ash::vk::AttachmentDescriptionFlags::empty(), // FIXME: may alias flag
- format: attachment.format.into(),
- samples: attachment.samples.into(),
- load_op: attachment.load.into(),
- store_op: attachment.store.into(),
- stencil_load_op: attachment.stencil_load.into(),
- stencil_store_op: attachment.stencil_store.into(),
- initial_layout: attachment.initial_layout.into(),
- final_layout: attachment.final_layout.into(),
- }
- })
- .collect::<SmallVec<[_; 16]>>();
-
- // We need to pass pointers to vkAttachmentReference structs when creating the render pass.
- // Therefore we need to allocate them in advance.
- //
- // This block allocates, for each pass, in order, all color attachment references, then all
- // input attachment references, then all resolve attachment references, then the depth
- // stencil attachment reference.
- let attachment_references = description
- .subpasses()
- .iter()
- .flat_map(|pass| {
- // Performing some validation with debug asserts.
- debug_assert!(
- pass.resolve_attachments.is_empty()
- || pass.resolve_attachments.len() == pass.color_attachments.len()
- );
- debug_assert!(pass
- .resolve_attachments
- .iter()
- .all(|a| attachments[a.0].samples == ash::vk::SampleCountFlags::TYPE_1));
- debug_assert!(
- pass.resolve_attachments.is_empty()
- || pass
- .color_attachments
- .iter()
- .all(|a| attachments[a.0].samples.as_raw() > 1)
- );
- debug_assert!(
- pass.resolve_attachments.is_empty()
- || pass
- .resolve_attachments
- .iter()
- .zip(pass.color_attachments.iter())
- .all(|(r, c)| { attachments[r.0].format == attachments[c.0].format })
- );
- debug_assert!(pass
- .color_attachments
- .iter()
- .cloned()
- .chain(pass.depth_stencil.clone().into_iter())
- .chain(pass.input_attachments.iter().cloned())
- .chain(pass.resolve_attachments.iter().cloned())
- .all(|(a, _)| {
- pass.preserve_attachments
- .iter()
- .find(|&&b| a == b)
- .is_none()
- }));
- debug_assert!(pass
- .color_attachments
- .iter()
- .cloned()
- .chain(pass.depth_stencil.clone().into_iter())
- .all(|(atch, layout)| {
- if let Some(r) = pass.input_attachments.iter().find(|r| r.0 == atch) {
- r.1 == layout
- } else {
- true
- }
- }));
-
- let resolve = pass.resolve_attachments.iter().map(|&(offset, img_la)| {
- debug_assert!(offset < attachments.len());
- ash::vk::AttachmentReference {
- attachment: offset as u32,
- layout: img_la.into(),
- }
- });
-
- let color = pass.color_attachments.iter().map(|&(offset, img_la)| {
- debug_assert!(offset < attachments.len());
- ash::vk::AttachmentReference {
- attachment: offset as u32,
- layout: img_la.into(),
- }
- });
-
- let input = pass.input_attachments.iter().map(|&(offset, img_la)| {
- debug_assert!(offset < attachments.len());
- ash::vk::AttachmentReference {
- attachment: offset as u32,
- layout: img_la.into(),
- }
- });
-
- let depthstencil = if let Some((offset, img_la)) = pass.depth_stencil {
- Some(ash::vk::AttachmentReference {
- attachment: offset as u32,
- layout: img_la.into(),
- })
- } else {
- None
- }
- .into_iter();
-
- color.chain(input).chain(resolve).chain(depthstencil)
- })
- .collect::<SmallVec<[_; 16]>>();
-
- // Same as `attachment_references` but only for the preserve attachments.
- // This is separate because attachment references are u32s and not `vkAttachmentReference`
- // structs.
- let preserve_attachments_references = description
- .subpasses()
- .iter()
- .flat_map(|pass| {
- pass.preserve_attachments
- .iter()
- .map(|&offset| offset as u32)
- })
- .collect::<SmallVec<[_; 16]>>();
-
- // Now iterating over passes.
- let passes = unsafe {
- // `ref_index` and `preserve_ref_index` are increased during the loop and point to the
- // next element to use in respectively `attachment_references` and
- // `preserve_attachments_references`.
- let mut ref_index = 0usize;
- let mut preserve_ref_index = 0usize;
- let mut out: SmallVec<[_; 16]> = SmallVec::new();
-
- for pass in description.subpasses() {
- if pass.color_attachments.len() as u32
- > device
- .physical_device()
- .properties()
- .max_color_attachments
- {
- return Err(RenderPassCreationError::ColorAttachmentsLimitExceeded);
- }
-
- let color_attachments = attachment_references.as_ptr().offset(ref_index as isize);
- ref_index += pass.color_attachments.len();
- let input_attachments = attachment_references.as_ptr().offset(ref_index as isize);
- ref_index += pass.input_attachments.len();
- let resolve_attachments = attachment_references.as_ptr().offset(ref_index as isize);
- ref_index += pass.resolve_attachments.len();
- let depth_stencil = if pass.depth_stencil.is_some() {
- let a = attachment_references.as_ptr().offset(ref_index as isize);
- ref_index += 1;
- a
- } else {
- ptr::null()
- };
-
- let preserve_attachments = preserve_attachments_references
- .as_ptr()
- .offset(preserve_ref_index as isize);
- preserve_ref_index += pass.preserve_attachments.len();
-
- out.push(ash::vk::SubpassDescription {
- flags: ash::vk::SubpassDescriptionFlags::empty(),
- pipeline_bind_point: ash::vk::PipelineBindPoint::GRAPHICS,
- input_attachment_count: pass.input_attachments.len() as u32,
- p_input_attachments: if pass.input_attachments.is_empty() {
- ptr::null()
- } else {
- input_attachments
- },
- color_attachment_count: pass.color_attachments.len() as u32,
- p_color_attachments: if pass.color_attachments.is_empty() {
- ptr::null()
- } else {
- color_attachments
- },
- p_resolve_attachments: if pass.resolve_attachments.is_empty() {
- ptr::null()
- } else {
- resolve_attachments
- },
- p_depth_stencil_attachment: depth_stencil,
- preserve_attachment_count: pass.preserve_attachments.len() as u32,
- p_preserve_attachments: if pass.preserve_attachments.is_empty() {
- ptr::null()
- } else {
- preserve_attachments
- },
- });
- }
-
- assert!(!out.is_empty());
- // If these assertions fails, there's a serious bug in the code above ^.
- debug_assert!(ref_index == attachment_references.len());
- debug_assert!(preserve_ref_index == preserve_attachments_references.len());
-
- out
- };
-
- let dependencies = description
- .dependencies()
- .iter()
- .map(|dependency| {
- debug_assert!(
- dependency.source_subpass as u32 == ash::vk::SUBPASS_EXTERNAL
- || dependency.source_subpass < passes.len()
- );
- debug_assert!(
- dependency.destination_subpass as u32 == ash::vk::SUBPASS_EXTERNAL
- || dependency.destination_subpass < passes.len()
- );
-
- ash::vk::SubpassDependency {
- src_subpass: dependency.source_subpass as u32,
- dst_subpass: dependency.destination_subpass as u32,
- src_stage_mask: dependency.source_stages.into(),
- dst_stage_mask: dependency.destination_stages.into(),
- src_access_mask: dependency.source_access.into(),
- dst_access_mask: dependency.destination_access.into(),
- dependency_flags: if dependency.by_region {
- ash::vk::DependencyFlags::BY_REGION
- } else {
- ash::vk::DependencyFlags::empty()
- },
- }
- })
- .collect::<SmallVec<[_; 16]>>();
-
- let multiview_create_info = match description.multiview() {
- Some(multiview) => {
- debug_assert!(device.enabled_features().multiview);
- debug_assert!(
- device
- .physical_device()
- .properties()
- .max_multiview_view_count
- .unwrap_or(0)
- >= multiview.used_layer_count()
- );
-
- // each subpass must have a corresponding view mask
- // or there are no view masks at all (which is probably a bug because
- // nothing will get drawn)
- debug_assert!(
- multiview.view_masks.len() == passes.len() || multiview.view_masks.is_empty()
- );
-
- // either all subpasses must have a non-zero view mask or all must be zero
- // (multiview is considered to be disabled when all view masks are zero)
- debug_assert!(
- multiview.view_masks.iter().all(|&mask| mask != 0)
- || multiview.view_masks.iter().all(|&mask| mask == 0)
- );
-
- // one view offset for each dependency
- // or no view offsets at all
- debug_assert!(
- dependencies.len() == multiview.view_offsets.len()
- || multiview.view_offsets.is_empty()
- );
-
- // VUID-VkRenderPassCreateInfo-pNext-02512
- debug_assert!(dependencies.iter().zip(&multiview.view_offsets).all(
- |(dependency, &view_offset)| dependency
- .dependency_flags
- .contains(ash::vk::DependencyFlags::VIEW_LOCAL)
- || view_offset == 0
- ));
-
- // VUID-VkRenderPassCreateInfo-pNext-02514
- debug_assert!(
- multiview.view_masks.iter().any(|&view_mask| view_mask != 0)
- || dependencies.iter().all(|dependency| !dependency
- .dependency_flags
- .contains(ash::vk::DependencyFlags::VIEW_LOCAL))
- );
-
- // VUID-VkRenderPassCreateInfo-pNext-02515
- debug_assert!(
- multiview.view_masks.iter().any(|&view_mask| view_mask != 0)
- || multiview.correlation_masks.is_empty()
- );
-
- // VUID-VkRenderPassMultiviewCreateInfo-pCorrelationMasks-00841
- // ensure that each view index is contained in at most one correlation mask
- // by checking for any overlap in all pairs of correlation masks
- debug_assert!(multiview
- .correlation_masks
- .iter()
- .enumerate()
- .all(|(i, &mask)| multiview.correlation_masks[i + 1..]
- .iter()
- .all(|&other_mask| other_mask & mask == 0)));
-
- ash::vk::RenderPassMultiviewCreateInfo {
- subpass_count: passes.len() as u32,
- p_view_masks: multiview.view_masks.as_ptr(),
- dependency_count: dependencies.len() as u32,
- p_view_offsets: multiview.view_offsets.as_ptr(),
- correlation_mask_count: multiview.correlation_masks.len() as u32,
- p_correlation_masks: multiview.correlation_masks.as_ptr(),
- ..Default::default()
- }
- }
- None => ash::vk::RenderPassMultiviewCreateInfo::default(),
- };
-
- let render_pass = unsafe {
- let infos = ash::vk::RenderPassCreateInfo {
- p_next: if description.multiview().is_none() {
- ptr::null()
- } else {
- &multiview_create_info as *const _ as _
- },
- flags: ash::vk::RenderPassCreateFlags::empty(),
- attachment_count: attachments.len() as u32,
- p_attachments: if attachments.is_empty() {
- ptr::null()
- } else {
- attachments.as_ptr()
- },
- subpass_count: passes.len() as u32,
- p_subpasses: if passes.is_empty() {
- ptr::null()
- } else {
- passes.as_ptr()
- },
- dependency_count: dependencies.len() as u32,
- p_dependencies: if dependencies.is_empty() {
- ptr::null()
- } else {
- dependencies.as_ptr()
- },
- ..Default::default()
- };
-
- let mut output = MaybeUninit::uninit();
- check_errors(fns.v1_0.create_render_pass(
- device.internal_object(),
- &infos,
- ptr::null(),
- output.as_mut_ptr(),
- ))?;
- output.assume_init()
- };
-
- Ok(RenderPass {
- device: device.clone(),
- render_pass,
- desc: description,
- granularity: Mutex::new(None),
- })
- }
-
- /// Builds a render pass with one subpass and no attachment.
- ///
- /// This method is useful for quick tests.
- #[inline]
- pub fn empty_single_pass(device: Arc<Device>) -> Result<RenderPass, RenderPassCreationError> {
- RenderPass::new(device, RenderPassDesc::empty())
- }
-
- #[inline]
- pub fn inner(&self) -> RenderPassSys {
- RenderPassSys(self.render_pass, PhantomData)
- }
-
- /// Returns the granularity of this render pass.
- ///
- /// If the render area of a render pass in a command buffer is a multiple of this granularity,
- /// then the performance will be optimal. Performances are always optimal for render areas
- /// that cover the whole framebuffer.
- pub fn granularity(&self) -> [u32; 2] {
- let mut granularity = self.granularity.lock().unwrap();
-
- if let Some(&granularity) = granularity.as_ref() {
- return granularity;
- }
-
- unsafe {
- let fns = self.device.fns();
- let mut out = MaybeUninit::uninit();
- fns.v1_0.get_render_area_granularity(
- self.device.internal_object(),
- self.render_pass,
- out.as_mut_ptr(),
- );
-
- let out = out.assume_init();
- debug_assert_ne!(out.width, 0);
- debug_assert_ne!(out.height, 0);
- let gran = [out.width, out.height];
- *granularity = Some(gran);
- gran
- }
- }
-
- /// Returns the description of the render pass.
- #[inline]
- pub fn desc(&self) -> &RenderPassDesc {
- &self.desc
- }
-}
-
-unsafe impl DeviceOwned for RenderPass {
- #[inline]
- fn device(&self) -> &Arc<Device> {
- &self.device
- }
-}
-
-impl fmt::Debug for RenderPass {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- fmt.debug_struct("RenderPass")
- .field("raw", &self.render_pass)
- .field("device", &self.device)
- .field("desc", &self.desc)
- .finish()
- }
-}
-
-impl Drop for RenderPass {
- #[inline]
- fn drop(&mut self) {
- unsafe {
- let fns = self.device.fns();
- fns.v1_0.destroy_render_pass(
- self.device.internal_object(),
- self.render_pass,
- ptr::null(),
- );
- }
- }
-}
-
-/// Opaque object that represents the render pass' internals.
-#[derive(Debug, Copy, Clone)]
-pub struct RenderPassSys<'a>(ash::vk::RenderPass, PhantomData<&'a ()>);
-
-unsafe impl<'a> VulkanObject for RenderPassSys<'a> {
- type Object = ash::vk::RenderPass;
-
- #[inline]
- fn internal_object(&self) -> ash::vk::RenderPass {
- self.0
- }
-}
-
-/// Error that can happen when creating a compute pipeline.
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum RenderPassCreationError {
- /// Not enough memory.
- OomError(OomError),
- /// The maximum number of color attachments has been exceeded.
- ColorAttachmentsLimitExceeded,
-}
-
-impl error::Error for RenderPassCreationError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- RenderPassCreationError::OomError(ref err) => Some(err),
- _ => None,
- }
- }
-}
-
-impl fmt::Display for RenderPassCreationError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- RenderPassCreationError::OomError(_) => "not enough memory available",
- RenderPassCreationError::ColorAttachmentsLimitExceeded => {
- "the maximum number of color attachments has been exceeded"
- }
- }
- )
- }
-}
-
-impl From<OomError> for RenderPassCreationError {
- #[inline]
- fn from(err: OomError) -> RenderPassCreationError {
- RenderPassCreationError::OomError(err)
- }
-}
-
-impl From<Error> for RenderPassCreationError {
- #[inline]
- fn from(err: Error) -> RenderPassCreationError {
- match err {
- err @ Error::OutOfHostMemory => RenderPassCreationError::OomError(OomError::from(err)),
- err @ Error::OutOfDeviceMemory => {
- RenderPassCreationError::OomError(OomError::from(err))
- }
- _ => panic!("unexpected error: {:?}", err),
- }
- }
-}
-
-/// Represents a subpass within a `RenderPass` object.
-///
-/// This struct doesn't correspond to anything in Vulkan. It is simply an equivalent to a
-/// tuple of a render pass and subpass index. Contrary to a tuple, however, the existence of the
-/// subpass is checked when the object is created. When you have a `Subpass` you are guaranteed
-/// that the given subpass does exist.
-#[derive(Debug, Clone)]
-pub struct Subpass {
- render_pass: Arc<RenderPass>,
- subpass_id: u32,
-}
-
-impl Subpass {
- /// Returns a handle that represents a subpass of a render pass.
- #[inline]
- pub fn from(render_pass: Arc<RenderPass>, id: u32) -> Option<Subpass> {
- if (id as usize) < render_pass.desc().subpasses().len() {
- Some(Subpass {
- render_pass,
- subpass_id: id,
- })
- } else {
- None
- }
- }
-
- #[inline]
- fn subpass_desc(&self) -> &SubpassDesc {
- &self.render_pass.desc().subpasses()[self.subpass_id as usize]
- }
-
- #[inline]
- fn attachment_desc(&self, atch_num: usize) -> &AttachmentDesc {
- &self.render_pass.desc().attachments()[atch_num]
- }
-
- /// Returns the number of color attachments in this subpass.
- #[inline]
- pub fn num_color_attachments(&self) -> u32 {
- self.subpass_desc().color_attachments.len() as u32
- }
-
- /// Returns true if the subpass has a depth attachment or a depth-stencil attachment.
- #[inline]
- pub fn has_depth(&self) -> bool {
- let subpass_desc = self.subpass_desc();
- let atch_num = match subpass_desc.depth_stencil {
- Some((d, _)) => d,
- None => return false,
- };
-
- match self.attachment_desc(atch_num).format.ty() {
- FormatTy::Depth => true,
- FormatTy::Stencil => false,
- FormatTy::DepthStencil => true,
- _ => unreachable!(),
- }
- }
-
- /// Returns true if the subpass has a depth attachment or a depth-stencil attachment whose
- /// layout is not `DepthStencilReadOnlyOptimal`.
- #[inline]
- pub fn has_writable_depth(&self) -> bool {
- let subpass_desc = self.subpass_desc();
- let atch_num = match subpass_desc.depth_stencil {
- Some((d, l)) => {
- if l == ImageLayout::DepthStencilReadOnlyOptimal {
- return false;
- }
- d
- }
- None => return false,
- };
-
- match self.attachment_desc(atch_num).format.ty() {
- FormatTy::Depth => true,
- FormatTy::Stencil => false,
- FormatTy::DepthStencil => true,
- _ => unreachable!(),
- }
- }
-
- /// Returns true if the subpass has a stencil attachment or a depth-stencil attachment.
- #[inline]
- pub fn has_stencil(&self) -> bool {
- let subpass_desc = self.subpass_desc();
- let atch_num = match subpass_desc.depth_stencil {
- Some((d, _)) => d,
- None => return false,
- };
-
- match self.attachment_desc(atch_num).format.ty() {
- FormatTy::Depth => false,
- FormatTy::Stencil => true,
- FormatTy::DepthStencil => true,
- _ => unreachable!(),
- }
- }
-
- /// Returns true if the subpass has a stencil attachment or a depth-stencil attachment whose
- /// layout is not `DepthStencilReadOnlyOptimal`.
- #[inline]
- pub fn has_writable_stencil(&self) -> bool {
- let subpass_desc = self.subpass_desc();
-
- let atch_num = match subpass_desc.depth_stencil {
- Some((d, l)) => {
- if l == ImageLayout::DepthStencilReadOnlyOptimal {
- return false;
- }
- d
- }
- None => return false,
- };
-
- match self.attachment_desc(atch_num).format.ty() {
- FormatTy::Depth => false,
- FormatTy::Stencil => true,
- FormatTy::DepthStencil => true,
- _ => unreachable!(),
- }
- }
-
- /// Returns true if the subpass has any color or depth/stencil attachment.
- #[inline]
- pub fn has_color_or_depth_stencil_attachment(&self) -> bool {
- if self.num_color_attachments() >= 1 {
- return true;
- }
-
- let subpass_desc = self.subpass_desc();
- match subpass_desc.depth_stencil {
- Some((d, _)) => true,
- None => false,
- }
- }
-
- /// Returns the number of samples in the color and/or depth/stencil attachments. Returns `None`
- /// if there is no such attachment in this subpass.
- #[inline]
- pub fn num_samples(&self) -> Option<SampleCount> {
- let subpass_desc = self.subpass_desc();
-
- // TODO: chain input attachments as well?
- subpass_desc
- .color_attachments
- .iter()
- .cloned()
- .chain(subpass_desc.depth_stencil.clone().into_iter())
- .filter_map(|a| self.render_pass.desc().attachments().get(a.0))
- .next()
- .map(|a| a.samples)
- }
-
- /// Returns the render pass of this subpass.
- #[inline]
- pub fn render_pass(&self) -> &Arc<RenderPass> {
- &self.render_pass
- }
-
- /// Returns the index of this subpass within the renderpass.
- #[inline]
- pub fn index(&self) -> u32 {
- self.subpass_id
- }
-
- /// Returns `true` if this subpass is compatible with the fragment output definition.
- // TODO: return proper error
- pub fn is_compatible_with(&self, shader_interface: &ShaderInterface) -> bool {
- self.render_pass
- .desc()
- .is_compatible_with_shader(self.subpass_id, shader_interface)
- }
-}
-
-impl From<Subpass> for (Arc<RenderPass>, u32) {
- #[inline]
- fn from(value: Subpass) -> (Arc<RenderPass>, u32) {
- (value.render_pass, value.subpass_id)
- }
-}
-
-#[cfg(test)]
-mod tests {
- use crate::format::Format;
- use crate::render_pass::RenderPass;
- use crate::render_pass::RenderPassCreationError;
-
- #[test]
- fn empty() {
- let (device, _) = gfx_dev_and_queue!();
- let _ = RenderPass::empty_single_pass(device).unwrap();
- }
-
- #[test]
- fn too_many_color_atch() {
- let (device, _) = gfx_dev_and_queue!();
-
- if device
- .physical_device()
- .properties()
- .max_color_attachments
- >= 10
- {
- return; // test ignored
- }
-
- let rp = single_pass_renderpass! {
- device.clone(),
- attachments: {
- a1: { load: Clear, store: DontCare, format: Format::R8G8B8A8Unorm, samples: 1, },
- a2: { load: Clear, store: DontCare, format: Format::R8G8B8A8Unorm, samples: 1, },
- a3: { load: Clear, store: DontCare, format: Format::R8G8B8A8Unorm, samples: 1, },
- a4: { load: Clear, store: DontCare, format: Format::R8G8B8A8Unorm, samples: 1, },
- a5: { load: Clear, store: DontCare, format: Format::R8G8B8A8Unorm, samples: 1, },
- a6: { load: Clear, store: DontCare, format: Format::R8G8B8A8Unorm, samples: 1, },
- a7: { load: Clear, store: DontCare, format: Format::R8G8B8A8Unorm, samples: 1, },
- a8: { load: Clear, store: DontCare, format: Format::R8G8B8A8Unorm, samples: 1, },
- a9: { load: Clear, store: DontCare, format: Format::R8G8B8A8Unorm, samples: 1, },
- a10: { load: Clear, store: DontCare, format: Format::R8G8B8A8Unorm, samples: 1, }
- },
- pass: {
- color: [a1, a2, a3, a4, a5, a6, a7, a8, a9, a10],
- depth_stencil: {}
- }
- };
-
- match rp {
- Err(RenderPassCreationError::ColorAttachmentsLimitExceeded) => (),
- _ => panic!(),
- }
- }
-
- #[test]
- fn non_zero_granularity() {
- let (device, _) = gfx_dev_and_queue!();
-
- let rp = single_pass_renderpass! {
- device.clone(),
- attachments: {
- a: { load: Clear, store: DontCare, format: Format::R8G8B8A8Unorm, samples: 1, }
- },
- pass: {
- color: [a],
- depth_stencil: {}
- }
- }
- .unwrap();
-
- let granularity = rp.granularity();
- assert_ne!(granularity[0], 0);
- assert_ne!(granularity[1], 0);
- }
-}
diff --git a/src/sampler.rs b/src/sampler.rs
deleted file mode 100644
index be7fc9b..0000000
--- a/src/sampler.rs
+++ /dev/null
@@ -1,1051 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-//! How to retrieve data from an image within a shader.
-//!
-//! When you retrieve data from an image, you have to pass the coordinates of the pixel you want
-//! to retrieve. The implementation then performs various calculations, and these operations are
-//! what the `Sampler` struct describes.
-//!
-//! Sampling is a very complex topic but that hasn't changed much since the beginnings of 3D
-//! rendering. Documentation here is missing, but any tutorial about OpenGL or DirectX can teach
-//! you how it works.
-//!
-//! # Examples
-//!
-//! A simple sampler for most usages:
-//!
-//! ```
-//! use vulkano::sampler::Sampler;
-//!
-//! # let device: std::sync::Arc<vulkano::device::Device> = return;
-//! let _sampler = Sampler::simple_repeat_linear_no_mipmap(device.clone());
-//! ```
-//!
-//! More detailed sampler creation:
-//!
-//! ```
-//! use vulkano::sampler;
-//!
-//! # let device: std::sync::Arc<vulkano::device::Device> = return;
-//! let _sampler = sampler::Sampler::new(device.clone(), sampler::Filter::Linear,
-//! sampler::Filter::Linear,
-//! sampler::MipmapMode::Nearest,
-//! sampler::SamplerAddressMode::Repeat,
-//! sampler::SamplerAddressMode::Repeat,
-//! sampler::SamplerAddressMode::Repeat, 1.0, 1.0,
-//! 0.0, 100.0).unwrap();;
-//! ```
-//!
-//! # About border colors
-//!
-//! One of the possible values of `SamplerAddressMode` and `UnnormalizedSamplerAddressMode` is
-//! `ClampToBorder`. This value indicates that accessing an image outside of its range must return
-//! the specified color.
-//!
-//! However this comes with restrictions. When using a floating-point border color, the sampler can
-//! only be used with floating-point or depth image views. When using an integer border color, the
-//! sampler can only be used with integer or stencil image views. In addition to this, you can't
-//! use an opaque black border color with an image view that uses components swizzling.
-//!
-//! > **Note**: The reason for this restriction about opaque black borders is that the value of the
-//! > alpha is 1.0 while the value of the color components is 0.0. In the other border colors, the
-//! > value of all the components is the same.
-//!
-//! Samplers that don't use `ClampToBorder` are not concerned by these restrictions.
-//!
-// FIXME: restrictions aren't checked yet
-
-use crate::check_errors;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-pub use crate::pipeline::depth_stencil::Compare;
-use crate::Error;
-use crate::OomError;
-use crate::VulkanObject;
-use std::error;
-use std::fmt;
-use std::mem::MaybeUninit;
-use std::ptr;
-use std::sync::Arc;
-
-/// Describes how to retrieve data from an image within a shader.
-pub struct Sampler {
- sampler: ash::vk::Sampler,
- device: Arc<Device>,
- compare_mode: bool,
- unnormalized: bool,
- usable_with_float_formats: bool,
- usable_with_int_formats: bool,
- usable_with_swizzling: bool,
-}
-
-impl Sampler {
- /// Shortcut for creating a sampler with linear sampling, linear mipmaps, and with the repeat
- /// mode for borders.
- ///
- /// Useful for prototyping, but can also be used in real projects.
- ///
- /// # Panic
- ///
- /// - Panics if out of memory or the maximum number of samplers has exceeded.
- ///
- #[inline]
- pub fn simple_repeat_linear(device: Arc<Device>) -> Arc<Sampler> {
- Sampler::new(
- device,
- Filter::Linear,
- Filter::Linear,
- MipmapMode::Linear,
- SamplerAddressMode::Repeat,
- SamplerAddressMode::Repeat,
- SamplerAddressMode::Repeat,
- 0.0,
- 1.0,
- 0.0,
- 1_000.0,
- )
- .unwrap()
- }
-
- /// Shortcut for creating a sampler with linear sampling, that only uses the main level of
- /// images, and with the repeat mode for borders.
- ///
- /// Useful for prototyping, but can also be used in real projects.
- ///
- /// # Panic
- ///
- /// - Panics if out of memory or the maximum number of samplers has exceeded.
- ///
- #[inline]
- pub fn simple_repeat_linear_no_mipmap(device: Arc<Device>) -> Arc<Sampler> {
- Sampler::new(
- device,
- Filter::Linear,
- Filter::Linear,
- MipmapMode::Nearest,
- SamplerAddressMode::Repeat,
- SamplerAddressMode::Repeat,
- SamplerAddressMode::Repeat,
- 0.0,
- 1.0,
- 0.0,
- 1.0,
- )
- .unwrap()
- }
-
- /// Creates a new `Sampler` with the given behavior.
- ///
- /// `mag_filter` and `min_filter` define how the implementation should sample from the image
- /// when it is respectively larger and smaller than the original.
- ///
- /// `mipmap_mode` defines how the implementation should choose which mipmap to use.
- ///
- /// `address_u`, `address_v` and `address_w` define how the implementation should behave when
- /// sampling outside of the texture coordinates range `[0.0, 1.0]`.
- ///
- /// `mip_lod_bias` is a value to add to .
- ///
- /// `max_anisotropy` must be greater than or equal to 1.0. If greater than 1.0, the
- /// implementation will use anisotropic filtering. Using a value greater than 1.0 requires
- /// the `sampler_anisotropy` feature to be enabled when creating the device.
- ///
- /// `min_lod` and `max_lod` are respectively the minimum and maximum mipmap level to use.
- /// `max_lod` must always be greater than or equal to `min_lod`.
- ///
- /// # Panic
- ///
- /// - Panics if multiple `ClampToBorder` values are passed and the border color is different.
- /// - Panics if `max_anisotropy < 1.0`.
- /// - Panics if `min_lod > max_lod`.
- ///
- #[inline(always)]
- pub fn new(
- device: Arc<Device>,
- mag_filter: Filter,
- min_filter: Filter,
- mipmap_mode: MipmapMode,
- address_u: SamplerAddressMode,
- address_v: SamplerAddressMode,
- address_w: SamplerAddressMode,
- mip_lod_bias: f32,
- max_anisotropy: f32,
- min_lod: f32,
- max_lod: f32,
- ) -> Result<Arc<Sampler>, SamplerCreationError> {
- Sampler::new_impl(
- device,
- mag_filter,
- min_filter,
- mipmap_mode,
- address_u,
- address_v,
- address_w,
- mip_lod_bias,
- max_anisotropy,
- min_lod,
- max_lod,
- None,
- )
- }
-
- /// Creates a new `Sampler` with the given behavior.
- ///
- /// Contrary to `new`, this creates a sampler that is used to compare depth values.
- ///
- /// A sampler like this can only operate on depth or depth-stencil textures. Instead of
- /// returning the value of the texture, this sampler will return a value between 0.0 and 1.0
- /// indicating how much the reference value (passed by the shader) compares to the value in the
- /// texture.
- ///
- /// Note that it doesn't make sense to create a compare-mode sampler with an integer border
- /// color, as such a sampler would be unusable.
- ///
- /// # Panic
- ///
- /// Same panic reasons as `new`.
- ///
- #[inline(always)]
- pub fn compare(
- device: Arc<Device>,
- mag_filter: Filter,
- min_filter: Filter,
- mipmap_mode: MipmapMode,
- address_u: SamplerAddressMode,
- address_v: SamplerAddressMode,
- address_w: SamplerAddressMode,
- mip_lod_bias: f32,
- max_anisotropy: f32,
- min_lod: f32,
- max_lod: f32,
- compare: Compare,
- ) -> Result<Arc<Sampler>, SamplerCreationError> {
- Sampler::new_impl(
- device,
- mag_filter,
- min_filter,
- mipmap_mode,
- address_u,
- address_v,
- address_w,
- mip_lod_bias,
- max_anisotropy,
- min_lod,
- max_lod,
- Some(compare),
- )
- }
-
- fn new_impl(
- device: Arc<Device>,
- mag_filter: Filter,
- min_filter: Filter,
- mipmap_mode: MipmapMode,
- address_u: SamplerAddressMode,
- address_v: SamplerAddressMode,
- address_w: SamplerAddressMode,
- mip_lod_bias: f32,
- max_anisotropy: f32,
- min_lod: f32,
- max_lod: f32,
- compare: Option<Compare>,
- ) -> Result<Arc<Sampler>, SamplerCreationError> {
- assert!(max_anisotropy >= 1.0);
- assert!(min_lod <= max_lod);
-
- // Check max anisotropy.
- if max_anisotropy > 1.0 {
- if !device.enabled_features().sampler_anisotropy {
- return Err(SamplerCreationError::SamplerAnisotropyFeatureNotEnabled);
- }
-
- let limit = device
- .physical_device()
- .properties()
- .max_sampler_anisotropy;
- if max_anisotropy > limit {
- return Err(SamplerCreationError::AnisotropyLimitExceeded {
- requested: max_anisotropy,
- maximum: limit,
- });
- }
- }
-
- // Check mip_lod_bias value.
- {
- let limit = device
- .physical_device()
- .properties()
- .max_sampler_lod_bias;
- if mip_lod_bias > limit {
- return Err(SamplerCreationError::MipLodBiasLimitExceeded {
- requested: mip_lod_bias,
- maximum: limit,
- });
- }
- }
-
- // Check MirrorClampToEdge extension support
- if [address_u, address_v, address_w]
- .iter()
- .any(|&mode| mode == SamplerAddressMode::MirrorClampToEdge)
- {
- if !device.enabled_extensions().khr_sampler_mirror_clamp_to_edge {
- return Err(SamplerCreationError::SamplerMirrorClampToEdgeExtensionNotEnabled);
- }
- }
-
- // Handling border color.
- let border_color = address_u.border_color();
- let border_color = match (border_color, address_v.border_color()) {
- (Some(b1), Some(b2)) => {
- assert_eq!(b1, b2);
- Some(b1)
- }
- (None, b) => b,
- (b, None) => b,
- };
- let border_color = match (border_color, address_w.border_color()) {
- (Some(b1), Some(b2)) => {
- assert_eq!(b1, b2);
- Some(b1)
- }
- (None, b) => b,
- (b, None) => b,
- };
-
- let fns = device.fns();
- let sampler = unsafe {
- let infos = ash::vk::SamplerCreateInfo {
- flags: ash::vk::SamplerCreateFlags::empty(),
- mag_filter: mag_filter.into(),
- min_filter: min_filter.into(),
- mipmap_mode: mipmap_mode.into(),
- address_mode_u: address_u.into(),
- address_mode_v: address_v.into(),
- address_mode_w: address_w.into(),
- mip_lod_bias: mip_lod_bias,
- anisotropy_enable: if max_anisotropy > 1.0 {
- ash::vk::TRUE
- } else {
- ash::vk::FALSE
- },
- max_anisotropy: max_anisotropy,
- compare_enable: if compare.is_some() {
- ash::vk::TRUE
- } else {
- ash::vk::FALSE
- },
- compare_op: compare
- .map(|c| c.into())
- .unwrap_or(ash::vk::CompareOp::NEVER),
- min_lod: min_lod,
- max_lod: max_lod,
- border_color: border_color
- .map(|b| b.into())
- .unwrap_or(ash::vk::BorderColor::FLOAT_TRANSPARENT_BLACK),
- unnormalized_coordinates: ash::vk::FALSE,
- ..Default::default()
- };
-
- let mut output = MaybeUninit::uninit();
- check_errors(fns.v1_0.create_sampler(
- device.internal_object(),
- &infos,
- ptr::null(),
- output.as_mut_ptr(),
- ))?;
- output.assume_init()
- };
-
- Ok(Arc::new(Sampler {
- sampler: sampler,
- device: device.clone(),
- compare_mode: compare.is_some(),
- unnormalized: false,
- usable_with_float_formats: match border_color {
- Some(BorderColor::FloatTransparentBlack) => true,
- Some(BorderColor::FloatOpaqueBlack) => true,
- Some(BorderColor::FloatOpaqueWhite) => true,
- Some(_) => false,
- None => true,
- },
- usable_with_int_formats: compare.is_none()
- && match border_color {
- Some(BorderColor::IntTransparentBlack) => true,
- Some(BorderColor::IntOpaqueBlack) => true,
- Some(BorderColor::IntOpaqueWhite) => true,
- Some(_) => false,
- None => true,
- },
- usable_with_swizzling: match border_color {
- Some(BorderColor::FloatOpaqueBlack) => false,
- Some(BorderColor::IntOpaqueBlack) => false,
- _ => true,
- },
- }))
- }
-
- /// Creates a sampler with unnormalized coordinates. This means that texture coordinates won't
- /// range between `0.0` and `1.0` but use plain pixel offsets.
- ///
- /// Using an unnormalized sampler adds a few restrictions:
- ///
- /// - It can only be used with non-array 1D or 2D images.
- /// - It can only be used with images with a single mipmap.
- /// - Projection and offsets can't be used by shaders. Only the first mipmap can be accessed.
- ///
- /// # Panic
- ///
- /// - Panics if multiple `ClampToBorder` values are passed and the border color is different.
- ///
- pub fn unnormalized(
- device: Arc<Device>,
- filter: Filter,
- address_u: UnnormalizedSamplerAddressMode,
- address_v: UnnormalizedSamplerAddressMode,
- ) -> Result<Arc<Sampler>, SamplerCreationError> {
- let fns = device.fns();
-
- let border_color = address_u.border_color();
- let border_color = match (border_color, address_v.border_color()) {
- (Some(b1), Some(b2)) => {
- assert_eq!(b1, b2);
- Some(b1)
- }
- (None, b) => b,
- (b, None) => b,
- };
-
- let sampler = unsafe {
- let infos = ash::vk::SamplerCreateInfo {
- flags: ash::vk::SamplerCreateFlags::empty(),
- mag_filter: filter.into(),
- min_filter: filter.into(),
- mipmap_mode: ash::vk::SamplerMipmapMode::NEAREST,
- address_mode_u: address_u.into(),
- address_mode_v: address_v.into(),
- address_mode_w: ash::vk::SamplerAddressMode::CLAMP_TO_EDGE, // unused by the impl
- mip_lod_bias: 0.0,
- anisotropy_enable: ash::vk::FALSE,
- max_anisotropy: 1.0,
- compare_enable: ash::vk::FALSE,
- compare_op: ash::vk::CompareOp::NEVER,
- min_lod: 0.0,
- max_lod: 0.0,
- border_color: border_color
- .map(|b| b.into())
- .unwrap_or(ash::vk::BorderColor::FLOAT_TRANSPARENT_BLACK),
- unnormalized_coordinates: ash::vk::TRUE,
- ..Default::default()
- };
-
- let mut output = MaybeUninit::uninit();
- check_errors(fns.v1_0.create_sampler(
- device.internal_object(),
- &infos,
- ptr::null(),
- output.as_mut_ptr(),
- ))?;
- output.assume_init()
- };
-
- Ok(Arc::new(Sampler {
- sampler: sampler,
- device: device.clone(),
- compare_mode: false,
- unnormalized: true,
- usable_with_float_formats: match border_color {
- Some(BorderColor::FloatTransparentBlack) => true,
- Some(BorderColor::FloatOpaqueBlack) => true,
- Some(BorderColor::FloatOpaqueWhite) => true,
- Some(_) => false,
- None => true,
- },
- usable_with_int_formats: match border_color {
- Some(BorderColor::IntTransparentBlack) => true,
- Some(BorderColor::IntOpaqueBlack) => true,
- Some(BorderColor::IntOpaqueWhite) => true,
- Some(_) => false,
- None => true,
- },
- usable_with_swizzling: match border_color {
- Some(BorderColor::FloatOpaqueBlack) => false,
- Some(BorderColor::IntOpaqueBlack) => false,
- _ => true,
- },
- }))
- }
-
- /// Returns true if the sampler is a compare-mode sampler.
- #[inline]
- pub fn compare_mode(&self) -> bool {
- self.compare_mode
- }
-
- /// Returns true if the sampler is unnormalized.
- #[inline]
- pub fn is_unnormalized(&self) -> bool {
- self.unnormalized
- }
-
- /// Returns true if the sampler can be used with floating-point image views. See the
- /// documentation of the `sampler` module for more info.
- #[inline]
- pub fn usable_with_float_formats(&self) -> bool {
- self.usable_with_float_formats
- }
-
- /// Returns true if the sampler can be used with integer image views. See the documentation of
- /// the `sampler` module for more info.
- #[inline]
- pub fn usable_with_int_formats(&self) -> bool {
- self.usable_with_int_formats
- }
-
- /// Returns true if the sampler can be used with image views that have non-identity swizzling.
- /// See the documentation of the `sampler` module for more info.
- #[inline]
- pub fn usable_with_swizzling(&self) -> bool {
- self.usable_with_swizzling
- }
-}
-
-unsafe impl DeviceOwned for Sampler {
- #[inline]
- fn device(&self) -> &Arc<Device> {
- &self.device
- }
-}
-
-unsafe impl VulkanObject for Sampler {
- type Object = ash::vk::Sampler;
-
- #[inline]
- fn internal_object(&self) -> ash::vk::Sampler {
- self.sampler
- }
-}
-
-impl fmt::Debug for Sampler {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(fmt, "<Vulkan sampler {:?}>", self.sampler)
- }
-}
-
-impl Drop for Sampler {
- #[inline]
- fn drop(&mut self) {
- unsafe {
- let fns = self.device.fns();
- fns.v1_0
- .destroy_sampler(self.device.internal_object(), self.sampler, ptr::null());
- }
- }
-}
-
-/// Describes how the color of each pixel should be determined.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-#[repr(i32)]
-pub enum Filter {
- /// The four pixels whose center surround the requested coordinates are taken, then their
- /// values are interpolated.
- Linear = ash::vk::Filter::LINEAR.as_raw(),
-
- /// The pixel whose center is nearest to the requested coordinates is taken from the source
- /// and its value is returned as-is.
- Nearest = ash::vk::Filter::NEAREST.as_raw(),
-}
-
-impl From<Filter> for ash::vk::Filter {
- #[inline]
- fn from(val: Filter) -> Self {
- Self::from_raw(val as i32)
- }
-}
-
-/// Describes which mipmap from the source to use.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-#[repr(i32)]
-pub enum MipmapMode {
- /// Use the mipmap whose dimensions are the nearest to the dimensions of the destination.
- Nearest = ash::vk::SamplerMipmapMode::NEAREST.as_raw(),
-
- /// Take the mipmap whose dimensions are no greater than that of the destination together
- /// with the next higher level mipmap, calculate the value for both, and interpolate them.
- Linear = ash::vk::SamplerMipmapMode::LINEAR.as_raw(),
-}
-
-impl From<MipmapMode> for ash::vk::SamplerMipmapMode {
- #[inline]
- fn from(val: MipmapMode) -> Self {
- Self::from_raw(val as i32)
- }
-}
-
-/// How the sampler should behave when it needs to access a pixel that is out of range of the
-/// texture.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub enum SamplerAddressMode {
- /// Repeat the texture. In other words, the pixel at coordinate `x + 1.0` is the same as the
- /// one at coordinate `x`.
- Repeat,
-
- /// Repeat the texture but mirror it at every repetition. In other words, the pixel at
- /// coordinate `x + 1.0` is the same as the one at coordinate `1.0 - x`.
- MirroredRepeat,
-
- /// The coordinates are clamped to the valid range. Coordinates below 0.0 have the same value
- /// as coordinate 0.0. Coordinates over 1.0 have the same value as coordinate 1.0.
- ClampToEdge,
-
- /// Any pixel out of range is considered to be part of the "border" of the image, which has a
- /// specific color of your choice.
- ///
- /// Note that if you use `ClampToBorder` multiple times, they must all have the same border
- /// color.
- ClampToBorder(BorderColor),
-
- /// Similar to `MirroredRepeat`, except that coordinates are clamped to the range
- /// `[-1.0, 1.0]`.
- MirrorClampToEdge,
-}
-
-impl SamplerAddressMode {
- #[inline]
- fn border_color(self) -> Option<BorderColor> {
- match self {
- SamplerAddressMode::ClampToBorder(c) => Some(c),
- _ => None,
- }
- }
-}
-
-impl From<SamplerAddressMode> for ash::vk::SamplerAddressMode {
- #[inline]
- fn from(val: SamplerAddressMode) -> Self {
- match val {
- SamplerAddressMode::Repeat => ash::vk::SamplerAddressMode::REPEAT,
- SamplerAddressMode::MirroredRepeat => ash::vk::SamplerAddressMode::MIRRORED_REPEAT,
- SamplerAddressMode::ClampToEdge => ash::vk::SamplerAddressMode::CLAMP_TO_EDGE,
- SamplerAddressMode::ClampToBorder(_) => ash::vk::SamplerAddressMode::CLAMP_TO_BORDER,
- SamplerAddressMode::MirrorClampToEdge => {
- ash::vk::SamplerAddressMode::MIRROR_CLAMP_TO_EDGE
- }
- }
- }
-}
-
-/// How the sampler should behave when it needs to access a pixel that is out of range of the
-/// texture.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-#[repr(u32)]
-pub enum UnnormalizedSamplerAddressMode {
- /// The coordinates are clamped to the valid range. Coordinates below 0 have the same value
- /// as coordinate 0. Coordinates over *size of texture* have the same value as coordinate
- /// *size of texture*.
- ClampToEdge,
-
- /// Any pixel out of range is considered to be part of the "border" of the image, which has a
- /// specific color of your choice.
- ///
- /// Note that if you use `ClampToBorder` multiple times, they must all have the same border
- /// color.
- ClampToBorder(BorderColor),
-}
-
-impl UnnormalizedSamplerAddressMode {
- #[inline]
- fn border_color(self) -> Option<BorderColor> {
- match self {
- UnnormalizedSamplerAddressMode::ClampToEdge => None,
- UnnormalizedSamplerAddressMode::ClampToBorder(c) => Some(c),
- }
- }
-}
-
-impl From<UnnormalizedSamplerAddressMode> for ash::vk::SamplerAddressMode {
- #[inline]
- fn from(val: UnnormalizedSamplerAddressMode) -> Self {
- match val {
- UnnormalizedSamplerAddressMode::ClampToEdge => {
- ash::vk::SamplerAddressMode::CLAMP_TO_EDGE
- }
- UnnormalizedSamplerAddressMode::ClampToBorder(_) => {
- ash::vk::SamplerAddressMode::CLAMP_TO_BORDER
- }
- }
- }
-}
-
-/// The color to use for the border of an image.
-///
-/// Only relevant if you use `ClampToBorder`.
-///
-/// Using a border color restricts the sampler to either floating-point images or integer images.
-/// See the documentation of the `sampler` module for more info.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-#[repr(i32)]
-pub enum BorderColor {
- /// The value `(0.0, 0.0, 0.0, 0.0)`. Can only be used with floating-point images.
- FloatTransparentBlack = ash::vk::BorderColor::FLOAT_TRANSPARENT_BLACK.as_raw(),
-
- /// The value `(0, 0, 0, 0)`. Can only be used with integer images.
- IntTransparentBlack = ash::vk::BorderColor::INT_TRANSPARENT_BLACK.as_raw(),
-
- /// The value `(0.0, 0.0, 0.0, 1.0)`. Can only be used with floating-point identity-swizzled
- /// images.
- FloatOpaqueBlack = ash::vk::BorderColor::FLOAT_OPAQUE_BLACK.as_raw(),
-
- /// The value `(0, 0, 0, 1)`. Can only be used with integer identity-swizzled images.
- IntOpaqueBlack = ash::vk::BorderColor::INT_OPAQUE_BLACK.as_raw(),
-
- /// The value `(1.0, 1.0, 1.0, 1.0)`. Can only be used with floating-point images.
- FloatOpaqueWhite = ash::vk::BorderColor::FLOAT_OPAQUE_WHITE.as_raw(),
-
- /// The value `(1, 1, 1, 1)`. Can only be used with integer images.
- IntOpaqueWhite = ash::vk::BorderColor::INT_OPAQUE_WHITE.as_raw(),
-}
-
-impl From<BorderColor> for ash::vk::BorderColor {
- #[inline]
- fn from(val: BorderColor) -> Self {
- Self::from_raw(val as i32)
- }
-}
-
-/// Error that can happen when creating an instance.
-#[derive(Clone, Debug, PartialEq)]
-pub enum SamplerCreationError {
- /// Not enough memory.
- OomError(OomError),
-
- /// Too many sampler objects have been created. You must destroy some before creating new ones.
- /// Note the specs guarantee that at least 4000 samplers can exist simultaneously.
- TooManyObjects,
-
- /// Using an anisotropy greater than 1.0 requires enabling the `sampler_anisotropy` feature
- /// when creating the device.
- SamplerAnisotropyFeatureNotEnabled,
-
- /// The requested anisotropy level exceeds the device's limits.
- AnisotropyLimitExceeded {
- /// The value that was requested.
- requested: f32,
- /// The maximum supported value.
- maximum: f32,
- },
-
- /// The requested mip lod bias exceeds the device's limits.
- MipLodBiasLimitExceeded {
- /// The value that was requested.
- requested: f32,
- /// The maximum supported value.
- maximum: f32,
- },
-
- /// Using `MirrorClampToEdge` requires enabling the `VK_KHR_sampler_mirror_clamp_to_edge`
- /// extension when creating the device.
- SamplerMirrorClampToEdgeExtensionNotEnabled,
-}
-
-impl error::Error for SamplerCreationError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- SamplerCreationError::OomError(ref err) => Some(err),
- _ => None,
- }
- }
-}
-
-impl fmt::Display for SamplerCreationError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- SamplerCreationError::OomError(_) => "not enough memory available",
- SamplerCreationError::TooManyObjects => "too many simultaneous sampler objects",
- SamplerCreationError::SamplerAnisotropyFeatureNotEnabled => {
- "the `sampler_anisotropy` feature is not enabled"
- }
- SamplerCreationError::AnisotropyLimitExceeded { .. } => "anisotropy limit exceeded",
- SamplerCreationError::MipLodBiasLimitExceeded { .. } =>
- "mip lod bias limit exceeded",
- SamplerCreationError::SamplerMirrorClampToEdgeExtensionNotEnabled => {
- "the device extension `VK_KHR_sampler_mirror_clamp_to_edge` is not enabled"
- }
- }
- )
- }
-}
-
-impl From<OomError> for SamplerCreationError {
- #[inline]
- fn from(err: OomError) -> SamplerCreationError {
- SamplerCreationError::OomError(err)
- }
-}
-
-impl From<Error> for SamplerCreationError {
- #[inline]
- fn from(err: Error) -> SamplerCreationError {
- match err {
- err @ Error::OutOfHostMemory => SamplerCreationError::OomError(OomError::from(err)),
- err @ Error::OutOfDeviceMemory => SamplerCreationError::OomError(OomError::from(err)),
- Error::TooManyObjects => SamplerCreationError::TooManyObjects,
- _ => panic!("unexpected error: {:?}", err),
- }
- }
-}
-
-#[cfg(test)]
-mod tests {
- use crate::sampler;
-
- #[test]
- fn create_regular() {
- let (device, queue) = gfx_dev_and_queue!();
-
- let s = sampler::Sampler::new(
- device,
- sampler::Filter::Linear,
- sampler::Filter::Linear,
- sampler::MipmapMode::Nearest,
- sampler::SamplerAddressMode::Repeat,
- sampler::SamplerAddressMode::Repeat,
- sampler::SamplerAddressMode::Repeat,
- 1.0,
- 1.0,
- 0.0,
- 2.0,
- )
- .unwrap();
- assert!(!s.compare_mode());
- assert!(!s.is_unnormalized());
- }
-
- #[test]
- fn create_compare() {
- let (device, queue) = gfx_dev_and_queue!();
-
- let s = sampler::Sampler::compare(
- device,
- sampler::Filter::Linear,
- sampler::Filter::Linear,
- sampler::MipmapMode::Nearest,
- sampler::SamplerAddressMode::Repeat,
- sampler::SamplerAddressMode::Repeat,
- sampler::SamplerAddressMode::Repeat,
- 1.0,
- 1.0,
- 0.0,
- 2.0,
- sampler::Compare::Less,
- )
- .unwrap();
-
- assert!(s.compare_mode());
- assert!(!s.is_unnormalized());
- }
-
- #[test]
- fn create_unnormalized() {
- let (device, queue) = gfx_dev_and_queue!();
-
- let s = sampler::Sampler::unnormalized(
- device,
- sampler::Filter::Linear,
- sampler::UnnormalizedSamplerAddressMode::ClampToEdge,
- sampler::UnnormalizedSamplerAddressMode::ClampToEdge,
- )
- .unwrap();
-
- assert!(!s.compare_mode());
- assert!(s.is_unnormalized());
- }
-
- #[test]
- fn simple_repeat_linear() {
- let (device, queue) = gfx_dev_and_queue!();
- let _ = sampler::Sampler::simple_repeat_linear(device);
- }
-
- #[test]
- fn simple_repeat_linear_no_mipmap() {
- let (device, queue) = gfx_dev_and_queue!();
- let _ = sampler::Sampler::simple_repeat_linear_no_mipmap(device);
- }
-
- #[test]
- fn min_lod_inferior() {
- let (device, queue) = gfx_dev_and_queue!();
-
- assert_should_panic!({
- let _ = sampler::Sampler::new(
- device,
- sampler::Filter::Linear,
- sampler::Filter::Linear,
- sampler::MipmapMode::Nearest,
- sampler::SamplerAddressMode::Repeat,
- sampler::SamplerAddressMode::Repeat,
- sampler::SamplerAddressMode::Repeat,
- 1.0,
- 1.0,
- 5.0,
- 2.0,
- );
- });
- }
-
- #[test]
- fn max_anisotropy() {
- let (device, queue) = gfx_dev_and_queue!();
-
- assert_should_panic!({
- let _ = sampler::Sampler::new(
- device,
- sampler::Filter::Linear,
- sampler::Filter::Linear,
- sampler::MipmapMode::Nearest,
- sampler::SamplerAddressMode::Repeat,
- sampler::SamplerAddressMode::Repeat,
- sampler::SamplerAddressMode::Repeat,
- 1.0,
- 0.5,
- 0.0,
- 2.0,
- );
- });
- }
-
- #[test]
- fn different_borders() {
- let (device, queue) = gfx_dev_and_queue!();
-
- let b1 = sampler::BorderColor::IntTransparentBlack;
- let b2 = sampler::BorderColor::FloatOpaqueWhite;
-
- assert_should_panic!({
- let _ = sampler::Sampler::new(
- device,
- sampler::Filter::Linear,
- sampler::Filter::Linear,
- sampler::MipmapMode::Nearest,
- sampler::SamplerAddressMode::ClampToBorder(b1),
- sampler::SamplerAddressMode::ClampToBorder(b2),
- sampler::SamplerAddressMode::Repeat,
- 1.0,
- 1.0,
- 5.0,
- 2.0,
- );
- });
- }
-
- #[test]
- fn anisotropy_feature() {
- let (device, queue) = gfx_dev_and_queue!();
-
- let r = sampler::Sampler::new(
- device,
- sampler::Filter::Linear,
- sampler::Filter::Linear,
- sampler::MipmapMode::Nearest,
- sampler::SamplerAddressMode::Repeat,
- sampler::SamplerAddressMode::Repeat,
- sampler::SamplerAddressMode::Repeat,
- 1.0,
- 2.0,
- 0.0,
- 2.0,
- );
-
- match r {
- Err(sampler::SamplerCreationError::SamplerAnisotropyFeatureNotEnabled) => (),
- _ => panic!(),
- }
- }
-
- #[test]
- fn anisotropy_limit() {
- let (device, queue) = gfx_dev_and_queue!(sampler_anisotropy);
-
- let r = sampler::Sampler::new(
- device,
- sampler::Filter::Linear,
- sampler::Filter::Linear,
- sampler::MipmapMode::Nearest,
- sampler::SamplerAddressMode::Repeat,
- sampler::SamplerAddressMode::Repeat,
- sampler::SamplerAddressMode::Repeat,
- 1.0,
- 100000000.0,
- 0.0,
- 2.0,
- );
-
- match r {
- Err(sampler::SamplerCreationError::AnisotropyLimitExceeded { .. }) => (),
- _ => panic!(),
- }
- }
-
- #[test]
- fn mip_lod_bias_limit() {
- let (device, queue) = gfx_dev_and_queue!();
-
- let r = sampler::Sampler::new(
- device,
- sampler::Filter::Linear,
- sampler::Filter::Linear,
- sampler::MipmapMode::Nearest,
- sampler::SamplerAddressMode::Repeat,
- sampler::SamplerAddressMode::Repeat,
- sampler::SamplerAddressMode::Repeat,
- 100000000.0,
- 1.0,
- 0.0,
- 2.0,
- );
-
- match r {
- Err(sampler::SamplerCreationError::MipLodBiasLimitExceeded { .. }) => (),
- _ => panic!(),
- }
- }
-
- #[test]
- fn sampler_mirror_clamp_to_edge_extension() {
- let (device, queue) = gfx_dev_and_queue!();
-
- let r = sampler::Sampler::new(
- device,
- sampler::Filter::Linear,
- sampler::Filter::Linear,
- sampler::MipmapMode::Nearest,
- sampler::SamplerAddressMode::MirrorClampToEdge,
- sampler::SamplerAddressMode::MirrorClampToEdge,
- sampler::SamplerAddressMode::MirrorClampToEdge,
- 1.0,
- 1.0,
- 0.0,
- 2.0,
- );
-
- match r {
- Err(sampler::SamplerCreationError::SamplerMirrorClampToEdgeExtensionNotEnabled) => (),
- _ => panic!(),
- }
- }
-}
diff --git a/src/sampler/mod.rs b/src/sampler/mod.rs
new file mode 100644
index 0000000..80f2649
--- /dev/null
+++ b/src/sampler/mod.rs
@@ -0,0 +1,1834 @@
+// Copyright (c) 2016 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+//! How to retrieve data from a sampled image within a shader.
+//!
+//! When you retrieve data from a sampled image, you have to pass the coordinates of the pixel you
+//! want to retrieve. The implementation then performs various calculations, and these operations
+//! are what the `Sampler` object describes.
+//!
+//! # Level of detail
+//!
+//! The level-of-detail (LOD) is a floating-point value that expresses a sense of how much texture
+//! detail is visible to the viewer. It is used in texture filtering and mipmapping calculations.
+//!
+//! LOD is calculated through one or more steps to produce a final value. The base LOD is
+//! determined by one of two ways:
+//! - Implicitly, by letting Vulkan calculate it automatically, based on factors such as number of
+//! pixels, distance and viewing angle. This is done using an `ImplicitLod` SPIR-V sampling
+//! operation, which corresponds to the `texture*` functions not suffixed with `Lod` in GLSL.
+//! - Explicitly, specified in the shader. This is done using an `ExplicitLod` SPIR-V sampling
+//! operation, which corresponds to the `texture*Lod` functions in GLSL.
+//!
+//! It is possible to provide a *bias* to the base LOD value, which is simply added to it.
+//! An LOD bias can be provided both in the sampler object and as part of the sampling operation in
+//! the shader, and are combined by addition to produce the final bias value, which is then added to
+//! the base LOD.
+//!
+//! Once LOD bias has been applied, the resulting value may be *clamped* to a minimum and maximum
+//! value to provide the final LOD. A maximum may be specified by the sampler, while a minimum
+//! can be specified by the sampler or the shader sampling operation.
+//!
+//! # Texel filtering
+//!
+//! Texel filtering operations determine how the color value to be sampled from each mipmap is
+//! calculated. The filtering mode can be set independently for different signs of the LOD value:
+//! - Negative or zero: **magnification**. The rendered object is closer to the viewer, and each
+//! pixel in the texture corresponds to exactly one or more than one framebuffer pixel.
+//! - Positive: **minification**. The rendered object is further from the viewer, and each pixel in
+//! the texture corresponds to less than one framebuffer pixel.
+
+pub mod ycbcr;
+
+use self::ycbcr::SamplerYcbcrConversion;
+use crate::{
+ device::{Device, DeviceOwned},
+ format::FormatFeatures,
+ image::{view::ImageViewType, ImageAspects, ImageViewAbstract},
+ macros::{impl_id_counter, vulkan_enum},
+ pipeline::graphics::depth_stencil::CompareOp,
+ shader::ShaderScalarType,
+ OomError, RequirementNotMet, RequiresOneOf, VulkanError, VulkanObject,
+};
+use std::{
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+ mem::MaybeUninit,
+ num::NonZeroU64,
+ ops::RangeInclusive,
+ ptr,
+ sync::Arc,
+};
+
+/// Describes how to retrieve data from a sampled image within a shader.
+///
+/// # Examples
+///
+/// A simple sampler for most usages:
+///
+/// ```
+/// use vulkano::sampler::{Sampler, SamplerCreateInfo};
+///
+/// # let device: std::sync::Arc<vulkano::device::Device> = return;
+/// let _sampler = Sampler::new(device.clone(), SamplerCreateInfo::simple_repeat_linear_no_mipmap());
+/// ```
+///
+/// More detailed sampler creation:
+///
+/// ```
+/// use vulkano::sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo};
+///
+/// # let device: std::sync::Arc<vulkano::device::Device> = return;
+/// let _sampler = Sampler::new(device.clone(), SamplerCreateInfo {
+/// mag_filter: Filter::Linear,
+/// min_filter: Filter::Linear,
+/// address_mode: [SamplerAddressMode::Repeat; 3],
+/// mip_lod_bias: 1.0,
+/// lod: 0.0..=100.0,
+/// ..Default::default()
+/// })
+/// .unwrap();
+/// ```
+#[derive(Debug)]
+pub struct Sampler {
+ handle: ash::vk::Sampler,
+ device: Arc<Device>,
+ id: NonZeroU64,
+
+ address_mode: [SamplerAddressMode; 3],
+ anisotropy: Option<f32>,
+ border_color: Option<BorderColor>,
+ compare: Option<CompareOp>,
+ lod: RangeInclusive<f32>,
+ mag_filter: Filter,
+ min_filter: Filter,
+ mip_lod_bias: f32,
+ mipmap_mode: SamplerMipmapMode,
+ reduction_mode: SamplerReductionMode,
+ sampler_ycbcr_conversion: Option<Arc<SamplerYcbcrConversion>>,
+ unnormalized_coordinates: bool,
+}
+
+impl Sampler {
+ /// Creates a new `Sampler`.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `create_info.anisotropy` is `Some` and contains a value less than 1.0.
+ /// - Panics if `create_info.lod` is empty.
+ pub fn new(
+ device: Arc<Device>,
+ create_info: SamplerCreateInfo,
+ ) -> Result<Arc<Sampler>, SamplerCreationError> {
+ let SamplerCreateInfo {
+ mag_filter,
+ min_filter,
+ mipmap_mode,
+ address_mode,
+ mip_lod_bias,
+ anisotropy,
+ compare,
+ lod,
+ border_color,
+ unnormalized_coordinates,
+ reduction_mode,
+ sampler_ycbcr_conversion,
+ _ne: _,
+ } = create_info;
+
+ for filter in [mag_filter, min_filter] {
+ // VUID-VkSamplerCreateInfo-magFilter-parameter
+ // VUID-VkSamplerCreateInfo-minFilter-parameter
+ filter.validate_device(&device)?;
+ }
+
+ // VUID-VkSamplerCreateInfo-mipmapMode-parameter
+ mipmap_mode.validate_device(&device)?;
+
+ for mode in address_mode {
+ // VUID-VkSamplerCreateInfo-addressModeU-parameter
+ // VUID-VkSamplerCreateInfo-addressModeV-parameter
+ // VUID-VkSamplerCreateInfo-addressModeW-parameter
+ mode.validate_device(&device)?;
+
+ if mode == SamplerAddressMode::ClampToBorder {
+ // VUID-VkSamplerCreateInfo-addressModeU-01078
+ border_color.validate_device(&device)?;
+ }
+ }
+
+ if address_mode.contains(&SamplerAddressMode::MirrorClampToEdge) {
+ if !device.enabled_features().sampler_mirror_clamp_to_edge
+ && !device.enabled_extensions().khr_sampler_mirror_clamp_to_edge
+ {
+ return Err(SamplerCreationError::RequirementNotMet {
+ required_for: "`create_info.address_mode` contains \
+ `SamplerAddressMode::MirrorClampToEdge`",
+ requires_one_of: RequiresOneOf {
+ features: &["sampler_mirror_clamp_to_edge"],
+ device_extensions: &["khr_sampler_mirror_clamp_to_edge"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+
+ {
+ assert!(!lod.is_empty());
+ let limit = device.physical_device().properties().max_sampler_lod_bias;
+ if mip_lod_bias.abs() > limit {
+ return Err(SamplerCreationError::MaxSamplerLodBiasExceeded {
+ requested: mip_lod_bias,
+ maximum: limit,
+ });
+ }
+ }
+
+ // VUID-VkSamplerCreateInfo-samplerMipLodBias-04467
+ if device.enabled_extensions().khr_portability_subset
+ && !device.enabled_features().sampler_mip_lod_bias
+ && mip_lod_bias != 0.0
+ {
+ return Err(SamplerCreationError::RequirementNotMet {
+ required_for: "this device is a portability subset device, and \
+ `create_info.mip_lod_bias` is not zero",
+ requires_one_of: RequiresOneOf {
+ features: &["sampler_mip_lod_bias"],
+ ..Default::default()
+ },
+ });
+ }
+
+ let (anisotropy_enable, max_anisotropy) = if let Some(max_anisotropy) = anisotropy {
+ assert!(max_anisotropy >= 1.0);
+
+ if !device.enabled_features().sampler_anisotropy {
+ return Err(SamplerCreationError::RequirementNotMet {
+ required_for: "`create_info.anisotropy` is `Some`",
+ requires_one_of: RequiresOneOf {
+ features: &["sampler_anisotropy"],
+ ..Default::default()
+ },
+ });
+ }
+
+ let limit = device.physical_device().properties().max_sampler_anisotropy;
+ if max_anisotropy > limit {
+ return Err(SamplerCreationError::MaxSamplerAnisotropyExceeded {
+ requested: max_anisotropy,
+ maximum: limit,
+ });
+ }
+
+ if [mag_filter, min_filter]
+ .into_iter()
+ .any(|filter| filter == Filter::Cubic)
+ {
+ return Err(SamplerCreationError::AnisotropyInvalidFilter {
+ mag_filter,
+ min_filter,
+ });
+ }
+
+ (ash::vk::TRUE, max_anisotropy)
+ } else {
+ (ash::vk::FALSE, 1.0)
+ };
+
+ let (compare_enable, compare_op) = if let Some(compare_op) = compare {
+ // VUID-VkSamplerCreateInfo-compareEnable-01080
+ compare_op.validate_device(&device)?;
+
+ if reduction_mode != SamplerReductionMode::WeightedAverage {
+ return Err(SamplerCreationError::CompareInvalidReductionMode { reduction_mode });
+ }
+
+ (ash::vk::TRUE, compare_op)
+ } else {
+ (ash::vk::FALSE, CompareOp::Never)
+ };
+
+ if unnormalized_coordinates {
+ if min_filter != mag_filter {
+ return Err(
+ SamplerCreationError::UnnormalizedCoordinatesFiltersNotEqual {
+ mag_filter,
+ min_filter,
+ },
+ );
+ }
+
+ if mipmap_mode != SamplerMipmapMode::Nearest {
+ return Err(
+ SamplerCreationError::UnnormalizedCoordinatesInvalidMipmapMode { mipmap_mode },
+ );
+ }
+
+ if lod != (0.0..=0.0) {
+ return Err(SamplerCreationError::UnnormalizedCoordinatesNonzeroLod { lod });
+ }
+
+ if address_mode[0..2].iter().any(|mode| {
+ !matches!(
+ mode,
+ SamplerAddressMode::ClampToEdge | SamplerAddressMode::ClampToBorder
+ )
+ }) {
+ return Err(
+ SamplerCreationError::UnnormalizedCoordinatesInvalidAddressMode {
+ address_mode: [address_mode[0], address_mode[1]],
+ },
+ );
+ }
+
+ if anisotropy.is_some() {
+ return Err(SamplerCreationError::UnnormalizedCoordinatesAnisotropyEnabled);
+ }
+
+ if compare.is_some() {
+ return Err(SamplerCreationError::UnnormalizedCoordinatesCompareEnabled);
+ }
+ }
+
+ let mut sampler_reduction_mode_create_info =
+ if reduction_mode != SamplerReductionMode::WeightedAverage {
+ if !(device.enabled_features().sampler_filter_minmax
+ || device.enabled_extensions().ext_sampler_filter_minmax)
+ {
+ return Err(SamplerCreationError::RequirementNotMet {
+ required_for: "`create_info.reduction_mode` is not \
+ `SamplerReductionMode::WeightedAverage`",
+ requires_one_of: RequiresOneOf {
+ features: &["sampler_filter_minmax"],
+ device_extensions: &["ext_sampler_filter_minmax"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkSamplerReductionModeCreateInfo-reductionMode-parameter
+ reduction_mode.validate_device(&device)?;
+
+ Some(ash::vk::SamplerReductionModeCreateInfo {
+ reduction_mode: reduction_mode.into(),
+ ..Default::default()
+ })
+ } else {
+ None
+ };
+
+ // Don't need to check features because you can't create a conversion object without the
+ // feature anyway.
+ let mut sampler_ycbcr_conversion_info = if let Some(sampler_ycbcr_conversion) =
+ &sampler_ycbcr_conversion
+ {
+ assert_eq!(&device, sampler_ycbcr_conversion.device());
+
+ // Use unchecked, because all validation has been done by the SamplerYcbcrConversion.
+ let potential_format_features = unsafe {
+ device
+ .physical_device()
+ .format_properties_unchecked(sampler_ycbcr_conversion.format().unwrap())
+ .potential_format_features()
+ };
+
+ // VUID-VkSamplerCreateInfo-minFilter-01645
+ if !potential_format_features.intersects(
+ FormatFeatures::SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER,
+ ) && !(mag_filter == sampler_ycbcr_conversion.chroma_filter()
+ && min_filter == sampler_ycbcr_conversion.chroma_filter())
+ {
+ return Err(
+ SamplerCreationError::SamplerYcbcrConversionChromaFilterMismatch {
+ chroma_filter: sampler_ycbcr_conversion.chroma_filter(),
+ mag_filter,
+ min_filter,
+ },
+ );
+ }
+
+ // VUID-VkSamplerCreateInfo-addressModeU-01646
+ if address_mode
+ .into_iter()
+ .any(|mode| !matches!(mode, SamplerAddressMode::ClampToEdge))
+ {
+ return Err(
+ SamplerCreationError::SamplerYcbcrConversionInvalidAddressMode { address_mode },
+ );
+ }
+
+ // VUID-VkSamplerCreateInfo-addressModeU-01646
+ if anisotropy.is_some() {
+ return Err(SamplerCreationError::SamplerYcbcrConversionAnisotropyEnabled);
+ }
+
+ // VUID-VkSamplerCreateInfo-addressModeU-01646
+ if unnormalized_coordinates {
+ return Err(
+ SamplerCreationError::SamplerYcbcrConversionUnnormalizedCoordinatesEnabled,
+ );
+ }
+
+ // VUID-VkSamplerCreateInfo-None-01647
+ if reduction_mode != SamplerReductionMode::WeightedAverage {
+ return Err(
+ SamplerCreationError::SamplerYcbcrConversionInvalidReductionMode {
+ reduction_mode,
+ },
+ );
+ }
+
+ Some(ash::vk::SamplerYcbcrConversionInfo {
+ conversion: sampler_ycbcr_conversion.handle(),
+ ..Default::default()
+ })
+ } else {
+ None
+ };
+
+ let mut create_info = ash::vk::SamplerCreateInfo {
+ flags: ash::vk::SamplerCreateFlags::empty(),
+ mag_filter: mag_filter.into(),
+ min_filter: min_filter.into(),
+ mipmap_mode: mipmap_mode.into(),
+ address_mode_u: address_mode[0].into(),
+ address_mode_v: address_mode[1].into(),
+ address_mode_w: address_mode[2].into(),
+ mip_lod_bias,
+ anisotropy_enable,
+ max_anisotropy,
+ compare_enable,
+ compare_op: compare_op.into(),
+ min_lod: *lod.start(),
+ max_lod: *lod.end(),
+ border_color: border_color.into(),
+ unnormalized_coordinates: unnormalized_coordinates as ash::vk::Bool32,
+ ..Default::default()
+ };
+
+ if let Some(sampler_reduction_mode_create_info) =
+ sampler_reduction_mode_create_info.as_mut()
+ {
+ sampler_reduction_mode_create_info.p_next = create_info.p_next;
+ create_info.p_next = sampler_reduction_mode_create_info as *const _ as *const _;
+ }
+
+ if let Some(sampler_ycbcr_conversion_info) = sampler_ycbcr_conversion_info.as_mut() {
+ sampler_ycbcr_conversion_info.p_next = create_info.p_next;
+ create_info.p_next = sampler_ycbcr_conversion_info as *const _ as *const _;
+ }
+
+ let handle = unsafe {
+ let fns = device.fns();
+ let mut output = MaybeUninit::uninit();
+ (fns.v1_0.create_sampler)(
+ device.handle(),
+ &create_info,
+ ptr::null(),
+ output.as_mut_ptr(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+ output.assume_init()
+ };
+
+ Ok(Arc::new(Sampler {
+ handle,
+ device,
+ id: Self::next_id(),
+ address_mode,
+ anisotropy,
+ border_color: address_mode
+ .into_iter()
+ .any(|mode| mode == SamplerAddressMode::ClampToBorder)
+ .then_some(border_color),
+ compare,
+ lod,
+ mag_filter,
+ min_filter,
+ mip_lod_bias,
+ mipmap_mode,
+ reduction_mode,
+ sampler_ycbcr_conversion,
+ unnormalized_coordinates,
+ }))
+ }
+
+ /// Creates a new `Sampler` from a raw object handle.
+ ///
+ /// # Safety
+ ///
+ /// - `handle` must be a valid Vulkan object handle created from `device`.
+ /// - `create_info` must match the info used to create the object.
+ #[inline]
+ pub unsafe fn from_handle(
+ device: Arc<Device>,
+ handle: ash::vk::Sampler,
+ create_info: SamplerCreateInfo,
+ ) -> Arc<Sampler> {
+ let SamplerCreateInfo {
+ mag_filter,
+ min_filter,
+ mipmap_mode,
+ address_mode,
+ mip_lod_bias,
+ anisotropy,
+ compare,
+ lod,
+ border_color,
+ unnormalized_coordinates,
+ reduction_mode,
+ sampler_ycbcr_conversion,
+ _ne: _,
+ } = create_info;
+
+ Arc::new(Sampler {
+ handle,
+ device,
+ id: Self::next_id(),
+ address_mode,
+ anisotropy,
+ border_color: address_mode
+ .into_iter()
+ .any(|mode| mode == SamplerAddressMode::ClampToBorder)
+ .then_some(border_color),
+ compare,
+ lod,
+ mag_filter,
+ min_filter,
+ mip_lod_bias,
+ mipmap_mode,
+ reduction_mode,
+ sampler_ycbcr_conversion,
+ unnormalized_coordinates,
+ })
+ }
+
+ /// Checks whether this sampler is compatible with `image_view`.
+ pub fn check_can_sample(
+ &self,
+ image_view: &(impl ImageViewAbstract + ?Sized),
+ ) -> Result<(), SamplerImageViewIncompatibleError> {
+ /*
+ Note: Most of these checks come from the Instruction/Sampler/Image View Validation
+ section, and are not strictly VUIDs.
+ https://registry.khronos.org/vulkan/specs/1.2-extensions/html/chap16.html#textures-input-validation
+ */
+
+ if self.compare.is_some() {
+ // VUID-vkCmdDispatch-None-06479
+ if !image_view
+ .format_features()
+ .intersects(FormatFeatures::SAMPLED_IMAGE_DEPTH_COMPARISON)
+ {
+ return Err(SamplerImageViewIncompatibleError::DepthComparisonNotSupported);
+ }
+
+ // The SPIR-V instruction is one of the OpImage*Dref* instructions, the image
+ // view format is one of the depth/stencil formats, and the image view aspect
+ // is not VK_IMAGE_ASPECT_DEPTH_BIT.
+ if !image_view
+ .subresource_range()
+ .aspects
+ .intersects(ImageAspects::DEPTH)
+ {
+ return Err(SamplerImageViewIncompatibleError::DepthComparisonWrongAspect);
+ }
+ } else {
+ if !image_view
+ .format_features()
+ .intersects(FormatFeatures::SAMPLED_IMAGE_FILTER_LINEAR)
+ {
+ // VUID-vkCmdDispatch-magFilter-04553
+ if self.mag_filter == Filter::Linear || self.min_filter == Filter::Linear {
+ return Err(SamplerImageViewIncompatibleError::FilterLinearNotSupported);
+ }
+
+ // VUID-vkCmdDispatch-mipmapMode-04770
+ if self.mipmap_mode == SamplerMipmapMode::Linear {
+ return Err(SamplerImageViewIncompatibleError::MipmapModeLinearNotSupported);
+ }
+ }
+ }
+
+ if self.mag_filter == Filter::Cubic || self.min_filter == Filter::Cubic {
+ // VUID-vkCmdDispatch-None-02692
+ if !image_view
+ .format_features()
+ .intersects(FormatFeatures::SAMPLED_IMAGE_FILTER_CUBIC)
+ {
+ return Err(SamplerImageViewIncompatibleError::FilterCubicNotSupported);
+ }
+
+ // VUID-vkCmdDispatch-filterCubic-02694
+ if !image_view.filter_cubic() {
+ return Err(SamplerImageViewIncompatibleError::FilterCubicNotSupported);
+ }
+
+ // VUID-vkCmdDispatch-filterCubicMinmax-02695
+ if matches!(
+ self.reduction_mode,
+ SamplerReductionMode::Min | SamplerReductionMode::Max
+ ) && !image_view.filter_cubic_minmax()
+ {
+ return Err(SamplerImageViewIncompatibleError::FilterCubicMinmaxNotSupported);
+ }
+ }
+
+ if let Some(border_color) = self.border_color {
+ let aspects = image_view.subresource_range().aspects;
+ let view_scalar_type = ShaderScalarType::from(
+ if aspects.intersects(
+ ImageAspects::COLOR
+ | ImageAspects::PLANE_0
+ | ImageAspects::PLANE_1
+ | ImageAspects::PLANE_2,
+ ) {
+ image_view.format().unwrap().type_color().unwrap()
+ } else if aspects.intersects(ImageAspects::DEPTH) {
+ image_view.format().unwrap().type_depth().unwrap()
+ } else if aspects.intersects(ImageAspects::STENCIL) {
+ image_view.format().unwrap().type_stencil().unwrap()
+ } else {
+ // Per `ImageViewBuilder::aspects` and
+ // VUID-VkDescriptorImageInfo-imageView-01976
+ unreachable!()
+ },
+ );
+
+ match border_color {
+ BorderColor::IntTransparentBlack
+ | BorderColor::IntOpaqueBlack
+ | BorderColor::IntOpaqueWhite => {
+ // The sampler borderColor is an integer type and the image view
+ // format is not one of the VkFormat integer types or a stencil
+ // component of a depth/stencil format.
+ if !matches!(
+ view_scalar_type,
+ ShaderScalarType::Sint | ShaderScalarType::Uint
+ ) {
+ return Err(
+ SamplerImageViewIncompatibleError::BorderColorFormatNotCompatible,
+ );
+ }
+ }
+ BorderColor::FloatTransparentBlack
+ | BorderColor::FloatOpaqueBlack
+ | BorderColor::FloatOpaqueWhite => {
+ // The sampler borderColor is a float type and the image view
+ // format is not one of the VkFormat float types or a depth
+ // component of a depth/stencil format.
+ if !matches!(view_scalar_type, ShaderScalarType::Float) {
+ return Err(
+ SamplerImageViewIncompatibleError::BorderColorFormatNotCompatible,
+ );
+ }
+ }
+ }
+
+ // The sampler borderColor is one of the opaque black colors
+ // (VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK or VK_BORDER_COLOR_INT_OPAQUE_BLACK)
+ // and the image view VkComponentSwizzle for any of the VkComponentMapping
+ // components is not the identity swizzle, and
+ // VkPhysicalDeviceBorderColorSwizzleFeaturesEXT::borderColorSwizzleFromImage
+ // feature is not enabled, and
+ // VkSamplerBorderColorComponentMappingCreateInfoEXT is not specified.
+ if matches!(
+ border_color,
+ BorderColor::FloatOpaqueBlack | BorderColor::IntOpaqueBlack
+ ) && !image_view.component_mapping().is_identity()
+ {
+ return Err(
+ SamplerImageViewIncompatibleError::BorderColorOpaqueBlackNotIdentitySwizzled,
+ );
+ }
+ }
+
+ // The sampler unnormalizedCoordinates is VK_TRUE and any of the limitations of
+ // unnormalized coordinates are violated.
+ // https://registry.khronos.org/vulkan/specs/1.2-extensions/html/chap13.html#samplers-unnormalizedCoordinates
+ if self.unnormalized_coordinates {
+ // The viewType must be either VK_IMAGE_VIEW_TYPE_1D or
+ // VK_IMAGE_VIEW_TYPE_2D.
+ // VUID-vkCmdDispatch-None-02702
+ if !matches!(
+ image_view.view_type(),
+ ImageViewType::Dim1d | ImageViewType::Dim2d
+ ) {
+ return Err(
+ SamplerImageViewIncompatibleError::UnnormalizedCoordinatesViewTypeNotCompatible,
+ );
+ }
+
+ // The image view must have a single layer and a single mip level.
+ if image_view.subresource_range().mip_levels.end
+ - image_view.subresource_range().mip_levels.start
+ != 1
+ {
+ return Err(
+ SamplerImageViewIncompatibleError::UnnormalizedCoordinatesMultipleMipLevels,
+ );
+ }
+ }
+
+ Ok(())
+ }
+
+ /// Returns the address modes for the u, v and w coordinates.
+ #[inline]
+ pub fn address_mode(&self) -> [SamplerAddressMode; 3] {
+ self.address_mode
+ }
+
+ /// Returns the anisotropy mode.
+ #[inline]
+ pub fn anisotropy(&self) -> Option<f32> {
+ self.anisotropy
+ }
+
+ /// Returns the border color if one is used by this sampler.
+ #[inline]
+ pub fn border_color(&self) -> Option<BorderColor> {
+ self.border_color
+ }
+
+ /// Returns the compare operation if the sampler is a compare-mode sampler.
+ #[inline]
+ pub fn compare(&self) -> Option<CompareOp> {
+ self.compare
+ }
+
+ /// Returns the LOD range.
+ #[inline]
+ pub fn lod(&self) -> RangeInclusive<f32> {
+ self.lod.clone()
+ }
+
+ /// Returns the magnification filter.
+ #[inline]
+ pub fn mag_filter(&self) -> Filter {
+ self.mag_filter
+ }
+
+ /// Returns the minification filter.
+ #[inline]
+ pub fn min_filter(&self) -> Filter {
+ self.min_filter
+ }
+
+ /// Returns the mip LOD bias.
+ #[inline]
+ pub fn mip_lod_bias(&self) -> f32 {
+ self.mip_lod_bias
+ }
+
+ /// Returns the mipmap mode.
+ #[inline]
+ pub fn mipmap_mode(&self) -> SamplerMipmapMode {
+ self.mipmap_mode
+ }
+
+ /// Returns the reduction mode.
+ #[inline]
+ pub fn reduction_mode(&self) -> SamplerReductionMode {
+ self.reduction_mode
+ }
+
+ /// Returns a reference to the sampler YCbCr conversion of this sampler, if any.
+ #[inline]
+ pub fn sampler_ycbcr_conversion(&self) -> Option<&Arc<SamplerYcbcrConversion>> {
+ self.sampler_ycbcr_conversion.as_ref()
+ }
+
+ /// Returns true if the sampler uses unnormalized coordinates.
+ #[inline]
+ pub fn unnormalized_coordinates(&self) -> bool {
+ self.unnormalized_coordinates
+ }
+}
+
+impl Drop for Sampler {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ let fns = self.device.fns();
+ (fns.v1_0.destroy_sampler)(self.device.handle(), self.handle, ptr::null());
+ }
+ }
+}
+
+unsafe impl VulkanObject for Sampler {
+ type Handle = ash::vk::Sampler;
+
+ #[inline]
+ fn handle(&self) -> Self::Handle {
+ self.handle
+ }
+}
+
+unsafe impl DeviceOwned for Sampler {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+}
+
+impl_id_counter!(Sampler);
+
+/// Error that can happen when creating an instance.
+#[derive(Clone, Debug, PartialEq)]
+pub enum SamplerCreationError {
+ /// Not enough memory.
+ OomError(OomError),
+
+ /// Too many sampler objects have been created. You must destroy some before creating new ones.
+ /// Note the specs guarantee that at least 4000 samplers can exist simultaneously.
+ TooManyObjects,
+
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+
+ /// Anisotropy was enabled with an invalid filter.
+ AnisotropyInvalidFilter {
+ mag_filter: Filter,
+ min_filter: Filter,
+ },
+
+ /// Depth comparison was enabled with an invalid reduction mode.
+ CompareInvalidReductionMode {
+ reduction_mode: SamplerReductionMode,
+ },
+
+ /// The requested anisotropy level exceeds the device's limits.
+ MaxSamplerAnisotropyExceeded {
+ /// The value that was requested.
+ requested: f32,
+ /// The maximum supported value.
+ maximum: f32,
+ },
+
+ /// The requested mip lod bias exceeds the device's limits.
+ MaxSamplerLodBiasExceeded {
+ /// The value that was requested.
+ requested: f32,
+ /// The maximum supported value.
+ maximum: f32,
+ },
+
+ /// Sampler YCbCr conversion was enabled together with anisotropy.
+ SamplerYcbcrConversionAnisotropyEnabled,
+
+ /// Sampler YCbCr conversion was enabled, and its format does not support
+ /// `sampled_image_ycbcr_conversion_separate_reconstruction_filter`, but `mag_filter` or
+ /// `min_filter` did not match the conversion's `chroma_filter`.
+ SamplerYcbcrConversionChromaFilterMismatch {
+ chroma_filter: Filter,
+ mag_filter: Filter,
+ min_filter: Filter,
+ },
+
+ /// Sampler YCbCr conversion was enabled, but the address mode for `u`, `v` or `w` was
+ /// something other than `ClampToEdge`.
+ SamplerYcbcrConversionInvalidAddressMode {
+ address_mode: [SamplerAddressMode; 3],
+ },
+
+ /// Sampler YCbCr conversion was enabled, but the reduction mode was something other than
+ /// `WeightedAverage`.
+ SamplerYcbcrConversionInvalidReductionMode {
+ reduction_mode: SamplerReductionMode,
+ },
+
+ /// Sampler YCbCr conversion was enabled together with unnormalized coordinates.
+ SamplerYcbcrConversionUnnormalizedCoordinatesEnabled,
+
+ /// Unnormalized coordinates were enabled together with anisotropy.
+ UnnormalizedCoordinatesAnisotropyEnabled,
+
+ /// Unnormalized coordinates were enabled together with depth comparison.
+ UnnormalizedCoordinatesCompareEnabled,
+
+ /// Unnormalized coordinates were enabled, but the min and mag filters were not equal.
+ UnnormalizedCoordinatesFiltersNotEqual {
+ mag_filter: Filter,
+ min_filter: Filter,
+ },
+
+ /// Unnormalized coordinates were enabled, but the address mode for `u` or `v` was something
+ /// other than `ClampToEdge` or `ClampToBorder`.
+ UnnormalizedCoordinatesInvalidAddressMode {
+ address_mode: [SamplerAddressMode; 2],
+ },
+
+ /// Unnormalized coordinates were enabled, but the mipmap mode was not `Nearest`.
+ UnnormalizedCoordinatesInvalidMipmapMode { mipmap_mode: SamplerMipmapMode },
+
+ /// Unnormalized coordinates were enabled, but the LOD range was not zero.
+ UnnormalizedCoordinatesNonzeroLod { lod: RangeInclusive<f32> },
+}
+
+impl Error for SamplerCreationError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ SamplerCreationError::OomError(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+impl Display for SamplerCreationError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::OomError(_) => write!(f, "not enough memory available"),
+ Self::TooManyObjects => write!(f, "too many simultaneous sampler objects"),
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ Self::AnisotropyInvalidFilter { .. } => {
+ write!(f, "anisotropy was enabled with an invalid filter")
+ }
+ Self::CompareInvalidReductionMode { .. } => write!(
+ f,
+ "depth comparison was enabled with an invalid reduction mode",
+ ),
+ Self::MaxSamplerAnisotropyExceeded { .. } => {
+ write!(f, "max_sampler_anisotropy limit exceeded")
+ }
+ Self::MaxSamplerLodBiasExceeded { .. } => write!(f, "mip lod bias limit exceeded"),
+ Self::SamplerYcbcrConversionAnisotropyEnabled => write!(
+ f,
+ "sampler YCbCr conversion was enabled together with anisotropy",
+ ),
+ Self::SamplerYcbcrConversionChromaFilterMismatch { .. } => write!(
+ f,
+ "sampler YCbCr conversion was enabled, and its format does not support
+ `sampled_image_ycbcr_conversion_separate_reconstruction_filter`, but `mag_filter`
+ or `min_filter` did not match the conversion's `chroma_filter`",
+ ),
+ Self::SamplerYcbcrConversionInvalidAddressMode { .. } => write!(
+ f,
+ "sampler YCbCr conversion was enabled, but the address mode for u, v or w was
+ something other than `ClampToEdge`",
+ ),
+ Self::SamplerYcbcrConversionInvalidReductionMode { .. } => write!(
+ f,
+ "sampler YCbCr conversion was enabled, but the reduction mode was something other \
+ than `WeightedAverage`",
+ ),
+ Self::SamplerYcbcrConversionUnnormalizedCoordinatesEnabled => write!(
+ f,
+ "sampler YCbCr conversion was enabled together with unnormalized coordinates",
+ ),
+ Self::UnnormalizedCoordinatesAnisotropyEnabled => write!(
+ f,
+ "unnormalized coordinates were enabled together with anisotropy",
+ ),
+ Self::UnnormalizedCoordinatesCompareEnabled => write!(
+ f,
+ "unnormalized coordinates were enabled together with depth comparison",
+ ),
+ Self::UnnormalizedCoordinatesFiltersNotEqual { .. } => write!(
+ f,
+ "unnormalized coordinates were enabled, but the min and mag filters were not equal",
+ ),
+ Self::UnnormalizedCoordinatesInvalidAddressMode { .. } => write!(
+ f,
+ "unnormalized coordinates were enabled, but the address mode for u or v was \
+ something other than `ClampToEdge` or `ClampToBorder`",
+ ),
+ Self::UnnormalizedCoordinatesInvalidMipmapMode { .. } => write!(
+ f,
+ "unnormalized coordinates were enabled, but the mipmap mode was not `Nearest`",
+ ),
+ Self::UnnormalizedCoordinatesNonzeroLod { .. } => write!(
+ f,
+ "unnormalized coordinates were enabled, but the LOD range was not zero",
+ ),
+ }
+ }
+}
+
+impl From<OomError> for SamplerCreationError {
+ fn from(err: OomError) -> Self {
+ Self::OomError(err)
+ }
+}
+
+impl From<VulkanError> for SamplerCreationError {
+ fn from(err: VulkanError) -> Self {
+ match err {
+ err @ VulkanError::OutOfHostMemory => Self::OomError(OomError::from(err)),
+ err @ VulkanError::OutOfDeviceMemory => Self::OomError(OomError::from(err)),
+ VulkanError::TooManyObjects => Self::TooManyObjects,
+ _ => panic!("unexpected error: {:?}", err),
+ }
+ }
+}
+
+impl From<RequirementNotMet> for SamplerCreationError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
+ }
+ }
+}
+
+/// Parameters to create a new `Sampler`.
+#[derive(Clone, Debug)]
+pub struct SamplerCreateInfo {
+ /// How the sampled value of a single mipmap should be calculated,
+ /// when magnification is applied (LOD <= 0.0).
+ ///
+ /// The default value is [`Nearest`](Filter::Nearest).
+ pub mag_filter: Filter,
+
+ /// How the sampled value of a single mipmap should be calculated,
+ /// when minification is applied (LOD > 0.0).
+ ///
+ /// The default value is [`Nearest`](Filter::Nearest).
+ pub min_filter: Filter,
+
+ /// How the final sampled value should be calculated from the samples of individual
+ /// mipmaps.
+ ///
+ /// The default value is [`Nearest`](SamplerMipmapMode::Nearest).
+ pub mipmap_mode: SamplerMipmapMode,
+
+ /// How out-of-range texture coordinates should be treated, for the `u`, `v` and `w` texture
+ /// coordinate indices respectively.
+ ///
+ /// The default value is [`ClampToEdge`](SamplerAddressMode::ClampToEdge).
+ pub address_mode: [SamplerAddressMode; 3],
+
+ /// The bias value to be added to the base LOD before clamping.
+ ///
+ /// The absolute value of the provided value must not exceed the
+ /// [`max_sampler_lod_bias`](crate::device::Properties::max_sampler_lod_bias) limit of the
+ /// device.
+ ///
+ /// On [portability subset](crate::instance#portability-subset-devices-and-the-enumerate_portability-flag)
+ /// devices, if `mip_lod_bias` is not `0.0`, the
+ /// [`sampler_mip_lod_bias`](crate::device::Features::sampler_mip_lod_bias)
+ /// feature must be enabled on the device.
+ ///
+ /// The default value is `0.0`.
+ pub mip_lod_bias: f32,
+
+ /// Whether anisotropic texel filtering is enabled (`Some`), and the maximum anisotropy value
+ /// to use if it is enabled.
+ ///
+ /// Anisotropic filtering is a special filtering mode that takes into account the differences in
+ /// scaling between the horizontal and vertical framebuffer axes.
+ ///
+ /// If set to `Some`, the [`sampler_anisotropy`](crate::device::Features::sampler_anisotropy)
+ /// feature must be enabled on the device, the provided maximum value must not exceed the
+ /// [`max_sampler_anisotropy`](crate::device::Properties::max_sampler_anisotropy) limit, and
+ /// the [`Cubic`](Filter::Cubic) filter must not be used.
+ ///
+ /// The default value is `None`.
+ pub anisotropy: Option<f32>,
+
+ /// Whether depth comparison is enabled (`Some`), and the comparison operator to use if it is
+ /// enabled.
+ ///
+ /// Depth comparison is an alternative mode for samplers that can be used in combination with
+ /// image views specifying the depth aspect. Instead of returning a value that is sampled from
+ /// the image directly, a comparison operation is applied between the sampled value and a
+ /// reference value that is specified as part of the operation. The result is binary: 1.0 if the
+ /// operation returns `true`, 0.0 if it returns `false`.
+ ///
+ /// If set to `Some`, the `reduction_mode` must be set to
+ /// [`WeightedAverage`](SamplerReductionMode::WeightedAverage).
+ ///
+ /// On [portability subset](crate::instance#portability-subset-devices-and-the-enumerate_portability-flag)
+ /// devices, if the sampler is going to be used as a mutable sampler (written to descriptor sets
+ /// rather than being an immutable part of a descriptor set layout), the
+ /// [`mutable_comparison_samplers`](crate::device::Features::mutable_comparison_samplers)
+ /// feature must be enabled on the device.
+ ///
+ /// The default value is `None`.
+ pub compare: Option<CompareOp>,
+
+ /// The range that LOD values must be clamped to.
+ ///
+ /// If the end of the range is set to [`LOD_CLAMP_NONE`], it is unbounded.
+ ///
+ /// The default value is `0.0..=0.0`.
+ pub lod: RangeInclusive<f32>,
+
+ /// The border color to use if `address_mode` is set to
+ /// [`ClampToBorder`](SamplerAddressMode::ClampToBorder).
+ ///
+ /// The default value is [`FloatTransparentBlack`](BorderColor::FloatTransparentBlack).
+ pub border_color: BorderColor,
+
+ /// Whether unnormalized texture coordinates are enabled.
+ ///
+ /// When a sampler is set to use unnormalized coordinates as input, the texture coordinates are
+ /// not scaled by the size of the image, and therefore range up to the size of the image rather
+ /// than 1.0. Enabling this comes with several restrictions:
+ /// - `min_filter` and `mag_filter` must be equal.
+ /// - `mipmap_mode` must be [`Nearest`](SamplerMipmapMode::Nearest).
+ /// - The `lod` range must be `0.0..=0.0`.
+ /// - `address_mode` for u and v must be either
+ /// [`ClampToEdge`](`SamplerAddressMode::ClampToEdge`) or
+ /// [`ClampToBorder`](`SamplerAddressMode::ClampToBorder`).
+ /// - Anisotropy and depth comparison must be disabled.
+ ///
+ /// Some restrictions also apply to the image view being sampled:
+ /// - The view type must be [`Dim1d`](crate::image::view::ImageViewType::Dim1d) or
+ /// [`Dim2d`](crate::image::view::ImageViewType::Dim2d). Arrayed types are not allowed.
+ /// - It must have a single mipmap level.
+ ///
+ /// Finally, restrictions apply to the sampling operations that can be used in a shader:
+ /// - Only explicit LOD operations are allowed, implicit LOD operations are not.
+ /// - Sampling with projection is not allowed.
+ /// - Sampling with an LOD bias is not allowed.
+ /// - Sampling with an offset is not allowed.
+ ///
+ /// The default value is `false`.
+ pub unnormalized_coordinates: bool,
+
+ /// How the value sampled from a mipmap should be calculated from the selected
+ /// pixels, for the `Linear` and `Cubic` filters.
+ ///
+ /// The default value is [`WeightedAverage`](SamplerReductionMode::WeightedAverage).
+ pub reduction_mode: SamplerReductionMode,
+
+ /// Adds a sampler YCbCr conversion to the sampler.
+ ///
+ /// If set to `Some`, several restrictions apply:
+ /// - If the `format` of `conversion` does not support
+ /// `sampled_image_ycbcr_conversion_separate_reconstruction_filter`, then `mag_filter` and
+ /// `min_filter` must be equal to the `chroma_filter` of `conversion`.
+ /// - `address_mode` for u, v and w must be [`ClampToEdge`](`SamplerAddressMode::ClampToEdge`).
+ /// - Anisotropy and unnormalized coordinates must be disabled.
+ /// - The `reduction_mode` must be [`WeightedAverage`](SamplerReductionMode::WeightedAverage).
+ ///
+ /// In addition, the sampler must only be used as an immutable sampler within a descriptor set
+ /// layout, and only in a combined image sampler descriptor.
+ ///
+ /// The default value is `None`.
+ pub sampler_ycbcr_conversion: Option<Arc<SamplerYcbcrConversion>>,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for SamplerCreateInfo {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ mag_filter: Filter::Nearest,
+ min_filter: Filter::Nearest,
+ mipmap_mode: SamplerMipmapMode::Nearest,
+ address_mode: [SamplerAddressMode::ClampToEdge; 3],
+ mip_lod_bias: 0.0,
+ anisotropy: None,
+ compare: None,
+ lod: 0.0..=0.0,
+ border_color: BorderColor::FloatTransparentBlack,
+ unnormalized_coordinates: false,
+ reduction_mode: SamplerReductionMode::WeightedAverage,
+ sampler_ycbcr_conversion: None,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+impl SamplerCreateInfo {
+ /// Shortcut for creating a sampler with linear sampling, linear mipmaps, and with the repeat
+ /// mode for borders.
+ #[inline]
+ pub fn simple_repeat_linear() -> Self {
+ Self {
+ mag_filter: Filter::Linear,
+ min_filter: Filter::Linear,
+ mipmap_mode: SamplerMipmapMode::Linear,
+ address_mode: [SamplerAddressMode::Repeat; 3],
+ lod: 0.0..=LOD_CLAMP_NONE,
+ ..Default::default()
+ }
+ }
+
+ /// Shortcut for creating a sampler with linear sampling, that only uses the main level of
+ /// images, and with the repeat mode for borders.
+ #[inline]
+ pub fn simple_repeat_linear_no_mipmap() -> Self {
+ Self {
+ mag_filter: Filter::Linear,
+ min_filter: Filter::Linear,
+ address_mode: [SamplerAddressMode::Repeat; 3],
+ lod: 0.0..=1.0,
+ ..Default::default()
+ }
+ }
+}
+
+/// A special value to indicate that the maximum LOD should not be clamped.
+pub const LOD_CLAMP_NONE: f32 = ash::vk::LOD_CLAMP_NONE;
+
+/// A mapping between components of a source format and components read by a shader.
+#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
+pub struct ComponentMapping {
+ /// First component.
+ pub r: ComponentSwizzle,
+ /// Second component.
+ pub g: ComponentSwizzle,
+ /// Third component.
+ pub b: ComponentSwizzle,
+ /// Fourth component.
+ pub a: ComponentSwizzle,
+}
+
+impl ComponentMapping {
+ /// Creates a `ComponentMapping` with all components identity swizzled.
+ #[inline]
+ pub fn identity() -> Self {
+ Self::default()
+ }
+
+ /// Returns `true` if all components are identity swizzled,
+ /// meaning that all the members are `Identity` or the name of that member.
+ ///
+ /// Certain operations require views that are identity swizzled, and will return an error
+ /// otherwise. For example, attaching a view to a framebuffer is only possible if the view is
+ /// identity swizzled.
+ #[inline]
+ pub fn is_identity(&self) -> bool {
+ self.r_is_identity() && self.g_is_identity() && self.b_is_identity() && self.a_is_identity()
+ }
+
+ /// Returns `true` if the red component mapping is identity swizzled.
+ #[inline]
+ pub fn r_is_identity(&self) -> bool {
+ matches!(self.r, ComponentSwizzle::Identity | ComponentSwizzle::Red)
+ }
+
+ /// Returns `true` if the green component mapping is identity swizzled.
+ #[inline]
+ pub fn g_is_identity(&self) -> bool {
+ matches!(self.g, ComponentSwizzle::Identity | ComponentSwizzle::Green)
+ }
+
+ /// Returns `true` if the blue component mapping is identity swizzled.
+ #[inline]
+ pub fn b_is_identity(&self) -> bool {
+ matches!(self.b, ComponentSwizzle::Identity | ComponentSwizzle::Blue)
+ }
+
+ /// Returns `true` if the alpha component mapping is identity swizzled.
+ #[inline]
+ pub fn a_is_identity(&self) -> bool {
+ matches!(self.a, ComponentSwizzle::Identity | ComponentSwizzle::Alpha)
+ }
+
+ /// Returns the component indices that each component reads from. The index is `None` if the
+ /// component has a fixed value and is not read from anywhere (`Zero` or `One`).
+ #[inline]
+ pub fn component_map(&self) -> [Option<usize>; 4] {
+ [
+ match self.r {
+ ComponentSwizzle::Identity => Some(0),
+ ComponentSwizzle::Zero => None,
+ ComponentSwizzle::One => None,
+ ComponentSwizzle::Red => Some(0),
+ ComponentSwizzle::Green => Some(1),
+ ComponentSwizzle::Blue => Some(2),
+ ComponentSwizzle::Alpha => Some(3),
+ },
+ match self.g {
+ ComponentSwizzle::Identity => Some(1),
+ ComponentSwizzle::Zero => None,
+ ComponentSwizzle::One => None,
+ ComponentSwizzle::Red => Some(0),
+ ComponentSwizzle::Green => Some(1),
+ ComponentSwizzle::Blue => Some(2),
+ ComponentSwizzle::Alpha => Some(3),
+ },
+ match self.b {
+ ComponentSwizzle::Identity => Some(2),
+ ComponentSwizzle::Zero => None,
+ ComponentSwizzle::One => None,
+ ComponentSwizzle::Red => Some(0),
+ ComponentSwizzle::Green => Some(1),
+ ComponentSwizzle::Blue => Some(2),
+ ComponentSwizzle::Alpha => Some(3),
+ },
+ match self.a {
+ ComponentSwizzle::Identity => Some(3),
+ ComponentSwizzle::Zero => None,
+ ComponentSwizzle::One => None,
+ ComponentSwizzle::Red => Some(0),
+ ComponentSwizzle::Green => Some(1),
+ ComponentSwizzle::Blue => Some(2),
+ ComponentSwizzle::Alpha => Some(3),
+ },
+ ]
+ }
+}
+
+impl From<ComponentMapping> for ash::vk::ComponentMapping {
+ #[inline]
+ fn from(value: ComponentMapping) -> Self {
+ Self {
+ r: value.r.into(),
+ g: value.g.into(),
+ b: value.b.into(),
+ a: value.a.into(),
+ }
+ }
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// Describes the value that an individual component must return when being accessed.
+ ComponentSwizzle = ComponentSwizzle(i32);
+
+ /// Returns the value that this component should normally have.
+ ///
+ /// This is the `Default` value.
+ Identity = IDENTITY,
+
+ /// Always return zero.
+ Zero = ZERO,
+
+ /// Always return one.
+ One = ONE,
+
+ /// Returns the value of the first component.
+ Red = R,
+
+ /// Returns the value of the second component.
+ Green = G,
+
+ /// Returns the value of the third component.
+ Blue = B,
+
+ /// Returns the value of the fourth component.
+ Alpha = A,
+}
+
+impl Default for ComponentSwizzle {
+ #[inline]
+ fn default() -> ComponentSwizzle {
+ ComponentSwizzle::Identity
+ }
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// Describes how the color of each pixel should be determined.
+ Filter = Filter(i32);
+
+ /// The pixel whose center is nearest to the requested coordinates is taken from the source
+ /// and its value is returned as-is.
+ Nearest = NEAREST,
+
+ /// The 8/4/2 pixels (depending on view dimensionality) whose center surround the requested
+ /// coordinates are taken, then their values are combined according to the chosen
+ /// `reduction_mode`.
+ Linear = LINEAR,
+
+ /// The 64/16/4 pixels (depending on the view dimensionality) whose center surround the
+ /// requested coordinates are taken, then their values are combined according to the chosen
+ /// `reduction_mode`.
+ ///
+ /// The [`ext_filter_cubic`](crate::device::DeviceExtensions::ext_filter_cubic) extension must
+ /// be enabled on the device, and anisotropy must be disabled. Sampled image views must have
+ /// a type of [`Dim2d`](crate::image::view::ImageViewType::Dim2d).
+ Cubic = CUBIC_EXT {
+ device_extensions: [ext_filter_cubic, img_filter_cubic],
+ },
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// Describes which mipmap from the source to use.
+ SamplerMipmapMode = SamplerMipmapMode(i32);
+
+ /// Use the mipmap whose dimensions are the nearest to the dimensions of the destination.
+ Nearest = NEAREST,
+
+ /// Take the mipmap whose dimensions are no greater than that of the destination together
+ /// with the next higher level mipmap, calculate the value for both, and interpolate them.
+ Linear = LINEAR,
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// How the sampler should behave when it needs to access a pixel that is out of range of the
+ /// texture.
+ SamplerAddressMode = SamplerAddressMode(i32);
+
+ /// Repeat the texture. In other words, the pixel at coordinate `x + 1.0` is the same as the
+ /// one at coordinate `x`.
+ Repeat = REPEAT,
+
+ /// Repeat the texture but mirror it at every repetition. In other words, the pixel at
+ /// coordinate `x + 1.0` is the same as the one at coordinate `1.0 - x`.
+ MirroredRepeat = MIRRORED_REPEAT,
+
+ /// The coordinates are clamped to the valid range. Coordinates below 0.0 have the same value
+ /// as coordinate 0.0. Coordinates over 1.0 have the same value as coordinate 1.0.
+ ClampToEdge = CLAMP_TO_EDGE,
+
+ /// Any pixel out of range is colored using the colour selected with the `border_color` on the
+ /// `SamplerBuilder`.
+ ///
+ /// When this mode is chosen, the numeric type of the image view's format must match the border
+ /// color. When using a floating-point border color, the sampler can only be used with
+ /// floating-point or depth image views. When using an integer border color, the sampler can
+ /// only be used with integer or stencil image views. In addition to this, you can't use an
+ /// opaque black border color with an image view that uses component swizzling.
+ ClampToBorder = CLAMP_TO_BORDER,
+
+ /// Similar to `MirroredRepeat`, except that coordinates are clamped to the range
+ /// `[-1.0, 1.0]`.
+ ///
+ /// The [`sampler_mirror_clamp_to_edge`](crate::device::Features::sampler_mirror_clamp_to_edge)
+ /// feature or the
+ /// [`khr_sampler_mirror_clamp_to_edge`](crate::device::DeviceExtensions::khr_sampler_mirror_clamp_to_edge)
+ /// extension must be enabled on the device.
+ MirrorClampToEdge = MIRROR_CLAMP_TO_EDGE {
+ api_version: V1_2,
+ device_extensions: [khr_sampler_mirror_clamp_to_edge],
+ },
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// The color to use for the border of an image.
+ ///
+ /// Only relevant if you use `ClampToBorder`.
+ ///
+ /// Using a border color restricts the sampler to either floating-point images or integer images.
+ BorderColor = BorderColor(i32);
+
+ /// The value `(0.0, 0.0, 0.0, 0.0)`. Can only be used with floating-point images.
+ FloatTransparentBlack = FLOAT_TRANSPARENT_BLACK,
+
+ /// The value `(0, 0, 0, 0)`. Can only be used with integer images.
+ IntTransparentBlack = INT_TRANSPARENT_BLACK,
+
+ /// The value `(0.0, 0.0, 0.0, 1.0)`. Can only be used with floating-point identity-swizzled
+ /// images.
+ FloatOpaqueBlack = FLOAT_OPAQUE_BLACK,
+
+ /// The value `(0, 0, 0, 1)`. Can only be used with integer identity-swizzled images.
+ IntOpaqueBlack = INT_OPAQUE_BLACK,
+
+ /// The value `(1.0, 1.0, 1.0, 1.0)`. Can only be used with floating-point images.
+ FloatOpaqueWhite = FLOAT_OPAQUE_WHITE,
+
+ /// The value `(1, 1, 1, 1)`. Can only be used with integer images.
+ IntOpaqueWhite = INT_OPAQUE_WHITE,
+
+ /* TODO: enable
+ // TODO: document
+ FloatCustom = VK_BORDER_COLOR_FLOAT_CUSTOM_EXT {
+ device_extensions: [ext_custom_border_color],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ IntCustom = INT_CUSTOM_EXT {
+ device_extensions: [ext_custom_border_color],
+ },*/
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// Describes how the value sampled from a mipmap should be calculated from the selected
+ /// pixels, for the `Linear` and `Cubic` filters.
+ SamplerReductionMode = SamplerReductionMode(i32);
+
+ /// Calculates a weighted average of the selected pixels. For `Linear` filtering the pixels
+ /// are evenly weighted, for `Cubic` filtering they use Catmull-Rom weights.
+ WeightedAverage = WEIGHTED_AVERAGE,
+
+ /// Calculates the minimum of the selected pixels.
+ ///
+ /// The [`sampler_filter_minmax`](crate::device::Features::sampler_filter_minmax)
+ /// feature or the
+ /// [`ext_sampler_filter_minmax`](crate::device::DeviceExtensions::ext_sampler_filter_minmax)
+ /// extension must be enabled on the device.
+ Min = MIN,
+
+ /// Calculates the maximum of the selected pixels.
+ ///
+ /// The [`sampler_filter_minmax`](crate::device::Features::sampler_filter_minmax)
+ /// feature or the
+ /// [`ext_sampler_filter_minmax`](crate::device::DeviceExtensions::ext_sampler_filter_minmax)
+ /// extension must be enabled on the device.
+ Max = MAX,
+}
+
+#[derive(Clone, Copy, Debug)]
+pub enum SamplerImageViewIncompatibleError {
+ /// The sampler has a border color with a numeric type different from the image view.
+ BorderColorFormatNotCompatible,
+
+ /// The sampler has an opaque black border color, but the image view is not identity swizzled.
+ BorderColorOpaqueBlackNotIdentitySwizzled,
+
+ /// The sampler has depth comparison enabled, but this is not supported by the image view.
+ DepthComparisonNotSupported,
+
+ /// The sampler has depth comparison enabled, but the image view does not select the `depth`
+ /// aspect.
+ DepthComparisonWrongAspect,
+
+ /// The sampler uses a linear filter, but this is not supported by the image view's format
+ /// features.
+ FilterLinearNotSupported,
+
+ /// The sampler uses a cubic filter, but this is not supported by the image view's format
+ /// features.
+ FilterCubicNotSupported,
+
+ /// The sampler uses a cubic filter with a `Min` or `Max` reduction mode, but this is not
+ /// supported by the image view's format features.
+ FilterCubicMinmaxNotSupported,
+
+ /// The sampler uses a linear mipmap mode, but this is not supported by the image view's format
+ /// features.
+ MipmapModeLinearNotSupported,
+
+ /// The sampler uses unnormalized coordinates, but the image view has multiple mip levels.
+ UnnormalizedCoordinatesMultipleMipLevels,
+
+ /// The sampler uses unnormalized coordinates, but the image view has a type other than `Dim1d`
+ /// or `Dim2d`.
+ UnnormalizedCoordinatesViewTypeNotCompatible,
+}
+
+impl Error for SamplerImageViewIncompatibleError {}
+
+impl Display for SamplerImageViewIncompatibleError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::BorderColorFormatNotCompatible => write!(
+ f,
+ "the sampler has a border color with a numeric type different from the image view",
+ ),
+ Self::BorderColorOpaqueBlackNotIdentitySwizzled => write!(
+ f,
+ "the sampler has an opaque black border color, but the image view is not identity \
+ swizzled",
+ ),
+ Self::DepthComparisonNotSupported => write!(
+ f,
+ "the sampler has depth comparison enabled, but this is not supported by the image \
+ view",
+ ),
+ Self::DepthComparisonWrongAspect => write!(
+ f,
+ "the sampler has depth comparison enabled, but the image view does not select the \
+ `depth` aspect",
+ ),
+ Self::FilterLinearNotSupported => write!(
+ f,
+ "the sampler uses a linear filter, but this is not supported by the image view's \
+ format features",
+ ),
+ Self::FilterCubicNotSupported => write!(
+ f,
+ "the sampler uses a cubic filter, but this is not supported by the image view's \
+ format features",
+ ),
+ Self::FilterCubicMinmaxNotSupported => write!(
+ f,
+ "the sampler uses a cubic filter with a `Min` or `Max` reduction mode, but this is \
+ not supported by the image view's format features",
+ ),
+ Self::MipmapModeLinearNotSupported => write!(
+ f,
+ "the sampler uses a linear mipmap mode, but this is not supported by the image \
+ view's format features",
+ ),
+ Self::UnnormalizedCoordinatesMultipleMipLevels => write!(
+ f,
+ "the sampler uses unnormalized coordinates, but the image view has multiple mip \
+ levels",
+ ),
+ Self::UnnormalizedCoordinatesViewTypeNotCompatible => write!(
+ f,
+ "the sampler uses unnormalized coordinates, but the image view has a type other \
+ than `Dim1d` or `Dim2d`",
+ ),
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::{
+ pipeline::graphics::depth_stencil::CompareOp,
+ sampler::{
+ Filter, Sampler, SamplerAddressMode, SamplerCreateInfo, SamplerCreationError,
+ SamplerReductionMode,
+ },
+ RequiresOneOf,
+ };
+
+ #[test]
+ fn create_regular() {
+ let (device, _queue) = gfx_dev_and_queue!();
+
+ let s = Sampler::new(
+ device,
+ SamplerCreateInfo {
+ mag_filter: Filter::Linear,
+ min_filter: Filter::Linear,
+ address_mode: [SamplerAddressMode::Repeat; 3],
+ mip_lod_bias: 1.0,
+ lod: 0.0..=2.0,
+ ..Default::default()
+ },
+ )
+ .unwrap();
+ assert!(s.compare().is_none());
+ assert!(!s.unnormalized_coordinates());
+ }
+
+ #[test]
+ fn create_compare() {
+ let (device, _queue) = gfx_dev_and_queue!();
+
+ let s = Sampler::new(
+ device,
+ SamplerCreateInfo {
+ mag_filter: Filter::Linear,
+ min_filter: Filter::Linear,
+ address_mode: [SamplerAddressMode::Repeat; 3],
+ mip_lod_bias: 1.0,
+ compare: Some(CompareOp::Less),
+ lod: 0.0..=2.0,
+ ..Default::default()
+ },
+ )
+ .unwrap();
+ assert!(s.compare().is_some());
+ assert!(!s.unnormalized_coordinates());
+ }
+
+ #[test]
+ fn create_unnormalized() {
+ let (device, _queue) = gfx_dev_and_queue!();
+
+ let s = Sampler::new(
+ device,
+ SamplerCreateInfo {
+ mag_filter: Filter::Linear,
+ min_filter: Filter::Linear,
+ unnormalized_coordinates: true,
+ ..Default::default()
+ },
+ )
+ .unwrap();
+ assert!(s.compare().is_none());
+ assert!(s.unnormalized_coordinates());
+ }
+
+ #[test]
+ fn simple_repeat_linear() {
+ let (device, _queue) = gfx_dev_and_queue!();
+ let _ = Sampler::new(device, SamplerCreateInfo::simple_repeat_linear());
+ }
+
+ #[test]
+ fn simple_repeat_linear_no_mipmap() {
+ let (device, _queue) = gfx_dev_and_queue!();
+ let _ = Sampler::new(device, SamplerCreateInfo::simple_repeat_linear_no_mipmap());
+ }
+
+ #[test]
+ fn min_lod_inferior() {
+ let (device, _queue) = gfx_dev_and_queue!();
+
+ assert_should_panic!({
+ let _ = Sampler::new(
+ device,
+ SamplerCreateInfo {
+ mag_filter: Filter::Linear,
+ min_filter: Filter::Linear,
+ address_mode: [SamplerAddressMode::Repeat; 3],
+ mip_lod_bias: 1.0,
+ lod: 5.0..=2.0,
+ ..Default::default()
+ },
+ );
+ });
+ }
+
+ #[test]
+ fn max_anisotropy() {
+ let (device, _queue) = gfx_dev_and_queue!();
+
+ assert_should_panic!({
+ let _ = Sampler::new(
+ device,
+ SamplerCreateInfo {
+ mag_filter: Filter::Linear,
+ min_filter: Filter::Linear,
+ address_mode: [SamplerAddressMode::Repeat; 3],
+ mip_lod_bias: 1.0,
+ anisotropy: Some(0.5),
+ lod: 0.0..=2.0,
+ ..Default::default()
+ },
+ );
+ });
+ }
+
+ #[test]
+ fn anisotropy_feature() {
+ let (device, _queue) = gfx_dev_and_queue!();
+
+ let r = Sampler::new(
+ device,
+ SamplerCreateInfo {
+ mag_filter: Filter::Linear,
+ min_filter: Filter::Linear,
+ address_mode: [SamplerAddressMode::Repeat; 3],
+ mip_lod_bias: 1.0,
+ anisotropy: Some(2.0),
+ lod: 0.0..=2.0,
+ ..Default::default()
+ },
+ );
+
+ match r {
+ Err(SamplerCreationError::RequirementNotMet {
+ requires_one_of: RequiresOneOf { features, .. },
+ ..
+ }) if features.contains(&"sampler_anisotropy") => (),
+ _ => panic!(),
+ }
+ }
+
+ #[test]
+ fn anisotropy_limit() {
+ let (device, _queue) = gfx_dev_and_queue!(sampler_anisotropy);
+
+ let r = Sampler::new(
+ device,
+ SamplerCreateInfo {
+ mag_filter: Filter::Linear,
+ min_filter: Filter::Linear,
+ address_mode: [SamplerAddressMode::Repeat; 3],
+ mip_lod_bias: 1.0,
+ anisotropy: Some(100000000.0),
+ lod: 0.0..=2.0,
+ ..Default::default()
+ },
+ );
+
+ match r {
+ Err(SamplerCreationError::MaxSamplerAnisotropyExceeded { .. }) => (),
+ _ => panic!(),
+ }
+ }
+
+ #[test]
+ fn mip_lod_bias_limit() {
+ let (device, _queue) = gfx_dev_and_queue!();
+
+ let r = Sampler::new(
+ device,
+ SamplerCreateInfo {
+ mag_filter: Filter::Linear,
+ min_filter: Filter::Linear,
+ address_mode: [SamplerAddressMode::Repeat; 3],
+ mip_lod_bias: 100000000.0,
+ lod: 0.0..=2.0,
+ ..Default::default()
+ },
+ );
+
+ match r {
+ Err(SamplerCreationError::MaxSamplerLodBiasExceeded { .. }) => (),
+ _ => panic!(),
+ }
+ }
+
+ #[test]
+ fn sampler_mirror_clamp_to_edge_extension() {
+ let (device, _queue) = gfx_dev_and_queue!();
+
+ let r = Sampler::new(
+ device,
+ SamplerCreateInfo {
+ mag_filter: Filter::Linear,
+ min_filter: Filter::Linear,
+ address_mode: [SamplerAddressMode::MirrorClampToEdge; 3],
+ mip_lod_bias: 1.0,
+ lod: 0.0..=2.0,
+ ..Default::default()
+ },
+ );
+
+ match r {
+ Err(SamplerCreationError::RequirementNotMet {
+ requires_one_of:
+ RequiresOneOf {
+ features,
+ device_extensions,
+ ..
+ },
+ ..
+ }) if features.contains(&"sampler_mirror_clamp_to_edge")
+ && device_extensions.contains(&"khr_sampler_mirror_clamp_to_edge") => {}
+ _ => panic!(),
+ }
+ }
+
+ #[test]
+ fn sampler_filter_minmax_extension() {
+ let (device, _queue) = gfx_dev_and_queue!();
+
+ let r = Sampler::new(
+ device,
+ SamplerCreateInfo {
+ mag_filter: Filter::Linear,
+ min_filter: Filter::Linear,
+ reduction_mode: SamplerReductionMode::Min,
+ ..Default::default()
+ },
+ );
+
+ match r {
+ Err(SamplerCreationError::RequirementNotMet {
+ requires_one_of:
+ RequiresOneOf {
+ features,
+ device_extensions,
+ ..
+ },
+ ..
+ }) if features.contains(&"sampler_filter_minmax")
+ && device_extensions.contains(&"ext_sampler_filter_minmax") => {}
+ _ => panic!(),
+ }
+ }
+}
diff --git a/src/sampler/ycbcr.rs b/src/sampler/ycbcr.rs
new file mode 100644
index 0000000..9d9aaf7
--- /dev/null
+++ b/src/sampler/ycbcr.rs
@@ -0,0 +1,809 @@
+// Copyright (c) 2022 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+//! Conversion from sampled YCbCr image data to RGB shader data.
+//!
+//! A sampler YCbCr conversion is an object that assists a sampler when converting from YCbCr
+//! formats and/or YCbCr texel input data. It is used to read frames of video data within a shader,
+//! possibly to apply it as texture on a rendered primitive. Sampler YCbCr conversion can only be
+//! used with certain formats, and conversely, some formats require the use of a sampler YCbCr
+//! conversion to be sampled at all.
+//!
+//! A sampler YCbCr conversion can only be used with a combined image sampler descriptor in a
+//! descriptor set. The conversion must be attached on both the image view and sampler in the
+//! descriptor, and the sampler must be included in the descriptor set layout as an immutable
+//! sampler.
+//!
+//! # Examples
+//!
+//! ```
+//! # let device: std::sync::Arc<vulkano::device::Device> = return;
+//! # let image_data: Vec<u8> = return;
+//! # let queue: std::sync::Arc<vulkano::device::Queue> = return;
+//! # let memory_allocator: vulkano::memory::allocator::StandardMemoryAllocator = return;
+//! # let descriptor_set_allocator: vulkano::descriptor_set::allocator::StandardDescriptorSetAllocator = return;
+//! # let mut command_buffer_builder: vulkano::command_buffer::AutoCommandBufferBuilder<vulkano::command_buffer::PrimaryAutoCommandBuffer> = return;
+//! use vulkano::descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet};
+//! use vulkano::descriptor_set::layout::{DescriptorSetLayout, DescriptorSetLayoutBinding, DescriptorSetLayoutCreateInfo, DescriptorType};
+//! use vulkano::format::Format;
+//! use vulkano::image::{ImmutableImage, ImageCreateFlags, ImageDimensions, ImageUsage, MipmapsCount};
+//! use vulkano::image::view::{ImageView, ImageViewCreateInfo};
+//! use vulkano::sampler::{Sampler, SamplerCreateInfo};
+//! use vulkano::sampler::ycbcr::{SamplerYcbcrConversion, SamplerYcbcrConversionCreateInfo, SamplerYcbcrModelConversion};
+//! use vulkano::shader::ShaderStage;
+//!
+//! let conversion = SamplerYcbcrConversion::new(device.clone(), SamplerYcbcrConversionCreateInfo {
+//! format: Some(Format::G8_B8_R8_3PLANE_420_UNORM),
+//! ycbcr_model: SamplerYcbcrModelConversion::YcbcrIdentity,
+//! ..Default::default()
+//! })
+//! .unwrap();
+//!
+//! let sampler = Sampler::new(device.clone(), SamplerCreateInfo {
+//! sampler_ycbcr_conversion: Some(conversion.clone()),
+//! ..Default::default()
+//! })
+//! .unwrap();
+//!
+//! let descriptor_set_layout = DescriptorSetLayout::new(
+//! device.clone(),
+//! DescriptorSetLayoutCreateInfo {
+//! bindings: [(
+//! 0,
+//! DescriptorSetLayoutBinding {
+//! stages: ShaderStage::Fragment.into(),
+//! immutable_samplers: vec![sampler],
+//! ..DescriptorSetLayoutBinding::descriptor_type(DescriptorType::CombinedImageSampler)
+//! },
+//! )]
+//! .into(),
+//! ..Default::default()
+//! },
+//! ).unwrap();
+//!
+//! let image = ImmutableImage::from_iter(
+//! &memory_allocator,
+//! image_data,
+//! ImageDimensions::Dim2d { width: 1920, height: 1080, array_layers: 1 },
+//! MipmapsCount::One,
+//! Format::G8_B8_R8_3PLANE_420_UNORM,
+//! &mut command_buffer_builder,
+//! ).unwrap();
+//!
+//! let create_info = ImageViewCreateInfo {
+//! sampler_ycbcr_conversion: Some(conversion.clone()),
+//! ..ImageViewCreateInfo::from_image(&image)
+//! };
+//! let image_view = ImageView::new(image, create_info).unwrap();
+//!
+//! let descriptor_set = PersistentDescriptorSet::new(
+//! &descriptor_set_allocator,
+//! descriptor_set_layout.clone(),
+//! [WriteDescriptorSet::image_view(0, image_view)],
+//! ).unwrap();
+//! ```
+
+use crate::{
+ device::{Device, DeviceOwned},
+ format::{ChromaSampling, Format, FormatFeatures, NumericType},
+ macros::{impl_id_counter, vulkan_enum},
+ sampler::{ComponentMapping, ComponentSwizzle, Filter},
+ OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject,
+};
+use std::{
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+ mem::MaybeUninit,
+ num::NonZeroU64,
+ ptr,
+ sync::Arc,
+};
+
+/// Describes how sampled image data should converted from a YCbCr representation to an RGB one.
+#[derive(Debug)]
+pub struct SamplerYcbcrConversion {
+ handle: ash::vk::SamplerYcbcrConversion,
+ device: Arc<Device>,
+ id: NonZeroU64,
+
+ format: Option<Format>,
+ ycbcr_model: SamplerYcbcrModelConversion,
+ ycbcr_range: SamplerYcbcrRange,
+ component_mapping: ComponentMapping,
+ chroma_offset: [ChromaLocation; 2],
+ chroma_filter: Filter,
+ force_explicit_reconstruction: bool,
+}
+
+impl SamplerYcbcrConversion {
+ /// Creates a new `SamplerYcbcrConversion`.
+ ///
+ /// The [`sampler_ycbcr_conversion`](crate::device::Features::sampler_ycbcr_conversion)
+ /// feature must be enabled on the device.
+ pub fn new(
+ device: Arc<Device>,
+ create_info: SamplerYcbcrConversionCreateInfo,
+ ) -> Result<Arc<SamplerYcbcrConversion>, SamplerYcbcrConversionCreationError> {
+ let SamplerYcbcrConversionCreateInfo {
+ format,
+ ycbcr_model,
+ ycbcr_range,
+ component_mapping,
+ chroma_offset,
+ chroma_filter,
+ force_explicit_reconstruction,
+ _ne: _,
+ } = create_info;
+
+ if !device.enabled_features().sampler_ycbcr_conversion {
+ return Err(SamplerYcbcrConversionCreationError::RequirementNotMet {
+ required_for: "`SamplerYcbcrConversion::new`",
+ requires_one_of: RequiresOneOf {
+ features: &["sampler_ycbcr_conversion"],
+ ..Default::default()
+ },
+ });
+ }
+
+ let format = match format {
+ Some(f) => f,
+ None => {
+ return Err(SamplerYcbcrConversionCreationError::FormatMissing);
+ }
+ };
+
+ // VUID-VkSamplerYcbcrConversionCreateInfo-format-parameter
+ format.validate_device(&device)?;
+
+ // VUID-VkSamplerYcbcrConversionCreateInfo-ycbcrModel-parameter
+ ycbcr_model.validate_device(&device)?;
+
+ // VUID-VkSamplerYcbcrConversionCreateInfo-ycbcrRange-parameter
+ ycbcr_range.validate_device(&device)?;
+
+ // VUID-VkComponentMapping-r-parameter
+ component_mapping.r.validate_device(&device)?;
+
+ // VUID-VkComponentMapping-g-parameter
+ component_mapping.g.validate_device(&device)?;
+
+ // VUID-VkComponentMapping-b-parameter
+ component_mapping.b.validate_device(&device)?;
+
+ // VUID-VkComponentMapping-a-parameter
+ component_mapping.a.validate_device(&device)?;
+
+ for offset in chroma_offset {
+ // VUID-VkSamplerYcbcrConversionCreateInfo-xChromaOffset-parameter
+ // VUID-VkSamplerYcbcrConversionCreateInfo-yChromaOffset-parameter
+ offset.validate_device(&device)?;
+ }
+
+ // VUID-VkSamplerYcbcrConversionCreateInfo-chromaFilter-parameter
+ chroma_filter.validate_device(&device)?;
+
+ // VUID-VkSamplerYcbcrConversionCreateInfo-format-04061
+ if !format
+ .type_color()
+ .map_or(false, |ty| ty == NumericType::UNORM)
+ {
+ return Err(SamplerYcbcrConversionCreationError::FormatNotUnorm);
+ }
+
+ // Use unchecked, because all validation has been done above.
+ let potential_format_features = unsafe {
+ device
+ .physical_device()
+ .format_properties_unchecked(format)
+ .potential_format_features()
+ };
+
+ // VUID-VkSamplerYcbcrConversionCreateInfo-format-01650
+ if !potential_format_features.intersects(
+ FormatFeatures::MIDPOINT_CHROMA_SAMPLES | FormatFeatures::COSITED_CHROMA_SAMPLES,
+ ) {
+ return Err(SamplerYcbcrConversionCreationError::FormatNotSupported);
+ }
+
+ if let Some(chroma_sampling @ (ChromaSampling::Mode422 | ChromaSampling::Mode420)) =
+ format.ycbcr_chroma_sampling()
+ {
+ let chroma_offsets_to_check = match chroma_sampling {
+ ChromaSampling::Mode420 => &chroma_offset[0..2],
+ ChromaSampling::Mode422 => &chroma_offset[0..1],
+ _ => unreachable!(),
+ };
+
+ for offset in chroma_offsets_to_check {
+ match offset {
+ ChromaLocation::CositedEven => {
+ // VUID-VkSamplerYcbcrConversionCreateInfo-xChromaOffset-01651
+ if !potential_format_features
+ .intersects(FormatFeatures::COSITED_CHROMA_SAMPLES)
+ {
+ return Err(
+ SamplerYcbcrConversionCreationError::FormatChromaOffsetNotSupported,
+ );
+ }
+ }
+ ChromaLocation::Midpoint => {
+ // VUID-VkSamplerYcbcrConversionCreateInfo-xChromaOffset-01652
+ if !potential_format_features
+ .intersects(FormatFeatures::MIDPOINT_CHROMA_SAMPLES)
+ {
+ return Err(
+ SamplerYcbcrConversionCreationError::FormatChromaOffsetNotSupported,
+ );
+ }
+ }
+ }
+ }
+
+ // VUID-VkSamplerYcbcrConversionCreateInfo-components-02581
+ let g_ok = component_mapping.g_is_identity();
+
+ // VUID-VkSamplerYcbcrConversionCreateInfo-components-02582
+ let a_ok = component_mapping.a_is_identity()
+ || matches!(
+ component_mapping.a,
+ ComponentSwizzle::One | ComponentSwizzle::Zero
+ );
+
+ // VUID-VkSamplerYcbcrConversionCreateInfo-components-02583
+ // VUID-VkSamplerYcbcrConversionCreateInfo-components-02584
+ // VUID-VkSamplerYcbcrConversionCreateInfo-components-02585
+ let rb_ok1 = component_mapping.r_is_identity() && component_mapping.b_is_identity();
+ let rb_ok2 = matches!(component_mapping.r, ComponentSwizzle::Blue)
+ && matches!(component_mapping.b, ComponentSwizzle::Red);
+
+ if !(g_ok && a_ok && (rb_ok1 || rb_ok2)) {
+ return Err(SamplerYcbcrConversionCreationError::FormatInvalidComponentMapping);
+ }
+ }
+
+ let components_bits = {
+ let bits = format.components();
+ component_mapping
+ .component_map()
+ .map(move |i| i.map(|i| bits[i]))
+ };
+
+ // VUID-VkSamplerYcbcrConversionCreateInfo-ycbcrModel-01655
+ if ycbcr_model != SamplerYcbcrModelConversion::RgbIdentity
+ && !components_bits[0..3]
+ .iter()
+ .all(|b| b.map_or(false, |b| b != 0))
+ {
+ return Err(SamplerYcbcrConversionCreationError::YcbcrModelInvalidComponentMapping);
+ }
+
+ // VUID-VkSamplerYcbcrConversionCreateInfo-ycbcrRange-02748
+ if ycbcr_range == SamplerYcbcrRange::ItuNarrow {
+ // TODO: Spec doesn't say how many bits `Zero` and `One` are considered to have, so
+ // just skip them for now.
+ for &bits in components_bits[0..3].iter().flatten() {
+ if bits < 8 {
+ return Err(SamplerYcbcrConversionCreationError::YcbcrRangeFormatNotEnoughBits);
+ }
+ }
+ }
+
+ // VUID-VkSamplerYcbcrConversionCreateInfo-forceExplicitReconstruction-01656
+ if force_explicit_reconstruction
+ && !potential_format_features.intersects(FormatFeatures::
+ SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE)
+ {
+ return Err(
+ SamplerYcbcrConversionCreationError::FormatForceExplicitReconstructionNotSupported,
+ );
+ }
+
+ match chroma_filter {
+ Filter::Nearest => (),
+ Filter::Linear => {
+ // VUID-VkSamplerYcbcrConversionCreateInfo-chromaFilter-01657
+ if !potential_format_features
+ .intersects(FormatFeatures::SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER)
+ {
+ return Err(
+ SamplerYcbcrConversionCreationError::FormatLinearFilterNotSupported,
+ );
+ }
+ }
+ Filter::Cubic => {
+ return Err(SamplerYcbcrConversionCreationError::CubicFilterNotSupported);
+ }
+ }
+
+ let create_info = ash::vk::SamplerYcbcrConversionCreateInfo {
+ format: format.into(),
+ ycbcr_model: ycbcr_model.into(),
+ ycbcr_range: ycbcr_range.into(),
+ components: component_mapping.into(),
+ x_chroma_offset: chroma_offset[0].into(),
+ y_chroma_offset: chroma_offset[1].into(),
+ chroma_filter: chroma_filter.into(),
+ force_explicit_reconstruction: force_explicit_reconstruction as ash::vk::Bool32,
+ ..Default::default()
+ };
+
+ let handle = unsafe {
+ let fns = device.fns();
+ let create_sampler_ycbcr_conversion = if device.api_version() >= Version::V1_1 {
+ fns.v1_1.create_sampler_ycbcr_conversion
+ } else {
+ fns.khr_sampler_ycbcr_conversion
+ .create_sampler_ycbcr_conversion_khr
+ };
+
+ let mut output = MaybeUninit::uninit();
+ create_sampler_ycbcr_conversion(
+ device.handle(),
+ &create_info,
+ ptr::null(),
+ output.as_mut_ptr(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+ output.assume_init()
+ };
+
+ Ok(Arc::new(SamplerYcbcrConversion {
+ handle,
+ device,
+ id: Self::next_id(),
+ format: Some(format),
+ ycbcr_model,
+ ycbcr_range,
+ component_mapping,
+ chroma_offset,
+ chroma_filter,
+ force_explicit_reconstruction,
+ }))
+ }
+
+ /// Creates a new `SamplerYcbcrConversion` from a raw object handle.
+ ///
+ /// # Safety
+ ///
+ /// - `handle` must be a valid Vulkan object handle created from `device`.
+ /// - `create_info` must match the info used to create the object.
+ /// - `create_info.format` must be `Some`.
+ #[inline]
+ pub unsafe fn from_handle(
+ device: Arc<Device>,
+ handle: ash::vk::SamplerYcbcrConversion,
+ create_info: SamplerYcbcrConversionCreateInfo,
+ ) -> Arc<SamplerYcbcrConversion> {
+ let SamplerYcbcrConversionCreateInfo {
+ format,
+ ycbcr_model,
+ ycbcr_range,
+ component_mapping,
+ chroma_offset,
+ chroma_filter,
+ force_explicit_reconstruction,
+ _ne: _,
+ } = create_info;
+
+ Arc::new(SamplerYcbcrConversion {
+ handle,
+ device,
+ id: Self::next_id(),
+ format,
+ ycbcr_model,
+ ycbcr_range,
+ component_mapping,
+ chroma_offset,
+ chroma_filter,
+ force_explicit_reconstruction,
+ })
+ }
+
+ /// Returns the chroma filter used by the conversion.
+ #[inline]
+ pub fn chroma_filter(&self) -> Filter {
+ self.chroma_filter
+ }
+
+ /// Returns the chroma offsets used by the conversion.
+ #[inline]
+ pub fn chroma_offset(&self) -> [ChromaLocation; 2] {
+ self.chroma_offset
+ }
+
+ /// Returns the component mapping of the conversion.
+ #[inline]
+ pub fn component_mapping(&self) -> ComponentMapping {
+ self.component_mapping
+ }
+
+ /// Returns whether the conversion has forced explicit reconstruction to be enabled.
+ #[inline]
+ pub fn force_explicit_reconstruction(&self) -> bool {
+ self.force_explicit_reconstruction
+ }
+
+ /// Returns the format that the conversion was created for.
+ #[inline]
+ pub fn format(&self) -> Option<Format> {
+ self.format
+ }
+
+ /// Returns the YCbCr model of the conversion.
+ #[inline]
+ pub fn ycbcr_model(&self) -> SamplerYcbcrModelConversion {
+ self.ycbcr_model
+ }
+
+ /// Returns the YCbCr range of the conversion.
+ #[inline]
+ pub fn ycbcr_range(&self) -> SamplerYcbcrRange {
+ self.ycbcr_range
+ }
+
+ /// Returns whether `self` is equal or identically defined to `other`.
+ #[inline]
+ pub fn is_identical(&self, other: &SamplerYcbcrConversion) -> bool {
+ self.handle == other.handle || {
+ let &Self {
+ handle: _,
+ device: _,
+ id: _,
+ format,
+ ycbcr_model,
+ ycbcr_range,
+ component_mapping,
+ chroma_offset,
+ chroma_filter,
+ force_explicit_reconstruction,
+ } = self;
+
+ format == other.format
+ && ycbcr_model == other.ycbcr_model
+ && ycbcr_range == other.ycbcr_range
+ && component_mapping == other.component_mapping
+ && chroma_offset == other.chroma_offset
+ && chroma_filter == other.chroma_filter
+ && force_explicit_reconstruction == other.force_explicit_reconstruction
+ }
+ }
+}
+
+impl Drop for SamplerYcbcrConversion {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ let fns = self.device.fns();
+ let destroy_sampler_ycbcr_conversion = if self.device.api_version() >= Version::V1_1 {
+ fns.v1_1.destroy_sampler_ycbcr_conversion
+ } else {
+ fns.khr_sampler_ycbcr_conversion
+ .destroy_sampler_ycbcr_conversion_khr
+ };
+
+ destroy_sampler_ycbcr_conversion(self.device.handle(), self.handle, ptr::null());
+ }
+ }
+}
+
+unsafe impl VulkanObject for SamplerYcbcrConversion {
+ type Handle = ash::vk::SamplerYcbcrConversion;
+
+ #[inline]
+ fn handle(&self) -> Self::Handle {
+ self.handle
+ }
+}
+
+unsafe impl DeviceOwned for SamplerYcbcrConversion {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+}
+
+impl_id_counter!(SamplerYcbcrConversion);
+
+/// Error that can happen when creating a `SamplerYcbcrConversion`.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum SamplerYcbcrConversionCreationError {
+ /// Not enough memory.
+ OomError(OomError),
+
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+
+ /// The `Cubic` filter was specified.
+ CubicFilterNotSupported,
+
+ /// No format was specified when one was required.
+ FormatMissing,
+
+ /// The format has a color type other than `UNORM`.
+ FormatNotUnorm,
+
+ /// The format does not support sampler YCbCr conversion.
+ FormatNotSupported,
+
+ /// The format does not support the chosen chroma offsets.
+ FormatChromaOffsetNotSupported,
+
+ /// The component mapping was not valid for use with the chosen format.
+ FormatInvalidComponentMapping,
+
+ /// The format does not support `force_explicit_reconstruction`.
+ FormatForceExplicitReconstructionNotSupported,
+
+ /// The format does not support the `Linear` filter.
+ FormatLinearFilterNotSupported,
+
+ /// The component mapping was not valid for use with the chosen YCbCr model.
+ YcbcrModelInvalidComponentMapping,
+
+ /// For the chosen `ycbcr_range`, the R, G or B components being read from the `format` do not
+ /// have the minimum number of required bits.
+ YcbcrRangeFormatNotEnoughBits,
+}
+
+impl Error for SamplerYcbcrConversionCreationError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ SamplerYcbcrConversionCreationError::OomError(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+impl Display for SamplerYcbcrConversionCreationError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::OomError(_) => write!(f, "not enough memory available"),
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ Self::CubicFilterNotSupported => {
+ write!(f, "the `Cubic` filter was specified")
+ }
+ Self::FormatMissing => {
+ write!(f, "no format was specified when one was required")
+ }
+ Self::FormatNotUnorm => {
+ write!(f, "the format has a color type other than `UNORM`")
+ }
+ Self::FormatNotSupported => {
+ write!(f, "the format does not support sampler YCbCr conversion")
+ }
+ Self::FormatChromaOffsetNotSupported => {
+ write!(f, "the format does not support the chosen chroma offsets")
+ }
+ Self::FormatInvalidComponentMapping => write!(
+ f,
+ "the component mapping was not valid for use with the chosen format",
+ ),
+ Self::FormatForceExplicitReconstructionNotSupported => write!(
+ f,
+ "the format does not support `force_explicit_reconstruction`",
+ ),
+ Self::FormatLinearFilterNotSupported => {
+ write!(f, "the format does not support the `Linear` filter")
+ }
+ Self::YcbcrModelInvalidComponentMapping => write!(
+ f,
+ "the component mapping was not valid for use with the chosen YCbCr model",
+ ),
+ Self::YcbcrRangeFormatNotEnoughBits => write!(
+ f,
+ "for the chosen `ycbcr_range`, the R, G or B components being read from the \
+ `format` do not have the minimum number of required bits",
+ ),
+ }
+ }
+}
+
+impl From<OomError> for SamplerYcbcrConversionCreationError {
+ fn from(err: OomError) -> SamplerYcbcrConversionCreationError {
+ SamplerYcbcrConversionCreationError::OomError(err)
+ }
+}
+
+impl From<VulkanError> for SamplerYcbcrConversionCreationError {
+ fn from(err: VulkanError) -> SamplerYcbcrConversionCreationError {
+ match err {
+ err @ VulkanError::OutOfHostMemory => {
+ SamplerYcbcrConversionCreationError::OomError(OomError::from(err))
+ }
+ err @ VulkanError::OutOfDeviceMemory => {
+ SamplerYcbcrConversionCreationError::OomError(OomError::from(err))
+ }
+ _ => panic!("unexpected error: {:?}", err),
+ }
+ }
+}
+
+impl From<RequirementNotMet> for SamplerYcbcrConversionCreationError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
+ }
+ }
+}
+
+/// Parameters to create a new `SamplerYcbcrConversion`.
+#[derive(Clone, Debug)]
+pub struct SamplerYcbcrConversionCreateInfo {
+ /// The image view format that this conversion will read data from. The conversion cannot be
+ /// used with image views of any other format.
+ ///
+ /// The format must support YCbCr conversions, meaning that its `FormatFeatures` must support
+ /// at least one of `cosited_chroma_samples` or `midpoint_chroma_samples`.
+ ///
+ /// If this is set to a format that has chroma subsampling (contains `422` or `420` in the name)
+ /// then `component_mapping` is restricted as follows:
+ /// - `g` must be identity swizzled.
+ /// - `a` must be identity swizzled or `Zero` or `One`.
+ /// - `r` and `b` must be identity swizzled or mapped to each other.
+ ///
+ /// Compatibility notice: currently, this value must be `Some`, but future additions may allow
+ /// `None` as a valid value as well.
+ ///
+ /// The default value is `None`.
+ pub format: Option<Format>,
+
+ /// The conversion between the input color model and the output RGB color model.
+ ///
+ /// If this is not set to `RgbIdentity`, then the `r`, `g` and `b` components of
+ /// `component_mapping` must not be `Zero` or `One`, and the component being read must exist in
+ /// `format` (must be represented as a nonzero number of bits).
+ ///
+ /// The default value is [`RgbIdentity`](SamplerYcbcrModelConversion::RgbIdentity).
+ pub ycbcr_model: SamplerYcbcrModelConversion,
+
+ /// If `ycbcr_model` is not `RgbIdentity`, specifies the range expansion of the input values
+ /// that should be used.
+ ///
+ /// If this is set to `ItuNarrow`, then the `r`, `g` and `b` components of `component_mapping`
+ /// must each map to a component of `format` that is represented with at least 8 bits.
+ ///
+ /// The default value is [`ItuFull`](SamplerYcbcrRange::ItuFull).
+ pub ycbcr_range: SamplerYcbcrRange,
+
+ /// The mapping to apply to the components of the input format, before color model conversion
+ /// and range expansion.
+ ///
+ /// The default value is [`ComponentMapping::identity()`].
+ pub component_mapping: ComponentMapping,
+
+ /// For formats with chroma subsampling and a `Linear` filter, specifies the sampled location
+ /// for the subsampled components, in the x and y direction.
+ ///
+ /// The value is ignored if the filter is `Nearest` or the corresponding axis is not chroma
+ /// subsampled. If the value is not ignored, the format must support the chosen mode.
+ ///
+ /// The default value is [`CositedEven`](ChromaLocation::CositedEven) for both axes.
+ pub chroma_offset: [ChromaLocation; 2],
+
+ /// For formats with chroma subsampling, specifies the filter used for reconstructing the chroma
+ /// components to full resolution.
+ ///
+ /// The `Cubic` filter is not supported. If `Linear` is used, the format must support it.
+ ///
+ /// The default value is [`Nearest`](Filter::Nearest).
+ pub chroma_filter: Filter,
+
+ /// Forces explicit reconstruction if the implementation does not use it by default. The format
+ /// must support it. See
+ /// [the spec](https://registry.khronos.org/vulkan/specs/1.2-extensions/html/chap16.html#textures-chroma-reconstruction)
+ /// for more information.
+ ///
+ /// The default value is `false`.
+ pub force_explicit_reconstruction: bool,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for SamplerYcbcrConversionCreateInfo {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ format: None,
+ ycbcr_model: SamplerYcbcrModelConversion::RgbIdentity,
+ ycbcr_range: SamplerYcbcrRange::ItuFull,
+ component_mapping: ComponentMapping::identity(),
+ chroma_offset: [ChromaLocation::CositedEven; 2],
+ chroma_filter: Filter::Nearest,
+ force_explicit_reconstruction: false,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// The conversion between the color model of the source image and the color model of the shader.
+ SamplerYcbcrModelConversion = SamplerYcbcrModelConversion(i32);
+
+ /// The input values are already in the shader's model, and are passed through unmodified.
+ RgbIdentity = RGB_IDENTITY,
+
+ /// The input values are only range expanded, no other modifications are done.
+ YcbcrIdentity = YCBCR_IDENTITY,
+
+ /// The input values are converted according to the
+ /// [ITU-R BT.709](https://en.wikipedia.org/wiki/Rec._709) standard.
+ Ycbcr709 = YCBCR_709,
+
+ /// The input values are converted according to the
+ /// [ITU-R BT.601](https://en.wikipedia.org/wiki/Rec._601) standard.
+ Ycbcr601 = YCBCR_601,
+
+ /// The input values are converted according to the
+ /// [ITU-R BT.2020](https://en.wikipedia.org/wiki/Rec._2020) standard.
+ Ycbcr2020 = YCBCR_2020,
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// How the numeric range of the input data is converted.
+ SamplerYcbcrRange = SamplerYcbcrRange(i32);
+
+ /// The input values cover the full numeric range, and are interpreted according to the ITU
+ /// "full range" rules.
+ ItuFull = ITU_FULL,
+
+ /// The input values cover only a subset of the numeric range, with the remainder reserved as
+ /// headroom/footroom. The values are interpreted according to the ITU "narrow range" rules.
+ ItuNarrow = ITU_NARROW,
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// For formats with chroma subsampling, the location where the chroma components are sampled,
+ /// relative to the luma component.
+ ChromaLocation = ChromaLocation(i32);
+
+ /// The chroma components are sampled at the even luma coordinate.
+ CositedEven = COSITED_EVEN,
+
+ /// The chroma components are sampled at the midpoint between the even luma coordinate and
+ /// the next higher odd luma coordinate.
+ Midpoint = MIDPOINT,
+}
+
+#[cfg(test)]
+mod tests {
+ use super::{SamplerYcbcrConversion, SamplerYcbcrConversionCreationError};
+ use crate::RequiresOneOf;
+
+ #[test]
+ fn feature_not_enabled() {
+ let (device, _queue) = gfx_dev_and_queue!();
+
+ let r = SamplerYcbcrConversion::new(device, Default::default());
+
+ match r {
+ Err(SamplerYcbcrConversionCreationError::RequirementNotMet {
+ requires_one_of: RequiresOneOf { features, .. },
+ ..
+ }) if features.contains(&"sampler_ycbcr_conversion") => (),
+ _ => panic!(),
+ }
+ }
+}
diff --git a/src/shader/mod.rs b/src/shader/mod.rs
new file mode 100644
index 0000000..298baad
--- /dev/null
+++ b/src/shader/mod.rs
@@ -0,0 +1,1402 @@
+// Copyright (c) 2016 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+//! A program that is run on the device.
+//!
+//! In Vulkan, shaders are grouped in *shader modules*. Each shader module is built from SPIR-V
+//! code and can contain one or more entry points. Note that for the moment the official
+//! GLSL-to-SPIR-V compiler does not support multiple entry points.
+//!
+//! The vulkano library can parse and introspect SPIR-V code, but it does not fully validate the
+//! code. You are encouraged to use the `vulkano-shaders` crate that will generate Rust code that
+//! wraps around vulkano's shaders API.
+//!
+//! # Shader interface
+//!
+//! Vulkan has specific rules for interfacing shaders with each other, and with other parts
+//! of a program.
+//!
+//! ## Endianness
+//!
+//! The Vulkan specification requires that a Vulkan implementation has runtime support for the
+//! types [`u8`], [`u16`], [`u32`], [`u64`] as well as their signed versions, as well as [`f32`]
+//! and [`f64`] on the host, and that the representation and endianness of these types matches
+//! those on the device. This means that if you have for example a `Subbuffer<u32>`, you can be
+//! sure that it is represented the same way on the host as it is on the device, and you don't need
+//! to worry about converting the endianness.
+//!
+//! ## Layout of data
+//!
+//! When buffers, push constants or other user-provided data are accessed in shaders,
+//! the shader expects the values inside to be laid out in a specific way. For every uniform buffer,
+//! storage buffer or push constant block, the SPIR-V specification requires the SPIR-V code to
+//! provide the `Offset` decoration for every member of a struct, indicating where it is placed
+//! relative to the start of the struct. If there are arrays or matrices among the variables, the
+//! SPIR-V code must also provide an `ArrayStride` or `MatrixStride` decoration for them,
+//! indicating the number of bytes between the start of each element in the array or column in the
+//! matrix. When providing data to shaders, you must make sure that your data is placed at the
+//! locations indicated within the SPIR-V code, or the shader will read the wrong data and produce
+//! nonsense.
+//!
+//! GLSL does not require you to give explicit offsets and/or strides to your variables (although
+//! it has the option to provide them if you wish). Instead, the shader compiler automatically
+//! assigns every variable an offset, increasing in the order you declare them in.
+//! To know the exact offsets that will be used, so that you can lay out your data appropriately,
+//! you must know the alignment rules that the shader compiler uses. The shader compiler will
+//! always give a variable the smallest offset that fits the alignment rules and doesn't overlap
+//! with the previous variable. The shader compiler uses default alignment rules depending on the
+//! type of block, but you can specify another layout by using the `layout` qualifier.
+//!
+//! ## Alignment rules
+//!
+//! The offset of each variable from the start of a block, matrix or array must be a
+//! multiple of a certain number, which is called its *alignment*. The stride of an array or matrix
+//! must likewise be a multiple of this number. An alignment is always a power-of-two value.
+//! Regardless of whether the offset/stride is provided manually in the compiled SPIR-V code,
+//! or assigned automatically by the shader compiler, all variable offsets/strides in a shader must
+//! follow these alignment rules.
+//!
+//! Three sets of [alignment rules] are supported by Vulkan. Each one has a GLSL qualifier that
+//! you can place in front of a block, to make the shader compiler use that layout for the block.
+//! If you don't provide this qualifier, it will use a default alignment.
+//!
+//! - **Scalar alignment** (GLSL qualifier: `layout(scalar)`, requires the
+//! [`GL_EXT_scalar_block_layout`] GLSL extension). This is the same as the C alignment,
+//! expressed in Rust with the
+//! [`#[repr(C)]`](https://doc.rust-lang.org/nomicon/other-reprs.html#reprc) attribute.
+//! The shader compiler does not use this alignment by default, so you must use the GLSL
+//! qualifier. You must also enable the [`scalar_block_layout`] feature in Vulkan.
+//! - **Base alignment**, also known as **std430** (GLSL qualifier: `layout(std430)`).
+//! The shader compiler uses this alignment by default for all shader data except uniform buffers.
+//! If you use the base alignment for a uniform buffer, you must also enable the
+//! [`uniform_buffer_standard_layout`] feature in Vulkan.
+//! - **Extended alignment**, also known as **std140** (GLSL qualifier: `layout(std140)`).
+//! The shader compiler uses this alignment by default for uniform buffers.
+//!
+//! Each alignment type is a subset of the ones above it, so if something adheres to the extended
+//! alignment rules, it also follows the rules for the base and scalar alignments.
+//!
+//! In all three of these alignment rules, a primitive/scalar value with a size of N bytes has an
+//! alignment of N, meaning that it must have an offset that is a multiple of its size,
+//! like in C or Rust. For example, a `float` (like a Rust `f32`) has a size of 4 bytes,
+//! and an alignment of 4.
+//!
+//! The differences between the alignment rules are in how compound types (vectors, matrices,
+//! arrays and structs) are expected to be laid out. For a compound type with an element whose
+//! alignment is N, the scalar alignment considers the alignment of the compound type to be also N.
+//! However, the base and extended alignments are stricter:
+//!
+//! | GLSL type | Scalar | Base | Extended |
+//! |-----------|-----------------|-----------------|--------------------------|
+//! | primitive | N | N | N |
+//! | `vec2` | N | N * 2 | N * 2 |
+//! | `vec3` | N | N * 4 | N * 4 |
+//! | `vec4` | N | N * 4 | N * 4 |
+//! | array | N | N | max(N, 16) |
+//! | `struct` | N<sub>max</sub> | N<sub>max</sub> | max(N<sub>max</sub>, 16) |
+//!
+//! In the base and extended alignment, the alignment of a vector is the size of the whole vector,
+//! rather than the size of its individual elements as is the case in the scalar alignment.
+//! But note that, because alignment must be a power of two, the alignment of `vec3` cannot be
+//! N * 3; it must be N * 4, the same alignment as `vec4`. This means that it is not possible to
+//! tightly pack multiple `vec3` values (e.g. in an array); there will always be empty padding
+//! between them.
+//!
+//! In both the scalar and base alignment, the alignment of arrays and their elements is equal to
+//! the alignment of the contained type. In the extended alignment, however, the alignment is
+//! always at least 16 (the size of a `vec4`). Therefore, the minimum stride of the array can be
+//! much greater than the element size. For example, in an array of `float`, the stride must be at
+//! least 16, even though a `float` itself is only 4 bytes in size. Every `float` element will be
+//! followed by at least 12 bytes of unused space.
+//!
+//! A matrix `matCxR` is considered equivalent to an array of column vectors `vecR[C]`.
+//! In the base and extended alignments, that means that if the matrix has 3 rows, there will be
+//! one element's worth of padding between the column vectors. In the extended alignment,
+//! the alignment is also at least 16, further increasing the amount of padding between the
+//! column vectors.
+//!
+//! The rules for `struct`s are similar to those of arrays. When the members of the struct have
+//! different alignment requirements, the alignment of the struct as a whole is the maximum
+//! of the alignments of its members. As with arrays, in the extended alignment, the alignment
+//! of a struct is at least 16.
+//!
+//! [alignment rules]: <https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap15.html#interfaces-resources-layout>
+//! [`GL_EXT_scalar_block_layout`]: <https://github.com/KhronosGroup/GLSL/blob/master/extensions/ext/GL_EXT_scalar_block_layout.txt>
+//! [`scalar_block_layout`]: crate::device::Features::scalar_block_layout
+//! [`uniform_buffer_standard_layout`]: crate::device::Features::uniform_buffer_standard_layout
+
+use crate::{
+ descriptor_set::layout::DescriptorType,
+ device::{Device, DeviceOwned},
+ format::{Format, NumericType},
+ image::view::ImageViewType,
+ macros::{impl_id_counter, vulkan_bitflags_enum},
+ pipeline::{graphics::input_assembly::PrimitiveTopology, layout::PushConstantRange},
+ shader::spirv::{Capability, Spirv, SpirvError},
+ sync::PipelineStages,
+ DeviceSize, OomError, Version, VulkanError, VulkanObject,
+};
+use ahash::{HashMap, HashSet};
+use std::{
+ borrow::Cow,
+ collections::hash_map::Entry,
+ error::Error,
+ ffi::{CStr, CString},
+ fmt::{Display, Error as FmtError, Formatter},
+ mem,
+ mem::MaybeUninit,
+ num::NonZeroU64,
+ ptr,
+ sync::Arc,
+};
+
+pub mod reflect;
+pub mod spirv;
+
+use spirv::ExecutionModel;
+
+// Generated by build.rs
+include!(concat!(env!("OUT_DIR"), "/spirv_reqs.rs"));
+
+/// Contains SPIR-V code with one or more entry points.
+#[derive(Debug)]
+pub struct ShaderModule {
+ handle: ash::vk::ShaderModule,
+ device: Arc<Device>,
+ id: NonZeroU64,
+ entry_points: HashMap<String, HashMap<ExecutionModel, EntryPointInfo>>,
+}
+
+impl ShaderModule {
+ /// Builds a new shader module from SPIR-V 32-bit words. The shader code is parsed and the
+ /// necessary information is extracted from it.
+ ///
+ /// # Safety
+ ///
+ /// - The SPIR-V code is not validated beyond the minimum needed to extract the information.
+ #[inline]
+ pub unsafe fn from_words(
+ device: Arc<Device>,
+ words: &[u32],
+ ) -> Result<Arc<ShaderModule>, ShaderCreationError> {
+ let spirv = Spirv::new(words)?;
+
+ Self::from_words_with_data(
+ device,
+ words,
+ spirv.version(),
+ reflect::spirv_capabilities(&spirv),
+ reflect::spirv_extensions(&spirv),
+ reflect::entry_points(&spirv),
+ )
+ }
+
+ /// As `from_words`, but takes a slice of bytes.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the length of `bytes` is not a multiple of 4.
+ #[inline]
+ pub unsafe fn from_bytes(
+ device: Arc<Device>,
+ bytes: &[u8],
+ ) -> Result<Arc<ShaderModule>, ShaderCreationError> {
+ assert!((bytes.len() % 4) == 0);
+
+ Self::from_words(
+ device,
+ std::slice::from_raw_parts(
+ bytes.as_ptr() as *const _,
+ bytes.len() / mem::size_of::<u32>(),
+ ),
+ )
+ }
+
+ /// As `from_words`, but does not parse the code. Instead, you must provide the needed
+ /// information yourself. This can be useful if you've already done parsing yourself and
+ /// want to prevent Vulkano from doing it a second time.
+ ///
+ /// # Safety
+ ///
+ /// - The SPIR-V code is not validated at all.
+ /// - The provided information must match what the SPIR-V code contains.
+ pub unsafe fn from_words_with_data<'a>(
+ device: Arc<Device>,
+ words: &[u32],
+ spirv_version: Version,
+ spirv_capabilities: impl IntoIterator<Item = &'a Capability>,
+ spirv_extensions: impl IntoIterator<Item = &'a str>,
+ entry_points: impl IntoIterator<Item = (String, ExecutionModel, EntryPointInfo)>,
+ ) -> Result<Arc<ShaderModule>, ShaderCreationError> {
+ if let Err(reason) = check_spirv_version(&device, spirv_version) {
+ return Err(ShaderCreationError::SpirvVersionNotSupported {
+ version: spirv_version,
+ reason,
+ });
+ }
+
+ for &capability in spirv_capabilities {
+ if let Err(reason) = check_spirv_capability(&device, capability) {
+ return Err(ShaderCreationError::SpirvCapabilityNotSupported {
+ capability,
+ reason,
+ });
+ }
+ }
+
+ for extension in spirv_extensions {
+ if let Err(reason) = check_spirv_extension(&device, extension) {
+ return Err(ShaderCreationError::SpirvExtensionNotSupported {
+ extension: extension.to_owned(),
+ reason,
+ });
+ }
+ }
+
+ let handle = {
+ let infos = ash::vk::ShaderModuleCreateInfo {
+ flags: ash::vk::ShaderModuleCreateFlags::empty(),
+ code_size: words.len() * mem::size_of::<u32>(),
+ p_code: words.as_ptr(),
+ ..Default::default()
+ };
+
+ let fns = device.fns();
+ let mut output = MaybeUninit::uninit();
+ (fns.v1_0.create_shader_module)(
+ device.handle(),
+ &infos,
+ ptr::null(),
+ output.as_mut_ptr(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+ output.assume_init()
+ };
+
+ let entries = entry_points.into_iter().collect::<Vec<_>>();
+ let entry_points = entries
+ .iter()
+ .map(|(name, _, _)| name)
+ .collect::<HashSet<_>>()
+ .iter()
+ .map(|name| {
+ (
+ (*name).clone(),
+ entries
+ .iter()
+ .filter_map(|(entry_name, entry_model, info)| {
+ if &entry_name == name {
+ Some((*entry_model, info.clone()))
+ } else {
+ None
+ }
+ })
+ .collect::<HashMap<_, _>>(),
+ )
+ })
+ .collect();
+
+ Ok(Arc::new(ShaderModule {
+ handle,
+ device,
+ id: Self::next_id(),
+ entry_points,
+ }))
+ }
+
+ /// As `from_words_with_data`, but takes a slice of bytes.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the length of `bytes` is not a multiple of 4.
+ pub unsafe fn from_bytes_with_data<'a>(
+ device: Arc<Device>,
+ bytes: &[u8],
+ spirv_version: Version,
+ spirv_capabilities: impl IntoIterator<Item = &'a Capability>,
+ spirv_extensions: impl IntoIterator<Item = &'a str>,
+ entry_points: impl IntoIterator<Item = (String, ExecutionModel, EntryPointInfo)>,
+ ) -> Result<Arc<ShaderModule>, ShaderCreationError> {
+ assert!((bytes.len() % 4) == 0);
+
+ Self::from_words_with_data(
+ device,
+ std::slice::from_raw_parts(
+ bytes.as_ptr() as *const _,
+ bytes.len() / mem::size_of::<u32>(),
+ ),
+ spirv_version,
+ spirv_capabilities,
+ spirv_extensions,
+ entry_points,
+ )
+ }
+
+ /// Returns information about the entry point with the provided name. Returns `None` if no entry
+ /// point with that name exists in the shader module or if multiple entry points with the same
+ /// name exist.
+ #[inline]
+ pub fn entry_point<'a>(&'a self, name: &str) -> Option<EntryPoint<'a>> {
+ self.entry_points.get(name).and_then(|infos| {
+ if infos.len() == 1 {
+ infos.iter().next().map(|(_, info)| EntryPoint {
+ module: self,
+ name: CString::new(name).unwrap(),
+ info,
+ })
+ } else {
+ None
+ }
+ })
+ }
+
+ /// Returns information about the entry point with the provided name and execution model.
+ /// Returns `None` if no entry and execution model exists in the shader module.
+ #[inline]
+ pub fn entry_point_with_execution<'a>(
+ &'a self,
+ name: &str,
+ execution: ExecutionModel,
+ ) -> Option<EntryPoint<'a>> {
+ self.entry_points.get(name).and_then(|infos| {
+ infos.get(&execution).map(|info| EntryPoint {
+ module: self,
+ name: CString::new(name).unwrap(),
+ info,
+ })
+ })
+ }
+}
+
+impl Drop for ShaderModule {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ let fns = self.device.fns();
+ (fns.v1_0.destroy_shader_module)(self.device.handle(), self.handle, ptr::null());
+ }
+ }
+}
+
+unsafe impl VulkanObject for ShaderModule {
+ type Handle = ash::vk::ShaderModule;
+
+ #[inline]
+ fn handle(&self) -> Self::Handle {
+ self.handle
+ }
+}
+
+unsafe impl DeviceOwned for ShaderModule {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+}
+
+impl_id_counter!(ShaderModule);
+
+/// Error that can happen when creating a new shader module.
+#[derive(Clone, Debug)]
+pub enum ShaderCreationError {
+ OomError(OomError),
+ SpirvCapabilityNotSupported {
+ capability: Capability,
+ reason: ShaderSupportError,
+ },
+ SpirvError(SpirvError),
+ SpirvExtensionNotSupported {
+ extension: String,
+ reason: ShaderSupportError,
+ },
+ SpirvVersionNotSupported {
+ version: Version,
+ reason: ShaderSupportError,
+ },
+}
+
+impl Error for ShaderCreationError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::OomError(err) => Some(err),
+ Self::SpirvCapabilityNotSupported { reason, .. } => Some(reason),
+ Self::SpirvError(err) => Some(err),
+ Self::SpirvExtensionNotSupported { reason, .. } => Some(reason),
+ Self::SpirvVersionNotSupported { reason, .. } => Some(reason),
+ }
+ }
+}
+
+impl Display for ShaderCreationError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::OomError(_) => write!(f, "not enough memory available"),
+ Self::SpirvCapabilityNotSupported { capability, .. } => write!(
+ f,
+ "the SPIR-V capability {:?} enabled by the shader is not supported by the device",
+ capability,
+ ),
+ Self::SpirvError(_) => write!(f, "the SPIR-V module could not be read"),
+ Self::SpirvExtensionNotSupported { extension, .. } => write!(
+ f,
+ "the SPIR-V extension {} enabled by the shader is not supported by the device",
+ extension,
+ ),
+ Self::SpirvVersionNotSupported { version, .. } => write!(
+ f,
+ "the shader uses SPIR-V version {}.{}, which is not supported by the device",
+ version.major, version.minor,
+ ),
+ }
+ }
+}
+
+impl From<VulkanError> for ShaderCreationError {
+ fn from(err: VulkanError) -> Self {
+ Self::OomError(err.into())
+ }
+}
+
+impl From<SpirvError> for ShaderCreationError {
+ fn from(err: SpirvError) -> Self {
+ Self::SpirvError(err)
+ }
+}
+
+/// Error that can happen when checking whether a shader is supported by a device.
+#[derive(Clone, Copy, Debug)]
+pub enum ShaderSupportError {
+ NotSupportedByVulkan,
+ RequirementsNotMet(&'static [&'static str]),
+}
+
+impl Error for ShaderSupportError {}
+
+impl Display for ShaderSupportError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::NotSupportedByVulkan => write!(f, "not supported by Vulkan"),
+ Self::RequirementsNotMet(requirements) => write!(
+ f,
+ "at least one of the following must be available/enabled on the device: {}",
+ requirements.join(", "),
+ ),
+ }
+ }
+}
+
+/// The information associated with a single entry point in a shader.
+#[derive(Clone, Debug)]
+pub struct EntryPointInfo {
+ pub execution: ShaderExecution,
+ pub descriptor_binding_requirements: HashMap<(u32, u32), DescriptorBindingRequirements>,
+ pub push_constant_requirements: Option<PushConstantRange>,
+ pub specialization_constant_requirements: HashMap<u32, SpecializationConstantRequirements>,
+ pub input_interface: ShaderInterface,
+ pub output_interface: ShaderInterface,
+}
+
+/// Represents a shader entry point in a shader module.
+///
+/// Can be obtained by calling [`entry_point`](ShaderModule::entry_point) on the shader module.
+#[derive(Clone, Debug)]
+pub struct EntryPoint<'a> {
+ module: &'a ShaderModule,
+ name: CString,
+ info: &'a EntryPointInfo,
+}
+
+impl<'a> EntryPoint<'a> {
+ /// Returns the module this entry point comes from.
+ #[inline]
+ pub fn module(&self) -> &'a ShaderModule {
+ self.module
+ }
+
+ /// Returns the name of the entry point.
+ #[inline]
+ pub fn name(&self) -> &CStr {
+ &self.name
+ }
+
+ /// Returns the execution model of the shader.
+ #[inline]
+ pub fn execution(&self) -> &ShaderExecution {
+ &self.info.execution
+ }
+
+ /// Returns the descriptor binding requirements.
+ #[inline]
+ pub fn descriptor_binding_requirements(
+ &self,
+ ) -> impl ExactSizeIterator<Item = ((u32, u32), &DescriptorBindingRequirements)> {
+ self.info
+ .descriptor_binding_requirements
+ .iter()
+ .map(|(k, v)| (*k, v))
+ }
+
+ /// Returns the push constant requirements.
+ #[inline]
+ pub fn push_constant_requirements(&self) -> Option<&PushConstantRange> {
+ self.info.push_constant_requirements.as_ref()
+ }
+
+ /// Returns the specialization constant requirements.
+ #[inline]
+ pub fn specialization_constant_requirements(
+ &self,
+ ) -> impl ExactSizeIterator<Item = (u32, &SpecializationConstantRequirements)> {
+ self.info
+ .specialization_constant_requirements
+ .iter()
+ .map(|(k, v)| (*k, v))
+ }
+
+ /// Returns the input attributes used by the shader stage.
+ #[inline]
+ pub fn input_interface(&self) -> &ShaderInterface {
+ &self.info.input_interface
+ }
+
+ /// Returns the output attributes used by the shader stage.
+ #[inline]
+ pub fn output_interface(&self) -> &ShaderInterface {
+ &self.info.output_interface
+ }
+}
+
+/// The mode in which a shader executes. This includes both information about the shader type/stage,
+/// and additional data relevant to particular shader types.
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub enum ShaderExecution {
+ Vertex,
+ TessellationControl,
+ TessellationEvaluation,
+ Geometry(GeometryShaderExecution),
+ Fragment(FragmentShaderExecution),
+ Compute,
+ RayGeneration,
+ AnyHit,
+ ClosestHit,
+ Miss,
+ Intersection,
+ Callable,
+ Task,
+ Mesh,
+ SubpassShading,
+}
+
+/*#[derive(Clone, Copy, Debug)]
+pub struct TessellationShaderExecution {
+ pub num_output_vertices: u32,
+ pub point_mode: bool,
+ pub subdivision: TessellationShaderSubdivision,
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub enum TessellationShaderSubdivision {
+ Triangles,
+ Quads,
+ Isolines,
+}*/
+
+/// The mode in which a geometry shader executes.
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub struct GeometryShaderExecution {
+ pub input: GeometryShaderInput,
+ /*pub max_output_vertices: u32,
+ pub num_invocations: u32,
+ pub output: GeometryShaderOutput,*/
+}
+
+/// The input primitive type that is expected by a geometry shader.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub enum GeometryShaderInput {
+ Points,
+ Lines,
+ LinesWithAdjacency,
+ Triangles,
+ TrianglesWithAdjacency,
+}
+
+impl GeometryShaderInput {
+ /// Returns true if the given primitive topology can be used as input for this geometry shader.
+ #[inline]
+ pub fn is_compatible_with(self, topology: PrimitiveTopology) -> bool {
+ match self {
+ Self::Points => matches!(topology, PrimitiveTopology::PointList),
+ Self::Lines => matches!(
+ topology,
+ PrimitiveTopology::LineList | PrimitiveTopology::LineStrip
+ ),
+ Self::LinesWithAdjacency => matches!(
+ topology,
+ PrimitiveTopology::LineListWithAdjacency
+ | PrimitiveTopology::LineStripWithAdjacency
+ ),
+ Self::Triangles => matches!(
+ topology,
+ PrimitiveTopology::TriangleList
+ | PrimitiveTopology::TriangleStrip
+ | PrimitiveTopology::TriangleFan,
+ ),
+ Self::TrianglesWithAdjacency => matches!(
+ topology,
+ PrimitiveTopology::TriangleListWithAdjacency
+ | PrimitiveTopology::TriangleStripWithAdjacency,
+ ),
+ }
+ }
+}
+
+/*#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub enum GeometryShaderOutput {
+ Points,
+ LineStrip,
+ TriangleStrip,
+}*/
+
+/// The mode in which a fragment shader executes.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub struct FragmentShaderExecution {
+ pub fragment_tests_stages: FragmentTestsStages,
+}
+
+/// The fragment tests stages that will be executed in a fragment shader.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub enum FragmentTestsStages {
+ Early,
+ Late,
+ EarlyAndLate,
+}
+
+/// The requirements imposed by a shader on a binding within a descriptor set layout, and on any
+/// resource that is bound to that binding.
+#[derive(Clone, Debug, Default)]
+pub struct DescriptorBindingRequirements {
+ /// The descriptor types that are allowed.
+ pub descriptor_types: Vec<DescriptorType>,
+
+ /// The number of descriptors (array elements) that the shader requires. The descriptor set
+ /// layout can declare more than this, but never less.
+ ///
+ /// `None` means that the shader declares this as a runtime-sized array, and could potentially
+ /// access every array element provided in the descriptor set.
+ pub descriptor_count: Option<u32>,
+
+ /// The image format that is required for image views bound to this binding. If this is
+ /// `None`, then any image format is allowed.
+ pub image_format: Option<Format>,
+
+ /// Whether image views bound to this binding must have multisampling enabled or disabled.
+ pub image_multisampled: bool,
+
+ /// The base scalar type required for the format of image views bound to this binding.
+ /// This is `None` for non-image bindings.
+ pub image_scalar_type: Option<ShaderScalarType>,
+
+ /// The view type that is required for image views bound to this binding.
+ /// This is `None` for non-image bindings.
+ pub image_view_type: Option<ImageViewType>,
+
+ /// The shader stages that the binding must be declared for.
+ pub stages: ShaderStages,
+
+ /// The requirements for individual descriptors within a binding.
+ ///
+ /// Keys with `Some` hold requirements for a specific descriptor index, if it is statically
+ /// known in the shader (a constant). The key `None` holds requirements for indices that are
+ /// not statically known, but determined only at runtime (calculated from an input variable).
+ pub descriptors: HashMap<Option<u32>, DescriptorRequirements>,
+}
+
+/// The requirements imposed by a shader on resources bound to a descriptor.
+#[derive(Clone, Debug, Default)]
+pub struct DescriptorRequirements {
+ /// For buffers and images, which shader stages perform read operations.
+ pub memory_read: ShaderStages,
+
+ /// For buffers and images, which shader stages perform write operations.
+ pub memory_write: ShaderStages,
+
+ /// For sampler bindings, whether the shader performs depth comparison operations.
+ pub sampler_compare: bool,
+
+ /// For sampler bindings, whether the shader performs sampling operations that are not
+ /// permitted with unnormalized coordinates. This includes sampling with `ImplicitLod`,
+ /// `Dref` or `Proj` SPIR-V instructions or with an LOD bias or offset.
+ pub sampler_no_unnormalized_coordinates: bool,
+
+ /// For sampler bindings, whether the shader performs sampling operations that are not
+ /// permitted with a sampler YCbCr conversion. This includes sampling with `Gather` SPIR-V
+ /// instructions or with an offset.
+ pub sampler_no_ycbcr_conversion: bool,
+
+ /// For sampler bindings, the sampled image descriptors that are used in combination with this
+ /// sampler.
+ pub sampler_with_images: HashSet<DescriptorIdentifier>,
+
+ /// For storage image bindings, whether the shader performs atomic operations.
+ pub storage_image_atomic: bool,
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct DescriptorIdentifier {
+ pub set: u32,
+ pub binding: u32,
+ pub index: u32,
+}
+
+impl DescriptorBindingRequirements {
+ /// Merges `other` into `self`, so that `self` satisfies the requirements of both.
+ /// An error is returned if the requirements conflict.
+ #[inline]
+ pub fn merge(&mut self, other: &Self) -> Result<(), DescriptorBindingRequirementsIncompatible> {
+ let Self {
+ descriptor_types,
+ descriptor_count,
+ image_format,
+ image_multisampled,
+ image_scalar_type,
+ image_view_type,
+ stages,
+ descriptors,
+ } = self;
+
+ /* Checks */
+
+ if !descriptor_types
+ .iter()
+ .any(|ty| other.descriptor_types.contains(ty))
+ {
+ return Err(DescriptorBindingRequirementsIncompatible::DescriptorType);
+ }
+
+ if let (Some(first), Some(second)) = (*image_format, other.image_format) {
+ if first != second {
+ return Err(DescriptorBindingRequirementsIncompatible::ImageFormat);
+ }
+ }
+
+ if let (Some(first), Some(second)) = (*image_scalar_type, other.image_scalar_type) {
+ if first != second {
+ return Err(DescriptorBindingRequirementsIncompatible::ImageScalarType);
+ }
+ }
+
+ if let (Some(first), Some(second)) = (*image_view_type, other.image_view_type) {
+ if first != second {
+ return Err(DescriptorBindingRequirementsIncompatible::ImageViewType);
+ }
+ }
+
+ if *image_multisampled != other.image_multisampled {
+ return Err(DescriptorBindingRequirementsIncompatible::ImageMultisampled);
+ }
+
+ /* Merge */
+
+ descriptor_types.retain(|ty| other.descriptor_types.contains(ty));
+
+ *descriptor_count = (*descriptor_count).max(other.descriptor_count);
+ *image_format = image_format.or(other.image_format);
+ *image_scalar_type = image_scalar_type.or(other.image_scalar_type);
+ *image_view_type = image_view_type.or(other.image_view_type);
+ *stages |= other.stages;
+
+ for (&index, other) in &other.descriptors {
+ match descriptors.entry(index) {
+ Entry::Vacant(entry) => {
+ entry.insert(other.clone());
+ }
+ Entry::Occupied(entry) => {
+ entry.into_mut().merge(other);
+ }
+ }
+ }
+
+ Ok(())
+ }
+}
+
+impl DescriptorRequirements {
+ /// Merges `other` into `self`, so that `self` satisfies the requirements of both.
+ #[inline]
+ pub fn merge(&mut self, other: &Self) {
+ let Self {
+ memory_read,
+ memory_write,
+ sampler_compare,
+ sampler_no_unnormalized_coordinates,
+ sampler_no_ycbcr_conversion,
+ sampler_with_images,
+ storage_image_atomic,
+ } = self;
+
+ *memory_read |= other.memory_read;
+ *memory_write |= other.memory_write;
+ *sampler_compare |= other.sampler_compare;
+ *sampler_no_unnormalized_coordinates |= other.sampler_no_unnormalized_coordinates;
+ *sampler_no_ycbcr_conversion |= other.sampler_no_ycbcr_conversion;
+ sampler_with_images.extend(&other.sampler_with_images);
+ *storage_image_atomic |= other.storage_image_atomic;
+ }
+}
+
+/// An error that can be returned when trying to create the intersection of two
+/// `DescriptorBindingRequirements` values.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum DescriptorBindingRequirementsIncompatible {
+ /// The allowed descriptor types of the descriptors do not overlap.
+ DescriptorType,
+ /// The descriptors require different formats.
+ ImageFormat,
+ /// The descriptors require different scalar types.
+ ImageScalarType,
+ /// The multisampling requirements of the descriptors differ.
+ ImageMultisampled,
+ /// The descriptors require different image view types.
+ ImageViewType,
+}
+
+impl Error for DescriptorBindingRequirementsIncompatible {}
+
+impl Display for DescriptorBindingRequirementsIncompatible {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ DescriptorBindingRequirementsIncompatible::DescriptorType => write!(
+ f,
+ "the allowed descriptor types of the two descriptors do not overlap",
+ ),
+ DescriptorBindingRequirementsIncompatible::ImageFormat => {
+ write!(f, "the descriptors require different formats",)
+ }
+ DescriptorBindingRequirementsIncompatible::ImageMultisampled => write!(
+ f,
+ "the multisampling requirements of the descriptors differ",
+ ),
+ DescriptorBindingRequirementsIncompatible::ImageScalarType => {
+ write!(f, "the descriptors require different scalar types",)
+ }
+ DescriptorBindingRequirementsIncompatible::ImageViewType => {
+ write!(f, "the descriptors require different image view types",)
+ }
+ }
+ }
+}
+
+/// The requirements imposed by a shader on a specialization constant.
+#[derive(Clone, Copy, Debug)]
+pub struct SpecializationConstantRequirements {
+ pub size: DeviceSize,
+}
+
+/// Trait for types that contain specialization data for shaders.
+///
+/// Shader modules can contain what is called *specialization constants*. They are the same as
+/// constants except that their values can be defined when you create a compute pipeline or a
+/// graphics pipeline. Doing so is done by passing a type that implements the
+/// `SpecializationConstants` trait and that stores the values in question. The `descriptors()`
+/// method of this trait indicates how to grab them.
+///
+/// Boolean specialization constants must be stored as 32bits integers, where `0` means `false` and
+/// any non-zero value means `true`. Integer and floating-point specialization constants are
+/// stored as their Rust equivalent.
+///
+/// This trait is implemented on `()` for shaders that don't have any specialization constant.
+///
+/// # Examples
+///
+/// ```rust
+/// use vulkano::shader::SpecializationConstants;
+/// use vulkano::shader::SpecializationMapEntry;
+///
+/// #[repr(C)] // `#[repr(C)]` guarantees that the struct has a specific layout
+/// struct MySpecConstants {
+/// my_integer_constant: i32,
+/// a_boolean: u32,
+/// floating_point: f32,
+/// }
+///
+/// unsafe impl SpecializationConstants for MySpecConstants {
+/// fn descriptors() -> &'static [SpecializationMapEntry] {
+/// static DESCRIPTORS: [SpecializationMapEntry; 3] = [
+/// SpecializationMapEntry {
+/// constant_id: 0,
+/// offset: 0,
+/// size: 4,
+/// },
+/// SpecializationMapEntry {
+/// constant_id: 1,
+/// offset: 4,
+/// size: 4,
+/// },
+/// SpecializationMapEntry {
+/// constant_id: 2,
+/// offset: 8,
+/// size: 4,
+/// },
+/// ];
+///
+/// &DESCRIPTORS
+/// }
+/// }
+/// ```
+///
+/// # Safety
+///
+/// - The `SpecializationMapEntry` returned must contain valid offsets and sizes.
+/// - The size of each `SpecializationMapEntry` must match the size of the corresponding constant
+/// (`4` for booleans).
+pub unsafe trait SpecializationConstants {
+ /// Returns descriptors of the struct's layout.
+ fn descriptors() -> &'static [SpecializationMapEntry];
+}
+
+unsafe impl SpecializationConstants for () {
+ #[inline]
+ fn descriptors() -> &'static [SpecializationMapEntry] {
+ &[]
+ }
+}
+
+/// Describes an individual constant to set in the shader. Also a field in the struct.
+// Implementation note: has the same memory representation as a `VkSpecializationMapEntry`.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[repr(C)]
+pub struct SpecializationMapEntry {
+ /// Identifier of the constant in the shader that corresponds to this field.
+ ///
+ /// For SPIR-V, this must be the value of the `SpecId` decoration applied to the specialization
+ /// constant.
+ /// For GLSL, this must be the value of `N` in the `layout(constant_id = N)` attribute applied
+ /// to a constant.
+ pub constant_id: u32,
+
+ /// Offset within the struct where the data can be found.
+ pub offset: u32,
+
+ /// Size of the data in bytes. Must match the size of the constant (`4` for booleans).
+ pub size: usize,
+}
+
+impl From<SpecializationMapEntry> for ash::vk::SpecializationMapEntry {
+ #[inline]
+ fn from(val: SpecializationMapEntry) -> Self {
+ Self {
+ constant_id: val.constant_id,
+ offset: val.offset,
+ size: val.size,
+ }
+ }
+}
+
+/// Type that contains the definition of an interface between two shader stages, or between
+/// the outside and a shader stage.
+#[derive(Clone, Debug)]
+pub struct ShaderInterface {
+ elements: Vec<ShaderInterfaceEntry>,
+}
+
+impl ShaderInterface {
+ /// Constructs a new `ShaderInterface`.
+ ///
+ /// # Safety
+ ///
+ /// - Must only provide one entry per location.
+ /// - The format of each element must not be larger than 128 bits.
+ // TODO: 4x64 bit formats are possible, but they require special handling.
+ // TODO: could this be made safe?
+ #[inline]
+ pub unsafe fn new_unchecked(elements: Vec<ShaderInterfaceEntry>) -> ShaderInterface {
+ ShaderInterface { elements }
+ }
+
+ /// Creates a description of an empty shader interface.
+ #[inline]
+ pub const fn empty() -> ShaderInterface {
+ ShaderInterface {
+ elements: Vec::new(),
+ }
+ }
+
+ /// Returns a slice containing the elements of the interface.
+ #[inline]
+ pub fn elements(&self) -> &[ShaderInterfaceEntry] {
+ self.elements.as_ref()
+ }
+
+ /// Checks whether the interface is potentially compatible with another one.
+ ///
+ /// Returns `Ok` if the two interfaces are compatible.
+ #[inline]
+ pub fn matches(&self, other: &ShaderInterface) -> Result<(), ShaderInterfaceMismatchError> {
+ if self.elements().len() != other.elements().len() {
+ return Err(ShaderInterfaceMismatchError::ElementsCountMismatch {
+ self_elements: self.elements().len() as u32,
+ other_elements: other.elements().len() as u32,
+ });
+ }
+
+ for a in self.elements() {
+ let location_range = a.location..a.location + a.ty.num_locations();
+ for loc in location_range {
+ let b = match other
+ .elements()
+ .iter()
+ .find(|e| loc >= e.location && loc < e.location + e.ty.num_locations())
+ {
+ None => {
+ return Err(ShaderInterfaceMismatchError::MissingElement { location: loc })
+ }
+ Some(b) => b,
+ };
+
+ if a.ty != b.ty {
+ return Err(ShaderInterfaceMismatchError::TypeMismatch {
+ location: loc,
+ self_ty: a.ty,
+ other_ty: b.ty,
+ });
+ }
+
+ // TODO: enforce this?
+ /*match (a.name, b.name) {
+ (Some(ref an), Some(ref bn)) => if an != bn { return false },
+ _ => ()
+ };*/
+ }
+ }
+
+ // Note: since we check that the number of elements is the same, we don't need to iterate
+ // over b's elements.
+
+ Ok(())
+ }
+}
+
+/// Entry of a shader interface definition.
+#[derive(Debug, Clone)]
+pub struct ShaderInterfaceEntry {
+ /// The location slot that the variable starts at.
+ pub location: u32,
+
+ /// The component slot that the variable starts at. Must be in the range 0..=3.
+ pub component: u32,
+
+ /// Name of the element, or `None` if the name is unknown.
+ pub name: Option<Cow<'static, str>>,
+
+ /// The type of the variable.
+ pub ty: ShaderInterfaceEntryType,
+}
+
+/// The type of a variable in a shader interface.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct ShaderInterfaceEntryType {
+ /// The base numeric type.
+ pub base_type: ShaderScalarType,
+
+ /// The number of vector components. Must be in the range 1..=4.
+ pub num_components: u32,
+
+ /// The number of array elements or matrix columns.
+ pub num_elements: u32,
+
+ /// Whether the base type is 64 bits wide. If true, each item of the base type takes up two
+ /// component slots instead of one.
+ pub is_64bit: bool,
+}
+
+impl ShaderInterfaceEntryType {
+ pub(crate) fn num_locations(&self) -> u32 {
+ assert!(!self.is_64bit); // TODO: implement
+ self.num_elements
+ }
+}
+
+/// The numeric base type of a shader variable.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub enum ShaderScalarType {
+ Float,
+ Sint,
+ Uint,
+}
+
+// https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap43.html#formats-numericformat
+impl From<NumericType> for ShaderScalarType {
+ #[inline]
+ fn from(val: NumericType) -> Self {
+ match val {
+ NumericType::SFLOAT => Self::Float,
+ NumericType::UFLOAT => Self::Float,
+ NumericType::SINT => Self::Sint,
+ NumericType::UINT => Self::Uint,
+ NumericType::SNORM => Self::Float,
+ NumericType::UNORM => Self::Float,
+ NumericType::SSCALED => Self::Float,
+ NumericType::USCALED => Self::Float,
+ NumericType::SRGB => Self::Float,
+ }
+ }
+}
+
+/// Error that can happen when the interface mismatches between two shader stages.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum ShaderInterfaceMismatchError {
+ /// The number of elements is not the same between the two shader interfaces.
+ ElementsCountMismatch {
+ /// Number of elements in the first interface.
+ self_elements: u32,
+ /// Number of elements in the second interface.
+ other_elements: u32,
+ },
+
+ /// An element is missing from one of the interfaces.
+ MissingElement {
+ /// Location of the missing element.
+ location: u32,
+ },
+
+ /// The type of an element does not match.
+ TypeMismatch {
+ /// Location of the element that mismatches.
+ location: u32,
+ /// Type in the first interface.
+ self_ty: ShaderInterfaceEntryType,
+ /// Type in the second interface.
+ other_ty: ShaderInterfaceEntryType,
+ },
+}
+
+impl Error for ShaderInterfaceMismatchError {}
+
+impl Display for ShaderInterfaceMismatchError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ write!(
+ f,
+ "{}",
+ match self {
+ ShaderInterfaceMismatchError::ElementsCountMismatch { .. } => {
+ "the number of elements mismatches"
+ }
+ ShaderInterfaceMismatchError::MissingElement { .. } => "an element is missing",
+ ShaderInterfaceMismatchError::TypeMismatch { .. } => {
+ "the type of an element does not match"
+ }
+ }
+ )
+ }
+}
+
+vulkan_bitflags_enum! {
+ #[non_exhaustive]
+
+ /// A set of [`ShaderStage`] values.
+ ShaderStages impl {
+ /// Creates a `ShaderStages` struct with all graphics stages set to `true`.
+ #[inline]
+ pub const fn all_graphics() -> ShaderStages {
+ ShaderStages::VERTEX
+ .union(ShaderStages::TESSELLATION_CONTROL)
+ .union(ShaderStages::TESSELLATION_EVALUATION)
+ .union(ShaderStages::GEOMETRY)
+ .union(ShaderStages::FRAGMENT)
+ }
+ },
+
+ /// A shader stage within a pipeline.
+ ShaderStage,
+
+ = ShaderStageFlags(u32);
+
+ // TODO: document
+ VERTEX, Vertex = VERTEX,
+
+ // TODO: document
+ TESSELLATION_CONTROL, TessellationControl = TESSELLATION_CONTROL,
+
+ // TODO: document
+ TESSELLATION_EVALUATION, TessellationEvaluation = TESSELLATION_EVALUATION,
+
+ // TODO: document
+ GEOMETRY, Geometry = GEOMETRY,
+
+ // TODO: document
+ FRAGMENT, Fragment = FRAGMENT,
+
+ // TODO: document
+ COMPUTE, Compute = COMPUTE,
+
+ // TODO: document
+ RAYGEN, Raygen = RAYGEN_KHR {
+ device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
+ },
+
+ // TODO: document
+ ANY_HIT, AnyHit = ANY_HIT_KHR {
+ device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
+ },
+
+ // TODO: document
+ CLOSEST_HIT, ClosestHit = CLOSEST_HIT_KHR {
+ device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
+ },
+
+ // TODO: document
+ MISS, Miss = MISS_KHR {
+ device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
+ },
+
+ // TODO: document
+ INTERSECTION, Intersection = INTERSECTION_KHR {
+ device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
+ },
+
+ // TODO: document
+ CALLABLE, Callable = CALLABLE_KHR {
+ device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
+ },
+
+ // TODO: document
+ TASK, Task = TASK_EXT {
+ device_extensions: [ext_mesh_shader, nv_mesh_shader],
+ },
+
+ // TODO: document
+ MESH, Mesh = MESH_EXT {
+ device_extensions: [ext_mesh_shader, nv_mesh_shader],
+ },
+
+ // TODO: document
+ SUBPASS_SHADING, SubpassShading = SUBPASS_SHADING_HUAWEI {
+ device_extensions: [huawei_subpass_shading],
+ },
+}
+
+impl From<ShaderExecution> for ShaderStage {
+ #[inline]
+ fn from(val: ShaderExecution) -> Self {
+ match val {
+ ShaderExecution::Vertex => Self::Vertex,
+ ShaderExecution::TessellationControl => Self::TessellationControl,
+ ShaderExecution::TessellationEvaluation => Self::TessellationEvaluation,
+ ShaderExecution::Geometry(_) => Self::Geometry,
+ ShaderExecution::Fragment(_) => Self::Fragment,
+ ShaderExecution::Compute => Self::Compute,
+ ShaderExecution::RayGeneration => Self::Raygen,
+ ShaderExecution::AnyHit => Self::AnyHit,
+ ShaderExecution::ClosestHit => Self::ClosestHit,
+ ShaderExecution::Miss => Self::Miss,
+ ShaderExecution::Intersection => Self::Intersection,
+ ShaderExecution::Callable => Self::Callable,
+ ShaderExecution::Task => Self::Task,
+ ShaderExecution::Mesh => Self::Mesh,
+ ShaderExecution::SubpassShading => Self::SubpassShading,
+ }
+ }
+}
+
+impl From<ShaderStages> for PipelineStages {
+ #[inline]
+ fn from(stages: ShaderStages) -> PipelineStages {
+ let mut result = PipelineStages::empty();
+
+ if stages.intersects(ShaderStages::VERTEX) {
+ result |= PipelineStages::VERTEX_SHADER
+ }
+
+ if stages.intersects(ShaderStages::TESSELLATION_CONTROL) {
+ result |= PipelineStages::TESSELLATION_CONTROL_SHADER
+ }
+
+ if stages.intersects(ShaderStages::TESSELLATION_EVALUATION) {
+ result |= PipelineStages::TESSELLATION_EVALUATION_SHADER
+ }
+
+ if stages.intersects(ShaderStages::GEOMETRY) {
+ result |= PipelineStages::GEOMETRY_SHADER
+ }
+
+ if stages.intersects(ShaderStages::FRAGMENT) {
+ result |= PipelineStages::FRAGMENT_SHADER
+ }
+
+ if stages.intersects(ShaderStages::COMPUTE) {
+ result |= PipelineStages::COMPUTE_SHADER
+ }
+
+ if stages.intersects(
+ ShaderStages::RAYGEN
+ | ShaderStages::ANY_HIT
+ | ShaderStages::CLOSEST_HIT
+ | ShaderStages::MISS
+ | ShaderStages::INTERSECTION
+ | ShaderStages::CALLABLE,
+ ) {
+ result |= PipelineStages::RAY_TRACING_SHADER
+ }
+
+ if stages.intersects(ShaderStages::TASK) {
+ result |= PipelineStages::TASK_SHADER;
+ }
+
+ if stages.intersects(ShaderStages::MESH) {
+ result |= PipelineStages::MESH_SHADER;
+ }
+
+ if stages.intersects(ShaderStages::SUBPASS_SHADING) {
+ result |= PipelineStages::SUBPASS_SHADING;
+ }
+
+ result
+ }
+}
+
+fn check_spirv_version(device: &Device, mut version: Version) -> Result<(), ShaderSupportError> {
+ version.patch = 0; // Ignore the patch version
+
+ match version {
+ Version::V1_0 => {}
+ Version::V1_1 | Version::V1_2 | Version::V1_3 => {
+ if !(device.api_version() >= Version::V1_1) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "Vulkan API version 1.1",
+ ]));
+ }
+ }
+ Version::V1_4 => {
+ if !(device.api_version() >= Version::V1_2 || device.enabled_extensions().khr_spirv_1_4)
+ {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "Vulkan API version 1.2",
+ "extension `khr_spirv_1_4`",
+ ]));
+ }
+ }
+ Version::V1_5 => {
+ if !(device.api_version() >= Version::V1_2) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "Vulkan API version 1.2",
+ ]));
+ }
+ }
+ Version::V1_6 => {
+ if !(device.api_version() >= Version::V1_3) {
+ return Err(ShaderSupportError::RequirementsNotMet(&[
+ "Vulkan API version 1.3",
+ ]));
+ }
+ }
+ _ => return Err(ShaderSupportError::NotSupportedByVulkan),
+ }
+ Ok(())
+}
diff --git a/src/shader/reflect.rs b/src/shader/reflect.rs
new file mode 100644
index 0000000..a96923f
--- /dev/null
+++ b/src/shader/reflect.rs
@@ -0,0 +1,1443 @@
+// Copyright (c) 2021 The Vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+//! Extraction of information from SPIR-V modules, that is needed by the rest of Vulkano.
+
+use super::{DescriptorBindingRequirements, FragmentShaderExecution, FragmentTestsStages};
+use crate::{
+ descriptor_set::layout::DescriptorType,
+ image::view::ImageViewType,
+ pipeline::layout::PushConstantRange,
+ shader::{
+ spirv::{
+ Capability, Decoration, Dim, ExecutionMode, ExecutionModel, Id, Instruction, Spirv,
+ StorageClass,
+ },
+ DescriptorIdentifier, DescriptorRequirements, EntryPointInfo, GeometryShaderExecution,
+ GeometryShaderInput, ShaderExecution, ShaderInterface, ShaderInterfaceEntry,
+ ShaderInterfaceEntryType, ShaderScalarType, ShaderStage,
+ SpecializationConstantRequirements,
+ },
+ DeviceSize,
+};
+use ahash::{HashMap, HashSet};
+use std::borrow::Cow;
+
+/// Returns an iterator of the capabilities used by `spirv`.
+#[inline]
+pub fn spirv_capabilities(spirv: &Spirv) -> impl Iterator<Item = &Capability> {
+ spirv
+ .iter_capability()
+ .filter_map(|instruction| match instruction {
+ Instruction::Capability { capability } => Some(capability),
+ _ => None,
+ })
+}
+
+/// Returns an iterator of the extensions used by `spirv`.
+#[inline]
+pub fn spirv_extensions(spirv: &Spirv) -> impl Iterator<Item = &str> {
+ spirv
+ .iter_extension()
+ .filter_map(|instruction| match instruction {
+ Instruction::Extension { name } => Some(name.as_str()),
+ _ => None,
+ })
+}
+
+/// Returns an iterator over all entry points in `spirv`, with information about the entry point.
+#[inline]
+pub fn entry_points(
+ spirv: &Spirv,
+) -> impl Iterator<Item = (String, ExecutionModel, EntryPointInfo)> + '_ {
+ let interface_variables = interface_variables(spirv);
+
+ spirv.iter_entry_point().filter_map(move |instruction| {
+ let (execution_model, function_id, entry_point_name, interface) = match instruction {
+ Instruction::EntryPoint {
+ execution_model,
+ entry_point,
+ name,
+ interface,
+ ..
+ } => (*execution_model, *entry_point, name, interface),
+ _ => return None,
+ };
+
+ let execution = shader_execution(spirv, execution_model, function_id);
+ let stage = ShaderStage::from(execution);
+
+ let descriptor_binding_requirements = inspect_entry_point(
+ &interface_variables.descriptor_binding,
+ spirv,
+ stage,
+ function_id,
+ );
+ let push_constant_requirements = push_constant_requirements(spirv, stage);
+ let specialization_constant_requirements = specialization_constant_requirements(spirv);
+ let input_interface = shader_interface(
+ spirv,
+ interface,
+ StorageClass::Input,
+ matches!(
+ execution_model,
+ ExecutionModel::TessellationControl
+ | ExecutionModel::TessellationEvaluation
+ | ExecutionModel::Geometry
+ ),
+ );
+ let output_interface = shader_interface(
+ spirv,
+ interface,
+ StorageClass::Output,
+ matches!(execution_model, ExecutionModel::TessellationControl),
+ );
+
+ Some((
+ entry_point_name.clone(),
+ execution_model,
+ EntryPointInfo {
+ execution,
+ descriptor_binding_requirements,
+ push_constant_requirements,
+ specialization_constant_requirements,
+ input_interface,
+ output_interface,
+ },
+ ))
+ })
+}
+
+/// Extracts the `ShaderExecution` for the entry point `function_id` from `spirv`.
+fn shader_execution(
+ spirv: &Spirv,
+ execution_model: ExecutionModel,
+ function_id: Id,
+) -> ShaderExecution {
+ match execution_model {
+ ExecutionModel::Vertex => ShaderExecution::Vertex,
+
+ ExecutionModel::TessellationControl => ShaderExecution::TessellationControl,
+
+ ExecutionModel::TessellationEvaluation => ShaderExecution::TessellationEvaluation,
+
+ ExecutionModel::Geometry => {
+ let mut input = None;
+
+ for instruction in spirv.iter_execution_mode() {
+ let mode = match instruction {
+ Instruction::ExecutionMode {
+ entry_point, mode, ..
+ } if *entry_point == function_id => mode,
+ _ => continue,
+ };
+
+ match mode {
+ ExecutionMode::InputPoints => {
+ input = Some(GeometryShaderInput::Points);
+ }
+ ExecutionMode::InputLines => {
+ input = Some(GeometryShaderInput::Lines);
+ }
+ ExecutionMode::InputLinesAdjacency => {
+ input = Some(GeometryShaderInput::LinesWithAdjacency);
+ }
+ ExecutionMode::Triangles => {
+ input = Some(GeometryShaderInput::Triangles);
+ }
+ ExecutionMode::InputTrianglesAdjacency => {
+ input = Some(GeometryShaderInput::TrianglesWithAdjacency);
+ }
+ _ => (),
+ }
+ }
+
+ ShaderExecution::Geometry(GeometryShaderExecution {
+ input: input
+ .expect("Geometry shader does not have an input primitive ExecutionMode"),
+ })
+ }
+
+ ExecutionModel::Fragment => {
+ let mut fragment_tests_stages = FragmentTestsStages::Late;
+
+ for instruction in spirv.iter_execution_mode() {
+ let mode = match instruction {
+ Instruction::ExecutionMode {
+ entry_point, mode, ..
+ } if *entry_point == function_id => mode,
+ _ => continue,
+ };
+
+ #[allow(clippy::single_match)]
+ match mode {
+ ExecutionMode::EarlyFragmentTests => {
+ fragment_tests_stages = FragmentTestsStages::Early;
+ }
+ /*ExecutionMode::EarlyAndLateFragmentTestsAMD => {
+ fragment_tests_stages = FragmentTestsStages::EarlyAndLate;
+ }*/
+ _ => (),
+ }
+ }
+
+ ShaderExecution::Fragment(FragmentShaderExecution {
+ fragment_tests_stages,
+ })
+ }
+
+ ExecutionModel::GLCompute => ShaderExecution::Compute,
+
+ ExecutionModel::RayGenerationKHR => ShaderExecution::RayGeneration,
+ ExecutionModel::IntersectionKHR => ShaderExecution::Intersection,
+ ExecutionModel::AnyHitKHR => ShaderExecution::AnyHit,
+ ExecutionModel::ClosestHitKHR => ShaderExecution::ClosestHit,
+ ExecutionModel::MissKHR => ShaderExecution::Miss,
+ ExecutionModel::CallableKHR => ShaderExecution::Callable,
+
+ ExecutionModel::TaskNV => ShaderExecution::Task,
+ ExecutionModel::MeshNV => ShaderExecution::Mesh,
+
+ ExecutionModel::Kernel => todo!(),
+ }
+}
+
+#[derive(Clone, Debug, Default)]
+struct InterfaceVariables {
+ descriptor_binding: HashMap<Id, DescriptorBindingVariable>,
+}
+
+// See also section 14.5.2 of the Vulkan specs: Descriptor Set Interface.
+#[derive(Clone, Debug)]
+struct DescriptorBindingVariable {
+ set: u32,
+ binding: u32,
+ reqs: DescriptorBindingRequirements,
+}
+
+fn interface_variables(spirv: &Spirv) -> InterfaceVariables {
+ let mut variables = InterfaceVariables::default();
+
+ for instruction in spirv.iter_global() {
+ if let Instruction::Variable {
+ result_id,
+ result_type_id: _,
+ storage_class,
+ ..
+ } = instruction
+ {
+ match storage_class {
+ StorageClass::StorageBuffer
+ | StorageClass::Uniform
+ | StorageClass::UniformConstant => {
+ variables.descriptor_binding.insert(
+ *result_id,
+ descriptor_binding_requirements_of(spirv, *result_id),
+ );
+ }
+ _ => (),
+ }
+ }
+ }
+
+ variables
+}
+
+fn inspect_entry_point(
+ global: &HashMap<Id, DescriptorBindingVariable>,
+ spirv: &Spirv,
+ stage: ShaderStage,
+ entry_point: Id,
+) -> HashMap<(u32, u32), DescriptorBindingRequirements> {
+ struct Context<'a> {
+ global: &'a HashMap<Id, DescriptorBindingVariable>,
+ spirv: &'a Spirv,
+ stage: ShaderStage,
+ inspected_functions: HashSet<Id>,
+ result: HashMap<Id, DescriptorBindingVariable>,
+ }
+
+ impl<'a> Context<'a> {
+ fn instruction_chain<const N: usize>(
+ &mut self,
+ chain: [fn(&Spirv, Id) -> Option<Id>; N],
+ id: Id,
+ ) -> Option<(&mut DescriptorBindingVariable, Option<u32>)> {
+ let id = chain
+ .into_iter()
+ .try_fold(id, |id, func| func(self.spirv, id))?;
+
+ if let Some(variable) = self.global.get(&id) {
+ // Variable was accessed without an access chain, return with index 0.
+ let variable = self.result.entry(id).or_insert_with(|| variable.clone());
+ variable.reqs.stages = self.stage.into();
+ return Some((variable, Some(0)));
+ }
+
+ let (id, indexes) = match *self.spirv.id(id).instruction() {
+ Instruction::AccessChain {
+ base, ref indexes, ..
+ } => (base, indexes),
+ _ => return None,
+ };
+
+ if let Some(variable) = self.global.get(&id) {
+ // Variable was accessed with an access chain.
+ // Retrieve index from instruction if it's a constant value.
+ // TODO: handle a `None` index too?
+ let index = match *self.spirv.id(*indexes.first().unwrap()).instruction() {
+ Instruction::Constant { ref value, .. } => Some(value[0]),
+ _ => None,
+ };
+ let variable = self.result.entry(id).or_insert_with(|| variable.clone());
+ variable.reqs.stages = self.stage.into();
+ return Some((variable, index));
+ }
+
+ None
+ }
+
+ fn inspect_entry_point_r(&mut self, function: Id) {
+ fn desc_reqs(
+ descriptor_variable: Option<(&mut DescriptorBindingVariable, Option<u32>)>,
+ ) -> Option<&mut DescriptorRequirements> {
+ descriptor_variable
+ .map(|(variable, index)| variable.reqs.descriptors.entry(index).or_default())
+ }
+
+ fn inst_image_texel_pointer(spirv: &Spirv, id: Id) -> Option<Id> {
+ match *spirv.id(id).instruction() {
+ Instruction::ImageTexelPointer { image, .. } => Some(image),
+ _ => None,
+ }
+ }
+
+ fn inst_load(spirv: &Spirv, id: Id) -> Option<Id> {
+ match *spirv.id(id).instruction() {
+ Instruction::Load { pointer, .. } => Some(pointer),
+ _ => None,
+ }
+ }
+
+ fn inst_sampled_image(spirv: &Spirv, id: Id) -> Option<Id> {
+ match *spirv.id(id).instruction() {
+ Instruction::SampledImage { sampler, .. } => Some(sampler),
+ _ => Some(id),
+ }
+ }
+
+ self.inspected_functions.insert(function);
+ let mut in_function = false;
+
+ for instruction in self.spirv.instructions() {
+ if !in_function {
+ match *instruction {
+ Instruction::Function { result_id, .. } if result_id == function => {
+ in_function = true;
+ }
+ _ => {}
+ }
+ } else {
+ let stage = self.stage;
+
+ match *instruction {
+ Instruction::AtomicLoad { pointer, .. } => {
+ // Storage buffer
+ if let Some(desc_reqs) = desc_reqs(self.instruction_chain([], pointer))
+ {
+ desc_reqs.memory_read = stage.into();
+ }
+
+ // Storage image
+ if let Some(desc_reqs) = desc_reqs(
+ self.instruction_chain([inst_image_texel_pointer], pointer),
+ ) {
+ desc_reqs.memory_read = stage.into();
+ desc_reqs.storage_image_atomic = true;
+ }
+ }
+
+ Instruction::AtomicStore { pointer, .. } => {
+ // Storage buffer
+ if let Some(desc_reqs) = desc_reqs(self.instruction_chain([], pointer))
+ {
+ desc_reqs.memory_write = stage.into();
+ }
+
+ // Storage image
+ if let Some(desc_reqs) = desc_reqs(
+ self.instruction_chain([inst_image_texel_pointer], pointer),
+ ) {
+ desc_reqs.memory_write = stage.into();
+ desc_reqs.storage_image_atomic = true;
+ }
+ }
+
+ Instruction::AtomicExchange { pointer, .. }
+ | Instruction::AtomicCompareExchange { pointer, .. }
+ | Instruction::AtomicCompareExchangeWeak { pointer, .. }
+ | Instruction::AtomicIIncrement { pointer, .. }
+ | Instruction::AtomicIDecrement { pointer, .. }
+ | Instruction::AtomicIAdd { pointer, .. }
+ | Instruction::AtomicISub { pointer, .. }
+ | Instruction::AtomicSMin { pointer, .. }
+ | Instruction::AtomicUMin { pointer, .. }
+ | Instruction::AtomicSMax { pointer, .. }
+ | Instruction::AtomicUMax { pointer, .. }
+ | Instruction::AtomicAnd { pointer, .. }
+ | Instruction::AtomicOr { pointer, .. }
+ | Instruction::AtomicXor { pointer, .. }
+ | Instruction::AtomicFlagTestAndSet { pointer, .. }
+ | Instruction::AtomicFlagClear { pointer, .. }
+ | Instruction::AtomicFMinEXT { pointer, .. }
+ | Instruction::AtomicFMaxEXT { pointer, .. }
+ | Instruction::AtomicFAddEXT { pointer, .. } => {
+ // Storage buffer
+ if let Some(desc_reqs) = desc_reqs(self.instruction_chain([], pointer))
+ {
+ desc_reqs.memory_read = stage.into();
+ desc_reqs.memory_write = stage.into();
+ }
+
+ // Storage image
+ if let Some(desc_reqs) = desc_reqs(
+ self.instruction_chain([inst_image_texel_pointer], pointer),
+ ) {
+ desc_reqs.memory_read = stage.into();
+ desc_reqs.memory_write = stage.into();
+ desc_reqs.storage_image_atomic = true;
+ }
+ }
+
+ Instruction::CopyMemory { target, source, .. } => {
+ self.instruction_chain([], target);
+ self.instruction_chain([], source);
+ }
+
+ Instruction::CopyObject { operand, .. } => {
+ self.instruction_chain([], operand);
+ }
+
+ Instruction::ExtInst { ref operands, .. } => {
+ // We don't know which extended instructions take pointers,
+ // so we must interpret every operand as a pointer.
+ for &operand in operands {
+ self.instruction_chain([], operand);
+ }
+ }
+
+ Instruction::FunctionCall {
+ function,
+ ref arguments,
+ ..
+ } => {
+ // Rather than trying to figure out the type of each argument, we just
+ // try all of them as pointers.
+ for &argument in arguments {
+ self.instruction_chain([], argument);
+ }
+
+ if !self.inspected_functions.contains(&function) {
+ self.inspect_entry_point_r(function);
+ }
+ }
+
+ Instruction::FunctionEnd => return,
+
+ Instruction::ImageGather {
+ sampled_image,
+ image_operands,
+ ..
+ }
+ | Instruction::ImageSparseGather {
+ sampled_image,
+ image_operands,
+ ..
+ } => {
+ if let Some(desc_reqs) =
+ desc_reqs(self.instruction_chain(
+ [inst_sampled_image, inst_load],
+ sampled_image,
+ ))
+ {
+ desc_reqs.memory_read = stage.into();
+ desc_reqs.sampler_no_ycbcr_conversion = true;
+
+ if image_operands.as_ref().map_or(false, |image_operands| {
+ image_operands.bias.is_some()
+ || image_operands.const_offset.is_some()
+ || image_operands.offset.is_some()
+ }) {
+ desc_reqs.sampler_no_unnormalized_coordinates = true;
+ }
+ }
+ }
+
+ Instruction::ImageDrefGather { sampled_image, .. }
+ | Instruction::ImageSparseDrefGather { sampled_image, .. } => {
+ if let Some(desc_reqs) =
+ desc_reqs(self.instruction_chain(
+ [inst_sampled_image, inst_load],
+ sampled_image,
+ ))
+ {
+ desc_reqs.memory_read = stage.into();
+ desc_reqs.sampler_no_unnormalized_coordinates = true;
+ desc_reqs.sampler_no_ycbcr_conversion = true;
+ }
+ }
+
+ Instruction::ImageSampleImplicitLod {
+ sampled_image,
+ image_operands,
+ ..
+ }
+ | Instruction::ImageSampleProjImplicitLod {
+ sampled_image,
+ image_operands,
+ ..
+ }
+ | Instruction::ImageSparseSampleProjImplicitLod {
+ sampled_image,
+ image_operands,
+ ..
+ }
+ | Instruction::ImageSparseSampleImplicitLod {
+ sampled_image,
+ image_operands,
+ ..
+ } => {
+ if let Some(desc_reqs) =
+ desc_reqs(self.instruction_chain(
+ [inst_sampled_image, inst_load],
+ sampled_image,
+ ))
+ {
+ desc_reqs.memory_read = stage.into();
+ desc_reqs.sampler_no_unnormalized_coordinates = true;
+
+ if image_operands.as_ref().map_or(false, |image_operands| {
+ image_operands.const_offset.is_some()
+ || image_operands.offset.is_some()
+ }) {
+ desc_reqs.sampler_no_ycbcr_conversion = true;
+ }
+ }
+ }
+
+ Instruction::ImageSampleProjExplicitLod {
+ sampled_image,
+ image_operands,
+ ..
+ }
+ | Instruction::ImageSparseSampleProjExplicitLod {
+ sampled_image,
+ image_operands,
+ ..
+ } => {
+ if let Some(desc_reqs) =
+ desc_reqs(self.instruction_chain(
+ [inst_sampled_image, inst_load],
+ sampled_image,
+ ))
+ {
+ desc_reqs.memory_read = stage.into();
+ desc_reqs.sampler_no_unnormalized_coordinates = true;
+
+ if image_operands.const_offset.is_some()
+ || image_operands.offset.is_some()
+ {
+ desc_reqs.sampler_no_ycbcr_conversion = true;
+ }
+ }
+ }
+
+ Instruction::ImageSampleDrefImplicitLod {
+ sampled_image,
+ image_operands,
+ ..
+ }
+ | Instruction::ImageSampleProjDrefImplicitLod {
+ sampled_image,
+ image_operands,
+ ..
+ }
+ | Instruction::ImageSparseSampleDrefImplicitLod {
+ sampled_image,
+ image_operands,
+ ..
+ }
+ | Instruction::ImageSparseSampleProjDrefImplicitLod {
+ sampled_image,
+ image_operands,
+ ..
+ } => {
+ if let Some(desc_reqs) =
+ desc_reqs(self.instruction_chain(
+ [inst_sampled_image, inst_load],
+ sampled_image,
+ ))
+ {
+ desc_reqs.memory_read = stage.into();
+ desc_reqs.sampler_no_unnormalized_coordinates = true;
+ desc_reqs.sampler_compare = true;
+
+ if image_operands.as_ref().map_or(false, |image_operands| {
+ image_operands.const_offset.is_some()
+ || image_operands.offset.is_some()
+ }) {
+ desc_reqs.sampler_no_ycbcr_conversion = true;
+ }
+ }
+ }
+
+ Instruction::ImageSampleDrefExplicitLod {
+ sampled_image,
+ image_operands,
+ ..
+ }
+ | Instruction::ImageSampleProjDrefExplicitLod {
+ sampled_image,
+ image_operands,
+ ..
+ }
+ | Instruction::ImageSparseSampleDrefExplicitLod {
+ sampled_image,
+ image_operands,
+ ..
+ }
+ | Instruction::ImageSparseSampleProjDrefExplicitLod {
+ sampled_image,
+ image_operands,
+ ..
+ } => {
+ if let Some(desc_reqs) =
+ desc_reqs(self.instruction_chain(
+ [inst_sampled_image, inst_load],
+ sampled_image,
+ ))
+ {
+ desc_reqs.memory_read = stage.into();
+ desc_reqs.sampler_no_unnormalized_coordinates = true;
+ desc_reqs.sampler_compare = true;
+
+ if image_operands.const_offset.is_some()
+ || image_operands.offset.is_some()
+ {
+ desc_reqs.sampler_no_ycbcr_conversion = true;
+ }
+ }
+ }
+
+ Instruction::ImageSampleExplicitLod {
+ sampled_image,
+ image_operands,
+ ..
+ }
+ | Instruction::ImageSparseSampleExplicitLod {
+ sampled_image,
+ image_operands,
+ ..
+ } => {
+ if let Some(desc_reqs) =
+ desc_reqs(self.instruction_chain(
+ [inst_sampled_image, inst_load],
+ sampled_image,
+ ))
+ {
+ desc_reqs.memory_read = stage.into();
+
+ if image_operands.bias.is_some()
+ || image_operands.const_offset.is_some()
+ || image_operands.offset.is_some()
+ {
+ desc_reqs.sampler_no_unnormalized_coordinates = true;
+ }
+
+ if image_operands.const_offset.is_some()
+ || image_operands.offset.is_some()
+ {
+ desc_reqs.sampler_no_ycbcr_conversion = true;
+ }
+ }
+ }
+
+ Instruction::ImageTexelPointer { image, .. } => {
+ self.instruction_chain([], image);
+ }
+
+ Instruction::ImageRead { image, .. } => {
+ if let Some(desc_reqs) =
+ desc_reqs(self.instruction_chain([inst_load], image))
+ {
+ desc_reqs.memory_read = stage.into();
+ }
+ }
+
+ Instruction::ImageWrite { image, .. } => {
+ if let Some(desc_reqs) =
+ desc_reqs(self.instruction_chain([inst_load], image))
+ {
+ desc_reqs.memory_write = stage.into();
+ }
+ }
+
+ Instruction::Load { pointer, .. } => {
+ if let Some((binding_variable, index)) =
+ self.instruction_chain([], pointer)
+ {
+ // Only loads on buffers access memory directly.
+ // Loads on images load the image object itself, but don't touch
+ // the texels in memory yet.
+ if binding_variable.reqs.descriptor_types.iter().any(|ty| {
+ matches!(
+ ty,
+ DescriptorType::UniformBuffer
+ | DescriptorType::UniformBufferDynamic
+ | DescriptorType::StorageBuffer
+ | DescriptorType::StorageBufferDynamic
+ )
+ }) {
+ if let Some(desc_reqs) =
+ desc_reqs(Some((binding_variable, index)))
+ {
+ desc_reqs.memory_read = stage.into();
+ }
+ }
+ }
+ }
+
+ Instruction::SampledImage { image, sampler, .. } => {
+ let identifier = match self.instruction_chain([inst_load], image) {
+ Some((variable, Some(index))) => DescriptorIdentifier {
+ set: variable.set,
+ binding: variable.binding,
+ index,
+ },
+ _ => continue,
+ };
+
+ if let Some(desc_reqs) =
+ desc_reqs(self.instruction_chain([inst_load], sampler))
+ {
+ desc_reqs.sampler_with_images.insert(identifier);
+ }
+ }
+
+ Instruction::Store { pointer, .. } => {
+ // This can only apply to buffers, right?
+ if let Some(desc_reqs) = desc_reqs(self.instruction_chain([], pointer))
+ {
+ desc_reqs.memory_write = stage.into();
+ }
+ }
+
+ _ => (),
+ }
+ }
+ }
+ }
+ }
+
+ let mut context = Context {
+ global,
+ spirv,
+ stage,
+ inspected_functions: HashSet::default(),
+ result: HashMap::default(),
+ };
+ context.inspect_entry_point_r(entry_point);
+
+ context
+ .result
+ .into_values()
+ .map(|variable| ((variable.set, variable.binding), variable.reqs))
+ .collect()
+}
+
+/// Returns a `DescriptorBindingRequirements` value for the pointed type.
+///
+/// See also section 14.5.2 of the Vulkan specs: Descriptor Set Interface
+fn descriptor_binding_requirements_of(spirv: &Spirv, variable_id: Id) -> DescriptorBindingVariable {
+ let variable_id_info = spirv.id(variable_id);
+
+ let mut reqs = DescriptorBindingRequirements {
+ descriptor_count: Some(1),
+ ..Default::default()
+ };
+
+ let (mut next_type_id, is_storage_buffer) = {
+ let variable_type_id = match *variable_id_info.instruction() {
+ Instruction::Variable { result_type_id, .. } => result_type_id,
+ _ => panic!("Id {} is not a variable", variable_id),
+ };
+
+ match *spirv.id(variable_type_id).instruction() {
+ Instruction::TypePointer {
+ ty, storage_class, ..
+ } => (Some(ty), storage_class == StorageClass::StorageBuffer),
+ _ => panic!(
+ "Variable {} result_type_id does not refer to a TypePointer instruction",
+ variable_id
+ ),
+ }
+ };
+
+ while let Some(id) = next_type_id {
+ let id_info = spirv.id(id);
+
+ next_type_id = match *id_info.instruction() {
+ Instruction::TypeStruct { .. } => {
+ let decoration_block = id_info.iter_decoration().any(|instruction| {
+ matches!(
+ instruction,
+ Instruction::Decorate {
+ decoration: Decoration::Block,
+ ..
+ }
+ )
+ });
+
+ let decoration_buffer_block = id_info.iter_decoration().any(|instruction| {
+ matches!(
+ instruction,
+ Instruction::Decorate {
+ decoration: Decoration::BufferBlock,
+ ..
+ }
+ )
+ });
+
+ assert!(
+ decoration_block ^ decoration_buffer_block,
+ "Structs in shader interface are expected to be decorated with one of Block or \
+ BufferBlock",
+ );
+
+ if decoration_buffer_block || decoration_block && is_storage_buffer {
+ reqs.descriptor_types = vec![
+ DescriptorType::StorageBuffer,
+ DescriptorType::StorageBufferDynamic,
+ ];
+ } else {
+ reqs.descriptor_types = vec![
+ DescriptorType::UniformBuffer,
+ DescriptorType::UniformBufferDynamic,
+ ];
+ };
+
+ None
+ }
+
+ Instruction::TypeImage {
+ sampled_type,
+ dim,
+ arrayed,
+ ms,
+ sampled,
+ image_format,
+ ..
+ } => {
+ assert!(
+ sampled != 0,
+ "Vulkan requires that variables of type OpTypeImage have a Sampled operand of \
+ 1 or 2",
+ );
+ reqs.image_format = image_format.into();
+ reqs.image_multisampled = ms != 0;
+ reqs.image_scalar_type = Some(match *spirv.id(sampled_type).instruction() {
+ Instruction::TypeInt {
+ width, signedness, ..
+ } => {
+ assert!(width == 32); // TODO: 64-bit components
+ match signedness {
+ 0 => ShaderScalarType::Uint,
+ 1 => ShaderScalarType::Sint,
+ _ => unreachable!(),
+ }
+ }
+ Instruction::TypeFloat { width, .. } => {
+ assert!(width == 32); // TODO: 64-bit components
+ ShaderScalarType::Float
+ }
+ _ => unreachable!(),
+ });
+
+ match dim {
+ Dim::SubpassData => {
+ assert!(
+ reqs.image_format.is_none(),
+ "If Dim is SubpassData, Image Format must be Unknown",
+ );
+ assert!(sampled == 2, "If Dim is SubpassData, Sampled must be 2");
+ assert!(arrayed == 0, "If Dim is SubpassData, Arrayed must be 0");
+
+ reqs.descriptor_types = vec![DescriptorType::InputAttachment];
+ }
+ Dim::Buffer => {
+ if sampled == 1 {
+ reqs.descriptor_types = vec![DescriptorType::UniformTexelBuffer];
+ } else {
+ reqs.descriptor_types = vec![DescriptorType::StorageTexelBuffer];
+ }
+ }
+ _ => {
+ reqs.image_view_type = Some(match (dim, arrayed) {
+ (Dim::Dim1D, 0) => ImageViewType::Dim1d,
+ (Dim::Dim1D, 1) => ImageViewType::Dim1dArray,
+ (Dim::Dim2D, 0) => ImageViewType::Dim2d,
+ (Dim::Dim2D, 1) => ImageViewType::Dim2dArray,
+ (Dim::Dim3D, 0) => ImageViewType::Dim3d,
+ (Dim::Dim3D, 1) => {
+ panic!("Vulkan doesn't support arrayed 3D textures")
+ }
+ (Dim::Cube, 0) => ImageViewType::Cube,
+ (Dim::Cube, 1) => ImageViewType::CubeArray,
+ (Dim::Rect, _) => {
+ panic!("Vulkan doesn't support rectangle textures")
+ }
+ _ => unreachable!(),
+ });
+
+ if reqs.descriptor_types.is_empty() {
+ if sampled == 1 {
+ reqs.descriptor_types = vec![DescriptorType::SampledImage];
+ } else {
+ reqs.descriptor_types = vec![DescriptorType::StorageImage];
+ }
+ }
+ }
+ }
+
+ None
+ }
+
+ Instruction::TypeSampler { .. } => {
+ reqs.descriptor_types = vec![DescriptorType::Sampler];
+
+ None
+ }
+
+ Instruction::TypeSampledImage { image_type, .. } => {
+ reqs.descriptor_types = vec![DescriptorType::CombinedImageSampler];
+
+ Some(image_type)
+ }
+
+ Instruction::TypeArray {
+ element_type,
+ length,
+ ..
+ } => {
+ let len = match spirv.id(length).instruction() {
+ Instruction::Constant { value, .. } => {
+ value.iter().rev().fold(0, |a, &b| (a << 32) | b as u64)
+ }
+ _ => panic!("failed to find array length"),
+ };
+
+ if let Some(count) = reqs.descriptor_count.as_mut() {
+ *count *= len as u32
+ }
+
+ Some(element_type)
+ }
+
+ Instruction::TypeRuntimeArray { element_type, .. } => {
+ reqs.descriptor_count = None;
+
+ Some(element_type)
+ }
+
+ Instruction::TypeAccelerationStructureKHR { .. } => None, // FIXME temporary workaround
+
+ _ => {
+ let name = variable_id_info
+ .iter_name()
+ .find_map(|instruction| match *instruction {
+ Instruction::Name { ref name, .. } => Some(name.as_str()),
+ _ => None,
+ })
+ .unwrap_or("__unnamed");
+
+ panic!(
+ "Couldn't find relevant type for global variable `{}` (id {}, maybe \
+ unimplemented)",
+ name, variable_id,
+ );
+ }
+ };
+ }
+
+ DescriptorBindingVariable {
+ set: variable_id_info
+ .iter_decoration()
+ .find_map(|instruction| match *instruction {
+ Instruction::Decorate {
+ decoration: Decoration::DescriptorSet { descriptor_set },
+ ..
+ } => Some(descriptor_set),
+ _ => None,
+ })
+ .unwrap(),
+ binding: variable_id_info
+ .iter_decoration()
+ .find_map(|instruction| match *instruction {
+ Instruction::Decorate {
+ decoration: Decoration::Binding { binding_point },
+ ..
+ } => Some(binding_point),
+ _ => None,
+ })
+ .unwrap(),
+ reqs,
+ }
+}
+
+/// Extracts the `PushConstantRange` from `spirv`.
+fn push_constant_requirements(spirv: &Spirv, stage: ShaderStage) -> Option<PushConstantRange> {
+ spirv
+ .iter_global()
+ .find_map(|instruction| match *instruction {
+ Instruction::TypePointer {
+ ty,
+ storage_class: StorageClass::PushConstant,
+ ..
+ } => {
+ let id_info = spirv.id(ty);
+ assert!(matches!(
+ id_info.instruction(),
+ Instruction::TypeStruct { .. }
+ ));
+ let start = offset_of_struct(spirv, ty);
+ let end =
+ size_of_type(spirv, ty).expect("Found runtime-sized push constants") as u32;
+
+ Some(PushConstantRange {
+ stages: stage.into(),
+ offset: start,
+ size: end - start,
+ })
+ }
+ _ => None,
+ })
+}
+
+/// Extracts the `SpecializationConstantRequirements` from `spirv`.
+fn specialization_constant_requirements(
+ spirv: &Spirv,
+) -> HashMap<u32, SpecializationConstantRequirements> {
+ spirv
+ .iter_global()
+ .filter_map(|instruction| {
+ match *instruction {
+ Instruction::SpecConstantTrue {
+ result_type_id,
+ result_id,
+ }
+ | Instruction::SpecConstantFalse {
+ result_type_id,
+ result_id,
+ }
+ | Instruction::SpecConstant {
+ result_type_id,
+ result_id,
+ ..
+ }
+ | Instruction::SpecConstantComposite {
+ result_type_id,
+ result_id,
+ ..
+ } => spirv
+ .id(result_id)
+ .iter_decoration()
+ .find_map(|instruction| match *instruction {
+ Instruction::Decorate {
+ decoration:
+ Decoration::SpecId {
+ specialization_constant_id,
+ },
+ ..
+ } => Some(specialization_constant_id),
+ _ => None,
+ })
+ .map(|constant_id| {
+ let size = match *spirv.id(result_type_id).instruction() {
+ Instruction::TypeBool { .. } => {
+ // Translate bool to Bool32
+ std::mem::size_of::<ash::vk::Bool32>() as DeviceSize
+ }
+ _ => size_of_type(spirv, result_type_id)
+ .expect("Found runtime-sized specialization constant"),
+ };
+ (constant_id, SpecializationConstantRequirements { size })
+ }),
+ _ => None,
+ }
+ })
+ .collect()
+}
+
+/// Extracts the `ShaderInterface` with the given storage class from `spirv`.
+fn shader_interface(
+ spirv: &Spirv,
+ interface: &[Id],
+ filter_storage_class: StorageClass,
+ ignore_first_array: bool,
+) -> ShaderInterface {
+ let elements: Vec<_> = interface
+ .iter()
+ .filter_map(|&id| {
+ let (result_type_id, result_id) = match *spirv.id(id).instruction() {
+ Instruction::Variable {
+ result_type_id,
+ result_id,
+ storage_class,
+ ..
+ } if storage_class == filter_storage_class => (result_type_id, result_id),
+ _ => return None,
+ };
+
+ if is_builtin(spirv, result_id) {
+ return None;
+ }
+
+ let id_info = spirv.id(result_id);
+
+ let name = id_info
+ .iter_name()
+ .find_map(|instruction| match *instruction {
+ Instruction::Name { ref name, .. } => Some(Cow::Owned(name.clone())),
+ _ => None,
+ });
+
+ let location = id_info
+ .iter_decoration()
+ .find_map(|instruction| match *instruction {
+ Instruction::Decorate {
+ decoration: Decoration::Location { location },
+ ..
+ } => Some(location),
+ _ => None,
+ })
+ .unwrap_or_else(|| {
+ panic!(
+ "Input/output variable with id {} (name {:?}) is missing a location",
+ result_id, name,
+ )
+ });
+ let component = id_info
+ .iter_decoration()
+ .find_map(|instruction| match *instruction {
+ Instruction::Decorate {
+ decoration: Decoration::Component { component },
+ ..
+ } => Some(component),
+ _ => None,
+ })
+ .unwrap_or(0);
+
+ let ty = shader_interface_type_of(spirv, result_type_id, ignore_first_array);
+ assert!(ty.num_elements >= 1);
+
+ Some(ShaderInterfaceEntry {
+ location,
+ component,
+ ty,
+ name,
+ })
+ })
+ .collect();
+
+ // Checking for overlapping elements.
+ for (offset, element1) in elements.iter().enumerate() {
+ for element2 in elements.iter().skip(offset + 1) {
+ if element1.location == element2.location
+ || (element1.location < element2.location
+ && element1.location + element1.ty.num_locations() > element2.location)
+ || (element2.location < element1.location
+ && element2.location + element2.ty.num_locations() > element1.location)
+ {
+ panic!(
+ "The locations of attributes `{:?}` ({}..{}) and `{:?}` ({}..{}) overlap",
+ element1.name,
+ element1.location,
+ element1.location + element1.ty.num_locations(),
+ element2.name,
+ element2.location,
+ element2.location + element2.ty.num_locations(),
+ );
+ }
+ }
+ }
+
+ ShaderInterface { elements }
+}
+
+/// Returns the size of a type, or `None` if its size cannot be determined.
+fn size_of_type(spirv: &Spirv, id: Id) -> Option<DeviceSize> {
+ let id_info = spirv.id(id);
+
+ match *id_info.instruction() {
+ Instruction::TypeBool { .. } => {
+ panic!("Can't put booleans in structs")
+ }
+ Instruction::TypeInt { width, .. } | Instruction::TypeFloat { width, .. } => {
+ assert!(width % 8 == 0);
+ Some(width as DeviceSize / 8)
+ }
+ Instruction::TypeVector {
+ component_type,
+ component_count,
+ ..
+ } => size_of_type(spirv, component_type)
+ .map(|component_size| component_size * component_count as DeviceSize),
+ Instruction::TypeMatrix {
+ column_type,
+ column_count,
+ ..
+ } => {
+ // FIXME: row-major or column-major
+ size_of_type(spirv, column_type)
+ .map(|column_size| column_size * column_count as DeviceSize)
+ }
+ Instruction::TypeArray { length, .. } => {
+ let stride = id_info
+ .iter_decoration()
+ .find_map(|instruction| match *instruction {
+ Instruction::Decorate {
+ decoration: Decoration::ArrayStride { array_stride },
+ ..
+ } => Some(array_stride),
+ _ => None,
+ })
+ .unwrap();
+ let length = match spirv.id(length).instruction() {
+ Instruction::Constant { value, .. } => Some(
+ value
+ .iter()
+ .rev()
+ .fold(0u64, |a, &b| (a << 32) | b as DeviceSize),
+ ),
+ _ => None,
+ }
+ .unwrap();
+
+ Some(stride as DeviceSize * length)
+ }
+ Instruction::TypeRuntimeArray { .. } => None,
+ Instruction::TypeStruct {
+ ref member_types, ..
+ } => {
+ let mut end_of_struct = 0;
+
+ for (&member, member_info) in member_types.iter().zip(id_info.iter_members()) {
+ // Built-ins have an unknown size.
+ if member_info.iter_decoration().any(|instruction| {
+ matches!(
+ instruction,
+ Instruction::MemberDecorate {
+ decoration: Decoration::BuiltIn { .. },
+ ..
+ }
+ )
+ }) {
+ return None;
+ }
+
+ // Some structs don't have `Offset` decorations, in the case they are used as local
+ // variables only. Ignoring these.
+ let offset =
+ member_info
+ .iter_decoration()
+ .find_map(|instruction| match *instruction {
+ Instruction::MemberDecorate {
+ decoration: Decoration::Offset { byte_offset },
+ ..
+ } => Some(byte_offset),
+ _ => None,
+ })?;
+ let size = size_of_type(spirv, member)?;
+ end_of_struct = end_of_struct.max(offset as DeviceSize + size);
+ }
+
+ Some(end_of_struct)
+ }
+ _ => panic!("Type {} not found", id),
+ }
+}
+
+/// Returns the smallest offset of all members of a struct, or 0 if `id` is not a struct.
+fn offset_of_struct(spirv: &Spirv, id: Id) -> u32 {
+ spirv
+ .id(id)
+ .iter_members()
+ .filter_map(|member_info| {
+ member_info
+ .iter_decoration()
+ .find_map(|instruction| match *instruction {
+ Instruction::MemberDecorate {
+ decoration: Decoration::Offset { byte_offset },
+ ..
+ } => Some(byte_offset),
+ _ => None,
+ })
+ })
+ .min()
+ .unwrap_or(0)
+}
+
+/// If `ignore_first_array` is true, the function expects the outermost instruction to be
+/// `OpTypeArray`. If it's the case, the OpTypeArray will be ignored. If not, the function will
+/// panic.
+fn shader_interface_type_of(
+ spirv: &Spirv,
+ id: Id,
+ ignore_first_array: bool,
+) -> ShaderInterfaceEntryType {
+ match *spirv.id(id).instruction() {
+ Instruction::TypeInt {
+ width, signedness, ..
+ } => {
+ assert!(!ignore_first_array);
+ ShaderInterfaceEntryType {
+ base_type: match signedness {
+ 0 => ShaderScalarType::Uint,
+ 1 => ShaderScalarType::Sint,
+ _ => unreachable!(),
+ },
+ num_components: 1,
+ num_elements: 1,
+ is_64bit: match width {
+ 8 | 16 | 32 => false,
+ 64 => true,
+ _ => unimplemented!(),
+ },
+ }
+ }
+ Instruction::TypeFloat { width, .. } => {
+ assert!(!ignore_first_array);
+ ShaderInterfaceEntryType {
+ base_type: ShaderScalarType::Float,
+ num_components: 1,
+ num_elements: 1,
+ is_64bit: match width {
+ 16 | 32 => false,
+ 64 => true,
+ _ => unimplemented!(),
+ },
+ }
+ }
+ Instruction::TypeVector {
+ component_type,
+ component_count,
+ ..
+ } => {
+ assert!(!ignore_first_array);
+ ShaderInterfaceEntryType {
+ num_components: component_count,
+ ..shader_interface_type_of(spirv, component_type, false)
+ }
+ }
+ Instruction::TypeMatrix {
+ column_type,
+ column_count,
+ ..
+ } => {
+ assert!(!ignore_first_array);
+ ShaderInterfaceEntryType {
+ num_elements: column_count,
+ ..shader_interface_type_of(spirv, column_type, false)
+ }
+ }
+ Instruction::TypeArray {
+ element_type,
+ length,
+ ..
+ } => {
+ if ignore_first_array {
+ shader_interface_type_of(spirv, element_type, false)
+ } else {
+ let mut ty = shader_interface_type_of(spirv, element_type, false);
+ let num_elements = spirv
+ .instructions()
+ .iter()
+ .find_map(|instruction| match *instruction {
+ Instruction::Constant {
+ result_id,
+ ref value,
+ ..
+ } if result_id == length => Some(value.clone()),
+ _ => None,
+ })
+ .expect("failed to find array length")
+ .iter()
+ .rev()
+ .fold(0u64, |a, &b| (a << 32) | b as u64)
+ as u32;
+ ty.num_elements *= num_elements;
+ ty
+ }
+ }
+ Instruction::TypePointer { ty, .. } => {
+ shader_interface_type_of(spirv, ty, ignore_first_array)
+ }
+ _ => panic!("Type {} not found or invalid", id),
+ }
+}
+
+/// Returns true if a `BuiltIn` decorator is applied on an id.
+fn is_builtin(spirv: &Spirv, id: Id) -> bool {
+ let id_info = spirv.id(id);
+
+ if id_info.iter_decoration().any(|instruction| {
+ matches!(
+ instruction,
+ Instruction::Decorate {
+ decoration: Decoration::BuiltIn { .. },
+ ..
+ }
+ )
+ }) {
+ return true;
+ }
+
+ if id_info
+ .iter_members()
+ .flat_map(|member_info| member_info.iter_decoration())
+ .any(|instruction| {
+ matches!(
+ instruction,
+ Instruction::MemberDecorate {
+ decoration: Decoration::BuiltIn { .. },
+ ..
+ }
+ )
+ })
+ {
+ return true;
+ }
+
+ match id_info.instruction() {
+ Instruction::Variable {
+ result_type_id: ty, ..
+ }
+ | Instruction::TypeArray {
+ element_type: ty, ..
+ }
+ | Instruction::TypeRuntimeArray {
+ element_type: ty, ..
+ }
+ | Instruction::TypePointer { ty, .. } => is_builtin(spirv, *ty),
+ Instruction::TypeStruct { member_types, .. } => {
+ member_types.iter().any(|ty| is_builtin(spirv, *ty))
+ }
+ _ => false,
+ }
+}
diff --git a/src/shader/spirv.rs b/src/shader/spirv.rs
new file mode 100644
index 0000000..14180d3
--- /dev/null
+++ b/src/shader/spirv.rs
@@ -0,0 +1,794 @@
+// Copyright (c) 2021 The Vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+//! Parsing and analysis utilities for SPIR-V shader binaries.
+//!
+//! This can be used to inspect and validate a SPIR-V module at runtime. The `Spirv` type does some
+//! validation, but you should not assume that code that is read successfully is valid.
+//!
+//! For more information about SPIR-V modules, instructions and types, see the
+//! [SPIR-V specification](https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html).
+
+use crate::Version;
+use ahash::{HashMap, HashMapExt};
+use std::{
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+ ops::Range,
+ string::FromUtf8Error,
+};
+
+// Generated by build.rs
+include!(concat!(env!("OUT_DIR"), "/spirv_parse.rs"));
+
+/// A parsed and analyzed SPIR-V module.
+#[derive(Clone, Debug)]
+pub struct Spirv {
+ version: Version,
+ bound: u32,
+ instructions: Vec<Instruction>,
+ ids: HashMap<Id, IdDataIndices>,
+
+ // Items described in the spec section "Logical Layout of a Module"
+ range_capability: Range<usize>,
+ range_extension: Range<usize>,
+ range_ext_inst_import: Range<usize>,
+ memory_model: usize,
+ range_entry_point: Range<usize>,
+ range_execution_mode: Range<usize>,
+ range_name: Range<usize>,
+ range_decoration: Range<usize>,
+ range_global: Range<usize>,
+}
+
+impl Spirv {
+ /// Parses a SPIR-V document from a list of words.
+ pub fn new(words: &[u32]) -> Result<Spirv, SpirvError> {
+ if words.len() < 5 {
+ return Err(SpirvError::InvalidHeader);
+ }
+
+ if words[0] != 0x07230203 {
+ return Err(SpirvError::InvalidHeader);
+ }
+
+ let version = Version {
+ major: (words[1] & 0x00ff0000) >> 16,
+ minor: (words[1] & 0x0000ff00) >> 8,
+ patch: words[1] & 0x000000ff,
+ };
+
+ let bound = words[3];
+
+ let instructions = {
+ let mut ret = Vec::new();
+ let mut rest = &words[5..];
+ while !rest.is_empty() {
+ let word_count = (rest[0] >> 16) as usize;
+ assert!(word_count >= 1);
+
+ if rest.len() < word_count {
+ return Err(ParseError {
+ instruction: ret.len(),
+ word: rest.len(),
+ error: ParseErrors::UnexpectedEOF,
+ words: rest.to_owned(),
+ }
+ .into());
+ }
+
+ let mut reader = InstructionReader::new(&rest[0..word_count], ret.len());
+ let instruction = Instruction::parse(&mut reader)?;
+
+ if !reader.is_empty() {
+ return Err(reader.map_err(ParseErrors::LeftoverOperands).into());
+ }
+
+ ret.push(instruction);
+ rest = &rest[word_count..];
+ }
+ ret
+ };
+
+ // It is impossible for a valid SPIR-V file to contain more Ids than instructions, so put
+ // a sane upper limit on the allocation. This prevents a malicious file from causing huge
+ // memory allocations.
+ let mut ids = HashMap::with_capacity(instructions.len().min(bound as usize));
+ let mut range_capability: Option<Range<usize>> = None;
+ let mut range_extension: Option<Range<usize>> = None;
+ let mut range_ext_inst_import: Option<Range<usize>> = None;
+ let mut range_memory_model: Option<Range<usize>> = None;
+ let mut range_entry_point: Option<Range<usize>> = None;
+ let mut range_execution_mode: Option<Range<usize>> = None;
+ let mut range_name: Option<Range<usize>> = None;
+ let mut range_decoration: Option<Range<usize>> = None;
+ let mut range_global: Option<Range<usize>> = None;
+ let mut in_function = false;
+
+ fn set_range(range: &mut Option<Range<usize>>, index: usize) -> Result<(), SpirvError> {
+ if let Some(range) = range {
+ if range.end != index {
+ return Err(SpirvError::BadLayout { index });
+ }
+
+ range.end = index + 1;
+ } else {
+ *range = Some(Range {
+ start: index,
+ end: index + 1,
+ });
+ }
+
+ Ok(())
+ }
+
+ for (index, instruction) in instructions.iter().enumerate() {
+ if let Some(id) = instruction.result_id() {
+ if u32::from(id) >= bound {
+ return Err(SpirvError::IdOutOfBounds { id, index, bound });
+ }
+
+ let members = if let Instruction::TypeStruct { member_types, .. } = instruction {
+ member_types
+ .iter()
+ .map(|_| StructMemberDataIndices::default())
+ .collect()
+ } else {
+ Vec::new()
+ };
+ let data = IdDataIndices {
+ index,
+ names: Vec::new(),
+ decorations: Vec::new(),
+ members,
+ };
+ if let Some(first) = ids.insert(id, data) {
+ return Err(SpirvError::DuplicateId {
+ id,
+ first_index: first.index,
+ second_index: index,
+ });
+ }
+ }
+
+ match instruction {
+ Instruction::Capability { .. } => set_range(&mut range_capability, index)?,
+ Instruction::Extension { .. } => set_range(&mut range_extension, index)?,
+ Instruction::ExtInstImport { .. } => set_range(&mut range_ext_inst_import, index)?,
+ Instruction::MemoryModel { .. } => set_range(&mut range_memory_model, index)?,
+ Instruction::EntryPoint { .. } => set_range(&mut range_entry_point, index)?,
+ Instruction::ExecutionMode { .. } | Instruction::ExecutionModeId { .. } => {
+ set_range(&mut range_execution_mode, index)?
+ }
+ Instruction::Name { .. } | Instruction::MemberName { .. } => {
+ set_range(&mut range_name, index)?
+ }
+ Instruction::Decorate { .. }
+ | Instruction::MemberDecorate { .. }
+ | Instruction::DecorationGroup { .. }
+ | Instruction::GroupDecorate { .. }
+ | Instruction::GroupMemberDecorate { .. }
+ | Instruction::DecorateId { .. }
+ | Instruction::DecorateString { .. }
+ | Instruction::MemberDecorateString { .. } => {
+ set_range(&mut range_decoration, index)?
+ }
+ Instruction::TypeVoid { .. }
+ | Instruction::TypeBool { .. }
+ | Instruction::TypeInt { .. }
+ | Instruction::TypeFloat { .. }
+ | Instruction::TypeVector { .. }
+ | Instruction::TypeMatrix { .. }
+ | Instruction::TypeImage { .. }
+ | Instruction::TypeSampler { .. }
+ | Instruction::TypeSampledImage { .. }
+ | Instruction::TypeArray { .. }
+ | Instruction::TypeRuntimeArray { .. }
+ | Instruction::TypeStruct { .. }
+ | Instruction::TypeOpaque { .. }
+ | Instruction::TypePointer { .. }
+ | Instruction::TypeFunction { .. }
+ | Instruction::TypeEvent { .. }
+ | Instruction::TypeDeviceEvent { .. }
+ | Instruction::TypeReserveId { .. }
+ | Instruction::TypeQueue { .. }
+ | Instruction::TypePipe { .. }
+ | Instruction::TypeForwardPointer { .. }
+ | Instruction::TypePipeStorage { .. }
+ | Instruction::TypeNamedBarrier { .. }
+ | Instruction::TypeRayQueryKHR { .. }
+ | Instruction::TypeAccelerationStructureKHR { .. }
+ | Instruction::TypeCooperativeMatrixNV { .. }
+ | Instruction::TypeVmeImageINTEL { .. }
+ | Instruction::TypeAvcImePayloadINTEL { .. }
+ | Instruction::TypeAvcRefPayloadINTEL { .. }
+ | Instruction::TypeAvcSicPayloadINTEL { .. }
+ | Instruction::TypeAvcMcePayloadINTEL { .. }
+ | Instruction::TypeAvcMceResultINTEL { .. }
+ | Instruction::TypeAvcImeResultINTEL { .. }
+ | Instruction::TypeAvcImeResultSingleReferenceStreamoutINTEL { .. }
+ | Instruction::TypeAvcImeResultDualReferenceStreamoutINTEL { .. }
+ | Instruction::TypeAvcImeSingleReferenceStreaminINTEL { .. }
+ | Instruction::TypeAvcImeDualReferenceStreaminINTEL { .. }
+ | Instruction::TypeAvcRefResultINTEL { .. }
+ | Instruction::TypeAvcSicResultINTEL { .. }
+ | Instruction::ConstantTrue { .. }
+ | Instruction::ConstantFalse { .. }
+ | Instruction::Constant { .. }
+ | Instruction::ConstantComposite { .. }
+ | Instruction::ConstantSampler { .. }
+ | Instruction::ConstantNull { .. }
+ | Instruction::ConstantPipeStorage { .. }
+ | Instruction::SpecConstantTrue { .. }
+ | Instruction::SpecConstantFalse { .. }
+ | Instruction::SpecConstant { .. }
+ | Instruction::SpecConstantComposite { .. }
+ | Instruction::SpecConstantOp { .. } => set_range(&mut range_global, index)?,
+ Instruction::Undef { .. } if !in_function => set_range(&mut range_global, index)?,
+ Instruction::Variable { storage_class, .. }
+ if *storage_class != StorageClass::Function =>
+ {
+ set_range(&mut range_global, index)?
+ }
+ Instruction::Function { .. } => {
+ in_function = true;
+ }
+ Instruction::Line { .. } | Instruction::NoLine { .. } => {
+ if !in_function {
+ set_range(&mut range_global, index)?
+ }
+ }
+ _ => (),
+ }
+ }
+
+ let mut spirv = Spirv {
+ version,
+ bound,
+ instructions,
+ ids,
+
+ range_capability: range_capability.unwrap_or_default(),
+ range_extension: range_extension.unwrap_or_default(),
+ range_ext_inst_import: range_ext_inst_import.unwrap_or_default(),
+ memory_model: if let Some(range) = range_memory_model {
+ if range.end - range.start != 1 {
+ return Err(SpirvError::MemoryModelInvalid);
+ }
+
+ range.start
+ } else {
+ return Err(SpirvError::MemoryModelInvalid);
+ },
+ range_entry_point: range_entry_point.unwrap_or_default(),
+ range_execution_mode: range_execution_mode.unwrap_or_default(),
+ range_name: range_name.unwrap_or_default(),
+ range_decoration: range_decoration.unwrap_or_default(),
+ range_global: range_global.unwrap_or_default(),
+ };
+
+ for index in spirv.range_name.clone() {
+ match &spirv.instructions[index] {
+ Instruction::Name { target, .. } => {
+ spirv.ids.get_mut(target).unwrap().names.push(index);
+ }
+ Instruction::MemberName { ty, member, .. } => {
+ spirv.ids.get_mut(ty).unwrap().members[*member as usize]
+ .names
+ .push(index);
+ }
+ _ => unreachable!(),
+ }
+ }
+
+ // First handle all regular decorations, including those targeting decoration groups.
+ for index in spirv.range_decoration.clone() {
+ match &spirv.instructions[index] {
+ Instruction::Decorate { target, .. }
+ | Instruction::DecorateId { target, .. }
+ | Instruction::DecorateString { target, .. } => {
+ spirv.ids.get_mut(target).unwrap().decorations.push(index);
+ }
+ Instruction::MemberDecorate {
+ structure_type: target,
+ member,
+ ..
+ }
+ | Instruction::MemberDecorateString {
+ struct_type: target,
+ member,
+ ..
+ } => {
+ spirv.ids.get_mut(target).unwrap().members[*member as usize]
+ .decorations
+ .push(index);
+ }
+ _ => (),
+ }
+ }
+
+ // Then, with decoration groups having their lists complete, handle group decorates.
+ for index in spirv.range_decoration.clone() {
+ match &spirv.instructions[index] {
+ Instruction::GroupDecorate {
+ decoration_group,
+ targets,
+ ..
+ } => {
+ let indices = {
+ let data = &spirv.ids[decoration_group];
+ if !matches!(
+ spirv.instructions[data.index],
+ Instruction::DecorationGroup { .. }
+ ) {
+ return Err(SpirvError::GroupDecorateNotGroup { index });
+ };
+ data.decorations.clone()
+ };
+
+ for target in targets {
+ spirv
+ .ids
+ .get_mut(target)
+ .unwrap()
+ .decorations
+ .extend(&indices);
+ }
+ }
+ Instruction::GroupMemberDecorate {
+ decoration_group,
+ targets,
+ ..
+ } => {
+ let indices = {
+ let data = &spirv.ids[decoration_group];
+ if !matches!(
+ spirv.instructions[data.index],
+ Instruction::DecorationGroup { .. }
+ ) {
+ return Err(SpirvError::GroupDecorateNotGroup { index });
+ };
+ data.decorations.clone()
+ };
+
+ for (target, member) in targets {
+ spirv.ids.get_mut(target).unwrap().members[*member as usize]
+ .decorations
+ .extend(&indices);
+ }
+ }
+ _ => (),
+ }
+ }
+
+ Ok(spirv)
+ }
+
+ /// Returns a reference to the instructions in the module.
+ #[inline]
+ pub fn instructions(&self) -> &[Instruction] {
+ &self.instructions
+ }
+
+ /// Returns the SPIR-V version that the module is compiled for.
+ #[inline]
+ pub fn version(&self) -> Version {
+ self.version
+ }
+
+ /// Returns the upper bound of `Id`s. All `Id`s should have a numeric value strictly less than
+ /// this value.
+ #[inline]
+ pub fn bound(&self) -> u32 {
+ self.bound
+ }
+
+ /// Returns information about an `Id`.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `id` is not defined in this module. This can in theory only happpen if you are
+ /// mixing `Id`s from different modules.
+ #[inline]
+ pub fn id(&self, id: Id) -> IdInfo<'_> {
+ IdInfo {
+ data_indices: &self.ids[&id],
+ instructions: &self.instructions,
+ }
+ }
+
+ /// Returns an iterator over all `Capability` instructions.
+ #[inline]
+ pub fn iter_capability(&self) -> impl ExactSizeIterator<Item = &Instruction> {
+ self.instructions[self.range_capability.clone()].iter()
+ }
+
+ /// Returns an iterator over all `Extension` instructions.
+ #[inline]
+ pub fn iter_extension(&self) -> impl ExactSizeIterator<Item = &Instruction> {
+ self.instructions[self.range_extension.clone()].iter()
+ }
+
+ /// Returns an iterator over all `ExtInstImport` instructions.
+ #[inline]
+ pub fn iter_ext_inst_import(&self) -> impl ExactSizeIterator<Item = &Instruction> {
+ self.instructions[self.range_ext_inst_import.clone()].iter()
+ }
+
+ /// Returns the `MemoryModel` instruction.
+ #[inline]
+ pub fn memory_model(&self) -> &Instruction {
+ &self.instructions[self.memory_model]
+ }
+
+ /// Returns an iterator over all `EntryPoint` instructions.
+ #[inline]
+ pub fn iter_entry_point(&self) -> impl ExactSizeIterator<Item = &Instruction> {
+ self.instructions[self.range_entry_point.clone()].iter()
+ }
+
+ /// Returns an iterator over all execution mode instructions.
+ #[inline]
+ pub fn iter_execution_mode(&self) -> impl ExactSizeIterator<Item = &Instruction> {
+ self.instructions[self.range_execution_mode.clone()].iter()
+ }
+
+ /// Returns an iterator over all name debug instructions.
+ #[inline]
+ pub fn iter_name(&self) -> impl ExactSizeIterator<Item = &Instruction> {
+ self.instructions[self.range_name.clone()].iter()
+ }
+
+ /// Returns an iterator over all decoration instructions.
+ #[inline]
+ pub fn iter_decoration(&self) -> impl ExactSizeIterator<Item = &Instruction> {
+ self.instructions[self.range_decoration.clone()].iter()
+ }
+
+ /// Returns an iterator over all global declaration instructions: types,
+ /// constants and global variables.
+ ///
+ /// Note: This can also include `Line` and `NoLine` instructions.
+ #[inline]
+ pub fn iter_global(&self) -> impl ExactSizeIterator<Item = &Instruction> {
+ self.instructions[self.range_global.clone()].iter()
+ }
+}
+
+#[derive(Clone, Debug)]
+struct IdDataIndices {
+ index: usize,
+ names: Vec<usize>,
+ decorations: Vec<usize>,
+ members: Vec<StructMemberDataIndices>,
+}
+
+#[derive(Clone, Debug, Default)]
+struct StructMemberDataIndices {
+ names: Vec<usize>,
+ decorations: Vec<usize>,
+}
+
+/// Information associated with an `Id`.
+#[derive(Clone, Debug)]
+pub struct IdInfo<'a> {
+ data_indices: &'a IdDataIndices,
+ instructions: &'a [Instruction],
+}
+
+impl<'a> IdInfo<'a> {
+ /// Returns the instruction that defines this `Id` with a `result_id` operand.
+ #[inline]
+ pub fn instruction(&self) -> &'a Instruction {
+ &self.instructions[self.data_indices.index]
+ }
+
+ /// Returns an iterator over all name debug instructions that target this `Id`.
+ #[inline]
+ pub fn iter_name(&self) -> impl ExactSizeIterator<Item = &'a Instruction> {
+ let instructions = self.instructions;
+ self.data_indices
+ .names
+ .iter()
+ .map(move |&index| &instructions[index])
+ }
+
+ /// Returns an iterator over all decorate instructions, that target this `Id`. This includes any
+ /// decorate instructions that target this `Id` indirectly via a `DecorationGroup`.
+ #[inline]
+ pub fn iter_decoration(&self) -> impl ExactSizeIterator<Item = &'a Instruction> {
+ let instructions = self.instructions;
+ self.data_indices
+ .decorations
+ .iter()
+ .map(move |&index| &instructions[index])
+ }
+
+ /// If this `Id` refers to a `TypeStruct`, returns an iterator of information about each member
+ /// of the struct. Empty otherwise.
+ #[inline]
+ pub fn iter_members(&self) -> impl ExactSizeIterator<Item = StructMemberInfo<'a>> {
+ let instructions = self.instructions;
+ self.data_indices
+ .members
+ .iter()
+ .map(move |data_indices| StructMemberInfo {
+ data_indices,
+ instructions,
+ })
+ }
+}
+
+/// Information associated with a member of a `TypeStruct` instruction.
+#[derive(Clone, Debug)]
+pub struct StructMemberInfo<'a> {
+ data_indices: &'a StructMemberDataIndices,
+ instructions: &'a [Instruction],
+}
+
+impl<'a> StructMemberInfo<'a> {
+ /// Returns an iterator over all name debug instructions that target this struct member.
+ #[inline]
+ pub fn iter_name(&self) -> impl ExactSizeIterator<Item = &'a Instruction> {
+ let instructions = self.instructions;
+ self.data_indices
+ .names
+ .iter()
+ .map(move |&index| &instructions[index])
+ }
+
+ /// Returns an iterator over all decorate instructions that target this struct member. This
+ /// includes any decorate instructions that target this member indirectly via a
+ /// `DecorationGroup`.
+ #[inline]
+ pub fn iter_decoration(&self) -> impl ExactSizeIterator<Item = &'a Instruction> {
+ let instructions = self.instructions;
+ self.data_indices
+ .decorations
+ .iter()
+ .map(move |&index| &instructions[index])
+ }
+}
+
+/// Used in SPIR-V to refer to the result of another instruction.
+///
+/// Ids are global across a module, and are always assigned by exactly one instruction.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+#[repr(transparent)]
+pub struct Id(u32);
+
+impl From<Id> for u32 {
+ #[inline]
+ fn from(id: Id) -> u32 {
+ id.0
+ }
+}
+
+impl Display for Id {
+ #[inline]
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ write!(f, "%{}", self.0)
+ }
+}
+
+/// Helper type for parsing the words of an instruction.
+#[derive(Debug)]
+struct InstructionReader<'a> {
+ words: &'a [u32],
+ next_word: usize,
+ instruction: usize,
+}
+
+impl<'a> InstructionReader<'a> {
+ /// Constructs a new reader from a slice of words for a single instruction, including the opcode
+ /// word. `instruction` is the number of the instruction currently being read, and is used for
+ /// error reporting.
+ fn new(words: &'a [u32], instruction: usize) -> Self {
+ debug_assert!(!words.is_empty());
+ Self {
+ words,
+ next_word: 0,
+ instruction,
+ }
+ }
+
+ /// Returns whether the reader has reached the end of the current instruction.
+ fn is_empty(&self) -> bool {
+ self.next_word >= self.words.len()
+ }
+
+ /// Converts the `ParseErrors` enum to the `ParseError` struct, adding contextual information.
+ fn map_err(&self, error: ParseErrors) -> ParseError {
+ ParseError {
+ instruction: self.instruction,
+ word: self.next_word - 1, // -1 because the word has already been read
+ error,
+ words: self.words.to_owned(),
+ }
+ }
+
+ /// Returns the next word in the sequence.
+ fn next_u32(&mut self) -> Result<u32, ParseError> {
+ let word = *self.words.get(self.next_word).ok_or(ParseError {
+ instruction: self.instruction,
+ word: self.next_word, // No -1 because we didn't advance yet
+ error: ParseErrors::MissingOperands,
+ words: self.words.to_owned(),
+ })?;
+ self.next_word += 1;
+
+ Ok(word)
+ }
+
+ /*
+ /// Returns the next two words as a single `u64`.
+ #[inline]
+ fn next_u64(&mut self) -> Result<u64, ParseError> {
+ Ok(self.next_u32()? as u64 | (self.next_u32()? as u64) << 32)
+ }
+ */
+
+ /// Reads a nul-terminated string.
+ fn next_string(&mut self) -> Result<String, ParseError> {
+ let mut bytes = Vec::new();
+ loop {
+ let word = self.next_u32()?.to_le_bytes();
+
+ if let Some(nul) = word.iter().position(|&b| b == 0) {
+ bytes.extend(&word[0..nul]);
+ break;
+ } else {
+ bytes.extend(word);
+ }
+ }
+ String::from_utf8(bytes).map_err(|err| self.map_err(ParseErrors::FromUtf8Error(err)))
+ }
+
+ /// Reads all remaining words.
+ fn remainder(&mut self) -> Vec<u32> {
+ let vec = self.words[self.next_word..].to_owned();
+ self.next_word = self.words.len();
+ vec
+ }
+}
+
+/// Error that can happen when reading a SPIR-V module.
+#[derive(Clone, Debug)]
+pub enum SpirvError {
+ BadLayout {
+ index: usize,
+ },
+ DuplicateId {
+ id: Id,
+ first_index: usize,
+ second_index: usize,
+ },
+ GroupDecorateNotGroup {
+ index: usize,
+ },
+ IdOutOfBounds {
+ id: Id,
+ index: usize,
+ bound: u32,
+ },
+ InvalidHeader,
+ MemoryModelInvalid,
+ ParseError(ParseError),
+}
+
+impl Display for SpirvError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::BadLayout { index } => write!(
+ f,
+ "the instruction at index {} does not follow the logical layout of a module",
+ index,
+ ),
+ Self::DuplicateId {
+ id,
+ first_index,
+ second_index,
+ } => write!(
+ f,
+ "id {} is assigned more than once, by instructions {} and {}",
+ id, first_index, second_index,
+ ),
+ Self::GroupDecorateNotGroup { index } => write!(
+ f,
+ "a GroupDecorate or GroupMemberDecorate instruction at index {} referred to an Id \
+ that was not a DecorationGroup",
+ index,
+ ),
+ Self::IdOutOfBounds { id, bound, index } => write!(
+ f,
+ "id {}, assigned at instruction {}, is not below the maximum bound {}",
+ id, index, bound,
+ ),
+ Self::InvalidHeader => write!(f, "the SPIR-V module header is invalid"),
+ Self::MemoryModelInvalid => {
+ write!(f, "the MemoryModel instruction is not present exactly once")
+ }
+ Self::ParseError(_) => write!(f, "parse error"),
+ }
+ }
+}
+
+impl Error for SpirvError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::ParseError(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+impl From<ParseError> for SpirvError {
+ fn from(err: ParseError) -> Self {
+ Self::ParseError(err)
+ }
+}
+
+/// Error that can happen when parsing SPIR-V instructions into Rust data structures.
+#[derive(Clone, Debug)]
+pub struct ParseError {
+ /// The instruction number the error happened at, starting from 0.
+ pub instruction: usize,
+ /// The word from the start of the instruction that the error happened at, starting from 0.
+ pub word: usize,
+ /// The error.
+ pub error: ParseErrors,
+ /// The words of the instruction.
+ pub words: Vec<u32>,
+}
+
+impl Display for ParseError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ write!(
+ f,
+ "at instruction {}, word {}: {}",
+ self.instruction, self.word, self.error,
+ )
+ }
+}
+
+impl Error for ParseError {}
+
+/// Individual types of parse error that can happen.
+#[derive(Clone, Debug)]
+pub enum ParseErrors {
+ FromUtf8Error(FromUtf8Error),
+ LeftoverOperands,
+ MissingOperands,
+ UnexpectedEOF,
+ UnknownEnumerant(&'static str, u32),
+ UnknownOpcode(u16),
+ UnknownSpecConstantOpcode(u16),
+}
+
+impl Display for ParseErrors {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::FromUtf8Error(_) => write!(f, "invalid UTF-8 in string literal"),
+ Self::LeftoverOperands => write!(f, "unparsed operands remaining"),
+ Self::MissingOperands => write!(
+ f,
+ "the instruction and its operands require more words than are present in the \
+ instruction",
+ ),
+ Self::UnexpectedEOF => write!(f, "encountered unexpected end of file"),
+ Self::UnknownEnumerant(ty, enumerant) => {
+ write!(f, "invalid enumerant {} for enum {}", enumerant, ty)
+ }
+ Self::UnknownOpcode(opcode) => write!(f, "invalid instruction opcode {}", opcode),
+ Self::UnknownSpecConstantOpcode(opcode) => {
+ write!(f, "invalid spec constant instruction opcode {}", opcode)
+ }
+ }
+ }
+}
diff --git a/src/swapchain/capabilities.rs b/src/swapchain/capabilities.rs
deleted file mode 100644
index 2a6feca..0000000
--- a/src/swapchain/capabilities.rs
+++ /dev/null
@@ -1,664 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::format::Format;
-use crate::image::ImageUsage;
-use std::iter::FromIterator;
-
-/// The capabilities of a surface when used by a physical device.
-///
-/// You have to match these capabilities when you create a swapchain.
-#[derive(Clone, Debug)]
-pub struct Capabilities {
- /// Minimum number of images that must be present in the swapchain.
- pub min_image_count: u32,
-
- /// Maximum number of images that must be present in the swapchain, or `None` if there is no
- /// maximum value. Note that "no maximum" doesn't mean that you can set a very high value, as
- /// you may still get out of memory errors.
- pub max_image_count: Option<u32>,
-
- /// The current dimensions of the surface. `None` means that the surface's dimensions will
- /// depend on the dimensions of the swapchain that you are going to create.
- pub current_extent: Option<[u32; 2]>,
-
- /// Minimum width and height of a swapchain that uses this surface.
- pub min_image_extent: [u32; 2],
-
- /// Maximum width and height of a swapchain that uses this surface.
- pub max_image_extent: [u32; 2],
-
- /// Maximum number of image layers if you create an image array. The minimum is 1.
- pub max_image_array_layers: u32,
-
- /// List of transforms supported for the swapchain.
- pub supported_transforms: SupportedSurfaceTransforms,
-
- /// Current transform used by the surface.
- pub current_transform: SurfaceTransform,
-
- /// List of composite alpha modes supports for the swapchain.
- pub supported_composite_alpha: SupportedCompositeAlpha,
-
- /// List of image usages that are supported for images of the swapchain. Only
- /// the `color_attachment` usage is guaranteed to be supported.
- pub supported_usage_flags: ImageUsage,
-
- /// List of formats supported for the swapchain.
- pub supported_formats: Vec<(Format, ColorSpace)>, // TODO: https://github.com/KhronosGroup/Vulkan-Docs/issues/207
-
- /// List of present modes that are supported. `Fifo` is always guaranteed to be supported.
- pub present_modes: SupportedPresentModes,
-}
-
-/// The way presenting a swapchain is accomplished.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-#[repr(i32)]
-pub enum PresentMode {
- /// Immediately shows the image to the user. May result in visible tearing.
- Immediate = ash::vk::PresentModeKHR::IMMEDIATE.as_raw(),
-
- /// The action of presenting an image puts it in wait. When the next vertical blanking period
- /// happens, the waiting image is effectively shown to the user. If an image is presented while
- /// another one is waiting, it is replaced.
- Mailbox = ash::vk::PresentModeKHR::MAILBOX.as_raw(),
-
- /// The action of presenting an image adds it to a queue of images. At each vertical blanking
- /// period, the queue is popped and an image is presented.
- ///
- /// Guaranteed to be always supported.
- ///
- /// This is the equivalent of OpenGL's `SwapInterval` with a value of 1.
- Fifo = ash::vk::PresentModeKHR::FIFO.as_raw(),
-
- /// Same as `Fifo`, except that if the queue was empty during the previous vertical blanking
- /// period then it is equivalent to `Immediate`.
- ///
- /// This is the equivalent of OpenGL's `SwapInterval` with a value of -1.
- Relaxed = ash::vk::PresentModeKHR::FIFO_RELAXED.as_raw(),
- // TODO: These can't be enabled yet because they have to be used with shared present surfaces
- // which vulkano doesnt support yet.
- //SharedDemand = ash::vk::PresentModeKHR::SHARED_DEMAND_REFRESH,
- //SharedContinuous = ash::vk::PresentModeKHR::SHARED_CONTINUOUS_REFRESH,
-}
-
-impl From<PresentMode> for ash::vk::PresentModeKHR {
- #[inline]
- fn from(val: PresentMode) -> Self {
- Self::from_raw(val as i32)
- }
-}
-
-/// List of `PresentMode`s that are supported.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub struct SupportedPresentModes {
- pub immediate: bool,
- pub mailbox: bool,
- pub fifo: bool,
- pub relaxed: bool,
- pub shared_demand: bool,
- pub shared_continuous: bool,
-}
-
-impl FromIterator<ash::vk::PresentModeKHR> for SupportedPresentModes {
- fn from_iter<T>(iter: T) -> Self
- where
- T: IntoIterator<Item = ash::vk::PresentModeKHR>,
- {
- let mut result = SupportedPresentModes::none();
- for e in iter {
- match e {
- ash::vk::PresentModeKHR::IMMEDIATE => result.immediate = true,
- ash::vk::PresentModeKHR::MAILBOX => result.mailbox = true,
- ash::vk::PresentModeKHR::FIFO => result.fifo = true,
- ash::vk::PresentModeKHR::FIFO_RELAXED => result.relaxed = true,
- ash::vk::PresentModeKHR::SHARED_DEMAND_REFRESH => result.shared_demand = true,
- ash::vk::PresentModeKHR::SHARED_CONTINUOUS_REFRESH => {
- result.shared_continuous = true
- }
- _ => {}
- }
- }
- result
- }
-}
-
-impl SupportedPresentModes {
- /// Builds a `SupportedPresentModes` with all fields set to false.
- #[inline]
- pub fn none() -> SupportedPresentModes {
- SupportedPresentModes {
- immediate: false,
- mailbox: false,
- fifo: false,
- relaxed: false,
- shared_demand: false,
- shared_continuous: false,
- }
- }
-
- /// Returns true if the given present mode is in this list of supported modes.
- #[inline]
- pub fn supports(&self, mode: PresentMode) -> bool {
- match mode {
- PresentMode::Immediate => self.immediate,
- PresentMode::Mailbox => self.mailbox,
- PresentMode::Fifo => self.fifo,
- PresentMode::Relaxed => self.relaxed,
- }
- }
-
- /// Returns an iterator to the list of supported present modes.
- #[inline]
- pub fn iter(&self) -> SupportedPresentModesIter {
- SupportedPresentModesIter(self.clone())
- }
-}
-
-/// Enumeration of the `PresentMode`s that are supported.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub struct SupportedPresentModesIter(SupportedPresentModes);
-
-impl Iterator for SupportedPresentModesIter {
- type Item = PresentMode;
-
- #[inline]
- fn next(&mut self) -> Option<PresentMode> {
- if self.0.immediate {
- self.0.immediate = false;
- return Some(PresentMode::Immediate);
- }
- if self.0.mailbox {
- self.0.mailbox = false;
- return Some(PresentMode::Mailbox);
- }
- if self.0.fifo {
- self.0.fifo = false;
- return Some(PresentMode::Fifo);
- }
- if self.0.relaxed {
- self.0.relaxed = false;
- return Some(PresentMode::Relaxed);
- }
- None
- }
-}
-
-/// A transformation to apply to the image before showing it on the screen.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-#[repr(u32)]
-pub enum SurfaceTransform {
- /// Don't transform the image.
- Identity = ash::vk::SurfaceTransformFlagsKHR::IDENTITY.as_raw(),
- /// Rotate 90 degrees.
- Rotate90 = ash::vk::SurfaceTransformFlagsKHR::ROTATE_90.as_raw(),
- /// Rotate 180 degrees.
- Rotate180 = ash::vk::SurfaceTransformFlagsKHR::ROTATE_180.as_raw(),
- /// Rotate 270 degrees.
- Rotate270 = ash::vk::SurfaceTransformFlagsKHR::ROTATE_270.as_raw(),
- /// Mirror the image horizontally.
- HorizontalMirror = ash::vk::SurfaceTransformFlagsKHR::HORIZONTAL_MIRROR.as_raw(),
- /// Mirror the image horizontally and rotate 90 degrees.
- HorizontalMirrorRotate90 =
- ash::vk::SurfaceTransformFlagsKHR::HORIZONTAL_MIRROR_ROTATE_90.as_raw(),
- /// Mirror the image horizontally and rotate 180 degrees.
- HorizontalMirrorRotate180 =
- ash::vk::SurfaceTransformFlagsKHR::HORIZONTAL_MIRROR_ROTATE_180.as_raw(),
- /// Mirror the image horizontally and rotate 270 degrees.
- HorizontalMirrorRotate270 =
- ash::vk::SurfaceTransformFlagsKHR::HORIZONTAL_MIRROR_ROTATE_270.as_raw(),
- /// Let the operating system or driver implementation choose.
- Inherit = ash::vk::SurfaceTransformFlagsKHR::INHERIT.as_raw(),
-}
-
-impl From<SurfaceTransform> for ash::vk::SurfaceTransformFlagsKHR {
- #[inline]
- fn from(val: SurfaceTransform) -> Self {
- Self::from_raw(val as u32)
- }
-}
-
-/// How the alpha values of the pixels of the window are treated.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-#[repr(u32)]
-pub enum CompositeAlpha {
- /// The alpha channel of the image is ignored. All the pixels are considered as if they have a
- /// value of 1.0.
- Opaque = ash::vk::CompositeAlphaFlagsKHR::OPAQUE.as_raw(),
-
- /// The alpha channel of the image is respected. The color channels are expected to have
- /// already been multiplied by the alpha value.
- PreMultiplied = ash::vk::CompositeAlphaFlagsKHR::PRE_MULTIPLIED.as_raw(),
-
- /// The alpha channel of the image is respected. The color channels will be multiplied by the
- /// alpha value by the compositor before being added to what is behind.
- PostMultiplied = ash::vk::CompositeAlphaFlagsKHR::POST_MULTIPLIED.as_raw(),
-
- /// Let the operating system or driver implementation choose.
- Inherit = ash::vk::CompositeAlphaFlagsKHR::INHERIT.as_raw(),
-}
-
-impl From<CompositeAlpha> for ash::vk::CompositeAlphaFlagsKHR {
- #[inline]
- fn from(val: CompositeAlpha) -> Self {
- Self::from_raw(val as u32)
- }
-}
-
-/// List of supported composite alpha modes.
-///
-/// See the docs of `CompositeAlpha`.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-#[allow(missing_docs)]
-pub struct SupportedCompositeAlpha {
- pub opaque: bool,
- pub pre_multiplied: bool,
- pub post_multiplied: bool,
- pub inherit: bool,
-}
-
-impl From<ash::vk::CompositeAlphaFlagsKHR> for SupportedCompositeAlpha {
- #[inline]
- fn from(val: ash::vk::CompositeAlphaFlagsKHR) -> SupportedCompositeAlpha {
- let mut result = SupportedCompositeAlpha::none();
- if !(val & ash::vk::CompositeAlphaFlagsKHR::OPAQUE).is_empty() {
- result.opaque = true;
- }
- if !(val & ash::vk::CompositeAlphaFlagsKHR::PRE_MULTIPLIED).is_empty() {
- result.pre_multiplied = true;
- }
- if !(val & ash::vk::CompositeAlphaFlagsKHR::POST_MULTIPLIED).is_empty() {
- result.post_multiplied = true;
- }
- if !(val & ash::vk::CompositeAlphaFlagsKHR::INHERIT).is_empty() {
- result.inherit = true;
- }
- result
- }
-}
-
-impl SupportedCompositeAlpha {
- /// Builds a `SupportedCompositeAlpha` with all fields set to false.
- #[inline]
- pub fn none() -> SupportedCompositeAlpha {
- SupportedCompositeAlpha {
- opaque: false,
- pre_multiplied: false,
- post_multiplied: false,
- inherit: false,
- }
- }
-
- /// Returns true if the given `CompositeAlpha` is in this list.
- #[inline]
- pub fn supports(&self, value: CompositeAlpha) -> bool {
- match value {
- CompositeAlpha::Opaque => self.opaque,
- CompositeAlpha::PreMultiplied => self.pre_multiplied,
- CompositeAlpha::PostMultiplied => self.post_multiplied,
- CompositeAlpha::Inherit => self.inherit,
- }
- }
-
- /// Returns an iterator to the list of supported composite alpha.
- #[inline]
- pub fn iter(&self) -> SupportedCompositeAlphaIter {
- SupportedCompositeAlphaIter(self.clone())
- }
-}
-
-/// Enumeration of the `CompositeAlpha` that are supported.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub struct SupportedCompositeAlphaIter(SupportedCompositeAlpha);
-
-impl Iterator for SupportedCompositeAlphaIter {
- type Item = CompositeAlpha;
-
- #[inline]
- fn next(&mut self) -> Option<CompositeAlpha> {
- if self.0.opaque {
- self.0.opaque = false;
- return Some(CompositeAlpha::Opaque);
- }
- if self.0.pre_multiplied {
- self.0.pre_multiplied = false;
- return Some(CompositeAlpha::PreMultiplied);
- }
- if self.0.post_multiplied {
- self.0.post_multiplied = false;
- return Some(CompositeAlpha::PostMultiplied);
- }
- if self.0.inherit {
- self.0.inherit = false;
- return Some(CompositeAlpha::Inherit);
- }
- None
- }
-}
-
-/// List of supported composite alpha modes.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub struct SupportedSurfaceTransforms {
- pub identity: bool,
- pub rotate90: bool,
- pub rotate180: bool,
- pub rotate270: bool,
- pub horizontal_mirror: bool,
- pub horizontal_mirror_rotate90: bool,
- pub horizontal_mirror_rotate180: bool,
- pub horizontal_mirror_rotate270: bool,
- pub inherit: bool,
-}
-
-impl From<ash::vk::SurfaceTransformFlagsKHR> for SupportedSurfaceTransforms {
- fn from(val: ash::vk::SurfaceTransformFlagsKHR) -> Self {
- macro_rules! v {
- ($val:expr, $out:ident, $e:expr, $f:ident) => {
- if !($val & $e).is_empty() {
- $out.$f = true;
- }
- };
- }
-
- let mut result = SupportedSurfaceTransforms::none();
- v!(
- val,
- result,
- ash::vk::SurfaceTransformFlagsKHR::IDENTITY,
- identity
- );
- v!(
- val,
- result,
- ash::vk::SurfaceTransformFlagsKHR::ROTATE_90,
- rotate90
- );
- v!(
- val,
- result,
- ash::vk::SurfaceTransformFlagsKHR::ROTATE_180,
- rotate180
- );
- v!(
- val,
- result,
- ash::vk::SurfaceTransformFlagsKHR::ROTATE_270,
- rotate270
- );
- v!(
- val,
- result,
- ash::vk::SurfaceTransformFlagsKHR::HORIZONTAL_MIRROR,
- horizontal_mirror
- );
- v!(
- val,
- result,
- ash::vk::SurfaceTransformFlagsKHR::HORIZONTAL_MIRROR_ROTATE_90,
- horizontal_mirror_rotate90
- );
- v!(
- val,
- result,
- ash::vk::SurfaceTransformFlagsKHR::HORIZONTAL_MIRROR_ROTATE_180,
- horizontal_mirror_rotate180
- );
- v!(
- val,
- result,
- ash::vk::SurfaceTransformFlagsKHR::HORIZONTAL_MIRROR_ROTATE_270,
- horizontal_mirror_rotate270
- );
- v!(
- val,
- result,
- ash::vk::SurfaceTransformFlagsKHR::INHERIT,
- inherit
- );
- result
- }
-}
-
-impl SupportedSurfaceTransforms {
- /// Builds a `SupportedSurfaceTransforms` with all fields set to false.
- #[inline]
- pub fn none() -> SupportedSurfaceTransforms {
- SupportedSurfaceTransforms {
- identity: false,
- rotate90: false,
- rotate180: false,
- rotate270: false,
- horizontal_mirror: false,
- horizontal_mirror_rotate90: false,
- horizontal_mirror_rotate180: false,
- horizontal_mirror_rotate270: false,
- inherit: false,
- }
- }
-
- /// Returns true if the given `SurfaceTransform` is in this list.
- #[inline]
- pub fn supports(&self, value: SurfaceTransform) -> bool {
- match value {
- SurfaceTransform::Identity => self.identity,
- SurfaceTransform::Rotate90 => self.rotate90,
- SurfaceTransform::Rotate180 => self.rotate180,
- SurfaceTransform::Rotate270 => self.rotate270,
- SurfaceTransform::HorizontalMirror => self.horizontal_mirror,
- SurfaceTransform::HorizontalMirrorRotate90 => self.horizontal_mirror_rotate90,
- SurfaceTransform::HorizontalMirrorRotate180 => self.horizontal_mirror_rotate180,
- SurfaceTransform::HorizontalMirrorRotate270 => self.horizontal_mirror_rotate270,
- SurfaceTransform::Inherit => self.inherit,
- }
- }
-
- /// Returns an iterator to the list of supported composite alpha.
- #[inline]
- pub fn iter(&self) -> SupportedSurfaceTransformsIter {
- SupportedSurfaceTransformsIter(self.clone())
- }
-}
-
-/// Enumeration of the `SurfaceTransform` that are supported.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub struct SupportedSurfaceTransformsIter(SupportedSurfaceTransforms);
-
-impl Iterator for SupportedSurfaceTransformsIter {
- type Item = SurfaceTransform;
-
- #[inline]
- fn next(&mut self) -> Option<SurfaceTransform> {
- if self.0.identity {
- self.0.identity = false;
- return Some(SurfaceTransform::Identity);
- }
- if self.0.rotate90 {
- self.0.rotate90 = false;
- return Some(SurfaceTransform::Rotate90);
- }
- if self.0.rotate180 {
- self.0.rotate180 = false;
- return Some(SurfaceTransform::Rotate180);
- }
- if self.0.rotate270 {
- self.0.rotate270 = false;
- return Some(SurfaceTransform::Rotate270);
- }
- if self.0.horizontal_mirror {
- self.0.horizontal_mirror = false;
- return Some(SurfaceTransform::HorizontalMirror);
- }
- if self.0.horizontal_mirror_rotate90 {
- self.0.horizontal_mirror_rotate90 = false;
- return Some(SurfaceTransform::HorizontalMirrorRotate90);
- }
- if self.0.horizontal_mirror_rotate180 {
- self.0.horizontal_mirror_rotate180 = false;
- return Some(SurfaceTransform::HorizontalMirrorRotate180);
- }
- if self.0.horizontal_mirror_rotate270 {
- self.0.horizontal_mirror_rotate270 = false;
- return Some(SurfaceTransform::HorizontalMirrorRotate270);
- }
- if self.0.inherit {
- self.0.inherit = false;
- return Some(SurfaceTransform::Inherit);
- }
- None
- }
-}
-
-impl Default for SurfaceTransform {
- #[inline]
- fn default() -> SurfaceTransform {
- SurfaceTransform::Identity
- }
-}
-
-/// How the presentation engine should interpret the data.
-///
-/// # A quick lesson about color spaces
-///
-/// ## What is a color space?
-///
-/// Each pixel of a monitor is made of three components: one red, one green, and one blue. In the
-/// past, computers would simply send to the monitor the intensity of each of the three components.
-///
-/// This proved to be problematic, because depending on the brand of the monitor the colors would
-/// not exactly be the same. For example on some monitors, a value of `[1.0, 0.0, 0.0]` would be a
-/// bit more orange than on others.
-///
-/// In order to standardize this, there exist what are called *color spaces*: sRGB, AdobeRGB,
-/// DCI-P3, scRGB, etc. When you manipulate RGB values in a specific color space, these values have
-/// a precise absolute meaning in terms of color, that is the same across all systems and monitors.
-///
-/// > **Note**: Color spaces are orthogonal to concept of RGB. *RGB* only indicates what is the
-/// > representation of the data, but not how it is interpreted. You can think of this a bit like
-/// > text encoding. An *RGB* value is a like a byte, in other words it is the medium by which
-/// > values are communicated, and a *color space* is like a text encoding (eg. UTF-8), in other
-/// > words it is the way the value should be interpreted.
-///
-/// The most commonly used color space today is sRGB. Most monitors today use this color space,
-/// and most images files are encoded in this color space.
-///
-/// ## Pixel formats and linear vs non-linear
-///
-/// In Vulkan all images have a specific format in which the data is stored. The data of an image
-/// consists of pixels in RGB but contains no information about the color space (or lack thereof)
-/// of these pixels. You are free to store them in whatever color space you want.
-///
-/// But one big practical problem with color spaces is that they are sometimes not linear, and in
-/// particular the popular sRGB color space is not linear. In a non-linear color space, a value of
-/// `[0.6, 0.6, 0.6]` for example is **not** twice as bright as a value of `[0.3, 0.3, 0.3]`. This
-/// is problematic, because operations such as taking the average of two colors or calculating the
-/// lighting of a texture with a dot product are mathematically incorrect and will produce
-/// incorrect colors.
-///
-/// > **Note**: If the texture format has an alpha component, it is not affected by the color space
-/// > and always behaves linearly.
-///
-/// In order to solve this Vulkan also provides image formats with the `Srgb` suffix, which are
-/// expected to contain RGB data in the sRGB color space. When you sample an image with such a
-/// format from a shader, the implementation will automatically turn the pixel values into a linear
-/// color space that is suitable for linear operations (such as additions or multiplications).
-/// When you write to a framebuffer attachment with such a format, the implementation will
-/// automatically perform the opposite conversion. These conversions are most of the time performed
-/// by the hardware and incur no additional cost.
-///
-/// ## Color space of the swapchain
-///
-/// The color space that you specify when you create a swapchain is how the implementation will
-/// interpret the raw data inside of the image.
-///
-/// > **Note**: The implementation can choose to send the data in the swapchain image directly to
-/// > the monitor, but it can also choose to write it in an intermediary buffer that is then read
-/// > by the operating system or windowing system. Therefore the color space that the
-/// > implementation supports is not necessarily the same as the one supported by the monitor.
-///
-/// It is *your* job to ensure that the data in the swapchain image is in the color space
-/// that is specified here, otherwise colors will be incorrect.
-/// The implementation will never perform any additional automatic conversion after the colors have
-/// been written to the swapchain image.
-///
-/// # How do I handle this correctly?
-///
-/// The easiest way to handle color spaces in a cross-platform program is:
-///
-/// - Always request the `SrgbNonLinear` color space when creating the swapchain.
-/// - Make sure that all your image files use the sRGB color space, and load them in images whose
-/// format has the `Srgb` suffix. Only use non-sRGB image formats for intermediary computations
-/// or to store non-color data.
-/// - Swapchain images should have a format with the `Srgb` suffix.
-///
-/// > **Note**: It is unclear whether the `SrgbNonLinear` color space is always supported by the
-/// > the implementation or not. See <https://github.com/KhronosGroup/Vulkan-Docs/issues/442>.
-///
-/// > **Note**: Lots of developers are confused by color spaces. You can sometimes find articles
-/// > talking about gamma correction and suggestion to put your colors to the power 2.2 for
-/// > example. These are all hacks and you should use the sRGB pixel formats instead.
-///
-/// If you follow these three rules, then everything should render the same way on all platforms.
-///
-/// Additionally you can try detect whether the implementation supports any additional color space
-/// and perform a manual conversion to that color space from inside your shader.
-///
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-#[repr(i32)]
-pub enum ColorSpace {
- SrgbNonLinear = ash::vk::ColorSpaceKHR::SRGB_NONLINEAR.as_raw(),
- DisplayP3NonLinear = ash::vk::ColorSpaceKHR::DISPLAY_P3_NONLINEAR_EXT.as_raw(),
- ExtendedSrgbLinear = ash::vk::ColorSpaceKHR::EXTENDED_SRGB_LINEAR_EXT.as_raw(),
- ExtendedSrgbNonLinear = ash::vk::ColorSpaceKHR::EXTENDED_SRGB_NONLINEAR_EXT.as_raw(),
- DciP3Linear = ash::vk::ColorSpaceKHR::DCI_P3_LINEAR_EXT.as_raw(),
- DciP3NonLinear = ash::vk::ColorSpaceKHR::DCI_P3_NONLINEAR_EXT.as_raw(),
- Bt709Linear = ash::vk::ColorSpaceKHR::BT709_LINEAR_EXT.as_raw(),
- Bt709NonLinear = ash::vk::ColorSpaceKHR::BT709_NONLINEAR_EXT.as_raw(),
- Bt2020Linear = ash::vk::ColorSpaceKHR::BT2020_LINEAR_EXT.as_raw(),
- Hdr10St2084 = ash::vk::ColorSpaceKHR::HDR10_ST2084_EXT.as_raw(),
- DolbyVision = ash::vk::ColorSpaceKHR::DOLBYVISION_EXT.as_raw(),
- Hdr10Hlg = ash::vk::ColorSpaceKHR::HDR10_HLG_EXT.as_raw(),
- AdobeRgbLinear = ash::vk::ColorSpaceKHR::ADOBERGB_LINEAR_EXT.as_raw(),
- AdobeRgbNonLinear = ash::vk::ColorSpaceKHR::ADOBERGB_NONLINEAR_EXT.as_raw(),
- PassThrough = ash::vk::ColorSpaceKHR::PASS_THROUGH_EXT.as_raw(),
- DisplayNative = ash::vk::ColorSpaceKHR::DISPLAY_NATIVE_AMD.as_raw(),
-}
-
-impl From<ColorSpace> for ash::vk::ColorSpaceKHR {
- #[inline]
- fn from(val: ColorSpace) -> Self {
- Self::from_raw(val as i32)
- }
-}
-
-impl From<ash::vk::ColorSpaceKHR> for ColorSpace {
- #[inline]
- fn from(val: ash::vk::ColorSpaceKHR) -> Self {
- match val {
- ash::vk::ColorSpaceKHR::SRGB_NONLINEAR => ColorSpace::SrgbNonLinear,
- ash::vk::ColorSpaceKHR::DISPLAY_P3_NONLINEAR_EXT => ColorSpace::DisplayP3NonLinear,
- ash::vk::ColorSpaceKHR::EXTENDED_SRGB_LINEAR_EXT => ColorSpace::ExtendedSrgbLinear,
- ash::vk::ColorSpaceKHR::EXTENDED_SRGB_NONLINEAR_EXT => {
- ColorSpace::ExtendedSrgbNonLinear
- }
- ash::vk::ColorSpaceKHR::DCI_P3_LINEAR_EXT => ColorSpace::DciP3Linear,
- ash::vk::ColorSpaceKHR::DCI_P3_NONLINEAR_EXT => ColorSpace::DciP3NonLinear,
- ash::vk::ColorSpaceKHR::BT709_LINEAR_EXT => ColorSpace::Bt709Linear,
- ash::vk::ColorSpaceKHR::BT709_NONLINEAR_EXT => ColorSpace::Bt709NonLinear,
- ash::vk::ColorSpaceKHR::BT2020_LINEAR_EXT => ColorSpace::Bt2020Linear,
- ash::vk::ColorSpaceKHR::HDR10_ST2084_EXT => ColorSpace::Hdr10St2084,
- ash::vk::ColorSpaceKHR::DOLBYVISION_EXT => ColorSpace::DolbyVision,
- ash::vk::ColorSpaceKHR::HDR10_HLG_EXT => ColorSpace::Hdr10Hlg,
- ash::vk::ColorSpaceKHR::ADOBERGB_LINEAR_EXT => ColorSpace::AdobeRgbLinear,
- ash::vk::ColorSpaceKHR::ADOBERGB_NONLINEAR_EXT => ColorSpace::AdobeRgbNonLinear,
- ash::vk::ColorSpaceKHR::PASS_THROUGH_EXT => ColorSpace::PassThrough,
- ash::vk::ColorSpaceKHR::DISPLAY_NATIVE_AMD => ColorSpace::DisplayNative,
- _ => panic!("Wrong value for color space enum {:?}", val),
- }
- }
-}
diff --git a/src/swapchain/display.rs b/src/swapchain/display.rs
index 67f135e..09517bd 100644
--- a/src/swapchain/display.rs
+++ b/src/swapchain/display.rs
@@ -22,23 +22,23 @@
//! rate. You can enumerate the modes available on a display with `Display::display_modes`, or
//! attempt to create your own mode with `TODO`.
//! - Choose a `DisplayPlane`. A display can show multiple planes in a stacking fashion.
-//! - Create a `Surface` object with `Surface::from_display_mode` and pass the chosen `DisplayMode`
+//! - Create a `Surface` object with `Surface::from_display_plane` and pass the chosen `DisplayMode`
//! and `DisplayPlane`.
#![allow(dead_code)] // TODO: this module isn't finished
#![allow(unused_variables)] // TODO: this module isn't finished
-use crate::check_errors;
-use crate::device::physical::PhysicalDevice;
-use crate::instance::Instance;
-use crate::swapchain::SupportedSurfaceTransforms;
-use crate::OomError;
-use crate::VulkanObject;
-use std::ffi::CStr;
-use std::fmt::Formatter;
-use std::sync::Arc;
-use std::vec::IntoIter;
-use std::{fmt, ptr};
+use crate::{
+ device::physical::PhysicalDevice, swapchain::SurfaceTransforms, OomError, VulkanError,
+ VulkanObject,
+};
+use std::{
+ ffi::CStr,
+ fmt::{Display as FmtDisplay, Error as FmtError, Formatter},
+ ptr,
+ sync::Arc,
+ vec::IntoIter,
+};
// TODO: extract this to a `display` module and solve the visibility problems
@@ -46,8 +46,7 @@ use std::{fmt, ptr};
// TODO: plane capabilities
// TODO: store properties in the instance?
pub struct DisplayPlane {
- instance: Arc<Instance>,
- physical_device: usize,
+ physical_device: Arc<PhysicalDevice>,
index: u32,
properties: ash::vk::DisplayPlanePropertiesKHR,
supported_displays: Vec<ash::vk::DisplayKHR>,
@@ -55,75 +54,86 @@ pub struct DisplayPlane {
impl DisplayPlane {
/// See the docs of enumerate().
- pub fn enumerate_raw(device: PhysicalDevice) -> Result<IntoIter<DisplayPlane>, OomError> {
- let fns = device.instance().fns();
-
- assert!(device.instance().enabled_extensions().khr_display); // TODO: return error instead
-
- let num = unsafe {
- let mut num: u32 = 0;
- check_errors(
- fns.khr_display
- .get_physical_device_display_plane_properties_khr(
- device.internal_object(),
- &mut num,
- ptr::null_mut(),
- ),
- )?;
- num
- };
-
- let planes: Vec<ash::vk::DisplayPlanePropertiesKHR> = unsafe {
- let mut planes = Vec::with_capacity(num as usize);
- let mut num = num;
- check_errors(
- fns.khr_display
- .get_physical_device_display_plane_properties_khr(
- device.internal_object(),
- &mut num,
- planes.as_mut_ptr(),
- ),
- )?;
- planes.set_len(num as usize);
- planes
+ pub fn enumerate_raw(
+ physical_device: Arc<PhysicalDevice>,
+ ) -> Result<IntoIter<DisplayPlane>, OomError> {
+ let fns = physical_device.instance().fns();
+
+ assert!(physical_device.instance().enabled_extensions().khr_display); // TODO: return error instead
+
+ let display_plane_properties = unsafe {
+ loop {
+ let mut count = 0;
+ (fns.khr_display
+ .get_physical_device_display_plane_properties_khr)(
+ physical_device.handle(),
+ &mut count,
+ ptr::null_mut(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+
+ let mut properties = Vec::with_capacity(count as usize);
+ let result = (fns
+ .khr_display
+ .get_physical_device_display_plane_properties_khr)(
+ physical_device.handle(),
+ &mut count,
+ properties.as_mut_ptr(),
+ );
+
+ match result {
+ ash::vk::Result::SUCCESS => {
+ properties.set_len(count as usize);
+ break properties;
+ }
+ ash::vk::Result::INCOMPLETE => (),
+ err => return Err(VulkanError::from(err).into()),
+ }
+ }
};
- Ok(planes
+ Ok(display_plane_properties
.into_iter()
.enumerate()
.map(|(index, prop)| {
- let num = unsafe {
- let mut num: u32 = 0;
- check_errors(fns.khr_display.get_display_plane_supported_displays_khr(
- device.internal_object(),
- index as u32,
- &mut num,
- ptr::null_mut(),
- ))
- .unwrap(); // TODO: shouldn't unwrap
- num
- };
-
- let supported_displays: Vec<ash::vk::DisplayKHR> = unsafe {
- let mut displays = Vec::with_capacity(num as usize);
- let mut num = num;
- check_errors(fns.khr_display.get_display_plane_supported_displays_khr(
- device.internal_object(),
- index as u32,
- &mut num,
- displays.as_mut_ptr(),
- ))
- .unwrap(); // TODO: shouldn't unwrap
- displays.set_len(num as usize);
- displays
+ let supported_displays = unsafe {
+ loop {
+ let mut count = 0;
+ (fns.khr_display.get_display_plane_supported_displays_khr)(
+ physical_device.handle(),
+ index as u32,
+ &mut count,
+ ptr::null_mut(),
+ )
+ .result()
+ .map_err(VulkanError::from)
+ .unwrap(); // TODO: shouldn't unwrap
+
+ let mut displays = Vec::with_capacity(count as usize);
+ let result = (fns.khr_display.get_display_plane_supported_displays_khr)(
+ physical_device.handle(),
+ index as u32,
+ &mut count,
+ displays.as_mut_ptr(),
+ );
+
+ match result {
+ ash::vk::Result::SUCCESS => {
+ displays.set_len(count as usize);
+ break displays;
+ }
+ ash::vk::Result::INCOMPLETE => (),
+ err => todo!(), // TODO: shouldn't panic
+ }
+ }
};
DisplayPlane {
- instance: device.instance().clone(),
- physical_device: device.index(),
+ physical_device: physical_device.clone(),
index: index as u32,
properties: prop,
- supported_displays: supported_displays,
+ supported_displays,
}
})
.collect::<Vec<_>>()
@@ -132,20 +142,19 @@ impl DisplayPlane {
/// Enumerates all the display planes that are available on a given physical device.
///
- /// # Panic
+ /// # Panics
///
/// - Panics if the device or host ran out of memory.
- ///
// TODO: move iterator creation here from raw constructor?
#[inline]
- pub fn enumerate(device: PhysicalDevice) -> IntoIter<DisplayPlane> {
- DisplayPlane::enumerate_raw(device).unwrap()
+ pub fn enumerate(physical_device: Arc<PhysicalDevice>) -> IntoIter<DisplayPlane> {
+ DisplayPlane::enumerate_raw(physical_device).unwrap()
}
/// Returns the physical device that was used to create this display.
#[inline]
- pub fn physical_device(&self) -> PhysicalDevice {
- PhysicalDevice::from_index(&self.instance, self.physical_device).unwrap()
+ pub fn physical_device(&self) -> &Arc<PhysicalDevice> {
+ &self.physical_device
}
/// Returns the index of the plane.
@@ -158,14 +167,13 @@ impl DisplayPlane {
#[inline]
pub fn supports(&self, display: &Display) -> bool {
// making sure that the physical device is the same
- if self.physical_device().internal_object() != display.physical_device().internal_object() {
+ if self.physical_device().handle() != display.physical_device().handle() {
return false;
}
self.supported_displays
.iter()
- .find(|&&d| d == display.internal_object())
- .is_some()
+ .any(|&d| d == display.handle())
}
}
@@ -173,44 +181,51 @@ impl DisplayPlane {
// TODO: store properties in the instance?
#[derive(Clone)]
pub struct Display {
- instance: Arc<Instance>,
- physical_device: usize,
+ physical_device: Arc<PhysicalDevice>,
properties: Arc<ash::vk::DisplayPropertiesKHR>, // TODO: Arc because struct isn't clone
}
impl Display {
/// See the docs of enumerate().
- pub fn enumerate_raw(device: PhysicalDevice) -> Result<IntoIter<Display>, OomError> {
- let fns = device.instance().fns();
- assert!(device.instance().enabled_extensions().khr_display); // TODO: return error instead
-
- let num = unsafe {
- let mut num = 0;
- check_errors(fns.khr_display.get_physical_device_display_properties_khr(
- device.internal_object(),
- &mut num,
- ptr::null_mut(),
- ))?;
- num
- };
-
- let displays: Vec<ash::vk::DisplayPropertiesKHR> = unsafe {
- let mut displays = Vec::with_capacity(num as usize);
- let mut num = num;
- check_errors(fns.khr_display.get_physical_device_display_properties_khr(
- device.internal_object(),
- &mut num,
- displays.as_mut_ptr(),
- ))?;
- displays.set_len(num as usize);
- displays
+ pub fn enumerate_raw(
+ physical_device: Arc<PhysicalDevice>,
+ ) -> Result<IntoIter<Display>, OomError> {
+ let fns = physical_device.instance().fns();
+ assert!(physical_device.instance().enabled_extensions().khr_display); // TODO: return error instead
+
+ let display_properties = unsafe {
+ loop {
+ let mut count = 0;
+ (fns.khr_display.get_physical_device_display_properties_khr)(
+ physical_device.handle(),
+ &mut count,
+ ptr::null_mut(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+
+ let mut properties = Vec::with_capacity(count as usize);
+ let result = (fns.khr_display.get_physical_device_display_properties_khr)(
+ physical_device.handle(),
+ &mut count,
+ properties.as_mut_ptr(),
+ );
+
+ match result {
+ ash::vk::Result::SUCCESS => {
+ properties.set_len(count as usize);
+ break properties;
+ }
+ ash::vk::Result::INCOMPLETE => (),
+ err => return Err(VulkanError::from(err).into()),
+ }
+ }
};
- Ok(displays
+ Ok(display_properties
.into_iter()
.map(|prop| Display {
- instance: device.instance().clone(),
- physical_device: device.index(),
+ physical_device: physical_device.clone(),
properties: Arc::new(prop),
})
.collect::<Vec<_>>()
@@ -219,14 +234,13 @@ impl Display {
/// Enumerates all the displays that are available on a given physical device.
///
- /// # Panic
+ /// # Panics
///
/// - Panics if the device or host ran out of memory.
- ///
// TODO: move iterator creation here from raw constructor?
#[inline]
- pub fn enumerate(device: PhysicalDevice) -> IntoIter<Display> {
- Display::enumerate_raw(device).unwrap()
+ pub fn enumerate(physical_device: Arc<PhysicalDevice>) -> IntoIter<Display> {
+ Display::enumerate_raw(physical_device).unwrap()
}
/// Returns the name of the display.
@@ -241,14 +255,14 @@ impl Display {
/// Returns the physical device that was used to create this display.
#[inline]
- pub fn physical_device(&self) -> PhysicalDevice {
- PhysicalDevice::from_index(&self.instance, self.physical_device).unwrap()
+ pub fn physical_device(&self) -> &Arc<PhysicalDevice> {
+ &self.physical_device
}
/// Returns the physical dimensions of the display in millimeters.
#[inline]
pub fn physical_dimensions(&self) -> [u32; 2] {
- let ref r = self.properties.physical_dimensions;
+ let r = &self.properties.physical_dimensions;
[r.width, r.height]
}
@@ -258,13 +272,13 @@ impl Display {
/// > only the "best" resolution.
#[inline]
pub fn physical_resolution(&self) -> [u32; 2] {
- let ref r = self.properties.physical_resolution;
+ let r = &self.properties.physical_resolution;
[r.width, r.height]
}
/// Returns the transforms supported by this display.
#[inline]
- pub fn supported_transforms(&self) -> SupportedSurfaceTransforms {
+ pub fn supported_transforms(&self) -> SurfaceTransforms {
self.properties.supported_transforms.into()
}
@@ -282,33 +296,40 @@ impl Display {
/// See the docs of display_modes().
pub fn display_modes_raw(&self) -> Result<IntoIter<DisplayMode>, OomError> {
- let fns = self.instance.fns();
-
- let num = unsafe {
- let mut num = 0;
- check_errors(fns.khr_display.get_display_mode_properties_khr(
- self.physical_device().internal_object(),
- self.properties.display,
- &mut num,
- ptr::null_mut(),
- ))?;
- num
- };
-
- let modes: Vec<ash::vk::DisplayModePropertiesKHR> = unsafe {
- let mut modes = Vec::with_capacity(num as usize);
- let mut num = num;
- check_errors(fns.khr_display.get_display_mode_properties_khr(
- self.physical_device().internal_object(),
- self.properties.display,
- &mut num,
- modes.as_mut_ptr(),
- ))?;
- modes.set_len(num as usize);
- modes
+ let fns = self.physical_device.instance().fns();
+
+ let mode_properties = unsafe {
+ loop {
+ let mut count = 0;
+ (fns.khr_display.get_display_mode_properties_khr)(
+ self.physical_device().handle(),
+ self.properties.display,
+ &mut count,
+ ptr::null_mut(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+
+ let mut properties = Vec::with_capacity(count as usize);
+ let result = (fns.khr_display.get_display_mode_properties_khr)(
+ self.physical_device().handle(),
+ self.properties.display,
+ &mut count,
+ properties.as_mut_ptr(),
+ );
+
+ match result {
+ ash::vk::Result::SUCCESS => {
+ properties.set_len(count as usize);
+ break properties;
+ }
+ ash::vk::Result::INCOMPLETE => (),
+ err => return Err(VulkanError::from(err).into()),
+ }
+ }
};
- Ok(modes
+ Ok(mode_properties
.into_iter()
.map(|mode| DisplayMode {
display: self.clone(),
@@ -321,10 +342,9 @@ impl Display {
/// Returns a list of all modes available on this display.
///
- /// # Panic
+ /// # Panics
///
/// - Panics if the device or host ran out of memory.
- ///
// TODO: move iterator creation here from display_modes_raw?
#[inline]
pub fn display_modes(&self) -> IntoIter<DisplayMode> {
@@ -333,10 +353,10 @@ impl Display {
}
unsafe impl VulkanObject for Display {
- type Object = ash::vk::DisplayKHR;
+ type Handle = ash::vk::DisplayKHR;
#[inline]
- fn internal_object(&self) -> ash::vk::DisplayKHR {
+ fn handle(&self) -> Self::Handle {
self.properties.display
}
}
@@ -368,9 +388,9 @@ impl DisplayMode {
};
let mut output = mem::uninitialized();
- check_errors(fns.v1_0.CreateDisplayModeKHR(display.device.internal_object(),
+ (fns.v1_0.CreateDisplayModeKHR)(display.device.handle(),
display.display, &infos, ptr::null(),
- &mut output))?;
+ &mut output).result().map_err(VulkanError::from)?;
output
};
@@ -390,7 +410,7 @@ impl DisplayMode {
/// Returns the dimensions of the region that is visible on the monitor.
#[inline]
pub fn visible_region(&self) -> [u32; 2] {
- let ref d = self.parameters.visible_region;
+ let d = &self.parameters.visible_region;
[d.width, d.height]
}
@@ -404,9 +424,9 @@ impl DisplayMode {
}
}
-impl fmt::Display for DisplayMode {
+impl FmtDisplay for DisplayMode {
#[inline]
- fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
let visible_region = self.visible_region();
write!(
@@ -421,10 +441,10 @@ impl fmt::Display for DisplayMode {
}
unsafe impl VulkanObject for DisplayMode {
- type Object = ash::vk::DisplayModeKHR;
+ type Handle = ash::vk::DisplayModeKHR;
#[inline]
- fn internal_object(&self) -> ash::vk::DisplayModeKHR {
+ fn handle(&self) -> Self::Handle {
self.display_mode
}
}
diff --git a/src/swapchain/mod.rs b/src/swapchain/mod.rs
index 0434a57..91b4c3a 100644
--- a/src/swapchain/mod.rs
+++ b/src/swapchain/mod.rs
@@ -40,7 +40,7 @@
//! - `VK_KHR_win32_surface`
//!
//! For example if you want to create a surface from an Android surface, you will have to enable
-//! the `VK_KHR_android_surface` extension and use `Surface::from_anativewindow`.
+//! the `VK_KHR_android_surface` extension and use `Surface::from_android`.
//! See the documentation of `Surface` for all the possible constructors.
//!
//! Trying to use one of these functions without enabling the proper extension will result in an
@@ -51,39 +51,50 @@
//! may be able to do this for you, if you pass it ownership of your Window (or a
//! reference-counting container for it).
//!
-//! ### Example
+//! ### Examples
//!
//! ```no_run
//! use std::ptr;
-//! use vulkano::instance::Instance;
-//! use vulkano::instance::InstanceExtensions;
-//! use vulkano::swapchain::Surface;
-//! use vulkano::Version;
+//! use vulkano::{
+//! instance::{Instance, InstanceCreateInfo, InstanceExtensions},
+//! swapchain::Surface,
+//! Version, VulkanLibrary,
+//! };
//!
//! let instance = {
+//! let library = VulkanLibrary::new()
+//! .unwrap_or_else(|err| panic!("Couldn't load Vulkan library: {:?}", err));
+//!
//! let extensions = InstanceExtensions {
//! khr_surface: true,
//! khr_win32_surface: true, // If you don't enable this, `from_hwnd` will fail.
-//! .. InstanceExtensions::none()
+//! .. InstanceExtensions::empty()
//! };
//!
-//! match Instance::new(None, Version::V1_1, &extensions, None) {
-//! Ok(i) => i,
-//! Err(err) => panic!("Couldn't build instance: {:?}", err)
-//! }
+//! Instance::new(
+//! library,
+//! InstanceCreateInfo {
+//! enabled_extensions: extensions,
+//! ..Default::default()
+//! },
+//! )
+//! .unwrap_or_else(|err| panic!("Couldn't create instance: {:?}", err))
//! };
//!
//! # use std::sync::Arc;
//! # struct Window(*const u32);
-//! # impl Window {
-//! # fn hwnd(&self) -> *const u32 { self.0 }
-//! # }
-//! #
+//! # impl Window { fn hwnd(&self) -> *const u32 { self.0 } }
+//! # unsafe impl Send for Window {}
+//! # unsafe impl Sync for Window {}
//! # fn build_window() -> Arc<Window> { Arc::new(Window(ptr::null())) }
-//! let window = build_window(); // Third-party function, not provided by vulkano
+//! let window = build_window(); // Third-party function, not provided by vulkano
//! let _surface = unsafe {
-//! let hinstance: *const () = ptr::null(); // Windows-specific object
-//! Surface::from_hwnd(instance.clone(), hinstance, window.hwnd(), Arc::clone(&window)).unwrap()
+//! let hinstance: *const () = ptr::null(); // Windows-specific object
+//! Surface::from_win32(
+//! instance.clone(),
+//! hinstance, window.hwnd(),
+//! Some(window),
+//! ).unwrap()
//! };
//! ```
//!
@@ -112,8 +123,7 @@
//! - How the alpha of the final output will be interpreted.
//! - How to perform the cycling between images in regard to vsync.
//!
-//! You can query the supported values of all these properties with
-//! [`Surface::capabilities()]`](struct.Surface.html#method.capabilities).
+//! You can query the supported values of all these properties from the physical device.
//!
//! ## Creating a swapchain
//!
@@ -124,85 +134,88 @@
//! # use vulkano::device::DeviceExtensions;
//! let ext = DeviceExtensions {
//! khr_swapchain: true,
-//! .. DeviceExtensions::none()
+//! .. DeviceExtensions::empty()
//! };
//! ```
//!
//! Then, query the capabilities of the surface with
-//! [`Surface::capabilities()`](struct.Surface.html#method.capabilities)
+//! [`PhysicalDevice::surface_capabilities`](crate::device::physical::PhysicalDevice::surface_capabilities)
+//! and
+//! [`PhysicalDevice::surface_formats`](crate::device::physical::PhysicalDevice::surface_formats)
//! and choose which values you are going to use.
//!
//! ```no_run
-//! # use std::sync::Arc;
+//! # use std::{error::Error, sync::Arc};
//! # use vulkano::device::Device;
//! # use vulkano::swapchain::Surface;
//! # use std::cmp::{max, min};
-//! # fn choose_caps(device: Arc<Device>, surface: Arc<Surface<()>>) -> Result<(), Box<std::error::Error>> {
-//! let caps = surface.capabilities(device.physical_device())?;
+//! # fn choose_caps(device: Arc<Device>, surface: Arc<Surface>) -> Result<(), Box<dyn Error>> {
+//! let surface_capabilities = device
+//! .physical_device()
+//! .surface_capabilities(&surface, Default::default())?;
//!
//! // Use the current window size or some fixed resolution.
-//! let dimensions = caps.current_extent.unwrap_or([640, 480]);
+//! let image_extent = surface_capabilities.current_extent.unwrap_or([640, 480]);
//!
//! // Try to use double-buffering.
-//! let buffers_count = match caps.max_image_count {
-//! None => max(2, caps.min_image_count),
-//! Some(limit) => min(max(2, caps.min_image_count), limit)
+//! let min_image_count = match surface_capabilities.max_image_count {
+//! None => max(2, surface_capabilities.min_image_count),
+//! Some(limit) => min(max(2, surface_capabilities.min_image_count), limit)
//! };
//!
//! // Preserve the current surface transform.
-//! let transform = caps.current_transform;
+//! let pre_transform = surface_capabilities.current_transform;
//!
//! // Use the first available format.
-//! let (format, color_space) = caps.supported_formats[0];
+//! let (image_format, color_space) = device
+//! .physical_device()
+//! .surface_formats(&surface, Default::default())?[0];
//! # Ok(())
//! # }
//! ```
//!
-//! Then, call [`Swapchain::new()`](struct.Swapchain.html#method.new).
+//! Then, call [`Swapchain::new`](crate::swapchain::Swapchain::new).
//!
//! ```no_run
-//! # use std::sync::Arc;
+//! # use std::{error::Error, sync::Arc};
//! # use vulkano::device::{Device, Queue};
//! # use vulkano::image::ImageUsage;
//! # use vulkano::sync::SharingMode;
//! # use vulkano::format::Format;
-//! # use vulkano::swapchain::{Surface, Swapchain, SurfaceTransform, PresentMode, CompositeAlpha, ColorSpace, FullscreenExclusive};
+//! # use vulkano::swapchain::{Surface, Swapchain, SurfaceTransform, PresentMode, CompositeAlpha, ColorSpace, FullScreenExclusive, SwapchainCreateInfo};
//! # fn create_swapchain(
-//! # device: Arc<Device>, surface: Arc<Surface<()>>, present_queue: Arc<Queue>,
-//! # buffers_count: u32, format: Format, dimensions: [u32; 2],
-//! # surface_transform: SurfaceTransform, composite_alpha: CompositeAlpha,
-//! # present_mode: PresentMode, fullscreen_exclusive: FullscreenExclusive
-//! # ) -> Result<(), Box<dyn std::error::Error>> {
-//! // The created swapchain will be used as a color attachment for rendering.
-//! let usage = ImageUsage {
-//! color_attachment: true,
-//! .. ImageUsage::none()
-//! };
-//!
-//! // Create the swapchain and its buffers.
-//! let (swapchain, buffers) = Swapchain::start(
-//! // Create the swapchain in this `device`'s memory.
-//! device,
-//! // The surface where the images will be presented.
-//! surface,
-//! )
-//! // How many buffers to use in the swapchain.
-//! .num_images(buffers_count)
-//! // The format of the images.
-//! .format(format)
-//! // The size of each image.
-//! .dimensions(dimensions)
-//! // What the images are going to be used for.
-//! .usage(usage)
-//! // What transformation to use with the surface.
-//! .transform(surface_transform)
-//! // How to handle the alpha channel.
-//! .composite_alpha(composite_alpha)
-//! // How to present images.
-//! .present_mode(present_mode)
-//! // How to handle fullscreen exclusivity
-//! .fullscreen_exclusive(fullscreen_exclusive)
-//! .build()?;
+//! # device: Arc<Device>, surface: Arc<Surface>,
+//! # min_image_count: u32, image_format: Format, image_extent: [u32; 2],
+//! # pre_transform: SurfaceTransform, composite_alpha: CompositeAlpha,
+//! # present_mode: PresentMode, full_screen_exclusive: FullScreenExclusive
+//! # ) -> Result<(), Box<dyn Error>> {
+//! // Create the swapchain and its images.
+//! let (swapchain, images) = Swapchain::new(
+//! // Create the swapchain in this `device`'s memory.
+//! device,
+//! // The surface where the images will be presented.
+//! surface,
+//! // The creation parameters.
+//! SwapchainCreateInfo {
+//! // How many images to use in the swapchain.
+//! min_image_count,
+//! // The format of the images.
+//! image_format: Some(image_format),
+//! // The size of each image.
+//! image_extent,
+//! // The created swapchain images will be used as a color attachment for rendering.
+//! image_usage: ImageUsage::COLOR_ATTACHMENT,
+//! // What transformation to use with the surface.
+//! pre_transform,
+//! // How to handle the alpha channel.
+//! composite_alpha,
+//! // How to present images.
+//! present_mode,
+//! // How to handle full-screen exclusivity
+//! full_screen_exclusive,
+//! ..Default::default()
+//! }
+//! )?;
//!
//! # Ok(())
//! # }
@@ -227,22 +240,27 @@
//! command to present the image on the screen after the draw operations are finished.
//!
//! ```
-//! use vulkano::swapchain;
+//! use vulkano::swapchain::{self, SwapchainPresentInfo};
//! use vulkano::sync::GpuFuture;
//! # let queue: ::std::sync::Arc<::vulkano::device::Queue> = return;
-//! # let mut swapchain: ::std::sync::Arc<swapchain::Swapchain<()>> = return;
+//! # let mut swapchain: ::std::sync::Arc<swapchain::Swapchain> = return;
//! // let mut (swapchain, images) = Swapchain::new(...);
//! loop {
-//! # let mut command_buffer: ::vulkano::command_buffer::PrimaryAutoCommandBuffer<()> = return;
-//! let (image_num, suboptimal, acquire_future)
+//! # let mut command_buffer: ::vulkano::command_buffer::PrimaryAutoCommandBuffer = return;
+//! let (image_index, suboptimal, acquire_future)
//! = swapchain::acquire_next_image(swapchain.clone(), None).unwrap();
//!
//! // The command_buffer contains the draw commands that modify the framebuffer
-//! // constructed from images[image_num]
+//! // constructed from images[image_index]
//! acquire_future
-//! .then_execute(queue.clone(), command_buffer).unwrap()
-//! .then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
-//! .then_signal_fence_and_flush().unwrap();
+//! .then_execute(queue.clone(), command_buffer)
+//! .unwrap()
+//! .then_swapchain_present(
+//! queue.clone(),
+//! SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index),
+//! )
+//! .then_signal_fence_and_flush()
+//! .unwrap();
//! }
//! ```
//!
@@ -257,83 +275,202 @@
//! rendering, you will need to *recreate* the swapchain by creating a new swapchain and passing
//! as last parameter the old swapchain.
//!
-//!
//! ```
//! use vulkano::swapchain;
-//! use vulkano::swapchain::AcquireError;
+//! use vulkano::swapchain::{AcquireError, SwapchainCreateInfo, SwapchainPresentInfo};
//! use vulkano::sync::GpuFuture;
//!
-//! // let mut swapchain = Swapchain::new(...);
-//! # let mut swapchain: (::std::sync::Arc<::vulkano::swapchain::Swapchain<()>>, _) = return;
+//! // let (swapchain, images) = Swapchain::new(...);
+//! # let mut swapchain: ::std::sync::Arc<::vulkano::swapchain::Swapchain> = return;
+//! # let mut images: Vec<::std::sync::Arc<::vulkano::image::SwapchainImage>> = return;
//! # let queue: ::std::sync::Arc<::vulkano::device::Queue> = return;
//! let mut recreate_swapchain = false;
//!
//! loop {
//! if recreate_swapchain {
-//! swapchain = swapchain.0.recreate().dimensions([1024, 768]).build().unwrap();
+//! let (new_swapchain, new_images) = swapchain.recreate(SwapchainCreateInfo {
+//! image_extent: [1024, 768],
+//! ..swapchain.create_info()
+//! })
+//! .unwrap();
+//! swapchain = new_swapchain;
+//! images = new_images;
//! recreate_swapchain = false;
//! }
//!
-//! let (ref swapchain, ref _images) = swapchain;
-//!
-//! let (index, suboptimal, acq_future) = match swapchain::acquire_next_image(swapchain.clone(), None) {
+//! let (image_index, suboptimal, acq_future) = match swapchain::acquire_next_image(swapchain.clone(), None) {
//! Ok(r) => r,
//! Err(AcquireError::OutOfDate) => { recreate_swapchain = true; continue; },
-//! Err(err) => panic!("{:?}", err)
+//! Err(err) => panic!("{:?}", err),
//! };
//!
//! // ...
//!
//! let final_future = acq_future
//! // .then_execute(...)
-//! .then_swapchain_present(queue.clone(), swapchain.clone(), index)
-//! .then_signal_fence_and_flush().unwrap(); // TODO: PresentError?
+//! .then_swapchain_present(
+//! queue.clone(),
+//! SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index),
+//! )
+//! .then_signal_fence_and_flush()
+//! .unwrap(); // TODO: PresentError?
//!
//! if suboptimal {
//! recreate_swapchain = true;
//! }
//! }
//! ```
-//!
-use std::sync::atomic::AtomicBool;
+pub use self::{
+ surface::{
+ ColorSpace, CompositeAlpha, CompositeAlphas, PresentMode, Surface, SurfaceApi,
+ SurfaceCapabilities, SurfaceCreationError, SurfaceInfo, SurfaceTransform,
+ SurfaceTransforms,
+ },
+ swapchain::{
+ acquire_next_image, acquire_next_image_raw, present, wait_for_present, AcquireError,
+ AcquiredImage, FullScreenExclusive, FullScreenExclusiveError, PresentFuture,
+ PresentWaitError, Swapchain, SwapchainAcquireFuture, SwapchainCreateInfo,
+ SwapchainCreationError, Win32Monitor,
+ },
+};
+#[cfg(target_os = "ios")]
+pub use surface::IOSMetalLayer;
-pub use self::capabilities::Capabilities;
-pub use self::capabilities::ColorSpace;
-pub use self::capabilities::CompositeAlpha;
-pub use self::capabilities::PresentMode;
-pub use self::capabilities::SupportedCompositeAlpha;
-pub use self::capabilities::SupportedCompositeAlphaIter;
-pub use self::capabilities::SupportedPresentModes;
-pub use self::capabilities::SupportedPresentModesIter;
-pub use self::capabilities::SupportedSurfaceTransforms;
-pub use self::capabilities::SupportedSurfaceTransformsIter;
-pub use self::capabilities::SurfaceTransform;
-pub use self::present_region::PresentRegion;
-pub use self::present_region::RectangleLayer;
-pub use self::surface::CapabilitiesError;
-pub use self::surface::Surface;
-pub use self::surface::SurfaceCreationError;
-pub use self::swapchain::acquire_next_image;
-pub use self::swapchain::acquire_next_image_raw;
-pub use self::swapchain::present;
-pub use self::swapchain::present_incremental;
-pub use self::swapchain::AcquireError;
-pub use self::swapchain::AcquiredImage;
-pub use self::swapchain::FullscreenExclusive;
-pub use self::swapchain::FullscreenExclusiveError;
-pub use self::swapchain::PresentFuture;
-pub use self::swapchain::Swapchain;
-pub use self::swapchain::SwapchainAcquireFuture;
-pub use self::swapchain::SwapchainBuilder;
-pub use self::swapchain::SwapchainCreationError;
+use crate::sync::semaphore::Semaphore;
+use std::{
+ num::NonZeroU64,
+ sync::{atomic::AtomicBool, Arc},
+};
-mod capabilities;
pub mod display;
-mod present_region;
mod surface;
mod swapchain;
+/// Parameters to execute present operations on a queue.
+#[derive(Clone, Debug)]
+pub struct PresentInfo {
+ /// The semaphores to wait for before beginning the execution of the present operations.
+ ///
+ /// The default value is empty.
+ pub wait_semaphores: Vec<Arc<Semaphore>>,
+
+ /// The present operations to perform.
+ ///
+ /// The default value is empty.
+ pub swapchain_infos: Vec<SwapchainPresentInfo>,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for PresentInfo {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ wait_semaphores: Vec::new(),
+ swapchain_infos: Vec::new(),
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// Parameters for a single present operation on a swapchain.
+#[derive(Clone, Debug)]
+pub struct SwapchainPresentInfo {
+ /// The swapchain to present to.
+ ///
+ /// There is no default value.
+ pub swapchain: Arc<Swapchain>,
+
+ /// The index of the swapchain image to present to.
+ ///
+ /// The image must have been acquired first; this is the index that `acquire_next_image`
+ /// returns.
+ ///
+ /// There is no default value.
+ pub image_index: u32,
+
+ /// An id used to identify this present operation.
+ ///
+ /// If `present_id` is `Some`, the [`present_id`](crate::device::Features::present_id) feature
+ /// must be enabled on the device. The id must be greater than any id previously used for
+ /// `swapchain`. If a swapchain is recreated, this resets.
+ ///
+ /// The default value is `None`.
+ pub present_id: Option<NonZeroU64>,
+
+ /// Am optimization hint to the implementation, that only some parts of the swapchain image are
+ /// going to be updated by the present operation.
+ ///
+ /// If `present_regions` is not empty, the
+ /// [`khr_incremental_present`](crate::device::DeviceExtensions::khr_incremental_present)
+ /// extension must be enabled on the device. The implementation will update the provided
+ /// regions of the swapchain image, and _may_ ignore the other areas. However, as this is just
+ /// a hint, the Vulkan implementation is free to ignore the regions altogether and update
+ /// everything.
+ ///
+ /// If `present_regions` is empty, that means that all of the swapchain image must be updated.
+ ///
+ /// The default value is empty.
+ pub present_regions: Vec<RectangleLayer>,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl SwapchainPresentInfo {
+ /// Returns a `SwapchainPresentInfo` with the specified `swapchain` and `image_index`.
+ #[inline]
+ pub fn swapchain_image_index(swapchain: Arc<Swapchain>, image_index: u32) -> Self {
+ Self {
+ swapchain,
+ image_index,
+ present_id: None,
+ present_regions: Vec::new(),
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// Represents a rectangular region on an image layer.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct RectangleLayer {
+ /// Coordinates in pixels of the top-left hand corner of the rectangle.
+ pub offset: [u32; 2],
+
+ /// Dimensions in pixels of the rectangle.
+ pub extent: [u32; 2],
+
+ /// The layer of the image. For images with only one layer, the value of layer must be 0.
+ pub layer: u32,
+}
+
+impl RectangleLayer {
+ /// Returns true if this rectangle layer is compatible with swapchain.
+ #[inline]
+ pub fn is_compatible_with(&self, swapchain: &Swapchain) -> bool {
+ self.offset[0] + self.extent[0] <= swapchain.image_extent()[0]
+ && self.offset[1] + self.extent[1] <= swapchain.image_extent()[1]
+ && self.layer < swapchain.image_array_layers()
+ }
+}
+
+impl From<&RectangleLayer> for ash::vk::RectLayerKHR {
+ #[inline]
+ fn from(val: &RectangleLayer) -> Self {
+ ash::vk::RectLayerKHR {
+ offset: ash::vk::Offset2D {
+ x: val.offset[0] as i32,
+ y: val.offset[1] as i32,
+ },
+ extent: ash::vk::Extent2D {
+ width: val.extent[0],
+ height: val.extent[1],
+ },
+ layer: val.layer,
+ }
+ }
+}
+
/// Internal trait so that creating/destroying a swapchain can access the surface's "has_swapchain"
/// flag.
// TODO: use pub(crate) maybe?
diff --git a/src/swapchain/present_region.rs b/src/swapchain/present_region.rs
deleted file mode 100644
index 7e5fdf4..0000000
--- a/src/swapchain/present_region.rs
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (c) 2017 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::swapchain::Swapchain;
-
-/// Represents a region on an image.
-///
-/// A region consists of an arbitrary amount of rectangles.
-#[derive(Debug, Clone)]
-pub struct PresentRegion {
- pub rectangles: Vec<RectangleLayer>,
-}
-
-impl PresentRegion {
- /// Returns true if this present region is compatible with swapchain.
- pub fn is_compatible_with<W>(&self, swapchain: &Swapchain<W>) -> bool {
- self.rectangles
- .iter()
- .all(|rect| rect.is_compatible_with(swapchain))
- }
-}
-
-/// Represents a rectangular region on an image layer.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct RectangleLayer {
- /// Coordinates in pixels of the top-left hand corner of the rectangle.
- pub offset: [i32; 2],
-
- /// Dimensions in pixels of the rectangle.
- pub extent: [u32; 2],
-
- /// The layer of the image. For images with only one layer, the value of layer must be 0.
- pub layer: u32,
-}
-
-impl RectangleLayer {
- /// Returns true if this rectangle layer is compatible with swapchain.
- pub fn is_compatible_with<W>(&self, swapchain: &Swapchain<W>) -> bool {
- // FIXME negative offset is not disallowed by spec, but semantically should not be possible
- debug_assert!(self.offset[0] >= 0);
- debug_assert!(self.offset[1] >= 0);
- self.offset[0] as u32 + self.extent[0] <= swapchain.dimensions()[0]
- && self.offset[1] as u32 + self.extent[1] <= swapchain.dimensions()[1]
- && self.layer < swapchain.layers()
- }
-}
-
-impl From<&RectangleLayer> for ash::vk::RectLayerKHR {
- #[inline]
- fn from(val: &RectangleLayer) -> Self {
- ash::vk::RectLayerKHR {
- offset: ash::vk::Offset2D {
- x: val.offset[0],
- y: val.offset[1],
- },
- extent: ash::vk::Extent2D {
- width: val.extent[0],
- height: val.extent[1],
- },
- layer: val.layer,
- }
- }
-}
diff --git a/src/swapchain/surface.rs b/src/swapchain/surface.rs
index 9bf5fd8..44dda8b 100644
--- a/src/swapchain/surface.rs
+++ b/src/swapchain/surface.rs
@@ -7,71 +7,165 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use crate::check_errors;
-use crate::device::physical::PhysicalDevice;
-use crate::device::physical::QueueFamily;
-use crate::format::Format;
-use crate::image::ImageUsage;
-use crate::instance::Instance;
-use crate::swapchain::capabilities::SupportedSurfaceTransforms;
-use crate::swapchain::display::DisplayMode;
-use crate::swapchain::display::DisplayPlane;
-use crate::swapchain::Capabilities;
-use crate::swapchain::SurfaceSwapchainLock;
-use crate::Error;
-use crate::OomError;
-use crate::VulkanObject;
-use std::convert::TryFrom;
-use std::error;
-use std::fmt;
-use std::mem::MaybeUninit;
-use std::os::raw::c_ulong;
-use std::ptr;
-use std::sync::atomic::AtomicBool;
-use std::sync::Arc;
+use super::{FullScreenExclusive, Win32Monitor};
+use crate::{
+ cache::OnceCache,
+ format::Format,
+ image::ImageUsage,
+ instance::Instance,
+ macros::{impl_id_counter, vulkan_bitflags_enum, vulkan_enum},
+ swapchain::{
+ display::{DisplayMode, DisplayPlane},
+ SurfaceSwapchainLock,
+ },
+ OomError, RequiresOneOf, VulkanError, VulkanObject,
+};
+
+#[cfg(target_os = "ios")]
+use objc::{class, msg_send, runtime::Object, sel, sel_impl};
+
+use std::{
+ any::Any,
+ error::Error,
+ fmt::{Debug, Display, Error as FmtError, Formatter},
+ mem::MaybeUninit,
+ num::NonZeroU64,
+ ptr,
+ sync::{atomic::AtomicBool, Arc},
+};
/// Represents a surface on the screen.
///
/// Creating a `Surface` is platform-specific.
-pub struct Surface<W> {
- window: W,
+pub struct Surface {
+ handle: ash::vk::SurfaceKHR,
instance: Arc<Instance>,
- surface: ash::vk::SurfaceKHR,
-
+ id: NonZeroU64,
+ api: SurfaceApi,
+ object: Option<Arc<dyn Any + Send + Sync>>,
// If true, a swapchain has been associated to this surface, and that any new swapchain
// creation should be forbidden.
has_swapchain: AtomicBool,
+ #[cfg(target_os = "ios")]
+ metal_layer: IOSMetalLayer,
+
+ // Data queried by the user at runtime, cached for faster lookups.
+ // This is stored here rather than on `PhysicalDevice` to ensure that it's freed when the
+ // `Surface` is destroyed.
+ pub(crate) surface_formats:
+ OnceCache<(ash::vk::PhysicalDevice, SurfaceInfo), Vec<(Format, ColorSpace)>>,
+ pub(crate) surface_present_modes: OnceCache<ash::vk::PhysicalDevice, Vec<PresentMode>>,
+ pub(crate) surface_support: OnceCache<(ash::vk::PhysicalDevice, u32), bool>,
}
-impl<W> Surface<W> {
- /// Creates a `Surface` given the raw handler.
+impl Surface {
+ /// Creates a `Surface` from a raw handle.
///
- /// Be careful when using it
+ /// # Safety
///
- pub unsafe fn from_raw_surface(
+ /// - `handle` must be a valid Vulkan object handle created from `instance`.
+ /// - `handle` must have been created from `api`.
+ /// - The window object that `handle` was created from must outlive the created `Surface`.
+ /// The `object` parameter can be used to ensure this.
+ pub unsafe fn from_handle(
instance: Arc<Instance>,
- surface: ash::vk::SurfaceKHR,
- win: W,
- ) -> Surface<W> {
+ handle: ash::vk::SurfaceKHR,
+ api: SurfaceApi,
+ object: Option<Arc<dyn Any + Send + Sync>>,
+ ) -> Self {
Surface {
- window: win,
+ handle,
instance,
- surface,
+ id: Self::next_id(),
+ api,
+ object,
has_swapchain: AtomicBool::new(false),
+ #[cfg(target_os = "ios")]
+ metal_layer: IOSMetalLayer::new(std::ptr::null_mut(), std::ptr::null_mut()),
+ surface_formats: OnceCache::new(),
+ surface_present_modes: OnceCache::new(),
+ surface_support: OnceCache::new(),
}
}
- /// Creates a `Surface` that covers a display mode.
+ /// Creates a `Surface` with no backing window or display.
+ ///
+ /// Presenting to a headless surface does nothing, so this is mostly useless in itself. However,
+ /// it may be useful for testing, and it is available for future extensions to layer on top of.
+ pub fn headless(
+ instance: Arc<Instance>,
+ object: Option<Arc<dyn Any + Send + Sync>>,
+ ) -> Result<Arc<Self>, SurfaceCreationError> {
+ Self::validate_headless(&instance)?;
+
+ unsafe { Ok(Self::headless_unchecked(instance, object)?) }
+ }
+
+ fn validate_headless(instance: &Instance) -> Result<(), SurfaceCreationError> {
+ if !instance.enabled_extensions().ext_headless_surface {
+ return Err(SurfaceCreationError::RequirementNotMet {
+ required_for: "`Surface::headless`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["ext_headless_surface"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn headless_unchecked(
+ instance: Arc<Instance>,
+ object: Option<Arc<dyn Any + Send + Sync>>,
+ ) -> Result<Arc<Self>, VulkanError> {
+ let create_info = ash::vk::HeadlessSurfaceCreateInfoEXT {
+ flags: ash::vk::HeadlessSurfaceCreateFlagsEXT::empty(),
+ ..Default::default()
+ };
+
+ let handle = {
+ let fns = instance.fns();
+ let mut output = MaybeUninit::uninit();
+ (fns.ext_headless_surface.create_headless_surface_ext)(
+ instance.handle(),
+ &create_info,
+ ptr::null(),
+ output.as_mut_ptr(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+ output.assume_init()
+ };
+
+ Ok(Arc::new(Self::from_handle(
+ instance,
+ handle,
+ SurfaceApi::Headless,
+ object,
+ )))
+ }
+
+ /// Creates a `Surface` from a `DisplayPlane`.
///
- /// # Panic
+ /// # Panics
///
/// - Panics if `display_mode` and `plane` don't belong to the same physical device.
/// - Panics if `plane` doesn't support the display of `display_mode`.
- ///
- pub fn from_display_mode(
+ pub fn from_display_plane(
+ display_mode: &DisplayMode,
+ plane: &DisplayPlane,
+ ) -> Result<Arc<Self>, SurfaceCreationError> {
+ Self::validate_from_display_plane(display_mode, plane)?;
+
+ unsafe { Ok(Self::from_display_plane_unchecked(display_mode, plane)?) }
+ }
+
+ fn validate_from_display_plane(
display_mode: &DisplayMode,
plane: &DisplayPlane,
- ) -> Result<Arc<Surface<()>>, SurfaceCreationError> {
+ ) -> Result<(), SurfaceCreationError> {
if !display_mode
.display()
.physical_device()
@@ -79,573 +173,1079 @@ impl<W> Surface<W> {
.enabled_extensions()
.khr_display
{
- return Err(SurfaceCreationError::MissingExtension {
- name: "VK_KHR_display",
+ return Err(SurfaceCreationError::RequirementNotMet {
+ required_for: "`Surface::from_display_plane`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["khr_display"],
+ ..Default::default()
+ },
});
}
assert_eq!(
- display_mode.display().physical_device().internal_object(),
- plane.physical_device().internal_object()
+ display_mode.display().physical_device(),
+ plane.physical_device()
);
assert!(plane.supports(display_mode.display()));
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn from_display_plane_unchecked(
+ display_mode: &DisplayMode,
+ plane: &DisplayPlane,
+ ) -> Result<Arc<Self>, VulkanError> {
let instance = display_mode.display().physical_device().instance();
- let fns = instance.fns();
-
- let surface = unsafe {
- let infos = ash::vk::DisplaySurfaceCreateInfoKHR {
- flags: ash::vk::DisplaySurfaceCreateFlagsKHR::empty(),
- display_mode: display_mode.internal_object(),
- plane_index: plane.index(),
- plane_stack_index: 0, // FIXME: plane.properties.currentStackIndex,
- transform: ash::vk::SurfaceTransformFlagsKHR::IDENTITY, // TODO: let user choose
- global_alpha: 0.0, // TODO: let user choose
- alpha_mode: ash::vk::DisplayPlaneAlphaFlagsKHR::OPAQUE, // TODO: let user choose
- image_extent: ash::vk::Extent2D {
- // TODO: let user choose
- width: display_mode.visible_region()[0],
- height: display_mode.visible_region()[1],
- },
- ..Default::default()
- };
+ let create_info = ash::vk::DisplaySurfaceCreateInfoKHR {
+ flags: ash::vk::DisplaySurfaceCreateFlagsKHR::empty(),
+ display_mode: display_mode.handle(),
+ plane_index: plane.index(),
+ plane_stack_index: 0, // FIXME: plane.properties.currentStackIndex,
+ transform: ash::vk::SurfaceTransformFlagsKHR::IDENTITY, // TODO: let user choose
+ global_alpha: 0.0, // TODO: let user choose
+ alpha_mode: ash::vk::DisplayPlaneAlphaFlagsKHR::OPAQUE, // TODO: let user choose
+ image_extent: ash::vk::Extent2D {
+ // TODO: let user choose
+ width: display_mode.visible_region()[0],
+ height: display_mode.visible_region()[1],
+ },
+ ..Default::default()
+ };
+
+ let handle = {
+ let fns = instance.fns();
let mut output = MaybeUninit::uninit();
- check_errors(fns.khr_display.create_display_plane_surface_khr(
- instance.internal_object(),
- &infos,
+ (fns.khr_display.create_display_plane_surface_khr)(
+ instance.handle(),
+ &create_info,
ptr::null(),
output.as_mut_ptr(),
- ))?;
+ )
+ .result()
+ .map_err(VulkanError::from)?;
output.assume_init()
};
- Ok(Arc::new(Surface {
- window: (),
- instance: instance.clone(),
- surface,
- has_swapchain: AtomicBool::new(false),
- }))
+ Ok(Arc::new(Self::from_handle(
+ instance.clone(),
+ handle,
+ SurfaceApi::DisplayPlane,
+ None,
+ )))
}
- /// Creates a `Surface` from a Win32 window.
- ///
- /// The surface's min, max and current extent will always match the window's dimensions.
+ /// Creates a `Surface` from an Android window.
///
/// # Safety
///
- /// The caller must ensure that the `hinstance` and the `hwnd` are both correct and stay
- /// alive for the entire lifetime of the surface. The `win` parameter can be used to ensure this.
-
- pub unsafe fn from_hwnd<T, U>(
+ /// - `window` must be a valid Android `ANativeWindow` handle.
+ /// - The object referred to by `window` must outlive the created `Surface`.
+ /// The `object` parameter can be used to ensure this.
+ pub unsafe fn from_android<W>(
instance: Arc<Instance>,
- hinstance: *const T,
- hwnd: *const U,
- win: W,
- ) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
- let fns = instance.fns();
+ window: *const W,
+ object: Option<Arc<dyn Any + Send + Sync>>,
+ ) -> Result<Arc<Self>, SurfaceCreationError> {
+ Self::validate_from_android(&instance, window)?;
- if !instance.enabled_extensions().khr_win32_surface {
- return Err(SurfaceCreationError::MissingExtension {
- name: "VK_KHR_win32_surface",
+ Ok(Self::from_android_unchecked(instance, window, object)?)
+ }
+
+ fn validate_from_android<W>(
+ instance: &Instance,
+ _window: *const W,
+ ) -> Result<(), SurfaceCreationError> {
+ if !instance.enabled_extensions().khr_android_surface {
+ return Err(SurfaceCreationError::RequirementNotMet {
+ required_for: "`Surface::from_android`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["khr_android_surface"],
+ ..Default::default()
+ },
});
}
- let surface = {
- let infos = ash::vk::Win32SurfaceCreateInfoKHR {
- flags: ash::vk::Win32SurfaceCreateFlagsKHR::empty(),
- hinstance: hinstance as *mut _,
- hwnd: hwnd as *mut _,
- ..Default::default()
- };
+ // VUID-VkAndroidSurfaceCreateInfoKHR-window-01248
+ // Can't validate, therefore unsafe
+
+ Ok(())
+ }
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn from_android_unchecked<W>(
+ instance: Arc<Instance>,
+ window: *const W,
+ object: Option<Arc<dyn Any + Send + Sync>>,
+ ) -> Result<Arc<Self>, VulkanError> {
+ let create_info = ash::vk::AndroidSurfaceCreateInfoKHR {
+ flags: ash::vk::AndroidSurfaceCreateFlagsKHR::empty(),
+ window: window as *mut _,
+ ..Default::default()
+ };
+
+ let handle = {
+ let fns = instance.fns();
let mut output = MaybeUninit::uninit();
- check_errors(fns.khr_win32_surface.create_win32_surface_khr(
- instance.internal_object(),
- &infos,
+ (fns.khr_android_surface.create_android_surface_khr)(
+ instance.handle(),
+ &create_info,
ptr::null(),
output.as_mut_ptr(),
- ))?;
+ )
+ .result()
+ .map_err(VulkanError::from)?;
output.assume_init()
};
- Ok(Arc::new(Surface {
- window: win,
- instance: instance.clone(),
- surface,
- has_swapchain: AtomicBool::new(false),
- }))
+ Ok(Arc::new(Self::from_handle(
+ instance,
+ handle,
+ SurfaceApi::Android,
+ object,
+ )))
}
- /// Creates a `Surface` from an XCB window.
- ///
- /// The surface's min, max and current extent will always match the window's dimensions.
+ /// Creates a `Surface` from a DirectFB surface.
///
/// # Safety
///
- /// The caller must ensure that the `connection` and the `window` are both correct and stay
- /// alive for the entire lifetime of the surface. The `win` parameter can be used to ensure this.
- pub unsafe fn from_xcb<C>(
+ /// - `dfb` must be a valid DirectFB `IDirectFB` handle.
+ /// - `surface` must be a valid DirectFB `IDirectFBSurface` handle.
+ /// - The object referred to by `dfb` and `surface` must outlive the created `Surface`.
+ /// The `object` parameter can be used to ensure this.
+ pub unsafe fn from_directfb<D, S>(
instance: Arc<Instance>,
- connection: *const C,
- window: u32,
- win: W,
- ) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
- let fns = instance.fns();
+ dfb: *const D,
+ surface: *const S,
+ object: Option<Arc<dyn Any + Send + Sync>>,
+ ) -> Result<Arc<Self>, SurfaceCreationError> {
+ Self::validate_from_directfb(&instance, dfb, surface)?;
- if !instance.enabled_extensions().khr_xcb_surface {
- return Err(SurfaceCreationError::MissingExtension {
- name: "VK_KHR_xcb_surface",
+ Ok(Self::from_directfb_unchecked(
+ instance, dfb, surface, object,
+ )?)
+ }
+
+ fn validate_from_directfb<D, S>(
+ instance: &Instance,
+ _dfb: *const D,
+ _surface: *const S,
+ ) -> Result<(), SurfaceCreationError> {
+ if !instance.enabled_extensions().ext_directfb_surface {
+ return Err(SurfaceCreationError::RequirementNotMet {
+ required_for: "`Surface::from_directfb`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["ext_directfb_surface"],
+ ..Default::default()
+ },
});
}
- let surface = {
- let infos = ash::vk::XcbSurfaceCreateInfoKHR {
- flags: ash::vk::XcbSurfaceCreateFlagsKHR::empty(),
- connection: connection as *mut _,
- window,
- ..Default::default()
- };
+ // VUID-VkDirectFBSurfaceCreateInfoEXT-dfb-04117
+ // Can't validate, therefore unsafe
+
+ // VUID-VkDirectFBSurfaceCreateInfoEXT-surface-04118
+ // Can't validate, therefore unsafe
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn from_directfb_unchecked<D, S>(
+ instance: Arc<Instance>,
+ dfb: *const D,
+ surface: *const S,
+ object: Option<Arc<dyn Any + Send + Sync>>,
+ ) -> Result<Arc<Self>, VulkanError> {
+ let create_info = ash::vk::DirectFBSurfaceCreateInfoEXT {
+ flags: ash::vk::DirectFBSurfaceCreateFlagsEXT::empty(),
+ dfb: dfb as *mut _,
+ surface: surface as *mut _,
+ ..Default::default()
+ };
+ let handle = {
+ let fns = instance.fns();
let mut output = MaybeUninit::uninit();
- check_errors(fns.khr_xcb_surface.create_xcb_surface_khr(
- instance.internal_object(),
- &infos,
+ (fns.ext_directfb_surface.create_direct_fb_surface_ext)(
+ instance.handle(),
+ &create_info,
ptr::null(),
output.as_mut_ptr(),
- ))?;
+ )
+ .result()
+ .map_err(VulkanError::from)?;
output.assume_init()
};
- Ok(Arc::new(Surface {
- window: win,
- instance: instance.clone(),
- surface,
- has_swapchain: AtomicBool::new(false),
- }))
+ Ok(Arc::new(Self::from_handle(
+ instance,
+ handle,
+ SurfaceApi::DirectFB,
+ object,
+ )))
}
- /// Creates a `Surface` from an Xlib window.
- ///
- /// The surface's min, max and current extent will always match the window's dimensions.
+ /// Creates a `Surface` from an Fuchsia ImagePipe.
///
/// # Safety
///
- /// The caller must ensure that the `display` and the `window` are both correct and stay
- /// alive for the entire lifetime of the surface. The `win` parameter can be used to ensure this.
- pub unsafe fn from_xlib<D>(
+ /// - `image_pipe_handle` must be a valid Fuchsia `zx_handle_t` handle.
+ /// - The object referred to by `image_pipe_handle` must outlive the created `Surface`.
+ /// The `object` parameter can be used to ensure this.
+ pub unsafe fn from_fuchsia_image_pipe(
instance: Arc<Instance>,
- display: *const D,
- window: c_ulong,
- win: W,
- ) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
- let fns = instance.fns();
+ image_pipe_handle: ash::vk::zx_handle_t,
+ object: Option<Arc<dyn Any + Send + Sync>>,
+ ) -> Result<Arc<Self>, SurfaceCreationError> {
+ Self::validate_from_fuchsia_image_pipe(&instance, image_pipe_handle)?;
- if !instance.enabled_extensions().khr_xlib_surface {
- return Err(SurfaceCreationError::MissingExtension {
- name: "VK_KHR_xlib_surface",
+ Ok(Self::from_fuchsia_image_pipe_unchecked(
+ instance,
+ image_pipe_handle,
+ object,
+ )?)
+ }
+
+ fn validate_from_fuchsia_image_pipe(
+ instance: &Instance,
+ _image_pipe_handle: ash::vk::zx_handle_t,
+ ) -> Result<(), SurfaceCreationError> {
+ if !instance.enabled_extensions().fuchsia_imagepipe_surface {
+ return Err(SurfaceCreationError::RequirementNotMet {
+ required_for: "`Surface::from_fuchsia_image_pipe`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["fuchsia_imagepipe_surface"],
+ ..Default::default()
+ },
});
}
- let surface = {
- let infos = ash::vk::XlibSurfaceCreateInfoKHR {
- flags: ash::vk::XlibSurfaceCreateFlagsKHR::empty(),
- dpy: display as *mut _,
- window,
- ..Default::default()
- };
+ // VUID-VkImagePipeSurfaceCreateInfoFUCHSIA-imagePipeHandle-04863
+ // Can't validate, therefore unsafe
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn from_fuchsia_image_pipe_unchecked(
+ instance: Arc<Instance>,
+ image_pipe_handle: ash::vk::zx_handle_t,
+ object: Option<Arc<dyn Any + Send + Sync>>,
+ ) -> Result<Arc<Self>, VulkanError> {
+ let create_info = ash::vk::ImagePipeSurfaceCreateInfoFUCHSIA {
+ flags: ash::vk::ImagePipeSurfaceCreateFlagsFUCHSIA::empty(),
+ image_pipe_handle,
+ ..Default::default()
+ };
+
+ let handle = {
+ let fns = instance.fns();
let mut output = MaybeUninit::uninit();
- check_errors(fns.khr_xlib_surface.create_xlib_surface_khr(
- instance.internal_object(),
- &infos,
+ (fns.fuchsia_imagepipe_surface
+ .create_image_pipe_surface_fuchsia)(
+ instance.handle(),
+ &create_info,
ptr::null(),
output.as_mut_ptr(),
- ))?;
+ )
+ .result()
+ .map_err(VulkanError::from)?;
output.assume_init()
};
- Ok(Arc::new(Surface {
- window: win,
- instance: instance.clone(),
- surface,
- has_swapchain: AtomicBool::new(false),
- }))
+ Ok(Arc::new(Self::from_handle(
+ instance,
+ handle,
+ SurfaceApi::FuchsiaImagePipe,
+ object,
+ )))
}
- /// Creates a `Surface` from a Wayland window.
+ /// Creates a `Surface` from a Google Games Platform stream descriptor.
///
- /// The window's dimensions will be set to the size of the swapchain.
+ /// # Safety
+ ///
+ /// - `stream_descriptor` must be a valid Google Games Platform `GgpStreamDescriptor` handle.
+ /// - The object referred to by `stream_descriptor` must outlive the created `Surface`.
+ /// The `object` parameter can be used to ensure this.
+ pub unsafe fn from_ggp_stream_descriptor(
+ instance: Arc<Instance>,
+ stream_descriptor: ash::vk::GgpStreamDescriptor,
+ object: Option<Arc<dyn Any + Send + Sync>>,
+ ) -> Result<Arc<Self>, SurfaceCreationError> {
+ Self::validate_from_ggp_stream_descriptor(&instance, stream_descriptor)?;
+
+ Ok(Self::from_ggp_stream_descriptor_unchecked(
+ instance,
+ stream_descriptor,
+ object,
+ )?)
+ }
+
+ fn validate_from_ggp_stream_descriptor(
+ instance: &Instance,
+ _stream_descriptor: ash::vk::GgpStreamDescriptor,
+ ) -> Result<(), SurfaceCreationError> {
+ if !instance.enabled_extensions().ggp_stream_descriptor_surface {
+ return Err(SurfaceCreationError::RequirementNotMet {
+ required_for: "`Surface::from_ggp_stream_descriptor`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["ggp_stream_descriptor_surface"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkStreamDescriptorSurfaceCreateInfoGGP-streamDescriptor-02681
+ // Can't validate, therefore unsafe
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn from_ggp_stream_descriptor_unchecked(
+ instance: Arc<Instance>,
+ stream_descriptor: ash::vk::GgpStreamDescriptor,
+ object: Option<Arc<dyn Any + Send + Sync>>,
+ ) -> Result<Arc<Self>, VulkanError> {
+ let create_info = ash::vk::StreamDescriptorSurfaceCreateInfoGGP {
+ flags: ash::vk::StreamDescriptorSurfaceCreateFlagsGGP::empty(),
+ stream_descriptor,
+ ..Default::default()
+ };
+
+ let handle = {
+ let fns = instance.fns();
+ let mut output = MaybeUninit::uninit();
+ (fns.ggp_stream_descriptor_surface
+ .create_stream_descriptor_surface_ggp)(
+ instance.handle(),
+ &create_info,
+ ptr::null(),
+ output.as_mut_ptr(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+ output.assume_init()
+ };
+
+ Ok(Arc::new(Self::from_handle(
+ instance,
+ handle,
+ SurfaceApi::GgpStreamDescriptor,
+ object,
+ )))
+ }
+
+ /// Creates a `Surface` from an iOS `UIView`.
///
/// # Safety
///
- /// The caller must ensure that the `display` and the `surface` are both correct and stay
- /// alive for the entire lifetime of the surface. The `win` parameter can be used to ensure this.
- pub unsafe fn from_wayland<D, S>(
+ /// - `metal_layer` must be a valid `IOSMetalLayer` handle.
+ /// - The object referred to by `metal_layer` must outlive the created `Surface`.
+ /// The `object` parameter can be used to ensure this.
+ /// - The `UIView` must be backed by a `CALayer` instance of type `CAMetalLayer`.
+ #[cfg(target_os = "ios")]
+ pub unsafe fn from_ios(
instance: Arc<Instance>,
- display: *const D,
- surface: *const S,
- win: W,
- ) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
- let fns = instance.fns();
+ metal_layer: IOSMetalLayer,
+ object: Option<Arc<dyn Any + Send + Sync>>,
+ ) -> Result<Arc<Self>, SurfaceCreationError> {
+ Self::validate_from_ios(&instance, &metal_layer)?;
- if !instance.enabled_extensions().khr_wayland_surface {
- return Err(SurfaceCreationError::MissingExtension {
- name: "VK_KHR_wayland_surface",
+ Ok(Self::from_ios_unchecked(instance, metal_layer, object)?)
+ }
+
+ #[cfg(target_os = "ios")]
+ fn validate_from_ios(
+ instance: &Instance,
+ _metal_layer: &IOSMetalLayer,
+ ) -> Result<(), SurfaceCreationError> {
+ if !instance.enabled_extensions().mvk_ios_surface {
+ return Err(SurfaceCreationError::RequirementNotMet {
+ required_for: "`Surface::from_ios`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["mvk_ios_surface"],
+ ..Default::default()
+ },
});
}
- let surface = {
- let infos = ash::vk::WaylandSurfaceCreateInfoKHR {
- flags: ash::vk::WaylandSurfaceCreateFlagsKHR::empty(),
- display: display as *mut _,
- surface: surface as *mut _,
- ..Default::default()
- };
+ // VUID-VkIOSSurfaceCreateInfoMVK-pView-04143
+ // Can't validate, therefore unsafe
+
+ // VUID-VkIOSSurfaceCreateInfoMVK-pView-01316
+ // Can't validate, therefore unsafe
+
+ Ok(())
+ }
+
+ #[cfg(target_os = "ios")]
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn from_ios_unchecked(
+ instance: Arc<Instance>,
+ metal_layer: IOSMetalLayer,
+ object: Option<Arc<dyn Any + Send + Sync>>,
+ ) -> Result<Arc<Self>, VulkanError> {
+ let create_info = ash::vk::IOSSurfaceCreateInfoMVK {
+ flags: ash::vk::IOSSurfaceCreateFlagsMVK::empty(),
+ p_view: metal_layer.render_layer.0 as *const _,
+ ..Default::default()
+ };
+ let handle = {
+ let fns = instance.fns();
let mut output = MaybeUninit::uninit();
- check_errors(fns.khr_wayland_surface.create_wayland_surface_khr(
- instance.internal_object(),
- &infos,
+ (fns.mvk_ios_surface.create_ios_surface_mvk)(
+ instance.handle(),
+ &create_info,
ptr::null(),
output.as_mut_ptr(),
- ))?;
+ )
+ .result()
+ .map_err(VulkanError::from)?;
output.assume_init()
};
- Ok(Arc::new(Surface {
- window: win,
- instance: instance.clone(),
- surface,
- has_swapchain: AtomicBool::new(false),
- }))
+ Ok(Arc::new(Self::from_handle(
+ instance,
+ handle,
+ SurfaceApi::Ios,
+ object,
+ )))
}
- /// Creates a `Surface` from an Android window.
+ /// Creates a `Surface` from a MacOS `NSView`.
///
/// # Safety
///
- /// The caller must ensure that the `window` is correct and stays alive for the entire
- /// lifetime of the surface. The `win` parameter can be used to ensure this.
- pub unsafe fn from_anativewindow<T>(
+ /// - `view` must be a valid `CAMetalLayer` or `NSView` handle.
+ /// - The object referred to by `view` must outlive the created `Surface`.
+ /// The `object` parameter can be used to ensure this.
+ /// - The `NSView` must be backed by a `CALayer` instance of type `CAMetalLayer`.
+ #[cfg(target_os = "macos")]
+ pub unsafe fn from_mac_os<V>(
instance: Arc<Instance>,
- window: *const T,
- win: W,
- ) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
- let fns = instance.fns();
+ view: *const V,
+ object: Option<Arc<dyn Any + Send + Sync>>,
+ ) -> Result<Arc<Self>, SurfaceCreationError> {
+ Self::validate_from_mac_os(&instance, view)?;
- if !instance.enabled_extensions().khr_android_surface {
- return Err(SurfaceCreationError::MissingExtension {
- name: "VK_KHR_android_surface",
+ Ok(Self::from_mac_os_unchecked(instance, view, object)?)
+ }
+
+ #[cfg(target_os = "macos")]
+ fn validate_from_mac_os<V>(
+ instance: &Instance,
+ _view: *const V,
+ ) -> Result<(), SurfaceCreationError> {
+ if !instance.enabled_extensions().mvk_macos_surface {
+ return Err(SurfaceCreationError::RequirementNotMet {
+ required_for: "`Surface::from_mac_os`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["mvk_macos_surface"],
+ ..Default::default()
+ },
});
}
- let surface = {
- let infos = ash::vk::AndroidSurfaceCreateInfoKHR {
- flags: ash::vk::AndroidSurfaceCreateFlagsKHR::empty(),
- window: window as *mut _,
- ..Default::default()
- };
+ // VUID-VkMacOSSurfaceCreateInfoMVK-pView-04144
+ // Can't validate, therefore unsafe
+
+ // VUID-VkMacOSSurfaceCreateInfoMVK-pView-01317
+ // Can't validate, therefore unsafe
+ Ok(())
+ }
+
+ #[cfg(target_os = "macos")]
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn from_mac_os_unchecked<V>(
+ instance: Arc<Instance>,
+ view: *const V,
+ object: Option<Arc<dyn Any + Send + Sync>>,
+ ) -> Result<Arc<Self>, VulkanError> {
+ let create_info = ash::vk::MacOSSurfaceCreateInfoMVK {
+ flags: ash::vk::MacOSSurfaceCreateFlagsMVK::empty(),
+ p_view: view as *const _,
+ ..Default::default()
+ };
+
+ let handle = {
+ let fns = instance.fns();
let mut output = MaybeUninit::uninit();
- check_errors(fns.khr_android_surface.create_android_surface_khr(
- instance.internal_object(),
- &infos,
+ (fns.mvk_macos_surface.create_mac_os_surface_mvk)(
+ instance.handle(),
+ &create_info,
ptr::null(),
output.as_mut_ptr(),
- ))?;
+ )
+ .result()
+ .map_err(VulkanError::from)?;
output.assume_init()
};
- Ok(Arc::new(Surface {
- window: win,
- instance: instance.clone(),
- surface,
- has_swapchain: AtomicBool::new(false),
- }))
+ Ok(Arc::new(Self::from_handle(
+ instance,
+ handle,
+ SurfaceApi::MacOs,
+ object,
+ )))
}
- /// Creates a `Surface` from an iOS `UIView`.
+ /// Creates a `Surface` from a Metal `CAMetalLayer`.
///
/// # Safety
///
- /// - The caller must ensure that the `view` is correct and stays alive for the entire
- /// lifetime of the surface. The win parameter can be used to ensure this.
- /// - The `UIView` must be backed by a `CALayer` instance of type `CAMetalLayer`.
- pub unsafe fn from_ios_moltenvk<T>(
+ /// - `layer` must be a valid Metal `CAMetalLayer` handle.
+ /// - The object referred to by `layer` must outlive the created `Surface`.
+ /// The `object` parameter can be used to ensure this.
+ pub unsafe fn from_metal<L>(
instance: Arc<Instance>,
- view: *const T,
- win: W,
- ) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
- let fns = instance.fns();
+ layer: *const L,
+ object: Option<Arc<dyn Any + Send + Sync>>,
+ ) -> Result<Arc<Self>, SurfaceCreationError> {
+ Self::validate_from_metal(&instance, layer)?;
- if !instance.enabled_extensions().mvk_ios_surface {
- return Err(SurfaceCreationError::MissingExtension {
- name: "VK_MVK_ios_surface",
+ Ok(Self::from_metal_unchecked(instance, layer, object)?)
+ }
+
+ fn validate_from_metal<L>(
+ instance: &Instance,
+ _layer: *const L,
+ ) -> Result<(), SurfaceCreationError> {
+ if !instance.enabled_extensions().ext_metal_surface {
+ return Err(SurfaceCreationError::RequirementNotMet {
+ required_for: "`Surface::from_metal`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["ext_metal_surface"],
+ ..Default::default()
+ },
});
}
- let surface = {
- let infos = ash::vk::IOSSurfaceCreateInfoMVK {
- flags: ash::vk::IOSSurfaceCreateFlagsMVK::empty(),
- p_view: view as *const _,
- ..Default::default()
- };
+ Ok(())
+ }
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn from_metal_unchecked<L>(
+ instance: Arc<Instance>,
+ layer: *const L,
+ object: Option<Arc<dyn Any + Send + Sync>>,
+ ) -> Result<Arc<Self>, VulkanError> {
+ let create_info = ash::vk::MetalSurfaceCreateInfoEXT {
+ flags: ash::vk::MetalSurfaceCreateFlagsEXT::empty(),
+ p_layer: layer as *const _,
+ ..Default::default()
+ };
+
+ let handle = {
+ let fns = instance.fns();
let mut output = MaybeUninit::uninit();
- check_errors(fns.mvk_ios_surface.create_ios_surface_mvk(
- instance.internal_object(),
- &infos,
+ (fns.ext_metal_surface.create_metal_surface_ext)(
+ instance.handle(),
+ &create_info,
ptr::null(),
output.as_mut_ptr(),
- ))?;
+ )
+ .result()
+ .map_err(VulkanError::from)?;
output.assume_init()
};
- Ok(Arc::new(Surface {
- window: win,
- instance: instance.clone(),
- surface,
- has_swapchain: AtomicBool::new(false),
- }))
+ Ok(Arc::new(Self::from_handle(
+ instance,
+ handle,
+ SurfaceApi::Metal,
+ object,
+ )))
}
- /// Creates a `Surface` from a MacOS `NSView`.
+ /// Creates a `Surface` from a QNX Screen window.
///
/// # Safety
///
- /// - The caller must ensure that the `view` is correct and stays alive for the entire
- /// lifetime of the surface. The `win` parameter can be used to ensure this.
- /// - The `NSView` must be backed by a `CALayer` instance of type `CAMetalLayer`.
- pub unsafe fn from_macos_moltenvk<T>(
+ /// - `context` must be a valid QNX Screen `_screen_context` handle.
+ /// - `window` must be a valid QNX Screen `_screen_window` handle.
+ /// - The object referred to by `window` must outlive the created `Surface`.
+ /// The `object` parameter can be used to ensure this.
+ pub unsafe fn from_qnx_screen<C, W>(
instance: Arc<Instance>,
- view: *const T,
- win: W,
- ) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
- let fns = instance.fns();
+ context: *const C,
+ window: *const W,
+ object: Option<Arc<dyn Any + Send + Sync>>,
+ ) -> Result<Arc<Self>, SurfaceCreationError> {
+ Self::validate_from_qnx_screen(&instance, context, window)?;
+
+ Ok(Self::from_qnx_screen_unchecked(
+ instance, context, window, object,
+ )?)
+ }
- if !instance.enabled_extensions().mvk_macos_surface {
- return Err(SurfaceCreationError::MissingExtension {
- name: "VK_MVK_macos_surface",
+ fn validate_from_qnx_screen<C, W>(
+ instance: &Instance,
+ _context: *const C,
+ _window: *const W,
+ ) -> Result<(), SurfaceCreationError> {
+ if !instance.enabled_extensions().qnx_screen_surface {
+ return Err(SurfaceCreationError::RequirementNotMet {
+ required_for: "`Surface::from_qnx_screen`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["qnx_screen_surface"],
+ ..Default::default()
+ },
});
}
- let surface = {
- let infos = ash::vk::MacOSSurfaceCreateInfoMVK {
- flags: ash::vk::MacOSSurfaceCreateFlagsMVK::empty(),
- p_view: view as *const _,
- ..Default::default()
- };
+ // VUID-VkScreenSurfaceCreateInfoQNX-context-04741
+ // Can't validate, therefore unsafe
+
+ // VUID-VkScreenSurfaceCreateInfoQNX-window-04742
+ // Can't validate, therefore unsafe
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn from_qnx_screen_unchecked<C, W>(
+ instance: Arc<Instance>,
+ context: *const C,
+ window: *const W,
+ object: Option<Arc<dyn Any + Send + Sync>>,
+ ) -> Result<Arc<Self>, VulkanError> {
+ let create_info = ash::vk::ScreenSurfaceCreateInfoQNX {
+ flags: ash::vk::ScreenSurfaceCreateFlagsQNX::empty(),
+ context: context as *mut _,
+ window: window as *mut _,
+ ..Default::default()
+ };
+ let handle = {
+ let fns = instance.fns();
let mut output = MaybeUninit::uninit();
- check_errors(fns.mvk_macos_surface.create_mac_os_surface_mvk(
- instance.internal_object(),
- &infos,
+ (fns.qnx_screen_surface.create_screen_surface_qnx)(
+ instance.handle(),
+ &create_info,
ptr::null(),
output.as_mut_ptr(),
- ))?;
+ )
+ .result()
+ .map_err(VulkanError::from)?;
output.assume_init()
};
- Ok(Arc::new(Surface {
- window: win,
- instance: instance.clone(),
- surface,
- has_swapchain: AtomicBool::new(false),
- }))
+ Ok(Arc::new(Self::from_handle(
+ instance,
+ handle,
+ SurfaceApi::Qnx,
+ object,
+ )))
}
/// Creates a `Surface` from a `code:nn::code:vi::code:Layer`.
///
/// # Safety
///
- /// The caller must ensure that the `window` is correct and stays alive for the entire
- /// lifetime of the surface. The `win` parameter can be used to ensure this.
- pub unsafe fn from_vi_surface<T>(
+ /// - `window` must be a valid `nn::vi::NativeWindowHandle` handle.
+ /// - The object referred to by `window` must outlive the created `Surface`.
+ /// The `object` parameter can be used to ensure this.
+ pub unsafe fn from_vi<W>(
instance: Arc<Instance>,
- window: *const T,
- win: W,
- ) -> Result<Arc<Surface<W>>, SurfaceCreationError> {
- let fns = instance.fns();
+ window: *const W,
+ object: Option<Arc<dyn Any + Send + Sync>>,
+ ) -> Result<Arc<Self>, SurfaceCreationError> {
+ Self::validate_from_vi(&instance, window)?;
+
+ Ok(Self::from_vi_unchecked(instance, window, object)?)
+ }
+ fn validate_from_vi<W>(
+ instance: &Instance,
+ _window: *const W,
+ ) -> Result<(), SurfaceCreationError> {
if !instance.enabled_extensions().nn_vi_surface {
- return Err(SurfaceCreationError::MissingExtension {
- name: "VK_NN_vi_surface",
+ return Err(SurfaceCreationError::RequirementNotMet {
+ required_for: "`Surface::from_vi`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["nn_vi_surface"],
+ ..Default::default()
+ },
});
}
- let surface = {
- let infos = ash::vk::ViSurfaceCreateInfoNN {
- flags: ash::vk::ViSurfaceCreateFlagsNN::empty(),
- window: window as *mut _,
- ..Default::default()
- };
+ // VUID-VkViSurfaceCreateInfoNN-window-01318
+ // Can't validate, therefore unsafe
+
+ Ok(())
+ }
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn from_vi_unchecked<W>(
+ instance: Arc<Instance>,
+ window: *const W,
+ object: Option<Arc<dyn Any + Send + Sync>>,
+ ) -> Result<Arc<Self>, VulkanError> {
+ let create_info = ash::vk::ViSurfaceCreateInfoNN {
+ flags: ash::vk::ViSurfaceCreateFlagsNN::empty(),
+ window: window as *mut _,
+ ..Default::default()
+ };
+
+ let handle = {
+ let fns = instance.fns();
let mut output = MaybeUninit::uninit();
- check_errors(fns.nn_vi_surface.create_vi_surface_nn(
- instance.internal_object(),
- &infos,
+ (fns.nn_vi_surface.create_vi_surface_nn)(
+ instance.handle(),
+ &create_info,
ptr::null(),
output.as_mut_ptr(),
- ))?;
+ )
+ .result()
+ .map_err(VulkanError::from)?;
output.assume_init()
};
- Ok(Arc::new(Surface {
- window: win,
- instance: instance.clone(),
- surface,
- has_swapchain: AtomicBool::new(false),
- }))
+ Ok(Arc::new(Self::from_handle(
+ instance,
+ handle,
+ SurfaceApi::Vi,
+ object,
+ )))
}
- /// Returns true if the given queue family can draw on this surface.
- // FIXME: vulkano doesn't check this for the moment!
- pub fn is_supported(&self, queue: QueueFamily) -> Result<bool, CapabilitiesError> {
- unsafe {
- let fns = self.instance.fns();
+ /// Creates a `Surface` from a Wayland window.
+ ///
+ /// The window's dimensions will be set to the size of the swapchain.
+ ///
+ /// # Safety
+ ///
+ /// - `display` must be a valid Wayland `wl_display` handle.
+ /// - `surface` must be a valid Wayland `wl_surface` handle.
+ /// - The objects referred to by `display` and `surface` must outlive the created `Surface`.
+ /// The `object` parameter can be used to ensure this.
+ pub unsafe fn from_wayland<D, S>(
+ instance: Arc<Instance>,
+ display: *const D,
+ surface: *const S,
+ object: Option<Arc<dyn Any + Send + Sync>>,
+ ) -> Result<Arc<Self>, SurfaceCreationError> {
+ Self::validate_from_wayland(&instance, display, surface)?;
+
+ Ok(Self::from_wayland_unchecked(
+ instance, display, surface, object,
+ )?)
+ }
+ fn validate_from_wayland<D, S>(
+ instance: &Instance,
+ _display: *const D,
+ _surface: *const S,
+ ) -> Result<(), SurfaceCreationError> {
+ if !instance.enabled_extensions().khr_wayland_surface {
+ return Err(SurfaceCreationError::RequirementNotMet {
+ required_for: "`Surface::from_wayland`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["khr_wayland_surface"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkWaylandSurfaceCreateInfoKHR-display-01304
+ // Can't validate, therefore unsafe
+
+ // VUID-VkWaylandSurfaceCreateInfoKHR-surface-01305
+ // Can't validate, therefore unsafe
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn from_wayland_unchecked<D, S>(
+ instance: Arc<Instance>,
+ display: *const D,
+ surface: *const S,
+ object: Option<Arc<dyn Any + Send + Sync>>,
+ ) -> Result<Arc<Self>, VulkanError> {
+ let create_info = ash::vk::WaylandSurfaceCreateInfoKHR {
+ flags: ash::vk::WaylandSurfaceCreateFlagsKHR::empty(),
+ display: display as *mut _,
+ surface: surface as *mut _,
+ ..Default::default()
+ };
+
+ let handle = {
+ let fns = instance.fns();
let mut output = MaybeUninit::uninit();
- check_errors(fns.khr_surface.get_physical_device_surface_support_khr(
- queue.physical_device().internal_object(),
- queue.id(),
- self.surface,
+ (fns.khr_wayland_surface.create_wayland_surface_khr)(
+ instance.handle(),
+ &create_info,
+ ptr::null(),
output.as_mut_ptr(),
- ))?;
- Ok(output.assume_init() != 0)
- }
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+ output.assume_init()
+ };
+
+ Ok(Arc::new(Self::from_handle(
+ instance,
+ handle,
+ SurfaceApi::Wayland,
+ object,
+ )))
}
- /// Retrieves the capabilities of a surface when used by a certain device.
+ /// Creates a `Surface` from a Win32 window.
///
- /// # Notes
+ /// The surface's min, max and current extent will always match the window's dimensions.
///
- /// - Capabilities that are not supported in `vk-sys` are silently dropped
+ /// # Safety
///
- /// # Panic
+ /// - `hinstance` must be a valid Win32 `HINSTANCE` handle.
+ /// - `hwnd` must be a valid Win32 `HWND` handle.
+ /// - The objects referred to by `hwnd` and `hinstance` must outlive the created `Surface`.
+ /// The `object` parameter can be used to ensure this.
+ pub unsafe fn from_win32<I, W>(
+ instance: Arc<Instance>,
+ hinstance: *const I,
+ hwnd: *const W,
+ object: Option<Arc<dyn Any + Send + Sync>>,
+ ) -> Result<Arc<Self>, SurfaceCreationError> {
+ Self::validate_from_win32(&instance, hinstance, hwnd)?;
+
+ Ok(Self::from_win32_unchecked(
+ instance, hinstance, hwnd, object,
+ )?)
+ }
+
+ fn validate_from_win32<I, W>(
+ instance: &Instance,
+ _hinstance: *const I,
+ _hwnd: *const W,
+ ) -> Result<(), SurfaceCreationError> {
+ if !instance.enabled_extensions().khr_win32_surface {
+ return Err(SurfaceCreationError::RequirementNotMet {
+ required_for: "`Surface::from_win32`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["khr_win32_surface"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkWin32SurfaceCreateInfoKHR-hinstance-01307
+ // Can't validate, therefore unsafe
+
+ // VUID-VkWin32SurfaceCreateInfoKHR-hwnd-01308
+ // Can't validate, therefore unsafe
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn from_win32_unchecked<I, W>(
+ instance: Arc<Instance>,
+ hinstance: *const I,
+ hwnd: *const W,
+ object: Option<Arc<dyn Any + Send + Sync>>,
+ ) -> Result<Arc<Self>, VulkanError> {
+ let create_info = ash::vk::Win32SurfaceCreateInfoKHR {
+ flags: ash::vk::Win32SurfaceCreateFlagsKHR::empty(),
+ hinstance: hinstance as *mut _,
+ hwnd: hwnd as *mut _,
+ ..Default::default()
+ };
+
+ let handle = {
+ let fns = instance.fns();
+ let mut output = MaybeUninit::uninit();
+ (fns.khr_win32_surface.create_win32_surface_khr)(
+ instance.handle(),
+ &create_info,
+ ptr::null(),
+ output.as_mut_ptr(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+ output.assume_init()
+ };
+
+ Ok(Arc::new(Self::from_handle(
+ instance,
+ handle,
+ SurfaceApi::Win32,
+ object,
+ )))
+ }
+
+ /// Creates a `Surface` from an XCB window.
///
- /// - Panics if the device and the surface don't belong to the same instance.
+ /// The surface's min, max and current extent will always match the window's dimensions.
///
- pub fn capabilities(&self, device: PhysicalDevice) -> Result<Capabilities, CapabilitiesError> {
- unsafe {
- assert_eq!(
- &*self.instance as *const _,
- &**device.instance() as *const _,
- "Instance mismatch in Surface::capabilities"
- );
-
- let fns = self.instance.fns();
+ /// # Safety
+ ///
+ /// - `connection` must be a valid X11 `xcb_connection_t` handle.
+ /// - `window` must be a valid X11 `xcb_window_t` handle.
+ /// - The objects referred to by `connection` and `window` must outlive the created `Surface`.
+ /// The `object` parameter can be used to ensure this.
+ pub unsafe fn from_xcb<C>(
+ instance: Arc<Instance>,
+ connection: *const C,
+ window: ash::vk::xcb_window_t,
+ object: Option<Arc<dyn Any + Send + Sync>>,
+ ) -> Result<Arc<Self>, SurfaceCreationError> {
+ Self::validate_from_xcb(&instance, connection, window)?;
+
+ Ok(Self::from_xcb_unchecked(
+ instance, connection, window, object,
+ )?)
+ }
- let caps = {
- let mut out: MaybeUninit<ash::vk::SurfaceCapabilitiesKHR> = MaybeUninit::uninit();
- check_errors(
- fns.khr_surface
- .get_physical_device_surface_capabilities_khr(
- device.internal_object(),
- self.surface,
- out.as_mut_ptr(),
- ),
- )?;
- out.assume_init()
- };
-
- let formats = {
- let mut num = 0;
- check_errors(fns.khr_surface.get_physical_device_surface_formats_khr(
- device.internal_object(),
- self.surface,
- &mut num,
- ptr::null_mut(),
- ))?;
-
- let mut formats = Vec::with_capacity(num as usize);
- check_errors(fns.khr_surface.get_physical_device_surface_formats_khr(
- device.internal_object(),
- self.surface,
- &mut num,
- formats.as_mut_ptr(),
- ))?;
- formats.set_len(num as usize);
- formats
- };
-
- let modes = {
- let mut num = 0;
- check_errors(
- fns.khr_surface
- .get_physical_device_surface_present_modes_khr(
- device.internal_object(),
- self.surface,
- &mut num,
- ptr::null_mut(),
- ),
- )?;
-
- let mut modes = Vec::with_capacity(num as usize);
- check_errors(
- fns.khr_surface
- .get_physical_device_surface_present_modes_khr(
- device.internal_object(),
- self.surface,
- &mut num,
- modes.as_mut_ptr(),
- ),
- )?;
- modes.set_len(num as usize);
- debug_assert!(modes
- .iter()
- .find(|&&m| m == ash::vk::PresentModeKHR::FIFO)
- .is_some());
- debug_assert!(modes.iter().count() > 0);
- modes.into_iter().collect()
- };
-
- Ok(Capabilities {
- min_image_count: caps.min_image_count,
- max_image_count: if caps.max_image_count == 0 {
- None
- } else {
- Some(caps.max_image_count)
- },
- current_extent: if caps.current_extent.width == 0xffffffff
- && caps.current_extent.height == 0xffffffff
- {
- None
- } else {
- Some([caps.current_extent.width, caps.current_extent.height])
+ fn validate_from_xcb<C>(
+ instance: &Instance,
+ _connection: *const C,
+ _window: ash::vk::xcb_window_t,
+ ) -> Result<(), SurfaceCreationError> {
+ if !instance.enabled_extensions().khr_xcb_surface {
+ return Err(SurfaceCreationError::RequirementNotMet {
+ required_for: "`Surface::from_xcb`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["khr_xcb_surface"],
+ ..Default::default()
},
- min_image_extent: [caps.min_image_extent.width, caps.min_image_extent.height],
- max_image_extent: [caps.max_image_extent.width, caps.max_image_extent.height],
- max_image_array_layers: caps.max_image_array_layers,
- supported_transforms: caps.supported_transforms.into(),
-
- current_transform: SupportedSurfaceTransforms::from(caps.current_transform)
- .iter()
- .next()
- .unwrap(), // TODO:
- supported_composite_alpha: caps.supported_composite_alpha.into(),
- supported_usage_flags: {
- let usage = ImageUsage::from(caps.supported_usage_flags);
- debug_assert!(usage.color_attachment); // specs say that this must be true
- usage
+ });
+ }
+
+ // VUID-VkXcbSurfaceCreateInfoKHR-connection-01310
+ // Can't validate, therefore unsafe
+
+ // VUID-VkXcbSurfaceCreateInfoKHR-window-01311
+ // Can't validate, therefore unsafe
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn from_xcb_unchecked<C>(
+ instance: Arc<Instance>,
+ connection: *const C,
+ window: ash::vk::xcb_window_t,
+ object: Option<Arc<dyn Any + Send + Sync>>,
+ ) -> Result<Arc<Self>, VulkanError> {
+ let create_info = ash::vk::XcbSurfaceCreateInfoKHR {
+ flags: ash::vk::XcbSurfaceCreateFlagsKHR::empty(),
+ connection: connection as *mut _,
+ window,
+ ..Default::default()
+ };
+
+ let handle = {
+ let fns = instance.fns();
+ let mut output = MaybeUninit::uninit();
+ (fns.khr_xcb_surface.create_xcb_surface_khr)(
+ instance.handle(),
+ &create_info,
+ ptr::null(),
+ output.as_mut_ptr(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+ output.assume_init()
+ };
+
+ Ok(Arc::new(Self::from_handle(
+ instance,
+ handle,
+ SurfaceApi::Xcb,
+ object,
+ )))
+ }
+
+ /// Creates a `Surface` from an Xlib window.
+ ///
+ /// The surface's min, max and current extent will always match the window's dimensions.
+ ///
+ /// # Safety
+ ///
+ /// - `display` must be a valid Xlib `Display` handle.
+ /// - `window` must be a valid Xlib `Window` handle.
+ /// - The objects referred to by `display` and `window` must outlive the created `Surface`.
+ /// The `object` parameter can be used to ensure this.
+ pub unsafe fn from_xlib<D>(
+ instance: Arc<Instance>,
+ display: *const D,
+ window: ash::vk::Window,
+ object: Option<Arc<dyn Any + Send + Sync>>,
+ ) -> Result<Arc<Self>, SurfaceCreationError> {
+ Self::validate_from_xlib(&instance, display, window)?;
+
+ Ok(Self::from_xlib_unchecked(
+ instance, display, window, object,
+ )?)
+ }
+
+ fn validate_from_xlib<D>(
+ instance: &Instance,
+ _display: *const D,
+ _window: ash::vk::Window,
+ ) -> Result<(), SurfaceCreationError> {
+ if !instance.enabled_extensions().khr_xlib_surface {
+ return Err(SurfaceCreationError::RequirementNotMet {
+ required_for: "`Surface::from_xlib`",
+ requires_one_of: RequiresOneOf {
+ instance_extensions: &["khr_xlib_surface"],
+ ..Default::default()
},
- supported_formats: formats
- .into_iter()
- .filter_map(|f| {
- // TODO: Change the way capabilities not supported in vk-sys are handled
- Format::try_from(f.format)
- .ok()
- .map(|format| (format, f.color_space.into()))
- })
- .collect(),
- present_modes: modes,
- })
+ });
}
+
+ // VUID-VkXlibSurfaceCreateInfoKHR-dpy-01313
+ // Can't validate, therefore unsafe
+
+ // VUID-VkXlibSurfaceCreateInfoKHR-window-01314
+ // Can't validate, therefore unsafe
+
+ Ok(())
}
- #[inline]
- pub fn window(&self) -> &W {
- &self.window
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn from_xlib_unchecked<D>(
+ instance: Arc<Instance>,
+ display: *const D,
+ window: ash::vk::Window,
+ object: Option<Arc<dyn Any + Send + Sync>>,
+ ) -> Result<Arc<Self>, VulkanError> {
+ let create_info = ash::vk::XlibSurfaceCreateInfoKHR {
+ flags: ash::vk::XlibSurfaceCreateFlagsKHR::empty(),
+ dpy: display as *mut _,
+ window,
+ ..Default::default()
+ };
+
+ let handle = {
+ let fns = instance.fns();
+ let mut output = MaybeUninit::uninit();
+ (fns.khr_xlib_surface.create_xlib_surface_khr)(
+ instance.handle(),
+ &create_info,
+ ptr::null(),
+ output.as_mut_ptr(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+ output.assume_init()
+ };
+
+ Ok(Arc::new(Self::from_handle(
+ instance,
+ handle,
+ SurfaceApi::Xlib,
+ object,
+ )))
}
/// Returns the instance this surface was created with.
@@ -653,167 +1253,622 @@ impl<W> Surface<W> {
pub fn instance(&self) -> &Arc<Instance> {
&self.instance
}
-}
-unsafe impl<W> SurfaceSwapchainLock for Surface<W> {
+ /// Returns the windowing API that was used to construct the surface.
#[inline]
- fn flag(&self) -> &AtomicBool {
- &self.has_swapchain
+ pub fn api(&self) -> SurfaceApi {
+ self.api
}
-}
-
-unsafe impl<W> VulkanObject for Surface<W> {
- type Object = ash::vk::SurfaceKHR;
+ /// Returns a reference to the `object` parameter that was passed when creating the
+ /// surface.
#[inline]
- fn internal_object(&self) -> ash::vk::SurfaceKHR {
- self.surface
+ pub fn object(&self) -> Option<&Arc<dyn Any + Send + Sync>> {
+ self.object.as_ref()
}
-}
-impl<W> fmt::Debug for Surface<W> {
+ /// Resizes the sublayer bounds on iOS.
+ /// It may not be necessary if original window size matches device's, but often it does not.
+ /// Thus this should be called after a resize has occurred abd swapchain has been recreated.
+ ///
+ /// On iOS, we've created CAMetalLayer as a sublayer. However, when the view changes size,
+ /// its sublayers are not automatically resized, and we must resize
+ /// it here.
+ #[cfg(target_os = "ios")]
#[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(fmt, "<Vulkan surface {:?}>", self.surface)
+ pub unsafe fn update_ios_sublayer_on_resize(&self) {
+ use core_graphics_types::geometry::CGRect;
+ let class = class!(CAMetalLayer);
+ let main_layer: *mut Object = self.metal_layer.main_layer.0;
+ let bounds: CGRect = msg_send![main_layer, bounds];
+ let render_layer: *mut Object = self.metal_layer.render_layer.0;
+ let () = msg_send![render_layer, setFrame: bounds];
}
}
-impl<W> Drop for Surface<W> {
+impl Drop for Surface {
#[inline]
fn drop(&mut self) {
unsafe {
let fns = self.instance.fns();
- fns.khr_surface.destroy_surface_khr(
- self.instance.internal_object(),
- self.surface,
- ptr::null(),
- );
+ (fns.khr_surface.destroy_surface_khr)(self.instance.handle(), self.handle, ptr::null());
}
}
}
+unsafe impl VulkanObject for Surface {
+ type Handle = ash::vk::SurfaceKHR;
+
+ #[inline]
+ fn handle(&self) -> Self::Handle {
+ self.handle
+ }
+}
+
+impl_id_counter!(Surface);
+
+impl Debug for Surface {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ let Self {
+ handle,
+ instance,
+ api,
+ object: _,
+ has_swapchain,
+ ..
+ } = self;
+
+ f.debug_struct("Surface")
+ .field("handle", handle)
+ .field("instance", instance)
+ .field("api", api)
+ .field("window", &())
+ .field("has_swapchain", &has_swapchain)
+ .finish()
+ }
+}
+
+unsafe impl SurfaceSwapchainLock for Surface {
+ #[inline]
+ fn flag(&self) -> &AtomicBool {
+ &self.has_swapchain
+ }
+}
+
/// Error that can happen when creating a debug callback.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum SurfaceCreationError {
/// Not enough memory.
OomError(OomError),
- /// The extension required for this function was not enabled.
- MissingExtension {
- /// Name of the missing extension.
- name: &'static str,
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
},
}
-impl error::Error for SurfaceCreationError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- SurfaceCreationError::OomError(ref err) => Some(err),
+impl Error for SurfaceCreationError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ SurfaceCreationError::OomError(err) => Some(err),
_ => None,
}
}
}
-impl fmt::Display for SurfaceCreationError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- SurfaceCreationError::OomError(_) => "not enough memory available",
- SurfaceCreationError::MissingExtension { .. } => {
- "the extension required for this function was not enabled"
- }
- }
- )
+impl Display for SurfaceCreationError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::OomError(_) => write!(f, "not enough memory available"),
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ }
}
}
impl From<OomError> for SurfaceCreationError {
- #[inline]
fn from(err: OomError) -> SurfaceCreationError {
SurfaceCreationError::OomError(err)
}
}
-impl From<Error> for SurfaceCreationError {
- #[inline]
- fn from(err: Error) -> SurfaceCreationError {
+impl From<VulkanError> for SurfaceCreationError {
+ fn from(err: VulkanError) -> SurfaceCreationError {
match err {
- err @ Error::OutOfHostMemory => SurfaceCreationError::OomError(OomError::from(err)),
- err @ Error::OutOfDeviceMemory => SurfaceCreationError::OomError(OomError::from(err)),
+ err @ VulkanError::OutOfHostMemory => {
+ SurfaceCreationError::OomError(OomError::from(err))
+ }
+ err @ VulkanError::OutOfDeviceMemory => {
+ SurfaceCreationError::OomError(OomError::from(err))
+ }
_ => panic!("unexpected error: {:?}", err),
}
}
}
-/// Error that can happen when retrieving a surface's capabilities.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-#[repr(u32)]
-pub enum CapabilitiesError {
- /// Not enough memory.
- OomError(OomError),
+/// The windowing API that was used to construct a surface.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+#[non_exhaustive]
+pub enum SurfaceApi {
+ Headless,
+ DisplayPlane,
+
+ // Alphabetical order
+ Android,
+ DirectFB,
+ FuchsiaImagePipe,
+ GgpStreamDescriptor,
+ Ios,
+ MacOs,
+ Metal,
+ Qnx,
+ Vi,
+ Wayland,
+ Win32,
+ Xcb,
+ Xlib,
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// The mode of action when a swapchain image is presented.
+ ///
+ /// Swapchain images can be in one of three possible states:
+ /// - Exactly one image is currently displayed on the screen.
+ /// - Zero or more are acquired by the application, or available to be acquired.
+ /// - Some may be held inside the presentation engine waiting to be displayed. The present mode
+ /// concerns the behaviour of this category, and by extension, which images are left over for
+ /// acquiring.
+ ///
+ /// The present mode affects what is commonly known as "vertical sync" or "vsync" for short.
+ /// The `Immediate` mode is equivalent to disabling vertical sync, while the others enable
+ /// vertical sync in various forms. An important aspect of the present modes is their potential
+ /// *latency*: the time between when an image is presented, and when it actually appears on
+ /// the display.
+ ///
+ /// Only `Fifo` is guaranteed to be supported on every device. For the others, you must call
+ /// [`surface_present_modes`] to see if they are supported.
+ ///
+ /// [`surface_present_modes`]: crate::device::physical::PhysicalDevice::surface_present_modes
+ PresentMode = PresentModeKHR(i32);
- /// The surface is no longer accessible and must be recreated.
- SurfaceLost,
+ /// The presentation engine holds only the currently displayed image. When presenting an image,
+ /// the currently displayed image is immediately replaced with the presented image. The old
+ /// image will be available for future acquire operations.
+ ///
+ /// This mode has the lowest latency of all present modes, but if the display is not in a
+ /// vertical blanking period when the image is replaced, a tear will be visible.
+ Immediate = IMMEDIATE,
+
+ /// The presentation engine holds the currently displayed image, and optionally another in a
+ /// waiting slot. The presentation engine waits until the next vertical blanking period, then
+ /// removes any image from the waiting slot and displays it. Tearing will never be visible.
+ /// When presenting an image, it is stored in the waiting slot. Any previous entry
+ /// in the slot is discarded, and will be available for future acquire operations.
+ ///
+ /// Latency is relatively low with this mode, and will never be longer than the time between
+ /// vertical blanking periods. However, if a previous image in the waiting slot is discarded,
+ /// the work that went into producing that image was wasted.
+ ///
+ /// With two swapchain images, this mode behaves essentially identical to `Fifo`: once both
+ /// images are held in the presentation engine, no images can be acquired until one is finished
+ /// displaying. But with three or more swapchain images, any images beyond those two are always
+ /// available to acquire.
+ Mailbox = MAILBOX,
+
+ /// The presentation engine holds the currently displayed image, and a queue of waiting images.
+ /// When presenting an image, it is added to the tail of the queue, after previously presented
+ /// images. The presentation engine waits until the next vertical blanking period, then removes
+ /// an image from the head of the queue and displays it. Tearing will never be visible. Images
+ /// become available for future acquire operations only after they have been displayed.
+ ///
+ /// This mode is guaranteed to be always supported. It is possible for all swapchain images to
+ /// end up being held by the presentation engine, either being displayed or in the queue. When
+ /// that happens, no images can be acquired until one is finished displaying. This can be used
+ /// to limit the presentation rate to the display frame rate. Latency is bounded only by the
+ /// number of images in the swapchain.
+ ///
+ /// This is the equivalent of OpenGL's `SwapInterval` with a value of 1.
+ Fifo = FIFO,
+
+ /// Similar to `Fifo`, but with the ability for images to "skip the queue" if presentation is
+ /// lagging behind the display frame rate. If the queue is empty and a vertical blanking period
+ /// has already passed since the previous image was displayed, then the currently displayed
+ /// image is immediately replaced with the presented image, as in `Immediate`.
+ ///
+ /// This mode has high latency if images are presented faster than the display frame rate,
+ /// as they will accumulate in the queue. But the latency is low if images are presented slower
+ /// than the display frame rate. However, slower presentation can result in visible tearing.
+ ///
+ /// This is the equivalent of OpenGL's `SwapInterval` with a value of -1.
+ FifoRelaxed = FIFO_RELAXED,
+
+ /* TODO: enable
+ // TODO: document
+ SharedDemandRefresh = SHARED_DEMAND_REFRESH_KHR {
+ device_extensions: [khr_shared_presentable_image],
+ },*/
+
+ /* TODO: enable
+ // TODO: document
+ SharedContinuousRefresh = SHARED_CONTINUOUS_REFRESH_KHR {
+ device_extensions: [khr_shared_presentable_image],
+ },*/
}
-impl error::Error for CapabilitiesError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- CapabilitiesError::OomError(ref err) => Some(err),
- _ => None,
- }
- }
+vulkan_bitflags_enum! {
+ #[non_exhaustive]
+
+ /// A set of [`SurfaceTransform`] values.
+ SurfaceTransforms,
+
+ /// The presentation transform to apply when presenting a swapchain image to a surface.
+ SurfaceTransform,
+
+ = SurfaceTransformFlagsKHR(u32);
+
+ /// Don't transform the image.
+ IDENTITY, Identity = IDENTITY,
+
+ /// Rotate 90 degrees.
+ ROTATE_90, Rotate90 = ROTATE_90,
+
+ /// Rotate 180 degrees.
+ ROTATE_180, Rotate180 = ROTATE_180,
+
+ /// Rotate 270 degrees.
+ ROTATE_270, Rotate270 = ROTATE_270,
+
+ /// Mirror the image horizontally.
+ HORIZONTAL_MIRROR, HorizontalMirror = HORIZONTAL_MIRROR,
+
+ /// Mirror the image horizontally and rotate 90 degrees.
+ HORIZONTAL_MIRROR_ROTATE_90, HorizontalMirrorRotate90 = HORIZONTAL_MIRROR_ROTATE_90,
+
+ /// Mirror the image horizontally and rotate 180 degrees.
+ HORIZONTAL_MIRROR_ROTATE_180, HorizontalMirrorRotate180 = HORIZONTAL_MIRROR_ROTATE_180,
+
+ /// Mirror the image horizontally and rotate 270 degrees.
+ HORIZONTAL_MIRROR_ROTATE_270, HorizontalMirrorRotate270 = HORIZONTAL_MIRROR_ROTATE_270,
+
+ /// Let the operating system or driver implementation choose.
+ INHERIT, Inherit = INHERIT,
}
-impl fmt::Display for CapabilitiesError {
+impl Default for SurfaceTransform {
#[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- CapabilitiesError::OomError(_) => "not enough memory",
- CapabilitiesError::SurfaceLost => "the surface is no longer valid",
- }
- )
+ fn default() -> SurfaceTransform {
+ SurfaceTransform::Identity
}
}
-impl From<OomError> for CapabilitiesError {
+vulkan_bitflags_enum! {
+ #[non_exhaustive]
+
+ /// A set of [`CompositeAlpha`] values.
+ CompositeAlphas,
+
+ /// How the alpha values of the pixels of the window are treated.
+ CompositeAlpha,
+
+ = CompositeAlphaFlagsKHR(u32);
+
+ /// The alpha channel of the image is ignored. All the pixels are considered as if they have a
+ /// value of 1.0.
+ OPAQUE, Opaque = OPAQUE,
+
+ /// The alpha channel of the image is respected. The color channels are expected to have
+ /// already been multiplied by the alpha value.
+ PRE_MULTIPLIED, PreMultiplied = PRE_MULTIPLIED,
+
+ /// The alpha channel of the image is respected. The color channels will be multiplied by the
+ /// alpha value by the compositor before being added to what is behind.
+ POST_MULTIPLIED, PostMultiplied = POST_MULTIPLIED,
+
+ /// Let the operating system or driver implementation choose.
+ INHERIT, Inherit = INHERIT,
+}
+
+vulkan_enum! {
+ #[non_exhaustive]
+
+ /// How the presentation engine should interpret the data.
+ ///
+ /// # A quick lesson about color spaces
+ ///
+ /// ## What is a color space?
+ ///
+ /// Each pixel of a monitor is made of three components: one red, one green, and one blue. In
+ /// the past, computers would simply send to the monitor the intensity of each of the three
+ /// components.
+ ///
+ /// This proved to be problematic, because depending on the brand of the monitor the colors
+ /// would not exactly be the same. For example on some monitors, a value of `[1.0, 0.0, 0.0]`
+ /// would be a
+ /// bit more orange than on others.
+ ///
+ /// In order to standardize this, there exist what are called *color spaces*: sRGB, AdobeRGB,
+ /// DCI-P3, scRGB, etc. When you manipulate RGB values in a specific color space, these values
+ /// have a precise absolute meaning in terms of color, that is the same across all systems and
+ /// monitors.
+ ///
+ /// > **Note**: Color spaces are orthogonal to concept of RGB. *RGB* only indicates what is the
+ /// > representation of the data, but not how it is interpreted. You can think of this a bit
+ /// > like text encoding. An *RGB* value is a like a byte, in other words it is the medium by
+ /// > which values are communicated, and a *color space* is like a text encoding (eg. UTF-8),
+ /// > in other words it is the way the value should be interpreted.
+ ///
+ /// The most commonly used color space today is sRGB. Most monitors today use this color space,
+ /// and most images files are encoded in this color space.
+ ///
+ /// ## Pixel formats and linear vs non-linear
+ ///
+ /// In Vulkan all images have a specific format in which the data is stored. The data of an
+ /// image consists of pixels in RGB but contains no information about the color space (or lack
+ /// thereof) of these pixels. You are free to store them in whatever color space you want.
+ ///
+ /// But one big practical problem with color spaces is that they are sometimes not linear, and
+ /// in particular the popular sRGB color space is not linear. In a non-linear color space, a
+ /// value of `[0.6, 0.6, 0.6]` for example is **not** twice as bright as a value of `[0.3, 0.3,
+ /// 0.3]`. This is problematic, because operations such as taking the average of two colors or
+ /// calculating the lighting of a texture with a dot product are mathematically incorrect and
+ /// will produce incorrect colors.
+ ///
+ /// > **Note**: If the texture format has an alpha component, it is not affected by the color
+ /// > space and always behaves linearly.
+ ///
+ /// In order to solve this Vulkan also provides image formats with the `Srgb` suffix, which are
+ /// expected to contain RGB data in the sRGB color space. When you sample an image with such a
+ /// format from a shader, the implementation will automatically turn the pixel values into a
+ /// linear color space that is suitable for linear operations (such as additions or
+ /// multiplications). When you write to a framebuffer attachment with such a format, the
+ /// implementation will automatically perform the opposite conversion. These conversions are
+ /// most of the time performed by the hardware and incur no additional cost.
+ ///
+ /// ## Color space of the swapchain
+ ///
+ /// The color space that you specify when you create a swapchain is how the implementation will
+ /// interpret the raw data inside of the image.
+ ///
+ /// > **Note**: The implementation can choose to send the data in the swapchain image directly
+ /// > to the monitor, but it can also choose to write it in an intermediary buffer that is then
+ /// > read by the operating system or windowing system. Therefore the color space that the
+ /// > implementation supports is not necessarily the same as the one supported by the monitor.
+ ///
+ /// It is *your* job to ensure that the data in the swapchain image is in the color space
+ /// that is specified here, otherwise colors will be incorrect. The implementation will never
+ /// perform any additional automatic conversion after the colors have been written to the
+ /// swapchain image.
+ ///
+ /// # How do I handle this correctly?
+ ///
+ /// The easiest way to handle color spaces in a cross-platform program is:
+ ///
+ /// - Always request the `SrgbNonLinear` color space when creating the swapchain.
+ /// - Make sure that all your image files use the sRGB color space, and load them in images
+ /// whose format has the `Srgb` suffix. Only use non-sRGB image formats for intermediary
+ /// computations or to store non-color data.
+ /// - Swapchain images should have a format with the `Srgb` suffix.
+ ///
+ /// > **Note**: Lots of developers are confused by color spaces. You can sometimes find articles
+ /// > talking about gamma correction and suggestion to put your colors to the power 2.2 for
+ /// > example. These are all hacks and you should use the sRGB pixel formats instead.
+ ///
+ /// If you follow these three rules, then everything should render the same way on all
+ /// platforms.
+ ///
+ /// Additionally you can try detect whether the implementation supports any additional color
+ /// space and perform a manual conversion to that color space from inside your shader.
+ ColorSpace = ColorSpaceKHR(i32);
+
+ // TODO: document
+ SrgbNonLinear = SRGB_NONLINEAR,
+
+ // TODO: document
+ DisplayP3NonLinear = DISPLAY_P3_NONLINEAR_EXT {
+ instance_extensions: [ext_swapchain_colorspace],
+ },
+
+ // TODO: document
+ ExtendedSrgbLinear = EXTENDED_SRGB_LINEAR_EXT {
+ instance_extensions: [ext_swapchain_colorspace],
+ },
+
+ // TODO: document
+ ExtendedSrgbNonLinear = EXTENDED_SRGB_NONLINEAR_EXT {
+ instance_extensions: [ext_swapchain_colorspace],
+ },
+
+ // TODO: document
+ DisplayP3Linear = DISPLAY_P3_LINEAR_EXT {
+ instance_extensions: [ext_swapchain_colorspace],
+ },
+
+ // TODO: document
+ DciP3NonLinear = DCI_P3_NONLINEAR_EXT {
+ instance_extensions: [ext_swapchain_colorspace],
+ },
+
+ // TODO: document
+ Bt709Linear = BT709_LINEAR_EXT {
+ instance_extensions: [ext_swapchain_colorspace],
+ },
+
+ // TODO: document
+ Bt709NonLinear = BT709_NONLINEAR_EXT {
+ instance_extensions: [ext_swapchain_colorspace],
+ },
+
+ // TODO: document
+ Bt2020Linear = BT2020_LINEAR_EXT {
+ instance_extensions: [ext_swapchain_colorspace],
+ },
+
+ // TODO: document
+ Hdr10St2084 = HDR10_ST2084_EXT {
+ instance_extensions: [ext_swapchain_colorspace],
+ },
+
+ // TODO: document
+ DolbyVision = DOLBYVISION_EXT {
+ instance_extensions: [ext_swapchain_colorspace],
+ },
+
+ // TODO: document
+ Hdr10Hlg = HDR10_HLG_EXT {
+ instance_extensions: [ext_swapchain_colorspace],
+ },
+
+ // TODO: document
+ AdobeRgbLinear = ADOBERGB_LINEAR_EXT {
+ instance_extensions: [ext_swapchain_colorspace],
+ },
+
+ // TODO: document
+ AdobeRgbNonLinear = ADOBERGB_NONLINEAR_EXT {
+ instance_extensions: [ext_swapchain_colorspace],
+ },
+
+ // TODO: document
+ PassThrough = PASS_THROUGH_EXT {
+ instance_extensions: [ext_swapchain_colorspace],
+ },
+
+ // TODO: document
+ DisplayNative = DISPLAY_NATIVE_AMD {
+ device_extensions: [amd_display_native_hdr],
+ },
+}
+
+/// Parameters for [`PhysicalDevice::surface_capabilities`] and [`PhysicalDevice::surface_formats`].
+///
+/// [`PhysicalDevice::surface_capabilities`]: crate::device::physical::PhysicalDevice::surface_capabilities
+/// [`PhysicalDevice::surface_formats`]: crate::device::physical::PhysicalDevice::surface_formats
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct SurfaceInfo {
+ pub full_screen_exclusive: FullScreenExclusive,
+ pub win32_monitor: Option<Win32Monitor>,
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for SurfaceInfo {
#[inline]
- fn from(err: OomError) -> CapabilitiesError {
- CapabilitiesError::OomError(err)
+ fn default() -> Self {
+ Self {
+ full_screen_exclusive: FullScreenExclusive::Default,
+ win32_monitor: None,
+ _ne: crate::NonExhaustive(()),
+ }
}
}
-impl From<Error> for CapabilitiesError {
+#[cfg(target_os = "ios")]
+struct LayerHandle(*mut Object);
+
+#[cfg(target_os = "ios")]
+unsafe impl Send for LayerHandle {}
+
+#[cfg(target_os = "ios")]
+unsafe impl Sync for LayerHandle {}
+
+/// Represents the metal layer for IOS
+#[cfg(target_os = "ios")]
+pub struct IOSMetalLayer {
+ main_layer: LayerHandle,
+ render_layer: LayerHandle,
+}
+
+#[cfg(target_os = "ios")]
+impl IOSMetalLayer {
#[inline]
- fn from(err: Error) -> CapabilitiesError {
- match err {
- err @ Error::OutOfHostMemory => CapabilitiesError::OomError(OomError::from(err)),
- err @ Error::OutOfDeviceMemory => CapabilitiesError::OomError(OomError::from(err)),
- Error::SurfaceLost => CapabilitiesError::SurfaceLost,
- _ => panic!("unexpected error: {:?}", err),
+ pub fn new(main_layer: *mut Object, render_layer: *mut Object) -> Self {
+ Self {
+ main_layer: LayerHandle(main_layer),
+ render_layer: LayerHandle(render_layer),
}
}
}
+#[cfg(target_os = "ios")]
+unsafe impl Send for IOSMetalLayer {}
+
+#[cfg(target_os = "ios")]
+unsafe impl Sync for IOSMetalLayer {}
+
+/// The capabilities of a surface when used by a physical device.
+///
+/// You have to match these capabilities when you create a swapchain.
+#[derive(Clone, Debug)]
+#[non_exhaustive]
+pub struct SurfaceCapabilities {
+ /// Minimum number of images that must be present in the swapchain.
+ pub min_image_count: u32,
+
+ /// Maximum number of images that must be present in the swapchain, or `None` if there is no
+ /// maximum value. Note that "no maximum" doesn't mean that you can set a very high value, as
+ /// you may still get out of memory errors.
+ pub max_image_count: Option<u32>,
+
+ /// The current dimensions of the surface. `None` means that the surface's dimensions will
+ /// depend on the dimensions of the swapchain that you are going to create.
+ pub current_extent: Option<[u32; 2]>,
+
+ /// Minimum width and height of a swapchain that uses this surface.
+ pub min_image_extent: [u32; 2],
+
+ /// Maximum width and height of a swapchain that uses this surface.
+ pub max_image_extent: [u32; 2],
+
+ /// Maximum number of image layers if you create an image array. The minimum is 1.
+ pub max_image_array_layers: u32,
+
+ /// List of transforms supported for the swapchain.
+ pub supported_transforms: SurfaceTransforms,
+
+ /// Current transform used by the surface.
+ pub current_transform: SurfaceTransform,
+
+ /// List of composite alpha modes supports for the swapchain.
+ pub supported_composite_alpha: CompositeAlphas,
+
+ /// List of image usages that are supported for images of the swapchain. Only
+ /// the `color_attachment` usage is guaranteed to be supported.
+ pub supported_usage_flags: ImageUsage,
+
+ /// Whether creating a protected swapchain is supported.
+ pub supports_protected: bool,
+
+ /// Whether full-screen exclusivity is supported.
+ pub full_screen_exclusive_supported: bool,
+}
+
#[cfg(test)]
mod tests {
- use crate::swapchain::Surface;
- use crate::swapchain::SurfaceCreationError;
+ use crate::{
+ swapchain::{Surface, SurfaceCreationError},
+ RequiresOneOf,
+ };
use std::ptr;
#[test]
fn khr_win32_surface_ext_missing() {
let instance = instance!();
- match unsafe { Surface::from_hwnd(instance, ptr::null::<u8>(), ptr::null::<u8>(), ()) } {
- Err(SurfaceCreationError::MissingExtension { .. }) => (),
+ match unsafe { Surface::from_win32(instance, ptr::null::<u8>(), ptr::null::<u8>(), None) } {
+ Err(SurfaceCreationError::RequirementNotMet {
+ requires_one_of:
+ RequiresOneOf {
+ instance_extensions,
+ ..
+ },
+ ..
+ }) if instance_extensions.contains(&"khr_win32_surface") => (),
_ => panic!(),
}
}
@@ -821,8 +1876,15 @@ mod tests {
#[test]
fn khr_xcb_surface_ext_missing() {
let instance = instance!();
- match unsafe { Surface::from_xcb(instance, ptr::null::<u8>(), 0, ()) } {
- Err(SurfaceCreationError::MissingExtension { .. }) => (),
+ match unsafe { Surface::from_xcb(instance, ptr::null::<u8>(), 0, None) } {
+ Err(SurfaceCreationError::RequirementNotMet {
+ requires_one_of:
+ RequiresOneOf {
+ instance_extensions,
+ ..
+ },
+ ..
+ }) if instance_extensions.contains(&"khr_xcb_surface") => (),
_ => panic!(),
}
}
@@ -830,8 +1892,15 @@ mod tests {
#[test]
fn khr_xlib_surface_ext_missing() {
let instance = instance!();
- match unsafe { Surface::from_xlib(instance, ptr::null::<u8>(), 0, ()) } {
- Err(SurfaceCreationError::MissingExtension { .. }) => (),
+ match unsafe { Surface::from_xlib(instance, ptr::null::<u8>(), 0, None) } {
+ Err(SurfaceCreationError::RequirementNotMet {
+ requires_one_of:
+ RequiresOneOf {
+ instance_extensions,
+ ..
+ },
+ ..
+ }) if instance_extensions.contains(&"khr_xlib_surface") => (),
_ => panic!(),
}
}
@@ -839,8 +1908,16 @@ mod tests {
#[test]
fn khr_wayland_surface_ext_missing() {
let instance = instance!();
- match unsafe { Surface::from_wayland(instance, ptr::null::<u8>(), ptr::null::<u8>(), ()) } {
- Err(SurfaceCreationError::MissingExtension { .. }) => (),
+ match unsafe { Surface::from_wayland(instance, ptr::null::<u8>(), ptr::null::<u8>(), None) }
+ {
+ Err(SurfaceCreationError::RequirementNotMet {
+ requires_one_of:
+ RequiresOneOf {
+ instance_extensions,
+ ..
+ },
+ ..
+ }) if instance_extensions.contains(&"khr_wayland_surface") => (),
_ => panic!(),
}
}
@@ -848,8 +1925,15 @@ mod tests {
#[test]
fn khr_android_surface_ext_missing() {
let instance = instance!();
- match unsafe { Surface::from_anativewindow(instance, ptr::null::<u8>(), ()) } {
- Err(SurfaceCreationError::MissingExtension { .. }) => (),
+ match unsafe { Surface::from_android(instance, ptr::null::<u8>(), None) } {
+ Err(SurfaceCreationError::RequirementNotMet {
+ requires_one_of:
+ RequiresOneOf {
+ instance_extensions,
+ ..
+ },
+ ..
+ }) if instance_extensions.contains(&"khr_android_surface") => (),
_ => panic!(),
}
}
diff --git a/src/swapchain/swapchain.rs b/src/swapchain/swapchain.rs
index 3eb9051..400b2b9 100644
--- a/src/swapchain/swapchain.rs
+++ b/src/swapchain/swapchain.rs
@@ -7,354 +7,782 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use crate::buffer::BufferAccess;
-use crate::check_errors;
-use crate::command_buffer::submit::SubmitAnyBuilder;
-use crate::command_buffer::submit::SubmitPresentBuilder;
-use crate::command_buffer::submit::SubmitPresentError;
-use crate::command_buffer::submit::SubmitSemaphoresWaitBuilder;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::device::Queue;
-use crate::format::Format;
-use crate::image::swapchain::SwapchainImage;
-use crate::image::sys::UnsafeImage;
-use crate::image::ImageAccess;
-use crate::image::ImageCreateFlags;
-use crate::image::ImageDimensions;
-use crate::image::ImageInner;
-use crate::image::ImageLayout;
-use crate::image::ImageTiling;
-use crate::image::ImageType;
-use crate::image::ImageUsage;
-use crate::image::SampleCount;
-use crate::swapchain::CapabilitiesError;
-use crate::swapchain::ColorSpace;
-use crate::swapchain::CompositeAlpha;
-use crate::swapchain::PresentMode;
-use crate::swapchain::PresentRegion;
-use crate::swapchain::Surface;
-use crate::swapchain::SurfaceSwapchainLock;
-use crate::swapchain::SurfaceTransform;
-use crate::sync::semaphore::SemaphoreError;
-use crate::sync::AccessCheckError;
-use crate::sync::AccessError;
-use crate::sync::AccessFlags;
-use crate::sync::Fence;
-use crate::sync::FlushError;
-use crate::sync::GpuFuture;
-use crate::sync::PipelineStages;
-use crate::sync::Semaphore;
-use crate::sync::SharingMode;
-use crate::Error;
-use crate::OomError;
-use crate::Success;
-use crate::VulkanObject;
-use std::error;
-use std::fmt;
-use std::mem;
-use std::mem::MaybeUninit;
-use std::ptr;
-use std::sync::atomic::AtomicBool;
-use std::sync::atomic::Ordering;
-use std::sync::Arc;
-use std::sync::Mutex;
-use std::time::Duration;
-
-/// The way fullscreen exclusivity is handled.
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-#[repr(i32)]
-pub enum FullscreenExclusive {
- /// Indicates that the driver should determine the appropriate full-screen method
- /// by whatever means it deems appropriate.
- Default = ash::vk::FullScreenExclusiveEXT::DEFAULT.as_raw(),
- /// Indicates that the driver may use full-screen exclusive mechanisms when available.
- /// Such mechanisms may result in better performance and/or the availability of
- /// different presentation capabilities, but may require a more disruptive transition
- // during swapchain initialization, first presentation and/or destruction.
- Allowed = ash::vk::FullScreenExclusiveEXT::ALLOWED.as_raw(),
- /// Indicates that the driver should avoid using full-screen mechanisms which rely
- /// on disruptive transitions.
- Disallowed = ash::vk::FullScreenExclusiveEXT::DISALLOWED.as_raw(),
- /// Indicates the application will manage full-screen exclusive mode by using
- /// `Swapchain::acquire_fullscreen_exclusive()` and
- /// `Swapchain::release_fullscreen_exclusive()` functions.
- AppControlled = ash::vk::FullScreenExclusiveEXT::APPLICATION_CONTROLLED.as_raw(),
-}
+use super::{
+ ColorSpace, CompositeAlpha, CompositeAlphas, PresentMode, Surface, SurfaceTransform,
+ SurfaceTransforms, SwapchainPresentInfo,
+};
+use crate::{
+ buffer::Buffer,
+ device::{Device, DeviceOwned, Queue},
+ format::Format,
+ image::{
+ sys::Image, ImageFormatInfo, ImageLayout, ImageTiling, ImageType, ImageUsage,
+ SwapchainImage,
+ },
+ macros::{impl_id_counter, vulkan_enum},
+ swapchain::{PresentInfo, SurfaceApi, SurfaceInfo, SurfaceSwapchainLock},
+ sync::{
+ fence::{Fence, FenceError},
+ future::{AccessCheckError, AccessError, FlushError, GpuFuture, SubmitAnyBuilder},
+ semaphore::{Semaphore, SemaphoreError},
+ Sharing,
+ },
+ DeviceSize, OomError, RequirementNotMet, RequiresOneOf, VulkanError, VulkanObject,
+};
+use parking_lot::Mutex;
+use smallvec::{smallvec, SmallVec};
+use std::{
+ error::Error,
+ fmt::{Debug, Display, Error as FmtError, Formatter},
+ mem::MaybeUninit,
+ num::NonZeroU64,
+ ops::Range,
+ ptr,
+ sync::{
+ atomic::{AtomicBool, AtomicU64, Ordering},
+ Arc,
+ },
+ thread,
+ time::Duration,
+};
-impl From<FullscreenExclusive> for ash::vk::FullScreenExclusiveEXT {
- #[inline]
- fn from(val: FullscreenExclusive) -> Self {
- Self::from_raw(val as i32)
- }
+/// Contains the swapping system and the images that can be shown on a surface.
+pub struct Swapchain {
+ handle: ash::vk::SwapchainKHR,
+ device: Arc<Device>,
+ surface: Arc<Surface>,
+ id: NonZeroU64,
+
+ min_image_count: u32,
+ image_format: Format,
+ image_color_space: ColorSpace,
+ image_extent: [u32; 2],
+ image_array_layers: u32,
+ image_usage: ImageUsage,
+ image_sharing: Sharing<SmallVec<[u32; 4]>>,
+ pre_transform: SurfaceTransform,
+ composite_alpha: CompositeAlpha,
+ present_mode: PresentMode,
+ clipped: bool,
+ full_screen_exclusive: FullScreenExclusive,
+ win32_monitor: Option<Win32Monitor>,
+ prev_present_id: AtomicU64,
+
+ // Whether full-screen exclusive is currently held.
+ full_screen_exclusive_held: AtomicBool,
+
+ // The images of this swapchain.
+ images: Vec<ImageEntry>,
+
+ // If true, that means we have tried to use this swapchain to recreate a new swapchain. The
+ // current swapchain can no longer be used for anything except presenting already-acquired
+ // images.
+ //
+ // We use a `Mutex` instead of an `AtomicBool` because we want to keep that locked while
+ // we acquire the image.
+ retired: Mutex<bool>,
}
-/// Tries to take ownership of an image in order to draw on it.
-///
-/// The function returns the index of the image in the array of images that was returned
-/// when creating the swapchain, plus a future that represents the moment when the image will
-/// become available from the GPU (which may not be *immediately*).
-///
-/// If you try to draw on an image without acquiring it first, the execution will block. (TODO
-/// behavior may change).
-///
-/// The second field in the tuple in the Ok result is a bool represent if the acquisition was
-/// suboptimal. In this case the acquired image is still usable, but the swapchain should be
-/// recreated as the Surface's properties no longer match the swapchain.
-pub fn acquire_next_image<W>(
- swapchain: Arc<Swapchain<W>>,
- timeout: Option<Duration>,
-) -> Result<(usize, bool, SwapchainAcquireFuture<W>), AcquireError> {
- let semaphore = Semaphore::from_pool(swapchain.device.clone())?;
- let fence = Fence::from_pool(swapchain.device.clone())?;
+#[derive(Debug)]
+struct ImageEntry {
+ handle: ash::vk::Image,
+ layout_initialized: AtomicBool,
+}
- let AcquiredImage { id, suboptimal } = {
- // Check that this is not an old swapchain. From specs:
- // > swapchain must not have been replaced by being passed as the
- // > VkSwapchainCreateInfoKHR::oldSwapchain value to vkCreateSwapchainKHR
- let stale = swapchain.stale.lock().unwrap();
- if *stale {
- return Err(AcquireError::OutOfDate);
+impl Swapchain {
+ /// Creates a new `Swapchain`.
+ ///
+ /// This function returns the swapchain plus a list of the images that belong to the
+ /// swapchain. The order in which the images are returned is important for the
+ /// `acquire_next_image` and `present` functions.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if the device and the surface don't belong to the same instance.
+ /// - Panics if `create_info.usage` is empty.
+ ///
+ // TODO: isn't it unsafe to take the surface through an Arc when it comes to vulkano-win?
+ pub fn new(
+ device: Arc<Device>,
+ surface: Arc<Surface>,
+ mut create_info: SwapchainCreateInfo,
+ ) -> Result<(Arc<Swapchain>, Vec<Arc<SwapchainImage>>), SwapchainCreationError> {
+ Self::validate(&device, &surface, &mut create_info)?;
+
+ // Checking that the surface doesn't already have a swapchain.
+ if surface.flag().swap(true, Ordering::AcqRel) {
+ return Err(SwapchainCreationError::SurfaceInUse);
}
- let acquire_result =
- unsafe { acquire_next_image_raw(&swapchain, timeout, Some(&semaphore), Some(&fence)) };
+ let (handle, image_handles) =
+ unsafe { Self::create(&device, &surface, &create_info, None)? };
+
+ let SwapchainCreateInfo {
+ min_image_count,
+ image_format,
+ image_color_space,
+ image_extent,
+ image_array_layers,
+ image_usage,
+ image_sharing,
+ pre_transform,
+ composite_alpha,
+ present_mode,
+ clipped,
+ full_screen_exclusive,
+ win32_monitor,
+ _ne: _,
+ } = create_info;
- if let &Err(AcquireError::FullscreenExclusiveLost) = &acquire_result {
- swapchain
- .fullscreen_exclusive_held
- .store(false, Ordering::SeqCst);
+ let swapchain = Arc::new(Swapchain {
+ handle,
+ device,
+ surface,
+ id: Self::next_id(),
+ min_image_count,
+ image_format: image_format.unwrap(),
+ image_color_space,
+ image_extent,
+ image_array_layers,
+ image_usage,
+ image_sharing,
+ pre_transform,
+ composite_alpha,
+ present_mode,
+ clipped,
+ full_screen_exclusive,
+ win32_monitor,
+ prev_present_id: Default::default(),
+ full_screen_exclusive_held: AtomicBool::new(false),
+ images: image_handles
+ .iter()
+ .map(|&handle| ImageEntry {
+ handle,
+ layout_initialized: AtomicBool::new(false),
+ })
+ .collect(),
+ retired: Mutex::new(false),
+ });
+
+ let swapchain_images = image_handles
+ .into_iter()
+ .enumerate()
+ .map(|(image_index, handle)| unsafe {
+ SwapchainImage::from_handle(handle, swapchain.clone(), image_index as u32)
+ })
+ .collect::<Result<_, _>>()?;
+
+ Ok((swapchain, swapchain_images))
+ }
+
+ /// Creates a new swapchain from this one.
+ ///
+ /// Use this when a swapchain has become invalidated, such as due to window resizes.
+ ///
+ /// # Panics
+ ///
+ /// - Panics if `create_info.usage` is empty.
+ pub fn recreate(
+ self: &Arc<Self>,
+ mut create_info: SwapchainCreateInfo,
+ ) -> Result<(Arc<Swapchain>, Vec<Arc<SwapchainImage>>), SwapchainCreationError> {
+ Self::validate(&self.device, &self.surface, &mut create_info)?;
+
+ {
+ let mut retired = self.retired.lock();
+
+ // The swapchain has already been used to create a new one.
+ if *retired {
+ return Err(SwapchainCreationError::SwapchainAlreadyRetired);
+ } else {
+ // According to the documentation of VkSwapchainCreateInfoKHR:
+ //
+ // > Upon calling vkCreateSwapchainKHR with a oldSwapchain that is not VK_NULL_HANDLE,
+ // > any images not acquired by the application may be freed by the implementation,
+ // > which may occur even if creation of the new swapchain fails.
+ //
+ // Therefore, we set retired to true and keep it to true even if the call to `vkCreateSwapchainKHR` below fails.
+ *retired = true;
+ }
}
- acquire_result?
- };
+ let (handle, image_handles) =
+ unsafe { Self::create(&self.device, &self.surface, &create_info, Some(self))? };
- Ok((
- id,
- suboptimal,
- SwapchainAcquireFuture {
- swapchain,
- semaphore: Some(semaphore),
- fence: Some(fence),
- image_id: id,
- finished: AtomicBool::new(false),
- },
- ))
-}
+ let full_screen_exclusive_held =
+ if self.full_screen_exclusive != FullScreenExclusive::ApplicationControlled {
+ false
+ } else {
+ self.full_screen_exclusive_held.load(Ordering::SeqCst)
+ };
-/// Presents an image on the screen.
-///
-/// The parameter is the same index as what `acquire_next_image` returned. The image must
-/// have been acquired first.
-///
-/// The actual behavior depends on the present mode that you passed when creating the
-/// swapchain.
-pub fn present<F, W>(
- swapchain: Arc<Swapchain<W>>,
- before: F,
- queue: Arc<Queue>,
- index: usize,
-) -> PresentFuture<F, W>
-where
- F: GpuFuture,
-{
- assert!(index < swapchain.images.len());
+ let SwapchainCreateInfo {
+ min_image_count,
+ image_format,
+ image_color_space,
+ image_extent,
+ image_array_layers,
+ image_usage,
+ image_sharing,
+ pre_transform,
+ composite_alpha,
+ present_mode,
+ clipped,
+ full_screen_exclusive,
+ win32_monitor,
+ _ne: _,
+ } = create_info;
- // TODO: restore this check with a dummy ImageAccess implementation
- /*let swapchain_image = me.images.lock().unwrap().get(index).unwrap().0.upgrade().unwrap(); // TODO: return error instead
- // Normally if `check_image_access` returns false we're supposed to call the `gpu_access`
- // function on the image instead. But since we know that this method on `SwapchainImage`
- // always returns false anyway (by design), we don't need to do it.
- assert!(before.check_image_access(&swapchain_image, ImageLayout::PresentSrc, true, &queue).is_ok()); // TODO: return error instead*/
+ let swapchain = Arc::new(Swapchain {
+ handle,
+ device: self.device.clone(),
+ surface: self.surface.clone(),
+ id: Self::next_id(),
+ min_image_count,
+ image_format: image_format.unwrap(),
+ image_color_space,
+ image_extent,
+ image_array_layers,
+ image_usage,
+ image_sharing,
+ pre_transform,
+ composite_alpha,
+ present_mode,
+ clipped,
+ full_screen_exclusive,
+ win32_monitor,
+ prev_present_id: Default::default(),
+ full_screen_exclusive_held: AtomicBool::new(full_screen_exclusive_held),
+ images: image_handles
+ .iter()
+ .map(|&handle| ImageEntry {
+ handle,
+ layout_initialized: AtomicBool::new(false),
+ })
+ .collect(),
+ retired: Mutex::new(false),
+ });
- PresentFuture {
- previous: before,
- queue,
- swapchain,
- image_id: index,
- present_region: None,
- flushed: AtomicBool::new(false),
- finished: AtomicBool::new(false),
+ let swapchain_images = image_handles
+ .into_iter()
+ .enumerate()
+ .map(|(image_index, handle)| unsafe {
+ SwapchainImage::from_handle(handle, swapchain.clone(), image_index as u32)
+ })
+ .collect::<Result<_, _>>()?;
+
+ Ok((swapchain, swapchain_images))
}
-}
-/// Same as `swapchain::present`, except it allows specifying a present region.
-/// Areas outside the present region may be ignored by Vulkan in order to optimize presentation.
-///
-/// This is just an optimization hint, as the Vulkan driver is free to ignore the given present region.
-///
-/// If `VK_KHR_incremental_present` is not enabled on the device, the parameter will be ignored.
-pub fn present_incremental<F, W>(
- swapchain: Arc<Swapchain<W>>,
- before: F,
- queue: Arc<Queue>,
- index: usize,
- present_region: PresentRegion,
-) -> PresentFuture<F, W>
-where
- F: GpuFuture,
-{
- assert!(index < swapchain.images.len());
+ fn validate(
+ device: &Device,
+ surface: &Surface,
+ create_info: &mut SwapchainCreateInfo,
+ ) -> Result<(), SwapchainCreationError> {
+ let &mut SwapchainCreateInfo {
+ min_image_count,
+ ref mut image_format,
+ image_color_space,
+ ref mut image_extent,
+ image_array_layers,
+ image_usage,
+ ref mut image_sharing,
+ pre_transform,
+ composite_alpha,
+ present_mode,
+ clipped: _,
+ full_screen_exclusive,
+ win32_monitor,
+ _ne: _,
+ } = create_info;
- // TODO: restore this check with a dummy ImageAccess implementation
- /*let swapchain_image = me.images.lock().unwrap().get(index).unwrap().0.upgrade().unwrap(); // TODO: return error instead
- // Normally if `check_image_access` returns false we're supposed to call the `gpu_access`
- // function on the image instead. But since we know that this method on `SwapchainImage`
- // always returns false anyway (by design), we don't need to do it.
- assert!(before.check_image_access(&swapchain_image, ImageLayout::PresentSrc, true, &queue).is_ok()); // TODO: return error instead*/
+ if !device.enabled_extensions().khr_swapchain {
+ return Err(SwapchainCreationError::RequirementNotMet {
+ required_for: "`Swapchain::new`",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["khr_swapchain"],
+ ..Default::default()
+ },
+ });
+ }
- PresentFuture {
- previous: before,
- queue,
- swapchain,
- image_id: index,
- present_region: Some(present_region),
- flushed: AtomicBool::new(false),
- finished: AtomicBool::new(false),
- }
-}
+ assert_eq!(device.instance(), surface.instance());
-/// Contains the swapping system and the images that can be shown on a surface.
-pub struct Swapchain<W> {
- // The Vulkan device this swapchain was created with.
- device: Arc<Device>,
- // The surface, which we need to keep alive.
- surface: Arc<Surface<W>>,
- // The swapchain object.
- swapchain: ash::vk::SwapchainKHR,
+ // VUID-VkSwapchainCreateInfoKHR-imageColorSpace-parameter
+ image_color_space.validate_device(device)?;
- // The images of this swapchain.
- images: Vec<ImageEntry>,
+ // VUID-VkSwapchainCreateInfoKHR-imageUsage-parameter
+ image_usage.validate_device(device)?;
- // If true, that means we have tried to use this swapchain to recreate a new swapchain. The current
- // swapchain can no longer be used for anything except presenting already-acquired images.
- //
- // We use a `Mutex` instead of an `AtomicBool` because we want to keep that locked while
- // we acquire the image.
- stale: Mutex<bool>,
-
- // Parameters passed to the constructor.
- num_images: u32,
- format: Format,
- color_space: ColorSpace,
- dimensions: [u32; 2],
- layers: u32,
- usage: ImageUsage,
- sharing_mode: SharingMode,
- transform: SurfaceTransform,
- composite_alpha: CompositeAlpha,
- present_mode: PresentMode,
- fullscreen_exclusive: FullscreenExclusive,
- fullscreen_exclusive_held: AtomicBool,
- clipped: bool,
-}
+ // VUID-VkSwapchainCreateInfoKHR-imageUsage-requiredbitmask
+ assert!(!image_usage.is_empty());
-struct ImageEntry {
- // The actual image.
- image: UnsafeImage,
- // If true, then the image is still in the undefined layout and must be transitioned.
- undefined_layout: AtomicBool,
-}
+ // VUID-VkSwapchainCreateInfoKHR-preTransform-parameter
+ pre_transform.validate_device(device)?;
-impl<W> Swapchain<W> {
- /// Starts the process of building a new swapchain, using default values for the parameters.
- #[inline]
- pub fn start(device: Arc<Device>, surface: Arc<Surface<W>>) -> SwapchainBuilder<W> {
- SwapchainBuilder {
- device,
- surface,
+ // VUID-VkSwapchainCreateInfoKHR-compositeAlpha-parameter
+ composite_alpha.validate_device(device)?;
- num_images: 2,
- format: None,
- color_space: ColorSpace::SrgbNonLinear,
- dimensions: None,
- layers: 1,
- usage: ImageUsage::none(),
- sharing_mode: SharingMode::Exclusive,
- transform: Default::default(),
- composite_alpha: CompositeAlpha::Opaque,
- present_mode: PresentMode::Fifo,
- fullscreen_exclusive: FullscreenExclusive::Default,
- clipped: true,
+ // VUID-VkSwapchainCreateInfoKHR-presentMode-parameter
+ present_mode.validate_device(device)?;
+
+ if full_screen_exclusive != FullScreenExclusive::Default {
+ if !device.enabled_extensions().ext_full_screen_exclusive {
+ return Err(SwapchainCreationError::RequirementNotMet {
+ required_for: "`create_info.full_screen_exclusive` is not \
+ `FullScreenExclusive::Default`",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["ext_full_screen_exclusive"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkSurfaceFullScreenExclusiveInfoEXT-fullScreenExclusive-parameter
+ full_screen_exclusive.validate_device(device)?;
+ }
+
+ if surface.api() == SurfaceApi::Win32
+ && full_screen_exclusive == FullScreenExclusive::ApplicationControlled
+ {
+ if win32_monitor.is_none() {
+ return Err(SwapchainCreationError::Win32MonitorInvalid);
+ }
+ } else {
+ if win32_monitor.is_some() {
+ return Err(SwapchainCreationError::Win32MonitorInvalid);
+ }
+ }
+
+ // VUID-VkSwapchainCreateInfoKHR-surface-01270
+ if !device
+ .active_queue_family_indices()
+ .iter()
+ .copied()
+ .any(|index| unsafe {
+ // Use unchecked, because all validation has been done above.
+ device
+ .physical_device()
+ .surface_support_unchecked(index, surface)
+ .unwrap_or_default()
+ })
+ {
+ return Err(SwapchainCreationError::SurfaceNotSupported);
+ }
+
+ *image_format = Some({
+ // Use unchecked, because all validation has been done above.
+ let surface_formats = unsafe {
+ device.physical_device().surface_formats_unchecked(
+ surface,
+ SurfaceInfo {
+ full_screen_exclusive,
+ win32_monitor,
+ ..Default::default()
+ },
+ )?
+ };
+
+ if let Some(format) = image_format {
+ // VUID-VkSwapchainCreateInfoKHR-imageFormat-parameter
+ format.validate_device(device)?;
+
+ // VUID-VkSwapchainCreateInfoKHR-imageFormat-01273
+ if !surface_formats
+ .into_iter()
+ .any(|(f, c)| f == *format && c == image_color_space)
+ {
+ return Err(SwapchainCreationError::FormatColorSpaceNotSupported);
+ }
+ *format
+ } else {
+ surface_formats
+ .into_iter()
+ .find_map(|(f, c)| {
+ (c == image_color_space
+ && [Format::R8G8B8A8_UNORM, Format::B8G8R8A8_UNORM].contains(&f))
+ .then_some(f)
+ })
+ .ok_or(SwapchainCreationError::FormatColorSpaceNotSupported)?
+ }
+ });
+
+ // Use unchecked, because all validation has been done above.
+ let surface_capabilities = unsafe {
+ device.physical_device().surface_capabilities_unchecked(
+ surface,
+ SurfaceInfo {
+ full_screen_exclusive,
+ win32_monitor,
+ ..Default::default()
+ },
+ )?
+ };
+
+ // VUID-VkSwapchainCreateInfoKHR-minImageCount-01272
+ // VUID-VkSwapchainCreateInfoKHR-presentMode-02839
+ if min_image_count < surface_capabilities.min_image_count
+ || surface_capabilities
+ .max_image_count
+ .map_or(false, |c| min_image_count > c)
+ {
+ return Err(SwapchainCreationError::MinImageCountNotSupported {
+ provided: min_image_count,
+ min_supported: surface_capabilities.min_image_count,
+ max_supported: surface_capabilities.max_image_count,
+ });
+ }
+
+ if image_extent[0] == 0 || image_extent[1] == 0 {
+ *image_extent = surface_capabilities.current_extent.unwrap();
+ }
+
+ // VUID-VkSwapchainCreateInfoKHR-imageExtent-01274
+ if image_extent[0] < surface_capabilities.min_image_extent[0]
+ || image_extent[1] < surface_capabilities.min_image_extent[1]
+ || image_extent[0] > surface_capabilities.max_image_extent[0]
+ || image_extent[1] > surface_capabilities.max_image_extent[1]
+ {
+ return Err(SwapchainCreationError::ImageExtentNotSupported {
+ provided: *image_extent,
+ min_supported: surface_capabilities.min_image_extent,
+ max_supported: surface_capabilities.max_image_extent,
+ });
+ }
- old_swapchain: None,
+ // VUID-VkSwapchainCreateInfoKHR-imageExtent-01689
+ // On some platforms, dimensions of zero-length can occur by minimizing the surface.
+ if image_extent.contains(&0) {
+ return Err(SwapchainCreationError::ImageExtentZeroLengthDimensions);
}
+
+ // VUID-VkSwapchainCreateInfoKHR-imageArrayLayers-01275
+ if image_array_layers == 0
+ || image_array_layers > surface_capabilities.max_image_array_layers
+ {
+ return Err(SwapchainCreationError::ImageArrayLayersNotSupported {
+ provided: image_array_layers,
+ max_supported: surface_capabilities.max_image_array_layers,
+ });
+ }
+
+ // VUID-VkSwapchainCreateInfoKHR-presentMode-01427
+ if (ash::vk::ImageUsageFlags::from(image_usage)
+ & ash::vk::ImageUsageFlags::from(surface_capabilities.supported_usage_flags))
+ != ash::vk::ImageUsageFlags::from(image_usage)
+ {
+ return Err(SwapchainCreationError::ImageUsageNotSupported {
+ provided: image_usage,
+ supported: surface_capabilities.supported_usage_flags,
+ });
+ }
+
+ match image_sharing {
+ Sharing::Exclusive => (),
+ Sharing::Concurrent(queue_family_indices) => {
+ // VUID-VkSwapchainCreateInfoKHR-imageSharingMode-01278
+ // VUID-VkSwapchainCreateInfoKHR-imageSharingMode-01428
+ queue_family_indices.sort_unstable();
+ queue_family_indices.dedup();
+ assert!(queue_family_indices.len() >= 2);
+
+ for &queue_family_index in queue_family_indices.iter() {
+ // VUID-VkSwapchainCreateInfoKHR-imageSharingMode-01428
+ if queue_family_index
+ >= device.physical_device().queue_family_properties().len() as u32
+ {
+ return Err(
+ SwapchainCreationError::ImageSharingQueueFamilyIndexOutOfRange {
+ queue_family_index,
+ queue_family_count: device
+ .physical_device()
+ .queue_family_properties()
+ .len()
+ as u32,
+ },
+ );
+ }
+ }
+ }
+ };
+
+ // VUID-VkSwapchainCreateInfoKHR-preTransform-01279
+ if !surface_capabilities
+ .supported_transforms
+ .contains_enum(pre_transform)
+ {
+ return Err(SwapchainCreationError::PreTransformNotSupported {
+ provided: pre_transform,
+ supported: surface_capabilities.supported_transforms,
+ });
+ }
+
+ // VUID-VkSwapchainCreateInfoKHR-compositeAlpha-01280
+ if !surface_capabilities
+ .supported_composite_alpha
+ .contains_enum(composite_alpha)
+ {
+ return Err(SwapchainCreationError::CompositeAlphaNotSupported {
+ provided: composite_alpha,
+ supported: surface_capabilities.supported_composite_alpha,
+ });
+ }
+
+ // VUID-VkSwapchainCreateInfoKHR-presentMode-01281
+ // Use unchecked, because all validation has been done above.
+ if !unsafe {
+ device
+ .physical_device()
+ .surface_present_modes_unchecked(surface)?
+ }
+ .any(|mode| mode == present_mode)
+ {
+ return Err(SwapchainCreationError::PresentModeNotSupported);
+ }
+
+ // VUID-VkSwapchainCreateInfoKHR-imageFormat-01778
+ // Use unchecked, because all validation has been done above.
+ if unsafe {
+ device
+ .physical_device()
+ .image_format_properties_unchecked(ImageFormatInfo {
+ format: *image_format,
+ image_type: ImageType::Dim2d,
+ tiling: ImageTiling::Optimal,
+ usage: image_usage,
+ ..Default::default()
+ })?
+ }
+ .is_none()
+ {
+ return Err(SwapchainCreationError::ImageFormatPropertiesNotSupported);
+ }
+
+ Ok(())
}
- /// Starts building a new swapchain from an existing swapchain.
- ///
- /// Use this when a swapchain has become invalidated, such as due to window resizes.
- /// The builder is pre-filled with the parameters of the old one, except for `dimensions`,
- /// which is set to `None`.
+ unsafe fn create(
+ device: &Device,
+ surface: &Surface,
+ create_info: &SwapchainCreateInfo,
+ old_swapchain: Option<&Swapchain>,
+ ) -> Result<(ash::vk::SwapchainKHR, Vec<ash::vk::Image>), SwapchainCreationError> {
+ let &SwapchainCreateInfo {
+ min_image_count,
+ image_format,
+ image_color_space,
+ image_extent,
+ image_array_layers,
+ image_usage,
+ ref image_sharing,
+ pre_transform,
+ composite_alpha,
+ present_mode,
+ clipped,
+ full_screen_exclusive,
+ win32_monitor,
+ _ne: _,
+ } = create_info;
+
+ let (image_sharing_mode, queue_family_index_count, p_queue_family_indices) =
+ match image_sharing {
+ Sharing::Exclusive => (ash::vk::SharingMode::EXCLUSIVE, 0, ptr::null()),
+ Sharing::Concurrent(ref ids) => (
+ ash::vk::SharingMode::CONCURRENT,
+ ids.len() as u32,
+ ids.as_ptr(),
+ ),
+ };
+
+ let mut info_vk = ash::vk::SwapchainCreateInfoKHR {
+ flags: ash::vk::SwapchainCreateFlagsKHR::empty(),
+ surface: surface.handle(),
+ min_image_count,
+ image_format: image_format.unwrap().into(),
+ image_color_space: image_color_space.into(),
+ image_extent: ash::vk::Extent2D {
+ width: image_extent[0],
+ height: image_extent[1],
+ },
+ image_array_layers,
+ image_usage: image_usage.into(),
+ image_sharing_mode,
+ queue_family_index_count,
+ p_queue_family_indices,
+ pre_transform: pre_transform.into(),
+ composite_alpha: composite_alpha.into(),
+ present_mode: present_mode.into(),
+ clipped: clipped as ash::vk::Bool32,
+ old_swapchain: old_swapchain.map_or(ash::vk::SwapchainKHR::null(), |os| os.handle),
+ ..Default::default()
+ };
+ let mut surface_full_screen_exclusive_info_vk = None;
+ let mut surface_full_screen_exclusive_win32_info_vk = None;
+
+ if full_screen_exclusive != FullScreenExclusive::Default {
+ let next = surface_full_screen_exclusive_info_vk.insert(
+ ash::vk::SurfaceFullScreenExclusiveInfoEXT {
+ full_screen_exclusive: full_screen_exclusive.into(),
+ ..Default::default()
+ },
+ );
+
+ next.p_next = info_vk.p_next as *mut _;
+ info_vk.p_next = next as *const _ as *const _;
+ }
+
+ if let Some(Win32Monitor(hmonitor)) = win32_monitor {
+ let next = surface_full_screen_exclusive_win32_info_vk.insert(
+ ash::vk::SurfaceFullScreenExclusiveWin32InfoEXT {
+ hmonitor,
+ ..Default::default()
+ },
+ );
+
+ next.p_next = info_vk.p_next as *mut _;
+ info_vk.p_next = next as *const _ as *const _;
+ }
+
+ let fns = device.fns();
+
+ let handle = {
+ let mut output = MaybeUninit::uninit();
+ (fns.khr_swapchain.create_swapchain_khr)(
+ device.handle(),
+ &info_vk,
+ ptr::null(),
+ output.as_mut_ptr(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+ output.assume_init()
+ };
+
+ let image_handles = loop {
+ let mut count = 0;
+ (fns.khr_swapchain.get_swapchain_images_khr)(
+ device.handle(),
+ handle,
+ &mut count,
+ ptr::null_mut(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+
+ let mut images = Vec::with_capacity(count as usize);
+ let result = (fns.khr_swapchain.get_swapchain_images_khr)(
+ device.handle(),
+ handle,
+ &mut count,
+ images.as_mut_ptr(),
+ );
+
+ match result {
+ ash::vk::Result::SUCCESS => {
+ images.set_len(count as usize);
+ break images;
+ }
+ ash::vk::Result::INCOMPLETE => (),
+ err => return Err(VulkanError::from(err).into()),
+ }
+ };
+
+ Ok((handle, image_handles))
+ }
+
+ /// Returns the creation parameters of the swapchain.
#[inline]
- pub fn recreate(self: &Arc<Self>) -> SwapchainBuilder<W> {
- SwapchainBuilder {
- device: self.device().clone(),
- surface: self.surface().clone(),
-
- num_images: self.images.len() as u32,
- format: Some(self.format),
- color_space: self.color_space,
- dimensions: None,
- layers: self.layers,
- usage: self.usage,
- sharing_mode: self.sharing_mode.clone(),
- transform: self.transform,
+ pub fn create_info(&self) -> SwapchainCreateInfo {
+ SwapchainCreateInfo {
+ min_image_count: self.min_image_count,
+ image_format: Some(self.image_format),
+ image_color_space: self.image_color_space,
+ image_extent: self.image_extent,
+ image_array_layers: self.image_array_layers,
+ image_usage: self.image_usage,
+ image_sharing: self.image_sharing.clone(),
+ pre_transform: self.pre_transform,
composite_alpha: self.composite_alpha,
present_mode: self.present_mode,
- fullscreen_exclusive: self.fullscreen_exclusive,
clipped: self.clipped,
-
- old_swapchain: Some(self.clone()),
+ full_screen_exclusive: self.full_screen_exclusive,
+ win32_monitor: self.win32_monitor,
+ _ne: crate::NonExhaustive(()),
}
}
/// Returns the saved Surface, from the Swapchain creation.
#[inline]
- pub fn surface(&self) -> &Arc<Surface<W>> {
+ pub fn surface(&self) -> &Arc<Surface> {
&self.surface
}
- /// Returns of the images that belong to this swapchain.
+ /// If `image` is one of the images of this swapchain, returns its index within the swapchain.
#[inline]
- pub fn raw_image(&self, offset: usize) -> Option<ImageInner> {
- self.images.get(offset).map(|i| ImageInner {
- image: &i.image,
- first_layer: 0,
- num_layers: self.layers as usize,
- first_mipmap_level: 0,
- num_mipmap_levels: 1,
- })
+ pub fn index_of_image(&self, image: &Image) -> Option<u32> {
+ self.images
+ .iter()
+ .position(|entry| entry.handle == image.handle())
+ .map(|i| i as u32)
}
/// Returns the number of images of the swapchain.
#[inline]
- pub fn num_images(&self) -> u32 {
+ pub fn image_count(&self) -> u32 {
self.images.len() as u32
}
/// Returns the format of the images of the swapchain.
#[inline]
- pub fn format(&self) -> Format {
- self.format
+ pub fn image_format(&self) -> Format {
+ self.image_format
+ }
+
+ /// Returns the color space of the images of the swapchain.
+ #[inline]
+ pub fn image_color_space(&self) -> ColorSpace {
+ self.image_color_space
+ }
+
+ /// Returns the extent of the images of the swapchain.
+ #[inline]
+ pub fn image_extent(&self) -> [u32; 2] {
+ self.image_extent
+ }
+
+ /// Returns the number of array layers of the images of the swapchain.
+ #[inline]
+ pub fn image_array_layers(&self) -> u32 {
+ self.image_array_layers
+ }
+
+ /// Returns the usage of the images of the swapchain.
+ #[inline]
+ pub fn image_usage(&self) -> ImageUsage {
+ self.image_usage
+ }
+
+ /// Returns the sharing of the images of the swapchain.
+ #[inline]
+ pub fn image_sharing(&self) -> &Sharing<SmallVec<[u32; 4]>> {
+ &self.image_sharing
}
- /// Returns the dimensions of the images of the swapchain.
#[inline]
- pub fn dimensions(&self) -> [u32; 2] {
- self.dimensions
+ pub(crate) unsafe fn full_screen_exclusive_held(&self) -> &AtomicBool {
+ &self.full_screen_exclusive_held
}
- /// Returns the number of layers of the images of the swapchain.
#[inline]
- pub fn layers(&self) -> u32 {
- self.layers
+ pub(crate) unsafe fn try_claim_present_id(&self, present_id: NonZeroU64) -> bool {
+ let present_id = u64::from(present_id);
+ self.prev_present_id.fetch_max(present_id, Ordering::SeqCst) < present_id
}
- /// Returns the transform that was passed when creating the swapchain.
+ /// Returns the pre-transform that was passed when creating the swapchain.
#[inline]
- pub fn transform(&self) -> SurfaceTransform {
- self.transform
+ pub fn pre_transform(&self) -> SurfaceTransform {
+ self.pre_transform
}
/// Returns the alpha mode that was passed when creating the swapchain.
@@ -375,75 +803,81 @@ impl<W> Swapchain<W> {
self.clipped
}
- /// Returns the value of 'fullscreen_exclusive` that was passed when creating the swapchain.
+ /// Returns the value of 'full_screen_exclusive` that was passed when creating the swapchain.
#[inline]
- pub fn fullscreen_exclusive(&self) -> FullscreenExclusive {
- self.fullscreen_exclusive
+ pub fn full_screen_exclusive(&self) -> FullScreenExclusive {
+ self.full_screen_exclusive
}
- /// `FullscreenExclusive::AppControlled` must be the active fullscreen exclusivity mode.
- /// Acquire fullscreen exclusivity until either the `release_fullscreen_exclusive` is
- /// called, or if any of the the other `Swapchain` functions return `FullscreenExclusiveLost`.
- /// Requires: `FullscreenExclusive::AppControlled`
- pub fn acquire_fullscreen_exclusive(&self) -> Result<(), FullscreenExclusiveError> {
- if self.fullscreen_exclusive != FullscreenExclusive::AppControlled {
- return Err(FullscreenExclusiveError::NotAppControlled);
+ /// Acquires full-screen exclusivity.
+ ///
+ /// The swapchain must have been created with [`FullScreenExclusive::ApplicationControlled`],
+ /// and must not already hold full-screen exclusivity. Full-screen exclusivity is held until
+ /// either the `release_full_screen_exclusive` is called, or if any of the the other `Swapchain`
+ /// functions return `FullScreenExclusiveLost`.
+ #[inline]
+ pub fn acquire_full_screen_exclusive(&self) -> Result<(), FullScreenExclusiveError> {
+ if self.full_screen_exclusive != FullScreenExclusive::ApplicationControlled {
+ return Err(FullScreenExclusiveError::NotApplicationControlled);
}
- if self.fullscreen_exclusive_held.swap(true, Ordering::SeqCst) {
- return Err(FullscreenExclusiveError::DoubleAcquire);
+ if self.full_screen_exclusive_held.swap(true, Ordering::SeqCst) {
+ return Err(FullScreenExclusiveError::DoubleAcquire);
}
unsafe {
- check_errors(
- self.device
- .fns()
- .ext_full_screen_exclusive
- .acquire_full_screen_exclusive_mode_ext(
- self.device.internal_object(),
- self.swapchain,
- ),
- )?;
+ let fns = self.device.fns();
+ (fns.ext_full_screen_exclusive
+ .acquire_full_screen_exclusive_mode_ext)(
+ self.device.handle(), self.handle
+ )
+ .result()
+ .map_err(VulkanError::from)?;
}
Ok(())
}
- /// `FullscreenExclusive::AppControlled` must be the active fullscreen exclusivity mode.
- /// Release fullscreen exclusivity.
- pub fn release_fullscreen_exclusive(&self) -> Result<(), FullscreenExclusiveError> {
- if self.fullscreen_exclusive != FullscreenExclusive::AppControlled {
- return Err(FullscreenExclusiveError::NotAppControlled);
+ /// Releases full-screen exclusivity.
+ ///
+ /// The swapchain must have been created with [`FullScreenExclusive::ApplicationControlled`],
+ /// and must currently hold full-screen exclusivity.
+ #[inline]
+ pub fn release_full_screen_exclusive(&self) -> Result<(), FullScreenExclusiveError> {
+ if self.full_screen_exclusive != FullScreenExclusive::ApplicationControlled {
+ return Err(FullScreenExclusiveError::NotApplicationControlled);
}
- if !self.fullscreen_exclusive_held.swap(false, Ordering::SeqCst) {
- return Err(FullscreenExclusiveError::DoubleRelease);
+ if !self
+ .full_screen_exclusive_held
+ .swap(false, Ordering::SeqCst)
+ {
+ return Err(FullScreenExclusiveError::DoubleRelease);
}
unsafe {
- check_errors(
- self.device
- .fns()
- .ext_full_screen_exclusive
- .release_full_screen_exclusive_mode_ext(
- self.device.internal_object(),
- self.swapchain,
- ),
- )?;
+ let fns = self.device.fns();
+ (fns.ext_full_screen_exclusive
+ .release_full_screen_exclusive_mode_ext)(
+ self.device.handle(), self.handle
+ )
+ .result()
+ .map_err(VulkanError::from)?;
}
Ok(())
}
- /// `FullscreenExclusive::AppControlled` is not the active fullscreen exclusivity mode,
+ /// `FullScreenExclusive::AppControlled` is not the active full-screen exclusivity mode,
/// then this function will always return false. If true is returned the swapchain
- /// is in `FullscreenExclusive::AppControlled` fullscreen exclusivity mode and exclusivity
+ /// is in `FullScreenExclusive::AppControlled` full-screen exclusivity mode and exclusivity
/// is currently acquired.
- pub fn is_fullscreen_exclusive(&self) -> bool {
- if self.fullscreen_exclusive != FullscreenExclusive::AppControlled {
+ #[inline]
+ pub fn is_full_screen_exclusive(&self) -> bool {
+ if self.full_screen_exclusive != FullScreenExclusive::ApplicationControlled {
false
} else {
- self.fullscreen_exclusive_held.load(Ordering::SeqCst)
+ self.full_screen_exclusive_held.load(Ordering::SeqCst)
}
}
@@ -451,813 +885,870 @@ impl<W> Swapchain<W> {
// transitioned out of their initial `undefined` image layout.
//
// See the `ImageAccess::layout_initialized` method documentation for more details.
- pub(crate) fn image_layout_initialized(&self, image_offset: usize) {
- let image_entry = self.images.get(image_offset);
- if let Some(ref image_entry) = image_entry {
- image_entry.undefined_layout.store(false, Ordering::SeqCst);
+ pub(crate) fn image_layout_initialized(&self, image_index: u32) {
+ let image_entry = self.images.get(image_index as usize);
+ if let Some(image_entry) = image_entry {
+ image_entry
+ .layout_initialized
+ .store(true, Ordering::Relaxed);
}
}
- pub(crate) fn is_image_layout_initialized(&self, image_offset: usize) -> bool {
- let image_entry = self.images.get(image_offset);
- if let Some(ref image_entry) = image_entry {
- !image_entry.undefined_layout.load(Ordering::SeqCst)
+ pub(crate) fn is_image_layout_initialized(&self, image_index: u32) -> bool {
+ let image_entry = self.images.get(image_index as usize);
+ if let Some(image_entry) = image_entry {
+ image_entry.layout_initialized.load(Ordering::Relaxed)
} else {
false
}
}
}
-unsafe impl<W> VulkanObject for Swapchain<W> {
- type Object = ash::vk::SwapchainKHR;
-
+impl Drop for Swapchain {
#[inline]
- fn internal_object(&self) -> ash::vk::SwapchainKHR {
- self.swapchain
+ fn drop(&mut self) {
+ unsafe {
+ let fns = self.device.fns();
+ (fns.khr_swapchain.destroy_swapchain_khr)(
+ self.device.handle(),
+ self.handle,
+ ptr::null(),
+ );
+ self.surface.flag().store(false, Ordering::Release);
+ }
}
}
-unsafe impl<W> DeviceOwned for Swapchain<W> {
- fn device(&self) -> &Arc<Device> {
- &self.device
- }
-}
+unsafe impl VulkanObject for Swapchain {
+ type Handle = ash::vk::SwapchainKHR;
-impl<W> fmt::Debug for Swapchain<W> {
#[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(fmt, "<Vulkan swapchain {:?}>", self.swapchain)
+ fn handle(&self) -> Self::Handle {
+ self.handle
}
}
-impl<W> Drop for Swapchain<W> {
+unsafe impl DeviceOwned for Swapchain {
#[inline]
- fn drop(&mut self) {
- unsafe {
- let fns = self.device.fns();
- fns.khr_swapchain.destroy_swapchain_khr(
- self.device.internal_object(),
- self.swapchain,
- ptr::null(),
- );
- self.surface.flag().store(false, Ordering::Release);
- }
+ fn device(&self) -> &Arc<Device> {
+ &self.device
}
}
-/// Builder for a [`Swapchain`].
-#[derive(Debug)]
-pub struct SwapchainBuilder<W> {
- device: Arc<Device>,
- surface: Arc<Surface<W>>,
- old_swapchain: Option<Arc<Swapchain<W>>>,
-
- num_images: u32,
- format: Option<Format>, // None = use a default
- color_space: ColorSpace,
- dimensions: Option<[u32; 2]>,
- layers: u32,
- usage: ImageUsage,
- sharing_mode: SharingMode,
- transform: SurfaceTransform,
- composite_alpha: CompositeAlpha,
- present_mode: PresentMode,
- fullscreen_exclusive: FullscreenExclusive,
- clipped: bool,
-}
+impl_id_counter!(Swapchain);
-impl<W> SwapchainBuilder<W> {
- /// Builds a new swapchain. Allocates images who content can be made visible on a surface.
- ///
- /// See also the `Surface::get_capabilities` function which returns the values that are
- /// supported by the implementation. All the parameters that you pass to the builder
- /// must be supported.
- ///
- /// This function returns the swapchain plus a list of the images that belong to the
- /// swapchain. The order in which the images are returned is important for the
- /// `acquire_next_image` and `present` functions.
- ///
- /// # Panic
- ///
- /// - Panics if the device and the surface don't belong to the same instance.
- /// - Panics if `usage` is empty.
- ///
- // TODO: isn't it unsafe to take the surface through an Arc when it comes to vulkano-win?
- pub fn build(
- self,
- ) -> Result<(Arc<Swapchain<W>>, Vec<Arc<SwapchainImage<W>>>), SwapchainCreationError> {
- let SwapchainBuilder {
+impl Debug for Swapchain {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ let Self {
+ handle,
device,
surface,
- old_swapchain,
-
- num_images,
- format,
- color_space,
- dimensions,
- layers,
- usage,
- sharing_mode,
- transform,
+ id: _,
+ min_image_count,
+ image_format,
+ image_color_space,
+ image_extent,
+ image_array_layers,
+ image_usage,
+ image_sharing,
+ pre_transform,
composite_alpha,
present_mode,
- fullscreen_exclusive,
clipped,
+ full_screen_exclusive,
+ win32_monitor,
+ prev_present_id,
+ full_screen_exclusive_held,
+ images,
+ retired,
} = self;
- assert_eq!(
- device.instance().internal_object(),
- surface.instance().internal_object()
- );
-
- // Checking that the requested parameters match the capabilities.
- let capabilities = surface.capabilities(device.physical_device())?;
- if num_images < capabilities.min_image_count {
- return Err(SwapchainCreationError::UnsupportedMinImagesCount);
- }
- if let Some(c) = capabilities.max_image_count {
- if num_images > c {
- return Err(SwapchainCreationError::UnsupportedMaxImagesCount);
- }
- }
+ f.debug_struct("Swapchain")
+ .field("handle", &handle)
+ .field("device", &device.handle())
+ .field("surface", &surface.handle())
+ .field("min_image_count", &min_image_count)
+ .field("image_format", &image_format)
+ .field("image_color_space", &image_color_space)
+ .field("image_extent", &image_extent)
+ .field("image_array_layers", &image_array_layers)
+ .field("image_usage", &image_usage)
+ .field("image_sharing", &image_sharing)
+ .field("pre_transform", &pre_transform)
+ .field("composite_alpha", &composite_alpha)
+ .field("present_mode", &present_mode)
+ .field("clipped", &clipped)
+ .field("full_screen_exclusive", &full_screen_exclusive)
+ .field("win32_monitor", &win32_monitor)
+ .field("prev_present_id", &prev_present_id)
+ .field("full_screen_exclusive_held", &full_screen_exclusive_held)
+ .field("images", &images)
+ .field("retired", &retired)
+ .finish()
+ }
+}
- let format = {
- if let Some(format) = format {
- if !capabilities
- .supported_formats
- .iter()
- .any(|&(f, c)| f == format && c == color_space)
- {
- return Err(SwapchainCreationError::UnsupportedFormat);
- }
- format
- } else {
- if let Some(format) = [Format::R8G8B8A8Unorm, Format::B8G8R8A8Unorm]
- .iter()
- .copied()
- .find(|&format| {
- capabilities
- .supported_formats
- .iter()
- .any(|&(f, c)| f == format && c == color_space)
- })
- {
- format
- } else {
- return Err(SwapchainCreationError::UnsupportedFormat);
- }
- }
- };
+/// Parameters to create a new `Swapchain`.
+///
+/// Many of the values here must be supported by the physical device.
+/// [`PhysicalDevice`](crate::device::physical::PhysicalDevice) has several
+/// methods to query what is supported.
+#[derive(Clone, Debug)]
+pub struct SwapchainCreateInfo {
+ /// The minimum number of images that will be created.
+ ///
+ /// The implementation is allowed to create more than this number, but never less.
+ ///
+ /// The default value is `2`.
+ pub min_image_count: u32,
- let dimensions = if let Some(dimensions) = dimensions {
- if dimensions[0] < capabilities.min_image_extent[0] {
- return Err(SwapchainCreationError::UnsupportedDimensions);
- }
- if dimensions[1] < capabilities.min_image_extent[1] {
- return Err(SwapchainCreationError::UnsupportedDimensions);
- }
- if dimensions[0] > capabilities.max_image_extent[0] {
- return Err(SwapchainCreationError::UnsupportedDimensions);
- }
- if dimensions[1] > capabilities.max_image_extent[1] {
- return Err(SwapchainCreationError::UnsupportedDimensions);
- }
- dimensions
- } else {
- capabilities.current_extent.unwrap()
- };
- if layers < 1 || layers > capabilities.max_image_array_layers {
- return Err(SwapchainCreationError::UnsupportedArrayLayers);
- }
- if (ash::vk::ImageUsageFlags::from(usage)
- & ash::vk::ImageUsageFlags::from(capabilities.supported_usage_flags))
- != ash::vk::ImageUsageFlags::from(usage)
- {
- return Err(SwapchainCreationError::UnsupportedUsageFlags);
- }
- if !capabilities.supported_transforms.supports(transform) {
- return Err(SwapchainCreationError::UnsupportedSurfaceTransform);
- }
- if !capabilities
- .supported_composite_alpha
- .supports(composite_alpha)
- {
- return Err(SwapchainCreationError::UnsupportedCompositeAlpha);
- }
- if !capabilities.present_modes.supports(present_mode) {
- return Err(SwapchainCreationError::UnsupportedPresentMode);
- }
+ /// The format of the created images.
+ ///
+ /// If set to `None`, [`Format::R8G8B8A8_UNORM`] or [`Format::B8G8R8A8_UNORM`] will be selected,
+ /// based on which is supported by the surface.
+ ///
+ /// The default value is `None`.
+ pub image_format: Option<Format>,
- let flags = ImageCreateFlags::none();
-
- // check that the physical device supports the swapchain image configuration
- match device.image_format_properties(
- format,
- ImageType::Dim2d,
- ImageTiling::Optimal,
- usage,
- flags,
- ) {
- Ok(_) => (),
- Err(e) => {
- eprintln!("{}", e);
- return Err(SwapchainCreationError::UnsupportedImageConfiguration);
- }
- }
+ /// The color space of the created images.
+ ///
+ /// The default value is [`ColorSpace::SrgbNonLinear`].
+ pub image_color_space: ColorSpace,
- // If we recreate a swapchain, make sure that the surface is the same.
- if let Some(ref sc) = old_swapchain {
- if surface.internal_object() != sc.surface.internal_object() {
- return Err(SwapchainCreationError::OldSwapchainSurfaceMismatch);
- }
- } else {
- // Checking that the surface doesn't already have a swapchain.
- let has_already = surface.flag().swap(true, Ordering::AcqRel);
- if has_already {
- return Err(SwapchainCreationError::SurfaceInUse);
- }
- }
+ /// The extent of the created images.
+ ///
+ /// If any of the values is 0, the value of
+ /// [`SurfaceCapabilities::current_extent`](crate::swapchain::SurfaceCapabilities) will be used.
+ ///
+ /// The default value is `[0, 0]`.
+ pub image_extent: [u32; 2],
- if !device.enabled_extensions().khr_swapchain {
- return Err(SwapchainCreationError::MissingExtensionKHRSwapchain);
- }
+ /// The number of array layers of the created images.
+ ///
+ /// The default value is `1`.
+ pub image_array_layers: u32,
- let mut surface_full_screen_exclusive_info = None;
-
- // TODO: VK_EXT_FULL_SCREEN_EXCLUSIVE requires these extensions, so they should always
- // be enabled if it is. A separate check here is unnecessary; this should be checked at
- // device creation.
- if device.enabled_extensions().ext_full_screen_exclusive
- && surface
- .instance()
- .enabled_extensions()
- .khr_get_physical_device_properties2
- && surface
- .instance()
- .enabled_extensions()
- .khr_get_surface_capabilities2
- {
- surface_full_screen_exclusive_info = Some(ash::vk::SurfaceFullScreenExclusiveInfoEXT {
- full_screen_exclusive: fullscreen_exclusive.into(),
- ..Default::default()
- });
- }
+ /// How the created images will be used.
+ ///
+ /// The default value is [`ImageUsage::empty()`], which must be overridden.
+ pub image_usage: ImageUsage,
- let p_next = match surface_full_screen_exclusive_info.as_ref() {
- Some(some) => unsafe { mem::transmute(some as *const _) },
- None => ptr::null(),
- };
+ /// Whether the created images can be shared across multiple queues, or are limited to a single
+ /// queue.
+ ///
+ /// The default value is [`Sharing::Exclusive`].
+ pub image_sharing: Sharing<SmallVec<[u32; 4]>>,
- // Required by the specs.
- assert_ne!(usage, ImageUsage::none());
+ /// The transform that should be applied to an image before it is presented.
+ ///
+ /// The default value is [`SurfaceTransform::Identity`].
+ pub pre_transform: SurfaceTransform,
- if let Some(ref old_swapchain) = old_swapchain {
- let mut stale = old_swapchain.stale.lock().unwrap();
+ /// How alpha values of the pixels in the image are to be treated.
+ ///
+ /// The default value is [`CompositeAlpha::Opaque`].
+ pub composite_alpha: CompositeAlpha,
- // The swapchain has already been used to create a new one.
- if *stale {
- return Err(SwapchainCreationError::OldSwapchainAlreadyUsed);
- } else {
- // According to the documentation of VkSwapchainCreateInfoKHR:
- //
- // > Upon calling vkCreateSwapchainKHR with a oldSwapchain that is not VK_NULL_HANDLE,
- // > any images not acquired by the application may be freed by the implementation,
- // > which may occur even if creation of the new swapchain fails.
- //
- // Therefore, we set stale to true and keep it to true even if the call to `vkCreateSwapchainKHR` below fails.
- *stale = true;
- }
- }
+ /// How the swapchain should behave when multiple images are waiting in the queue to be
+ /// presented.
+ ///
+ /// The default is [`PresentMode::Fifo`].
+ pub present_mode: PresentMode,
- let fns = device.fns();
+ /// Whether the implementation is allowed to discard rendering operations that affect regions of
+ /// the surface which aren't visible. This is important to take into account if your fragment
+ /// shader has side-effects or if you want to read back the content of the image afterwards.
+ ///
+ /// The default value is `true`.
+ pub clipped: bool,
- let swapchain = unsafe {
- let (sh_mode, sh_count, sh_indices) = match sharing_mode {
- SharingMode::Exclusive => (ash::vk::SharingMode::EXCLUSIVE, 0, ptr::null()),
- SharingMode::Concurrent(ref ids) => (
- ash::vk::SharingMode::CONCURRENT,
- ids.len() as u32,
- ids.as_ptr(),
- ),
- };
+ /// How full-screen exclusivity is to be handled.
+ ///
+ /// If set to anything other than [`FullScreenExclusive::Default`], then the
+ /// [`ext_full_screen_exclusive`](crate::device::DeviceExtensions::ext_full_screen_exclusive)
+ /// extension must be enabled on the device.
+ ///
+ /// The default value is [`FullScreenExclusive::Default`].
+ pub full_screen_exclusive: FullScreenExclusive,
- let infos = ash::vk::SwapchainCreateInfoKHR {
- p_next,
- flags: ash::vk::SwapchainCreateFlagsKHR::empty(),
- surface: surface.internal_object(),
- min_image_count: num_images,
- image_format: format.into(),
- image_color_space: color_space.into(),
- image_extent: ash::vk::Extent2D {
- width: dimensions[0],
- height: dimensions[1],
- },
- image_array_layers: layers,
- image_usage: usage.into(),
- image_sharing_mode: sh_mode,
- queue_family_index_count: sh_count,
- p_queue_family_indices: sh_indices,
- pre_transform: transform.into(),
- composite_alpha: composite_alpha.into(),
- present_mode: present_mode.into(),
- clipped: if clipped {
- ash::vk::TRUE
- } else {
- ash::vk::FALSE
- },
- old_swapchain: if let Some(ref old_swapchain) = old_swapchain {
- old_swapchain.swapchain
- } else {
- ash::vk::SwapchainKHR::null()
- },
- ..Default::default()
- };
+ /// For Win32 surfaces, if `full_screen_exclusive` is
+ /// [`FullScreenExclusive::ApplicationControlled`], this specifies the monitor on which
+ /// full-screen exclusivity should be used.
+ ///
+ /// For this case, the value must be `Some`, and for all others it must be `None`.
+ ///
+ /// The default value is `None`.
+ pub win32_monitor: Option<Win32Monitor>,
- let mut output = MaybeUninit::uninit();
- check_errors(fns.khr_swapchain.create_swapchain_khr(
- device.internal_object(),
- &infos,
- ptr::null(),
- output.as_mut_ptr(),
- ))?;
- output.assume_init()
- };
+ pub _ne: crate::NonExhaustive,
+}
- let image_handles = unsafe {
- let mut num = 0;
- check_errors(fns.khr_swapchain.get_swapchain_images_khr(
- device.internal_object(),
- swapchain,
- &mut num,
- ptr::null_mut(),
- ))?;
+impl Default for SwapchainCreateInfo {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ min_image_count: 2,
+ image_format: None,
+ image_color_space: ColorSpace::SrgbNonLinear,
+ image_extent: [0, 0],
+ image_array_layers: 1,
+ image_usage: ImageUsage::empty(),
+ image_sharing: Sharing::Exclusive,
+ pre_transform: SurfaceTransform::Identity,
+ composite_alpha: CompositeAlpha::Opaque,
+ present_mode: PresentMode::Fifo,
+ clipped: true,
+ full_screen_exclusive: FullScreenExclusive::Default,
+ win32_monitor: None,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
- let mut images = Vec::with_capacity(num as usize);
- check_errors(fns.khr_swapchain.get_swapchain_images_khr(
- device.internal_object(),
- swapchain,
- &mut num,
- images.as_mut_ptr(),
- ))?;
- images.set_len(num as usize);
- images
- };
+/// Error that can happen when creating a `Swapchain`.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum SwapchainCreationError {
+ /// Not enough memory.
+ OomError(OomError),
- let images = image_handles
- .into_iter()
- .map(|image| unsafe {
- let dims = ImageDimensions::Dim2d {
- width: dimensions[0],
- height: dimensions[1],
- array_layers: layers,
- };
-
- let img = UnsafeImage::from_raw(
- device.clone(),
- image,
- usage,
- format,
- flags,
- dims,
- SampleCount::Sample1,
- 1,
- );
-
- ImageEntry {
- image: img,
- undefined_layout: AtomicBool::new(true),
- }
- })
- .collect::<Vec<_>>();
-
- let fullscreen_exclusive_held = old_swapchain
- .as_ref()
- .map(|old_swapchain| {
- if old_swapchain.fullscreen_exclusive != FullscreenExclusive::AppControlled {
- false
- } else {
- old_swapchain
- .fullscreen_exclusive_held
- .load(Ordering::SeqCst)
- }
- })
- .unwrap_or(false);
+ /// The device was lost.
+ DeviceLost,
- let swapchain = Arc::new(Swapchain {
- device: device.clone(),
- surface: surface.clone(),
- swapchain,
- images,
- stale: Mutex::new(false),
- num_images,
- format,
- color_space,
- dimensions,
- layers,
- usage: usage.clone(),
- sharing_mode,
- transform,
- composite_alpha,
- present_mode,
- fullscreen_exclusive,
- fullscreen_exclusive_held: AtomicBool::new(fullscreen_exclusive_held),
- clipped,
- });
+ /// The surface was lost.
+ SurfaceLost,
- let swapchain_images = unsafe {
- let mut swapchain_images = Vec::with_capacity(swapchain.images.len());
- for n in 0..swapchain.images.len() {
- swapchain_images.push(SwapchainImage::from_raw(swapchain.clone(), n)?);
- }
- swapchain_images
- };
+ /// The surface is already used by another swapchain.
+ SurfaceInUse,
- Ok((swapchain, swapchain_images))
- }
+ /// The window is already in use by another API.
+ NativeWindowInUse,
- /// Sets the number of images that will be created.
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+
+ /// The provided `composite_alpha` is not supported by the surface for this device.
+ CompositeAlphaNotSupported {
+ provided: CompositeAlpha,
+ supported: CompositeAlphas,
+ },
+
+ /// The provided `format` and `color_space` are not supported by the surface for this device.
+ FormatColorSpaceNotSupported,
+
+ /// The provided `image_array_layers` is greater than what is supported by the surface for this
+ /// device.
+ ImageArrayLayersNotSupported { provided: u32, max_supported: u32 },
+
+ /// The provided `image_extent` is not within the range supported by the surface for this
+ /// device.
+ ImageExtentNotSupported {
+ provided: [u32; 2],
+ min_supported: [u32; 2],
+ max_supported: [u32; 2],
+ },
+
+ /// The provided `image_extent` contained at least one dimension of zero length.
+ /// This is prohibited by [VUID-VkSwapchainCreateInfoKHR-imageExtent-01689](https://khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkSwapchainCreateInfoKHR.html#VUID-VkSwapchainCreateInfoKHR-imageExtent-01689)
+ /// which requires both the width and height be non-zero.
///
- /// The default is 2.
- #[inline]
- pub fn num_images(mut self, num_images: u32) -> Self {
- self.num_images = num_images;
- self
- }
+ /// This error is distinct from `ImageExtentNotSupported` because a surface's minimum supported
+ /// length may not enforce this rule.
+ ImageExtentZeroLengthDimensions,
+
+ /// The provided image parameters are not supported as queried from `image_format_properties`.
+ ImageFormatPropertiesNotSupported,
+
+ /// The provided `image_sharing` was set to `Concurrent`, but one of the specified queue family
+ /// indices was out of range.
+ ImageSharingQueueFamilyIndexOutOfRange {
+ queue_family_index: u32,
+ queue_family_count: u32,
+ },
+
+ /// The provided `image_usage` has fields set that are not supported by the surface for this
+ /// device.
+ ImageUsageNotSupported {
+ provided: ImageUsage,
+ supported: ImageUsage,
+ },
+
+ /// The provided `min_image_count` is not within the range supported by the surface for this
+ /// device.
+ MinImageCountNotSupported {
+ provided: u32,
+ min_supported: u32,
+ max_supported: Option<u32>,
+ },
+
+ /// The provided `present_mode` is not supported by the surface for this device.
+ PresentModeNotSupported,
+
+ /// The provided `pre_transform` is not supported by the surface for this device.
+ PreTransformNotSupported {
+ provided: SurfaceTransform,
+ supported: SurfaceTransforms,
+ },
+
+ /// The provided `surface` is not supported by any of the device's queue families.
+ SurfaceNotSupported,
+
+ /// The swapchain has already been used to create a new one.
+ SwapchainAlreadyRetired,
+
+ /// The `win32_monitor` value was `Some` when it must be `None` or vice-versa.
+ Win32MonitorInvalid,
+}
- /// Sets the pixel format that will be used for the images.
- ///
- /// The default is either `R8G8B8A8Unorm` or `B8G8R8A8Unorm`, whichever is supported.
- #[inline]
- pub fn format(mut self, format: Format) -> Self {
- self.format = Some(format);
- self
+impl Error for SwapchainCreationError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::OomError(err) => Some(err),
+ _ => None,
+ }
}
+}
- /// Sets the color space that will be used for the images.
- ///
- /// The default is `SrgbNonLinear`.
- #[inline]
- pub fn color_space(mut self, color_space: ColorSpace) -> Self {
- self.color_space = color_space;
- self
+impl Display for SwapchainCreationError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::OomError(_) => write!(f, "not enough memory available"),
+ Self::DeviceLost => write!(f, "the device was lost"),
+ Self::SurfaceLost => write!(f, "the surface was lost"),
+ Self::SurfaceInUse => {
+ write!(f, "the surface is already used by another swapchain")
+ }
+ Self::NativeWindowInUse => {
+ write!(f, "the window is already in use by another API")
+ }
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ Self::CompositeAlphaNotSupported { .. } => write!(
+ f,
+ "the provided `composite_alpha` is not supported by the surface for this device",
+ ),
+ Self::FormatColorSpaceNotSupported => write!(
+ f,
+ "the provided `format` and `color_space` are not supported by the surface for this \
+ device",
+ ),
+ Self::ImageArrayLayersNotSupported {
+ provided,
+ max_supported,
+ } => write!(
+ f,
+ "the provided `image_array_layers` ({}) is greater than what is supported ({}) by \
+ the surface for this device",
+ provided, max_supported,
+ ),
+ Self::ImageExtentNotSupported {
+ provided,
+ min_supported,
+ max_supported,
+ } => write!(
+ f,
+ "the provided `image_extent` ({:?}) is not within the range (min: {:?}, max: {:?}) \
+ supported by the surface for this device",
+ provided, min_supported, max_supported,
+ ),
+ Self::ImageExtentZeroLengthDimensions => write!(
+ f,
+ "the provided `image_extent` contained at least one dimension of zero length",
+ ),
+ Self::ImageFormatPropertiesNotSupported => write!(
+ f,
+ "the provided image parameters are not supported as queried from \
+ `image_format_properties`",
+ ),
+ Self::ImageSharingQueueFamilyIndexOutOfRange {
+ queue_family_index,
+ queue_family_count: _,
+ } => write!(
+ f,
+ "the provided `image_sharing` was set to `Concurrent`, but one of the specified \
+ queue family indices ({}) was out of range",
+ queue_family_index,
+ ),
+ Self::ImageUsageNotSupported { .. } => write!(
+ f,
+ "the provided `image_usage` has fields set that are not supported by the surface \
+ for this device",
+ ),
+ Self::MinImageCountNotSupported {
+ provided,
+ min_supported,
+ max_supported,
+ } => write!(
+ f,
+ "the provided `min_image_count` ({}) is not within the range (min: {}, max: {:?}) \
+ supported by the surface for this device",
+ provided, min_supported, max_supported,
+ ),
+ Self::PresentModeNotSupported => write!(
+ f,
+ "the provided `present_mode` is not supported by the surface for this device",
+ ),
+ Self::PreTransformNotSupported { .. } => write!(
+ f,
+ "the provided `pre_transform` is not supported by the surface for this device",
+ ),
+ Self::SurfaceNotSupported => write!(
+ f,
+ "the provided `surface` is not supported by any of the device's queue families",
+ ),
+ Self::SwapchainAlreadyRetired => {
+ write!(f, "the swapchain has already been used to create a new one")
+ }
+ Self::Win32MonitorInvalid => write!(
+ f,
+ "the `win32_monitor` value was `Some` when it must be `None` or vice-versa",
+ ),
+ }
}
+}
- /// Sets the dimensions of the images.
- ///
- /// The default is `None`, which means the value of
- /// [`Capabilities::current_extent`](crate::swapchain::Capabilities::current_extent) will be
- /// used. Setting this will override it with a custom `Some` value.
- #[inline]
- pub fn dimensions(mut self, dimensions: [u32; 2]) -> Self {
- self.dimensions = Some(dimensions);
- self
+impl From<VulkanError> for SwapchainCreationError {
+ fn from(err: VulkanError) -> SwapchainCreationError {
+ match err {
+ err @ VulkanError::OutOfHostMemory => Self::OomError(OomError::from(err)),
+ err @ VulkanError::OutOfDeviceMemory => Self::OomError(OomError::from(err)),
+ VulkanError::DeviceLost => Self::DeviceLost,
+ VulkanError::SurfaceLost => Self::SurfaceLost,
+ VulkanError::NativeWindowInUse => Self::NativeWindowInUse,
+ _ => panic!("unexpected error: {:?}", err),
+ }
}
+}
- /// Sets the number of layers for each image.
- ///
- /// The default is 1.
- #[inline]
- pub fn layers(mut self, layers: u32) -> Self {
- self.layers = layers;
- self
+impl From<OomError> for SwapchainCreationError {
+ fn from(err: OomError) -> SwapchainCreationError {
+ Self::OomError(err)
}
+}
- /// Sets how the images will be used.
- ///
- /// The default is `ImageUsage::none()`.
- #[inline]
- pub fn usage(mut self, usage: ImageUsage) -> Self {
- self.usage = usage;
- self
+impl From<RequirementNotMet> for SwapchainCreationError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
+ }
}
+}
- /// Sets the sharing mode of the images.
- ///
- /// The default is `Exclusive`.
- #[inline]
- pub fn sharing_mode<S>(mut self, sharing_mode: S) -> Self
- where
- S: Into<SharingMode>,
- {
- self.sharing_mode = sharing_mode.into();
- self
- }
+vulkan_enum! {
+ #[non_exhaustive]
- /// Sets the transform that is to be applied to the surface.
- ///
- /// The default is `Identity`.
- #[inline]
- pub fn transform(mut self, transform: SurfaceTransform) -> Self {
- self.transform = transform;
- self
- }
+ /// The way full-screen exclusivity is handled.
+ FullScreenExclusive = FullScreenExclusiveEXT(i32);
- /// Sets how alpha values of the pixels in the image are to be treated.
- ///
- /// The default is `Opaque`.
- #[inline]
- pub fn composite_alpha(mut self, composite_alpha: CompositeAlpha) -> Self {
- self.composite_alpha = composite_alpha;
- self
- }
+ /// Indicates that the driver should determine the appropriate full-screen method
+ /// by whatever means it deems appropriate.
+ Default = DEFAULT,
- /// Sets the present mode for the swapchain.
- ///
- /// The default is `Fifo`.
- #[inline]
- pub fn present_mode(mut self, present_mode: PresentMode) -> Self {
- self.present_mode = present_mode;
- self
- }
+ /// Indicates that the driver may use full-screen exclusive mechanisms when available.
+ /// Such mechanisms may result in better performance and/or the availability of
+ /// different presentation capabilities, but may require a more disruptive transition
+ // during swapchain initialization, first presentation and/or destruction.
+ Allowed = ALLOWED,
- /// Sets how fullscreen exclusivity is to be handled.
- ///
- /// The default is `Default`.
- #[inline]
- pub fn fullscreen_exclusive(mut self, fullscreen_exclusive: FullscreenExclusive) -> Self {
- self.fullscreen_exclusive = fullscreen_exclusive;
- self
- }
+ /// Indicates that the driver should avoid using full-screen mechanisms which rely
+ /// on disruptive transitions.
+ Disallowed = DISALLOWED,
+
+ /// Indicates the application will manage full-screen exclusive mode by using the
+ /// [`Swapchain::acquire_full_screen_exclusive()`] and
+ /// [`Swapchain::release_full_screen_exclusive()`] functions.
+ ApplicationControlled = APPLICATION_CONTROLLED,
+}
+
+/// A wrapper around a Win32 monitor handle.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct Win32Monitor(pub(crate) ash::vk::HMONITOR);
- /// Sets whether the implementation is allowed to discard rendering operations that affect
- /// regions of the surface which aren't visible. This is important to take into account if
- /// your fragment shader has side-effects or if you want to read back the content of the image
- /// afterwards.
+impl Win32Monitor {
+ /// Wraps a Win32 monitor handle.
///
- /// The default is `true`.
- #[inline]
- pub fn clipped(mut self, clipped: bool) -> Self {
- self.clipped = clipped;
- self
+ /// # Safety
+ ///
+ /// - `hmonitor` must be a valid handle as returned by the Win32 API.
+ pub unsafe fn new<T>(hmonitor: *const T) -> Self {
+ Self(hmonitor as _)
}
}
-/// Error that can happen when creation a swapchain.
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum SwapchainCreationError {
+// Winit's `MonitorHandle` is Send on Win32, so this seems safe.
+unsafe impl Send for Win32Monitor {}
+unsafe impl Sync for Win32Monitor {}
+
+/// Error that can happen when calling `Swapchain::acquire_full_screen_exclusive` or
+/// `Swapchain::release_full_screen_exclusive`.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum FullScreenExclusiveError {
/// Not enough memory.
OomError(OomError),
- /// The device was lost.
- DeviceLost,
- /// The surface was lost.
+
+ /// Operation could not be completed for driver specific reasons.
+ InitializationFailed,
+
+ /// The surface is no longer accessible and must be recreated.
SurfaceLost,
- /// The surface is already used by another swapchain.
- SurfaceInUse,
- /// The window is already in use by another API.
- NativeWindowInUse,
- /// The `VK_KHR_swapchain` extension was not enabled.
- MissingExtensionKHRSwapchain,
- /// The `VK_EXT_full_screen_exclusive` extension was not enabled.
- MissingExtensionExtFullScreenExclusive,
- /// Surface mismatch between old and new swapchain.
- OldSwapchainSurfaceMismatch,
- /// The old swapchain has already been used to recreate another one.
- OldSwapchainAlreadyUsed,
- /// The requested number of swapchain images is not supported by the surface.
- UnsupportedMinImagesCount,
- /// The requested number of swapchain images is not supported by the surface.
- UnsupportedMaxImagesCount,
- /// The requested image format is not supported by the surface.
- UnsupportedFormat,
- /// The requested dimensions are not supported by the surface.
- UnsupportedDimensions,
- /// The requested array layers count is not supported by the surface.
- UnsupportedArrayLayers,
- /// The requested image usage is not supported by the surface.
- UnsupportedUsageFlags,
- /// The requested surface transform is not supported by the surface.
- UnsupportedSurfaceTransform,
- /// The requested composite alpha is not supported by the surface.
- UnsupportedCompositeAlpha,
- /// The requested present mode is not supported by the surface.
- UnsupportedPresentMode,
- /// The image configuration is not supported by the physical device.
- UnsupportedImageConfiguration,
+
+ /// Full-screen exclusivity is already acquired.
+ DoubleAcquire,
+
+ /// Full-screen exclusivity is not currently acquired.
+ DoubleRelease,
+
+ /// The swapchain is not in full-screen exclusive application controlled mode.
+ NotApplicationControlled,
}
-impl error::Error for SwapchainCreationError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- SwapchainCreationError::OomError(ref err) => Some(err),
+impl Error for FullScreenExclusiveError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ FullScreenExclusiveError::OomError(err) => Some(err),
_ => None,
}
}
}
-impl fmt::Display for SwapchainCreationError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+impl Display for FullScreenExclusiveError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
write!(
- fmt,
+ f,
"{}",
- match *self {
- SwapchainCreationError::OomError(_) => "not enough memory available",
- SwapchainCreationError::DeviceLost => "the device was lost",
- SwapchainCreationError::SurfaceLost => "the surface was lost",
- SwapchainCreationError::SurfaceInUse => {
- "the surface is already used by another swapchain"
- }
- SwapchainCreationError::NativeWindowInUse => {
- "the window is already in use by another API"
- }
- SwapchainCreationError::MissingExtensionKHRSwapchain => {
- "the `VK_KHR_swapchain` extension was not enabled"
- }
- SwapchainCreationError::MissingExtensionExtFullScreenExclusive => {
- "the `VK_EXT_full_screen_exclusive` extension was not enabled"
- }
- SwapchainCreationError::OldSwapchainSurfaceMismatch => {
- "surface mismatch between old and new swapchain"
- }
- SwapchainCreationError::OldSwapchainAlreadyUsed => {
- "old swapchain has already been used to recreate a new one"
- }
- SwapchainCreationError::UnsupportedMinImagesCount => {
- "the requested number of swapchain images is not supported by the surface"
- }
- SwapchainCreationError::UnsupportedMaxImagesCount => {
- "the requested number of swapchain images is not supported by the surface"
- }
- SwapchainCreationError::UnsupportedFormat => {
- "the requested image format is not supported by the surface"
- }
- SwapchainCreationError::UnsupportedDimensions => {
- "the requested dimensions are not supported by the surface"
- }
- SwapchainCreationError::UnsupportedArrayLayers => {
- "the requested array layers count is not supported by the surface"
- }
- SwapchainCreationError::UnsupportedUsageFlags => {
- "the requested image usage is not supported by the surface"
- }
- SwapchainCreationError::UnsupportedSurfaceTransform => {
- "the requested surface transform is not supported by the surface"
- }
- SwapchainCreationError::UnsupportedCompositeAlpha => {
- "the requested composite alpha is not supported by the surface"
+ match self {
+ FullScreenExclusiveError::OomError(_) => "not enough memory",
+ FullScreenExclusiveError::SurfaceLost => {
+ "the surface of this swapchain is no longer valid"
}
- SwapchainCreationError::UnsupportedPresentMode => {
- "the requested present mode is not supported by the surface"
+ FullScreenExclusiveError::InitializationFailed => {
+ "operation could not be completed for driver specific reasons"
}
- SwapchainCreationError::UnsupportedImageConfiguration => {
- "the requested image configuration is not supported by the physical device"
+ FullScreenExclusiveError::DoubleAcquire =>
+ "full-screen exclusivity is already acquired",
+ FullScreenExclusiveError::DoubleRelease =>
+ "full-screen exclusivity is not acquired",
+ FullScreenExclusiveError::NotApplicationControlled => {
+ "the swapchain is not in full-screen exclusive application controlled mode"
}
}
)
}
}
-impl From<Error> for SwapchainCreationError {
- #[inline]
- fn from(err: Error) -> SwapchainCreationError {
+impl From<VulkanError> for FullScreenExclusiveError {
+ fn from(err: VulkanError) -> FullScreenExclusiveError {
match err {
- err @ Error::OutOfHostMemory => SwapchainCreationError::OomError(OomError::from(err)),
- err @ Error::OutOfDeviceMemory => SwapchainCreationError::OomError(OomError::from(err)),
- Error::DeviceLost => SwapchainCreationError::DeviceLost,
- Error::SurfaceLost => SwapchainCreationError::SurfaceLost,
- Error::NativeWindowInUse => SwapchainCreationError::NativeWindowInUse,
+ err @ VulkanError::OutOfHostMemory => {
+ FullScreenExclusiveError::OomError(OomError::from(err))
+ }
+ err @ VulkanError::OutOfDeviceMemory => {
+ FullScreenExclusiveError::OomError(OomError::from(err))
+ }
+ VulkanError::SurfaceLost => FullScreenExclusiveError::SurfaceLost,
+ VulkanError::InitializationFailed => FullScreenExclusiveError::InitializationFailed,
_ => panic!("unexpected error: {:?}", err),
}
}
}
-impl From<OomError> for SwapchainCreationError {
- #[inline]
- fn from(err: OomError) -> SwapchainCreationError {
- SwapchainCreationError::OomError(err)
+impl From<OomError> for FullScreenExclusiveError {
+ fn from(err: OomError) -> FullScreenExclusiveError {
+ FullScreenExclusiveError::OomError(err)
}
}
-impl From<CapabilitiesError> for SwapchainCreationError {
- #[inline]
- fn from(err: CapabilitiesError) -> SwapchainCreationError {
- match err {
- CapabilitiesError::OomError(err) => SwapchainCreationError::OomError(err),
- CapabilitiesError::SurfaceLost => SwapchainCreationError::SurfaceLost,
+/// Tries to take ownership of an image in order to draw on it.
+///
+/// The function returns the index of the image in the array of images that was returned
+/// when creating the swapchain, plus a future that represents the moment when the image will
+/// become available from the GPU (which may not be *immediately*).
+///
+/// If you try to draw on an image without acquiring it first, the execution will block. (TODO
+/// behavior may change).
+///
+/// The second field in the tuple in the Ok result is a bool represent if the acquisition was
+/// suboptimal. In this case the acquired image is still usable, but the swapchain should be
+/// recreated as the Surface's properties no longer match the swapchain.
+pub fn acquire_next_image(
+ swapchain: Arc<Swapchain>,
+ timeout: Option<Duration>,
+) -> Result<(u32, bool, SwapchainAcquireFuture), AcquireError> {
+ let semaphore = Arc::new(Semaphore::from_pool(swapchain.device.clone())?);
+ let fence = Fence::from_pool(swapchain.device.clone())?;
+
+ let AcquiredImage {
+ image_index,
+ suboptimal,
+ } = {
+ // Check that this is not an old swapchain. From specs:
+ // > swapchain must not have been replaced by being passed as the
+ // > VkSwapchainCreateInfoKHR::oldSwapchain value to vkCreateSwapchainKHR
+ let retired = swapchain.retired.lock();
+ if *retired {
+ return Err(AcquireError::OutOfDate);
+ }
+
+ let acquire_result =
+ unsafe { acquire_next_image_raw(&swapchain, timeout, Some(&semaphore), Some(&fence)) };
+
+ if let &Err(AcquireError::FullScreenExclusiveModeLost) = &acquire_result {
+ swapchain
+ .full_screen_exclusive_held
+ .store(false, Ordering::SeqCst);
+ }
+
+ acquire_result?
+ };
+
+ Ok((
+ image_index,
+ suboptimal,
+ SwapchainAcquireFuture {
+ swapchain,
+ semaphore: Some(semaphore),
+ fence: Some(fence),
+ image_index,
+ finished: AtomicBool::new(false),
+ },
+ ))
+}
+
+/// Presents an image on the screen.
+///
+/// The actual behavior depends on the present mode that you passed when creating the swapchain.
+pub fn present<F>(
+ before: F,
+ queue: Arc<Queue>,
+ swapchain_info: SwapchainPresentInfo,
+) -> PresentFuture<F>
+where
+ F: GpuFuture,
+{
+ assert!(swapchain_info.image_index < swapchain_info.swapchain.image_count());
+
+ // TODO: restore this check with a dummy ImageAccess implementation
+ /*let swapchain_image = me.images.lock().unwrap().get(index).unwrap().0.upgrade().unwrap(); // TODO: return error instead
+ // Normally if `check_image_access` returns false we're supposed to call the `gpu_access`
+ // function on the image instead. But since we know that this method on `SwapchainImage`
+ // always returns false anyway (by design), we don't need to do it.
+ assert!(before.check_image_access(&swapchain_image, ImageLayout::PresentSrc, true, &queue).is_ok()); // TODO: return error instead*/
+
+ PresentFuture {
+ previous: before,
+ queue,
+ swapchain_info,
+ flushed: AtomicBool::new(false),
+ finished: AtomicBool::new(false),
+ }
+}
+
+/// Wait for an image to be presented to the user. Must be used with a `present_id` given to
+/// `present_with_id`.
+///
+/// Returns a bool to represent if the presentation was suboptimal. In this case the swapchain is
+/// still usable, but the swapchain should be recreated as the Surface's properties no longer match
+/// the swapchain.
+pub fn wait_for_present(
+ swapchain: Arc<Swapchain>,
+ present_id: u64,
+ timeout: Option<Duration>,
+) -> Result<bool, PresentWaitError> {
+ let retired = swapchain.retired.lock();
+
+ // VUID-vkWaitForPresentKHR-swapchain-04997
+ if *retired {
+ return Err(PresentWaitError::OutOfDate);
+ }
+
+ if present_id == 0 {
+ return Err(PresentWaitError::PresentIdZero);
+ }
+
+ // VUID-vkWaitForPresentKHR-presentWait-06234
+ if !swapchain.device.enabled_features().present_wait {
+ return Err(PresentWaitError::RequirementNotMet {
+ required_for: "`wait_for_present`",
+ requires_one_of: RequiresOneOf {
+ features: &["present_wait"],
+ ..Default::default()
+ },
+ });
+ }
+
+ let timeout_ns = timeout.map(|dur| dur.as_nanos() as u64).unwrap_or(0);
+
+ let result = unsafe {
+ (swapchain.device.fns().khr_present_wait.wait_for_present_khr)(
+ swapchain.device.handle(),
+ swapchain.handle,
+ present_id,
+ timeout_ns,
+ )
+ };
+
+ match result {
+ ash::vk::Result::SUCCESS => Ok(false),
+ ash::vk::Result::SUBOPTIMAL_KHR => Ok(true),
+ ash::vk::Result::TIMEOUT => Err(PresentWaitError::Timeout),
+ err => {
+ let err = VulkanError::from(err).into();
+
+ if let PresentWaitError::FullScreenExclusiveModeLost = &err {
+ swapchain
+ .full_screen_exclusive_held
+ .store(false, Ordering::SeqCst);
+ }
+
+ Err(err)
}
}
}
/// Represents the moment when the GPU will have access to a swapchain image.
#[must_use]
-pub struct SwapchainAcquireFuture<W> {
- swapchain: Arc<Swapchain<W>>,
- image_id: usize,
+pub struct SwapchainAcquireFuture {
+ swapchain: Arc<Swapchain>,
+ image_index: u32,
// Semaphore that is signalled when the acquire is complete. Empty if the acquire has already
// happened.
- semaphore: Option<Semaphore>,
+ semaphore: Option<Arc<Semaphore>>,
// Fence that is signalled when the acquire is complete. Empty if the acquire has already
// happened.
fence: Option<Fence>,
finished: AtomicBool,
}
-impl<W> SwapchainAcquireFuture<W> {
+impl SwapchainAcquireFuture {
/// Returns the index of the image in the list of images returned when creating the swapchain.
- #[inline]
- pub fn image_id(&self) -> usize {
- self.image_id
+ pub fn image_index(&self) -> u32 {
+ self.image_index
}
/// Returns the corresponding swapchain.
- #[inline]
- pub fn swapchain(&self) -> &Arc<Swapchain<W>> {
+ pub fn swapchain(&self) -> &Arc<Swapchain> {
&self.swapchain
}
+
+ /// Blocks the current thread until the swapchain image has been acquired, or timeout
+ ///
+ /// If timeout is `None`, will potentially block forever
+ ///
+ /// You still need to join with this future for present to work
+ pub fn wait(&self, timeout: Option<Duration>) -> Result<(), FenceError> {
+ match &self.fence {
+ Some(fence) => fence.wait(timeout),
+ None => Ok(()),
+ }
+ }
}
-unsafe impl<W> GpuFuture for SwapchainAcquireFuture<W> {
- #[inline]
+unsafe impl GpuFuture for SwapchainAcquireFuture {
fn cleanup_finished(&mut self) {}
- #[inline]
unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
if let Some(ref semaphore) = self.semaphore {
- let mut sem = SubmitSemaphoresWaitBuilder::new();
- sem.add_wait_semaphore(&semaphore);
+ let sem = smallvec![semaphore.clone()];
Ok(SubmitAnyBuilder::SemaphoresWait(sem))
} else {
Ok(SubmitAnyBuilder::Empty)
}
}
- #[inline]
fn flush(&self) -> Result<(), FlushError> {
Ok(())
}
- #[inline]
unsafe fn signal_finished(&self) {
self.finished.store(true, Ordering::SeqCst);
}
- #[inline]
fn queue_change_allowed(&self) -> bool {
true
}
- #[inline]
fn queue(&self) -> Option<Arc<Queue>> {
None
}
- #[inline]
fn check_buffer_access(
&self,
- _: &dyn BufferAccess,
- _: bool,
- _: &Queue,
- ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
+ _buffer: &Buffer,
+ _range: Range<DeviceSize>,
+ _exclusive: bool,
+ _queue: &Queue,
+ ) -> Result<(), AccessCheckError> {
Err(AccessCheckError::Unknown)
}
- #[inline]
fn check_image_access(
&self,
- image: &dyn ImageAccess,
- layout: ImageLayout,
- _: bool,
- _: &Queue,
- ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
- let swapchain_image = self.swapchain.raw_image(self.image_id).unwrap();
- if swapchain_image.image.internal_object() != image.inner().image.internal_object() {
+ image: &Image,
+ _range: Range<DeviceSize>,
+ _exclusive: bool,
+ expected_layout: ImageLayout,
+ _queue: &Queue,
+ ) -> Result<(), AccessCheckError> {
+ if self.swapchain.index_of_image(image) != Some(self.image_index) {
return Err(AccessCheckError::Unknown);
}
- if self.swapchain.images[self.image_id]
- .undefined_layout
+ if !self.swapchain.images[self.image_index as usize]
+ .layout_initialized
.load(Ordering::Relaxed)
- && layout != ImageLayout::Undefined
+ && expected_layout != ImageLayout::Undefined
{
return Err(AccessCheckError::Denied(AccessError::ImageNotInitialized {
- requested: layout,
+ requested: expected_layout,
}));
}
- if layout != ImageLayout::Undefined && layout != ImageLayout::PresentSrc {
+ if expected_layout != ImageLayout::Undefined && expected_layout != ImageLayout::PresentSrc {
return Err(AccessCheckError::Denied(
AccessError::UnexpectedImageLayout {
allowed: ImageLayout::PresentSrc,
- requested: layout,
+ requested: expected_layout,
},
));
}
- Ok(None)
+ Ok(())
}
-}
-unsafe impl<W> DeviceOwned for SwapchainAcquireFuture<W> {
#[inline]
- fn device(&self) -> &Arc<Device> {
- &self.swapchain.device
+ fn check_swapchain_image_acquired(
+ &self,
+ swapchain: &Swapchain,
+ image_index: u32,
+ before: bool,
+ ) -> Result<(), AccessCheckError> {
+ if before {
+ Ok(())
+ } else {
+ if swapchain == self.swapchain.as_ref() && image_index == self.image_index {
+ Ok(())
+ } else {
+ Err(AccessCheckError::Unknown)
+ }
+ }
}
}
-impl<W> Drop for SwapchainAcquireFuture<W> {
+impl Drop for SwapchainAcquireFuture {
fn drop(&mut self) {
- if let Some(ref fence) = self.fence {
+ if thread::panicking() {
+ return;
+ }
+
+ if let Some(fence) = &self.fence {
fence.wait(None).unwrap(); // TODO: handle error?
self.semaphore = None;
}
@@ -1267,168 +1758,195 @@ impl<W> Drop for SwapchainAcquireFuture<W> {
}
}
-/// Error that can happen when calling `Swapchain::acquire_fullscreen_exclusive` or `Swapchain::release_fullscreen_exclusive`
+unsafe impl DeviceOwned for SwapchainAcquireFuture {
+ fn device(&self) -> &Arc<Device> {
+ &self.swapchain.device
+ }
+}
+
+/// Error that can happen when calling `acquire_next_image`.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u32)]
-pub enum FullscreenExclusiveError {
+pub enum AcquireError {
/// Not enough memory.
OomError(OomError),
- /// Operation could not be completed for driver specific reasons.
- InitializationFailed,
+ /// The connection to the device has been lost.
+ DeviceLost,
+
+ /// The timeout of the function has been reached before an image was available.
+ Timeout,
/// The surface is no longer accessible and must be recreated.
SurfaceLost,
- /// Fullscreen exclusivity is already acquired.
- DoubleAcquire,
-
- /// Fullscreen exclusivity is not current acquired.
- DoubleRelease,
+ /// The swapchain has lost or doesn't have full-screen exclusivity possibly for
+ /// implementation-specific reasons outside of the application’s control.
+ FullScreenExclusiveModeLost,
- /// Swapchain is not in fullscreen exclusive app controlled mode
- NotAppControlled,
-}
+ /// The surface has changed in a way that makes the swapchain unusable. You must query the
+ /// surface's new properties and recreate a new swapchain if you want to continue drawing.
+ OutOfDate,
-impl From<Error> for FullscreenExclusiveError {
- #[inline]
- fn from(err: Error) -> FullscreenExclusiveError {
- match err {
- err @ Error::OutOfHostMemory => FullscreenExclusiveError::OomError(OomError::from(err)),
- err @ Error::OutOfDeviceMemory => {
- FullscreenExclusiveError::OomError(OomError::from(err))
- }
- Error::SurfaceLost => FullscreenExclusiveError::SurfaceLost,
- Error::InitializationFailed => FullscreenExclusiveError::InitializationFailed,
- _ => panic!("unexpected error: {:?}", err),
- }
- }
-}
+ /// Error during fence creation.
+ FenceError(FenceError),
-impl From<OomError> for FullscreenExclusiveError {
- #[inline]
- fn from(err: OomError) -> FullscreenExclusiveError {
- FullscreenExclusiveError::OomError(err)
- }
+ /// Error during semaphore creation.
+ SemaphoreError(SemaphoreError),
}
-impl error::Error for FullscreenExclusiveError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- FullscreenExclusiveError::OomError(ref err) => Some(err),
+impl Error for AcquireError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ AcquireError::OomError(err) => Some(err),
_ => None,
}
}
}
-impl fmt::Display for FullscreenExclusiveError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+impl Display for AcquireError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
write!(
- fmt,
+ f,
"{}",
- match *self {
- FullscreenExclusiveError::OomError(_) => "not enough memory",
- FullscreenExclusiveError::SurfaceLost => {
- "the surface of this swapchain is no longer valid"
- }
- FullscreenExclusiveError::InitializationFailed => {
- "operation could not be completed for driver specific reasons"
- }
- FullscreenExclusiveError::DoubleAcquire =>
- "fullscreen exclusivity is already acquired",
- FullscreenExclusiveError::DoubleRelease => "fullscreen exclusivity is not acquired",
- FullscreenExclusiveError::NotAppControlled => {
- "swapchain is not in fullscreen exclusive app controlled mode"
+ match self {
+ AcquireError::OomError(_) => "not enough memory",
+ AcquireError::DeviceLost => "the connection to the device has been lost",
+ AcquireError::Timeout => "no image is available for acquiring yet",
+ AcquireError::SurfaceLost => "the surface of this swapchain is no longer valid",
+ AcquireError::OutOfDate => "the swapchain needs to be recreated",
+ AcquireError::FullScreenExclusiveModeLost => {
+ "the swapchain no longer has full-screen exclusivity"
}
+ AcquireError::FenceError(_) => "error creating fence",
+ AcquireError::SemaphoreError(_) => "error creating semaphore",
}
)
}
}
+impl From<FenceError> for AcquireError {
+ fn from(err: FenceError) -> Self {
+ AcquireError::FenceError(err)
+ }
+}
+
+impl From<SemaphoreError> for AcquireError {
+ fn from(err: SemaphoreError) -> Self {
+ AcquireError::SemaphoreError(err)
+ }
+}
+
+impl From<OomError> for AcquireError {
+ fn from(err: OomError) -> AcquireError {
+ AcquireError::OomError(err)
+ }
+}
+
+impl From<VulkanError> for AcquireError {
+ fn from(err: VulkanError) -> AcquireError {
+ match err {
+ err @ VulkanError::OutOfHostMemory => AcquireError::OomError(OomError::from(err)),
+ err @ VulkanError::OutOfDeviceMemory => AcquireError::OomError(OomError::from(err)),
+ VulkanError::DeviceLost => AcquireError::DeviceLost,
+ VulkanError::SurfaceLost => AcquireError::SurfaceLost,
+ VulkanError::OutOfDate => AcquireError::OutOfDate,
+ VulkanError::FullScreenExclusiveModeLost => AcquireError::FullScreenExclusiveModeLost,
+ _ => panic!("unexpected error: {:?}", err),
+ }
+ }
+}
+
/// Error that can happen when calling `acquire_next_image`.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u32)]
-pub enum AcquireError {
+pub enum PresentWaitError {
/// Not enough memory.
OomError(OomError),
/// The connection to the device has been lost.
DeviceLost,
- /// The timeout of the function has been reached before an image was available.
- Timeout,
+ /// The surface has changed in a way that makes the swapchain unusable. You must query the
+ /// surface's new properties and recreate a new swapchain if you want to continue drawing.
+ OutOfDate,
/// The surface is no longer accessible and must be recreated.
SurfaceLost,
- /// The swapchain has lost or doesn't have fullscreen exclusivity possibly for
+ /// The swapchain has lost or doesn't have full-screen exclusivity possibly for
/// implementation-specific reasons outside of the application’s control.
- FullscreenExclusiveLost,
+ FullScreenExclusiveModeLost,
- /// The surface has changed in a way that makes the swapchain unusable. You must query the
- /// surface's new properties and recreate a new swapchain if you want to continue drawing.
- OutOfDate,
+ /// The timeout of the function has been reached before the present occured.
+ Timeout,
- /// Error during semaphore creation
- SemaphoreError(SemaphoreError),
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+
+ /// Present id of zero is invalid.
+ PresentIdZero,
}
-impl error::Error for AcquireError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- AcquireError::OomError(ref err) => Some(err),
+impl Error for PresentWaitError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::OomError(err) => Some(err),
_ => None,
}
}
}
-impl fmt::Display for AcquireError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- AcquireError::OomError(_) => "not enough memory",
- AcquireError::DeviceLost => "the connection to the device has been lost",
- AcquireError::Timeout => "no image is available for acquiring yet",
- AcquireError::SurfaceLost => "the surface of this swapchain is no longer valid",
- AcquireError::OutOfDate => "the swapchain needs to be recreated",
- AcquireError::FullscreenExclusiveLost => {
- "the swapchain no longer has fullscreen exclusivity"
- }
- AcquireError::SemaphoreError(_) => "error creating semaphore",
+impl Display for PresentWaitError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::OomError(e) => write!(f, "{}", e),
+ Self::DeviceLost => write!(f, "the connection to the device has been lost"),
+ Self::Timeout => write!(f, "no image is available for acquiring yet"),
+ Self::SurfaceLost => write!(f, "the surface of this swapchain is no longer valid"),
+ Self::OutOfDate => write!(f, "the swapchain needs to be recreated"),
+ Self::FullScreenExclusiveModeLost => {
+ write!(f, "the swapchain no longer has full-screen exclusivity")
}
- )
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ Self::PresentIdZero => write!(f, "present id of zero is invalid"),
+ }
}
}
-impl From<SemaphoreError> for AcquireError {
- fn from(err: SemaphoreError) -> Self {
- AcquireError::SemaphoreError(err)
+impl From<OomError> for PresentWaitError {
+ fn from(err: OomError) -> PresentWaitError {
+ Self::OomError(err)
}
}
-impl From<OomError> for AcquireError {
- #[inline]
- fn from(err: OomError) -> AcquireError {
- AcquireError::OomError(err)
+impl From<RequirementNotMet> for PresentWaitError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
+ }
}
}
-impl From<Error> for AcquireError {
- #[inline]
- fn from(err: Error) -> AcquireError {
+impl From<VulkanError> for PresentWaitError {
+ fn from(err: VulkanError) -> PresentWaitError {
match err {
- err @ Error::OutOfHostMemory => AcquireError::OomError(OomError::from(err)),
- err @ Error::OutOfDeviceMemory => AcquireError::OomError(OomError::from(err)),
- Error::DeviceLost => AcquireError::DeviceLost,
- Error::SurfaceLost => AcquireError::SurfaceLost,
- Error::OutOfDate => AcquireError::OutOfDate,
- Error::FullscreenExclusiveLost => AcquireError::FullscreenExclusiveLost,
+ err @ VulkanError::OutOfHostMemory => Self::OomError(OomError::from(err)),
+ err @ VulkanError::OutOfDeviceMemory => Self::OomError(OomError::from(err)),
+ VulkanError::DeviceLost => Self::DeviceLost,
+ VulkanError::SurfaceLost => Self::SurfaceLost,
+ VulkanError::OutOfDate => Self::OutOfDate,
+ VulkanError::FullScreenExclusiveModeLost => Self::FullScreenExclusiveModeLost,
_ => panic!("unexpected error: {:?}", err),
}
}
@@ -1436,15 +1954,13 @@ impl From<Error> for AcquireError {
/// Represents a swapchain image being presented on the screen.
#[must_use = "Dropping this object will immediately block the thread until the GPU has finished processing the submission"]
-pub struct PresentFuture<P, W>
+pub struct PresentFuture<P>
where
P: GpuFuture,
{
previous: P,
queue: Arc<Queue>,
- swapchain: Arc<Swapchain<W>>,
- image_id: usize,
- present_region: Option<PresentRegion>,
+ swapchain_info: SwapchainPresentInfo,
// True if `flush()` has been called on the future, which means that the present command has
// been submitted.
flushed: AtomicBool,
@@ -1453,174 +1969,180 @@ where
finished: AtomicBool,
}
-impl<P, W> PresentFuture<P, W>
+impl<P> PresentFuture<P>
where
P: GpuFuture,
{
/// Returns the index of the image in the list of images returned when creating the swapchain.
- #[inline]
- pub fn image_id(&self) -> usize {
- self.image_id
+ pub fn image_id(&self) -> u32 {
+ self.swapchain_info.image_index
}
/// Returns the corresponding swapchain.
- #[inline]
- pub fn swapchain(&self) -> &Arc<Swapchain<W>> {
- &self.swapchain
+ pub fn swapchain(&self) -> &Arc<Swapchain> {
+ &self.swapchain_info.swapchain
}
}
-unsafe impl<P, W> GpuFuture for PresentFuture<P, W>
+unsafe impl<P> GpuFuture for PresentFuture<P>
where
P: GpuFuture,
{
- #[inline]
fn cleanup_finished(&mut self) {
self.previous.cleanup_finished();
}
- #[inline]
unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
if self.flushed.load(Ordering::SeqCst) {
return Ok(SubmitAnyBuilder::Empty);
}
- let queue = self.previous.queue().map(|q| q.clone());
+ let mut swapchain_info = self.swapchain_info.clone();
+ debug_assert!(swapchain_info.image_index < swapchain_info.swapchain.image_count());
+ let device = swapchain_info.swapchain.device();
+
+ if !device.enabled_features().present_id {
+ swapchain_info.present_id = None;
+ }
+
+ if device.enabled_extensions().khr_incremental_present {
+ for rectangle in &swapchain_info.present_regions {
+ assert!(rectangle.is_compatible_with(swapchain_info.swapchain.as_ref()));
+ }
+ } else {
+ swapchain_info.present_regions = Default::default();
+ }
+
+ let _queue = self.previous.queue();
// TODO: if the swapchain image layout is not PRESENT, should add a transition command
// buffer
Ok(match self.previous.build_submission()? {
- SubmitAnyBuilder::Empty => {
- let mut builder = SubmitPresentBuilder::new();
- builder.add_swapchain(
- &self.swapchain,
- self.image_id as u32,
- self.present_region.as_ref(),
- );
- SubmitAnyBuilder::QueuePresent(builder)
- }
- SubmitAnyBuilder::SemaphoresWait(sem) => {
- let mut builder: SubmitPresentBuilder = sem.into();
- builder.add_swapchain(
- &self.swapchain,
- self.image_id as u32,
- self.present_region.as_ref(),
- );
- SubmitAnyBuilder::QueuePresent(builder)
+ SubmitAnyBuilder::Empty => SubmitAnyBuilder::QueuePresent(PresentInfo {
+ swapchain_infos: vec![self.swapchain_info.clone()],
+ ..Default::default()
+ }),
+ SubmitAnyBuilder::SemaphoresWait(semaphores) => {
+ SubmitAnyBuilder::QueuePresent(PresentInfo {
+ wait_semaphores: semaphores.into_iter().collect(),
+ swapchain_infos: vec![self.swapchain_info.clone()],
+ ..Default::default()
+ })
}
- SubmitAnyBuilder::CommandBuffer(cb) => {
+ SubmitAnyBuilder::CommandBuffer(_, _) => {
// submit the command buffer by flushing previous.
// Since the implementation should remember being flushed it's safe to call build_submission multiple times
self.previous.flush()?;
- let mut builder = SubmitPresentBuilder::new();
- builder.add_swapchain(
- &self.swapchain,
- self.image_id as u32,
- self.present_region.as_ref(),
- );
- SubmitAnyBuilder::QueuePresent(builder)
+ SubmitAnyBuilder::QueuePresent(PresentInfo {
+ swapchain_infos: vec![self.swapchain_info.clone()],
+ ..Default::default()
+ })
}
- SubmitAnyBuilder::BindSparse(cb) => {
+ SubmitAnyBuilder::BindSparse(_, _) => {
// submit the command buffer by flushing previous.
// Since the implementation should remember being flushed it's safe to call build_submission multiple times
self.previous.flush()?;
- let mut builder = SubmitPresentBuilder::new();
- builder.add_swapchain(
- &self.swapchain,
- self.image_id as u32,
- self.present_region.as_ref(),
- );
- SubmitAnyBuilder::QueuePresent(builder)
+ SubmitAnyBuilder::QueuePresent(PresentInfo {
+ swapchain_infos: vec![self.swapchain_info.clone()],
+ ..Default::default()
+ })
}
- SubmitAnyBuilder::QueuePresent(present) => {
- unimplemented!() // TODO:
- /*present.submit();
- let mut builder = SubmitPresentBuilder::new();
- builder.add_swapchain(self.command_buffer.inner(), self.image_id);
- SubmitAnyBuilder::CommandBuffer(builder)*/
+ SubmitAnyBuilder::QueuePresent(mut present_info) => {
+ present_info
+ .swapchain_infos
+ .push(self.swapchain_info.clone());
+
+ SubmitAnyBuilder::QueuePresent(present_info)
}
})
}
- #[inline]
fn flush(&self) -> Result<(), FlushError> {
unsafe {
// If `flushed` already contains `true`, then `build_submission` will return `Empty`.
let build_submission_result = self.build_submission();
-
- if let &Err(FlushError::FullscreenExclusiveLost) = &build_submission_result {
- self.swapchain
- .fullscreen_exclusive_held
- .store(false, Ordering::SeqCst);
- }
+ self.flushed.store(true, Ordering::SeqCst);
match build_submission_result? {
- SubmitAnyBuilder::Empty => {}
- SubmitAnyBuilder::QueuePresent(present) => {
- let present_result = present.submit(&self.queue);
-
- if let &Err(SubmitPresentError::FullscreenExclusiveLost) = &present_result {
- self.swapchain
- .fullscreen_exclusive_held
- .store(false, Ordering::SeqCst);
+ SubmitAnyBuilder::Empty => Ok(()),
+ SubmitAnyBuilder::QueuePresent(present_info) => {
+ // VUID-VkPresentIdKHR-presentIds-04999
+ for swapchain_info in &present_info.swapchain_infos {
+ if swapchain_info.present_id.map_or(false, |present_id| {
+ !swapchain_info.swapchain.try_claim_present_id(present_id)
+ }) {
+ return Err(FlushError::PresentIdLessThanOrEqual);
+ }
+ }
+
+ match self.previous.check_swapchain_image_acquired(
+ &self.swapchain_info.swapchain,
+ self.swapchain_info.image_index,
+ true,
+ ) {
+ Ok(_) => (),
+ Err(AccessCheckError::Unknown) => {
+ return Err(AccessError::SwapchainImageNotAcquired.into())
+ }
+ Err(AccessCheckError::Denied(e)) => return Err(e.into()),
}
- present_result?;
+ Ok(self
+ .queue
+ .with(|mut q| q.present_unchecked(present_info))?
+ .map(|r| r.map(|_| ()))
+ .fold(Ok(()), Result::and)?)
}
_ => unreachable!(),
}
-
- self.flushed.store(true, Ordering::SeqCst);
- Ok(())
}
}
- #[inline]
unsafe fn signal_finished(&self) {
self.flushed.store(true, Ordering::SeqCst);
self.finished.store(true, Ordering::SeqCst);
self.previous.signal_finished();
}
- #[inline]
fn queue_change_allowed(&self) -> bool {
false
}
- #[inline]
fn queue(&self) -> Option<Arc<Queue>> {
debug_assert!(match self.previous.queue() {
None => true,
- Some(q) => q.is_same(&self.queue),
+ Some(q) => q == self.queue,
});
Some(self.queue.clone())
}
- #[inline]
fn check_buffer_access(
&self,
- buffer: &dyn BufferAccess,
+ buffer: &Buffer,
+ range: Range<DeviceSize>,
exclusive: bool,
queue: &Queue,
- ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
- self.previous.check_buffer_access(buffer, exclusive, queue)
+ ) -> Result<(), AccessCheckError> {
+ self.previous
+ .check_buffer_access(buffer, range, exclusive, queue)
}
- #[inline]
fn check_image_access(
&self,
- image: &dyn ImageAccess,
- layout: ImageLayout,
+ image: &Image,
+ range: Range<DeviceSize>,
exclusive: bool,
+ expected_layout: ImageLayout,
queue: &Queue,
- ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
- let swapchain_image = self.swapchain.raw_image(self.image_id).unwrap();
- if swapchain_image.image.internal_object() == image.inner().image.internal_object() {
+ ) -> Result<(), AccessCheckError> {
+ if self.swapchain_info.swapchain.index_of_image(image)
+ == Some(self.swapchain_info.image_index)
+ {
// This future presents the swapchain image, which "unlocks" it. Therefore any attempt
// to use this swapchain image afterwards shouldn't get granted automatic access.
// Instead any attempt to access the image afterwards should get an authorization from
@@ -1628,46 +2150,67 @@ where
Err(AccessCheckError::Unknown)
} else {
self.previous
- .check_image_access(image, layout, exclusive, queue)
+ .check_image_access(image, range, exclusive, expected_layout, queue)
+ }
+ }
+
+ #[inline]
+ fn check_swapchain_image_acquired(
+ &self,
+ swapchain: &Swapchain,
+ image_index: u32,
+ before: bool,
+ ) -> Result<(), AccessCheckError> {
+ if before {
+ self.previous
+ .check_swapchain_image_acquired(swapchain, image_index, false)
+ } else if swapchain == self.swapchain_info.swapchain.as_ref()
+ && image_index == self.swapchain_info.image_index
+ {
+ Err(AccessError::SwapchainImageNotAcquired.into())
+ } else {
+ self.previous
+ .check_swapchain_image_acquired(swapchain, image_index, false)
}
}
}
-unsafe impl<P, W> DeviceOwned for PresentFuture<P, W>
+unsafe impl<P> DeviceOwned for PresentFuture<P>
where
P: GpuFuture,
{
- #[inline]
fn device(&self) -> &Arc<Device> {
self.queue.device()
}
}
-impl<P, W> Drop for PresentFuture<P, W>
+impl<P> Drop for PresentFuture<P>
where
P: GpuFuture,
{
fn drop(&mut self) {
+ if thread::panicking() {
+ return;
+ }
+
unsafe {
+ if !*self.flushed.get_mut() {
+ // Flushing may fail, that's okay. We will still wait for the queue later, so any
+ // previous futures that were flushed correctly will still be waited upon.
+ self.flush().ok();
+ }
+
if !*self.finished.get_mut() {
- match self.flush() {
- Ok(()) => {
- // Block until the queue finished.
- self.queue().unwrap().wait().unwrap();
- self.previous.signal_finished();
- }
- Err(_) => {
- // In case of error we simply do nothing, as there's nothing to do
- // anyway.
- }
- }
+ // Block until the queue finished.
+ self.queue().unwrap().with(|mut q| q.wait_idle()).unwrap();
+ self.previous.signal_finished();
}
}
}
}
pub struct AcquiredImage {
- pub id: usize,
+ pub image_index: u32,
pub suboptimal: bool,
}
@@ -1678,8 +2221,8 @@ pub struct AcquiredImage {
/// - The semaphore and/or the fence must be kept alive until it is signaled.
/// - The swapchain must not have been replaced by being passed as the old swapchain when creating
/// a new one.
-pub unsafe fn acquire_next_image_raw<W>(
- swapchain: &Swapchain<W>,
+pub unsafe fn acquire_next_image_raw(
+ swapchain: &Swapchain,
timeout: Option<Duration>,
semaphore: Option<&Semaphore>,
fence: Option<&Fence>,
@@ -1696,29 +2239,37 @@ pub unsafe fn acquire_next_image_raw<W>(
};
let mut out = MaybeUninit::uninit();
- let r = check_errors(
- fns.khr_swapchain.acquire_next_image_khr(
- swapchain.device.internal_object(),
- swapchain.swapchain,
- timeout_ns,
- semaphore
- .map(|s| s.internal_object())
- .unwrap_or(ash::vk::Semaphore::null()),
- fence
- .map(|f| f.internal_object())
- .unwrap_or(ash::vk::Fence::null()),
- out.as_mut_ptr(),
- ),
- )?;
-
- let out = out.assume_init();
- let (id, suboptimal) = match r {
- Success::Success => (out as usize, false),
- Success::Suboptimal => (out as usize, true),
- Success::NotReady => return Err(AcquireError::Timeout),
- Success::Timeout => return Err(AcquireError::Timeout),
- s => panic!("unexpected success value: {:?}", s),
+ let result = (fns.khr_swapchain.acquire_next_image_khr)(
+ swapchain.device.handle(),
+ swapchain.handle,
+ timeout_ns,
+ semaphore
+ .map(|s| s.handle())
+ .unwrap_or(ash::vk::Semaphore::null()),
+ fence.map(|f| f.handle()).unwrap_or(ash::vk::Fence::null()),
+ out.as_mut_ptr(),
+ );
+
+ let suboptimal = match result {
+ ash::vk::Result::SUCCESS => false,
+ ash::vk::Result::SUBOPTIMAL_KHR => true,
+ ash::vk::Result::NOT_READY => return Err(AcquireError::Timeout),
+ ash::vk::Result::TIMEOUT => return Err(AcquireError::Timeout),
+ err => return Err(VulkanError::from(err).into()),
};
- Ok(AcquiredImage { id, suboptimal })
+ if let Some(semaphore) = semaphore {
+ let mut state = semaphore.state();
+ state.swapchain_acquire();
+ }
+
+ if let Some(fence) = fence {
+ let mut state = fence.state();
+ state.import_swapchain_acquire();
+ }
+
+ Ok(AcquiredImage {
+ image_index: out.assume_init(),
+ suboptimal,
+ })
}
diff --git a/src/sync/event.rs b/src/sync/event.rs
index 2f02da6..8f8bc33 100644
--- a/src/sync/event.rs
+++ b/src/sync/event.rs
@@ -7,15 +7,36 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use crate::check_errors;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::OomError;
-use crate::Success;
-use crate::VulkanObject;
-use std::mem::MaybeUninit;
-use std::ptr;
-use std::sync::Arc;
+//! An event provides fine-grained synchronization within a single queue, or from the host to a
+//! queue.
+//!
+//! When an event is signaled from a queue using the [`set_event`] command buffer command,
+//! an event acts similar to a [pipeline barrier], but the synchronization scopes are split:
+//! the source synchronization scope includes only commands before the `set_event` command,
+//! while the destination synchronization scope includes only commands after the
+//! [`wait_events`] command. Commands in between the two are not included.
+//!
+//! An event can also be signaled from the host, by calling the [`set`] method directly on the
+//! [`Event`].
+//!
+//! [`set_event`]: crate::command_buffer::CommandBufferBuilder::set_event
+//! [pipeline barrier]: crate::command_buffer::CommandBufferBuilder::pipeline_barrier
+//! [`wait_events`]: crate::command_buffer::CommandBufferBuilder::wait_events
+//! [`set`]: Event::set
+
+use crate::{
+ device::{Device, DeviceOwned},
+ macros::impl_id_counter,
+ OomError, RequiresOneOf, VulkanError, VulkanObject,
+};
+use std::{
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+ mem::MaybeUninit,
+ num::NonZeroU64,
+ ptr,
+ sync::Arc,
+};
/// Used to block the GPU execution until an event on the CPU occurs.
///
@@ -25,71 +46,114 @@ use std::sync::Arc;
/// device loss.
#[derive(Debug)]
pub struct Event {
- // The event.
- event: ash::vk::Event,
- // The device.
+ handle: ash::vk::Event,
device: Arc<Device>,
+ id: NonZeroU64,
must_put_in_pool: bool,
}
impl Event {
+ /// Creates a new `Event`.
+ ///
+ /// On [portability subset](crate::instance#portability-subset-devices-and-the-enumerate_portability-flag)
+ /// devices, the
+ /// [`events`](crate::device::Features::events)
+ /// feature must be enabled on the device.
+ #[inline]
+ pub fn new(device: Arc<Device>, _create_info: EventCreateInfo) -> Result<Event, EventError> {
+ // VUID-vkCreateEvent-events-04468
+ if device.enabled_extensions().khr_portability_subset && !device.enabled_features().events {
+ return Err(EventError::RequirementNotMet {
+ required_for: "this device is a portability subset device, and `Event::new` was \
+ called",
+ requires_one_of: RequiresOneOf {
+ features: &["events"],
+ ..Default::default()
+ },
+ });
+ }
+
+ let create_info = ash::vk::EventCreateInfo {
+ flags: ash::vk::EventCreateFlags::empty(),
+ ..Default::default()
+ };
+
+ let handle = unsafe {
+ let mut output = MaybeUninit::uninit();
+ let fns = device.fns();
+ (fns.v1_0.create_event)(
+ device.handle(),
+ &create_info,
+ ptr::null(),
+ output.as_mut_ptr(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+ output.assume_init()
+ };
+
+ Ok(Event {
+ handle,
+ device,
+ id: Self::next_id(),
+ must_put_in_pool: false,
+ })
+ }
+
/// Takes an event from the vulkano-provided event pool.
/// If the pool is empty, a new event will be allocated.
/// Upon `drop`, the event is put back into the pool.
///
/// For most applications, using the event pool should be preferred,
/// in order to avoid creating new events every frame.
- pub fn from_pool(device: Arc<Device>) -> Result<Event, OomError> {
- let maybe_raw_event = device.event_pool().lock().unwrap().pop();
- match maybe_raw_event {
- Some(raw_event) => {
+ #[inline]
+ pub fn from_pool(device: Arc<Device>) -> Result<Event, EventError> {
+ let handle = device.event_pool().lock().pop();
+ let event = match handle {
+ Some(handle) => {
unsafe {
// Make sure the event isn't signaled
let fns = device.fns();
- check_errors(fns.v1_0.reset_event(device.internal_object(), raw_event))?;
+ (fns.v1_0.reset_event)(device.handle(), handle)
+ .result()
+ .map_err(VulkanError::from)?;
}
- Ok(Event {
- event: raw_event,
- device: device,
+ Event {
+ handle,
+ device,
+ id: Self::next_id(),
must_put_in_pool: true,
- })
+ }
}
None => {
// Pool is empty, alloc new event
- Event::alloc_impl(device, true)
+ let mut event = Event::new(device, Default::default())?;
+ event.must_put_in_pool = true;
+ event
}
- }
- }
+ };
- /// Builds a new event.
- #[inline]
- pub fn alloc(device: Arc<Device>) -> Result<Event, OomError> {
- Event::alloc_impl(device, false)
+ Ok(event)
}
- fn alloc_impl(device: Arc<Device>, must_put_in_pool: bool) -> Result<Event, OomError> {
- let event = unsafe {
- let infos = ash::vk::EventCreateInfo {
- flags: ash::vk::EventCreateFlags::empty(),
- ..Default::default()
- };
-
- let mut output = MaybeUninit::uninit();
- let fns = device.fns();
- check_errors(fns.v1_0.create_event(
- device.internal_object(),
- &infos,
- ptr::null(),
- output.as_mut_ptr(),
- ))?;
- output.assume_init()
- };
-
- Ok(Event {
- device: device,
- event: event,
- must_put_in_pool: must_put_in_pool,
- })
+ /// Creates a new `Event` from a raw object handle.
+ ///
+ /// # Safety
+ ///
+ /// - `handle` must be a valid Vulkan object handle created from `device`.
+ /// - `create_info` must match the info used to create the object.
+ #[inline]
+ pub unsafe fn from_handle(
+ device: Arc<Device>,
+ handle: ash::vk::Event,
+ _create_info: EventCreateInfo,
+ ) -> Event {
+ Event {
+ handle,
+ device,
+ id: Self::next_id(),
+ must_put_in_pool: false,
+ }
}
/// Returns true if the event is signaled.
@@ -97,14 +161,11 @@ impl Event {
pub fn signaled(&self) -> Result<bool, OomError> {
unsafe {
let fns = self.device.fns();
- let result = check_errors(
- fns.v1_0
- .get_event_status(self.device.internal_object(), self.event),
- )?;
+ let result = (fns.v1_0.get_event_status)(self.device.handle(), self.handle);
match result {
- Success::EventSet => Ok(true),
- Success::EventReset => Ok(false),
- _ => unreachable!(),
+ ash::vk::Result::EVENT_SET => Ok(true),
+ ash::vk::Result::EVENT_RESET => Ok(false),
+ err => Err(VulkanError::from(err).into()),
}
}
}
@@ -114,10 +175,9 @@ impl Event {
pub fn set_raw(&mut self) -> Result<(), OomError> {
unsafe {
let fns = self.device.fns();
- check_errors(
- fns.v1_0
- .set_event(self.device.internal_object(), self.event),
- )?;
+ (fns.v1_0.set_event)(self.device.handle(), self.handle)
+ .result()
+ .map_err(VulkanError::from)?;
Ok(())
}
}
@@ -126,10 +186,9 @@ impl Event {
///
/// If a command buffer is waiting on this event, it is then unblocked.
///
- /// # Panic
+ /// # Panics
///
/// - Panics if the device or host ran out of memory.
- ///
#[inline]
pub fn set(&mut self) {
self.set_raw().unwrap();
@@ -140,26 +199,48 @@ impl Event {
pub fn reset_raw(&mut self) -> Result<(), OomError> {
unsafe {
let fns = self.device.fns();
- check_errors(
- fns.v1_0
- .reset_event(self.device.internal_object(), self.event),
- )?;
+ (fns.v1_0.reset_event)(self.device.handle(), self.handle)
+ .result()
+ .map_err(VulkanError::from)?;
Ok(())
}
}
/// Changes the `Event` to the unsignaled state.
///
- /// # Panic
+ /// # Panics
///
/// - Panics if the device or host ran out of memory.
- ///
#[inline]
pub fn reset(&mut self) {
self.reset_raw().unwrap();
}
}
+impl Drop for Event {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ if self.must_put_in_pool {
+ let raw_event = self.handle;
+ self.device.event_pool().lock().push(raw_event);
+ } else {
+ let fns = self.device.fns();
+ (fns.v1_0.destroy_event)(self.device.handle(), self.handle, ptr::null());
+ }
+ }
+ }
+}
+
+unsafe impl VulkanObject for Event {
+ type Handle = ash::vk::Event;
+
+ #[inline]
+ fn handle(&self) -> Self::Handle {
+ self.handle
+ }
+}
+
unsafe impl DeviceOwned for Event {
#[inline]
fn device(&self) -> &Arc<Device> {
@@ -167,47 +248,85 @@ unsafe impl DeviceOwned for Event {
}
}
-unsafe impl VulkanObject for Event {
- type Object = ash::vk::Event;
+impl_id_counter!(Event);
+
+/// Parameters to create a new `Event`.
+#[derive(Clone, Debug)]
+pub struct EventCreateInfo {
+ pub _ne: crate::NonExhaustive,
+}
+impl Default for EventCreateInfo {
#[inline]
- fn internal_object(&self) -> ash::vk::Event {
- self.event
+ fn default() -> Self {
+ Self {
+ _ne: crate::NonExhaustive(()),
+ }
}
}
-impl Drop for Event {
- #[inline]
- fn drop(&mut self) {
- unsafe {
- if self.must_put_in_pool {
- let raw_event = self.event;
- self.device.event_pool().lock().unwrap().push(raw_event);
- } else {
- let fns = self.device.fns();
- fns.v1_0
- .destroy_event(self.device.internal_object(), self.event, ptr::null());
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum EventError {
+ /// Not enough memory available.
+ OomError(OomError),
+
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+}
+
+impl Error for EventError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::OomError(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+impl Display for EventError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::OomError(_) => write!(f, "not enough memory available"),
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+ }
+ }
+}
+
+impl From<VulkanError> for EventError {
+ fn from(err: VulkanError) -> Self {
+ match err {
+ e @ VulkanError::OutOfHostMemory | e @ VulkanError::OutOfDeviceMemory => {
+ Self::OomError(e.into())
}
+ _ => panic!("unexpected error: {:?}", err),
}
}
}
#[cfg(test)]
mod tests {
- use crate::sync::Event;
- use crate::VulkanObject;
+ use crate::{sync::event::Event, VulkanObject};
#[test]
fn event_create() {
let (device, _) = gfx_dev_and_queue!();
- let event = Event::alloc(device).unwrap();
+ let event = Event::new(device, Default::default()).unwrap();
assert!(!event.signaled().unwrap());
}
#[test]
fn event_set() {
let (device, _) = gfx_dev_and_queue!();
- let mut event = Event::alloc(device).unwrap();
+ let mut event = Event::new(device, Default::default()).unwrap();
assert!(!event.signaled().unwrap());
event.set();
@@ -218,7 +337,7 @@ mod tests {
fn event_reset() {
let (device, _) = gfx_dev_and_queue!();
- let mut event = Event::alloc(device).unwrap();
+ let mut event = Event::new(device, Default::default()).unwrap();
event.set();
assert!(event.signaled().unwrap());
@@ -230,16 +349,16 @@ mod tests {
fn event_pool() {
let (device, _) = gfx_dev_and_queue!();
- assert_eq!(device.event_pool().lock().unwrap().len(), 0);
+ assert_eq!(device.event_pool().lock().len(), 0);
let event1_internal_obj = {
let event = Event::from_pool(device.clone()).unwrap();
- assert_eq!(device.event_pool().lock().unwrap().len(), 0);
- event.internal_object()
+ assert_eq!(device.event_pool().lock().len(), 0);
+ event.handle()
};
- assert_eq!(device.event_pool().lock().unwrap().len(), 1);
+ assert_eq!(device.event_pool().lock().len(), 1);
let event2 = Event::from_pool(device.clone()).unwrap();
- assert_eq!(device.event_pool().lock().unwrap().len(), 0);
- assert_eq!(event2.internal_object(), event1_internal_obj);
+ assert_eq!(device.event_pool().lock().len(), 0);
+ assert_eq!(event2.handle(), event1_internal_obj);
}
}
diff --git a/src/sync/fence.rs b/src/sync/fence.rs
index 208573a..05968f2 100644
--- a/src/sync/fence.rs
+++ b/src/sync/fence.rs
@@ -7,148 +7,293 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use crate::check_errors;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::Error;
-use crate::OomError;
-use crate::SafeDeref;
-use crate::Success;
-use crate::VulkanObject;
+//! A fence provides synchronization between the device and the host, or between an external source
+//! and the host.
+
+use crate::{
+ device::{Device, DeviceOwned, Queue},
+ macros::{impl_id_counter, vulkan_bitflags, vulkan_bitflags_enum},
+ OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject,
+};
+use parking_lot::{Mutex, MutexGuard};
use smallvec::SmallVec;
-use std::error;
-use std::fmt;
-use std::mem::MaybeUninit;
-use std::ptr;
-use std::sync::atomic::AtomicBool;
-use std::sync::atomic::Ordering;
-use std::sync::Arc;
-use std::time::Duration;
-
-/// A fence is used to know when a command buffer submission has finished its execution.
+#[cfg(unix)]
+use std::fs::File;
+use std::{
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+ future::Future,
+ mem::MaybeUninit,
+ num::NonZeroU64,
+ pin::Pin,
+ ptr,
+ sync::{Arc, Weak},
+ task::{Context, Poll},
+ time::Duration,
+};
+
+/// A two-state synchronization primitive that is signalled by the device and waited on by the host.
+///
+/// # Queue-to-host synchronization
+///
+/// The primary use of a fence is to know when execution of a queue has reached a particular point.
+/// When adding a command to a queue, a fence can be provided with the command, to be signaled
+/// when the operation finishes. You can check for a fence's current status by calling
+/// `is_signaled`, `wait` or `await` on it. If the fence is found to be signaled, that means that
+/// the queue has completed the operation that is associated with the fence, and all operations that
+/// were submitted before it have been completed as well.
+///
+/// When a queue command accesses a resource, it must be kept alive until the queue command has
+/// finished executing, and you may not be allowed to perform certain other operations (or even any)
+/// while the resource is in use. By calling `is_signaled`, `wait` or `await`, the queue will be
+/// notified when the fence is signaled, so that all resources of the associated queue operation and
+/// preceding operations can be released.
///
-/// When a command buffer accesses a resource, you have to ensure that the CPU doesn't access
-/// the same resource simultaneously (except for concurrent reads). Therefore in order to know
-/// when the CPU can access a resource again, a fence has to be used.
+/// Because of this, it is highly recommended to call `is_signaled`, `wait` or `await` on your fences.
+/// Otherwise, the queue will hold onto resources indefinitely (using up memory)
+/// and resource locks will not be released, which may cause errors when submitting future
+/// queue operations. It is not strictly necessary to wait for *every* fence, as a fence
+/// that was signaled later in the queue will automatically clean up resources associated with
+/// earlier fences too.
#[derive(Debug)]
-pub struct Fence<D = Arc<Device>>
-where
- D: SafeDeref<Target = Device>,
-{
- fence: ash::vk::Fence,
-
- device: D,
+pub struct Fence {
+ handle: ash::vk::Fence,
+ device: Arc<Device>,
+ id: NonZeroU64,
+ must_put_in_pool: bool,
- // If true, we know that the `Fence` is signaled. If false, we don't know.
- // This variable exists so that we don't need to call `vkGetFenceStatus` or `vkWaitForFences`
- // multiple times.
- signaled: AtomicBool,
+ export_handle_types: ExternalFenceHandleTypes,
- // Indicates whether this fence was taken from the fence pool.
- // If true, will be put back into fence pool on drop.
- must_put_in_pool: bool,
+ state: Mutex<FenceState>,
}
-impl<D> Fence<D>
-where
- D: SafeDeref<Target = Device>,
-{
+impl Fence {
+ /// Creates a new `Fence`.
+ #[inline]
+ pub fn new(device: Arc<Device>, create_info: FenceCreateInfo) -> Result<Fence, FenceError> {
+ Self::validate_new(&device, &create_info)?;
+
+ unsafe { Ok(Self::new_unchecked(device, create_info)?) }
+ }
+
+ fn validate_new(device: &Device, create_info: &FenceCreateInfo) -> Result<(), FenceError> {
+ let &FenceCreateInfo {
+ signaled: _,
+ export_handle_types,
+ _ne: _,
+ } = create_info;
+
+ if !export_handle_types.is_empty() {
+ if !(device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_external_fence)
+ {
+ return Err(FenceError::RequirementNotMet {
+ required_for: "`create_info.export_handle_types` is not empty",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_1),
+ device_extensions: &["khr_external_fence"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkExportFenceCreateInfo-handleTypes-01446
+ export_handle_types.validate_device(device)?;
+
+ // VUID-VkExportFenceCreateInfo-handleTypes-01446
+ for handle_type in export_handle_types.into_iter() {
+ let external_fence_properties = unsafe {
+ device
+ .physical_device()
+ .external_fence_properties_unchecked(ExternalFenceInfo::handle_type(
+ handle_type,
+ ))
+ };
+
+ if !external_fence_properties.exportable {
+ return Err(FenceError::HandleTypeNotExportable { handle_type });
+ }
+
+ if !external_fence_properties
+ .compatible_handle_types
+ .contains(export_handle_types)
+ {
+ return Err(FenceError::ExportHandleTypesNotCompatible);
+ }
+ }
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ #[inline]
+ pub unsafe fn new_unchecked(
+ device: Arc<Device>,
+ create_info: FenceCreateInfo,
+ ) -> Result<Fence, VulkanError> {
+ let FenceCreateInfo {
+ signaled,
+ export_handle_types,
+ _ne: _,
+ } = create_info;
+
+ let mut flags = ash::vk::FenceCreateFlags::empty();
+
+ if signaled {
+ flags |= ash::vk::FenceCreateFlags::SIGNALED;
+ }
+
+ let mut create_info_vk = ash::vk::FenceCreateInfo {
+ flags,
+ ..Default::default()
+ };
+ let mut export_fence_create_info_vk = None;
+
+ if !export_handle_types.is_empty() {
+ let _ = export_fence_create_info_vk.insert(ash::vk::ExportFenceCreateInfo {
+ handle_types: export_handle_types.into(),
+ ..Default::default()
+ });
+ }
+
+ if let Some(info) = export_fence_create_info_vk.as_mut() {
+ info.p_next = create_info_vk.p_next;
+ create_info_vk.p_next = info as *const _ as *const _;
+ }
+
+ let handle = {
+ let fns = device.fns();
+ let mut output = MaybeUninit::uninit();
+ (fns.v1_0.create_fence)(
+ device.handle(),
+ &create_info_vk,
+ ptr::null(),
+ output.as_mut_ptr(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+
+ output.assume_init()
+ };
+
+ Ok(Fence {
+ handle,
+ device,
+ id: Self::next_id(),
+ must_put_in_pool: false,
+ export_handle_types,
+ state: Mutex::new(FenceState {
+ is_signaled: signaled,
+ ..Default::default()
+ }),
+ })
+ }
+
/// Takes a fence from the vulkano-provided fence pool.
- /// If the pool is empty, a new fence will be allocated.
+ /// If the pool is empty, a new fence will be created.
/// Upon `drop`, the fence is put back into the pool.
///
/// For most applications, using the fence pool should be preferred,
/// in order to avoid creating new fences every frame.
- pub fn from_pool(device: D) -> Result<Fence<D>, OomError> {
- let maybe_raw_fence = device.fence_pool().lock().unwrap().pop();
- match maybe_raw_fence {
- Some(raw_fence) => {
+ #[inline]
+ pub fn from_pool(device: Arc<Device>) -> Result<Fence, FenceError> {
+ let handle = device.fence_pool().lock().pop();
+ let fence = match handle {
+ Some(handle) => {
unsafe {
// Make sure the fence isn't signaled
let fns = device.fns();
- check_errors(
- fns.v1_0
- .reset_fences(device.internal_object(), 1, &raw_fence),
- )?;
+ (fns.v1_0.reset_fences)(device.handle(), 1, &handle)
+ .result()
+ .map_err(VulkanError::from)?;
}
- Ok(Fence {
- fence: raw_fence,
- device: device,
- signaled: AtomicBool::new(false),
+
+ Fence {
+ handle,
+ device,
+ id: Self::next_id(),
must_put_in_pool: true,
- })
+ export_handle_types: ExternalFenceHandleTypes::empty(),
+ state: Mutex::new(Default::default()),
+ }
}
None => {
// Pool is empty, alloc new fence
- Fence::alloc_impl(device, false, true)
+ let mut fence = Fence::new(device, FenceCreateInfo::default())?;
+ fence.must_put_in_pool = true;
+ fence
}
- }
- }
+ };
- /// Builds a new fence.
- #[inline]
- pub fn alloc(device: D) -> Result<Fence<D>, OomError> {
- Fence::alloc_impl(device, false, false)
+ Ok(fence)
}
- /// Builds a new fence in signaled state.
+ /// Creates a new `Fence` from a raw object handle.
+ ///
+ /// # Safety
+ ///
+ /// - `handle` must be a valid Vulkan object handle created from `device`.
+ /// - `create_info` must match the info used to create the object.
#[inline]
- pub fn alloc_signaled(device: D) -> Result<Fence<D>, OomError> {
- Fence::alloc_impl(device, true, false)
- }
+ pub unsafe fn from_handle(
+ device: Arc<Device>,
+ handle: ash::vk::Fence,
+ create_info: FenceCreateInfo,
+ ) -> Fence {
+ let FenceCreateInfo {
+ signaled,
+ export_handle_types,
+ _ne: _,
+ } = create_info;
- fn alloc_impl(device: D, signaled: bool, must_put_in_pool: bool) -> Result<Fence<D>, OomError> {
- let fence = unsafe {
- let infos = ash::vk::FenceCreateInfo {
- flags: if signaled {
- ash::vk::FenceCreateFlags::SIGNALED
- } else {
- ash::vk::FenceCreateFlags::empty()
- },
+ Fence {
+ handle,
+ device,
+ id: Self::next_id(),
+ must_put_in_pool: false,
+ export_handle_types,
+ state: Mutex::new(FenceState {
+ is_signaled: signaled,
..Default::default()
- };
-
- let fns = device.fns();
- let mut output = MaybeUninit::uninit();
- check_errors(fns.v1_0.create_fence(
- device.internal_object(),
- &infos,
- ptr::null(),
- output.as_mut_ptr(),
- ))?;
- output.assume_init()
- };
-
- Ok(Fence {
- fence: fence,
- device: device,
- signaled: AtomicBool::new(signaled),
- must_put_in_pool: must_put_in_pool,
- })
+ }),
+ }
}
/// Returns true if the fence is signaled.
#[inline]
- pub fn ready(&self) -> Result<bool, OomError> {
- unsafe {
- if self.signaled.load(Ordering::Relaxed) {
- return Ok(true);
+ pub fn is_signaled(&self) -> Result<bool, OomError> {
+ let queue_to_signal = {
+ let mut state = self.state();
+
+ // If the fence is already signaled, or it's unsignaled but there's no queue that
+ // could signal it, return the currently known value.
+ if let Some(is_signaled) = state.is_signaled() {
+ return Ok(is_signaled);
}
- let fns = self.device.fns();
- let result = check_errors(
- fns.v1_0
- .get_fence_status(self.device.internal_object(), self.fence),
- )?;
+ // We must ask Vulkan for the state.
+ let result = unsafe {
+ let fns = self.device.fns();
+ (fns.v1_0.get_fence_status)(self.device.handle(), self.handle)
+ };
+
match result {
- Success::Success => {
- self.signaled.store(true, Ordering::Relaxed);
- Ok(true)
- }
- Success::NotReady => Ok(false),
- _ => unreachable!(),
+ ash::vk::Result::SUCCESS => unsafe { state.set_signaled() },
+ ash::vk::Result::NOT_READY => return Ok(false),
+ err => return Err(VulkanError::from(err).into()),
+ }
+ };
+
+ // If we have a queue that we need to signal our status to,
+ // do so now after the state lock is dropped, to avoid deadlocks.
+ if let Some(queue) = queue_to_signal {
+ unsafe {
+ queue.with(|mut q| q.fence_signaled(self));
}
}
+
+ Ok(true)
}
/// Waits until the fence is signaled, or at least until the timeout duration has elapsed.
@@ -156,281 +301,1356 @@ where
/// Returns `Ok` if the fence is now signaled. Returns `Err` if the timeout was reached instead.
///
/// If you pass a duration of 0, then the function will return without blocking.
- pub fn wait(&self, timeout: Option<Duration>) -> Result<(), FenceWaitError> {
- unsafe {
- if self.signaled.load(Ordering::Relaxed) {
+ pub fn wait(&self, timeout: Option<Duration>) -> Result<(), FenceError> {
+ let queue_to_signal = {
+ let mut state = self.state.lock();
+
+ // If the fence is already signaled, we don't need to wait.
+ if state.is_signaled().unwrap_or(false) {
return Ok(());
}
- let timeout_ns = if let Some(timeout) = timeout {
+ let timeout_ns = timeout.map_or(u64::MAX, |timeout| {
timeout
.as_secs()
.saturating_mul(1_000_000_000)
.saturating_add(timeout.subsec_nanos() as u64)
- } else {
- u64::MAX
+ });
+
+ let result = unsafe {
+ let fns = self.device.fns();
+ (fns.v1_0.wait_for_fences)(
+ self.device.handle(),
+ 1,
+ &self.handle,
+ ash::vk::TRUE,
+ timeout_ns,
+ )
};
- let fns = self.device.fns();
- let r = check_errors(fns.v1_0.wait_for_fences(
- self.device.internal_object(),
- 1,
- &self.fence,
- ash::vk::TRUE,
- timeout_ns,
- ))?;
-
- match r {
- Success::Success => {
- self.signaled.store(true, Ordering::Relaxed);
- Ok(())
- }
- Success::Timeout => Err(FenceWaitError::Timeout),
- _ => unreachable!(),
+ match result {
+ ash::vk::Result::SUCCESS => unsafe { state.set_signaled() },
+ ash::vk::Result::TIMEOUT => return Err(FenceError::Timeout),
+ err => return Err(VulkanError::from(err).into()),
+ }
+ };
+
+ // If we have a queue that we need to signal our status to,
+ // do so now after the state lock is dropped, to avoid deadlocks.
+ if let Some(queue) = queue_to_signal {
+ unsafe {
+ queue.with(|mut q| q.fence_signaled(self));
}
}
+
+ Ok(())
}
/// Waits for multiple fences at once.
///
- /// # Panic
+ /// # Panics
///
- /// Panics if not all fences belong to the same device.
- pub fn multi_wait<'a, I>(iter: I, timeout: Option<Duration>) -> Result<(), FenceWaitError>
- where
- I: IntoIterator<Item = &'a Fence<D>>,
- D: 'a,
- {
- let mut device: Option<&Device> = None;
+ /// - Panics if not all fences belong to the same device.
+ pub fn multi_wait<'a>(
+ fences: impl IntoIterator<Item = &'a Fence>,
+ timeout: Option<Duration>,
+ ) -> Result<(), FenceError> {
+ let fences: SmallVec<[_; 8]> = fences.into_iter().collect();
+ Self::validate_multi_wait(&fences, timeout)?;
- let fences: SmallVec<[ash::vk::Fence; 8]> = iter
- .into_iter()
- .filter_map(|fence| {
- match &mut device {
- dev @ &mut None => *dev = Some(&*fence.device),
- &mut Some(ref dev)
- if &**dev as *const Device == &*fence.device as *const Device => {}
- _ => panic!(
- "Tried to wait for multiple fences that didn't belong to the \
- same device"
- ),
- };
+ unsafe { Self::multi_wait_unchecked(fences, timeout) }
+ }
+
+ fn validate_multi_wait(
+ fences: &[&Fence],
+ _timeout: Option<Duration>,
+ ) -> Result<(), FenceError> {
+ if fences.is_empty() {
+ return Ok(());
+ }
+
+ let device = &fences[0].device;
+
+ for fence in fences {
+ // VUID-vkWaitForFences-pFences-parent
+ assert_eq!(device, &fence.device);
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn multi_wait_unchecked<'a>(
+ fences: impl IntoIterator<Item = &'a Fence>,
+ timeout: Option<Duration>,
+ ) -> Result<(), FenceError> {
+ let queues_to_signal: SmallVec<[_; 8]> = {
+ let iter = fences.into_iter();
+ let mut fences_vk: SmallVec<[_; 8]> = SmallVec::new();
+ let mut fences: SmallVec<[_; 8]> = SmallVec::new();
+ let mut states: SmallVec<[_; 8]> = SmallVec::new();
+
+ for fence in iter {
+ let state = fence.state.lock();
- if fence.signaled.load(Ordering::Relaxed) {
- None
- } else {
- Some(fence.fence)
+ // Skip the fences that are already signaled.
+ if !state.is_signaled().unwrap_or(false) {
+ fences_vk.push(fence.handle);
+ fences.push(fence);
+ states.push(state);
}
- })
- .collect();
+ }
- let timeout_ns = if let Some(timeout) = timeout {
- timeout
- .as_secs()
- .saturating_mul(1_000_000_000)
- .saturating_add(timeout.subsec_nanos() as u64)
- } else {
- u64::MAX
- };
+ // VUID-vkWaitForFences-fenceCount-arraylength
+ // If there are no fences, or all the fences are signaled, we don't need to wait.
+ if fences_vk.is_empty() {
+ return Ok(());
+ }
- let r = if let Some(device) = device {
- unsafe {
+ let device = &fences[0].device;
+ let timeout_ns = timeout.map_or(u64::MAX, |timeout| {
+ timeout
+ .as_secs()
+ .saturating_mul(1_000_000_000)
+ .saturating_add(timeout.subsec_nanos() as u64)
+ });
+
+ let result = {
let fns = device.fns();
- check_errors(fns.v1_0.wait_for_fences(
- device.internal_object(),
- fences.len() as u32,
- fences.as_ptr(),
- ash::vk::TRUE,
+ (fns.v1_0.wait_for_fences)(
+ device.handle(),
+ fences_vk.len() as u32,
+ fences_vk.as_ptr(),
+ ash::vk::TRUE, // TODO: let the user choose false here?
timeout_ns,
- ))?
+ )
+ };
+
+ match result {
+ ash::vk::Result::SUCCESS => fences
+ .into_iter()
+ .zip(&mut states)
+ .filter_map(|(fence, state)| state.set_signaled().map(|state| (state, fence)))
+ .collect(),
+ ash::vk::Result::TIMEOUT => return Err(FenceError::Timeout),
+ err => return Err(VulkanError::from(err).into()),
}
- } else {
- return Ok(());
};
- match r {
- Success::Success => Ok(()),
- Success::Timeout => Err(FenceWaitError::Timeout),
- _ => unreachable!(),
+ // If we have queues that we need to signal our status to,
+ // do so now after the state locks are dropped, to avoid deadlocks.
+ for (queue, fence) in queues_to_signal {
+ queue.with(|mut q| q.fence_signaled(fence));
}
+
+ Ok(())
}
/// Resets the fence.
- // This function takes a `&mut self` because the Vulkan API requires that the fence be
- // externally synchronized.
+ ///
+ /// The fence must not be in use by a queue operation.
#[inline]
- pub fn reset(&mut self) -> Result<(), OomError> {
- unsafe {
- let fns = self.device.fns();
- check_errors(
- fns.v1_0
- .reset_fences(self.device.internal_object(), 1, &self.fence),
- )?;
- self.signaled.store(false, Ordering::Relaxed);
- Ok(())
+ pub fn reset(&self) -> Result<(), FenceError> {
+ let mut state = self.state.lock();
+ self.validate_reset(&state)?;
+
+ unsafe { Ok(self.reset_unchecked_locked(&mut state)?) }
+ }
+
+ fn validate_reset(&self, state: &FenceState) -> Result<(), FenceError> {
+ // VUID-vkResetFences-pFences-01123
+ if state.is_in_queue() {
+ return Err(FenceError::InQueue);
}
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ #[inline]
+ pub unsafe fn reset_unchecked(&self) -> Result<(), VulkanError> {
+ let mut state = self.state.lock();
+
+ self.reset_unchecked_locked(&mut state)
+ }
+
+ unsafe fn reset_unchecked_locked(&self, state: &mut FenceState) -> Result<(), VulkanError> {
+ let fns = self.device.fns();
+ (fns.v1_0.reset_fences)(self.device.handle(), 1, &self.handle)
+ .result()
+ .map_err(VulkanError::from)?;
+
+ state.reset();
+
+ Ok(())
}
/// Resets multiple fences at once.
///
- /// # Panic
+ /// The fences must not be in use by a queue operation.
///
- /// - Panics if not all fences belong to the same device.
+ /// # Panics
///
- pub fn multi_reset<'a, I>(iter: I) -> Result<(), OomError>
- where
- I: IntoIterator<Item = &'a mut Fence<D>>,
- D: 'a,
- {
- let mut device: Option<&Device> = None;
-
- let fences: SmallVec<[ash::vk::Fence; 8]> = iter
+ /// - Panics if not all fences belong to the same device.
+ pub fn multi_reset<'a>(fences: impl IntoIterator<Item = &'a Fence>) -> Result<(), FenceError> {
+ let (fences, mut states): (SmallVec<[_; 8]>, SmallVec<[_; 8]>) = fences
.into_iter()
.map(|fence| {
- match &mut device {
- dev @ &mut None => *dev = Some(&*fence.device),
- &mut Some(ref dev)
- if &**dev as *const Device == &*fence.device as *const Device => {}
- _ => panic!(
- "Tried to reset multiple fences that didn't belong to the same \
- device"
- ),
- };
+ let state = fence.state.lock();
+ (fence, state)
+ })
+ .unzip();
+ Self::validate_multi_reset(&fences, &states)?;
+
+ unsafe { Ok(Self::multi_reset_unchecked_locked(&fences, &mut states)?) }
+ }
+
+ fn validate_multi_reset(
+ fences: &[&Fence],
+ states: &[MutexGuard<'_, FenceState>],
+ ) -> Result<(), FenceError> {
+ if fences.is_empty() {
+ return Ok(());
+ }
+
+ let device = &fences[0].device;
+
+ for (fence, state) in fences.iter().zip(states) {
+ // VUID-vkResetFences-pFences-parent
+ assert_eq!(device, &fence.device);
+
+ // VUID-vkResetFences-pFences-01123
+ if state.is_in_queue() {
+ return Err(FenceError::InQueue);
+ }
+ }
+
+ Ok(())
+ }
- fence.signaled.store(false, Ordering::Relaxed);
- fence.fence
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn multi_reset_unchecked<'a>(
+ fences: impl IntoIterator<Item = &'a Fence>,
+ ) -> Result<(), VulkanError> {
+ let (fences, mut states): (SmallVec<[_; 8]>, SmallVec<[_; 8]>) = fences
+ .into_iter()
+ .map(|fence| {
+ let state = fence.state.lock();
+ (fence, state)
})
- .collect();
+ .unzip();
- if let Some(device) = device {
- unsafe {
- let fns = device.fns();
- check_errors(fns.v1_0.reset_fences(
- device.internal_object(),
- fences.len() as u32,
- fences.as_ptr(),
- ))?;
+ Self::multi_reset_unchecked_locked(&fences, &mut states)
+ }
+
+ unsafe fn multi_reset_unchecked_locked(
+ fences: &[&Fence],
+ states: &mut [MutexGuard<'_, FenceState>],
+ ) -> Result<(), VulkanError> {
+ if fences.is_empty() {
+ return Ok(());
+ }
+
+ let device = &fences[0].device;
+ let fences_vk: SmallVec<[_; 8]> = fences.iter().map(|fence| fence.handle).collect();
+
+ let fns = device.fns();
+ (fns.v1_0.reset_fences)(device.handle(), fences_vk.len() as u32, fences_vk.as_ptr())
+ .result()
+ .map_err(VulkanError::from)?;
+
+ for state in states {
+ state.reset();
+ }
+
+ Ok(())
+ }
+
+ /// Exports the fence into a POSIX file descriptor. The caller owns the returned `File`.
+ ///
+ /// The [`khr_external_fence_fd`](crate::device::DeviceExtensions::khr_external_fence_fd)
+ /// extension must be enabled on the device.
+ #[cfg(unix)]
+ #[inline]
+ pub fn export_fd(&self, handle_type: ExternalFenceHandleType) -> Result<File, FenceError> {
+ let mut state = self.state.lock();
+ self.validate_export_fd(handle_type, &state)?;
+
+ unsafe { Ok(self.export_fd_unchecked_locked(handle_type, &mut state)?) }
+ }
+
+ #[cfg(unix)]
+ fn validate_export_fd(
+ &self,
+ handle_type: ExternalFenceHandleType,
+ state: &FenceState,
+ ) -> Result<(), FenceError> {
+ if !self.device.enabled_extensions().khr_external_fence_fd {
+ return Err(FenceError::RequirementNotMet {
+ required_for: "`Fence::export_fd`",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["khr_external_fence_fd"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkFenceGetFdInfoKHR-handleType-parameter
+ handle_type.validate_device(&self.device)?;
+
+ // VUID-VkFenceGetFdInfoKHR-handleType-01453
+ if !self.export_handle_types.intersects(handle_type.into()) {
+ return Err(FenceError::HandleTypeNotEnabled);
+ }
+
+ // VUID-VkFenceGetFdInfoKHR-handleType-01454
+ if handle_type.has_copy_transference()
+ && !(state.is_signaled().unwrap_or(false) || state.is_in_queue())
+ {
+ return Err(FenceError::HandleTypeCopyNotSignaled);
+ }
+
+ // VUID-VkFenceGetFdInfoKHR-fence-01455
+ if let Some(imported_handle_type) = state.current_import {
+ match imported_handle_type {
+ ImportType::SwapchainAcquire => {
+ return Err(FenceError::ImportedForSwapchainAcquire)
+ }
+ ImportType::ExternalFence(imported_handle_type) => {
+ let external_fence_properties = unsafe {
+ self.device
+ .physical_device()
+ .external_fence_properties_unchecked(ExternalFenceInfo::handle_type(
+ handle_type,
+ ))
+ };
+
+ if !external_fence_properties
+ .export_from_imported_handle_types
+ .intersects(imported_handle_type.into())
+ {
+ return Err(FenceError::ExportFromImportedNotSupported {
+ imported_handle_type,
+ });
+ }
+ }
}
}
+
+ // VUID-VkFenceGetFdInfoKHR-handleType-01456
+ if !matches!(
+ handle_type,
+ ExternalFenceHandleType::OpaqueFd | ExternalFenceHandleType::SyncFd
+ ) {
+ return Err(FenceError::HandleTypeNotFd);
+ }
+
Ok(())
}
-}
-unsafe impl DeviceOwned for Fence {
+ #[cfg(unix)]
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
#[inline]
- fn device(&self) -> &Arc<Device> {
- &self.device
+ pub unsafe fn export_fd_unchecked(
+ &self,
+ handle_type: ExternalFenceHandleType,
+ ) -> Result<File, VulkanError> {
+ let mut state = self.state.lock();
+ self.export_fd_unchecked_locked(handle_type, &mut state)
+ }
+
+ #[cfg(unix)]
+ unsafe fn export_fd_unchecked_locked(
+ &self,
+ handle_type: ExternalFenceHandleType,
+ state: &mut FenceState,
+ ) -> Result<File, VulkanError> {
+ use std::os::unix::io::FromRawFd;
+
+ let info_vk = ash::vk::FenceGetFdInfoKHR {
+ fence: self.handle,
+ handle_type: handle_type.into(),
+ ..Default::default()
+ };
+
+ let mut output = MaybeUninit::uninit();
+ let fns = self.device.fns();
+ (fns.khr_external_fence_fd.get_fence_fd_khr)(
+ self.device.handle(),
+ &info_vk,
+ output.as_mut_ptr(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+
+ state.export(handle_type);
+
+ Ok(File::from_raw_fd(output.assume_init()))
+ }
+
+ /// Exports the fence into a Win32 handle.
+ ///
+ /// The [`khr_external_fence_win32`](crate::device::DeviceExtensions::khr_external_fence_win32)
+ /// extension must be enabled on the device.
+ #[cfg(windows)]
+ #[inline]
+ pub fn export_win32_handle(
+ &self,
+ handle_type: ExternalFenceHandleType,
+ ) -> Result<*mut std::ffi::c_void, FenceError> {
+ let mut state = self.state.lock();
+ self.validate_export_win32_handle(handle_type, &state)?;
+
+ unsafe { Ok(self.export_win32_handle_unchecked_locked(handle_type, &mut state)?) }
+ }
+
+ #[cfg(windows)]
+ fn validate_export_win32_handle(
+ &self,
+ handle_type: ExternalFenceHandleType,
+ state: &FenceState,
+ ) -> Result<(), FenceError> {
+ if !self.device.enabled_extensions().khr_external_fence_win32 {
+ return Err(FenceError::RequirementNotMet {
+ required_for: "`Fence::export_win32_handle`",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["khr_external_fence_win32"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkFenceGetWin32HandleInfoKHR-handleType-parameter
+ handle_type.validate_device(&self.device)?;
+
+ // VUID-VkFenceGetWin32HandleInfoKHR-handleType-01448
+ if !self.export_handle_types.intersects(handle_type.into()) {
+ return Err(FenceError::HandleTypeNotEnabled);
+ }
+
+ // VUID-VkFenceGetWin32HandleInfoKHR-handleType-01449
+ if matches!(handle_type, ExternalFenceHandleType::OpaqueWin32)
+ && state.is_exported(handle_type)
+ {
+ return Err(FenceError::AlreadyExported);
+ }
+
+ // VUID-VkFenceGetWin32HandleInfoKHR-handleType-01451
+ if handle_type.has_copy_transference()
+ && !(state.is_signaled().unwrap_or(false) || state.is_in_queue())
+ {
+ return Err(FenceError::HandleTypeCopyNotSignaled);
+ }
+
+ // VUID-VkFenceGetWin32HandleInfoKHR-fence-01450
+ if let Some(imported_handle_type) = state.current_import {
+ match imported_handle_type {
+ ImportType::SwapchainAcquire => {
+ return Err(FenceError::ImportedForSwapchainAcquire)
+ }
+ ImportType::ExternalFence(imported_handle_type) => {
+ let external_fence_properties = unsafe {
+ self.device
+ .physical_device()
+ .external_fence_properties_unchecked(ExternalFenceInfo::handle_type(
+ handle_type,
+ ))
+ };
+
+ if !external_fence_properties
+ .export_from_imported_handle_types
+ .intersects(imported_handle_type.into())
+ {
+ return Err(FenceError::ExportFromImportedNotSupported {
+ imported_handle_type,
+ });
+ }
+ }
+ }
+ }
+
+ // VUID-VkFenceGetWin32HandleInfoKHR-handleType-01452
+ if !matches!(
+ handle_type,
+ ExternalFenceHandleType::OpaqueWin32 | ExternalFenceHandleType::OpaqueWin32Kmt
+ ) {
+ return Err(FenceError::HandleTypeNotWin32);
+ }
+
+ Ok(())
+ }
+
+ #[cfg(windows)]
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ #[inline]
+ pub unsafe fn export_win32_handle_unchecked(
+ &self,
+ handle_type: ExternalFenceHandleType,
+ ) -> Result<*mut std::ffi::c_void, VulkanError> {
+ let mut state = self.state.lock();
+ self.export_win32_handle_unchecked_locked(handle_type, &mut state)
+ }
+
+ #[cfg(windows)]
+ unsafe fn export_win32_handle_unchecked_locked(
+ &self,
+ handle_type: ExternalFenceHandleType,
+ state: &mut FenceState,
+ ) -> Result<*mut std::ffi::c_void, VulkanError> {
+ let info_vk = ash::vk::FenceGetWin32HandleInfoKHR {
+ fence: self.handle,
+ handle_type: handle_type.into(),
+ ..Default::default()
+ };
+
+ let mut output = MaybeUninit::uninit();
+ let fns = self.device.fns();
+ (fns.khr_external_fence_win32.get_fence_win32_handle_khr)(
+ self.device.handle(),
+ &info_vk,
+ output.as_mut_ptr(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+
+ state.export(handle_type);
+
+ Ok(output.assume_init())
+ }
+
+ /// Imports a fence from a POSIX file descriptor.
+ ///
+ /// The [`khr_external_fence_fd`](crate::device::DeviceExtensions::khr_external_fence_fd)
+ /// extension must be enabled on the device.
+ ///
+ /// # Safety
+ ///
+ /// - If in `import_fence_fd_info`, `handle_type` is `ExternalHandleType::OpaqueFd`,
+ /// then `file` must represent a fence that was exported from Vulkan or a compatible API,
+ /// with a driver and device UUID equal to those of the device that owns `self`.
+ #[cfg(unix)]
+ #[inline]
+ pub unsafe fn import_fd(
+ &self,
+ import_fence_fd_info: ImportFenceFdInfo,
+ ) -> Result<(), FenceError> {
+ let mut state = self.state.lock();
+ self.validate_import_fd(&import_fence_fd_info, &state)?;
+
+ Ok(self.import_fd_unchecked_locked(import_fence_fd_info, &mut state)?)
}
-}
-unsafe impl<D> VulkanObject for Fence<D>
-where
- D: SafeDeref<Target = Device>,
-{
- type Object = ash::vk::Fence;
+ #[cfg(unix)]
+ fn validate_import_fd(
+ &self,
+ import_fence_fd_info: &ImportFenceFdInfo,
+ state: &FenceState,
+ ) -> Result<(), FenceError> {
+ if !self.device.enabled_extensions().khr_external_fence_fd {
+ return Err(FenceError::RequirementNotMet {
+ required_for: "`Fence::import_fd`",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["khr_external_fence_fd"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkImportFenceFdKHR-fence-01463
+ if state.is_in_queue() {
+ return Err(FenceError::InQueue);
+ }
+
+ let &ImportFenceFdInfo {
+ flags,
+ handle_type,
+ file: _,
+ _ne: _,
+ } = import_fence_fd_info;
+
+ // VUID-VkImportFenceFdInfoKHR-flags-parameter
+ flags.validate_device(&self.device)?;
+
+ // VUID-VkImportFenceFdInfoKHR-handleType-parameter
+ handle_type.validate_device(&self.device)?;
+
+ // VUID-VkImportFenceFdInfoKHR-handleType-01464
+ if !matches!(
+ handle_type,
+ ExternalFenceHandleType::OpaqueFd | ExternalFenceHandleType::SyncFd
+ ) {
+ return Err(FenceError::HandleTypeNotFd);
+ }
+
+ // VUID-VkImportFenceFdInfoKHR-fd-01541
+ // Can't validate, therefore unsafe
+
+ // VUID-VkImportFenceFdInfoKHR-handleType-07306
+ if handle_type.has_copy_transference() && !flags.intersects(FenceImportFlags::TEMPORARY) {
+ return Err(FenceError::HandletypeCopyNotTemporary);
+ }
+ Ok(())
+ }
+
+ #[cfg(unix)]
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
#[inline]
- fn internal_object(&self) -> ash::vk::Fence {
- self.fence
+ pub unsafe fn import_fd_unchecked(
+ &self,
+ import_fence_fd_info: ImportFenceFdInfo,
+ ) -> Result<(), VulkanError> {
+ let mut state = self.state.lock();
+ self.import_fd_unchecked_locked(import_fence_fd_info, &mut state)
+ }
+
+ #[cfg(unix)]
+ unsafe fn import_fd_unchecked_locked(
+ &self,
+ import_fence_fd_info: ImportFenceFdInfo,
+ state: &mut FenceState,
+ ) -> Result<(), VulkanError> {
+ use std::os::unix::io::IntoRawFd;
+
+ let ImportFenceFdInfo {
+ flags,
+ handle_type,
+ file,
+ _ne: _,
+ } = import_fence_fd_info;
+
+ let info_vk = ash::vk::ImportFenceFdInfoKHR {
+ fence: self.handle,
+ flags: flags.into(),
+ handle_type: handle_type.into(),
+ fd: file.map_or(-1, |file| file.into_raw_fd()),
+ ..Default::default()
+ };
+
+ let fns = self.device.fns();
+ (fns.khr_external_fence_fd.import_fence_fd_khr)(self.device.handle(), &info_vk)
+ .result()
+ .map_err(VulkanError::from)?;
+
+ state.import(handle_type, flags.intersects(FenceImportFlags::TEMPORARY));
+
+ Ok(())
+ }
+
+ /// Imports a fence from a Win32 handle.
+ ///
+ /// The [`khr_external_fence_win32`](crate::device::DeviceExtensions::khr_external_fence_win32)
+ /// extension must be enabled on the device.
+ ///
+ /// # Safety
+ ///
+ /// - In `import_fence_win32_handle_info`, `handle` must represent a fence that was exported
+ /// from Vulkan or a compatible API, with a driver and device UUID equal to those of the
+ /// device that owns `self`.
+ #[cfg(windows)]
+ #[inline]
+ pub unsafe fn import_win32_handle(
+ &self,
+ import_fence_win32_handle_info: ImportFenceWin32HandleInfo,
+ ) -> Result<(), FenceError> {
+ let mut state = self.state.lock();
+ self.validate_import_win32_handle(&import_fence_win32_handle_info, &state)?;
+
+ Ok(self.import_win32_handle_unchecked_locked(import_fence_win32_handle_info, &mut state)?)
+ }
+
+ #[cfg(windows)]
+ fn validate_import_win32_handle(
+ &self,
+ import_fence_win32_handle_info: &ImportFenceWin32HandleInfo,
+ state: &FenceState,
+ ) -> Result<(), FenceError> {
+ if !self.device.enabled_extensions().khr_external_fence_win32 {
+ return Err(FenceError::RequirementNotMet {
+ required_for: "`Fence::import_win32_handle`",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["khr_external_fence_win32"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkImportFenceWin32HandleKHR-fence-04448
+ if state.is_in_queue() {
+ return Err(FenceError::InQueue);
+ }
+
+ let &ImportFenceWin32HandleInfo {
+ flags,
+ handle_type,
+ handle: _,
+ _ne: _,
+ } = import_fence_win32_handle_info;
+
+ // VUID-VkImportFenceWin32HandleInfoKHR-flags-parameter
+ flags.validate_device(&self.device)?;
+
+ // VUID-VkImportFenceWin32HandleInfoKHR-handleType-01457
+ handle_type.validate_device(&self.device)?;
+
+ // VUID-VkImportFenceWin32HandleInfoKHR-handleType-01457
+ if !matches!(
+ handle_type,
+ ExternalFenceHandleType::OpaqueWin32 | ExternalFenceHandleType::OpaqueWin32Kmt
+ ) {
+ return Err(FenceError::HandleTypeNotWin32);
+ }
+
+ // VUID-VkImportFenceWin32HandleInfoKHR-handle-01539
+ // Can't validate, therefore unsafe
+
+ // VUID?
+ if handle_type.has_copy_transference() && !flags.intersects(FenceImportFlags::TEMPORARY) {
+ return Err(FenceError::HandletypeCopyNotTemporary);
+ }
+
+ Ok(())
+ }
+
+ #[cfg(windows)]
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ #[inline]
+ pub unsafe fn import_win32_handle_unchecked(
+ &self,
+ import_fence_win32_handle_info: ImportFenceWin32HandleInfo,
+ ) -> Result<(), VulkanError> {
+ let mut state = self.state.lock();
+ self.import_win32_handle_unchecked_locked(import_fence_win32_handle_info, &mut state)
+ }
+
+ #[cfg(windows)]
+ unsafe fn import_win32_handle_unchecked_locked(
+ &self,
+ import_fence_win32_handle_info: ImportFenceWin32HandleInfo,
+ state: &mut FenceState,
+ ) -> Result<(), VulkanError> {
+ let ImportFenceWin32HandleInfo {
+ flags,
+ handle_type,
+ handle,
+ _ne: _,
+ } = import_fence_win32_handle_info;
+
+ let info_vk = ash::vk::ImportFenceWin32HandleInfoKHR {
+ fence: self.handle,
+ flags: flags.into(),
+ handle_type: handle_type.into(),
+ handle,
+ name: ptr::null(), // TODO: support?
+ ..Default::default()
+ };
+
+ let fns = self.device.fns();
+ (fns.khr_external_fence_win32.import_fence_win32_handle_khr)(
+ self.device.handle(),
+ &info_vk,
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+
+ state.import(handle_type, flags.intersects(FenceImportFlags::TEMPORARY));
+
+ Ok(())
+ }
+
+ pub(crate) fn state(&self) -> MutexGuard<'_, FenceState> {
+ self.state.lock()
+ }
+
+ // Shared by Fence and FenceSignalFuture
+ pub(crate) fn poll_impl(&self, cx: &mut Context<'_>) -> Poll<Result<(), OomError>> {
+ // Vulkan only allows polling of the fence status, so we have to use a spin future.
+ // This is still better than blocking in async applications, since a smart-enough async engine
+ // can choose to run some other tasks between probing this one.
+
+ // Check if we are done without blocking
+ match self.is_signaled() {
+ Err(e) => return Poll::Ready(Err(e)),
+ Ok(signalled) => {
+ if signalled {
+ return Poll::Ready(Ok(()));
+ }
+ }
+ }
+
+ // Otherwise spin
+ cx.waker().wake_by_ref();
+ Poll::Pending
}
}
-impl<D> Drop for Fence<D>
-where
- D: SafeDeref<Target = Device>,
-{
+impl Drop for Fence {
#[inline]
fn drop(&mut self) {
unsafe {
if self.must_put_in_pool {
- let raw_fence = self.fence;
- self.device.fence_pool().lock().unwrap().push(raw_fence);
+ let raw_fence = self.handle;
+ self.device.fence_pool().lock().push(raw_fence);
} else {
let fns = self.device.fns();
- fns.v1_0
- .destroy_fence(self.device.internal_object(), self.fence, ptr::null());
+ (fns.v1_0.destroy_fence)(self.device.handle(), self.handle, ptr::null());
}
}
}
}
-/// Error that can be returned when waiting on a fence.
+impl Future for Fence {
+ type Output = Result<(), OomError>;
+
+ fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+ self.poll_impl(cx)
+ }
+}
+
+unsafe impl VulkanObject for Fence {
+ type Handle = ash::vk::Fence;
+
+ #[inline]
+ fn handle(&self) -> Self::Handle {
+ self.handle
+ }
+}
+
+unsafe impl DeviceOwned for Fence {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+}
+
+impl_id_counter!(Fence);
+
+#[derive(Debug, Default)]
+pub(crate) struct FenceState {
+ is_signaled: bool,
+ pending_signal: Option<Weak<Queue>>,
+
+ reference_exported: bool,
+ exported_handle_types: ExternalFenceHandleTypes,
+ current_import: Option<ImportType>,
+ permanent_import: Option<ExternalFenceHandleType>,
+}
+
+impl FenceState {
+ /// If the fence is not in a queue and has no external references, returns the current status.
+ #[inline]
+ fn is_signaled(&self) -> Option<bool> {
+ // If either of these is true, we can't be certain of the status.
+ if self.is_in_queue() || self.has_external_reference() {
+ None
+ } else {
+ Some(self.is_signaled)
+ }
+ }
+
+ #[inline]
+ fn is_in_queue(&self) -> bool {
+ self.pending_signal.is_some()
+ }
+
+ /// Returns whether there are any potential external references to the fence payload.
+ /// That is, the fence has been exported by reference transference, or imported.
+ #[inline]
+ fn has_external_reference(&self) -> bool {
+ self.reference_exported || self.current_import.is_some()
+ }
+
+ #[allow(dead_code)]
+ #[inline]
+ fn is_exported(&self, handle_type: ExternalFenceHandleType) -> bool {
+ self.exported_handle_types.intersects(handle_type.into())
+ }
+
+ #[inline]
+ pub(crate) unsafe fn add_queue_signal(&mut self, queue: &Arc<Queue>) {
+ self.pending_signal = Some(Arc::downgrade(queue));
+ }
+
+ /// Called when a fence first discovers that it is signaled.
+ /// Returns the queue that should be informed about it.
+ #[inline]
+ unsafe fn set_signaled(&mut self) -> Option<Arc<Queue>> {
+ self.is_signaled = true;
+
+ // Fences with external references can't be used to determine queue completion.
+ if self.has_external_reference() {
+ self.pending_signal = None;
+ None
+ } else {
+ self.pending_signal.take().and_then(|queue| queue.upgrade())
+ }
+ }
+
+ /// Called when a queue is unlocking resources.
+ #[inline]
+ pub(crate) unsafe fn set_signal_finished(&mut self) {
+ self.is_signaled = true;
+ self.pending_signal = None;
+ }
+
+ #[inline]
+ unsafe fn reset(&mut self) {
+ debug_assert!(!self.is_in_queue());
+ self.current_import = self.permanent_import.map(Into::into);
+ self.is_signaled = false;
+ }
+
+ #[allow(dead_code)]
+ #[inline]
+ unsafe fn export(&mut self, handle_type: ExternalFenceHandleType) {
+ self.exported_handle_types |= handle_type.into();
+
+ if handle_type.has_copy_transference() {
+ self.reset();
+ } else {
+ self.reference_exported = true;
+ }
+ }
+
+ #[allow(dead_code)]
+ #[inline]
+ unsafe fn import(&mut self, handle_type: ExternalFenceHandleType, temporary: bool) {
+ debug_assert!(!self.is_in_queue());
+ self.current_import = Some(handle_type.into());
+
+ if !temporary {
+ self.permanent_import = Some(handle_type);
+ }
+ }
+
+ #[inline]
+ pub(crate) unsafe fn import_swapchain_acquire(&mut self) {
+ debug_assert!(!self.is_in_queue());
+ self.current_import = Some(ImportType::SwapchainAcquire);
+ }
+}
+
+#[derive(Clone, Copy, Debug)]
+enum ImportType {
+ SwapchainAcquire,
+ ExternalFence(ExternalFenceHandleType),
+}
+
+impl From<ExternalFenceHandleType> for ImportType {
+ #[inline]
+ fn from(handle_type: ExternalFenceHandleType) -> Self {
+ Self::ExternalFence(handle_type)
+ }
+}
+
+/// Parameters to create a new `Fence`.
+#[derive(Clone, Debug)]
+pub struct FenceCreateInfo {
+ /// Whether the fence should be created in the signaled state.
+ ///
+ /// The default value is `false`.
+ pub signaled: bool,
+
+ /// The handle types that can be exported from the fence.
+ pub export_handle_types: ExternalFenceHandleTypes,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for FenceCreateInfo {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ signaled: false,
+ export_handle_types: ExternalFenceHandleTypes::empty(),
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+vulkan_bitflags_enum! {
+ #[non_exhaustive]
+ /// A set of [`ExternalFenceHandleType`] values.
+ ExternalFenceHandleTypes,
+
+ /// The handle type used to export or import fences to/from an external source.
+ ExternalFenceHandleType impl {
+ /// Returns whether the given handle type has *copy transference* rather than *reference
+ /// transference*.
+ ///
+ /// Imports of handles with copy transference must always be temporary. Exports of such
+ /// handles must only occur if the fence is already signaled, or if there is a fence signal
+ /// operation pending in a queue.
+ #[inline]
+ pub fn has_copy_transference(self) -> bool {
+ // As defined by
+ // https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap7.html#synchronization-fence-handletypes-win32
+ // https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap7.html#synchronization-fence-handletypes-fd
+ matches!(self, Self::SyncFd)
+ }
+ },
+
+ = ExternalFenceHandleTypeFlags(u32);
+
+ /// A POSIX file descriptor handle that is only usable with Vulkan and compatible APIs.
+ ///
+ /// This handle type has *reference transference*.
+ OPAQUE_FD, OpaqueFd = OPAQUE_FD,
+
+ /// A Windows NT handle that is only usable with Vulkan and compatible APIs.
+ ///
+ /// This handle type has *reference transference*.
+ OPAQUE_WIN32, OpaqueWin32 = OPAQUE_WIN32,
+
+ /// A Windows global share handle that is only usable with Vulkan and compatible APIs.
+ ///
+ /// This handle type has *reference transference*.
+ OPAQUE_WIN32_KMT, OpaqueWin32Kmt = OPAQUE_WIN32_KMT,
+
+ /// A POSIX file descriptor handle to a Linux Sync File or Android Fence object.
+ ///
+ /// This handle type has *copy transference*.
+ SYNC_FD, SyncFd = SYNC_FD,
+}
+
+vulkan_bitflags! {
+ #[non_exhaustive]
+
+ /// Additional parameters for a fence payload import.
+ FenceImportFlags = FenceImportFlags(u32);
+
+ /// The fence payload will be imported only temporarily, regardless of the permanence of the
+ /// imported handle type.
+ TEMPORARY = TEMPORARY,
+}
+
+#[cfg(unix)]
+#[derive(Debug)]
+pub struct ImportFenceFdInfo {
+ /// Additional parameters for the import operation.
+ ///
+ /// If `handle_type` has *copy transference*, this must include the `temporary` flag.
+ ///
+ /// The default value is [`FenceImportFlags::empty()`].
+ pub flags: FenceImportFlags,
+
+ /// The handle type of `file`.
+ ///
+ /// There is no default value.
+ pub handle_type: ExternalFenceHandleType,
+
+ /// The file to import the fence from.
+ ///
+ /// If `handle_type` is `ExternalFenceHandleType::SyncFd`, then `file` can be `None`.
+ /// Instead of an imported file descriptor, a dummy file descriptor `-1` is used,
+ /// which represents a fence that is always signaled.
+ ///
+ /// The default value is `None`, which must be overridden if `handle_type` is not
+ /// `ExternalFenceHandleType::SyncFd`.
+ pub file: Option<File>,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+#[cfg(unix)]
+impl ImportFenceFdInfo {
+ /// Returns an `ImportFenceFdInfo` with the specified `handle_type`.
+ #[inline]
+ pub fn handle_type(handle_type: ExternalFenceHandleType) -> Self {
+ Self {
+ flags: FenceImportFlags::empty(),
+ handle_type,
+ file: None,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+#[cfg(windows)]
+#[derive(Debug)]
+pub struct ImportFenceWin32HandleInfo {
+ /// Additional parameters for the import operation.
+ ///
+ /// If `handle_type` has *copy transference*, this must include the `temporary` flag.
+ ///
+ /// The default value is [`FenceImportFlags::empty()`].
+ pub flags: FenceImportFlags,
+
+ /// The handle type of `handle`.
+ ///
+ /// There is no default value.
+ pub handle_type: ExternalFenceHandleType,
+
+ /// The file to import the fence from.
+ ///
+ /// The default value is `null`, which must be overridden.
+ pub handle: *mut std::ffi::c_void,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+#[cfg(windows)]
+impl ImportFenceWin32HandleInfo {
+ /// Returns an `ImportFenceWin32HandleInfo` with the specified `handle_type`.
+ #[inline]
+ pub fn handle_type(handle_type: ExternalFenceHandleType) -> Self {
+ Self {
+ flags: FenceImportFlags::empty(),
+ handle_type,
+ handle: ptr::null_mut(),
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// The fence configuration to query in
+/// [`PhysicalDevice::external_fence_properties`](crate::device::physical::PhysicalDevice::external_fence_properties).
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct ExternalFenceInfo {
+ /// The external handle type that will be used with the fence.
+ pub handle_type: ExternalFenceHandleType,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl ExternalFenceInfo {
+ /// Returns an `ExternalFenceInfo` with the specified `handle_type`.
+ #[inline]
+ pub fn handle_type(handle_type: ExternalFenceHandleType) -> Self {
+ Self {
+ handle_type,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// The properties for exporting or importing external handles, when a fence is created
+/// with a specific configuration.
+#[derive(Clone, Debug)]
+#[non_exhaustive]
+pub struct ExternalFenceProperties {
+ /// Whether a handle can be exported to an external source with the queried
+ /// external handle type.
+ pub exportable: bool,
+
+ /// Whether a handle can be imported from an external source with the queried
+ /// external handle type.
+ pub importable: bool,
+
+ /// Which external handle types can be re-exported after the queried external handle type has
+ /// been imported.
+ pub export_from_imported_handle_types: ExternalFenceHandleTypes,
+
+ /// Which external handle types can be enabled along with the queried external handle type
+ /// when creating the fence.
+ pub compatible_handle_types: ExternalFenceHandleTypes,
+}
+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum FenceWaitError {
- /// Not enough memory to complete the wait.
+pub enum FenceError {
+ /// Not enough memory available.
OomError(OomError),
+ /// The device has been lost.
+ DeviceLost,
+
/// The specified timeout wasn't long enough.
Timeout,
- /// The device has been lost.
- DeviceLostError,
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+
+ /// The provided handle type does not permit more than one export,
+ /// and a handle of this type was already exported previously.
+ AlreadyExported,
+
+ /// The provided handle type cannot be exported from the current import handle type.
+ ExportFromImportedNotSupported {
+ imported_handle_type: ExternalFenceHandleType,
+ },
+
+ /// One of the export handle types is not compatible with the other provided handles.
+ ExportHandleTypesNotCompatible,
+
+ /// A handle type with copy transference was provided, but the fence is not signaled and there
+ /// is no pending queue operation that will signal it.
+ HandleTypeCopyNotSignaled,
+
+ /// A handle type with copy transference was provided,
+ /// but the `temporary` import flag was not set.
+ HandletypeCopyNotTemporary,
+
+ /// The provided export handle type was not set in `export_handle_types` when creating the
+ /// fence.
+ HandleTypeNotEnabled,
+
+ /// Exporting is not supported for the provided handle type.
+ HandleTypeNotExportable {
+ handle_type: ExternalFenceHandleType,
+ },
+
+ /// The provided handle type is not a POSIX file descriptor handle.
+ HandleTypeNotFd,
+
+ /// The provided handle type is not a Win32 handle.
+ HandleTypeNotWin32,
+
+ /// The fence currently has a temporary import for a swapchain acquire operation.
+ ImportedForSwapchainAcquire,
+
+ /// The fence is currently in use by a queue.
+ InQueue,
}
-impl error::Error for FenceWaitError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- FenceWaitError::OomError(ref err) => Some(err),
+impl Error for FenceError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::OomError(err) => Some(err),
_ => None,
}
}
}
-impl fmt::Display for FenceWaitError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- write!(
- fmt,
- "{}",
- match *self {
- FenceWaitError::OomError(_) => "no memory available",
- FenceWaitError::Timeout => "the timeout has been reached",
- FenceWaitError::DeviceLostError => "the device was lost",
+impl Display for FenceError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::OomError(_) => write!(f, "not enough memory available"),
+ Self::DeviceLost => write!(f, "the device was lost"),
+ Self::Timeout => write!(f, "the timeout has been reached"),
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+
+ Self::AlreadyExported => write!(
+ f,
+ "the provided handle type does not permit more than one export, and a handle of \
+ this type was already exported previously",
+ ),
+ Self::ExportFromImportedNotSupported {
+ imported_handle_type,
+ } => write!(
+ f,
+ "the provided handle type cannot be exported from the current imported handle type \
+ {:?}",
+ imported_handle_type,
+ ),
+ Self::ExportHandleTypesNotCompatible => write!(
+ f,
+ "one of the export handle types is not compatible with the other provided handles",
+ ),
+ Self::HandleTypeCopyNotSignaled => write!(
+ f,
+ "a handle type with copy transference was provided, but the fence is not signaled \
+ and there is no pending queue operation that will signal it",
+ ),
+ Self::HandletypeCopyNotTemporary => write!(
+ f,
+ "a handle type with copy transference was provided, but the `temporary` \
+ import flag was not set",
+ ),
+ Self::HandleTypeNotEnabled => write!(
+ f,
+ "the provided export handle type was not set in `export_handle_types` when \
+ creating the fence",
+ ),
+ Self::HandleTypeNotExportable { handle_type } => write!(
+ f,
+ "exporting is not supported for handles of type {:?}",
+ handle_type,
+ ),
+ Self::HandleTypeNotFd => write!(
+ f,
+ "the provided handle type is not a POSIX file descriptor handle",
+ ),
+ Self::HandleTypeNotWin32 => {
+ write!(f, "the provided handle type is not a Win32 handle")
}
- )
+ Self::ImportedForSwapchainAcquire => write!(
+ f,
+ "the fence currently has a temporary import for a swapchain acquire operation",
+ ),
+ Self::InQueue => write!(f, "the fence is currently in use by a queue"),
+ }
}
}
-impl From<Error> for FenceWaitError {
- #[inline]
- fn from(err: Error) -> FenceWaitError {
+impl From<VulkanError> for FenceError {
+ fn from(err: VulkanError) -> Self {
match err {
- Error::OutOfHostMemory => FenceWaitError::OomError(From::from(err)),
- Error::OutOfDeviceMemory => FenceWaitError::OomError(From::from(err)),
- Error::DeviceLost => FenceWaitError::DeviceLostError,
- _ => panic!("Unexpected error value: {}", err as i32),
+ e @ VulkanError::OutOfHostMemory | e @ VulkanError::OutOfDeviceMemory => {
+ Self::OomError(e.into())
+ }
+ VulkanError::DeviceLost => Self::DeviceLost,
+ _ => panic!("unexpected error: {:?}", err),
+ }
+ }
+}
+
+impl From<OomError> for FenceError {
+ fn from(err: OomError) -> Self {
+ Self::OomError(err)
+ }
+}
+
+impl From<RequirementNotMet> for FenceError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
}
}
}
#[cfg(test)]
mod tests {
- use crate::sync::Fence;
- use crate::VulkanObject;
+ use crate::{
+ sync::fence::{Fence, FenceCreateInfo},
+ VulkanObject,
+ };
use std::time::Duration;
#[test]
fn fence_create() {
let (device, _) = gfx_dev_and_queue!();
- let fence = Fence::alloc(device.clone()).unwrap();
- assert!(!fence.ready().unwrap());
+ let fence = Fence::new(device, Default::default()).unwrap();
+ assert!(!fence.is_signaled().unwrap());
}
#[test]
fn fence_create_signaled() {
let (device, _) = gfx_dev_and_queue!();
- let fence = Fence::alloc_signaled(device.clone()).unwrap();
- assert!(fence.ready().unwrap());
+ let fence = Fence::new(
+ device,
+ FenceCreateInfo {
+ signaled: true,
+ ..Default::default()
+ },
+ )
+ .unwrap();
+ assert!(fence.is_signaled().unwrap());
}
#[test]
fn fence_signaled_wait() {
let (device, _) = gfx_dev_and_queue!();
- let fence = Fence::alloc_signaled(device.clone()).unwrap();
+ let fence = Fence::new(
+ device,
+ FenceCreateInfo {
+ signaled: true,
+ ..Default::default()
+ },
+ )
+ .unwrap();
fence.wait(Some(Duration::new(0, 10))).unwrap();
}
@@ -438,9 +1658,16 @@ mod tests {
fn fence_reset() {
let (device, _) = gfx_dev_and_queue!();
- let mut fence = Fence::alloc_signaled(device.clone()).unwrap();
+ let fence = Fence::new(
+ device,
+ FenceCreateInfo {
+ signaled: true,
+ ..Default::default()
+ },
+ )
+ .unwrap();
fence.reset().unwrap();
- assert!(!fence.ready().unwrap());
+ assert!(!fence.is_signaled().unwrap());
}
#[test]
@@ -448,54 +1675,72 @@ mod tests {
let (device1, _) = gfx_dev_and_queue!();
let (device2, _) = gfx_dev_and_queue!();
- assert_should_panic!(
- "Tried to wait for multiple fences that didn't belong \
- to the same device",
- {
- let fence1 = Fence::alloc_signaled(device1.clone()).unwrap();
- let fence2 = Fence::alloc_signaled(device2.clone()).unwrap();
+ assert_should_panic!({
+ let fence1 = Fence::new(
+ device1.clone(),
+ FenceCreateInfo {
+ signaled: true,
+ ..Default::default()
+ },
+ )
+ .unwrap();
+ let fence2 = Fence::new(
+ device2.clone(),
+ FenceCreateInfo {
+ signaled: true,
+ ..Default::default()
+ },
+ )
+ .unwrap();
- let _ = Fence::multi_wait(
- [&fence1, &fence2].iter().cloned(),
- Some(Duration::new(0, 10)),
- );
- }
- );
+ let _ = Fence::multi_wait(
+ [&fence1, &fence2].iter().cloned(),
+ Some(Duration::new(0, 10)),
+ );
+ });
}
#[test]
fn multireset_different_devices() {
- use std::iter::once;
-
let (device1, _) = gfx_dev_and_queue!();
let (device2, _) = gfx_dev_and_queue!();
- assert_should_panic!(
- "Tried to reset multiple fences that didn't belong \
- to the same device",
- {
- let mut fence1 = Fence::alloc_signaled(device1.clone()).unwrap();
- let mut fence2 = Fence::alloc_signaled(device2.clone()).unwrap();
+ assert_should_panic!({
+ let fence1 = Fence::new(
+ device1.clone(),
+ FenceCreateInfo {
+ signaled: true,
+ ..Default::default()
+ },
+ )
+ .unwrap();
+ let fence2 = Fence::new(
+ device2.clone(),
+ FenceCreateInfo {
+ signaled: true,
+ ..Default::default()
+ },
+ )
+ .unwrap();
- let _ = Fence::multi_reset(once(&mut fence1).chain(once(&mut fence2)));
- }
- );
+ let _ = Fence::multi_reset([&fence1, &fence2]);
+ });
}
#[test]
fn fence_pool() {
let (device, _) = gfx_dev_and_queue!();
- assert_eq!(device.fence_pool().lock().unwrap().len(), 0);
+ assert_eq!(device.fence_pool().lock().len(), 0);
let fence1_internal_obj = {
let fence = Fence::from_pool(device.clone()).unwrap();
- assert_eq!(device.fence_pool().lock().unwrap().len(), 0);
- fence.internal_object()
+ assert_eq!(device.fence_pool().lock().len(), 0);
+ fence.handle()
};
- assert_eq!(device.fence_pool().lock().unwrap().len(), 1);
+ assert_eq!(device.fence_pool().lock().len(), 1);
let fence2 = Fence::from_pool(device.clone()).unwrap();
- assert_eq!(device.fence_pool().lock().unwrap().len(), 0);
- assert_eq!(fence2.internal_object(), fence1_internal_obj);
+ assert_eq!(device.fence_pool().lock().len(), 0);
+ assert_eq!(fence2.handle(), fence1_internal_obj);
}
}
diff --git a/src/sync/future/fence_signal.rs b/src/sync/future/fence_signal.rs
index c2f5338..7f71d88 100644
--- a/src/sync/future/fence_signal.rs
+++ b/src/sync/future/fence_signal.rs
@@ -7,29 +7,33 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use std::mem;
-use std::sync::Arc;
-use std::sync::Mutex;
-use std::sync::MutexGuard;
-use std::time::Duration;
-
-use crate::buffer::BufferAccess;
-use crate::command_buffer::submit::SubmitAnyBuilder;
-use crate::command_buffer::submit::SubmitCommandBufferBuilder;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::device::Queue;
-use crate::image::ImageAccess;
-use crate::image::ImageLayout;
-use crate::sync::AccessCheckError;
-use crate::sync::AccessFlags;
-use crate::sync::Fence;
-use crate::sync::FlushError;
-use crate::sync::GpuFuture;
-use crate::sync::PipelineStages;
+use super::{AccessCheckError, FlushError, GpuFuture};
+use crate::{
+ buffer::Buffer,
+ command_buffer::{SemaphoreSubmitInfo, SubmitInfo},
+ device::{Device, DeviceOwned, Queue, QueueFlags},
+ image::{sys::Image, ImageLayout},
+ swapchain::Swapchain,
+ sync::{
+ fence::Fence,
+ future::{AccessError, SubmitAnyBuilder},
+ PipelineStages,
+ },
+ DeviceSize, OomError,
+};
+use parking_lot::{Mutex, MutexGuard};
+use std::{
+ future::Future,
+ mem::replace,
+ ops::Range,
+ pin::Pin,
+ sync::Arc,
+ task::{Context, Poll},
+ thread,
+ time::Duration,
+};
/// Builds a new fence signal future.
-#[inline]
pub fn then_signal_fence<F>(future: F, behavior: FenceSignalFutureBehavior) -> FenceSignalFuture<F>
where
F: GpuFuture,
@@ -38,11 +42,11 @@ where
assert!(future.queue().is_some()); // TODO: document
- let fence = Fence::from_pool(device.clone()).unwrap();
+ let fence = Arc::new(Fence::from_pool(device.clone()).unwrap());
FenceSignalFuture {
- device: device,
+ device,
state: Mutex::new(FenceSignalFutureState::Pending(future, fence)),
- behavior: behavior,
+ behavior,
}
}
@@ -52,6 +56,7 @@ pub enum FenceSignalFutureBehavior {
/// Continue execution on the same queue.
Continue,
/// Wait for the fence to be signalled before submitting any further operation.
+ #[allow(dead_code)] // TODO: why is this never constructed?
Block {
/// How long to block the current thread.
timeout: Option<Duration>,
@@ -63,6 +68,11 @@ pub enum FenceSignalFutureBehavior {
/// Contrary to most other future types, it is possible to block the current thread until the event
/// happens. This is done by calling the `wait()` function.
///
+/// This can also be done through Rust's Async system by simply `.await`ing this object. Note though
+/// that (due to the Vulkan API fence design) this will spin to check the fence, rather than
+/// blocking in the driver. Therefore if you have a long-running task, blocking may be less
+/// CPU intense (depending on the driver's implementation).
+///
/// Also note that the `GpuFuture` trait is implemented on `Arc<FenceSignalFuture<_>>`.
/// This means that you can put this future in an `Arc` and keep a copy of it somewhere in order
/// to know when the execution reached that point.
@@ -71,7 +81,7 @@ pub enum FenceSignalFutureBehavior {
/// use std::sync::Arc;
/// use vulkano::sync::GpuFuture;
///
-/// # let future: Box<GpuFuture> = return;
+/// # let future: Box<dyn GpuFuture> = return;
/// // Assuming you have a chain of operations, like this:
/// // let future = ...
/// // .then_execute(foo)
@@ -106,17 +116,17 @@ where
// been dropped).
enum FenceSignalFutureState<F> {
// Newly-created. Not submitted yet.
- Pending(F, Fence),
+ Pending(F, Arc<Fence>),
// Partially submitted to the queue. Only happens in situations where submitting requires two
// steps, and when the first step succeeded while the second step failed.
//
// Note that if there's ever a submit operation that needs three steps we will need to rework
// this code, as it was designed for two-step operations only.
- PartiallyFlushed(F, Fence),
+ PartiallyFlushed(F, Arc<Fence>),
// Submitted to the queue.
- Flushed(F, Fence),
+ Flushed(F, Arc<Fence>),
// The submission is finished. The previous future and the fence have been cleaned.
Cleaned,
@@ -129,6 +139,19 @@ impl<F> FenceSignalFuture<F>
where
F: GpuFuture,
{
+ /// Returns true if the fence is signaled by the GPU.
+ pub fn is_signaled(&self) -> Result<bool, OomError> {
+ let state = self.state.lock();
+
+ match &*state {
+ FenceSignalFutureState::Pending(_, fence)
+ | FenceSignalFutureState::PartiallyFlushed(_, fence)
+ | FenceSignalFutureState::Flushed(_, fence) => fence.is_signaled(),
+ FenceSignalFutureState::Cleaned => Ok(true),
+ FenceSignalFutureState::Poisoned => unreachable!(),
+ }
+ }
+
/// Blocks the current thread until the fence is signaled by the GPU. Performs a flush if
/// necessary.
///
@@ -138,11 +161,11 @@ where
/// If the wait is successful, this function also cleans any resource locked by previous
/// submissions.
pub fn wait(&self, timeout: Option<Duration>) -> Result<(), FlushError> {
- let mut state = self.state.lock().unwrap();
+ let mut state = self.state.lock();
self.flush_impl(&mut state)?;
- match mem::replace(&mut *state, FenceSignalFutureState::Cleaned) {
+ match replace(&mut *state, FenceSignalFutureState::Cleaned) {
FenceSignalFutureState::Flushed(previous, fence) => {
fence.wait(timeout)?;
unsafe {
@@ -162,48 +185,43 @@ where
{
// Implementation of `cleanup_finished`, but takes a `&self` instead of a `&mut self`.
// This is an external function so that we can also call it from an `Arc<FenceSignalFuture>`.
- #[inline]
fn cleanup_finished_impl(&self) {
- let mut state = self.state.lock().unwrap();
+ let mut state = self.state.lock();
match *state {
FenceSignalFutureState::Flushed(ref mut prev, ref fence) => {
match fence.wait(Some(Duration::from_secs(0))) {
- Ok(()) => unsafe { prev.signal_finished() },
+ Ok(()) => {
+ unsafe { prev.signal_finished() }
+ *state = FenceSignalFutureState::Cleaned;
+ }
Err(_) => {
prev.cleanup_finished();
- return;
}
}
}
FenceSignalFutureState::Pending(ref mut prev, _) => {
prev.cleanup_finished();
- return;
}
FenceSignalFutureState::PartiallyFlushed(ref mut prev, _) => {
prev.cleanup_finished();
- return;
}
- _ => return,
- };
-
- // This code can only be reached if we're already flushed and waiting on the fence
- // succeeded.
- *state = FenceSignalFutureState::Cleaned;
+ _ => (),
+ }
}
// Implementation of `flush`. You must lock the state and pass the mutex guard here.
fn flush_impl(
&self,
- state: &mut MutexGuard<FenceSignalFutureState<F>>,
+ state: &mut MutexGuard<'_, FenceSignalFutureState<F>>,
) -> Result<(), FlushError> {
unsafe {
// In this function we temporarily replace the current state with `Poisoned` at the
// beginning, and we take care to always put back a value into `state` before
// returning (even in case of error).
- let old_state = mem::replace(&mut **state, FenceSignalFutureState::Poisoned);
+ let old_state = replace(&mut **state, FenceSignalFutureState::Poisoned);
- let (previous, fence, partially_flushed) = match old_state {
+ let (previous, new_fence, partially_flushed) = match old_state {
FenceSignalFutureState::Pending(prev, fence) => (prev, fence, false),
FenceSignalFutureState::PartiallyFlushed(prev, fence) => (prev, fence, true),
other => {
@@ -215,7 +233,7 @@ where
};
// TODO: meh for unwrap
- let queue = previous.queue().unwrap().clone();
+ let queue = previous.queue().unwrap();
// There are three possible outcomes for the flush operation: success, partial success
// in which case `result` will contain `Err(OutcomeErr::Partial)`, or total failure
@@ -227,51 +245,107 @@ where
let result = match previous.build_submission()? {
SubmitAnyBuilder::Empty => {
debug_assert!(!partially_flushed);
- let mut b = SubmitCommandBufferBuilder::new();
- b.set_fence_signal(&fence);
- b.submit(&queue).map_err(|err| OutcomeErr::Full(err.into()))
+
+ queue
+ .with(|mut q| {
+ q.submit_unchecked([Default::default()], Some(new_fence.clone()))
+ })
+ .map_err(|err| OutcomeErr::Full(err.into()))
}
- SubmitAnyBuilder::SemaphoresWait(sem) => {
+ SubmitAnyBuilder::SemaphoresWait(semaphores) => {
debug_assert!(!partially_flushed);
- let b: SubmitCommandBufferBuilder = sem.into();
- debug_assert!(!b.has_fence());
- b.submit(&queue).map_err(|err| OutcomeErr::Full(err.into()))
+
+ queue
+ .with(|mut q| {
+ q.submit_unchecked(
+ [SubmitInfo {
+ wait_semaphores: semaphores
+ .into_iter()
+ .map(|semaphore| {
+ SemaphoreSubmitInfo {
+ // TODO: correct stages ; hard
+ stages: PipelineStages::ALL_COMMANDS,
+ ..SemaphoreSubmitInfo::semaphore(semaphore)
+ }
+ })
+ .collect(),
+ ..Default::default()
+ }],
+ None,
+ )
+ })
+ .map_err(|err| OutcomeErr::Full(err.into()))
}
- SubmitAnyBuilder::CommandBuffer(mut cb_builder) => {
+ SubmitAnyBuilder::CommandBuffer(submit_info, fence) => {
debug_assert!(!partially_flushed);
// The assert below could technically be a debug assertion as it is part of the
// safety contract of the trait. However it is easy to get this wrong if you
// write a custom implementation, and if so the consequences would be
// disastrous and hard to debug. Therefore we prefer to just use a regular
// assertion.
- assert!(!cb_builder.has_fence());
- cb_builder.set_fence_signal(&fence);
- cb_builder
- .submit(&queue)
- .map_err(|err| OutcomeErr::Full(err.into()))
+ assert!(fence.is_none());
+
+ queue
+ .with(|mut q| {
+ q.submit_with_future(
+ submit_info,
+ Some(new_fence.clone()),
+ &previous,
+ &queue,
+ )
+ })
+ .map_err(OutcomeErr::Full)
}
- SubmitAnyBuilder::BindSparse(mut sparse) => {
+ SubmitAnyBuilder::BindSparse(bind_infos, fence) => {
debug_assert!(!partially_flushed);
// Same remark as `CommandBuffer`.
- assert!(!sparse.has_fence());
- sparse.set_fence_signal(&fence);
- sparse
- .submit(&queue)
+ assert!(fence.is_none());
+ debug_assert!(queue.device().physical_device().queue_family_properties()
+ [queue.queue_family_index() as usize]
+ .queue_flags
+ .intersects(QueueFlags::SPARSE_BINDING));
+
+ queue
+ .with(|mut q| q.bind_sparse_unchecked(bind_infos, Some(new_fence.clone())))
.map_err(|err| OutcomeErr::Full(err.into()))
}
- SubmitAnyBuilder::QueuePresent(present) => {
+ SubmitAnyBuilder::QueuePresent(present_info) => {
let intermediary_result = if partially_flushed {
Ok(())
} else {
- present.submit(&queue)
+ // VUID-VkPresentIdKHR-presentIds-04999
+ for swapchain_info in &present_info.swapchain_infos {
+ if swapchain_info.present_id.map_or(false, |present_id| {
+ !swapchain_info.swapchain.try_claim_present_id(present_id)
+ }) {
+ return Err(FlushError::PresentIdLessThanOrEqual);
+ }
+
+ match previous.check_swapchain_image_acquired(
+ &swapchain_info.swapchain,
+ swapchain_info.image_index,
+ true,
+ ) {
+ Ok(_) => (),
+ Err(AccessCheckError::Unknown) => {
+ return Err(AccessError::SwapchainImageNotAcquired.into())
+ }
+ Err(AccessCheckError::Denied(e)) => return Err(e.into()),
+ }
+ }
+
+ queue
+ .with(|mut q| q.present_unchecked(present_info))?
+ .map(|r| r.map(|_| ()))
+ .fold(Ok(()), Result::and)
};
+
match intermediary_result {
- Ok(()) => {
- let mut b = SubmitCommandBufferBuilder::new();
- b.set_fence_signal(&fence);
- b.submit(&queue)
- .map_err(|err| OutcomeErr::Partial(err.into()))
- }
+ Ok(()) => queue
+ .with(|mut q| {
+ q.submit_unchecked([Default::default()], Some(new_fence.clone()))
+ })
+ .map_err(|err| OutcomeErr::Partial(err.into())),
Err(err) => Err(OutcomeErr::Full(err.into())),
}
}
@@ -280,15 +354,15 @@ where
// Restore the state before returning.
match result {
Ok(()) => {
- **state = FenceSignalFutureState::Flushed(previous, fence);
+ **state = FenceSignalFutureState::Flushed(previous, new_fence);
Ok(())
}
Err(OutcomeErr::Partial(err)) => {
- **state = FenceSignalFutureState::PartiallyFlushed(previous, fence);
+ **state = FenceSignalFutureState::PartiallyFlushed(previous, new_fence);
Err(err)
}
Err(OutcomeErr::Full(err)) => {
- **state = FenceSignalFutureState::Pending(previous, fence);
+ **state = FenceSignalFutureState::Pending(previous, new_fence);
Err(err)
}
}
@@ -296,13 +370,32 @@ where
}
}
+impl<F> Future for FenceSignalFuture<F>
+where
+ F: GpuFuture,
+{
+ type Output = Result<(), OomError>;
+
+ fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+ // Implement through fence
+ let state = self.state.lock();
+
+ match &*state {
+ FenceSignalFutureState::Pending(_, fence)
+ | FenceSignalFutureState::PartiallyFlushed(_, fence)
+ | FenceSignalFutureState::Flushed(_, fence) => fence.poll_impl(cx),
+ FenceSignalFutureState::Cleaned => Poll::Ready(Ok(())),
+ FenceSignalFutureState::Poisoned => unreachable!(),
+ }
+ }
+}
+
impl<F> FenceSignalFutureState<F> {
- #[inline]
fn get_prev(&self) -> Option<&F> {
- match *self {
- FenceSignalFutureState::Pending(ref prev, _) => Some(prev),
- FenceSignalFutureState::PartiallyFlushed(ref prev, _) => Some(prev),
- FenceSignalFutureState::Flushed(ref prev, _) => Some(prev),
+ match self {
+ FenceSignalFutureState::Pending(prev, _) => Some(prev),
+ FenceSignalFutureState::PartiallyFlushed(prev, _) => Some(prev),
+ FenceSignalFutureState::Flushed(prev, _) => Some(prev),
FenceSignalFutureState::Cleaned => None,
FenceSignalFutureState::Poisoned => None,
}
@@ -313,18 +406,16 @@ unsafe impl<F> GpuFuture for FenceSignalFuture<F>
where
F: GpuFuture,
{
- #[inline]
fn cleanup_finished(&mut self) {
self.cleanup_finished_impl()
}
- #[inline]
unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
- let mut state = self.state.lock().unwrap();
+ let mut state = self.state.lock();
self.flush_impl(&mut state)?;
- match *state {
- FenceSignalFutureState::Flushed(_, ref fence) => match self.behavior {
+ match &*state {
+ FenceSignalFutureState::Flushed(_, fence) => match self.behavior {
FenceSignalFutureBehavior::Block { timeout } => {
fence.wait(timeout)?;
}
@@ -338,15 +429,13 @@ where
Ok(SubmitAnyBuilder::Empty)
}
- #[inline]
fn flush(&self) -> Result<(), FlushError> {
- let mut state = self.state.lock().unwrap();
+ let mut state = self.state.lock();
self.flush_impl(&mut state)
}
- #[inline]
unsafe fn signal_finished(&self) {
- let state = self.state.lock().unwrap();
+ let state = self.state.lock();
match *state {
FenceSignalFutureState::Flushed(ref prev, _) => {
prev.signal_finished();
@@ -356,24 +445,18 @@ where
}
}
- #[inline]
fn queue_change_allowed(&self) -> bool {
match self.behavior {
FenceSignalFutureBehavior::Continue => {
- let state = self.state.lock().unwrap();
- if state.get_prev().is_some() {
- false
- } else {
- true
- }
+ let state = self.state.lock();
+ state.get_prev().is_none()
}
FenceSignalFutureBehavior::Block { .. } => true,
}
}
- #[inline]
fn queue(&self) -> Option<Arc<Queue>> {
- let state = self.state.lock().unwrap();
+ let state = self.state.lock();
if let Some(prev) = state.get_prev() {
prev.queue()
} else {
@@ -381,32 +464,46 @@ where
}
}
- #[inline]
fn check_buffer_access(
&self,
- buffer: &dyn BufferAccess,
+ buffer: &Buffer,
+ range: Range<DeviceSize>,
exclusive: bool,
queue: &Queue,
- ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
- let state = self.state.lock().unwrap();
+ ) -> Result<(), AccessCheckError> {
+ let state = self.state.lock();
if let Some(previous) = state.get_prev() {
- previous.check_buffer_access(buffer, exclusive, queue)
+ previous.check_buffer_access(buffer, range, exclusive, queue)
} else {
Err(AccessCheckError::Unknown)
}
}
- #[inline]
fn check_image_access(
&self,
- image: &dyn ImageAccess,
- layout: ImageLayout,
+ image: &Image,
+ range: Range<DeviceSize>,
exclusive: bool,
+ expected_layout: ImageLayout,
queue: &Queue,
- ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
- let state = self.state.lock().unwrap();
+ ) -> Result<(), AccessCheckError> {
+ let state = self.state.lock();
if let Some(previous) = state.get_prev() {
- previous.check_image_access(image, layout, exclusive, queue)
+ previous.check_image_access(image, range, exclusive, expected_layout, queue)
+ } else {
+ Err(AccessCheckError::Unknown)
+ }
+ }
+
+ #[inline]
+ fn check_swapchain_image_acquired(
+ &self,
+ swapchain: &Swapchain,
+ image_index: u32,
+ _before: bool,
+ ) -> Result<(), AccessCheckError> {
+ if let Some(previous) = self.state.lock().get_prev() {
+ previous.check_swapchain_image_acquired(swapchain, image_index, false)
} else {
Err(AccessCheckError::Unknown)
}
@@ -417,7 +514,6 @@ unsafe impl<F> DeviceOwned for FenceSignalFuture<F>
where
F: GpuFuture,
{
- #[inline]
fn device(&self) -> &Arc<Device> {
&self.device
}
@@ -428,12 +524,16 @@ where
F: GpuFuture,
{
fn drop(&mut self) {
- let mut state = self.state.lock().unwrap();
+ if thread::panicking() {
+ return;
+ }
+
+ let mut state = self.state.lock();
// We ignore any possible error while submitting for now. Problems are handled below.
let _ = self.flush_impl(&mut state);
- match mem::replace(&mut *state, FenceSignalFutureState::Cleaned) {
+ match replace(&mut *state, FenceSignalFutureState::Cleaned) {
FenceSignalFutureState::Flushed(previous, fence) => {
// This is a normal situation. Submitting worked.
// TODO: handle errors?
@@ -461,56 +561,60 @@ unsafe impl<F> GpuFuture for Arc<FenceSignalFuture<F>>
where
F: GpuFuture,
{
- #[inline]
fn cleanup_finished(&mut self) {
self.cleanup_finished_impl()
}
- #[inline]
unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
// Note that this is sound because we always return `SubmitAnyBuilder::Empty`. See the
// documentation of `build_submission`.
(**self).build_submission()
}
- #[inline]
fn flush(&self) -> Result<(), FlushError> {
(**self).flush()
}
- #[inline]
unsafe fn signal_finished(&self) {
(**self).signal_finished()
}
- #[inline]
fn queue_change_allowed(&self) -> bool {
(**self).queue_change_allowed()
}
- #[inline]
fn queue(&self) -> Option<Arc<Queue>> {
(**self).queue()
}
- #[inline]
fn check_buffer_access(
&self,
- buffer: &dyn BufferAccess,
+ buffer: &Buffer,
+ range: Range<DeviceSize>,
exclusive: bool,
queue: &Queue,
- ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
- (**self).check_buffer_access(buffer, exclusive, queue)
+ ) -> Result<(), AccessCheckError> {
+ (**self).check_buffer_access(buffer, range, exclusive, queue)
}
- #[inline]
fn check_image_access(
&self,
- image: &dyn ImageAccess,
- layout: ImageLayout,
+ image: &Image,
+ range: Range<DeviceSize>,
exclusive: bool,
+ expected_layout: ImageLayout,
queue: &Queue,
- ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
- (**self).check_image_access(image, layout, exclusive, queue)
+ ) -> Result<(), AccessCheckError> {
+ (**self).check_image_access(image, range, exclusive, expected_layout, queue)
+ }
+
+ #[inline]
+ fn check_swapchain_image_acquired(
+ &self,
+ swapchain: &Swapchain,
+ image_index: u32,
+ before: bool,
+ ) -> Result<(), AccessCheckError> {
+ (**self).check_swapchain_image_acquired(swapchain, image_index, before)
}
}
diff --git a/src/sync/future/join.rs b/src/sync/future/join.rs
index c45a764..6ead696 100644
--- a/src/sync/future/join.rs
+++ b/src/sync/future/join.rs
@@ -7,44 +7,30 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use std::sync::Arc;
-
-use crate::buffer::BufferAccess;
-use crate::command_buffer::submit::SubmitAnyBuilder;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::device::Queue;
-use crate::image::ImageAccess;
-use crate::image::ImageLayout;
-use crate::sync::AccessCheckError;
-use crate::sync::AccessFlags;
-use crate::sync::FlushError;
-use crate::sync::GpuFuture;
-use crate::sync::PipelineStages;
-
-use crate::VulkanObject;
+use super::{AccessCheckError, FlushError, GpuFuture, SubmitAnyBuilder};
+use crate::{
+ buffer::Buffer,
+ device::{Device, DeviceOwned, Queue},
+ image::{sys::Image, ImageLayout},
+ swapchain::Swapchain,
+ DeviceSize, VulkanObject,
+};
+use std::{ops::Range, sync::Arc};
/// Joins two futures together.
// TODO: handle errors
-#[inline]
pub fn join<F, S>(first: F, second: S) -> JoinFuture<F, S>
where
F: GpuFuture,
S: GpuFuture,
{
- assert_eq!(
- first.device().internal_object(),
- second.device().internal_object()
- );
+ assert_eq!(first.device().handle(), second.device().handle());
if !first.queue_change_allowed() && !second.queue_change_allowed() {
- assert!(first.queue().unwrap().is_same(&second.queue().unwrap()));
+ assert!(first.queue().unwrap() == second.queue().unwrap());
}
- JoinFuture {
- first: first,
- second: second,
- }
+ JoinFuture { first, second }
}
/// Two futures joined into one.
@@ -59,13 +45,9 @@ where
A: DeviceOwned,
B: DeviceOwned,
{
- #[inline]
fn device(&self) -> &Arc<Device> {
let device = self.first.device();
- debug_assert_eq!(
- self.second.device().internal_object(),
- device.internal_object()
- );
+ debug_assert_eq!(self.second.device().handle(), device.handle());
device
}
}
@@ -75,22 +57,20 @@ where
A: GpuFuture,
B: GpuFuture,
{
- #[inline]
fn cleanup_finished(&mut self) {
self.first.cleanup_finished();
self.second.cleanup_finished();
}
- #[inline]
fn flush(&self) -> Result<(), FlushError> {
// Since each future remembers whether it has been flushed, there's no safety issue here
// if we call this function multiple times.
self.first.flush()?;
self.second.flush()?;
+
Ok(())
}
- #[inline]
unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
// TODO: review this function
let first = self.first.build_submission()?;
@@ -102,90 +82,106 @@ where
(SubmitAnyBuilder::Empty, b) => b,
(a, SubmitAnyBuilder::Empty) => a,
(SubmitAnyBuilder::SemaphoresWait(mut a), SubmitAnyBuilder::SemaphoresWait(b)) => {
- a.merge(b);
+ a.extend(b);
SubmitAnyBuilder::SemaphoresWait(a)
}
- (SubmitAnyBuilder::SemaphoresWait(a), SubmitAnyBuilder::CommandBuffer(b)) => {
+ (SubmitAnyBuilder::SemaphoresWait(a), SubmitAnyBuilder::CommandBuffer(_, _)) => {
self.second.flush()?;
SubmitAnyBuilder::SemaphoresWait(a)
}
- (SubmitAnyBuilder::CommandBuffer(a), SubmitAnyBuilder::SemaphoresWait(b)) => {
+ (SubmitAnyBuilder::CommandBuffer(_, _), SubmitAnyBuilder::SemaphoresWait(b)) => {
self.first.flush()?;
SubmitAnyBuilder::SemaphoresWait(b)
}
- (SubmitAnyBuilder::SemaphoresWait(a), SubmitAnyBuilder::QueuePresent(b)) => {
+ (SubmitAnyBuilder::SemaphoresWait(a), SubmitAnyBuilder::QueuePresent(_)) => {
self.second.flush()?;
SubmitAnyBuilder::SemaphoresWait(a)
}
- (SubmitAnyBuilder::QueuePresent(a), SubmitAnyBuilder::SemaphoresWait(b)) => {
+ (SubmitAnyBuilder::QueuePresent(_), SubmitAnyBuilder::SemaphoresWait(b)) => {
self.first.flush()?;
SubmitAnyBuilder::SemaphoresWait(b)
}
- (SubmitAnyBuilder::SemaphoresWait(a), SubmitAnyBuilder::BindSparse(b)) => {
+ (SubmitAnyBuilder::SemaphoresWait(a), SubmitAnyBuilder::BindSparse(_, _)) => {
self.second.flush()?;
SubmitAnyBuilder::SemaphoresWait(a)
}
- (SubmitAnyBuilder::BindSparse(a), SubmitAnyBuilder::SemaphoresWait(b)) => {
+ (SubmitAnyBuilder::BindSparse(_, _), SubmitAnyBuilder::SemaphoresWait(b)) => {
self.first.flush()?;
SubmitAnyBuilder::SemaphoresWait(b)
}
- (SubmitAnyBuilder::CommandBuffer(a), SubmitAnyBuilder::CommandBuffer(b)) => {
- // TODO: we may want to add debug asserts here
- let new = a.merge(b);
- SubmitAnyBuilder::CommandBuffer(new)
+ (
+ SubmitAnyBuilder::CommandBuffer(mut submit_info_a, fence_a),
+ SubmitAnyBuilder::CommandBuffer(submit_info_b, fence_b),
+ ) => {
+ assert!(
+ fence_a.is_none() || fence_b.is_none(),
+ "Can't merge two queue submits that both have a fence"
+ );
+
+ submit_info_a
+ .wait_semaphores
+ .extend(submit_info_b.wait_semaphores);
+ submit_info_a
+ .command_buffers
+ .extend(submit_info_b.command_buffers);
+ submit_info_a
+ .signal_semaphores
+ .extend(submit_info_b.signal_semaphores);
+
+ SubmitAnyBuilder::CommandBuffer(submit_info_a, fence_a.or(fence_b))
}
- (SubmitAnyBuilder::QueuePresent(a), SubmitAnyBuilder::QueuePresent(b)) => {
+ (SubmitAnyBuilder::QueuePresent(_), SubmitAnyBuilder::QueuePresent(_)) => {
self.first.flush()?;
self.second.flush()?;
SubmitAnyBuilder::Empty
}
- (SubmitAnyBuilder::CommandBuffer(a), SubmitAnyBuilder::QueuePresent(b)) => {
+ (SubmitAnyBuilder::CommandBuffer(_, _), SubmitAnyBuilder::QueuePresent(_)) => {
unimplemented!()
}
- (SubmitAnyBuilder::QueuePresent(a), SubmitAnyBuilder::CommandBuffer(b)) => {
+ (SubmitAnyBuilder::QueuePresent(_), SubmitAnyBuilder::CommandBuffer(_, _)) => {
unimplemented!()
}
- (SubmitAnyBuilder::BindSparse(a), SubmitAnyBuilder::QueuePresent(b)) => {
+ (SubmitAnyBuilder::BindSparse(_, _), SubmitAnyBuilder::QueuePresent(_)) => {
unimplemented!()
}
- (SubmitAnyBuilder::QueuePresent(a), SubmitAnyBuilder::BindSparse(b)) => {
+ (SubmitAnyBuilder::QueuePresent(_), SubmitAnyBuilder::BindSparse(_, _)) => {
unimplemented!()
}
- (SubmitAnyBuilder::BindSparse(a), SubmitAnyBuilder::CommandBuffer(b)) => {
+ (SubmitAnyBuilder::BindSparse(_, _), SubmitAnyBuilder::CommandBuffer(_, _)) => {
unimplemented!()
}
- (SubmitAnyBuilder::CommandBuffer(a), SubmitAnyBuilder::BindSparse(b)) => {
+ (SubmitAnyBuilder::CommandBuffer(_, _), SubmitAnyBuilder::BindSparse(_, _)) => {
unimplemented!()
}
- (SubmitAnyBuilder::BindSparse(mut a), SubmitAnyBuilder::BindSparse(b)) => {
- match a.merge(b) {
- Ok(()) => SubmitAnyBuilder::BindSparse(a),
- Err(_) => {
- // TODO: this happens if both bind sparse have been given a fence already
- // annoying, but not impossible, to handle
- unimplemented!()
- }
+ (
+ SubmitAnyBuilder::BindSparse(mut bind_infos_a, fence_a),
+ SubmitAnyBuilder::BindSparse(bind_infos_b, fence_b),
+ ) => {
+ if fence_a.is_some() && fence_b.is_some() {
+ // TODO: this happens if both bind sparse have been given a fence already
+ // annoying, but not impossible, to handle
+ unimplemented!()
}
+
+ bind_infos_a.extend(bind_infos_b);
+ SubmitAnyBuilder::BindSparse(bind_infos_a, fence_a)
}
})
}
- #[inline]
unsafe fn signal_finished(&self) {
self.first.signal_finished();
self.second.signal_finished();
}
- #[inline]
fn queue_change_allowed(&self) -> bool {
self.first.queue_change_allowed() && self.second.queue_change_allowed()
}
- #[inline]
fn queue(&self) -> Option<Arc<Queue>> {
match (self.first.queue(), self.second.queue()) {
(Some(q1), Some(q2)) => {
- if q1.is_same(&q2) {
+ if q1 == q2 {
Some(q1)
} else if self.first.queue_change_allowed() {
Some(q2)
@@ -201,68 +197,93 @@ where
}
}
- #[inline]
fn check_buffer_access(
&self,
- buffer: &dyn BufferAccess,
+ buffer: &Buffer,
+ range: Range<DeviceSize>,
exclusive: bool,
queue: &Queue,
- ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
- let first = self.first.check_buffer_access(buffer, exclusive, queue);
- let second = self.second.check_buffer_access(buffer, exclusive, queue);
+ ) -> Result<(), AccessCheckError> {
+ let first = self
+ .first
+ .check_buffer_access(buffer, range.clone(), exclusive, queue);
+ let second = self
+ .second
+ .check_buffer_access(buffer, range, exclusive, queue);
debug_assert!(
- !exclusive || !(first.is_ok() && second.is_ok()),
+ !(exclusive && first.is_ok() && second.is_ok()),
"Two futures gave exclusive access to the same resource"
);
match (first, second) {
(v, Err(AccessCheckError::Unknown)) => v,
(Err(AccessCheckError::Unknown), v) => v,
- (Err(AccessCheckError::Denied(e1)), Err(AccessCheckError::Denied(e2))) => {
+ (Err(AccessCheckError::Denied(e1)), Err(AccessCheckError::Denied(_))) => {
Err(AccessCheckError::Denied(e1))
} // TODO: which one?
- (Ok(_), Err(AccessCheckError::Denied(_)))
- | (Err(AccessCheckError::Denied(_)), Ok(_)) => panic!(
+ (Ok(()), Err(AccessCheckError::Denied(_)))
+ | (Err(AccessCheckError::Denied(_)), Ok(())) => panic!(
"Contradictory information \
between two futures"
),
- (Ok(None), Ok(None)) => Ok(None),
- (Ok(Some(a)), Ok(None)) | (Ok(None), Ok(Some(a))) => Ok(Some(a)),
- (Ok(Some((a1, a2))), Ok(Some((b1, b2)))) => Ok(Some((a1 | b1, a2 | b2))),
+ (Ok(()), Ok(())) => Ok(()),
}
}
- #[inline]
fn check_image_access(
&self,
- image: &dyn ImageAccess,
- layout: ImageLayout,
+ image: &Image,
+ range: Range<DeviceSize>,
exclusive: bool,
+ expected_layout: ImageLayout,
queue: &Queue,
- ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
+ ) -> Result<(), AccessCheckError> {
+ let first =
+ self.first
+ .check_image_access(image, range.clone(), exclusive, expected_layout, queue);
+ let second =
+ self.second
+ .check_image_access(image, range, exclusive, expected_layout, queue);
+ debug_assert!(
+ !(exclusive && first.is_ok() && second.is_ok()),
+ "Two futures gave exclusive access to the same resource"
+ );
+ match (first, second) {
+ (v, Err(AccessCheckError::Unknown)) => v,
+ (Err(AccessCheckError::Unknown), v) => v,
+ (Err(AccessCheckError::Denied(e1)), Err(AccessCheckError::Denied(_))) => {
+ Err(AccessCheckError::Denied(e1))
+ } // TODO: which one?
+ (Ok(()), Err(AccessCheckError::Denied(_)))
+ | (Err(AccessCheckError::Denied(_)), Ok(())) => {
+ panic!("Contradictory information between two futures")
+ }
+ (Ok(()), Ok(())) => Ok(()),
+ }
+ }
+
+ #[inline]
+ fn check_swapchain_image_acquired(
+ &self,
+ swapchain: &Swapchain,
+ image_index: u32,
+ _before: bool,
+ ) -> Result<(), AccessCheckError> {
let first = self
.first
- .check_image_access(image, layout, exclusive, queue);
+ .check_swapchain_image_acquired(swapchain, image_index, false);
let second = self
.second
- .check_image_access(image, layout, exclusive, queue);
- debug_assert!(
- !exclusive || !(first.is_ok() && second.is_ok()),
- "Two futures gave exclusive access to the same resource"
- );
+ .check_swapchain_image_acquired(swapchain, image_index, false);
+
match (first, second) {
(v, Err(AccessCheckError::Unknown)) => v,
(Err(AccessCheckError::Unknown), v) => v,
- (Err(AccessCheckError::Denied(e1)), Err(AccessCheckError::Denied(e2))) => {
+ (Err(AccessCheckError::Denied(e1)), Err(AccessCheckError::Denied(_))) => {
Err(AccessCheckError::Denied(e1))
} // TODO: which one?
- (Ok(_), Err(AccessCheckError::Denied(_)))
- | (Err(AccessCheckError::Denied(_)), Ok(_)) => panic!(
- "Contradictory information \
- between two futures"
- ),
- (Ok(None), Ok(None)) => Ok(None),
- (Ok(Some(a)), Ok(None)) | (Ok(None), Ok(Some(a))) => Ok(Some(a)),
- (Ok(Some((a1, a2))), Ok(Some((b1, b2)))) => Ok(Some((a1 | b1, a2 | b2))),
+ (Ok(()), Err(AccessCheckError::Denied(_)))
+ | (Err(AccessCheckError::Denied(_)), Ok(())) => Ok(()),
+ (Ok(()), Ok(())) => Ok(()), // TODO: Double Acquired?
}
}
}
diff --git a/src/sync/future/mod.rs b/src/sync/future/mod.rs
index e6fde7a..e03e54b 100644
--- a/src/sync/future/mod.rs
+++ b/src/sync/future/mod.rs
@@ -7,33 +7,118 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-pub use self::fence_signal::{FenceSignalFuture, FenceSignalFutureBehavior};
-pub use self::join::JoinFuture;
-pub use self::now::{now, NowFuture};
-pub use self::semaphore_signal::SemaphoreSignalFuture;
-use crate::buffer::BufferAccess;
-use crate::command_buffer::submit::SubmitAnyBuilder;
-use crate::command_buffer::submit::SubmitBindSparseError;
-use crate::command_buffer::submit::SubmitCommandBufferError;
-use crate::command_buffer::submit::SubmitPresentError;
-use crate::command_buffer::CommandBufferExecError;
-use crate::command_buffer::CommandBufferExecFuture;
-use crate::command_buffer::PrimaryCommandBuffer;
-use crate::device::DeviceOwned;
-use crate::device::Queue;
-use crate::image::ImageAccess;
-use crate::image::ImageLayout;
-use crate::swapchain;
-use crate::swapchain::PresentFuture;
-use crate::swapchain::PresentRegion;
-use crate::swapchain::Swapchain;
-use crate::sync::AccessFlags;
-use crate::sync::FenceWaitError;
-use crate::sync::PipelineStages;
-use crate::OomError;
-use std::error;
-use std::fmt;
-use std::sync::Arc;
+//! Represents an event that will happen on the GPU in the future.
+//!
+//! Whenever you ask the GPU to start an operation by using a function of the vulkano library (for
+//! example executing a command buffer), this function will return a *future*. A future is an
+//! object that implements [the `GpuFuture` trait](crate::sync::GpuFuture) and that represents the
+//! point in time when this operation is over.
+//!
+//! No function in vulkano immediately sends an operation to the GPU (with the exception of some
+//! unsafe low-level functions). Instead they return a future that is in the pending state. Before
+//! the GPU actually starts doing anything, you have to *flush* the future by calling the `flush()`
+//! method or one of its derivatives.
+//!
+//! Futures serve several roles:
+//!
+//! - Futures can be used to build dependencies between operations and makes it possible to ask
+//! that an operation starts only after a previous operation is finished.
+//! - Submitting an operation to the GPU is a costly operation. By chaining multiple operations
+//! with futures you will submit them all at once instead of one by one, thereby reducing this
+//! cost.
+//! - Futures keep alive the resources and objects used by the GPU so that they don't get destroyed
+//! while they are still in use.
+//!
+//! The last point means that you should keep futures alive in your program for as long as their
+//! corresponding operation is potentially still being executed by the GPU. Dropping a future
+//! earlier will block the current thread (after flushing, if necessary) until the GPU has finished
+//! the operation, which is usually not what you want.
+//!
+//! If you write a function that submits an operation to the GPU in your program, you are
+//! encouraged to let this function return the corresponding future and let the caller handle it.
+//! This way the caller will be able to chain multiple futures together and decide when it wants to
+//! keep the future alive or drop it.
+//!
+//! # Executing an operation after a future
+//!
+//! Respecting the order of operations on the GPU is important, as it is what *proves* vulkano that
+//! what you are doing is indeed safe. For example if you submit two operations that modify the
+//! same buffer, then you need to execute one after the other instead of submitting them
+//! independently. Failing to do so would mean that these two operations could potentially execute
+//! simultaneously on the GPU, which would be unsafe.
+//!
+//! This is done by calling one of the methods of the `GpuFuture` trait. For example calling
+//! `prev_future.then_execute(command_buffer)` takes ownership of `prev_future` and will make sure
+//! to only start executing `command_buffer` after the moment corresponding to `prev_future`
+//! happens. The object returned by the `then_execute` function is itself a future that corresponds
+//! to the moment when the execution of `command_buffer` ends.
+//!
+//! ## Between two different GPU queues
+//!
+//! When you want to perform an operation after another operation on two different queues, you
+//! **must** put a *semaphore* between them. Failure to do so would result in a runtime error.
+//! Adding a semaphore is a simple as replacing `prev_future.then_execute(...)` with
+//! `prev_future.then_signal_semaphore().then_execute(...)`.
+//!
+//! > **Note**: A common use-case is using a transfer queue (ie. a queue that is only capable of
+//! > performing transfer operations) to write data to a buffer, then read that data from the
+//! > rendering queue.
+//!
+//! What happens when you do so is that the first queue will execute the first set of operations
+//! (represented by `prev_future` in the example), then put a semaphore in the signalled state.
+//! Meanwhile the second queue blocks (if necessary) until that same semaphore gets signalled, and
+//! then only will execute the second set of operations.
+//!
+//! Since you want to avoid blocking the second queue as much as possible, you probably want to
+//! flush the operation to the first queue as soon as possible. This can easily be done by calling
+//! `then_signal_semaphore_and_flush()` instead of `then_signal_semaphore()`.
+//!
+//! ## Between several different GPU queues
+//!
+//! The `then_signal_semaphore()` method is appropriate when you perform an operation in one queue,
+//! and want to see the result in another queue. However in some situations you want to start
+//! multiple operations on several different queues.
+//!
+//! TODO: this is not yet implemented
+//!
+//! # Fences
+//!
+//! A `Fence` is an object that is used to signal the CPU when an operation on the GPU is finished.
+//!
+//! Signalling a fence is done by calling `then_signal_fence()` on a future. Just like semaphores,
+//! you are encouraged to use `then_signal_fence_and_flush()` instead.
+//!
+//! Signalling a fence is kind of a "terminator" to a chain of futures
+
+pub use self::{
+ fence_signal::{FenceSignalFuture, FenceSignalFutureBehavior},
+ join::JoinFuture,
+ now::{now, NowFuture},
+ semaphore_signal::SemaphoreSignalFuture,
+};
+use super::{
+ fence::{Fence, FenceError},
+ semaphore::Semaphore,
+};
+use crate::{
+ buffer::Buffer,
+ command_buffer::{
+ CommandBufferExecError, CommandBufferExecFuture, PrimaryCommandBufferAbstract,
+ ResourceUseRef, SubmitInfo,
+ },
+ device::{DeviceOwned, Queue},
+ image::{sys::Image, ImageLayout},
+ memory::BindSparseInfo,
+ swapchain::{self, PresentFuture, PresentInfo, Swapchain, SwapchainPresentInfo},
+ DeviceSize, OomError, VulkanError,
+};
+use smallvec::SmallVec;
+use std::{
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+ ops::Range,
+ sync::Arc,
+};
mod fence_signal;
mod join;
@@ -108,24 +193,19 @@ pub unsafe trait GpuFuture: DeviceOwned {
/// Checks whether submitting something after this future grants access (exclusive or shared,
/// depending on the parameter) to the given buffer on the given queue.
///
- /// If the access is granted, returns the pipeline stage and access flags of the latest usage
- /// of this resource, or `None` if irrelevant.
- ///
/// > **Note**: Returning `Ok` means "access granted", while returning `Err` means
/// > "don't know". Therefore returning `Err` is never unsafe.
fn check_buffer_access(
&self,
- buffer: &dyn BufferAccess,
+ buffer: &Buffer,
+ range: Range<DeviceSize>,
exclusive: bool,
queue: &Queue,
- ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>;
+ ) -> Result<(), AccessCheckError>;
/// Checks whether submitting something after this future grants access (exclusive or shared,
/// depending on the parameter) to the given image on the given queue.
///
- /// If the access is granted, returns the pipeline stage and access flags of the latest usage
- /// of this resource, or `None` if irrelevant.
- ///
/// Implementations must ensure that the image is in the given layout. However if the `layout`
/// is `Undefined` then the implementation should accept any actual layout.
///
@@ -136,11 +216,23 @@ pub unsafe trait GpuFuture: DeviceOwned {
/// > access.
fn check_image_access(
&self,
- image: &dyn ImageAccess,
- layout: ImageLayout,
+ image: &Image,
+ range: Range<DeviceSize>,
exclusive: bool,
+ expected_layout: ImageLayout,
queue: &Queue,
- ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>;
+ ) -> Result<(), AccessCheckError>;
+
+ /// Checks whether accessing a swapchain image is permitted.
+ ///
+ /// > **Note**: Setting `before` to `true` should skip checking the current future and always
+ /// > forward the call to the future before.
+ fn check_swapchain_image_acquired(
+ &self,
+ swapchain: &Swapchain,
+ image_index: u32,
+ before: bool,
+ ) -> Result<(), AccessCheckError>;
/// Joins this future with another one, representing the moment when both events have happened.
// TODO: handle errors
@@ -156,15 +248,14 @@ pub unsafe trait GpuFuture: DeviceOwned {
///
/// > **Note**: This is just a shortcut function. The actual implementation is in the
/// > `CommandBuffer` trait.
- #[inline]
fn then_execute<Cb>(
self,
queue: Arc<Queue>,
command_buffer: Cb,
- ) -> Result<CommandBufferExecFuture<Self, Cb>, CommandBufferExecError>
+ ) -> Result<CommandBufferExecFuture<Self>, CommandBufferExecError>
where
Self: Sized,
- Cb: PrimaryCommandBuffer + 'static,
+ Cb: PrimaryCommandBufferAbstract + 'static,
{
command_buffer.execute_after(self, queue)
}
@@ -173,16 +264,15 @@ pub unsafe trait GpuFuture: DeviceOwned {
///
/// > **Note**: This is just a shortcut function. The actual implementation is in the
/// > `CommandBuffer` trait.
- #[inline]
fn then_execute_same_queue<Cb>(
self,
command_buffer: Cb,
- ) -> Result<CommandBufferExecFuture<Self, Cb>, CommandBufferExecError>
+ ) -> Result<CommandBufferExecFuture<Self>, CommandBufferExecError>
where
Self: Sized,
- Cb: PrimaryCommandBuffer + 'static,
+ Cb: PrimaryCommandBufferAbstract + 'static,
{
- let queue = self.queue().unwrap().clone();
+ let queue = self.queue().unwrap();
command_buffer.execute_after(self, queue)
}
@@ -218,6 +308,7 @@ pub unsafe trait GpuFuture: DeviceOwned {
{
let f = self.then_signal_semaphore();
f.flush()?;
+
Ok(f)
}
@@ -243,6 +334,7 @@ pub unsafe trait GpuFuture: DeviceOwned {
{
let f = self.then_signal_fence();
f.flush()?;
+
Ok(f)
}
@@ -253,41 +345,58 @@ pub unsafe trait GpuFuture: DeviceOwned {
///
/// > **Note**: This is just a shortcut for the `Swapchain::present()` function.
#[inline]
- fn then_swapchain_present<W>(
+ fn then_swapchain_present(
self,
queue: Arc<Queue>,
- swapchain: Arc<Swapchain<W>>,
- image_index: usize,
- ) -> PresentFuture<Self, W>
+ swapchain_info: SwapchainPresentInfo,
+ ) -> PresentFuture<Self>
where
Self: Sized,
{
- swapchain::present(swapchain, self, queue, image_index)
+ swapchain::present(self, queue, swapchain_info)
}
- /// Same as `then_swapchain_present`, except it allows specifying a present region.
+ /// Turn the current future into a `Box<dyn GpuFuture>`.
///
- /// > **Note**: This is just a shortcut for the `Swapchain::present_incremental()` function.
+ /// This is a helper function that calls `Box::new(yourFuture) as Box<dyn GpuFuture>`.
#[inline]
- fn then_swapchain_present_incremental<W>(
- self,
- queue: Arc<Queue>,
- swapchain: Arc<Swapchain<W>>,
- image_index: usize,
- present_region: PresentRegion,
- ) -> PresentFuture<Self, W>
+ fn boxed(self) -> Box<dyn GpuFuture>
where
- Self: Sized,
+ Self: Sized + 'static,
{
- swapchain::present_incremental(swapchain, self, queue, image_index, present_region)
+ Box::new(self) as _
}
- /// Turn the current future into a `Box<dyn GpuFuture>`.
+ /// Turn the current future into a `Box<dyn GpuFuture + Send>`.
///
- /// This is a helper function that calls `Box::new(yourFuture) as Box<dyn GpuFuture>`.
- fn boxed(self) -> Box<dyn GpuFuture>
+ /// This is a helper function that calls `Box::new(yourFuture) as Box<dyn GpuFuture + Send>`.
+ #[inline]
+ fn boxed_send(self) -> Box<dyn GpuFuture + Send>
where
- Self: Sized + 'static,
+ Self: Sized + Send + 'static,
+ {
+ Box::new(self) as _
+ }
+
+ /// Turn the current future into a `Box<dyn GpuFuture + Sync>`.
+ ///
+ /// This is a helper function that calls `Box::new(yourFuture) as Box<dyn GpuFuture + Sync>`.
+ #[inline]
+ fn boxed_sync(self) -> Box<dyn GpuFuture + Sync>
+ where
+ Self: Sized + Sync + 'static,
+ {
+ Box::new(self) as _
+ }
+
+ /// Turn the current future into a `Box<dyn GpuFuture + Send + Sync>`.
+ ///
+ /// This is a helper function that calls `Box::new(yourFuture) as Box<dyn GpuFuture + Send +
+ /// Sync>`.
+ #[inline]
+ fn boxed_send_sync(self) -> Box<dyn GpuFuture + Send + Sync>
+ where
+ Self: Sized + Send + Sync + 'static,
{
Box::new(self) as _
}
@@ -297,55 +406,77 @@ unsafe impl<F: ?Sized> GpuFuture for Box<F>
where
F: GpuFuture,
{
- #[inline]
fn cleanup_finished(&mut self) {
(**self).cleanup_finished()
}
- #[inline]
unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
(**self).build_submission()
}
- #[inline]
fn flush(&self) -> Result<(), FlushError> {
(**self).flush()
}
- #[inline]
unsafe fn signal_finished(&self) {
(**self).signal_finished()
}
- #[inline]
fn queue_change_allowed(&self) -> bool {
(**self).queue_change_allowed()
}
- #[inline]
fn queue(&self) -> Option<Arc<Queue>> {
(**self).queue()
}
- #[inline]
fn check_buffer_access(
&self,
- buffer: &dyn BufferAccess,
+ buffer: &Buffer,
+ range: Range<DeviceSize>,
exclusive: bool,
queue: &Queue,
- ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
- (**self).check_buffer_access(buffer, exclusive, queue)
+ ) -> Result<(), AccessCheckError> {
+ (**self).check_buffer_access(buffer, range, exclusive, queue)
}
- #[inline]
fn check_image_access(
&self,
- image: &dyn ImageAccess,
- layout: ImageLayout,
+ image: &Image,
+ range: Range<DeviceSize>,
exclusive: bool,
+ expected_layout: ImageLayout,
queue: &Queue,
- ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
- (**self).check_image_access(image, layout, exclusive, queue)
+ ) -> Result<(), AccessCheckError> {
+ (**self).check_image_access(image, range, exclusive, expected_layout, queue)
+ }
+
+ #[inline]
+ fn check_swapchain_image_acquired(
+ &self,
+ swapchain: &Swapchain,
+ image_index: u32,
+ before: bool,
+ ) -> Result<(), AccessCheckError> {
+ (**self).check_swapchain_image_acquired(swapchain, image_index, before)
+ }
+}
+
+/// Contains all the possible submission builders.
+#[derive(Debug)]
+pub enum SubmitAnyBuilder {
+ Empty,
+ SemaphoresWait(SmallVec<[Arc<Semaphore>; 8]>),
+ CommandBuffer(SubmitInfo, Option<Arc<Fence>>),
+ QueuePresent(PresentInfo),
+ BindSparse(SmallVec<[BindSparseInfo; 1]>, Option<Arc<Fence>>),
+}
+
+impl SubmitAnyBuilder {
+ /// Returns true if equal to `SubmitAnyBuilder::Empty`.
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ matches!(self, SubmitAnyBuilder::Empty)
}
}
@@ -374,18 +505,17 @@ pub enum AccessError {
BufferNotInitialized,
/// Trying to use a swapchain image without depending on a corresponding acquire image future.
- SwapchainImageAcquireOnly,
+ SwapchainImageNotAcquired,
}
-impl error::Error for AccessError {}
+impl Error for AccessError {}
-impl fmt::Display for AccessError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+impl Display for AccessError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
write!(
- fmt,
+ f,
"{}",
- match *self {
+ match self {
AccessError::ExclusiveDenied => "only shared access is allowed for this resource",
AccessError::AlreadyInUse => {
"the resource is already in use, and there is no tracking of concurrent usages"
@@ -395,14 +525,14 @@ impl fmt::Display for AccessError {
}
AccessError::ImageNotInitialized { .. } => {
"trying to use an image without transitioning it from the undefined or \
- preinitialized layouts first"
+ preinitialized layouts first"
}
AccessError::BufferNotInitialized => {
"trying to use a buffer that still contains garbage data"
}
- AccessError::SwapchainImageAcquireOnly => {
+ AccessError::SwapchainImageNotAcquired => {
"trying to use a swapchain image without depending on a corresponding acquire \
- image future"
+ image future"
}
}
)
@@ -418,15 +548,14 @@ pub enum AccessCheckError {
Unknown,
}
-impl error::Error for AccessCheckError {}
+impl Error for AccessCheckError {}
-impl fmt::Display for AccessCheckError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+impl Display for AccessCheckError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
write!(
- fmt,
+ f,
"{}",
- match *self {
+ match self {
AccessCheckError::Denied(_) => "access to the resource has been denied",
AccessCheckError::Unknown => "the resource is unknown",
}
@@ -435,7 +564,6 @@ impl fmt::Display for AccessCheckError {
}
impl From<AccessError> for AccessCheckError {
- #[inline]
fn from(err: AccessError) -> AccessCheckError {
AccessCheckError::Denied(err)
}
@@ -460,43 +588,72 @@ pub enum FlushError {
/// surface's new properties and recreate a new swapchain if you want to continue drawing.
OutOfDate,
- /// The swapchain has lost or doesn't have fullscreen exclusivity possibly for
+ /// The swapchain has lost or doesn't have full screen exclusivity possibly for
/// implementation-specific reasons outside of the application’s control.
- FullscreenExclusiveLost,
+ FullScreenExclusiveModeLost,
/// The flush operation needed to block, but the timeout has elapsed.
Timeout,
+
+ /// A non-zero present_id must be greater than any non-zero present_id passed previously
+ /// for the same swapchain.
+ PresentIdLessThanOrEqual,
+
+ /// Access to a resource has been denied.
+ ResourceAccessError {
+ error: AccessError,
+ use_ref: Option<ResourceUseRef>,
+ },
+
+ /// The command buffer or one of the secondary command buffers it executes was created with the
+ /// "one time submit" flag, but has already been submitted it the past.
+ OneTimeSubmitAlreadySubmitted,
+
+ /// The command buffer or one of the secondary command buffers it executes is already in use by
+ /// the GPU and was not created with the "concurrent" flag.
+ ExclusiveAlreadyInUse,
}
-impl error::Error for FlushError {
- #[inline]
- fn source(&self) -> Option<&(dyn error::Error + 'static)> {
- match *self {
- FlushError::AccessError(ref err) => Some(err),
- FlushError::OomError(ref err) => Some(err),
+impl Error for FlushError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ FlushError::AccessError(err) => Some(err),
+ FlushError::OomError(err) => Some(err),
+ FlushError::ResourceAccessError { error, .. } => Some(error),
_ => None,
}
}
}
-impl fmt::Display for FlushError {
- #[inline]
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+impl Display for FlushError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
write!(
- fmt,
+ f,
"{}",
- match *self {
+ match self {
FlushError::AccessError(_) => "access to a resource has been denied",
FlushError::OomError(_) => "not enough memory",
FlushError::DeviceLost => "the connection to the device has been lost",
FlushError::SurfaceLost => "the surface of this swapchain is no longer valid",
FlushError::OutOfDate => "the swapchain needs to be recreated",
- FlushError::FullscreenExclusiveLost => {
- "the swapchain no longer has fullscreen exclusivity"
+ FlushError::FullScreenExclusiveModeLost => {
+ "the swapchain no longer has full screen exclusivity"
}
FlushError::Timeout => {
- "the flush operation needed to block, but the timeout has \
- elapsed"
+ "the flush operation needed to block, but the timeout has elapsed"
+ }
+ FlushError::PresentIdLessThanOrEqual => {
+ "present id is less than or equal to previous"
+ }
+ FlushError::ResourceAccessError { .. } => "access to a resource has been denied",
+ FlushError::OneTimeSubmitAlreadySubmitted => {
+ "the command buffer or one of the secondary command buffers it executes was \
+ created with the \"one time submit\" flag, but has already been submitted in \
+ the past"
+ }
+ FlushError::ExclusiveAlreadyInUse => {
+ "the command buffer or one of the secondary command buffers it executes is \
+ already in use was not created with the \"concurrent\" flag"
}
}
)
@@ -504,52 +661,33 @@ impl fmt::Display for FlushError {
}
impl From<AccessError> for FlushError {
- #[inline]
fn from(err: AccessError) -> FlushError {
FlushError::AccessError(err)
}
}
-impl From<SubmitPresentError> for FlushError {
- #[inline]
- fn from(err: SubmitPresentError) -> FlushError {
+impl From<VulkanError> for FlushError {
+ fn from(err: VulkanError) -> Self {
match err {
- SubmitPresentError::OomError(err) => FlushError::OomError(err),
- SubmitPresentError::DeviceLost => FlushError::DeviceLost,
- SubmitPresentError::SurfaceLost => FlushError::SurfaceLost,
- SubmitPresentError::OutOfDate => FlushError::OutOfDate,
- SubmitPresentError::FullscreenExclusiveLost => FlushError::FullscreenExclusiveLost,
- }
- }
-}
-
-impl From<SubmitCommandBufferError> for FlushError {
- #[inline]
- fn from(err: SubmitCommandBufferError) -> FlushError {
- match err {
- SubmitCommandBufferError::OomError(err) => FlushError::OomError(err),
- SubmitCommandBufferError::DeviceLost => FlushError::DeviceLost,
- }
- }
-}
-
-impl From<SubmitBindSparseError> for FlushError {
- #[inline]
- fn from(err: SubmitBindSparseError) -> FlushError {
- match err {
- SubmitBindSparseError::OomError(err) => FlushError::OomError(err),
- SubmitBindSparseError::DeviceLost => FlushError::DeviceLost,
+ VulkanError::OutOfHostMemory | VulkanError::OutOfDeviceMemory => {
+ Self::OomError(err.into())
+ }
+ VulkanError::DeviceLost => Self::DeviceLost,
+ VulkanError::SurfaceLost => Self::SurfaceLost,
+ VulkanError::OutOfDate => Self::OutOfDate,
+ VulkanError::FullScreenExclusiveModeLost => Self::FullScreenExclusiveModeLost,
+ _ => panic!("unexpected error: {:?}", err),
}
}
}
-impl From<FenceWaitError> for FlushError {
- #[inline]
- fn from(err: FenceWaitError) -> FlushError {
+impl From<FenceError> for FlushError {
+ fn from(err: FenceError) -> FlushError {
match err {
- FenceWaitError::OomError(err) => FlushError::OomError(err),
- FenceWaitError::Timeout => FlushError::Timeout,
- FenceWaitError::DeviceLostError => FlushError::DeviceLost,
+ FenceError::OomError(err) => FlushError::OomError(err),
+ FenceError::Timeout => FlushError::Timeout,
+ FenceError::DeviceLost => FlushError::DeviceLost,
+ _ => unreachable!(),
}
}
}
diff --git a/src/sync/future/now.rs b/src/sync/future/now.rs
index 131eed6..11e53db 100644
--- a/src/sync/future/now.rs
+++ b/src/sync/future/now.rs
@@ -7,25 +7,20 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use std::sync::Arc;
-
-use crate::buffer::BufferAccess;
-use crate::command_buffer::submit::SubmitAnyBuilder;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::device::Queue;
-use crate::image::ImageAccess;
-use crate::image::ImageLayout;
-use crate::sync::AccessCheckError;
-use crate::sync::AccessFlags;
-use crate::sync::FlushError;
-use crate::sync::GpuFuture;
-use crate::sync::PipelineStages;
+use super::{AccessCheckError, FlushError, GpuFuture, SubmitAnyBuilder};
+use crate::{
+ buffer::Buffer,
+ device::{Device, DeviceOwned, Queue},
+ image::{sys::Image, ImageLayout},
+ swapchain::Swapchain,
+ DeviceSize,
+};
+use std::{ops::Range, sync::Arc};
/// Builds a future that represents "now".
#[inline]
pub fn now(device: Arc<Device>) -> NowFuture {
- NowFuture { device: device }
+ NowFuture { device }
}
/// A dummy future that represents "now".
@@ -63,21 +58,33 @@ unsafe impl GpuFuture for NowFuture {
#[inline]
fn check_buffer_access(
&self,
- buffer: &dyn BufferAccess,
- _: bool,
- _: &Queue,
- ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
+ _buffer: &Buffer,
+ _range: Range<DeviceSize>,
+ _exclusive: bool,
+ _queue: &Queue,
+ ) -> Result<(), AccessCheckError> {
Err(AccessCheckError::Unknown)
}
#[inline]
fn check_image_access(
&self,
- _: &dyn ImageAccess,
- _: ImageLayout,
- _: bool,
- _: &Queue,
- ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
+ _image: &Image,
+ _range: Range<DeviceSize>,
+ _exclusive: bool,
+ _expected_layout: ImageLayout,
+ _queue: &Queue,
+ ) -> Result<(), AccessCheckError> {
+ Err(AccessCheckError::Unknown)
+ }
+
+ #[inline]
+ fn check_swapchain_image_acquired(
+ &self,
+ _swapchain: &Swapchain,
+ _image_index: u32,
+ _before: bool,
+ ) -> Result<(), AccessCheckError> {
Err(AccessCheckError::Unknown)
}
}
diff --git a/src/sync/future/semaphore_signal.rs b/src/sync/future/semaphore_signal.rs
index 829860b..f31d37a 100644
--- a/src/sync/future/semaphore_signal.rs
+++ b/src/sync/future/semaphore_signal.rs
@@ -7,29 +7,28 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use std::sync::atomic::AtomicBool;
-use std::sync::atomic::Ordering;
-use std::sync::Arc;
-use std::sync::Mutex;
-
-use crate::buffer::BufferAccess;
-use crate::command_buffer::submit::SubmitAnyBuilder;
-use crate::command_buffer::submit::SubmitCommandBufferBuilder;
-use crate::command_buffer::submit::SubmitSemaphoresWaitBuilder;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::device::Queue;
-use crate::image::ImageAccess;
-use crate::image::ImageLayout;
-use crate::sync::AccessCheckError;
-use crate::sync::AccessFlags;
-use crate::sync::FlushError;
-use crate::sync::GpuFuture;
-use crate::sync::PipelineStages;
-use crate::sync::Semaphore;
+use super::{AccessCheckError, FlushError, GpuFuture, SubmitAnyBuilder};
+use crate::{
+ buffer::Buffer,
+ command_buffer::{SemaphoreSubmitInfo, SubmitInfo},
+ device::{Device, DeviceOwned, Queue},
+ image::{sys::Image, ImageLayout},
+ swapchain::Swapchain,
+ sync::{future::AccessError, semaphore::Semaphore, PipelineStages},
+ DeviceSize,
+};
+use parking_lot::Mutex;
+use smallvec::smallvec;
+use std::{
+ ops::Range,
+ sync::{
+ atomic::{AtomicBool, Ordering},
+ Arc,
+ },
+ thread,
+};
/// Builds a new semaphore signal future.
-#[inline]
pub fn then_signal_semaphore<F>(future: F) -> SemaphoreSignalFuture<F>
where
F: GpuFuture,
@@ -40,7 +39,7 @@ where
SemaphoreSignalFuture {
previous: future,
- semaphore: Semaphore::from_pool(device).unwrap(),
+ semaphore: Arc::new(Semaphore::from_pool(device).unwrap()),
wait_submitted: Mutex::new(false),
finished: AtomicBool::new(false),
}
@@ -54,7 +53,7 @@ where
F: GpuFuture,
{
previous: F,
- semaphore: Semaphore,
+ semaphore: Arc<Semaphore>,
// True if the signaling command has already been submitted.
// If flush is called multiple times, we want to block so that only one flushing is executed.
// Therefore we use a `Mutex<bool>` and not an `AtomicBool`.
@@ -66,58 +65,120 @@ unsafe impl<F> GpuFuture for SemaphoreSignalFuture<F>
where
F: GpuFuture,
{
- #[inline]
fn cleanup_finished(&mut self) {
self.previous.cleanup_finished();
}
- #[inline]
unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
// Flushing the signaling part, since it must always be submitted before the waiting part.
self.flush()?;
+ let sem = smallvec![self.semaphore.clone()];
- let mut sem = SubmitSemaphoresWaitBuilder::new();
- sem.add_wait_semaphore(&self.semaphore);
Ok(SubmitAnyBuilder::SemaphoresWait(sem))
}
fn flush(&self) -> Result<(), FlushError> {
unsafe {
- let mut wait_submitted = self.wait_submitted.lock().unwrap();
+ let mut wait_submitted = self.wait_submitted.lock();
if *wait_submitted {
return Ok(());
}
- let queue = self.previous.queue().unwrap().clone();
+ let queue = self.previous.queue().unwrap();
match self.previous.build_submission()? {
SubmitAnyBuilder::Empty => {
- let mut builder = SubmitCommandBufferBuilder::new();
- builder.add_signal_semaphore(&self.semaphore);
- builder.submit(&queue)?;
+ queue.with(|mut q| {
+ q.submit_unchecked(
+ [SubmitInfo {
+ signal_semaphores: vec![SemaphoreSubmitInfo::semaphore(
+ self.semaphore.clone(),
+ )],
+ ..Default::default()
+ }],
+ None,
+ )
+ })?;
}
- SubmitAnyBuilder::SemaphoresWait(sem) => {
- let mut builder: SubmitCommandBufferBuilder = sem.into();
- builder.add_signal_semaphore(&self.semaphore);
- builder.submit(&queue)?;
+ SubmitAnyBuilder::SemaphoresWait(semaphores) => {
+ queue.with(|mut q| {
+ q.submit_unchecked(
+ [SubmitInfo {
+ wait_semaphores: semaphores
+ .into_iter()
+ .map(|semaphore| {
+ SemaphoreSubmitInfo {
+ // TODO: correct stages ; hard
+ stages: PipelineStages::ALL_COMMANDS,
+ ..SemaphoreSubmitInfo::semaphore(semaphore)
+ }
+ })
+ .collect(),
+ signal_semaphores: vec![SemaphoreSubmitInfo::semaphore(
+ self.semaphore.clone(),
+ )],
+ ..Default::default()
+ }],
+ None,
+ )
+ })?;
}
- SubmitAnyBuilder::CommandBuffer(mut builder) => {
- debug_assert_eq!(builder.num_signal_semaphores(), 0);
- builder.add_signal_semaphore(&self.semaphore);
- builder.submit(&queue)?;
+ SubmitAnyBuilder::CommandBuffer(mut submit_info, fence) => {
+ debug_assert!(submit_info.signal_semaphores.is_empty());
+
+ submit_info
+ .signal_semaphores
+ .push(SemaphoreSubmitInfo::semaphore(self.semaphore.clone()));
+
+ queue.with(|mut q| {
+ q.submit_with_future(submit_info, fence, &self.previous, &queue)
+ })?;
}
- SubmitAnyBuilder::BindSparse(_) => {
+ SubmitAnyBuilder::BindSparse(_, _) => {
unimplemented!() // TODO: how to do that?
/*debug_assert_eq!(builder.num_signal_semaphores(), 0);
builder.add_signal_semaphore(&self.semaphore);
builder.submit(&queue)?;*/
}
- SubmitAnyBuilder::QueuePresent(present) => {
- present.submit(&queue)?;
- let mut builder = SubmitCommandBufferBuilder::new();
- builder.add_signal_semaphore(&self.semaphore);
- builder.submit(&queue)?; // FIXME: problematic because if we return an error and flush() is called again, then we'll submit the present twice
+ SubmitAnyBuilder::QueuePresent(present_info) => {
+ // VUID-VkPresentIdKHR-presentIds-04999
+ for swapchain_info in &present_info.swapchain_infos {
+ if swapchain_info.present_id.map_or(false, |present_id| {
+ !swapchain_info.swapchain.try_claim_present_id(present_id)
+ }) {
+ return Err(FlushError::PresentIdLessThanOrEqual);
+ }
+
+ match self.previous.check_swapchain_image_acquired(
+ &swapchain_info.swapchain,
+ swapchain_info.image_index,
+ true,
+ ) {
+ Ok(_) => (),
+ Err(AccessCheckError::Unknown) => {
+ return Err(AccessError::SwapchainImageNotAcquired.into())
+ }
+ Err(AccessCheckError::Denied(e)) => return Err(e.into()),
+ }
+ }
+
+ queue.with(|mut q| {
+ q.present_unchecked(present_info)?
+ .map(|r| r.map(|_| ()))
+ .fold(Ok(()), Result::and)?;
+ // FIXME: problematic because if we return an error and flush() is called again, then we'll submit the present twice
+ q.submit_unchecked(
+ [SubmitInfo {
+ signal_semaphores: vec![SemaphoreSubmitInfo::semaphore(
+ self.semaphore.clone(),
+ )],
+ ..Default::default()
+ }],
+ None,
+ )?;
+ Ok::<_, FlushError>(())
+ })?;
}
};
@@ -127,46 +188,52 @@ where
}
}
- #[inline]
unsafe fn signal_finished(&self) {
- debug_assert!(*self.wait_submitted.lock().unwrap());
+ debug_assert!(*self.wait_submitted.lock());
self.finished.store(true, Ordering::SeqCst);
self.previous.signal_finished();
}
- #[inline]
fn queue_change_allowed(&self) -> bool {
true
}
- #[inline]
fn queue(&self) -> Option<Arc<Queue>> {
self.previous.queue()
}
- #[inline]
fn check_buffer_access(
&self,
- buffer: &dyn BufferAccess,
+ buffer: &Buffer,
+ range: Range<DeviceSize>,
exclusive: bool,
queue: &Queue,
- ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
+ ) -> Result<(), AccessCheckError> {
self.previous
- .check_buffer_access(buffer, exclusive, queue)
- .map(|_| None)
+ .check_buffer_access(buffer, range, exclusive, queue)
}
- #[inline]
fn check_image_access(
&self,
- image: &dyn ImageAccess,
- layout: ImageLayout,
+ image: &Image,
+ range: Range<DeviceSize>,
exclusive: bool,
+ expected_layout: ImageLayout,
queue: &Queue,
- ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
+ ) -> Result<(), AccessCheckError> {
self.previous
- .check_image_access(image, layout, exclusive, queue)
- .map(|_| None)
+ .check_image_access(image, range, exclusive, expected_layout, queue)
+ }
+
+ #[inline]
+ fn check_swapchain_image_acquired(
+ &self,
+ swapchain: &Swapchain,
+ image_index: u32,
+ _before: bool,
+ ) -> Result<(), AccessCheckError> {
+ self.previous
+ .check_swapchain_image_acquired(swapchain, image_index, false)
}
}
@@ -174,7 +241,6 @@ unsafe impl<F> DeviceOwned for SemaphoreSignalFuture<F>
where
F: GpuFuture,
{
- #[inline]
fn device(&self) -> &Arc<Device> {
self.semaphore.device()
}
@@ -185,14 +251,12 @@ where
F: GpuFuture,
{
fn drop(&mut self) {
- unsafe {
- if !*self.finished.get_mut() {
- // TODO: handle errors?
- self.flush().unwrap();
- // Block until the queue finished.
- self.queue().unwrap().wait().unwrap();
- self.previous.signal_finished();
- }
+ if !*self.finished.get_mut() && !thread::panicking() {
+ // TODO: handle errors?
+ self.flush().unwrap();
+ // Block until the queue finished.
+ self.queue().unwrap().with(|mut q| q.wait_idle()).unwrap();
+ unsafe { self.previous.signal_finished() };
}
}
}
diff --git a/src/sync/mod.rs b/src/sync/mod.rs
index decbd7d..512c02e 100644
--- a/src/sync/mod.rs
+++ b/src/sync/mod.rs
@@ -15,122 +15,24 @@
//!
//! This safety is enforced at runtime by vulkano but it is not magic and you will require some
//! knowledge if you want to avoid errors.
-//!
-//! # Futures
-//!
-//! Whenever you ask the GPU to start an operation by using a function of the vulkano library (for
-//! example executing a command buffer), this function will return a *future*. A future is an
-//! object that implements [the `GpuFuture` trait](trait.GpuFuture.html) and that represents the
-//! point in time when this operation is over.
-//!
-//! No function in vulkano immediately sends an operation to the GPU (with the exception of some
-//! unsafe low-level functions). Instead they return a future that is in the pending state. Before
-//! the GPU actually starts doing anything, you have to *flush* the future by calling the `flush()`
-//! method or one of its derivatives.
-//!
-//! Futures serve several roles:
-//!
-//! - Futures can be used to build dependencies between operations and makes it possible to ask
-//! that an operation starts only after a previous operation is finished.
-//! - Submitting an operation to the GPU is a costly operation. By chaining multiple operations
-//! with futures you will submit them all at once instead of one by one, thereby reducing this
-//! cost.
-//! - Futures keep alive the resources and objects used by the GPU so that they don't get destroyed
-//! while they are still in use.
-//!
-//! The last point means that you should keep futures alive in your program for as long as their
-//! corresponding operation is potentially still being executed by the GPU. Dropping a future
-//! earlier will block the current thread (after flushing, if necessary) until the GPU has finished
-//! the operation, which is usually not what you want.
-//!
-//! If you write a function that submits an operation to the GPU in your program, you are
-//! encouraged to let this function return the corresponding future and let the caller handle it.
-//! This way the caller will be able to chain multiple futures together and decide when it wants to
-//! keep the future alive or drop it.
-//!
-//! # Executing an operation after a future
-//!
-//! Respecting the order of operations on the GPU is important, as it is what *proves* vulkano that
-//! what you are doing is indeed safe. For example if you submit two operations that modify the
-//! same buffer, then you need to execute one after the other instead of submitting them
-//! independently. Failing to do so would mean that these two operations could potentially execute
-//! simultaneously on the GPU, which would be unsafe.
-//!
-//! This is done by calling one of the methods of the `GpuFuture` trait. For example calling
-//! `prev_future.then_execute(command_buffer)` takes ownership of `prev_future` and will make sure
-//! to only start executing `command_buffer` after the moment corresponding to `prev_future`
-//! happens. The object returned by the `then_execute` function is itself a future that corresponds
-//! to the moment when the execution of `command_buffer` ends.
-//!
-//! ## Between two different GPU queues
-//!
-//! When you want to perform an operation after another operation on two different queues, you
-//! **must** put a *semaphore* between them. Failure to do so would result in a runtime error.
-//! Adding a semaphore is a simple as replacing `prev_future.then_execute(...)` with
-//! `prev_future.then_signal_semaphore().then_execute(...)`.
-//!
-//! > **Note**: A common use-case is using a transfer queue (ie. a queue that is only capable of
-//! > performing transfer operations) to write data to a buffer, then read that data from the
-//! > rendering queue.
-//!
-//! What happens when you do so is that the first queue will execute the first set of operations
-//! (represented by `prev_future` in the example), then put a semaphore in the signalled state.
-//! Meanwhile the second queue blocks (if necessary) until that same semaphore gets signalled, and
-//! then only will execute the second set of operations.
-//!
-//! Since you want to avoid blocking the second queue as much as possible, you probably want to
-//! flush the operation to the first queue as soon as possible. This can easily be done by calling
-//! `then_signal_semaphore_and_flush()` instead of `then_signal_semaphore()`.
-//!
-//! ## Between several different GPU queues
-//!
-//! The `then_signal_semaphore()` method is appropriate when you perform an operation in one queue,
-//! and want to see the result in another queue. However in some situations you want to start
-//! multiple operations on several different queues.
-//!
-//! TODO: this is not yet implemented
-//!
-//! # Fences
-//!
-//! A `Fence` is an object that is used to signal the CPU when an operation on the GPU is finished.
-//!
-//! Signalling a fence is done by calling `then_signal_fence()` on a future. Just like semaphores,
-//! you are encouraged to use `then_signal_fence_and_flush()` instead.
-//!
-//! Signalling a fence is kind of a "terminator" to a chain of futures.
-//!
-//! TODO: lots of problems with how to use fences
-//! TODO: talk about fence + semaphore simultaneously
-//! TODO: talk about using fences to clean up
+pub(crate) use self::pipeline::{PipelineStageAccess, PipelineStageAccessSet};
+pub use self::{
+ future::{now, FlushError, GpuFuture},
+ pipeline::{
+ AccessFlags, BufferMemoryBarrier, DependencyFlags, DependencyInfo, ImageMemoryBarrier,
+ MemoryBarrier, PipelineMemoryAccess, PipelineStage, PipelineStages,
+ QueueFamilyOwnershipTransfer,
+ },
+};
use crate::device::Queue;
use std::sync::Arc;
-pub use self::event::Event;
-pub use self::fence::Fence;
-pub use self::fence::FenceWaitError;
-pub use self::future::now;
-pub use self::future::AccessCheckError;
-pub use self::future::AccessError;
-pub use self::future::FenceSignalFuture;
-pub use self::future::FlushError;
-pub use self::future::GpuFuture;
-pub use self::future::JoinFuture;
-pub use self::future::NowFuture;
-pub use self::future::SemaphoreSignalFuture;
-pub use self::pipeline::AccessFlags;
-pub use self::pipeline::PipelineMemoryAccess;
-pub use self::pipeline::PipelineStage;
-pub use self::pipeline::PipelineStages;
-pub use self::semaphore::ExternalSemaphoreHandleType;
-pub use self::semaphore::Semaphore;
-pub use self::semaphore::SemaphoreError;
-
-mod event;
-mod fence;
-mod future;
+pub mod event;
+pub mod fence;
+pub mod future;
mod pipeline;
-pub(crate) mod semaphore;
+pub mod semaphore;
/// Declares in which queue(s) a resource can be used.
///
@@ -148,7 +50,7 @@ pub enum SharingMode {
impl<'a> From<&'a Arc<Queue>> for SharingMode {
#[inline]
- fn from(queue: &'a Arc<Queue>) -> SharingMode {
+ fn from(_queue: &'a Arc<Queue>) -> SharingMode {
SharingMode::Exclusive
}
}
@@ -156,7 +58,12 @@ impl<'a> From<&'a Arc<Queue>> for SharingMode {
impl<'a> From<&'a [&'a Arc<Queue>]> for SharingMode {
#[inline]
fn from(queues: &'a [&'a Arc<Queue>]) -> SharingMode {
- SharingMode::Concurrent(queues.iter().map(|queue| queue.family().id()).collect())
+ SharingMode::Concurrent(
+ queues
+ .iter()
+ .map(|queue| queue.queue_family_index())
+ .collect(),
+ )
}
}
@@ -164,10 +71,26 @@ impl<'a> From<&'a [&'a Arc<Queue>]> for SharingMode {
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Sharing<I>
where
- I: Iterator<Item = u32>,
+ I: IntoIterator<Item = u32>,
{
/// The resource is used is only one queue family.
Exclusive,
/// The resource is used in multiple queue families. Can be slower than `Exclusive`.
Concurrent(I),
}
+
+/// How the memory of a resource is currently being accessed.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub(crate) enum CurrentAccess {
+ /// The resource is currently being accessed exclusively by the CPU.
+ CpuExclusive,
+
+ /// The resource is currently being accessed exclusively by the GPU.
+ /// The GPU can have multiple exclusive accesses, if they are separated by synchronization.
+ ///
+ /// `gpu_writes` must not be 0. If it's decremented to 0, switch to `Shared`.
+ GpuExclusive { gpu_reads: usize, gpu_writes: usize },
+
+ /// The resource is not currently being accessed, or is being accessed for reading only.
+ Shared { cpu_reads: usize, gpu_reads: usize },
+}
diff --git a/src/sync/pipeline.rs b/src/sync/pipeline.rs
index 62cd95c..53e3941 100644
--- a/src/sync/pipeline.rs
+++ b/src/sync/pipeline.rs
@@ -7,80 +7,550 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use std::ops;
+use crate::{
+ buffer::Buffer,
+ descriptor_set::layout::DescriptorType,
+ device::{Device, QueueFlags},
+ image::{sys::Image, ImageAspects, ImageLayout, ImageSubresourceRange},
+ macros::{vulkan_bitflags, vulkan_bitflags_enum},
+ shader::ShaderStages,
+ DeviceSize, RequirementNotMet, Version,
+};
+use ahash::HashMap;
+use once_cell::sync::Lazy;
+use smallvec::SmallVec;
+use std::{ops::Range, sync::Arc};
-macro_rules! pipeline_stages {
- ($($elem:ident, $var:ident => $val:expr, $queue:expr;)+) => (
- #[derive(Debug, Copy, Clone, PartialEq, Eq)]
- pub struct PipelineStages {
- $(
- pub $elem: bool,
- )+
+vulkan_bitflags_enum! {
+ #[non_exhaustive]
+ /// A set of [`PipelineStage`] values.
+ PipelineStages impl {
+ /// Returns whether `self` contains stages that are only available in
+ /// `VkPipelineStageFlagBits2`.
+ pub(crate) fn is_2(self) -> bool {
+ !(self
+ - (PipelineStages::TOP_OF_PIPE
+ | PipelineStages::DRAW_INDIRECT
+ | PipelineStages::VERTEX_INPUT
+ | PipelineStages::VERTEX_SHADER
+ | PipelineStages::TESSELLATION_CONTROL_SHADER
+ | PipelineStages::TESSELLATION_EVALUATION_SHADER
+ | PipelineStages::GEOMETRY_SHADER
+ | PipelineStages::FRAGMENT_SHADER
+ | PipelineStages::EARLY_FRAGMENT_TESTS
+ | PipelineStages::LATE_FRAGMENT_TESTS
+ | PipelineStages::COLOR_ATTACHMENT_OUTPUT
+ | PipelineStages::COMPUTE_SHADER
+ | PipelineStages::ALL_TRANSFER
+ | PipelineStages::BOTTOM_OF_PIPE
+ | PipelineStages::HOST
+ | PipelineStages::ALL_GRAPHICS
+ | PipelineStages::ALL_COMMANDS
+ | PipelineStages::TRANSFORM_FEEDBACK
+ | PipelineStages::CONDITIONAL_RENDERING
+ | PipelineStages::ACCELERATION_STRUCTURE_BUILD
+ | PipelineStages::RAY_TRACING_SHADER
+ | PipelineStages::FRAGMENT_DENSITY_PROCESS
+ | PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT
+ | PipelineStages::COMMAND_PREPROCESS
+ | PipelineStages::TASK_SHADER
+ | PipelineStages::MESH_SHADER))
+ .is_empty()
}
- impl PipelineStages {
- /// Builds an `PipelineStages` struct with none of the stages set.
- pub fn none() -> PipelineStages {
- PipelineStages {
- $(
- $elem: false,
- )+
- }
+ /// Replaces and unsets flags that are equivalent to multiple other flags.
+ ///
+ /// This may set flags that are not supported by the device, so this is for internal use only
+ /// and should not be passed on to Vulkan.
+ pub(crate) fn expand(mut self, queue_flags: QueueFlags) -> Self {
+ if self.intersects(PipelineStages::ALL_COMMANDS) {
+ self -= PipelineStages::ALL_COMMANDS;
+ self |= queue_flags.into();
}
- }
- impl From<PipelineStages> for ash::vk::PipelineStageFlags {
- #[inline]
- fn from(val: PipelineStages) -> Self {
- let mut result = ash::vk::PipelineStageFlags::empty();
- $(
- if val.$elem { result |= $val }
- )+
- result
+ if self.intersects(PipelineStages::ALL_GRAPHICS) {
+ self -= PipelineStages::ALL_GRAPHICS;
+ self |= QueueFlags::GRAPHICS.into();
}
- }
- impl ops::BitOr for PipelineStages {
- type Output = PipelineStages;
+ if self.intersects(PipelineStages::VERTEX_INPUT) {
+ self -= PipelineStages::VERTEX_INPUT;
+ self |= PipelineStages::INDEX_INPUT | PipelineStages::VERTEX_ATTRIBUTE_INPUT;
+ }
- #[inline]
- fn bitor(self, rhs: PipelineStages) -> PipelineStages {
- PipelineStages {
- $(
- $elem: self.$elem || rhs.$elem,
- )+
- }
+ if self.intersects(PipelineStages::PRE_RASTERIZATION_SHADERS) {
+ self -= PipelineStages::PRE_RASTERIZATION_SHADERS;
+ self |= PipelineStages::VERTEX_SHADER
+ | PipelineStages::TESSELLATION_CONTROL_SHADER
+ | PipelineStages::TESSELLATION_EVALUATION_SHADER
+ | PipelineStages::GEOMETRY_SHADER
+ | PipelineStages::TASK_SHADER
+ | PipelineStages::MESH_SHADER;
}
- }
- impl ops::BitOrAssign for PipelineStages {
- #[inline]
- fn bitor_assign(&mut self, rhs: PipelineStages) {
- $(
- self.$elem = self.$elem || rhs.$elem;
- )+
+ if self.intersects(PipelineStages::ALL_TRANSFER) {
+ self -= PipelineStages::ALL_TRANSFER;
+ self |= PipelineStages::COPY
+ | PipelineStages::RESOLVE
+ | PipelineStages::BLIT
+ | PipelineStages::CLEAR
+ | PipelineStages::ACCELERATION_STRUCTURE_COPY;
}
+
+ self
}
- #[derive(Debug, Copy, Clone, PartialEq, Eq)]
- #[repr(u32)]
- pub enum PipelineStage {
+ pub(crate) fn with_earlier(self) -> Self {
+ STAGE_ORDER.iter().rev().fold(
+ self,
+ |stages, &(before, after)| if stages.intersects(after) {
+ stages.union(before)
+ } else {
+ stages
+ }
+ )
+ }
+
+ pub(crate) fn with_later(self) -> Self {
+ STAGE_ORDER.iter().fold(
+ self,
+ |stages, &(before, after)| if stages.intersects(before) {
+ stages.union(after)
+ } else {
+ stages
+ }
+ )
+ }
+ },
+
+ /// A single stage in the device's processing pipeline.
+ PipelineStage,
+
+ = PipelineStageFlags2(u64);
+
+ /// A pseudo-stage representing the start of the pipeline.
+ TOP_OF_PIPE, TopOfPipe = TOP_OF_PIPE,
+
+ /// Indirect buffers are read.
+ DRAW_INDIRECT, DrawIndirect = DRAW_INDIRECT,
+
+ /// Vertex and index buffers are read.
+ ///
+ /// It is currently equivalent to setting all of the following flags, but automatically
+ /// omitting any that are not supported in a given context. It also implicitly includes future
+ /// flags that are added to Vulkan, if they are not yet supported by Vulkano.
+ /// - `index_input`
+ /// - `vertex_attribute_input`
+ VERTEX_INPUT, VertexInput = VERTEX_INPUT,
+
+ /// Vertex shaders are executed.
+ VERTEX_SHADER, VertexShader = VERTEX_SHADER,
+
+ /// Tessellation control shaders are executed.
+ TESSELLATION_CONTROL_SHADER, TessellationControlShader = TESSELLATION_CONTROL_SHADER,
+
+ /// Tessellation evaluation shaders are executed.
+ TESSELLATION_EVALUATION_SHADER, TessellationEvaluationShader = TESSELLATION_EVALUATION_SHADER,
+
+ /// Geometry shaders are executed.
+ GEOMETRY_SHADER, GeometryShader = GEOMETRY_SHADER,
+
+ /// Fragment shaders are executed.
+ FRAGMENT_SHADER, FragmentShader = FRAGMENT_SHADER,
+
+ /// Early fragment tests (depth and stencil tests before fragment shading) are performed.
+ /// Subpass load operations for framebuffer attachments with a depth/stencil format are
+ /// performed.
+ EARLY_FRAGMENT_TESTS, EarlyFragmentTests = EARLY_FRAGMENT_TESTS,
+
+ /// Late fragment tests (depth and stencil tests after fragment shading) are performed.
+ /// Subpass store operations for framebuffer attachments with a depth/stencil format are
+ /// performed.
+ LATE_FRAGMENT_TESTS, LateFragmentTests = LATE_FRAGMENT_TESTS,
+
+ /// The final color values are output from the pipeline after blending.
+ /// Subpass load and store operations, multisample resolve operations for framebuffer
+ /// attachments with a color or depth/stencil format, and `clear_attachments` are performed.
+ COLOR_ATTACHMENT_OUTPUT, ColorAttachmentOutput = COLOR_ATTACHMENT_OUTPUT,
+
+ /// Compute shaders are executed.
+ COMPUTE_SHADER, ComputeShader = COMPUTE_SHADER,
+
+ /// The set of all current and future transfer pipeline stages.
+ ///
+ /// It is currently equivalent to setting all of the following flags, but automatically
+ /// omitting any that are not supported in a given context. It also implicitly includes future
+ /// flags that are added to Vulkan, if they are not yet supported by Vulkano.
+ /// - `copy`
+ /// - `blit`
+ /// - `resolve`
+ /// - `clear`
+ /// - `acceleration_structure_copy`
+ ALL_TRANSFER, AllTransfer = ALL_TRANSFER,
+
+ /// A pseudo-stage representing the end of the pipeline.
+ BOTTOM_OF_PIPE, BottomOfPipe = BOTTOM_OF_PIPE,
+
+ /// A pseudo-stage representing reads and writes to device memory on the host.
+ HOST, Host = HOST,
+
+ /// The set of all current and future graphics pipeline stages.
+ ///
+ /// It is currently equivalent to setting all of the following flags, but automatically
+ /// omitting any that are not supported in a given context. It also implicitly includes future
+ /// flags that are added to Vulkan, if they are not yet supported by Vulkano.
+ /// - `draw_indirect`
+ /// - `task_shader`
+ /// - `mesh_shader`
+ /// - `vertex_input`
+ /// - `vertex_shader`
+ /// - `tessellation_control_shader`
+ /// - `tessellation_evaluation_shader`
+ /// - `geometry_shader`
+ /// - `fragment_shader`
+ /// - `early_fragment_tests`
+ /// - `late_fragment_tests`
+ /// - `color_attachment_output`
+ /// - `conditional_rendering`
+ /// - `transform_feedback`
+ /// - `fragment_shading_rate_attachment`
+ /// - `fragment_density_process`
+ /// - `invocation_mask`
+ ALL_GRAPHICS, AllGraphics = ALL_GRAPHICS,
+
+ /// The set of all current and future pipeline stages of all types.
+ ///
+ /// It is currently equivalent to setting all flags in `PipelineStages`, but automatically
+ /// omitting any that are not supported in a given context. It also implicitly includes future
+ /// flags that are added to Vulkan, if they are not yet supported by Vulkano.
+ ALL_COMMANDS, AllCommands = ALL_COMMANDS,
+
+ /// The `copy_buffer`, `copy_image`, `copy_buffer_to_image`, `copy_image_to_buffer` and
+ /// `copy_query_pool_results` commands are executed.
+ COPY, Copy = COPY {
+ api_version: V1_3,
+ device_extensions: [khr_synchronization2],
+ },
+
+ /// The `resolve_image` command is executed.
+ RESOLVE, Resolve = RESOLVE {
+ api_version: V1_3,
+ device_extensions: [khr_synchronization2],
+ },
+
+ /// The `blit_image` command is executed.
+ BLIT, Blit = BLIT {
+ api_version: V1_3,
+ device_extensions: [khr_synchronization2],
+ },
+
+ /// The `clear_color_image`, `clear_depth_stencil_image`, `fill_buffer` and `update_buffer`
+ /// commands are executed.
+ CLEAR, Clear = CLEAR {
+ api_version: V1_3,
+ device_extensions: [khr_synchronization2],
+ },
+
+ /// Index buffers are read.
+ INDEX_INPUT, IndexInput = INDEX_INPUT {
+ api_version: V1_3,
+ device_extensions: [khr_synchronization2],
+ },
+
+ /// Vertex buffers are read.
+ VERTEX_ATTRIBUTE_INPUT, VertexAttributeInput = VERTEX_ATTRIBUTE_INPUT {
+ api_version: V1_3,
+ device_extensions: [khr_synchronization2],
+ },
+
+ /// The various pre-rasterization shader types are executed.
+ ///
+ /// It is currently equivalent to setting all of the following flags, but automatically
+ /// omitting any that are not supported in a given context. It also implicitly includes future
+ /// flags that are added to Vulkan, if they are not yet supported by Vulkano.
+ /// - `vertex_shader`
+ /// - `tessellation_control_shader`
+ /// - `tessellation_evaluation_shader`
+ /// - `geometry_shader`
+ /// - `task_shader`
+ /// - `mesh_shader`
+ PRE_RASTERIZATION_SHADERS, PreRasterizationShaders = PRE_RASTERIZATION_SHADERS {
+ api_version: V1_3,
+ device_extensions: [khr_synchronization2],
+ },
+
+ /// Video decode operations are performed.
+ VIDEO_DECODE, VideoDecode = VIDEO_DECODE_KHR {
+ device_extensions: [khr_video_decode_queue],
+ },
+
+ /// Video encode operations are performed.
+ VIDEO_ENCODE, VideoEncode = VIDEO_ENCODE_KHR {
+ device_extensions: [khr_video_encode_queue],
+ },
+
+ /// Vertex attribute output values are written to the transform feedback buffers.
+ TRANSFORM_FEEDBACK, TransformFeedback = TRANSFORM_FEEDBACK_EXT {
+ device_extensions: [ext_transform_feedback],
+ },
+
+ /// The predicate of conditional rendering is read.
+ CONDITIONAL_RENDERING, ConditionalRendering = CONDITIONAL_RENDERING_EXT {
+ device_extensions: [ext_conditional_rendering],
+ },
+
+ /// Acceleration_structure commands are executed.
+ ACCELERATION_STRUCTURE_BUILD, AccelerationStructureBuild = ACCELERATION_STRUCTURE_BUILD_KHR {
+ device_extensions: [khr_acceleration_structure, nv_ray_tracing],
+ },
+
+ /// The various ray tracing shader types are executed.
+ RAY_TRACING_SHADER, RayTracingShader = RAY_TRACING_SHADER_KHR {
+ device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing],
+ },
+
+ /// The fragment density map is read to generate the fragment areas.
+ FRAGMENT_DENSITY_PROCESS, FragmentDensityProcess = FRAGMENT_DENSITY_PROCESS_EXT {
+ device_extensions: [ext_fragment_density_map],
+ },
+
+ /// The fragment shading rate attachment or shading rate image is read to determine the
+ /// fragment shading rate for portions of a rasterized primitive.
+ FRAGMENT_SHADING_RATE_ATTACHMENT, FragmentShadingRateAttachment = FRAGMENT_SHADING_RATE_ATTACHMENT_KHR {
+ device_extensions: [khr_fragment_shading_rate],
+ },
+
+ /// Device-side preprocessing for generated commands via the `preprocess_generated_commands`
+ /// command is handled.
+ COMMAND_PREPROCESS, CommandPreprocess = COMMAND_PREPROCESS_NV {
+ device_extensions: [nv_device_generated_commands],
+ },
+
+ /// Task shaders are executed.
+ TASK_SHADER, TaskShader = TASK_SHADER_EXT {
+ device_extensions: [ext_mesh_shader, nv_mesh_shader],
+ },
+
+ /// Mesh shaders are executed.
+ MESH_SHADER, MeshShader = MESH_SHADER_EXT {
+ device_extensions: [ext_mesh_shader, nv_mesh_shader],
+ },
+
+ /// Subpass shading shaders are executed.
+ SUBPASS_SHADING, SubpassShading = SUBPASS_SHADING_HUAWEI {
+ device_extensions: [huawei_subpass_shading],
+ },
+
+ /// The invocation mask image is read to optimize ray dispatch.
+ INVOCATION_MASK, InvocationMask = INVOCATION_MASK_HUAWEI {
+ device_extensions: [huawei_invocation_mask],
+ },
+
+ /// The `copy_acceleration_structure` command is executed.
+ ACCELERATION_STRUCTURE_COPY, AccelerationStructureCopy = ACCELERATION_STRUCTURE_COPY_KHR {
+ device_extensions: [khr_ray_tracing_maintenance1],
+ },
+
+ /// Micromap commands are executed.
+ MICROMAP_BUILD, MicromapBuild = MICROMAP_BUILD_EXT {
+ device_extensions: [ext_opacity_micromap],
+ },
+
+ /// Optical flow operations are performed.
+ OPTICAL_FLOW, OpticalFlow = OPTICAL_FLOW_NV {
+ device_extensions: [nv_optical_flow],
+ },
+}
+
+macro_rules! stage_order {
+ {
+ $((
+ $($before:ident)|+,
+ $($after:ident)|+,
+ ),)+
+ } => {
+ static STAGE_ORDER: [(PipelineStages, PipelineStages); 15] = [
$(
- $var = $val.as_raw(),
+ (
+ PipelineStages::empty()
+ $(.union(PipelineStages::$before))+
+ ,
+ PipelineStages::empty()
+ $(.union(PipelineStages::$after))+
+ ),
)+
+ ];
+ };
+}
+
+// Per
+// https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap7.html#synchronization-pipeline-stages-types
+stage_order! {
+ (
+ TOP_OF_PIPE,
+ DRAW_INDIRECT
+ | COPY | RESOLVE | BLIT | CLEAR
+ | VIDEO_DECODE | VIDEO_ENCODE
+ | CONDITIONAL_RENDERING
+ | COMMAND_PREPROCESS
+ | ACCELERATION_STRUCTURE_BUILD
+ | SUBPASS_SHADING
+ | ACCELERATION_STRUCTURE_COPY
+ | MICROMAP_BUILD
+ | OPTICAL_FLOW,
+ ),
+
+ (
+ DRAW_INDIRECT,
+ COMPUTE_SHADER | INDEX_INPUT | RAY_TRACING_SHADER | TASK_SHADER,
+ ),
+
+ (
+ INDEX_INPUT,
+ VERTEX_ATTRIBUTE_INPUT,
+ ),
+
+ (
+ VERTEX_ATTRIBUTE_INPUT,
+ VERTEX_SHADER,
+ ),
+
+ (
+ VERTEX_SHADER,
+ TESSELLATION_CONTROL_SHADER,
+ ),
+
+ (
+ TESSELLATION_CONTROL_SHADER,
+ TESSELLATION_EVALUATION_SHADER,
+ ),
+
+ (
+ TESSELLATION_EVALUATION_SHADER,
+ GEOMETRY_SHADER,
+ ),
+
+ (
+ GEOMETRY_SHADER,
+ TRANSFORM_FEEDBACK,
+ ),
+
+ (
+ TASK_SHADER,
+ MESH_SHADER,
+ ),
+
+ (
+ TRANSFORM_FEEDBACK | MESH_SHADER,
+ FRAGMENT_SHADING_RATE_ATTACHMENT,
+ ),
+
+ (
+ FRAGMENT_DENSITY_PROCESS | FRAGMENT_SHADING_RATE_ATTACHMENT,
+ EARLY_FRAGMENT_TESTS,
+ ),
+
+ (
+ EARLY_FRAGMENT_TESTS,
+ FRAGMENT_SHADER,
+ ),
+
+ (
+ FRAGMENT_SHADER,
+ LATE_FRAGMENT_TESTS,
+ ),
+
+ (
+ LATE_FRAGMENT_TESTS,
+ COLOR_ATTACHMENT_OUTPUT,
+ ),
+
+ (
+ COLOR_ATTACHMENT_OUTPUT
+ | COMPUTE_SHADER
+ | COPY | RESOLVE | BLIT | CLEAR
+ | VIDEO_DECODE | VIDEO_ENCODE
+ | CONDITIONAL_RENDERING
+ | COMMAND_PREPROCESS
+ | ACCELERATION_STRUCTURE_BUILD | RAY_TRACING_SHADER
+ | SUBPASS_SHADING
+ | ACCELERATION_STRUCTURE_COPY
+ | MICROMAP_BUILD
+ | OPTICAL_FLOW,
+ BOTTOM_OF_PIPE,
+ ),
+}
+
+impl From<QueueFlags> for PipelineStages {
+ /// Corresponds to the table "[Supported pipeline stage flags]" in the Vulkan specification.
+ ///
+ /// [Supported pipeline stage flags]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap7.html#synchronization-pipeline-stages-supported
+ #[inline]
+ fn from(val: QueueFlags) -> Self {
+ let mut result = PipelineStages::TOP_OF_PIPE
+ | PipelineStages::BOTTOM_OF_PIPE
+ | PipelineStages::HOST
+ | PipelineStages::ALL_COMMANDS;
+
+ if val.intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE | QueueFlags::TRANSFER) {
+ result |= PipelineStages::ALL_TRANSFER
+ | PipelineStages::COPY
+ | PipelineStages::RESOLVE
+ | PipelineStages::BLIT
+ | PipelineStages::CLEAR
+ | PipelineStages::ACCELERATION_STRUCTURE_COPY;
}
- impl PipelineStage {
- #[inline]
- pub fn required_queue_flags(&self) -> ash::vk::QueueFlags {
- match self {
- $(
- Self::$var => $queue,
- )+
- }
- }
+ if val.intersects(QueueFlags::GRAPHICS) {
+ result |= PipelineStages::DRAW_INDIRECT
+ | PipelineStages::VERTEX_INPUT
+ | PipelineStages::VERTEX_SHADER
+ | PipelineStages::TESSELLATION_CONTROL_SHADER
+ | PipelineStages::TESSELLATION_EVALUATION_SHADER
+ | PipelineStages::GEOMETRY_SHADER
+ | PipelineStages::FRAGMENT_SHADER
+ | PipelineStages::EARLY_FRAGMENT_TESTS
+ | PipelineStages::LATE_FRAGMENT_TESTS
+ | PipelineStages::COLOR_ATTACHMENT_OUTPUT
+ | PipelineStages::ALL_GRAPHICS
+ | PipelineStages::INDEX_INPUT
+ | PipelineStages::VERTEX_ATTRIBUTE_INPUT
+ | PipelineStages::PRE_RASTERIZATION_SHADERS
+ | PipelineStages::CONDITIONAL_RENDERING
+ | PipelineStages::TRANSFORM_FEEDBACK
+ | PipelineStages::COMMAND_PREPROCESS
+ | PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT
+ | PipelineStages::TASK_SHADER
+ | PipelineStages::MESH_SHADER
+ | PipelineStages::FRAGMENT_DENSITY_PROCESS
+ | PipelineStages::SUBPASS_SHADING
+ | PipelineStages::INVOCATION_MASK;
+ }
+
+ if val.intersects(QueueFlags::COMPUTE) {
+ result |= PipelineStages::DRAW_INDIRECT
+ | PipelineStages::COMPUTE_SHADER
+ | PipelineStages::CONDITIONAL_RENDERING
+ | PipelineStages::COMMAND_PREPROCESS
+ | PipelineStages::ACCELERATION_STRUCTURE_BUILD
+ | PipelineStages::RAY_TRACING_SHADER
+ | PipelineStages::MICROMAP_BUILD;
+ }
+
+ if val.intersects(QueueFlags::VIDEO_DECODE) {
+ result |= PipelineStages::VIDEO_DECODE;
+ }
+
+ if val.intersects(QueueFlags::VIDEO_ENCODE) {
+ result |= PipelineStages::VIDEO_ENCODE;
}
- );
+
+ if val.intersects(QueueFlags::OPTICAL_FLOW) {
+ result |= PipelineStages::OPTICAL_FLOW;
+ }
+
+ result
+ }
}
impl From<PipelineStage> for ash::vk::PipelineStageFlags {
@@ -90,177 +560,434 @@ impl From<PipelineStage> for ash::vk::PipelineStageFlags {
}
}
-pipeline_stages! {
- top_of_pipe, TopOfPipe => ash::vk::PipelineStageFlags::TOP_OF_PIPE, ash::vk::QueueFlags::empty();
- draw_indirect, DrawIndirect => ash::vk::PipelineStageFlags::DRAW_INDIRECT, ash::vk::QueueFlags::GRAPHICS | ash::vk::QueueFlags::COMPUTE;
- vertex_input, VertexInput => ash::vk::PipelineStageFlags::VERTEX_INPUT, ash::vk::QueueFlags::GRAPHICS;
- vertex_shader, VertexShader => ash::vk::PipelineStageFlags::VERTEX_SHADER, ash::vk::QueueFlags::GRAPHICS;
- tessellation_control_shader, TessellationControlShader => ash::vk::PipelineStageFlags::TESSELLATION_CONTROL_SHADER, ash::vk::QueueFlags::GRAPHICS;
- tessellation_evaluation_shader, TessellationEvaluationShader => ash::vk::PipelineStageFlags::TESSELLATION_EVALUATION_SHADER, ash::vk::QueueFlags::GRAPHICS;
- geometry_shader, GeometryShader => ash::vk::PipelineStageFlags::GEOMETRY_SHADER, ash::vk::QueueFlags::GRAPHICS;
- fragment_shader, FragmentShader => ash::vk::PipelineStageFlags::FRAGMENT_SHADER, ash::vk::QueueFlags::GRAPHICS;
- early_fragment_tests, EarlyFragmentTests => ash::vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS, ash::vk::QueueFlags::GRAPHICS;
- late_fragment_tests, LateFragmentTests => ash::vk::PipelineStageFlags::LATE_FRAGMENT_TESTS, ash::vk::QueueFlags::GRAPHICS;
- color_attachment_output, ColorAttachmentOutput => ash::vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT, ash::vk::QueueFlags::GRAPHICS;
- compute_shader, ComputeShader => ash::vk::PipelineStageFlags::COMPUTE_SHADER, ash::vk::QueueFlags::COMPUTE;
- transfer, Transfer => ash::vk::PipelineStageFlags::TRANSFER, ash::vk::QueueFlags::GRAPHICS | ash::vk::QueueFlags::COMPUTE | ash::vk::QueueFlags::TRANSFER;
- bottom_of_pipe, BottomOfPipe => ash::vk::PipelineStageFlags::BOTTOM_OF_PIPE, ash::vk::QueueFlags::empty();
- host, Host => ash::vk::PipelineStageFlags::HOST, ash::vk::QueueFlags::empty();
- all_graphics, AllGraphics => ash::vk::PipelineStageFlags::ALL_GRAPHICS, ash::vk::QueueFlags::GRAPHICS;
- all_commands, AllCommands => ash::vk::PipelineStageFlags::ALL_COMMANDS, ash::vk::QueueFlags::empty();
-}
-
-macro_rules! access_flags {
- ($($elem:ident => $val:expr,)+) => (
- #[derive(Debug, Copy, Clone)]
- #[allow(missing_docs)]
- pub struct AccessFlags {
- $(
- pub $elem: bool,
- )+
+impl From<PipelineStages> for ash::vk::PipelineStageFlags {
+ #[inline]
+ fn from(val: PipelineStages) -> Self {
+ Self::from_raw(ash::vk::PipelineStageFlags2::from(val).as_raw() as u32)
+ }
+}
+
+vulkan_bitflags! {
+ #[non_exhaustive]
+
+ /// A set of memory access types that are included in a memory dependency.
+ AccessFlags impl {
+ /// Returns whether `self` contains stages that are only available in
+ /// `VkAccessFlagBits2`.
+ pub(crate) fn is_2(self) -> bool {
+ !(self
+ - (AccessFlags::INDIRECT_COMMAND_READ
+ | AccessFlags::INDEX_READ
+ | AccessFlags::VERTEX_ATTRIBUTE_READ
+ | AccessFlags::UNIFORM_READ
+ | AccessFlags::INPUT_ATTACHMENT_READ
+ | AccessFlags::SHADER_READ
+ | AccessFlags::SHADER_WRITE
+ | AccessFlags::COLOR_ATTACHMENT_READ
+ | AccessFlags::COLOR_ATTACHMENT_WRITE
+ | AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ
+ | AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE
+ | AccessFlags::TRANSFER_READ
+ | AccessFlags::TRANSFER_WRITE
+ | AccessFlags::HOST_READ
+ | AccessFlags::HOST_WRITE
+ | AccessFlags::MEMORY_READ
+ | AccessFlags::MEMORY_WRITE
+ | AccessFlags::SHADER_SAMPLED_READ
+ | AccessFlags::SHADER_STORAGE_READ
+ | AccessFlags::SHADER_STORAGE_WRITE
+ | AccessFlags::VIDEO_DECODE_READ
+ | AccessFlags::VIDEO_DECODE_WRITE
+ | AccessFlags::VIDEO_ENCODE_READ
+ | AccessFlags::VIDEO_ENCODE_WRITE
+ | AccessFlags::TRANSFORM_FEEDBACK_WRITE
+ | AccessFlags::TRANSFORM_FEEDBACK_COUNTER_READ
+ | AccessFlags::TRANSFORM_FEEDBACK_COUNTER_WRITE
+ | AccessFlags::CONDITIONAL_RENDERING_READ
+ | AccessFlags::COMMAND_PREPROCESS_READ
+ | AccessFlags::COMMAND_PREPROCESS_WRITE
+ | AccessFlags::FRAGMENT_SHADING_RATE_ATTACHMENT_READ
+ | AccessFlags::ACCELERATION_STRUCTURE_READ
+ | AccessFlags::ACCELERATION_STRUCTURE_WRITE
+ | AccessFlags::FRAGMENT_DENSITY_MAP_READ
+ | AccessFlags::COLOR_ATTACHMENT_READ_NONCOHERENT
+ | AccessFlags::INVOCATION_MASK_READ))
+ .is_empty()
}
- impl AccessFlags {
- /// Builds an `AccessFlags` struct with all bits set.
- pub fn all() -> AccessFlags {
- AccessFlags {
- $(
- $elem: true,
- )+
- }
+ /// Replaces and unsets flags that are equivalent to multiple other flags.
+ ///
+ /// This may set flags that are not supported by the device, so this is for internal use
+ /// only and should not be passed on to Vulkan.
+ #[allow(dead_code)] // TODO: use this function
+ pub(crate) fn expand(mut self) -> Self {
+ if self.intersects(AccessFlags::SHADER_READ) {
+ self -= AccessFlags::SHADER_READ;
+ self |= AccessFlags::UNIFORM_READ
+ | AccessFlags::SHADER_SAMPLED_READ
+ | AccessFlags::SHADER_STORAGE_READ
+ | AccessFlags::SHADER_BINDING_TABLE_READ;
}
- /// Builds an `AccessFlags` struct with none of the bits set.
- pub fn none() -> AccessFlags {
- AccessFlags {
- $(
- $elem: false,
- )+
- }
+ if self.intersects(AccessFlags::SHADER_WRITE) {
+ self -= AccessFlags::SHADER_WRITE;
+ self |= AccessFlags::SHADER_STORAGE_WRITE;
}
- }
- impl From<AccessFlags> for ash::vk::AccessFlags {
- #[inline]
- fn from(val: AccessFlags) -> Self {
- let mut result = ash::vk::AccessFlags::empty();
- $(
- if val.$elem { result |= $val }
- )+
- result
- }
+ self
}
+ }
+ = AccessFlags2(u64);
- impl ops::BitOr for AccessFlags {
- type Output = AccessFlags;
+ /// Read access to an indirect buffer.
+ INDIRECT_COMMAND_READ = INDIRECT_COMMAND_READ,
- #[inline]
- fn bitor(self, rhs: AccessFlags) -> AccessFlags {
- AccessFlags {
- $(
- $elem: self.$elem || rhs.$elem,
- )+
- }
- }
- }
+ /// Read access to an index buffer.
+ INDEX_READ = INDEX_READ,
- impl ops::BitOrAssign for AccessFlags {
- #[inline]
- fn bitor_assign(&mut self, rhs: AccessFlags) {
- $(
- self.$elem = self.$elem || rhs.$elem;
- )+
- }
- }
- );
-}
+ /// Read access to a vertex buffer.
+ VERTEX_ATTRIBUTE_READ = VERTEX_ATTRIBUTE_READ,
+
+ /// Read access to a uniform buffer in a shader.
+ UNIFORM_READ = UNIFORM_READ,
+
+ /// Read access to an input attachment in a fragment shader, within a render pass.
+ INPUT_ATTACHMENT_READ = INPUT_ATTACHMENT_READ,
+
+ /// Read access to a buffer or image in a shader.
+ ///
+ /// It is currently equivalent to setting all of the following flags, but automatically
+ /// omitting any that are not supported in a given context. It also implicitly includes future
+ /// flags that are added to Vulkan, if they are not yet supported by Vulkano.
+ /// - `uniform_read`
+ /// - `shader_sampled_read`
+ /// - `shader_storage_read`
+ /// - `shader_binding_table_read`
+ SHADER_READ = SHADER_READ,
+
+ /// Write access to a buffer or image in a shader.
+ ///
+ /// It is currently equivalent to `shader_storage_write`. It also implicitly includes future
+ /// flags that are added to Vulkan, if they are not yet supported by Vulkano.
+ SHADER_WRITE = SHADER_WRITE,
+
+ /// Read access to a color attachment during blending, logic operations or
+ /// subpass load operations.
+ COLOR_ATTACHMENT_READ = COLOR_ATTACHMENT_READ,
+
+ /// Write access to a color, resolve or depth/stencil resolve attachment during a render pass
+ /// or subpass store operations.
+ COLOR_ATTACHMENT_WRITE = COLOR_ATTACHMENT_WRITE,
+
+ /// Read access to a depth/stencil attachment during depth/stencil operations or
+ /// subpass load operations.
+ DEPTH_STENCIL_ATTACHMENT_READ = DEPTH_STENCIL_ATTACHMENT_READ,
+
+ /// Write access to a depth/stencil attachment during depth/stencil operations or
+ /// subpass store operations.
+ DEPTH_STENCIL_ATTACHMENT_WRITE = DEPTH_STENCIL_ATTACHMENT_WRITE,
+
+ /// Read access to a buffer or image during a copy, blit or resolve command.
+ TRANSFER_READ = TRANSFER_READ,
+
+ /// Write access to a buffer or image during a copy, blit, resolve or clear command.
+ TRANSFER_WRITE = TRANSFER_WRITE,
+
+ /// Read access performed by the host.
+ HOST_READ = HOST_READ,
+
+ /// Write access performed by the host.
+ HOST_WRITE = HOST_WRITE,
+
+ /// Any type of read access.
+ ///
+ /// This is equivalent to setting all `_read` flags that are allowed in the given context.
+ MEMORY_READ = MEMORY_READ,
+
+ /// Any type of write access.
+ ///
+ /// This is equivalent to setting all `_write` flags that are allowed in the given context.
+ MEMORY_WRITE = MEMORY_WRITE,
+
+ /// Read access to a uniform texel buffer or sampled image in a shader.
+ SHADER_SAMPLED_READ = SHADER_SAMPLED_READ {
+ api_version: V1_3,
+ device_extensions: [khr_synchronization2],
+ },
+
+ /// Read access to a storage buffer, storage texel buffer or storage image in a shader.
+ SHADER_STORAGE_READ = SHADER_STORAGE_READ {
+ api_version: V1_3,
+ device_extensions: [khr_synchronization2],
+ },
+
+ /// Write access to a storage buffer, storage texel buffer or storage image in a shader.
+ SHADER_STORAGE_WRITE = SHADER_STORAGE_WRITE {
+ api_version: V1_3,
+ device_extensions: [khr_synchronization2],
+ },
+
+ /// Read access to an image or buffer as part of a video decode operation.
+ VIDEO_DECODE_READ = VIDEO_DECODE_READ_KHR {
+ device_extensions: [khr_video_decode_queue],
+ },
+
+ /// Write access to an image or buffer as part of a video decode operation.
+ VIDEO_DECODE_WRITE = VIDEO_DECODE_WRITE_KHR {
+ device_extensions: [khr_video_decode_queue],
+ },
+
+ /// Read access to an image or buffer as part of a video encode operation.
+ VIDEO_ENCODE_READ = VIDEO_ENCODE_READ_KHR {
+ device_extensions: [khr_video_encode_queue],
+ },
+
+ /// Write access to an image or buffer as part of a video encode operation.
+ VIDEO_ENCODE_WRITE = VIDEO_ENCODE_WRITE_KHR {
+ device_extensions: [khr_video_encode_queue],
+ },
+
+ /// Write access to a transform feedback buffer during transform feedback operations.
+ TRANSFORM_FEEDBACK_WRITE = TRANSFORM_FEEDBACK_WRITE_EXT {
+ device_extensions: [ext_transform_feedback],
+ },
+
+ /// Read access to a transform feedback counter buffer during transform feedback operations.
+ TRANSFORM_FEEDBACK_COUNTER_READ = TRANSFORM_FEEDBACK_COUNTER_READ_EXT {
+ device_extensions: [ext_transform_feedback],
+ },
+
+ /// Write access to a transform feedback counter buffer during transform feedback operations.
+ TRANSFORM_FEEDBACK_COUNTER_WRITE = TRANSFORM_FEEDBACK_COUNTER_WRITE_EXT {
+ device_extensions: [ext_transform_feedback],
+ },
+
+ /// Read access to a predicate during conditional rendering.
+ CONDITIONAL_RENDERING_READ = CONDITIONAL_RENDERING_READ_EXT {
+ device_extensions: [ext_conditional_rendering],
+ },
+
+ /// Read access to preprocess buffers input to `preprocess_generated_commands`.
+ COMMAND_PREPROCESS_READ = COMMAND_PREPROCESS_READ_NV {
+ device_extensions: [nv_device_generated_commands],
+ },
+
+ /// Read access to sequences buffers output by `preprocess_generated_commands`.
+ COMMAND_PREPROCESS_WRITE = COMMAND_PREPROCESS_WRITE_NV {
+ device_extensions: [nv_device_generated_commands],
+ },
+
+ /// Read access to a fragment shading rate attachment during rasterization.
+ FRAGMENT_SHADING_RATE_ATTACHMENT_READ = FRAGMENT_SHADING_RATE_ATTACHMENT_READ_KHR {
+ device_extensions: [khr_fragment_shading_rate],
+ },
-access_flags! {
- indirect_command_read => ash::vk::AccessFlags::INDIRECT_COMMAND_READ,
- index_read => ash::vk::AccessFlags::INDEX_READ,
- vertex_attribute_read => ash::vk::AccessFlags::VERTEX_ATTRIBUTE_READ,
- uniform_read => ash::vk::AccessFlags::UNIFORM_READ,
- input_attachment_read => ash::vk::AccessFlags::INPUT_ATTACHMENT_READ,
- shader_read => ash::vk::AccessFlags::SHADER_READ,
- shader_write => ash::vk::AccessFlags::SHADER_WRITE,
- color_attachment_read => ash::vk::AccessFlags::COLOR_ATTACHMENT_READ,
- color_attachment_write => ash::vk::AccessFlags::COLOR_ATTACHMENT_WRITE,
- depth_stencil_attachment_read => ash::vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ,
- depth_stencil_attachment_write => ash::vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE,
- transfer_read => ash::vk::AccessFlags::TRANSFER_READ,
- transfer_write => ash::vk::AccessFlags::TRANSFER_WRITE,
- host_read => ash::vk::AccessFlags::HOST_READ,
- host_write => ash::vk::AccessFlags::HOST_WRITE,
- memory_read => ash::vk::AccessFlags::MEMORY_READ,
- memory_write => ash::vk::AccessFlags::MEMORY_WRITE,
+ /// Read access to an acceleration structure or acceleration structure scratch buffer during
+ /// trace, build or copy commands.
+ ACCELERATION_STRUCTURE_READ = ACCELERATION_STRUCTURE_READ_KHR {
+ device_extensions: [khr_acceleration_structure, nv_ray_tracing],
+ },
+
+ /// Write access to an acceleration structure or acceleration structure scratch buffer during
+ /// trace, build or copy commands.
+ ACCELERATION_STRUCTURE_WRITE = ACCELERATION_STRUCTURE_WRITE_KHR {
+ device_extensions: [khr_acceleration_structure, nv_ray_tracing],
+ },
+
+ /// Read access to a fragment density map attachment during dynamic fragment density map
+ /// operations.
+ FRAGMENT_DENSITY_MAP_READ = FRAGMENT_DENSITY_MAP_READ_EXT {
+ device_extensions: [ext_fragment_density_map],
+ },
+
+ /// Read access to color attachments when performing advanced blend operations.
+ COLOR_ATTACHMENT_READ_NONCOHERENT = COLOR_ATTACHMENT_READ_NONCOHERENT_EXT {
+ device_extensions: [ext_blend_operation_advanced],
+ },
+
+ /// Read access to an invocation mask image.
+ INVOCATION_MASK_READ = INVOCATION_MASK_READ_HUAWEI {
+ device_extensions: [huawei_invocation_mask],
+ },
+
+ /// Read access to a shader binding table.
+ SHADER_BINDING_TABLE_READ = SHADER_BINDING_TABLE_READ_KHR {
+ device_extensions: [khr_ray_tracing_maintenance1],
+ },
+
+ /// Read access to a micromap object.
+ MICROMAP_READ = MICROMAP_READ_EXT {
+ device_extensions: [ext_opacity_micromap],
+ },
+
+ /// Write access to a micromap object.
+ MICROMAP_WRITE = MICROMAP_WRITE_EXT {
+ device_extensions: [ext_opacity_micromap],
+ },
+
+ /// Read access to a buffer or image during optical flow operations.
+ OPTICAL_FLOW_READ = OPTICAL_FLOW_READ_NV {
+ device_extensions: [nv_optical_flow],
+ },
+
+ /// Write access to a buffer or image during optical flow operations.
+ OPTICAL_FLOW_WRITE = OPTICAL_FLOW_WRITE_NV {
+ device_extensions: [nv_optical_flow],
+ },
}
-impl AccessFlags {
- /// Returns true if the access flags can be used with the given pipeline stages.
+impl From<PipelineStages> for AccessFlags {
+ /// Corresponds to the table "[Supported access types]" in the Vulkan specification.
///
- /// Corresponds to `Table 4. Supported access types` in section `6.1.3. Access Types` of the
- /// Vulkan specs.
- pub fn is_compatible_with(&self, stages: &PipelineStages) -> bool {
- if stages.all_commands {
- return true;
+ /// [Supported access types]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap7.html#synchronization-access-types-supported
+ #[inline]
+ fn from(mut val: PipelineStages) -> Self {
+ if val.is_empty() {
+ return AccessFlags::empty();
}
- if self.indirect_command_read && !stages.draw_indirect && !stages.all_graphics {
- return false;
+ val = val.expand(QueueFlags::GRAPHICS | QueueFlags::COMPUTE | QueueFlags::TRANSFER);
+ let mut result = AccessFlags::MEMORY_READ | AccessFlags::MEMORY_WRITE;
+
+ if val.intersects(PipelineStages::DRAW_INDIRECT) {
+ result |=
+ AccessFlags::INDIRECT_COMMAND_READ | AccessFlags::TRANSFORM_FEEDBACK_COUNTER_READ;
}
- if (self.index_read || self.vertex_attribute_read)
- && !stages.vertex_input
- && !stages.all_graphics
- {
- return false;
+ if val.intersects(
+ PipelineStages::VERTEX_SHADER
+ | PipelineStages::TESSELLATION_CONTROL_SHADER
+ | PipelineStages::TESSELLATION_EVALUATION_SHADER
+ | PipelineStages::GEOMETRY_SHADER
+ | PipelineStages::FRAGMENT_SHADER
+ | PipelineStages::COMPUTE_SHADER
+ | PipelineStages::RAY_TRACING_SHADER
+ | PipelineStages::TASK_SHADER
+ | PipelineStages::MESH_SHADER,
+ ) {
+ result |= AccessFlags::SHADER_READ
+ | AccessFlags::UNIFORM_READ
+ | AccessFlags::SHADER_SAMPLED_READ
+ | AccessFlags::SHADER_STORAGE_READ
+ | AccessFlags::SHADER_WRITE
+ | AccessFlags::SHADER_STORAGE_WRITE
+ | AccessFlags::ACCELERATION_STRUCTURE_READ;
}
- if (self.uniform_read || self.shader_read || self.shader_write)
- && !stages.vertex_shader
- && !stages.tessellation_control_shader
- && !stages.tessellation_evaluation_shader
- && !stages.geometry_shader
- && !stages.fragment_shader
- && !stages.compute_shader
- && !stages.all_graphics
+ if val.intersects(PipelineStages::FRAGMENT_SHADER | PipelineStages::SUBPASS_SHADING) {
+ result |= AccessFlags::INPUT_ATTACHMENT_READ;
+ }
+
+ if val
+ .intersects(PipelineStages::EARLY_FRAGMENT_TESTS | PipelineStages::LATE_FRAGMENT_TESTS)
{
- return false;
+ result |= AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ
+ | AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE;
}
- if self.input_attachment_read && !stages.fragment_shader && !stages.all_graphics {
- return false;
+ if val.intersects(PipelineStages::COLOR_ATTACHMENT_OUTPUT) {
+ result |= AccessFlags::COLOR_ATTACHMENT_READ
+ | AccessFlags::COLOR_ATTACHMENT_WRITE
+ | AccessFlags::COLOR_ATTACHMENT_READ_NONCOHERENT;
}
- if (self.color_attachment_read || self.color_attachment_write)
- && !stages.color_attachment_output
- && !stages.all_graphics
- {
- return false;
+ if val.intersects(PipelineStages::HOST) {
+ result |= AccessFlags::HOST_READ | AccessFlags::HOST_WRITE;
}
- if (self.depth_stencil_attachment_read || self.depth_stencil_attachment_write)
- && !stages.early_fragment_tests
- && !stages.late_fragment_tests
- && !stages.all_graphics
- {
- return false;
+ if val.intersects(
+ PipelineStages::COPY
+ | PipelineStages::RESOLVE
+ | PipelineStages::BLIT
+ | PipelineStages::ACCELERATION_STRUCTURE_COPY,
+ ) {
+ result |= AccessFlags::TRANSFER_READ | AccessFlags::TRANSFER_WRITE;
+ }
+
+ if val.intersects(PipelineStages::CLEAR) {
+ result |= AccessFlags::TRANSFER_WRITE;
}
- if (self.transfer_read || self.transfer_write) && !stages.transfer {
- return false;
+ if val.intersects(PipelineStages::INDEX_INPUT) {
+ result |= AccessFlags::INDEX_READ;
}
- if (self.host_read || self.host_write) && !stages.host {
- return false;
+ if val.intersects(PipelineStages::VERTEX_ATTRIBUTE_INPUT) {
+ result |= AccessFlags::VERTEX_ATTRIBUTE_READ;
}
- true
+ if val.intersects(PipelineStages::VIDEO_DECODE) {
+ result |= AccessFlags::VIDEO_DECODE_READ | AccessFlags::VIDEO_DECODE_WRITE;
+ }
+
+ if val.intersects(PipelineStages::VIDEO_ENCODE) {
+ result |= AccessFlags::VIDEO_ENCODE_READ | AccessFlags::VIDEO_ENCODE_WRITE;
+ }
+
+ if val.intersects(PipelineStages::TRANSFORM_FEEDBACK) {
+ result |= AccessFlags::TRANSFORM_FEEDBACK_WRITE
+ | AccessFlags::TRANSFORM_FEEDBACK_COUNTER_WRITE
+ | AccessFlags::TRANSFORM_FEEDBACK_COUNTER_READ;
+ }
+
+ if val.intersects(PipelineStages::CONDITIONAL_RENDERING) {
+ result |= AccessFlags::CONDITIONAL_RENDERING_READ;
+ }
+
+ if val.intersects(PipelineStages::ACCELERATION_STRUCTURE_BUILD) {
+ result |= AccessFlags::INDIRECT_COMMAND_READ
+ | AccessFlags::SHADER_READ
+ | AccessFlags::SHADER_SAMPLED_READ
+ | AccessFlags::SHADER_STORAGE_READ
+ | AccessFlags::SHADER_STORAGE_WRITE
+ | AccessFlags::TRANSFER_READ
+ | AccessFlags::TRANSFER_WRITE
+ | AccessFlags::ACCELERATION_STRUCTURE_READ
+ | AccessFlags::ACCELERATION_STRUCTURE_WRITE
+ | AccessFlags::MICROMAP_READ;
+ }
+
+ if val.intersects(PipelineStages::RAY_TRACING_SHADER) {
+ result |= AccessFlags::SHADER_BINDING_TABLE_READ;
+ }
+
+ if val.intersects(PipelineStages::FRAGMENT_DENSITY_PROCESS) {
+ result |= AccessFlags::FRAGMENT_DENSITY_MAP_READ;
+ }
+
+ if val.intersects(PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT) {
+ result |= AccessFlags::FRAGMENT_SHADING_RATE_ATTACHMENT_READ;
+ }
+
+ if val.intersects(PipelineStages::COMMAND_PREPROCESS) {
+ result |= AccessFlags::COMMAND_PREPROCESS_READ | AccessFlags::COMMAND_PREPROCESS_WRITE;
+ }
+
+ if val.intersects(PipelineStages::INVOCATION_MASK) {
+ result |= AccessFlags::INVOCATION_MASK_READ;
+ }
+
+ if val.intersects(PipelineStages::MICROMAP_BUILD) {
+ result |= AccessFlags::MICROMAP_READ | AccessFlags::MICROMAP_WRITE;
+ }
+
+ if val.intersects(PipelineStages::OPTICAL_FLOW) {
+ result |= AccessFlags::OPTICAL_FLOW_READ | AccessFlags::OPTICAL_FLOW_WRITE;
+ }
+
+ result
+ }
+}
+
+impl From<AccessFlags> for ash::vk::AccessFlags {
+ #[inline]
+ fn from(val: AccessFlags) -> Self {
+ Self::from_raw(ash::vk::AccessFlags2::from(val).as_raw() as u32)
}
}
/// The full specification of memory access by the pipeline for a particular resource.
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct PipelineMemoryAccess {
/// The pipeline stages the resource will be accessed in.
pub stages: PipelineStages,
@@ -269,3 +996,1736 @@ pub struct PipelineMemoryAccess {
/// Whether the resource needs exclusive (mutable) access or can be shared.
pub exclusive: bool,
}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+#[allow(non_camel_case_types, dead_code)]
+#[repr(u8)]
+pub(crate) enum PipelineStageAccess {
+ // There is no stage/access for this, but it is a memory write operation nonetheless.
+ ImageLayoutTransition,
+
+ DrawIndirect_IndirectCommandRead,
+ DrawIndirect_TransformFeedbackCounterRead,
+ VertexShader_UniformRead,
+ VertexShader_ShaderSampledRead,
+ VertexShader_ShaderStorageRead,
+ VertexShader_ShaderStorageWrite,
+ VertexShader_AccelerationStructureRead,
+ TessellationControlShader_UniformRead,
+ TessellationControlShader_ShaderSampledRead,
+ TessellationControlShader_ShaderStorageRead,
+ TessellationControlShader_ShaderStorageWrite,
+ TessellationControlShader_AccelerationStructureRead,
+ TessellationEvaluationShader_UniformRead,
+ TessellationEvaluationShader_ShaderSampledRead,
+ TessellationEvaluationShader_ShaderStorageRead,
+ TessellationEvaluationShader_ShaderStorageWrite,
+ TessellationEvaluationShader_AccelerationStructureRead,
+ GeometryShader_UniformRead,
+ GeometryShader_ShaderSampledRead,
+ GeometryShader_ShaderStorageRead,
+ GeometryShader_ShaderStorageWrite,
+ GeometryShader_AccelerationStructureRead,
+ FragmentShader_UniformRead,
+ FragmentShader_InputAttachmentRead,
+ FragmentShader_ShaderSampledRead,
+ FragmentShader_ShaderStorageRead,
+ FragmentShader_ShaderStorageWrite,
+ FragmentShader_AccelerationStructureRead,
+ EarlyFragmentTests_DepthStencilAttachmentRead,
+ EarlyFragmentTests_DepthStencilAttachmentWrite,
+ LateFragmentTests_DepthStencilAttachmentRead,
+ LateFragmentTests_DepthStencilAttachmentWrite,
+ ColorAttachmentOutput_ColorAttachmentRead,
+ ColorAttachmentOutput_ColorAttachmentWrite,
+ ColorAttachmentOutput_ColorAttachmentReadNoncoherent,
+ ComputeShader_UniformRead,
+ ComputeShader_ShaderSampledRead,
+ ComputeShader_ShaderStorageRead,
+ ComputeShader_ShaderStorageWrite,
+ ComputeShader_AccelerationStructureRead,
+ Host_HostRead,
+ Host_HostWrite,
+ Copy_TransferRead,
+ Copy_TransferWrite,
+ Resolve_TransferRead,
+ Resolve_TransferWrite,
+ Blit_TransferRead,
+ Blit_TransferWrite,
+ Clear_TransferWrite,
+ IndexInput_IndexRead,
+ VertexAttributeInput_VertexAttributeRead,
+ VideoDecode_VideoDecodeRead,
+ VideoDecode_VideoDecodeWrite,
+ VideoEncode_VideoEncodeRead,
+ VideoEncode_VideoEncodeWrite,
+ TransformFeedback_TransformFeedbackWrite,
+ TransformFeedback_TransformFeedbackCounterRead,
+ TransformFeedback_TransformFeedbackCounterWrite,
+ ConditionalRendering_ConditionalRenderingRead,
+ AccelerationStructureBuild_IndirectCommandRead,
+ AccelerationStructureBuild_UniformRead,
+ AccelerationStructureBuild_TransferRead,
+ AccelerationStructureBuild_TransferWrite,
+ AccelerationStructureBuild_ShaderSampledRead,
+ AccelerationStructureBuild_ShaderStorageRead,
+ AccelerationStructureBuild_AccelerationStructureRead,
+ AccelerationStructureBuild_AccelerationStructureWrite,
+ AccelerationStructureBuild_MicromapRead,
+ RayTracingShader_UniformRead,
+ RayTracingShader_ShaderSampledRead,
+ RayTracingShader_ShaderStorageRead,
+ RayTracingShader_ShaderStorageWrite,
+ RayTracingShader_AccelerationStructureRead,
+ RayTracingShader_ShaderBindingTableRead,
+ FragmentDensityProcess_FragmentDensityMapRead,
+ FragmentShadingRateAttachment_FragmentShadingRateAttachmentRead,
+ CommandPreprocess_CommandPreprocessRead,
+ CommandPreprocess_CommandPreprocessWrite,
+ TaskShader_UniformRead,
+ TaskShader_ShaderSampledRead,
+ TaskShader_ShaderStorageRead,
+ TaskShader_ShaderStorageWrite,
+ TaskShader_AccelerationStructureRead,
+ MeshShader_UniformRead,
+ MeshShader_ShaderSampledRead,
+ MeshShader_ShaderStorageRead,
+ MeshShader_ShaderStorageWrite,
+ MeshShader_AccelerationStructureRead,
+ SubpassShading_InputAttachmentRead,
+ InvocationMask_InvocationMaskRead,
+ AccelerationStructureCopy_TransferRead,
+ AccelerationStructureCopy_TransferWrite,
+ OpticalFlow_OpticalFlowRead,
+ OpticalFlow_OpticalFlowWrite,
+ MicromapBuild_MicromapRead,
+ MicromapBuild_MicromapWrite,
+
+ // If there are ever more than 128 preceding values, then there will be a compile error:
+ // "discriminant value `128` assigned more than once"
+ __MAX_VALUE__ = 128,
+}
+
+impl PipelineStageAccess {
+ #[inline]
+ pub(crate) const fn is_write(self) -> bool {
+ matches!(
+ self,
+ PipelineStageAccess::ImageLayoutTransition
+ | PipelineStageAccess::VertexShader_ShaderStorageWrite
+ | PipelineStageAccess::TessellationControlShader_ShaderStorageWrite
+ | PipelineStageAccess::TessellationEvaluationShader_ShaderStorageWrite
+ | PipelineStageAccess::GeometryShader_ShaderStorageWrite
+ | PipelineStageAccess::FragmentShader_ShaderStorageWrite
+ | PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentWrite
+ | PipelineStageAccess::LateFragmentTests_DepthStencilAttachmentWrite
+ | PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentWrite
+ | PipelineStageAccess::ComputeShader_ShaderStorageWrite
+ | PipelineStageAccess::Host_HostWrite
+ | PipelineStageAccess::Copy_TransferWrite
+ | PipelineStageAccess::Resolve_TransferWrite
+ | PipelineStageAccess::Blit_TransferWrite
+ | PipelineStageAccess::Clear_TransferWrite
+ | PipelineStageAccess::VideoDecode_VideoDecodeWrite
+ | PipelineStageAccess::VideoEncode_VideoEncodeWrite
+ | PipelineStageAccess::TransformFeedback_TransformFeedbackWrite
+ | PipelineStageAccess::TransformFeedback_TransformFeedbackCounterWrite
+ | PipelineStageAccess::AccelerationStructureBuild_TransferWrite
+ | PipelineStageAccess::AccelerationStructureBuild_AccelerationStructureWrite
+ | PipelineStageAccess::RayTracingShader_ShaderStorageWrite
+ | PipelineStageAccess::CommandPreprocess_CommandPreprocessWrite
+ | PipelineStageAccess::TaskShader_ShaderStorageWrite
+ | PipelineStageAccess::MeshShader_ShaderStorageWrite
+ | PipelineStageAccess::AccelerationStructureCopy_TransferWrite
+ | PipelineStageAccess::OpticalFlow_OpticalFlowWrite
+ | PipelineStageAccess::MicromapBuild_MicromapWrite
+ )
+ }
+
+ pub(crate) fn iter_descriptor_stages(
+ descriptor_type: DescriptorType,
+ stages_read: ShaderStages,
+ stages_write: ShaderStages,
+ ) -> impl Iterator<Item = Self> + 'static {
+ static MAP_READ: Lazy<
+ HashMap<DescriptorType, HashMap<PipelineStage, PipelineStageAccess>>,
+ > = Lazy::new(|| {
+ let uniform_read = [
+ DescriptorType::UniformBuffer,
+ DescriptorType::UniformBufferDynamic,
+ ]
+ .into_iter()
+ .map(|descriptor_type| {
+ (
+ descriptor_type,
+ [
+ (
+ PipelineStage::VertexShader,
+ PipelineStageAccess::VertexShader_UniformRead,
+ ),
+ (
+ PipelineStage::TessellationControlShader,
+ PipelineStageAccess::TessellationControlShader_UniformRead,
+ ),
+ (
+ PipelineStage::TessellationEvaluationShader,
+ PipelineStageAccess::TessellationControlShader_UniformRead,
+ ),
+ (
+ PipelineStage::GeometryShader,
+ PipelineStageAccess::GeometryShader_UniformRead,
+ ),
+ (
+ PipelineStage::FragmentShader,
+ PipelineStageAccess::FragmentShader_UniformRead,
+ ),
+ (
+ PipelineStage::ComputeShader,
+ PipelineStageAccess::ComputeShader_UniformRead,
+ ),
+ (
+ PipelineStage::RayTracingShader,
+ PipelineStageAccess::RayTracingShader_UniformRead,
+ ),
+ (
+ PipelineStage::TaskShader,
+ PipelineStageAccess::TaskShader_UniformRead,
+ ),
+ (
+ PipelineStage::MeshShader,
+ PipelineStageAccess::MeshShader_UniformRead,
+ ),
+ ]
+ .into_iter()
+ .collect(),
+ )
+ });
+
+ let shader_sampled_read = [
+ DescriptorType::CombinedImageSampler,
+ DescriptorType::SampledImage,
+ DescriptorType::UniformTexelBuffer,
+ ]
+ .into_iter()
+ .map(|descriptor_type| {
+ (
+ descriptor_type,
+ [
+ (
+ PipelineStage::VertexShader,
+ PipelineStageAccess::VertexShader_ShaderSampledRead,
+ ),
+ (
+ PipelineStage::TessellationControlShader,
+ PipelineStageAccess::TessellationControlShader_ShaderSampledRead,
+ ),
+ (
+ PipelineStage::TessellationEvaluationShader,
+ PipelineStageAccess::TessellationControlShader_ShaderSampledRead,
+ ),
+ (
+ PipelineStage::GeometryShader,
+ PipelineStageAccess::GeometryShader_ShaderSampledRead,
+ ),
+ (
+ PipelineStage::FragmentShader,
+ PipelineStageAccess::FragmentShader_ShaderSampledRead,
+ ),
+ (
+ PipelineStage::ComputeShader,
+ PipelineStageAccess::ComputeShader_ShaderSampledRead,
+ ),
+ (
+ PipelineStage::RayTracingShader,
+ PipelineStageAccess::RayTracingShader_ShaderSampledRead,
+ ),
+ (
+ PipelineStage::TaskShader,
+ PipelineStageAccess::TaskShader_ShaderSampledRead,
+ ),
+ (
+ PipelineStage::MeshShader,
+ PipelineStageAccess::MeshShader_ShaderSampledRead,
+ ),
+ ]
+ .into_iter()
+ .collect(),
+ )
+ });
+
+ let shader_storage_read = [
+ DescriptorType::StorageImage,
+ DescriptorType::StorageTexelBuffer,
+ DescriptorType::StorageBuffer,
+ DescriptorType::StorageBufferDynamic,
+ ]
+ .into_iter()
+ .map(|descriptor_type| {
+ (
+ descriptor_type,
+ [
+ (
+ PipelineStage::VertexShader,
+ PipelineStageAccess::VertexShader_ShaderStorageRead,
+ ),
+ (
+ PipelineStage::TessellationControlShader,
+ PipelineStageAccess::TessellationControlShader_ShaderStorageRead,
+ ),
+ (
+ PipelineStage::TessellationEvaluationShader,
+ PipelineStageAccess::TessellationControlShader_ShaderStorageRead,
+ ),
+ (
+ PipelineStage::GeometryShader,
+ PipelineStageAccess::GeometryShader_ShaderStorageRead,
+ ),
+ (
+ PipelineStage::FragmentShader,
+ PipelineStageAccess::FragmentShader_ShaderStorageRead,
+ ),
+ (
+ PipelineStage::ComputeShader,
+ PipelineStageAccess::ComputeShader_ShaderStorageRead,
+ ),
+ (
+ PipelineStage::RayTracingShader,
+ PipelineStageAccess::RayTracingShader_ShaderStorageRead,
+ ),
+ (
+ PipelineStage::TaskShader,
+ PipelineStageAccess::TaskShader_ShaderStorageRead,
+ ),
+ (
+ PipelineStage::MeshShader,
+ PipelineStageAccess::MeshShader_ShaderStorageRead,
+ ),
+ ]
+ .into_iter()
+ .collect(),
+ )
+ });
+
+ let input_attachment_read =
+ [DescriptorType::InputAttachment]
+ .into_iter()
+ .map(|descriptor_type| {
+ (
+ descriptor_type,
+ [(
+ PipelineStage::FragmentShader,
+ PipelineStageAccess::FragmentShader_InputAttachmentRead,
+ )]
+ .into_iter()
+ .collect(),
+ )
+ });
+
+ uniform_read
+ .chain(shader_sampled_read)
+ .chain(shader_storage_read)
+ .chain(input_attachment_read)
+ .collect()
+ });
+ static MAP_WRITE: Lazy<
+ HashMap<DescriptorType, HashMap<PipelineStage, PipelineStageAccess>>,
+ > = Lazy::new(|| {
+ let shader_storage_write = [
+ DescriptorType::StorageImage,
+ DescriptorType::StorageTexelBuffer,
+ DescriptorType::StorageBuffer,
+ DescriptorType::StorageBufferDynamic,
+ ]
+ .into_iter()
+ .map(|descriptor_type| {
+ (
+ descriptor_type,
+ [
+ (
+ PipelineStage::VertexShader,
+ PipelineStageAccess::VertexShader_ShaderStorageWrite,
+ ),
+ (
+ PipelineStage::TessellationControlShader,
+ PipelineStageAccess::TessellationControlShader_ShaderStorageWrite,
+ ),
+ (
+ PipelineStage::TessellationEvaluationShader,
+ PipelineStageAccess::TessellationControlShader_ShaderStorageWrite,
+ ),
+ (
+ PipelineStage::GeometryShader,
+ PipelineStageAccess::GeometryShader_ShaderStorageWrite,
+ ),
+ (
+ PipelineStage::FragmentShader,
+ PipelineStageAccess::FragmentShader_ShaderStorageWrite,
+ ),
+ (
+ PipelineStage::ComputeShader,
+ PipelineStageAccess::ComputeShader_ShaderStorageWrite,
+ ),
+ (
+ PipelineStage::RayTracingShader,
+ PipelineStageAccess::RayTracingShader_ShaderStorageWrite,
+ ),
+ (
+ PipelineStage::TaskShader,
+ PipelineStageAccess::TaskShader_ShaderStorageWrite,
+ ),
+ (
+ PipelineStage::MeshShader,
+ PipelineStageAccess::MeshShader_ShaderStorageWrite,
+ ),
+ ]
+ .into_iter()
+ .collect(),
+ )
+ });
+
+ shader_storage_write.collect()
+ });
+
+ [
+ (stages_read, &*MAP_READ, "read"),
+ (stages_write, &*MAP_WRITE, "write"),
+ ]
+ .into_iter()
+ .filter(|(stages, _, _)| !stages.is_empty())
+ .flat_map(move |(stages, descriptor_map, access)| {
+ let stages_map = descriptor_map.get(&descriptor_type).unwrap_or_else(|| {
+ panic!(
+ "DescriptorType::{:?} does not {} memory",
+ descriptor_type, access,
+ )
+ });
+
+ PipelineStages::from(stages).into_iter().map(move |stage| {
+ *stages_map.get(&stage).unwrap_or_else(|| {
+ panic!(
+ "DescriptorType::{:?} does not {} memory in PipelineStage::{:?}",
+ descriptor_type, access, stage,
+ )
+ })
+ })
+ })
+ }
+}
+
+impl TryFrom<PipelineStageAccess> for PipelineStage {
+ type Error = ();
+
+ #[inline]
+ fn try_from(val: PipelineStageAccess) -> Result<Self, Self::Error> {
+ Ok(match val {
+ PipelineStageAccess::ImageLayoutTransition => return Err(()),
+ PipelineStageAccess::DrawIndirect_IndirectCommandRead
+ | PipelineStageAccess::DrawIndirect_TransformFeedbackCounterRead => PipelineStage::DrawIndirect,
+ PipelineStageAccess::VertexShader_UniformRead
+ | PipelineStageAccess::VertexShader_ShaderSampledRead
+ | PipelineStageAccess::VertexShader_ShaderStorageRead
+ | PipelineStageAccess::VertexShader_ShaderStorageWrite
+ | PipelineStageAccess::VertexShader_AccelerationStructureRead => PipelineStage::VertexShader,
+ PipelineStageAccess::TessellationControlShader_UniformRead
+ | PipelineStageAccess::TessellationControlShader_ShaderSampledRead
+ | PipelineStageAccess::TessellationControlShader_ShaderStorageRead
+ | PipelineStageAccess::TessellationControlShader_ShaderStorageWrite
+ | PipelineStageAccess::TessellationControlShader_AccelerationStructureRead => PipelineStage::TessellationControlShader,
+ PipelineStageAccess::TessellationEvaluationShader_UniformRead
+ | PipelineStageAccess::TessellationEvaluationShader_ShaderSampledRead
+ | PipelineStageAccess::TessellationEvaluationShader_ShaderStorageRead
+ | PipelineStageAccess::TessellationEvaluationShader_ShaderStorageWrite
+ | PipelineStageAccess::TessellationEvaluationShader_AccelerationStructureRead => PipelineStage::TessellationEvaluationShader,
+ PipelineStageAccess::GeometryShader_UniformRead
+ | PipelineStageAccess::GeometryShader_ShaderSampledRead
+ | PipelineStageAccess::GeometryShader_ShaderStorageRead
+ | PipelineStageAccess::GeometryShader_ShaderStorageWrite
+ | PipelineStageAccess::GeometryShader_AccelerationStructureRead => PipelineStage::GeometryShader,
+ PipelineStageAccess::FragmentShader_UniformRead
+ | PipelineStageAccess::FragmentShader_InputAttachmentRead
+ | PipelineStageAccess::FragmentShader_ShaderSampledRead
+ | PipelineStageAccess::FragmentShader_ShaderStorageRead
+ | PipelineStageAccess::FragmentShader_ShaderStorageWrite
+ | PipelineStageAccess::FragmentShader_AccelerationStructureRead => PipelineStage::FragmentShader,
+ PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentRead
+ | PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentWrite => PipelineStage::EarlyFragmentTests,
+ PipelineStageAccess::LateFragmentTests_DepthStencilAttachmentRead
+ | PipelineStageAccess::LateFragmentTests_DepthStencilAttachmentWrite => PipelineStage::LateFragmentTests,
+ PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentRead
+ | PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentWrite
+ | PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentReadNoncoherent => PipelineStage::ColorAttachmentOutput,
+ PipelineStageAccess::ComputeShader_UniformRead
+ | PipelineStageAccess::ComputeShader_ShaderSampledRead
+ | PipelineStageAccess::ComputeShader_ShaderStorageRead
+ | PipelineStageAccess::ComputeShader_ShaderStorageWrite
+ | PipelineStageAccess::ComputeShader_AccelerationStructureRead => PipelineStage::ComputeShader,
+ PipelineStageAccess::Host_HostRead
+ | PipelineStageAccess::Host_HostWrite => PipelineStage::Host,
+ PipelineStageAccess::Copy_TransferRead
+ | PipelineStageAccess::Copy_TransferWrite => PipelineStage::Copy,
+ PipelineStageAccess::Resolve_TransferRead
+ | PipelineStageAccess::Resolve_TransferWrite => PipelineStage::Resolve,
+ PipelineStageAccess::Blit_TransferRead
+ | PipelineStageAccess::Blit_TransferWrite => PipelineStage::Blit,
+ PipelineStageAccess::Clear_TransferWrite => PipelineStage::Clear,
+ PipelineStageAccess::IndexInput_IndexRead => PipelineStage::IndexInput,
+ PipelineStageAccess::VertexAttributeInput_VertexAttributeRead => PipelineStage::VertexAttributeInput,
+ PipelineStageAccess::VideoDecode_VideoDecodeRead
+ | PipelineStageAccess::VideoDecode_VideoDecodeWrite => PipelineStage::VideoDecode,
+ PipelineStageAccess::VideoEncode_VideoEncodeRead
+ | PipelineStageAccess::VideoEncode_VideoEncodeWrite => PipelineStage::VideoEncode,
+ PipelineStageAccess::TransformFeedback_TransformFeedbackWrite
+ | PipelineStageAccess::TransformFeedback_TransformFeedbackCounterRead
+ | PipelineStageAccess::TransformFeedback_TransformFeedbackCounterWrite => PipelineStage::TransformFeedback,
+ PipelineStageAccess::ConditionalRendering_ConditionalRenderingRead => PipelineStage::ConditionalRendering,
+ PipelineStageAccess::AccelerationStructureBuild_IndirectCommandRead
+ | PipelineStageAccess::AccelerationStructureBuild_UniformRead
+ | PipelineStageAccess::AccelerationStructureBuild_TransferRead
+ | PipelineStageAccess::AccelerationStructureBuild_TransferWrite
+ | PipelineStageAccess::AccelerationStructureBuild_ShaderSampledRead
+ | PipelineStageAccess::AccelerationStructureBuild_ShaderStorageRead
+ | PipelineStageAccess::AccelerationStructureBuild_AccelerationStructureRead
+ | PipelineStageAccess::AccelerationStructureBuild_AccelerationStructureWrite
+ | PipelineStageAccess::AccelerationStructureBuild_MicromapRead => PipelineStage::AccelerationStructureBuild,
+ PipelineStageAccess::RayTracingShader_UniformRead
+ | PipelineStageAccess::RayTracingShader_ShaderSampledRead
+ | PipelineStageAccess::RayTracingShader_ShaderStorageRead
+ | PipelineStageAccess::RayTracingShader_ShaderStorageWrite
+ | PipelineStageAccess::RayTracingShader_AccelerationStructureRead => PipelineStage::RayTracingShader,
+ | PipelineStageAccess::RayTracingShader_ShaderBindingTableRead => PipelineStage::RayTracingShader,
+ PipelineStageAccess::FragmentDensityProcess_FragmentDensityMapRead => PipelineStage::FragmentDensityProcess,
+ PipelineStageAccess::FragmentShadingRateAttachment_FragmentShadingRateAttachmentRead => PipelineStage::FragmentShadingRateAttachment,
+ PipelineStageAccess::CommandPreprocess_CommandPreprocessRead
+ | PipelineStageAccess::CommandPreprocess_CommandPreprocessWrite => PipelineStage::CommandPreprocess,
+ PipelineStageAccess::TaskShader_UniformRead
+ | PipelineStageAccess::TaskShader_ShaderSampledRead
+ | PipelineStageAccess::TaskShader_ShaderStorageRead
+ | PipelineStageAccess::TaskShader_ShaderStorageWrite
+ | PipelineStageAccess::TaskShader_AccelerationStructureRead => PipelineStage::TaskShader,
+ PipelineStageAccess::MeshShader_UniformRead
+ | PipelineStageAccess::MeshShader_ShaderSampledRead
+ | PipelineStageAccess::MeshShader_ShaderStorageRead
+ | PipelineStageAccess::MeshShader_ShaderStorageWrite
+ | PipelineStageAccess::MeshShader_AccelerationStructureRead => PipelineStage::MeshShader,
+ PipelineStageAccess::SubpassShading_InputAttachmentRead => PipelineStage::SubpassShading,
+ PipelineStageAccess::InvocationMask_InvocationMaskRead => PipelineStage::InvocationMask,
+ PipelineStageAccess::AccelerationStructureCopy_TransferRead
+ | PipelineStageAccess::AccelerationStructureCopy_TransferWrite => PipelineStage::AccelerationStructureCopy,
+ PipelineStageAccess::OpticalFlow_OpticalFlowRead
+ | PipelineStageAccess::OpticalFlow_OpticalFlowWrite => PipelineStage::OpticalFlow,
+ PipelineStageAccess::MicromapBuild_MicromapRead
+ | PipelineStageAccess::MicromapBuild_MicromapWrite => PipelineStage::MicromapBuild,
+ PipelineStageAccess::__MAX_VALUE__ => unreachable!(),
+ })
+ }
+}
+
+impl From<PipelineStageAccess> for AccessFlags {
+ #[inline]
+ fn from(val: PipelineStageAccess) -> Self {
+ match val {
+ PipelineStageAccess::ImageLayoutTransition => AccessFlags::empty(),
+ PipelineStageAccess::DrawIndirect_IndirectCommandRead
+ | PipelineStageAccess::AccelerationStructureBuild_IndirectCommandRead => AccessFlags::INDIRECT_COMMAND_READ,
+ PipelineStageAccess::IndexInput_IndexRead => AccessFlags::INDEX_READ,
+ PipelineStageAccess::VertexAttributeInput_VertexAttributeRead => AccessFlags::VERTEX_ATTRIBUTE_READ,
+ PipelineStageAccess::VertexShader_UniformRead
+ | PipelineStageAccess::TessellationControlShader_UniformRead
+ | PipelineStageAccess::TessellationEvaluationShader_UniformRead
+ | PipelineStageAccess::GeometryShader_UniformRead
+ | PipelineStageAccess::FragmentShader_UniformRead
+ | PipelineStageAccess::ComputeShader_UniformRead
+ | PipelineStageAccess::AccelerationStructureBuild_UniformRead
+ | PipelineStageAccess::RayTracingShader_UniformRead
+ | PipelineStageAccess::TaskShader_UniformRead
+ | PipelineStageAccess::MeshShader_UniformRead => AccessFlags::UNIFORM_READ,
+ PipelineStageAccess::FragmentShader_InputAttachmentRead
+ | PipelineStageAccess::SubpassShading_InputAttachmentRead => AccessFlags::INPUT_ATTACHMENT_READ,
+ PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentRead => AccessFlags::COLOR_ATTACHMENT_READ,
+ PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentWrite => AccessFlags::COLOR_ATTACHMENT_WRITE,
+ PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentRead
+ | PipelineStageAccess::LateFragmentTests_DepthStencilAttachmentRead => AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ,
+ PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentWrite
+ | PipelineStageAccess::LateFragmentTests_DepthStencilAttachmentWrite => AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE,
+ PipelineStageAccess::Copy_TransferRead
+ | PipelineStageAccess::Resolve_TransferRead
+ | PipelineStageAccess::Blit_TransferRead
+ | PipelineStageAccess::AccelerationStructureBuild_TransferRead
+ | PipelineStageAccess::AccelerationStructureCopy_TransferRead => AccessFlags::TRANSFER_READ,
+ PipelineStageAccess::Copy_TransferWrite
+ | PipelineStageAccess::Resolve_TransferWrite
+ | PipelineStageAccess::Blit_TransferWrite
+ | PipelineStageAccess::Clear_TransferWrite
+ | PipelineStageAccess::AccelerationStructureBuild_TransferWrite
+ | PipelineStageAccess::AccelerationStructureCopy_TransferWrite => AccessFlags::TRANSFER_WRITE,
+ PipelineStageAccess::Host_HostRead => AccessFlags::HOST_READ,
+ PipelineStageAccess::Host_HostWrite => AccessFlags::HOST_WRITE,
+ PipelineStageAccess::VertexShader_ShaderSampledRead
+ | PipelineStageAccess::TessellationControlShader_ShaderSampledRead
+ | PipelineStageAccess::TessellationEvaluationShader_ShaderSampledRead
+ | PipelineStageAccess::GeometryShader_ShaderSampledRead
+ | PipelineStageAccess::FragmentShader_ShaderSampledRead
+ | PipelineStageAccess::ComputeShader_ShaderSampledRead
+ | PipelineStageAccess::AccelerationStructureBuild_ShaderSampledRead
+ | PipelineStageAccess::RayTracingShader_ShaderSampledRead
+ | PipelineStageAccess::TaskShader_ShaderSampledRead
+ | PipelineStageAccess::MeshShader_ShaderSampledRead => AccessFlags::SHADER_SAMPLED_READ,
+ PipelineStageAccess::VertexShader_ShaderStorageRead
+ | PipelineStageAccess::TessellationControlShader_ShaderStorageRead
+ | PipelineStageAccess::TessellationEvaluationShader_ShaderStorageRead
+ | PipelineStageAccess::GeometryShader_ShaderStorageRead
+ | PipelineStageAccess::FragmentShader_ShaderStorageRead
+ | PipelineStageAccess::ComputeShader_ShaderStorageRead
+ | PipelineStageAccess::AccelerationStructureBuild_ShaderStorageRead
+ | PipelineStageAccess::RayTracingShader_ShaderStorageRead
+ | PipelineStageAccess::TaskShader_ShaderStorageRead
+ | PipelineStageAccess::MeshShader_ShaderStorageRead => AccessFlags::SHADER_STORAGE_READ,
+ PipelineStageAccess::VertexShader_ShaderStorageWrite
+ | PipelineStageAccess::TessellationControlShader_ShaderStorageWrite
+ | PipelineStageAccess::TessellationEvaluationShader_ShaderStorageWrite
+ | PipelineStageAccess::GeometryShader_ShaderStorageWrite
+ | PipelineStageAccess::FragmentShader_ShaderStorageWrite
+ | PipelineStageAccess::ComputeShader_ShaderStorageWrite
+ | PipelineStageAccess::RayTracingShader_ShaderStorageWrite
+ | PipelineStageAccess::TaskShader_ShaderStorageWrite
+ | PipelineStageAccess::MeshShader_ShaderStorageWrite => AccessFlags::SHADER_STORAGE_WRITE,
+ PipelineStageAccess::VideoDecode_VideoDecodeRead => AccessFlags::VIDEO_DECODE_READ,
+ PipelineStageAccess::VideoDecode_VideoDecodeWrite => AccessFlags::VIDEO_DECODE_WRITE,
+ PipelineStageAccess::VideoEncode_VideoEncodeRead => AccessFlags::VIDEO_ENCODE_READ,
+ PipelineStageAccess::VideoEncode_VideoEncodeWrite => AccessFlags::VIDEO_ENCODE_WRITE,
+ PipelineStageAccess::TransformFeedback_TransformFeedbackWrite => AccessFlags::TRANSFORM_FEEDBACK_WRITE,
+ PipelineStageAccess::DrawIndirect_TransformFeedbackCounterRead
+ | PipelineStageAccess::TransformFeedback_TransformFeedbackCounterRead => AccessFlags::TRANSFORM_FEEDBACK_COUNTER_READ,
+ PipelineStageAccess::TransformFeedback_TransformFeedbackCounterWrite => AccessFlags::TRANSFORM_FEEDBACK_COUNTER_WRITE,
+ PipelineStageAccess::ConditionalRendering_ConditionalRenderingRead => AccessFlags::CONDITIONAL_RENDERING_READ,
+ PipelineStageAccess::CommandPreprocess_CommandPreprocessRead => AccessFlags::COMMAND_PREPROCESS_READ,
+ PipelineStageAccess::CommandPreprocess_CommandPreprocessWrite => AccessFlags::COMMAND_PREPROCESS_WRITE,
+ PipelineStageAccess::FragmentShadingRateAttachment_FragmentShadingRateAttachmentRead => AccessFlags::FRAGMENT_SHADING_RATE_ATTACHMENT_READ,
+ PipelineStageAccess::VertexShader_AccelerationStructureRead
+ | PipelineStageAccess::TessellationControlShader_AccelerationStructureRead
+ | PipelineStageAccess::TessellationEvaluationShader_AccelerationStructureRead
+ | PipelineStageAccess::GeometryShader_AccelerationStructureRead
+ | PipelineStageAccess::FragmentShader_AccelerationStructureRead
+ | PipelineStageAccess::ComputeShader_AccelerationStructureRead
+ | PipelineStageAccess::AccelerationStructureBuild_AccelerationStructureRead
+ | PipelineStageAccess::RayTracingShader_AccelerationStructureRead
+ | PipelineStageAccess::TaskShader_AccelerationStructureRead
+ | PipelineStageAccess::MeshShader_AccelerationStructureRead => AccessFlags::ACCELERATION_STRUCTURE_READ,
+ PipelineStageAccess::AccelerationStructureBuild_AccelerationStructureWrite => AccessFlags::ACCELERATION_STRUCTURE_WRITE,
+ PipelineStageAccess::FragmentDensityProcess_FragmentDensityMapRead => AccessFlags::FRAGMENT_DENSITY_MAP_READ,
+ PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentReadNoncoherent => AccessFlags::COLOR_ATTACHMENT_READ_NONCOHERENT,
+ PipelineStageAccess::InvocationMask_InvocationMaskRead => AccessFlags::INVOCATION_MASK_READ,
+ PipelineStageAccess::RayTracingShader_ShaderBindingTableRead => AccessFlags::SHADER_BINDING_TABLE_READ,
+ PipelineStageAccess::AccelerationStructureBuild_MicromapRead
+ | PipelineStageAccess::MicromapBuild_MicromapRead => AccessFlags::MICROMAP_READ,
+ PipelineStageAccess::MicromapBuild_MicromapWrite => AccessFlags::MICROMAP_WRITE,
+ PipelineStageAccess::OpticalFlow_OpticalFlowRead => AccessFlags::OPTICAL_FLOW_READ,
+ PipelineStageAccess::OpticalFlow_OpticalFlowWrite => AccessFlags::OPTICAL_FLOW_WRITE,
+ PipelineStageAccess::__MAX_VALUE__ => unreachable!(),
+ }
+ }
+}
+
+#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
+pub(crate) struct PipelineStageAccessSet(u128);
+
+#[allow(dead_code)]
+impl PipelineStageAccessSet {
+ #[inline]
+ pub(crate) const fn empty() -> Self {
+ Self(0)
+ }
+
+ #[inline]
+ pub(crate) const fn count(self) -> u32 {
+ self.0.count_ones()
+ }
+
+ #[inline]
+ pub(crate) const fn is_empty(self) -> bool {
+ self.0 == 0
+ }
+
+ #[inline]
+ pub(crate) const fn intersects(self, other: Self) -> bool {
+ self.0 & other.0 != 0
+ }
+
+ #[inline]
+ pub(crate) const fn contains(self, other: Self) -> bool {
+ self.0 & other.0 == other.0
+ }
+
+ #[inline]
+ pub(crate) const fn union(self, other: Self) -> Self {
+ Self(self.0 | other.0)
+ }
+
+ #[inline]
+ pub(crate) const fn intersection(self, other: Self) -> Self {
+ Self(self.0 & other.0)
+ }
+
+ #[inline]
+ pub(crate) const fn difference(self, other: Self) -> Self {
+ Self(self.0 & !other.0)
+ }
+
+ #[inline]
+ pub(crate) const fn symmetric_difference(self, other: Self) -> Self {
+ Self(self.0 ^ other.0)
+ }
+
+ #[inline]
+ pub(crate) fn contains_enum(self, val: PipelineStageAccess) -> bool {
+ self.intersects(val.into())
+ }
+}
+
+impl std::ops::BitAnd for PipelineStageAccessSet {
+ type Output = Self;
+
+ #[inline]
+ fn bitand(self, rhs: Self) -> Self {
+ self.intersection(rhs)
+ }
+}
+
+impl std::ops::BitAndAssign for PipelineStageAccessSet {
+ #[inline]
+ fn bitand_assign(&mut self, rhs: Self) {
+ *self = self.intersection(rhs);
+ }
+}
+
+impl std::ops::BitOr for PipelineStageAccessSet {
+ type Output = Self;
+
+ #[inline]
+ fn bitor(self, rhs: Self) -> Self {
+ self.union(rhs)
+ }
+}
+
+impl std::ops::BitOrAssign for PipelineStageAccessSet {
+ #[inline]
+ fn bitor_assign(&mut self, rhs: Self) {
+ *self = self.union(rhs);
+ }
+}
+
+impl std::ops::BitXor for PipelineStageAccessSet {
+ type Output = Self;
+
+ #[inline]
+ fn bitxor(self, rhs: Self) -> Self {
+ self.symmetric_difference(rhs)
+ }
+}
+
+impl std::ops::BitXorAssign for PipelineStageAccessSet {
+ #[inline]
+ fn bitxor_assign(&mut self, rhs: Self) {
+ *self = self.symmetric_difference(rhs);
+ }
+}
+
+impl std::ops::Sub for PipelineStageAccessSet {
+ type Output = Self;
+
+ #[inline]
+ fn sub(self, rhs: Self) -> Self {
+ self.difference(rhs)
+ }
+}
+
+impl std::ops::SubAssign for PipelineStageAccessSet {
+ #[inline]
+ fn sub_assign(&mut self, rhs: Self) {
+ *self = self.difference(rhs);
+ }
+}
+
+impl From<PipelineStageAccess> for PipelineStageAccessSet {
+ #[inline]
+ fn from(val: PipelineStageAccess) -> Self {
+ debug_assert!(val != PipelineStageAccess::__MAX_VALUE__); // You did something very dumb...
+ Self(1u128 << val as u8)
+ }
+}
+
+impl From<PipelineStages> for PipelineStageAccessSet {
+ #[inline]
+ fn from(stages: PipelineStages) -> Self {
+ let mut result = Self::empty();
+
+ if stages.intersects(PipelineStages::DRAW_INDIRECT) {
+ result |= Self::from(PipelineStageAccess::DrawIndirect_IndirectCommandRead)
+ | Self::from(PipelineStageAccess::DrawIndirect_TransformFeedbackCounterRead)
+ }
+
+ if stages.intersects(PipelineStages::VERTEX_SHADER) {
+ result |= Self::from(PipelineStageAccess::VertexShader_UniformRead)
+ | Self::from(PipelineStageAccess::VertexShader_ShaderSampledRead)
+ | Self::from(PipelineStageAccess::VertexShader_ShaderStorageRead)
+ | Self::from(PipelineStageAccess::VertexShader_ShaderStorageWrite)
+ | Self::from(PipelineStageAccess::VertexShader_AccelerationStructureRead)
+ }
+
+ if stages.intersects(PipelineStages::TESSELLATION_CONTROL_SHADER) {
+ result |= Self::from(PipelineStageAccess::TessellationControlShader_UniformRead)
+ | Self::from(PipelineStageAccess::TessellationControlShader_ShaderSampledRead)
+ | Self::from(PipelineStageAccess::TessellationControlShader_ShaderStorageRead)
+ | Self::from(PipelineStageAccess::TessellationControlShader_ShaderStorageWrite)
+ | Self::from(
+ PipelineStageAccess::TessellationControlShader_AccelerationStructureRead,
+ )
+ }
+
+ if stages.intersects(PipelineStages::TESSELLATION_EVALUATION_SHADER) {
+ result |= Self::from(PipelineStageAccess::TessellationEvaluationShader_UniformRead)
+ | Self::from(PipelineStageAccess::TessellationEvaluationShader_ShaderSampledRead)
+ | Self::from(PipelineStageAccess::TessellationEvaluationShader_ShaderStorageRead)
+ | Self::from(PipelineStageAccess::TessellationEvaluationShader_ShaderStorageWrite)
+ | Self::from(
+ PipelineStageAccess::TessellationEvaluationShader_AccelerationStructureRead,
+ )
+ }
+
+ if stages.intersects(PipelineStages::GEOMETRY_SHADER) {
+ result |= Self::from(PipelineStageAccess::GeometryShader_UniformRead)
+ | Self::from(PipelineStageAccess::GeometryShader_ShaderSampledRead)
+ | Self::from(PipelineStageAccess::GeometryShader_ShaderStorageRead)
+ | Self::from(PipelineStageAccess::GeometryShader_ShaderStorageWrite)
+ | Self::from(PipelineStageAccess::GeometryShader_AccelerationStructureRead)
+ }
+
+ if stages.intersects(PipelineStages::FRAGMENT_SHADER) {
+ result |= Self::from(PipelineStageAccess::FragmentShader_UniformRead)
+ | Self::from(PipelineStageAccess::FragmentShader_InputAttachmentRead)
+ | Self::from(PipelineStageAccess::FragmentShader_ShaderSampledRead)
+ | Self::from(PipelineStageAccess::FragmentShader_ShaderStorageRead)
+ | Self::from(PipelineStageAccess::FragmentShader_ShaderStorageWrite)
+ | Self::from(PipelineStageAccess::FragmentShader_AccelerationStructureRead)
+ }
+
+ if stages.intersects(PipelineStages::EARLY_FRAGMENT_TESTS) {
+ result |= Self::from(PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentRead)
+ | Self::from(PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentWrite)
+ }
+
+ if stages.intersects(PipelineStages::LATE_FRAGMENT_TESTS) {
+ result |= Self::from(PipelineStageAccess::LateFragmentTests_DepthStencilAttachmentRead)
+ | Self::from(PipelineStageAccess::LateFragmentTests_DepthStencilAttachmentWrite)
+ }
+
+ if stages.intersects(PipelineStages::COLOR_ATTACHMENT_OUTPUT) {
+ result |= Self::from(PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentRead)
+ | Self::from(PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentWrite)
+ | Self::from(
+ PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentReadNoncoherent,
+ )
+ }
+
+ if stages.intersects(PipelineStages::COMPUTE_SHADER) {
+ result |= Self::from(PipelineStageAccess::ComputeShader_UniformRead)
+ | Self::from(PipelineStageAccess::ComputeShader_ShaderSampledRead)
+ | Self::from(PipelineStageAccess::ComputeShader_ShaderStorageRead)
+ | Self::from(PipelineStageAccess::ComputeShader_ShaderStorageWrite)
+ | Self::from(PipelineStageAccess::ComputeShader_AccelerationStructureRead)
+ }
+
+ if stages.intersects(PipelineStages::HOST) {
+ result |= Self::from(PipelineStageAccess::Host_HostRead)
+ | Self::from(PipelineStageAccess::Host_HostWrite)
+ }
+
+ if stages.intersects(PipelineStages::COPY) {
+ result |= Self::from(PipelineStageAccess::Copy_TransferRead)
+ | Self::from(PipelineStageAccess::Copy_TransferWrite)
+ }
+
+ if stages.intersects(PipelineStages::RESOLVE) {
+ result |= Self::from(PipelineStageAccess::Resolve_TransferRead)
+ | Self::from(PipelineStageAccess::Resolve_TransferWrite)
+ }
+
+ if stages.intersects(PipelineStages::BLIT) {
+ result |= Self::from(PipelineStageAccess::Blit_TransferRead)
+ | Self::from(PipelineStageAccess::Blit_TransferWrite)
+ }
+
+ if stages.intersects(PipelineStages::CLEAR) {
+ result |= Self::from(PipelineStageAccess::Clear_TransferWrite)
+ }
+
+ if stages.intersects(PipelineStages::INDEX_INPUT) {
+ result |= Self::from(PipelineStageAccess::IndexInput_IndexRead)
+ }
+
+ if stages.intersects(PipelineStages::VERTEX_ATTRIBUTE_INPUT) {
+ result |= Self::from(PipelineStageAccess::VertexAttributeInput_VertexAttributeRead)
+ }
+
+ if stages.intersects(PipelineStages::VIDEO_DECODE) {
+ result |= Self::from(PipelineStageAccess::VideoDecode_VideoDecodeRead)
+ | Self::from(PipelineStageAccess::VideoDecode_VideoDecodeWrite)
+ }
+
+ if stages.intersects(PipelineStages::VIDEO_ENCODE) {
+ result |= Self::from(PipelineStageAccess::VideoEncode_VideoEncodeRead)
+ | Self::from(PipelineStageAccess::VideoEncode_VideoEncodeWrite)
+ }
+
+ if stages.intersects(PipelineStages::TRANSFORM_FEEDBACK) {
+ result |= Self::from(PipelineStageAccess::TransformFeedback_TransformFeedbackWrite)
+ | Self::from(PipelineStageAccess::TransformFeedback_TransformFeedbackCounterRead)
+ | Self::from(PipelineStageAccess::TransformFeedback_TransformFeedbackCounterWrite)
+ }
+
+ if stages.intersects(PipelineStages::CONDITIONAL_RENDERING) {
+ result |= Self::from(PipelineStageAccess::ConditionalRendering_ConditionalRenderingRead)
+ }
+
+ if stages.intersects(PipelineStages::ACCELERATION_STRUCTURE_BUILD) {
+ result |=
+ Self::from(PipelineStageAccess::AccelerationStructureBuild_IndirectCommandRead)
+ | Self::from(PipelineStageAccess::AccelerationStructureBuild_UniformRead)
+ | Self::from(PipelineStageAccess::AccelerationStructureBuild_TransferRead)
+ | Self::from(PipelineStageAccess::AccelerationStructureBuild_TransferWrite)
+ | Self::from(PipelineStageAccess::AccelerationStructureBuild_ShaderSampledRead)
+ | Self::from(PipelineStageAccess::AccelerationStructureBuild_ShaderStorageRead)
+ | Self::from(
+ PipelineStageAccess::AccelerationStructureBuild_AccelerationStructureRead,
+ )
+ | Self::from(
+ PipelineStageAccess::AccelerationStructureBuild_AccelerationStructureWrite,
+ )
+ // | Self::from(PipelineStageAccess::AccelerationStructureBuild_MicromapRead)
+ }
+
+ if stages.intersects(PipelineStages::RAY_TRACING_SHADER) {
+ result |= Self::from(PipelineStageAccess::RayTracingShader_UniformRead)
+ | Self::from(PipelineStageAccess::RayTracingShader_ShaderSampledRead)
+ | Self::from(PipelineStageAccess::RayTracingShader_ShaderStorageRead)
+ | Self::from(PipelineStageAccess::RayTracingShader_ShaderStorageWrite)
+ | Self::from(PipelineStageAccess::RayTracingShader_AccelerationStructureRead)
+ // | Self::from(PipelineStageAccess::RayTracingShader_ShaderBindingTableRead)
+ }
+
+ if stages.intersects(PipelineStages::FRAGMENT_DENSITY_PROCESS) {
+ result |= Self::from(PipelineStageAccess::FragmentDensityProcess_FragmentDensityMapRead)
+ }
+
+ if stages.intersects(PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT) {
+ result |=
+ PipelineStageAccess::FragmentShadingRateAttachment_FragmentShadingRateAttachmentRead
+ .into()
+ }
+
+ if stages.intersects(PipelineStages::COMMAND_PREPROCESS) {
+ result |= Self::from(PipelineStageAccess::CommandPreprocess_CommandPreprocessRead)
+ | Self::from(PipelineStageAccess::CommandPreprocess_CommandPreprocessWrite)
+ }
+
+ if stages.intersects(PipelineStages::TASK_SHADER) {
+ result |= Self::from(PipelineStageAccess::TaskShader_UniformRead)
+ | Self::from(PipelineStageAccess::TaskShader_ShaderSampledRead)
+ | Self::from(PipelineStageAccess::TaskShader_ShaderStorageRead)
+ | Self::from(PipelineStageAccess::TaskShader_ShaderStorageWrite)
+ | Self::from(PipelineStageAccess::TaskShader_AccelerationStructureRead)
+ }
+
+ if stages.intersects(PipelineStages::MESH_SHADER) {
+ result |= Self::from(PipelineStageAccess::MeshShader_UniformRead)
+ | Self::from(PipelineStageAccess::MeshShader_ShaderSampledRead)
+ | Self::from(PipelineStageAccess::MeshShader_ShaderStorageRead)
+ | Self::from(PipelineStageAccess::MeshShader_ShaderStorageWrite)
+ | Self::from(PipelineStageAccess::MeshShader_AccelerationStructureRead)
+ }
+
+ if stages.intersects(PipelineStages::SUBPASS_SHADING) {
+ result |= Self::from(PipelineStageAccess::SubpassShading_InputAttachmentRead)
+ }
+
+ if stages.intersects(PipelineStages::INVOCATION_MASK) {
+ result |= Self::from(PipelineStageAccess::InvocationMask_InvocationMaskRead)
+ }
+
+ /*
+ if stages.intersects(PipelineStages::OPTICAL_FLOW) {
+ result |= Self::from(PipelineStageAccess::OpticalFlow_OpticalFlowRead)
+ | Self::from(PipelineStageAccess::OpticalFlow_OpticalFlowWrite)
+ }
+
+ if stages.intersects(PipelineStages::MICROMAP_BUILD) {
+ result |= Self::from(PipelineStageAccess::MicromapBuild_MicromapWrite)
+ | Self::from(PipelineStageAccess::MicromapBuild_MicromapRead)
+ }
+ */
+
+ result
+ }
+}
+
+impl From<AccessFlags> for PipelineStageAccessSet {
+ #[inline]
+ fn from(access: AccessFlags) -> Self {
+ let mut result = Self::empty();
+
+ if access.intersects(AccessFlags::INDIRECT_COMMAND_READ) {
+ result |= Self::from(PipelineStageAccess::DrawIndirect_IndirectCommandRead)
+ | Self::from(PipelineStageAccess::AccelerationStructureBuild_IndirectCommandRead)
+ }
+
+ if access.intersects(AccessFlags::INDEX_READ) {
+ result |= Self::from(PipelineStageAccess::IndexInput_IndexRead)
+ }
+
+ if access.intersects(AccessFlags::VERTEX_ATTRIBUTE_READ) {
+ result |= Self::from(PipelineStageAccess::VertexAttributeInput_VertexAttributeRead)
+ }
+
+ if access.intersects(AccessFlags::UNIFORM_READ) {
+ result |= Self::from(PipelineStageAccess::VertexShader_UniformRead)
+ | Self::from(PipelineStageAccess::TessellationControlShader_UniformRead)
+ | Self::from(PipelineStageAccess::TessellationEvaluationShader_UniformRead)
+ | Self::from(PipelineStageAccess::GeometryShader_UniformRead)
+ | Self::from(PipelineStageAccess::FragmentShader_UniformRead)
+ | Self::from(PipelineStageAccess::ComputeShader_UniformRead)
+ | Self::from(PipelineStageAccess::AccelerationStructureBuild_UniformRead)
+ | Self::from(PipelineStageAccess::RayTracingShader_UniformRead)
+ | Self::from(PipelineStageAccess::TaskShader_UniformRead)
+ | Self::from(PipelineStageAccess::MeshShader_UniformRead)
+ }
+
+ if access.intersects(AccessFlags::INPUT_ATTACHMENT_READ) {
+ result |= Self::from(PipelineStageAccess::FragmentShader_InputAttachmentRead)
+ | Self::from(PipelineStageAccess::SubpassShading_InputAttachmentRead)
+ }
+
+ if access.intersects(AccessFlags::COLOR_ATTACHMENT_READ) {
+ result |= Self::from(PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentRead)
+ }
+
+ if access.intersects(AccessFlags::COLOR_ATTACHMENT_WRITE) {
+ result |= Self::from(PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentWrite)
+ }
+
+ if access.intersects(AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ) {
+ result |= Self::from(PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentRead)
+ | Self::from(PipelineStageAccess::LateFragmentTests_DepthStencilAttachmentRead)
+ }
+
+ if access.intersects(AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE) {
+ result |=
+ Self::from(PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentWrite)
+ | Self::from(PipelineStageAccess::LateFragmentTests_DepthStencilAttachmentWrite)
+ }
+
+ if access.intersects(AccessFlags::TRANSFER_READ) {
+ result |= Self::from(PipelineStageAccess::Copy_TransferRead)
+ | Self::from(PipelineStageAccess::Resolve_TransferRead)
+ | Self::from(PipelineStageAccess::Blit_TransferRead)
+ | Self::from(PipelineStageAccess::AccelerationStructureBuild_TransferRead)
+ }
+
+ if access.intersects(AccessFlags::TRANSFER_WRITE) {
+ result |= Self::from(PipelineStageAccess::Copy_TransferWrite)
+ | Self::from(PipelineStageAccess::Resolve_TransferWrite)
+ | Self::from(PipelineStageAccess::Blit_TransferWrite)
+ | Self::from(PipelineStageAccess::Clear_TransferWrite)
+ | Self::from(PipelineStageAccess::AccelerationStructureBuild_TransferWrite)
+ }
+
+ if access.intersects(AccessFlags::HOST_READ) {
+ result |= Self::from(PipelineStageAccess::Host_HostRead)
+ }
+
+ if access.intersects(AccessFlags::HOST_WRITE) {
+ result |= Self::from(PipelineStageAccess::Host_HostWrite)
+ }
+
+ if access.intersects(AccessFlags::SHADER_SAMPLED_READ) {
+ result |= Self::from(PipelineStageAccess::VertexShader_ShaderSampledRead)
+ | Self::from(PipelineStageAccess::TessellationControlShader_ShaderSampledRead)
+ | Self::from(PipelineStageAccess::TessellationEvaluationShader_ShaderSampledRead)
+ | Self::from(PipelineStageAccess::GeometryShader_ShaderSampledRead)
+ | Self::from(PipelineStageAccess::FragmentShader_ShaderSampledRead)
+ | Self::from(PipelineStageAccess::ComputeShader_ShaderSampledRead)
+ | Self::from(PipelineStageAccess::AccelerationStructureBuild_ShaderSampledRead)
+ | Self::from(PipelineStageAccess::RayTracingShader_ShaderSampledRead)
+ | Self::from(PipelineStageAccess::TaskShader_ShaderSampledRead)
+ | Self::from(PipelineStageAccess::MeshShader_ShaderSampledRead)
+ }
+
+ if access.intersects(AccessFlags::SHADER_STORAGE_READ) {
+ result |= Self::from(PipelineStageAccess::VertexShader_ShaderStorageRead)
+ | Self::from(PipelineStageAccess::TessellationControlShader_ShaderStorageRead)
+ | Self::from(PipelineStageAccess::TessellationEvaluationShader_ShaderStorageRead)
+ | Self::from(PipelineStageAccess::GeometryShader_ShaderStorageRead)
+ | Self::from(PipelineStageAccess::FragmentShader_ShaderStorageRead)
+ | Self::from(PipelineStageAccess::ComputeShader_ShaderStorageRead)
+ | Self::from(PipelineStageAccess::AccelerationStructureBuild_ShaderStorageRead)
+ | Self::from(PipelineStageAccess::RayTracingShader_ShaderStorageRead)
+ | Self::from(PipelineStageAccess::TaskShader_ShaderStorageRead)
+ | Self::from(PipelineStageAccess::MeshShader_ShaderStorageRead)
+ }
+
+ if access.intersects(AccessFlags::SHADER_STORAGE_WRITE) {
+ result |= Self::from(PipelineStageAccess::VertexShader_ShaderStorageWrite)
+ | Self::from(PipelineStageAccess::TessellationControlShader_ShaderStorageWrite)
+ | Self::from(PipelineStageAccess::TessellationEvaluationShader_ShaderStorageWrite)
+ | Self::from(PipelineStageAccess::GeometryShader_ShaderStorageWrite)
+ | Self::from(PipelineStageAccess::FragmentShader_ShaderStorageWrite)
+ | Self::from(PipelineStageAccess::ComputeShader_ShaderStorageWrite)
+ | Self::from(PipelineStageAccess::RayTracingShader_ShaderStorageWrite)
+ | Self::from(PipelineStageAccess::TaskShader_ShaderStorageWrite)
+ | Self::from(PipelineStageAccess::MeshShader_ShaderStorageWrite)
+ }
+
+ if access.intersects(AccessFlags::VIDEO_DECODE_READ) {
+ result |= Self::from(PipelineStageAccess::VideoDecode_VideoDecodeRead)
+ }
+
+ if access.intersects(AccessFlags::VIDEO_DECODE_WRITE) {
+ result |= Self::from(PipelineStageAccess::VideoDecode_VideoDecodeWrite)
+ }
+
+ if access.intersects(AccessFlags::VIDEO_ENCODE_READ) {
+ result |= Self::from(PipelineStageAccess::VideoEncode_VideoEncodeRead)
+ }
+
+ if access.intersects(AccessFlags::VIDEO_ENCODE_WRITE) {
+ result |= Self::from(PipelineStageAccess::VideoEncode_VideoEncodeWrite)
+ }
+
+ if access.intersects(AccessFlags::TRANSFORM_FEEDBACK_WRITE) {
+ result |= Self::from(PipelineStageAccess::TransformFeedback_TransformFeedbackWrite)
+ }
+
+ if access.intersects(AccessFlags::TRANSFORM_FEEDBACK_COUNTER_READ) {
+ result |= Self::from(PipelineStageAccess::DrawIndirect_TransformFeedbackCounterRead)
+ | Self::from(PipelineStageAccess::TransformFeedback_TransformFeedbackCounterRead)
+ }
+
+ if access.intersects(AccessFlags::TRANSFORM_FEEDBACK_COUNTER_WRITE) {
+ result |=
+ Self::from(PipelineStageAccess::TransformFeedback_TransformFeedbackCounterWrite)
+ }
+
+ if access.intersects(AccessFlags::CONDITIONAL_RENDERING_READ) {
+ result |= Self::from(PipelineStageAccess::ConditionalRendering_ConditionalRenderingRead)
+ }
+
+ if access.intersects(AccessFlags::COMMAND_PREPROCESS_READ) {
+ result |= Self::from(PipelineStageAccess::CommandPreprocess_CommandPreprocessRead)
+ }
+
+ if access.intersects(AccessFlags::COMMAND_PREPROCESS_WRITE) {
+ result |= Self::from(PipelineStageAccess::CommandPreprocess_CommandPreprocessWrite)
+ }
+
+ if access.intersects(AccessFlags::FRAGMENT_SHADING_RATE_ATTACHMENT_READ) {
+ result |=
+ Self::from(PipelineStageAccess::FragmentShadingRateAttachment_FragmentShadingRateAttachmentRead)
+ }
+
+ if access.intersects(AccessFlags::ACCELERATION_STRUCTURE_READ) {
+ result |= Self::from(PipelineStageAccess::VertexShader_AccelerationStructureRead)
+ | Self::from(
+ PipelineStageAccess::TessellationControlShader_AccelerationStructureRead,
+ )
+ | Self::from(
+ PipelineStageAccess::TessellationEvaluationShader_AccelerationStructureRead,
+ )
+ | Self::from(PipelineStageAccess::GeometryShader_AccelerationStructureRead)
+ | Self::from(PipelineStageAccess::FragmentShader_AccelerationStructureRead)
+ | Self::from(PipelineStageAccess::ComputeShader_AccelerationStructureRead)
+ | Self::from(
+ PipelineStageAccess::AccelerationStructureBuild_AccelerationStructureRead,
+ )
+ | Self::from(PipelineStageAccess::RayTracingShader_AccelerationStructureRead)
+ | Self::from(PipelineStageAccess::TaskShader_AccelerationStructureRead)
+ | Self::from(PipelineStageAccess::MeshShader_AccelerationStructureRead)
+ }
+
+ if access.intersects(AccessFlags::ACCELERATION_STRUCTURE_WRITE) {
+ result |= Self::from(
+ PipelineStageAccess::AccelerationStructureBuild_AccelerationStructureWrite,
+ )
+ }
+
+ if access.intersects(AccessFlags::FRAGMENT_DENSITY_MAP_READ) {
+ result |= Self::from(PipelineStageAccess::FragmentDensityProcess_FragmentDensityMapRead)
+ }
+
+ if access.intersects(AccessFlags::COLOR_ATTACHMENT_READ_NONCOHERENT) {
+ result |= Self::from(
+ PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentReadNoncoherent,
+ )
+ }
+
+ if access.intersects(AccessFlags::INVOCATION_MASK_READ) {
+ result |= Self::from(PipelineStageAccess::InvocationMask_InvocationMaskRead)
+ }
+
+ /*
+ if access.intersects(AccessFlags::SHADER_BINDING_TABLE_READ) {
+ result |= Self::from(PipelineStageAccess::RayTracingShader_ShaderBindingTableRead)
+ }
+
+ if access.intersects(AccessFlags::MICROMAP_READ) {
+ result |= Self::from(PipelineStageAccess::AccelerationStructureBuild_MicromapRead)
+ | Self::from(PipelineStageAccess::MicromapBuild_MicromapRead)
+ }
+
+ if access.intersects(AccessFlags::MICROMAP_WRITE) {
+ result |= Self::from(PipelineStageAccess::MicromapBuild_MicromapWrite)
+ }
+
+ if access.intersects(AccessFlags::OPTICAL_FLOW_READ) {
+ result |= Self::from(PipelineStageAccess::OpticalFlow_OpticalFlowRead)
+ }
+
+ if access.intersects(AccessFlags::OPTICAL_FLOW_WRITE) {
+ result |= Self::from(PipelineStageAccess::OpticalFlow_OpticalFlowWrite)
+ }
+ */
+
+ result
+ }
+}
+
+/// Dependency info for barriers in a pipeline barrier or event command.
+///
+/// A pipeline barrier creates a dependency between commands submitted before the barrier (the
+/// source scope) and commands submitted after it (the destination scope). An event command acts
+/// like a split pipeline barrier: the source scope and destination scope are defined
+/// relative to different commands. Each `DependencyInfo` consists of multiple individual barriers
+/// that concern a either single resource or operate globally.
+///
+/// Each barrier has a set of source/destination pipeline stages and source/destination memory
+/// access types. The pipeline stages create an *execution dependency*: the `src_stages` of
+/// commands submitted before the barrier must be completely finished before before any of the
+/// `dst_stages` of commands after the barrier are allowed to start. The memory access types
+/// create a *memory dependency*: in addition to the execution dependency, any `src_access`
+/// performed before the barrier must be made available and visible before any `dst_access`
+/// are made after the barrier.
+#[derive(Clone, Debug)]
+pub struct DependencyInfo {
+ /// Flags to modify how the execution and memory dependencies are formed.
+ ///
+ /// The default value is empty.
+ pub dependency_flags: DependencyFlags,
+
+ /// Memory barriers for global operations and accesses, not limited to a single resource.
+ ///
+ /// The default value is empty.
+ pub memory_barriers: SmallVec<[MemoryBarrier; 2]>,
+
+ /// Memory barriers for individual buffers.
+ ///
+ /// The default value is empty.
+ pub buffer_memory_barriers: SmallVec<[BufferMemoryBarrier; 8]>,
+
+ /// Memory barriers for individual images.
+ ///
+ /// The default value is empty.
+ pub image_memory_barriers: SmallVec<[ImageMemoryBarrier; 8]>,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl DependencyInfo {
+ /// Returns whether `self` contains any barriers.
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.memory_barriers.is_empty()
+ && self.buffer_memory_barriers.is_empty()
+ && self.image_memory_barriers.is_empty()
+ }
+
+ /// Clears all barriers.
+ #[inline]
+ pub fn clear(&mut self) {
+ self.memory_barriers.clear();
+ self.buffer_memory_barriers.clear();
+ self.image_memory_barriers.clear();
+ }
+}
+
+impl Default for DependencyInfo {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ dependency_flags: DependencyFlags::empty(),
+ memory_barriers: SmallVec::new(),
+ buffer_memory_barriers: SmallVec::new(),
+ image_memory_barriers: SmallVec::new(),
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+vulkan_bitflags! {
+ #[non_exhaustive]
+
+ /// Flags that modify how execution and memory dependencies are formed.
+ DependencyFlags = DependencyFlags(u32);
+
+ /// For framebuffer-space pipeline stages, specifies that the dependency is framebuffer-local.
+ /// The implementation can start the destination operation for some given pixels as long as the
+ /// source operation is finished for these given pixels.
+ ///
+ /// Framebuffer-local dependencies are usually more efficient, especially on tile-based
+ /// architectures.
+ BY_REGION = BY_REGION,
+
+ /// For devices that consist of multiple physical devices, specifies that the dependency is
+ /// device-local. The dependency will only apply to the operations on each physical device
+ /// individually, rather than applying to all physical devices as a whole. This allows each
+ /// physical device to operate independently of the others.
+ ///
+ /// The device API version must be at least 1.1, or the [`khr_device_group`] extension must be
+ /// enabled on the device.
+ ///
+ /// [`khr_device_group`]: crate::device::DeviceExtensions::khr_device_group
+ DEVICE_GROUP = DEVICE_GROUP {
+ api_version: V1_1,
+ device_extensions: [khr_device_group],
+ },
+
+
+ /// For subpass dependencies, and pipeline barriers executing within a render pass instance,
+ /// if the render pass uses multiview rendering, specifies that the dependency is view-local.
+ /// Each view in the destination subpass will only depend on a single view in the destination
+ /// subpass, instead of all views.
+ ///
+ /// The device API version must be at least 1.1, or the [`khr_multiview`] extension must be
+ /// enabled on the device.
+ ///
+ /// [`khr_multiview`]: crate::device::DeviceExtensions::khr_multiview
+ VIEW_LOCAL = VIEW_LOCAL {
+ api_version: V1_1,
+ device_extensions: [khr_multiview],
+ },
+}
+
+/// A memory barrier that is applied globally.
+#[derive(Clone, Debug)]
+pub struct MemoryBarrier {
+ /// The pipeline stages in the source scope to wait for.
+ ///
+ /// The default value is [`PipelineStages::empty()`].
+ pub src_stages: PipelineStages,
+
+ /// The memory accesses in the source scope to make available and visible.
+ ///
+ /// The default value is [`AccessFlags::empty()`].
+ pub src_access: AccessFlags,
+
+ /// The pipeline stages in the destination scope that must wait for `src_stages`.
+ ///
+ /// The default value is [`PipelineStages::empty()`].
+ pub dst_stages: PipelineStages,
+
+ /// The memory accesses in the destination scope that must wait for `src_access` to be made
+ /// available and visible.
+ pub dst_access: AccessFlags,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for MemoryBarrier {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ src_stages: PipelineStages::empty(),
+ src_access: AccessFlags::empty(),
+ dst_stages: PipelineStages::empty(),
+ dst_access: AccessFlags::empty(),
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// A memory barrier that is applied to a single buffer.
+#[derive(Clone, Debug)]
+pub struct BufferMemoryBarrier {
+ /// The pipeline stages in the source scope to wait for.
+ ///
+ /// The default value is [`PipelineStages::empty()`].
+ pub src_stages: PipelineStages,
+
+ /// The memory accesses in the source scope to make available and visible.
+ ///
+ /// The default value is [`AccessFlags::empty()`].
+ pub src_access: AccessFlags,
+
+ /// The pipeline stages in the destination scope that must wait for `src_stages`.
+ ///
+ /// The default value is [`PipelineStages::empty()`].
+ pub dst_stages: PipelineStages,
+
+ /// The memory accesses in the destination scope that must wait for `src_access` to be made
+ /// available and visible.
+ pub dst_access: AccessFlags,
+
+ /// For resources created with [`Sharing::Exclusive`](crate::sync::Sharing), transfers
+ /// ownership of a resource from one queue family to another.
+ pub queue_family_ownership_transfer: Option<QueueFamilyOwnershipTransfer>,
+
+ /// The buffer to apply the barrier to.
+ pub buffer: Arc<Buffer>,
+
+ /// The byte range of `buffer` to apply the barrier to.
+ pub range: Range<DeviceSize>,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl BufferMemoryBarrier {
+ #[inline]
+ pub fn buffer(buffer: Arc<Buffer>) -> Self {
+ Self {
+ src_stages: PipelineStages::empty(),
+ src_access: AccessFlags::empty(),
+ dst_stages: PipelineStages::empty(),
+ dst_access: AccessFlags::empty(),
+ queue_family_ownership_transfer: None,
+ buffer,
+ range: 0..0,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// A memory barrier that is applied to a single image.
+#[derive(Clone, Debug)]
+pub struct ImageMemoryBarrier {
+ /// The pipeline stages in the source scope to wait for.
+ ///
+ /// The default value is [`PipelineStages::empty()`].
+ pub src_stages: PipelineStages,
+
+ /// The memory accesses in the source scope to make available and visible.
+ ///
+ /// The default value is [`AccessFlags::empty()`].
+ pub src_access: AccessFlags,
+
+ /// The pipeline stages in the destination scope that must wait for `src_stages`.
+ ///
+ /// The default value is [`PipelineStages::empty()`].
+ pub dst_stages: PipelineStages,
+
+ /// The memory accesses in the destination scope that must wait for `src_access` to be made
+ /// available and visible.
+ pub dst_access: AccessFlags,
+
+ /// The layout that the specified `subresource_range` of `image` is expected to be in when the
+ /// source scope completes.
+ pub old_layout: ImageLayout,
+
+ /// The layout that the specified `subresource_range` of `image` will be transitioned to before
+ /// the destination scope begins.
+ pub new_layout: ImageLayout,
+
+ /// For resources created with [`Sharing::Exclusive`](crate::sync::Sharing), transfers
+ /// ownership of a resource from one queue family to another.
+ pub queue_family_ownership_transfer: Option<QueueFamilyOwnershipTransfer>,
+
+ /// The image to apply the barrier to.
+ pub image: Arc<Image>,
+
+ /// The subresource range of `image` to apply the barrier to.
+ pub subresource_range: ImageSubresourceRange,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl ImageMemoryBarrier {
+ #[inline]
+ pub fn image(image: Arc<Image>) -> Self {
+ Self {
+ src_stages: PipelineStages::empty(),
+ src_access: AccessFlags::empty(),
+ dst_stages: PipelineStages::empty(),
+ dst_access: AccessFlags::empty(),
+ old_layout: ImageLayout::Undefined,
+ new_layout: ImageLayout::Undefined,
+ queue_family_ownership_transfer: None,
+ image,
+ subresource_range: ImageSubresourceRange {
+ aspects: ImageAspects::empty(), // Can't use image format aspects because `color` can't be specified with `planeN`.
+ mip_levels: 0..0,
+ array_layers: 0..0,
+ },
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// Specifies a queue family ownership transfer for a resource.
+///
+/// There are three classes of queues that can be used in an ownership transfer:
+/// - A **local** queue exists on the current [`Instance`] and [`Device`].
+/// - An **external** queue does not exist on the current [`Instance`], but has the same
+/// [`device_uuid`] and [`driver_uuid`] as the current [`Device`].
+/// - A **foreign** queue can be an external queue, or any queue on another device for which the
+/// mentioned parameters do not match.
+///
+/// [`Instance`]: crate::instance::Instance
+/// [`Device`]: crate::device::Device
+/// [`device_uuid`]: crate::device::Properties::device_uuid
+/// [`driver_uuid`]: crate::device::Properties::driver_uuid
+#[derive(Clone, Copy, Debug)]
+pub enum QueueFamilyOwnershipTransfer {
+ /// For a resource with [`Sharing::Exclusive`], transfers ownership between two local queues.
+ ///
+ /// [`Sharing::Exclusive`]: crate::sync::Sharing::Exclusive
+ ExclusiveBetweenLocal {
+ /// The queue family that currently owns the resource.
+ src_index: u32,
+
+ /// The queue family to transfer ownership to.
+ dst_index: u32,
+ },
+
+ /// For a resource with [`Sharing::Exclusive`], transfers ownership from a local queue to an
+ /// external queue.
+ ///
+ /// The device API version must be at least 1.1, or the [`khr_external_memory`] extension must
+ /// be enabled on the device.
+ ///
+ /// [`Sharing::Exclusive`]: crate::sync::Sharing::Exclusive
+ /// [`khr_external_memory`]: crate::device::DeviceExtensions::khr_external_memory
+ ExclusiveToExternal {
+ /// The queue family that currently owns the resource.
+ src_index: u32,
+ },
+
+ /// For a resource with [`Sharing::Exclusive`], transfers ownership from an external queue to a
+ /// local queue.
+ ///
+ /// The device API version must be at least 1.1, or the [`khr_external_memory`] extension must
+ /// be enabled on the device.
+ ///
+ /// [`Sharing::Exclusive`]: crate::sync::Sharing::Exclusive
+ /// [`khr_external_memory`]: crate::device::DeviceExtensions::khr_external_memory
+ ExclusiveFromExternal {
+ /// The queue family to transfer ownership to.
+ dst_index: u32,
+ },
+
+ /// For a resource with [`Sharing::Exclusive`], transfers ownership from a local queue to a
+ /// foreign queue.
+ ///
+ /// The [`ext_queue_family_foreign`] extension must be enabled on the device.
+ ///
+ /// [`Sharing::Exclusive`]: crate::sync::Sharing::Exclusive
+ /// [`ext_queue_family_foreign`]: crate::device::DeviceExtensions::ext_queue_family_foreign
+ ExclusiveToForeign {
+ /// The queue family that currently owns the resource.
+ src_index: u32,
+ },
+
+ /// For a resource with [`Sharing::Exclusive`], transfers ownership from a foreign queue to a
+ /// local queue.
+ ///
+ /// The [`ext_queue_family_foreign`] extension must be enabled on the device.
+ ///
+ /// [`Sharing::Exclusive`]: crate::sync::Sharing::Exclusive
+ /// [`ext_queue_family_foreign`]: crate::device::DeviceExtensions::ext_queue_family_foreign
+ ExclusiveFromForeign {
+ /// The queue family to transfer ownership to.
+ dst_index: u32,
+ },
+
+ /// For a resource with [`Sharing::Concurrent`], transfers ownership from its local queues to
+ /// an external queue.
+ ///
+ /// The device API version must be at least 1.1, or the [`khr_external_memory`] extension must
+ /// be enabled on the device.
+ ///
+ /// [`Sharing::Concurrent`]: crate::sync::Sharing::Concurrent
+ /// [`khr_external_memory`]: crate::device::DeviceExtensions::khr_external_memory
+ ConcurrentToExternal,
+
+ /// For a resource with [`Sharing::Concurrent`], transfers ownership from an external queue to
+ /// its local queues.
+ ///
+ /// The device API version must be at least 1.1, or the [`khr_external_memory`] extension must
+ /// be enabled on the device.
+ ///
+ /// [`Sharing::Concurrent`]: crate::sync::Sharing::Concurrent
+ /// [`khr_external_memory`]: crate::device::DeviceExtensions::khr_external_memory
+ ConcurrentFromExternal,
+
+ /// For a resource with [`Sharing::Concurrent`], transfers ownership from its local queues to
+ /// a foreign queue.
+ ///
+ /// The [`ext_queue_family_foreign`] extension must be enabled on the device.
+ ///
+ /// [`Sharing::Concurrent`]: crate::sync::Sharing::Concurrent
+ /// [`ext_queue_family_foreign`]: crate::device::DeviceExtensions::ext_queue_family_foreign
+ ConcurrentToForeign,
+
+ /// For a resource with [`Sharing::Concurrent`], transfers ownership from a foreign queue to
+ /// its local queues.
+ ///
+ /// The [`ext_queue_family_foreign`] extension must be enabled on the device.
+ ///
+ /// [`Sharing::Concurrent`]: crate::sync::Sharing::Concurrent
+ /// [`ext_queue_family_foreign`]: crate::device::DeviceExtensions::ext_queue_family_foreign
+ ConcurrentFromForeign,
+}
+
+impl QueueFamilyOwnershipTransfer {
+ pub(crate) fn validate_device(self, device: &Device) -> Result<(), RequirementNotMet> {
+ match self {
+ QueueFamilyOwnershipTransfer::ExclusiveToExternal { .. } => {
+ if !(device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_external_memory)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`QueueFamilyOwnershipTransfer::ExclusiveToExternal",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(Version::V1_1),
+ device_extensions: &["khr_external_memory"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ QueueFamilyOwnershipTransfer::ExclusiveFromExternal { .. } => {
+ if !(device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_external_memory)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`QueueFamilyOwnershipTransfer::ExclusiveFromExternal",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(Version::V1_1),
+ device_extensions: &["khr_external_memory"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ QueueFamilyOwnershipTransfer::ExclusiveToForeign { .. } => {
+ if !device.enabled_extensions().ext_queue_family_foreign {
+ return Err(crate::RequirementNotMet {
+ required_for: "`QueueFamilyOwnershipTransfer::ExclusiveToForeign",
+ requires_one_of: crate::RequiresOneOf {
+ device_extensions: &["ext_queue_family_foreign"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ QueueFamilyOwnershipTransfer::ExclusiveFromForeign { .. } => {
+ if !device.enabled_extensions().ext_queue_family_foreign {
+ return Err(crate::RequirementNotMet {
+ required_for: "`QueueFamilyOwnershipTransfer::ExclusiveFromForeign",
+ requires_one_of: crate::RequiresOneOf {
+ device_extensions: &["ext_queue_family_foreign"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ QueueFamilyOwnershipTransfer::ConcurrentToExternal => {
+ if !(device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_external_memory)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`QueueFamilyOwnershipTransfer::ConcurrentToExternal",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(Version::V1_1),
+ device_extensions: &["khr_external_memory"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ QueueFamilyOwnershipTransfer::ConcurrentFromExternal => {
+ if !(device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_external_memory)
+ {
+ return Err(crate::RequirementNotMet {
+ required_for: "`QueueFamilyOwnershipTransfer::ConcurrentFromExternal",
+ requires_one_of: crate::RequiresOneOf {
+ api_version: Some(Version::V1_1),
+ device_extensions: &["khr_external_memory"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ QueueFamilyOwnershipTransfer::ConcurrentToForeign => {
+ if !device.enabled_extensions().ext_queue_family_foreign {
+ return Err(crate::RequirementNotMet {
+ required_for: "`QueueFamilyOwnershipTransfer::ConcurrentToForeign",
+ requires_one_of: crate::RequiresOneOf {
+ device_extensions: &["ext_queue_family_foreign"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ QueueFamilyOwnershipTransfer::ConcurrentFromForeign => {
+ if !device.enabled_extensions().ext_queue_family_foreign {
+ return Err(crate::RequirementNotMet {
+ required_for: "`QueueFamilyOwnershipTransfer::ConcurrentFromForeign",
+ requires_one_of: crate::RequiresOneOf {
+ device_extensions: &["ext_queue_family_foreign"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+ _ => (),
+ }
+
+ Ok(())
+ }
+}
+
+impl From<QueueFamilyOwnershipTransfer> for (u32, u32) {
+ fn from(val: QueueFamilyOwnershipTransfer) -> Self {
+ match val {
+ QueueFamilyOwnershipTransfer::ExclusiveBetweenLocal {
+ src_index,
+ dst_index,
+ } => (src_index, dst_index),
+ QueueFamilyOwnershipTransfer::ExclusiveToExternal { src_index } => {
+ (src_index, ash::vk::QUEUE_FAMILY_EXTERNAL)
+ }
+ QueueFamilyOwnershipTransfer::ExclusiveFromExternal { dst_index } => {
+ (ash::vk::QUEUE_FAMILY_EXTERNAL, dst_index)
+ }
+ QueueFamilyOwnershipTransfer::ExclusiveToForeign { src_index } => {
+ (src_index, ash::vk::QUEUE_FAMILY_FOREIGN_EXT)
+ }
+ QueueFamilyOwnershipTransfer::ExclusiveFromForeign { dst_index } => {
+ (ash::vk::QUEUE_FAMILY_FOREIGN_EXT, dst_index)
+ }
+ QueueFamilyOwnershipTransfer::ConcurrentToExternal => (
+ ash::vk::QUEUE_FAMILY_IGNORED,
+ ash::vk::QUEUE_FAMILY_EXTERNAL,
+ ),
+ QueueFamilyOwnershipTransfer::ConcurrentFromExternal => (
+ ash::vk::QUEUE_FAMILY_EXTERNAL,
+ ash::vk::QUEUE_FAMILY_IGNORED,
+ ),
+ QueueFamilyOwnershipTransfer::ConcurrentToForeign => (
+ ash::vk::QUEUE_FAMILY_IGNORED,
+ ash::vk::QUEUE_FAMILY_FOREIGN_EXT,
+ ),
+ QueueFamilyOwnershipTransfer::ConcurrentFromForeign => (
+ ash::vk::QUEUE_FAMILY_FOREIGN_EXT,
+ ash::vk::QUEUE_FAMILY_IGNORED,
+ ),
+ }
+ }
+}
diff --git a/src/sync/semaphore.rs b/src/sync/semaphore.rs
new file mode 100644
index 0000000..ac0ca56
--- /dev/null
+++ b/src/sync/semaphore.rs
@@ -0,0 +1,1667 @@
+// Copyright (c) 2016 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+//! A semaphore provides synchronization between multiple queues, with non-command buffer
+//! commands on the same queue, or between the device and an external source.
+
+use crate::{
+ device::{Device, DeviceOwned, Queue},
+ macros::{impl_id_counter, vulkan_bitflags, vulkan_bitflags_enum},
+ OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject,
+};
+use parking_lot::{Mutex, MutexGuard};
+#[cfg(unix)]
+use std::fs::File;
+use std::{
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+ mem::MaybeUninit,
+ num::NonZeroU64,
+ ptr,
+ sync::{Arc, Weak},
+};
+
+/// Used to provide synchronization between command buffers during their execution.
+///
+/// It is similar to a fence, except that it is purely on the GPU side. The CPU can't query a
+/// semaphore's status or wait for it to be signaled.
+#[derive(Debug)]
+pub struct Semaphore {
+ handle: ash::vk::Semaphore,
+ device: Arc<Device>,
+ id: NonZeroU64,
+ must_put_in_pool: bool,
+
+ export_handle_types: ExternalSemaphoreHandleTypes,
+
+ state: Mutex<SemaphoreState>,
+}
+
+impl Semaphore {
+ /// Creates a new `Semaphore`.
+ #[inline]
+ pub fn new(
+ device: Arc<Device>,
+ create_info: SemaphoreCreateInfo,
+ ) -> Result<Semaphore, SemaphoreError> {
+ Self::validate_new(&device, &create_info)?;
+
+ unsafe { Ok(Self::new_unchecked(device, create_info)?) }
+ }
+
+ fn validate_new(
+ device: &Device,
+ create_info: &SemaphoreCreateInfo,
+ ) -> Result<(), SemaphoreError> {
+ let &SemaphoreCreateInfo {
+ export_handle_types,
+ _ne: _,
+ } = create_info;
+
+ if !export_handle_types.is_empty() {
+ if !(device.api_version() >= Version::V1_1
+ || device.enabled_extensions().khr_external_semaphore)
+ {
+ return Err(SemaphoreError::RequirementNotMet {
+ required_for: "`create_info.export_handle_types` is not empty",
+ requires_one_of: RequiresOneOf {
+ api_version: Some(Version::V1_1),
+ device_extensions: &["khr_external_semaphore"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkExportSemaphoreCreateInfo-handleTypes-parameter
+ export_handle_types.validate_device(device)?;
+
+ // VUID-VkExportSemaphoreCreateInfo-handleTypes-01124
+ for handle_type in export_handle_types.into_iter() {
+ let external_semaphore_properties = unsafe {
+ device
+ .physical_device()
+ .external_semaphore_properties_unchecked(
+ ExternalSemaphoreInfo::handle_type(handle_type),
+ )
+ };
+
+ if !external_semaphore_properties.exportable {
+ return Err(SemaphoreError::HandleTypeNotExportable { handle_type });
+ }
+
+ if !external_semaphore_properties
+ .compatible_handle_types
+ .contains(export_handle_types)
+ {
+ return Err(SemaphoreError::ExportHandleTypesNotCompatible);
+ }
+ }
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ #[inline]
+ pub unsafe fn new_unchecked(
+ device: Arc<Device>,
+ create_info: SemaphoreCreateInfo,
+ ) -> Result<Semaphore, VulkanError> {
+ let SemaphoreCreateInfo {
+ export_handle_types,
+ _ne: _,
+ } = create_info;
+
+ let mut create_info_vk = ash::vk::SemaphoreCreateInfo {
+ flags: ash::vk::SemaphoreCreateFlags::empty(),
+ ..Default::default()
+ };
+ let mut export_semaphore_create_info_vk = None;
+
+ if !export_handle_types.is_empty() {
+ let _ = export_semaphore_create_info_vk.insert(ash::vk::ExportSemaphoreCreateInfo {
+ handle_types: export_handle_types.into(),
+ ..Default::default()
+ });
+ };
+
+ if let Some(info) = export_semaphore_create_info_vk.as_mut() {
+ info.p_next = create_info_vk.p_next;
+ create_info_vk.p_next = info as *const _ as *const _;
+ }
+
+ let handle = {
+ let fns = device.fns();
+ let mut output = MaybeUninit::uninit();
+ (fns.v1_0.create_semaphore)(
+ device.handle(),
+ &create_info_vk,
+ ptr::null(),
+ output.as_mut_ptr(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+ output.assume_init()
+ };
+
+ Ok(Semaphore {
+ handle,
+ device,
+ id: Self::next_id(),
+ must_put_in_pool: false,
+ export_handle_types,
+ state: Mutex::new(Default::default()),
+ })
+ }
+
+ /// Takes a semaphore from the vulkano-provided semaphore pool.
+ /// If the pool is empty, a new semaphore will be allocated.
+ /// Upon `drop`, the semaphore is put back into the pool.
+ ///
+ /// For most applications, using the pool should be preferred,
+ /// in order to avoid creating new semaphores every frame.
+ #[inline]
+ pub fn from_pool(device: Arc<Device>) -> Result<Semaphore, SemaphoreError> {
+ let handle = device.semaphore_pool().lock().pop();
+ let semaphore = match handle {
+ Some(handle) => Semaphore {
+ handle,
+ device,
+ id: Self::next_id(),
+ must_put_in_pool: true,
+ export_handle_types: ExternalSemaphoreHandleTypes::empty(),
+ state: Mutex::new(Default::default()),
+ },
+ None => {
+ // Pool is empty, alloc new semaphore
+ let mut semaphore = Semaphore::new(device, Default::default())?;
+ semaphore.must_put_in_pool = true;
+ semaphore
+ }
+ };
+
+ Ok(semaphore)
+ }
+
+ /// Creates a new `Semaphore` from a raw object handle.
+ ///
+ /// # Safety
+ ///
+ /// - `handle` must be a valid Vulkan object handle created from `device`.
+ /// - `create_info` must match the info used to create the object.
+ #[inline]
+ pub unsafe fn from_handle(
+ device: Arc<Device>,
+ handle: ash::vk::Semaphore,
+ create_info: SemaphoreCreateInfo,
+ ) -> Semaphore {
+ let SemaphoreCreateInfo {
+ export_handle_types,
+ _ne: _,
+ } = create_info;
+
+ Semaphore {
+ handle,
+ device,
+ id: Self::next_id(),
+ must_put_in_pool: false,
+ export_handle_types,
+ state: Mutex::new(Default::default()),
+ }
+ }
+
+ /// Exports the semaphore into a POSIX file descriptor. The caller owns the returned `File`.
+ #[cfg(unix)]
+ #[inline]
+ pub fn export_fd(
+ &self,
+ handle_type: ExternalSemaphoreHandleType,
+ ) -> Result<File, SemaphoreError> {
+ let mut state = self.state.lock();
+ self.validate_export_fd(handle_type, &state)?;
+
+ unsafe { Ok(self.export_fd_unchecked_locked(handle_type, &mut state)?) }
+ }
+
+ #[cfg(unix)]
+ fn validate_export_fd(
+ &self,
+ handle_type: ExternalSemaphoreHandleType,
+ state: &SemaphoreState,
+ ) -> Result<(), SemaphoreError> {
+ if !self.device.enabled_extensions().khr_external_semaphore_fd {
+ return Err(SemaphoreError::RequirementNotMet {
+ required_for: "`Semaphore::export_fd`",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["khr_external_semaphore_fd"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkSemaphoreGetFdInfoKHR-handleType-parameter
+ handle_type.validate_device(&self.device)?;
+
+ // VUID-VkSemaphoreGetFdInfoKHR-handleType-01132
+ if !self.export_handle_types.intersects(handle_type.into()) {
+ return Err(SemaphoreError::HandleTypeNotEnabled);
+ }
+
+ // VUID-VkSemaphoreGetFdInfoKHR-semaphore-01133
+ if let Some(imported_handle_type) = state.current_import {
+ match imported_handle_type {
+ ImportType::SwapchainAcquire => {
+ return Err(SemaphoreError::ImportedForSwapchainAcquire)
+ }
+ ImportType::ExternalSemaphore(imported_handle_type) => {
+ let external_semaphore_properties = unsafe {
+ self.device
+ .physical_device()
+ .external_semaphore_properties_unchecked(
+ ExternalSemaphoreInfo::handle_type(handle_type),
+ )
+ };
+
+ if !external_semaphore_properties
+ .export_from_imported_handle_types
+ .intersects(imported_handle_type.into())
+ {
+ return Err(SemaphoreError::ExportFromImportedNotSupported {
+ imported_handle_type,
+ });
+ }
+ }
+ }
+ }
+
+ if handle_type.has_copy_transference() {
+ // VUID-VkSemaphoreGetFdInfoKHR-handleType-01134
+ if state.is_wait_pending() {
+ return Err(SemaphoreError::QueueIsWaiting);
+ }
+
+ // VUID-VkSemaphoreGetFdInfoKHR-handleType-01135
+ // VUID-VkSemaphoreGetFdInfoKHR-handleType-03254
+ if !(state.is_signaled().unwrap_or(false) || state.is_signal_pending()) {
+ return Err(SemaphoreError::HandleTypeCopyNotSignaled);
+ }
+ }
+
+ // VUID-VkSemaphoreGetFdInfoKHR-handleType-01136
+ if !matches!(
+ handle_type,
+ ExternalSemaphoreHandleType::OpaqueFd | ExternalSemaphoreHandleType::SyncFd
+ ) {
+ return Err(SemaphoreError::HandleTypeNotFd);
+ }
+
+ Ok(())
+ }
+
+ #[cfg(unix)]
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ #[inline]
+ pub unsafe fn export_fd_unchecked(
+ &self,
+ handle_type: ExternalSemaphoreHandleType,
+ ) -> Result<File, VulkanError> {
+ let mut state = self.state.lock();
+ self.export_fd_unchecked_locked(handle_type, &mut state)
+ }
+
+ #[cfg(unix)]
+ unsafe fn export_fd_unchecked_locked(
+ &self,
+ handle_type: ExternalSemaphoreHandleType,
+ state: &mut SemaphoreState,
+ ) -> Result<File, VulkanError> {
+ use std::os::unix::io::FromRawFd;
+
+ let info = ash::vk::SemaphoreGetFdInfoKHR {
+ semaphore: self.handle,
+ handle_type: handle_type.into(),
+ ..Default::default()
+ };
+
+ let mut output = MaybeUninit::uninit();
+ let fns = self.device.fns();
+ (fns.khr_external_semaphore_fd.get_semaphore_fd_khr)(
+ self.device.handle(),
+ &info,
+ output.as_mut_ptr(),
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+
+ state.export(handle_type);
+
+ Ok(File::from_raw_fd(output.assume_init()))
+ }
+
+ /// Exports the semaphore into a Win32 handle.
+ ///
+ /// The [`khr_external_semaphore_win32`](crate::device::DeviceExtensions::khr_external_semaphore_win32)
+ /// extension must be enabled on the device.
+ #[cfg(windows)]
+ #[inline]
+ pub fn export_win32_handle(
+ &self,
+ handle_type: ExternalSemaphoreHandleType,
+ ) -> Result<*mut std::ffi::c_void, SemaphoreError> {
+ let mut state = self.state.lock();
+ self.validate_export_win32_handle(handle_type, &state)?;
+
+ unsafe { Ok(self.export_win32_handle_unchecked_locked(handle_type, &mut state)?) }
+ }
+
+ #[cfg(windows)]
+ fn validate_export_win32_handle(
+ &self,
+ handle_type: ExternalSemaphoreHandleType,
+ state: &SemaphoreState,
+ ) -> Result<(), SemaphoreError> {
+ if !self
+ .device
+ .enabled_extensions()
+ .khr_external_semaphore_win32
+ {
+ return Err(SemaphoreError::RequirementNotMet {
+ required_for: "`Semaphore::export_win32_handle`",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["khr_external_semaphore_win32"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-parameter
+ handle_type.validate_device(&self.device)?;
+
+ // VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01126
+ if !self.export_handle_types.intersects(handle_type.into()) {
+ return Err(SemaphoreError::HandleTypeNotEnabled);
+ }
+
+ // VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01127
+ if matches!(
+ handle_type,
+ ExternalSemaphoreHandleType::OpaqueWin32 | ExternalSemaphoreHandleType::D3D12Fence
+ ) && state.is_exported(handle_type)
+ {
+ return Err(SemaphoreError::AlreadyExported);
+ }
+
+ // VUID-VkSemaphoreGetWin32HandleInfoKHR-semaphore-01128
+ if let Some(imported_handle_type) = state.current_import {
+ match imported_handle_type {
+ ImportType::SwapchainAcquire => {
+ return Err(SemaphoreError::ImportedForSwapchainAcquire)
+ }
+ ImportType::ExternalSemaphore(imported_handle_type) => {
+ let external_semaphore_properties = unsafe {
+ self.device
+ .physical_device()
+ .external_semaphore_properties_unchecked(
+ ExternalSemaphoreInfo::handle_type(handle_type),
+ )
+ };
+
+ if !external_semaphore_properties
+ .export_from_imported_handle_types
+ .intersects(imported_handle_type.into())
+ {
+ return Err(SemaphoreError::ExportFromImportedNotSupported {
+ imported_handle_type,
+ });
+ }
+ }
+ }
+ }
+
+ if handle_type.has_copy_transference() {
+ // VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01129
+ if state.is_wait_pending() {
+ return Err(SemaphoreError::QueueIsWaiting);
+ }
+
+ // VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01130
+ if !(state.is_signaled().unwrap_or(false) || state.is_signal_pending()) {
+ return Err(SemaphoreError::HandleTypeCopyNotSignaled);
+ }
+ }
+
+ // VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01131
+ if !matches!(
+ handle_type,
+ ExternalSemaphoreHandleType::OpaqueWin32
+ | ExternalSemaphoreHandleType::OpaqueWin32Kmt
+ | ExternalSemaphoreHandleType::D3D12Fence
+ ) {
+ return Err(SemaphoreError::HandleTypeNotWin32);
+ }
+
+ Ok(())
+ }
+
+ #[cfg(windows)]
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ #[inline]
+ pub unsafe fn export_win32_handle_unchecked(
+ &self,
+ handle_type: ExternalSemaphoreHandleType,
+ ) -> Result<*mut std::ffi::c_void, VulkanError> {
+ let mut state = self.state.lock();
+ self.export_win32_handle_unchecked_locked(handle_type, &mut state)
+ }
+
+ #[cfg(windows)]
+ unsafe fn export_win32_handle_unchecked_locked(
+ &self,
+ handle_type: ExternalSemaphoreHandleType,
+ state: &mut SemaphoreState,
+ ) -> Result<*mut std::ffi::c_void, VulkanError> {
+ let info_vk = ash::vk::SemaphoreGetWin32HandleInfoKHR {
+ semaphore: self.handle,
+ handle_type: handle_type.into(),
+ ..Default::default()
+ };
+
+ let mut output = MaybeUninit::uninit();
+ let fns = self.device.fns();
+ (fns.khr_external_semaphore_win32
+ .get_semaphore_win32_handle_khr)(
+ self.device.handle(), &info_vk, output.as_mut_ptr()
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+
+ state.export(handle_type);
+
+ Ok(output.assume_init())
+ }
+
+ /// Exports the semaphore into a Zircon event handle.
+ #[cfg(target_os = "fuchsia")]
+ #[inline]
+ pub fn export_zircon_handle(
+ &self,
+ handle_type: ExternalSemaphoreHandleType,
+ ) -> Result<ash::vk::zx_handle_t, SemaphoreError> {
+ let mut state = self.state.lock();
+ self.validate_export_zircon_handle(handle_type, &state)?;
+
+ unsafe { Ok(self.export_zircon_handle_unchecked_locked(handle_type, &mut state)?) }
+ }
+
+ #[cfg(target_os = "fuchsia")]
+ fn validate_export_zircon_handle(
+ &self,
+ handle_type: ExternalSemaphoreHandleType,
+ state: &SemaphoreState,
+ ) -> Result<(), SemaphoreError> {
+ if !self.device.enabled_extensions().fuchsia_external_semaphore {
+ return Err(SemaphoreError::RequirementNotMet {
+ required_for: "`Semaphore::export_zircon_handle`",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["fuchsia_external_semaphore"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-parameter
+ handle_type.validate_device(&self.device)?;
+
+ // VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-04758
+ if !self.export_handle_types.intersects(&handle_type.into()) {
+ return Err(SemaphoreError::HandleTypeNotEnabled);
+ }
+
+ // VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-semaphore-04759
+ if let Some(imported_handle_type) = state.current_import {
+ match imported_handle_type {
+ ImportType::SwapchainAcquire => {
+ return Err(SemaphoreError::ImportedForSwapchainAcquire)
+ }
+ ImportType::ExternalSemaphore(imported_handle_type) => {
+ let external_semaphore_properties = unsafe {
+ self.device
+ .physical_device()
+ .external_semaphore_properties_unchecked(
+ ExternalSemaphoreInfo::handle_type(handle_type),
+ )
+ };
+
+ if !external_semaphore_properties
+ .export_from_imported_handle_types
+ .intersects(&imported_handle_type.into())
+ {
+ return Err(SemaphoreError::ExportFromImportedNotSupported {
+ imported_handle_type,
+ });
+ }
+ }
+ }
+ }
+
+ if handle_type.has_copy_transference() {
+ // VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-04760
+ if state.is_wait_pending() {
+ return Err(SemaphoreError::QueueIsWaiting);
+ }
+
+ // VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-04761
+ if !(state.is_signaled().unwrap_or(false) || state.is_signal_pending()) {
+ return Err(SemaphoreError::HandleTypeCopyNotSignaled);
+ }
+ }
+
+ // VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-04762
+ if !matches!(handle_type, ExternalSemaphoreHandleType::ZirconEvent) {
+ return Err(SemaphoreError::HandleTypeNotZircon);
+ }
+
+ Ok(())
+ }
+
+ #[cfg(target_os = "fuchsia")]
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ #[inline]
+ pub unsafe fn export_zircon_handle_unchecked(
+ &self,
+ handle_type: ExternalSemaphoreHandleType,
+ ) -> Result<ash::vk::zx_handle_t, VulkanError> {
+ let mut state = self.state.lock();
+ self.export_zircon_handle_unchecked_locked(handle_type, &mut state)
+ }
+
+ #[cfg(target_os = "fuchsia")]
+ unsafe fn export_zircon_handle_unchecked_locked(
+ &self,
+ handle_type: ExternalSemaphoreHandleType,
+ state: &mut SemaphoreState,
+ ) -> Result<ash::vk::zx_handle_t, VulkanError> {
+ let info = ash::vk::SemaphoreGetZirconHandleInfoFUCHSIA {
+ semaphore: self.handle,
+ handle_type: handle_type.into(),
+ ..Default::default()
+ };
+
+ let mut output = MaybeUninit::uninit();
+ let fns = self.device.fns();
+ (fns.fuchsia_external_semaphore
+ .get_semaphore_zircon_handle_fuchsia)(
+ self.device.handle(), &info, output.as_mut_ptr()
+ )
+ .result()
+ .map_err(VulkanError::from)?;
+
+ state.export(handle_type);
+
+ Ok(output.assume_init())
+ }
+
+ /// Imports a semaphore from a POSIX file descriptor.
+ ///
+ /// The [`khr_external_semaphore_fd`](crate::device::DeviceExtensions::khr_external_semaphore_fd)
+ /// extension must be enabled on the device.
+ ///
+ /// # Safety
+ ///
+ /// - If in `import_semaphore_fd_info`, `handle_type` is `ExternalHandleType::OpaqueFd`,
+ /// then `file` must represent a binary semaphore that was exported from Vulkan or a
+ /// compatible API, with a driver and device UUID equal to those of the device that owns
+ /// `self`.
+ #[cfg(unix)]
+ #[inline]
+ pub unsafe fn import_fd(
+ &self,
+ import_semaphore_fd_info: ImportSemaphoreFdInfo,
+ ) -> Result<(), SemaphoreError> {
+ let mut state = self.state.lock();
+ self.validate_import_fd(&import_semaphore_fd_info, &state)?;
+
+ Ok(self.import_fd_unchecked_locked(import_semaphore_fd_info, &mut state)?)
+ }
+
+ #[cfg(unix)]
+ fn validate_import_fd(
+ &self,
+ import_semaphore_fd_info: &ImportSemaphoreFdInfo,
+ state: &SemaphoreState,
+ ) -> Result<(), SemaphoreError> {
+ if !self.device.enabled_extensions().khr_external_semaphore_fd {
+ return Err(SemaphoreError::RequirementNotMet {
+ required_for: "`Semaphore::import_fd`",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["khr_external_semaphore_fd"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkImportSemaphoreFdKHR-semaphore-01142
+ if state.is_in_queue() {
+ return Err(SemaphoreError::InQueue);
+ }
+
+ let &ImportSemaphoreFdInfo {
+ flags,
+ handle_type,
+ file: _,
+ _ne: _,
+ } = import_semaphore_fd_info;
+
+ // VUID-VkImportSemaphoreFdInfoKHR-flags-parameter
+ flags.validate_device(&self.device)?;
+
+ // VUID-VkImportSemaphoreFdInfoKHR-handleType-parameter
+ handle_type.validate_device(&self.device)?;
+
+ // VUID-VkImportSemaphoreFdInfoKHR-handleType-01143
+ if !matches!(
+ handle_type,
+ ExternalSemaphoreHandleType::OpaqueFd | ExternalSemaphoreHandleType::SyncFd
+ ) {
+ return Err(SemaphoreError::HandleTypeNotFd);
+ }
+
+ // VUID-VkImportSemaphoreFdInfoKHR-fd-01544
+ // VUID-VkImportSemaphoreFdInfoKHR-handleType-03263
+ // Can't validate, therefore unsafe
+
+ // VUID-VkImportSemaphoreFdInfoKHR-handleType-07307
+ if handle_type.has_copy_transference() && !flags.intersects(SemaphoreImportFlags::TEMPORARY)
+ {
+ return Err(SemaphoreError::HandletypeCopyNotTemporary);
+ }
+
+ Ok(())
+ }
+
+ #[cfg(unix)]
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ #[inline]
+ pub unsafe fn import_fd_unchecked(
+ &self,
+ import_semaphore_fd_info: ImportSemaphoreFdInfo,
+ ) -> Result<(), VulkanError> {
+ let mut state = self.state.lock();
+ self.import_fd_unchecked_locked(import_semaphore_fd_info, &mut state)
+ }
+
+ #[cfg(unix)]
+ unsafe fn import_fd_unchecked_locked(
+ &self,
+ import_semaphore_fd_info: ImportSemaphoreFdInfo,
+ state: &mut SemaphoreState,
+ ) -> Result<(), VulkanError> {
+ use std::os::unix::io::IntoRawFd;
+
+ let ImportSemaphoreFdInfo {
+ flags,
+ handle_type,
+ file,
+ _ne: _,
+ } = import_semaphore_fd_info;
+
+ let info_vk = ash::vk::ImportSemaphoreFdInfoKHR {
+ semaphore: self.handle,
+ flags: flags.into(),
+ handle_type: handle_type.into(),
+ fd: file.map_or(-1, |file| file.into_raw_fd()),
+ ..Default::default()
+ };
+
+ let fns = self.device.fns();
+ (fns.khr_external_semaphore_fd.import_semaphore_fd_khr)(self.device.handle(), &info_vk)
+ .result()
+ .map_err(VulkanError::from)?;
+
+ state.import(
+ handle_type,
+ flags.intersects(SemaphoreImportFlags::TEMPORARY),
+ );
+
+ Ok(())
+ }
+
+ /// Imports a semaphore from a Win32 handle.
+ ///
+ /// The [`khr_external_semaphore_win32`](crate::device::DeviceExtensions::khr_external_semaphore_win32)
+ /// extension must be enabled on the device.
+ ///
+ /// # Safety
+ ///
+ /// - In `import_semaphore_win32_handle_info`, `handle` must represent a binary semaphore that
+ /// was exported from Vulkan or a compatible API, with a driver and device UUID equal to
+ /// those of the device that owns `self`.
+ #[cfg(windows)]
+ #[inline]
+ pub unsafe fn import_win32_handle(
+ &self,
+ import_semaphore_win32_handle_info: ImportSemaphoreWin32HandleInfo,
+ ) -> Result<(), SemaphoreError> {
+ let mut state = self.state.lock();
+ self.validate_import_win32_handle(&import_semaphore_win32_handle_info, &state)?;
+
+ Ok(self
+ .import_win32_handle_unchecked_locked(import_semaphore_win32_handle_info, &mut state)?)
+ }
+
+ #[cfg(windows)]
+ fn validate_import_win32_handle(
+ &self,
+ import_semaphore_win32_handle_info: &ImportSemaphoreWin32HandleInfo,
+ state: &SemaphoreState,
+ ) -> Result<(), SemaphoreError> {
+ if !self
+ .device
+ .enabled_extensions()
+ .khr_external_semaphore_win32
+ {
+ return Err(SemaphoreError::RequirementNotMet {
+ required_for: "`Semaphore::import_win32_handle`",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["khr_external_semaphore_win32"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID?
+ if state.is_in_queue() {
+ return Err(SemaphoreError::InQueue);
+ }
+
+ let &ImportSemaphoreWin32HandleInfo {
+ flags,
+ handle_type,
+ handle: _,
+ _ne: _,
+ } = import_semaphore_win32_handle_info;
+
+ // VUID-VkImportSemaphoreWin32HandleInfoKHR-flags-parameter
+ flags.validate_device(&self.device)?;
+
+ // VUID-VkImportSemaphoreWin32HandleInfoKHR-handleType-01140
+ handle_type.validate_device(&self.device)?;
+
+ // VUID-VkImportSemaphoreWin32HandleInfoKHR-handleType-01140
+ if !matches!(
+ handle_type,
+ ExternalSemaphoreHandleType::OpaqueWin32
+ | ExternalSemaphoreHandleType::OpaqueWin32Kmt
+ | ExternalSemaphoreHandleType::D3D12Fence
+ ) {
+ return Err(SemaphoreError::HandleTypeNotWin32);
+ }
+
+ // VUID-VkImportSemaphoreWin32HandleInfoKHR-handle-01542
+ // Can't validate, therefore unsafe
+
+ // VUID?
+ if handle_type.has_copy_transference() && !flags.intersects(SemaphoreImportFlags::TEMPORARY)
+ {
+ return Err(SemaphoreError::HandletypeCopyNotTemporary);
+ }
+
+ Ok(())
+ }
+
+ #[cfg(windows)]
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ #[inline]
+ pub unsafe fn import_win32_handle_unchecked(
+ &self,
+ import_semaphore_win32_handle_info: ImportSemaphoreWin32HandleInfo,
+ ) -> Result<(), VulkanError> {
+ let mut state = self.state.lock();
+ self.import_win32_handle_unchecked_locked(import_semaphore_win32_handle_info, &mut state)
+ }
+
+ #[cfg(windows)]
+ unsafe fn import_win32_handle_unchecked_locked(
+ &self,
+ import_semaphore_win32_handle_info: ImportSemaphoreWin32HandleInfo,
+ state: &mut SemaphoreState,
+ ) -> Result<(), VulkanError> {
+ let ImportSemaphoreWin32HandleInfo {
+ flags,
+ handle_type,
+ handle,
+ _ne: _,
+ } = import_semaphore_win32_handle_info;
+
+ let info_vk = ash::vk::ImportSemaphoreWin32HandleInfoKHR {
+ semaphore: self.handle,
+ flags: flags.into(),
+ handle_type: handle_type.into(),
+ handle,
+ name: ptr::null(), // TODO: support?
+ ..Default::default()
+ };
+
+ let fns = self.device.fns();
+ (fns.khr_external_semaphore_win32
+ .import_semaphore_win32_handle_khr)(self.device.handle(), &info_vk)
+ .result()
+ .map_err(VulkanError::from)?;
+
+ state.import(
+ handle_type,
+ flags.intersects(SemaphoreImportFlags::TEMPORARY),
+ );
+
+ Ok(())
+ }
+
+ /// Imports a semaphore from a Zircon event handle.
+ ///
+ /// The [`fuchsia_external_semaphore`](crate::device::DeviceExtensions::fuchsia_external_semaphore)
+ /// extension must be enabled on the device.
+ ///
+ /// # Safety
+ ///
+ /// - In `import_semaphore_zircon_handle_info`, `zircon_handle` must have `ZX_RIGHTS_BASIC` and
+ /// `ZX_RIGHTS_SIGNAL`.
+ #[cfg(target_os = "fuchsia")]
+ #[inline]
+ pub unsafe fn import_zircon_handle(
+ &self,
+ import_semaphore_zircon_handle_info: ImportSemaphoreZirconHandleInfo,
+ ) -> Result<(), SemaphoreError> {
+ let mut state = self.state.lock();
+ self.validate_import_zircon_handle(&import_semaphore_zircon_handle_info, &state)?;
+
+ Ok(self.import_zircon_handle_unchecked_locked(
+ import_semaphore_zircon_handle_info,
+ &mut state,
+ )?)
+ }
+
+ #[cfg(target_os = "fuchsia")]
+ fn validate_import_zircon_handle(
+ &self,
+ import_semaphore_zircon_handle_info: &ImportSemaphoreZirconHandleInfo,
+ state: &SemaphoreState,
+ ) -> Result<(), SemaphoreError> {
+ if !self.device.enabled_extensions().fuchsia_external_semaphore {
+ return Err(SemaphoreError::RequirementNotMet {
+ required_for: "`Semaphore::import_zircon_handle`",
+ requires_one_of: RequiresOneOf {
+ device_extensions: &["fuchsia_external_semaphore"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkImportSemaphoreZirconHandleFUCHSIA-semaphore-04764
+ if state.is_in_queue() {
+ return Err(SemaphoreError::InQueue);
+ }
+
+ let &ImportSemaphoreZirconHandleInfo {
+ flags,
+ handle_type,
+ zircon_handle: _,
+ _ne: _,
+ } = import_semaphore_zircon_handle_info;
+
+ // VUID-VkImportSemaphoreZirconHandleInfoFUCHSIA-flags-parameter
+ flags.validate_device(&self.device)?;
+
+ // VUID-VkImportSemaphoreZirconHandleInfoFUCHSIA-handleType-parameter
+ handle_type.validate_device(&self.device)?;
+
+ // VUID-VkImportSemaphoreZirconHandleInfoFUCHSIA-handleType-04765
+ if !matches!(handle_type, ExternalSemaphoreHandleType::ZirconEvent) {
+ return Err(SemaphoreError::HandleTypeNotFd);
+ }
+
+ // VUID-VkImportSemaphoreZirconHandleInfoFUCHSIA-zirconHandle-04766
+ // VUID-VkImportSemaphoreZirconHandleInfoFUCHSIA-zirconHandle-04767
+ // Can't validate, therefore unsafe
+
+ if handle_type.has_copy_transference() && !flags.intersects(SemaphoreImportFlags::TEMPORARY)
+ {
+ return Err(SemaphoreError::HandletypeCopyNotTemporary);
+ }
+
+ Ok(())
+ }
+
+ #[cfg(target_os = "fuchsia")]
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ #[inline]
+ pub unsafe fn import_zircon_handle_unchecked(
+ &self,
+ import_semaphore_zircon_handle_info: ImportSemaphoreZirconHandleInfo,
+ ) -> Result<(), VulkanError> {
+ let mut state = self.state.lock();
+ self.import_zircon_handle_unchecked_locked(import_semaphore_zircon_handle_info, &mut state)
+ }
+
+ #[cfg(target_os = "fuchsia")]
+ unsafe fn import_zircon_handle_unchecked_locked(
+ &self,
+ import_semaphore_zircon_handle_info: ImportSemaphoreZirconHandleInfo,
+ state: &mut SemaphoreState,
+ ) -> Result<(), VulkanError> {
+ let ImportSemaphoreZirconHandleInfo {
+ flags,
+ handle_type,
+ zircon_handle,
+ _ne: _,
+ } = import_semaphore_zircon_handle_info;
+
+ let info_vk = ash::vk::ImportSemaphoreZirconHandleInfoFUCHSIA {
+ semaphore: self.handle,
+ flags: flags.into(),
+ handle_type: handle_type.into(),
+ zircon_handle,
+ ..Default::default()
+ };
+
+ let fns = self.device.fns();
+ (fns.fuchsia_external_semaphore
+ .import_semaphore_zircon_handle_fuchsia)(self.device.handle(), &info_vk)
+ .result()
+ .map_err(VulkanError::from)?;
+
+ state.import(
+ handle_type,
+ flags.intersects(SemaphoreImportFlags::TEMPORARY),
+ );
+
+ Ok(())
+ }
+
+ pub(crate) fn state(&self) -> MutexGuard<'_, SemaphoreState> {
+ self.state.lock()
+ }
+}
+
+impl Drop for Semaphore {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe {
+ if self.must_put_in_pool {
+ let raw_sem = self.handle;
+ self.device.semaphore_pool().lock().push(raw_sem);
+ } else {
+ let fns = self.device.fns();
+ (fns.v1_0.destroy_semaphore)(self.device.handle(), self.handle, ptr::null());
+ }
+ }
+ }
+}
+
+unsafe impl VulkanObject for Semaphore {
+ type Handle = ash::vk::Semaphore;
+
+ #[inline]
+ fn handle(&self) -> Self::Handle {
+ self.handle
+ }
+}
+
+unsafe impl DeviceOwned for Semaphore {
+ #[inline]
+ fn device(&self) -> &Arc<Device> {
+ &self.device
+ }
+}
+
+impl_id_counter!(Semaphore);
+
+#[derive(Debug, Default)]
+pub(crate) struct SemaphoreState {
+ is_signaled: bool,
+ pending_signal: Option<SignalType>,
+ pending_wait: Option<Weak<Queue>>,
+
+ reference_exported: bool,
+ exported_handle_types: ExternalSemaphoreHandleTypes,
+ current_import: Option<ImportType>,
+ permanent_import: Option<ExternalSemaphoreHandleType>,
+}
+
+impl SemaphoreState {
+ /// If the semaphore does not have a pending operation and has no external references,
+ /// returns the current status.
+ #[inline]
+ fn is_signaled(&self) -> Option<bool> {
+ // If any of these is true, we can't be certain of the status.
+ if self.pending_signal.is_some()
+ || self.pending_wait.is_some()
+ || self.has_external_reference()
+ {
+ None
+ } else {
+ Some(self.is_signaled)
+ }
+ }
+
+ #[inline]
+ fn is_signal_pending(&self) -> bool {
+ self.pending_signal.is_some()
+ }
+
+ #[inline]
+ fn is_wait_pending(&self) -> bool {
+ self.pending_wait.is_some()
+ }
+
+ #[inline]
+ fn is_in_queue(&self) -> bool {
+ matches!(self.pending_signal, Some(SignalType::Queue(_))) || self.pending_wait.is_some()
+ }
+
+ /// Returns whether there are any potential external references to the semaphore payload.
+ /// That is, the semaphore has been exported by reference transference, or imported.
+ #[inline]
+ fn has_external_reference(&self) -> bool {
+ self.reference_exported || self.current_import.is_some()
+ }
+
+ #[allow(dead_code)]
+ #[inline]
+ fn is_exported(&self, handle_type: ExternalSemaphoreHandleType) -> bool {
+ self.exported_handle_types.intersects(handle_type.into())
+ }
+
+ #[inline]
+ pub(crate) unsafe fn add_queue_signal(&mut self, queue: &Arc<Queue>) {
+ self.pending_signal = Some(SignalType::Queue(Arc::downgrade(queue)));
+ }
+
+ #[inline]
+ pub(crate) unsafe fn add_queue_wait(&mut self, queue: &Arc<Queue>) {
+ self.pending_wait = Some(Arc::downgrade(queue));
+ }
+
+ /// Called when a queue is unlocking resources.
+ #[inline]
+ pub(crate) unsafe fn set_signal_finished(&mut self) {
+ self.pending_signal = None;
+ self.is_signaled = true;
+ }
+
+ /// Called when a queue is unlocking resources.
+ #[inline]
+ pub(crate) unsafe fn set_wait_finished(&mut self) {
+ self.pending_wait = None;
+ self.current_import = self.permanent_import.map(Into::into);
+ self.is_signaled = false;
+ }
+
+ #[allow(dead_code)]
+ #[inline]
+ unsafe fn export(&mut self, handle_type: ExternalSemaphoreHandleType) {
+ self.exported_handle_types |= handle_type.into();
+
+ if handle_type.has_copy_transference() {
+ self.current_import = self.permanent_import.map(Into::into);
+ self.is_signaled = false;
+ } else {
+ self.reference_exported = true;
+ }
+ }
+
+ #[allow(dead_code)]
+ #[inline]
+ unsafe fn import(&mut self, handle_type: ExternalSemaphoreHandleType, temporary: bool) {
+ self.current_import = Some(handle_type.into());
+
+ if !temporary {
+ self.permanent_import = Some(handle_type);
+ }
+ }
+
+ #[inline]
+ pub(crate) unsafe fn swapchain_acquire(&mut self) {
+ self.pending_signal = Some(SignalType::SwapchainAcquire);
+ self.current_import = Some(ImportType::SwapchainAcquire);
+ }
+}
+
+#[derive(Clone, Debug)]
+enum SignalType {
+ Queue(Weak<Queue>),
+ SwapchainAcquire,
+}
+
+#[derive(Clone, Copy, Debug)]
+enum ImportType {
+ SwapchainAcquire,
+ ExternalSemaphore(ExternalSemaphoreHandleType),
+}
+
+impl From<ExternalSemaphoreHandleType> for ImportType {
+ #[inline]
+ fn from(handle_type: ExternalSemaphoreHandleType) -> Self {
+ Self::ExternalSemaphore(handle_type)
+ }
+}
+
+/// Parameters to create a new `Semaphore`.
+#[derive(Clone, Debug)]
+pub struct SemaphoreCreateInfo {
+ /// The handle types that can be exported from the semaphore.
+ ///
+ /// The default value is [`ExternalSemaphoreHandleTypes::empty()`].
+ pub export_handle_types: ExternalSemaphoreHandleTypes,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl Default for SemaphoreCreateInfo {
+ #[inline]
+ fn default() -> Self {
+ Self {
+ export_handle_types: ExternalSemaphoreHandleTypes::empty(),
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+vulkan_bitflags_enum! {
+ #[non_exhaustive]
+
+ /// A set of [`ExternalSemaphoreHandleType`] values.
+ ExternalSemaphoreHandleTypes,
+
+ /// The handle type used to export or import semaphores to/from an external source.
+ ExternalSemaphoreHandleType impl {
+ /// Returns whether the given handle type has *copy transference* rather than *reference
+ /// transference*.
+ ///
+ /// Imports of handles with copy transference must always be temporary. Exports of such
+ /// handles must only occur if no queue is waiting on the semaphore, and only if the semaphore
+ /// is already signaled, or if there is a semaphore signal operation pending in a queue.
+ #[inline]
+ pub fn has_copy_transference(self) -> bool {
+ // As defined by
+ // https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap7.html#synchronization-semaphore-handletypes-win32
+ // https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap7.html#synchronization-semaphore-handletypes-fd
+ // https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap7.html#synchronization-semaphore-handletypes-fuchsia
+ matches!(self, Self::SyncFd)
+ }
+ },
+
+ = ExternalSemaphoreHandleTypeFlags(u32);
+
+ /// A POSIX file descriptor handle that is only usable with Vulkan and compatible APIs.
+ ///
+ /// This handle type has *reference transference*.
+ OPAQUE_FD, OpaqueFd = OPAQUE_FD,
+
+ /// A Windows NT handle that is only usable with Vulkan and compatible APIs.
+ ///
+ /// This handle type has *reference transference*.
+ OPAQUE_WIN32, OpaqueWin32 = OPAQUE_WIN32,
+
+ /// A Windows global share handle that is only usable with Vulkan and compatible APIs.
+ ///
+ /// This handle type has *reference transference*.
+ OPAQUE_WIN32_KMT, OpaqueWin32Kmt = OPAQUE_WIN32_KMT,
+
+ /// A Windows NT handle that refers to a Direct3D 11 or 12 fence.
+ ///
+ /// This handle type has *reference transference*.
+ D3D12_FENCE, D3D12Fence = D3D12_FENCE,
+
+ /// A POSIX file descriptor handle to a Linux Sync File or Android Fence object.
+ ///
+ /// This handle type has *copy transference*.
+ SYNC_FD, SyncFd = SYNC_FD,
+
+ /// A handle to a Zircon event object.
+ ///
+ /// This handle type has *reference transference*.
+ ///
+ /// The [`fuchsia_external_semaphore`] extension must be enabled on the device.
+ ///
+ /// [`fuchsia_external_semaphore`]: crate::device::DeviceExtensions::fuchsia_external_semaphore
+ ZIRCON_EVENT, ZirconEvent = ZIRCON_EVENT_FUCHSIA {
+ device_extensions: [fuchsia_external_semaphore],
+ },
+}
+
+vulkan_bitflags! {
+ #[non_exhaustive]
+
+ /// Additional parameters for a semaphore payload import.
+ SemaphoreImportFlags = SemaphoreImportFlags(u32);
+
+ /// The semaphore payload will be imported only temporarily, regardless of the permanence of the
+ /// imported handle type.
+ TEMPORARY = TEMPORARY,
+}
+
+#[cfg(unix)]
+#[derive(Debug)]
+pub struct ImportSemaphoreFdInfo {
+ /// Additional parameters for the import operation.
+ ///
+ /// If `handle_type` has *copy transference*, this must include the `temporary` flag.
+ ///
+ /// The default value is [`SemaphoreImportFlags::empty()`].
+ pub flags: SemaphoreImportFlags,
+
+ /// The handle type of `file`.
+ ///
+ /// There is no default value.
+ pub handle_type: ExternalSemaphoreHandleType,
+
+ /// The file to import the semaphore from.
+ ///
+ /// If `handle_type` is `ExternalSemaphoreHandleType::SyncFd`, then `file` can be `None`.
+ /// Instead of an imported file descriptor, a dummy file descriptor `-1` is used,
+ /// which represents a semaphore that is always signaled.
+ ///
+ /// The default value is `None`, which must be overridden if `handle_type` is not
+ /// `ExternalSemaphoreHandleType::SyncFd`.
+ pub file: Option<File>,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+#[cfg(unix)]
+impl ImportSemaphoreFdInfo {
+ /// Returns an `ImportSemaphoreFdInfo` with the specified `handle_type`.
+ #[inline]
+ pub fn handle_type(handle_type: ExternalSemaphoreHandleType) -> Self {
+ Self {
+ flags: SemaphoreImportFlags::empty(),
+ handle_type,
+ file: None,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+#[cfg(windows)]
+#[derive(Debug)]
+pub struct ImportSemaphoreWin32HandleInfo {
+ /// Additional parameters for the import operation.
+ ///
+ /// If `handle_type` has *copy transference*, this must include the `temporary` flag.
+ ///
+ /// The default value is [`SemaphoreImportFlags::empty()`].
+ pub flags: SemaphoreImportFlags,
+
+ /// The handle type of `handle`.
+ ///
+ /// There is no default value.
+ pub handle_type: ExternalSemaphoreHandleType,
+
+ /// The handle to import the semaphore from.
+ ///
+ /// The default value is `null`, which must be overridden.
+ pub handle: *mut std::ffi::c_void,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+#[cfg(windows)]
+impl ImportSemaphoreWin32HandleInfo {
+ /// Returns an `ImportSemaphoreWin32HandleInfo` with the specified `handle_type`.
+ #[inline]
+ pub fn handle_type(handle_type: ExternalSemaphoreHandleType) -> Self {
+ Self {
+ flags: SemaphoreImportFlags::empty(),
+ handle_type,
+ handle: ptr::null_mut(),
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+#[cfg(target_os = "fuchsia")]
+#[derive(Debug)]
+pub struct ImportSemaphoreZirconHandleInfo {
+ /// Additional parameters for the import operation.
+ ///
+ /// If `handle_type` has *copy transference*, this must include the `temporary` flag.
+ ///
+ /// The default value is [`SemaphoreImportFlags::empty()`].
+ pub flags: SemaphoreImportFlags,
+
+ /// The handle type of `handle`.
+ ///
+ /// There is no default value.
+ pub handle_type: ExternalSemaphoreHandleType,
+
+ /// The handle to import the semaphore from.
+ ///
+ /// The default value is `ZX_HANDLE_INVALID`, which must be overridden.
+ pub zircon_handle: ash::vk::zx_handle_t,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+#[cfg(target_os = "fuchsia")]
+impl ImportSemaphoreZirconHandleInfo {
+ /// Returns an `ImportSemaphoreZirconHandleInfo` with the specified `handle_type`.
+ #[inline]
+ pub fn handle_type(handle_type: ExternalSemaphoreHandleType) -> Self {
+ Self {
+ flags: SemaphoreImportFlags::empty(),
+ handle_type,
+ zircon_handle: 0,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// The semaphore configuration to query in
+/// [`PhysicalDevice::external_semaphore_properties`](crate::device::physical::PhysicalDevice::external_semaphore_properties).
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct ExternalSemaphoreInfo {
+ /// The external handle type that will be used with the semaphore.
+ pub handle_type: ExternalSemaphoreHandleType,
+
+ pub _ne: crate::NonExhaustive,
+}
+
+impl ExternalSemaphoreInfo {
+ /// Returns an `ExternalSemaphoreInfo` with the specified `handle_type`.
+ #[inline]
+ pub fn handle_type(handle_type: ExternalSemaphoreHandleType) -> Self {
+ Self {
+ handle_type,
+ _ne: crate::NonExhaustive(()),
+ }
+ }
+}
+
+/// The properties for exporting or importing external handles, when a semaphore is created
+/// with a specific configuration.
+#[derive(Clone, Debug)]
+#[non_exhaustive]
+pub struct ExternalSemaphoreProperties {
+ /// Whether a handle can be exported to an external source with the queried
+ /// external handle type.
+ pub exportable: bool,
+
+ /// Whether a handle can be imported from an external source with the queried
+ /// external handle type.
+ pub importable: bool,
+
+ /// Which external handle types can be re-exported after the queried external handle type has
+ /// been imported.
+ pub export_from_imported_handle_types: ExternalSemaphoreHandleTypes,
+
+ /// Which external handle types can be enabled along with the queried external handle type
+ /// when creating the semaphore.
+ pub compatible_handle_types: ExternalSemaphoreHandleTypes,
+}
+
+/// Error that can be returned from operations on a semaphore.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum SemaphoreError {
+ /// Not enough memory available.
+ OomError(OomError),
+
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+
+ /// The provided handle type does not permit more than one export,
+ /// and a handle of this type was already exported previously.
+ AlreadyExported,
+
+ /// The provided handle type cannot be exported from the current import handle type.
+ ExportFromImportedNotSupported {
+ imported_handle_type: ExternalSemaphoreHandleType,
+ },
+
+ /// One of the export handle types is not compatible with the other provided handles.
+ ExportHandleTypesNotCompatible,
+
+ /// A handle type with copy transference was provided, but the semaphore is not signaled and
+ /// there is no pending queue operation that will signal it.
+ HandleTypeCopyNotSignaled,
+
+ /// A handle type with copy transference was provided,
+ /// but the `temporary` import flag was not set.
+ HandletypeCopyNotTemporary,
+
+ /// The provided export handle type was not set in `export_handle_types` when creating the
+ /// semaphore.
+ HandleTypeNotEnabled,
+
+ /// Exporting is not supported for the provided handle type.
+ HandleTypeNotExportable {
+ handle_type: ExternalSemaphoreHandleType,
+ },
+
+ /// The provided handle type is not a POSIX file descriptor handle.
+ HandleTypeNotFd,
+
+ /// The provided handle type is not a Win32 handle.
+ HandleTypeNotWin32,
+
+ /// The provided handle type is not a Zircon event handle.
+ HandleTypeNotZircon,
+
+ /// The semaphore currently has a temporary import for a swapchain acquire operation.
+ ImportedForSwapchainAcquire,
+
+ /// The semaphore is currently in use by a queue.
+ InQueue,
+
+ /// A queue is currently waiting on the semaphore.
+ QueueIsWaiting,
+}
+
+impl Error for SemaphoreError {
+ fn source(&self) -> Option<&(dyn Error + 'static)> {
+ match self {
+ Self::OomError(err) => Some(err),
+ _ => None,
+ }
+ }
+}
+
+impl Display for SemaphoreError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::OomError(_) => write!(f, "not enough memory available"),
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+
+ Self::AlreadyExported => write!(
+ f,
+ "the provided handle type does not permit more than one export, and a handle of \
+ this type was already exported previously",
+ ),
+ Self::ExportFromImportedNotSupported {
+ imported_handle_type,
+ } => write!(
+ f,
+ "the provided handle type cannot be exported from the current imported handle type \
+ {:?}",
+ imported_handle_type,
+ ),
+ Self::ExportHandleTypesNotCompatible => write!(
+ f,
+ "one of the export handle types is not compatible with the other provided handles",
+ ),
+ Self::HandleTypeCopyNotSignaled => write!(
+ f,
+ "a handle type with copy transference was provided, but the semaphore is not \
+ signaled and there is no pending queue operation that will signal it",
+ ),
+ Self::HandletypeCopyNotTemporary => write!(
+ f,
+ "a handle type with copy transference was provided, but the `temporary` \
+ import flag was not set",
+ ),
+ Self::HandleTypeNotEnabled => write!(
+ f,
+ "the provided export handle type was not set in `export_handle_types` when \
+ creating the semaphore",
+ ),
+ Self::HandleTypeNotExportable { handle_type } => write!(
+ f,
+ "exporting is not supported for handles of type {:?}",
+ handle_type,
+ ),
+ Self::HandleTypeNotFd => write!(
+ f,
+ "the provided handle type is not a POSIX file descriptor handle",
+ ),
+ Self::HandleTypeNotWin32 => {
+ write!(f, "the provided handle type is not a Win32 handle")
+ }
+ Self::HandleTypeNotZircon => {
+ write!(f, "the provided handle type is not a Zircon event handle")
+ }
+ Self::ImportedForSwapchainAcquire => write!(
+ f,
+ "the semaphore currently has a temporary import for a swapchain acquire operation",
+ ),
+ Self::InQueue => write!(f, "the semaphore is currently in use by a queue"),
+ Self::QueueIsWaiting => write!(f, "a queue is currently waiting on the semaphore"),
+ }
+ }
+}
+
+impl From<VulkanError> for SemaphoreError {
+ fn from(err: VulkanError) -> Self {
+ match err {
+ e @ VulkanError::OutOfHostMemory | e @ VulkanError::OutOfDeviceMemory => {
+ Self::OomError(e.into())
+ }
+ _ => panic!("unexpected error: {:?}", err),
+ }
+ }
+}
+
+impl From<OomError> for SemaphoreError {
+ fn from(err: OomError) -> Self {
+ Self::OomError(err)
+ }
+}
+
+impl From<RequirementNotMet> for SemaphoreError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ #[cfg(unix)]
+ use crate::{
+ device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo},
+ instance::{Instance, InstanceCreateInfo, InstanceExtensions},
+ sync::semaphore::{
+ ExternalSemaphoreHandleType, ExternalSemaphoreHandleTypes, SemaphoreCreateInfo,
+ },
+ VulkanLibrary,
+ };
+ use crate::{sync::semaphore::Semaphore, VulkanObject};
+
+ #[test]
+ fn semaphore_create() {
+ let (device, _) = gfx_dev_and_queue!();
+ let _ = Semaphore::new(device, Default::default());
+ }
+
+ #[test]
+ fn semaphore_pool() {
+ let (device, _) = gfx_dev_and_queue!();
+
+ assert_eq!(device.semaphore_pool().lock().len(), 0);
+ let sem1_internal_obj = {
+ let sem = Semaphore::from_pool(device.clone()).unwrap();
+ assert_eq!(device.semaphore_pool().lock().len(), 0);
+ sem.handle()
+ };
+
+ assert_eq!(device.semaphore_pool().lock().len(), 1);
+ let sem2 = Semaphore::from_pool(device.clone()).unwrap();
+ assert_eq!(device.semaphore_pool().lock().len(), 0);
+ assert_eq!(sem2.handle(), sem1_internal_obj);
+ }
+
+ #[test]
+ #[cfg(unix)]
+ fn semaphore_export_fd() {
+ let library = match VulkanLibrary::new() {
+ Ok(x) => x,
+ Err(_) => return,
+ };
+
+ let instance = match Instance::new(
+ library,
+ InstanceCreateInfo {
+ enabled_extensions: InstanceExtensions {
+ khr_get_physical_device_properties2: true,
+ khr_external_semaphore_capabilities: true,
+ ..InstanceExtensions::empty()
+ },
+ ..Default::default()
+ },
+ ) {
+ Ok(x) => x,
+ Err(_) => return,
+ };
+
+ let physical_device = match instance.enumerate_physical_devices() {
+ Ok(mut x) => x.next().unwrap(),
+ Err(_) => return,
+ };
+
+ let (device, _) = match Device::new(
+ physical_device,
+ DeviceCreateInfo {
+ enabled_extensions: DeviceExtensions {
+ khr_external_semaphore: true,
+ khr_external_semaphore_fd: true,
+ ..DeviceExtensions::empty()
+ },
+ queue_create_infos: vec![QueueCreateInfo {
+ queue_family_index: 0,
+ ..Default::default()
+ }],
+ ..Default::default()
+ },
+ ) {
+ Ok(x) => x,
+ Err(_) => return,
+ };
+
+ let sem = Semaphore::new(
+ device,
+ SemaphoreCreateInfo {
+ export_handle_types: ExternalSemaphoreHandleTypes::OPAQUE_FD,
+ ..Default::default()
+ },
+ )
+ .unwrap();
+ let _fd = sem
+ .export_fd(ExternalSemaphoreHandleType::OpaqueFd)
+ .unwrap();
+ }
+}
diff --git a/src/sync/semaphore/external_semaphore_handle_type.rs b/src/sync/semaphore/external_semaphore_handle_type.rs
deleted file mode 100644
index 35af2fa..0000000
--- a/src/sync/semaphore/external_semaphore_handle_type.rs
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright (c) 2021 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use std::ops::BitOr;
-
-/// Describes the handle type used for Vulkan external semaphore APIs. This is **not**
-/// just a suggestion. Check out VkExternalSemaphoreHandleTypeFlagBits in the Vulkan
-/// spec.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub struct ExternalSemaphoreHandleType {
- pub opaque_fd: bool,
- pub opaque_win32: bool,
- pub opaque_win32_kmt: bool,
- pub d3d12_fence: bool,
- pub sync_fd: bool,
-}
-
-impl ExternalSemaphoreHandleType {
- /// Builds a `ExternalSemaphoreHandleType` with all values set to false. Useful as a default value.
- ///
- /// # Example
- ///
- /// ```rust
- /// use vulkano::sync::ExternalSemaphoreHandleType as ExternalSemaphoreHandleType;
- ///
- /// let _handle_type = ExternalSemaphoreHandleType {
- /// opaque_fd: true,
- /// .. ExternalSemaphoreHandleType::none()
- /// };
- /// ```
- #[inline]
- pub fn none() -> ExternalSemaphoreHandleType {
- ExternalSemaphoreHandleType {
- opaque_fd: false,
- opaque_win32: false,
- opaque_win32_kmt: false,
- d3d12_fence: false,
- sync_fd: false,
- }
- }
-
- /// Builds an `ExternalSemaphoreHandleType` for a posix file descriptor.
- ///
- /// # Example
- ///
- /// ```rust
- /// use vulkano::sync::ExternalSemaphoreHandleType as ExternalSemaphoreHandleType;
- ///
- /// let _handle_type = ExternalSemaphoreHandleType::posix();
- /// ```
- #[inline]
- pub fn posix() -> ExternalSemaphoreHandleType {
- ExternalSemaphoreHandleType {
- opaque_fd: true,
- ..ExternalSemaphoreHandleType::none()
- }
- }
-}
-
-impl From<ExternalSemaphoreHandleType> for ash::vk::ExternalSemaphoreHandleTypeFlags {
- #[inline]
- fn from(val: ExternalSemaphoreHandleType) -> Self {
- let mut result = ash::vk::ExternalSemaphoreHandleTypeFlags::empty();
- if val.opaque_fd {
- result |= ash::vk::ExternalSemaphoreHandleTypeFlags::OPAQUE_FD;
- }
- if val.opaque_win32 {
- result |= ash::vk::ExternalSemaphoreHandleTypeFlags::OPAQUE_WIN32;
- }
- if val.opaque_win32_kmt {
- result |= ash::vk::ExternalSemaphoreHandleTypeFlags::OPAQUE_WIN32_KMT;
- }
- if val.d3d12_fence {
- result |= ash::vk::ExternalSemaphoreHandleTypeFlags::D3D12_FENCE;
- }
- if val.sync_fd {
- result |= ash::vk::ExternalSemaphoreHandleTypeFlags::SYNC_FD;
- }
- result
- }
-}
-
-impl BitOr for ExternalSemaphoreHandleType {
- type Output = Self;
-
- fn bitor(self, rhs: Self) -> Self {
- ExternalSemaphoreHandleType {
- opaque_fd: self.opaque_fd || rhs.opaque_fd,
- opaque_win32: self.opaque_win32 || rhs.opaque_win32,
- opaque_win32_kmt: self.opaque_win32_kmt || rhs.opaque_win32_kmt,
- d3d12_fence: self.d3d12_fence || rhs.d3d12_fence,
- sync_fd: self.sync_fd || rhs.sync_fd,
- }
- }
-}
diff --git a/src/sync/semaphore/semaphore.rs b/src/sync/semaphore/semaphore.rs
deleted file mode 100644
index 29c9952..0000000
--- a/src/sync/semaphore/semaphore.rs
+++ /dev/null
@@ -1,355 +0,0 @@
-// Copyright (c) 2016 The vulkano developers
-// Licensed under the Apache License, Version 2.0
-// <LICENSE-APACHE or
-// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
-// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
-// at your option. All files in the project carrying such
-// notice may not be copied, modified, or distributed except
-// according to those terms.
-
-use crate::check_errors;
-use crate::device::Device;
-use crate::device::DeviceOwned;
-use crate::Error;
-use crate::OomError;
-use crate::SafeDeref;
-use crate::VulkanObject;
-use std::fmt;
-#[cfg(target_os = "linux")]
-use std::fs::File;
-use std::mem::MaybeUninit;
-#[cfg(target_os = "linux")]
-use std::os::unix::io::FromRawFd;
-use std::ptr;
-use std::sync::Arc;
-
-use crate::sync::semaphore::ExternalSemaphoreHandleType;
-
-/// Used to provide synchronization between command buffers during their execution.
-///
-/// It is similar to a fence, except that it is purely on the GPU side. The CPU can't query a
-/// semaphore's status or wait for it to be signaled.
-#[derive(Debug)]
-pub struct Semaphore<D = Arc<Device>>
-where
- D: SafeDeref<Target = Device>,
-{
- semaphore: ash::vk::Semaphore,
- device: D,
- must_put_in_pool: bool,
-}
-
-// TODO: Add support for VkExportSemaphoreWin32HandleInfoKHR
-// TODO: Add suport for importable semaphores
-pub struct SemaphoreBuilder<D = Arc<Device>>
-where
- D: SafeDeref<Target = Device>,
-{
- device: D,
- export_info: Option<ash::vk::ExportSemaphoreCreateInfo>,
- create: ash::vk::SemaphoreCreateInfo,
- must_put_in_pool: bool,
-}
-
-impl<D> SemaphoreBuilder<D>
-where
- D: SafeDeref<Target = Device>,
-{
- pub fn new(device: D) -> Self {
- let create = ash::vk::SemaphoreCreateInfo::default();
-
- Self {
- device,
- export_info: None,
- create,
- must_put_in_pool: false,
- }
- }
- /// Configures the semaphore to be added to the semaphore pool once it is destroyed.
- pub(crate) fn in_pool(mut self) -> Self {
- self.must_put_in_pool = true;
- self
- }
-
- /// Sets an optional field for exportable allocations in the `SemaphoreBuilder`.
- ///
- /// # Panic
- ///
- /// - Panics if the export info has already been set.
- pub fn export_info(mut self, handle_types: ExternalSemaphoreHandleType) -> Self {
- assert!(self.export_info.is_none());
- let export_info = ash::vk::ExportSemaphoreCreateInfo {
- handle_types: handle_types.into(),
- ..Default::default()
- };
-
- self.export_info = Some(export_info);
- self.create.p_next = unsafe { std::mem::transmute(&export_info) };
-
- self
- }
-
- pub fn build(self) -> Result<Semaphore<D>, SemaphoreError> {
- if self.export_info.is_some()
- && !self
- .device
- .instance()
- .enabled_extensions()
- .khr_external_semaphore_capabilities
- {
- Err(SemaphoreError::MissingExtension(
- "khr_external_semaphore_capabilities",
- ))
- } else {
- let semaphore = unsafe {
- let fns = self.device.fns();
- let mut output = MaybeUninit::uninit();
- check_errors(fns.v1_0.create_semaphore(
- self.device.internal_object(),
- &self.create,
- ptr::null(),
- output.as_mut_ptr(),
- ))?;
- output.assume_init()
- };
-
- Ok(Semaphore {
- device: self.device,
- semaphore,
- must_put_in_pool: self.must_put_in_pool,
- })
- }
- }
-}
-
-impl<D> Semaphore<D>
-where
- D: SafeDeref<Target = Device>,
-{
- /// Takes a semaphore from the vulkano-provided semaphore pool.
- /// If the pool is empty, a new semaphore will be allocated.
- /// Upon `drop`, the semaphore is put back into the pool.
- ///
- /// For most applications, using the pool should be preferred,
- /// in order to avoid creating new semaphores every frame.
- pub fn from_pool(device: D) -> Result<Semaphore<D>, SemaphoreError> {
- let maybe_raw_sem = device.semaphore_pool().lock().unwrap().pop();
- match maybe_raw_sem {
- Some(raw_sem) => Ok(Semaphore {
- device,
- semaphore: raw_sem,
- must_put_in_pool: true,
- }),
- None => {
- // Pool is empty, alloc new semaphore
- SemaphoreBuilder::new(device).in_pool().build()
- }
- }
- }
-
- /// Builds a new semaphore.
- #[inline]
- pub fn alloc(device: D) -> Result<Semaphore<D>, SemaphoreError> {
- SemaphoreBuilder::new(device).build()
- }
-
- /// Same as `alloc`, but allows exportable opaque file descriptor on Linux
- #[inline]
- #[cfg(target_os = "linux")]
- pub fn alloc_with_exportable_fd(device: D) -> Result<Semaphore<D>, SemaphoreError> {
- SemaphoreBuilder::new(device)
- .export_info(ExternalSemaphoreHandleType::posix())
- .build()
- }
-
- #[cfg(target_os = "linux")]
- pub fn export_opaque_fd(&self) -> Result<File, SemaphoreError> {
- let fns = self.device.fns();
-
- assert!(self.device.enabled_extensions().khr_external_semaphore);
- assert!(self.device.enabled_extensions().khr_external_semaphore_fd);
-
- let fd = unsafe {
- let info = ash::vk::SemaphoreGetFdInfoKHR {
- semaphore: self.semaphore,
- handle_type: ash::vk::ExternalSemaphoreHandleTypeFlagsKHR::OPAQUE_FD,
- ..Default::default()
- };
-
- let mut output = MaybeUninit::uninit();
- check_errors(fns.khr_external_semaphore_fd.get_semaphore_fd_khr(
- self.device.internal_object(),
- &info,
- output.as_mut_ptr(),
- ))?;
- output.assume_init()
- };
- let file = unsafe { File::from_raw_fd(fd) };
- Ok(file)
- }
-}
-
-unsafe impl DeviceOwned for Semaphore {
- #[inline]
- fn device(&self) -> &Arc<Device> {
- &self.device
- }
-}
-
-unsafe impl<D> VulkanObject for Semaphore<D>
-where
- D: SafeDeref<Target = Device>,
-{
- type Object = ash::vk::Semaphore;
-
- #[inline]
- fn internal_object(&self) -> ash::vk::Semaphore {
- self.semaphore
- }
-}
-
-impl<D> Drop for Semaphore<D>
-where
- D: SafeDeref<Target = Device>,
-{
- #[inline]
- fn drop(&mut self) {
- unsafe {
- if self.must_put_in_pool {
- let raw_sem = self.semaphore;
- self.device.semaphore_pool().lock().unwrap().push(raw_sem);
- } else {
- let fns = self.device.fns();
- fns.v1_0.destroy_semaphore(
- self.device.internal_object(),
- self.semaphore,
- ptr::null(),
- );
- }
- }
- }
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum SemaphoreError {
- /// Not enough memory available.
- OomError(OomError),
- /// An extensions is missing.
- MissingExtension(&'static str),
-}
-
-impl fmt::Display for SemaphoreError {
- fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- match *self {
- SemaphoreError::OomError(_) => write!(fmt, "not enough memory available"),
- SemaphoreError::MissingExtension(s) => {
- write!(fmt, "Missing the following extension: {}", s)
- }
- }
- }
-}
-
-impl From<Error> for SemaphoreError {
- #[inline]
- fn from(err: Error) -> SemaphoreError {
- match err {
- e @ Error::OutOfHostMemory | e @ Error::OutOfDeviceMemory => {
- SemaphoreError::OomError(e.into())
- }
- _ => panic!("unexpected error: {:?}", err),
- }
- }
-}
-
-impl std::error::Error for SemaphoreError {
- #[inline]
- fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
- match *self {
- SemaphoreError::OomError(ref err) => Some(err),
- _ => None,
- }
- }
-}
-
-impl From<OomError> for SemaphoreError {
- #[inline]
- fn from(err: OomError) -> SemaphoreError {
- SemaphoreError::OomError(err)
- }
-}
-
-#[cfg(test)]
-mod tests {
- use crate::device::physical::PhysicalDevice;
- use crate::device::{Device, DeviceExtensions};
- use crate::instance::{Instance, InstanceExtensions};
- use crate::VulkanObject;
- use crate::{sync::Semaphore, Version};
-
- #[test]
- fn semaphore_create() {
- let (device, _) = gfx_dev_and_queue!();
- let _ = Semaphore::alloc(device.clone());
- }
-
- #[test]
- fn semaphore_pool() {
- let (device, _) = gfx_dev_and_queue!();
-
- assert_eq!(device.semaphore_pool().lock().unwrap().len(), 0);
- let sem1_internal_obj = {
- let sem = Semaphore::from_pool(device.clone()).unwrap();
- assert_eq!(device.semaphore_pool().lock().unwrap().len(), 0);
- sem.internal_object()
- };
-
- assert_eq!(device.semaphore_pool().lock().unwrap().len(), 1);
- let sem2 = Semaphore::from_pool(device.clone()).unwrap();
- assert_eq!(device.semaphore_pool().lock().unwrap().len(), 0);
- assert_eq!(sem2.internal_object(), sem1_internal_obj);
- }
-
- #[test]
- #[cfg(target_os = "linux")]
- fn semaphore_export() {
- let supported_ext = InstanceExtensions::supported_by_core().unwrap();
- if supported_ext.khr_get_display_properties2
- && supported_ext.khr_external_semaphore_capabilities
- {
- let instance = Instance::new(
- None,
- Version::V1_1,
- &InstanceExtensions {
- khr_get_physical_device_properties2: true,
- khr_external_semaphore_capabilities: true,
- ..InstanceExtensions::none()
- },
- None,
- )
- .unwrap();
-
- let physical = PhysicalDevice::enumerate(&instance).next().unwrap();
-
- let queue_family = physical.queue_families().next().unwrap();
-
- let device_ext = DeviceExtensions {
- khr_external_semaphore: true,
- khr_external_semaphore_fd: true,
- ..DeviceExtensions::none()
- };
- let (device, _) = Device::new(
- physical,
- physical.supported_features(),
- &device_ext,
- [(queue_family, 0.5)].iter().cloned(),
- )
- .unwrap();
-
- let supported_ext = physical.supported_extensions();
- if supported_ext.khr_external_semaphore && supported_ext.khr_external_semaphore_fd {
- let sem = Semaphore::alloc_with_exportable_fd(device.clone()).unwrap();
- let fd = sem.export_opaque_fd().unwrap();
- }
- }
- }
-}
diff --git a/src/tests.rs b/src/tests.rs
index 563fa9e..d8b6ebb 100644
--- a/src/tests.rs
+++ b/src/tests.rs
@@ -12,16 +12,15 @@
/// Creates an instance or returns if initialization fails.
macro_rules! instance {
() => {{
- use crate::instance;
- use crate::Version;
+ use crate::{instance::Instance, VulkanLibrary};
- match instance::Instance::new(
- None,
- Version::V1_1,
- &instance::InstanceExtensions::none(),
- None,
- ) {
- Ok(i) => i,
+ let library = match VulkanLibrary::new() {
+ Ok(x) => x,
+ Err(_) => return,
+ };
+
+ match Instance::new(library, Default::default()) {
+ Ok(x) => x,
Err(_) => return,
}
}};
@@ -30,42 +29,61 @@ macro_rules! instance {
/// Creates a device and a queue for graphics operations.
macro_rules! gfx_dev_and_queue {
($($feature:ident),*) => ({
- use crate::device::physical::PhysicalDevice;
- use crate::device::Device;
- use crate::device::DeviceExtensions;
+ use crate::device::physical::PhysicalDeviceType;
+ use crate::device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo};
use crate::device::Features;
let instance = instance!();
-
- let physical = match PhysicalDevice::enumerate(&instance).next() {
- Some(p) => p,
- None => return
- };
-
- let queue = match physical.queue_families().find(|q| q.supports_graphics()) {
- Some(q) => q,
- None => return
- };
-
- let extensions = DeviceExtensions::none();
-
- let features = Features {
+ let enabled_extensions = DeviceExtensions::empty();
+ let enabled_features = Features {
$(
$feature: true,
)*
- .. Features::none()
+ .. Features::empty()
};
- // If the physical device doesn't support the requested features, just return.
- if !physical.supported_features().is_superset_of(&features) {
- return;
+ let select = match instance.enumerate_physical_devices() {
+ Ok(x) => x,
+ Err(_) => return,
}
+ .filter(|p| {
+ p.supported_extensions().contains(&enabled_extensions) &&
+ p.supported_features().contains(&enabled_features)
+ })
+ .filter_map(|p| {
+ p.queue_family_properties().iter()
+ .position(|q| q.queue_flags.intersects(crate::device::QueueFlags::GRAPHICS))
+ .map(|i| (p, i as u32))
+ })
+ .min_by_key(|(p, _)| {
+ match p.properties().device_type {
+ PhysicalDeviceType::DiscreteGpu => 0,
+ PhysicalDeviceType::IntegratedGpu => 1,
+ PhysicalDeviceType::VirtualGpu => 2,
+ PhysicalDeviceType::Cpu => 3,
+ PhysicalDeviceType::Other => 4,
+ }
+ });
+
+ let (physical_device, queue_family_index) = match select {
+ Some(x) => x,
+ None => return,
+ };
- let (device, mut queues) = match Device::new(physical, &features,
- &extensions, [(queue, 0.5)].iter().cloned())
- {
+ let (device, mut queues) = match Device::new(
+ physical_device,
+ DeviceCreateInfo {
+ queue_create_infos: vec![QueueCreateInfo {
+ queue_family_index,
+ ..Default::default()
+ }],
+ enabled_extensions,
+ enabled_features,
+ ..Default::default()
+ }
+ ) {
Ok(r) => r,
- Err(_) => return
+ Err(_) => return,
};
(device, queues.next().unwrap())
diff --git a/src/version.rs b/src/version.rs
index f4ef595..4871337 100644
--- a/src/version.rs
+++ b/src/version.rs
@@ -9,8 +9,14 @@
// The `Version` object is reexported from the `instance` module.
-use std::convert::TryFrom;
-use std::fmt;
+use std::{
+ fmt::{Debug, Display, Error as FmtError, Formatter},
+ num::ParseIntError,
+ str::FromStr,
+};
+
+// Generated by build.rs
+include!(concat!(env!("OUT_DIR"), "/version.rs"));
/// Represents an API version of Vulkan.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
@@ -27,6 +33,10 @@ impl Version {
pub const V1_0: Version = Version::major_minor(1, 0);
pub const V1_1: Version = Version::major_minor(1, 1);
pub const V1_2: Version = Version::major_minor(1, 2);
+ pub const V1_3: Version = Version::major_minor(1, 3);
+ pub const V1_4: Version = Version::major_minor(1, 4);
+ pub const V1_5: Version = Version::major_minor(1, 5);
+ pub const V1_6: Version = Version::major_minor(1, 6);
/// Constructs a `Version` from the given major and minor version numbers.
#[inline]
@@ -40,6 +50,7 @@ impl Version {
}
impl Default for Version {
+ #[inline]
fn default() -> Self {
Self::V1_0
}
@@ -71,22 +82,40 @@ impl TryFrom<Version> for u32 {
}
}
-impl fmt::Debug for Version {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch)
+impl FromStr for Version {
+ type Err = ParseIntError;
+
+ #[inline]
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ let mut iter = s.splitn(3, '.');
+ let major: u32 = iter.next().unwrap().parse()?;
+ let minor: u32 = iter.next().map_or(Ok(0), |n| n.parse())?;
+ let patch: u32 = iter.next().map_or(Ok(0), |n| n.parse())?;
+
+ Ok(Version {
+ major,
+ minor,
+ patch,
+ })
+ }
+}
+
+impl Debug for Version {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
}
}
-impl fmt::Display for Version {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- fmt::Debug::fmt(self, formatter)
+impl Display for Version {
+ #[inline]
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ Debug::fmt(self, f)
}
}
#[cfg(test)]
mod tests {
use super::Version;
- use std::convert::TryFrom;
#[test]
fn into_vk_version() {
@@ -142,4 +171,37 @@ mod tests {
};
assert!(v2 > v1);
}
+
+ #[test]
+ fn version_parse() {
+ assert!(matches!(
+ "1.1.1".parse::<Version>(),
+ Ok(Version {
+ major: 1,
+ minor: 1,
+ patch: 1,
+ })
+ ));
+ assert!(matches!(
+ "1.1".parse::<Version>(),
+ Ok(Version {
+ major: 1,
+ minor: 1,
+ patch: 0,
+ })
+ ));
+ assert!(matches!(
+ "1".parse::<Version>(),
+ Ok(Version {
+ major: 1,
+ minor: 0,
+ patch: 0,
+ })
+ ));
+
+ assert!("".parse::<Version>().is_err());
+ assert!("1.1.1.1".parse::<Version>().is_err());
+ assert!("foobar".parse::<Version>().is_err());
+ assert!("1.bar".parse::<Version>().is_err());
+ }
}
diff --git a/vk.xml b/vk.xml
index 81901e6..ca2ca43 100644
--- a/vk.xml
+++ b/vk.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<registry>
<comment>
-Copyright 2015-2021 The Khronos Group Inc.
+Copyright 2015-2022 The Khronos Group Inc.
SPDX-License-Identifier: Apache-2.0 OR MIT
</comment>
@@ -56,6 +56,7 @@ branch of the member gitlab server.
<tag name="GOOGLE" author="Google LLC" contact="Jesse Hall @critsec"/>
<tag name="QCOM" author="Qualcomm Technologies, Inc." contact="Jeff Leger @jackohounhd"/>
<tag name="LUNARG" author="LunarG, Inc." contact="Karen Ghavam @karenghavam-lunarg"/>
+ <tag name="NZXT" author="NZXT Inc." contact="Jacob Kiesel @xaeroxe"/>
<tag name="SAMSUNG" author="Samsung Electronics Co., Ltd." contact="Alon Or-bach @alonorbach"/>
<tag name="SEC" author="Samsung Electronics Co., Ltd." contact="Alon Or-bach @alonorbach"/>
<tag name="TIZEN" author="Samsung Electronics Co., Ltd." contact="Alon Or-bach @alonorbach"/>
@@ -67,15 +68,16 @@ branch of the member gitlab server.
<tag name="EXT" author="Multivendor" contact="Jon Leech @oddhack"/>
<tag name="MESA" author="Mesa open source project" contact="Chad Versace @chadversary, Daniel Stone @fooishbar, David Airlie @airlied, Jason Ekstrand @jekstrand"/>
<tag name="INTEL" author="Intel Corporation" contact="Slawek Grajewski @sgrajewski"/>
- <tag name="HUAWEI" author="Huawei Technologies Co. Ltd." contact="Hueilong Wang @wyvernathuawei, Yunpeng Zhu @yunxingzhu"/>
+ <tag name="HUAWEI" author="Huawei Technologies Co. Ltd." contact="Pan Gao @PanGao-h, Juntao Li @Lawrenceleehw"/>
<tag name="VALVE" author="Valve Corporation" contact="Pierre-Loup Griffais @plagman, Joshua Ashton @Joshua-Ashton, Hans-Kristian Arntzen @HansKristian-Work"/>
<tag name="QNX" author="BlackBerry Limited" contact="Mike Gorchak @mgorchak-blackberry"/>
<tag name="JUICE" author="Juice Technologies, Inc." contact="David McCloskey @damcclos, Dean Beeler @canadacow"/>
<tag name="FB" author="Facebook, Inc" contact="Artem Bolgar @artyom17"/>
+ <tag name="RASTERGRID" author="RasterGrid Kft." contact="Daniel Rakos @aqnuep1"/>
</tags>
<types comment="Vulkan type definitions">
- <type name="vk_platform" category="include">#include "vulkan/vk_platform.h"</type>
+ <type name="vk_platform" category="include">#include "vk_platform.h"</type>
<comment>WSI extensions</comment>
@@ -154,10 +156,12 @@ branch of the member gitlab server.
#define <name>VK_API_VERSION_1_1</name> <type>VK_MAKE_API_VERSION</type>(0, 1, 1, 0)// Patch version should always be set to 0</type>
<type category="define" requires="VK_MAKE_API_VERSION">// Vulkan 1.2 version number
#define <name>VK_API_VERSION_1_2</name> <type>VK_MAKE_API_VERSION</type>(0, 1, 2, 0)// Patch version should always be set to 0</type>
+ <type category="define" requires="VK_MAKE_API_VERSION">// Vulkan 1.3 version number
+#define <name>VK_API_VERSION_1_3</name> <type>VK_MAKE_API_VERSION</type>(0, 1, 3, 0)// Patch version should always be set to 0</type>
<type category="define">// Version of this file
-#define <name>VK_HEADER_VERSION</name> 186</type>
+#define <name>VK_HEADER_VERSION</name> 238</type>
<type category="define" requires="VK_HEADER_VERSION">// Complete version of this file
-#define <name>VK_HEADER_VERSION_COMPLETE</name> <type>VK_MAKE_API_VERSION</type>(0, 1, 2, VK_HEADER_VERSION)</type>
+#define <name>VK_HEADER_VERSION_COMPLETE</name> <type>VK_MAKE_API_VERSION</type>(0, 1, 3, VK_HEADER_VERSION)</type>
<type category="define">
#define <name>VK_DEFINE_HANDLE</name>(object) typedef struct object##_T* object;</type>
@@ -196,12 +200,42 @@ branch of the member gitlab server.
<type category="basetype">struct <name>ANativeWindow</name>;</type>
<type category="basetype">struct <name>AHardwareBuffer</name>;</type>
- <type category="basetype">
-#ifdef __OBJC__
+ <type category="basetype">#ifdef __OBJC__
@class CAMetalLayer;
#else
typedef void <name>CAMetalLayer</name>;
#endif</type>
+ <type category="basetype">#ifdef __OBJC__
+@protocol MTLDevice;
+typedef id&lt;MTLDevice&gt; MTLDevice_id;
+#else
+typedef void* <name>MTLDevice_id</name>;
+#endif</type>
+ <type category="basetype">#ifdef __OBJC__
+@protocol MTLCommandQueue;
+typedef id&lt;MTLCommandQueue&gt; MTLCommandQueue_id;
+#else
+typedef void* <name>MTLCommandQueue_id</name>;
+#endif</type>
+ <type category="basetype">#ifdef __OBJC__
+@protocol MTLBuffer;
+typedef id&lt;MTLBuffer&gt; MTLBuffer_id;
+#else
+typedef void* <name>MTLBuffer_id</name>;
+#endif</type>
+ <type category="basetype">#ifdef __OBJC__
+@protocol MTLTexture;
+typedef id&lt;MTLTexture&gt; MTLTexture_id;
+#else
+typedef void* <name>MTLTexture_id</name>;
+#endif</type>
+ <type category="basetype">#ifdef __OBJC__
+@protocol MTLSharedEvent;
+typedef id&lt;MTLSharedEvent&gt; MTLSharedEvent_id;
+#else
+typedef void* <name>MTLSharedEvent_id</name>;
+#endif</type>
+ <type category="basetype">typedef struct __IOSurface* <name>IOSurfaceRef</name>;</type>
<type category="basetype">typedef <type>uint32_t</type> <name>VkSampleMask</name>;</type>
<type category="basetype">typedef <type>uint32_t</type> <name>VkBool32</name>;</type>
@@ -231,11 +265,11 @@ typedef void <name>CAMetalLayer</name>;
<type category="bitmask">typedef <type>VkFlags</type> <name>VkQueryPoolCreateFlags</name>;</type>
<type requires="VkRenderPassCreateFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkRenderPassCreateFlags</name>;</type>
<type requires="VkSamplerCreateFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkSamplerCreateFlags</name>;</type>
- <type category="bitmask">typedef <type>VkFlags</type> <name>VkPipelineLayoutCreateFlags</name>;</type>
+ <type requires="VkPipelineLayoutCreateFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkPipelineLayoutCreateFlags</name>;</type>
<type requires="VkPipelineCacheCreateFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkPipelineCacheCreateFlags</name>;</type>
- <type category="bitmask">typedef <type>VkFlags</type> <name>VkPipelineDepthStencilStateCreateFlags</name>;</type>
+ <type requires="VkPipelineDepthStencilStateCreateFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkPipelineDepthStencilStateCreateFlags</name>;</type>
<type category="bitmask">typedef <type>VkFlags</type> <name>VkPipelineDynamicStateCreateFlags</name>;</type>
- <type category="bitmask">typedef <type>VkFlags</type> <name>VkPipelineColorBlendStateCreateFlags</name>;</type>
+ <type requires="VkPipelineColorBlendStateCreateFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkPipelineColorBlendStateCreateFlags</name>;</type>
<type category="bitmask">typedef <type>VkFlags</type> <name>VkPipelineMultisampleStateCreateFlags</name>;</type>
<type category="bitmask">typedef <type>VkFlags</type> <name>VkPipelineRasterizationStateCreateFlags</name>;</type>
<type category="bitmask">typedef <type>VkFlags</type> <name>VkPipelineViewportStateCreateFlags</name>;</type>
@@ -245,7 +279,7 @@ typedef void <name>CAMetalLayer</name>;
<type requires="VkPipelineShaderStageCreateFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkPipelineShaderStageCreateFlags</name>;</type>
<type requires="VkDescriptorSetLayoutCreateFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkDescriptorSetLayoutCreateFlags</name>;</type>
<type category="bitmask">typedef <type>VkFlags</type> <name>VkBufferViewCreateFlags</name>;</type>
- <type category="bitmask">typedef <type>VkFlags</type> <name>VkInstanceCreateFlags</name>;</type>
+ <type requires="VkInstanceCreateFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkInstanceCreateFlags</name>;</type>
<type category="bitmask">typedef <type>VkFlags</type> <name>VkDeviceCreateFlags</name>;</type>
<type requires="VkDeviceQueueCreateFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkDeviceQueueCreateFlags</name>;</type>
<type requires="VkQueueFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkQueueFlags</name>;</type>
@@ -261,12 +295,11 @@ typedef void <name>CAMetalLayer</name>;
<type requires="VkPipelineCreateFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkPipelineCreateFlags</name>;</type>
<type requires="VkColorComponentFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkColorComponentFlags</name>;</type>
<type requires="VkFenceCreateFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkFenceCreateFlags</name>;</type>
- <comment>When VkSemaphoreCreateFlagBits is first extended, need to add a requires= attribute for it to VkSemaphoreCreateFlags</comment>
<type category="bitmask">typedef <type>VkFlags</type> <name>VkSemaphoreCreateFlags</name>;</type>
<type requires="VkFormatFeatureFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkFormatFeatureFlags</name>;</type>
<type requires="VkQueryControlFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkQueryControlFlags</name>;</type>
<type requires="VkQueryResultFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkQueryResultFlags</name>;</type>
- <type requires="VkShaderModuleCreateFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkShaderModuleCreateFlags</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkShaderModuleCreateFlags</name>;</type>
<type requires="VkEventCreateFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkEventCreateFlags</name>;</type>
<type requires="VkCommandPoolCreateFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkCommandPoolCreateFlags</name>;</type>
<type requires="VkCommandPoolResetFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkCommandPoolResetFlags</name>;</type>
@@ -295,11 +328,13 @@ typedef void <name>CAMetalLayer</name>;
<type category="bitmask" name="VkGeometryInstanceFlagsNV" alias="VkGeometryInstanceFlagsKHR"/>
<type requires="VkBuildAccelerationStructureFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkBuildAccelerationStructureFlagsKHR</name>;</type>
<type category="bitmask" name="VkBuildAccelerationStructureFlagsNV" alias="VkBuildAccelerationStructureFlagsKHR"/>
- <type requires="VkPrivateDataSlotCreateFlagBitsEXT" category="bitmask">typedef <type>VkFlags</type> <name>VkPrivateDataSlotCreateFlagsEXT</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkPrivateDataSlotCreateFlags</name>;</type>
+ <type category="bitmask" name="VkPrivateDataSlotCreateFlagsEXT" alias="VkPrivateDataSlotCreateFlags"/>
<type requires="VkAccelerationStructureCreateFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkAccelerationStructureCreateFlagsKHR</name>;</type>
<type category="bitmask">typedef <type>VkFlags</type> <name>VkDescriptorUpdateTemplateCreateFlags</name>;</type>
<type category="bitmask" name="VkDescriptorUpdateTemplateCreateFlagsKHR" alias="VkDescriptorUpdateTemplateCreateFlags"/>
- <type requires="VkPipelineCreationFeedbackFlagBitsEXT" category="bitmask">typedef <type>VkFlags</type> <name>VkPipelineCreationFeedbackFlagsEXT</name>;</type>
+ <type requires="VkPipelineCreationFeedbackFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkPipelineCreationFeedbackFlags</name>;</type>
+ <type category="bitmask" name="VkPipelineCreationFeedbackFlagsEXT" alias="VkPipelineCreationFeedbackFlags"/>
<type requires="VkPerformanceCounterDescriptionFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkPerformanceCounterDescriptionFlagsKHR</name>;</type>
<type requires="VkAcquireProfilingLockFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkAcquireProfilingLockFlagsKHR</name>;</type>
<type requires="VkSemaphoreWaitFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkSemaphoreWaitFlags</name>;</type>
@@ -307,10 +342,20 @@ typedef void <name>CAMetalLayer</name>;
<type requires="VkPipelineCompilerControlFlagBitsAMD" category="bitmask">typedef <type>VkFlags</type> <name>VkPipelineCompilerControlFlagsAMD</name>;</type>
<type requires="VkShaderCorePropertiesFlagBitsAMD" category="bitmask">typedef <type>VkFlags</type> <name>VkShaderCorePropertiesFlagsAMD</name>;</type>
<type requires="VkDeviceDiagnosticsConfigFlagBitsNV" category="bitmask">typedef <type>VkFlags</type> <name>VkDeviceDiagnosticsConfigFlagsNV</name>;</type>
- <type bitvalues="VkAccessFlagBits2KHR" category="bitmask">typedef <type>VkFlags64</type> <name>VkAccessFlags2KHR</name>;</type>
- <type bitvalues="VkPipelineStageFlagBits2KHR" category="bitmask">typedef <type>VkFlags64</type> <name>VkPipelineStageFlags2KHR</name>;</type>
- <type category="bitmask">typedef <type>VkFlags</type> <name>VkAccelerationStructureMotionInfoFlagsNV</name>;</type>
- <type category="bitmask">typedef <type>VkFlags</type> <name>VkAccelerationStructureMotionInstanceFlagsNV</name>;</type>
+ <type bitvalues="VkAccessFlagBits2" category="bitmask">typedef <type>VkFlags64</type> <name>VkAccessFlags2</name>;</type>
+ <type category="bitmask" name="VkAccessFlags2KHR" alias="VkAccessFlags2"/>
+ <type bitvalues="VkPipelineStageFlagBits2" category="bitmask">typedef <type>VkFlags64</type> <name>VkPipelineStageFlags2</name>;</type>
+ <type category="bitmask" name="VkPipelineStageFlags2KHR" alias="VkPipelineStageFlags2"/>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkAccelerationStructureMotionInfoFlagsNV</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkAccelerationStructureMotionInstanceFlagsNV</name>;</type>
+ <type bitvalues="VkFormatFeatureFlagBits2" category="bitmask">typedef <type>VkFlags64</type> <name>VkFormatFeatureFlags2</name>;</type>
+ <type category="bitmask" name="VkFormatFeatureFlags2KHR" alias="VkFormatFeatureFlags2"/>
+ <type requires="VkRenderingFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkRenderingFlags</name>;</type>
+ <type bitvalues="VkMemoryDecompressionMethodFlagBitsNV" category="bitmask">typedef <type>VkFlags64</type> <name>VkMemoryDecompressionMethodFlagsNV</name>;</type>
+ <type category="bitmask" name="VkRenderingFlagsKHR" alias="VkRenderingFlags"/>
+ <type requires="VkBuildMicromapFlagBitsEXT" category="bitmask">typedef <type>VkFlags</type> <name>VkBuildMicromapFlagsEXT</name>;</type>
+ <type requires="VkMicromapCreateFlagBitsEXT" category="bitmask">typedef <type>VkFlags</type> <name>VkMicromapCreateFlagsEXT</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkDirectDriverLoadingFlagsLUNARG</name>;</type>
<comment>WSI extensions</comment>
<type requires="VkCompositeAlphaFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkCompositeAlphaFlagsKHR</name>;</type>
@@ -381,40 +426,62 @@ typedef void <name>CAMetalLayer</name>;
<type category="bitmask">typedef <type>VkFlags</type> <name>VkPipelineRasterizationStateStreamCreateFlagsEXT</name>;</type>
<type category="bitmask">typedef <type>VkFlags</type> <name>VkPipelineRasterizationDepthClipStateCreateFlagsEXT</name>;</type>
<type requires="VkSwapchainImageUsageFlagBitsANDROID" category="bitmask">typedef <type>VkFlags</type> <name>VkSwapchainImageUsageFlagsANDROID</name>;</type>
- <type requires="VkToolPurposeFlagBitsEXT" category="bitmask">typedef <type>VkFlags</type> <name>VkToolPurposeFlagsEXT</name>;</type>
- <type requires="VkSubmitFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkSubmitFlagsKHR</name>;</type>
+ <type requires="VkToolPurposeFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkToolPurposeFlags</name>;</type>
+ <type category="bitmask" name="VkToolPurposeFlagsEXT" alias="VkToolPurposeFlags"/>
+ <type requires="VkSubmitFlagBits" category="bitmask">typedef <type>VkFlags</type> <name>VkSubmitFlags</name>;</type>
+ <type category="bitmask" name="VkSubmitFlagsKHR" alias="VkSubmitFlags"/>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkImageFormatConstraintsFlagsFUCHSIA</name>;</type>
+ <type requires="VkImageConstraintsInfoFlagBitsFUCHSIA" category="bitmask">typedef <type>VkFlags</type> <name>VkImageConstraintsInfoFlagsFUCHSIA</name>;</type>
+ <type requires="VkGraphicsPipelineLibraryFlagBitsEXT" category="bitmask">typedef <type>VkFlags</type> <name>VkGraphicsPipelineLibraryFlagsEXT</name>;</type>
+ <type requires="VkImageCompressionFlagBitsEXT" category="bitmask">typedef <type>VkFlags</type> <name>VkImageCompressionFlagsEXT</name>;</type>
+ <type requires="VkImageCompressionFixedRateFlagBitsEXT" category="bitmask">typedef <type>VkFlags</type> <name>VkImageCompressionFixedRateFlagsEXT</name>;</type>
+ <type requires="VkExportMetalObjectTypeFlagBitsEXT" category="bitmask">typedef <type>VkFlags</type> <name>VkExportMetalObjectTypeFlagsEXT</name>;</type>
+ <type requires="VkDeviceAddressBindingFlagBitsEXT" category="bitmask">typedef <type>VkFlags</type> <name>VkDeviceAddressBindingFlagsEXT</name>;</type>
+ <type requires="VkOpticalFlowGridSizeFlagBitsNV" category="bitmask">typedef <type>VkFlags</type> <name>VkOpticalFlowGridSizeFlagsNV</name>;</type>
+ <type requires="VkOpticalFlowUsageFlagBitsNV" category="bitmask">typedef <type>VkFlags</type> <name>VkOpticalFlowUsageFlagsNV</name>;</type>
+ <type requires="VkOpticalFlowSessionCreateFlagBitsNV" category="bitmask">typedef <type>VkFlags</type> <name>VkOpticalFlowSessionCreateFlagsNV</name>;</type>
+ <type requires="VkOpticalFlowExecuteFlagBitsNV" category="bitmask">typedef <type>VkFlags</type> <name>VkOpticalFlowExecuteFlagsNV</name>;</type>
+ <type requires="VkPresentScalingFlagBitsEXT" category="bitmask">typedef <type>VkFlags</type> <name>VkPresentScalingFlagsEXT</name>;</type>
+ <type requires="VkPresentGravityFlagBitsEXT" category="bitmask">typedef <type>VkFlags</type> <name>VkPresentGravityFlagsEXT</name>;</type>
<comment>Video Core extension</comment>
<type requires="VkVideoCodecOperationFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkVideoCodecOperationFlagsKHR</name>;</type>
- <type requires="VkVideoCapabilitiesFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkVideoCapabilitiesFlagsKHR</name>;</type>
+ <type requires="VkVideoCapabilityFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkVideoCapabilityFlagsKHR</name>;</type>
<type requires="VkVideoSessionCreateFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkVideoSessionCreateFlagsKHR</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkVideoSessionParametersCreateFlagsKHR</name>;</type>
<type category="bitmask">typedef <type>VkFlags</type> <name>VkVideoBeginCodingFlagsKHR</name>;</type>
<type category="bitmask">typedef <type>VkFlags</type> <name>VkVideoEndCodingFlagsKHR</name>;</type>
- <type requires="VkVideoCodingQualityPresetFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkVideoCodingQualityPresetFlagsKHR</name>;</type>
<type requires="VkVideoCodingControlFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkVideoCodingControlFlagsKHR</name>;</type>
<comment>Video Decode Core extension</comment>
- <type requires="VkVideoDecodeFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkVideoDecodeFlagsKHR</name>;</type>
+ <type requires="VkVideoDecodeUsageFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkVideoDecodeUsageFlagsKHR</name>;</type>
+ <type requires="VkVideoDecodeCapabilityFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkVideoDecodeCapabilityFlagsKHR</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkVideoDecodeFlagsKHR</name>;</type>
<comment>Video Decode H.264 extension</comment>
- <type requires="VkVideoDecodeH264FieldLayoutFlagBitsEXT" category="bitmask">typedef <type>VkFlags</type> <name>VkVideoDecodeH264FieldLayoutFlagsEXT</name>;</type>
- <type category="bitmask">typedef <type>VkFlags</type> <name>VkVideoDecodeH264CreateFlagsEXT</name>;</type>
-
- <comment>Video Decode H.265 extension</comment>
- <type category="bitmask">typedef <type>VkFlags</type> <name>VkVideoDecodeH265CreateFlagsEXT</name>;</type>
+ <type requires="VkVideoDecodeH264PictureLayoutFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkVideoDecodeH264PictureLayoutFlagsKHR</name>;</type>
<comment>Video Encode Core extension</comment>
- <type requires="VkVideoEncodeFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkVideoEncodeFlagsKHR</name>;</type>
- <type requires="VkVideoEncodeRateControlFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkVideoEncodeRateControlFlagsKHR</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkVideoEncodeFlagsKHR</name>;</type>
+ <type requires="VkVideoEncodeUsageFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkVideoEncodeUsageFlagsKHR</name>;</type>
+ <type requires="VkVideoEncodeContentFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkVideoEncodeContentFlagsKHR</name>;</type>
+ <type requires="VkVideoEncodeCapabilityFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkVideoEncodeCapabilityFlagsKHR</name>;</type>
+ <type category="bitmask">typedef <type>VkFlags</type> <name>VkVideoEncodeRateControlFlagsKHR</name>;</type>
<type requires="VkVideoEncodeRateControlModeFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkVideoEncodeRateControlModeFlagsKHR</name>;</type>
<type requires="VkVideoChromaSubsamplingFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkVideoChromaSubsamplingFlagsKHR</name>;</type>
<type requires="VkVideoComponentBitDepthFlagBitsKHR" category="bitmask">typedef <type>VkFlags</type> <name>VkVideoComponentBitDepthFlagsKHR</name>;</type>
<comment>Video Encode H.264 extension</comment>
- <type requires="VkVideoEncodeH264CapabilitiesFlagBitsEXT" category="bitmask">typedef <type>VkFlags</type> <name>VkVideoEncodeH264CapabilitiesFlagsEXT</name>;</type>
+ <type requires="VkVideoEncodeH264CapabilityFlagBitsEXT" category="bitmask">typedef <type>VkFlags</type> <name>VkVideoEncodeH264CapabilityFlagsEXT</name>;</type>
<type requires="VkVideoEncodeH264InputModeFlagBitsEXT" category="bitmask">typedef <type>VkFlags</type> <name>VkVideoEncodeH264InputModeFlagsEXT</name>;</type>
<type requires="VkVideoEncodeH264OutputModeFlagBitsEXT" category="bitmask">typedef <type>VkFlags</type> <name>VkVideoEncodeH264OutputModeFlagsEXT</name>;</type>
- <type requires="VkVideoEncodeH264CreateFlagBitsEXT" category="bitmask">typedef <type>VkFlags</type> <name>VkVideoEncodeH264CreateFlagsEXT</name>;</type>
+
+ <comment>Video Encode H.265 extension</comment>
+ <type requires="VkVideoEncodeH265CapabilityFlagBitsEXT" category="bitmask">typedef <type>VkFlags</type> <name>VkVideoEncodeH265CapabilityFlagsEXT</name>;</type>
+ <type requires="VkVideoEncodeH265InputModeFlagBitsEXT" category="bitmask">typedef <type>VkFlags</type> <name>VkVideoEncodeH265InputModeFlagsEXT</name>;</type>
+ <type requires="VkVideoEncodeH265OutputModeFlagBitsEXT" category="bitmask">typedef <type>VkFlags</type> <name>VkVideoEncodeH265OutputModeFlagsEXT</name>;</type>
+ <type requires="VkVideoEncodeH265CtbSizeFlagBitsEXT" category="bitmask">typedef <type>VkFlags</type> <name>VkVideoEncodeH265CtbSizeFlagsEXT</name>;</type>
+ <type requires="VkVideoEncodeH265TransformBlockSizeFlagBitsEXT" category="bitmask">typedef <type>VkFlags</type> <name>VkVideoEncodeH265TransformBlockSizeFlagsEXT</name>;</type>
<comment>Types which can be void pointers or class pointers, selected at compile time</comment>
<type category="handle" objtypeenum="VK_OBJECT_TYPE_INSTANCE"><type>VK_DEFINE_HANDLE</type>(<name>VkInstance</name>)</type>
@@ -451,16 +518,20 @@ typedef void <name>CAMetalLayer</name>;
<type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkAccelerationStructureKHR</name>)</type>
<type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkAccelerationStructureNV</name>)</type>
<type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_PERFORMANCE_CONFIGURATION_INTEL"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkPerformanceConfigurationINTEL</name>)</type>
+ <type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_BUFFER_COLLECTION_FUCHSIA"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkBufferCollectionFUCHSIA</name>)</type>
<type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_DEFERRED_OPERATION_KHR"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkDeferredOperationKHR</name>)</type>
- <type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_PRIVATE_DATA_SLOT_EXT"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkPrivateDataSlotEXT</name>)</type>
+ <type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_PRIVATE_DATA_SLOT"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkPrivateDataSlot</name>)</type>
+ <type category="handle" name="VkPrivateDataSlotEXT" alias="VkPrivateDataSlot"/>
<type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_CU_MODULE_NVX"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkCuModuleNVX</name>)</type>
<type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_CU_FUNCTION_NVX"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkCuFunctionNVX</name>)</type>
+ <type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_OPTICAL_FLOW_SESSION_NV"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkOpticalFlowSessionNV</name>)</type>
+ <type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_MICROMAP_EXT"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkMicromapEXT</name>)</type>
<comment>WSI extensions</comment>
<type category="handle" parent="VkPhysicalDevice" objtypeenum="VK_OBJECT_TYPE_DISPLAY_KHR"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkDisplayKHR</name>)</type>
<type category="handle" parent="VkDisplayKHR" objtypeenum="VK_OBJECT_TYPE_DISPLAY_MODE_KHR"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkDisplayModeKHR</name>)</type>
<type category="handle" parent="VkInstance" objtypeenum="VK_OBJECT_TYPE_SURFACE_KHR"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkSurfaceKHR</name>)</type>
- <type category="handle" parent="VkSurfaceKHR" objtypeenum="VK_OBJECT_TYPE_SWAPCHAIN_KHR"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkSwapchainKHR</name>)</type>
+ <type category="handle" parent="VkDevice" objtypeenum="VK_OBJECT_TYPE_SWAPCHAIN_KHR"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkSwapchainKHR</name>)</type>
<type category="handle" parent="VkInstance" objtypeenum="VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkDebugReportCallbackEXT</name>)</type>
<type category="handle" parent="VkInstance" objtypeenum="VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT"><type>VK_DEFINE_NON_DISPATCHABLE_HANDLE</type>(<name>VkDebugUtilsMessengerEXT</name>)</type>
@@ -548,13 +619,15 @@ typedef void <name>CAMetalLayer</name>;
<type name="VkObjectType" category="enum"/>
<type name="VkEventCreateFlagBits" category="enum"/>
<type name="VkPipelineLayoutCreateFlagBits" category="enum"/>
- <comment>When VkSemaphoreCreateFlagBits is first extended, need to add a type enum tag for it here</comment>
+ <type name="VkSemaphoreCreateFlagBits" category="enum"/>
+ <type name="VkRayTracingInvocationReorderModeNV" category="enum"/>
<comment>Extensions</comment>
<type name="VkIndirectCommandsLayoutUsageFlagBitsNV" category="enum"/>
<type name="VkIndirectCommandsTokenTypeNV" category="enum"/>
<type name="VkIndirectStateFlagBitsNV" category="enum"/>
- <type name="VkPrivateDataSlotCreateFlagBitsEXT" category="enum"/>
+ <type name="VkPrivateDataSlotCreateFlagBits" category="enum"/>
+ <type category="enum" name="VkPrivateDataSlotCreateFlagBitsEXT" alias="VkPrivateDataSlotCreateFlagBits"/>
<type name="VkDescriptorUpdateTemplateType" category="enum"/>
<type category="enum" name="VkDescriptorUpdateTemplateTypeKHR" alias="VkDescriptorUpdateTemplateType"/>
<type name="VkViewportCoordinateSwizzleNV" category="enum"/>
@@ -566,7 +639,8 @@ typedef void <name>CAMetalLayer</name>;
<type name="VkCoverageReductionModeNV" category="enum"/>
<type name="VkValidationCacheHeaderVersionEXT" category="enum"/>
<type name="VkShaderInfoTypeAMD" category="enum"/>
- <type name="VkQueueGlobalPriorityEXT" category="enum"/>
+ <type name="VkQueueGlobalPriorityKHR" category="enum"/>
+ <type name="VkQueueGlobalPriorityEXT" category="enum" alias="VkQueueGlobalPriorityKHR"/>
<type name="VkTimeDomainEXT" category="enum"/>
<type name="VkConservativeRasterizationModeEXT" category="enum"/>
<type name="VkResolveModeFlagBits" category="enum"/>
@@ -600,7 +674,8 @@ typedef void <name>CAMetalLayer</name>;
<type name="VkScopeNV" category="enum"/>
<type name="VkComponentTypeNV" category="enum"/>
<type name="VkDeviceDiagnosticsConfigFlagBitsNV" category="enum"/>
- <type name="VkPipelineCreationFeedbackFlagBitsEXT" category="enum"/>
+ <type name="VkPipelineCreationFeedbackFlagBits" category="enum"/>
+ <type category="enum" name="VkPipelineCreationFeedbackFlagBitsEXT" alias="VkPipelineCreationFeedbackFlagBits"/>
<type name="VkPerformanceCounterScopeKHR" category="enum"/>
<type name="VkPerformanceCounterUnitKHR" category="enum"/>
<type name="VkPerformanceCounterStorageKHR" category="enum"/>
@@ -617,12 +692,41 @@ typedef void <name>CAMetalLayer</name>;
<type name="VkShaderModuleCreateFlagBits" category="enum"/>
<type name="VkPipelineCompilerControlFlagBitsAMD" category="enum"/>
<type name="VkShaderCorePropertiesFlagBitsAMD" category="enum"/>
- <type name="VkToolPurposeFlagBitsEXT" category="enum"/>
+ <type name="VkToolPurposeFlagBits" category="enum"/>
+ <type category="enum" name="VkToolPurposeFlagBitsEXT" alias="VkToolPurposeFlagBits"/>
<type name="VkFragmentShadingRateNV" category="enum"/>
<type name="VkFragmentShadingRateTypeNV" category="enum"/>
- <type name="VkAccessFlagBits2KHR" category="enum"/>
- <type name="VkPipelineStageFlagBits2KHR" category="enum"/>
+ <type name="VkSubpassMergeStatusEXT" category="enum"/>
+ <type name="VkAccessFlagBits2" category="enum"/>
+ <type category="enum" name="VkAccessFlagBits2KHR" alias="VkAccessFlagBits2"/>
+ <type name="VkPipelineStageFlagBits2" category="enum"/>
+ <type category="enum" name="VkPipelineStageFlagBits2KHR" alias="VkPipelineStageFlagBits2"/>
<type name="VkProvokingVertexModeEXT" category="enum"/>
+ <type name="VkImageFormatConstraintsFlagBitsFUCHSIA" category="enum"/>
+ <type name="VkImageConstraintsInfoFlagBitsFUCHSIA" category="enum"/>
+ <type name="VkFormatFeatureFlagBits2" category="enum"/>
+ <type category="enum" name="VkFormatFeatureFlagBits2KHR" alias="VkFormatFeatureFlagBits2"/>
+ <type name="VkRenderingFlagBits" category="enum"/>
+ <type category="enum" name="VkRenderingFlagBitsKHR" alias="VkRenderingFlagBits"/>
+ <type name="VkPipelineDepthStencilStateCreateFlagBits" category="enum"/>
+ <type name="VkPipelineColorBlendStateCreateFlagBits" category="enum"/>
+ <type name="VkImageCompressionFlagBitsEXT" category="enum"/>
+ <type name="VkImageCompressionFixedRateFlagBitsEXT" category="enum"/>
+ <type name="VkExportMetalObjectTypeFlagBitsEXT" category="enum"/>
+ <type name="VkPipelineRobustnessBufferBehaviorEXT" category="enum"/>
+ <type name="VkPipelineRobustnessImageBehaviorEXT" category="enum"/>
+ <type name="VkDeviceAddressBindingFlagBitsEXT" category="enum"/>
+ <type name="VkDeviceAddressBindingTypeEXT" category="enum"/>
+ <type name="VkMicromapTypeEXT" category="enum"/>
+ <type name="VkBuildMicromapModeEXT" category="enum"/>
+ <type name="VkCopyMicromapModeEXT" category="enum"/>
+ <type name="VkBuildMicromapFlagBitsEXT" category="enum"/>
+ <type name="VkMicromapCreateFlagBitsEXT" category="enum"/>
+ <type name="VkOpacityMicromapFormatEXT" category="enum"/>
+ <type name="VkOpacityMicromapSpecialIndexEXT" category="enum"/>
+ <type name="VkDeviceFaultVendorBinaryHeaderVersionEXT" category="enum"/>
+ <type name="VkMemoryDecompressionMethodFlagBitsNV" category="enum"/>
+ <type name="VkDirectDriverLoadingModeLUNARG" category="enum"/>
<comment>WSI extensions</comment>
<type name="VkColorSpaceKHR" category="enum"/>
@@ -684,7 +788,18 @@ typedef void <name>CAMetalLayer</name>;
<type category="enum" name="VkShaderFloatControlsIndependenceKHR" alias="VkShaderFloatControlsIndependence"/>
<type name="VkSwapchainImageUsageFlagBitsANDROID" category="enum"/>
<type name="VkFragmentShadingRateCombinerOpKHR" category="enum"/>
- <type name="VkSubmitFlagBitsKHR" category="enum"/>
+ <type name="VkSubmitFlagBits" category="enum"/>
+ <type category="enum" name="VkSubmitFlagBitsKHR" alias="VkSubmitFlagBits"/>
+ <type name="VkGraphicsPipelineLibraryFlagBitsEXT" category="enum"/>
+ <type name="VkOpticalFlowGridSizeFlagBitsNV" category="enum"/>
+ <type name="VkOpticalFlowUsageFlagBitsNV" category="enum"/>
+ <type name="VkOpticalFlowPerformanceLevelNV" category="enum"/>
+ <type name="VkOpticalFlowSessionBindingPointNV" category="enum"/>
+ <type name="VkOpticalFlowSessionCreateFlagBitsNV" category="enum"/>
+ <type name="VkOpticalFlowExecuteFlagBitsNV" category="enum"/>
+ <type name="VkDeviceFaultAddressTypeEXT" category="enum"/>
+ <type name="VkPresentScalingFlagBitsEXT" category="enum"/>
+ <type name="VkPresentGravityFlagBitsEXT" category="enum"/>
<comment>Enumerated types in the header, but not used by the API</comment>
<type name="VkVendorId" category="enum"/>
@@ -698,30 +813,40 @@ typedef void <name>CAMetalLayer</name>;
<type name="VkVideoCodecOperationFlagBitsKHR" category="enum"/>
<type name="VkVideoChromaSubsamplingFlagBitsKHR" category="enum"/>
<type name="VkVideoComponentBitDepthFlagBitsKHR" category="enum"/>
- <type name="VkVideoCapabilitiesFlagBitsKHR" category="enum"/>
+ <type name="VkVideoCapabilityFlagBitsKHR" category="enum"/>
<type name="VkVideoSessionCreateFlagBitsKHR" category="enum"/>
- <type name="VkVideoCodingQualityPresetFlagBitsKHR" category="enum"/>
<type name="VkVideoCodingControlFlagBitsKHR" category="enum"/>
<type name="VkQueryResultStatusKHR" category="enum"/>
<comment>Video Decode extensions</comment>
- <type name="VkVideoDecodeFlagBitsKHR" category="enum"/>
+ <type name="VkVideoDecodeUsageFlagBitsKHR" category="enum"/>
+ <type name="VkVideoDecodeCapabilityFlagBitsKHR" category="enum"/>
<comment>Video H.264 Decode extensions</comment>
- <type name="VkVideoDecodeH264FieldLayoutFlagBitsEXT" category="enum"/>
+ <type name="VkVideoDecodeH264PictureLayoutFlagBitsKHR" category="enum"/>
<comment>Video H.265 Decode extensions</comment>
<comment>Video Encode extensions</comment>
- <type name="VkVideoEncodeFlagBitsKHR" category="enum"/>
- <type name="VkVideoEncodeRateControlFlagBitsKHR" category="enum"/>
+ <type name="VkVideoEncodeUsageFlagBitsKHR" category="enum"/>
+ <type name="VkVideoEncodeContentFlagBitsKHR" category="enum"/>
+ <type name="VkVideoEncodeTuningModeKHR" category="enum"/>
+ <type name="VkVideoEncodeCapabilityFlagBitsKHR" category="enum"/>
<type name="VkVideoEncodeRateControlModeFlagBitsKHR" category="enum"/>
<comment>Video H.264 Encode extensions</comment>
- <type name="VkVideoEncodeH264CapabilitiesFlagBitsEXT" category="enum"/>
+ <type name="VkVideoEncodeH264CapabilityFlagBitsEXT" category="enum"/>
<type name="VkVideoEncodeH264InputModeFlagBitsEXT" category="enum"/>
<type name="VkVideoEncodeH264OutputModeFlagBitsEXT" category="enum"/>
- <type name="VkVideoEncodeH264CreateFlagBitsEXT" category="enum"/>
+ <type name="VkVideoEncodeH264RateControlStructureEXT" category="enum"/>
+
+ <comment>Video H.265 Encode extensions</comment>
+ <type name="VkVideoEncodeH265CapabilityFlagBitsEXT" category="enum"/>
+ <type name="VkVideoEncodeH265InputModeFlagBitsEXT" category="enum"/>
+ <type name="VkVideoEncodeH265OutputModeFlagBitsEXT" category="enum"/>
+ <type name="VkVideoEncodeH265RateControlStructureEXT" category="enum"/>
+ <type name="VkVideoEncodeH265CtbSizeFlagBitsEXT" category="enum"/>
+ <type name="VkVideoEncodeH265TransformBlockSizeFlagBitsEXT" category="enum"/>
<comment>The PFN_vk*Function types are used by VkAllocationCallbacks below</comment>
<type category="funcpointer">typedef void (VKAPI_PTR *<name>PFN_vkInternalAllocationNotification</name>)(
@@ -775,6 +900,15 @@ typedef void <name>CAMetalLayer</name>;
const <type>VkDeviceMemoryReportCallbackDataEXT</type>* pCallbackData,
<type>void</type>* pUserData);</type>
+ <comment>The PFN_vkGetInstanceProcAddrLUNARG type is used by the
+ VkDirectDriverLoadingInfoLUNARG structure.
+ We cannot introduce an explicit dependency on the
+ equivalent PFN_vkGetInstanceProcAddr type, even though
+ it is implicitly generated in the C header, because
+ that results in multiple definitions.</comment>
+ <type category="funcpointer" requires="VkInstance">typedef PFN_vkVoidFunction (VKAPI_PTR *<name>PFN_vkGetInstanceProcAddrLUNARG</name>)(
+ <type>VkInstance</type> instance, const <type>char</type>* pName);</type>
+
<comment>Struct types</comment>
<type category="struct" name="VkBaseOutStructure">
<member><type>VkStructureType</type> <name>sType</name></member>
@@ -894,10 +1028,10 @@ typedef void <name>CAMetalLayer</name>;
<member len="enabledExtensionCount,null-terminated">const <type>char</type>* const* <name>ppEnabledExtensionNames</name><comment>Extension names to be enabled</comment></member>
</type>
<type category="struct" name="VkQueueFamilyProperties" returnedonly="true">
- <member optional="true"><type>VkQueueFlags</type> <name>queueFlags</name><comment>Queue flags</comment></member>
- <member><type>uint32_t</type> <name>queueCount</name></member>
- <member><type>uint32_t</type> <name>timestampValidBits</name></member>
- <member><type>VkExtent3D</type> <name>minImageTransferGranularity</name><comment>Minimum alignment requirement for image transfers</comment></member>
+ <member optional="true" limittype="bitmask"><type>VkQueueFlags</type> <name>queueFlags</name><comment>Queue flags</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>queueCount</name></member>
+ <member limittype="bits"><type>uint32_t</type> <name>timestampValidBits</name></member>
+ <member limittype="min,mul"><type>VkExtent3D</type> <name>minImageTransferGranularity</name><comment>Minimum alignment requirement for image transfers</comment></member>
</type>
<type category="struct" name="VkPhysicalDeviceMemoryProperties" returnedonly="true">
<member><type>uint32_t</type> <name>memoryTypeCount</name></member>
@@ -917,9 +1051,9 @@ typedef void <name>CAMetalLayer</name>;
<member><type>uint32_t</type> <name>memoryTypeBits</name><comment>Bitmask of the allowed memory type indices into memoryTypes[] for this object</comment></member>
</type>
<type category="struct" name="VkSparseImageFormatProperties" returnedonly="true">
- <member optional="true"><type>VkImageAspectFlags</type> <name>aspectMask</name></member>
- <member><type>VkExtent3D</type> <name>imageGranularity</name></member>
- <member optional="true"><type>VkSparseImageFormatFlags</type> <name>flags</name></member>
+ <member limittype="bitmask" optional="true"><type>VkImageAspectFlags</type> <name>aspectMask</name></member>
+ <member limittype="min,mul"><type>VkExtent3D</type> <name>imageGranularity</name></member>
+ <member limittype="bitmask" optional="true"><type>VkSparseImageFormatFlags</type> <name>flags</name></member>
</type>
<type category="struct" name="VkSparseImageMemoryRequirements" returnedonly="true">
<member><type>VkSparseImageFormatProperties</type> <name>formatProperties</name></member>
@@ -944,9 +1078,9 @@ typedef void <name>CAMetalLayer</name>;
<member><type>VkDeviceSize</type> <name>size</name><comment>Size of the range within the memory object</comment></member>
</type>
<type category="struct" name="VkFormatProperties" returnedonly="true">
- <member optional="true"><type>VkFormatFeatureFlags</type> <name>linearTilingFeatures</name><comment>Format features in case of linear tiling</comment></member>
- <member optional="true"><type>VkFormatFeatureFlags</type> <name>optimalTilingFeatures</name><comment>Format features in case of optimal tiling</comment></member>
- <member optional="true"><type>VkFormatFeatureFlags</type> <name>bufferFeatures</name><comment>Format features supported by buffers</comment></member>
+ <member optional="true" limittype="bitmask"><type>VkFormatFeatureFlags</type> <name>linearTilingFeatures</name><comment>Format features in case of linear tiling</comment></member>
+ <member optional="true" limittype="bitmask"><type>VkFormatFeatureFlags</type> <name>optimalTilingFeatures</name><comment>Format features in case of optimal tiling</comment></member>
+ <member optional="true" limittype="bitmask"><type>VkFormatFeatureFlags</type> <name>bufferFeatures</name><comment>Format features supported by buffers</comment></member>
</type>
<type category="struct" name="VkImageFormatProperties" returnedonly="true">
<member><type>VkExtent3D</type> <name>maxExtent</name><comment>max image dimensions for this resource type</comment></member>
@@ -1001,7 +1135,7 @@ typedef void <name>CAMetalLayer</name>;
<type category="struct" name="VkBufferViewCreateInfo">
<member values="VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true">const <type>void</type>* <name>pNext</name></member>
- <member optional="true"><type>VkBufferViewCreateFlags</type><name>flags</name></member>
+ <member optional="true"><type>VkBufferViewCreateFlags</type> <name>flags</name></member>
<member><type>VkBuffer</type> <name>buffer</name></member>
<member><type>VkFormat</type> <name>format</name><comment>Optionally specifies format of elements</comment></member>
<member><type>VkDeviceSize</type> <name>offset</name><comment>Specified in bytes</comment></member>
@@ -1071,7 +1205,7 @@ typedef void <name>CAMetalLayer</name>;
<member noautovalidity="true" len="queueFamilyIndexCount">const <type>uint32_t</type>* <name>pQueueFamilyIndices</name><comment>Array of queue family indices to share across</comment></member>
<member><type>VkImageLayout</type> <name>initialLayout</name><comment>Initial image layout for all subresources</comment></member>
</type>
- <type category="struct" name="VkSubresourceLayout" returnedonly="true">
+ <type category="struct" name="VkSubresourceLayout">
<member><type>VkDeviceSize</type> <name>offset</name><comment>Specified in bytes</comment></member>
<member><type>VkDeviceSize</type> <name>size</name><comment>Specified in bytes</comment></member>
<member><type>VkDeviceSize</type> <name>rowPitch</name><comment>Specified in bytes</comment></member>
@@ -1098,7 +1232,7 @@ typedef void <name>CAMetalLayer</name>;
<member><type>VkDeviceSize</type> <name>size</name><comment>Specified in bytes</comment></member>
<member optional="true"><type>VkDeviceMemory</type> <name>memory</name></member>
<member><type>VkDeviceSize</type> <name>memoryOffset</name><comment>Specified in bytes</comment></member>
- <member optional="true"><type>VkSparseMemoryBindFlags</type><name>flags</name></member>
+ <member optional="true"><type>VkSparseMemoryBindFlags</type> <name>flags</name></member>
</type>
<type category="struct" name="VkSparseImageMemoryBind">
<member><type>VkImageSubresource</type> <name>subresource</name></member>
@@ -1106,7 +1240,7 @@ typedef void <name>CAMetalLayer</name>;
<member><type>VkExtent3D</type> <name>extent</name></member>
<member optional="true"><type>VkDeviceMemory</type> <name>memory</name></member>
<member><type>VkDeviceSize</type> <name>memoryOffset</name><comment>Specified in bytes</comment></member>
- <member optional="true"><type>VkSparseMemoryBindFlags</type><name>flags</name></member>
+ <member optional="true"><type>VkSparseMemoryBindFlags</type> <name>flags</name></member>
</type>
<type category="struct" name="VkSparseBufferMemoryBindInfo">
<member><type>VkBuffer</type> <name>buffer</name></member>
@@ -1158,6 +1292,19 @@ typedef void <name>CAMetalLayer</name>;
<member><type>VkOffset3D</type> <name>imageOffset</name><comment>Specified in pixels for both compressed and uncompressed images</comment></member>
<member><type>VkExtent3D</type> <name>imageExtent</name><comment>Specified in pixels for both compressed and uncompressed images</comment></member>
</type>
+ <type category="struct" name="VkCopyMemoryIndirectCommandNV">
+ <member><type>VkDeviceAddress</type> <name>srcAddress</name></member>
+ <member><type>VkDeviceAddress</type> <name>dstAddress</name></member>
+ <member><type>VkDeviceSize</type> <name>size</name><comment>Specified in bytes</comment></member>
+ </type>
+ <type category="struct" name="VkCopyMemoryToImageIndirectCommandNV">
+ <member><type>VkDeviceAddress</type> <name>srcAddress</name></member>
+ <member><type>uint32_t</type> <name>bufferRowLength</name><comment>Specified in texels</comment></member>
+ <member><type>uint32_t</type> <name>bufferImageHeight</name></member>
+ <member><type>VkImageSubresourceLayers</type> <name>imageSubresource</name></member>
+ <member><type>VkOffset3D</type> <name>imageOffset</name><comment>Specified in pixels for both compressed and uncompressed images</comment></member>
+ <member><type>VkExtent3D</type> <name>imageExtent</name><comment>Specified in pixels for both compressed and uncompressed images</comment></member>
+ </type>
<type category="struct" name="VkImageResolve">
<member><type>VkImageSubresourceLayers</type> <name>srcSubresource</name></member>
<member><type>VkOffset3D</type> <name>srcOffset</name></member>
@@ -1165,9 +1312,9 @@ typedef void <name>CAMetalLayer</name>;
<member><type>VkOffset3D</type> <name>dstOffset</name></member>
<member><type>VkExtent3D</type> <name>extent</name></member>
</type>
- <type category="struct" name="VkShaderModuleCreateInfo">
+ <type category="struct" name="VkShaderModuleCreateInfo" structextends="VkPipelineShaderStageCreateInfo">
<member values="VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
- <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member noautovalidity="true" optional="true">const <type>void</type>* <name>pNext</name><comment>noautovalidity because this structure can be either an explicit parameter, or passed in a pNext chain</comment></member>
<member optional="true"><type>VkShaderModuleCreateFlags</type> <name>flags</name></member>
<member><type>size_t</type> <name>codeSize</name><comment>Specified in bytes</comment></member>
<member len="latexmath:[\textrm{codeSize} \over 4]" altlen="codeSize / 4">const <type>uint32_t</type>* <name>pCode</name><comment>Binary code of size codeSize</comment></member>
@@ -1195,7 +1342,7 @@ typedef void <name>CAMetalLayer</name>;
<member optional="true">const <type>void</type>* <name>pNext</name></member>
<member optional="true"><type>VkDescriptorPoolCreateFlags</type> <name>flags</name></member>
<member><type>uint32_t</type> <name>maxSets</name></member>
- <member><type>uint32_t</type> <name>poolSizeCount</name></member>
+ <member optional="true"><type>uint32_t</type> <name>poolSizeCount</name></member>
<member len="poolSizeCount">const <type>VkDescriptorPoolSize</type>* <name>pPoolSizes</name></member>
</type>
<type category="struct" name="VkDescriptorSetAllocateInfo">
@@ -1221,7 +1368,7 @@ typedef void <name>CAMetalLayer</name>;
<member optional="true">const <type>void</type>* <name>pNext</name></member>
<member optional="true"><type>VkPipelineShaderStageCreateFlags</type> <name>flags</name></member>
<member><type>VkShaderStageFlagBits</type> <name>stage</name><comment>Shader stage</comment></member>
- <member><type>VkShaderModule</type> <name>module</name><comment>Module containing entry point</comment></member>
+ <member optional="true"><type>VkShaderModule</type> <name>module</name><comment>Module containing entry point</comment></member>
<member len="null-terminated">const <type>char</type>* <name>pName</name><comment>Null-terminated entry point name</comment></member>
<member optional="true">const <type>VkSpecializationInfo</type>* <name>pSpecializationInfo</name></member>
</type>
@@ -1319,7 +1466,7 @@ typedef void <name>CAMetalLayer</name>;
<member><type>VkBool32</type> <name>logicOpEnable</name></member>
<member noautovalidity="true"><type>VkLogicOp</type> <name>logicOp</name></member>
<member optional="true"><type>uint32_t</type> <name>attachmentCount</name><comment># of pAttachments</comment></member>
- <member len="attachmentCount">const <type>VkPipelineColorBlendAttachmentState</type>* <name>pAttachments</name></member>
+ <member optional="true" len="attachmentCount">const <type>VkPipelineColorBlendAttachmentState</type>* <name>pAttachments</name></member>
<member><type>float</type> <name>blendConstants</name>[4]</member>
</type>
<type category="struct" name="VkPipelineDynamicStateCreateInfo">
@@ -1356,20 +1503,20 @@ typedef void <name>CAMetalLayer</name>;
<member values="VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true">const <type>void</type>* <name>pNext</name></member>
<member optional="true"><type>VkPipelineCreateFlags</type> <name>flags</name><comment>Pipeline creation flags</comment></member>
- <member><type>uint32_t</type> <name>stageCount</name></member>
- <member len="stageCount">const <type>VkPipelineShaderStageCreateInfo</type>* <name>pStages</name><comment>One entry for each active shader stage</comment></member>
+ <member noautovalidity="true" optional="true"><type>uint32_t</type> <name>stageCount</name></member>
+ <member noautovalidity="true" len="stageCount" optional="true">const <type>VkPipelineShaderStageCreateInfo</type>* <name>pStages</name><comment>One entry for each active shader stage</comment></member>
<member noautovalidity="true" optional="true">const <type>VkPipelineVertexInputStateCreateInfo</type>* <name>pVertexInputState</name></member>
<member noautovalidity="true" optional="true">const <type>VkPipelineInputAssemblyStateCreateInfo</type>* <name>pInputAssemblyState</name></member>
<member noautovalidity="true" optional="true">const <type>VkPipelineTessellationStateCreateInfo</type>* <name>pTessellationState</name></member>
<member noautovalidity="true" optional="true">const <type>VkPipelineViewportStateCreateInfo</type>* <name>pViewportState</name></member>
- <member>const <type>VkPipelineRasterizationStateCreateInfo</type>* <name>pRasterizationState</name></member>
+ <member noautovalidity="true" optional="true">const <type>VkPipelineRasterizationStateCreateInfo</type>* <name>pRasterizationState</name></member>
<member noautovalidity="true" optional="true">const <type>VkPipelineMultisampleStateCreateInfo</type>* <name>pMultisampleState</name></member>
<member noautovalidity="true" optional="true">const <type>VkPipelineDepthStencilStateCreateInfo</type>* <name>pDepthStencilState</name></member>
<member noautovalidity="true" optional="true">const <type>VkPipelineColorBlendStateCreateInfo</type>* <name>pColorBlendState</name></member>
<member optional="true">const <type>VkPipelineDynamicStateCreateInfo</type>* <name>pDynamicState</name></member>
- <member><type>VkPipelineLayout</type> <name>layout</name><comment>Interface layout of the pipeline</comment></member>
- <member><type>VkRenderPass</type> <name>renderPass</name></member>
- <member><type>uint32_t</type> <name>subpass</name></member>
+ <member noautovalidity="true" optional="true"><type>VkPipelineLayout</type> <name>layout</name><comment>Interface layout of the pipeline</comment></member>
+ <member noautovalidity="true" optional="true"><type>VkRenderPass</type> <name>renderPass</name></member>
+ <member noautovalidity="true"><type>uint32_t</type> <name>subpass</name></member>
<member noautovalidity="true" optional="true"><type>VkPipeline</type> <name>basePipelineHandle</name><comment>If VK_PIPELINE_CREATE_DERIVATIVE_BIT is set and this value is nonzero, it specifies the handle of the base pipeline this is a derivative of</comment></member>
<member><type>int32_t</type> <name>basePipelineIndex</name><comment>If VK_PIPELINE_CREATE_DERIVATIVE_BIT is set and this value is not -1, it specifies an index into pCreateInfos of the base pipeline this is a derivative of</comment></member>
</type>
@@ -1398,7 +1545,7 @@ typedef void <name>CAMetalLayer</name>;
<member optional="true">const <type>void</type>* <name>pNext</name></member>
<member optional="true"><type>VkPipelineLayoutCreateFlags</type> <name>flags</name></member>
<member optional="true"><type>uint32_t</type> <name>setLayoutCount</name><comment>Number of descriptor sets interfaced by the pipeline</comment></member>
- <member len="setLayoutCount">const <type>VkDescriptorSetLayout</type>* <name>pSetLayouts</name><comment>Array of setCount number of descriptor set layout objects defining the layout of the</comment></member>
+ <member optional="false,true" len="setLayoutCount">const <type>VkDescriptorSetLayout</type>* <name>pSetLayouts</name><comment>Array of setCount number of descriptor set layout objects defining the layout of the</comment></member>
<member optional="true"><type>uint32_t</type> <name>pushConstantRangeCount</name><comment>Number of push-constant ranges used by the pipeline</comment></member>
<member len="pushConstantRangeCount">const <type>VkPushConstantRange</type>* <name>pPushConstantRanges</name><comment>Array of pushConstantRangeCount number of ranges used by various shader stages</comment></member>
</type>
@@ -1546,7 +1693,7 @@ typedef void <name>CAMetalLayer</name>;
<member><type>VkBool32</type> <name>dualSrcBlend</name><comment>blend operations which take two sources</comment></member>
<member><type>VkBool32</type> <name>logicOp</name><comment>logic operations</comment></member>
<member><type>VkBool32</type> <name>multiDrawIndirect</name><comment>multi draw indirect</comment></member>
- <member><type>VkBool32</type> <name>drawIndirectFirstInstance</name><comment>indirect draws can use non-zero firstInstance</comment></member>
+ <member><type>VkBool32</type> <name>drawIndirectFirstInstance</name><comment>indirect drawing can use non-zero firstInstance</comment></member>
<member><type>VkBool32</type> <name>depthClamp</name><comment>depth clamping</comment></member>
<member><type>VkBool32</type> <name>depthBiasClamp</name><comment>depth bias clamping</comment></member>
<member><type>VkBool32</type> <name>fillModeNonSolid</name><comment>point and wireframe fill modes</comment></member>
@@ -1593,11 +1740,11 @@ typedef void <name>CAMetalLayer</name>;
<member><type>VkBool32</type> <name>inheritedQueries</name><comment>Queries may be inherited from primary to secondary command buffers</comment></member>
</type>
<type category="struct" name="VkPhysicalDeviceSparseProperties" returnedonly="true">
- <member limittype="bitmask"><type>VkBool32</type> <name>residencyStandard2DBlockShape</name><comment>Sparse resources support: GPU will access all 2D (single sample) sparse resources using the standard sparse image block shapes (based on pixel format)</comment></member>
- <member limittype="bitmask"><type>VkBool32</type> <name>residencyStandard2DMultisampleBlockShape</name><comment>Sparse resources support: GPU will access all 2D (multisample) sparse resources using the standard sparse image block shapes (based on pixel format)</comment></member>
- <member limittype="bitmask"><type>VkBool32</type> <name>residencyStandard3DBlockShape</name><comment>Sparse resources support: GPU will access all 3D sparse resources using the standard sparse image block shapes (based on pixel format)</comment></member>
- <member limittype="bitmask"><type>VkBool32</type> <name>residencyAlignedMipSize</name><comment>Sparse resources support: Images with mip level dimensions that are NOT a multiple of the sparse image block dimensions will be placed in the mip tail</comment></member>
- <member limittype="bitmask"><type>VkBool32</type> <name>residencyNonResidentStrict</name><comment>Sparse resources support: GPU can consistently access non-resident regions of a resource, all reads return as if data is 0, writes are discarded</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>residencyStandard2DBlockShape</name><comment>Sparse resources support: GPU will access all 2D (single sample) sparse resources using the standard sparse image block shapes (based on pixel format)</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>residencyStandard2DMultisampleBlockShape</name><comment>Sparse resources support: GPU will access all 2D (multisample) sparse resources using the standard sparse image block shapes (based on pixel format)</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>residencyStandard3DBlockShape</name><comment>Sparse resources support: GPU will access all 3D sparse resources using the standard sparse image block shapes (based on pixel format)</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>residencyAlignedMipSize</name><comment>Sparse resources support: Images with mip level dimensions that are NOT a multiple of the sparse image block dimensions will be placed in the mip tail</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>residencyNonResidentStrict</name><comment>Sparse resources support: GPU can consistently access non-resident regions of a resource, all reads return as if data is 0, writes are discarded</comment></member>
</type>
<type category="struct" name="VkPhysicalDeviceLimits" returnedonly="true">
<comment>resource maximum sizes</comment>
@@ -1613,7 +1760,7 @@ typedef void <name>CAMetalLayer</name>;
<comment>memory limits</comment>
<member limittype="max"><type>uint32_t</type> <name>maxMemoryAllocationCount</name><comment>max number of device memory allocations supported</comment></member>
<member limittype="max"><type>uint32_t</type> <name>maxSamplerAllocationCount</name><comment>max number of samplers that can be allocated on a device</comment></member>
- <member limittype="noauto"><type>VkDeviceSize</type> <name>bufferImageGranularity</name><comment>Granularity (in bytes) at which buffers and images can be bound to adjacent memory for simultaneous usage</comment></member>
+ <member limittype="min,mul"><type>VkDeviceSize</type> <name>bufferImageGranularity</name><comment>Granularity (in bytes) at which buffers and images can be bound to adjacent memory for simultaneous usage</comment></member>
<member limittype="max"><type>VkDeviceSize</type> <name>sparseAddressSpaceSize</name><comment>Total address space available for sparse allocations (bytes)</comment></member>
<comment>descriptor set limits</comment>
<member limittype="max"><type>uint32_t</type> <name>maxBoundDescriptorSets</name><comment>max number of descriptors sets that can be bound to a pipeline</comment></member>
@@ -1664,28 +1811,28 @@ typedef void <name>CAMetalLayer</name>;
<member limittype="max"><type>uint32_t</type> <name>maxComputeWorkGroupCount</name>[3]<comment>max num of compute work groups that may be dispatched by a single command (x,y,z)</comment></member>
<member limittype="max"><type>uint32_t</type> <name>maxComputeWorkGroupInvocations</name><comment>max total compute invocations in a single local work group</comment></member>
<member limittype="max"><type>uint32_t</type> <name>maxComputeWorkGroupSize</name>[3]<comment>max local size of a compute work group (x,y,z)</comment></member>
- <member limittype="noauto"><type>uint32_t</type> <name>subPixelPrecisionBits</name><comment>number bits of subpixel precision in screen x and y</comment></member>
- <member limittype="noauto"><type>uint32_t</type> <name>subTexelPrecisionBits</name><comment>number bits of precision for selecting texel weights</comment></member>
- <member limittype="noauto"><type>uint32_t</type> <name>mipmapPrecisionBits</name><comment>number bits of precision for selecting mipmap weights</comment></member>
+ <member limittype="bits"><type>uint32_t</type> <name>subPixelPrecisionBits</name><comment>number bits of subpixel precision in screen x and y</comment></member>
+ <member limittype="bits"><type>uint32_t</type> <name>subTexelPrecisionBits</name><comment>number bits of precision for selecting texel weights</comment></member>
+ <member limittype="bits"><type>uint32_t</type> <name>mipmapPrecisionBits</name><comment>number bits of precision for selecting mipmap weights</comment></member>
<member limittype="max"><type>uint32_t</type> <name>maxDrawIndexedIndexValue</name><comment>max index value for indexed draw calls (for 32-bit indices)</comment></member>
- <member limittype="max"><type>uint32_t</type> <name>maxDrawIndirectCount</name><comment>max draw count for indirect draw calls</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxDrawIndirectCount</name><comment>max draw count for indirect drawing calls</comment></member>
<member limittype="max"><type>float</type> <name>maxSamplerLodBias</name><comment>max absolute sampler LOD bias</comment></member>
<member limittype="max"><type>float</type> <name>maxSamplerAnisotropy</name><comment>max degree of sampler anisotropy</comment></member>
<member limittype="max"><type>uint32_t</type> <name>maxViewports</name><comment>max number of active viewports</comment></member>
<member limittype="max"><type>uint32_t</type> <name>maxViewportDimensions</name>[2]<comment>max viewport dimensions (x,y)</comment></member>
- <member limittype="range"><type>float</type> <name>viewportBoundsRange</name>[2]<comment>viewport bounds range (min,max)</comment></member>
- <member limittype="noauto"><type>uint32_t</type> <name>viewportSubPixelBits</name><comment>number bits of subpixel precision for viewport</comment></member>
- <member limittype="noauto"><type>size_t</type> <name>minMemoryMapAlignment</name><comment>min required alignment of pointers returned by MapMemory (bytes)</comment></member>
- <member limittype="noauto"><type>VkDeviceSize</type> <name>minTexelBufferOffsetAlignment</name><comment>min required alignment for texel buffer offsets (bytes) </comment></member>
- <member limittype="noauto"><type>VkDeviceSize</type> <name>minUniformBufferOffsetAlignment</name><comment>min required alignment for uniform buffer sizes and offsets (bytes)</comment></member>
- <member limittype="noauto"><type>VkDeviceSize</type> <name>minStorageBufferOffsetAlignment</name><comment>min required alignment for storage buffer offsets (bytes)</comment></member>
+ <member limittype="range"><type>float</type> <name>viewportBoundsRange</name>[2]<comment>viewport bounds range (min,max)</comment></member>
+ <member limittype="bits"><type>uint32_t</type> <name>viewportSubPixelBits</name><comment>number bits of subpixel precision for viewport</comment></member>
+ <member limittype="min,pot"><type>size_t</type> <name>minMemoryMapAlignment</name><comment>min required alignment of pointers returned by MapMemory (bytes)</comment></member>
+ <member limittype="min,pot"><type>VkDeviceSize</type> <name>minTexelBufferOffsetAlignment</name><comment>min required alignment for texel buffer offsets (bytes) </comment></member>
+ <member limittype="min,pot"><type>VkDeviceSize</type> <name>minUniformBufferOffsetAlignment</name><comment>min required alignment for uniform buffer sizes and offsets (bytes)</comment></member>
+ <member limittype="min,pot"><type>VkDeviceSize</type> <name>minStorageBufferOffsetAlignment</name><comment>min required alignment for storage buffer offsets (bytes)</comment></member>
<member limittype="min"><type>int32_t</type> <name>minTexelOffset</name><comment>min texel offset for OpTextureSampleOffset</comment></member>
<member limittype="max"><type>uint32_t</type> <name>maxTexelOffset</name><comment>max texel offset for OpTextureSampleOffset</comment></member>
<member limittype="min"><type>int32_t</type> <name>minTexelGatherOffset</name><comment>min texel offset for OpTextureGatherOffset</comment></member>
<member limittype="max"><type>uint32_t</type> <name>maxTexelGatherOffset</name><comment>max texel offset for OpTextureGatherOffset</comment></member>
<member limittype="min"><type>float</type> <name>minInterpolationOffset</name><comment>furthest negative offset for interpolateAtOffset</comment></member>
<member limittype="max"><type>float</type> <name>maxInterpolationOffset</name><comment>furthest positive offset for interpolateAtOffset</comment></member>
- <member limittype="noauto"><type>uint32_t</type> <name>subPixelInterpolationOffsetBits</name><comment>number of subpixel bits for interpolateAtOffset</comment></member>
+ <member limittype="bits"><type>uint32_t</type> <name>subPixelInterpolationOffsetBits</name><comment>number of subpixel bits for interpolateAtOffset</comment></member>
<member limittype="max"><type>uint32_t</type> <name>maxFramebufferWidth</name><comment>max width for a framebuffer</comment></member>
<member limittype="max"><type>uint32_t</type> <name>maxFramebufferHeight</name><comment>max height for a framebuffer</comment></member>
<member limittype="max"><type>uint32_t</type> <name>maxFramebufferLayers</name><comment>max layer count for a layered framebuffer</comment></member>
@@ -1693,28 +1840,28 @@ typedef void <name>CAMetalLayer</name>;
<member limittype="bitmask" optional="true"><type>VkSampleCountFlags</type> <name>framebufferDepthSampleCounts</name><comment>supported depth sample counts for a framebuffer</comment></member>
<member limittype="bitmask" optional="true"><type>VkSampleCountFlags</type> <name>framebufferStencilSampleCounts</name><comment>supported stencil sample counts for a framebuffer</comment></member>
<member limittype="bitmask" optional="true"><type>VkSampleCountFlags</type> <name>framebufferNoAttachmentsSampleCounts</name><comment>supported sample counts for a subpass which uses no attachments</comment></member>
- <member limittype="bitmask"><type>uint32_t</type> <name>maxColorAttachments</name><comment>max number of color attachments per subpass</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxColorAttachments</name><comment>max number of color attachments per subpass</comment></member>
<member limittype="bitmask" optional="true"><type>VkSampleCountFlags</type> <name>sampledImageColorSampleCounts</name><comment>supported color sample counts for a non-integer sampled image</comment></member>
<member limittype="bitmask" optional="true"><type>VkSampleCountFlags</type> <name>sampledImageIntegerSampleCounts</name><comment>supported sample counts for an integer image</comment></member>
<member limittype="bitmask" optional="true"><type>VkSampleCountFlags</type> <name>sampledImageDepthSampleCounts</name><comment>supported depth sample counts for a sampled image</comment></member>
<member limittype="bitmask" optional="true"><type>VkSampleCountFlags</type> <name>sampledImageStencilSampleCounts</name><comment>supported stencil sample counts for a sampled image</comment></member>
<member limittype="bitmask" optional="true"><type>VkSampleCountFlags</type> <name>storageImageSampleCounts</name><comment>supported sample counts for a storage image</comment></member>
<member limittype="max"><type>uint32_t</type> <name>maxSampleMaskWords</name><comment>max number of sample mask words</comment></member>
- <member limittype="bitmask"><type>VkBool32</type> <name>timestampComputeAndGraphics</name><comment>timestamps on graphics and compute queues</comment></member>
- <member limittype="noauto"><type>float</type> <name>timestampPeriod</name><comment>number of nanoseconds it takes for timestamp query value to increment by 1</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>timestampComputeAndGraphics</name><comment>timestamps on graphics and compute queues</comment></member>
+ <member limittype="min,mul"><type>float</type> <name>timestampPeriod</name><comment>number of nanoseconds it takes for timestamp query value to increment by 1</comment></member>
<member limittype="max"><type>uint32_t</type> <name>maxClipDistances</name><comment>max number of clip distances</comment></member>
<member limittype="max"><type>uint32_t</type> <name>maxCullDistances</name><comment>max number of cull distances</comment></member>
<member limittype="max"><type>uint32_t</type> <name>maxCombinedClipAndCullDistances</name><comment>max combined number of user clipping</comment></member>
<member limittype="max"><type>uint32_t</type> <name>discreteQueuePriorities</name><comment>distinct queue priorities available </comment></member>
- <member limittype="range"><type>float</type> <name>pointSizeRange</name>[2]<comment>range (min,max) of supported point sizes</comment></member>
- <member limittype="range"><type>float</type> <name>lineWidthRange</name>[2]<comment>range (min,max) of supported line widths</comment></member>
- <member limittype="max"><type>float</type> <name>pointSizeGranularity</name><comment>granularity of supported point sizes</comment></member>
- <member limittype="max"><type>float</type> <name>lineWidthGranularity</name><comment>granularity of supported line widths</comment></member>
- <member limittype="noauto"><type>VkBool32</type> <name>strictLines</name><comment>line rasterization follows preferred rules</comment></member>
- <member limittype="noauto"><type>VkBool32</type> <name>standardSampleLocations</name><comment>supports standard sample locations for all supported sample counts</comment></member>
- <member limittype="noauto"><type>VkDeviceSize</type> <name>optimalBufferCopyOffsetAlignment</name><comment>optimal offset of buffer copies</comment></member>
- <member limittype="noauto"><type>VkDeviceSize</type> <name>optimalBufferCopyRowPitchAlignment</name><comment>optimal pitch of buffer copies</comment></member>
- <member limittype="noauto"><type>VkDeviceSize</type> <name>nonCoherentAtomSize</name><comment>minimum size and alignment for non-coherent host-mapped device memory access</comment></member>
+ <member limittype="range"><type>float</type> <name>pointSizeRange</name>[2]<comment>range (min,max) of supported point sizes</comment></member>
+ <member limittype="range"><type>float</type> <name>lineWidthRange</name>[2]<comment>range (min,max) of supported line widths</comment></member>
+ <member limittype="min,mul"><type>float</type> <name>pointSizeGranularity</name><comment>granularity of supported point sizes</comment></member>
+ <member limittype="min,mul"><type>float</type> <name>lineWidthGranularity</name><comment>granularity of supported line widths</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>strictLines</name><comment>line rasterization follows preferred rules</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>standardSampleLocations</name><comment>supports standard sample locations for all supported sample counts</comment></member>
+ <member limittype="min,pot"><type>VkDeviceSize</type> <name>optimalBufferCopyOffsetAlignment</name><comment>optimal offset of buffer copies</comment></member>
+ <member limittype="min,pot"><type>VkDeviceSize</type> <name>optimalBufferCopyRowPitchAlignment</name><comment>optimal pitch of buffer copies</comment></member>
+ <member limittype="min,pot"><type>VkDeviceSize</type> <name>nonCoherentAtomSize</name><comment>minimum size and alignment for non-coherent host-mapped device memory access</comment></member>
</type>
<type category="struct" name="VkSemaphoreCreateInfo">
<member values="VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
@@ -1733,7 +1880,7 @@ typedef void <name>CAMetalLayer</name>;
<member values="VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true">const <type>void</type>* <name>pNext</name></member>
<member optional="true"><type>VkFramebufferCreateFlags</type> <name>flags</name></member>
- <member><type>VkRenderPass</type> <name>renderPass</name></member>
+ <member><type>VkRenderPass</type> <name>renderPass</name></member>
<member optional="true"><type>uint32_t</type> <name>attachmentCount</name></member>
<member noautovalidity="true" len="attachmentCount">const <type>VkImageView</type>* <name>pAttachments</name></member>
<member><type>uint32_t</type> <name>width</name></member>
@@ -1772,7 +1919,7 @@ typedef void <name>CAMetalLayer</name>;
<member optional="true">const <type>void</type>* <name>pNext</name></member>
<member optional="true"><type>uint32_t</type> <name>waitSemaphoreCount</name></member>
<member len="waitSemaphoreCount">const <type>VkSemaphore</type>* <name>pWaitSemaphores</name></member>
- <member len="waitSemaphoreCount">const <type>VkPipelineStageFlags</type>* <name>pWaitDstStageMask</name></member>
+ <member optional="false,true" len="waitSemaphoreCount">const <type>VkPipelineStageFlags</type>* <name>pWaitDstStageMask</name></member>
<member optional="true"><type>uint32_t</type> <name>commandBufferCount</name></member>
<member len="commandBufferCount">const <type>VkCommandBuffer</type>* <name>pCommandBuffers</name></member>
<member optional="true"><type>uint32_t</type> <name>signalSemaphoreCount</name></member>
@@ -2040,7 +2187,7 @@ typedef void <name>CAMetalLayer</name>;
<member optional="true">const <type>SECURITY_ATTRIBUTES</type>* <name>pAttributes</name></member>
<member optional="true"><type>DWORD</type> <name>dwAccess</name></member>
</type>
- <type category="struct" name="VkWin32KeyedMutexAcquireReleaseInfoNV" structextends="VkSubmitInfo,VkSubmitInfo2KHR">
+ <type category="struct" name="VkWin32KeyedMutexAcquireReleaseInfoNV" structextends="VkSubmitInfo,VkSubmitInfo2">
<member values="VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_NV"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true">const <type>void</type>* <name>pNext</name></member>
<member optional="true"><type>uint32_t</type> <name>acquireCount</name></member>
@@ -2052,25 +2199,28 @@ typedef void <name>CAMetalLayer</name>;
<member len="releaseCount">const <type>uint64_t</type>* <name>pReleaseKeys</name></member>
</type>
<type category="struct" name="VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
- <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_FEATURES_NV"><type>VkStructureType</type><name>sType</name></member>
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_FEATURES_NV"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>deviceGeneratedCommands</name></member>
</type>
- <type category="struct" name="VkDevicePrivateDataCreateInfoEXT" allowduplicate="true" structextends="VkDeviceCreateInfo">
- <member values="VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <type category="struct" name="VkDevicePrivateDataCreateInfo" allowduplicate="true" structextends="VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true">const <type>void</type>* <name>pNext</name></member>
<member><type>uint32_t</type> <name>privateDataSlotRequestCount</name></member>
</type>
- <type category="struct" name="VkPrivateDataSlotCreateInfoEXT">
- <member values="VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <type category="struct" name="VkDevicePrivateDataCreateInfoEXT" alias="VkDevicePrivateDataCreateInfo"/>
+ <type category="struct" name="VkPrivateDataSlotCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true">const <type>void</type>* <name>pNext</name></member>
- <member><type>VkPrivateDataSlotCreateFlagsEXT</type> <name>flags</name></member>
+ <member><type>VkPrivateDataSlotCreateFlags</type> <name>flags</name></member>
</type>
- <type category="struct" name="VkPhysicalDevicePrivateDataFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
- <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <type category="struct" name="VkPrivateDataSlotCreateInfoEXT" alias="VkPrivateDataSlotCreateInfo"/>
+ <type category="struct" name="VkPhysicalDevicePrivateDataFeatures" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>privateData</name></member>
</type>
+ <type category="struct" name="VkPhysicalDevicePrivateDataFeaturesEXT" alias="VkPhysicalDevicePrivateDataFeatures"/>
<type category="struct" name="VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV" structextends="VkPhysicalDeviceProperties2" returnedonly="true">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_NV"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
@@ -2080,14 +2230,14 @@ typedef void <name>CAMetalLayer</name>;
<member limittype="max"><type>uint32_t</type> <name>maxIndirectCommandsStreamCount</name></member>
<member limittype="max"><type>uint32_t</type> <name>maxIndirectCommandsTokenOffset</name></member>
<member limittype="max"><type>uint32_t</type> <name>maxIndirectCommandsStreamStride</name></member>
- <member limittype="noauto"><type>uint32_t</type> <name>minSequencesCountBufferOffsetAlignment</name></member>
- <member limittype="noauto"><type>uint32_t</type> <name>minSequencesIndexBufferOffsetAlignment</name></member>
- <member limittype="noauto"><type>uint32_t</type> <name>minIndirectCommandsBufferOffsetAlignment</name></member>
+ <member limittype="min"><type>uint32_t</type> <name>minSequencesCountBufferOffsetAlignment</name></member>
+ <member limittype="min"><type>uint32_t</type> <name>minSequencesIndexBufferOffsetAlignment</name></member>
+ <member limittype="min"><type>uint32_t</type> <name>minIndirectCommandsBufferOffsetAlignment</name></member>
</type>
<type category="struct" name="VkPhysicalDeviceMultiDrawPropertiesEXT" structextends="VkPhysicalDeviceProperties2" returnedonly="true">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
- <member><type>uint32_t</type> <name>maxMultiDrawCount</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxMultiDrawCount</name></member>
</type>
<type category="struct" name="VkGraphicsShaderGroupCreateInfoNV">
<member values="VK_STRUCTURE_TYPE_GRAPHICS_SHADER_GROUP_CREATE_INFO_NV"><type>VkStructureType</type> <name>sType</name></member>
@@ -2099,8 +2249,8 @@ typedef void <name>CAMetalLayer</name>;
</type>
<type category="struct" name="VkGraphicsPipelineShaderGroupsCreateInfoNV" structextends="VkGraphicsPipelineCreateInfo">
<member values="VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_SHADER_GROUPS_CREATE_INFO_NV"><type>VkStructureType</type> <name>sType</name></member>
- <member optional="true">const <type>void</type>* <name>pNext</name></member>
- <member><type>uint32_t</type> <name>groupCount</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>uint32_t</type> <name>groupCount</name></member>
<member len="groupCount">const <type>VkGraphicsShaderGroupCreateInfoNV</type>* <name>pGroups</name></member>
<member optional="true"><type>uint32_t</type> <name>pipelineCount</name></member>
<member len="pipelineCount">const <type>VkPipeline</type>* <name>pPipelines</name></member>
@@ -2214,7 +2364,7 @@ typedef void <name>CAMetalLayer</name>;
<type category="struct" name="VkQueueFamilyProperties2" returnedonly="true">
<member values="VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
- <member><type>VkQueueFamilyProperties</type> <name>queueFamilyProperties</name></member>
+ <member limittype="struct"><type>VkQueueFamilyProperties</type> <name>queueFamilyProperties</name></member>
</type>
<type category="struct" name="VkQueueFamilyProperties2KHR" alias="VkQueueFamilyProperties2"/>
<type category="struct" name="VkPhysicalDeviceMemoryProperties2" returnedonly="true">
@@ -2226,7 +2376,7 @@ typedef void <name>CAMetalLayer</name>;
<type category="struct" name="VkSparseImageFormatProperties2" returnedonly="true">
<member values="VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
- <member><type>VkSparseImageFormatProperties</type> <name>properties</name></member>
+ <member limittype="struct"><type>VkSparseImageFormatProperties</type> <name>properties</name></member>
</type>
<type category="struct" name="VkSparseImageFormatProperties2KHR" alias="VkSparseImageFormatProperties2"/>
<type category="struct" name="VkPhysicalDeviceSparseImageFormatInfo2">
@@ -2254,10 +2404,10 @@ typedef void <name>CAMetalLayer</name>;
<type category="struct" name="VkPhysicalDeviceDriverProperties" structextends="VkPhysicalDeviceProperties2" returnedonly="true">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
- <member limittype="noauto"><type>VkDriverId</type> <name>driverID</name></member>
- <member limittype="noauto"><type>char</type> <name>driverName</name>[<enum>VK_MAX_DRIVER_NAME_SIZE</enum>]</member>
- <member limittype="noauto"><type>char</type> <name>driverInfo</name>[<enum>VK_MAX_DRIVER_INFO_SIZE</enum>]</member>
- <member limittype="noauto"><type>VkConformanceVersion</type> <name>conformanceVersion</name></member>
+ <member limittype="exact"><type>VkDriverId</type> <name>driverID</name></member>
+ <member limittype="exact"><type>char</type> <name>driverName</name>[<enum>VK_MAX_DRIVER_NAME_SIZE</enum>]</member>
+ <member limittype="exact"><type>char</type> <name>driverInfo</name>[<enum>VK_MAX_DRIVER_INFO_SIZE</enum>]</member>
+ <member limittype="exact"><type>VkConformanceVersion</type> <name>conformanceVersion</name></member>
</type>
<type category="struct" name="VkPhysicalDeviceDriverPropertiesKHR" alias="VkPhysicalDeviceDriverProperties"/>
<type category="struct" name="VkPresentRegionsKHR" structextends="VkPresentInfoKHR">
@@ -2319,11 +2469,11 @@ typedef void <name>CAMetalLayer</name>;
<type category="struct" name="VkPhysicalDeviceIDProperties" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
- <member limittype="noauto"><type>uint8_t</type> <name>deviceUUID</name>[<enum>VK_UUID_SIZE</enum>]</member>
- <member limittype="noauto"><type>uint8_t</type> <name>driverUUID</name>[<enum>VK_UUID_SIZE</enum>]</member>
- <member limittype="noauto"><type>uint8_t</type> <name>deviceLUID</name>[<enum>VK_LUID_SIZE</enum>]</member>
- <member limittype="noauto"><type>uint32_t</type> <name>deviceNodeMask</name></member>
- <member limittype="noauto"><type>VkBool32</type> <name>deviceLUIDValid</name></member>
+ <member limittype="noauto"><type>uint8_t</type> <name>deviceUUID</name>[<enum>VK_UUID_SIZE</enum>]</member>
+ <member limittype="noauto"><type>uint8_t</type> <name>driverUUID</name>[<enum>VK_UUID_SIZE</enum>]</member>
+ <member limittype="noauto"><type>uint8_t</type> <name>deviceLUID</name>[<enum>VK_LUID_SIZE</enum>]</member>
+ <member limittype="noauto"><type>uint32_t</type> <name>deviceNodeMask</name></member>
+ <member limittype="noauto"><type>VkBool32</type> <name>deviceLUIDValid</name></member>
</type>
<type category="struct" name="VkPhysicalDeviceIDPropertiesKHR" alias="VkPhysicalDeviceIDProperties"/>
<type category="struct" name="VkExternalMemoryImageCreateInfo" structextends="VkImageCreateInfo">
@@ -2360,18 +2510,18 @@ typedef void <name>CAMetalLayer</name>;
</type>
<type category="struct" name="VkImportMemoryZirconHandleInfoFUCHSIA" structextends="VkMemoryAllocateInfo">
<member values="VK_STRUCTURE_TYPE_IMPORT_MEMORY_ZIRCON_HANDLE_INFO_FUCHSIA"><type>VkStructureType</type> <name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
<member optional="true"><type>VkExternalMemoryHandleTypeFlagBits</type> <name>handleType</name></member>
<member optional="true"><type>zx_handle_t</type> <name>handle</name></member>
</type>
<type category="struct" name="VkMemoryZirconHandlePropertiesFUCHSIA" returnedonly="true">
<member values="VK_STRUCTURE_TYPE_MEMORY_ZIRCON_HANDLE_PROPERTIES_FUCHSIA"><type>VkStructureType</type> <name>sType</name></member>
- <member><type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
<member><type>uint32_t</type> <name>memoryTypeBits</name></member>
</type>
<type category="struct" name="VkMemoryGetZirconHandleInfoFUCHSIA">
<member values="VK_STRUCTURE_TYPE_MEMORY_GET_ZIRCON_HANDLE_INFO_FUCHSIA"><type>VkStructureType</type> <name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
<member><type>VkDeviceMemory</type> <name>memory</name></member>
<member><type>VkExternalMemoryHandleTypeFlagBits</type> <name>handleType</name></member>
</type>
@@ -2403,7 +2553,7 @@ typedef void <name>CAMetalLayer</name>;
<member><type>VkDeviceMemory</type> <name>memory</name></member>
<member><type>VkExternalMemoryHandleTypeFlagBits</type> <name>handleType</name></member>
</type>
- <type category="struct" name="VkWin32KeyedMutexAcquireReleaseInfoKHR" structextends="VkSubmitInfo,VkSubmitInfo2KHR">
+ <type category="struct" name="VkWin32KeyedMutexAcquireReleaseInfoKHR" structextends="VkSubmitInfo,VkSubmitInfo2">
<member values="VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true">const <type>void</type>* <name>pNext</name></member>
<member optional="true"><type>uint32_t</type> <name>acquireCount</name></member>
@@ -2656,7 +2806,7 @@ typedef void <name>CAMetalLayer</name>;
<member len="splitInstanceBindRegionCount">const <type>VkRect2D</type>* <name>pSplitInstanceBindRegions</name></member>
</type>
<type category="struct" name="VkBindImageMemoryDeviceGroupInfoKHR" alias="VkBindImageMemoryDeviceGroupInfo"/>
- <type category="struct" name="VkDeviceGroupRenderPassBeginInfo" structextends="VkRenderPassBeginInfo">
+ <type category="struct" name="VkDeviceGroupRenderPassBeginInfo" structextends="VkRenderPassBeginInfo,VkRenderingInfo">
<member values="VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true">const <type>void</type>* <name>pNext</name></member>
<member><type>uint32_t</type> <name>deviceMask</name></member>
@@ -2751,7 +2901,7 @@ typedef void <name>CAMetalLayer</name>;
<member><type>VkDescriptorUpdateTemplateType</type> <name>templateType</name></member>
<member noautovalidity="true"><type>VkDescriptorSetLayout</type> <name>descriptorSetLayout</name></member>
<member noautovalidity="true"><type>VkPipelineBindPoint</type> <name>pipelineBindPoint</name></member>
- <member noautovalidity="true"><type>VkPipelineLayout</type><name>pipelineLayout</name><comment>If used for push descriptors, this is the only allowed layout</comment></member>
+ <member noautovalidity="true"><type>VkPipelineLayout</type> <name>pipelineLayout</name><comment>If used for push descriptors, this is the only allowed layout</comment></member>
<member noautovalidity="true"><type>uint32_t</type> <name>set</name></member>
</type>
<type category="struct" name="VkDescriptorUpdateTemplateCreateInfoKHR" alias="VkDescriptorUpdateTemplateCreateInfo"/>
@@ -2766,7 +2916,7 @@ typedef void <name>CAMetalLayer</name>;
</type>
<type category="struct" name="VkPresentIdKHR" structextends="VkPresentInfoKHR">
<member values="VK_STRUCTURE_TYPE_PRESENT_ID_KHR"><type>VkStructureType</type> <name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
<member><type>uint32_t</type> <name>swapchainCount</name><comment>Copy of VkPresentInfoKHR::swapchainCount</comment></member>
<member len="swapchainCount" optional="true">const <type>uint64_t</type>* <name>pPresentIds</name><comment>Present ID values for each swapchain</comment></member>
</type>
@@ -2896,7 +3046,7 @@ typedef void <name>CAMetalLayer</name>;
<type category="struct" name="VkPhysicalDeviceSurfaceInfo2KHR">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true">const <type>void</type>* <name>pNext</name></member>
- <member><type>VkSurfaceKHR</type> <name>surface</name></member>
+ <member optional="true"><type>VkSurfaceKHR</type> <name>surface</name></member>
</type>
<type category="struct" name="VkSurfaceCapabilities2KHR" returnedonly="true">
<member values="VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
@@ -2951,7 +3101,7 @@ typedef void <name>CAMetalLayer</name>;
<type category="struct" name="VkPhysicalDeviceSubgroupProperties" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
- <member limittype="noauto" noautovalidity="true"><type>uint32_t</type> <name>subgroupSize</name><comment>The size of a subgroup for this queue.</comment></member>
+ <member limittype="max,pot" noautovalidity="true"><type>uint32_t</type> <name>subgroupSize</name><comment>The size of a subgroup for this queue.</comment></member>
<member limittype="bitmask" noautovalidity="true"><type>VkShaderStageFlags</type> <name>supportedStages</name><comment>Bitfield of what shader stages support subgroup operations</comment></member>
<member limittype="bitmask" noautovalidity="true"><type>VkSubgroupFeatureFlags</type> <name>supportedOperations</name><comment>Bitfield of what subgroup operations are supported.</comment></member>
<member limittype="bitmask" noautovalidity="true"><type>VkBool32</type> <name>quadOperationsInAllStages</name><comment>Flag to specify whether quad operations are available in all stages.</comment></member>
@@ -2968,6 +3118,12 @@ typedef void <name>CAMetalLayer</name>;
<member><type>VkBuffer</type> <name>buffer</name></member>
</type>
<type category="struct" name="VkBufferMemoryRequirementsInfo2KHR" alias="VkBufferMemoryRequirementsInfo2"/>
+ <type category="struct" name="VkDeviceBufferMemoryRequirements">
+ <member values="VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member>const <type>VkBufferCreateInfo</type>* <name>pCreateInfo</name></member>
+ </type>
+ <type category="struct" name="VkDeviceBufferMemoryRequirementsKHR" alias="VkDeviceBufferMemoryRequirements"/>
<type category="struct" name="VkImageMemoryRequirementsInfo2">
<member values="VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true">const <type>void</type>* <name>pNext</name></member>
@@ -2980,6 +3136,13 @@ typedef void <name>CAMetalLayer</name>;
<member><type>VkImage</type> <name>image</name></member>
</type>
<type category="struct" name="VkImageSparseMemoryRequirementsInfo2KHR" alias="VkImageSparseMemoryRequirementsInfo2"/>
+ <type category="struct" name="VkDeviceImageMemoryRequirements">
+ <member values="VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member>const <type>VkImageCreateInfo</type>* <name>pCreateInfo</name></member>
+ <member optional="true"><type>VkImageAspectFlagBits</type> <name>planeAspect</name></member>
+ </type>
+ <type category="struct" name="VkDeviceImageMemoryRequirementsKHR" alias="VkDeviceImageMemoryRequirements"/>
<type category="struct" name="VkMemoryRequirements2" returnedonly="true">
<member values="VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
@@ -2995,7 +3158,7 @@ typedef void <name>CAMetalLayer</name>;
<type category="struct" name="VkPhysicalDevicePointClippingProperties" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
- <member limittype="noauto"><type>VkPointClippingBehavior</type> <name>pointClippingBehavior</name></member>
+ <member limittype="exact"><type>VkPointClippingBehavior</type> <name>pointClippingBehavior</name></member>
</type>
<type category="struct" name="VkPhysicalDevicePointClippingPropertiesKHR" alias="VkPhysicalDevicePointClippingProperties"/>
<type category="struct" name="VkMemoryDedicatedRequirements" returnedonly="true" structextends="VkMemoryRequirements2">
@@ -3092,7 +3255,7 @@ typedef void <name>CAMetalLayer</name>;
<type category="struct" name="VkPhysicalDeviceProtectedMemoryProperties" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
- <member limittype="noauto"><type>VkBool32</type> <name>protectedNoFault</name></member>
+ <member limittype="exact"><type>VkBool32</type> <name>protectedNoFault</name></member>
</type>
<type category="struct" name="VkDeviceQueueInfo2">
<member values="VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2"><type>VkStructureType</type> <name>sType</name></member>
@@ -3119,7 +3282,7 @@ typedef void <name>CAMetalLayer</name>;
<member><type>float</type> <name>x</name></member>
<member><type>float</type> <name>y</name></member>
</type>
- <type category="struct" name="VkSampleLocationsInfoEXT" structextends="VkImageMemoryBarrier,VkImageMemoryBarrier2KHR">
+ <type category="struct" name="VkSampleLocationsInfoEXT" structextends="VkImageMemoryBarrier,VkImageMemoryBarrier2">
<member values="VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true">const <type>void</type>* <name>pNext</name></member>
<member noautovalidity="true"><type>VkSampleCountFlagBits</type> <name>sampleLocationsPerPixel</name></member>
@@ -3155,7 +3318,7 @@ typedef void <name>CAMetalLayer</name>;
<member limittype="bitmask"><type>VkSampleCountFlags</type> <name>sampleLocationSampleCounts</name></member>
<member limittype="max"><type>VkExtent2D</type> <name>maxSampleLocationGridSize</name></member>
<member limittype="range"><type>float</type> <name>sampleLocationCoordinateRange</name>[2]</member>
- <member limittype="noauto"><type>uint32_t</type> <name>sampleLocationSubPixelBits</name></member>
+ <member limittype="bits"><type>uint32_t</type> <name>sampleLocationSubPixelBits</name></member>
<member limittype="bitmask"><type>VkBool32</type> <name>variableSampleLocations</name></member>
</type>
<type category="struct" name="VkMultisamplePropertiesEXT" returnedonly="true">
@@ -3176,7 +3339,7 @@ typedef void <name>CAMetalLayer</name>;
</type>
<type category="struct" name="VkPhysicalDeviceMultiDrawFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
- <member noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>multiDraw</name></member>
</type>
<type category="struct" name="VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
@@ -3196,14 +3359,15 @@ typedef void <name>CAMetalLayer</name>;
<member><type>VkBool32</type> <name>dstPremultiplied</name></member>
<member><type>VkBlendOverlapEXT</type> <name>blendOverlap</name></member>
</type>
- <type category="struct" name="VkPhysicalDeviceInlineUniformBlockFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
- <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
- <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <type category="struct" name="VkPhysicalDeviceInlineUniformBlockFeatures" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>inlineUniformBlock</name></member>
<member><type>VkBool32</type> <name>descriptorBindingInlineUniformBlockUpdateAfterBind</name></member>
</type>
- <type category="struct" name="VkPhysicalDeviceInlineUniformBlockPropertiesEXT" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
- <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <type category="struct" name="VkPhysicalDeviceInlineUniformBlockFeaturesEXT" alias="VkPhysicalDeviceInlineUniformBlockFeatures"/>
+ <type category="struct" name="VkPhysicalDeviceInlineUniformBlockProperties" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
<member limittype="max"><type>uint32_t</type> <name>maxInlineUniformBlockSize</name></member>
<member limittype="max"><type>uint32_t</type> <name>maxPerStageDescriptorInlineUniformBlocks</name></member>
@@ -3211,17 +3375,20 @@ typedef void <name>CAMetalLayer</name>;
<member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetInlineUniformBlocks</name></member>
<member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetUpdateAfterBindInlineUniformBlocks</name></member>
</type>
- <type category="struct" name="VkWriteDescriptorSetInlineUniformBlockEXT" structextends="VkWriteDescriptorSet">
- <member values="VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT"><type>VkStructureType</type> <name>sType</name></member>
- <member optional="true">const <type>void</type>* <name>pNext</name></member>
- <member><type>uint32_t</type> <name>dataSize</name></member>
- <member len="dataSize">const <type>void</type>* <name>pData</name></member>
+ <type category="struct" name="VkPhysicalDeviceInlineUniformBlockPropertiesEXT" alias="VkPhysicalDeviceInlineUniformBlockProperties"/>
+ <type category="struct" name="VkWriteDescriptorSetInlineUniformBlock" structextends="VkWriteDescriptorSet">
+ <member values="VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>dataSize</name></member>
+ <member len="dataSize">const <type>void</type>* <name>pData</name></member>
</type>
- <type category="struct" name="VkDescriptorPoolInlineUniformBlockCreateInfoEXT" structextends="VkDescriptorPoolCreateInfo">
- <member values="VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
- <member optional="true">const <type>void</type>* <name>pNext</name></member>
- <member><type>uint32_t</type> <name>maxInlineUniformBlockBindings</name></member>
+ <type category="struct" name="VkWriteDescriptorSetInlineUniformBlockEXT" alias="VkWriteDescriptorSetInlineUniformBlock"/>
+ <type category="struct" name="VkDescriptorPoolInlineUniformBlockCreateInfo" structextends="VkDescriptorPoolCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>maxInlineUniformBlockBindings</name></member>
</type>
+ <type category="struct" name="VkDescriptorPoolInlineUniformBlockCreateInfoEXT" alias="VkDescriptorPoolInlineUniformBlockCreateInfo"/>
<type category="struct" name="VkPipelineCoverageModulationStateCreateInfoNV" structextends="VkPipelineMultisampleStateCreateInfo">
<member values="VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true">const <type>void</type>* <name>pNext</name></member>
@@ -3245,7 +3412,7 @@ typedef void <name>CAMetalLayer</name>;
<member optional="true"><type>size_t</type> <name>initialDataSize</name></member>
<member len="initialDataSize">const <type>void</type>* <name>pInitialData</name></member>
</type>
- <type category="struct" name="VkShaderModuleValidationCacheCreateInfoEXT" structextends="VkShaderModuleCreateInfo">
+ <type category="struct" name="VkShaderModuleValidationCacheCreateInfoEXT" structextends="VkShaderModuleCreateInfo,VkPipelineShaderStageCreateInfo">
<member values="VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true">const <type>void</type>* <name>pNext</name></member>
<member><type>VkValidationCacheEXT</type> <name>validationCache</name></member>
@@ -3257,6 +3424,18 @@ typedef void <name>CAMetalLayer</name>;
<member limittype="max"><type>VkDeviceSize</type> <name>maxMemoryAllocationSize</name></member>
</type>
<type category="struct" name="VkPhysicalDeviceMaintenance3PropertiesKHR" alias="VkPhysicalDeviceMaintenance3Properties"/>
+ <type category="struct" name="VkPhysicalDeviceMaintenance4Features" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>maintenance4</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceMaintenance4FeaturesKHR" alias="VkPhysicalDeviceMaintenance4Features"/>
+ <type category="struct" name="VkPhysicalDeviceMaintenance4Properties" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member limittype="max"><type>VkDeviceSize</type> <name>maxBufferSize</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceMaintenance4PropertiesKHR" alias="VkPhysicalDeviceMaintenance4Properties"/>
<type category="struct" name="VkDescriptorSetLayoutSupport" returnedonly="true">
<member values="VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
@@ -3280,8 +3459,8 @@ typedef void <name>CAMetalLayer</name>;
<type category="struct" name="VkPhysicalDeviceFloatControlsProperties" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
- <member limittype="noauto"><type>VkShaderFloatControlsIndependence</type> <name>denormBehaviorIndependence</name></member>
- <member limittype="noauto"><type>VkShaderFloatControlsIndependence</type> <name>roundingModeIndependence</name></member>
+ <member limittype="exact"><type>VkShaderFloatControlsIndependence</type> <name>denormBehaviorIndependence</name></member>
+ <member limittype="exact"><type>VkShaderFloatControlsIndependence</type> <name>roundingModeIndependence</name></member>
<member limittype="bitmask"><type>VkBool32</type> <name>shaderSignedZeroInfNanPreserveFloat16</name><comment>An implementation can preserve signed zero, nan, inf</comment></member>
<member limittype="bitmask"><type>VkBool32</type> <name>shaderSignedZeroInfNanPreserveFloat32</name><comment>An implementation can preserve signed zero, nan, inf</comment></member>
<member limittype="bitmask"><type>VkBool32</type> <name>shaderSignedZeroInfNanPreserveFloat64</name><comment>An implementation can preserve signed zero, nan, inf</comment></member>
@@ -3344,23 +3523,26 @@ typedef void <name>CAMetalLayer</name>;
<member><type>uint32_t</type> <name>numAvailableSgprs</name></member>
<member><type>uint32_t</type> <name>computeWorkGroupSize</name>[3]</member>
</type>
- <type category="struct" name="VkDeviceQueueGlobalPriorityCreateInfoEXT" structextends="VkDeviceQueueCreateInfo">
- <member values="VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <type category="struct" name="VkDeviceQueueGlobalPriorityCreateInfoKHR" structextends="VkDeviceQueueCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true">const <type>void</type>* <name>pNext</name></member>
- <member><type>VkQueueGlobalPriorityEXT</type> <name>globalPriority</name></member>
+ <member><type>VkQueueGlobalPriorityKHR</type> <name>globalPriority</name></member>
</type>
- <type category="struct" name="VkPhysicalDeviceGlobalPriorityQueryFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
- <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
- <member noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <type category="struct" name="VkDeviceQueueGlobalPriorityCreateInfoEXT" alias="VkDeviceQueueGlobalPriorityCreateInfoKHR"/>
+ <type category="struct" name="VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>globalPriorityQuery</name></member>
</type>
- <type category="struct" name="VkQueueFamilyGlobalPriorityPropertiesEXT" structextends="VkQueueFamilyProperties2">
- <member values="VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <type category="struct" name="VkPhysicalDeviceGlobalPriorityQueryFeaturesEXT" alias="VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR"/>
+ <type category="struct" name="VkQueueFamilyGlobalPriorityPropertiesKHR" structextends="VkQueueFamilyProperties2">
+ <member values="VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_KHR"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
- <member><type>uint32_t</type> <name>priorityCount</name></member>
- <member><type>VkQueueGlobalPriorityEXT</type> <name>priorities</name>[<enum>VK_MAX_GLOBAL_PRIORITY_SIZE_EXT</enum>]</member>
+ <member limittype="max"><type>uint32_t</type> <name>priorityCount</name></member>
+ <member limittype="bitmask"><type>VkQueueGlobalPriorityKHR</type> <name>priorities</name>[<enum>VK_MAX_GLOBAL_PRIORITY_SIZE_KHR</enum>]</member>
</type>
- <type category="struct" name="VkDebugUtilsObjectNameInfoEXT">
+ <type category="struct" name="VkQueueFamilyGlobalPriorityPropertiesEXT" alias="VkQueueFamilyGlobalPriorityPropertiesKHR"/>
+ <type category="struct" name="VkDebugUtilsObjectNameInfoEXT" structextends="VkPipelineShaderStageCreateInfo">
<member values="VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true">const <type>void</type>* <name>pNext</name></member>
<member><type>VkObjectType</type> <name>objectType</name></member>
@@ -3425,7 +3607,7 @@ typedef void <name>CAMetalLayer</name>;
<member><type>uint64_t</type> <name>memoryObjectId</name></member>
<member><type>VkDeviceSize</type> <name>size</name></member>
<member><type>VkObjectType</type> <name>objectType</name></member>
- <member><type>uint64_t</type> <name>objectHandle</name></member>
+ <member objecttype="objectType"><type>uint64_t</type> <name>objectHandle</name></member>
<member><type>uint32_t</type> <name>heapIndex</name></member>
</type>
<type category="struct" name="VkImportMemoryHostPointerInfoEXT" structextends="VkMemoryAllocateInfo">
@@ -3442,18 +3624,18 @@ typedef void <name>CAMetalLayer</name>;
<type category="struct" name="VkPhysicalDeviceExternalMemoryHostPropertiesEXT" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
- <member limittype="noauto"><type>VkDeviceSize</type> <name>minImportedHostPointerAlignment</name></member>
+ <member limittype="min,pot"><type>VkDeviceSize</type> <name>minImportedHostPointerAlignment</name></member>
</type>
<type category="struct" name="VkPhysicalDeviceConservativeRasterizationPropertiesEXT" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
- <member limittype="noauto"><type>float</type> <name>primitiveOverestimationSize</name><comment>The size in pixels the primitive is enlarged at each edge during conservative rasterization</comment></member>
- <member limittype="max"><type>float</type> <name>maxExtraPrimitiveOverestimationSize</name><comment>The maximum additional overestimation the client can specify in the pipeline state</comment></member>
- <member limittype="noauto"><type>float</type> <name>extraPrimitiveOverestimationSizeGranularity</name><comment>The granularity of extra overestimation sizes the implementations supports between 0 and maxExtraOverestimationSize</comment></member>
+ <member limittype="exact"><type>float</type> <name>primitiveOverestimationSize</name><comment>The size in pixels the primitive is enlarged at each edge during conservative rasterization</comment></member>
+ <member limittype="max"><type>float</type> <name>maxExtraPrimitiveOverestimationSize</name><comment>The maximum additional overestimation the client can specify in the pipeline state</comment></member>
+ <member limittype="min,mul"><type>float</type> <name>extraPrimitiveOverestimationSizeGranularity</name><comment>The granularity of extra overestimation sizes the implementations supports between 0 and maxExtraOverestimationSize</comment></member>
<member limittype="bitmask"><type>VkBool32</type> <name>primitiveUnderestimation</name><comment>true if the implementation supports conservative rasterization underestimation mode</comment></member>
- <member limittype="noauto"><type>VkBool32</type> <name>conservativePointAndLineRasterization</name><comment>true if conservative rasterization also applies to points and lines</comment></member>
- <member limittype="noauto"><type>VkBool32</type> <name>degenerateTrianglesRasterized</name><comment>true if degenerate triangles (those with zero area after snap) are rasterized</comment></member>
- <member limittype="noauto"><type>VkBool32</type> <name>degenerateLinesRasterized</name><comment>true if degenerate lines (those with zero length after snap) are rasterized</comment></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>conservativePointAndLineRasterization</name><comment>true if conservative rasterization also applies to points and lines</comment></member>
+ <member limittype="exact"><type>VkBool32</type> <name>degenerateTrianglesRasterized</name><comment>true if degenerate triangles (those with zero area after snap) are rasterized</comment></member>
+ <member limittype="exact"><type>VkBool32</type> <name>degenerateLinesRasterized</name><comment>true if degenerate lines (those with zero length after snap) are rasterized</comment></member>
<member limittype="bitmask"><type>VkBool32</type> <name>fullyCoveredFragmentShaderInputVariable</name><comment>true if the implementation supports the FullyCoveredEXT SPIR-V builtin fragment shader input variable</comment></member>
<member limittype="bitmask"><type>VkBool32</type> <name>conservativeRasterizationPostDepthCoverage</name><comment>true if the implementation supports both conservative rasterization and post depth coverage sample coverage mask</comment></member>
</type>
@@ -3465,20 +3647,20 @@ typedef void <name>CAMetalLayer</name>;
<type category="struct" name="VkPhysicalDeviceShaderCorePropertiesAMD" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
- <member limittype="max"><type>uint32_t</type> <name>shaderEngineCount</name><comment>number of shader engines</comment></member>
- <member limittype="max"><type>uint32_t</type> <name>shaderArraysPerEngineCount</name><comment>number of shader arrays</comment></member>
- <member limittype="max"><type>uint32_t</type> <name>computeUnitsPerShaderArray</name><comment>number of physical CUs per shader array</comment></member>
- <member limittype="max"><type>uint32_t</type> <name>simdPerComputeUnit</name><comment>number of SIMDs per compute unit</comment></member>
- <member limittype="max"><type>uint32_t</type> <name>wavefrontsPerSimd</name><comment>number of wavefront slots in each SIMD</comment></member>
- <member limittype="max"><type>uint32_t</type> <name>wavefrontSize</name><comment>maximum number of threads per wavefront</comment></member>
- <member limittype="max"><type>uint32_t</type> <name>sgprsPerSimd</name><comment>number of physical SGPRs per SIMD</comment></member>
- <member limittype="min"><type>uint32_t</type> <name>minSgprAllocation</name><comment>minimum number of SGPRs that can be allocated by a wave</comment></member>
- <member limittype="max"><type>uint32_t</type> <name>maxSgprAllocation</name><comment>number of available SGPRs</comment></member>
- <member limittype="noauto"><type>uint32_t</type> <name>sgprAllocationGranularity</name><comment>SGPRs are allocated in groups of this size</comment></member>
- <member limittype="max"><type>uint32_t</type> <name>vgprsPerSimd</name><comment>number of physical VGPRs per SIMD</comment></member>
- <member limittype="min"><type>uint32_t</type> <name>minVgprAllocation</name><comment>minimum number of VGPRs that can be allocated by a wave</comment></member>
- <member limittype="max"><type>uint32_t</type> <name>maxVgprAllocation</name><comment>number of available VGPRs</comment></member>
- <member limittype="noauto"><type>uint32_t</type> <name>vgprAllocationGranularity</name><comment>VGPRs are allocated in groups of this size</comment></member>
+ <member limittype="exact"><type>uint32_t</type> <name>shaderEngineCount</name><comment>number of shader engines</comment></member>
+ <member limittype="exact"><type>uint32_t</type> <name>shaderArraysPerEngineCount</name><comment>number of shader arrays</comment></member>
+ <member limittype="exact"><type>uint32_t</type> <name>computeUnitsPerShaderArray</name><comment>number of physical CUs per shader array</comment></member>
+ <member limittype="exact"><type>uint32_t</type> <name>simdPerComputeUnit</name><comment>number of SIMDs per compute unit</comment></member>
+ <member limittype="exact"><type>uint32_t</type> <name>wavefrontsPerSimd</name><comment>number of wavefront slots in each SIMD</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>wavefrontSize</name><comment>maximum number of threads per wavefront</comment></member>
+ <member limittype="exact"><type>uint32_t</type> <name>sgprsPerSimd</name><comment>number of physical SGPRs per SIMD</comment></member>
+ <member limittype="min"><type>uint32_t</type> <name>minSgprAllocation</name><comment>minimum number of SGPRs that can be allocated by a wave</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxSgprAllocation</name><comment>number of available SGPRs</comment></member>
+ <member limittype="min,mul"><type>uint32_t</type> <name>sgprAllocationGranularity</name><comment>SGPRs are allocated in groups of this size</comment></member>
+ <member limittype="exact"><type>uint32_t</type> <name>vgprsPerSimd</name><comment>number of physical VGPRs per SIMD</comment></member>
+ <member limittype="min"><type>uint32_t</type> <name>minVgprAllocation</name><comment>minimum number of VGPRs that can be allocated by a wave</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxVgprAllocation</name><comment>number of available VGPRs</comment></member>
+ <member limittype="min,mul"><type>uint32_t</type> <name>vgprAllocationGranularity</name><comment>VGPRs are allocated in groups of this size</comment></member>
</type>
<type category="struct" name="VkPhysicalDeviceShaderCoreProperties2AMD" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_2_AMD"><type>VkStructureType</type> <name>sType</name></member>
@@ -3799,7 +3981,7 @@ typedef void <name>CAMetalLayer</name>;
</type>
<type category="struct" name="VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_2_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
- <member><type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>shaderBufferFloat16Atomics</name></member>
<member><type>VkBool32</type> <name>shaderBufferFloat16AtomicAdd</name></member>
<member><type>VkBool32</type> <name>shaderBufferFloat16AtomicMinMax</name></member>
@@ -3822,7 +4004,7 @@ typedef void <name>CAMetalLayer</name>;
<type category="struct" name="VkQueueFamilyCheckpointPropertiesNV" structextends="VkQueueFamilyProperties2" returnedonly="true">
<member values="VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
- <member><type>VkPipelineStageFlags</type> <name>checkpointExecutionStageMask</name></member>
+ <member limittype="bitmask"><type>VkPipelineStageFlags</type> <name>checkpointExecutionStageMask</name></member>
</type>
<type category="struct" name="VkCheckpointDataNV" returnedonly="true">
<member values="VK_STRUCTURE_TYPE_CHECKPOINT_DATA_NV"><type>VkStructureType</type> <name>sType</name></member>
@@ -3871,7 +4053,7 @@ typedef void <name>CAMetalLayer</name>;
<member limittype="max"><type>VkDeviceSize</type> <name>maxTransformFeedbackBufferSize</name></member>
<member limittype="max"><type>uint32_t</type> <name>maxTransformFeedbackStreamDataSize</name></member>
<member limittype="max"><type>uint32_t</type> <name>maxTransformFeedbackBufferDataSize</name></member>
- <member limittype="noauto"><type>uint32_t</type> <name>maxTransformFeedbackBufferDataStride</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxTransformFeedbackBufferDataStride</name></member>
<member limittype="bitmask"><type>VkBool32</type> <name>transformFeedbackQueries</name></member>
<member limittype="bitmask"><type>VkBool32</type> <name>transformFeedbackStreamsLinesTriangles</name></member>
<member limittype="bitmask"><type>VkBool32</type> <name>transformFeedbackRasterizationStreamSelect</name></member>
@@ -3884,7 +4066,7 @@ typedef void <name>CAMetalLayer</name>;
<member><type>uint32_t</type> <name>rasterizationStream</name></member>
</type>
<type category="struct" name="VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
- <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV"><type>VkStructureType</type><name>sType</name></member>
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>representativeFragmentTest</name></member>
</type>
@@ -3915,11 +4097,7 @@ typedef void <name>CAMetalLayer</name>;
<member><type>VkBool32</type> <name>computeDerivativeGroupQuads</name></member>
<member><type>VkBool32</type> <name>computeDerivativeGroupLinear</name></member>
</type>
- <type category="struct" name="VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
- <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_NV"><type>VkStructureType</type> <name>sType</name></member>
- <member optional="true"><type>void</type>* <name>pNext</name></member>
- <member><type>VkBool32</type> <name>fragmentShaderBarycentric</name></member>
- </type>
+ <type category="struct" name="VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV" alias="VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR"/>
<type category="struct" name="VkPhysicalDeviceShaderImageFootprintFeaturesNV" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_FOOTPRINT_FEATURES_NV"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
@@ -3930,6 +4108,27 @@ typedef void <name>CAMetalLayer</name>;
<member optional="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>dedicatedAllocationImageAliasing</name></member>
</type>
+ <type category="struct" name="VkPhysicalDeviceCopyMemoryIndirectFeaturesNV" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_FEATURES_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>indirectCopy</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceCopyMemoryIndirectPropertiesNV" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_PROPERTIES_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member limittype="bitmask" noautovalidity="true"><type>VkQueueFlags</type> <name>supportedQueues</name><comment>Bitfield of which queues are supported for indirect copy</comment></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceMemoryDecompressionFeaturesNV" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_FEATURES_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>memoryDecompression</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceMemoryDecompressionPropertiesNV" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_PROPERTIES_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member limittype="bitmask"><type>VkMemoryDecompressionMethodFlagsNV</type> <name>decompressionMethods</name></member>
+ <member limittype="max"><type>uint64_t</type> <name>maxDecompressionIndirectCount</name></member>
+ </type>
<type category="struct" name="VkShadingRatePaletteNV">
<member><type>uint32_t</type> <name>shadingRatePaletteEntryCount</name></member>
<member len="shadingRatePaletteEntryCount">const <type>VkShadingRatePaletteEntryNV</type>* <name>pShadingRatePaletteEntries</name></member>
@@ -3950,7 +4149,7 @@ typedef void <name>CAMetalLayer</name>;
<type category="struct" name="VkPhysicalDeviceShadingRateImagePropertiesNV" structextends="VkPhysicalDeviceProperties2" returnedonly="true">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
- <member limittype="noauto"><type>VkExtent2D</type> <name>shadingRateTexelSize</name></member>
+ <member limittype="exact"><type>VkExtent2D</type> <name>shadingRateTexelSize</name></member>
<member limittype="max"><type>uint32_t</type> <name>shadingRatePaletteSize</name></member>
<member limittype="max"><type>uint32_t</type> <name>shadingRateMaxCoarseSamples</name></member>
</type>
@@ -3997,13 +4196,59 @@ typedef void <name>CAMetalLayer</name>;
<member limittype="max"><type>uint32_t</type> <name>maxMeshOutputVertices</name></member>
<member limittype="max"><type>uint32_t</type> <name>maxMeshOutputPrimitives</name></member>
<member limittype="max"><type>uint32_t</type> <name>maxMeshMultiviewViewCount</name></member>
- <member limittype="noauto"><type>uint32_t</type> <name>meshOutputPerVertexGranularity</name></member>
- <member limittype="noauto"><type>uint32_t</type> <name>meshOutputPerPrimitiveGranularity</name></member>
+ <member limittype="min,mul"><type>uint32_t</type> <name>meshOutputPerVertexGranularity</name></member>
+ <member limittype="min,mul"><type>uint32_t</type> <name>meshOutputPerPrimitiveGranularity</name></member>
</type>
<type category="struct" name="VkDrawMeshTasksIndirectCommandNV">
<member><type>uint32_t</type> <name>taskCount</name></member>
<member><type>uint32_t</type> <name>firstTask</name></member>
</type>
+ <type category="struct" name="VkPhysicalDeviceMeshShaderFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>taskShader</name></member>
+ <member><type>VkBool32</type> <name>meshShader</name></member>
+ <member><type>VkBool32</type> <name>multiviewMeshShader</name></member>
+ <member><type>VkBool32</type> <name>primitiveFragmentShadingRateMeshShader</name></member>
+ <member><type>VkBool32</type> <name>meshShaderQueries</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceMeshShaderPropertiesEXT" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxTaskWorkGroupTotalCount</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxTaskWorkGroupCount</name>[3]</member>
+ <member limittype="max"><type>uint32_t</type> <name>maxTaskWorkGroupInvocations</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxTaskWorkGroupSize</name>[3]</member>
+ <member limittype="max"><type>uint32_t</type> <name>maxTaskPayloadSize</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxTaskSharedMemorySize</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxTaskPayloadAndSharedMemorySize</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxMeshWorkGroupTotalCount</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxMeshWorkGroupCount</name>[3]</member>
+ <member limittype="max"><type>uint32_t</type> <name>maxMeshWorkGroupInvocations</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxMeshWorkGroupSize</name>[3]</member>
+ <member limittype="max"><type>uint32_t</type> <name>maxMeshSharedMemorySize</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxMeshPayloadAndSharedMemorySize</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxMeshOutputMemorySize</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxMeshPayloadAndOutputMemorySize</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxMeshOutputComponents</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxMeshOutputVertices</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxMeshOutputPrimitives</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxMeshOutputLayers</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxMeshMultiviewViewCount</name></member>
+ <member limittype="noauto"><type>uint32_t</type> <name>meshOutputPerVertexGranularity</name></member>
+ <member limittype="noauto"><type>uint32_t</type> <name>meshOutputPerPrimitiveGranularity</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxPreferredTaskWorkGroupInvocations</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxPreferredMeshWorkGroupInvocations</name></member>
+ <member limittype="noauto"><type>VkBool32</type> <name>prefersLocalInvocationVertexOutput</name></member>
+ <member limittype="noauto"><type>VkBool32</type> <name>prefersLocalInvocationPrimitiveOutput</name></member>
+ <member limittype="noauto"><type>VkBool32</type> <name>prefersCompactVertexOutput</name></member>
+ <member limittype="noauto"><type>VkBool32</type> <name>prefersCompactPrimitiveOutput</name></member>
+ </type>
+ <type category="struct" name="VkDrawMeshTasksIndirectCommandEXT">
+ <member noautovalidity="true"><type>uint32_t</type> <name>groupCountX</name></member>
+ <member noautovalidity="true"><type>uint32_t</type> <name>groupCountY</name></member>
+ <member noautovalidity="true"><type>uint32_t</type> <name>groupCountZ</name></member>
+ </type>
<type category="struct" name="VkRayTracingShaderGroupCreateInfoNV">
<member values="VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true">const <type>void</type>* <name>pNext</name></member>
@@ -4090,7 +4335,7 @@ typedef void <name>CAMetalLayer</name>;
<member values="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true">const <type>void</type>* <name>pNext</name></member>
<member><type>VkAccelerationStructureTypeNV</type> <name>type</name></member>
- <member optional="true"><type>VkBuildAccelerationStructureFlagsNV</type><name>flags</name></member>
+ <member optional="true"><type>VkBuildAccelerationStructureFlagsNV</type> <name>flags</name></member>
<member optional="true"><type>uint32_t</type> <name>instanceCount</name></member>
<member optional="true"><type>uint32_t</type> <name>geometryCount</name></member>
<member len="geometryCount">const <type>VkGeometryNV</type>* <name>pGeometries</name></member>
@@ -4166,22 +4411,22 @@ typedef void <name>CAMetalLayer</name>;
<type category="struct" name="VkPhysicalDeviceRayTracingPipelinePropertiesKHR" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
- <member limittype="noauto"><type>uint32_t</type> <name>shaderGroupHandleSize</name></member>
+ <member limittype="exact"><type>uint32_t</type> <name>shaderGroupHandleSize</name></member>
<member limittype="max"><type>uint32_t</type> <name>maxRayRecursionDepth</name></member>
<member limittype="max"><type>uint32_t</type> <name>maxShaderGroupStride</name></member>
- <member limittype="noauto"><type>uint32_t</type> <name>shaderGroupBaseAlignment</name></member>
- <member limittype="noauto"><type>uint32_t</type> <name>shaderGroupHandleCaptureReplaySize</name></member>
+ <member limittype="exact"><type>uint32_t</type> <name>shaderGroupBaseAlignment</name></member>
+ <member limittype="exact"><type>uint32_t</type> <name>shaderGroupHandleCaptureReplaySize</name></member>
<member limittype="max"><type>uint32_t</type> <name>maxRayDispatchInvocationCount</name></member>
- <member limittype="noauto"><type>uint32_t</type> <name>shaderGroupHandleAlignment</name></member>
+ <member limittype="min,pot"><type>uint32_t</type> <name>shaderGroupHandleAlignment</name></member>
<member limittype="max"><type>uint32_t</type> <name>maxRayHitAttributeSize</name></member>
</type>
<type category="struct" name="VkPhysicalDeviceRayTracingPropertiesNV" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
- <member limittype="noauto"><type>uint32_t</type> <name>shaderGroupHandleSize</name></member>
+ <member limittype="exact"><type>uint32_t</type> <name>shaderGroupHandleSize</name></member>
<member limittype="max"><type>uint32_t</type> <name>maxRecursionDepth</name></member>
<member limittype="max"><type>uint32_t</type> <name>maxShaderGroupStride</name></member>
- <member limittype="noauto"><type>uint32_t</type> <name>shaderGroupBaseAlignment</name></member>
+ <member limittype="exact"><type>uint32_t</type> <name>shaderGroupBaseAlignment</name></member>
<member limittype="max"><type>uint64_t</type> <name>maxGeometryCount</name></member>
<member limittype="max"><type>uint64_t</type> <name>maxInstanceCount</name></member>
<member limittype="max"><type>uint64_t</type> <name>maxTriangleCount</name></member>
@@ -4197,11 +4442,33 @@ typedef void <name>CAMetalLayer</name>;
<member><type>uint32_t</type> <name>height</name></member>
<member><type>uint32_t</type> <name>depth</name></member>
</type>
+ <type category="struct" name="VkTraceRaysIndirectCommand2KHR">
+ <member><type>VkDeviceAddress</type> <name>raygenShaderRecordAddress</name></member>
+ <member><type>VkDeviceSize</type> <name>raygenShaderRecordSize</name></member>
+ <member><type>VkDeviceAddress</type> <name>missShaderBindingTableAddress</name></member>
+ <member><type>VkDeviceSize</type> <name>missShaderBindingTableSize</name></member>
+ <member><type>VkDeviceSize</type> <name>missShaderBindingTableStride</name></member>
+ <member><type>VkDeviceAddress</type> <name>hitShaderBindingTableAddress</name></member>
+ <member><type>VkDeviceSize</type> <name>hitShaderBindingTableSize</name></member>
+ <member><type>VkDeviceSize</type> <name>hitShaderBindingTableStride</name></member>
+ <member><type>VkDeviceAddress</type> <name>callableShaderBindingTableAddress</name></member>
+ <member><type>VkDeviceSize</type> <name>callableShaderBindingTableSize</name></member>
+ <member><type>VkDeviceSize</type> <name>callableShaderBindingTableStride</name></member>
+ <member><type>uint32_t</type> <name>width</name></member>
+ <member><type>uint32_t</type> <name>height</name></member>
+ <member><type>uint32_t</type> <name>depth</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MAINTENANCE_1_FEATURES_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>rayTracingMaintenance1</name></member>
+ <member><type>VkBool32</type> <name>rayTracingPipelineTraceRaysIndirect2</name></member>
+ </type>
<type category="struct" name="VkDrmFormatModifierPropertiesListEXT" returnedonly="true" structextends="VkFormatProperties2">
<member values="VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
<member optional="true"><type>uint32_t</type> <name>drmFormatModifierCount</name></member>
- <member optional="true,false" len="drmFormatModifierCount"><type>VkDrmFormatModifierPropertiesEXT</type>* <name>pDrmFormatModifierProperties</name></member>
+ <member optional="true" len="drmFormatModifierCount"><type>VkDrmFormatModifierPropertiesEXT</type>* <name>pDrmFormatModifierProperties</name></member>
</type>
<type category="struct" name="VkDrmFormatModifierPropertiesEXT" returnedonly="true">
<member><type>uint64_t</type> <name>drmFormatModifier</name></member>
@@ -4257,26 +4524,42 @@ typedef void <name>CAMetalLayer</name>;
<member optional="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>fragmentDensityMapDeferred</name></member>
</type>
+ <type category="struct" name="VkPhysicalDeviceFragmentDensityMapOffsetFeaturesQCOM" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_FEATURES_QCOM"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>fragmentDensityMapOffset</name></member>
+ </type>
<type category="struct" name="VkPhysicalDeviceFragmentDensityMapPropertiesEXT" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
<member limittype="min"><type>VkExtent2D</type> <name>minFragmentDensityTexelSize</name></member>
<member limittype="max"><type>VkExtent2D</type> <name>maxFragmentDensityTexelSize</name></member>
- <member limittype="bitmask"><type>VkBool32</type> <name>fragmentDensityInvocations</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>fragmentDensityInvocations</name></member>
</type>
<type category="struct" name="VkPhysicalDeviceFragmentDensityMap2PropertiesEXT" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_PROPERTIES_EXT"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
- <member limittype="noauto"><type>VkBool32</type> <name>subsampledLoads</name></member>
- <member limittype="noauto"><type>VkBool32</type> <name>subsampledCoarseReconstructionEarlyAccess</name></member>
+ <member limittype="exact"><type>VkBool32</type> <name>subsampledLoads</name></member>
+ <member limittype="exact"><type>VkBool32</type> <name>subsampledCoarseReconstructionEarlyAccess</name></member>
<member limittype="max"><type>uint32_t</type> <name>maxSubsampledArrayLayers</name></member>
<member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetSubsampledSamplers</name></member>
</type>
+ <type category="struct" name="VkPhysicalDeviceFragmentDensityMapOffsetPropertiesQCOM" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_PROPERTIES_QCOM"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member limittype="min,mul"><type>VkExtent2D</type> <name>fragmentDensityOffsetGranularity</name></member>
+ </type>
<type category="struct" name="VkRenderPassFragmentDensityMapCreateInfoEXT" structextends="VkRenderPassCreateInfo,VkRenderPassCreateInfo2">
<member values="VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_CREATE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true">const <type>void</type>* <name>pNext</name></member>
<member><type>VkAttachmentReference</type> <name>fragmentDensityMapAttachment</name></member>
</type>
+ <type category="struct" name="VkSubpassFragmentDensityMapOffsetEndInfoQCOM" structextends="VkSubpassEndInfo">
+ <member values="VK_STRUCTURE_TYPE_SUBPASS_FRAGMENT_DENSITY_MAP_OFFSET_END_INFO_QCOM"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>uint32_t</type> <name>fragmentDensityOffsetCount</name></member>
+ <member len="fragmentDensityOffsetCount">const <type>VkOffset2D</type>* <name>pFragmentDensityOffsets</name></member>
+ </type>
<type category="struct" name="VkPhysicalDeviceScalarBlockLayoutFeatures" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
@@ -4321,6 +4604,11 @@ typedef void <name>CAMetalLayer</name>;
<member optional="true">const <type>void</type>* <name>pNext</name></member>
<member><type>float</type> <name>priority</name></member>
</type>
+ <type category="struct" name="VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PAGEABLE_DEVICE_LOCAL_MEMORY_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>pageableDeviceLocalMemory</name></member>
+ </type>
<type category="struct" name="VkPhysicalDeviceBufferDeviceAddressFeatures" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
@@ -4398,11 +4686,12 @@ typedef void <name>CAMetalLayer</name>;
<member len="attachmentCount">const <type>VkImageView</type>* <name>pAttachments</name></member>
</type>
<type category="struct" name="VkRenderPassAttachmentBeginInfoKHR" alias="VkRenderPassAttachmentBeginInfo"/>
- <type category="struct" name="VkPhysicalDeviceTextureCompressionASTCHDRFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
- <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
- <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <type category="struct" name="VkPhysicalDeviceTextureCompressionASTCHDRFeatures" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>textureCompressionASTC_HDR</name></member>
</type>
+ <type category="struct" name="VkPhysicalDeviceTextureCompressionASTCHDRFeaturesEXT" alias="VkPhysicalDeviceTextureCompressionASTCHDRFeatures"/>
<type category="struct" name="VkPhysicalDeviceCooperativeMatrixFeaturesNV" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_NV"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
@@ -4449,17 +4738,19 @@ typedef void <name>CAMetalLayer</name>;
<member optional="true">const <type>void</type>* <name>pNext</name></member>
<member><type>GgpFrameToken</type> <name>frameToken</name></member>
</type>
- <type category="struct" name="VkPipelineCreationFeedbackEXT" returnedonly="true">
- <member><type>VkPipelineCreationFeedbackFlagsEXT</type> <name>flags</name></member>
+ <type category="struct" name="VkPipelineCreationFeedback" returnedonly="true">
+ <member><type>VkPipelineCreationFeedbackFlags</type> <name>flags</name></member>
<member><type>uint64_t</type> <name>duration</name></member>
</type>
- <type category="struct" name="VkPipelineCreationFeedbackCreateInfoEXT" structextends="VkGraphicsPipelineCreateInfo,VkComputePipelineCreateInfo,VkRayTracingPipelineCreateInfoNV,VkRayTracingPipelineCreateInfoKHR">
- <member values="VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
- <member optional="true">const <type>void</type>* <name>pNext</name></member>
- <member><type>VkPipelineCreationFeedbackEXT</type>* <name>pPipelineCreationFeedback</name><comment>Output pipeline creation feedback.</comment></member>
- <member><type>uint32_t</type> <name>pipelineStageCreationFeedbackCount</name></member>
- <member len="pipelineStageCreationFeedbackCount"><type>VkPipelineCreationFeedbackEXT</type>* <name>pPipelineStageCreationFeedbacks</name><comment>One entry for each shader stage specified in the parent Vk*PipelineCreateInfo struct</comment></member>
+ <type category="struct" name="VkPipelineCreationFeedbackEXT" alias="VkPipelineCreationFeedback"/>
+ <type category="struct" name="VkPipelineCreationFeedbackCreateInfo" structextends="VkGraphicsPipelineCreateInfo,VkComputePipelineCreateInfo,VkRayTracingPipelineCreateInfoNV,VkRayTracingPipelineCreateInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkPipelineCreationFeedback</type>* <name>pPipelineCreationFeedback</name><comment>Output pipeline creation feedback.</comment></member>
+ <member optional="true"><type>uint32_t</type> <name>pipelineStageCreationFeedbackCount</name></member>
+ <member len="pipelineStageCreationFeedbackCount"><type>VkPipelineCreationFeedback</type>* <name>pPipelineStageCreationFeedbacks</name><comment>One entry for each shader stage specified in the parent Vk*PipelineCreateInfo struct</comment></member>
</type>
+ <type category="struct" name="VkPipelineCreationFeedbackCreateInfoEXT" alias="VkPipelineCreationFeedbackCreateInfo"/>
<type category="struct" name="VkSurfaceFullScreenExclusiveInfoEXT" structextends="VkPhysicalDeviceSurfaceInfo2KHR,VkSwapchainCreateInfoKHR">
<member values="VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
@@ -4475,6 +4766,21 @@ typedef void <name>CAMetalLayer</name>;
<member optional="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>fullScreenExclusiveSupported</name></member>
</type>
+ <type category="struct" name="VkPhysicalDevicePresentBarrierFeaturesNV" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_BARRIER_FEATURES_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>presentBarrier</name></member>
+ </type>
+ <type category="struct" name="VkSurfaceCapabilitiesPresentBarrierNV" structextends="VkSurfaceCapabilities2KHR">
+ <member values="VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_PRESENT_BARRIER_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>presentBarrierSupported</name></member>
+ </type>
+ <type category="struct" name="VkSwapchainPresentBarrierCreateInfoNV" structextends="VkSwapchainCreateInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_BARRIER_CREATE_INFO_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>presentBarrierEnable</name></member>
+ </type>
<type category="struct" name="VkPhysicalDevicePerformanceQueryFeaturesKHR" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_FEATURES_KHR"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
@@ -4523,7 +4829,7 @@ typedef void <name>CAMetalLayer</name>;
<member optional="true"><type>VkAcquireProfilingLockFlagsKHR</type> <name>flags</name><comment>Acquire profiling lock flags</comment></member>
<member><type>uint64_t</type> <name>timeout</name></member>
</type>
- <type category="struct" name="VkPerformanceQuerySubmitInfoKHR" structextends="VkSubmitInfo,VkSubmitInfo2KHR">
+ <type category="struct" name="VkPerformanceQuerySubmitInfoKHR" structextends="VkSubmitInfo,VkSubmitInfo2">
<member values="VK_STRUCTURE_TYPE_PERFORMANCE_QUERY_SUBMIT_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true">const <type>void</type>* <name>pNext</name></member>
<member><type>uint32_t</type> <name>counterPassIndex</name><comment>Index for which counter pass to submit</comment></member>
@@ -4534,7 +4840,7 @@ typedef void <name>CAMetalLayer</name>;
<member optional="true"><type>VkHeadlessSurfaceCreateFlagsEXT</type> <name>flags</name></member>
</type>
<type category="struct" name="VkPhysicalDeviceCoverageReductionModeFeaturesNV" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
- <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COVERAGE_REDUCTION_MODE_FEATURES_NV"><type>VkStructureType</type><name>sType</name></member>
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COVERAGE_REDUCTION_MODE_FEATURES_NV"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>coverageReductionMode</name></member>
</type>
@@ -4619,7 +4925,7 @@ typedef void <name>CAMetalLayer</name>;
<member limittype="max"><type>uint32_t</type> <name>shaderWarpsPerSM</name></member>
</type>
<type category="struct" name="VkPhysicalDeviceShaderSMBuiltinsFeaturesNV" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
- <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_FEATURES_NV"><type>VkStructureType</type><name>sType</name></member>
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_FEATURES_NV"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>shaderSMBuiltins</name></member>
</type>
@@ -4631,19 +4937,25 @@ typedef void <name>CAMetalLayer</name>;
<member><type>VkBool32</type> <name>fragmentShaderShadingRateInterlock</name></member>
</type>
<type category="struct" name="VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
- <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES"><type>VkStructureType</type><name>sType</name></member>
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SEPARATE_DEPTH_STENCIL_LAYOUTS_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>separateDepthStencilLayouts</name></member>
</type>
<type category="struct" name="VkPhysicalDeviceSeparateDepthStencilLayoutsFeaturesKHR" alias="VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures"/>
<type category="struct" name="VkAttachmentReferenceStencilLayout" structextends="VkAttachmentReference2">
- <member values="VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_STENCIL_LAYOUT"><type>VkStructureType</type><name>sType</name></member>
+ <member values="VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_STENCIL_LAYOUT"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkImageLayout</type> <name>stencilLayout</name></member>
</type>
+ <type category="struct" name="VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>primitiveTopologyListRestart</name></member>
+ <member><type>VkBool32</type> <name>primitiveTopologyPatchListRestart</name></member>
+ </type>
<type category="struct" name="VkAttachmentReferenceStencilLayoutKHR" alias="VkAttachmentReferenceStencilLayout"/>
<type category="struct" name="VkAttachmentDescriptionStencilLayout" structextends="VkAttachmentDescription2">
- <member values="VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT"><type>VkStructureType</type><name>sType</name></member>
+ <member values="VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_STENCIL_LAYOUT"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkImageLayout</type> <name>stencilInitialLayout</name></member>
<member><type>VkImageLayout</type> <name>stencilFinalLayout</name></member>
@@ -4659,6 +4971,7 @@ typedef void <name>CAMetalLayer</name>;
<member optional="true">const <type>void</type>* <name>pNext</name></member>
<member><type>VkPipeline</type> <name>pipeline</name></member>
</type>
+ <type category="struct" name="VkPipelineInfoEXT" alias="VkPipelineInfoKHR"/>
<type category="struct" name="VkPipelineExecutablePropertiesKHR" returnedonly="true">
<member values="VK_STRUCTURE_TYPE_PIPELINE_EXECUTABLE_PROPERTIES_KHR"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
@@ -4696,53 +5009,58 @@ typedef void <name>CAMetalLayer</name>;
<member><type>size_t</type> <name>dataSize</name></member>
<member optional="true" len="dataSize"><type>void</type>* <name>pData</name></member>
</type>
- <type category="struct" name="VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
- <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
- <member optional="true"><type>void</type>* <name>pNext</name></member>
- <member><type>VkBool32</type> <name>shaderDemoteToHelperInvocation</name></member>
+ <type category="struct" name="VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>shaderDemoteToHelperInvocation</name></member>
</type>
+ <type category="struct" name="VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT" alias="VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures"/>
<type category="struct" name="VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>texelBufferAlignment</name></member>
</type>
- <type category="struct" name="VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT" structextends="VkPhysicalDeviceProperties2" returnedonly="true">
- <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <type category="struct" name="VkPhysicalDeviceTexelBufferAlignmentProperties" structextends="VkPhysicalDeviceProperties2" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
- <member limittype="noauto"><type>VkDeviceSize</type> <name>storageTexelBufferOffsetAlignmentBytes</name></member>
- <member limittype="noauto"><type>VkBool32</type> <name>storageTexelBufferOffsetSingleTexelAlignment</name></member>
- <member limittype="noauto"><type>VkDeviceSize</type> <name>uniformTexelBufferOffsetAlignmentBytes</name></member>
- <member limittype="noauto"><type>VkBool32</type> <name>uniformTexelBufferOffsetSingleTexelAlignment</name></member>
- </type>
- <type category="struct" name="VkPhysicalDeviceSubgroupSizeControlFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
- <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
- <member optional="true"><type>void</type>* <name>pNext</name></member>
- <member><type>VkBool32</type> <name>subgroupSizeControl</name></member>
- <member><type>VkBool32</type> <name>computeFullSubgroups</name></member>
- </type>
- <type category="struct" name="VkPhysicalDeviceSubgroupSizeControlPropertiesEXT" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
- <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member limittype="min,pot"><type>VkDeviceSize</type> <name>storageTexelBufferOffsetAlignmentBytes</name></member>
+ <member limittype="exact"><type>VkBool32</type> <name>storageTexelBufferOffsetSingleTexelAlignment</name></member>
+ <member limittype="min,pot"><type>VkDeviceSize</type> <name>uniformTexelBufferOffsetAlignmentBytes</name></member>
+ <member limittype="exact"><type>VkBool32</type> <name>uniformTexelBufferOffsetSingleTexelAlignment</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT" alias="VkPhysicalDeviceTexelBufferAlignmentProperties"/>
+ <type category="struct" name="VkPhysicalDeviceSubgroupSizeControlFeatures" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>subgroupSizeControl</name></member>
+ <member><type>VkBool32</type> <name>computeFullSubgroups</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceSubgroupSizeControlFeaturesEXT" alias="VkPhysicalDeviceSubgroupSizeControlFeatures"/>
+ <type category="struct" name="VkPhysicalDeviceSubgroupSizeControlProperties" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
- <member limittype="min" noautovalidity="true"><type>uint32_t</type> <name>minSubgroupSize</name><comment>The minimum subgroup size supported by this device</comment></member>
- <member limittype="max" noautovalidity="true"><type>uint32_t</type> <name>maxSubgroupSize</name><comment>The maximum subgroup size supported by this device</comment></member>
+ <member limittype="min,pot" noautovalidity="true"><type>uint32_t</type> <name>minSubgroupSize</name><comment>The minimum subgroup size supported by this device</comment></member>
+ <member limittype="max,pot" noautovalidity="true"><type>uint32_t</type> <name>maxSubgroupSize</name><comment>The maximum subgroup size supported by this device</comment></member>
<member limittype="max" noautovalidity="true"><type>uint32_t</type> <name>maxComputeWorkgroupSubgroups</name><comment>The maximum number of subgroups supported in a workgroup</comment></member>
- <member limittype="bitmask"><type>VkShaderStageFlags</type> <name>requiredSubgroupSizeStages</name><comment>The shader stages that support specifying a subgroup size</comment></member>
+ <member limittype="bitmask"><type>VkShaderStageFlags</type> <name>requiredSubgroupSizeStages</name><comment>The shader stages that support specifying a subgroup size</comment></member>
</type>
- <type category="struct" name="VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT" returnedonly="true" structextends="VkPipelineShaderStageCreateInfo">
- <member values="VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
- <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <type category="struct" name="VkPhysicalDeviceSubgroupSizeControlPropertiesEXT" alias="VkPhysicalDeviceSubgroupSizeControlProperties"/>
+ <type category="struct" name="VkPipelineShaderStageRequiredSubgroupSizeCreateInfo" returnedonly="true" structextends="VkPipelineShaderStageCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
<member><type>uint32_t</type> <name>requiredSubgroupSize</name></member>
</type>
+ <type category="struct" name="VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT" alias="VkPipelineShaderStageRequiredSubgroupSizeCreateInfo"/>
<type category="struct" name="VkSubpassShadingPipelineCreateInfoHUAWEI" returnedonly="true" structextends="VkComputePipelineCreateInfo">
<member values="VK_STRUCTURE_TYPE_SUBPASS_SHADING_PIPELINE_CREATE_INFO_HUAWEI"><type>VkStructureType</type> <name>sType</name></member>
- <member><type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkRenderPass</type> <name>renderPass</name></member>
<member><type>uint32_t</type> <name>subpass</name></member>
</type>
<type category="struct" name="VkPhysicalDeviceSubpassShadingPropertiesHUAWEI" structextends="VkPhysicalDeviceProperties2" returnedonly="true">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_PROPERTIES_HUAWEI"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
- <member limittype="noauto"><type>uint32_t</type> <name>maxSubpassShadingWorkgroupSizeAspectRatio</name></member>
+ <member limittype="max,pot"><type>uint32_t</type> <name>maxSubpassShadingWorkgroupSizeAspectRatio</name></member>
</type>
<type category="struct" name="VkMemoryOpaqueCaptureAddressAllocateInfo" structextends="VkMemoryAllocateInfo">
<member values="VK_STRUCTURE_TYPE_MEMORY_OPAQUE_CAPTURE_ADDRESS_ALLOCATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
@@ -4769,7 +5087,7 @@ typedef void <name>CAMetalLayer</name>;
<type category="struct" name="VkPhysicalDeviceLineRasterizationPropertiesEXT" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES_EXT"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
- <member limittype="noauto"><type>uint32_t</type> <name>lineSubPixelPrecisionBits</name></member>
+ <member limittype="bits"><type>uint32_t</type> <name>lineSubPixelPrecisionBits</name></member>
</type>
<type category="struct" name="VkPipelineRasterizationLineStateCreateInfoEXT" structextends="VkPipelineRasterizationStateCreateInfo">
<member values="VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
@@ -4779,13 +5097,14 @@ typedef void <name>CAMetalLayer</name>;
<member><type>uint32_t</type> <name>lineStippleFactor</name></member>
<member><type>uint16_t</type> <name>lineStipplePattern</name></member>
</type>
- <type category="struct" name="VkPhysicalDevicePipelineCreationCacheControlFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
- <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <type category="struct" name="VkPhysicalDevicePipelineCreationCacheControlFeatures" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
- <member><type>VkBool32</type> <name>pipelineCreationCacheControl</name></member>
+ <member><type>VkBool32</type> <name>pipelineCreationCacheControl</name></member>
</type>
+ <type category="struct" name="VkPhysicalDevicePipelineCreationCacheControlFeaturesEXT" alias="VkPhysicalDevicePipelineCreationCacheControlFeatures"/>
<type category="struct" name="VkPhysicalDeviceVulkan11Features" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
- <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES"><type>VkStructureType</type><name>sType</name></member>
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>storageBuffer16BitAccess</name><comment>16-bit integer/floating-point variables supported in BufferBlock</comment></member>
<member><type>VkBool32</type> <name>uniformAndStorageBuffer16BitAccess</name><comment>16-bit integer/floating-point variables supported in BufferBlock and Block</comment></member>
@@ -4801,26 +5120,26 @@ typedef void <name>CAMetalLayer</name>;
<member><type>VkBool32</type> <name>shaderDrawParameters</name></member>
</type>
<type category="struct" name="VkPhysicalDeviceVulkan11Properties" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
- <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES"><type>VkStructureType</type><name>sType</name></member>
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
- <member limittype="noauto"><type>uint8_t</type> <name>deviceUUID</name>[<enum>VK_UUID_SIZE</enum>]</member>
- <member limittype="noauto"><type>uint8_t</type> <name>driverUUID</name>[<enum>VK_UUID_SIZE</enum>]</member>
- <member limittype="noauto"><type>uint8_t</type> <name>deviceLUID</name>[<enum>VK_LUID_SIZE</enum>]</member>
- <member limittype="noauto"><type>uint32_t</type> <name>deviceNodeMask</name></member>
- <member limittype="noauto"><type>VkBool32</type> <name>deviceLUIDValid</name></member>
- <member limittype="noauto" noautovalidity="true"><type>uint32_t</type> <name>subgroupSize</name><comment>The size of a subgroup for this queue.</comment></member>
+ <member limittype="exact"><type>uint8_t</type> <name>deviceUUID</name>[<enum>VK_UUID_SIZE</enum>]</member>
+ <member limittype="exact"><type>uint8_t</type> <name>driverUUID</name>[<enum>VK_UUID_SIZE</enum>]</member>
+ <member limittype="exact"><type>uint8_t</type> <name>deviceLUID</name>[<enum>VK_LUID_SIZE</enum>]</member>
+ <member limittype="exact"><type>uint32_t</type> <name>deviceNodeMask</name></member>
+ <member limittype="exact"><type>VkBool32</type> <name>deviceLUIDValid</name></member>
+ <member limittype="max,pot" noautovalidity="true"><type>uint32_t</type> <name>subgroupSize</name><comment>The size of a subgroup for this queue.</comment></member>
<member limittype="bitmask" noautovalidity="true"><type>VkShaderStageFlags</type> <name>subgroupSupportedStages</name><comment>Bitfield of what shader stages support subgroup operations</comment></member>
<member limittype="bitmask" noautovalidity="true"><type>VkSubgroupFeatureFlags</type> <name>subgroupSupportedOperations</name><comment>Bitfield of what subgroup operations are supported.</comment></member>
<member limittype="bitmask" noautovalidity="true"><type>VkBool32</type> <name>subgroupQuadOperationsInAllStages</name><comment>Flag to specify whether quad operations are available in all stages.</comment></member>
- <member limittype="noauto"><type>VkPointClippingBehavior</type> <name>pointClippingBehavior</name></member>
+ <member limittype="exact"><type>VkPointClippingBehavior</type> <name>pointClippingBehavior</name></member>
<member limittype="max"><type>uint32_t</type> <name>maxMultiviewViewCount</name><comment>max number of views in a subpass</comment></member>
<member limittype="max"><type>uint32_t</type> <name>maxMultiviewInstanceIndex</name><comment>max instance index for a draw in a multiview subpass</comment></member>
- <member limittype="noauto"><type>VkBool32</type> <name>protectedNoFault</name></member>
+ <member limittype="exact"><type>VkBool32</type> <name>protectedNoFault</name></member>
<member limittype="max"><type>uint32_t</type> <name>maxPerSetDescriptors</name></member>
<member limittype="max"><type>VkDeviceSize</type> <name>maxMemoryAllocationSize</name></member>
</type>
<type category="struct" name="VkPhysicalDeviceVulkan12Features" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
- <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES"><type>VkStructureType</type><name>sType</name></member>
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>samplerMirrorClampToEdge</name></member>
<member><type>VkBool32</type> <name>drawIndirectCount</name></member>
@@ -4871,14 +5190,14 @@ typedef void <name>CAMetalLayer</name>;
<member><type>VkBool32</type> <name>subgroupBroadcastDynamicId</name></member>
</type>
<type category="struct" name="VkPhysicalDeviceVulkan12Properties" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
- <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES"><type>VkStructureType</type><name>sType</name></member>
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
<member limittype="noauto"><type>VkDriverId</type> <name>driverID</name></member>
<member limittype="noauto"><type>char</type> <name>driverName</name>[<enum>VK_MAX_DRIVER_NAME_SIZE</enum>]</member>
<member limittype="noauto"><type>char</type> <name>driverInfo</name>[<enum>VK_MAX_DRIVER_INFO_SIZE</enum>]</member>
<member limittype="noauto"><type>VkConformanceVersion</type> <name>conformanceVersion</name></member>
- <member limittype="noauto"><type>VkShaderFloatControlsIndependence</type><name>denormBehaviorIndependence</name></member>
- <member limittype="noauto"><type>VkShaderFloatControlsIndependence</type><name>roundingModeIndependence</name></member>
+ <member limittype="exact"><type>VkShaderFloatControlsIndependence</type> <name>denormBehaviorIndependence</name></member>
+ <member limittype="exact"><type>VkShaderFloatControlsIndependence</type> <name>roundingModeIndependence</name></member>
<member limittype="bitmask"><type>VkBool32</type> <name>shaderSignedZeroInfNanPreserveFloat16</name><comment>An implementation can preserve signed zero, nan, inf</comment></member>
<member limittype="bitmask"><type>VkBool32</type> <name>shaderSignedZeroInfNanPreserveFloat32</name><comment>An implementation can preserve signed zero, nan, inf</comment></member>
<member limittype="bitmask"><type>VkBool32</type> <name>shaderSignedZeroInfNanPreserveFloat64</name><comment>An implementation can preserve signed zero, nan, inf</comment></member>
@@ -4926,6 +5245,74 @@ typedef void <name>CAMetalLayer</name>;
<member limittype="max"><type>uint64_t</type> <name>maxTimelineSemaphoreValueDifference</name></member>
<member limittype="bitmask" optional="true"><type>VkSampleCountFlags</type> <name>framebufferIntegerColorSampleCounts</name></member>
</type>
+ <type category="struct" name="VkPhysicalDeviceVulkan13Features" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>robustImageAccess</name></member>
+ <member><type>VkBool32</type> <name>inlineUniformBlock</name></member>
+ <member><type>VkBool32</type> <name>descriptorBindingInlineUniformBlockUpdateAfterBind</name></member>
+ <member><type>VkBool32</type> <name>pipelineCreationCacheControl</name></member>
+ <member><type>VkBool32</type> <name>privateData</name></member>
+ <member><type>VkBool32</type> <name>shaderDemoteToHelperInvocation</name></member>
+ <member><type>VkBool32</type> <name>shaderTerminateInvocation</name></member>
+ <member><type>VkBool32</type> <name>subgroupSizeControl</name></member>
+ <member><type>VkBool32</type> <name>computeFullSubgroups</name></member>
+ <member><type>VkBool32</type> <name>synchronization2</name></member>
+ <member><type>VkBool32</type> <name>textureCompressionASTC_HDR</name></member>
+ <member><type>VkBool32</type> <name>shaderZeroInitializeWorkgroupMemory</name></member>
+ <member><type>VkBool32</type> <name>dynamicRendering</name></member>
+ <member><type>VkBool32</type> <name>shaderIntegerDotProduct</name></member>
+ <member><type>VkBool32</type> <name>maintenance4</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceVulkan13Properties" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member limittype="min,pot" noautovalidity="true"><type>uint32_t</type> <name>minSubgroupSize</name><comment>The minimum subgroup size supported by this device</comment></member>
+ <member limittype="max,pot" noautovalidity="true"><type>uint32_t</type> <name>maxSubgroupSize</name><comment>The maximum subgroup size supported by this device</comment></member>
+ <member limittype="max" noautovalidity="true"><type>uint32_t</type> <name>maxComputeWorkgroupSubgroups</name><comment>The maximum number of subgroups supported in a workgroup</comment></member>
+ <member limittype="bitmask"><type>VkShaderStageFlags</type> <name>requiredSubgroupSizeStages</name><comment>The shader stages that support specifying a subgroup size</comment></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxInlineUniformBlockSize</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxPerStageDescriptorInlineUniformBlocks</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetInlineUniformBlocks</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxDescriptorSetUpdateAfterBindInlineUniformBlocks</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxInlineUniformTotalSize</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProduct8BitUnsignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProduct8BitSignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProduct8BitMixedSignednessAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProduct4x8BitPackedUnsignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProduct4x8BitPackedSignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProduct4x8BitPackedMixedSignednessAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProduct16BitUnsignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProduct16BitSignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProduct16BitMixedSignednessAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProduct32BitUnsignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProduct32BitSignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProduct32BitMixedSignednessAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProduct64BitUnsignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProduct64BitSignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProduct64BitMixedSignednessAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProductAccumulatingSaturating8BitUnsignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProductAccumulatingSaturating8BitSignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProductAccumulatingSaturating16BitUnsignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProductAccumulatingSaturating16BitSignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProductAccumulatingSaturating32BitUnsignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProductAccumulatingSaturating32BitSignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProductAccumulatingSaturating64BitUnsignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProductAccumulatingSaturating64BitSignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated</name></member>
+ <member limittype="min,pot"><type>VkDeviceSize</type> <name>storageTexelBufferOffsetAlignmentBytes</name></member>
+ <member limittype="exact"><type>VkBool32</type> <name>storageTexelBufferOffsetSingleTexelAlignment</name></member>
+ <member limittype="min,pot"><type>VkDeviceSize</type> <name>uniformTexelBufferOffsetAlignmentBytes</name></member>
+ <member limittype="exact"><type>VkBool32</type> <name>uniformTexelBufferOffsetSingleTexelAlignment</name></member>
+ <member limittype="max"><type>VkDeviceSize</type> <name>maxBufferSize</name></member>
+ </type>
<type category="struct" name="VkPipelineCompilerControlCreateInfoAMD" structextends="VkGraphicsPipelineCreateInfo,VkComputePipelineCreateInfo">
<member values="VK_STRUCTURE_TYPE_PIPELINE_COMPILER_CONTROL_CREATE_INFO_AMD"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true">const <type>void</type>* <name>pNext</name></member>
@@ -4936,15 +5323,16 @@ typedef void <name>CAMetalLayer</name>;
<member optional="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>deviceCoherentMemory</name></member>
</type>
- <type category="struct" name="VkPhysicalDeviceToolPropertiesEXT" returnedonly="true">
- <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <type category="struct" name="VkPhysicalDeviceToolProperties" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
- <member><type>char</type> <name>name</name>[<enum>VK_MAX_EXTENSION_NAME_SIZE</enum>]</member>
- <member><type>char</type> <name>version</name>[<enum>VK_MAX_EXTENSION_NAME_SIZE</enum>]</member>
- <member><type>VkToolPurposeFlagsEXT</type> <name>purposes</name></member>
- <member><type>char</type> <name>description</name>[<enum>VK_MAX_DESCRIPTION_SIZE</enum>]</member>
- <member><type>char</type> <name>layer</name>[<enum>VK_MAX_EXTENSION_NAME_SIZE</enum>]</member>
+ <member><type>char</type> <name>name</name>[<enum>VK_MAX_EXTENSION_NAME_SIZE</enum>]</member>
+ <member><type>char</type> <name>version</name>[<enum>VK_MAX_EXTENSION_NAME_SIZE</enum>]</member>
+ <member><type>VkToolPurposeFlags</type> <name>purposes</name></member>
+ <member><type>char</type> <name>description</name>[<enum>VK_MAX_DESCRIPTION_SIZE</enum>]</member>
+ <member><type>char</type> <name>layer</name>[<enum>VK_MAX_EXTENSION_NAME_SIZE</enum>]</member>
</type>
+ <type category="struct" name="VkPhysicalDeviceToolPropertiesEXT" alias="VkPhysicalDeviceToolProperties"/>
<type category="struct" name="VkSamplerCustomBorderColorCreateInfoEXT" structextends="VkSamplerCreateInfo">
<member values="VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true">const <type>void</type>* <name>pNext</name></member>
@@ -4962,6 +5350,18 @@ typedef void <name>CAMetalLayer</name>;
<member><type>VkBool32</type> <name>customBorderColors</name></member>
<member><type>VkBool32</type> <name>customBorderColorWithoutFormat</name></member>
</type>
+ <type category="struct" name="VkSamplerBorderColorComponentMappingCreateInfoEXT" structextends="VkSamplerCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_SAMPLER_BORDER_COLOR_COMPONENT_MAPPING_CREATE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkComponentMapping</type> <name>components</name></member>
+ <member><type>VkBool32</type> <name>srgb</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceBorderColorSwizzleFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BORDER_COLOR_SWIZZLE_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>borderColorSwizzle</name></member>
+ <member><type>VkBool32</type> <name>borderColorSwizzleFromImage</name></member>
+ </type>
<type category="union" name="VkDeviceOrHostAddressKHR">
<member noautovalidity="true"><type>VkDeviceAddress</type> <name>deviceAddress</name></member>
<member noautovalidity="true"><type>void</type>* <name>hostAddress</name></member>
@@ -5065,7 +5465,7 @@ typedef void <name>CAMetalLayer</name>;
<type category="struct" name="VkAccelerationStructureVersionInfoKHR">
<member values="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_VERSION_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true">const <type>void</type>* <name>pNext</name></member>
- <member len="2*ename:VK_UUID_SIZE" altlen="2*VK_UUID_SIZE">const <type>uint8_t</type>* <name>pVersionData</name></member>
+ <member len="latexmath:[2 \times \mathtt{VK\_UUID\_SIZE}]" altlen="2*VK_UUID_SIZE">const <type>uint8_t</type>* <name>pVersionData</name></member>
</type>
<type category="struct" name="VkCopyAccelerationStructureInfoKHR">
<member values="VK_STRUCTURE_TYPE_COPY_ACCELERATION_STRUCTURE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
@@ -5094,7 +5494,7 @@ typedef void <name>CAMetalLayer</name>;
<member><type>uint32_t</type> <name>maxPipelineRayPayloadSize</name></member>
<member><type>uint32_t</type> <name>maxPipelineRayHitAttributeSize</name></member>
</type>
- <type category="struct" name="VkPipelineLibraryCreateInfoKHR">
+ <type category="struct" name="VkPipelineLibraryCreateInfoKHR" structextends="VkGraphicsPipelineCreateInfo">
<member values="VK_STRUCTURE_TYPE_PIPELINE_LIBRARY_CREATE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true">const <type>void</type>* <name>pNext</name></member>
<member optional="true"><type>uint32_t</type> <name>libraryCount</name></member>
@@ -5112,12 +5512,67 @@ typedef void <name>CAMetalLayer</name>;
<member><type>VkBool32</type> <name>extendedDynamicState2LogicOp</name></member>
<member><type>VkBool32</type> <name>extendedDynamicState2PatchControlPoints</name></member>
</type>
+ <type category="struct" name="VkPhysicalDeviceExtendedDynamicState3FeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState3TessellationDomainOrigin</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState3DepthClampEnable</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState3PolygonMode</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState3RasterizationSamples</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState3SampleMask</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState3AlphaToCoverageEnable</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState3AlphaToOneEnable</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState3LogicOpEnable</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState3ColorBlendEnable</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState3ColorBlendEquation</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState3ColorWriteMask</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState3RasterizationStream</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState3ConservativeRasterizationMode</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState3ExtraPrimitiveOverestimationSize</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState3DepthClipEnable</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState3SampleLocationsEnable</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState3ColorBlendAdvanced</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState3ProvokingVertexMode</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState3LineRasterizationMode</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState3LineStippleEnable</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState3DepthClipNegativeOneToOne</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState3ViewportWScalingEnable</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState3ViewportSwizzle</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState3CoverageToColorEnable</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState3CoverageToColorLocation</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState3CoverageModulationMode</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState3CoverageModulationTableEnable</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState3CoverageModulationTable</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState3CoverageReductionMode</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState3RepresentativeFragmentTestEnable</name></member>
+ <member><type>VkBool32</type> <name>extendedDynamicState3ShadingRateImageEnable</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceExtendedDynamicState3PropertiesEXT" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_PROPERTIES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>dynamicPrimitiveTopologyUnrestricted</name></member>
+ </type>
+ <type category="struct" name="VkColorBlendEquationEXT">
+ <member><type>VkBlendFactor</type> <name>srcColorBlendFactor</name></member>
+ <member><type>VkBlendFactor</type> <name>dstColorBlendFactor</name></member>
+ <member><type>VkBlendOp</type> <name>colorBlendOp</name></member>
+ <member><type>VkBlendFactor</type> <name>srcAlphaBlendFactor</name></member>
+ <member><type>VkBlendFactor</type> <name>dstAlphaBlendFactor</name></member>
+ <member><type>VkBlendOp</type> <name>alphaBlendOp</name></member>
+ </type>
+ <type category="struct" name="VkColorBlendAdvancedEXT">
+ <member><type>VkBlendOp</type> <name>advancedBlendOp</name></member>
+ <member><type>VkBool32</type> <name>srcPremultiplied</name></member>
+ <member><type>VkBool32</type> <name>dstPremultiplied</name></member>
+ <member><type>VkBlendOverlapEXT</type> <name>blendOverlap</name></member>
+ <member><type>VkBool32</type> <name>clampResults</name></member>
+ </type>
<type category="struct" name="VkRenderPassTransformBeginInfoQCOM" structextends="VkRenderPassBeginInfo">
<member values="VK_STRUCTURE_TYPE_RENDER_PASS_TRANSFORM_BEGIN_INFO_QCOM"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name><comment>Pointer to next structure</comment></member>
<member noautovalidity="true"><type>VkSurfaceTransformFlagBitsKHR</type> <name>transform</name></member>
</type>
- <type category="struct" name="VkCopyCommandTransformInfoQCOM" structextends="VkBufferImageCopy2KHR,VkImageBlit2KHR">
+ <type category="struct" name="VkCopyCommandTransformInfoQCOM" structextends="VkBufferImageCopy2,VkImageBlit2">
<member values="VK_STRUCTURE_TYPE_COPY_COMMAND_TRANSFORM_INFO_QCOM"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true" noautovalidity="true">const <type>void</type>* <name>pNext</name></member>
<member noautovalidity="true"><type>VkSurfaceTransformFlagBitsKHR</type> <name>transform</name></member>
@@ -5129,7 +5584,7 @@ typedef void <name>CAMetalLayer</name>;
<member><type>VkRect2D</type> <name>renderArea</name></member>
</type>
<type category="struct" name="VkPhysicalDeviceDiagnosticsConfigFeaturesNV" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
- <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV"><type>VkStructureType</type><name>sType</name></member>
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>diagnosticsConfig</name></member>
</type>
@@ -5138,37 +5593,39 @@ typedef void <name>CAMetalLayer</name>;
<member optional="true">const <type>void</type>* <name>pNext</name></member>
<member optional="true"><type>VkDeviceDiagnosticsConfigFlagsNV</type> <name>flags</name></member>
</type>
- <type category="struct" name="VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeaturesKHR" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
- <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES_KHR"><type>VkStructureType</type> <name>sType</name></member>
- <member><type>void</type>* <name>pNext</name></member>
+ <type category="struct" name="VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>shaderZeroInitializeWorkgroupMemory</name></member>
</type>
+ <type category="struct" name="VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeaturesKHR" alias="VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures"/>
<type category="struct" name="VkPhysicalDeviceShaderSubgroupUniformControlFlowFeaturesKHR" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_UNIFORM_CONTROL_FLOW_FEATURES_KHR"><type>VkStructureType</type> <name>sType</name></member>
- <member><type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>shaderSubgroupUniformControlFlow</name></member>
</type>
<type category="struct" name="VkPhysicalDeviceRobustness2FeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
- <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>robustBufferAccess2</name></member>
<member><type>VkBool32</type> <name>robustImageAccess2</name></member>
<member><type>VkBool32</type> <name>nullDescriptor</name></member>
</type>
<type category="struct" name="VkPhysicalDeviceRobustness2PropertiesEXT" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_EXT"><type>VkStructureType</type> <name>sType</name></member>
- <member optional="true"><type>void</type>* <name>pNext</name></member>
- <member limittype="noauto"><type>VkDeviceSize</type> <name>robustStorageBufferAccessSizeAlignment</name></member>
- <member limittype="noauto"><type>VkDeviceSize</type> <name>robustUniformBufferAccessSizeAlignment</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member limittype="min,pot"><type>VkDeviceSize</type> <name>robustStorageBufferAccessSizeAlignment</name></member>
+ <member limittype="min,pot"><type>VkDeviceSize</type> <name>robustUniformBufferAccessSizeAlignment</name></member>
</type>
- <type category="struct" name="VkPhysicalDeviceImageRobustnessFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
- <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
- <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <type category="struct" name="VkPhysicalDeviceImageRobustnessFeatures" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>robustImageAccess</name></member>
</type>
+ <type category="struct" name="VkPhysicalDeviceImageRobustnessFeaturesEXT" alias="VkPhysicalDeviceImageRobustnessFeatures"/>
<type category="struct" name="VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_FEATURES_KHR"><type>VkStructureType</type> <name>sType</name></member>
- <member noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>workgroupMemoryExplicitLayout</name></member>
<member><type>VkBool32</type> <name>workgroupMemoryExplicitLayoutScalarBlockLayout</name></member>
<member><type>VkBool32</type> <name>workgroupMemoryExplicitLayout8BitAccess</name></member>
@@ -5196,119 +5653,130 @@ typedef void <name>CAMetalLayer</name>;
<type category="struct" name="VkPhysicalDevicePortabilitySubsetPropertiesKHR" structextends="VkPhysicalDeviceProperties2">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_PROPERTIES_KHR"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
- <member limittype="noauto"><type>uint32_t</type> <name>minVertexInputBindingStrideAlignment</name></member>
+ <member limittype="min,pot"><type>uint32_t</type> <name>minVertexInputBindingStrideAlignment</name></member>
</type>
<type category="struct" name="VkPhysicalDevice4444FormatsFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
- <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>formatA4R4G4B4</name></member>
<member><type>VkBool32</type> <name>formatA4B4G4R4</name></member>
</type>
<type category="struct" name="VkPhysicalDeviceSubpassShadingFeaturesHUAWEI" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_FEATURES_HUAWEI"><type>VkStructureType</type> <name>sType</name></member>
- <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>subpassShading</name></member>
</type>
- <type category="struct" name="VkBufferCopy2KHR">
- <member values="VK_STRUCTURE_TYPE_BUFFER_COPY_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
- <member optional="true">const <type>void</type>* <name>pNext</name></member>
- <member><type>VkDeviceSize</type> <name>srcOffset</name><comment>Specified in bytes</comment></member>
- <member><type>VkDeviceSize</type> <name>dstOffset</name><comment>Specified in bytes</comment></member>
+ <type category="struct" name="VkBufferCopy2">
+ <member values="VK_STRUCTURE_TYPE_BUFFER_COPY_2"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkDeviceSize</type> <name>srcOffset</name><comment>Specified in bytes</comment></member>
+ <member><type>VkDeviceSize</type> <name>dstOffset</name><comment>Specified in bytes</comment></member>
<member noautovalidity="true"><type>VkDeviceSize</type> <name>size</name><comment>Specified in bytes</comment></member>
</type>
- <type category="struct" name="VkImageCopy2KHR">
- <member values="VK_STRUCTURE_TYPE_IMAGE_COPY_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
- <member optional="true">const <type>void</type>* <name>pNext</name></member>
- <member><type>VkImageSubresourceLayers</type> <name>srcSubresource</name></member>
- <member><type>VkOffset3D</type> <name>srcOffset</name><comment>Specified in pixels for both compressed and uncompressed images</comment></member>
- <member><type>VkImageSubresourceLayers</type> <name>dstSubresource</name></member>
- <member><type>VkOffset3D</type> <name>dstOffset</name><comment>Specified in pixels for both compressed and uncompressed images</comment></member>
- <member><type>VkExtent3D</type> <name>extent</name><comment>Specified in pixels for both compressed and uncompressed images</comment></member>
- </type>
- <type category="struct" name="VkImageBlit2KHR">
- <member values="VK_STRUCTURE_TYPE_IMAGE_BLIT_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
- <member optional="true">const <type>void</type>* <name>pNext</name></member>
- <member><type>VkImageSubresourceLayers</type> <name>srcSubresource</name></member>
- <member><type>VkOffset3D</type> <name>srcOffsets</name>[2]<comment>Specified in pixels for both compressed and uncompressed images</comment></member>
- <member><type>VkImageSubresourceLayers</type> <name>dstSubresource</name></member>
- <member><type>VkOffset3D</type> <name>dstOffsets</name>[2]<comment>Specified in pixels for both compressed and uncompressed images</comment></member>
- </type>
- <type category="struct" name="VkBufferImageCopy2KHR">
- <member values="VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
- <member optional="true">const <type>void</type>* <name>pNext</name></member>
- <member><type>VkDeviceSize</type> <name>bufferOffset</name><comment>Specified in bytes</comment></member>
- <member><type>uint32_t</type> <name>bufferRowLength</name><comment>Specified in texels</comment></member>
- <member><type>uint32_t</type> <name>bufferImageHeight</name></member>
- <member><type>VkImageSubresourceLayers</type> <name>imageSubresource</name></member>
- <member><type>VkOffset3D</type> <name>imageOffset</name><comment>Specified in pixels for both compressed and uncompressed images</comment></member>
- <member><type>VkExtent3D</type> <name>imageExtent</name><comment>Specified in pixels for both compressed and uncompressed images</comment></member>
- </type>
- <type category="struct" name="VkImageResolve2KHR">
- <member values="VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
- <member optional="true">const <type>void</type>* <name>pNext</name></member>
- <member><type>VkImageSubresourceLayers</type> <name>srcSubresource</name></member>
- <member><type>VkOffset3D</type> <name>srcOffset</name></member>
- <member><type>VkImageSubresourceLayers</type> <name>dstSubresource</name></member>
- <member><type>VkOffset3D</type> <name>dstOffset</name></member>
- <member><type>VkExtent3D</type> <name>extent</name></member>
- </type>
- <type category="struct" name="VkCopyBufferInfo2KHR">
- <member values="VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
- <member optional="true">const <type>void</type>* <name>pNext</name></member>
- <member><type>VkBuffer</type> <name>srcBuffer</name></member>
- <member><type>VkBuffer</type> <name>dstBuffer</name></member>
- <member><type>uint32_t</type> <name>regionCount</name></member>
- <member len="regionCount">const <type>VkBufferCopy2KHR</type>* <name>pRegions</name></member>
- </type>
- <type category="struct" name="VkCopyImageInfo2KHR">
- <member values="VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
- <member optional="true">const <type>void</type>* <name>pNext</name></member>
- <member><type>VkImage</type> <name>srcImage</name></member>
- <member><type>VkImageLayout</type> <name>srcImageLayout</name></member>
- <member><type>VkImage</type> <name>dstImage</name></member>
- <member><type>VkImageLayout</type> <name>dstImageLayout</name></member>
- <member><type>uint32_t</type> <name>regionCount</name></member>
- <member len="regionCount">const <type>VkImageCopy2KHR</type>* <name>pRegions</name></member>
- </type>
- <type category="struct" name="VkBlitImageInfo2KHR">
- <member values="VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
- <member optional="true">const <type>void</type>* <name>pNext</name></member>
- <member><type>VkImage</type> <name>srcImage</name></member>
- <member><type>VkImageLayout</type> <name>srcImageLayout</name></member>
- <member><type>VkImage</type> <name>dstImage</name></member>
- <member><type>VkImageLayout</type> <name>dstImageLayout</name></member>
- <member><type>uint32_t</type> <name>regionCount</name></member>
- <member len="regionCount">const <type>VkImageBlit2KHR</type>* <name>pRegions</name></member>
- <member><type>VkFilter</type> <name>filter</name></member>
- </type>
- <type category="struct" name="VkCopyBufferToImageInfo2KHR">
- <member values="VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
- <member optional="true">const <type>void</type>* <name>pNext</name></member>
- <member><type>VkBuffer</type> <name>srcBuffer</name></member>
- <member><type>VkImage</type> <name>dstImage</name></member>
- <member><type>VkImageLayout</type> <name>dstImageLayout</name></member>
- <member><type>uint32_t</type> <name>regionCount</name></member>
- <member len="regionCount">const <type>VkBufferImageCopy2KHR</type>* <name>pRegions</name></member>
- </type>
- <type category="struct" name="VkCopyImageToBufferInfo2KHR">
- <member values="VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
- <member optional="true">const <type>void</type>* <name>pNext</name></member>
- <member><type>VkImage</type> <name>srcImage</name></member>
- <member><type>VkImageLayout</type> <name>srcImageLayout</name></member>
- <member><type>VkBuffer</type> <name>dstBuffer</name></member>
- <member><type>uint32_t</type> <name>regionCount</name></member>
- <member len="regionCount">const <type>VkBufferImageCopy2KHR</type>* <name>pRegions</name></member>
- </type>
- <type category="struct" name="VkResolveImageInfo2KHR">
- <member values="VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
- <member optional="true">const <type>void</type>* <name>pNext</name></member>
- <member><type>VkImage</type> <name>srcImage</name></member>
- <member><type>VkImageLayout</type> <name>srcImageLayout</name></member>
- <member><type>VkImage</type> <name>dstImage</name></member>
- <member><type>VkImageLayout</type> <name>dstImageLayout</name></member>
- <member><type>uint32_t</type> <name>regionCount</name></member>
- <member len="regionCount">const <type>VkImageResolve2KHR</type>* <name>pRegions</name></member>
- </type>
+ <type category="struct" name="VkBufferCopy2KHR" alias="VkBufferCopy2"/>
+ <type category="struct" name="VkImageCopy2">
+ <member values="VK_STRUCTURE_TYPE_IMAGE_COPY_2"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkImageSubresourceLayers</type> <name>srcSubresource</name></member>
+ <member><type>VkOffset3D</type> <name>srcOffset</name><comment>Specified in pixels for both compressed and uncompressed images</comment></member>
+ <member><type>VkImageSubresourceLayers</type> <name>dstSubresource</name></member>
+ <member><type>VkOffset3D</type> <name>dstOffset</name><comment>Specified in pixels for both compressed and uncompressed images</comment></member>
+ <member><type>VkExtent3D</type> <name>extent</name><comment>Specified in pixels for both compressed and uncompressed images</comment></member>
+ </type>
+ <type category="struct" name="VkImageCopy2KHR" alias="VkImageCopy2"/>
+ <type category="struct" name="VkImageBlit2">
+ <member values="VK_STRUCTURE_TYPE_IMAGE_BLIT_2"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkImageSubresourceLayers</type> <name>srcSubresource</name></member>
+ <member><type>VkOffset3D</type> <name>srcOffsets</name>[2]<comment>Specified in pixels for both compressed and uncompressed images</comment></member>
+ <member><type>VkImageSubresourceLayers</type> <name>dstSubresource</name></member>
+ <member><type>VkOffset3D</type> <name>dstOffsets</name>[2]<comment>Specified in pixels for both compressed and uncompressed images</comment></member>
+ </type>
+ <type category="struct" name="VkImageBlit2KHR" alias="VkImageBlit2"/>
+ <type category="struct" name="VkBufferImageCopy2">
+ <member values="VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkDeviceSize</type> <name>bufferOffset</name><comment>Specified in bytes</comment></member>
+ <member><type>uint32_t</type> <name>bufferRowLength</name><comment>Specified in texels</comment></member>
+ <member><type>uint32_t</type> <name>bufferImageHeight</name></member>
+ <member><type>VkImageSubresourceLayers</type> <name>imageSubresource</name></member>
+ <member><type>VkOffset3D</type> <name>imageOffset</name><comment>Specified in pixels for both compressed and uncompressed images</comment></member>
+ <member><type>VkExtent3D</type> <name>imageExtent</name><comment>Specified in pixels for both compressed and uncompressed images</comment></member>
+ </type>
+ <type category="struct" name="VkBufferImageCopy2KHR" alias="VkBufferImageCopy2"/>
+ <type category="struct" name="VkImageResolve2">
+ <member values="VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkImageSubresourceLayers</type> <name>srcSubresource</name></member>
+ <member><type>VkOffset3D</type> <name>srcOffset</name></member>
+ <member><type>VkImageSubresourceLayers</type> <name>dstSubresource</name></member>
+ <member><type>VkOffset3D</type> <name>dstOffset</name></member>
+ <member><type>VkExtent3D</type> <name>extent</name></member>
+ </type>
+ <type category="struct" name="VkImageResolve2KHR" alias="VkImageResolve2"/>
+ <type category="struct" name="VkCopyBufferInfo2">
+ <member values="VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkBuffer</type> <name>srcBuffer</name></member>
+ <member><type>VkBuffer</type> <name>dstBuffer</name></member>
+ <member><type>uint32_t</type> <name>regionCount</name></member>
+ <member len="regionCount">const <type>VkBufferCopy2</type>* <name>pRegions</name></member>
+ </type>
+ <type category="struct" name="VkCopyBufferInfo2KHR" alias="VkCopyBufferInfo2"/>
+ <type category="struct" name="VkCopyImageInfo2">
+ <member values="VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkImage</type> <name>srcImage</name></member>
+ <member><type>VkImageLayout</type> <name>srcImageLayout</name></member>
+ <member><type>VkImage</type> <name>dstImage</name></member>
+ <member><type>VkImageLayout</type> <name>dstImageLayout</name></member>
+ <member><type>uint32_t</type> <name>regionCount</name></member>
+ <member len="regionCount">const <type>VkImageCopy2</type>* <name>pRegions</name></member>
+ </type>
+ <type category="struct" name="VkCopyImageInfo2KHR" alias="VkCopyImageInfo2"/>
+ <type category="struct" name="VkBlitImageInfo2">
+ <member values="VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkImage</type> <name>srcImage</name></member>
+ <member><type>VkImageLayout</type> <name>srcImageLayout</name></member>
+ <member><type>VkImage</type> <name>dstImage</name></member>
+ <member><type>VkImageLayout</type> <name>dstImageLayout</name></member>
+ <member><type>uint32_t</type> <name>regionCount</name></member>
+ <member len="regionCount">const <type>VkImageBlit2</type>* <name>pRegions</name></member>
+ <member><type>VkFilter</type> <name>filter</name></member>
+ </type>
+ <type category="struct" name="VkBlitImageInfo2KHR" alias="VkBlitImageInfo2"/>
+ <type category="struct" name="VkCopyBufferToImageInfo2">
+ <member values="VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkBuffer</type> <name>srcBuffer</name></member>
+ <member><type>VkImage</type> <name>dstImage</name></member>
+ <member><type>VkImageLayout</type> <name>dstImageLayout</name></member>
+ <member><type>uint32_t</type> <name>regionCount</name></member>
+ <member len="regionCount">const <type>VkBufferImageCopy2</type>* <name>pRegions</name></member>
+ </type>
+ <type category="struct" name="VkCopyBufferToImageInfo2KHR" alias="VkCopyBufferToImageInfo2"/>
+ <type category="struct" name="VkCopyImageToBufferInfo2">
+ <member values="VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkImage</type> <name>srcImage</name></member>
+ <member><type>VkImageLayout</type> <name>srcImageLayout</name></member>
+ <member><type>VkBuffer</type> <name>dstBuffer</name></member>
+ <member><type>uint32_t</type> <name>regionCount</name></member>
+ <member len="regionCount">const <type>VkBufferImageCopy2</type>* <name>pRegions</name></member>
+ </type>
+ <type category="struct" name="VkCopyImageToBufferInfo2KHR" alias="VkCopyImageToBufferInfo2"/>
+ <type category="struct" name="VkResolveImageInfo2">
+ <member values="VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkImage</type> <name>srcImage</name></member>
+ <member><type>VkImageLayout</type> <name>srcImageLayout</name></member>
+ <member><type>VkImage</type> <name>dstImage</name></member>
+ <member><type>VkImageLayout</type> <name>dstImageLayout</name></member>
+ <member><type>uint32_t</type> <name>regionCount</name></member>
+ <member len="regionCount">const <type>VkImageResolve2</type>* <name>pRegions</name></member>
+ </type>
+ <type category="struct" name="VkResolveImageInfo2KHR" alias="VkResolveImageInfo2"/>
<type category="struct" name="VkPhysicalDeviceShaderImageAtomicInt64FeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_ATOMIC_INT64_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
@@ -5325,7 +5793,7 @@ typedef void <name>CAMetalLayer</name>;
<member values="VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true">const <type>void</type>* <name>pNext</name></member>
<member><type>VkExtent2D</type> <name>fragmentSize</name></member>
- <member><type>VkFragmentShadingRateCombinerOpKHR</type> <name>combinerOps</name>[2]</member>
+ <member noautovalidity="true"><type>VkFragmentShadingRateCombinerOpKHR</type> <name>combinerOps</name>[2]</member>
</type>
<type category="struct" name="VkPhysicalDeviceFragmentShadingRateFeaturesKHR" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR"><type>VkStructureType</type> <name>sType</name></member>
@@ -5339,13 +5807,13 @@ typedef void <name>CAMetalLayer</name>;
<member optional="true"><type>void</type>* <name>pNext</name></member>
<member limittype="min"><type>VkExtent2D</type> <name>minFragmentShadingRateAttachmentTexelSize</name></member>
<member limittype="max"><type>VkExtent2D</type> <name>maxFragmentShadingRateAttachmentTexelSize</name></member>
- <member limittype="noauto"><type>uint32_t</type> <name>maxFragmentShadingRateAttachmentTexelSizeAspectRatio</name></member>
+ <member limittype="max,pot"><type>uint32_t</type> <name>maxFragmentShadingRateAttachmentTexelSizeAspectRatio</name></member>
<member limittype="bitmask"><type>VkBool32</type> <name>primitiveFragmentShadingRateWithMultipleViewports</name></member>
<member limittype="bitmask"><type>VkBool32</type> <name>layeredShadingRateAttachments</name></member>
<member limittype="bitmask"><type>VkBool32</type> <name>fragmentShadingRateNonTrivialCombinerOps</name></member>
<member limittype="max"><type>VkExtent2D</type> <name>maxFragmentSize</name></member>
- <member limittype="noauto"><type>uint32_t</type> <name>maxFragmentSizeAspectRatio</name></member>
- <member limittype="noauto"><type>uint32_t</type> <name>maxFragmentShadingRateCoverageSamples</name></member>
+ <member limittype="max,pot"><type>uint32_t</type> <name>maxFragmentSizeAspectRatio</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxFragmentShadingRateCoverageSamples</name></member>
<member limittype="max"><type>VkSampleCountFlagBits</type> <name>maxFragmentShadingRateRasterizationSamples</name></member>
<member limittype="bitmask"><type>VkBool32</type> <name>fragmentShadingRateWithShaderDepthStencilWrites</name></member>
<member limittype="bitmask"><type>VkBool32</type> <name>fragmentShadingRateWithSampleMask</name></member>
@@ -5361,14 +5829,15 @@ typedef void <name>CAMetalLayer</name>;
<member><type>VkSampleCountFlags</type> <name>sampleCounts</name></member>
<member><type>VkExtent2D</type> <name>fragmentSize</name></member>
</type>
- <type category="struct" name="VkPhysicalDeviceShaderTerminateInvocationFeaturesKHR" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
- <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES_KHR"><type>VkStructureType</type><name>sType</name></member>
+ <type category="struct" name="VkPhysicalDeviceShaderTerminateInvocationFeatures" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
- <member><type>VkBool32</type> <name>shaderTerminateInvocation</name></member>
+ <member><type>VkBool32</type> <name>shaderTerminateInvocation</name></member>
</type>
+ <type category="struct" name="VkPhysicalDeviceShaderTerminateInvocationFeaturesKHR" alias="VkPhysicalDeviceShaderTerminateInvocationFeatures"/>
<type category="struct" name="VkPhysicalDeviceFragmentShadingRateEnumsFeaturesNV" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_FEATURES_NV"><type>VkStructureType</type> <name>sType</name></member>
- <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>fragmentShadingRateEnums</name></member>
<member><type>VkBool32</type> <name>supersampleFragmentShadingRates</name></member>
<member><type>VkBool32</type> <name>noInvocationFragmentShadingRates</name></member>
@@ -5376,14 +5845,14 @@ typedef void <name>CAMetalLayer</name>;
<type category="struct" name="VkPhysicalDeviceFragmentShadingRateEnumsPropertiesNV" structextends="VkPhysicalDeviceProperties2">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_PROPERTIES_NV"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true"><type>void</type>* <name>pNext</name></member>
- <member limittype="bitmask"><type>VkSampleCountFlagBits</type> <name>maxFragmentShadingRateInvocationCount</name></member>
+ <member limittype="max"><type>VkSampleCountFlagBits</type> <name>maxFragmentShadingRateInvocationCount</name></member>
</type>
<type category="struct" name="VkPipelineFragmentShadingRateEnumStateCreateInfoNV" structextends="VkGraphicsPipelineCreateInfo">
<member values="VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_ENUM_STATE_CREATE_INFO_NV"><type>VkStructureType</type> <name>sType</name></member>
<member optional="true">const <type>void</type>* <name>pNext</name></member>
- <member><type>VkFragmentShadingRateTypeNV</type> <name>shadingRateType</name></member>
- <member><type>VkFragmentShadingRateNV</type> <name>shadingRate</name></member>
- <member><type>VkFragmentShadingRateCombinerOpKHR</type> <name>combinerOps</name>[2]</member>
+ <member noautovalidity="true"><type>VkFragmentShadingRateTypeNV</type> <name>shadingRateType</name></member>
+ <member noautovalidity="true"><type>VkFragmentShadingRateNV</type> <name>shadingRate</name></member>
+ <member noautovalidity="true"><type>VkFragmentShadingRateCombinerOpKHR</type> <name>combinerOps</name>[2]</member>
</type>
<type category="struct" name="VkAccelerationStructureBuildSizesInfoKHR">
<member values="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
@@ -5392,42 +5861,61 @@ typedef void <name>CAMetalLayer</name>;
<member><type>VkDeviceSize</type> <name>updateScratchSize</name></member>
<member><type>VkDeviceSize</type> <name>buildScratchSize</name></member>
</type>
- <type category="struct" name="VkPhysicalDeviceMutableDescriptorTypeFeaturesVALVE" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
- <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_VALVE"><type>VkStructureType</type> <name>sType</name></member>
- <member noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <type category="struct" name="VkPhysicalDeviceImage2DViewOf3DFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_2D_VIEW_OF_3D_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>image2DViewOf3D</name></member>
+ <member><type>VkBool32</type> <name>sampler2DViewOf3D</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>mutableDescriptorType</name></member>
</type>
- <type category="struct" name="VkMutableDescriptorTypeListVALVE">
- <member optional="true"><type>uint32_t</type> <name>descriptorTypeCount</name></member>
+ <type category="struct" name="VkPhysicalDeviceMutableDescriptorTypeFeaturesVALVE" alias="VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT"/>
+ <type category="struct" name="VkMutableDescriptorTypeListEXT">
+ <member optional="true"><type>uint32_t</type> <name>descriptorTypeCount</name></member>
<member len="descriptorTypeCount">const <type>VkDescriptorType</type>* <name>pDescriptorTypes</name></member>
</type>
- <type category="struct" name="VkMutableDescriptorTypeCreateInfoVALVE" structextends="VkDescriptorSetLayoutCreateInfo,VkDescriptorPoolCreateInfo">
- <member values="VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_VALVE"><type>VkStructureType</type> <name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member optional="true"><type>uint32_t</type> <name>mutableDescriptorTypeListCount</name></member>
- <member len="mutableDescriptorTypeListCount">const <type>VkMutableDescriptorTypeListVALVE</type>* <name>pMutableDescriptorTypeLists</name></member>
+ <type category="struct" name="VkMutableDescriptorTypeListVALVE" alias="VkMutableDescriptorTypeListEXT"/>
+ <type category="struct" name="VkMutableDescriptorTypeCreateInfoEXT" structextends="VkDescriptorSetLayoutCreateInfo,VkDescriptorPoolCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>uint32_t</type> <name>mutableDescriptorTypeListCount</name></member>
+ <member len="mutableDescriptorTypeListCount">const <type>VkMutableDescriptorTypeListEXT</type>* <name>pMutableDescriptorTypeLists</name></member>
+ </type>
+ <type category="struct" name="VkMutableDescriptorTypeCreateInfoVALVE" alias="VkMutableDescriptorTypeCreateInfoEXT"/>
+ <type category="struct" name="VkPhysicalDeviceDepthClipControlFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>depthClipControl</name></member>
+ </type>
+ <type category="struct" name="VkPipelineViewportDepthClipControlCreateInfoEXT" structextends="VkPipelineViewportStateCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_DEPTH_CLIP_CONTROL_CREATE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>negativeOneToOne</name></member>
</type>
<type category="struct" name="VkPhysicalDeviceVertexInputDynamicStateFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_INPUT_DYNAMIC_STATE_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
- <member noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>vertexInputDynamicState</name></member>
</type>
<type category="struct" name="VkPhysicalDeviceExternalMemoryRDMAFeaturesNV" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_RDMA_FEATURES_NV"><type>VkStructureType</type> <name>sType</name></member>
- <member noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>externalMemoryRDMA</name></member>
</type>
<type category="struct" name="VkVertexInputBindingDescription2EXT">
- <member values="VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT"><type>VkStructureType</type><name>sType</name></member>
- <member noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <member values="VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
<member><type>uint32_t</type> <name>binding</name></member>
<member><type>uint32_t</type> <name>stride</name></member>
<member><type>VkVertexInputRate</type> <name>inputRate</name></member>
<member><type>uint32_t</type> <name>divisor</name></member>
</type>
<type category="struct" name="VkVertexInputAttributeDescription2EXT">
- <member values="VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT"><type>VkStructureType</type><name>sType</name></member>
- <member noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <member values="VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
<member><type>uint32_t</type> <name>location</name><comment>location of the shader vertex attrib</comment></member>
<member><type>uint32_t</type> <name>binding</name><comment>Vertex buffer binding id</comment></member>
<member><type>VkFormat</type> <name>format</name><comment>format of source data</comment></member>
@@ -5444,181 +5932,240 @@ typedef void <name>CAMetalLayer</name>;
<member optional="true"><type>uint32_t</type> <name>attachmentCount</name><comment># of pAttachments</comment></member>
<member len="attachmentCount">const <type>VkBool32</type>* <name>pColorWriteEnables</name></member>
</type>
- <type category="struct" name="VkMemoryBarrier2KHR" structextends="VkSubpassDependency2">
- <member values="VK_STRUCTURE_TYPE_MEMORY_BARRIER_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member optional="true"><type>VkPipelineStageFlags2KHR</type> <name>srcStageMask</name></member>
- <member optional="true"><type>VkAccessFlags2KHR</type> <name>srcAccessMask</name></member>
- <member optional="true"><type>VkPipelineStageFlags2KHR</type> <name>dstStageMask</name></member>
- <member optional="true"><type>VkAccessFlags2KHR</type> <name>dstAccessMask</name></member>
- </type>
- <type category="struct" name="VkImageMemoryBarrier2KHR">
- <member values="VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member optional="true"><type>VkPipelineStageFlags2KHR</type> <name>srcStageMask</name></member>
- <member optional="true"><type>VkAccessFlags2KHR</type> <name>srcAccessMask</name></member>
- <member optional="true"><type>VkPipelineStageFlags2KHR</type> <name>dstStageMask</name></member>
- <member optional="true"><type>VkAccessFlags2KHR</type> <name>dstAccessMask</name></member>
- <member><type>VkImageLayout</type> <name>oldLayout</name></member>
- <member><type>VkImageLayout</type> <name>newLayout</name></member>
- <member><type>uint32_t</type> <name>srcQueueFamilyIndex</name></member>
- <member><type>uint32_t</type> <name>dstQueueFamilyIndex</name></member>
- <member><type>VkImage</type> <name>image</name></member>
- <member><type>VkImageSubresourceRange</type> <name>subresourceRange</name></member>
- </type>
- <type category="struct" name="VkBufferMemoryBarrier2KHR">
- <member values="VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member optional="true"><type>VkPipelineStageFlags2KHR</type> <name>srcStageMask</name></member>
- <member optional="true"><type>VkAccessFlags2KHR</type> <name>srcAccessMask</name></member>
- <member optional="true"><type>VkPipelineStageFlags2KHR</type> <name>dstStageMask</name></member>
- <member optional="true"><type>VkAccessFlags2KHR</type> <name>dstAccessMask</name></member>
- <member><type>uint32_t</type> <name>srcQueueFamilyIndex</name></member>
- <member><type>uint32_t</type> <name>dstQueueFamilyIndex</name></member>
- <member><type>VkBuffer</type> <name>buffer</name></member>
- <member><type>VkDeviceSize</type> <name>offset</name></member>
- <member><type>VkDeviceSize</type> <name>size</name></member>
- </type>
- <type category="struct" name="VkDependencyInfoKHR">
- <member values="VK_STRUCTURE_TYPE_DEPENDENCY_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member optional="true"><type>VkDependencyFlags</type> <name>dependencyFlags</name></member>
- <member optional="true"><type>uint32_t</type> <name>memoryBarrierCount</name></member>
- <member len="memoryBarrierCount">const <type>VkMemoryBarrier2KHR</type>* <name>pMemoryBarriers</name></member>
- <member optional="true"><type>uint32_t</type> <name>bufferMemoryBarrierCount</name></member>
- <member len="bufferMemoryBarrierCount">const <type>VkBufferMemoryBarrier2KHR</type>* <name>pBufferMemoryBarriers</name></member>
- <member optional="true"><type>uint32_t</type> <name>imageMemoryBarrierCount</name></member>
- <member len="imageMemoryBarrierCount">const <type>VkImageMemoryBarrier2KHR</type>* <name>pImageMemoryBarriers</name></member>
- </type>
- <type category="struct" name="VkSemaphoreSubmitInfoKHR">
- <member values="VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
+ <type category="struct" name="VkMemoryBarrier2" structextends="VkSubpassDependency2">
+ <member values="VK_STRUCTURE_TYPE_MEMORY_BARRIER_2"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkPipelineStageFlags2</type> <name>srcStageMask</name></member>
+ <member optional="true"><type>VkAccessFlags2</type> <name>srcAccessMask</name></member>
+ <member optional="true"><type>VkPipelineStageFlags2</type> <name>dstStageMask</name></member>
+ <member optional="true"><type>VkAccessFlags2</type> <name>dstAccessMask</name></member>
+ </type>
+ <type category="struct" name="VkMemoryBarrier2KHR" alias="VkMemoryBarrier2"/>
+ <type category="struct" name="VkImageMemoryBarrier2">
+ <member values="VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkPipelineStageFlags2</type> <name>srcStageMask</name></member>
+ <member optional="true"><type>VkAccessFlags2</type> <name>srcAccessMask</name></member>
+ <member optional="true"><type>VkPipelineStageFlags2</type> <name>dstStageMask</name></member>
+ <member optional="true"><type>VkAccessFlags2</type> <name>dstAccessMask</name></member>
+ <member><type>VkImageLayout</type> <name>oldLayout</name></member>
+ <member><type>VkImageLayout</type> <name>newLayout</name></member>
+ <member><type>uint32_t</type> <name>srcQueueFamilyIndex</name></member>
+ <member><type>uint32_t</type> <name>dstQueueFamilyIndex</name></member>
+ <member><type>VkImage</type> <name>image</name></member>
+ <member><type>VkImageSubresourceRange</type> <name>subresourceRange</name></member>
+ </type>
+ <type category="struct" name="VkImageMemoryBarrier2KHR" alias="VkImageMemoryBarrier2"/>
+ <type category="struct" name="VkBufferMemoryBarrier2">
+ <member values="VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkPipelineStageFlags2</type> <name>srcStageMask</name></member>
+ <member optional="true"><type>VkAccessFlags2</type> <name>srcAccessMask</name></member>
+ <member optional="true"><type>VkPipelineStageFlags2</type> <name>dstStageMask</name></member>
+ <member optional="true"><type>VkAccessFlags2</type> <name>dstAccessMask</name></member>
+ <member><type>uint32_t</type> <name>srcQueueFamilyIndex</name></member>
+ <member><type>uint32_t</type> <name>dstQueueFamilyIndex</name></member>
+ <member><type>VkBuffer</type> <name>buffer</name></member>
+ <member><type>VkDeviceSize</type> <name>offset</name></member>
+ <member><type>VkDeviceSize</type> <name>size</name></member>
+ </type>
+ <type category="struct" name="VkBufferMemoryBarrier2KHR" alias="VkBufferMemoryBarrier2"/>
+ <type category="struct" name="VkDependencyInfo">
+ <member values="VK_STRUCTURE_TYPE_DEPENDENCY_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkDependencyFlags</type> <name>dependencyFlags</name></member>
+ <member optional="true"><type>uint32_t</type> <name>memoryBarrierCount</name></member>
+ <member len="memoryBarrierCount">const <type>VkMemoryBarrier2</type>* <name>pMemoryBarriers</name></member>
+ <member optional="true"><type>uint32_t</type> <name>bufferMemoryBarrierCount</name></member>
+ <member len="bufferMemoryBarrierCount">const <type>VkBufferMemoryBarrier2</type>* <name>pBufferMemoryBarriers</name></member>
+ <member optional="true"><type>uint32_t</type> <name>imageMemoryBarrierCount</name></member>
+ <member len="imageMemoryBarrierCount">const <type>VkImageMemoryBarrier2</type>* <name>pImageMemoryBarriers</name></member>
+ </type>
+ <type category="struct" name="VkDependencyInfoKHR" alias="VkDependencyInfo"/>
+ <type category="struct" name="VkSemaphoreSubmitInfo">
+ <member values="VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
<member><type>VkSemaphore</type> <name>semaphore</name></member>
<member><type>uint64_t</type> <name>value</name></member>
- <member optional="true"><type>VkPipelineStageFlags2KHR</type> <name>stageMask</name></member>
+ <member optional="true"><type>VkPipelineStageFlags2</type> <name>stageMask</name></member>
<member><type>uint32_t</type> <name>deviceIndex</name></member>
</type>
- <type category="struct" name="VkCommandBufferSubmitInfoKHR">
- <member values="VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
+ <type category="struct" name="VkSemaphoreSubmitInfoKHR" alias="VkSemaphoreSubmitInfo"/>
+ <type category="struct" name="VkCommandBufferSubmitInfo">
+ <member values="VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
<member><type>VkCommandBuffer</type> <name>commandBuffer</name></member>
<member><type>uint32_t</type> <name>deviceMask</name></member>
</type>
- <type category="struct" name="VkSubmitInfo2KHR">
- <member values="VK_STRUCTURE_TYPE_SUBMIT_INFO_2_KHR"><type>VkStructureType</type> <name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member optional="true"><type>VkSubmitFlagsKHR</type> <name>flags</name></member>
+ <type category="struct" name="VkCommandBufferSubmitInfoKHR" alias="VkCommandBufferSubmitInfo"/>
+ <type category="struct" name="VkSubmitInfo2">
+ <member values="VK_STRUCTURE_TYPE_SUBMIT_INFO_2"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkSubmitFlags</type> <name>flags</name></member>
<member optional="true"><type>uint32_t</type> <name>waitSemaphoreInfoCount</name></member>
- <member len="waitSemaphoreInfoCount">const <type>VkSemaphoreSubmitInfoKHR</type>* <name>pWaitSemaphoreInfos</name></member>
+ <member len="waitSemaphoreInfoCount">const <type>VkSemaphoreSubmitInfo</type>* <name>pWaitSemaphoreInfos</name></member>
<member optional="true"><type>uint32_t</type> <name>commandBufferInfoCount</name></member>
- <member len="commandBufferInfoCount">const <type>VkCommandBufferSubmitInfoKHR</type>* <name>pCommandBufferInfos</name></member>
+ <member len="commandBufferInfoCount">const <type>VkCommandBufferSubmitInfo</type>* <name>pCommandBufferInfos</name></member>
<member optional="true"><type>uint32_t</type> <name>signalSemaphoreInfoCount</name></member>
- <member len="signalSemaphoreInfoCount">const <type>VkSemaphoreSubmitInfoKHR</type>* <name>pSignalSemaphoreInfos</name></member>
+ <member len="signalSemaphoreInfoCount">const <type>VkSemaphoreSubmitInfo</type>* <name>pSignalSemaphoreInfos</name></member>
</type>
+ <type category="struct" name="VkSubmitInfo2KHR" alias="VkSubmitInfo2"/>
<type category="struct" name="VkQueueFamilyCheckpointProperties2NV" structextends="VkQueueFamilyProperties2" returnedonly="true">
<member values="VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_2_NV"><type>VkStructureType</type> <name>sType</name></member>
- <member><type>void</type>* <name>pNext</name></member>
- <member><type>VkPipelineStageFlags2KHR</type> <name>checkpointExecutionStageMask</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member limittype="bitmask"><type>VkPipelineStageFlags2</type> <name>checkpointExecutionStageMask</name></member>
</type>
<type category="struct" name="VkCheckpointData2NV" returnedonly="true">
<member values="VK_STRUCTURE_TYPE_CHECKPOINT_DATA_2_NV"><type>VkStructureType</type> <name>sType</name></member>
- <member><type>void</type>* <name>pNext</name></member>
- <member><type>VkPipelineStageFlags2KHR</type> <name>stage</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkPipelineStageFlags2</type> <name>stage</name></member>
<member noautovalidity="true"><type>void</type>* <name>pCheckpointMarker</name></member>
</type>
- <type category="struct" name="VkPhysicalDeviceSynchronization2FeaturesKHR" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
- <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR"><type>VkStructureType</type> <name>sType</name></member>
- <member noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <type category="struct" name="VkPhysicalDeviceSynchronization2Features" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>synchronization2</name></member>
</type>
- <type category="struct" name="VkVideoQueueFamilyProperties2KHR" structextends="VkQueueFamilyProperties2">
- <member values="VK_STRUCTURE_TYPE_VIDEO_QUEUE_FAMILY_PROPERTIES_2_KHR"><type>VkStructureType</type><name>sType</name></member>
- <member><type>void</type>* <name>pNext</name></member>
- <member><type>VkVideoCodecOperationFlagsKHR</type> <name>videoCodecOperations</name></member>
+ <type category="struct" name="VkPhysicalDeviceSynchronization2FeaturesKHR" alias="VkPhysicalDeviceSynchronization2Features"/>
+ <type category="struct" name="VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>primitivesGeneratedQuery</name></member>
+ <member><type>VkBool32</type> <name>primitivesGeneratedQueryWithRasterizerDiscard</name></member>
+ <member><type>VkBool32</type> <name>primitivesGeneratedQueryWithNonZeroStreams</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceLegacyDitheringFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_DITHERING_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>legacyDithering</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>multisampledRenderToSingleSampled</name></member>
+ </type>
+ <type category="struct" name="VkSubpassResolvePerformanceQueryEXT" returnedonly="true" structextends="VkFormatProperties2">
+ <member values="VK_STRUCTURE_TYPE_SUBPASS_RESOLVE_PERFORMANCE_QUERY_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>optimal</name></member>
+ </type>
+ <type category="struct" name="VkMultisampledRenderToSingleSampledInfoEXT" structextends="VkSubpassDescription2,VkRenderingInfo">
+ <member values="VK_STRUCTURE_TYPE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>multisampledRenderToSingleSampledEnable</name></member>
+ <member><type>VkSampleCountFlagBits</type> <name>rasterizationSamples</name></member>
</type>
- <type category="struct" name="VkVideoProfilesKHR" structextends="VkFormatProperties2,VkImageCreateInfo,VkImageViewCreateInfo,VkBufferCreateInfo">
- <member values="VK_STRUCTURE_TYPE_VIDEO_PROFILES_KHR"><type>VkStructureType</type><name>sType</name></member>
- <member><type>void</type>* <name>pNext</name></member>
- <member><type>uint32_t</type> <name>profileCount</name></member>
- <member>const <type>VkVideoProfileKHR</type>* <name>pProfiles</name></member>
+ <type category="struct" name="VkPhysicalDevicePipelineProtectedAccessFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROTECTED_ACCESS_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>pipelineProtectedAccess</name></member>
</type>
- <type category="struct" name="VkPhysicalDeviceVideoFormatInfoKHR" returnedonly="true">
- <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_FORMAT_INFO_KHR"><type>VkStructureType</type><name>sType</name></member>
- <member><type>void</type>* <name>pNext</name></member>
- <member><type>VkImageUsageFlags</type> <name>imageUsage</name></member>
- <member>const <type>VkVideoProfilesKHR</type>* <name>pVideoProfiles</name></member>
+ <type category="struct" name="VkQueueFamilyVideoPropertiesKHR" returnedonly="true" structextends="VkQueueFamilyProperties2">
+ <member values="VK_STRUCTURE_TYPE_QUEUE_FAMILY_VIDEO_PROPERTIES_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member limittype="bitmask"><type>VkVideoCodecOperationFlagsKHR</type> <name>videoCodecOperations</name></member>
+ </type>
+ <type category="struct" name="VkQueueFamilyQueryResultStatusPropertiesKHR" returnedonly="true" structextends="VkQueueFamilyProperties2">
+ <member values="VK_STRUCTURE_TYPE_QUEUE_FAMILY_QUERY_RESULT_STATUS_PROPERTIES_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>queryResultStatusSupport</name></member>
+ </type>
+ <type category="struct" name="VkVideoProfileListInfoKHR" structextends="VkPhysicalDeviceImageFormatInfo2,VkPhysicalDeviceVideoFormatInfoKHR,VkImageCreateInfo,VkBufferCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>uint32_t</type> <name>profileCount</name></member>
+ <member len="profileCount">const <type>VkVideoProfileInfoKHR</type>* <name>pProfiles</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceVideoFormatInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_FORMAT_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkImageUsageFlags</type> <name>imageUsage</name></member>
</type>
<type category="struct" name="VkVideoFormatPropertiesKHR" returnedonly="true">
- <member values="VK_STRUCTURE_TYPE_VIDEO_FORMAT_PROPERTIES_KHR"><type>VkStructureType</type><name>sType</name></member>
- <member><type>void</type>* <name>pNext</name></member>
- <member><type>VkFormat</type> <name>format</name></member>
- </type>
- <type category="struct" name="VkVideoProfileKHR" structextends="VkQueryPoolCreateInfo,VkFormatProperties2,VkImageCreateInfo,VkImageViewCreateInfo,VkBufferCreateInfo">
- <member values="VK_STRUCTURE_TYPE_VIDEO_PROFILE_KHR"><type>VkStructureType</type><name>sType</name></member>
- <member><type>void</type>* <name>pNext</name></member>
- <member><type>VkVideoCodecOperationFlagBitsKHR</type> <name>videoCodecOperation</name></member>
- <member><type>VkVideoChromaSubsamplingFlagsKHR</type> <name>chromaSubsampling</name></member>
- <member><type>VkVideoComponentBitDepthFlagsKHR</type> <name>lumaBitDepth</name></member>
- <member><type>VkVideoComponentBitDepthFlagsKHR</type> <name>chromaBitDepth</name></member>
+ <member values="VK_STRUCTURE_TYPE_VIDEO_FORMAT_PROPERTIES_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkFormat</type> <name>format</name></member>
+ <member><type>VkComponentMapping</type> <name>componentMapping</name></member>
+ <member><type>VkImageCreateFlags</type> <name>imageCreateFlags</name></member>
+ <member><type>VkImageType</type> <name>imageType</name></member>
+ <member><type>VkImageTiling</type> <name>imageTiling</name></member>
+ <member><type>VkImageUsageFlags</type> <name>imageUsageFlags</name></member>
+ </type>
+ <type category="struct" name="VkVideoProfileInfoKHR" structextends="VkQueryPoolCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_PROFILE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkVideoCodecOperationFlagBitsKHR</type> <name>videoCodecOperation</name></member>
+ <member><type>VkVideoChromaSubsamplingFlagsKHR</type> <name>chromaSubsampling</name></member>
+ <member><type>VkVideoComponentBitDepthFlagsKHR</type> <name>lumaBitDepth</name></member>
+ <member optional="true"><type>VkVideoComponentBitDepthFlagsKHR</type> <name>chromaBitDepth</name></member>
</type>
<type category="struct" name="VkVideoCapabilitiesKHR" returnedonly="true">
- <member values="VK_STRUCTURE_TYPE_VIDEO_CAPABILITIES_KHR"><type>VkStructureType</type><name>sType</name></member>
- <member><type>void</type>* <name>pNext</name></member>
- <member><type>VkVideoCapabilitiesFlagsKHR</type> <name>capabilityFlags</name></member>
- <member><type>VkDeviceSize</type> <name>minBitstreamBufferOffsetAlignment</name></member>
- <member><type>VkDeviceSize</type> <name>minBitstreamBufferSizeAlignment</name></member>
- <member><type>VkExtent2D</type> <name>videoPictureExtentGranularity</name></member>
- <member><type>VkExtent2D</type> <name>minExtent</name></member>
- <member><type>VkExtent2D</type> <name>maxExtent</name></member>
- <member><type>uint32_t</type> <name>maxReferencePicturesSlotsCount</name></member>
- <member><type>uint32_t</type> <name>maxReferencePicturesActiveCount</name></member>
- </type>
- <type category="struct" name="VkVideoGetMemoryPropertiesKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_GET_MEMORY_PROPERTIES_KHR"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member><type>uint32_t</type> <name>memoryBindIndex</name></member>
- <member><type>VkMemoryRequirements2</type>* <name>pMemoryRequirements</name></member>
- </type>
- <type category="struct" name="VkVideoBindMemoryKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_BIND_MEMORY_KHR"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member><type>uint32_t</type> <name>memoryBindIndex</name></member>
- <member><type>VkDeviceMemory</type> <name>memory</name></member>
- <member><type>VkDeviceSize</type> <name>memoryOffset</name></member>
- <member><type>VkDeviceSize</type> <name>memorySize</name></member>
- </type>
- <type category="struct" name="VkVideoPictureResourceKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_KHR"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member><type>VkOffset2D</type> <name>codedOffset</name><comment>The offset to be used for the picture resource, currently only used in field mode</comment></member>
- <member><type>VkExtent2D</type> <name>codedExtent</name><comment>The extent to be used for the picture resource</comment></member>
- <member><type>uint32_t</type> <name>baseArrayLayer</name><comment>TThe first array layer to be accessed for the Decode or Encode Operations</comment></member>
- <member><type>VkImageView</type> <name>imageViewBinding</name><comment>The ImageView binding of the resource</comment></member>
- </type>
- <type category="struct" name="VkVideoReferenceSlotKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_REFERENCE_SLOT_KHR"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member><type>int8_t</type> <name>slotIndex</name><comment>The reference slot index</comment></member>
- <member>const <type>VkVideoPictureResourceKHR</type>* <name>pPictureResource</name><comment>The reference picture resource</comment></member>
+ <member values="VK_STRUCTURE_TYPE_VIDEO_CAPABILITIES_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkVideoCapabilityFlagsKHR</type> <name>flags</name></member>
+ <member><type>VkDeviceSize</type> <name>minBitstreamBufferOffsetAlignment</name></member>
+ <member><type>VkDeviceSize</type> <name>minBitstreamBufferSizeAlignment</name></member>
+ <member><type>VkExtent2D</type> <name>pictureAccessGranularity</name></member>
+ <member><type>VkExtent2D</type> <name>minCodedExtent</name></member>
+ <member><type>VkExtent2D</type> <name>maxCodedExtent</name></member>
+ <member><type>uint32_t</type> <name>maxDpbSlots</name></member>
+ <member><type>uint32_t</type> <name>maxActiveReferencePictures</name></member>
+ <member><type>VkExtensionProperties</type> <name>stdHeaderVersion</name></member>
+ </type>
+ <type category="struct" name="VkVideoSessionMemoryRequirementsKHR" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_SESSION_MEMORY_REQUIREMENTS_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>memoryBindIndex</name></member>
+ <member><type>VkMemoryRequirements</type> <name>memoryRequirements</name></member>
+ </type>
+ <type category="struct" name="VkBindVideoSessionMemoryInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_BIND_VIDEO_SESSION_MEMORY_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>memoryBindIndex</name></member>
+ <member><type>VkDeviceMemory</type> <name>memory</name></member>
+ <member><type>VkDeviceSize</type> <name>memoryOffset</name></member>
+ <member><type>VkDeviceSize</type> <name>memorySize</name></member>
+ </type>
+ <type category="struct" name="VkVideoPictureResourceInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkOffset2D</type> <name>codedOffset</name><comment>The offset to be used for the picture resource, currently only used in field mode</comment></member>
+ <member><type>VkExtent2D</type> <name>codedExtent</name><comment>The extent to be used for the picture resource</comment></member>
+ <member><type>uint32_t</type> <name>baseArrayLayer</name><comment>The first array layer to be accessed for the Decode or Encode Operations</comment></member>
+ <member><type>VkImageView</type> <name>imageViewBinding</name><comment>The ImageView binding of the resource</comment></member>
+ </type>
+ <type category="struct" name="VkVideoReferenceSlotInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_REFERENCE_SLOT_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>int32_t</type> <name>slotIndex</name><comment>The reference slot index</comment></member>
+ <member optional="true">const <type>VkVideoPictureResourceInfoKHR</type>* <name>pPictureResource</name><comment>The reference picture resource</comment></member>
+ </type>
+ <type category="struct" name="VkVideoDecodeCapabilitiesKHR" returnedonly="true" structextends="VkVideoCapabilitiesKHR">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_DECODE_CAPABILITIES_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member noautovalidity="true"><type>VkVideoDecodeCapabilityFlagsKHR</type> <name>flags</name></member>
+ </type>
+ <type category="struct" name="VkVideoDecodeUsageInfoKHR" structextends="VkVideoProfileInfoKHR,VkQueryPoolCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_DECODE_USAGE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkVideoDecodeUsageFlagsKHR</type> <name>videoUsageHints</name></member>
</type>
<type category="struct" name="VkVideoDecodeInfoKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_DECODE_INFO_KHR"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member optional="true"><type>VkVideoDecodeFlagsKHR</type> <name>flags</name></member>
- <member><type>VkOffset2D</type> <name>codedOffset</name></member>
- <member><type>VkExtent2D</type> <name>codedExtent</name></member>
- <member><type>VkBuffer</type> <name>srcBuffer</name></member>
- <member><type>VkDeviceSize</type> <name>srcBufferOffset</name></member>
- <member><type>VkDeviceSize</type> <name>srcBufferRange</name></member>
- <member><type>VkVideoPictureResourceKHR</type> <name>dstPictureResource</name></member>
- <member>const <type>VkVideoReferenceSlotKHR</type>* <name>pSetupReferenceSlot</name></member>
- <member><type>uint32_t</type> <name>referenceSlotCount</name></member>
- <member len="referenceSlotCount">const <type>VkVideoReferenceSlotKHR</type>* <name>pReferenceSlots</name></member>
+ <member values="VK_STRUCTURE_TYPE_VIDEO_DECODE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkVideoDecodeFlagsKHR</type> <name>flags</name></member>
+ <member><type>VkBuffer</type> <name>srcBuffer</name></member>
+ <member><type>VkDeviceSize</type> <name>srcBufferOffset</name></member>
+ <member><type>VkDeviceSize</type> <name>srcBufferRange</name></member>
+ <member><type>VkVideoPictureResourceInfoKHR</type> <name>dstPictureResource</name></member>
+ <member optional="true">const <type>VkVideoReferenceSlotInfoKHR</type>* <name>pSetupReferenceSlot</name></member>
+ <member optional="true"><type>uint32_t</type> <name>referenceSlotCount</name></member>
+ <member len="referenceSlotCount">const <type>VkVideoReferenceSlotInfoKHR</type>* <name>pReferenceSlots</name></member>
</type>
<comment>Video Decode Codec Standard specific structures</comment>
<type category="include" name="vk_video/vulkan_video_codec_h264std.h">#include "vk_video/vulkan_video_codec_h264std.h"</type>
<type requires="vk_video/vulkan_video_codec_h264std.h" name="StdVideoH264ProfileIdc"/>
- <type requires="vk_video/vulkan_video_codec_h264std.h" name="StdVideoH264Level"/>
+ <type requires="vk_video/vulkan_video_codec_h264std.h" name="StdVideoH264LevelIdc"/>
<type requires="vk_video/vulkan_video_codec_h264std.h" name="StdVideoH264ChromaFormatIdc"/>
<type requires="vk_video/vulkan_video_codec_h264std.h" name="StdVideoH264PocType"/>
<type requires="vk_video/vulkan_video_codec_h264std.h" name="StdVideoH264SpsFlags"/>
@@ -5627,7 +6174,7 @@ typedef void <name>CAMetalLayer</name>;
<type requires="vk_video/vulkan_video_codec_h264std.h" name="StdVideoH264AspectRatioIdc"/>
<type requires="vk_video/vulkan_video_codec_h264std.h" name="StdVideoH264HrdParameters"/>
<type requires="vk_video/vulkan_video_codec_h264std.h" name="StdVideoH264SpsVuiFlags"/>
- <type requires="vk_video/vulkan_video_codec_h264std.h" name="StdVideoH264WeightedBiPredIdc"/>
+ <type requires="vk_video/vulkan_video_codec_h264std.h" name="StdVideoH264WeightedBipredIdc"/>
<type requires="vk_video/vulkan_video_codec_h264std.h" name="StdVideoH264PpsFlags"/>
<type requires="vk_video/vulkan_video_codec_h264std.h" name="StdVideoH264SliceType"/>
<type requires="vk_video/vulkan_video_codec_h264std.h" name="StdVideoH264CabacInitIdc"/>
@@ -5638,63 +6185,48 @@ typedef void <name>CAMetalLayer</name>;
<type category="include" name="vk_video/vulkan_video_codec_h264std_decode.h">#include "vk_video/vulkan_video_codec_h264std_decode.h"</type>
<type requires="vk_video/vulkan_video_codec_h264std_decode.h" name="StdVideoDecodeH264PictureInfo"/>
<type requires="vk_video/vulkan_video_codec_h264std_decode.h" name="StdVideoDecodeH264ReferenceInfo"/>
- <type requires="vk_video/vulkan_video_codec_h264std_decode.h" name="StdVideoDecodeH264Mvc"/>
<type requires="vk_video/vulkan_video_codec_h264std_decode.h" name="StdVideoDecodeH264PictureInfoFlags"/>
<type requires="vk_video/vulkan_video_codec_h264std_decode.h" name="StdVideoDecodeH264ReferenceInfoFlags"/>
- <type requires="vk_video/vulkan_video_codec_h264std_decode.h" name="StdVideoDecodeH264MvcElement"/>
- <type requires="vk_video/vulkan_video_codec_h264std_decode.h" name="StdVideoDecodeH264MvcElementFlags"/>
- <type category="struct" name="VkVideoDecodeH264ProfileEXT" structextends="VkVideoProfileKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PROFILE_EXT"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member><type>StdVideoH264ProfileIdc</type> <name>stdProfileIdc</name></member>
- <member><type>VkVideoDecodeH264FieldLayoutFlagsEXT</type> <name>fieldLayout</name></member>
- </type>
- <type category="struct" name="VkVideoDecodeH264CapabilitiesEXT" returnedonly="true" structextends="VkVideoCapabilitiesKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_CAPABILITIES_EXT"><type>VkStructureType</type><name>sType</name></member>
- <member><type>void</type>* <name>pNext</name></member>
- <member><type>uint32_t</type> <name>maxLevel</name></member>
- <member><type>VkOffset2D</type> <name>fieldOffsetGranularity</name></member>
- <member><type>VkExtensionProperties</type> <name>stdExtensionVersion</name></member>
- </type>
- <type category="struct" name="VkVideoDecodeH264SessionCreateInfoEXT" structextends="VkVideoSessionCreateInfoKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_CREATE_INFO_EXT"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member><type>VkVideoDecodeH264CreateFlagsEXT</type> <name>flags</name></member>
- <member>const <type>VkExtensionProperties</type>* <name>pStdExtensionVersion</name></member>
+ <type category="struct" name="VkVideoDecodeH264ProfileInfoKHR" structextends="VkVideoProfileInfoKHR,VkQueryPoolCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PROFILE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>StdVideoH264ProfileIdc</type> <name>stdProfileIdc</name></member>
+ <member optional="true"><type>VkVideoDecodeH264PictureLayoutFlagBitsKHR</type> <name>pictureLayout</name></member>
+ </type>
+ <type category="struct" name="VkVideoDecodeH264CapabilitiesKHR" returnedonly="true" structextends="VkVideoCapabilitiesKHR">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_CAPABILITIES_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>StdVideoH264LevelIdc</type> <name>maxLevelIdc</name></member>
+ <member><type>VkOffset2D</type> <name>fieldOffsetGranularity</name></member>
</type>
<type requires="vk_video/vulkan_video_codec_h264std.h" name="StdVideoH264SequenceParameterSet"/>
<type requires="vk_video/vulkan_video_codec_h264std.h" name="StdVideoH264PictureParameterSet"/>
- <type category="struct" name="VkVideoDecodeH264SessionParametersAddInfoEXT" structextends="VkVideoSessionParametersUpdateInfoKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_ADD_INFO_EXT"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member><type>uint32_t</type> <name>spsStdCount</name></member>
- <member len="spsStdCount" optional="true">const <type>StdVideoH264SequenceParameterSet</type>* <name>pSpsStd</name></member>
- <member><type>uint32_t</type> <name>ppsStdCount</name></member>
- <member len="ppsStdCount" optional="true">const <type>StdVideoH264PictureParameterSet</type>* <name>pPpsStd</name><comment>List of Picture Parameters associated with the spsStd, above</comment></member>
- </type>
- <type category="struct" name="VkVideoDecodeH264SessionParametersCreateInfoEXT" structextends="VkVideoSessionParametersCreateInfoKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_CREATE_INFO_EXT"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member><type>uint32_t</type> <name>maxSpsStdCount</name></member>
- <member><type>uint32_t</type> <name>maxPpsStdCount</name></member>
- <member optional="true">const <type>VkVideoDecodeH264SessionParametersAddInfoEXT</type>* <name>pParametersAddInfo</name></member>
- </type>
- <type category="struct" name="VkVideoDecodeH264PictureInfoEXT" structextends="VkVideoDecodeInfoKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PICTURE_INFO_EXT"><type>VkStructureType</type><name>sType</name></member>
- <member noautovalidity="true">const <type>void</type>* <name>pNext</name></member>
- <member>const <type>StdVideoDecodeH264PictureInfo</type>* <name>pStdPictureInfo</name></member>
- <member><type>uint32_t</type> <name>slicesCount</name></member>
- <member len="slicesCount">const <type>uint32_t</type>* <name>pSlicesDataOffsets</name></member>
- </type>
- <type category="struct" name="VkVideoDecodeH264DpbSlotInfoEXT" structextends="VkVideoReferenceSlotKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_DPB_SLOT_INFO_EXT"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member>const <type>StdVideoDecodeH264ReferenceInfo</type>* <name>pStdReferenceInfo</name></member>
- </type>
- <type category="struct" name="VkVideoDecodeH264MvcEXT" structextends="VkVideoDecodeH264PictureInfoEXT">
- <member values="VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_MVC_EXT"><type>VkStructureType</type><name>sType</name></member>
- <member noautovalidity="true">const <type>void</type>*<name>pNext</name></member>
- <member>const <type>StdVideoDecodeH264Mvc</type>* <name>pStdMvc</name></member>
+ <type category="struct" name="VkVideoDecodeH264SessionParametersAddInfoKHR" structextends="VkVideoSessionParametersUpdateInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_ADD_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>uint32_t</type> <name>stdSPSCount</name></member>
+ <member len="stdSPSCount">const <type>StdVideoH264SequenceParameterSet</type>* <name>pStdSPSs</name></member>
+ <member optional="true"><type>uint32_t</type> <name>stdPPSCount</name></member>
+ <member len="stdPPSCount">const <type>StdVideoH264PictureParameterSet</type>* <name>pStdPPSs</name><comment>List of Picture Parameters associated with the spsStd, above</comment></member>
+ </type>
+ <type category="struct" name="VkVideoDecodeH264SessionParametersCreateInfoKHR" structextends="VkVideoSessionParametersCreateInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_CREATE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>maxStdSPSCount</name></member>
+ <member><type>uint32_t</type> <name>maxStdPPSCount</name></member>
+ <member optional="true">const <type>VkVideoDecodeH264SessionParametersAddInfoKHR</type>* <name>pParametersAddInfo</name></member>
+ </type>
+ <type category="struct" name="VkVideoDecodeH264PictureInfoKHR" structextends="VkVideoDecodeInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PICTURE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member>const <type>StdVideoDecodeH264PictureInfo</type>* <name>pStdPictureInfo</name></member>
+ <member><type>uint32_t</type> <name>sliceCount</name></member>
+ <member len="sliceCount">const <type>uint32_t</type>* <name>pSliceOffsets</name></member>
+ </type>
+ <type category="struct" name="VkVideoDecodeH264DpbSlotInfoKHR" structextends="VkVideoReferenceSlotInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_DPB_SLOT_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member>const <type>StdVideoDecodeH264ReferenceInfo</type>* <name>pStdReferenceInfo</name></member>
</type>
<type category="include" name="vk_video/vulkan_video_codec_h265std.h">#include "vk_video/vulkan_video_codec_h265std.h"</type>
<type requires="vk_video/vulkan_video_codec_h265std.h" name="StdVideoH265ProfileIdc"/>
@@ -5704,7 +6236,7 @@ typedef void <name>CAMetalLayer</name>;
<type requires="vk_video/vulkan_video_codec_h265std.h" name="StdVideoH265DecPicBufMgr"/>
<type requires="vk_video/vulkan_video_codec_h265std.h" name="StdVideoH265HrdParameters"/>
<type requires="vk_video/vulkan_video_codec_h265std.h" name="StdVideoH265VpsFlags"/>
- <type requires="vk_video/vulkan_video_codec_h265std.h" name="StdVideoH265Level"/>
+ <type requires="vk_video/vulkan_video_codec_h265std.h" name="StdVideoH265LevelIdc"/>
<type requires="vk_video/vulkan_video_codec_h265std.h" name="StdVideoH265SpsFlags"/>
<type requires="vk_video/vulkan_video_codec_h265std.h" name="StdVideoH265ScalingLists"/>
<type requires="vk_video/vulkan_video_codec_h265std.h" name="StdVideoH265SequenceParameterSetVui"/>
@@ -5713,261 +6245,438 @@ typedef void <name>CAMetalLayer</name>;
<type requires="vk_video/vulkan_video_codec_h265std.h" name="StdVideoH265SubLayerHrdParameters"/>
<type requires="vk_video/vulkan_video_codec_h265std.h" name="StdVideoH265HrdFlags"/>
<type requires="vk_video/vulkan_video_codec_h265std.h" name="StdVideoH265SpsVuiFlags"/>
+ <type requires="vk_video/vulkan_video_codec_h265std.h" name="StdVideoH265SliceType"/>
+ <type requires="vk_video/vulkan_video_codec_h265std.h" name="StdVideoH265PictureType"/>
<type category="include" name="vk_video/vulkan_video_codec_h265std_decode.h">#include "vk_video/vulkan_video_codec_h265std_decode.h"</type>
<type requires="vk_video/vulkan_video_codec_h265std_decode.h" name="StdVideoDecodeH265PictureInfo"/>
<type requires="vk_video/vulkan_video_codec_h265std_decode.h" name="StdVideoDecodeH265ReferenceInfo"/>
<type requires="vk_video/vulkan_video_codec_h265std_decode.h" name="StdVideoDecodeH265PictureInfoFlags"/>
<type requires="vk_video/vulkan_video_codec_h265std_decode.h" name="StdVideoDecodeH265ReferenceInfoFlags"/>
- <type category="struct" name="VkVideoDecodeH265ProfileEXT" structextends="VkVideoProfileKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PROFILE_EXT"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member><type>StdVideoH265ProfileIdc</type> <name>stdProfileIdc</name></member>
- </type>
- <type category="struct" name="VkVideoDecodeH265CapabilitiesEXT" returnedonly="true" structextends="VkVideoCapabilitiesKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_CAPABILITIES_EXT"><type>VkStructureType</type><name>sType</name></member>
- <member><type>void</type>* <name>pNext</name></member>
- <member><type>uint32_t</type> <name>maxLevel</name></member>
- <member><type>VkExtensionProperties</type> <name>stdExtensionVersion</name></member>
- </type>
- <type category="struct" name="VkVideoDecodeH265SessionCreateInfoEXT" structextends="VkVideoSessionCreateInfoKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_CREATE_INFO_EXT"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member><type>VkVideoDecodeH265CreateFlagsEXT</type> <name>flags</name></member>
- <member>const <type>VkExtensionProperties</type>* <name>pStdExtensionVersion</name></member>
- </type>
- <type category="struct" name="VkVideoDecodeH265SessionParametersAddInfoEXT" structextends="VkVideoSessionParametersUpdateInfoKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_ADD_INFO_EXT"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member><type>uint32_t</type> <name>spsStdCount</name></member>
- <member len="spsStdCount" optional="true">const <type>StdVideoH265SequenceParameterSet</type>* <name>pSpsStd</name></member>
- <member><type>uint32_t</type> <name>ppsStdCount</name></member>
- <member len="ppsStdCount" optional="true">const <type>StdVideoH265PictureParameterSet</type>* <name>pPpsStd</name><comment>List of Picture Parameters associated with the spsStd, above</comment></member>
- </type>
- <type category="struct" name="VkVideoDecodeH265SessionParametersCreateInfoEXT" structextends="VkVideoSessionParametersCreateInfoKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_CREATE_INFO_EXT"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member><type>uint32_t</type> <name>maxSpsStdCount</name></member>
- <member><type>uint32_t</type> <name>maxPpsStdCount</name></member>
- <member optional="true">const <type>VkVideoDecodeH265SessionParametersAddInfoEXT</type>* <name>pParametersAddInfo</name></member>
- </type>
- <type category="struct" name="VkVideoDecodeH265PictureInfoEXT" structextends="VkVideoDecodeInfoKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PICTURE_INFO_EXT"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member><type>StdVideoDecodeH265PictureInfo</type>* <name>pStdPictureInfo</name></member>
- <member><type>uint32_t</type> <name>slicesCount</name></member>
- <member len="slicesCount">const <type>uint32_t</type>* <name>pSlicesDataOffsets</name></member>
- </type>
- <type category="struct" name="VkVideoDecodeH265DpbSlotInfoEXT" structextends="VkVideoReferenceSlotKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_DPB_SLOT_INFO_EXT"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member>const <type>StdVideoDecodeH265ReferenceInfo</type>* <name>pStdReferenceInfo</name></member>
+ <type category="struct" name="VkVideoDecodeH265ProfileInfoKHR" structextends="VkVideoProfileInfoKHR,VkQueryPoolCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PROFILE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>StdVideoH265ProfileIdc</type> <name>stdProfileIdc</name></member>
+ </type>
+ <type category="struct" name="VkVideoDecodeH265CapabilitiesKHR" returnedonly="true" structextends="VkVideoCapabilitiesKHR">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_CAPABILITIES_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>StdVideoH265LevelIdc</type> <name>maxLevelIdc</name></member>
+ </type>
+ <type category="struct" name="VkVideoDecodeH265SessionParametersAddInfoKHR" structextends="VkVideoSessionParametersUpdateInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_ADD_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>uint32_t</type> <name>stdVPSCount</name></member>
+ <member len="stdVPSCount">const <type>StdVideoH265VideoParameterSet</type>* <name>pStdVPSs</name></member>
+ <member optional="true"><type>uint32_t</type> <name>stdSPSCount</name></member>
+ <member len="stdSPSCount">const <type>StdVideoH265SequenceParameterSet</type>* <name>pStdSPSs</name></member>
+ <member optional="true"><type>uint32_t</type> <name>stdPPSCount</name></member>
+ <member len="stdPPSCount">const <type>StdVideoH265PictureParameterSet</type>* <name>pStdPPSs</name><comment>List of Picture Parameters associated with the spsStd, above</comment></member>
+ </type>
+ <type category="struct" name="VkVideoDecodeH265SessionParametersCreateInfoKHR" structextends="VkVideoSessionParametersCreateInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_CREATE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>maxStdVPSCount</name></member>
+ <member><type>uint32_t</type> <name>maxStdSPSCount</name></member>
+ <member><type>uint32_t</type> <name>maxStdPPSCount</name></member>
+ <member optional="true">const <type>VkVideoDecodeH265SessionParametersAddInfoKHR</type>* <name>pParametersAddInfo</name></member>
+ </type>
+ <type category="struct" name="VkVideoDecodeH265PictureInfoKHR" structextends="VkVideoDecodeInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PICTURE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>StdVideoDecodeH265PictureInfo</type>* <name>pStdPictureInfo</name></member>
+ <member><type>uint32_t</type> <name>sliceSegmentCount</name></member>
+ <member len="sliceSegmentCount">const <type>uint32_t</type>* <name>pSliceSegmentOffsets</name></member>
+ </type>
+ <type category="struct" name="VkVideoDecodeH265DpbSlotInfoKHR" structextends="VkVideoReferenceSlotInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_DPB_SLOT_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member>const <type>StdVideoDecodeH265ReferenceInfo</type>* <name>pStdReferenceInfo</name></member>
</type>
<type category="struct" name="VkVideoSessionCreateInfoKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_SESSION_CREATE_INFO_KHR"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member><type>uint32_t</type> <name>queueFamilyIndex</name></member>
- <member optional="true"><type>VkVideoSessionCreateFlagsKHR</type> <name>flags</name></member>
- <member>const <type>VkVideoProfileKHR</type>* <name>pVideoProfile</name></member>
- <member><type>VkFormat</type> <name>pictureFormat</name></member>
- <member><type>VkExtent2D</type> <name>maxCodedExtent</name></member>
- <member><type>VkFormat</type> <name>referencePicturesFormat</name></member>
- <member><type>uint32_t</type> <name>maxReferencePicturesSlotsCount</name></member>
- <member><type>uint32_t</type> <name>maxReferencePicturesActiveCount</name></member>
+ <member values="VK_STRUCTURE_TYPE_VIDEO_SESSION_CREATE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>queueFamilyIndex</name></member>
+ <member optional="true"><type>VkVideoSessionCreateFlagsKHR</type> <name>flags</name></member>
+ <member>const <type>VkVideoProfileInfoKHR</type>* <name>pVideoProfile</name></member>
+ <member><type>VkFormat</type> <name>pictureFormat</name></member>
+ <member><type>VkExtent2D</type> <name>maxCodedExtent</name></member>
+ <member><type>VkFormat</type> <name>referencePictureFormat</name></member>
+ <member><type>uint32_t</type> <name>maxDpbSlots</name></member>
+ <member><type>uint32_t</type> <name>maxActiveReferencePictures</name></member>
+ <member>const <type>VkExtensionProperties</type>* <name>pStdHeaderVersion</name></member>
</type>
<type category="struct" name="VkVideoSessionParametersCreateInfoKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_CREATE_INFO_KHR"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member><type>VkVideoSessionParametersKHR</type> <name>videoSessionParametersTemplate</name></member>
- <member><type>VkVideoSessionKHR</type> <name>videoSession</name></member>
+ <member values="VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_CREATE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkVideoSessionParametersCreateFlagsKHR</type> <name>flags</name></member>
+ <member optional="true"><type>VkVideoSessionParametersKHR</type> <name>videoSessionParametersTemplate</name></member>
+ <member><type>VkVideoSessionKHR</type> <name>videoSession</name></member>
</type>
<type category="struct" name="VkVideoSessionParametersUpdateInfoKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_UPDATE_INFO_KHR"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member><type>uint32_t</type> <name>updateSequenceCount</name></member>
+ <member values="VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_UPDATE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>updateSequenceCount</name></member>
</type>
<type category="struct" name="VkVideoBeginCodingInfoKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_BEGIN_CODING_INFO_KHR"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member optional="true"><type>VkVideoBeginCodingFlagsKHR</type> <name>flags</name></member>
- <member><type>VkVideoCodingQualityPresetFlagsKHR</type> <name>codecQualityPreset</name></member>
- <member><type>VkVideoSessionKHR</type> <name>videoSession</name></member>
- <member optional="true"><type>VkVideoSessionParametersKHR</type> <name>videoSessionParameters</name></member>
- <member><type>uint32_t</type> <name>referenceSlotCount</name></member>
- <member len="referenceSlotCount">const <type>VkVideoReferenceSlotKHR</type>* <name>pReferenceSlots</name></member>
+ <member values="VK_STRUCTURE_TYPE_VIDEO_BEGIN_CODING_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkVideoBeginCodingFlagsKHR</type> <name>flags</name></member>
+ <member><type>VkVideoSessionKHR</type> <name>videoSession</name></member>
+ <member optional="true"><type>VkVideoSessionParametersKHR</type> <name>videoSessionParameters</name></member>
+ <member optional="true"><type>uint32_t</type> <name>referenceSlotCount</name></member>
+ <member len="referenceSlotCount">const <type>VkVideoReferenceSlotInfoKHR</type>* <name>pReferenceSlots</name></member>
</type>
<type category="struct" name="VkVideoEndCodingInfoKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_END_CODING_INFO_KHR"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member optional="true"><type>VkVideoEndCodingFlagsKHR</type> <name>flags</name></member>
+ <member values="VK_STRUCTURE_TYPE_VIDEO_END_CODING_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkVideoEndCodingFlagsKHR</type> <name>flags</name></member>
</type>
<type category="struct" name="VkVideoCodingControlInfoKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_CODING_CONTROL_INFO_KHR"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member optional="true"><type>VkVideoCodingControlFlagsKHR</type> <name>flags</name></member>
+ <member values="VK_STRUCTURE_TYPE_VIDEO_CODING_CONTROL_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="false"><type>VkVideoCodingControlFlagsKHR</type> <name>flags</name></member>
+ </type>
+ <type category="struct" name="VkVideoEncodeUsageInfoKHR" structextends="VkVideoProfileInfoKHR,VkQueryPoolCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_USAGE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkVideoEncodeUsageFlagsKHR</type> <name>videoUsageHints</name></member>
+ <member optional="true"><type>VkVideoEncodeContentFlagsKHR</type> <name>videoContentHints</name></member>
+ <member optional="true"><type>VkVideoEncodeTuningModeKHR</type> <name>tuningMode</name></member>
</type>
<type category="struct" name="VkVideoEncodeInfoKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_INFO_KHR"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member optional="true"><type>VkVideoEncodeFlagsKHR</type> <name>flags</name></member>
- <member><type>uint32_t</type> <name>qualityLevel</name></member>
- <member><type>VkExtent2D</type> <name>codedExtent</name></member>
- <member><type>VkBuffer</type> <name>dstBitstreamBuffer</name></member>
- <member><type>VkDeviceSize</type> <name>dstBitstreamBufferOffset</name></member>
- <member><type>VkDeviceSize</type> <name>dstBitstreamBufferMaxRange</name></member>
- <member><type>VkVideoPictureResourceKHR</type> <name>srcPictureResource</name></member>
- <member>const <type>VkVideoReferenceSlotKHR</type>* <name>pSetupReferenceSlot</name></member>
- <member><type>uint32_t</type> <name>referenceSlotCount</name></member>
- <member len="referenceSlotCount">const <type>VkVideoReferenceSlotKHR</type>* <name>pReferenceSlots</name></member>
+ <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkVideoEncodeFlagsKHR</type> <name>flags</name></member>
+ <member><type>uint32_t</type> <name>qualityLevel</name></member>
+ <member><type>VkBuffer</type> <name>dstBitstreamBuffer</name></member>
+ <member><type>VkDeviceSize</type> <name>dstBitstreamBufferOffset</name></member>
+ <member><type>VkDeviceSize</type> <name>dstBitstreamBufferMaxRange</name></member>
+ <member><type>VkVideoPictureResourceInfoKHR</type> <name>srcPictureResource</name></member>
+ <member optional="true">const <type>VkVideoReferenceSlotInfoKHR</type>* <name>pSetupReferenceSlot</name></member>
+ <member optional="true"><type>uint32_t</type> <name>referenceSlotCount</name></member>
+ <member len="referenceSlotCount">const <type>VkVideoReferenceSlotInfoKHR</type>* <name>pReferenceSlots</name></member>
+ <member><type>uint32_t</type> <name>precedingExternallyEncodedBytes</name></member>
</type>
<type category="struct" name="VkVideoEncodeRateControlInfoKHR" structextends="VkVideoCodingControlInfoKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_RATE_CONTROL_INFO_KHR"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member><type>VkVideoEncodeRateControlFlagsKHR</type> <name>flags</name></member>
- <member><type>VkVideoEncodeRateControlModeFlagBitsKHR</type> <name>rateControlMode</name></member>
- <member><type>uint32_t</type> <name>averageBitrate</name></member>
- <member><type>uint16_t</type> <name>peakToAverageBitrateRatio</name></member>
- <member><type>uint16_t</type> <name>frameRateNumerator</name></member>
- <member><type>uint16_t</type> <name>frameRateDenominator</name></member>
- <member><type>uint32_t</type> <name>virtualBufferSizeInMs</name></member>
- </type>
- <type category="struct" name="VkVideoEncodeH264CapabilitiesEXT" structextends="VkVideoCapabilitiesKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_CAPABILITIES_EXT"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member><type>VkVideoEncodeH264CapabilitiesFlagsEXT</type> <name>flags</name></member>
- <member><type>VkVideoEncodeH264InputModeFlagsEXT</type> <name>inputModeFlags</name></member>
- <member><type>VkVideoEncodeH264OutputModeFlagsEXT</type> <name>outputModeFlags</name></member>
- <member><type>VkExtent2D</type> <name>minPictureSizeInMbs</name></member>
- <member><type>VkExtent2D</type> <name>maxPictureSizeInMbs</name></member>
- <member><type>VkExtent2D</type> <name>inputImageDataAlignment</name></member>
- <member><type>uint8_t</type> <name>maxNumL0ReferenceForP</name></member>
- <member><type>uint8_t</type> <name>maxNumL0ReferenceForB</name></member>
- <member><type>uint8_t</type> <name>maxNumL1Reference</name></member>
- <member><type>uint8_t</type> <name>qualityLevelCount</name></member>
- <member><type>VkExtensionProperties</type> <name>stdExtensionVersion</name></member>
- </type>
- <type category="struct" name="VkVideoEncodeH264SessionCreateInfoEXT" structextends="VkVideoSessionCreateInfoKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_CREATE_INFO_EXT"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member><type>VkVideoEncodeH264CreateFlagsEXT</type> <name>flags</name></member>
- <member><type>VkExtent2D</type> <name>maxPictureSizeInMbs</name></member>
- <member>const <type>VkExtensionProperties</type>* <name>pStdExtensionVersion</name></member>
+ <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_RATE_CONTROL_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkVideoEncodeRateControlFlagsKHR</type> <name>flags</name></member>
+ <member><type>VkVideoEncodeRateControlModeFlagBitsKHR</type> <name>rateControlMode</name></member>
+ <member><type>uint8_t</type> <name>layerCount</name></member>
+ <member len="layerCount">const <type>VkVideoEncodeRateControlLayerInfoKHR</type>* <name>pLayerConfigs</name></member>
+ </type>
+ <type category="struct" name="VkVideoEncodeRateControlLayerInfoKHR" structextends="VkVideoCodingControlInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_RATE_CONTROL_LAYER_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member>const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>averageBitrate</name></member>
+ <member><type>uint32_t</type> <name>maxBitrate</name></member>
+ <member><type>uint32_t</type> <name>frameRateNumerator</name></member>
+ <member><type>uint32_t</type> <name>frameRateDenominator</name></member>
+ <member><type>uint32_t</type> <name>virtualBufferSizeInMs</name></member>
+ <member><type>uint32_t</type> <name>initialVirtualBufferSizeInMs</name></member>
+ </type>
+ <type category="struct" name="VkVideoEncodeCapabilitiesKHR" returnedonly="true" structextends="VkVideoCapabilitiesKHR">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_CAPABILITIES_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member noautovalidity="true"><type>VkVideoEncodeCapabilityFlagsKHR</type> <name>flags</name></member>
+ <member><type>VkVideoEncodeRateControlModeFlagsKHR</type> <name>rateControlModes</name></member>
+ <member><type>uint8_t</type> <name>rateControlLayerCount</name></member>
+ <member><type>uint8_t</type> <name>qualityLevelCount</name></member>
+ <member><type>VkExtent2D</type> <name>inputImageDataFillAlignment</name></member>
+ </type>
+ <type category="struct" name="VkVideoEncodeH264CapabilitiesEXT" returnedonly="true" structextends="VkVideoCapabilitiesKHR">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_CAPABILITIES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member noautovalidity="true"><type>VkVideoEncodeH264CapabilityFlagsEXT</type> <name>flags</name></member>
+ <member><type>VkVideoEncodeH264InputModeFlagsEXT</type> <name>inputModeFlags</name></member>
+ <member><type>VkVideoEncodeH264OutputModeFlagsEXT</type> <name>outputModeFlags</name></member>
+ <member><type>uint8_t</type> <name>maxPPictureL0ReferenceCount</name></member>
+ <member><type>uint8_t</type> <name>maxBPictureL0ReferenceCount</name></member>
+ <member><type>uint8_t</type> <name>maxL1ReferenceCount</name></member>
+ <member><type>VkBool32</type> <name>motionVectorsOverPicBoundariesFlag</name></member>
+ <member><type>uint32_t</type> <name>maxBytesPerPicDenom</name></member>
+ <member><type>uint32_t</type> <name>maxBitsPerMbDenom</name></member>
+ <member><type>uint32_t</type> <name>log2MaxMvLengthHorizontal</name></member>
+ <member><type>uint32_t</type> <name>log2MaxMvLengthVertical</name></member>
</type>
<type category="include" name="vk_video/vulkan_video_codec_h264std_encode.h">#include "vk_video/vulkan_video_codec_h264std_encode.h"</type>
<type requires="vk_video/vulkan_video_codec_h264std_encode.h" name="StdVideoEncodeH264SliceHeader"/>
<type requires="vk_video/vulkan_video_codec_h264std_encode.h" name="StdVideoEncodeH264PictureInfo"/>
+ <type requires="vk_video/vulkan_video_codec_h264std_encode.h" name="StdVideoEncodeH264ReferenceInfo"/>
<type requires="vk_video/vulkan_video_codec_h264std_encode.h" name="StdVideoEncodeH264SliceHeaderFlags"/>
<type requires="vk_video/vulkan_video_codec_h264std_encode.h" name="StdVideoEncodeH264RefMemMgmtCtrlOperations"/>
<type requires="vk_video/vulkan_video_codec_h264std_encode.h" name="StdVideoEncodeH264PictureInfoFlags"/>
+ <type requires="vk_video/vulkan_video_codec_h264std_encode.h" name="StdVideoEncodeH264ReferenceInfoFlags"/>
<type requires="vk_video/vulkan_video_codec_h264std_encode.h" name="StdVideoEncodeH264RefMgmtFlags"/>
<type requires="vk_video/vulkan_video_codec_h264std_encode.h" name="StdVideoEncodeH264RefListModEntry"/>
<type requires="vk_video/vulkan_video_codec_h264std_encode.h" name="StdVideoEncodeH264RefPicMarkingEntry"/>
<type category="struct" name="VkVideoEncodeH264SessionParametersAddInfoEXT" structextends="VkVideoSessionParametersUpdateInfoKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_ADD_INFO_EXT"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member><type>uint32_t</type> <name>spsStdCount</name></member>
- <member len="spsStdCount" optional="true">const <type>StdVideoH264SequenceParameterSet</type>* <name>pSpsStd</name></member>
- <member><type>uint32_t</type> <name>ppsStdCount</name></member>
- <member len="ppsStdCount" optional="true">const <type>StdVideoH264PictureParameterSet</type>* <name>pPpsStd</name><comment>List of Picture Parameters associated with the spsStd, above</comment></member>
+ <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_ADD_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>stdSPSCount</name></member>
+ <member len="stdSPSCount" optional="true">const <type>StdVideoH264SequenceParameterSet</type>* <name>pStdSPSs</name></member>
+ <member><type>uint32_t</type> <name>stdPPSCount</name></member>
+ <member len="stdPPSCount" optional="true">const <type>StdVideoH264PictureParameterSet</type>* <name>pStdPPSs</name><comment>List of Picture Parameters associated with the spsStd, above</comment></member>
</type>
<type category="struct" name="VkVideoEncodeH264SessionParametersCreateInfoEXT" structextends="VkVideoSessionParametersCreateInfoKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_CREATE_INFO_EXT"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member><type>uint32_t</type> <name>maxSpsStdCount</name></member>
- <member><type>uint32_t</type> <name>maxPpsStdCount</name></member>
- <member optional="true">const <type>VkVideoEncodeH264SessionParametersAddInfoEXT</type>* <name>pParametersAddInfo</name></member>
+ <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_CREATE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>maxStdSPSCount</name></member>
+ <member><type>uint32_t</type> <name>maxStdPPSCount</name></member>
+ <member optional="true">const <type>VkVideoEncodeH264SessionParametersAddInfoEXT</type>* <name>pParametersAddInfo</name></member>
</type>
<type category="struct" name="VkVideoEncodeH264DpbSlotInfoEXT">
- <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_DPB_SLOT_INFO_EXT"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member><type>int8_t</type> <name>slotIndex</name></member>
- <member>const <type>StdVideoEncodeH264PictureInfo</type>* <name>pStdPictureInfo</name></member>
+ <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_DPB_SLOT_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>int8_t</type> <name>slotIndex</name></member>
+ <member>const <type>StdVideoEncodeH264ReferenceInfo</type>* <name>pStdReferenceInfo</name></member>
</type>
<type category="struct" name="VkVideoEncodeH264VclFrameInfoEXT" structextends="VkVideoEncodeInfoKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_VCL_FRAME_INFO_EXT"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member><type>uint8_t</type> <name>refDefaultFinalList0EntryCount</name></member>
- <member len="refDefaultFinalList0EntryCount">const <type>VkVideoEncodeH264DpbSlotInfoEXT</type>* <name>pRefDefaultFinalList0Entries</name></member>
- <member><type>uint8_t</type> <name>refDefaultFinalList1EntryCount</name></member>
- <member len="refDefaultFinalList1EntryCount">const <type>VkVideoEncodeH264DpbSlotInfoEXT</type>* <name>pRefDefaultFinalList1Entries</name></member>
- <member><type>uint32_t</type> <name>naluSliceEntryCount</name></member>
- <member len="naluSliceEntryCount">const <type>VkVideoEncodeH264NaluSliceEXT</type>* <name>pNaluSliceEntries</name></member>
- <member>const <type>VkVideoEncodeH264DpbSlotInfoEXT</type>* <name>pCurrentPictureInfo</name></member>
- </type>
- <type category="struct" name="VkVideoEncodeH264EmitPictureParametersEXT" structextends="VkVideoEncodeInfoKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_EMIT_PICTURE_PARAMETERS_EXT"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member><type>uint8_t</type> <name>spsId</name></member>
- <member><type>VkBool32</type> <name>emitSpsEnable</name></member>
- <member><type>uint32_t</type> <name>ppsIdEntryCount</name></member>
- <member len="ppsIdEntryCount">const <type>uint8_t</type>* <name>ppsIdEntries</name></member>
- </type>
- <type category="struct" name="VkVideoEncodeH264ProfileEXT" structextends="VkVideoProfileKHR">
- <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_PROFILE_EXT"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member><type>StdVideoH264ProfileIdc</type> <name>stdProfileIdc</name></member>
- </type>
- <type category="struct" name="VkVideoEncodeH264NaluSliceEXT">
- <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_NALU_SLICE_EXT"><type>VkStructureType</type><name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member>const <type>StdVideoEncodeH264SliceHeader</type>* <name>pSliceHeaderStd</name></member>
- <member><type>uint32_t</type> <name>mbCount</name></member>
- <member><type>uint8_t</type> <name>refFinalList0EntryCount</name></member>
- <member len="refFinalList0EntryCount">const <type>VkVideoEncodeH264DpbSlotInfoEXT</type>* <name>pRefFinalList0Entries</name></member>
- <member><type>uint8_t</type> <name>refFinalList1EntryCount</name></member>
- <member len="refFinalList1EntryCount">const <type>VkVideoEncodeH264DpbSlotInfoEXT</type>* <name>pRefFinalList1Entries</name></member>
- <member><type>uint32_t</type> <name>precedingNaluBytes</name></member>
- <member><type>uint8_t</type> <name>minQp</name></member>
- <member><type>uint8_t</type> <name>maxQp</name></member>
+ <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_VCL_FRAME_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true">const <type>VkVideoEncodeH264ReferenceListsInfoEXT</type>* <name>pReferenceFinalLists</name></member>
+ <member><type>uint32_t</type> <name>naluSliceEntryCount</name></member>
+ <member len="naluSliceEntryCount">const <type>VkVideoEncodeH264NaluSliceInfoEXT</type>* <name>pNaluSliceEntries</name></member>
+ <member>const <type>StdVideoEncodeH264PictureInfo</type>* <name>pCurrentPictureInfo</name></member>
+ </type>
+ <type category="struct" name="VkVideoEncodeH264ReferenceListsInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_REFERENCE_LISTS_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>uint8_t</type> <name>referenceList0EntryCount</name></member>
+ <member len="referenceList0EntryCount">const <type>VkVideoEncodeH264DpbSlotInfoEXT</type>* <name>pReferenceList0Entries</name></member>
+ <member optional="true"><type>uint8_t</type> <name>referenceList1EntryCount</name></member>
+ <member len="referenceList1EntryCount">const <type>VkVideoEncodeH264DpbSlotInfoEXT</type>* <name>pReferenceList1Entries</name></member>
+ <member>const <type>StdVideoEncodeH264RefMemMgmtCtrlOperations</type>* <name>pMemMgmtCtrlOperations</name></member>
+ </type>
+ <type category="struct" name="VkVideoEncodeH264EmitPictureParametersInfoEXT" structextends="VkVideoEncodeInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_EMIT_PICTURE_PARAMETERS_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint8_t</type> <name>spsId</name></member>
+ <member><type>VkBool32</type> <name>emitSpsEnable</name></member>
+ <member><type>uint32_t</type> <name>ppsIdEntryCount</name></member>
+ <member len="ppsIdEntryCount">const <type>uint8_t</type>* <name>ppsIdEntries</name></member>
+ </type>
+ <type category="struct" name="VkVideoEncodeH264ProfileInfoEXT" structextends="VkVideoProfileInfoKHR,VkQueryPoolCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_PROFILE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>StdVideoH264ProfileIdc</type> <name>stdProfileIdc</name></member>
+ </type>
+ <type category="struct" name="VkVideoEncodeH264NaluSliceInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_NALU_SLICE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>mbCount</name></member>
+ <member optional="true">const <type>VkVideoEncodeH264ReferenceListsInfoEXT</type>* <name>pReferenceFinalLists</name></member>
+ <member>const <type>StdVideoEncodeH264SliceHeader</type>* <name>pSliceHeaderStd</name></member>
+ </type>
+ <type category="struct" name="VkVideoEncodeH264RateControlInfoEXT" structextends="VkVideoCodingControlInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_RATE_CONTROL_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>gopFrameCount</name></member>
+ <member><type>uint32_t</type> <name>idrPeriod</name></member>
+ <member><type>uint32_t</type> <name>consecutiveBFrameCount</name></member>
+ <member><type>VkVideoEncodeH264RateControlStructureEXT</type> <name>rateControlStructure</name></member>
+ <member><type>uint8_t</type> <name>temporalLayerCount</name></member>
+ </type>
+ <type category="struct" name="VkVideoEncodeH264QpEXT">
+ <member noautovalidity="true"><type>int32_t</type> <name>qpI</name></member>
+ <member noautovalidity="true"><type>int32_t</type> <name>qpP</name></member>
+ <member noautovalidity="true"><type>int32_t</type> <name>qpB</name></member>
+ </type>
+ <type category="struct" name="VkVideoEncodeH264FrameSizeEXT">
+ <member noautovalidity="true"><type>uint32_t</type> <name>frameISize</name></member>
+ <member noautovalidity="true"><type>uint32_t</type> <name>framePSize</name></member>
+ <member noautovalidity="true"><type>uint32_t</type> <name>frameBSize</name></member>
+ </type>
+ <type category="struct" name="VkVideoEncodeH264RateControlLayerInfoEXT" structextends="VkVideoCodingControlInfoKHR,VkVideoEncodeRateControlLayerInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_RATE_CONTROL_LAYER_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint8_t</type> <name>temporalLayerId</name></member>
+ <member><type>VkBool32</type> <name>useInitialRcQp</name></member>
+ <member><type>VkVideoEncodeH264QpEXT</type> <name>initialRcQp</name></member>
+ <member><type>VkBool32</type> <name>useMinQp</name></member>
+ <member><type>VkVideoEncodeH264QpEXT</type> <name>minQp</name></member>
+ <member><type>VkBool32</type> <name>useMaxQp</name></member>
+ <member><type>VkVideoEncodeH264QpEXT</type> <name>maxQp</name></member>
+ <member><type>VkBool32</type> <name>useMaxFrameSize</name></member>
+ <member><type>VkVideoEncodeH264FrameSizeEXT</type> <name>maxFrameSize</name></member>
+ </type>
+ <type category="struct" name="VkVideoEncodeH265CapabilitiesEXT" returnedonly="true" structextends="VkVideoCapabilitiesKHR">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_CAPABILITIES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member noautovalidity="true"><type>VkVideoEncodeH265CapabilityFlagsEXT</type> <name>flags</name></member>
+ <member><type>VkVideoEncodeH265InputModeFlagsEXT</type> <name>inputModeFlags</name></member>
+ <member><type>VkVideoEncodeH265OutputModeFlagsEXT</type> <name>outputModeFlags</name></member>
+ <member><type>VkVideoEncodeH265CtbSizeFlagsEXT</type> <name>ctbSizes</name></member>
+ <member><type>VkVideoEncodeH265TransformBlockSizeFlagsEXT</type> <name>transformBlockSizes</name></member>
+ <member><type>uint8_t</type> <name>maxPPictureL0ReferenceCount</name></member>
+ <member><type>uint8_t</type> <name>maxBPictureL0ReferenceCount</name></member>
+ <member><type>uint8_t</type> <name>maxL1ReferenceCount</name></member>
+ <member><type>uint8_t</type> <name>maxSubLayersCount</name></member>
+ <member><type>uint8_t</type> <name>minLog2MinLumaCodingBlockSizeMinus3</name></member>
+ <member><type>uint8_t</type> <name>maxLog2MinLumaCodingBlockSizeMinus3</name></member>
+ <member><type>uint8_t</type> <name>minLog2MinLumaTransformBlockSizeMinus2</name></member>
+ <member><type>uint8_t</type> <name>maxLog2MinLumaTransformBlockSizeMinus2</name></member>
+ <member><type>uint8_t</type> <name>minMaxTransformHierarchyDepthInter</name></member>
+ <member><type>uint8_t</type> <name>maxMaxTransformHierarchyDepthInter</name></member>
+ <member><type>uint8_t</type> <name>minMaxTransformHierarchyDepthIntra</name></member>
+ <member><type>uint8_t</type> <name>maxMaxTransformHierarchyDepthIntra</name></member>
+ <member><type>uint8_t</type> <name>maxDiffCuQpDeltaDepth</name></member>
+ <member><type>uint8_t</type> <name>minMaxNumMergeCand</name></member>
+ <member><type>uint8_t</type> <name>maxMaxNumMergeCand</name></member>
+ </type>
+ <type category="include" name="vk_video/vulkan_video_codec_h265std_encode.h">#include "vk_video/vulkan_video_codec_h265std_encode.h"</type>
+ <type requires="vk_video/vulkan_video_codec_h265std_encode.h" name="StdVideoEncodeH265PictureInfoFlags"/>
+ <type requires="vk_video/vulkan_video_codec_h265std_encode.h" name="StdVideoEncodeH265PictureInfo"/>
+ <type requires="vk_video/vulkan_video_codec_h265std_encode.h" name="StdVideoEncodeH265SliceSegmentHeader"/>
+ <type requires="vk_video/vulkan_video_codec_h265std_encode.h" name="StdVideoEncodeH265ReferenceInfo"/>
+ <type requires="vk_video/vulkan_video_codec_h265std_encode.h" name="StdVideoEncodeH265ReferenceModifications"/>
+ <type requires="vk_video/vulkan_video_codec_h265std_encode.h" name="StdVideoEncodeH265SliceSegmentHeaderFlags"/>
+ <type requires="vk_video/vulkan_video_codec_h265std_encode.h" name="StdVideoEncodeH265ReferenceInfoFlags"/>
+ <type requires="vk_video/vulkan_video_codec_h265std_encode.h" name="StdVideoEncodeH265ReferenceModificationFlags"/>
+ <type category="struct" name="VkVideoEncodeH265SessionParametersAddInfoEXT" structextends="VkVideoSessionParametersUpdateInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_ADD_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>stdVPSCount</name></member>
+ <member len="stdVPSCount" optional="true">const <type>StdVideoH265VideoParameterSet</type>* <name>pStdVPSs</name></member>
+ <member><type>uint32_t</type> <name>stdSPSCount</name></member>
+ <member len="stdSPSCount" optional="true">const <type>StdVideoH265SequenceParameterSet</type>* <name>pStdSPSs</name></member>
+ <member><type>uint32_t</type> <name>stdPPSCount</name></member>
+ <member len="stdPPSCount" optional="true">const <type>StdVideoH265PictureParameterSet</type>* <name>pStdPPSs</name><comment>List of Picture Parameters associated with the spsStd, above</comment></member>
+ </type>
+ <type category="struct" name="VkVideoEncodeH265SessionParametersCreateInfoEXT" structextends="VkVideoSessionParametersCreateInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_CREATE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>maxStdVPSCount</name></member>
+ <member><type>uint32_t</type> <name>maxStdSPSCount</name></member>
+ <member><type>uint32_t</type> <name>maxStdPPSCount</name></member>
+ <member optional="true">const <type>VkVideoEncodeH265SessionParametersAddInfoEXT</type>* <name>pParametersAddInfo</name></member>
+ </type>
+ <type category="struct" name="VkVideoEncodeH265VclFrameInfoEXT" structextends="VkVideoEncodeInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_VCL_FRAME_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true">const <type>VkVideoEncodeH265ReferenceListsInfoEXT</type>* <name>pReferenceFinalLists</name></member>
+ <member><type>uint32_t</type> <name>naluSliceSegmentEntryCount</name></member>
+ <member len="naluSliceSegmentEntryCount">const <type>VkVideoEncodeH265NaluSliceSegmentInfoEXT</type>* <name>pNaluSliceSegmentEntries</name></member>
+ <member>const <type>StdVideoEncodeH265PictureInfo</type>* <name>pCurrentPictureInfo</name></member>
+ </type>
+ <type category="struct" name="VkVideoEncodeH265EmitPictureParametersInfoEXT" structextends="VkVideoEncodeInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_EMIT_PICTURE_PARAMETERS_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint8_t</type> <name>vpsId</name></member>
+ <member><type>uint8_t</type> <name>spsId</name></member>
+ <member><type>VkBool32</type> <name>emitVpsEnable</name></member>
+ <member><type>VkBool32</type> <name>emitSpsEnable</name></member>
+ <member optional="true"><type>uint32_t</type> <name>ppsIdEntryCount</name></member>
+ <member len="ppsIdEntryCount">const <type>uint8_t</type>* <name>ppsIdEntries</name></member>
+ </type>
+ <type category="struct" name="VkVideoEncodeH265NaluSliceSegmentInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_NALU_SLICE_SEGMENT_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>ctbCount</name></member>
+ <member optional="true">const <type>VkVideoEncodeH265ReferenceListsInfoEXT</type>* <name>pReferenceFinalLists</name></member>
+ <member>const <type>StdVideoEncodeH265SliceSegmentHeader</type>* <name>pSliceSegmentHeaderStd</name></member>
+ </type>
+ <type category="struct" name="VkVideoEncodeH265RateControlInfoEXT" structextends="VkVideoCodingControlInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_RATE_CONTROL_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>gopFrameCount</name></member>
+ <member><type>uint32_t</type> <name>idrPeriod</name></member>
+ <member><type>uint32_t</type> <name>consecutiveBFrameCount</name></member>
+ <member><type>VkVideoEncodeH265RateControlStructureEXT</type> <name>rateControlStructure</name></member>
+ <member><type>uint8_t</type> <name>subLayerCount</name></member>
+ </type>
+ <type category="struct" name="VkVideoEncodeH265QpEXT">
+ <member noautovalidity="true"><type>int32_t</type> <name>qpI</name></member>
+ <member noautovalidity="true"><type>int32_t</type> <name>qpP</name></member>
+ <member noautovalidity="true"><type>int32_t</type> <name>qpB</name></member>
+ </type>
+ <type category="struct" name="VkVideoEncodeH265FrameSizeEXT">
+ <member noautovalidity="true"><type>uint32_t</type> <name>frameISize</name></member>
+ <member noautovalidity="true"><type>uint32_t</type> <name>framePSize</name></member>
+ <member noautovalidity="true"><type>uint32_t</type> <name>frameBSize</name></member>
+ </type>
+ <type category="struct" name="VkVideoEncodeH265RateControlLayerInfoEXT" structextends="VkVideoCodingControlInfoKHR,VkVideoEncodeRateControlLayerInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_RATE_CONTROL_LAYER_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint8_t</type> <name>temporalId</name></member>
+ <member><type>VkBool32</type> <name>useInitialRcQp</name></member>
+ <member><type>VkVideoEncodeH265QpEXT</type> <name>initialRcQp</name></member>
+ <member><type>VkBool32</type> <name>useMinQp</name></member>
+ <member><type>VkVideoEncodeH265QpEXT</type> <name>minQp</name></member>
+ <member><type>VkBool32</type> <name>useMaxQp</name></member>
+ <member><type>VkVideoEncodeH265QpEXT</type> <name>maxQp</name></member>
+ <member><type>VkBool32</type> <name>useMaxFrameSize</name></member>
+ <member><type>VkVideoEncodeH265FrameSizeEXT</type> <name>maxFrameSize</name></member>
+ </type>
+ <type category="struct" name="VkVideoEncodeH265ProfileInfoEXT" structextends="VkVideoProfileInfoKHR,VkQueryPoolCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_PROFILE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>StdVideoH265ProfileIdc</type> <name>stdProfileIdc</name></member>
+ </type>
+ <type category="struct" name="VkVideoEncodeH265DpbSlotInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_DPB_SLOT_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>int8_t</type> <name>slotIndex</name></member>
+ <member>const <type>StdVideoEncodeH265ReferenceInfo</type>* <name>pStdReferenceInfo</name></member>
+ </type>
+ <type category="struct" name="VkVideoEncodeH265ReferenceListsInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_REFERENCE_LISTS_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>uint8_t</type> <name>referenceList0EntryCount</name></member>
+ <member len="referenceList0EntryCount">const <type>VkVideoEncodeH265DpbSlotInfoEXT</type>* <name>pReferenceList0Entries</name></member>
+ <member optional="true"><type>uint8_t</type> <name>referenceList1EntryCount</name></member>
+ <member len="referenceList1EntryCount">const <type>VkVideoEncodeH265DpbSlotInfoEXT</type>* <name>pReferenceList1Entries</name></member>
+ <member>const <type>StdVideoEncodeH265ReferenceModifications</type>* <name>pReferenceModifications</name></member>
</type>
<type category="struct" name="VkPhysicalDeviceInheritedViewportScissorFeaturesNV" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
- <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INHERITED_VIEWPORT_SCISSOR_FEATURES_NV"><type>VkStructureType</type> <name>sType</name></member>
- <member><type>void</type>* <name>pNext</name></member>
- <member><type>VkBool32</type> <name>inheritedViewportScissor2D</name></member>
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INHERITED_VIEWPORT_SCISSOR_FEATURES_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>inheritedViewportScissor2D</name></member>
</type>
<type category="struct" name="VkCommandBufferInheritanceViewportScissorInfoNV" structextends="VkCommandBufferInheritanceInfo">
- <member values="VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_VIEWPORT_SCISSOR_INFO_NV"><type>VkStructureType</type> <name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
- <member><type>VkBool32</type> <name>viewportScissor2D</name></member>
- <member><type>uint32_t</type> <name>viewportDepthCount</name></member>
- <member noautovalidity="true">const <type>VkViewport</type>* <name>pViewportDepths</name></member>
+ <member values="VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_VIEWPORT_SCISSOR_INFO_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>viewportScissor2D</name></member>
+ <member><type>uint32_t</type> <name>viewportDepthCount</name></member>
+ <member noautovalidity="true">const <type>VkViewport</type>* <name>pViewportDepths</name></member>
</type>
<type category="struct" name="VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
- <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
- <member optional="true"><type>void</type>* <name>pNext</name></member>
- <member><type>VkBool32</type> <name>ycbcr2plane444Formats</name></member>
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>ycbcr2plane444Formats</name></member>
</type>
<type category="struct" name="VkPhysicalDeviceProvokingVertexFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
- <member noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>provokingVertexLast</name></member>
<member><type>VkBool32</type> <name>transformFeedbackPreservesProvokingVertex</name></member>
</type>
<type category="struct" name="VkPhysicalDeviceProvokingVertexPropertiesEXT" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_PROPERTIES_EXT"><type>VkStructureType</type> <name>sType</name></member>
- <member><type>void</type>* <name>pNext</name></member>
- <member><type>VkBool32</type> <name>provokingVertexModePerPipeline</name></member>
- <member><type>VkBool32</type> <name>transformFeedbackPreservesTriangleFanProvokingVertex</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>provokingVertexModePerPipeline</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>transformFeedbackPreservesTriangleFanProvokingVertex</name></member>
</type>
<type category="struct" name="VkPipelineRasterizationProvokingVertexStateCreateInfoEXT" structextends="VkPipelineRasterizationStateCreateInfo">
<member values="VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
<member><type>VkProvokingVertexModeEXT</type> <name>provokingVertexMode</name></member>
</type>
<type category="struct" name="VkCuModuleCreateInfoNVX">
<member values="VK_STRUCTURE_TYPE_CU_MODULE_CREATE_INFO_NVX"><type>VkStructureType</type> <name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
<member><type>size_t</type> <name>dataSize</name></member>
- <member>const <type>void</type>* <name>pData</name></member>
+ <member len="dataSize">const <type>void</type>* <name>pData</name></member>
</type>
<type category="struct" name="VkCuFunctionCreateInfoNVX">
<member values="VK_STRUCTURE_TYPE_CU_FUNCTION_CREATE_INFO_NVX"><type>VkStructureType</type> <name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
<member><type>VkCuModuleNVX</type> <name>module</name></member>
<member len="null-terminated">const <type>char</type>* <name>pName</name></member>
</type>
<type category="struct" name="VkCuLaunchInfoNVX">
<member values="VK_STRUCTURE_TYPE_CU_LAUNCH_INFO_NVX"><type>VkStructureType</type> <name>sType</name></member>
- <member>const <type>void</type>* <name>pNext</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
<member><type>VkCuFunctionNVX</type> <name>function</name></member>
<member><type>uint32_t</type> <name>gridDimX</name></member>
<member><type>uint32_t</type> <name>gridDimY</name></member>
@@ -5976,24 +6685,192 @@ typedef void <name>CAMetalLayer</name>;
<member><type>uint32_t</type> <name>blockDimY</name></member>
<member><type>uint32_t</type> <name>blockDimZ</name></member>
<member><type>uint32_t</type> <name>sharedMemBytes</name></member>
- <member><type>size_t</type> <name>paramCount</name></member>
+ <member optional="true"><type>size_t</type> <name>paramCount</name></member>
<member len="paramCount">const <type>void</type>* const * <name>pParams</name></member>
- <member><type>size_t</type> <name>extraCount</name></member>
+ <member optional="true"><type>size_t</type> <name>extraCount</name></member>
<member len="extraCount">const <type>void</type>* const * <name>pExtras</name></member>
</type>
+ <type category="struct" name="VkPhysicalDeviceDescriptorBufferFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>descriptorBuffer</name></member>
+ <member><type>VkBool32</type> <name>descriptorBufferCaptureReplay</name></member>
+ <member><type>VkBool32</type> <name>descriptorBufferImageLayoutIgnored</name></member>
+ <member><type>VkBool32</type> <name>descriptorBufferPushDescriptors</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceDescriptorBufferPropertiesEXT" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member limittype="noauto"><type>VkBool32</type> <name>combinedImageSamplerDescriptorSingleArray</name></member>
+ <member limittype="noauto"><type>VkBool32</type> <name>bufferlessPushDescriptors</name></member>
+ <member limittype="noauto"><type>VkBool32</type> <name>allowSamplerImageViewPostSubmitCreation</name></member>
+ <member limittype="noauto"><type>VkDeviceSize</type> <name>descriptorBufferOffsetAlignment</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxDescriptorBufferBindings</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxResourceDescriptorBufferBindings</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxSamplerDescriptorBufferBindings</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxEmbeddedImmutableSamplerBindings</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxEmbeddedImmutableSamplers</name></member>
+ <member limittype="noauto"><type>size_t</type> <name>bufferCaptureReplayDescriptorDataSize</name></member>
+ <member limittype="noauto"><type>size_t</type> <name>imageCaptureReplayDescriptorDataSize</name></member>
+ <member limittype="noauto"><type>size_t</type> <name>imageViewCaptureReplayDescriptorDataSize</name></member>
+ <member limittype="noauto"><type>size_t</type> <name>samplerCaptureReplayDescriptorDataSize</name></member>
+ <member limittype="noauto"><type>size_t</type> <name>accelerationStructureCaptureReplayDescriptorDataSize</name></member>
+ <member limittype="max"><type>size_t</type> <name>samplerDescriptorSize</name></member>
+ <member limittype="max"><type>size_t</type> <name>combinedImageSamplerDescriptorSize</name></member>
+ <member limittype="max"><type>size_t</type> <name>sampledImageDescriptorSize</name></member>
+ <member limittype="max"><type>size_t</type> <name>storageImageDescriptorSize</name></member>
+ <member limittype="max"><type>size_t</type> <name>uniformTexelBufferDescriptorSize</name></member>
+ <member limittype="max"><type>size_t</type> <name>robustUniformTexelBufferDescriptorSize</name></member>
+ <member limittype="max"><type>size_t</type> <name>storageTexelBufferDescriptorSize</name></member>
+ <member limittype="max"><type>size_t</type> <name>robustStorageTexelBufferDescriptorSize</name></member>
+ <member limittype="max"><type>size_t</type> <name>uniformBufferDescriptorSize</name></member>
+ <member limittype="max"><type>size_t</type> <name>robustUniformBufferDescriptorSize</name></member>
+ <member limittype="max"><type>size_t</type> <name>storageBufferDescriptorSize</name></member>
+ <member limittype="max"><type>size_t</type> <name>robustStorageBufferDescriptorSize</name></member>
+ <member limittype="max"><type>size_t</type> <name>inputAttachmentDescriptorSize</name></member>
+ <member limittype="max"><type>size_t</type> <name>accelerationStructureDescriptorSize</name></member>
+ <member limittype="max"><type>VkDeviceSize</type> <name>maxSamplerDescriptorBufferRange</name></member>
+ <member limittype="max"><type>VkDeviceSize</type> <name>maxResourceDescriptorBufferRange</name></member>
+ <member limittype="max"><type>VkDeviceSize</type> <name>samplerDescriptorBufferAddressSpaceSize</name></member>
+ <member limittype="max"><type>VkDeviceSize</type> <name>resourceDescriptorBufferAddressSpaceSize</name></member>
+ <member limittype="max"><type>VkDeviceSize</type> <name>descriptorBufferAddressSpaceSize</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceDescriptorBufferDensityMapPropertiesEXT" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_DENSITY_MAP_PROPERTIES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member limittype="max"><type>size_t</type> <name>combinedImageSamplerDensityMapDescriptorSize</name></member>
+ </type>
+ <type category="struct" name="VkDescriptorAddressInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_DESCRIPTOR_ADDRESS_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkDeviceAddress</type> <name>address</name></member>
+ <member><type>VkDeviceSize</type> <name>range</name></member>
+ <member><type>VkFormat</type> <name>format</name></member>
+ </type>
+ <type category="struct" name="VkDescriptorBufferBindingInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_DESCRIPTOR_BUFFER_BINDING_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkDeviceAddress</type> <name>address</name></member>
+ <member><type>VkBufferUsageFlags</type> <name>usage</name></member>
+ </type>
+ <type category="struct" name="VkDescriptorBufferBindingPushDescriptorBufferHandleEXT" structextends="VkDescriptorBufferBindingInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_DESCRIPTOR_BUFFER_BINDING_PUSH_DESCRIPTOR_BUFFER_HANDLE_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member ><type>VkBuffer</type> <name>buffer</name></member>
+ </type>
+ <type category="union" name="VkDescriptorDataEXT">
+ <member selection="VK_DESCRIPTOR_TYPE_SAMPLER">const <type>VkSampler</type>* <name>pSampler</name></member>
+ <member selection="VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER">const <type>VkDescriptorImageInfo</type>* <name>pCombinedImageSampler</name></member>
+ <member selection="VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT">const <type>VkDescriptorImageInfo</type>* <name>pInputAttachmentImage</name></member>
+ <member selection="VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE" optional="true">const <type>VkDescriptorImageInfo</type>* <name>pSampledImage</name></member>
+ <member selection="VK_DESCRIPTOR_TYPE_STORAGE_IMAGE" optional="true">const <type>VkDescriptorImageInfo</type>* <name>pStorageImage</name></member>
+ <member selection="VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER" optional="true">const <type>VkDescriptorAddressInfoEXT</type>* <name>pUniformTexelBuffer</name></member>
+ <member selection="VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER" optional="true">const <type>VkDescriptorAddressInfoEXT</type>* <name>pStorageTexelBuffer</name></member>
+ <member selection="VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER" optional="true">const <type>VkDescriptorAddressInfoEXT</type>* <name>pUniformBuffer</name></member>
+ <member selection="VK_DESCRIPTOR_TYPE_STORAGE_BUFFER" optional="true">const <type>VkDescriptorAddressInfoEXT</type>* <name>pStorageBuffer</name></member>
+ <member selection="VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR,VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV"><type>VkDeviceAddress</type> <name>accelerationStructure</name></member>
+ </type>
+ <type category="struct" name="VkDescriptorGetInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkDescriptorType</type> <name>type</name></member>
+ <member selector="type" noautovalidity="true"><type>VkDescriptorDataEXT</type> <name>data</name></member>
+ </type>
+ <type category="struct" name="VkBufferCaptureDescriptorDataInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_BUFFER_CAPTURE_DESCRIPTOR_DATA_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkBuffer</type> <name>buffer</name></member>
+ </type>
+ <type category="struct" name="VkImageCaptureDescriptorDataInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_IMAGE_CAPTURE_DESCRIPTOR_DATA_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkImage</type> <name>image</name></member>
+ </type>
+ <type category="struct" name="VkImageViewCaptureDescriptorDataInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_IMAGE_VIEW_CAPTURE_DESCRIPTOR_DATA_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkImageView</type> <name>imageView</name></member>
+ </type>
+ <type category="struct" name="VkSamplerCaptureDescriptorDataInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_SAMPLER_CAPTURE_DESCRIPTOR_DATA_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkSampler</type> <name>sampler</name></member>
+ </type>
+ <type category="struct" name="VkAccelerationStructureCaptureDescriptorDataInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CAPTURE_DESCRIPTOR_DATA_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkAccelerationStructureKHR</type> <name>accelerationStructure</name></member>
+ <member optional="true"><type>VkAccelerationStructureNV</type> <name>accelerationStructureNV</name></member>
+ </type>
+ <type category="struct" name="VkOpaqueCaptureDescriptorDataCreateInfoEXT" structextends="VkBufferCreateInfo,VkImageCreateInfo,VkImageViewCreateInfo,VkSamplerCreateInfo,VkAccelerationStructureCreateInfoKHR,VkAccelerationStructureCreateInfoNV">
+ <member values="VK_STRUCTURE_TYPE_OPAQUE_CAPTURE_DESCRIPTOR_DATA_CREATE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member>const <type>void</type>* <name>opaqueCaptureDescriptorData</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceShaderIntegerDotProductFeatures" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>shaderIntegerDotProduct</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceShaderIntegerDotProductFeaturesKHR" alias="VkPhysicalDeviceShaderIntegerDotProductFeatures"/>
+ <type category="struct" name="VkPhysicalDeviceShaderIntegerDotProductProperties" structextends="VkPhysicalDeviceProperties2" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProduct8BitUnsignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProduct8BitSignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProduct8BitMixedSignednessAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProduct4x8BitPackedUnsignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProduct4x8BitPackedSignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProduct4x8BitPackedMixedSignednessAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProduct16BitUnsignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProduct16BitSignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProduct16BitMixedSignednessAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProduct32BitUnsignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProduct32BitSignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProduct32BitMixedSignednessAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProduct64BitUnsignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProduct64BitSignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProduct64BitMixedSignednessAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProductAccumulatingSaturating8BitUnsignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProductAccumulatingSaturating8BitSignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProductAccumulatingSaturating16BitUnsignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProductAccumulatingSaturating16BitSignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProductAccumulatingSaturating32BitUnsignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProductAccumulatingSaturating32BitSignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProductAccumulatingSaturating64BitUnsignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProductAccumulatingSaturating64BitSignedAccelerated</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceShaderIntegerDotProductPropertiesKHR" alias="VkPhysicalDeviceShaderIntegerDotProductProperties"/>
<type category="struct" name="VkPhysicalDeviceDrmPropertiesEXT" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRM_PROPERTIES_EXT"><type>VkStructureType</type> <name>sType</name></member>
- <member><type>void</type>* <name>pNext</name></member>
- <member><type>VkBool32</type> <name>hasPrimary</name></member>
- <member><type>VkBool32</type> <name>hasRender</name></member>
- <member><type>int64_t</type> <name>primaryMajor</name></member>
- <member><type>int64_t</type> <name>primaryMinor</name></member>
- <member><type>int64_t</type> <name>renderMajor</name></member>
- <member><type>int64_t</type> <name>renderMinor</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>hasPrimary</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>hasRender</name></member>
+ <member limittype="noauto"><type>int64_t</type> <name>primaryMajor</name></member>
+ <member limittype="noauto"><type>int64_t</type> <name>primaryMinor</name></member>
+ <member limittype="noauto"><type>int64_t</type> <name>renderMajor</name></member>
+ <member limittype="noauto"><type>int64_t</type> <name>renderMinor</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>fragmentShaderBarycentric</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceFragmentShaderBarycentricPropertiesKHR" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_PROPERTIES_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>triStripVertexOrderIndependentOfProvokingVertex</name></member>
</type>
<type category="struct" name="VkPhysicalDeviceRayTracingMotionBlurFeaturesNV" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
<member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MOTION_BLUR_FEATURES_NV"><type>VkStructureType</type> <name>sType</name></member>
- <member noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
<member><type>VkBool32</type> <name>rayTracingMotionBlur</name></member>
<member><type>VkBool32</type> <name>rayTracingMotionBlurPipelineTraceRaysIndirect</name></member>
</type>
@@ -6064,7 +6941,817 @@ typedef void <name>CAMetalLayer</name>;
<member><type>VkDeviceMemory</type> <name>memory</name></member>
<member><type>VkExternalMemoryHandleTypeFlagBits</type> <name>handleType</name></member>
</type>
+ <type category="struct" name="VkImportMemoryBufferCollectionFUCHSIA" structextends="VkMemoryAllocateInfo">
+ <member values="VK_STRUCTURE_TYPE_IMPORT_MEMORY_BUFFER_COLLECTION_FUCHSIA"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkBufferCollectionFUCHSIA</type> <name>collection</name></member>
+ <member><type>uint32_t</type> <name>index</name></member>
+ </type>
+ <type category="struct" name="VkBufferCollectionImageCreateInfoFUCHSIA" structextends="VkImageCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_BUFFER_COLLECTION_IMAGE_CREATE_INFO_FUCHSIA"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkBufferCollectionFUCHSIA</type> <name>collection</name></member>
+ <member><type>uint32_t</type> <name>index</name></member>
+ </type>
+ <type category="struct" name="VkBufferCollectionBufferCreateInfoFUCHSIA" structextends="VkBufferCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_BUFFER_COLLECTION_BUFFER_CREATE_INFO_FUCHSIA"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkBufferCollectionFUCHSIA</type> <name>collection</name></member>
+ <member><type>uint32_t</type> <name>index</name></member>
+ </type>
+ <type category="struct" name="VkBufferCollectionCreateInfoFUCHSIA">
+ <member values="VK_STRUCTURE_TYPE_BUFFER_COLLECTION_CREATE_INFO_FUCHSIA"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>zx_handle_t</type> <name>collectionToken</name></member>
+ </type>
+ <type category="struct" name="VkBufferCollectionPropertiesFUCHSIA">
+ <member values="VK_STRUCTURE_TYPE_BUFFER_COLLECTION_PROPERTIES_FUCHSIA"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>memoryTypeBits</name></member>
+ <member><type>uint32_t</type> <name>bufferCount</name></member>
+ <member><type>uint32_t</type> <name>createInfoIndex</name></member>
+ <member><type>uint64_t</type> <name>sysmemPixelFormat</name></member>
+ <member><type>VkFormatFeatureFlags</type> <name>formatFeatures</name></member>
+ <member><type>VkSysmemColorSpaceFUCHSIA</type> <name>sysmemColorSpaceIndex</name></member>
+ <member><type>VkComponentMapping</type> <name>samplerYcbcrConversionComponents</name></member>
+ <member><type>VkSamplerYcbcrModelConversion</type> <name>suggestedYcbcrModel</name></member>
+ <member><type>VkSamplerYcbcrRange</type> <name>suggestedYcbcrRange</name></member>
+ <member><type>VkChromaLocation</type> <name>suggestedXChromaOffset</name></member>
+ <member><type>VkChromaLocation</type> <name>suggestedYChromaOffset</name></member>
+ </type>
+ <type category="struct" name="VkBufferConstraintsInfoFUCHSIA">
+ <member values="VK_STRUCTURE_TYPE_BUFFER_CONSTRAINTS_INFO_FUCHSIA"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkBufferCreateInfo</type> <name>createInfo</name></member>
+ <member optional="true"><type>VkFormatFeatureFlags</type> <name>requiredFormatFeatures</name></member>
+ <member><type>VkBufferCollectionConstraintsInfoFUCHSIA</type> <name>bufferCollectionConstraints</name></member>
+ </type>
+ <type category="struct" name="VkSysmemColorSpaceFUCHSIA">
+ <member values="VK_STRUCTURE_TYPE_SYSMEM_COLOR_SPACE_FUCHSIA"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>colorSpace</name></member>
+ </type>
+ <type category="struct" name="VkImageFormatConstraintsInfoFUCHSIA">
+ <member values="VK_STRUCTURE_TYPE_IMAGE_FORMAT_CONSTRAINTS_INFO_FUCHSIA"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkImageCreateInfo</type> <name>imageCreateInfo</name></member>
+ <member><type>VkFormatFeatureFlags</type> <name>requiredFormatFeatures</name></member>
+ <member optional="true"><type>VkImageFormatConstraintsFlagsFUCHSIA</type> <name>flags</name></member>
+ <member optional="true"><type>uint64_t</type> <name>sysmemPixelFormat</name></member>
+ <member><type>uint32_t</type> <name>colorSpaceCount</name></member>
+ <member len="colorSpaceCount">const <type>VkSysmemColorSpaceFUCHSIA</type>* <name>pColorSpaces</name></member>
+ </type>
+ <type category="struct" name="VkImageConstraintsInfoFUCHSIA">
+ <member values="VK_STRUCTURE_TYPE_IMAGE_CONSTRAINTS_INFO_FUCHSIA"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>formatConstraintsCount</name></member>
+ <member len="formatConstraintsCount">const <type>VkImageFormatConstraintsInfoFUCHSIA</type>* <name>pFormatConstraints</name></member>
+ <member><type>VkBufferCollectionConstraintsInfoFUCHSIA</type> <name>bufferCollectionConstraints</name></member>
+ <member optional="true"><type>VkImageConstraintsInfoFlagsFUCHSIA</type> <name>flags</name></member>
+ </type>
+ <type category="struct" name="VkBufferCollectionConstraintsInfoFUCHSIA">
+ <member values="VK_STRUCTURE_TYPE_BUFFER_COLLECTION_CONSTRAINTS_INFO_FUCHSIA"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>minBufferCount</name></member>
+ <member><type>uint32_t</type> <name>maxBufferCount</name></member>
+ <member><type>uint32_t</type> <name>minBufferCountForCamping</name></member>
+ <member><type>uint32_t</type> <name>minBufferCountForDedicatedSlack</name></member>
+ <member><type>uint32_t</type> <name>minBufferCountForSharedSlack</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RGBA10X6_FORMATS_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>formatRgba10x6WithoutYCbCrSampler</name></member>
+ </type>
+ <type category="struct" name="VkFormatProperties3" returnedonly="true" structextends="VkFormatProperties2">
+ <member values="VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member optional="true" limittype="bitmask"><type>VkFormatFeatureFlags2</type> <name>linearTilingFeatures</name></member>
+ <member optional="true" limittype="bitmask"><type>VkFormatFeatureFlags2</type> <name>optimalTilingFeatures</name></member>
+ <member optional="true" limittype="bitmask"><type>VkFormatFeatureFlags2</type> <name>bufferFeatures</name></member>
+ </type>
+ <type category="struct" name="VkFormatProperties3KHR" alias="VkFormatProperties3"/>
+ <type category="struct" name="VkDrmFormatModifierPropertiesList2EXT" returnedonly="true" structextends="VkFormatProperties2">
+ <member values="VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_2_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>uint32_t</type> <name>drmFormatModifierCount</name></member>
+ <member optional="true" len="drmFormatModifierCount"><type>VkDrmFormatModifierProperties2EXT</type>* <name>pDrmFormatModifierProperties</name></member>
+ </type>
+ <type category="struct" name="VkDrmFormatModifierProperties2EXT" returnedonly="true">
+ <member><type>uint64_t</type> <name>drmFormatModifier</name></member>
+ <member><type>uint32_t</type> <name>drmFormatModifierPlaneCount</name></member>
+ <member><type>VkFormatFeatureFlags2</type> <name>drmFormatModifierTilingFeatures</name></member>
+ </type>
+ <type category="struct" name="VkAndroidHardwareBufferFormatProperties2ANDROID" structextends="VkAndroidHardwareBufferPropertiesANDROID" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_2_ANDROID"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkFormat</type> <name>format</name></member>
+ <member><type>uint64_t</type> <name>externalFormat</name></member>
+ <member><type>VkFormatFeatureFlags2</type> <name>formatFeatures</name></member>
+ <member><type>VkComponentMapping</type> <name>samplerYcbcrConversionComponents</name></member>
+ <member><type>VkSamplerYcbcrModelConversion</type> <name>suggestedYcbcrModel</name></member>
+ <member><type>VkSamplerYcbcrRange</type> <name>suggestedYcbcrRange</name></member>
+ <member><type>VkChromaLocation</type> <name>suggestedXChromaOffset</name></member>
+ <member><type>VkChromaLocation</type> <name>suggestedYChromaOffset</name></member>
+ </type>
+ <type category="struct" name="VkPipelineRenderingCreateInfo" structextends="VkGraphicsPipelineCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>viewMask</name></member>
+ <member optional="true"><type>uint32_t</type> <name>colorAttachmentCount</name></member>
+ <member noautovalidity="true" len="colorAttachmentCount">const <type>VkFormat</type>* <name>pColorAttachmentFormats</name></member>
+ <member noautovalidity="true"><type>VkFormat</type> <name>depthAttachmentFormat</name></member>
+ <member noautovalidity="true"><type>VkFormat</type> <name>stencilAttachmentFormat</name></member>
+ </type>
+ <type category="struct" name="VkPipelineRenderingCreateInfoKHR" alias="VkPipelineRenderingCreateInfo"/>
+ <type category="struct" name="VkRenderingInfo">
+ <member values="VK_STRUCTURE_TYPE_RENDERING_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkRenderingFlags</type> <name>flags</name></member>
+ <member><type>VkRect2D</type> <name>renderArea</name></member>
+ <member><type>uint32_t</type> <name>layerCount</name></member>
+ <member><type>uint32_t</type> <name>viewMask</name></member>
+ <member optional="true"><type>uint32_t</type> <name>colorAttachmentCount</name></member>
+ <member len="colorAttachmentCount">const <type>VkRenderingAttachmentInfo</type>* <name>pColorAttachments</name></member>
+ <member optional="true">const <type>VkRenderingAttachmentInfo</type>* <name>pDepthAttachment</name></member>
+ <member optional="true">const <type>VkRenderingAttachmentInfo</type>* <name>pStencilAttachment</name></member>
+ </type>
+ <type category="struct" name="VkRenderingInfoKHR" alias="VkRenderingInfo"/>
+ <type category="struct" name="VkRenderingAttachmentInfo">
+ <member values="VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkImageView</type> <name>imageView</name></member>
+ <member><type>VkImageLayout</type> <name>imageLayout</name></member>
+ <member optional="true"><type>VkResolveModeFlagBits</type> <name>resolveMode</name></member>
+ <member optional="true"><type>VkImageView</type> <name>resolveImageView</name></member>
+ <member><type>VkImageLayout</type> <name>resolveImageLayout</name></member>
+ <member><type>VkAttachmentLoadOp</type> <name>loadOp</name></member>
+ <member><type>VkAttachmentStoreOp</type> <name>storeOp</name></member>
+ <member><type>VkClearValue</type> <name>clearValue</name></member>
+ </type>
+ <type category="struct" name="VkRenderingAttachmentInfoKHR" alias="VkRenderingAttachmentInfo"/>
+ <type category="struct" name="VkRenderingFragmentShadingRateAttachmentInfoKHR" structextends="VkRenderingInfo">
+ <member values="VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkImageView</type> <name>imageView</name></member>
+ <member><type>VkImageLayout</type> <name>imageLayout</name></member>
+ <member><type>VkExtent2D</type> <name>shadingRateAttachmentTexelSize</name></member>
+ </type>
+ <type category="struct" name="VkRenderingFragmentDensityMapAttachmentInfoEXT" structextends="VkRenderingInfo">
+ <member values="VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkImageView</type> <name>imageView</name></member>
+ <member><type>VkImageLayout</type> <name>imageLayout</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceDynamicRenderingFeatures" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>dynamicRendering</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceDynamicRenderingFeaturesKHR" alias="VkPhysicalDeviceDynamicRenderingFeatures"/>
+ <type category="struct" name="VkCommandBufferInheritanceRenderingInfo" structextends="VkCommandBufferInheritanceInfo">
+ <member values="VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkRenderingFlags</type> <name>flags</name></member>
+ <member><type>uint32_t</type> <name>viewMask</name></member>
+ <member optional="true"><type>uint32_t</type> <name>colorAttachmentCount</name></member>
+ <member len="colorAttachmentCount">const <type>VkFormat</type>* <name>pColorAttachmentFormats</name></member>
+ <member><type>VkFormat</type> <name>depthAttachmentFormat</name></member>
+ <member><type>VkFormat</type> <name>stencilAttachmentFormat</name></member>
+ <member optional="true"><type>VkSampleCountFlagBits</type> <name>rasterizationSamples</name></member>
+ </type>
+ <type category="struct" name="VkCommandBufferInheritanceRenderingInfoKHR" alias="VkCommandBufferInheritanceRenderingInfo"/>
+ <type category="struct" name="VkAttachmentSampleCountInfoAMD" structextends="VkCommandBufferInheritanceInfo,VkGraphicsPipelineCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_ATTACHMENT_SAMPLE_COUNT_INFO_AMD"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>uint32_t</type> <name>colorAttachmentCount</name></member>
+ <member noautovalidity="true" len="colorAttachmentCount">const <type>VkSampleCountFlagBits</type>* <name>pColorAttachmentSamples</name></member>
+ <member noautovalidity="true" optional="true"><type>VkSampleCountFlagBits</type> <name>depthStencilAttachmentSamples</name></member>
+ </type>
+ <type category="struct" name="VkAttachmentSampleCountInfoNV" alias="VkAttachmentSampleCountInfoAMD"/>
+ <type category="struct" name="VkMultiviewPerViewAttributesInfoNVX" structextends="VkCommandBufferInheritanceInfo,VkGraphicsPipelineCreateInfo,VkRenderingInfo">
+ <member values="VK_STRUCTURE_TYPE_MULTIVIEW_PER_VIEW_ATTRIBUTES_INFO_NVX"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>perViewAttributes</name></member>
+ <member><type>VkBool32</type> <name>perViewAttributesPositionXOnly</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceImageViewMinLodFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_MIN_LOD_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>minLod</name></member>
+ </type>
+ <type category="struct" name="VkImageViewMinLodCreateInfoEXT" structextends="VkImageViewCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_IMAGE_VIEW_MIN_LOD_CREATE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>float</type> <name>minLod</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>rasterizationOrderColorAttachmentAccess</name></member>
+ <member><type>VkBool32</type> <name>rasterizationOrderDepthAttachmentAccess</name></member>
+ <member><type>VkBool32</type> <name>rasterizationOrderStencilAttachmentAccess</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesARM" alias="VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT"/>
+ <type category="struct" name="VkPhysicalDeviceLinearColorAttachmentFeaturesNV" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINEAR_COLOR_ATTACHMENT_FEATURES_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>linearColorAttachment</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>graphicsPipelineLibrary</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_PROPERTIES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>graphicsPipelineLibraryFastLinking</name></member>
+ <member limittype="bitmask"><type>VkBool32</type> <name>graphicsPipelineLibraryIndependentInterpolationDecoration</name></member>
+ </type>
+ <type category="struct" name="VkGraphicsPipelineLibraryCreateInfoEXT" structextends="VkGraphicsPipelineCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_LIBRARY_CREATE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkGraphicsPipelineLibraryFlagsEXT</type> <name>flags</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_SET_HOST_MAPPING_FEATURES_VALVE"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>descriptorSetHostMapping</name></member>
+ </type>
+ <type category="struct" name="VkDescriptorSetBindingReferenceVALVE">
+ <member values="VK_STRUCTURE_TYPE_DESCRIPTOR_SET_BINDING_REFERENCE_VALVE"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkDescriptorSetLayout</type> <name>descriptorSetLayout</name></member>
+ <member><type>uint32_t</type> <name>binding</name></member>
+ </type>
+ <type category="struct" name="VkDescriptorSetLayoutHostMappingInfoVALVE">
+ <member values="VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_HOST_MAPPING_INFO_VALVE"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>size_t</type> <name>descriptorOffset</name></member>
+ <member><type>uint32_t</type> <name>descriptorSize</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>shaderModuleIdentifier</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceShaderModuleIdentifierPropertiesEXT" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_PROPERTIES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <member limittype="noauto"><type>uint8_t</type> <name>shaderModuleIdentifierAlgorithmUUID</name>[<enum>VK_UUID_SIZE</enum>]</member>
+ </type>
+ <type category="struct" name="VkPipelineShaderStageModuleIdentifierCreateInfoEXT" structextends="VkPipelineShaderStageCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_MODULE_IDENTIFIER_CREATE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>uint32_t</type> <name>identifierSize</name></member>
+ <member len="identifierSize">const <type>uint8_t</type>* <name>pIdentifier</name></member>
+ </type>
+ <type category="struct" name="VkShaderModuleIdentifierEXT" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_SHADER_MODULE_IDENTIFIER_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member noautovalidity="true"><type>uint32_t</type> <name>identifierSize</name></member>
+ <member><type>uint8_t</type> <name>identifier</name>[<enum>VK_MAX_SHADER_MODULE_IDENTIFIER_SIZE_EXT</enum>]</member>
+ </type>
+ <type category="struct" name="VkImageCompressionControlEXT" structextends="VkImageCreateInfo,VkSwapchainCreateInfoKHR,VkPhysicalDeviceImageFormatInfo2">
+ <member values="VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member noautovalidity="true"><type>VkImageCompressionFlagsEXT</type> <name>flags</name></member>
+ <member optional="true"><type>uint32_t</type> <name>compressionControlPlaneCount</name></member>
+ <member noautovalidity="true" len="compressionControlPlaneCount"><type>VkImageCompressionFixedRateFlagsEXT</type>* <name>pFixedRateFlags</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceImageCompressionControlFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>imageCompressionControl</name></member>
+ </type>
+ <type category="struct" name="VkImageCompressionPropertiesEXT" structextends="VkImageFormatProperties2,VkSurfaceFormat2KHR,VkSubresourceLayout2EXT" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkImageCompressionFlagsEXT</type> <name>imageCompressionFlags</name></member>
+ <member><type>VkImageCompressionFixedRateFlagsEXT</type> <name>imageCompressionFixedRateFlags</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>imageCompressionControlSwapchain</name></member>
+ </type>
+ <type category="struct" name="VkImageSubresource2EXT">
+ <member values="VK_STRUCTURE_TYPE_IMAGE_SUBRESOURCE_2_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkImageSubresource</type> <name>imageSubresource</name></member>
+ </type>
+ <type category="struct" name="VkSubresourceLayout2EXT" returnedonly="true">
+ <member values="VK_STRUCTURE_TYPE_SUBRESOURCE_LAYOUT_2_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkSubresourceLayout</type> <name>subresourceLayout</name></member>
+ </type>
+ <type category="struct" name="VkRenderPassCreationControlEXT" structextends="VkRenderPassCreateInfo2,VkSubpassDescription2">
+ <member values="VK_STRUCTURE_TYPE_RENDER_PASS_CREATION_CONTROL_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>disallowMerging</name></member>
+ </type>
+ <type category="struct" name="VkRenderPassCreationFeedbackInfoEXT" returnedonly="true">
+ <member><type>uint32_t</type> <name>postMergeSubpassCount</name></member>
+ </type>
+ <type category="struct" name="VkRenderPassCreationFeedbackCreateInfoEXT" structextends="VkRenderPassCreateInfo2">
+ <member values="VK_STRUCTURE_TYPE_RENDER_PASS_CREATION_FEEDBACK_CREATE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkRenderPassCreationFeedbackInfoEXT</type>* <name>pRenderPassFeedback</name></member>
+ </type>
+ <type category="struct" name="VkRenderPassSubpassFeedbackInfoEXT" returnedonly="true">
+ <member><type>VkSubpassMergeStatusEXT</type> <name>subpassMergeStatus</name></member>
+ <member><type>char</type> <name>description</name>[<enum>VK_MAX_DESCRIPTION_SIZE</enum>]</member>
+ <member><type>uint32_t</type> <name>postMergeIndex</name></member>
+ </type>
+ <type category="struct" name="VkRenderPassSubpassFeedbackCreateInfoEXT" structextends="VkSubpassDescription2">
+ <member values="VK_STRUCTURE_TYPE_RENDER_PASS_SUBPASS_FEEDBACK_CREATE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkRenderPassSubpassFeedbackInfoEXT</type>* <name>pSubpassFeedback</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceSubpassMergeFeedbackFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_MERGE_FEEDBACK_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>subpassMergeFeedback</name></member>
+ </type>
+ <type category="struct" name="VkMicromapBuildInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_MICROMAP_BUILD_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkMicromapTypeEXT</type> <name>type</name></member>
+ <member optional="true"><type>VkBuildMicromapFlagsEXT</type> <name>flags</name></member>
+ <member noautovalidity="true"><type>VkBuildMicromapModeEXT</type> <name>mode</name></member>
+ <member optional="true" noautovalidity="true"><type>VkMicromapEXT</type> <name>dstMicromap</name></member>
+ <member optional="true"><type>uint32_t</type> <name>usageCountsCount</name></member>
+ <member len="usageCountsCount" optional="true">const <type>VkMicromapUsageEXT</type>* <name>pUsageCounts</name></member>
+ <member len="usageCountsCount,1" optional="true,false">const <type>VkMicromapUsageEXT</type>* const* <name>ppUsageCounts</name></member>
+ <member noautovalidity="true"><type>VkDeviceOrHostAddressConstKHR</type> <name>data</name></member>
+ <member noautovalidity="true"><type>VkDeviceOrHostAddressKHR</type> <name>scratchData</name></member>
+ <member noautovalidity="true"><type>VkDeviceOrHostAddressConstKHR</type> <name>triangleArray</name></member>
+ <member><type>VkDeviceSize</type> <name>triangleArrayStride</name></member>
+ </type>
+ <type category="struct" name="VkMicromapCreateInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_MICROMAP_CREATE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkMicromapCreateFlagsEXT</type> <name>createFlags</name></member>
+ <member><type>VkBuffer</type> <name>buffer</name></member>
+ <member><type>VkDeviceSize</type> <name>offset</name><comment>Specified in bytes</comment></member>
+ <member><type>VkDeviceSize</type> <name>size</name></member>
+ <member><type>VkMicromapTypeEXT</type> <name>type</name></member>
+ <member optional="true"><type>VkDeviceAddress</type> <name>deviceAddress</name></member>
+ </type>
+ <type category="struct" name="VkMicromapVersionInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_MICROMAP_VERSION_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member len="latexmath:[2 \times \mathtt{VK\_UUID\_SIZE}]" altlen="2*VK_UUID_SIZE">const <type>uint8_t</type>* <name>pVersionData</name></member>
+ </type>
+ <type category="struct" name="VkCopyMicromapInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_COPY_MICROMAP_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkMicromapEXT</type> <name>src</name></member>
+ <member><type>VkMicromapEXT</type> <name>dst</name></member>
+ <member><type>VkCopyMicromapModeEXT</type> <name>mode</name></member>
+ </type>
+ <type category="struct" name="VkCopyMicromapToMemoryInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_COPY_MICROMAP_TO_MEMORY_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkMicromapEXT</type> <name>src</name></member>
+ <member noautovalidity="true"><type>VkDeviceOrHostAddressKHR</type> <name>dst</name></member>
+ <member><type>VkCopyMicromapModeEXT</type> <name>mode</name></member>
+ </type>
+ <type category="struct" name="VkCopyMemoryToMicromapInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_COPY_MEMORY_TO_MICROMAP_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member noautovalidity="true"><type>VkDeviceOrHostAddressConstKHR</type> <name>src</name></member>
+ <member><type>VkMicromapEXT</type> <name>dst</name></member>
+ <member><type>VkCopyMicromapModeEXT</type> <name>mode</name></member>
+ </type>
+ <type category="struct" name="VkMicromapBuildSizesInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_MICROMAP_BUILD_SIZES_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkDeviceSize</type> <name>micromapSize</name></member>
+ <member><type>VkDeviceSize</type> <name>buildScratchSize</name></member>
+ <member><type>VkBool32</type> <name>discardable</name></member>
+ </type>
+ <type category="struct" name="VkMicromapUsageEXT">
+ <member><type>uint32_t</type> <name>count</name></member>
+ <member><type>uint32_t</type> <name>subdivisionLevel</name></member>
+ <member><type>uint32_t</type> <name>format</name><comment>Interpretation depends on parent type</comment></member>
+ </type>
+ <type category="struct" name="VkMicromapTriangleEXT">
+ <member><type>uint32_t</type> <name>dataOffset</name><comment>Specified in bytes</comment></member>
+ <member><type>uint16_t</type> <name>subdivisionLevel</name></member>
+ <member><type>uint16_t</type> <name>format</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceOpacityMicromapFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>micromap</name></member>
+ <member><type>VkBool32</type> <name>micromapCaptureReplay</name></member>
+ <member><type>VkBool32</type> <name>micromapHostCommands</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceOpacityMicromapPropertiesEXT" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_PROPERTIES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxOpacity2StateSubdivisionLevel</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>maxOpacity4StateSubdivisionLevel</name></member>
+ </type>
+ <type category="struct" name="VkAccelerationStructureTrianglesOpacityMicromapEXT" structextends="VkAccelerationStructureGeometryTrianglesDataKHR">
+ <member values="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_TRIANGLES_OPACITY_MICROMAP_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkIndexType</type> <name>indexType</name></member>
+ <member noautovalidity="true"><type>VkDeviceOrHostAddressConstKHR</type> <name>indexBuffer</name></member>
+ <member><type>VkDeviceSize</type> <name>indexStride</name></member>
+ <member><type>uint32_t</type> <name>baseTriangle</name></member>
+ <member optional="true"><type>uint32_t</type> <name>usageCountsCount</name></member>
+ <member len="usageCountsCount" optional="true">const <type>VkMicromapUsageEXT</type>* <name>pUsageCounts</name></member>
+ <member len="usageCountsCount,1" optional="true,false">const <type>VkMicromapUsageEXT</type>* const* <name>ppUsageCounts</name></member>
+ <member><type>VkMicromapEXT</type> <name>micromap</name></member>
+ </type>
+ <type category="struct" name="VkPipelinePropertiesIdentifierEXT">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_PROPERTIES_IDENTIFIER_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>uint8_t</type> <name>pipelineIdentifier</name>[<enum>VK_UUID_SIZE</enum>]</member>
+ </type>
+ <type category="struct" name="VkPhysicalDevicePipelinePropertiesFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROPERTIES_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>pipelinePropertiesIdentifier</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceShaderEarlyAndLateFragmentTestsFeaturesAMD" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_FEATURES_AMD"><type>VkStructureType</type> <name>sType</name></member>
+ <member noautovalidity="true" optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>shaderEarlyAndLateFragmentTests</name></member>
+ </type>
+ <type category="struct" name="VkExportMetalObjectCreateInfoEXT" structextends="VkInstanceCreateInfo,VkMemoryAllocateInfo,VkImageCreateInfo,VkImageViewCreateInfo,VkBufferViewCreateInfo,VkSemaphoreCreateInfo,VkEventCreateInfo" allowduplicate="true">
+ <member values="VK_STRUCTURE_TYPE_EXPORT_METAL_OBJECT_CREATE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkExportMetalObjectTypeFlagBitsEXT</type> <name>exportObjectType</name></member>
+ </type>
+ <type category="struct" name="VkExportMetalObjectsInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_EXPORT_METAL_OBJECTS_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ </type>
+ <type category="struct" name="VkExportMetalDeviceInfoEXT" structextends="VkExportMetalObjectsInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_EXPORT_METAL_DEVICE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>MTLDevice_id</type> <name>mtlDevice</name></member>
+ </type>
+ <type category="struct" name="VkExportMetalCommandQueueInfoEXT" structextends="VkExportMetalObjectsInfoEXT" allowduplicate="true">
+ <member values="VK_STRUCTURE_TYPE_EXPORT_METAL_COMMAND_QUEUE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkQueue</type> <name>queue</name></member>
+ <member><type>MTLCommandQueue_id</type> <name>mtlCommandQueue</name></member>
+ </type>
+ <type category="struct" name="VkExportMetalBufferInfoEXT" structextends="VkExportMetalObjectsInfoEXT" allowduplicate="true">
+ <member values="VK_STRUCTURE_TYPE_EXPORT_METAL_BUFFER_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkDeviceMemory</type> <name>memory</name></member>
+ <member><type>MTLBuffer_id</type> <name>mtlBuffer</name></member>
+ </type>
+ <type category="struct" name="VkImportMetalBufferInfoEXT" structextends="VkMemoryAllocateInfo" allowduplicate="false">
+ <member values="VK_STRUCTURE_TYPE_IMPORT_METAL_BUFFER_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>MTLBuffer_id</type> <name>mtlBuffer</name></member>
+ </type>
+ <type category="struct" name="VkExportMetalTextureInfoEXT" structextends="VkExportMetalObjectsInfoEXT" allowduplicate="true">
+ <member values="VK_STRUCTURE_TYPE_EXPORT_METAL_TEXTURE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkImage</type> <name>image</name></member>
+ <member optional="true"><type>VkImageView</type> <name>imageView</name></member>
+ <member optional="true"><type>VkBufferView</type> <name>bufferView</name></member>
+ <member><type>VkImageAspectFlagBits</type> <name>plane</name></member>
+ <member><type>MTLTexture_id</type> <name>mtlTexture</name></member>
+ </type>
+ <type category="struct" name="VkImportMetalTextureInfoEXT" structextends="VkImageCreateInfo" allowduplicate="true">
+ <member values="VK_STRUCTURE_TYPE_IMPORT_METAL_TEXTURE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkImageAspectFlagBits</type> <name>plane</name></member>
+ <member><type>MTLTexture_id</type> <name>mtlTexture</name></member>
+ </type>
+ <type category="struct" name="VkExportMetalIOSurfaceInfoEXT" structextends="VkExportMetalObjectsInfoEXT" allowduplicate="true">
+ <member values="VK_STRUCTURE_TYPE_EXPORT_METAL_IO_SURFACE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkImage</type> <name>image</name></member>
+ <member><type>IOSurfaceRef</type> <name>ioSurface</name></member>
+ </type>
+ <type category="struct" name="VkImportMetalIOSurfaceInfoEXT" structextends="VkImageCreateInfo" allowduplicate="false">
+ <member values="VK_STRUCTURE_TYPE_IMPORT_METAL_IO_SURFACE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>IOSurfaceRef</type> <name>ioSurface</name></member>
+ </type>
+ <type category="struct" name="VkExportMetalSharedEventInfoEXT" structextends="VkExportMetalObjectsInfoEXT" allowduplicate="true">
+ <member values="VK_STRUCTURE_TYPE_EXPORT_METAL_SHARED_EVENT_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkSemaphore</type> <name>semaphore</name></member>
+ <member optional="true"><type>VkEvent</type> <name>event</name></member>
+ <member><type>MTLSharedEvent_id</type> <name>mtlSharedEvent</name></member>
+ </type>
+ <type category="struct" name="VkImportMetalSharedEventInfoEXT" structextends="VkSemaphoreCreateInfo,VkEventCreateInfo" allowduplicate="false">
+ <member values="VK_STRUCTURE_TYPE_IMPORT_METAL_SHARED_EVENT_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>MTLSharedEvent_id</type> <name>mtlSharedEvent</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NON_SEAMLESS_CUBE_MAP_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>nonSeamlessCubeMap</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDevicePipelineRobustnessFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member noautovalidity="true" optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>pipelineRobustness</name></member>
+ </type>
+ <type category="struct" name="VkPipelineRobustnessCreateInfoEXT" structextends="VkGraphicsPipelineCreateInfo,VkComputePipelineCreateInfo,VkPipelineShaderStageCreateInfo,VkRayTracingPipelineCreateInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member noautovalidity="true" optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkPipelineRobustnessBufferBehaviorEXT</type> <name>storageBuffers</name></member>
+ <member><type>VkPipelineRobustnessBufferBehaviorEXT</type> <name>uniformBuffers</name></member>
+ <member><type>VkPipelineRobustnessBufferBehaviorEXT</type> <name>vertexInputs</name></member>
+ <member><type>VkPipelineRobustnessImageBehaviorEXT</type> <name>images</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDevicePipelineRobustnessPropertiesEXT" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_PROPERTIES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member limittype="exact"><type>VkPipelineRobustnessBufferBehaviorEXT</type> <name>defaultRobustnessStorageBuffers</name></member>
+ <member limittype="exact"><type>VkPipelineRobustnessBufferBehaviorEXT</type> <name>defaultRobustnessUniformBuffers</name></member>
+ <member limittype="exact"><type>VkPipelineRobustnessBufferBehaviorEXT</type> <name>defaultRobustnessVertexInputs</name></member>
+ <member limittype="exact"><type>VkPipelineRobustnessImageBehaviorEXT</type> <name>defaultRobustnessImages</name></member>
+ </type>
+ <type category="struct" name="VkImageViewSampleWeightCreateInfoQCOM" structextends="VkImageViewCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_IMAGE_VIEW_SAMPLE_WEIGHT_CREATE_INFO_QCOM"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkOffset2D</type> <name>filterCenter</name></member>
+ <member><type>VkExtent2D</type> <name>filterSize</name></member>
+ <member><type>uint32_t</type> <name>numPhases</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceImageProcessingFeaturesQCOM" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_FEATURES_QCOM"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>textureSampleWeighted</name></member>
+ <member><type>VkBool32</type> <name>textureBoxFilter</name></member>
+ <member><type>VkBool32</type> <name>textureBlockMatch</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceImageProcessingPropertiesQCOM" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_PROPERTIES_QCOM"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member limittype="max" optional="true"><type>uint32_t</type> <name>maxWeightFilterPhases</name></member>
+ <member limittype="max" optional="true"><type>VkExtent2D</type> <name>maxWeightFilterDimension</name></member>
+ <member limittype="max" optional="true"><type>VkExtent2D</type> <name>maxBlockMatchRegion</name></member>
+ <member limittype="max" optional="true"><type>VkExtent2D</type> <name>maxBoxFilterBlockSize</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceTilePropertiesFeaturesQCOM" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_PROPERTIES_FEATURES_QCOM"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>tileProperties</name></member>
+ </type>
+ <type category="struct" name="VkTilePropertiesQCOM">
+ <member values="VK_STRUCTURE_TYPE_TILE_PROPERTIES_QCOM"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkExtent3D</type> <name>tileSize</name></member>
+ <member><type>VkExtent2D</type> <name>apronSize</name></member>
+ <member><type>VkOffset2D</type> <name>origin</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceAmigoProfilingFeaturesSEC" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_AMIGO_PROFILING_FEATURES_SEC"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>amigoProfiling</name></member>
+ </type>
+ <type category="struct" name="VkAmigoProfilingSubmitInfoSEC" structextends="VkSubmitInfo">
+ <member values="VK_STRUCTURE_TYPE_AMIGO_PROFILING_SUBMIT_INFO_SEC"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>uint64_t</type> <name>firstDrawTimestamp</name></member>
+ <member><type>uint64_t</type> <name>swapBufferTimestamp</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>attachmentFeedbackLoopLayout</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceDepthClampZeroOneFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLAMP_ZERO_ONE_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>depthClampZeroOne</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceAddressBindingReportFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ADDRESS_BINDING_REPORT_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>reportAddressBinding</name></member>
+ </type>
+ <type category="struct" name="VkDeviceAddressBindingCallbackDataEXT" structextends="VkDebugUtilsMessengerCallbackDataEXT">
+ <member values="VK_STRUCTURE_TYPE_DEVICE_ADDRESS_BINDING_CALLBACK_DATA_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkDeviceAddressBindingFlagsEXT</type> <name>flags</name></member>
+ <member><type>VkDeviceAddress</type> <name>baseAddress</name></member>
+ <member><type>VkDeviceSize</type> <name>size</name></member>
+ <member><type>VkDeviceAddressBindingTypeEXT</type> <name>bindingType</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceOpticalFlowFeaturesNV" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_FEATURES_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>opticalFlow</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceOpticalFlowPropertiesNV" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_PROPERTIES_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member limittype="bitmask"><type>VkOpticalFlowGridSizeFlagsNV</type> <name>supportedOutputGridSizes</name></member>
+ <member limittype="bitmask"><type>VkOpticalFlowGridSizeFlagsNV</type> <name>supportedHintGridSizes</name></member>
+ <member limittype="noauto"><type>VkBool32</type> <name>hintSupported</name></member>
+ <member limittype="noauto"><type>VkBool32</type> <name>costSupported</name></member>
+ <member limittype="noauto"><type>VkBool32</type> <name>bidirectionalFlowSupported</name></member>
+ <member limittype="noauto"><type>VkBool32</type> <name>globalFlowSupported</name></member>
+ <member limittype="noauto"><type>uint32_t</type> <name>minWidth</name></member>
+ <member limittype="noauto"><type>uint32_t</type> <name>minHeight</name></member>
+ <member limittype="noauto"><type>uint32_t</type> <name>maxWidth</name></member>
+ <member limittype="noauto"><type>uint32_t</type> <name>maxHeight</name></member>
+ <member limittype="noauto"><type>uint32_t</type> <name>maxNumRegionsOfInterest</name></member>
+ </type>
+ <type category="struct" name="VkOpticalFlowImageFormatInfoNV" structextends="VkPhysicalDeviceImageFormatInfo2,VkImageCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_OPTICAL_FLOW_IMAGE_FORMAT_INFO_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkOpticalFlowUsageFlagsNV</type> <name>usage</name></member>
+ </type>
+ <type category="struct" name="VkOpticalFlowImageFormatPropertiesNV" returnedonly="true" >
+ <member values="VK_STRUCTURE_TYPE_OPTICAL_FLOW_IMAGE_FORMAT_PROPERTIES_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member><type>VkFormat</type> <name>format</name></member>
+ </type>
+ <type category="struct" name="VkOpticalFlowSessionCreateInfoNV">
+ <member values="VK_STRUCTURE_TYPE_OPTICAL_FLOW_SESSION_CREATE_INFO_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>width</name></member>
+ <member><type>uint32_t</type> <name>height</name></member>
+ <member><type>VkFormat</type> <name>imageFormat</name></member>
+ <member><type>VkFormat</type> <name>flowVectorFormat</name></member>
+ <member optional="true"><type>VkFormat</type> <name>costFormat</name></member>
+ <member><type>VkOpticalFlowGridSizeFlagsNV</type> <name>outputGridSize</name></member>
+ <member optional="true"><type>VkOpticalFlowGridSizeFlagsNV</type> <name>hintGridSize</name></member>
+ <member optional="true"><type>VkOpticalFlowPerformanceLevelNV</type> <name>performanceLevel</name></member>
+ <member optional="true"><type>VkOpticalFlowSessionCreateFlagsNV</type> <name>flags</name></member>
+ </type>
+ <type category="struct" name="VkOpticalFlowSessionCreatePrivateDataInfoNV" structextends="VkOpticalFlowSessionCreateInfoNV"><comment>NV internal use only</comment>
+ <member values="VK_STRUCTURE_TYPE_OPTICAL_FLOW_SESSION_CREATE_PRIVATE_DATA_INFO_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>id</name></member>
+ <member><type>uint32_t</type> <name>size</name></member>
+ <member>const <type>void</type>* <name>pPrivateData</name></member>
+ </type>
+ <type category="struct" name="VkOpticalFlowExecuteInfoNV">
+ <member values="VK_STRUCTURE_TYPE_OPTICAL_FLOW_EXECUTE_INFO_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkOpticalFlowExecuteFlagsNV</type> <name>flags</name></member>
+ <member optional="true"><type>uint32_t</type> <name>regionCount</name></member>
+ <member len="regionCount">const <type>VkRect2D</type>* <name>pRegions</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceFaultFeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>deviceFault</name></member>
+ <member><type>VkBool32</type> <name>deviceFaultVendorBinary</name></member>
+ </type>
+ <type category="struct" name="VkDeviceFaultAddressInfoEXT">
+ <member><type>VkDeviceFaultAddressTypeEXT</type> <name>addressType</name></member>
+ <member><type>VkDeviceAddress</type> <name>reportedAddress</name></member>
+ <member><type>VkDeviceSize</type> <name>addressPrecision</name></member>
+ </type>
+ <type category="struct" name="VkDeviceFaultVendorInfoEXT">
+ <member noautovalidity="true"><type>char</type> <name>description</name>[<enum>VK_MAX_DESCRIPTION_SIZE</enum>]<comment>Free-form description of the fault</comment></member>
+ <member><type>uint64_t</type> <name>vendorFaultCode</name></member>
+ <member><type>uint64_t</type> <name>vendorFaultData</name></member>
+ </type>
+ <type category="struct" name="VkDeviceFaultCountsEXT">
+ <member values="VK_STRUCTURE_TYPE_DEVICE_FAULT_COUNTS_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>uint32_t</type> <name>addressInfoCount</name></member>
+ <member optional="true"><type>uint32_t</type> <name>vendorInfoCount</name></member>
+ <member optional="true"><type>VkDeviceSize</type> <name>vendorBinarySize</name><comment>Specified in bytes</comment></member>
+ </type>
+ <type category="struct" name="VkDeviceFaultInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_DEVICE_FAULT_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member noautovalidity="true"><type>char</type> <name>description</name>[<enum>VK_MAX_DESCRIPTION_SIZE</enum>]<comment>Free-form description of the fault</comment></member>
+ <member optional="true"><type>VkDeviceFaultAddressInfoEXT</type>* <name>pAddressInfos</name></member>
+ <member optional="true"><type>VkDeviceFaultVendorInfoEXT</type>* <name>pVendorInfos</name></member>
+ <member optional="true"><type>void</type>* <name>pVendorBinaryData</name></member>
+ </type>
+ <type category="struct" name="VkDeviceFaultVendorBinaryHeaderVersionOneEXT">
+ <comment>The fields in this structure are non-normative since structure packing is implementation-defined in C. The specification defines the normative layout.</comment>
+ <member><type>uint32_t</type> <name>headerSize</name></member>
+ <member><type>VkDeviceFaultVendorBinaryHeaderVersionEXT</type> <name>headerVersion</name></member>
+ <member><type>uint32_t</type> <name>vendorID</name></member>
+ <member><type>uint32_t</type> <name>deviceID</name></member>
+ <member><type>uint32_t</type> <name>driverVersion</name></member>
+ <member><type>uint8_t</type> <name>pipelineCacheUUID</name>[<enum>VK_UUID_SIZE</enum>]</member>
+ <member><type>uint32_t</type> <name>applicationNameOffset</name></member>
+ <member><type>uint32_t</type> <name>applicationVersion</name></member>
+ <member><type>uint32_t</type> <name>engineNameOffset</name></member>
+ </type>
+ <type category="struct" name="VkDecompressMemoryRegionNV">
+ <member><type>VkDeviceAddress</type> <name>srcAddress</name></member>
+ <member><type>VkDeviceAddress</type> <name>dstAddress</name></member>
+ <member><type>VkDeviceSize</type> <name>compressedSize</name><comment>Specified in bytes</comment></member>
+ <member><type>VkDeviceSize</type> <name>decompressedSize</name><comment>Specified in bytes</comment></member>
+ <member><type>VkMemoryDecompressionMethodFlagsNV</type> <name>decompressionMethod</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceShaderCoreBuiltinsPropertiesARM" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_PROPERTIES_ARM"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member limittype="bitmask"><type>uint64_t</type> <name>shaderCoreMask</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>shaderCoreCount</name></member>
+ <member limittype="max"><type>uint32_t</type> <name>shaderWarpsPerCore</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_FEATURES_ARM"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>shaderCoreBuiltins</name></member>
+ </type>
+ <type category="struct" name="VkSurfacePresentModeEXT" structextends="VkPhysicalDeviceSurfaceInfo2KHR">
+ <member values="VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkPresentModeKHR</type> <name>presentMode</name></member>
+ </type>
+ <type category="struct" name="VkSurfacePresentScalingCapabilitiesEXT" structextends="VkSurfaceCapabilities2KHR">
+ <member values="VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkPresentScalingFlagsEXT</type> <name>supportedPresentScaling</name></member>
+ <member optional="true"><type>VkPresentGravityFlagsEXT</type> <name>supportedPresentGravityX</name></member>
+ <member optional="true"><type>VkPresentGravityFlagsEXT</type> <name>supportedPresentGravityY</name></member>
+ <member optional="true"><type>VkExtent2D</type> <name>minScaledImageExtent</name><comment>Supported minimum image width and height for the surface when scaling is used</comment></member>
+ <member optional="true"><type>VkExtent2D</type> <name>maxScaledImageExtent</name><comment>Supported maximum image width and height for the surface when scaling is used</comment></member>
+ </type>
+ <type category="struct" name="VkSurfacePresentModeCompatibilityEXT" structextends="VkSurfaceCapabilities2KHR">
+ <member values="VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>uint32_t</type> <name>presentModeCount</name></member>
+ <member optional="true" len="presentModeCount"><type>VkPresentModeKHR</type>* <name>pPresentModes</name><comment>Output list of present modes compatible with the one specified in VkSurfacePresentModeEXT</comment></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>swapchainMaintenance1</name></member>
+ </type>
+ <type category="struct" name="VkSwapchainPresentFenceInfoEXT" structextends="VkPresentInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_FENCE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>swapchainCount</name><comment>Copy of VkPresentInfoKHR::swapchainCount</comment></member>
+ <member len="swapchainCount">const <type>VkFence</type>* <name>pFences</name><comment>Fence to signal for each swapchain</comment></member>
+ </type>
+ <type category="struct" name="VkSwapchainPresentModesCreateInfoEXT" structextends="VkSwapchainCreateInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODES_CREATE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>presentModeCount</name></member><comment>Length of the pPresentModes array</comment>
+ <member len="presentModeCount">const <type>VkPresentModeKHR</type>* <name>pPresentModes</name></member><comment>Presentation modes which will be usable with this swapchain</comment>
+ </type>
+ <type category="struct" name="VkSwapchainPresentModeInfoEXT" structextends="VkPresentInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>uint32_t</type> <name>swapchainCount</name><comment>Copy of VkPresentInfoKHR::swapchainCount</comment></member>
+ <member len="swapchainCount">const <type>VkPresentModeKHR</type>* <name>pPresentModes</name><comment>Presentation mode for each swapchain</comment></member>
+ </type>
+ <type category="struct" name="VkSwapchainPresentScalingCreateInfoEXT" structextends="VkSwapchainCreateInfoKHR">
+ <member values="VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_SCALING_CREATE_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member optional="true"><type>VkPresentScalingFlagsEXT</type> <name>scalingBehavior</name></member>
+ <member optional="true"><type>VkPresentGravityFlagsEXT</type> <name>presentGravityX</name></member>
+ <member optional="true"><type>VkPresentGravityFlagsEXT</type> <name>presentGravityY</name></member>
+ </type>
+ <type category="struct" name="VkReleaseSwapchainImagesInfoEXT">
+ <member values="VK_STRUCTURE_TYPE_RELEASE_SWAPCHAIN_IMAGES_INFO_EXT"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true">const <type>void</type>* <name>pNext</name></member>
+ <member externsync="true"><type>VkSwapchainKHR</type> <name>swapchain</name><comment>Swapchain for which images are being released</comment></member>
+ <member><type>uint32_t</type> <name>imageIndexCount</name><comment>Number of indices to release</comment></member>
+ <member len="imageIndexCount">const <type>uint32_t</type>* <name>pImageIndices</name><comment>Indices of which presentable images to release</comment></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceRayTracingInvocationReorderFeaturesNV" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_FEATURES_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>rayTracingInvocationReorder</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceRayTracingInvocationReorderPropertiesNV" returnedonly="true" structextends="VkPhysicalDeviceProperties2">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_PROPERTIES_NV"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <member limittype="noauto"><type>VkRayTracingInvocationReorderModeNV</type> <name>rayTracingInvocationReorderReorderingHint</name></member>
+ </type>
+ <type category="struct" name="VkDirectDriverLoadingInfoLUNARG">
+ <member values="VK_STRUCTURE_TYPE_DIRECT_DRIVER_LOADING_INFO_LUNARG"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkDirectDriverLoadingFlagsLUNARG</type> <name>flags</name></member>
+ <member noautovalidity="true"><type>PFN_vkGetInstanceProcAddrLUNARG</type> <name>pfnGetInstanceProcAddr</name></member>
+ </type>
+ <type category="struct" name="VkDirectDriverLoadingListLUNARG" structextends="VkInstanceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_DIRECT_DRIVER_LOADING_LIST_LUNARG"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true" noautovalidity="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkDirectDriverLoadingModeLUNARG</type> <name>mode</name></member>
+ <member><type>uint32_t</type> <name>driverCount</name></member>
+ <member len="driverCount">const <type>VkDirectDriverLoadingInfoLUNARG</type>* <name>pDrivers</name></member>
+ </type>
+ <type category="struct" name="VkPhysicalDeviceMultiviewPerViewViewportsFeaturesQCOM" structextends="VkPhysicalDeviceFeatures2,VkDeviceCreateInfo">
+ <member values="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_VIEWPORTS_FEATURES_QCOM"><type>VkStructureType</type> <name>sType</name></member>
+ <member optional="true"><type>void</type>* <name>pNext</name></member>
+ <member><type>VkBool32</type> <name>multiviewPerViewViewports</name></member>
+ </type>
</types>
+
+
<comment>Vulkan enumerant (token) definitions</comment>
<enums name="API Constants" comment="Vulkan hardcoded constants - not an enumerated type, part of the header boilerplate">
@@ -6096,7 +7783,9 @@ typedef void <name>CAMetalLayer</name>;
<enum name="VK_MAX_DRIVER_INFO_SIZE_KHR" alias="VK_MAX_DRIVER_INFO_SIZE"/>
<enum type="uint32_t" value="(~0U)" name="VK_SHADER_UNUSED_KHR"/>
<enum name="VK_SHADER_UNUSED_NV" alias="VK_SHADER_UNUSED_KHR"/>
- <enum type="uint32_t" value="16" name="VK_MAX_GLOBAL_PRIORITY_SIZE_EXT"/>
+ <enum type="uint32_t" value="16" name="VK_MAX_GLOBAL_PRIORITY_SIZE_KHR"/>
+ <enum name="VK_MAX_GLOBAL_PRIORITY_SIZE_EXT" alias="VK_MAX_GLOBAL_PRIORITY_SIZE_KHR"/>
+ <enum type="uint32_t" value="32" name="VK_MAX_SHADER_MODULE_IDENTIFIER_SIZE_EXT"/>
</enums>
<comment>
@@ -6192,7 +7881,8 @@ typedef void <name>CAMetalLayer</name>;
<enums name="VkPipelineCacheHeaderVersion" type="enum">
<enum value="1" name="VK_PIPELINE_CACHE_HEADER_VERSION_ONE"/>
</enums>
- <enums name="VkPipelineCacheCreateFlagBits" type="bitmask"></enums>
+ <enums name="VkPipelineCacheCreateFlagBits" type="bitmask">
+ </enums>
<enums name="VkPrimitiveTopology" type="enum">
<enum value="0" name="VK_PRIMITIVE_TOPOLOGY_POINT_LIST"/>
<enum value="1" name="VK_PRIMITIVE_TOPOLOGY_LINE_LIST"/>
@@ -6582,7 +8272,7 @@ typedef void <name>CAMetalLayer</name>;
<comment>Error codes (negative values)</comment>
<enum value="-1" name="VK_ERROR_OUT_OF_HOST_MEMORY" comment="A host memory allocation has failed"/>
<enum value="-2" name="VK_ERROR_OUT_OF_DEVICE_MEMORY" comment="A device memory allocation has failed"/>
- <enum value="-3" name="VK_ERROR_INITIALIZATION_FAILED" comment="Initialization of a object has failed"/>
+ <enum value="-3" name="VK_ERROR_INITIALIZATION_FAILED" comment="Initialization of an object has failed"/>
<enum value="-4" name="VK_ERROR_DEVICE_LOST" comment="The logical device has been lost. See &lt;&lt;devsandqueues-lost-device&gt;&gt;"/>
<enum value="-5" name="VK_ERROR_MEMORY_MAP_FAILED" comment="Mapping of a memory object has failed"/>
<enum value="-6" name="VK_ERROR_LAYER_NOT_PRESENT" comment="Layer specified does not exist"/>
@@ -6637,6 +8327,14 @@ typedef void <name>CAMetalLayer</name>;
<enum value="24" name="VK_OBJECT_TYPE_FRAMEBUFFER"/>
<enum value="25" name="VK_OBJECT_TYPE_COMMAND_POOL"/>
</enums>
+ <enums name="VkRayTracingInvocationReorderModeNV" type="enum">
+ <enum value="0" name="VK_RAY_TRACING_INVOCATION_REORDER_MODE_NONE_NV"/>
+ <enum value="1" name="VK_RAY_TRACING_INVOCATION_REORDER_MODE_REORDER_NV"/>
+ </enums>
+ <enums name="VkDirectDriverLoadingModeLUNARG" type="enum">
+ <enum value="0" name="VK_DIRECT_DRIVER_LOADING_MODE_EXCLUSIVE_LUNARG"/>
+ <enum value="1" name="VK_DIRECT_DRIVER_LOADING_MODE_INCLUSIVE_LUNARG"/>
+ </enums>
<comment>Flags</comment>
<enums name="VkQueueFlagBits" type="bitmask">
@@ -6651,8 +8349,10 @@ typedef void <name>CAMetalLayer</name>;
<enum bitpos="1" name="VK_CULL_MODE_BACK_BIT"/>
<enum value="0x00000003" name="VK_CULL_MODE_FRONT_AND_BACK"/>
</enums>
- <enums name="VkRenderPassCreateFlagBits" type="bitmask"></enums>
- <enums name="VkDeviceQueueCreateFlagBits" type="bitmask"></enums>
+ <enums name="VkRenderPassCreateFlagBits" type="bitmask">
+ </enums>
+ <enums name="VkDeviceQueueCreateFlagBits" type="bitmask">
+ </enums>
<enums name="VkMemoryPropertyFlagBits" type="bitmask">
<enum bitpos="0" name="VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT" comment="If otherwise stated, then allocate memory on device"/>
<enum bitpos="1" name="VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT" comment="Memory is mappable by host"/>
@@ -6745,7 +8445,8 @@ typedef void <name>CAMetalLayer</name>;
<enums name="VkFenceCreateFlagBits" type="bitmask">
<enum bitpos="0" name="VK_FENCE_CREATE_SIGNALED_BIT"/>
</enums>
- <comment>When VkSemaphoreCreateFlagBits is first extended, need to add a bitmask enums tag for it here</comment>
+ <enums name="VkSemaphoreCreateFlagBits" type="bitmask">
+ </enums>
<enums name="VkFormatFeatureFlagBits" type="bitmask">
<enum bitpos="0" name="VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT" comment="Format can be used for sampled images (SAMPLED_IMAGE and COMBINED_IMAGE_SAMPLER descriptor types)"/>
<enum bitpos="1" name="VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT" comment="Format can be used for storage images (STORAGE_IMAGE descriptor type)"/>
@@ -6847,7 +8548,7 @@ typedef void <name>CAMetalLayer</name>;
<enum bitpos="0" name="VK_STENCIL_FACE_FRONT_BIT" comment="Front face"/>
<enum bitpos="1" name="VK_STENCIL_FACE_BACK_BIT" comment="Back face"/>
<enum value="0x00000003" name="VK_STENCIL_FACE_FRONT_AND_BACK" comment="Front and back faces"/>
- <enum name="VK_STENCIL_FRONT_AND_BACK" alias="VK_STENCIL_FACE_FRONT_AND_BACK" comment="Alias for backwards compatibility"/>
+ <enum name="VK_STENCIL_FRONT_AND_BACK" alias="VK_STENCIL_FACE_FRONT_AND_BACK" comment="Backwards-compatible alias containing a typo"/>
</enums>
<enums name="VkDescriptorPoolCreateFlagBits" type="bitmask">
<enum bitpos="0" name="VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT" comment="Descriptor sets may be freed individually"/>
@@ -6946,8 +8647,10 @@ typedef void <name>CAMetalLayer</name>;
<enum name="VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT" alias="VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT" comment="Backwards-compatible alias containing a typo"/>
<enum value="29" name="VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT"/>
<enum value="30" name="VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT"/>
- <!--<enum value="31" name="VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT" comment="Removed NVX_device_generated_commands"/>-->
- <!--<enum value="32" name="VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT" comment="Removed NVX_device_generated_commands"/>-->
+ <comment>NVX_device_generated_commands formerly used these enum values, but that extension has been removed
+ value 31 / name VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT
+ value 32 / name VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT
+ </comment>
<enum value="33" name="VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT"/>
<enum name="VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT" alias="VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT" comment="Backwards-compatible alias containing a typo"/>
</enums>
@@ -7022,7 +8725,7 @@ typedef void <name>CAMetalLayer</name>;
<enum value="6" name="VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_NV"/>
<enum value="7" name="VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_TASKS_NV"/>
</enums>
- <enums name="VkPrivateDataSlotCreateFlagBitsEXT" type="bitmask">
+ <enums name="VkPrivateDataSlotCreateFlagBits" type="bitmask">
</enums>
<enums name="VkDescriptorSetLayoutCreateFlagBits" type="bitmask">
</enums>
@@ -7167,11 +8870,15 @@ typedef void <name>CAMetalLayer</name>;
<enum value="1" name="VK_SHADER_INFO_TYPE_BINARY_AMD"/>
<enum value="2" name="VK_SHADER_INFO_TYPE_DISASSEMBLY_AMD"/>
</enums>
- <enums name="VkQueueGlobalPriorityEXT" type="enum">
- <enum value="128" name="VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT"/>
- <enum value="256" name="VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT"/>
- <enum value="512" name="VK_QUEUE_GLOBAL_PRIORITY_HIGH_EXT"/>
- <enum value="1024" name="VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT"/>
+ <enums name="VkQueueGlobalPriorityKHR" type="enum">
+ <enum value="128" name="VK_QUEUE_GLOBAL_PRIORITY_LOW_KHR"/>
+ <enum value="256" name="VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR"/>
+ <enum value="512" name="VK_QUEUE_GLOBAL_PRIORITY_HIGH_KHR"/>
+ <enum value="1024" name="VK_QUEUE_GLOBAL_PRIORITY_REALTIME_KHR"/>
+ <enum name="VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT" alias="VK_QUEUE_GLOBAL_PRIORITY_LOW_KHR"/>
+ <enum name="VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT" alias="VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_KHR"/>
+ <enum name="VK_QUEUE_GLOBAL_PRIORITY_HIGH_EXT" alias="VK_QUEUE_GLOBAL_PRIORITY_HIGH_KHR"/>
+ <enum name="VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT" alias="VK_QUEUE_GLOBAL_PRIORITY_REALTIME_KHR"/>
</enums>
<enums name="VkDebugUtilsMessageSeverityFlagBitsEXT" type="bitmask">
<enum bitpos="0" name="VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT"/>
@@ -7227,6 +8934,14 @@ typedef void <name>CAMetalLayer</name>;
<enum value="14" name="VK_DRIVER_ID_MOLTENVK" comment="MoltenVK"/>
<enum value="15" name="VK_DRIVER_ID_COREAVI_PROPRIETARY" comment="Core Avionics &amp; Industrial Inc."/>
<enum value="16" name="VK_DRIVER_ID_JUICE_PROPRIETARY" comment="Juice Technologies, Inc."/>
+ <enum value="17" name="VK_DRIVER_ID_VERISILICON_PROPRIETARY" comment="Verisilicon, Inc."/>
+ <enum value="18" name="VK_DRIVER_ID_MESA_TURNIP" comment="Mesa open source project"/>
+ <enum value="19" name="VK_DRIVER_ID_MESA_V3DV" comment="Mesa open source project"/>
+ <enum value="20" name="VK_DRIVER_ID_MESA_PANVK" comment="Mesa open source project"/>
+ <enum value="21" name="VK_DRIVER_ID_SAMSUNG_PROPRIETARY" comment="Samsung Electronics Co., Ltd."/>
+ <enum value="22" name="VK_DRIVER_ID_MESA_VENUS" comment="Mesa open source project"/>
+ <enum value="23" name="VK_DRIVER_ID_MESA_DOZEN" comment="Mesa open source project"/>
+ <enum value="24" name="VK_DRIVER_ID_MESA_NVK" comment="Mesa open source project"/>
</enums>
<enums name="VkConditionalRenderingFlagBitsEXT" type="bitmask">
<enum bitpos="0" name="VK_CONDITIONAL_RENDERING_INVERTED_BIT_EXT"/>
@@ -7260,9 +8975,10 @@ typedef void <name>CAMetalLayer</name>;
</enums>
<enums name="VkGeometryInstanceFlagBitsKHR" type="bitmask">
<enum bitpos="0" name="VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR"/>
- <enum bitpos="1" name="VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_KHR"/>
+ <enum bitpos="1" name="VK_GEOMETRY_INSTANCE_TRIANGLE_FLIP_FACING_BIT_KHR"/>
<enum bitpos="2" name="VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR"/>
<enum bitpos="3" name="VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR"/>
+ <enum name="VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_KHR" alias="VK_GEOMETRY_INSTANCE_TRIANGLE_FLIP_FACING_BIT_KHR"/>
</enums>
<enums name="VkGeometryFlagBitsKHR" type="bitmask">
<enum bitpos="0" name="VK_GEOMETRY_OPAQUE_BIT_KHR"/>
@@ -7353,11 +9069,15 @@ typedef void <name>CAMetalLayer</name>;
<enum bitpos="0" name="VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_SHADER_DEBUG_INFO_BIT_NV"/>
<enum bitpos="1" name="VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_RESOURCE_TRACKING_BIT_NV"/>
<enum bitpos="2" name="VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_AUTOMATIC_CHECKPOINTS_BIT_NV"/>
+ <enum bitpos="3" name="VK_DEVICE_DIAGNOSTICS_CONFIG_ENABLE_SHADER_ERROR_REPORTING_BIT_NV"/>
</enums>
- <enums name="VkPipelineCreationFeedbackFlagBitsEXT" type="bitmask">
- <enum bitpos="0" name="VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT"/>
- <enum bitpos="1" name="VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT"/>
- <enum bitpos="2" name="VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT"/>
+ <enums name="VkPipelineCreationFeedbackFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT"/>
+ <enum name="VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT_EXT" alias="VK_PIPELINE_CREATION_FEEDBACK_VALID_BIT"/>
+ <enum bitpos="1" name="VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT"/>
+ <enum name="VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT_EXT" alias="VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT"/>
+ <enum bitpos="2" name="VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT"/>
+ <enum name="VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT_EXT" alias="VK_PIPELINE_CREATION_FEEDBACK_BASE_PIPELINE_ACCELERATION_BIT"/>
</enums>
<enums name="VkFullScreenExclusiveEXT" type="enum">
<enum value="0" name="VK_FULL_SCREEN_EXCLUSIVE_DEFAULT_EXT"/>
@@ -7369,9 +9089,12 @@ typedef void <name>CAMetalLayer</name>;
<enum value="0" name="VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_BUFFER_KHR"/>
<enum value="1" name="VK_PERFORMANCE_COUNTER_SCOPE_RENDER_PASS_KHR"/>
<enum value="2" name="VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_KHR"/>
- <enum name="VK_QUERY_SCOPE_COMMAND_BUFFER_KHR" alias="VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_BUFFER_KHR"/>
- <enum name="VK_QUERY_SCOPE_RENDER_PASS_KHR" alias="VK_PERFORMANCE_COUNTER_SCOPE_RENDER_PASS_KHR"/>
- <enum name="VK_QUERY_SCOPE_COMMAND_KHR" alias="VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_KHR"/>
+ <enum name="VK_QUERY_SCOPE_COMMAND_BUFFER_KHR" alias="VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_BUFFER_KHR" comment="Backwards-compatible alias containing a typo"/>
+ <enum name="VK_QUERY_SCOPE_RENDER_PASS_KHR" alias="VK_PERFORMANCE_COUNTER_SCOPE_RENDER_PASS_KHR" comment="Backwards-compatible alias containing a typo"/>
+ <enum name="VK_QUERY_SCOPE_COMMAND_KHR" alias="VK_PERFORMANCE_COUNTER_SCOPE_COMMAND_KHR" comment="Backwards-compatible alias containing a typo"/>
+ </enums>
+ <enums name="VkMemoryDecompressionMethodFlagBitsNV" type="bitmask" bitwidth="64">
+ <enum bitpos="0" name="VK_MEMORY_DECOMPRESSION_METHOD_GDEFLATE_1_0_BIT_NV"/>
</enums>
<enums name="VkPerformanceCounterUnitKHR" type="enum">
<enum value="0" name="VK_PERFORMANCE_COUNTER_UNIT_GENERIC_KHR"/>
@@ -7446,12 +9169,17 @@ typedef void <name>CAMetalLayer</name>;
</enums>
<enums name="VkPipelineCompilerControlFlagBitsAMD" type="bitmask">
</enums>
- <enums name="VkToolPurposeFlagBitsEXT" type="bitmask">
- <enum bitpos="0" name="VK_TOOL_PURPOSE_VALIDATION_BIT_EXT"/>
- <enum bitpos="1" name="VK_TOOL_PURPOSE_PROFILING_BIT_EXT"/>
- <enum bitpos="2" name="VK_TOOL_PURPOSE_TRACING_BIT_EXT"/>
- <enum bitpos="3" name="VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT_EXT"/>
- <enum bitpos="4" name="VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT_EXT"/>
+ <enums name="VkToolPurposeFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_TOOL_PURPOSE_VALIDATION_BIT"/>
+ <enum name="VK_TOOL_PURPOSE_VALIDATION_BIT_EXT" alias="VK_TOOL_PURPOSE_VALIDATION_BIT"/>
+ <enum bitpos="1" name="VK_TOOL_PURPOSE_PROFILING_BIT"/>
+ <enum name="VK_TOOL_PURPOSE_PROFILING_BIT_EXT" alias="VK_TOOL_PURPOSE_PROFILING_BIT"/>
+ <enum bitpos="2" name="VK_TOOL_PURPOSE_TRACING_BIT"/>
+ <enum name="VK_TOOL_PURPOSE_TRACING_BIT_EXT" alias="VK_TOOL_PURPOSE_TRACING_BIT"/>
+ <enum bitpos="3" name="VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT"/>
+ <enum name="VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT_EXT" alias="VK_TOOL_PURPOSE_ADDITIONAL_FEATURES_BIT"/>
+ <enum bitpos="4" name="VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT"/>
+ <enum name="VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT_EXT" alias="VK_TOOL_PURPOSE_MODIFYING_FEATURES_BIT"/>
</enums>
<enums name="VkFragmentShadingRateCombinerOpKHR" type="enum">
<enum value="0" name="VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR"/>
@@ -7478,61 +9206,125 @@ typedef void <name>CAMetalLayer</name>;
<enum value="0" name="VK_FRAGMENT_SHADING_RATE_TYPE_FRAGMENT_SIZE_NV"/>
<enum value="1" name="VK_FRAGMENT_SHADING_RATE_TYPE_ENUMS_NV"/>
</enums>
- <enums name="VkAccessFlagBits2KHR" type="bitmask" bitwidth="64">
- <enum value="0" name="VK_ACCESS_2_NONE_KHR"/>
- <enum bitpos="0" name="VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT_KHR"/>
- <enum bitpos="1" name="VK_ACCESS_2_INDEX_READ_BIT_KHR"/>
- <enum bitpos="2" name="VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT_KHR"/>
- <enum bitpos="3" name="VK_ACCESS_2_UNIFORM_READ_BIT_KHR"/>
- <enum bitpos="4" name="VK_ACCESS_2_INPUT_ATTACHMENT_READ_BIT_KHR"/>
- <enum bitpos="5" name="VK_ACCESS_2_SHADER_READ_BIT_KHR"/>
- <enum bitpos="6" name="VK_ACCESS_2_SHADER_WRITE_BIT_KHR"/>
- <enum bitpos="7" name="VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT_KHR"/>
- <enum bitpos="8" name="VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR"/>
- <enum bitpos="9" name="VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT_KHR"/>
- <enum bitpos="10" name="VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR"/>
- <enum bitpos="11" name="VK_ACCESS_2_TRANSFER_READ_BIT_KHR"/>
- <enum bitpos="12" name="VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR"/>
- <enum bitpos="13" name="VK_ACCESS_2_HOST_READ_BIT_KHR"/>
- <enum bitpos="14" name="VK_ACCESS_2_HOST_WRITE_BIT_KHR"/>
- <enum bitpos="15" name="VK_ACCESS_2_MEMORY_READ_BIT_KHR"/>
- <enum bitpos="16" name="VK_ACCESS_2_MEMORY_WRITE_BIT_KHR"/>
- <!-- bitpos 17-31 are specified by extensions to the original VkAccessFlagBits enum -->
- <enum bitpos="32" name="VK_ACCESS_2_SHADER_SAMPLED_READ_BIT_KHR"/>
- <enum bitpos="33" name="VK_ACCESS_2_SHADER_STORAGE_READ_BIT_KHR"/>
- <enum bitpos="34" name="VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT_KHR"/>
+ <enums name="VkSubpassMergeStatusEXT" type="enum">
+ <enum value="0" name="VK_SUBPASS_MERGE_STATUS_MERGED_EXT"/>
+ <enum value="1" name="VK_SUBPASS_MERGE_STATUS_DISALLOWED_EXT"/>
+ <enum value="2" name="VK_SUBPASS_MERGE_STATUS_NOT_MERGED_SIDE_EFFECTS_EXT"/>
+ <enum value="3" name="VK_SUBPASS_MERGE_STATUS_NOT_MERGED_SAMPLES_MISMATCH_EXT"/>
+ <enum value="4" name="VK_SUBPASS_MERGE_STATUS_NOT_MERGED_VIEWS_MISMATCH_EXT"/>
+ <enum value="5" name="VK_SUBPASS_MERGE_STATUS_NOT_MERGED_ALIASING_EXT"/>
+ <enum value="6" name="VK_SUBPASS_MERGE_STATUS_NOT_MERGED_DEPENDENCIES_EXT"/>
+ <enum value="7" name="VK_SUBPASS_MERGE_STATUS_NOT_MERGED_INCOMPATIBLE_INPUT_ATTACHMENT_EXT"/>
+ <enum value="8" name="VK_SUBPASS_MERGE_STATUS_NOT_MERGED_TOO_MANY_ATTACHMENTS_EXT"/>
+ <enum value="9" name="VK_SUBPASS_MERGE_STATUS_NOT_MERGED_INSUFFICIENT_STORAGE_EXT"/>
+ <enum value="10" name="VK_SUBPASS_MERGE_STATUS_NOT_MERGED_DEPTH_STENCIL_COUNT_EXT"/>
+ <enum value="11" name="VK_SUBPASS_MERGE_STATUS_NOT_MERGED_RESOLVE_ATTACHMENT_REUSE_EXT"/>
+ <enum value="12" name="VK_SUBPASS_MERGE_STATUS_NOT_MERGED_SINGLE_SUBPASS_EXT"/>
+ <enum value="13" name="VK_SUBPASS_MERGE_STATUS_NOT_MERGED_UNSPECIFIED_EXT"/>
+ </enums>
+ <enums name="VkAccessFlagBits2" type="bitmask" bitwidth="64">
+ <enum value="0" name="VK_ACCESS_2_NONE"/>
+ <enum name="VK_ACCESS_2_NONE_KHR" alias="VK_ACCESS_2_NONE"/>
+ <enum bitpos="0" name="VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT"/>
+ <enum name="VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT_KHR" alias="VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT"/>
+ <enum bitpos="1" name="VK_ACCESS_2_INDEX_READ_BIT"/>
+ <enum name="VK_ACCESS_2_INDEX_READ_BIT_KHR" alias="VK_ACCESS_2_INDEX_READ_BIT"/>
+ <enum bitpos="2" name="VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT"/>
+ <enum name="VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT_KHR" alias="VK_ACCESS_2_VERTEX_ATTRIBUTE_READ_BIT"/>
+ <enum bitpos="3" name="VK_ACCESS_2_UNIFORM_READ_BIT"/>
+ <enum name="VK_ACCESS_2_UNIFORM_READ_BIT_KHR" alias="VK_ACCESS_2_UNIFORM_READ_BIT"/>
+ <enum bitpos="4" name="VK_ACCESS_2_INPUT_ATTACHMENT_READ_BIT"/>
+ <enum name="VK_ACCESS_2_INPUT_ATTACHMENT_READ_BIT_KHR" alias="VK_ACCESS_2_INPUT_ATTACHMENT_READ_BIT"/>
+ <enum bitpos="5" name="VK_ACCESS_2_SHADER_READ_BIT"/>
+ <enum name="VK_ACCESS_2_SHADER_READ_BIT_KHR" alias="VK_ACCESS_2_SHADER_READ_BIT"/>
+ <enum bitpos="6" name="VK_ACCESS_2_SHADER_WRITE_BIT"/>
+ <enum name="VK_ACCESS_2_SHADER_WRITE_BIT_KHR" alias="VK_ACCESS_2_SHADER_WRITE_BIT"/>
+ <enum bitpos="7" name="VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT"/>
+ <enum name="VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT_KHR" alias="VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT"/>
+ <enum bitpos="8" name="VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT"/>
+ <enum name="VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT_KHR" alias="VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT"/>
+ <enum bitpos="9" name="VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT"/>
+ <enum name="VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT_KHR" alias="VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT"/>
+ <enum bitpos="10" name="VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT"/>
+ <enum name="VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT_KHR" alias="VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT"/>
+ <enum bitpos="11" name="VK_ACCESS_2_TRANSFER_READ_BIT"/>
+ <enum name="VK_ACCESS_2_TRANSFER_READ_BIT_KHR" alias="VK_ACCESS_2_TRANSFER_READ_BIT"/>
+ <enum bitpos="12" name="VK_ACCESS_2_TRANSFER_WRITE_BIT"/>
+ <enum name="VK_ACCESS_2_TRANSFER_WRITE_BIT_KHR" alias="VK_ACCESS_2_TRANSFER_WRITE_BIT"/>
+ <enum bitpos="13" name="VK_ACCESS_2_HOST_READ_BIT"/>
+ <enum name="VK_ACCESS_2_HOST_READ_BIT_KHR" alias="VK_ACCESS_2_HOST_READ_BIT"/>
+ <enum bitpos="14" name="VK_ACCESS_2_HOST_WRITE_BIT"/>
+ <enum name="VK_ACCESS_2_HOST_WRITE_BIT_KHR" alias="VK_ACCESS_2_HOST_WRITE_BIT"/>
+ <enum bitpos="15" name="VK_ACCESS_2_MEMORY_READ_BIT"/>
+ <enum name="VK_ACCESS_2_MEMORY_READ_BIT_KHR" alias="VK_ACCESS_2_MEMORY_READ_BIT"/>
+ <enum bitpos="16" name="VK_ACCESS_2_MEMORY_WRITE_BIT"/>
+ <enum name="VK_ACCESS_2_MEMORY_WRITE_BIT_KHR" alias="VK_ACCESS_2_MEMORY_WRITE_BIT"/>
+ <comment>bitpos 17-31 are specified by extensions to the original VkAccessFlagBits enum</comment>
+ <enum bitpos="32" name="VK_ACCESS_2_SHADER_SAMPLED_READ_BIT"/>
+ <enum name="VK_ACCESS_2_SHADER_SAMPLED_READ_BIT_KHR" alias="VK_ACCESS_2_SHADER_SAMPLED_READ_BIT"/>
+ <enum bitpos="33" name="VK_ACCESS_2_SHADER_STORAGE_READ_BIT"/>
+ <enum name="VK_ACCESS_2_SHADER_STORAGE_READ_BIT_KHR" alias="VK_ACCESS_2_SHADER_STORAGE_READ_BIT"/>
+ <enum bitpos="34" name="VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT"/>
+ <enum name="VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT_KHR" alias="VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT"/>
</enums>
- <enums name="VkPipelineStageFlagBits2KHR" type="bitmask" bitwidth="64">
- <enum value="0" name="VK_PIPELINE_STAGE_2_NONE_KHR"/>
- <enum bitpos="0" name="VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR"/>
- <enum bitpos="1" name="VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT_KHR"/>
- <enum bitpos="2" name="VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT_KHR"/>
- <enum bitpos="3" name="VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT_KHR"/>
- <enum bitpos="4" name="VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT_KHR"/>
- <enum bitpos="5" name="VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT_KHR"/>
- <enum bitpos="6" name="VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT_KHR"/>
- <enum bitpos="7" name="VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT_KHR"/>
- <enum bitpos="8" name="VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR"/>
- <enum bitpos="9" name="VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR"/>
- <enum bitpos="10" name="VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR"/>
- <enum bitpos="11" name="VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT_KHR"/>
- <enum bitpos="12" name="VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT_KHR"/>
- <enum name="VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR" alias="VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT_KHR"/>
- <enum bitpos="13" name="VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR"/>
- <enum bitpos="14" name="VK_PIPELINE_STAGE_2_HOST_BIT_KHR"/>
- <enum bitpos="15" name="VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT_KHR"/>
- <enum bitpos="16" name="VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR"/>
- <!-- bitpos 17-31 are specified by extensions to the original VkPipelineStageFlagBits enum -->
- <enum bitpos="32" name="VK_PIPELINE_STAGE_2_COPY_BIT_KHR"/>
- <enum bitpos="33" name="VK_PIPELINE_STAGE_2_RESOLVE_BIT_KHR"/>
- <enum bitpos="34" name="VK_PIPELINE_STAGE_2_BLIT_BIT_KHR"/>
- <enum bitpos="35" name="VK_PIPELINE_STAGE_2_CLEAR_BIT_KHR"/>
- <enum bitpos="36" name="VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT_KHR"/>
- <enum bitpos="37" name="VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT_KHR"/>
- <enum bitpos="38" name="VK_PIPELINE_STAGE_2_PRE_RASTERIZATION_SHADERS_BIT_KHR"/>
+ <enums name="VkPipelineStageFlagBits2" type="bitmask" bitwidth="64">
+ <enum value="0" name="VK_PIPELINE_STAGE_2_NONE"/>
+ <enum name="VK_PIPELINE_STAGE_2_NONE_KHR" alias="VK_PIPELINE_STAGE_2_NONE"/>
+ <enum bitpos="0" name="VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT"/>
+ <enum name="VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT_KHR" alias="VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT"/>
+ <enum bitpos="1" name="VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT"/>
+ <enum name="VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT_KHR" alias="VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT"/>
+ <enum bitpos="2" name="VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT"/>
+ <enum name="VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT_KHR" alias="VK_PIPELINE_STAGE_2_VERTEX_INPUT_BIT"/>
+ <enum bitpos="3" name="VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT"/>
+ <enum name="VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT_KHR" alias="VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT"/>
+ <enum bitpos="4" name="VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT"/>
+ <enum name="VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT_KHR" alias="VK_PIPELINE_STAGE_2_TESSELLATION_CONTROL_SHADER_BIT"/>
+ <enum bitpos="5" name="VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT"/>
+ <enum name="VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT_KHR" alias="VK_PIPELINE_STAGE_2_TESSELLATION_EVALUATION_SHADER_BIT"/>
+ <enum bitpos="6" name="VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT"/>
+ <enum name="VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT_KHR" alias="VK_PIPELINE_STAGE_2_GEOMETRY_SHADER_BIT"/>
+ <enum bitpos="7" name="VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT"/>
+ <enum name="VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT_KHR" alias="VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT"/>
+ <enum bitpos="8" name="VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT"/>
+ <enum name="VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT_KHR" alias="VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT"/>
+ <enum bitpos="9" name="VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT"/>
+ <enum name="VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT_KHR" alias="VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT"/>
+ <enum bitpos="10" name="VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT"/>
+ <enum name="VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR" alias="VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT"/>
+ <enum bitpos="11" name="VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT"/>
+ <enum name="VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT_KHR" alias="VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT"/>
+ <enum bitpos="12" name="VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT"/>
+ <enum name="VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT_KHR" alias="VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT"/>
+ <enum name="VK_PIPELINE_STAGE_2_TRANSFER_BIT" alias="VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT_KHR"/>
+ <enum name="VK_PIPELINE_STAGE_2_TRANSFER_BIT_KHR" alias="VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT"/>
+ <enum bitpos="13" name="VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT"/>
+ <enum name="VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT_KHR" alias="VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT"/>
+ <enum bitpos="14" name="VK_PIPELINE_STAGE_2_HOST_BIT"/>
+ <enum name="VK_PIPELINE_STAGE_2_HOST_BIT_KHR" alias="VK_PIPELINE_STAGE_2_HOST_BIT"/>
+ <enum bitpos="15" name="VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT"/>
+ <enum name="VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT_KHR" alias="VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT"/>
+ <enum bitpos="16" name="VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT"/>
+ <enum name="VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT_KHR" alias="VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT"/>
+ <comment>bitpos 17-31 are specified by extensions to the original VkPipelineStageFlagBits enum</comment>
+ <enum bitpos="32" name="VK_PIPELINE_STAGE_2_COPY_BIT"/>
+ <enum name="VK_PIPELINE_STAGE_2_COPY_BIT_KHR" alias="VK_PIPELINE_STAGE_2_COPY_BIT"/>
+ <enum bitpos="33" name="VK_PIPELINE_STAGE_2_RESOLVE_BIT"/>
+ <enum name="VK_PIPELINE_STAGE_2_RESOLVE_BIT_KHR" alias="VK_PIPELINE_STAGE_2_RESOLVE_BIT"/>
+ <enum bitpos="34" name="VK_PIPELINE_STAGE_2_BLIT_BIT"/>
+ <enum name="VK_PIPELINE_STAGE_2_BLIT_BIT_KHR" alias="VK_PIPELINE_STAGE_2_BLIT_BIT"/>
+ <enum bitpos="35" name="VK_PIPELINE_STAGE_2_CLEAR_BIT"/>
+ <enum name="VK_PIPELINE_STAGE_2_CLEAR_BIT_KHR" alias="VK_PIPELINE_STAGE_2_CLEAR_BIT"/>
+ <enum bitpos="36" name="VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT"/>
+ <enum name="VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT_KHR" alias="VK_PIPELINE_STAGE_2_INDEX_INPUT_BIT"/>
+ <enum bitpos="37" name="VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT"/>
+ <enum name="VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT_KHR" alias="VK_PIPELINE_STAGE_2_VERTEX_ATTRIBUTE_INPUT_BIT"/>
+ <enum bitpos="38" name="VK_PIPELINE_STAGE_2_PRE_RASTERIZATION_SHADERS_BIT"/>
+ <enum name="VK_PIPELINE_STAGE_2_PRE_RASTERIZATION_SHADERS_BIT_KHR" alias="VK_PIPELINE_STAGE_2_PRE_RASTERIZATION_SHADERS_BIT"/>
</enums>
- <enums name="VkSubmitFlagBitsKHR" type="bitmask">
- <enum bitpos="0" name="VK_SUBMIT_PROTECTED_BIT_KHR"/>
+ <enums name="VkSubmitFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_SUBMIT_PROTECTED_BIT"/>
+ <enum name="VK_SUBMIT_PROTECTED_BIT_KHR" alias="VK_SUBMIT_PROTECTED_BIT"/>
</enums>
<enums name="VkEventCreateFlagBits" type="bitmask">
</enums>
@@ -7547,12 +9339,39 @@ typedef void <name>CAMetalLayer</name>;
<enum value="1" name="VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_MATRIX_MOTION_NV"/>
<enum value="2" name="VK_ACCELERATION_STRUCTURE_MOTION_INSTANCE_TYPE_SRT_MOTION_NV"/>
</enums>
+ <enums name="VkPipelineColorBlendStateCreateFlagBits" type="bitmask">
+ </enums>
+ <enums name="VkPipelineDepthStencilStateCreateFlagBits" type="bitmask">
+ </enums>
+ <enums name="VkGraphicsPipelineLibraryFlagBitsEXT" type="bitmask">
+ <enum bitpos="0" name="VK_GRAPHICS_PIPELINE_LIBRARY_VERTEX_INPUT_INTERFACE_BIT_EXT"/>
+ <enum bitpos="1" name="VK_GRAPHICS_PIPELINE_LIBRARY_PRE_RASTERIZATION_SHADERS_BIT_EXT"/>
+ <enum bitpos="2" name="VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_SHADER_BIT_EXT"/>
+ <enum bitpos="3" name="VK_GRAPHICS_PIPELINE_LIBRARY_FRAGMENT_OUTPUT_INTERFACE_BIT_EXT"/>
+ </enums>
+ <enums name="VkDeviceAddressBindingFlagBitsEXT" type="bitmask">
+ <enum bitpos="0" name="VK_DEVICE_ADDRESS_BINDING_INTERNAL_OBJECT_BIT_EXT"/>
+ </enums>
+ <enums name="VkDeviceAddressBindingTypeEXT" type="enum">
+ <enum value="0" name="VK_DEVICE_ADDRESS_BINDING_TYPE_BIND_EXT"/>
+ <enum value="1" name="VK_DEVICE_ADDRESS_BINDING_TYPE_UNBIND_EXT"/>
+ </enums>
+ <enums name="VkPresentScalingFlagBitsEXT" type="bitmask">
+ <enum bitpos="0" name="VK_PRESENT_SCALING_ONE_TO_ONE_BIT_EXT"/>
+ <enum bitpos="1" name="VK_PRESENT_SCALING_ASPECT_RATIO_STRETCH_BIT_EXT"/>
+ <enum bitpos="2" name="VK_PRESENT_SCALING_STRETCH_BIT_EXT"/>
+ </enums>
+ <enums name="VkPresentGravityFlagBitsEXT" type="bitmask">
+ <enum bitpos="0" name="VK_PRESENT_GRAVITY_MIN_BIT_EXT"/>
+ <enum bitpos="1" name="VK_PRESENT_GRAVITY_MAX_BIT_EXT"/>
+ <enum bitpos="2" name="VK_PRESENT_GRAVITY_CENTERED_BIT_EXT"/>
+ </enums>
<enums name="VkVideoCodecOperationFlagBitsKHR" type="bitmask">
- <enum value="0" name="VK_VIDEO_CODEC_OPERATION_INVALID_BIT_KHR"/>
+ <enum value="0" name="VK_VIDEO_CODEC_OPERATION_NONE_KHR"/>
</enums>
<enums name="VkVideoChromaSubsamplingFlagBitsKHR" type="bitmask" comment="Vulkan video chroma subsampling definitions">
- <enum value="0" name="VK_VIDEO_CHROMA_SUBSAMPLING_INVALID_BIT_KHR"/>
+ <enum value="0" name="VK_VIDEO_CHROMA_SUBSAMPLING_INVALID_KHR"/>
<enum bitpos="0" name="VK_VIDEO_CHROMA_SUBSAMPLING_MONOCHROME_BIT_KHR"/>
<enum bitpos="1" name="VK_VIDEO_CHROMA_SUBSAMPLING_420_BIT_KHR"/>
<enum bitpos="2" name="VK_VIDEO_CHROMA_SUBSAMPLING_422_BIT_KHR"/>
@@ -7564,27 +9383,19 @@ typedef void <name>CAMetalLayer</name>;
<enum bitpos="2" name="VK_VIDEO_COMPONENT_BIT_DEPTH_10_BIT_KHR"/>
<enum bitpos="4" name="VK_VIDEO_COMPONENT_BIT_DEPTH_12_BIT_KHR"/>
</enums>
- <enums name="VkVideoCapabilitiesFlagBitsKHR" type="bitmask">
- <enum bitpos="0" name="VK_VIDEO_CAPABILITIES_PROTECTED_CONTENT_BIT_KHR"/>
- <enum bitpos="1" name="VK_VIDEO_CAPABILITIES_SEPARATE_REFERENCE_IMAGES_BIT_KHR"/>
+ <enums name="VkVideoCapabilityFlagBitsKHR" type="bitmask">
+ <enum bitpos="0" name="VK_VIDEO_CAPABILITY_PROTECTED_CONTENT_BIT_KHR"/>
+ <enum bitpos="1" name="VK_VIDEO_CAPABILITY_SEPARATE_REFERENCE_IMAGES_BIT_KHR"/>
</enums>
<enums name="VkVideoSessionCreateFlagBitsKHR" type="bitmask">
- <enum value="0" name="VK_VIDEO_SESSION_CREATE_DEFAULT_KHR"/>
<enum bitpos="0" name="VK_VIDEO_SESSION_CREATE_PROTECTED_CONTENT_BIT_KHR"/>
</enums>
- <enums name="VkVideoCodingQualityPresetFlagBitsKHR" type="bitmask">
- <enum value="0" name="VK_VIDEO_CODING_QUALITY_PRESET_DEFAULT_BIT_KHR"/>
- <enum bitpos="0" name="VK_VIDEO_CODING_QUALITY_PRESET_NORMAL_BIT_KHR"/>
- <enum bitpos="1" name="VK_VIDEO_CODING_QUALITY_PRESET_POWER_BIT_KHR"/>
- <enum bitpos="2" name="VK_VIDEO_CODING_QUALITY_PRESET_QUALITY_BIT_KHR"/>
- </enums>
- <enums name="VkVideoDecodeH264FieldLayoutFlagBitsEXT" type="bitmask">
- <enum value="0" name="VK_VIDEO_DECODE_H264_PROGRESSIVE_PICTURES_ONLY_EXT"/>
- <enum bitpos="0" name="VK_VIDEO_DECODE_H264_FIELD_LAYOUT_LINE_INTERLACED_PLANE_BIT_EXT"/>
- <enum bitpos="1" name="VK_VIDEO_DECODE_H264_FIELD_LAYOUT_SEPARATE_INTERLACED_PLANE_BIT_EXT"/>
+ <enums name="VkVideoDecodeH264PictureLayoutFlagBitsKHR" type="bitmask">
+ <enum value="0" name="VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_PROGRESSIVE_KHR"/>
+ <enum bitpos="0" name="VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_INTERLACED_INTERLEAVED_LINES_BIT_KHR"/>
+ <enum bitpos="1" name="VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_INTERLACED_SEPARATE_PLANES_BIT_KHR"/>
</enums>
<enums name="VkVideoCodingControlFlagBitsKHR" type="bitmask">
- <enum value="0" name="VK_VIDEO_CODING_CONTROL_DEFAULT_KHR"/>
<enum bitpos="0" name="VK_VIDEO_CODING_CONTROL_RESET_BIT_KHR"/>
</enums>
<enums name="VkQueryResultStatusKHR" type="enum">
@@ -7592,35 +9403,70 @@ typedef void <name>CAMetalLayer</name>;
<enum value="0" name="VK_QUERY_RESULT_STATUS_NOT_READY_KHR"/>
<enum value="1" name="VK_QUERY_RESULT_STATUS_COMPLETE_KHR"/>
</enums>
- <enums name="VkVideoDecodeFlagBitsKHR" type="bitmask">
- <enum value="0" name="VK_VIDEO_DECODE_DEFAULT_KHR"/>
- <enum bitpos="0" name="VK_VIDEO_DECODE_RESERVED_0_BIT_KHR"/>
+ <enums name="VkVideoDecodeUsageFlagBitsKHR" type="bitmask">
+ <enum value="0" name="VK_VIDEO_DECODE_USAGE_DEFAULT_KHR"/>
+ <enum bitpos="0" name="VK_VIDEO_DECODE_USAGE_TRANSCODING_BIT_KHR"/>
+ <enum bitpos="1" name="VK_VIDEO_DECODE_USAGE_OFFLINE_BIT_KHR"/>
+ <enum bitpos="2" name="VK_VIDEO_DECODE_USAGE_STREAMING_BIT_KHR"/>
+ </enums>
+ <enums name="VkVideoDecodeCapabilityFlagBitsKHR" type="bitmask">
+ <enum bitpos="0" name="VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_COINCIDE_BIT_KHR"/>
+ <enum bitpos="1" name="VK_VIDEO_DECODE_CAPABILITY_DPB_AND_OUTPUT_DISTINCT_BIT_KHR"/>
+ </enums>
+ <enums name="VkVideoEncodeUsageFlagBitsKHR" type="bitmask">
+ <enum value="0" name="VK_VIDEO_ENCODE_USAGE_DEFAULT_KHR"/>
+ <enum bitpos="0" name="VK_VIDEO_ENCODE_USAGE_TRANSCODING_BIT_KHR"/>
+ <enum bitpos="1" name="VK_VIDEO_ENCODE_USAGE_STREAMING_BIT_KHR"/>
+ <enum bitpos="2" name="VK_VIDEO_ENCODE_USAGE_RECORDING_BIT_KHR"/>
+ <enum bitpos="3" name="VK_VIDEO_ENCODE_USAGE_CONFERENCING_BIT_KHR"/>
+ </enums>
+ <enums name="VkVideoEncodeContentFlagBitsKHR" type="bitmask">
+ <enum value="0" name="VK_VIDEO_ENCODE_CONTENT_DEFAULT_KHR"/>
+ <enum bitpos="0" name="VK_VIDEO_ENCODE_CONTENT_CAMERA_BIT_KHR"/>
+ <enum bitpos="1" name="VK_VIDEO_ENCODE_CONTENT_DESKTOP_BIT_KHR"/>
+ <enum bitpos="2" name="VK_VIDEO_ENCODE_CONTENT_RENDERED_BIT_KHR"/>
</enums>
- <enums name="VkVideoEncodeFlagBitsKHR" type="bitmask">
- <enum value="0" name="VK_VIDEO_ENCODE_DEFAULT_KHR"/>
- <enum bitpos="0" name="VK_VIDEO_ENCODE_RESERVED_0_BIT_KHR"/>
+ <enums name="VkVideoEncodeTuningModeKHR" type="enum">
+ <enum value="0" name="VK_VIDEO_ENCODE_TUNING_MODE_DEFAULT_KHR"/>
+ <enum value="1" name="VK_VIDEO_ENCODE_TUNING_MODE_HIGH_QUALITY_KHR"/>
+ <enum value="2" name="VK_VIDEO_ENCODE_TUNING_MODE_LOW_LATENCY_KHR"/>
+ <enum value="3" name="VK_VIDEO_ENCODE_TUNING_MODE_ULTRA_LOW_LATENCY_KHR"/>
+ <enum value="4" name="VK_VIDEO_ENCODE_TUNING_MODE_LOSSLESS_KHR"/>
</enums>
- <enums name="VkVideoEncodeRateControlFlagBitsKHR" type="bitmask">
- <enum value="0" name="VK_VIDEO_ENCODE_RATE_CONTROL_DEFAULT_KHR"/>
- <enum bitpos="0" name="VK_VIDEO_ENCODE_RATE_CONTROL_RESET_BIT_KHR"/>
+ <enums name="VkVideoEncodeCapabilityFlagBitsKHR" type="bitmask">
+ <enum bitpos="0" name="VK_VIDEO_ENCODE_CAPABILITY_PRECEDING_EXTERNALLY_ENCODED_BYTES_BIT_KHR"/>
</enums>
<enums name="VkVideoEncodeRateControlModeFlagBitsKHR" type="bitmask">
<enum value="0" name="VK_VIDEO_ENCODE_RATE_CONTROL_MODE_NONE_BIT_KHR"/>
<enum value="1" name="VK_VIDEO_ENCODE_RATE_CONTROL_MODE_CBR_BIT_KHR"/>
<enum value="2" name="VK_VIDEO_ENCODE_RATE_CONTROL_MODE_VBR_BIT_KHR"/>
</enums>
- <enums name="VkVideoEncodeH264CapabilitiesFlagBitsEXT" type="bitmask">
- <enum bitpos="0" name="VK_VIDEO_ENCODE_H264_CAPABILITY_CABAC_BIT_EXT"/>
- <enum bitpos="1" name="VK_VIDEO_ENCODE_H264_CAPABILITY_CAVLC_BIT_EXT"/>
- <enum bitpos="2" name="VK_VIDEO_ENCODE_H264_CAPABILITY_WEIGHTED_BI_PRED_IMPLICIT_BIT_EXT"/>
- <enum bitpos="3" name="VK_VIDEO_ENCODE_H264_CAPABILITY_TRANSFORM_8X8_BIT_EXT"/>
- <enum bitpos="4" name="VK_VIDEO_ENCODE_H264_CAPABILITY_CHROMA_QP_OFFSET_BIT_EXT"/>
- <enum bitpos="5" name="VK_VIDEO_ENCODE_H264_CAPABILITY_SECOND_CHROMA_QP_OFFSET_BIT_EXT"/>
- <enum bitpos="6" name="VK_VIDEO_ENCODE_H264_CAPABILITY_DEBLOCKING_FILTER_DISABLED_BIT_EXT"/>
- <enum bitpos="7" name="VK_VIDEO_ENCODE_H264_CAPABILITY_DEBLOCKING_FILTER_ENABLED_BIT_EXT"/>
- <enum bitpos="8" name="VK_VIDEO_ENCODE_H264_CAPABILITY_DEBLOCKING_FILTER_PARTIAL_BIT_EXT"/>
- <enum bitpos="9" name="VK_VIDEO_ENCODE_H264_CAPABILITY_MULTIPLE_SLICE_PER_FRAME_BIT_EXT"/>
- <enum bitpos="10" name="VK_VIDEO_ENCODE_H264_CAPABILITY_EVENLY_DISTRIBUTED_SLICE_SIZE_BIT_EXT"/>
+ <enums name="VkVideoEncodeH264CapabilityFlagBitsEXT" type="bitmask">
+ <enum bitpos="0" name="VK_VIDEO_ENCODE_H264_CAPABILITY_DIRECT_8X8_INFERENCE_ENABLED_BIT_EXT"/>
+ <enum bitpos="1" name="VK_VIDEO_ENCODE_H264_CAPABILITY_DIRECT_8X8_INFERENCE_DISABLED_BIT_EXT"/>
+ <enum bitpos="2" name="VK_VIDEO_ENCODE_H264_CAPABILITY_SEPARATE_COLOUR_PLANE_BIT_EXT"/>
+ <enum bitpos="3" name="VK_VIDEO_ENCODE_H264_CAPABILITY_QPPRIME_Y_ZERO_TRANSFORM_BYPASS_BIT_EXT"/>
+ <enum bitpos="4" name="VK_VIDEO_ENCODE_H264_CAPABILITY_SCALING_LISTS_BIT_EXT"/>
+ <enum bitpos="5" name="VK_VIDEO_ENCODE_H264_CAPABILITY_HRD_COMPLIANCE_BIT_EXT"/>
+ <enum bitpos="6" name="VK_VIDEO_ENCODE_H264_CAPABILITY_CHROMA_QP_OFFSET_BIT_EXT"/>
+ <enum bitpos="7" name="VK_VIDEO_ENCODE_H264_CAPABILITY_SECOND_CHROMA_QP_OFFSET_BIT_EXT"/>
+ <enum bitpos="8" name="VK_VIDEO_ENCODE_H264_CAPABILITY_PIC_INIT_QP_MINUS26_BIT_EXT"/>
+ <enum bitpos="9" name="VK_VIDEO_ENCODE_H264_CAPABILITY_WEIGHTED_PRED_BIT_EXT"/>
+ <enum bitpos="10" name="VK_VIDEO_ENCODE_H264_CAPABILITY_WEIGHTED_BIPRED_EXPLICIT_BIT_EXT"/>
+ <enum bitpos="11" name="VK_VIDEO_ENCODE_H264_CAPABILITY_WEIGHTED_BIPRED_IMPLICIT_BIT_EXT"/>
+ <enum bitpos="12" name="VK_VIDEO_ENCODE_H264_CAPABILITY_WEIGHTED_PRED_NO_TABLE_BIT_EXT"/>
+ <enum bitpos="13" name="VK_VIDEO_ENCODE_H264_CAPABILITY_TRANSFORM_8X8_BIT_EXT"/>
+ <enum bitpos="14" name="VK_VIDEO_ENCODE_H264_CAPABILITY_CABAC_BIT_EXT"/>
+ <enum bitpos="15" name="VK_VIDEO_ENCODE_H264_CAPABILITY_CAVLC_BIT_EXT"/>
+ <enum bitpos="16" name="VK_VIDEO_ENCODE_H264_CAPABILITY_DEBLOCKING_FILTER_DISABLED_BIT_EXT"/>
+ <enum bitpos="17" name="VK_VIDEO_ENCODE_H264_CAPABILITY_DEBLOCKING_FILTER_ENABLED_BIT_EXT"/>
+ <enum bitpos="18" name="VK_VIDEO_ENCODE_H264_CAPABILITY_DEBLOCKING_FILTER_PARTIAL_BIT_EXT"/>
+ <enum bitpos="19" name="VK_VIDEO_ENCODE_H264_CAPABILITY_DISABLE_DIRECT_SPATIAL_MV_PRED_BIT_EXT"/>
+ <enum bitpos="20" name="VK_VIDEO_ENCODE_H264_CAPABILITY_MULTIPLE_SLICE_PER_FRAME_BIT_EXT"/>
+ <enum bitpos="21" name="VK_VIDEO_ENCODE_H264_CAPABILITY_SLICE_MB_COUNT_BIT_EXT"/>
+ <enum bitpos="22" name="VK_VIDEO_ENCODE_H264_CAPABILITY_ROW_UNALIGNED_SLICE_BIT_EXT"/>
+ <enum bitpos="23" name="VK_VIDEO_ENCODE_H264_CAPABILITY_DIFFERENT_SLICE_TYPE_BIT_EXT"/>
+ <enum bitpos="24" name="VK_VIDEO_ENCODE_H264_CAPABILITY_B_FRAME_IN_L1_LIST_BIT_EXT"/>
</enums>
<enums name="VkVideoEncodeH264InputModeFlagBitsEXT" type="bitmask">
<enum bitpos="0" name="VK_VIDEO_ENCODE_H264_INPUT_MODE_FRAME_BIT_EXT"/>
@@ -7632,11 +9478,277 @@ typedef void <name>CAMetalLayer</name>;
<enum bitpos="1" name="VK_VIDEO_ENCODE_H264_OUTPUT_MODE_SLICE_BIT_EXT"/>
<enum bitpos="2" name="VK_VIDEO_ENCODE_H264_OUTPUT_MODE_NON_VCL_BIT_EXT"/>
</enums>
- <enums name="VkVideoEncodeH264CreateFlagBitsEXT" type="bitmask">
- <enum value="0" name="VK_VIDEO_ENCODE_H264_CREATE_DEFAULT_EXT"/>
- <enum bitpos="0" name="VK_VIDEO_ENCODE_H264_CREATE_RESERVED_0_BIT_EXT"/>
+ <enums name="VkVideoEncodeH264RateControlStructureEXT" type="enum">
+ <enum value="0" name="VK_VIDEO_ENCODE_H264_RATE_CONTROL_STRUCTURE_UNKNOWN_EXT"/>
+ <enum value="1" name="VK_VIDEO_ENCODE_H264_RATE_CONTROL_STRUCTURE_FLAT_EXT"/>
+ <enum value="2" name="VK_VIDEO_ENCODE_H264_RATE_CONTROL_STRUCTURE_DYADIC_EXT"/>
+ </enums>
+ <enums name="VkImageFormatConstraintsFlagBitsFUCHSIA" type="bitmask">
+ </enums>
+ <enums name="VkImageConstraintsInfoFlagBitsFUCHSIA" type="bitmask">
+ <enum bitpos="0" name="VK_IMAGE_CONSTRAINTS_INFO_CPU_READ_RARELY_FUCHSIA"/>
+ <enum bitpos="1" name="VK_IMAGE_CONSTRAINTS_INFO_CPU_READ_OFTEN_FUCHSIA"/>
+ <enum bitpos="2" name="VK_IMAGE_CONSTRAINTS_INFO_CPU_WRITE_RARELY_FUCHSIA"/>
+ <enum bitpos="3" name="VK_IMAGE_CONSTRAINTS_INFO_CPU_WRITE_OFTEN_FUCHSIA"/>
+ <enum bitpos="4" name="VK_IMAGE_CONSTRAINTS_INFO_PROTECTED_OPTIONAL_FUCHSIA"/>
+ </enums>
+ <enums name="VkFormatFeatureFlagBits2" type="bitmask" bitwidth="64">
+ <enum bitpos="0" name="VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT"/>
+ <enum name="VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT_KHR" alias="VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_BIT"/>
+ <enum bitpos="1" name="VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT"/>
+ <enum name="VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT_KHR" alias="VK_FORMAT_FEATURE_2_STORAGE_IMAGE_BIT"/>
+ <enum bitpos="2" name="VK_FORMAT_FEATURE_2_STORAGE_IMAGE_ATOMIC_BIT"/>
+ <enum name="VK_FORMAT_FEATURE_2_STORAGE_IMAGE_ATOMIC_BIT_KHR" alias="VK_FORMAT_FEATURE_2_STORAGE_IMAGE_ATOMIC_BIT"/>
+ <enum bitpos="3" name="VK_FORMAT_FEATURE_2_UNIFORM_TEXEL_BUFFER_BIT"/>
+ <enum name="VK_FORMAT_FEATURE_2_UNIFORM_TEXEL_BUFFER_BIT_KHR" alias="VK_FORMAT_FEATURE_2_UNIFORM_TEXEL_BUFFER_BIT"/>
+ <enum bitpos="4" name="VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_BIT"/>
+ <enum name="VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_BIT_KHR" alias="VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_BIT"/>
+ <enum bitpos="5" name="VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_ATOMIC_BIT"/>
+ <enum name="VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_ATOMIC_BIT_KHR" alias="VK_FORMAT_FEATURE_2_STORAGE_TEXEL_BUFFER_ATOMIC_BIT"/>
+ <enum bitpos="6" name="VK_FORMAT_FEATURE_2_VERTEX_BUFFER_BIT"/>
+ <enum name="VK_FORMAT_FEATURE_2_VERTEX_BUFFER_BIT_KHR" alias="VK_FORMAT_FEATURE_2_VERTEX_BUFFER_BIT"/>
+ <enum bitpos="7" name="VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT"/>
+ <enum name="VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT_KHR" alias="VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BIT"/>
+ <enum bitpos="8" name="VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BLEND_BIT"/>
+ <enum name="VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BLEND_BIT_KHR" alias="VK_FORMAT_FEATURE_2_COLOR_ATTACHMENT_BLEND_BIT"/>
+ <enum bitpos="9" name="VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT"/>
+ <enum name="VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT_KHR" alias="VK_FORMAT_FEATURE_2_DEPTH_STENCIL_ATTACHMENT_BIT"/>
+ <enum bitpos="10" name="VK_FORMAT_FEATURE_2_BLIT_SRC_BIT"/>
+ <enum name="VK_FORMAT_FEATURE_2_BLIT_SRC_BIT_KHR" alias="VK_FORMAT_FEATURE_2_BLIT_SRC_BIT"/>
+ <enum bitpos="11" name="VK_FORMAT_FEATURE_2_BLIT_DST_BIT"/>
+ <enum name="VK_FORMAT_FEATURE_2_BLIT_DST_BIT_KHR" alias="VK_FORMAT_FEATURE_2_BLIT_DST_BIT"/>
+ <enum bitpos="12" name="VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_LINEAR_BIT"/>
+ <enum name="VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_LINEAR_BIT_KHR" alias="VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_LINEAR_BIT"/>
+ <enum bitpos="13" name="VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_CUBIC_BIT"/>
+ <enum name="VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT" alias="VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_CUBIC_BIT"/>
+ <enum bitpos="14" name="VK_FORMAT_FEATURE_2_TRANSFER_SRC_BIT"/>
+ <enum name="VK_FORMAT_FEATURE_2_TRANSFER_SRC_BIT_KHR" alias="VK_FORMAT_FEATURE_2_TRANSFER_SRC_BIT"/>
+ <enum bitpos="15" name="VK_FORMAT_FEATURE_2_TRANSFER_DST_BIT"/>
+ <enum name="VK_FORMAT_FEATURE_2_TRANSFER_DST_BIT_KHR" alias="VK_FORMAT_FEATURE_2_TRANSFER_DST_BIT"/>
+ <enum bitpos="16" name="VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_MINMAX_BIT"/>
+ <enum name="VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_MINMAX_BIT_KHR" alias="VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_MINMAX_BIT"/>
+ <enum bitpos="17" name="VK_FORMAT_FEATURE_2_MIDPOINT_CHROMA_SAMPLES_BIT"/>
+ <enum name="VK_FORMAT_FEATURE_2_MIDPOINT_CHROMA_SAMPLES_BIT_KHR" alias="VK_FORMAT_FEATURE_2_MIDPOINT_CHROMA_SAMPLES_BIT"/>
+ <enum bitpos="18" name="VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT"/>
+ <enum name="VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT_KHR" alias="VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT"/>
+ <enum bitpos="19" name="VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT"/>
+ <enum name="VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT_KHR" alias="VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT"/>
+ <enum bitpos="20" name="VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT"/>
+ <enum name="VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT_KHR" alias="VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT"/>
+ <enum bitpos="21" name="VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT"/>
+ <enum name="VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT_KHR" alias="VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT"/>
+ <enum bitpos="22" name="VK_FORMAT_FEATURE_2_DISJOINT_BIT"/>
+ <enum name="VK_FORMAT_FEATURE_2_DISJOINT_BIT_KHR" alias="VK_FORMAT_FEATURE_2_DISJOINT_BIT"/>
+ <enum bitpos="23" name="VK_FORMAT_FEATURE_2_COSITED_CHROMA_SAMPLES_BIT"/>
+ <enum name="VK_FORMAT_FEATURE_2_COSITED_CHROMA_SAMPLES_BIT_KHR" alias="VK_FORMAT_FEATURE_2_COSITED_CHROMA_SAMPLES_BIT"/>
+ <enum bitpos="31" name="VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT"/>
+ <enum name="VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT_KHR" alias="VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT"/>
+ <enum bitpos="32" name="VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT"/>
+ <enum name="VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT_KHR" alias="VK_FORMAT_FEATURE_2_STORAGE_WRITE_WITHOUT_FORMAT_BIT"/>
+ <enum bitpos="33" name="VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_DEPTH_COMPARISON_BIT"/>
+ <enum name="VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_DEPTH_COMPARISON_BIT_KHR" alias="VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_DEPTH_COMPARISON_BIT"/>
+ </enums>
+ <enums name="VkRenderingFlagBits" type="bitmask">
+ <enum bitpos="0" name="VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT"/>
+ <enum name="VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT_KHR" alias="VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT"/>
+ <enum bitpos="1" name="VK_RENDERING_SUSPENDING_BIT"/>
+ <enum name="VK_RENDERING_SUSPENDING_BIT_KHR" alias="VK_RENDERING_SUSPENDING_BIT"/>
+ <enum bitpos="2" name="VK_RENDERING_RESUMING_BIT"/>
+ <enum name="VK_RENDERING_RESUMING_BIT_KHR" alias="VK_RENDERING_RESUMING_BIT"/>
+ </enums>
+ <enums name="VkVideoEncodeH265CapabilityFlagBitsEXT" type="bitmask">
+ <enum bitpos="0" name="VK_VIDEO_ENCODE_H265_CAPABILITY_SEPARATE_COLOUR_PLANE_BIT_EXT"/>
+ <enum bitpos="1" name="VK_VIDEO_ENCODE_H265_CAPABILITY_SCALING_LISTS_BIT_EXT"/>
+ <enum bitpos="2" name="VK_VIDEO_ENCODE_H265_CAPABILITY_SAMPLE_ADAPTIVE_OFFSET_ENABLED_BIT_EXT"/>
+ <enum bitpos="3" name="VK_VIDEO_ENCODE_H265_CAPABILITY_PCM_ENABLE_BIT_EXT"/>
+ <enum bitpos="4" name="VK_VIDEO_ENCODE_H265_CAPABILITY_SPS_TEMPORAL_MVP_ENABLED_BIT_EXT"/>
+ <enum bitpos="5" name="VK_VIDEO_ENCODE_H265_CAPABILITY_HRD_COMPLIANCE_BIT_EXT"/>
+ <enum bitpos="6" name="VK_VIDEO_ENCODE_H265_CAPABILITY_INIT_QP_MINUS26_BIT_EXT"/>
+ <enum bitpos="7" name="VK_VIDEO_ENCODE_H265_CAPABILITY_LOG2_PARALLEL_MERGE_LEVEL_MINUS2_BIT_EXT"/>
+ <enum bitpos="8" name="VK_VIDEO_ENCODE_H265_CAPABILITY_SIGN_DATA_HIDING_ENABLED_BIT_EXT"/>
+ <enum bitpos="9" name="VK_VIDEO_ENCODE_H265_CAPABILITY_TRANSFORM_SKIP_ENABLED_BIT_EXT"/>
+ <enum bitpos="10" name="VK_VIDEO_ENCODE_H265_CAPABILITY_TRANSFORM_SKIP_DISABLED_BIT_EXT"/>
+ <enum bitpos="11" name="VK_VIDEO_ENCODE_H265_CAPABILITY_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT_BIT_EXT"/>
+ <enum bitpos="12" name="VK_VIDEO_ENCODE_H265_CAPABILITY_WEIGHTED_PRED_BIT_EXT"/>
+ <enum bitpos="13" name="VK_VIDEO_ENCODE_H265_CAPABILITY_WEIGHTED_BIPRED_BIT_EXT"/>
+ <enum bitpos="14" name="VK_VIDEO_ENCODE_H265_CAPABILITY_WEIGHTED_PRED_NO_TABLE_BIT_EXT"/>
+ <enum bitpos="15" name="VK_VIDEO_ENCODE_H265_CAPABILITY_TRANSQUANT_BYPASS_ENABLED_BIT_EXT"/>
+ <enum bitpos="16" name="VK_VIDEO_ENCODE_H265_CAPABILITY_ENTROPY_CODING_SYNC_ENABLED_BIT_EXT"/>
+ <enum bitpos="17" name="VK_VIDEO_ENCODE_H265_CAPABILITY_DEBLOCKING_FILTER_OVERRIDE_ENABLED_BIT_EXT"/>
+ <enum bitpos="18" name="VK_VIDEO_ENCODE_H265_CAPABILITY_MULTIPLE_TILE_PER_FRAME_BIT_EXT"/>
+ <enum bitpos="19" name="VK_VIDEO_ENCODE_H265_CAPABILITY_MULTIPLE_SLICE_PER_TILE_BIT_EXT"/>
+ <enum bitpos="20" name="VK_VIDEO_ENCODE_H265_CAPABILITY_MULTIPLE_TILE_PER_SLICE_BIT_EXT"/>
+ <enum bitpos="21" name="VK_VIDEO_ENCODE_H265_CAPABILITY_SLICE_SEGMENT_CTB_COUNT_BIT_EXT"/>
+ <enum bitpos="22" name="VK_VIDEO_ENCODE_H265_CAPABILITY_ROW_UNALIGNED_SLICE_SEGMENT_BIT_EXT"/>
+ <enum bitpos="23" name="VK_VIDEO_ENCODE_H265_CAPABILITY_DEPENDENT_SLICE_SEGMENT_BIT_EXT"/>
+ <enum bitpos="24" name="VK_VIDEO_ENCODE_H265_CAPABILITY_DIFFERENT_SLICE_TYPE_BIT_EXT"/>
+ <enum bitpos="25" name="VK_VIDEO_ENCODE_H265_CAPABILITY_B_FRAME_IN_L1_LIST_BIT_EXT"/>
+ </enums>
+ <enums name="VkVideoEncodeH265InputModeFlagBitsEXT" type="bitmask">
+ <enum bitpos="0" name="VK_VIDEO_ENCODE_H265_INPUT_MODE_FRAME_BIT_EXT"/>
+ <enum bitpos="1" name="VK_VIDEO_ENCODE_H265_INPUT_MODE_SLICE_SEGMENT_BIT_EXT"/>
+ <enum bitpos="2" name="VK_VIDEO_ENCODE_H265_INPUT_MODE_NON_VCL_BIT_EXT"/>
+ </enums>
+ <enums name="VkVideoEncodeH265OutputModeFlagBitsEXT" type="bitmask">
+ <enum bitpos="0" name="VK_VIDEO_ENCODE_H265_OUTPUT_MODE_FRAME_BIT_EXT"/>
+ <enum bitpos="1" name="VK_VIDEO_ENCODE_H265_OUTPUT_MODE_SLICE_SEGMENT_BIT_EXT"/>
+ <enum bitpos="2" name="VK_VIDEO_ENCODE_H265_OUTPUT_MODE_NON_VCL_BIT_EXT"/>
+ </enums>
+ <enums name="VkVideoEncodeH265RateControlStructureEXT" type="enum">
+ <enum value="0" name="VK_VIDEO_ENCODE_H265_RATE_CONTROL_STRUCTURE_UNKNOWN_EXT"/>
+ <enum value="1" name="VK_VIDEO_ENCODE_H265_RATE_CONTROL_STRUCTURE_FLAT_EXT"/>
+ <enum value="2" name="VK_VIDEO_ENCODE_H265_RATE_CONTROL_STRUCTURE_DYADIC_EXT"/>
+ </enums>
+ <enums name="VkVideoEncodeH265CtbSizeFlagBitsEXT" type="bitmask">
+ <enum bitpos="0" name="VK_VIDEO_ENCODE_H265_CTB_SIZE_16_BIT_EXT"/>
+ <enum bitpos="1" name="VK_VIDEO_ENCODE_H265_CTB_SIZE_32_BIT_EXT"/>
+ <enum bitpos="2" name="VK_VIDEO_ENCODE_H265_CTB_SIZE_64_BIT_EXT"/>
+ </enums>
+ <enums name="VkVideoEncodeH265TransformBlockSizeFlagBitsEXT" type="bitmask">
+ <enum bitpos="0" name="VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_4_BIT_EXT"/>
+ <enum bitpos="1" name="VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_8_BIT_EXT"/>
+ <enum bitpos="2" name="VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_16_BIT_EXT"/>
+ <enum bitpos="3" name="VK_VIDEO_ENCODE_H265_TRANSFORM_BLOCK_SIZE_32_BIT_EXT"/>
+ </enums>
+ <enums name="VkExportMetalObjectTypeFlagBitsEXT" type="bitmask">
+ <enum bitpos="0" name="VK_EXPORT_METAL_OBJECT_TYPE_METAL_DEVICE_BIT_EXT"/>
+ <enum bitpos="1" name="VK_EXPORT_METAL_OBJECT_TYPE_METAL_COMMAND_QUEUE_BIT_EXT"/>
+ <enum bitpos="2" name="VK_EXPORT_METAL_OBJECT_TYPE_METAL_BUFFER_BIT_EXT"/>
+ <enum bitpos="3" name="VK_EXPORT_METAL_OBJECT_TYPE_METAL_TEXTURE_BIT_EXT"/>
+ <enum bitpos="4" name="VK_EXPORT_METAL_OBJECT_TYPE_METAL_IOSURFACE_BIT_EXT"/>
+ <enum bitpos="5" name="VK_EXPORT_METAL_OBJECT_TYPE_METAL_SHARED_EVENT_BIT_EXT"/>
+ </enums>
+ <enums name="VkInstanceCreateFlagBits" type="bitmask">
+ </enums>
+ <enums name="VkImageCompressionFlagBitsEXT" type="bitmask">
+ <enum value="0" name="VK_IMAGE_COMPRESSION_DEFAULT_EXT"/>
+ <enum bitpos="0" name="VK_IMAGE_COMPRESSION_FIXED_RATE_DEFAULT_EXT"/>
+ <enum bitpos="1" name="VK_IMAGE_COMPRESSION_FIXED_RATE_EXPLICIT_EXT"/>
+ <enum bitpos="2" name="VK_IMAGE_COMPRESSION_DISABLED_EXT"/>
+ </enums>
+ <enums name="VkImageCompressionFixedRateFlagBitsEXT" type="bitmask">
+ <enum value="0" name="VK_IMAGE_COMPRESSION_FIXED_RATE_NONE_EXT"/>
+ <enum bitpos="0" name="VK_IMAGE_COMPRESSION_FIXED_RATE_1BPC_BIT_EXT"/>
+ <enum bitpos="1" name="VK_IMAGE_COMPRESSION_FIXED_RATE_2BPC_BIT_EXT"/>
+ <enum bitpos="2" name="VK_IMAGE_COMPRESSION_FIXED_RATE_3BPC_BIT_EXT"/>
+ <enum bitpos="3" name="VK_IMAGE_COMPRESSION_FIXED_RATE_4BPC_BIT_EXT"/>
+ <enum bitpos="4" name="VK_IMAGE_COMPRESSION_FIXED_RATE_5BPC_BIT_EXT"/>
+ <enum bitpos="5" name="VK_IMAGE_COMPRESSION_FIXED_RATE_6BPC_BIT_EXT"/>
+ <enum bitpos="6" name="VK_IMAGE_COMPRESSION_FIXED_RATE_7BPC_BIT_EXT"/>
+ <enum bitpos="7" name="VK_IMAGE_COMPRESSION_FIXED_RATE_8BPC_BIT_EXT"/>
+ <enum bitpos="8" name="VK_IMAGE_COMPRESSION_FIXED_RATE_9BPC_BIT_EXT"/>
+ <enum bitpos="9" name="VK_IMAGE_COMPRESSION_FIXED_RATE_10BPC_BIT_EXT"/>
+ <enum bitpos="10" name="VK_IMAGE_COMPRESSION_FIXED_RATE_11BPC_BIT_EXT"/>
+ <enum bitpos="11" name="VK_IMAGE_COMPRESSION_FIXED_RATE_12BPC_BIT_EXT"/>
+ <enum bitpos="12" name="VK_IMAGE_COMPRESSION_FIXED_RATE_13BPC_BIT_EXT"/>
+ <enum bitpos="13" name="VK_IMAGE_COMPRESSION_FIXED_RATE_14BPC_BIT_EXT"/>
+ <enum bitpos="14" name="VK_IMAGE_COMPRESSION_FIXED_RATE_15BPC_BIT_EXT"/>
+ <enum bitpos="15" name="VK_IMAGE_COMPRESSION_FIXED_RATE_16BPC_BIT_EXT"/>
+ <enum bitpos="16" name="VK_IMAGE_COMPRESSION_FIXED_RATE_17BPC_BIT_EXT"/>
+ <enum bitpos="17" name="VK_IMAGE_COMPRESSION_FIXED_RATE_18BPC_BIT_EXT"/>
+ <enum bitpos="18" name="VK_IMAGE_COMPRESSION_FIXED_RATE_19BPC_BIT_EXT"/>
+ <enum bitpos="19" name="VK_IMAGE_COMPRESSION_FIXED_RATE_20BPC_BIT_EXT"/>
+ <enum bitpos="20" name="VK_IMAGE_COMPRESSION_FIXED_RATE_21BPC_BIT_EXT"/>
+ <enum bitpos="21" name="VK_IMAGE_COMPRESSION_FIXED_RATE_22BPC_BIT_EXT"/>
+ <enum bitpos="22" name="VK_IMAGE_COMPRESSION_FIXED_RATE_23BPC_BIT_EXT"/>
+ <enum bitpos="23" name="VK_IMAGE_COMPRESSION_FIXED_RATE_24BPC_BIT_EXT"/>
+ </enums>
+ <enums name="VkPipelineRobustnessBufferBehaviorEXT" type="enum">
+ <enum value="0" name="VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DEVICE_DEFAULT_EXT" />
+ <enum value="1" name="VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DISABLED_EXT" />
+ <enum value="2" name="VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT" />
+ <enum value="3" name="VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_2_EXT" />
+ </enums>
+ <enums name="VkPipelineRobustnessImageBehaviorEXT" type="enum">
+ <enum value="0" name="VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DEVICE_DEFAULT_EXT" />
+ <enum value="1" name="VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DISABLED_EXT" />
+ <enum value="2" name="VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS_EXT" />
+ <enum value="3" name="VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS_2_EXT" />
+ </enums>
+ <enums name="VkOpticalFlowGridSizeFlagBitsNV" type="bitmask">
+ <enum value="0" name="VK_OPTICAL_FLOW_GRID_SIZE_UNKNOWN_NV"/>
+ <enum bitpos="0" name="VK_OPTICAL_FLOW_GRID_SIZE_1X1_BIT_NV"/>
+ <enum bitpos="1" name="VK_OPTICAL_FLOW_GRID_SIZE_2X2_BIT_NV"/>
+ <enum bitpos="2" name="VK_OPTICAL_FLOW_GRID_SIZE_4X4_BIT_NV"/>
+ <enum bitpos="3" name="VK_OPTICAL_FLOW_GRID_SIZE_8X8_BIT_NV"/>
+ </enums>
+ <enums name="VkOpticalFlowUsageFlagBitsNV" type="bitmask">
+ <enum value="0" name="VK_OPTICAL_FLOW_USAGE_UNKNOWN_NV"/>
+ <enum bitpos="0" name="VK_OPTICAL_FLOW_USAGE_INPUT_BIT_NV"/>
+ <enum bitpos="1" name="VK_OPTICAL_FLOW_USAGE_OUTPUT_BIT_NV"/>
+ <enum bitpos="2" name="VK_OPTICAL_FLOW_USAGE_HINT_BIT_NV"/>
+ <enum bitpos="3" name="VK_OPTICAL_FLOW_USAGE_COST_BIT_NV"/>
+ <enum bitpos="4" name="VK_OPTICAL_FLOW_USAGE_GLOBAL_FLOW_BIT_NV"/>
+ </enums>
+ <enums name="VkOpticalFlowPerformanceLevelNV" type="enum">
+ <enum value="0" name="VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_UNKNOWN_NV"/>
+ <enum value="1" name="VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_SLOW_NV"/>
+ <enum value="2" name="VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_MEDIUM_NV"/>
+ <enum value="3" name="VK_OPTICAL_FLOW_PERFORMANCE_LEVEL_FAST_NV"/>
+ </enums>
+ <enums name="VkOpticalFlowSessionBindingPointNV" type="enum">
+ <enum value="0" name="VK_OPTICAL_FLOW_SESSION_BINDING_POINT_UNKNOWN_NV"/>
+ <enum value="1" name="VK_OPTICAL_FLOW_SESSION_BINDING_POINT_INPUT_NV"/>
+ <enum value="2" name="VK_OPTICAL_FLOW_SESSION_BINDING_POINT_REFERENCE_NV"/>
+ <enum value="3" name="VK_OPTICAL_FLOW_SESSION_BINDING_POINT_HINT_NV"/>
+ <enum value="4" name="VK_OPTICAL_FLOW_SESSION_BINDING_POINT_FLOW_VECTOR_NV"/>
+ <enum value="5" name="VK_OPTICAL_FLOW_SESSION_BINDING_POINT_BACKWARD_FLOW_VECTOR_NV"/>
+ <enum value="6" name="VK_OPTICAL_FLOW_SESSION_BINDING_POINT_COST_NV"/>
+ <enum value="7" name="VK_OPTICAL_FLOW_SESSION_BINDING_POINT_BACKWARD_COST_NV"/>
+ <enum value="8" name="VK_OPTICAL_FLOW_SESSION_BINDING_POINT_GLOBAL_FLOW_NV"/>
+ </enums>
+ <enums name="VkOpticalFlowSessionCreateFlagBitsNV" type="bitmask">
+ <enum bitpos="0" name="VK_OPTICAL_FLOW_SESSION_CREATE_ENABLE_HINT_BIT_NV"/>
+ <enum bitpos="1" name="VK_OPTICAL_FLOW_SESSION_CREATE_ENABLE_COST_BIT_NV"/>
+ <enum bitpos="2" name="VK_OPTICAL_FLOW_SESSION_CREATE_ENABLE_GLOBAL_FLOW_BIT_NV"/>
+ <enum bitpos="3" name="VK_OPTICAL_FLOW_SESSION_CREATE_ALLOW_REGIONS_BIT_NV"/>
+ <enum bitpos="4" name="VK_OPTICAL_FLOW_SESSION_CREATE_BOTH_DIRECTIONS_BIT_NV"/>
+ </enums>
+ <enums name="VkOpticalFlowExecuteFlagBitsNV" type="bitmask">
+ <enum bitpos="0" name="VK_OPTICAL_FLOW_EXECUTE_DISABLE_TEMPORAL_HINTS_BIT_NV"/>
+ </enums>
+ <enums name="VkMicromapTypeEXT" type="enum">
+ <enum value="0" name="VK_MICROMAP_TYPE_OPACITY_MICROMAP_EXT"/>
+ </enums>
+ <enums name="VkBuildMicromapFlagBitsEXT" type="bitmask">
+ <enum bitpos="0" name="VK_BUILD_MICROMAP_PREFER_FAST_TRACE_BIT_EXT"/>
+ <enum bitpos="1" name="VK_BUILD_MICROMAP_PREFER_FAST_BUILD_BIT_EXT"/>
+ <enum bitpos="2" name="VK_BUILD_MICROMAP_ALLOW_COMPACTION_BIT_EXT"/>
+ </enums>
+ <enums name="VkMicromapCreateFlagBitsEXT" type="bitmask">
+ <enum bitpos="0" name="VK_MICROMAP_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT"/>
+ </enums>
+ <enums name="VkCopyMicromapModeEXT" type="enum">
+ <enum value="0" name="VK_COPY_MICROMAP_MODE_CLONE_EXT"/>
+ <enum value="1" name="VK_COPY_MICROMAP_MODE_SERIALIZE_EXT"/>
+ <enum value="2" name="VK_COPY_MICROMAP_MODE_DESERIALIZE_EXT"/>
+ <enum value="3" name="VK_COPY_MICROMAP_MODE_COMPACT_EXT"/>
+ </enums>
+ <enums name="VkBuildMicromapModeEXT" type="enum">
+ <enum value="0" name="VK_BUILD_MICROMAP_MODE_BUILD_EXT"/>
+ </enums>
+ <enums name="VkOpacityMicromapFormatEXT" type="enum">
+ <enum value="1" name="VK_OPACITY_MICROMAP_FORMAT_2_STATE_EXT"/>
+ <enum value="2" name="VK_OPACITY_MICROMAP_FORMAT_4_STATE_EXT"/>
+ </enums>
+ <enums name="VkOpacityMicromapSpecialIndexEXT" type="enum">
+ <enum value="-1" name="VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_TRANSPARENT_EXT"/>
+ <enum value="-2" name="VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_OPAQUE_EXT"/>
+ <enum value="-3" name="VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_UNKNOWN_TRANSPARENT_EXT"/>
+ <enum value="-4" name="VK_OPACITY_MICROMAP_SPECIAL_INDEX_FULLY_UNKNOWN_OPAQUE_EXT"/>
+ </enums>
+ <enums name="VkDeviceFaultAddressTypeEXT" type="enum">
+ <enum value="0" name="VK_DEVICE_FAULT_ADDRESS_TYPE_NONE_EXT" comment="Currently unused"/>
+ <enum value="1" name="VK_DEVICE_FAULT_ADDRESS_TYPE_READ_INVALID_EXT"/>
+ <enum value="2" name="VK_DEVICE_FAULT_ADDRESS_TYPE_WRITE_INVALID_EXT"/>
+ <enum value="3" name="VK_DEVICE_FAULT_ADDRESS_TYPE_EXECUTE_INVALID_EXT"/>
+ <enum value="4" name="VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_UNKNOWN_EXT"/>
+ <enum value="5" name="VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_INVALID_EXT"/>
+ <enum value="6" name="VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_FAULT_EXT"/>
+ </enums>
+ <enums name="VkDeviceFaultVendorBinaryHeaderVersionEXT" type="enum">
+ <enum value="1" name="VK_DEVICE_FAULT_VENDOR_BINARY_HEADER_VERSION_ONE_EXT"/>
</enums>
-
<commands comment="Vulkan command definitions">
<command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_INITIALIZATION_FAILED,VK_ERROR_LAYER_NOT_PRESENT,VK_ERROR_EXTENSION_NOT_PRESENT,VK_ERROR_INCOMPATIBLE_DRIVER">
<proto><type>VkResult</type> <name>vkCreateInstance</name></proto>
@@ -7717,7 +9829,7 @@ typedef void <name>CAMetalLayer</name>;
<param optional="true" externsync="true"><type>VkDevice</type> <name>device</name></param>
<param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
<implicitexternsyncparams>
- <param>all sname:VkQueue objects received from pname:device</param>
+ <param>all sname:VkQueue objects created from pname:device</param>
</implicitexternsyncparams>
</command>
<command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY">
@@ -7866,7 +9978,7 @@ typedef void <name>CAMetalLayer</name>;
<proto><type>VkResult</type> <name>vkQueueBindSparse</name></proto>
<param externsync="true"><type>VkQueue</type> <name>queue</name></param>
<param optional="true"><type>uint32_t</type> <name>bindInfoCount</name></param>
- <param len="bindInfoCount" externsync="pBindInfo[].pBufferBinds[].buffer,pBindInfo[].pImageOpaqueBinds[].image,pBindInfo[].pImageBinds[].image">const <type>VkBindSparseInfo</type>* <name>pBindInfo</name></param>
+ <param len="bindInfoCount">const <type>VkBindSparseInfo</type>* <name>pBindInfo</name></param>
<param optional="true" externsync="true"><type>VkFence</type> <name>fence</name></param>
</command>
<command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
@@ -8000,7 +10112,7 @@ typedef void <name>CAMetalLayer</name>;
<param optional="true" externsync="true"><type>VkBufferView</type> <name>bufferView</name></param>
<param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
</command>
- <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_COMPRESSION_EXHAUSTED_EXT,VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS_KHR">
<proto><type>VkResult</type> <name>vkCreateImage</name></proto>
<param><type>VkDevice</type> <name>device</name></param>
<param>const <type>VkImageCreateInfo</type>* <name>pCreateInfo</name></param>
@@ -8020,7 +10132,7 @@ typedef void <name>CAMetalLayer</name>;
<param>const <type>VkImageSubresource</type>* <name>pSubresource</name></param>
<param><type>VkSubresourceLayout</type>* <name>pLayout</name></param>
</command>
- <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS_KHR">
<proto><type>VkResult</type> <name>vkCreateImageView</name></proto>
<param><type>VkDevice</type> <name>device</name></param>
<param>const <type>VkImageViewCreateInfo</type>* <name>pCreateInfo</name></param>
@@ -8116,7 +10228,7 @@ typedef void <name>CAMetalLayer</name>;
<param optional="true" externsync="true"><type>VkPipelineLayout</type> <name>pipelineLayout</name></param>
<param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
</command>
- <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS_KHR">
<proto><type>VkResult</type> <name>vkCreateSampler</name></proto>
<param><type>VkDevice</type> <name>device</name></param>
<param>const <type>VkSamplerCreateInfo</type>* <name>pCreateInfo</name></param>
@@ -8181,9 +10293,9 @@ typedef void <name>CAMetalLayer</name>;
<proto><type>void</type> <name>vkUpdateDescriptorSets</name></proto>
<param><type>VkDevice</type> <name>device</name></param>
<param optional="true"><type>uint32_t</type> <name>descriptorWriteCount</name></param>
- <param len="descriptorWriteCount" externsync="pDescriptorWrites[].dstSet">const <type>VkWriteDescriptorSet</type>* <name>pDescriptorWrites</name></param>
+ <param len="descriptorWriteCount">const <type>VkWriteDescriptorSet</type>* <name>pDescriptorWrites</name></param>
<param optional="true"><type>uint32_t</type> <name>descriptorCopyCount</name></param>
- <param len="descriptorCopyCount" externsync="pDescriptorCopies[].dstSet">const <type>VkCopyDescriptorSet</type>* <name>pDescriptorCopies</name></param>
+ <param len="descriptorCopyCount">const <type>VkCopyDescriptorSet</type>* <name>pDescriptorCopies</name></param>
</command>
<command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
<proto><type>VkResult</type> <name>vkCreateFramebuffer</name></proto>
@@ -8272,86 +10384,86 @@ typedef void <name>CAMetalLayer</name>;
<param>the sname:VkCommandPool that pname:commandBuffer was allocated from</param>
</implicitexternsyncparams>
</command>
- <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdBindPipeline</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkPipelineBindPoint</type> <name>pipelineBindPoint</name></param>
<param><type>VkPipeline</type> <name>pipeline</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdSetViewport</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>firstViewport</name></param>
<param><type>uint32_t</type> <name>viewportCount</name></param>
<param len="viewportCount">const <type>VkViewport</type>* <name>pViewports</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdSetScissor</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>firstScissor</name></param>
<param><type>uint32_t</type> <name>scissorCount</name></param>
<param len="scissorCount">const <type>VkRect2D</type>* <name>pScissors</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdSetLineWidth</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>float</type> <name>lineWidth</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdSetDepthBias</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>float</type> <name>depthBiasConstantFactor</name></param>
<param><type>float</type> <name>depthBiasClamp</name></param>
<param><type>float</type> <name>depthBiasSlopeFactor</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdSetBlendConstants</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param>const <type>float</type> <name>blendConstants</name>[4]</param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdSetDepthBounds</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>float</type> <name>minDepthBounds</name></param>
<param><type>float</type> <name>maxDepthBounds</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdSetStencilCompareMask</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkStencilFaceFlags</type> <name>faceMask</name></param>
<param><type>uint32_t</type> <name>compareMask</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdSetStencilWriteMask</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkStencilFaceFlags</type> <name>faceMask</name></param>
<param><type>uint32_t</type> <name>writeMask</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdSetStencilReference</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkStencilFaceFlags</type> <name>faceMask</name></param>
<param><type>uint32_t</type> <name>reference</name></param>
</command>
- <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdBindDescriptorSets</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkPipelineBindPoint</type> <name>pipelineBindPoint</name></param>
<param><type>VkPipelineLayout</type> <name>layout</name></param>
<param><type>uint32_t</type> <name>firstSet</name></param>
<param><type>uint32_t</type> <name>descriptorSetCount</name></param>
- <param len="descriptorSetCount">const <type>VkDescriptorSet</type>* <name>pDescriptorSets</name></param>
+ <param len="descriptorSetCount" optional="false,true">const <type>VkDescriptorSet</type>* <name>pDescriptorSets</name></param>
<param optional="true"><type>uint32_t</type> <name>dynamicOffsetCount</name></param>
<param len="dynamicOffsetCount">const <type>uint32_t</type>* <name>pDynamicOffsets</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdBindIndexBuffer</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkBuffer</type> <name>buffer</name></param>
<param><type>VkDeviceSize</type> <name>offset</name></param>
<param><type>VkIndexType</type> <name>indexType</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdBindVertexBuffers</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>firstBinding</name></param>
@@ -8359,7 +10471,7 @@ typedef void <name>CAMetalLayer</name>;
<param len="bindingCount" optional="false,true">const <type>VkBuffer</type>* <name>pBuffers</name></param>
<param len="bindingCount">const <type>VkDeviceSize</type>* <name>pOffsets</name></param>
</command>
- <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdDraw</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>vertexCount</name></param>
@@ -8367,7 +10479,7 @@ typedef void <name>CAMetalLayer</name>;
<param><type>uint32_t</type> <name>firstVertex</name></param>
<param><type>uint32_t</type> <name>firstInstance</name></param>
</command>
- <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdDrawIndexed</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>indexCount</name></param>
@@ -8376,26 +10488,26 @@ typedef void <name>CAMetalLayer</name>;
<param><type>int32_t</type> <name>vertexOffset</name></param>
<param><type>uint32_t</type> <name>firstInstance</name></param>
</command>
- <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdDrawMultiEXT</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param optional="true"><type>uint32_t</type> <name>drawCount</name></param>
- <param noautovalidity="true" len="drawCount">const <type>VkMultiDrawInfoEXT</type>* <name>pVertexInfo</name></param>
+ <param noautovalidity="true" len="drawCount" stride="stride">const <type>VkMultiDrawInfoEXT</type>* <name>pVertexInfo</name></param>
<param><type>uint32_t</type> <name>instanceCount</name></param>
<param><type>uint32_t</type> <name>firstInstance</name></param>
<param><type>uint32_t</type> <name>stride</name></param>
</command>
- <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdDrawMultiIndexedEXT</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param optional="true"><type>uint32_t</type> <name>drawCount</name></param>
- <param noautovalidity="true" len="drawCount">const <type>VkMultiDrawIndexedInfoEXT</type>* <name>pIndexInfo</name></param>
+ <param noautovalidity="true" len="drawCount" stride="stride">const <type>VkMultiDrawIndexedInfoEXT</type>* <name>pIndexInfo</name></param>
<param><type>uint32_t</type> <name>instanceCount</name></param>
<param><type>uint32_t</type> <name>firstInstance</name></param>
<param><type>uint32_t</type> <name>stride</name></param>
<param optional="true">const <type>int32_t</type>* <name>pVertexOffset</name></param>
</command>
- <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdDrawIndirect</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkBuffer</type> <name>buffer</name></param>
@@ -8403,7 +10515,7 @@ typedef void <name>CAMetalLayer</name>;
<param><type>uint32_t</type> <name>drawCount</name></param>
<param><type>uint32_t</type> <name>stride</name></param>
</command>
- <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdDrawIndexedIndirect</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkBuffer</type> <name>buffer</name></param>
@@ -8411,24 +10523,24 @@ typedef void <name>CAMetalLayer</name>;
<param><type>uint32_t</type> <name>drawCount</name></param>
<param><type>uint32_t</type> <name>stride</name></param>
</command>
- <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdDispatch</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>groupCountX</name></param>
<param><type>uint32_t</type> <name>groupCountY</name></param>
<param><type>uint32_t</type> <name>groupCountZ</name></param>
</command>
- <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdDispatchIndirect</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkBuffer</type> <name>buffer</name></param>
<param><type>VkDeviceSize</type> <name>offset</name></param>
</command>
- <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdSubpassShadingHUAWEI</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
</command>
- <command queues="transfer,graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <command queues="transfer,graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdCopyBuffer</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkBuffer</type> <name>srcBuffer</name></param>
@@ -8436,7 +10548,7 @@ typedef void <name>CAMetalLayer</name>;
<param><type>uint32_t</type> <name>regionCount</name></param>
<param len="regionCount">const <type>VkBufferCopy</type>* <name>pRegions</name></param>
</command>
- <command queues="transfer,graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <command queues="transfer,graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdCopyImage</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkImage</type> <name>srcImage</name></param>
@@ -8446,7 +10558,7 @@ typedef void <name>CAMetalLayer</name>;
<param><type>uint32_t</type> <name>regionCount</name></param>
<param len="regionCount">const <type>VkImageCopy</type>* <name>pRegions</name></param>
</command>
- <command queues="graphics" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdBlitImage</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkImage</type> <name>srcImage</name></param>
@@ -8457,7 +10569,7 @@ typedef void <name>CAMetalLayer</name>;
<param len="regionCount">const <type>VkImageBlit</type>* <name>pRegions</name></param>
<param><type>VkFilter</type> <name>filter</name></param>
</command>
- <command queues="transfer,graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <command queues="transfer,graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdCopyBufferToImage</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkBuffer</type> <name>srcBuffer</name></param>
@@ -8466,7 +10578,7 @@ typedef void <name>CAMetalLayer</name>;
<param><type>uint32_t</type> <name>regionCount</name></param>
<param len="regionCount">const <type>VkBufferImageCopy</type>* <name>pRegions</name></param>
</command>
- <command queues="transfer,graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <command queues="transfer,graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdCopyImageToBuffer</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkImage</type> <name>srcImage</name></param>
@@ -8475,7 +10587,24 @@ typedef void <name>CAMetalLayer</name>;
<param><type>uint32_t</type> <name>regionCount</name></param>
<param len="regionCount">const <type>VkBufferImageCopy</type>* <name>pRegions</name></param>
</command>
- <command queues="transfer,graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <command queues="transfer,graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
+ <proto><type>void</type> <name>vkCmdCopyMemoryIndirectNV</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkDeviceAddress</type> <name>copyBufferAddress</name></param>
+ <param><type>uint32_t</type> <name>copyCount</name></param>
+ <param><type>uint32_t</type> <name>stride</name></param>
+ </command>
+ <command queues="transfer,graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
+ <proto><type>void</type> <name>vkCmdCopyMemoryToImageIndirectNV</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkDeviceAddress</type> <name>copyBufferAddress</name></param>
+ <param><type>uint32_t</type> <name>copyCount</name></param>
+ <param><type>uint32_t</type> <name>stride</name></param>
+ <param><type>VkImage</type> <name>dstImage</name></param>
+ <param><type>VkImageLayout</type> <name>dstImageLayout</name></param>
+ <param len="copyCount">const <type>VkImageSubresourceLayers</type>* <name>pImageSubresources</name></param>
+ </command>
+ <command queues="transfer,graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdUpdateBuffer</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkBuffer</type> <name>dstBuffer</name></param>
@@ -8483,7 +10612,7 @@ typedef void <name>CAMetalLayer</name>;
<param><type>VkDeviceSize</type> <name>dataSize</name></param>
<param len="dataSize">const <type>void</type>* <name>pData</name></param>
</command>
- <command queues="transfer,graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary" comment="transfer support is only available when VK_KHR_maintenance1 is enabled, as documented in valid usage language in the specification">
+ <command queues="transfer,graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action" comment="transfer support is only available when VK_KHR_maintenance1 is enabled, as documented in valid usage language in the specification">
<proto><type>void</type> <name>vkCmdFillBuffer</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkBuffer</type> <name>dstBuffer</name></param>
@@ -8491,7 +10620,7 @@ typedef void <name>CAMetalLayer</name>;
<param><type>VkDeviceSize</type> <name>size</name></param>
<param><type>uint32_t</type> <name>data</name></param>
</command>
- <command queues="graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <command queues="graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdClearColorImage</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkImage</type> <name>image</name></param>
@@ -8500,7 +10629,7 @@ typedef void <name>CAMetalLayer</name>;
<param><type>uint32_t</type> <name>rangeCount</name></param>
<param len="rangeCount">const <type>VkImageSubresourceRange</type>* <name>pRanges</name></param>
</command>
- <command queues="graphics" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdClearDepthStencilImage</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkImage</type> <name>image</name></param>
@@ -8509,7 +10638,7 @@ typedef void <name>CAMetalLayer</name>;
<param><type>uint32_t</type> <name>rangeCount</name></param>
<param len="rangeCount">const <type>VkImageSubresourceRange</type>* <name>pRanges</name></param>
</command>
- <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdClearAttachments</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>attachmentCount</name></param>
@@ -8517,7 +10646,7 @@ typedef void <name>CAMetalLayer</name>;
<param><type>uint32_t</type> <name>rectCount</name></param>
<param len="rectCount">const <type>VkClearRect</type>* <name>pRects</name></param>
</command>
- <command queues="graphics" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdResolveImage</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkImage</type> <name>srcImage</name></param>
@@ -8527,19 +10656,19 @@ typedef void <name>CAMetalLayer</name>;
<param><type>uint32_t</type> <name>regionCount</name></param>
<param len="regionCount">const <type>VkImageResolve</type>* <name>pRegions</name></param>
</command>
- <command queues="graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <command queues="graphics,compute,decode,encode" renderpass="outside" videocoding="both" cmdbufferlevel="primary,secondary" tasks="synchronization">
<proto><type>void</type> <name>vkCmdSetEvent</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkEvent</type> <name>event</name></param>
<param optional="true"><type>VkPipelineStageFlags</type> <name>stageMask</name></param>
</command>
- <command queues="graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <command queues="graphics,compute,decode,encode" renderpass="outside" videocoding="both" cmdbufferlevel="primary,secondary" tasks="synchronization">
<proto><type>void</type> <name>vkCmdResetEvent</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkEvent</type> <name>event</name></param>
<param optional="true"><type>VkPipelineStageFlags</type> <name>stageMask</name></param>
</command>
- <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics,compute,decode,encode" renderpass="both" videocoding="both" cmdbufferlevel="primary,secondary" tasks="synchronization">
<proto><type>void</type> <name>vkCmdWaitEvents</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>eventCount</name></param>
@@ -8553,7 +10682,7 @@ typedef void <name>CAMetalLayer</name>;
<param optional="true"><type>uint32_t</type> <name>imageMemoryBarrierCount</name></param>
<param len="imageMemoryBarrierCount">const <type>VkImageMemoryBarrier</type>* <name>pImageMemoryBarriers</name></param>
</command>
- <command queues="transfer,graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="transfer,graphics,compute,decode,encode" renderpass="both" videocoding="both" cmdbufferlevel="primary,secondary" tasks="synchronization">
<proto><type>void</type> <name>vkCmdPipelineBarrier</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param optional="true"><type>VkPipelineStageFlags</type> <name>srcStageMask</name></param>
@@ -8566,43 +10695,43 @@ typedef void <name>CAMetalLayer</name>;
<param optional="true"><type>uint32_t</type> <name>imageMemoryBarrierCount</name></param>
<param len="imageMemoryBarrierCount">const <type>VkImageMemoryBarrier</type>* <name>pImageMemoryBarriers</name></param>
</command>
- <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics,compute,decode,encode" renderpass="both" videocoding="both" cmdbufferlevel="primary,secondary" tasks="action,state">
<proto><type>void</type> <name>vkCmdBeginQuery</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkQueryPool</type> <name>queryPool</name></param>
<param><type>uint32_t</type> <name>query</name></param>
<param optional="true"><type>VkQueryControlFlags</type> <name>flags</name></param>
</command>
- <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics,compute,decode,encode" renderpass="both" videocoding="both" cmdbufferlevel="primary,secondary" tasks="action,state">
<proto><type>void</type> <name>vkCmdEndQuery</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkQueryPool</type> <name>queryPool</name></param>
<param><type>uint32_t</type> <name>query</name></param>
</command>
- <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary" tasks="action,state">
<proto><type>void</type> <name>vkCmdBeginConditionalRenderingEXT</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param>const <type>VkConditionalRenderingBeginInfoEXT</type>* <name>pConditionalRenderingBegin</name></param>
</command>
- <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary" tasks="action,state">
<proto><type>void</type> <name>vkCmdEndConditionalRenderingEXT</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
</command>
- <command queues="graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <command queues="graphics,compute,decode,encode,opticalflow" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdResetQueryPool</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkQueryPool</type> <name>queryPool</name></param>
<param><type>uint32_t</type> <name>firstQuery</name></param>
<param><type>uint32_t</type> <name>queryCount</name></param>
</command>
- <command queues="transfer,graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="transfer,graphics,compute,decode,encode,opticalflow" renderpass="both" videocoding="both" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdWriteTimestamp</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkPipelineStageFlagBits</type> <name>pipelineStage</name></param>
<param><type>VkQueryPool</type> <name>queryPool</name></param>
<param><type>uint32_t</type> <name>query</name></param>
</command>
- <command queues="graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <command queues="graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdCopyQueryPoolResults</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkQueryPool</type> <name>queryPool</name></param>
@@ -8613,7 +10742,7 @@ typedef void <name>CAMetalLayer</name>;
<param><type>VkDeviceSize</type> <name>stride</name></param>
<param optional="true"><type>VkQueryResultFlags</type> <name>flags</name></param>
</command>
- <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdPushConstants</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkPipelineLayout</type> <name>layout</name></param>
@@ -8622,22 +10751,22 @@ typedef void <name>CAMetalLayer</name>;
<param><type>uint32_t</type> <name>size</name></param>
<param len="size">const <type>void</type>* <name>pValues</name></param>
</command>
- <command queues="graphics" renderpass="outside" cmdbufferlevel="primary">
+ <command queues="graphics" renderpass="outside" cmdbufferlevel="primary" tasks="action,state,synchronization">
<proto><type>void</type> <name>vkCmdBeginRenderPass</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param>const <type>VkRenderPassBeginInfo</type>* <name>pRenderPassBegin</name></param>
<param><type>VkSubpassContents</type> <name>contents</name></param>
</command>
- <command queues="graphics" renderpass="inside" cmdbufferlevel="primary">
+ <command queues="graphics" renderpass="inside" cmdbufferlevel="primary" tasks="action,state,synchronization">
<proto><type>void</type> <name>vkCmdNextSubpass</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkSubpassContents</type> <name>contents</name></param>
</command>
- <command queues="graphics" renderpass="inside" cmdbufferlevel="primary">
+ <command queues="graphics" renderpass="inside" cmdbufferlevel="primary" tasks="action,state,synchronization">
<proto><type>void</type> <name>vkCmdEndRenderPass</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
</command>
- <command queues="transfer,graphics,compute" renderpass="both" cmdbufferlevel="primary">
+ <command queues="transfer,graphics,compute" renderpass="both" cmdbufferlevel="primary" tasks="indirection">
<proto><type>void</type> <name>vkCmdExecuteCommands</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>commandBufferCount</name></param>
@@ -8728,18 +10857,18 @@ typedef void <name>CAMetalLayer</name>;
<command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_SURFACE_LOST_KHR">
<proto><type>VkResult</type> <name>vkGetPhysicalDeviceSurfaceFormatsKHR</name></proto>
<param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
- <param><type>VkSurfaceKHR</type> <name>surface</name></param>
+ <param optional="true"><type>VkSurfaceKHR</type> <name>surface</name></param>
<param optional="false,true"><type>uint32_t</type>* <name>pSurfaceFormatCount</name></param>
<param optional="true" len="pSurfaceFormatCount"><type>VkSurfaceFormatKHR</type>* <name>pSurfaceFormats</name></param>
</command>
<command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_SURFACE_LOST_KHR">
<proto><type>VkResult</type> <name>vkGetPhysicalDeviceSurfacePresentModesKHR</name></proto>
<param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
- <param><type>VkSurfaceKHR</type> <name>surface</name></param>
+ <param optional="true"><type>VkSurfaceKHR</type> <name>surface</name></param>
<param optional="false,true"><type>uint32_t</type>* <name>pPresentModeCount</name></param>
<param optional="true" len="pPresentModeCount"><type>VkPresentModeKHR</type>* <name>pPresentModes</name></param>
</command>
- <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_DEVICE_LOST,VK_ERROR_SURFACE_LOST_KHR,VK_ERROR_NATIVE_WINDOW_IN_USE_KHR,VK_ERROR_INITIALIZATION_FAILED">
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_DEVICE_LOST,VK_ERROR_SURFACE_LOST_KHR,VK_ERROR_NATIVE_WINDOW_IN_USE_KHR,VK_ERROR_INITIALIZATION_FAILED,VK_ERROR_COMPRESSION_EXHAUSTED_EXT">
<proto><type>VkResult</type> <name>vkCreateSwapchainKHR</name></proto>
<param><type>VkDevice</type> <name>device</name></param>
<param externsync="pCreateInfo-&gt;surface,pCreateInfo-&gt;oldSwapchain">const <type>VkSwapchainCreateInfoKHR</type>* <name>pCreateInfo</name></param>
@@ -8907,16 +11036,16 @@ typedef void <name>CAMetalLayer</name>;
<param><type>VkDevice</type> <name>device</name></param>
<param externsync="pTagInfo-&gt;object">const <type>VkDebugMarkerObjectTagInfoEXT</type>* <name>pTagInfo</name></param>
</command>
- <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdDebugMarkerBeginEXT</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param>const <type>VkDebugMarkerMarkerInfoEXT</type>* <name>pMarkerInfo</name></param>
</command>
- <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdDebugMarkerEndEXT</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
</command>
- <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdDebugMarkerInsertEXT</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param>const <type>VkDebugMarkerMarkerInfoEXT</type>* <name>pMarkerInfo</name></param>
@@ -8939,18 +11068,18 @@ typedef void <name>CAMetalLayer</name>;
<param><type>VkExternalMemoryHandleTypeFlagsNV</type> <name>handleType</name></param>
<param><type>HANDLE</type>* <name>pHandle</name></param>
</command>
- <command queues="graphics,compute" renderpass="inside" cmdbufferlevel="primary,secondary">
+ <command queues="graphics,compute" renderpass="inside" cmdbufferlevel="primary,secondary" tasks="action,indirection">
<proto><type>void</type> <name>vkCmdExecuteGeneratedCommandsNV</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkBool32</type> <name>isPreprocessed</name></param>
<param>const <type>VkGeneratedCommandsInfoNV</type>* <name>pGeneratedCommandsInfo</name></param>
</command>
- <command queues="graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <command queues="graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdPreprocessGeneratedCommandsNV</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param>const <type>VkGeneratedCommandsInfoNV</type>* <name>pGeneratedCommandsInfo</name></param>
</command>
- <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdBindPipelineShaderGroupNV</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkPipelineBindPoint</type> <name>pipelineBindPoint</name></param>
@@ -8995,7 +11124,7 @@ typedef void <name>CAMetalLayer</name>;
<param><type>VkFormatProperties2</type>* <name>pFormatProperties</name></param>
</command>
<command name="vkGetPhysicalDeviceFormatProperties2KHR" alias="vkGetPhysicalDeviceFormatProperties2"/>
- <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_FORMAT_NOT_SUPPORTED">
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_FORMAT_NOT_SUPPORTED,VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR,VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR,VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR,VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR,VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR">
<proto><type>VkResult</type> <name>vkGetPhysicalDeviceImageFormatProperties2</name></proto>
<param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
<param>const <type>VkPhysicalDeviceImageFormatInfo2</type>* <name>pImageFormatInfo</name></param>
@@ -9023,7 +11152,7 @@ typedef void <name>CAMetalLayer</name>;
<param optional="true" len="pPropertyCount"><type>VkSparseImageFormatProperties2</type>* <name>pProperties</name></param>
</command>
<command name="vkGetPhysicalDeviceSparseImageFormatProperties2KHR" alias="vkGetPhysicalDeviceSparseImageFormatProperties2"/>
- <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdPushDescriptorSetKHR</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkPipelineBindPoint</type> <name>pipelineBindPoint</name></param>
@@ -9253,7 +11382,7 @@ typedef void <name>CAMetalLayer</name>;
<param len="bindInfoCount">const <type>VkBindImageMemoryInfo</type>* <name>pBindInfos</name></param>
</command>
<command name="vkBindImageMemory2KHR" alias="vkBindImageMemory2"/>
- <command queues="graphics,compute,transfer" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics,compute,transfer" renderpass="both" videocoding="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdSetDeviceMask</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>deviceMask</name></param>
@@ -9276,7 +11405,7 @@ typedef void <name>CAMetalLayer</name>;
<param>const <type>VkAcquireNextImageInfoKHR</type>* <name>pAcquireInfo</name></param>
<param><type>uint32_t</type>* <name>pImageIndex</name></param>
</command>
- <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdDispatchBase</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>baseGroupX</name></param>
@@ -9312,12 +11441,12 @@ typedef void <name>CAMetalLayer</name>;
<command>
<proto><type>void</type> <name>vkUpdateDescriptorSetWithTemplate</name></proto>
<param><type>VkDevice</type> <name>device</name></param>
- <param externsync="true"><type>VkDescriptorSet</type> <name>descriptorSet</name></param>
+ <param><type>VkDescriptorSet</type> <name>descriptorSet</name></param>
<param><type>VkDescriptorUpdateTemplate</type> <name>descriptorUpdateTemplate</name></param>
<param noautovalidity="true">const <type>void</type>* <name>pData</name></param>
</command>
<command name="vkUpdateDescriptorSetWithTemplateKHR" alias="vkUpdateDescriptorSetWithTemplate"/>
- <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdPushDescriptorSetWithTemplateKHR</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkDescriptorUpdateTemplate</type> <name>descriptorUpdateTemplate</name></param>
@@ -9371,21 +11500,21 @@ typedef void <name>CAMetalLayer</name>;
<param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
<param><type>VkSurfaceKHR</type>* <name>pSurface</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdSetViewportWScalingNV</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>firstViewport</name></param>
<param><type>uint32_t</type> <name>viewportCount</name></param>
<param len="viewportCount">const <type>VkViewportWScalingNV</type>* <name>pViewportWScalings</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdSetDiscardRectangleEXT</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>firstDiscardRectangle</name></param>
<param><type>uint32_t</type> <name>discardRectangleCount</name></param>
<param len="discardRectangleCount">const <type>VkRect2D</type>* <name>pDiscardRectangles</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdSetSampleLocationsEXT</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param>const <type>VkSampleLocationsInfoEXT</type>* <name>pSampleLocationsInfo</name></param>
@@ -9456,6 +11585,28 @@ typedef void <name>CAMetalLayer</name>;
<param optional="true" len="pSparseMemoryRequirementCount"><type>VkSparseImageMemoryRequirements2</type>* <name>pSparseMemoryRequirements</name></param>
</command>
<command name="vkGetImageSparseMemoryRequirements2KHR" alias="vkGetImageSparseMemoryRequirements2"/>
+ <command>
+ <proto><type>void</type> <name>vkGetDeviceBufferMemoryRequirements</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkDeviceBufferMemoryRequirements</type>* <name>pInfo</name></param>
+ <param><type>VkMemoryRequirements2</type>* <name>pMemoryRequirements</name></param>
+ </command>
+ <command name="vkGetDeviceBufferMemoryRequirementsKHR" alias="vkGetDeviceBufferMemoryRequirements"/>
+ <command>
+ <proto><type>void</type> <name>vkGetDeviceImageMemoryRequirements</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkDeviceImageMemoryRequirements</type>* <name>pInfo</name></param>
+ <param><type>VkMemoryRequirements2</type>* <name>pMemoryRequirements</name></param>
+ </command>
+ <command name="vkGetDeviceImageMemoryRequirementsKHR" alias="vkGetDeviceImageMemoryRequirements"/>
+ <command>
+ <proto><type>void</type> <name>vkGetDeviceImageSparseMemoryRequirements</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkDeviceImageMemoryRequirements</type>* <name>pInfo</name></param>
+ <param optional="false,true"><type>uint32_t</type>* <name>pSparseMemoryRequirementCount</name></param>
+ <param optional="true" len="pSparseMemoryRequirementCount"><type>VkSparseImageMemoryRequirements2</type>* <name>pSparseMemoryRequirements</name></param>
+ </command>
+ <command name="vkGetDeviceImageSparseMemoryRequirementsKHR" alias="vkGetDeviceImageSparseMemoryRequirements"/>
<command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
<proto><type>VkResult</type> <name>vkCreateSamplerYcbcrConversion</name></proto>
<param><type>VkDevice</type> <name>device</name></param>
@@ -9596,16 +11747,16 @@ typedef void <name>CAMetalLayer</name>;
<param><type>VkQueue</type> <name>queue</name></param>
<param>const <type>VkDebugUtilsLabelEXT</type>* <name>pLabelInfo</name></param>
</command>
- <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary" tasks="action,state">
<proto><type>void</type> <name>vkCmdBeginDebugUtilsLabelEXT</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param>const <type>VkDebugUtilsLabelEXT</type>* <name>pLabelInfo</name></param>
</command>
- <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary" tasks="action,state">
<proto><type>void</type> <name>vkCmdEndDebugUtilsLabelEXT</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
</command>
- <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdInsertDebugUtilsLabelEXT</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param>const <type>VkDebugUtilsLabelEXT</type>* <name>pLabelInfo</name></param>
@@ -9637,10 +11788,10 @@ typedef void <name>CAMetalLayer</name>;
<param optional="false">const <type>void</type>* <name>pHostPointer</name></param>
<param><type>VkMemoryHostPointerPropertiesEXT</type>* <name>pMemoryHostPointerProperties</name></param>
</command>
- <command queues="transfer,graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="transfer,graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdWriteBufferMarkerAMD</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
- <param><type>VkPipelineStageFlagBits</type> <name>pipelineStage</name></param>
+ <param optional="true"><type>VkPipelineStageFlagBits</type> <name>pipelineStage</name></param>
<param><type>VkBuffer</type> <name>dstBuffer</name></param>
<param><type>VkDeviceSize</type> <name>dstOffset</name></param>
<param><type>uint32_t</type> <name>marker</name></param>
@@ -9653,21 +11804,21 @@ typedef void <name>CAMetalLayer</name>;
<param><type>VkRenderPass</type>* <name>pRenderPass</name></param>
</command>
<command name="vkCreateRenderPass2KHR" alias="vkCreateRenderPass2"/>
- <command queues="graphics" renderpass="outside" cmdbufferlevel="primary">
+ <command queues="graphics" renderpass="outside" cmdbufferlevel="primary" tasks="action,state,synchronization">
<proto><type>void</type> <name>vkCmdBeginRenderPass2</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param>const <type>VkRenderPassBeginInfo</type>* <name>pRenderPassBegin</name></param>
<param>const <type>VkSubpassBeginInfo</type>* <name>pSubpassBeginInfo</name></param>
</command>
<command name="vkCmdBeginRenderPass2KHR" alias="vkCmdBeginRenderPass2"/>
- <command queues="graphics" renderpass="inside" cmdbufferlevel="primary">
+ <command queues="graphics" renderpass="inside" cmdbufferlevel="primary" tasks="action,state,synchronization">
<proto><type>void</type> <name>vkCmdNextSubpass2</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param>const <type>VkSubpassBeginInfo</type>* <name>pSubpassBeginInfo</name></param>
<param>const <type>VkSubpassEndInfo</type>* <name>pSubpassEndInfo</name></param>
</command>
<command name="vkCmdNextSubpass2KHR" alias="vkCmdNextSubpass2"/>
- <command queues="graphics" renderpass="inside" cmdbufferlevel="primary">
+ <command queues="graphics" renderpass="inside" cmdbufferlevel="primary" tasks="action,state,synchronization">
<proto><type>void</type> <name>vkCmdEndRenderPass2</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param>const <type>VkSubpassEndInfo</type>* <name>pSubpassEndInfo</name></param>
@@ -9705,7 +11856,7 @@ typedef void <name>CAMetalLayer</name>;
<param>const <type>VkMemoryGetAndroidHardwareBufferInfoANDROID</type>* <name>pInfo</name></param>
<param>struct <type>AHardwareBuffer</type>** <name>pBuffer</name></param>
</command>
- <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdDrawIndirectCount</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkBuffer</type> <name>buffer</name></param>
@@ -9717,7 +11868,7 @@ typedef void <name>CAMetalLayer</name>;
</command>
<command name="vkCmdDrawIndirectCountKHR" alias="vkCmdDrawIndirectCount"/>
<command name="vkCmdDrawIndirectCountAMD" alias="vkCmdDrawIndirectCount"/>
- <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdDrawIndexedIndirectCount</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkBuffer</type> <name>buffer</name></param>
@@ -9729,7 +11880,7 @@ typedef void <name>CAMetalLayer</name>;
</command>
<command name="vkCmdDrawIndexedIndirectCountKHR" alias="vkCmdDrawIndexedIndirectCount"/>
<command name="vkCmdDrawIndexedIndirectCountAMD" alias="vkCmdDrawIndexedIndirectCount"/>
- <command queues="graphics,compute,transfer" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics,compute,transfer" renderpass="both" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdSetCheckpointNV</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param noautovalidity="true">const <type>void</type>* <name>pCheckpointMarker</name></param>
@@ -9740,7 +11891,7 @@ typedef void <name>CAMetalLayer</name>;
<param optional="false,true"><type>uint32_t</type>* <name>pCheckpointDataCount</name></param>
<param optional="true" len="pCheckpointDataCount"><type>VkCheckpointDataNV</type>* <name>pCheckpointData</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdBindTransformFeedbackBuffersEXT</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>firstBinding</name></param>
@@ -9749,7 +11900,7 @@ typedef void <name>CAMetalLayer</name>;
<param len="bindingCount">const <type>VkDeviceSize</type>* <name>pOffsets</name></param>
<param optional="true" len="bindingCount" noautovalidity="true">const <type>VkDeviceSize</type>* <name>pSizes</name></param>
</command>
- <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdBeginTransformFeedbackEXT</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>firstCounterBuffer</name></param>
@@ -9757,7 +11908,7 @@ typedef void <name>CAMetalLayer</name>;
<param noautovalidity="true" len="counterBufferCount">const <type>VkBuffer</type>* <name>pCounterBuffers</name></param>
<param optional="true" len="counterBufferCount">const <type>VkDeviceSize</type>* <name>pCounterBufferOffsets</name></param>
</command>
- <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdEndTransformFeedbackEXT</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>firstCounterBuffer</name></param>
@@ -9765,7 +11916,7 @@ typedef void <name>CAMetalLayer</name>;
<param noautovalidity="true" len="counterBufferCount">const <type>VkBuffer</type>* <name>pCounterBuffers</name></param>
<param optional="true" len="counterBufferCount">const <type>VkDeviceSize</type>* <name>pCounterBufferOffsets</name></param>
</command>
- <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics,compute,decode,encode" renderpass="both" cmdbufferlevel="primary,secondary" tasks="action,state">
<proto><type>void</type> <name>vkCmdBeginQueryIndexedEXT</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkQueryPool</type> <name>queryPool</name></param>
@@ -9773,14 +11924,14 @@ typedef void <name>CAMetalLayer</name>;
<param optional="true"><type>VkQueryControlFlags</type> <name>flags</name></param>
<param><type>uint32_t</type> <name>index</name></param>
</command>
- <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics,compute,decode,encode" renderpass="both" cmdbufferlevel="primary,secondary" tasks="action,state">
<proto><type>void</type> <name>vkCmdEndQueryIndexedEXT</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkQueryPool</type> <name>queryPool</name></param>
<param><type>uint32_t</type> <name>query</name></param>
<param><type>uint32_t</type> <name>index</name></param>
</command>
- <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdDrawIndirectByteCountEXT</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>instanceCount</name></param>
@@ -9790,40 +11941,40 @@ typedef void <name>CAMetalLayer</name>;
<param><type>uint32_t</type> <name>counterOffset</name></param>
<param><type>uint32_t</type> <name>vertexStride</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdSetExclusiveScissorNV</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>firstExclusiveScissor</name></param>
<param><type>uint32_t</type> <name>exclusiveScissorCount</name></param>
<param len="exclusiveScissorCount">const <type>VkRect2D</type>* <name>pExclusiveScissors</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdBindShadingRateImageNV</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param optional="true"><type>VkImageView</type> <name>imageView</name></param>
<param><type>VkImageLayout</type> <name>imageLayout</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdSetViewportShadingRatePaletteNV</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>firstViewport</name></param>
<param><type>uint32_t</type> <name>viewportCount</name></param>
<param len="viewportCount">const <type>VkShadingRatePaletteNV</type>* <name>pShadingRatePalettes</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdSetCoarseSampleOrderNV</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkCoarseSampleOrderTypeNV</type> <name>sampleOrderType</name></param>
<param optional="true"><type>uint32_t</type> <name>customSampleOrderCount</name></param>
<param len="customSampleOrderCount">const <type>VkCoarseSampleOrderCustomNV</type>* <name>pCustomSampleOrders</name></param>
</command>
- <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdDrawMeshTasksNV</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>taskCount</name></param>
<param><type>uint32_t</type> <name>firstTask</name></param>
</command>
- <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdDrawMeshTasksIndirectNV</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkBuffer</type> <name>buffer</name></param>
@@ -9831,7 +11982,7 @@ typedef void <name>CAMetalLayer</name>;
<param><type>uint32_t</type> <name>drawCount</name></param>
<param><type>uint32_t</type> <name>stride</name></param>
</command>
- <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdDrawMeshTasksIndirectCountNV</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkBuffer</type> <name>buffer</name></param>
@@ -9841,6 +11992,31 @@ typedef void <name>CAMetalLayer</name>;
<param><type>uint32_t</type> <name>maxDrawCount</name></param>
<param><type>uint32_t</type> <name>stride</name></param>
</command>
+ <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary" tasks="action">
+ <proto><type>void</type> <name>vkCmdDrawMeshTasksEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>uint32_t</type> <name>groupCountX</name></param>
+ <param><type>uint32_t</type> <name>groupCountY</name></param>
+ <param><type>uint32_t</type> <name>groupCountZ</name></param>
+ </command>
+ <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary" tasks="action">
+ <proto><type>void</type> <name>vkCmdDrawMeshTasksIndirectEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkBuffer</type> <name>buffer</name></param>
+ <param><type>VkDeviceSize</type> <name>offset</name></param>
+ <param><type>uint32_t</type> <name>drawCount</name></param>
+ <param><type>uint32_t</type> <name>stride</name></param>
+ </command>
+ <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary" tasks="action">
+ <proto><type>void</type> <name>vkCmdDrawMeshTasksIndirectCountEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkBuffer</type> <name>buffer</name></param>
+ <param><type>VkDeviceSize</type> <name>offset</name></param>
+ <param><type>VkBuffer</type> <name>countBuffer</name></param>
+ <param><type>VkDeviceSize</type> <name>countBufferOffset</name></param>
+ <param><type>uint32_t</type> <name>maxDrawCount</name></param>
+ <param><type>uint32_t</type> <name>stride</name></param>
+ </command>
<command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
<proto><type>VkResult</type> <name>vkCompileDeferredNV</name></proto>
<param><type>VkDevice</type> <name>device</name></param>
@@ -9854,7 +12030,7 @@ typedef void <name>CAMetalLayer</name>;
<param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
<param><type>VkAccelerationStructureNV</type>* <name>pAccelerationStructure</name></param>
</command>
- <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdBindInvocationMaskHUAWEI</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param optional="true"><type>VkImageView</type> <name>imageView</name></param>
@@ -9884,14 +12060,14 @@ typedef void <name>CAMetalLayer</name>;
<param><type>uint32_t</type> <name>bindInfoCount</name></param>
<param len="bindInfoCount">const <type>VkBindAccelerationStructureMemoryInfoNV</type>* <name>pBindInfos</name></param>
</command>
- <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdCopyAccelerationStructureNV</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkAccelerationStructureNV</type> <name>dst</name></param>
<param><type>VkAccelerationStructureNV</type> <name>src</name></param>
<param><type>VkCopyAccelerationStructureModeKHR</type> <name>mode</name></param>
</command>
- <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdCopyAccelerationStructureKHR</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param>const <type>VkCopyAccelerationStructureInfoKHR</type>* <name>pInfo</name></param>
@@ -9902,7 +12078,7 @@ typedef void <name>CAMetalLayer</name>;
<param optional="true"><type>VkDeferredOperationKHR</type> <name>deferredOperation</name></param>
<param>const <type>VkCopyAccelerationStructureInfoKHR</type>* <name>pInfo</name></param>
</command>
- <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdCopyAccelerationStructureToMemoryKHR</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param>const <type>VkCopyAccelerationStructureToMemoryInfoKHR</type>* <name>pInfo</name></param>
@@ -9913,7 +12089,7 @@ typedef void <name>CAMetalLayer</name>;
<param optional="true"><type>VkDeferredOperationKHR</type> <name>deferredOperation</name></param>
<param>const <type>VkCopyAccelerationStructureToMemoryInfoKHR</type>* <name>pInfo</name></param>
</command>
- <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdCopyMemoryToAccelerationStructureKHR</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param>const <type>VkCopyMemoryToAccelerationStructureInfoKHR</type>* <name>pInfo</name></param>
@@ -9924,7 +12100,7 @@ typedef void <name>CAMetalLayer</name>;
<param optional="true"><type>VkDeferredOperationKHR</type> <name>deferredOperation</name></param>
<param>const <type>VkCopyMemoryToAccelerationStructureInfoKHR</type>* <name>pInfo</name></param>
</command>
- <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdWriteAccelerationStructuresPropertiesKHR</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>accelerationStructureCount</name></param>
@@ -9933,7 +12109,7 @@ typedef void <name>CAMetalLayer</name>;
<param><type>VkQueryPool</type> <name>queryPool</name></param>
<param><type>uint32_t</type> <name>firstQuery</name></param>
</command>
- <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdWriteAccelerationStructuresPropertiesNV</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>accelerationStructureCount</name></param>
@@ -9942,7 +12118,7 @@ typedef void <name>CAMetalLayer</name>;
<param><type>VkQueryPool</type> <name>queryPool</name></param>
<param><type>uint32_t</type> <name>firstQuery</name></param>
</command>
- <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdBuildAccelerationStructureNV</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param>const <type>VkAccelerationStructureInfoNV</type>* <name>pInfo</name></param>
@@ -9964,7 +12140,7 @@ typedef void <name>CAMetalLayer</name>;
<param len="dataSize"><type>void</type>* <name>pData</name></param>
<param><type>size_t</type> <name>stride</name></param>
</command>
- <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdTraceRaysKHR</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param>const <type>VkStridedDeviceAddressRegionKHR</type>* <name>pRaygenShaderBindingTable</name></param>
@@ -9975,7 +12151,7 @@ typedef void <name>CAMetalLayer</name>;
<param><type>uint32_t</type> <name>height</name></param>
<param><type>uint32_t</type> <name>depth</name></param>
</command>
- <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdTraceRaysNV</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkBuffer</type> <name>raygenShaderBindingTableBuffer</name></param>
@@ -10044,7 +12220,7 @@ typedef void <name>CAMetalLayer</name>;
<param optional="false,true"><type>uint32_t</type>* <name>pPropertyCount</name></param>
<param optional="true" len="pPropertyCount"><type>VkCooperativeMatrixPropertiesNV</type>* <name>pProperties</name></param>
</command>
- <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdTraceRaysIndirectKHR</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param>const <type>VkStridedDeviceAddressRegionKHR</type>* <name>pRaygenShaderBindingTable</name></param>
@@ -10053,6 +12229,11 @@ typedef void <name>CAMetalLayer</name>;
<param>const <type>VkStridedDeviceAddressRegionKHR</type>* <name>pCallableShaderBindingTable</name></param>
<param><type>VkDeviceAddress</type> <name>indirectDeviceAddress</name></param>
</command>
+ <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
+ <proto><type>void</type> <name>vkCmdTraceRaysIndirect2KHR</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkDeviceAddress</type> <name>indirectDeviceAddress</name></param>
+ </command>
<command>
<proto><type>void</type> <name>vkGetDeviceAccelerationStructureCompatibilityKHR</name></proto>
<param><type>VkDevice</type> <name>device</name></param>
@@ -10066,7 +12247,7 @@ typedef void <name>CAMetalLayer</name>;
<param><type>uint32_t</type> <name>group</name></param>
<param><type>VkShaderGroupShaderKHR</type> <name>groupShader</name></param>
</command>
- <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdSetRayTracingPipelineStackSizeKHR</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>pipelineStackSize</name></param>
@@ -10169,17 +12350,17 @@ typedef void <name>CAMetalLayer</name>;
<proto><type>void</type> <name>vkUninitializePerformanceApiINTEL</name></proto>
<param><type>VkDevice</type> <name>device</name></param>
</command>
- <command queues="graphics,compute,transfer" renderpass="both" cmdbufferlevel="primary,secondary" successcodes="VK_SUCCESS" errorcodes="VK_ERROR_TOO_MANY_OBJECTS,VK_ERROR_OUT_OF_HOST_MEMORY">
+ <command queues="graphics,compute,transfer" renderpass="both" cmdbufferlevel="primary,secondary" successcodes="VK_SUCCESS" errorcodes="VK_ERROR_TOO_MANY_OBJECTS,VK_ERROR_OUT_OF_HOST_MEMORY" tasks="action,state">
<proto><type>VkResult</type> <name>vkCmdSetPerformanceMarkerINTEL</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param>const <type>VkPerformanceMarkerInfoINTEL</type>* <name>pMarkerInfo</name></param>
</command>
- <command queues="graphics,compute,transfer" renderpass="both" cmdbufferlevel="primary,secondary" successcodes="VK_SUCCESS" errorcodes="VK_ERROR_TOO_MANY_OBJECTS,VK_ERROR_OUT_OF_HOST_MEMORY">
+ <command queues="graphics,compute,transfer" renderpass="both" cmdbufferlevel="primary,secondary" successcodes="VK_SUCCESS" errorcodes="VK_ERROR_TOO_MANY_OBJECTS,VK_ERROR_OUT_OF_HOST_MEMORY" tasks="action,state">
<proto><type>VkResult</type> <name>vkCmdSetPerformanceStreamMarkerINTEL</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param>const <type>VkPerformanceStreamMarkerInfoINTEL</type>* <name>pMarkerInfo</name></param>
</command>
- <command queues="graphics,compute,transfer" renderpass="both" cmdbufferlevel="primary,secondary" successcodes="VK_SUCCESS" errorcodes="VK_ERROR_TOO_MANY_OBJECTS,VK_ERROR_OUT_OF_HOST_MEMORY">
+ <command queues="graphics,compute,transfer" renderpass="both" cmdbufferlevel="primary,secondary" successcodes="VK_SUCCESS" errorcodes="VK_ERROR_TOO_MANY_OBJECTS,VK_ERROR_OUT_OF_HOST_MEMORY" tasks="state">
<proto><type>VkResult</type> <name>vkCmdSetPerformanceOverrideINTEL</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param>const <type>VkPerformanceOverrideInfoINTEL</type>* <name>pOverrideInfo</name></param>
@@ -10233,18 +12414,19 @@ typedef void <name>CAMetalLayer</name>;
<param optional="false,true"><type>uint32_t</type>* <name>pInternalRepresentationCount</name></param>
<param optional="true" len="pInternalRepresentationCount"><type>VkPipelineExecutableInternalRepresentationKHR</type>* <name>pInternalRepresentations</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdSetLineStippleEXT</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>lineStippleFactor</name></param>
<param><type>uint16_t</type> <name>lineStipplePattern</name></param>
</command>
<command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY">
- <proto><type>VkResult</type> <name>vkGetPhysicalDeviceToolPropertiesEXT</name></proto>
+ <proto><type>VkResult</type> <name>vkGetPhysicalDeviceToolProperties</name></proto>
<param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
<param optional="false,true"><type>uint32_t</type>* <name>pToolCount</name></param>
- <param optional="true" len="pToolCount"><type>VkPhysicalDeviceToolPropertiesEXT</type>* <name>pToolProperties</name></param>
+ <param optional="true" len="pToolCount"><type>VkPhysicalDeviceToolProperties</type>* <name>pToolProperties</name></param>
</command>
+ <command name="vkGetPhysicalDeviceToolPropertiesEXT" alias="vkGetPhysicalDeviceToolProperties"/>
<command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS_KHR">
<proto><type>VkResult</type> <name>vkCreateAccelerationStructureKHR</name></proto>
<param><type>VkDevice</type> <name>device</name></param>
@@ -10252,14 +12434,14 @@ typedef void <name>CAMetalLayer</name>;
<param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
<param><type>VkAccelerationStructureKHR</type>* <name>pAccelerationStructure</name></param>
</command>
- <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdBuildAccelerationStructuresKHR</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>infoCount</name></param>
<param len="infoCount">const <type>VkAccelerationStructureBuildGeometryInfoKHR</type>* <name>pInfos</name></param>
<param len="infoCount">const <type>VkAccelerationStructureBuildRangeInfoKHR</type>* const* <name>ppBuildRangeInfos</name></param>
</command>
- <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary">
+ <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdBuildAccelerationStructuresIndirectKHR</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>infoCount</name></param>
@@ -10308,35 +12490,40 @@ typedef void <name>CAMetalLayer</name>;
<param><type>VkDevice</type> <name>device</name></param>
<param><type>VkDeferredOperationKHR</type> <name>operation</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
- <proto><type>void</type> <name>vkCmdSetCullModeEXT</name></proto>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetCullMode</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param optional="true"><type>VkCullModeFlags</type> <name>cullMode</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
- <proto><type>void</type> <name>vkCmdSetFrontFaceEXT</name></proto>
+ <command name="vkCmdSetCullModeEXT" alias="vkCmdSetCullMode"/>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetFrontFace</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkFrontFace</type> <name>frontFace</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
- <proto><type>void</type> <name>vkCmdSetPrimitiveTopologyEXT</name></proto>
+ <command name="vkCmdSetFrontFaceEXT" alias="vkCmdSetFrontFace"/>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetPrimitiveTopology</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkPrimitiveTopology</type> <name>primitiveTopology</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
- <proto><type>void</type> <name>vkCmdSetViewportWithCountEXT</name></proto>
+ <command name="vkCmdSetPrimitiveTopologyEXT" alias="vkCmdSetPrimitiveTopology"/>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetViewportWithCount</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>viewportCount</name></param>
<param len="viewportCount">const <type>VkViewport</type>* <name>pViewports</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
- <proto><type>void</type> <name>vkCmdSetScissorWithCountEXT</name></proto>
+ <command name="vkCmdSetViewportWithCountEXT" alias="vkCmdSetViewportWithCount"/>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetScissorWithCount</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>scissorCount</name></param>
<param len="scissorCount">const <type>VkRect2D</type>* <name>pScissors</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
- <proto><type>void</type> <name>vkCmdBindVertexBuffers2EXT</name></proto>
+ <command name="vkCmdSetScissorWithCountEXT" alias="vkCmdSetScissorWithCount"/>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdBindVertexBuffers2</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>firstBinding</name></param>
<param><type>uint32_t</type> <name>bindingCount</name></param>
@@ -10345,33 +12532,39 @@ typedef void <name>CAMetalLayer</name>;
<param optional="true" len="bindingCount">const <type>VkDeviceSize</type>* <name>pSizes</name></param>
<param optional="true" len="bindingCount">const <type>VkDeviceSize</type>* <name>pStrides</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
- <proto><type>void</type> <name>vkCmdSetDepthTestEnableEXT</name></proto>
+ <command name="vkCmdBindVertexBuffers2EXT" alias="vkCmdBindVertexBuffers2"/>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetDepthTestEnable</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkBool32</type> <name>depthTestEnable</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
- <proto><type>void</type> <name>vkCmdSetDepthWriteEnableEXT</name></proto>
+ <command name="vkCmdSetDepthTestEnableEXT" alias="vkCmdSetDepthTestEnable"/>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetDepthWriteEnable</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkBool32</type> <name>depthWriteEnable</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
- <proto><type>void</type> <name>vkCmdSetDepthCompareOpEXT</name></proto>
+ <command name="vkCmdSetDepthWriteEnableEXT" alias="vkCmdSetDepthWriteEnable"/>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetDepthCompareOp</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkCompareOp</type> <name>depthCompareOp</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
- <proto><type>void</type> <name>vkCmdSetDepthBoundsTestEnableEXT</name></proto>
+ <command name="vkCmdSetDepthCompareOpEXT" alias="vkCmdSetDepthCompareOp"/>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetDepthBoundsTestEnable</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkBool32</type> <name>depthBoundsTestEnable</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
- <proto><type>void</type> <name>vkCmdSetStencilTestEnableEXT</name></proto>
+ <command name="vkCmdSetDepthBoundsTestEnableEXT" alias="vkCmdSetDepthBoundsTestEnable"/>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetStencilTestEnable</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkBool32</type> <name>stencilTestEnable</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
- <proto><type>void</type> <name>vkCmdSetStencilOpEXT</name></proto>
+ <command name="vkCmdSetStencilTestEnableEXT" alias="vkCmdSetStencilTestEnable"/>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetStencilOp</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkStencilFaceFlags</type> <name>faceMask</name></param>
<param><type>VkStencilOp</type> <name>failOp</name></param>
@@ -10379,91 +12572,272 @@ typedef void <name>CAMetalLayer</name>;
<param><type>VkStencilOp</type> <name>depthFailOp</name></param>
<param><type>VkCompareOp</type> <name>compareOp</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command name="vkCmdSetStencilOpEXT" alias="vkCmdSetStencilOp"/>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdSetPatchControlPointsEXT</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>patchControlPoints</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
- <proto><type>void</type> <name>vkCmdSetRasterizerDiscardEnableEXT</name></proto>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetRasterizerDiscardEnable</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkBool32</type> <name>rasterizerDiscardEnable</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
- <proto><type>void</type> <name>vkCmdSetDepthBiasEnableEXT</name></proto>
+ <command name="vkCmdSetRasterizerDiscardEnableEXT" alias="vkCmdSetRasterizerDiscardEnable"/>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetDepthBiasEnable</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkBool32</type> <name>depthBiasEnable</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command name="vkCmdSetDepthBiasEnableEXT" alias="vkCmdSetDepthBiasEnable"/>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdSetLogicOpEXT</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkLogicOp</type> <name>logicOp</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
- <proto><type>void</type> <name>vkCmdSetPrimitiveRestartEnableEXT</name></proto>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetPrimitiveRestartEnable</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkBool32</type> <name>primitiveRestartEnable</name></param>
</command>
+ <command name="vkCmdSetPrimitiveRestartEnableEXT" alias="vkCmdSetPrimitiveRestartEnable"/>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetTessellationDomainOriginEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkTessellationDomainOrigin</type> <name>domainOrigin</name></param>
+ </command>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetDepthClampEnableEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkBool32</type> <name>depthClampEnable</name></param>
+ </command>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetPolygonModeEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkPolygonMode</type> <name>polygonMode</name></param>
+ </command>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetRasterizationSamplesEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkSampleCountFlagBits</type> <name>rasterizationSamples</name></param>
+ </command>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetSampleMaskEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkSampleCountFlagBits</type> <name>samples</name></param>
+ <param len="latexmath:[\lceil{\mathit{samples} \over 32}\rceil]" altlen="(samples + 31) / 32">const <type>VkSampleMask</type>* <name>pSampleMask</name></param>
+ </command>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetAlphaToCoverageEnableEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkBool32</type> <name>alphaToCoverageEnable</name></param>
+ </command>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetAlphaToOneEnableEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkBool32</type> <name>alphaToOneEnable</name></param>
+ </command>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetLogicOpEnableEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkBool32</type> <name>logicOpEnable</name></param>
+ </command>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetColorBlendEnableEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>uint32_t</type> <name>firstAttachment</name></param>
+ <param><type>uint32_t</type> <name>attachmentCount</name></param>
+ <param len="attachmentCount">const <type>VkBool32</type>* <name>pColorBlendEnables</name></param>
+ </command>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetColorBlendEquationEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>uint32_t</type> <name>firstAttachment</name></param>
+ <param><type>uint32_t</type> <name>attachmentCount</name></param>
+ <param len="attachmentCount">const <type>VkColorBlendEquationEXT</type>* <name>pColorBlendEquations</name></param>
+ </command>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetColorWriteMaskEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>uint32_t</type> <name>firstAttachment</name></param>
+ <param><type>uint32_t</type> <name>attachmentCount</name></param>
+ <param len="attachmentCount" optional="false,true">const <type>VkColorComponentFlags</type>* <name>pColorWriteMasks</name></param>
+ </command>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetRasterizationStreamEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>uint32_t</type> <name>rasterizationStream</name></param>
+ </command>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetConservativeRasterizationModeEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkConservativeRasterizationModeEXT</type> <name>conservativeRasterizationMode</name></param>
+ </command>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetExtraPrimitiveOverestimationSizeEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>float</type> <name>extraPrimitiveOverestimationSize</name></param>
+ </command>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetDepthClipEnableEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkBool32</type> <name>depthClipEnable</name></param>
+ </command>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetSampleLocationsEnableEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkBool32</type> <name>sampleLocationsEnable</name></param>
+ </command>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetColorBlendAdvancedEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>uint32_t</type> <name>firstAttachment</name></param>
+ <param><type>uint32_t</type> <name>attachmentCount</name></param>
+ <param len="attachmentCount">const <type>VkColorBlendAdvancedEXT</type>* <name>pColorBlendAdvanced</name></param>
+ </command>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetProvokingVertexModeEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkProvokingVertexModeEXT</type> <name>provokingVertexMode</name></param>
+ </command>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetLineRasterizationModeEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkLineRasterizationModeEXT</type> <name>lineRasterizationMode</name></param>
+ </command>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetLineStippleEnableEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkBool32</type> <name>stippledLineEnable</name></param>
+ </command>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetDepthClipNegativeOneToOneEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkBool32</type> <name>negativeOneToOne</name></param>
+ </command>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetViewportWScalingEnableNV</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkBool32</type> <name>viewportWScalingEnable</name></param>
+ </command>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetViewportSwizzleNV</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>uint32_t</type> <name>firstViewport</name></param>
+ <param><type>uint32_t</type> <name>viewportCount</name></param>
+ <param len="viewportCount">const <type>VkViewportSwizzleNV</type>* <name>pViewportSwizzles</name></param>
+ </command>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetCoverageToColorEnableNV</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkBool32</type> <name>coverageToColorEnable</name></param>
+ </command>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetCoverageToColorLocationNV</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>uint32_t</type> <name>coverageToColorLocation</name></param>
+ </command>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetCoverageModulationModeNV</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkCoverageModulationModeNV</type> <name>coverageModulationMode</name></param>
+ </command>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetCoverageModulationTableEnableNV</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkBool32</type> <name>coverageModulationTableEnable</name></param>
+ </command>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetCoverageModulationTableNV</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>uint32_t</type> <name>coverageModulationTableCount</name></param>
+ <param len="coverageModulationTableCount">const <type>float</type>* <name>pCoverageModulationTable</name></param>
+ </command>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetShadingRateImageEnableNV</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkBool32</type> <name>shadingRateImageEnable</name></param>
+ </command>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetCoverageReductionModeNV</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkCoverageReductionModeNV</type> <name>coverageReductionMode</name></param>
+ </command>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetRepresentativeFragmentTestEnableNV</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkBool32</type> <name>representativeFragmentTestEnable</name></param>
+ </command>
<command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY">
- <proto><type>VkResult</type> <name>vkCreatePrivateDataSlotEXT</name></proto>
+ <proto><type>VkResult</type> <name>vkCreatePrivateDataSlot</name></proto>
<param><type>VkDevice</type> <name>device</name></param>
- <param>const <type>VkPrivateDataSlotCreateInfoEXT</type>* <name>pCreateInfo</name></param>
+ <param>const <type>VkPrivateDataSlotCreateInfo</type>* <name>pCreateInfo</name></param>
<param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
- <param><type>VkPrivateDataSlotEXT</type>* <name>pPrivateDataSlot</name></param>
+ <param><type>VkPrivateDataSlot</type>* <name>pPrivateDataSlot</name></param>
</command>
+ <command name="vkCreatePrivateDataSlotEXT" alias="vkCreatePrivateDataSlot"/>
<command>
- <proto><type>void</type> <name>vkDestroyPrivateDataSlotEXT</name></proto>
+ <proto><type>void</type> <name>vkDestroyPrivateDataSlot</name></proto>
<param><type>VkDevice</type> <name>device</name></param>
- <param optional="true" externsync="true"><type>VkPrivateDataSlotEXT</type> <name>privateDataSlot</name></param>
+ <param optional="true" externsync="true"><type>VkPrivateDataSlot</type> <name>privateDataSlot</name></param>
<param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
</command>
+ <command name="vkDestroyPrivateDataSlotEXT" alias="vkDestroyPrivateDataSlot"/>
<command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY">
- <proto><type>VkResult</type> <name>vkSetPrivateDataEXT</name></proto>
+ <proto><type>VkResult</type> <name>vkSetPrivateData</name></proto>
<param><type>VkDevice</type> <name>device</name></param>
<param><type>VkObjectType</type> <name>objectType</name></param>
<param objecttype="objectType"><type>uint64_t</type> <name>objectHandle</name></param>
- <param><type>VkPrivateDataSlotEXT</type> <name>privateDataSlot</name></param>
+ <param><type>VkPrivateDataSlot</type> <name>privateDataSlot</name></param>
<param><type>uint64_t</type> <name>data</name></param>
</command>
+ <command name="vkSetPrivateDataEXT" alias="vkSetPrivateData"/>
<command>
- <proto><type>void</type> <name>vkGetPrivateDataEXT</name></proto>
+ <proto><type>void</type> <name>vkGetPrivateData</name></proto>
<param><type>VkDevice</type> <name>device</name></param>
<param><type>VkObjectType</type> <name>objectType</name></param>
<param objecttype="objectType"><type>uint64_t</type> <name>objectHandle</name></param>
- <param><type>VkPrivateDataSlotEXT</type> <name>privateDataSlot</name></param>
+ <param><type>VkPrivateDataSlot</type> <name>privateDataSlot</name></param>
<param><type>uint64_t</type>* <name>pData</name></param>
</command>
- <command queues="transfer,graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary">
- <proto><type>void</type> <name>vkCmdCopyBuffer2KHR</name></proto>
+ <command name="vkGetPrivateDataEXT" alias="vkGetPrivateData"/>
+ <command queues="transfer,graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
+ <proto><type>void</type> <name>vkCmdCopyBuffer2</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
- <param>const <type>VkCopyBufferInfo2KHR</type>* <name>pCopyBufferInfo</name></param>
+ <param>const <type>VkCopyBufferInfo2</type>* <name>pCopyBufferInfo</name></param>
</command>
- <command queues="transfer,graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary">
- <proto><type>void</type> <name>vkCmdCopyImage2KHR</name></proto>
+ <command name="vkCmdCopyBuffer2KHR" alias="vkCmdCopyBuffer2"/>
+ <command queues="transfer,graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
+ <proto><type>void</type> <name>vkCmdCopyImage2</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
- <param>const <type>VkCopyImageInfo2KHR</type>* <name>pCopyImageInfo</name></param>
+ <param>const <type>VkCopyImageInfo2</type>* <name>pCopyImageInfo</name></param>
</command>
- <command queues="graphics" renderpass="outside" cmdbufferlevel="primary,secondary">
- <proto><type>void</type> <name>vkCmdBlitImage2KHR</name></proto>
+ <command name="vkCmdCopyImage2KHR" alias="vkCmdCopyImage2"/>
+ <command queues="graphics" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
+ <proto><type>void</type> <name>vkCmdBlitImage2</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
- <param>const <type>VkBlitImageInfo2KHR</type>* <name>pBlitImageInfo</name></param>
+ <param>const <type>VkBlitImageInfo2</type>* <name>pBlitImageInfo</name></param>
</command>
- <command queues="transfer,graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary">
- <proto><type>void</type> <name>vkCmdCopyBufferToImage2KHR</name></proto>
+ <command name="vkCmdBlitImage2KHR" alias="vkCmdBlitImage2"/>
+ <command queues="transfer,graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
+ <proto><type>void</type> <name>vkCmdCopyBufferToImage2</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
- <param>const <type>VkCopyBufferToImageInfo2KHR</type>* <name>pCopyBufferToImageInfo</name></param>
+ <param>const <type>VkCopyBufferToImageInfo2</type>* <name>pCopyBufferToImageInfo</name></param>
</command>
- <command queues="transfer,graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary">
- <proto><type>void</type> <name>vkCmdCopyImageToBuffer2KHR</name></proto>
+ <command name="vkCmdCopyBufferToImage2KHR" alias="vkCmdCopyBufferToImage2"/>
+ <command queues="transfer,graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
+ <proto><type>void</type> <name>vkCmdCopyImageToBuffer2</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
- <param>const <type>VkCopyImageToBufferInfo2KHR</type>* <name>pCopyImageToBufferInfo</name></param>
+ <param>const <type>VkCopyImageToBufferInfo2</type>* <name>pCopyImageToBufferInfo</name></param>
</command>
- <command queues="graphics" renderpass="outside" cmdbufferlevel="primary,secondary">
- <proto><type>void</type> <name>vkCmdResolveImage2KHR</name></proto>
+ <command name="vkCmdCopyImageToBuffer2KHR" alias="vkCmdCopyImageToBuffer2"/>
+ <command queues="graphics" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
+ <proto><type>void</type> <name>vkCmdResolveImage2</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
- <param>const <type>VkResolveImageInfo2KHR</type>* <name>pResolveImageInfo</name></param>
+ <param>const <type>VkResolveImageInfo2</type>* <name>pResolveImageInfo</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command name="vkCmdResolveImage2KHR" alias="vkCmdResolveImage2"/>
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdSetFragmentShadingRateKHR</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param>const <type>VkExtent2D</type>* <name>pFragmentSize</name></param>
@@ -10475,7 +12849,7 @@ typedef void <name>CAMetalLayer</name>;
<param optional="false,true"><type>uint32_t</type>* <name>pFragmentShadingRateCount</name></param>
<param optional="true" len="pFragmentShadingRateCount"><type>VkPhysicalDeviceFragmentShadingRateKHR</type>* <name>pFragmentShadingRates</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdSetFragmentShadingRateEnumNV</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkFragmentShadingRateNV</type> <name>shadingRate</name></param>
@@ -10489,7 +12863,7 @@ typedef void <name>CAMetalLayer</name>;
<param optional="true" len="pBuildInfo-&gt;geometryCount">const <type>uint32_t</type>* <name>pMaxPrimitiveCounts</name></param>
<param><type>VkAccelerationStructureBuildSizesInfoKHR</type>* <name>pSizeInfo</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdSetVertexInputEXT</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param optional="true"><type>uint32_t</type> <name>vertexBindingDescriptionCount</name></param>
@@ -10497,54 +12871,60 @@ typedef void <name>CAMetalLayer</name>;
<param optional="true"><type>uint32_t</type> <name>vertexAttributeDescriptionCount</name></param>
<param len="vertexAttributeDescriptionCount">const <type>VkVertexInputAttributeDescription2EXT</type>* <name>pVertexAttributeDescriptions</name></param>
</command>
- <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
<proto><type>void</type> <name>vkCmdSetColorWriteEnableEXT</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>attachmentCount</name></param>
<param len="attachmentCount">const <type>VkBool32</type>* <name>pColorWriteEnables</name></param>
</command>
- <command queues="graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary">
- <proto><type>void</type> <name>vkCmdSetEvent2KHR</name></proto>
+ <command queues="graphics,compute,decode,encode" renderpass="outside" videocoding="both" cmdbufferlevel="primary,secondary" tasks="synchronization">
+ <proto><type>void</type> <name>vkCmdSetEvent2</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkEvent</type> <name>event</name></param>
- <param>const <type>VkDependencyInfoKHR</type>* <name>pDependencyInfo</name></param>
+ <param>const <type>VkDependencyInfo</type>* <name>pDependencyInfo</name></param>
</command>
- <command queues="graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary">
- <proto><type>void</type> <name>vkCmdResetEvent2KHR</name></proto>
+ <command name="vkCmdSetEvent2KHR" alias="vkCmdSetEvent2"/>
+ <command queues="graphics,compute,decode,encode" renderpass="outside" videocoding="both" cmdbufferlevel="primary,secondary" tasks="synchronization">
+ <proto><type>void</type> <name>vkCmdResetEvent2</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>VkEvent</type> <name>event</name></param>
- <param><type>VkPipelineStageFlags2KHR</type> <name>stageMask</name></param>
+ <param optional="true"><type>VkPipelineStageFlags2</type> <name>stageMask</name></param>
</command>
- <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary">
- <proto><type>void</type> <name>vkCmdWaitEvents2KHR</name></proto>
+ <command name="vkCmdResetEvent2KHR" alias="vkCmdResetEvent2"/>
+ <command queues="graphics,compute,decode,encode" renderpass="both" videocoding="both" cmdbufferlevel="primary,secondary" tasks="synchronization">
+ <proto><type>void</type> <name>vkCmdWaitEvents2</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param><type>uint32_t</type> <name>eventCount</name></param>
<param len="eventCount">const <type>VkEvent</type>* <name>pEvents</name></param>
- <param len="eventCount">const <type>VkDependencyInfoKHR</type>* <name>pDependencyInfos</name></param>
+ <param len="eventCount">const <type>VkDependencyInfo</type>* <name>pDependencyInfos</name></param>
</command>
- <command queues="transfer,graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary">
- <proto><type>void</type> <name>vkCmdPipelineBarrier2KHR</name></proto>
+ <command name="vkCmdWaitEvents2KHR" alias="vkCmdWaitEvents2"/>
+ <command queues="transfer,graphics,compute,decode,encode" renderpass="both" videocoding="both" cmdbufferlevel="primary,secondary" tasks="synchronization">
+ <proto><type>void</type> <name>vkCmdPipelineBarrier2</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
- <param>const <type>VkDependencyInfoKHR</type>* <name>pDependencyInfo</name></param>
+ <param>const <type>VkDependencyInfo</type>* <name>pDependencyInfo</name></param>
</command>
+ <command name="vkCmdPipelineBarrier2KHR" alias="vkCmdPipelineBarrier2"/>
<command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_DEVICE_LOST">
- <proto><type>VkResult</type> <name>vkQueueSubmit2KHR</name></proto>
+ <proto><type>VkResult</type> <name>vkQueueSubmit2</name></proto>
<param externsync="true"><type>VkQueue</type> <name>queue</name></param>
<param optional="true"><type>uint32_t</type> <name>submitCount</name></param>
- <param len="submitCount">const <type>VkSubmitInfo2KHR</type>* <name>pSubmits</name></param>
+ <param len="submitCount">const <type>VkSubmitInfo2</type>* <name>pSubmits</name></param>
<param optional="true" externsync="true"><type>VkFence</type> <name>fence</name></param>
</command>
- <command queues="transfer,graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary">
- <proto><type>void</type> <name>vkCmdWriteTimestamp2KHR</name></proto>
+ <command name="vkQueueSubmit2KHR" alias="vkQueueSubmit2"/>
+ <command queues="transfer,graphics,compute,decode,encode" renderpass="both" videocoding="both" cmdbufferlevel="primary,secondary" tasks="action">
+ <proto><type>void</type> <name>vkCmdWriteTimestamp2</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
- <param><type>VkPipelineStageFlags2KHR</type> <name>stage</name></param>
+ <param optional="true"><type>VkPipelineStageFlags2</type> <name>stage</name></param>
<param><type>VkQueryPool</type> <name>queryPool</name></param>
<param><type>uint32_t</type> <name>query</name></param>
</command>
- <command queues="transfer,graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command name="vkCmdWriteTimestamp2KHR" alias="vkCmdWriteTimestamp2"/>
+ <command queues="transfer,graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdWriteBufferMarker2AMD</name></proto>
<param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
- <param><type>VkPipelineStageFlags2KHR</type> <name>stage</name></param>
+ <param optional="true"><type>VkPipelineStageFlags2</type> <name>stage</name></param>
<param><type>VkBuffer</type> <name>dstBuffer</name></param>
<param><type>VkDeviceSize</type> <name>dstOffset</name></param>
<param><type>uint32_t</type> <name>marker</name></param>
@@ -10555,20 +12935,20 @@ typedef void <name>CAMetalLayer</name>;
<param optional="false,true"><type>uint32_t</type>* <name>pCheckpointDataCount</name></param>
<param optional="true" len="pCheckpointDataCount"><type>VkCheckpointData2NV</type>* <name>pCheckpointData</name></param>
</command>
- <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_EXTENSION_NOT_PRESENT,VK_ERROR_INITIALIZATION_FAILED,VK_ERROR_FEATURE_NOT_PRESENT,VK_ERROR_FORMAT_NOT_SUPPORTED">
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR,VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR,VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR,VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR">
<proto><type>VkResult</type> <name>vkGetPhysicalDeviceVideoCapabilitiesKHR</name></proto>
<param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
- <param>const <type>VkVideoProfileKHR</type>* <name>pVideoProfile</name></param>
+ <param>const <type>VkVideoProfileInfoKHR</type>* <name>pVideoProfile</name></param>
<param><type>VkVideoCapabilitiesKHR</type>* <name>pCapabilities</name></param>
</command>
- <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_EXTENSION_NOT_PRESENT,VK_ERROR_INITIALIZATION_FAILED,VK_ERROR_FORMAT_NOT_SUPPORTED">
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR,VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR,VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR,VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR,VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR">
<proto><type>VkResult</type> <name>vkGetPhysicalDeviceVideoFormatPropertiesKHR</name></proto>
<param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
<param>const <type>VkPhysicalDeviceVideoFormatInfoKHR</type>* <name>pVideoFormatInfo</name></param>
<param optional="false,true"><type>uint32_t</type>* <name>pVideoFormatPropertyCount</name></param>
<param optional="true" len="pVideoFormatPropertyCount"><type>VkVideoFormatPropertiesKHR</type>* <name>pVideoFormatProperties</name></param>
</command>
- <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_INITIALIZATION_FAILED,VK_ERROR_INCOMPATIBLE_DRIVER,VK_ERROR_FEATURE_NOT_PRESENT">
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_INITIALIZATION_FAILED,VK_ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR">
<proto><type>VkResult</type> <name>vkCreateVideoSessionKHR</name></proto>
<param><type>VkDevice</type> <name>device</name></param>
<param>const <type>VkVideoSessionCreateInfoKHR</type>* <name>pCreateInfo</name></param>
@@ -10578,17 +12958,17 @@ typedef void <name>CAMetalLayer</name>;
<command>
<proto><type>void</type> <name>vkDestroyVideoSessionKHR</name></proto>
<param><type>VkDevice</type> <name>device</name></param>
- <param><type>VkVideoSessionKHR</type> <name>videoSession</name></param>
+ <param optional="true" externsync="true"><type>VkVideoSessionKHR</type> <name>videoSession</name></param>
<param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
</command>
- <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_TOO_MANY_OBJECTS">
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_INITIALIZATION_FAILED">
<proto><type>VkResult</type> <name>vkCreateVideoSessionParametersKHR</name></proto>
<param><type>VkDevice</type> <name>device</name></param>
<param>const <type>VkVideoSessionParametersCreateInfoKHR</type>* <name>pCreateInfo</name></param>
<param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
<param><type>VkVideoSessionParametersKHR</type>* <name>pVideoSessionParameters</name></param>
</command>
- <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_INITIALIZATION_FAILED,VK_ERROR_TOO_MANY_OBJECTS">
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
<proto><type>VkResult</type> <name>vkUpdateVideoSessionParametersKHR</name></proto>
<param><type>VkDevice</type> <name>device</name></param>
<param><type>VkVideoSessionParametersKHR</type> <name>videoSessionParameters</name></param>
@@ -10597,48 +12977,61 @@ typedef void <name>CAMetalLayer</name>;
<command>
<proto><type>void</type> <name>vkDestroyVideoSessionParametersKHR</name></proto>
<param><type>VkDevice</type> <name>device</name></param>
- <param><type>VkVideoSessionParametersKHR</type> <name>videoSessionParameters</name></param>
+ <param optional="true" externsync="true"><type>VkVideoSessionParametersKHR</type> <name>videoSessionParameters</name></param>
<param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
</command>
- <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_INITIALIZATION_FAILED">
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE">
<proto><type>VkResult</type> <name>vkGetVideoSessionMemoryRequirementsKHR</name></proto>
<param><type>VkDevice</type> <name>device</name></param>
<param><type>VkVideoSessionKHR</type> <name>videoSession</name></param>
- <param optional="false,true"><type>uint32_t</type>* <name>pVideoSessionMemoryRequirementsCount</name></param>
- <param optional="true" len="pVideoSessionMemoryRequirementsCount"><type>VkVideoGetMemoryPropertiesKHR</type>* <name>pVideoSessionMemoryRequirements</name></param>
+ <param optional="false,true"><type>uint32_t</type>* <name>pMemoryRequirementsCount</name></param>
+ <param optional="true" len="pMemoryRequirementsCount"><type>VkVideoSessionMemoryRequirementsKHR</type>* <name>pMemoryRequirements</name></param>
</command>
- <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_INITIALIZATION_FAILED">
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
<proto><type>VkResult</type> <name>vkBindVideoSessionMemoryKHR</name></proto>
<param><type>VkDevice</type> <name>device</name></param>
- <param><type>VkVideoSessionKHR</type> <name>videoSession</name></param>
- <param><type>uint32_t</type> <name>videoSessionBindMemoryCount</name></param>
- <param len="videoSessionBindMemoryCount">const <type>VkVideoBindMemoryKHR</type>* <name>pVideoSessionBindMemories</name></param>
+ <param externsync="true"><type>VkVideoSessionKHR</type> <name>videoSession</name></param>
+ <param><type>uint32_t</type> <name>bindSessionMemoryInfoCount</name></param>
+ <param len="bindSessionMemoryInfoCount">const <type>VkBindVideoSessionMemoryInfoKHR</type>* <name>pBindSessionMemoryInfos</name></param>
</command>
- <command queues="decode" renderpass="outside" cmdbufferlevel="primary">
+ <command queues="decode" renderpass="outside" videocoding="inside" cmdbufferlevel="primary" tasks="action">
<proto><type>void</type> <name>vkCmdDecodeVideoKHR</name></proto>
- <param><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
- <param>const <type>VkVideoDecodeInfoKHR</type>* <name>pFrameInfo</name></param>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param>const <type>VkVideoDecodeInfoKHR</type>* <name>pDecodeInfo</name></param>
</command>
- <command queues="decode,encode" renderpass="outside" cmdbufferlevel="primary">
+ <command queues="decode,encode" renderpass="outside" videocoding="outside" cmdbufferlevel="primary" tasks="action,state">
<proto><type>void</type> <name>vkCmdBeginVideoCodingKHR</name></proto>
- <param><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param>const <type>VkVideoBeginCodingInfoKHR</type>* <name>pBeginInfo</name></param>
</command>
- <command queues="decode,encode" renderpass="outside" cmdbufferlevel="primary">
+ <command queues="decode,encode" renderpass="outside" videocoding="inside" cmdbufferlevel="primary" tasks="action">
<proto><type>void</type> <name>vkCmdControlVideoCodingKHR</name></proto>
- <param><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param>const <type>VkVideoCodingControlInfoKHR</type>* <name>pCodingControlInfo</name></param>
</command>
- <command queues="decode,encode" renderpass="outside" cmdbufferlevel="primary">
+ <command queues="decode,encode" renderpass="outside" videocoding="inside" cmdbufferlevel="primary" tasks="action,state">
<proto><type>void</type> <name>vkCmdEndVideoCodingKHR</name></proto>
- <param><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param>const <type>VkVideoEndCodingInfoKHR</type>* <name>pEndCodingInfo</name></param>
</command>
- <command queues="encode" renderpass="outside" cmdbufferlevel="primary">
+ <command queues="encode" renderpass="outside" videocoding="inside" cmdbufferlevel="primary" tasks="action">
<proto><type>void</type> <name>vkCmdEncodeVideoKHR</name></proto>
- <param><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param>const <type>VkVideoEncodeInfoKHR</type>* <name>pEncodeInfo</name></param>
</command>
+ <command queues="graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
+ <proto><type>void</type> <name>vkCmdDecompressMemoryNV</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>uint32_t</type> <name>decompressRegionCount</name></param>
+ <param len="decompressRegionCount">const <type>VkDecompressMemoryRegionNV</type>* <name>pDecompressMemoryRegions</name></param>
+ </command>
+ <command queues="graphics,compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
+ <proto><type>void</type> <name>vkCmdDecompressMemoryIndirectCountNV</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkDeviceAddress</type> <name>indirectCommandsAddress</name></param>
+ <param><type>VkDeviceAddress</type> <name>indirectCommandsCountAddress</name></param>
+ <param><type>uint32_t</type> <name>stride</name></param>
+ </command>
<command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_INITIALIZATION_FAILED">
<proto><type>VkResult</type> <name>vkCreateCuModuleNVX</name></proto>
<param><type>VkDevice</type> <name>device</name></param>
@@ -10665,11 +13058,90 @@ typedef void <name>CAMetalLayer</name>;
<param><type>VkCuFunctionNVX</type> <name>function</name></param>
<param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
</command>
- <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary">
+ <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary" tasks="action">
<proto><type>void</type> <name>vkCmdCuLaunchKernelNVX</name></proto>
<param><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
<param>const <type>VkCuLaunchInfoNVX</type>* <name>pLaunchInfo</name></param>
</command>
+ <command>
+ <proto><type>void</type> <name>vkGetDescriptorSetLayoutSizeEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkDescriptorSetLayout</type> <name>layout</name></param>
+ <param><type>VkDeviceSize</type>* <name>pLayoutSizeInBytes</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetDescriptorSetLayoutBindingOffsetEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkDescriptorSetLayout</type> <name>layout</name></param>
+ <param><type>uint32_t</type> <name>binding</name></param>
+ <param><type>VkDeviceSize</type>* <name>pOffset</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetDescriptorEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkDescriptorGetInfoEXT</type>* <name>pDescriptorInfo</name></param>
+ <param><type>size_t</type> <name>dataSize</name></param>
+ <param len="dataSize"><type>void</type>* <name>pDescriptor</name></param>
+ </command>
+ <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdBindDescriptorBuffersEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>uint32_t</type> <name>bufferCount</name></param>
+ <param len="bufferCount">const <type>VkDescriptorBufferBindingInfoEXT</type>* <name>pBindingInfos</name></param>
+ </command>
+ <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdSetDescriptorBufferOffsetsEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkPipelineBindPoint</type> <name>pipelineBindPoint</name></param>
+ <param><type>VkPipelineLayout</type> <name>layout</name></param>
+ <param><type>uint32_t</type> <name>firstSet</name></param>
+ <param><type>uint32_t</type> <name>setCount</name></param>
+ <param len="setCount">const <type>uint32_t</type>* <name>pBufferIndices</name></param>
+ <param len="setCount">const <type>VkDeviceSize</type>* <name>pOffsets</name></param>
+ </command>
+ <command queues="graphics,compute" renderpass="both" cmdbufferlevel="primary,secondary" tasks="state">
+ <proto><type>void</type> <name>vkCmdBindDescriptorBufferEmbeddedSamplersEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkPipelineBindPoint</type> <name>pipelineBindPoint</name></param>
+ <param><type>VkPipelineLayout</type> <name>layout</name></param>
+ <param><type>uint32_t</type> <name>set</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetBufferOpaqueCaptureDescriptorDataEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkBufferCaptureDescriptorDataInfoEXT</type>* <name>pInfo</name></param>
+ <param><type>void</type>* <name>pData</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetImageOpaqueCaptureDescriptorDataEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkImageCaptureDescriptorDataInfoEXT</type>* <name>pInfo</name></param>
+ <param><type>void</type>* <name>pData</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetImageViewOpaqueCaptureDescriptorDataEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkImageViewCaptureDescriptorDataInfoEXT</type>* <name>pInfo</name></param>
+ <param><type>void</type>* <name>pData</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetSamplerOpaqueCaptureDescriptorDataEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkSamplerCaptureDescriptorDataInfoEXT</type>* <name>pInfo</name></param>
+ <param><type>void</type>* <name>pData</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkAccelerationStructureCaptureDescriptorDataInfoEXT</type>* <name>pInfo</name></param>
+ <param><type>void</type>* <name>pData</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkSetDeviceMemoryPriorityEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkDeviceMemory</type> <name>memory</name></param>
+ <param><type>float</type> <name>priority</name></param>
+ </command>
<command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_INITIALIZATION_FAILED">
<proto><type>VkResult</type> <name>vkAcquireDrmDisplayEXT</name></proto>
<param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
@@ -10683,13 +13155,247 @@ typedef void <name>CAMetalLayer</name>;
<param><type>uint32_t</type> <name>connectorId</name></param>
<param><type>VkDisplayKHR</type>* <name>display</name></param>
</command>
- <command successcodes="VK_SUCCESS,VK_TIMEOUT" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_DEVICE_LOST">
- <proto><type>VkResult</type> <name>vkWaitForPresentKHR</name></proto>
- <param><type>VkDevice</type> <name>device</name></param>
- <param externsync="true"><type>VkSwapchainKHR</type> <name>swapchain</name></param>
- <param><type>uint64_t</type> <name>presentId</name></param>
- <param><type>uint64_t</type> <name>timeout</name></param>
- </command>
+ <command successcodes="VK_SUCCESS,VK_TIMEOUT,VK_SUBOPTIMAL_KHR" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY,VK_ERROR_DEVICE_LOST,VK_ERROR_OUT_OF_DATE_KHR,VK_ERROR_SURFACE_LOST_KHR,VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT">
+ <proto><type>VkResult</type> <name>vkWaitForPresentKHR</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param externsync="true"><type>VkSwapchainKHR</type> <name>swapchain</name></param>
+ <param><type>uint64_t</type> <name>presentId</name></param>
+ <param><type>uint64_t</type> <name>timeout</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_INVALID_EXTERNAL_HANDLE,VK_ERROR_INITIALIZATION_FAILED">
+ <proto><type>VkResult</type> <name>vkCreateBufferCollectionFUCHSIA</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkBufferCollectionCreateInfoFUCHSIA</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkBufferCollectionFUCHSIA</type>* <name>pCollection</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_INITIALIZATION_FAILED,VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_FORMAT_NOT_SUPPORTED">
+ <proto><type>VkResult</type> <name>vkSetBufferCollectionBufferConstraintsFUCHSIA</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkBufferCollectionFUCHSIA</type> <name>collection</name></param>
+ <param>const <type>VkBufferConstraintsInfoFUCHSIA</type>* <name>pBufferConstraintsInfo</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_INITIALIZATION_FAILED,VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_FORMAT_NOT_SUPPORTED">
+ <proto><type>VkResult</type> <name>vkSetBufferCollectionImageConstraintsFUCHSIA</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkBufferCollectionFUCHSIA</type> <name>collection</name></param>
+ <param>const <type>VkImageConstraintsInfoFUCHSIA</type>* <name>pImageConstraintsInfo</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroyBufferCollectionFUCHSIA</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkBufferCollectionFUCHSIA</type> <name>collection</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_INITIALIZATION_FAILED">
+ <proto><type>VkResult</type> <name>vkGetBufferCollectionPropertiesFUCHSIA</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkBufferCollectionFUCHSIA</type> <name>collection</name></param>
+ <param><type>VkBufferCollectionPropertiesFUCHSIA</type>* <name>pProperties</name></param>
+ </command>
+ <command queues="graphics" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action,state">
+ <proto><type>void</type> <name>vkCmdBeginRendering</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param>const <type>VkRenderingInfo</type>* <name>pRenderingInfo</name></param>
+ </command>
+ <command name="vkCmdBeginRenderingKHR" alias="vkCmdBeginRendering"/>
+ <command queues="graphics" renderpass="inside" cmdbufferlevel="primary,secondary" tasks="action,state">
+ <proto><type>void</type> <name>vkCmdEndRendering</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ </command>
+
+ <command name="vkCmdEndRenderingKHR" alias="vkCmdEndRendering"/>
+ <command>
+ <proto><type>void</type> <name>vkGetDescriptorSetLayoutHostMappingInfoVALVE</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkDescriptorSetBindingReferenceVALVE</type>* <name>pBindingReference</name></param>
+ <param><type>VkDescriptorSetLayoutHostMappingInfoVALVE</type>* <name>pHostMapping</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetDescriptorSetHostMappingVALVE</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkDescriptorSet</type> <name>descriptorSet</name></param>
+ <param><type>void</type>** <name>ppData</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS_KHR">
+ <proto><type>VkResult</type> <name>vkCreateMicromapEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkMicromapCreateInfoEXT</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkMicromapEXT</type>* <name>pMicromap</name></param>
+ </command>
+ <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
+ <proto><type>void</type> <name>vkCmdBuildMicromapsEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>uint32_t</type> <name>infoCount</name></param>
+ <param len="infoCount">const <type>VkMicromapBuildInfoEXT</type>* <name>pInfos</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_OPERATION_DEFERRED_KHR,VK_OPERATION_NOT_DEFERRED_KHR" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkBuildMicromapsEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true"><type>VkDeferredOperationKHR</type> <name>deferredOperation</name></param>
+ <param><type>uint32_t</type> <name>infoCount</name></param>
+ <param len="infoCount">const <type>VkMicromapBuildInfoEXT</type>* <name>pInfos</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroyMicromapEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true" externsync="true"><type>VkMicromapEXT</type> <name>micromap</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ </command>
+ <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
+ <proto><type>void</type> <name>vkCmdCopyMicromapEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param>const <type>VkCopyMicromapInfoEXT</type>* <name>pInfo</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_OPERATION_DEFERRED_KHR,VK_OPERATION_NOT_DEFERRED_KHR" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkCopyMicromapEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true"><type>VkDeferredOperationKHR</type> <name>deferredOperation</name></param>
+ <param>const <type>VkCopyMicromapInfoEXT</type>* <name>pInfo</name></param>
+ </command>
+ <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
+ <proto><type>void</type> <name>vkCmdCopyMicromapToMemoryEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param>const <type>VkCopyMicromapToMemoryInfoEXT</type>* <name>pInfo</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_OPERATION_DEFERRED_KHR,VK_OPERATION_NOT_DEFERRED_KHR" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkCopyMicromapToMemoryEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true"><type>VkDeferredOperationKHR</type> <name>deferredOperation</name></param>
+ <param>const <type>VkCopyMicromapToMemoryInfoEXT</type>* <name>pInfo</name></param>
+ </command>
+ <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
+ <proto><type>void</type> <name>vkCmdCopyMemoryToMicromapEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param>const <type>VkCopyMemoryToMicromapInfoEXT</type>* <name>pInfo</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_OPERATION_DEFERRED_KHR,VK_OPERATION_NOT_DEFERRED_KHR" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkCopyMemoryToMicromapEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param optional="true"><type>VkDeferredOperationKHR</type> <name>deferredOperation</name></param>
+ <param>const <type>VkCopyMemoryToMicromapInfoEXT</type>* <name>pInfo</name></param>
+ </command>
+ <command queues="compute" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
+ <proto><type>void</type> <name>vkCmdWriteMicromapsPropertiesEXT</name></proto>
+ <param externsync="true"><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>uint32_t</type> <name>micromapCount</name></param>
+ <param len="micromapCount">const <type>VkMicromapEXT</type>* <name>pMicromaps</name></param>
+ <param><type>VkQueryType</type> <name>queryType</name></param>
+ <param><type>VkQueryPool</type> <name>queryPool</name></param>
+ <param><type>uint32_t</type> <name>firstQuery</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_OUT_OF_DEVICE_MEMORY">
+ <proto><type>VkResult</type> <name>vkWriteMicromapsPropertiesEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>uint32_t</type> <name>micromapCount</name></param>
+ <param len="micromapCount">const <type>VkMicromapEXT</type>* <name>pMicromaps</name></param>
+ <param><type>VkQueryType</type> <name>queryType</name></param>
+ <param><type>size_t</type> <name>dataSize</name></param>
+ <param len="dataSize"><type>void</type>* <name>pData</name></param>
+ <param><type>size_t</type> <name>stride</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetDeviceMicromapCompatibilityEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkMicromapVersionInfoEXT</type>* <name>pVersionInfo</name></param>
+ <param><type>VkAccelerationStructureCompatibilityKHR</type>* <name>pCompatibility</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetMicromapBuildSizesEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkAccelerationStructureBuildTypeKHR</type> <name>buildType</name></param>
+ <param>const <type>VkMicromapBuildInfoEXT</type>* <name>pBuildInfo</name></param>
+ <param><type>VkMicromapBuildSizesInfoEXT</type>* <name>pSizeInfo</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetShaderModuleIdentifierEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkShaderModule</type> <name>shaderModule</name></param>
+ <param><type>VkShaderModuleIdentifierEXT</type>* <name>pIdentifier</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetShaderModuleCreateInfoIdentifierEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkShaderModuleCreateInfo</type>* <name>pCreateInfo</name></param>
+ <param><type>VkShaderModuleIdentifierEXT</type>* <name>pIdentifier</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkGetImageSubresourceLayout2EXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkImage</type> <name>image</name></param>
+ <param>const <type>VkImageSubresource2EXT</type>* <name>pSubresource</name></param>
+ <param><type>VkSubresourceLayout2EXT</type>* <name>pLayout</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetPipelinePropertiesEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkPipelineInfoEXT</type>* <name>pPipelineInfo</name></param>
+ <param noautovalidity="true" validstructs="VkPipelinePropertiesIdentifierEXT"><type>VkBaseOutStructure</type>* <name>pPipelineProperties</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkExportMetalObjectsEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkExportMetalObjectsInfoEXT</type>* <name>pMetalObjectsInfo</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE">
+ <proto><type>VkResult</type> <name>vkGetFramebufferTilePropertiesQCOM</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkFramebuffer</type> <name>framebuffer</name></param>
+ <param optional="false,true"><type>uint32_t</type>* <name>pPropertiesCount</name></param>
+ <param optional="true" len="pPropertiesCount"><type>VkTilePropertiesQCOM</type>* <name>pProperties</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS">
+ <proto><type>VkResult</type> <name>vkGetDynamicRenderingTilePropertiesQCOM</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkRenderingInfo</type>* <name>pRenderingInfo</name></param>
+ <param><type>VkTilePropertiesQCOM</type>* <name>pProperties</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_EXTENSION_NOT_PRESENT,VK_ERROR_INITIALIZATION_FAILED,VK_ERROR_FORMAT_NOT_SUPPORTED">
+ <proto><type>VkResult</type> <name>vkGetPhysicalDeviceOpticalFlowImageFormatsNV</name></proto>
+ <param><type>VkPhysicalDevice</type> <name>physicalDevice</name></param>
+ <param>const <type>VkOpticalFlowImageFormatInfoNV</type>* <name>pOpticalFlowImageFormatInfo</name></param>
+ <param optional="false,true"><type>uint32_t</type>* <name>pFormatCount</name></param>
+ <param optional="true" len="pFormatCount"><type>VkOpticalFlowImageFormatPropertiesNV</type>* <name>pImageFormatProperties</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_INITIALIZATION_FAILED">
+ <proto><type>VkResult</type> <name>vkCreateOpticalFlowSessionNV</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkOpticalFlowSessionCreateInfoNV</type>* <name>pCreateInfo</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ <param><type>VkOpticalFlowSessionNV</type>* <name>pSession</name></param>
+ </command>
+ <command>
+ <proto><type>void</type> <name>vkDestroyOpticalFlowSessionNV</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkOpticalFlowSessionNV</type> <name>session</name></param>
+ <param optional="true">const <type>VkAllocationCallbacks</type>* <name>pAllocator</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY,VK_ERROR_INITIALIZATION_FAILED">
+ <proto><type>VkResult</type> <name>vkBindOpticalFlowSessionImageNV</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkOpticalFlowSessionNV</type> <name>session</name></param>
+ <param><type>VkOpticalFlowSessionBindingPointNV</type> <name>bindingPoint</name></param>
+ <param optional="true"><type>VkImageView</type> <name>view</name></param>
+ <param><type>VkImageLayout</type> <name>layout</name></param>
+ </command>
+ <command queues="opticalflow" renderpass="outside" cmdbufferlevel="primary,secondary" tasks="action">
+ <proto><type>void</type> <name>vkCmdOpticalFlowExecuteNV</name></proto>
+ <param><type>VkCommandBuffer</type> <name>commandBuffer</name></param>
+ <param><type>VkOpticalFlowSessionNV</type> <name>session</name></param>
+ <param>const <type>VkOpticalFlowExecuteInfoNV</type>* <name>pExecuteInfo</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS,VK_INCOMPLETE" errorcodes="VK_ERROR_OUT_OF_HOST_MEMORY">
+ <proto><type>VkResult</type> <name>vkGetDeviceFaultInfoEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param><type>VkDeviceFaultCountsEXT</type>* <name>pFaultCounts</name></param>
+ <param optional="true"><type>VkDeviceFaultInfoEXT</type>* <name>pFaultInfo</name></param>
+ </command>
+ <command successcodes="VK_SUCCESS" errorcodes="VK_ERROR_SURFACE_LOST_KHR">
+ <proto><type>VkResult</type> <name>vkReleaseSwapchainImagesEXT</name></proto>
+ <param><type>VkDevice</type> <name>device</name></param>
+ <param>const <type>VkReleaseSwapchainImagesInfoEXT</type>* <name>pReleaseInfo</name></param>
+ </command>
</commands>
<feature api="vulkan" name="VK_VERSION_1_0" number="1.0" comment="Vulkan core API interface definitions">
@@ -10713,6 +13419,24 @@ typedef void <name>CAMetalLayer</name>;
<type name="VkResult"/>
<type name="VkStructureType"/>
</require>
+ <require comment="API constants">
+ <enum name="VK_ATTACHMENT_UNUSED"/>
+ <enum name="VK_FALSE"/>
+ <enum name="VK_LOD_CLAMP_NONE"/>
+ <enum name="VK_QUEUE_FAMILY_IGNORED"/>
+ <enum name="VK_REMAINING_ARRAY_LAYERS"/>
+ <enum name="VK_REMAINING_MIP_LEVELS"/>
+ <enum name="VK_SUBPASS_EXTERNAL"/>
+ <enum name="VK_TRUE"/>
+ <enum name="VK_WHOLE_SIZE"/>
+ <enum name="VK_MAX_MEMORY_TYPES"/>
+ <enum name="VK_MAX_PHYSICAL_DEVICE_NAME_SIZE"/>
+ <enum name="VK_UUID_SIZE"/>
+ <enum name="VK_MAX_EXTENSION_NAME_SIZE"/>
+ <enum name="VK_MAX_DESCRIPTION_SIZE"/>
+ <enum name="VK_MAX_MEMORY_HEAPS"/>
+ <type name="VkPipelineCacheHeaderVersion"/>
+ </require>
<require comment="These types are part of the API, though not directly used in API commands or data structures">
<type name="VkBaseInStructure"/>
<type name="VkBaseOutStructure"/>
@@ -10741,18 +13465,6 @@ typedef void <name>CAMetalLayer</name>;
<type name="VK_API_VERSION_MINOR"/>
<type name="VK_API_VERSION_PATCH"/>
</require>
- <require comment="API constants">
- <enum name="VK_ATTACHMENT_UNUSED"/>
- <enum name="VK_FALSE"/>
- <enum name="VK_LOD_CLAMP_NONE"/>
- <enum name="VK_QUEUE_FAMILY_IGNORED"/>
- <enum name="VK_REMAINING_ARRAY_LAYERS"/>
- <enum name="VK_REMAINING_MIP_LEVELS"/>
- <enum name="VK_SUBPASS_EXTERNAL"/>
- <enum name="VK_TRUE"/>
- <enum name="VK_WHOLE_SIZE"/>
- <type name="VkPipelineCacheHeaderVersion"/>
- </require>
<require comment="Device initialization">
<type name="PFN_vkAllocationFunction"/>
<type name="PFN_vkFreeFunction"/>
@@ -10775,6 +13487,7 @@ typedef void <name>CAMetalLayer</name>;
<type name="VkImageUsageFlags"/>
<type name="VkInstance"/>
<type name="VkInstanceCreateFlags"/>
+ <type name="VkInstanceCreateFlagBits"/>
<type name="VkInstanceCreateInfo"/>
<type name="VkInternalAllocationType"/>
<type name="VkMemoryHeap"/>
@@ -10810,10 +13523,9 @@ typedef void <name>CAMetalLayer</name>;
</require>
<require comment="Device commands">
<type name="VkDevice"/>
- <type name="VkDeviceCreateFlags"/>
+ <type name="VkDeviceCreateFlags" comment="Will add VkDeviceCreateFlagBits when bits are defined in the future"/>
<type name="VkDeviceCreateInfo"/>
- <type name="VkDeviceQueueCreateFlagBits"/>
- <type name="VkDeviceQueueCreateFlags"/>
+ <type name="VkDeviceQueueCreateFlags" comment="VkDeviceQueueCreateFlagBits was added later"/>
<type name="VkDeviceQueueCreateInfo"/>
<command name="vkCreateDevice"/>
<command name="vkDestroyDevice"/>
@@ -10891,7 +13603,7 @@ typedef void <name>CAMetalLayer</name>;
</require>
<require comment="Queue semaphore commands">
<type name="VkSemaphore"/>
- <type name="VkSemaphoreCreateFlags"/>
+ <type name="VkSemaphoreCreateFlags" comment="Will add VkSemaphoreCreateFlagBits when bits are defined in the future"/>
<type name="VkSemaphoreCreateInfo"/>
<command name="vkCreateSemaphore"/>
<command name="vkDestroySemaphore"/>
@@ -10911,7 +13623,7 @@ typedef void <name>CAMetalLayer</name>;
<type name="VkQueryPipelineStatisticFlagBits"/>
<type name="VkQueryPipelineStatisticFlags"/>
<type name="VkQueryPool"/>
- <type name="VkQueryPoolCreateFlags"/>
+ <type name="VkQueryPoolCreateFlags" comment="Will add VkQueryPoolCreateFlagBits when bits are defined in the future"/>
<type name="VkQueryPoolCreateInfo"/>
<type name="VkQueryResultFlagBits"/>
<type name="VkQueryResultFlags"/>
@@ -10933,7 +13645,7 @@ typedef void <name>CAMetalLayer</name>;
</require>
<require comment="Buffer view commands">
<type name="VkBufferView"/>
- <type name="VkBufferViewCreateFlags" comment="Will need FlagBits type eventually"/>
+ <type name="VkBufferViewCreateFlags" comment="Will add VkBufferViewFlagBits when bits are defined in the future"/>
<type name="VkBufferViewCreateInfo"/>
<command name="vkCreateBufferView"/>
<command name="vkDestroyBufferView"/>
@@ -10961,7 +13673,6 @@ typedef void <name>CAMetalLayer</name>;
</require>
<require comment="Shader commands">
<type name="VkShaderModule"/>
- <type name="VkShaderModuleCreateFlagBits"/>
<type name="VkShaderModuleCreateFlags"/>
<type name="VkShaderModuleCreateInfo"/>
<command name="vkCreateShaderModule"/>
@@ -10969,8 +13680,7 @@ typedef void <name>CAMetalLayer</name>;
</require>
<require comment="Pipeline Cache commands">
<type name="VkPipelineCache"/>
- <type name="VkPipelineCacheCreateFlagBits"/>
- <type name="VkPipelineCacheCreateFlags"/>
+ <type name="VkPipelineCacheCreateFlags" comment="VkPipelineCacheCreateFlagBits was added later"/>
<type name="VkPipelineCacheCreateInfo"/>
<command name="vkCreatePipelineCache"/>
<command name="vkDestroyPipelineCache"/>
@@ -10992,29 +13702,29 @@ typedef void <name>CAMetalLayer</name>;
<type name="VkLogicOp"/>
<type name="VkPipeline"/>
<type name="VkPipelineColorBlendAttachmentState"/>
- <type name="VkPipelineColorBlendStateCreateFlags" comment="Will need FlagBits type eventually"/>
+ <type name="VkPipelineColorBlendStateCreateFlags" comment="Will add VkPipeline*StateFlagBits when bits are defined in the future"/>
<type name="VkPipelineColorBlendStateCreateInfo"/>
<type name="VkPipelineCreateFlagBits"/>
<type name="VkPipelineCreateFlags"/>
- <type name="VkPipelineDepthStencilStateCreateFlags" comment="Will need FlagBits type eventually"/>
+ <type name="VkPipelineDepthStencilStateCreateFlags" comment="Will add VkPipeline*StateFlagBits when bits are defined in the future"/>
<type name="VkPipelineDepthStencilStateCreateInfo"/>
- <type name="VkPipelineDynamicStateCreateFlags" comment="Will need FlagBits type eventually"/>
+ <type name="VkPipelineDynamicStateCreateFlags" comment="Will add VkPipeline*StateFlagBits when bits are defined in the future"/>
<type name="VkPipelineDynamicStateCreateInfo"/>
- <type name="VkPipelineInputAssemblyStateCreateFlags" comment="Will need FlagBits type eventually"/>
+ <type name="VkPipelineInputAssemblyStateCreateFlags" comment="Will add VkPipeline*StateFlagBits when bits are defined in the future"/>
<type name="VkPipelineInputAssemblyStateCreateInfo"/>
- <type name="VkPipelineLayoutCreateFlags" comment="Will need FlagBits type eventually"/>
- <type name="VkPipelineMultisampleStateCreateFlags" comment="Will need FlagBits type eventually"/>
+ <type name="VkPipelineLayoutCreateFlags" comment="Will add VkPipelineLayoutCreateFlagBits when bits are defined in the future"/>
+ <type name="VkPipelineMultisampleStateCreateFlags" comment="Will add VkPipelineMultisampleStateCreateFlagBits when bits are defined in the future"/>
<type name="VkPipelineMultisampleStateCreateInfo"/>
- <type name="VkPipelineRasterizationStateCreateFlags" comment="Will need FlagBits type eventually"/>
+ <type name="VkPipelineRasterizationStateCreateFlags" comment="Will add VkPipelineRasterizationStateCreateFlagBits when bits are defined in the future"/>
<type name="VkPipelineRasterizationStateCreateInfo"/>
<type name="VkPipelineShaderStageCreateFlagBits"/>
<type name="VkPipelineShaderStageCreateFlags"/>
<type name="VkPipelineShaderStageCreateInfo"/>
- <type name="VkPipelineTessellationStateCreateFlags" comment="Will need FlagBits type eventually"/>
+ <type name="VkPipelineTessellationStateCreateFlags" comment="Will add VkPipelineTessellationStateCreateFlagBits when bits are defined in the future"/>
<type name="VkPipelineTessellationStateCreateInfo"/>
- <type name="VkPipelineVertexInputStateCreateFlags" comment="Will need FlagBits type eventually"/>
+ <type name="VkPipelineVertexInputStateCreateFlags" comment="Will add VkPipelineVertexInputStateCreateFlagBits when bits are defined in the future"/>
<type name="VkPipelineVertexInputStateCreateInfo"/>
- <type name="VkPipelineViewportStateCreateFlags" comment="Will need FlagBits type eventually"/>
+ <type name="VkPipelineViewportStateCreateFlags" comment="Will add VkPipelineViewportStateCreateFlagBits when bits are defined in the future"/>
<type name="VkPipelineViewportStateCreateInfo"/>
<type name="VkPolygonMode"/>
<type name="VkPrimitiveTopology"/>
@@ -11360,13 +14070,14 @@ typedef void <name>CAMetalLayer</name>;
<type name="VkPhysicalDeviceVariablePointerFeatures"/>
<type name="VkPhysicalDeviceVariablePointersFeatures"/>
</require>
- <require comment="Originally based on VK_KHR_protected_memory (extension 146), which was never published; thus the mystifying large value= numbers below. These are not aliased since they weren't actually promoted from an extension.">
+ <require comment="Originally based on VK_KHR_protected_memory (extension 146), which was never published; thus the mystifying large value= numbers below. These are not aliased since they were not actually promoted from an extension.">
<enum extends="VkStructureType" extnumber="146" offset="0" name="VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO"/>
<enum extends="VkStructureType" extnumber="146" offset="1" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES"/>
<enum extends="VkStructureType" extnumber="146" offset="2" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES"/>
<enum extends="VkStructureType" extnumber="146" offset="3" name="VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2"/>
<enum bitpos="4" extends="VkQueueFlagBits" name="VK_QUEUE_PROTECTED_BIT" comment="Queues may support protected operations"/>
<enum bitpos="0" extends="VkDeviceQueueCreateFlagBits" name="VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT" comment="Queue is a protected-capable device queue"/>
+ <type name="VkDeviceQueueCreateFlagBits" comment="This is a temporary workaround for processors not recognizing that VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT above also requires this type"/>
<enum bitpos="5" extends="VkMemoryPropertyFlagBits" name="VK_MEMORY_PROPERTY_PROTECTED_BIT" comment="Memory is protected"/>
<enum bitpos="3" extends="VkBufferCreateFlagBits" name="VK_BUFFER_CREATE_PROTECTED_BIT" comment="Buffer requires protected memory"/>
<enum bitpos="11" extends="VkImageCreateFlagBits" name="VK_IMAGE_CREATE_PROTECTED_BIT" comment="Image requires protected memory"/>
@@ -11728,6 +14439,270 @@ typedef void <name>CAMetalLayer</name>;
<command name="vkGetDeviceMemoryOpaqueCaptureAddress"/>
</require>
</feature>
+ <feature api="vulkan" name="VK_VERSION_1_3" number="1.3" comment="Vulkan 1.3 core API interface definitions.">
+ <require>
+ <type name="VK_API_VERSION_1_3"/>
+ </require>
+ <require>
+ <type name="VkFlags64"/>
+ </require>
+ <require>
+ <enum extends="VkStructureType" value="53" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES"/>
+ <enum extends="VkStructureType" value="54" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES"/>
+ <type name="VkPhysicalDeviceVulkan13Features"/>
+ <type name="VkPhysicalDeviceVulkan13Properties"/>
+ </require>
+ <require comment="Promoted from VK_EXT_pipeline_creation_feedback (extension 193)">
+ <enum offset="0" extends="VkStructureType" extnumber="193" name="VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO"/>
+ <type name="VkPipelineCreationFeedbackFlagBits"/>
+ <type name="VkPipelineCreationFeedbackFlags"/>
+ <type name="VkPipelineCreationFeedbackCreateInfo"/>
+ <type name="VkPipelineCreationFeedback"/>
+ </require>
+ <require comment="Promoted from VK_KHR_shader_terminate_invocation (extension 216)">
+ <enum offset="0" extends="VkStructureType" extnumber="216" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES"/>
+ <type name="VkPhysicalDeviceShaderTerminateInvocationFeatures"/>
+ </require>
+ <require comment="Promoted from VK_EXT_tooling_info (extension 246)">
+ <enum offset="0" extends="VkStructureType" extnumber="246" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES"/>
+ <type name="VkToolPurposeFlagBits"/>
+ <type name="VkToolPurposeFlags"/>
+ <type name="VkPhysicalDeviceToolProperties"/>
+ <command name="vkGetPhysicalDeviceToolProperties"/>
+ </require>
+ <require comment="Promoted from VK_EXT_shader_demote_to_helper_invocation (extension 277)">
+ <enum offset="0" extends="VkStructureType" extnumber="277" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES"/>
+ <type name="VkPhysicalDeviceShaderDemoteToHelperInvocationFeatures"/>
+ </require>
+ <require comment="Promoted from VK_KHR_shader_non_semantic_info (extension 294)">
+ </require>
+ <require comment="Promoted from VK_EXT_private_data (extension 296)">
+ <enum offset="0" extends="VkStructureType" extnumber="296" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES"/>
+ <enum offset="1" extends="VkStructureType" extnumber="296" name="VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO"/>
+ <enum offset="2" extends="VkStructureType" extnumber="296" name="VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO"/>
+ <enum offset="0" extends="VkObjectType" extnumber="296" name="VK_OBJECT_TYPE_PRIVATE_DATA_SLOT"/>
+ <type name="VkPhysicalDevicePrivateDataFeatures"/>
+ <type name="VkDevicePrivateDataCreateInfo"/>
+ <type name="VkPrivateDataSlotCreateInfo"/>
+ <type name="VkPrivateDataSlot"/>
+ <type name="VkPrivateDataSlotCreateFlags" comment="Will add VkPrivateDataSlotCreateFlagBits when bits are defined in the future"/>
+ <command name="vkCreatePrivateDataSlot"/>
+ <command name="vkDestroyPrivateDataSlot"/>
+ <command name="vkSetPrivateData"/>
+ <command name="vkGetPrivateData"/>
+ </require>
+ <require comment="Promoted from VK_EXT_pipeline_creation_cache_control (extension 298)">
+ <enum offset="0" extends="VkStructureType" extnumber="298" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES"/>
+ <type name="VkPhysicalDevicePipelineCreationCacheControlFeatures"/>
+ <enum bitpos="8" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT"/>
+ <enum bitpos="9" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT"/>
+ <enum offset="0" extends="VkResult" extnumber="298" name="VK_PIPELINE_COMPILE_REQUIRED"/>
+ <enum bitpos="0" extends="VkPipelineCacheCreateFlagBits" name="VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT"/>
+ </require>
+ <require comment="Promoted from VK_KHR_synchronization2 (extension 315)">
+ <enum offset="0" extends="VkStructureType" extnumber="315" name="VK_STRUCTURE_TYPE_MEMORY_BARRIER_2"/>
+ <enum offset="1" extends="VkStructureType" extnumber="315" name="VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2"/>
+ <enum offset="2" extends="VkStructureType" extnumber="315" name="VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2"/>
+ <enum offset="3" extends="VkStructureType" extnumber="315" name="VK_STRUCTURE_TYPE_DEPENDENCY_INFO"/>
+ <enum offset="4" extends="VkStructureType" extnumber="315" name="VK_STRUCTURE_TYPE_SUBMIT_INFO_2"/>
+ <enum offset="5" extends="VkStructureType" extnumber="315" name="VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO"/>
+ <enum offset="6" extends="VkStructureType" extnumber="315" name="VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO"/>
+ <enum offset="7" extends="VkStructureType" extnumber="315" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES"/>
+ <enum bitpos="0" extends="VkEventCreateFlagBits" name="VK_EVENT_CREATE_DEVICE_ONLY_BIT"/>
+ <enum offset="0" extends="VkImageLayout" extnumber="315" name="VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL"/>
+ <enum offset="1" extends="VkImageLayout" extnumber="315" name="VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL"/>
+ <enum value="0" extends="VkPipelineStageFlagBits" name="VK_PIPELINE_STAGE_NONE"/>
+ <enum value="0" extends="VkAccessFlagBits" name="VK_ACCESS_NONE"/>
+ <type name="VkPipelineStageFlags2"/>
+ <type name="VkPipelineStageFlagBits2"/>
+ <type name="VkAccessFlags2"/>
+ <type name="VkAccessFlagBits2"/>
+ <type name="VkMemoryBarrier2"/>
+ <type name="VkBufferMemoryBarrier2"/>
+ <type name="VkImageMemoryBarrier2"/>
+ <type name="VkDependencyInfo"/>
+ <type name="VkSubmitInfo2"/>
+ <type name="VkSemaphoreSubmitInfo"/>
+ <type name="VkCommandBufferSubmitInfo"/>
+ <type name="VkSubmitFlagBits"/>
+ <type name="VkSubmitFlags"/>
+ <type name="VkPhysicalDeviceSynchronization2Features"/>
+ <command name="vkCmdSetEvent2"/>
+ <command name="vkCmdResetEvent2"/>
+ <command name="vkCmdWaitEvents2"/>
+ <command name="vkCmdPipelineBarrier2"/>
+ <command name="vkCmdWriteTimestamp2"/>
+ <command name="vkQueueSubmit2"/>
+ </require>
+ <require comment="Promoted from VK_KHR_zero_initialize_workgroup_memory (extension 326)">
+ <enum offset="0" extends="VkStructureType" extnumber="326" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES"/>
+ <type name="VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeatures"/>
+ </require>
+ <require comment="Promoted from VK_EXT_image_robustness (extension 336)">
+ <enum offset="0" extends="VkStructureType" extnumber="336" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES"/>
+ <type name="VkPhysicalDeviceImageRobustnessFeatures"/>
+ </require>
+ <require comment="Promoted from VK_KHR_copy_commands2 (extension 338)">
+ <enum offset="0" extends="VkStructureType" extnumber="338" name="VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2"/>
+ <enum offset="1" extends="VkStructureType" extnumber="338" name="VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2"/>
+ <enum offset="2" extends="VkStructureType" extnumber="338" name="VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2"/>
+ <enum offset="3" extends="VkStructureType" extnumber="338" name="VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2"/>
+ <enum offset="4" extends="VkStructureType" extnumber="338" name="VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2"/>
+ <enum offset="5" extends="VkStructureType" extnumber="338" name="VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2"/>
+ <enum offset="6" extends="VkStructureType" extnumber="338" name="VK_STRUCTURE_TYPE_BUFFER_COPY_2"/>
+ <enum offset="7" extends="VkStructureType" extnumber="338" name="VK_STRUCTURE_TYPE_IMAGE_COPY_2"/>
+ <enum offset="8" extends="VkStructureType" extnumber="338" name="VK_STRUCTURE_TYPE_IMAGE_BLIT_2"/>
+ <enum offset="9" extends="VkStructureType" extnumber="338" name="VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2"/>
+ <enum offset="10" extends="VkStructureType" extnumber="338" name="VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2"/>
+ <type name="VkCopyBufferInfo2"/>
+ <type name="VkCopyImageInfo2"/>
+ <type name="VkCopyBufferToImageInfo2"/>
+ <type name="VkCopyImageToBufferInfo2"/>
+ <type name="VkBlitImageInfo2"/>
+ <type name="VkResolveImageInfo2"/>
+ <type name="VkBufferCopy2"/>
+ <type name="VkImageCopy2"/>
+ <type name="VkImageBlit2"/>
+ <type name="VkBufferImageCopy2"/>
+ <type name="VkImageResolve2"/>
+ <command name="vkCmdCopyBuffer2"/>
+ <command name="vkCmdCopyImage2"/>
+ <command name="vkCmdCopyBufferToImage2"/>
+ <command name="vkCmdCopyImageToBuffer2"/>
+ <command name="vkCmdBlitImage2"/>
+ <command name="vkCmdResolveImage2"/>
+ </require>
+ <require comment="Promoted from VK_EXT_subgroup_size_control (STDPROMOTE/PROPLIMCHANGE) (extension 226)">
+ <type name="VkPhysicalDeviceSubgroupSizeControlFeatures"/>
+ <type name="VkPhysicalDeviceSubgroupSizeControlProperties"/>
+ <type name="VkPipelineShaderStageRequiredSubgroupSizeCreateInfo"/>
+ <enum offset="0" extends="VkStructureType" extnumber="226" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES"/>
+ <enum offset="1" extends="VkStructureType" extnumber="226" name="VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO"/>
+ <enum offset="2" extends="VkStructureType" extnumber="226" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES"/>
+ <enum bitpos="0" extends="VkPipelineShaderStageCreateFlagBits" name="VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT"/>
+ <enum bitpos="1" extends="VkPipelineShaderStageCreateFlagBits" name="VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT"/>
+ </require>
+ <require comment="Promoted from VK_EXT_inline_uniform_block (STDPROMOTE/PROPLIMCHANGE) (extension 139)">
+ <enum offset="0" extends="VkDescriptorType" extnumber="139" name="VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK"/>
+ <enum offset="0" extends="VkStructureType" extnumber="139" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES"/>
+ <enum offset="1" extends="VkStructureType" extnumber="139" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES"/>
+ <enum offset="2" extends="VkStructureType" extnumber="139" name="VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK"/>
+ <enum offset="3" extends="VkStructureType" extnumber="139" name="VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO"/>
+ <type name="VkPhysicalDeviceInlineUniformBlockFeatures"/>
+ <type name="VkPhysicalDeviceInlineUniformBlockProperties"/>
+ <type name="VkWriteDescriptorSetInlineUniformBlock"/>
+ <type name="VkDescriptorPoolInlineUniformBlockCreateInfo"/>
+ </require>
+ <require comment="Promoted from VK_EXT_ycbcr_2plane_444_formats (does not promote the Feature struct, just the formats) (extension 331)">
+ <enum offset="0" extends="VkFormat" extnumber="331" name="VK_FORMAT_G8_B8R8_2PLANE_444_UNORM"/>
+ <enum offset="1" extends="VkFormat" extnumber="331" name="VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16"/>
+ <enum offset="2" extends="VkFormat" extnumber="331" name="VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16"/>
+ <enum offset="3" extends="VkFormat" extnumber="331" name="VK_FORMAT_G16_B16R16_2PLANE_444_UNORM"/>
+ </require>
+ <require comment="Promoted from VK_EXT_4444_formats (does not promote the Feature struct, just the formats) (extension 341)">
+ <enum offset="0" extends="VkFormat" extnumber="341" name="VK_FORMAT_A4R4G4B4_UNORM_PACK16"/>
+ <enum offset="1" extends="VkFormat" extnumber="341" name="VK_FORMAT_A4B4G4R4_UNORM_PACK16"/>
+ </require>
+ <require comment="Promoted from VK_EXT_texture_compression_astc_hdr (Feature struct is promoted, but becomes optional) (extension 67)">
+ <enum offset="0" extends="VkStructureType" extnumber="67" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES"/>
+ <type name="VkPhysicalDeviceTextureCompressionASTCHDRFeatures"/>
+ <enum offset="0" extends="VkFormat" extnumber="67" name="VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK"/>
+ <enum offset="1" extends="VkFormat" extnumber="67" name="VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK"/>
+ <enum offset="2" extends="VkFormat" extnumber="67" name="VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK"/>
+ <enum offset="3" extends="VkFormat" extnumber="67" name="VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK"/>
+ <enum offset="4" extends="VkFormat" extnumber="67" name="VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK"/>
+ <enum offset="5" extends="VkFormat" extnumber="67" name="VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK"/>
+ <enum offset="6" extends="VkFormat" extnumber="67" name="VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK"/>
+ <enum offset="7" extends="VkFormat" extnumber="67" name="VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK"/>
+ <enum offset="8" extends="VkFormat" extnumber="67" name="VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK"/>
+ <enum offset="9" extends="VkFormat" extnumber="67" name="VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK"/>
+ <enum offset="10" extends="VkFormat" extnumber="67" name="VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK"/>
+ <enum offset="11" extends="VkFormat" extnumber="67" name="VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK"/>
+ <enum offset="12" extends="VkFormat" extnumber="67" name="VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK"/>
+ <enum offset="13" extends="VkFormat" extnumber="67" name="VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK"/>
+ </require>
+ <require comment="Promoted from VK_KHR_dynamic_rendering (extension 45)">
+ <command name="vkCmdBeginRendering"/>
+ <command name="vkCmdEndRendering"/>
+ <enum offset="0" extends="VkStructureType" extnumber="45" name="VK_STRUCTURE_TYPE_RENDERING_INFO"/>
+ <enum offset="1" extends="VkStructureType" extnumber="45" name="VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO"/>
+ <enum offset="2" extends="VkStructureType" extnumber="45" name="VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO"/>
+ <enum offset="3" extends="VkStructureType" extnumber="45" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES"/>
+ <enum offset="4" extends="VkStructureType" extnumber="45" name="VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO"/>
+ <enum offset="0" extends="VkAttachmentStoreOp" extnumber="302" name="VK_ATTACHMENT_STORE_OP_NONE"/>
+ <type name="VkRenderingInfo"/>
+ <type name="VkRenderingAttachmentInfo"/>
+ <type name="VkPipelineRenderingCreateInfo"/>
+ <type name="VkPhysicalDeviceDynamicRenderingFeatures"/>
+ <type name="VkCommandBufferInheritanceRenderingInfo"/>
+ <type name="VkRenderingFlags"/>
+ <type name="VkRenderingFlagBits"/>
+ </require>
+ <require comment="Promoted from VK_EXT_extended_dynamic_state (Feature struct is not promoted) (extension 268)">
+ <enum offset="0" extends="VkDynamicState" extnumber="268" name="VK_DYNAMIC_STATE_CULL_MODE"/>
+ <enum offset="1" extends="VkDynamicState" extnumber="268" name="VK_DYNAMIC_STATE_FRONT_FACE"/>
+ <enum offset="2" extends="VkDynamicState" extnumber="268" name="VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY"/>
+ <enum offset="3" extends="VkDynamicState" extnumber="268" name="VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT"/>
+ <enum offset="4" extends="VkDynamicState" extnumber="268" name="VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT"/>
+ <enum offset="5" extends="VkDynamicState" extnumber="268" name="VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE"/>
+ <enum offset="6" extends="VkDynamicState" extnumber="268" name="VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE"/>
+ <enum offset="7" extends="VkDynamicState" extnumber="268" name="VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE"/>
+ <enum offset="8" extends="VkDynamicState" extnumber="268" name="VK_DYNAMIC_STATE_DEPTH_COMPARE_OP"/>
+ <enum offset="9" extends="VkDynamicState" extnumber="268" name="VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE"/>
+ <enum offset="10" extends="VkDynamicState" extnumber="268" name="VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE"/>
+ <enum offset="11" extends="VkDynamicState" extnumber="268" name="VK_DYNAMIC_STATE_STENCIL_OP"/>
+ <command name="vkCmdSetCullMode"/>
+ <command name="vkCmdSetFrontFace"/>
+ <command name="vkCmdSetPrimitiveTopology"/>
+ <command name="vkCmdSetViewportWithCount"/>
+ <command name="vkCmdSetScissorWithCount"/>
+ <command name="vkCmdBindVertexBuffers2"/>
+ <command name="vkCmdSetDepthTestEnable"/>
+ <command name="vkCmdSetDepthWriteEnable"/>
+ <command name="vkCmdSetDepthCompareOp"/>
+ <command name="vkCmdSetDepthBoundsTestEnable"/>
+ <command name="vkCmdSetStencilTestEnable"/>
+ <command name="vkCmdSetStencilOp"/>
+ </require>
+ <require comment="Promoted from VK_KHR_shader_integer_dot_product (extension 281)">
+ <enum offset="0" extends="VkStructureType" extnumber="281" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES"/>
+ <enum offset="1" extends="VkStructureType" extnumber="281" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES"/>
+ <type name="VkPhysicalDeviceShaderIntegerDotProductFeatures"/>
+ <type name="VkPhysicalDeviceShaderIntegerDotProductProperties"/>
+ </require>
+ <require comment="Promoted from VK_EXT_texel_buffer_alignment (extension 282)">
+ <enum offset="1" extends="VkStructureType" extnumber="282" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES"/>
+ <type name="VkPhysicalDeviceTexelBufferAlignmentProperties"/>
+ </require>
+ <require comment="Promoted from VK_KHR_format_feature_flags2 (extension 361)">
+ <enum offset="0" extends="VkStructureType" extnumber="361" name="VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3"/>
+ <type name="VkFormatFeatureFlags2"/>
+ <type name="VkFormatFeatureFlagBits2"/>
+ <type name="VkFormatProperties3"/>
+ </require>
+ <require comment="Promoted from VK_EXT_extended_dynamic_state2 (Feature struct and optional state are not promoted) (extension 378)">
+ <enum offset="1" extends="VkDynamicState" extnumber="378" name="VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE"/>
+ <enum offset="2" extends="VkDynamicState" extnumber="378" name="VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE"/>
+ <enum offset="4" extends="VkDynamicState" extnumber="378" name="VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE"/>
+ <command name="vkCmdSetRasterizerDiscardEnable"/>
+ <command name="vkCmdSetDepthBiasEnable"/>
+ <command name="vkCmdSetPrimitiveRestartEnable"/>
+ </require>
+ <require comment="Promoted from VK_KHR_maintenance4 (extension 414)">
+ <enum offset="0" extends="VkStructureType" extnumber="414" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES"/>
+ <enum offset="1" extends="VkStructureType" extnumber="414" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES"/>
+ <enum offset="2" extends="VkStructureType" extnumber="414" name="VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS"/>
+ <enum offset="3" extends="VkStructureType" extnumber="414" name="VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS"/>
+ <enum value="0" extends="VkImageAspectFlagBits" name="VK_IMAGE_ASPECT_NONE"/>
+ <type name="VkPhysicalDeviceMaintenance4Features"/>
+ <type name="VkPhysicalDeviceMaintenance4Properties"/>
+ <type name="VkDeviceBufferMemoryRequirements"/>
+ <type name="VkDeviceImageMemoryRequirements"/>
+ <command name="vkGetDeviceBufferMemoryRequirements"/>
+ <command name="vkGetDeviceImageMemoryRequirements"/>
+ <command name="vkGetDeviceImageSparseMemoryRequirements"/>
+ </require>
+ </feature>
<extensions comment="Vulkan extension interface definitions">
<extension name="VK_KHR_surface" number="1" type="instance" author="KHR" contact="James Jones @cubanismo,Ian Elliott @ianelliottus" supported="vulkan">
@@ -11901,11 +14876,11 @@ typedef void <name>CAMetalLayer</name>;
</extension>
<extension name="VK_ANDROID_native_buffer" number="11" type="device" author="ANDROID" platform="android" contact="Jesse Hall @critsec" supported="disabled">
<require>
- <comment>VK_ANDROID_native_buffer is used between the Android Vulkan loader and drivers to implement the WSI extensions. It isn't exposed to applications and uses types that aren't part of Android's stable public API, so it is left disabled to keep it out of the standard Vulkan headers.</comment>
+ <comment>VK_ANDROID_native_buffer is used between the Android Vulkan loader and drivers to implement the WSI extensions. It is not exposed to applications and uses types that are not part of Android's stable public API, so it is left disabled to keep it out of the standard Vulkan headers.</comment>
<enum value="8" name="VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION"/>
<enum value="11" name="VK_ANDROID_NATIVE_BUFFER_NUMBER"/>
- <enum value="&quot;VK_ANDROID_native_buffer&quot;" name="VK_ANDROID_NATIVE_BUFFER_NAME"/>
- <enum name="VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME" alias="VK_ANDROID_NATIVE_BUFFER_NAME"/>
+ <enum value="&quot;VK_ANDROID_native_buffer&quot;" name="VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME"/>
+ <enum name="VK_ANDROID_NATIVE_BUFFER_NAME" alias="VK_ANDROID_NATIVE_BUFFER_EXTENSION_NAME"/>
<enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID"/>
<enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SWAPCHAIN_IMAGE_CREATE_INFO_ANDROID"/>
<enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENTATION_PROPERTIES_ANDROID"/>
@@ -11970,8 +14945,8 @@ typedef void <name>CAMetalLayer</name>;
<require>
<enum value="1" name="VK_IMG_FILTER_CUBIC_SPEC_VERSION"/>
<enum value="&quot;VK_IMG_filter_cubic&quot;" name="VK_IMG_FILTER_CUBIC_EXTENSION_NAME"/>
- <enum offset="0" extends="VkFilter" name="VK_FILTER_CUBIC_IMG"/>
- <enum bitpos="13" extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG" comment="Format can be filtered with VK_FILTER_CUBIC_IMG when being sampled"/>
+ <enum extends="VkFilter" name="VK_FILTER_CUBIC_IMG" alias="VK_FILTER_CUBIC_EXT"/>
+ <enum extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG" alias="VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT" comment="Format can be filtered with VK_FILTER_CUBIC_IMG when being sampled"/>
</require>
</extension>
<extension name="VK_AMD_extension_17" number="17" author="AMD" contact="Daniel Rakos @drakos-amd" supported="disabled">
@@ -12031,32 +15006,40 @@ typedef void <name>CAMetalLayer</name>;
<command name="vkCmdDebugMarkerInsertEXT"/>
</require>
</extension>
- <extension name="VK_KHR_video_queue" number="24" type="device" requires="VK_KHR_get_physical_device_properties2,VK_KHR_sampler_ycbcr_conversion" author="KHR" contact="Tony Zlatinski @tzlatinski" provisional="true" platform="provisional" supported="vulkan">
+ <extension name="VK_KHR_video_queue" number="24" type="device" requires="VK_KHR_get_physical_device_properties2,VK_KHR_synchronization2" author="KHR" contact="Tony Zlatinski @tzlatinski" supported="vulkan" requiresCore="1.1">
<require>
- <enum value="1" name="VK_KHR_VIDEO_QUEUE_SPEC_VERSION"/>
+ <enum value="8" name="VK_KHR_VIDEO_QUEUE_SPEC_VERSION"/>
<enum value="&quot;VK_KHR_video_queue&quot;" name="VK_KHR_VIDEO_QUEUE_EXTENSION_NAME"/>
- <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_PROFILE_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_CAPABILITIES_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_GET_MEMORY_PROPERTIES_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_BIND_MEMORY_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="5" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_SESSION_CREATE_INFO_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="6" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_CREATE_INFO_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="7" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_UPDATE_INFO_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="8" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_BEGIN_CODING_INFO_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="9" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_END_CODING_INFO_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="10" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_CODING_CONTROL_INFO_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="11" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_REFERENCE_SLOT_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="12" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_QUEUE_FAMILY_PROPERTIES_2_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="13" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_PROFILES_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="14" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_FORMAT_INFO_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="15" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_FORMAT_PROPERTIES_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_PROFILE_INFO_KHR"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_CAPABILITIES_KHR"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_PICTURE_RESOURCE_INFO_KHR"/>
+ <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_SESSION_MEMORY_REQUIREMENTS_KHR"/>
+ <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_BIND_VIDEO_SESSION_MEMORY_INFO_KHR"/>
+ <enum offset="5" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_SESSION_CREATE_INFO_KHR"/>
+ <enum offset="6" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_CREATE_INFO_KHR"/>
+ <enum offset="7" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_SESSION_PARAMETERS_UPDATE_INFO_KHR"/>
+ <enum offset="8" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_BEGIN_CODING_INFO_KHR"/>
+ <enum offset="9" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_END_CODING_INFO_KHR"/>
+ <enum offset="10" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_CODING_CONTROL_INFO_KHR"/>
+ <enum offset="11" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_REFERENCE_SLOT_INFO_KHR"/>
+ <enum offset="12" extends="VkStructureType" name="VK_STRUCTURE_TYPE_QUEUE_FAMILY_VIDEO_PROPERTIES_KHR"/>
+ <enum offset="13" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_PROFILE_LIST_INFO_KHR"/>
+ <enum offset="14" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VIDEO_FORMAT_INFO_KHR"/>
+ <enum offset="15" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_FORMAT_PROPERTIES_KHR"/>
+ <enum offset="16" extends="VkStructureType" name="VK_STRUCTURE_TYPE_QUEUE_FAMILY_QUERY_RESULT_STATUS_PROPERTIES_KHR"/>
- <enum offset="0" extends="VkObjectType" name="VK_OBJECT_TYPE_VIDEO_SESSION_KHR" comment="VkVideoSessionKHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="1" extends="VkObjectType" name="VK_OBJECT_TYPE_VIDEO_SESSION_PARAMETERS_KHR" comment="VkVideoSessionParametersKHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum offset="0" extends="VkObjectType" name="VK_OBJECT_TYPE_VIDEO_SESSION_KHR" comment="VkVideoSessionKHR"/>
+ <enum offset="1" extends="VkObjectType" name="VK_OBJECT_TYPE_VIDEO_SESSION_PARAMETERS_KHR" comment="VkVideoSessionParametersKHR"/>
- <enum offset="0" extends="VkQueryType" name="VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum bitpos="4" extends="VkQueryResultFlagBits" name="VK_QUERY_RESULT_WITH_STATUS_BIT_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum offset="0" extends="VkQueryType" name="VK_QUERY_TYPE_RESULT_STATUS_ONLY_KHR"/>
+ <enum bitpos="4" extends="VkQueryResultFlagBits" name="VK_QUERY_RESULT_WITH_STATUS_BIT_KHR"/>
+
+ <enum offset="0" extends="VkResult" dir="-" name="VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR"/>
+ <enum offset="1" extends="VkResult" dir="-" name="VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR"/>
+ <enum offset="2" extends="VkResult" dir="-" name="VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR"/>
+ <enum offset="3" extends="VkResult" dir="-" name="VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR"/>
+ <enum offset="4" extends="VkResult" dir="-" name="VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR"/>
+ <enum offset="5" extends="VkResult" dir="-" name="VK_ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR"/>
<type name="VkVideoSessionKHR"/>
<type name="VkVideoSessionParametersKHR"/>
@@ -12067,29 +15050,29 @@ typedef void <name>CAMetalLayer</name>;
<type name="VkVideoChromaSubsamplingFlagsKHR"/>
<type name="VkVideoComponentBitDepthFlagBitsKHR"/>
<type name="VkVideoComponentBitDepthFlagsKHR"/>
- <type name="VkVideoCapabilitiesFlagBitsKHR"/>
- <type name="VkVideoCapabilitiesFlagsKHR"/>
+ <type name="VkVideoCapabilityFlagBitsKHR"/>
+ <type name="VkVideoCapabilityFlagsKHR"/>
<type name="VkVideoSessionCreateFlagBitsKHR"/>
<type name="VkVideoSessionCreateFlagsKHR"/>
+ <type name="VkVideoSessionParametersCreateFlagsKHR"/>
<type name="VkVideoBeginCodingFlagsKHR"/>
<type name="VkVideoEndCodingFlagsKHR"/>
<type name="VkVideoCodingControlFlagBitsKHR"/>
<type name="VkVideoCodingControlFlagsKHR"/>
- <type name="VkVideoCodingQualityPresetFlagBitsKHR"/>
- <type name="VkVideoCodingQualityPresetFlagsKHR"/>
+ <type name="VkQueueFamilyQueryResultStatusPropertiesKHR"/>
<type name="VkQueryResultStatusKHR"/>
- <type name="VkVideoQueueFamilyProperties2KHR"/>
- <type name="VkVideoProfileKHR"/>
- <type name="VkVideoProfilesKHR"/>
+ <type name="VkQueueFamilyVideoPropertiesKHR"/>
+ <type name="VkVideoProfileInfoKHR"/>
+ <type name="VkVideoProfileListInfoKHR"/>
<type name="VkVideoCapabilitiesKHR"/>
<type name="VkPhysicalDeviceVideoFormatInfoKHR"/>
<type name="VkVideoFormatPropertiesKHR"/>
- <type name="VkVideoPictureResourceKHR"/>
- <type name="VkVideoReferenceSlotKHR"/>
- <type name="VkVideoGetMemoryPropertiesKHR"/>
- <type name="VkVideoBindMemoryKHR"/>
+ <type name="VkVideoPictureResourceInfoKHR"/>
+ <type name="VkVideoReferenceSlotInfoKHR"/>
+ <type name="VkVideoSessionMemoryRequirementsKHR"/>
+ <type name="VkBindVideoSessionMemoryInfoKHR"/>
<type name="VkVideoSessionCreateInfoKHR"/>
<type name="VkVideoSessionParametersCreateInfoKHR"/>
<type name="VkVideoSessionParametersUpdateInfoKHR"/>
@@ -12112,32 +15095,46 @@ typedef void <name>CAMetalLayer</name>;
<command name="vkCmdControlVideoCodingKHR"/>
</require>
</extension>
- <extension name="VK_KHR_video_decode_queue" number="25" type="device" requires="VK_KHR_video_queue,VK_KHR_synchronization2" author="KHR" contact="jake.beju@amd.com" provisional="true" platform="provisional" supported="vulkan">
+ <extension name="VK_KHR_video_decode_queue" number="25" type="device" requires="VK_KHR_video_queue,VK_KHR_synchronization2" author="KHR" contact="jake.beju@amd.com" supported="vulkan">
<require>
- <enum value="1" name="VK_KHR_VIDEO_DECODE_QUEUE_SPEC_VERSION"/>
+ <enum value="7" name="VK_KHR_VIDEO_DECODE_QUEUE_SPEC_VERSION"/>
<enum value="&quot;VK_KHR_video_decode_queue&quot;" name="VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME"/>
- <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_DECODE_INFO_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum bitpos="5" extends="VkQueueFlagBits" name="VK_QUEUE_VIDEO_DECODE_BIT_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum bitpos="26" extends="VkPipelineStageFlagBits2KHR" name="VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum bitpos="35" extends="VkAccessFlagBits2KHR" name="VK_ACCESS_2_VIDEO_DECODE_READ_BIT_KHR" protect="VK_ENABLE_BETA_EXTENSIONS" />
- <enum bitpos="36" extends="VkAccessFlagBits2KHR" name="VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum bitpos="13" extends="VkBufferUsageFlagBits" name="VK_BUFFER_USAGE_VIDEO_DECODE_SRC_BIT_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum bitpos="14" extends="VkBufferUsageFlagBits" name="VK_BUFFER_USAGE_VIDEO_DECODE_DST_BIT_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum bitpos="10" extends="VkImageUsageFlagBits" name="VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum bitpos="11" extends="VkImageUsageFlagBits" name="VK_IMAGE_USAGE_VIDEO_DECODE_SRC_BIT_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum bitpos="12" extends="VkImageUsageFlagBits" name="VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum bitpos="25" extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_VIDEO_DECODE_OUTPUT_BIT_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum bitpos="26" extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_VIDEO_DECODE_DPB_BIT_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="0" extends="VkImageLayout" name="VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="1" extends="VkImageLayout" name="VK_IMAGE_LAYOUT_VIDEO_DECODE_SRC_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="2" extends="VkImageLayout" name="VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_DECODE_INFO_KHR"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_DECODE_CAPABILITIES_KHR"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_DECODE_USAGE_INFO_KHR"/>
+ <enum bitpos="5" extends="VkQueueFlagBits" name="VK_QUEUE_VIDEO_DECODE_BIT_KHR"/>
+ <!-- VkPipelineStageFlagBits bitpos="26" is reserved by this extension, but not used -->
+ <enum bitpos="26" extends="VkPipelineStageFlagBits2" name="VK_PIPELINE_STAGE_2_VIDEO_DECODE_BIT_KHR"/>
+ <enum bitpos="35" extends="VkAccessFlagBits2" name="VK_ACCESS_2_VIDEO_DECODE_READ_BIT_KHR"/>
+ <enum bitpos="36" extends="VkAccessFlagBits2" name="VK_ACCESS_2_VIDEO_DECODE_WRITE_BIT_KHR"/>
+ <enum bitpos="13" extends="VkBufferUsageFlagBits" name="VK_BUFFER_USAGE_VIDEO_DECODE_SRC_BIT_KHR"/>
+ <enum bitpos="14" extends="VkBufferUsageFlagBits" name="VK_BUFFER_USAGE_VIDEO_DECODE_DST_BIT_KHR"/>
+ <enum bitpos="10" extends="VkImageUsageFlagBits" name="VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR"/>
+ <enum bitpos="11" extends="VkImageUsageFlagBits" name="VK_IMAGE_USAGE_VIDEO_DECODE_SRC_BIT_KHR"/>
+ <enum bitpos="12" extends="VkImageUsageFlagBits" name="VK_IMAGE_USAGE_VIDEO_DECODE_DPB_BIT_KHR"/>
+ <enum bitpos="25" extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_VIDEO_DECODE_OUTPUT_BIT_KHR"/>
+ <enum bitpos="26" extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_VIDEO_DECODE_DPB_BIT_KHR"/>
+ <enum offset="0" extends="VkImageLayout" name="VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR"/>
+ <enum offset="1" extends="VkImageLayout" name="VK_IMAGE_LAYOUT_VIDEO_DECODE_SRC_KHR"/>
+ <enum offset="2" extends="VkImageLayout" name="VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR"/>
+
+ <type name="VkVideoDecodeCapabilityFlagBitsKHR"/>
+ <type name="VkVideoDecodeCapabilityFlagsKHR"/>
+ <type name="VkVideoDecodeCapabilitiesKHR"/>
+
+ <type name="VkVideoDecodeUsageFlagBitsKHR"/>
+ <type name="VkVideoDecodeUsageFlagsKHR"/>
+ <type name="VkVideoDecodeUsageInfoKHR"/>
- <type name="VkVideoDecodeFlagBitsKHR"/>
<type name="VkVideoDecodeFlagsKHR"/>
<type name="VkVideoDecodeInfoKHR"/>
<command name="vkCmdDecodeVideoKHR"/>
</require>
+ <require extension="VK_KHR_format_feature_flags2">
+ <enum bitpos="25" extends="VkFormatFeatureFlagBits2" name="VK_FORMAT_FEATURE_2_VIDEO_DECODE_OUTPUT_BIT_KHR"/>
+ <enum bitpos="26" extends="VkFormatFeatureFlagBits2" name="VK_FORMAT_FEATURE_2_VIDEO_DECODE_DPB_BIT_KHR"/>
+ </require>
</extension>
<extension name="VK_AMD_gcn_shader" number="26" type="device" author="AMD" contact="Dominik Witczak @dominikwitczakamd" supported="vulkan">
<require>
@@ -12160,7 +15157,7 @@ typedef void <name>CAMetalLayer</name>;
<extension name="VK_EXT_extension_28" number="28" author="NV" contact="Piers Daniell @pdaniell-nv" supported="disabled">
<require>
<enum value="0" name="VK_EXT_EXTENSION_28_SPEC_VERSION"/>
- <enum value="&quot;VK_NV_extension_28&quot;" name="VK_EXT_EXTENSION_28_EXTENSION_NAME"/>
+ <enum value="&quot;VK_EXT_extension_28&quot;" name="VK_EXT_EXTENSION_28_EXTENSION_NAME"/>
</require>
</extension>
<extension name="VK_EXT_transform_feedback" number="29" type="device" author="NV" contact="Piers Daniell @pdaniell-nv" specialuse="glemulation,d3demulation,devtools" supported="vulkan" requires="VK_KHR_get_physical_device_properties2">
@@ -12180,8 +15177,8 @@ typedef void <name>CAMetalLayer</name>;
<enum offset="4" extends="VkQueryType" name="VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT"/>
- <enum bitpos="11" extends="VkBufferUsageFlagBits" name="VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT"/>
- <enum bitpos="12" extends="VkBufferUsageFlagBits" name="VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT"/>
+ <enum bitpos="11" extends="VkBufferUsageFlagBits" name="VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT"/>
+ <enum bitpos="12" extends="VkBufferUsageFlagBits" name="VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT"/>
<enum bitpos="25" extends="VkAccessFlagBits" name="VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT"/>
<enum bitpos="26" extends="VkAccessFlagBits" name="VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT"/>
@@ -12196,7 +15193,7 @@ typedef void <name>CAMetalLayer</name>;
<type name="VkPipelineRasterizationStateStreamCreateFlagsEXT"/>
</require>
</extension>
- <extension name="VK_NVX_binary_import" number="30" type="device" author="NVX" contact="Eric Werness @ewerness,Liam Middlebrook @liam-middlebrook" supported="vulkan">
+ <extension name="VK_NVX_binary_import" number="30" type="device" author="NVX" contact="Eric Werness @ewerness-nv,Liam Middlebrook @liam-middlebrook" supported="vulkan">
<require>
<enum value="1" name="VK_NVX_BINARY_IMPORT_SPEC_VERSION"/>
<enum value="&quot;VK_NVX_binary_import&quot;" name="VK_NVX_BINARY_IMPORT_EXTENSION_NAME"/>
@@ -12219,7 +15216,7 @@ typedef void <name>CAMetalLayer</name>;
<command name="vkCmdCuLaunchKernelNVX"/>
</require>
</extension>
- <extension name="VK_NVX_image_view_handle" number="31" type="device" author="NVX" contact="Eric Werness @ewerness" supported="vulkan">
+ <extension name="VK_NVX_image_view_handle" number="31" type="device" author="NVX" contact="Eric Werness @ewerness-nv" supported="vulkan">
<require>
<enum value="2" name="VK_NVX_IMAGE_VIEW_HANDLE_SPEC_VERSION"/>
<enum value="&quot;VK_NVX_image_view_handle&quot;" name="VK_NVX_IMAGE_VIEW_HANDLE_EXTENSION_NAME"/>
@@ -12277,69 +15274,106 @@ typedef void <name>CAMetalLayer</name>;
</extension>
<extension name="VK_EXT_video_encode_h264" number="39" type="device" requires="VK_KHR_video_encode_queue" author="KHR" contact="Ahmed Abdelkhalek @aabdelkh" provisional="true" platform="provisional" supported="vulkan">
<require>
- <enum value="1" name="VK_EXT_VIDEO_ENCODE_H264_SPEC_VERSION"/>
+ <enum value="9" name="VK_EXT_VIDEO_ENCODE_H264_SPEC_VERSION"/>
<enum value="&quot;VK_EXT_video_encode_h264&quot;" name="VK_EXT_VIDEO_ENCODE_H264_EXTENSION_NAME"/>
<enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_CAPABILITIES_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_CREATE_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_CREATE_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_ADD_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_VCL_FRAME_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="5" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_DPB_SLOT_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="6" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_NALU_SLICE_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="7" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_EMIT_PICTURE_PARAMETERS_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="8" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_PROFILE_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_CREATE_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_SESSION_PARAMETERS_ADD_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_VCL_FRAME_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_DPB_SLOT_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum offset="5" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_NALU_SLICE_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum offset="6" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_EMIT_PICTURE_PARAMETERS_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum offset="7" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_PROFILE_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum offset="8" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_RATE_CONTROL_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum offset="9" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_RATE_CONTROL_LAYER_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum offset="10" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H264_REFERENCE_LISTS_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
<enum bitpos="16" extends="VkVideoCodecOperationFlagBitsKHR" name="VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <type name="VkVideoEncodeH264CapabilitiesFlagBitsEXT"/>
- <type name="VkVideoEncodeH264CapabilitiesFlagsEXT"/>
+ <type name="VkVideoEncodeH264CapabilityFlagBitsEXT"/>
+ <type name="VkVideoEncodeH264CapabilityFlagsEXT"/>
<type name="VkVideoEncodeH264InputModeFlagBitsEXT"/>
<type name="VkVideoEncodeH264InputModeFlagsEXT"/>
<type name="VkVideoEncodeH264OutputModeFlagBitsEXT"/>
<type name="VkVideoEncodeH264OutputModeFlagsEXT"/>
- <type name="VkVideoEncodeH264CreateFlagBitsEXT"/>
- <type name="VkVideoEncodeH264CreateFlagsEXT"/>
<type name="VkVideoEncodeH264CapabilitiesEXT"/>
- <type name="VkVideoEncodeH264SessionCreateInfoEXT"/>
<type name="VkVideoEncodeH264SessionParametersCreateInfoEXT"/>
<type name="VkVideoEncodeH264SessionParametersAddInfoEXT"/>
<type name="VkVideoEncodeH264VclFrameInfoEXT"/>
- <type name="VkVideoEncodeH264EmitPictureParametersEXT"/>
+ <type name="VkVideoEncodeH264ReferenceListsInfoEXT"/>
+ <type name="VkVideoEncodeH264EmitPictureParametersInfoEXT"/>
<type name="VkVideoEncodeH264DpbSlotInfoEXT"/>
- <type name="VkVideoEncodeH264NaluSliceEXT"/>
- <type name="VkVideoEncodeH264ProfileEXT"/>
+ <type name="VkVideoEncodeH264NaluSliceInfoEXT"/>
+ <type name="VkVideoEncodeH264ProfileInfoEXT"/>
+ <type name="VkVideoEncodeH264RateControlInfoEXT"/>
+ <type name="VkVideoEncodeH264RateControlStructureEXT"/>
+ <type name="VkVideoEncodeH264RateControlLayerInfoEXT"/>
+ <type name="VkVideoEncodeH264QpEXT"/>
+ <type name="VkVideoEncodeH264FrameSizeEXT"/>
</require>
</extension>
- <extension name="VK_EXT_video_encode_h265" number="40" type="device" requires="VK_KHR_video_encode_queue" author="KHR" contact="Ahmed Abdelkhalek @aabdelkh" supported="disabled">
+ <extension name="VK_EXT_video_encode_h265" number="40" type="device" requires="VK_KHR_video_encode_queue" author="KHR" contact="Ahmed Abdelkhalek @aabdelkh" provisional="true" platform="provisional" supported="vulkan">
<require>
- <enum value="0" name="VK_EXT_VIDEO_ENCODE_H265_SPEC_VERSION"/>
+ <enum value="9" name="VK_EXT_VIDEO_ENCODE_H265_SPEC_VERSION"/>
<enum value="&quot;VK_EXT_video_encode_h265&quot;" name="VK_EXT_VIDEO_ENCODE_H265_EXTENSION_NAME"/>
- </require>
- </extension>
- <extension name="VK_EXT_video_decode_h264" number="41" type="device" requires="VK_KHR_video_decode_queue" author="KHR" contact="peter.fang@amd.com" provisional="true" platform="provisional" supported="vulkan">
- <require>
- <enum value="1" name="VK_EXT_VIDEO_DECODE_H264_SPEC_VERSION"/>
- <enum value="&quot;VK_EXT_video_decode_h264&quot;" name="VK_EXT_VIDEO_DECODE_H264_EXTENSION_NAME"/>
- <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_CAPABILITIES_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_CREATE_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PICTURE_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_MVC_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PROFILE_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="5" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_CREATE_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="6" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_ADD_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="7" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_DPB_SLOT_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum bitpos="0" extends="VkVideoCodecOperationFlagBitsKHR" name="VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <type name="VkVideoDecodeH264FieldLayoutFlagBitsEXT"/>
- <type name="VkVideoDecodeH264FieldLayoutFlagsEXT"/>
- <type name="VkVideoDecodeH264CreateFlagsEXT"/>
- <type name="VkVideoDecodeH264ProfileEXT"/>
- <type name="VkVideoDecodeH264CapabilitiesEXT"/>
- <type name="VkVideoDecodeH264SessionCreateInfoEXT"/>
- <type name="VkVideoDecodeH264SessionParametersCreateInfoEXT"/>
- <type name="VkVideoDecodeH264SessionParametersAddInfoEXT"/>
- <type name="VkVideoDecodeH264PictureInfoEXT"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_CAPABILITIES_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_CREATE_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_SESSION_PARAMETERS_ADD_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_VCL_FRAME_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_DPB_SLOT_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum offset="5" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_NALU_SLICE_SEGMENT_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum offset="6" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_EMIT_PICTURE_PARAMETERS_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum offset="7" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_PROFILE_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum offset="8" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_REFERENCE_LISTS_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum offset="9" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_RATE_CONTROL_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum offset="10" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_H265_RATE_CONTROL_LAYER_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum bitpos="17" extends="VkVideoCodecOperationFlagBitsKHR" name="VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+
+ <type name="VkVideoEncodeH265CapabilityFlagBitsEXT"/>
+ <type name="VkVideoEncodeH265CapabilityFlagsEXT"/>
+ <type name="VkVideoEncodeH265InputModeFlagBitsEXT"/>
+ <type name="VkVideoEncodeH265InputModeFlagsEXT"/>
+ <type name="VkVideoEncodeH265OutputModeFlagBitsEXT"/>
+ <type name="VkVideoEncodeH265OutputModeFlagsEXT"/>
- <type name="VkVideoDecodeH264MvcEXT"/>
- <type name="VkVideoDecodeH264DpbSlotInfoEXT"/>
+ <type name="VkVideoEncodeH265CtbSizeFlagBitsEXT"/>
+ <type name="VkVideoEncodeH265CtbSizeFlagsEXT"/>
+ <type name="VkVideoEncodeH265TransformBlockSizeFlagBitsEXT"/>
+ <type name="VkVideoEncodeH265TransformBlockSizeFlagsEXT"/>
+ <type name="VkVideoEncodeH265CapabilitiesEXT"/>
+ <type name="VkVideoEncodeH265SessionParametersCreateInfoEXT"/>
+ <type name="VkVideoEncodeH265SessionParametersAddInfoEXT"/>
+ <type name="VkVideoEncodeH265VclFrameInfoEXT"/>
+ <type name="VkVideoEncodeH265EmitPictureParametersInfoEXT"/>
+ <type name="VkVideoEncodeH265DpbSlotInfoEXT"/>
+ <type name="VkVideoEncodeH265NaluSliceSegmentInfoEXT"/>
+ <type name="VkVideoEncodeH265ProfileInfoEXT"/>
+ <type name="VkVideoEncodeH265ReferenceListsInfoEXT"/>
+ <type name="VkVideoEncodeH265RateControlInfoEXT"/>
+ <type name="VkVideoEncodeH265RateControlStructureEXT"/>
+ <type name="VkVideoEncodeH265RateControlLayerInfoEXT"/>
+ <type name="VkVideoEncodeH265QpEXT"/>
+ <type name="VkVideoEncodeH265FrameSizeEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_video_decode_h264" number="41" type="device" requires="VK_KHR_video_decode_queue" author="KHR" contact="peter.fang@amd.com" supported="vulkan">
+ <require>
+ <enum value="8" name="VK_KHR_VIDEO_DECODE_H264_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_video_decode_h264&quot;" name="VK_KHR_VIDEO_DECODE_H264_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_CAPABILITIES_KHR"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PICTURE_INFO_KHR"/>
+ <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PROFILE_INFO_KHR"/>
+ <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_CREATE_INFO_KHR"/>
+ <enum offset="5" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_SESSION_PARAMETERS_ADD_INFO_KHR"/>
+ <enum offset="6" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_DPB_SLOT_INFO_KHR"/>
+ <enum bitpos="0" extends="VkVideoCodecOperationFlagBitsKHR" name="VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR"/>
+ <type name="VkVideoDecodeH264PictureLayoutFlagBitsKHR"/>
+ <type name="VkVideoDecodeH264PictureLayoutFlagsKHR"/>
+ <type name="VkVideoDecodeH264ProfileInfoKHR"/>
+ <type name="VkVideoDecodeH264CapabilitiesKHR"/>
+ <type name="VkVideoDecodeH264SessionParametersCreateInfoKHR"/>
+ <type name="VkVideoDecodeH264SessionParametersAddInfoKHR"/>
+ <type name="VkVideoDecodeH264PictureInfoKHR"/>
+ <type name="VkVideoDecodeH264DpbSlotInfoKHR"/>
</require>
</extension>
<extension name="VK_AMD_texture_gather_bias_lod" number="42" author="AMD" contact="Rex Xu @amdrexu" supported="vulkan" type="device" requires="VK_KHR_get_physical_device_properties2">
@@ -12366,12 +15400,49 @@ typedef void <name>CAMetalLayer</name>;
<enum value="&quot;VK_AMD_extension_44&quot;" name="VK_AMD_EXTENSION_44_EXTENSION_NAME"/>
</require>
</extension>
- <extension name="VK_AMD_extension_45" number="45" author="AMD" contact="Daniel Rakos @drakos-amd" supported="disabled">
- <require>
- <enum value="0" name="VK_AMD_EXTENSION_45_SPEC_VERSION"/>
- <enum value="&quot;VK_AMD_extension_45&quot;" name="VK_AMD_EXTENSION_45_EXTENSION_NAME"/>
- <enum bitpos="21" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_RESERVED_21_BIT_AMD"/>
- <enum bitpos="22" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_RESERVED_22_BIT_AMD"/>
+ <extension name="VK_KHR_dynamic_rendering" number="45" author="KHR" type="device" requires="VK_KHR_depth_stencil_resolve,VK_KHR_get_physical_device_properties2" contact="Tobias Hector @tobski" supported="vulkan" promotedto="VK_VERSION_1_3">
+ <require>
+ <enum value="1" name="VK_KHR_DYNAMIC_RENDERING_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_dynamic_rendering&quot;" name="VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME"/>
+ <command name="vkCmdBeginRenderingKHR"/>
+ <command name="vkCmdEndRenderingKHR"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_RENDERING_INFO_KHR" alias="VK_STRUCTURE_TYPE_RENDERING_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR" alias="VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR" alias="VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR" alias="VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO"/>
+ <enum extends="VkAttachmentStoreOp" name="VK_ATTACHMENT_STORE_OP_NONE_KHR" alias="VK_ATTACHMENT_STORE_OP_NONE"/>
+ <type name="VkRenderingInfoKHR"/>
+ <type name="VkRenderingAttachmentInfoKHR"/>
+ <type name="VkPipelineRenderingCreateInfoKHR"/>
+ <type name="VkPhysicalDeviceDynamicRenderingFeaturesKHR"/>
+ <type name="VkCommandBufferInheritanceRenderingInfoKHR"/>
+ <type name="VkRenderingFlagsKHR"/>
+ <type name="VkRenderingFlagBitsKHR"/>
+ </require>
+ <require extension="VK_KHR_fragment_shading_rate">
+ <enum bitpos="21" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR"/>
+ <enum alias="VK_PIPELINE_CREATE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_RASTERIZATION_STATE_CREATE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR" comment="Backwards-compatible alias containing a typo"/>
+ <enum offset="6" extends="VkStructureType" extnumber="45" name="VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR"/>
+ <type name="VkRenderingFragmentShadingRateAttachmentInfoKHR"/>
+ </require>
+ <require extension="VK_EXT_fragment_density_map">
+ <enum bitpos="22" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT"/>
+ <enum alias="VK_PIPELINE_CREATE_RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_RASTERIZATION_STATE_CREATE_FRAGMENT_DENSITY_MAP_ATTACHMENT_BIT_EXT" comment="Backwards-compatible alias containing a typo"/>
+ <enum offset="7" extends="VkStructureType" extnumber="45" name="VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_DENSITY_MAP_ATTACHMENT_INFO_EXT"/>
+ <type name="VkRenderingFragmentDensityMapAttachmentInfoEXT"/>
+ </require>
+ <require extension="VK_AMD_mixed_attachment_samples">
+ <enum offset="8" extends="VkStructureType" extnumber="45" name="VK_STRUCTURE_TYPE_ATTACHMENT_SAMPLE_COUNT_INFO_AMD"/>
+ <type name="VkAttachmentSampleCountInfoAMD"/>
+ </require>
+ <require extension="VK_NV_framebuffer_mixed_samples">
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_ATTACHMENT_SAMPLE_COUNT_INFO_NV" alias="VK_STRUCTURE_TYPE_ATTACHMENT_SAMPLE_COUNT_INFO_AMD"/>
+ <type name="VkAttachmentSampleCountInfoNV"/>
+ </require>
+ <require extension="VK_NVX_multiview_per_view_attributes">
+ <enum offset="9" extends="VkStructureType" extnumber="45" name="VK_STRUCTURE_TYPE_MULTIVIEW_PER_VIEW_ATTRIBUTES_INFO_NVX"/>
+ <type name="VkMultiviewPerViewAttributesInfoNVX"/>
</require>
</extension>
<extension name="VK_AMD_extension_46" number="46" author="AMD" contact="Daniel Rakos @drakos-amd" supported="disabled">
@@ -12421,8 +15492,6 @@ typedef void <name>CAMetalLayer</name>;
<require>
<enum value="0" name="VK_NV_EXTENSION_52_SPEC_VERSION"/>
<enum value="&quot;VK_NV_extension_52&quot;" name="VK_NV_EXTENSION_52_EXTENSION_NAME"/>
- <enum bitpos="0" extends="VkShaderModuleCreateFlagBits" name="VK_SHADER_MODULE_CREATE_RESERVED_0_BIT_NV"/>
- <enum bitpos="2" extends="VkPipelineShaderStageCreateFlagBits" name="VK_PIPELINE_SHADER_STAGE_CREATE_RESERVED_2_BIT_NV"/>
</require>
</extension>
<extension name="VK_NV_extension_53" number="53" author="NV" contact="Jeff Bolz @jeffbolznv" supported="disabled">
@@ -12444,7 +15513,7 @@ typedef void <name>CAMetalLayer</name>;
<type name="VkPhysicalDeviceMultiviewPropertiesKHR"/>
</require>
</extension>
- <extension name="VK_IMG_format_pvrtc" number="55" type="device" author="IMG" contact="Stuart Smith" supported="vulkan">
+ <extension name="VK_IMG_format_pvrtc" number="55" type="device" author="IMG" contact="Stuart Smith" supported="vulkan" deprecatedby="">
<require>
<enum value="1" name="VK_IMG_FORMAT_PVRTC_SPEC_VERSION"/>
<enum value="&quot;VK_IMG_format_pvrtc&quot;" name="VK_IMG_FORMAT_PVRTC_EXTENSION_NAME"/>
@@ -12628,48 +15697,58 @@ typedef void <name>CAMetalLayer</name>;
<enum value="&quot;VK_EXT_shader_subgroup_vote&quot;" name="VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME"/>
</require>
</extension>
- <extension name="VK_EXT_texture_compression_astc_hdr" number="67" type="device" author="ARM" contact="Jan-Harald Fredriksen @janharaldfredriksen-arm" requires="VK_KHR_get_physical_device_properties2" supported="vulkan">
+ <extension name="VK_EXT_texture_compression_astc_hdr" number="67" type="device" author="ARM" contact="Jan-Harald Fredriksen @janharaldfredriksen-arm" requires="VK_KHR_get_physical_device_properties2" supported="vulkan" promotedto="VK_VERSION_1_3">
<require>
- <enum value="1" name="VK_EXT_TEXTURE_COMPRESSION_ASTC_HDR_SPEC_VERSION"/>
- <enum value="&quot;VK_EXT_texture_compression_astc_hdr&quot;" name="VK_EXT_TEXTURE_COMPRESSION_ASTC_HDR_EXTENSION_NAME"/>
- <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES_EXT"/>
+ <enum value="1" name="VK_EXT_TEXTURE_COMPRESSION_ASTC_HDR_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_texture_compression_astc_hdr&quot;" name="VK_EXT_TEXTURE_COMPRESSION_ASTC_HDR_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES_EXT" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES"/>
<type name="VkPhysicalDeviceTextureCompressionASTCHDRFeaturesEXT"/>
- <enum extends="VkFormat" extnumber="67" offset="0" name="VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT"/>
- <enum extends="VkFormat" extnumber="67" offset="1" name="VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT"/>
- <enum extends="VkFormat" extnumber="67" offset="2" name="VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT"/>
- <enum extends="VkFormat" extnumber="67" offset="3" name="VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT"/>
- <enum extends="VkFormat" extnumber="67" offset="4" name="VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT"/>
- <enum extends="VkFormat" extnumber="67" offset="5" name="VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT"/>
- <enum extends="VkFormat" extnumber="67" offset="6" name="VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT"/>
- <enum extends="VkFormat" extnumber="67" offset="7" name="VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT"/>
- <enum extends="VkFormat" extnumber="67" offset="8" name="VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT"/>
- <enum extends="VkFormat" extnumber="67" offset="9" name="VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT"/>
- <enum extends="VkFormat" extnumber="67" offset="10" name="VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT"/>
- <enum extends="VkFormat" extnumber="67" offset="11" name="VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT"/>
- <enum extends="VkFormat" extnumber="67" offset="12" name="VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT"/>
- <enum extends="VkFormat" extnumber="67" offset="13" name="VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT"/>
+ <enum extends="VkFormat" name="VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT" alias="VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK"/>
+ <enum extends="VkFormat" name="VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT" alias="VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK"/>
+ <enum extends="VkFormat" name="VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT" alias="VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK"/>
+ <enum extends="VkFormat" name="VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT" alias="VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK"/>
+ <enum extends="VkFormat" name="VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT" alias="VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK"/>
+ <enum extends="VkFormat" name="VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT" alias="VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK"/>
+ <enum extends="VkFormat" name="VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT" alias="VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK"/>
+ <enum extends="VkFormat" name="VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT" alias="VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK"/>
+ <enum extends="VkFormat" name="VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT" alias="VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK"/>
+ <enum extends="VkFormat" name="VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT" alias="VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK"/>
+ <enum extends="VkFormat" name="VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT" alias="VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK"/>
+ <enum extends="VkFormat" name="VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT" alias="VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK"/>
+ <enum extends="VkFormat" name="VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT" alias="VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK"/>
+ <enum extends="VkFormat" name="VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT" alias="VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK"/>
</require>
</extension>
<extension name="VK_EXT_astc_decode_mode" number="68" type="device" author="ARM" contact="Jan-Harald Fredriksen @janharaldfredriksen-arm" requires="VK_KHR_get_physical_device_properties2" supported="vulkan">
<require>
- <enum value="1" name="VK_EXT_ASTC_DECODE_MODE_SPEC_VERSION"/>
- <enum value="&quot;VK_EXT_astc_decode_mode&quot;" name="VK_EXT_ASTC_DECODE_MODE_EXTENSION_NAME"/>
- <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_VIEW_ASTC_DECODE_MODE_EXT"/>
- <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT"/>
+ <enum value="1" name="VK_EXT_ASTC_DECODE_MODE_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_astc_decode_mode&quot;" name="VK_EXT_ASTC_DECODE_MODE_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_VIEW_ASTC_DECODE_MODE_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT"/>
<type name="VkImageViewASTCDecodeModeEXT"/>
<type name="VkPhysicalDeviceASTCDecodeFeaturesEXT"/>
</require>
</extension>
- <extension name="VK_IMG_extension_69" number="69" type="device" author="IMG" contact="Tobias Hector @tobski" supported="disabled">
+ <extension name="VK_EXT_pipeline_robustness" requires="VK_KHR_get_physical_device_properties2" number="69" type="device" author="IMG" contact="Jarred Davies" supported="vulkan">
<require>
- <enum value="0" name="VK_IMG_EXTENSION_69_SPEC_VERSION"/>
- <enum value="&quot;VK_IMG_extension_69&quot;" name="VK_IMG_EXTENSION_69_EXTENSION_NAME"/>
+ <enum value="1" name="VK_EXT_PIPELINE_ROBUSTNESS_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_pipeline_robustness&quot;" name="VK_EXT_PIPELINE_ROBUSTNESS_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_FEATURES_EXT"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_PROPERTIES_EXT"/>
+ <type name="VkPhysicalDevicePipelineRobustnessFeaturesEXT"/>
+ <type name="VkPhysicalDevicePipelineRobustnessPropertiesEXT"/>
+ <type name="VkPipelineRobustnessCreateInfoEXT"/>
+ <type name="VkPipelineRobustnessBufferBehaviorEXT"/>
+ <type name="VkPipelineRobustnessImageBehaviorEXT"/>
</require>
</extension>
<extension name="VK_KHR_maintenance1" number="70" type="device" author="KHR" contact="Piers Daniell @pdaniell-nv" supported="vulkan" promotedto="VK_VERSION_1_1">
<require>
- <enum value="2" name="VK_KHR_MAINTENANCE1_SPEC_VERSION"/>
- <enum value="&quot;VK_KHR_maintenance1&quot;" name="VK_KHR_MAINTENANCE1_EXTENSION_NAME"/>
+ <enum value="2" name="VK_KHR_MAINTENANCE_1_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_maintenance1&quot;" name="VK_KHR_MAINTENANCE_1_EXTENSION_NAME"/>
+ <enum alias="VK_KHR_MAINTENANCE_1_SPEC_VERSION" name="VK_KHR_MAINTENANCE1_SPEC_VERSION" comment="Backwards-compatible alias containing a typo"/>
+ <enum alias="VK_KHR_MAINTENANCE_1_EXTENSION_NAME" name="VK_KHR_MAINTENANCE1_EXTENSION_NAME" comment="Backwards-compatible alias containing a typo"/>
<enum extends="VkResult" name="VK_ERROR_OUT_OF_POOL_MEMORY_KHR" alias="VK_ERROR_OUT_OF_POOL_MEMORY"/>
<enum extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR" alias="VK_FORMAT_FEATURE_TRANSFER_SRC_BIT"/>
<enum extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR" alias="VK_FORMAT_FEATURE_TRANSFER_DST_BIT"/>
@@ -12879,10 +15958,10 @@ typedef void <name>CAMetalLayer</name>;
</extension>
<extension name="VK_KHR_shader_float16_int8" number="83" type="device" requires="VK_KHR_get_physical_device_properties2" author="KHR" contact="Alexander Galazin @alegal-arm" supported="vulkan" promotedto="VK_VERSION_1_2">
<require>
- <enum value="1" name="VK_KHR_SHADER_FLOAT16_INT8_SPEC_VERSION"/>
- <enum value="&quot;VK_KHR_shader_float16_int8&quot;" name="VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME"/>
- <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES"/>
- <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES"/>
+ <enum value="1" name="VK_KHR_SHADER_FLOAT16_INT8_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_shader_float16_int8&quot;" name="VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES"/>
<type name="VkPhysicalDeviceShaderFloat16Int8FeaturesKHR"/>
<type name="VkPhysicalDeviceFloat16Int8FeaturesKHR"/>
</require>
@@ -13007,7 +16086,11 @@ typedef void <name>CAMetalLayer</name>;
<command name="vkGetPastPresentationTimingGOOGLE"/>
</require>
</extension>
- <extension name="RESERVED_DO_NOT_USE_94" number="94" supported="disabled" comment="Used for functionality subsumed into Vulkan 1.1 and not published as an extension">
+ <extension name="VK_RESERVED_do_not_use_94" number="94" supported="disabled" comment="Used for functionality subsumed into Vulkan 1.1 and not published as an extension">
+ <require>
+ <enum value="1" name="VK_RESERVED_DO_NOT_USE_94_SPEC_VERSION"/>
+ <enum value="&quot;VK_RESERVED_do_not_use_94&quot;" name="VK_RESERVED_DO_NOT_USE_94_EXTENSION_NAME"/>
+ </require>
</extension>
<extension name="VK_NV_sample_mask_override_coverage" number="95" type="device" author="NV" contact="Piers Daniell @pdaniell-nv" supported="vulkan">
<require>
@@ -13028,8 +16111,10 @@ typedef void <name>CAMetalLayer</name>;
</extension>
<extension name="VK_NV_viewport_array2" number="97" type="device" author="NV" contact="Daniel Koch @dgkoch" supported="vulkan">
<require>
- <enum value="1" name="VK_NV_VIEWPORT_ARRAY2_SPEC_VERSION"/>
- <enum value="&quot;VK_NV_viewport_array2&quot;" name="VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME"/>
+ <enum value="1" name="VK_NV_VIEWPORT_ARRAY_2_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_viewport_array2&quot;" name="VK_NV_VIEWPORT_ARRAY_2_EXTENSION_NAME"/>
+ <enum alias="VK_NV_VIEWPORT_ARRAY_2_SPEC_VERSION" name="VK_NV_VIEWPORT_ARRAY2_SPEC_VERSION" comment="Backwards-compatible alias containing a typo"/>
+ <enum alias="VK_NV_VIEWPORT_ARRAY_2_EXTENSION_NAME" name="VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME" comment="Backwards-compatible alias containing a typo"/>
</require>
</extension>
<extension name="VK_NVX_multiview_per_view_attributes" number="98" type="device" requires="VK_KHR_multiview" author="NVX" contact="Jeff Bolz @jeffbolznv" supported="vulkan">
@@ -13120,7 +16205,7 @@ typedef void <name>CAMetalLayer</name>;
<enum offset="12" extends="VkColorSpaceKHR" name="VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT"/>
<enum offset="13" extends="VkColorSpaceKHR" name="VK_COLOR_SPACE_PASS_THROUGH_EXT"/>
<enum offset="14" extends="VkColorSpaceKHR" name="VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT"/>
- <enum extends="VkColorSpaceKHR" name="VK_COLOR_SPACE_DCI_P3_LINEAR_EXT" alias="VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT" comment="Deprecated name for backwards compatibility"/>
+ <enum extends="VkColorSpaceKHR" name="VK_COLOR_SPACE_DCI_P3_LINEAR_EXT" alias="VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT" comment="Backwards-compatible alias containing a typo"/>
</require>
</extension>
<extension name="VK_EXT_hdr_metadata" number="106" type="device" requires="VK_KHR_swapchain" author="GOOGLE" contact="Courtney Goeltzenleuchter @courtney-g" supported="vulkan">
@@ -13160,7 +16245,7 @@ typedef void <name>CAMetalLayer</name>;
<enum extends="VkFramebufferCreateFlagBits" name="VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT_KHR" alias="VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT"/>
</require>
</extension>
- <extension name="VK_KHR_create_renderpass2" requires="VK_KHR_multiview,VK_KHR_maintenance2" number="110" contact="Tobias Hector @tobias" type="device" supported="vulkan" promotedto="VK_VERSION_1_2">
+ <extension name="VK_KHR_create_renderpass2" requires="VK_KHR_multiview,VK_KHR_maintenance2" number="110" author="KHR" contact="Tobias Hector @tobias" type="device" supported="vulkan" promotedto="VK_VERSION_1_2">
<require>
<enum value="1" name="VK_KHR_CREATE_RENDERPASS_2_SPEC_VERSION"/>
<enum value="&quot;VK_KHR_create_renderpass2&quot;" name="VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME"/>
@@ -13298,8 +16383,10 @@ typedef void <name>CAMetalLayer</name>;
</extension>
<extension name="VK_KHR_maintenance2" number="118" type="device" author="KHR" contact="Michael Worcester @michaelworcester" supported="vulkan" promotedto="VK_VERSION_1_1">
<require>
- <enum value="1" name="VK_KHR_MAINTENANCE2_SPEC_VERSION"/>
- <enum value="&quot;VK_KHR_maintenance2&quot;" name="VK_KHR_MAINTENANCE2_EXTENSION_NAME"/>
+ <enum value="1" name="VK_KHR_MAINTENANCE_2_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_maintenance2&quot;" name="VK_KHR_MAINTENANCE_2_EXTENSION_NAME"/>
+ <enum alias="VK_KHR_MAINTENANCE_2_SPEC_VERSION" name="VK_KHR_MAINTENANCE2_SPEC_VERSION" comment="Backwards-compatible alias containing a typo"/>
+ <enum alias="VK_KHR_MAINTENANCE_2_EXTENSION_NAME" name="VK_KHR_MAINTENANCE2_EXTENSION_NAME" comment="Backwards-compatible alias containing a typo"/>
<enum extends="VkImageCreateFlagBits" name="VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR" alias="VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT"/>
<enum extends="VkImageCreateFlagBits" name="VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR" alias="VK_IMAGE_CREATE_EXTENDED_USAGE_BIT"/>
<enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES"/>
@@ -13353,13 +16440,13 @@ typedef void <name>CAMetalLayer</name>;
</extension>
<extension name="VK_KHR_get_display_properties2" number="122" type="instance" requires="VK_KHR_display" author="KHR" contact="James Jones @cubanismo" supported="vulkan">
<require>
- <enum value="1" name="VK_KHR_GET_DISPLAY_PROPERTIES_2_SPEC_VERSION"/>
- <enum value="&quot;VK_KHR_get_display_properties2&quot;" name="VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME"/>
- <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DISPLAY_PROPERTIES_2_KHR"/>
- <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DISPLAY_PLANE_PROPERTIES_2_KHR"/>
- <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DISPLAY_MODE_PROPERTIES_2_KHR"/>
- <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DISPLAY_PLANE_INFO_2_KHR"/>
- <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DISPLAY_PLANE_CAPABILITIES_2_KHR"/>
+ <enum value="1" name="VK_KHR_GET_DISPLAY_PROPERTIES_2_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_get_display_properties2&quot;" name="VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DISPLAY_PROPERTIES_2_KHR"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DISPLAY_PLANE_PROPERTIES_2_KHR"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DISPLAY_MODE_PROPERTIES_2_KHR"/>
+ <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DISPLAY_PLANE_INFO_2_KHR"/>
+ <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DISPLAY_PLANE_CAPABILITIES_2_KHR"/>
<type name="VkDisplayProperties2KHR"/>
<type name="VkDisplayPlaneProperties2KHR"/>
<type name="VkDisplayModeProperties2KHR"/>
@@ -13459,7 +16546,7 @@ typedef void <name>CAMetalLayer</name>;
</extension>
<extension name="VK_ANDROID_external_memory_android_hardware_buffer" number="130" type="device" author="ANDROID" requires="VK_KHR_sampler_ycbcr_conversion,VK_KHR_external_memory,VK_EXT_queue_family_foreign,VK_KHR_dedicated_allocation" platform="android" contact="Jesse Hall @critsec" supported="vulkan">
<require>
- <enum value="3" name="VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_SPEC_VERSION"/>
+ <enum value="5" name="VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_SPEC_VERSION"/>
<enum value="&quot;VK_ANDROID_external_memory_android_hardware_buffer&quot;" name="VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME"/>
<enum bitpos="10" extends="VkExternalMemoryHandleTypeFlagBits" name="VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID"/>
<enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID"/>
@@ -13478,6 +16565,10 @@ typedef void <name>CAMetalLayer</name>;
<command name="vkGetMemoryAndroidHardwareBufferANDROID"/>
<type name="AHardwareBuffer"/>
</require>
+ <require extension="VK_KHR_format_feature_flags2">
+ <type name="VkAndroidHardwareBufferFormatProperties2ANDROID"/>
+ <enum offset="6" extends="VkStructureType" name="VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_2_ANDROID"/>
+ </require>
</extension>
<extension name="VK_EXT_sampler_filter_minmax" number="131" type="device" author="NV" requires="VK_KHR_get_physical_device_properties2" contact="Jeff Bolz @jeffbolznv" supported="vulkan" promotedto="VK_VERSION_1_2">
<require>
@@ -13516,6 +16607,7 @@ typedef void <name>CAMetalLayer</name>;
<require>
<enum value="0" name="VK_AMD_EXTENSION_135_SPEC_VERSION"/>
<enum value="&quot;VK_AMD_extension_135&quot;" name="VK_AMD_EXTENSION_135_EXTENSION_NAME"/>
+ <enum bitpos="25" extends="VkBufferUsageFlagBits" name="VK_BUFFER_USAGE_RESERVED_25_BIT_AMD"/>
</require>
</extension>
<extension name="VK_AMD_extension_136" number="136" author="AMD" contact="Mais Alnasser @malnasse" supported="disabled">
@@ -13536,15 +16628,15 @@ typedef void <name>CAMetalLayer</name>;
<enum value="&quot;VK_AMD_shader_fragment_mask&quot;" name="VK_AMD_SHADER_FRAGMENT_MASK_EXTENSION_NAME"/>
</require>
</extension>
- <extension name="VK_EXT_inline_uniform_block" number="139" type="device" author="EXT" requires="VK_KHR_get_physical_device_properties2,VK_KHR_maintenance1" contact="Daniel Rakos @aqnuep" supported="vulkan">
+ <extension name="VK_EXT_inline_uniform_block" number="139" type="device" author="EXT" requires="VK_KHR_get_physical_device_properties2,VK_KHR_maintenance1" contact="Daniel Rakos @aqnuep" supported="vulkan" promotedto="VK_VERSION_1_3">
<require>
- <enum value="1" name="VK_EXT_INLINE_UNIFORM_BLOCK_SPEC_VERSION"/>
- <enum value="&quot;VK_EXT_inline_uniform_block&quot;" name="VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME"/>
- <enum offset="0" extends="VkDescriptorType" name="VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT"/>
- <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT"/>
- <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT"/>
- <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT"/>
- <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT"/>
+ <enum value="1" name="VK_EXT_INLINE_UNIFORM_BLOCK_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_inline_uniform_block&quot;" name="VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME"/>
+ <enum extends="VkDescriptorType" name="VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT" alias="VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT" alias="VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT" alias="VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO"/>
<type name="VkPhysicalDeviceInlineUniformBlockFeaturesEXT"/>
<type name="VkPhysicalDeviceInlineUniformBlockPropertiesEXT"/>
<type name="VkWriteDescriptorSetInlineUniformBlockEXT"/>
@@ -13604,7 +16696,11 @@ typedef void <name>CAMetalLayer</name>;
<enum value="&quot;VK_KHR_relaxed_block_layout&quot;" name="VK_KHR_RELAXED_BLOCK_LAYOUT_EXTENSION_NAME"/>
</require>
</extension>
- <extension name="RESERVED_DO_NOT_USE_146" number="146" supported="disabled" comment="Used for functionality subsumed into Vulkan 1.1 and not published as an extension">
+ <extension name="VK_RESERVED_do_not_use_146" number="146" supported="disabled" comment="Used for functionality subsumed into Vulkan 1.1 and not published as an extension">
+ <require>
+ <enum value="1" name="VK_RESERVED_DO_NOT_USE_146_SPEC_VERSION"/>
+ <enum value="&quot;VK_RESERVED_do_not_use_146&quot;" name="VK_RESERVED_DO_NOT_USE_146_EXTENSION_NAME"/>
+ </require>
</extension>
<extension name="VK_KHR_get_memory_requirements2" number="147" type="device" author="KHR" contact="Jason Ekstrand @jekstrand" supported="vulkan" promotedto="VK_VERSION_1_1">
<require>
@@ -13633,7 +16729,7 @@ typedef void <name>CAMetalLayer</name>;
<type name="VkImageFormatListCreateInfoKHR"/>
</require>
</extension>
- <extension name="VK_EXT_blend_operation_advanced" number="149" type="device" author="NV" contact="Jeff Bolz @jeffbolznv" supported="vulkan">
+ <extension name="VK_EXT_blend_operation_advanced" number="149" type="device" author="NV" contact="Jeff Bolz @jeffbolznv" supported="vulkan" requires="VK_KHR_get_physical_device_properties2">
<require>
<enum value="2" name="VK_EXT_BLEND_OPERATION_ADVANCED_SPEC_VERSION"/>
<enum value="&quot;VK_EXT_blend_operation_advanced&quot;" name="VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME"/>
@@ -13704,7 +16800,7 @@ typedef void <name>CAMetalLayer</name>;
</extension>
<extension name="VK_KHR_acceleration_structure" number="151" type="device" requiresCore="1.1" requires="VK_EXT_descriptor_indexing,VK_KHR_buffer_device_address,VK_KHR_deferred_host_operations" author="KHR" contact="Daniel Koch @dgkoch" supported="vulkan" sortorder="1">
<require>
- <enum value="11" name="VK_KHR_ACCELERATION_STRUCTURE_SPEC_VERSION"/>
+ <enum value="13" name="VK_KHR_ACCELERATION_STRUCTURE_SPEC_VERSION"/>
<enum value="&quot;VK_KHR_acceleration_structure&quot;" name="VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME"/>
<enum offset="7" extends="VkStructureType" name="VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR"/>
<enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR"/>
@@ -13787,6 +16883,9 @@ typedef void <name>CAMetalLayer</name>;
<command name="vkGetDeviceAccelerationStructureCompatibilityKHR"/>
<command name="vkGetAccelerationStructureBuildSizesKHR"/>
</require>
+ <require extension="VK_KHR_format_feature_flags2">
+ <enum bitpos="29" extends="VkFormatFeatureFlagBits2" name="VK_FORMAT_FEATURE_2_ACCELERATION_STRUCTURE_VERTEX_BUFFER_BIT_KHR"/>
+ </require>
</extension>
<extension name="VK_KHR_ray_tracing_pipeline" number="348" type="device" requiresCore="1.1" requires="VK_KHR_spirv_1_4,VK_KHR_acceleration_structure" author="KHR" contact="Daniel Koch @dgkoch" supported="vulkan" sortorder="1">
<require>
@@ -13978,33 +17077,32 @@ typedef void <name>CAMetalLayer</name>;
</extension>
<extension name="VK_EXT_image_drm_format_modifier" number="159" type="device" requires="VK_KHR_bind_memory2,VK_KHR_get_physical_device_properties2,VK_KHR_image_format_list,VK_KHR_sampler_ycbcr_conversion" author="EXT" contact="Chad Versace @chadversary" supported="vulkan">
<require>
- <enum value="1" name="VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_SPEC_VERSION"/>
+ <enum value="2" name="VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_SPEC_VERSION"/>
<enum value="&quot;VK_EXT_image_drm_format_modifier&quot;" name="VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME"/>
-
- <enum offset="0" dir="-" extends="VkResult" name="VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT"/>
-
- <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT"/>
- <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT"/>
- <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT"/>
- <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT"/>
- <enum offset="5" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT"/>
-
- <enum offset="0" extends="VkImageTiling" name="VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT"/>
-
- <enum bitpos="7" extends="VkImageAspectFlagBits" name="VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT"/>
- <enum bitpos="8" extends="VkImageAspectFlagBits" name="VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT"/>
- <enum bitpos="9" extends="VkImageAspectFlagBits" name="VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT"/>
- <enum bitpos="10" extends="VkImageAspectFlagBits" name="VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT"/>
-
+ <enum offset="0" dir="-" extends="VkResult" name="VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT"/>
+ <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT"/>
+ <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT"/>
+ <enum offset="5" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT"/>
+ <enum offset="0" extends="VkImageTiling" name="VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT"/>
+ <enum bitpos="7" extends="VkImageAspectFlagBits" name="VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT"/>
+ <enum bitpos="8" extends="VkImageAspectFlagBits" name="VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT"/>
+ <enum bitpos="9" extends="VkImageAspectFlagBits" name="VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT"/>
+ <enum bitpos="10" extends="VkImageAspectFlagBits" name="VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT"/>
<type name="VkDrmFormatModifierPropertiesListEXT"/>
<type name="VkDrmFormatModifierPropertiesEXT"/>
<type name="VkPhysicalDeviceImageDrmFormatModifierInfoEXT"/>
<type name="VkImageDrmFormatModifierListCreateInfoEXT"/>
<type name="VkImageDrmFormatModifierExplicitCreateInfoEXT"/>
<type name="VkImageDrmFormatModifierPropertiesEXT"/>
-
<command name="vkGetImageDrmFormatModifierPropertiesEXT"/>
</require>
+ <require extension="VK_KHR_format_feature_flags2">
+ <type name="VkDrmFormatModifierPropertiesList2EXT"/>
+ <type name="VkDrmFormatModifierProperties2EXT"/>
+ <enum offset="6" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_2_EXT"/>
+ </require>
</extension>
<extension name="VK_EXT_extension_160" number="160" author="EXT" contact="Mark Young @marky-lunarg" supported="disabled">
<require>
@@ -14099,7 +17197,7 @@ typedef void <name>CAMetalLayer</name>;
<command name="vkCmdSetCoarseSampleOrderNV"/>
</require>
</extension>
- <extension name="VK_NV_ray_tracing" number="166" type="device" requires="VK_KHR_get_physical_device_properties2,VK_KHR_get_memory_requirements2" author="NV" contact="Eric Werness @ewerness" supported="vulkan">
+ <extension name="VK_NV_ray_tracing" number="166" type="device" requires="VK_KHR_get_physical_device_properties2,VK_KHR_get_memory_requirements2" author="NV" contact="Eric Werness @ewerness-nv" supported="vulkan">
<require>
<enum value="3" name="VK_NV_RAY_TRACING_SPEC_VERSION"/>
<enum value="&quot;VK_NV_ray_tracing&quot;" name="VK_NV_RAY_TRACING_EXTENSION_NAME"/>
@@ -14207,14 +17305,16 @@ typedef void <name>CAMetalLayer</name>;
</extension>
<extension name="VK_NV_extension_168" number="168" author="NV" contact="Daniel Koch @dgkoch" supported="disabled">
<require>
- <enum value="0" name="VK_EXT_EXTENSION_168_SPEC_VERSION"/>
- <enum value="&quot;VK_NV_extension_168&quot;" name="VK_EXT_EXTENSION_168_EXTENSION_NAME"/>
+ <enum value="0" name="VK_NV_EXTENSION_168_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_extension_168&quot;" name="VK_NV_EXTENSION_168_EXTENSION_NAME"/>
</require>
</extension>
<extension name="VK_KHR_maintenance3" number="169" type="device" requires="VK_KHR_get_physical_device_properties2" author="KHR" contact="Jeff Bolz @jeffbolznv" supported="vulkan" promotedto="VK_VERSION_1_1">
<require>
- <enum value="1" name="VK_KHR_MAINTENANCE3_SPEC_VERSION"/>
- <enum value="&quot;VK_KHR_maintenance3&quot;" name="VK_KHR_MAINTENANCE3_EXTENSION_NAME"/>
+ <enum value="1" name="VK_KHR_MAINTENANCE_3_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_maintenance3&quot;" name="VK_KHR_MAINTENANCE_3_EXTENSION_NAME"/>
+ <enum alias="VK_KHR_MAINTENANCE_3_SPEC_VERSION" name="VK_KHR_MAINTENANCE3_SPEC_VERSION" comment="Backwards-compatible alias containing a typo"/>
+ <enum alias="VK_KHR_MAINTENANCE_3_EXTENSION_NAME" name="VK_KHR_MAINTENANCE3_EXTENSION_NAME" comment="Backwards-compatible alias containing a typo"/>
<enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES"/>
<enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT_KHR" alias="VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT"/>
<type name="VkPhysicalDeviceMaintenance3PropertiesKHR"/>
@@ -14234,8 +17334,8 @@ typedef void <name>CAMetalLayer</name>;
<require>
<enum value="3" name="VK_EXT_FILTER_CUBIC_SPEC_VERSION"/>
<enum value="&quot;VK_EXT_filter_cubic&quot;" name="VK_EXT_FILTER_CUBIC_EXTENSION_NAME"/>
- <enum extends="VkFilter" name="VK_FILTER_CUBIC_EXT" alias="VK_FILTER_CUBIC_IMG"/>
- <enum extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT" alias="VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG"/>
+ <enum offset="0" extends="VkFilter" extnumber="16" name="VK_FILTER_CUBIC_EXT"/>
+ <enum bitpos="13" extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_EXT"/>
<enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_IMAGE_FORMAT_INFO_EXT"/>
<enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_FILTER_CUBIC_IMAGE_VIEW_IMAGE_FORMAT_PROPERTIES_EXT"/>
<type name="VkPhysicalDeviceImageViewImageFormatInfoEXT"/>
@@ -14252,8 +17352,8 @@ typedef void <name>CAMetalLayer</name>;
</extension>
<extension name="VK_QCOM_extension_173" number="173" author="QCOM" contact="Bill Licea-Kane @wwlk" supported="disabled">
<require>
- <enum value="0" name="VK_QCOM_extension_173_SPEC_VERSION"/>
- <enum value="&quot;VK_QCOM_extension_173&quot;" name="VK_QCOM_extension_173_EXTENSION_NAME"/>
+ <enum value="0" name="VK_QCOM_EXTENSION_173_SPEC_VERSION"/>
+ <enum value="&quot;VK_QCOM_extension_173&quot;" name="VK_QCOM_EXTENSION_173_EXTENSION_NAME"/>
<enum bitpos="18" extends="VkBufferUsageFlagBits" name="VK_BUFFER_USAGE_RESERVED_18_BIT_QCOM"/>
<enum bitpos="16" extends="VkImageUsageFlagBits" name="VK_IMAGE_USAGE_RESERVED_16_BIT_QCOM"/>
<enum bitpos="17" extends="VkImageUsageFlagBits" name="VK_IMAGE_USAGE_RESERVED_17_BIT_QCOM"/>
@@ -14261,16 +17361,16 @@ typedef void <name>CAMetalLayer</name>;
</extension>
<extension name="VK_QCOM_extension_174" number="174" author="QCOM" contact="Bill Licea-Kane @wwlk" supported="disabled">
<require>
- <enum value="0" name="VK_QCOM_extension_174_SPEC_VERSION"/>
- <enum value="&quot;VK_QCOM_extension_174&quot;" name="VK_QCOM_extension_174_EXTENSION_NAME"/>
+ <enum value="0" name="VK_QCOM_EXTENSION_174_SPEC_VERSION"/>
+ <enum value="&quot;VK_QCOM_extension_174&quot;" name="VK_QCOM_EXTENSION_174_EXTENSION_NAME"/>
</require>
</extension>
- <extension name="VK_EXT_global_priority" number="175" type="device" author="EXT" contact="Andres Rodriguez @lostgoat" supported="vulkan">
+ <extension name="VK_EXT_global_priority" number="175" type="device" author="EXT" contact="Andres Rodriguez @lostgoat" supported="vulkan" promotedto="VK_KHR_global_priority">
<require>
<enum value="2" name="VK_EXT_GLOBAL_PRIORITY_SPEC_VERSION"/>
<enum value="&quot;VK_EXT_global_priority&quot;" name="VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME"/>
- <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT"/>
- <enum offset="1" dir="-" extends="VkResult" name="VK_ERROR_NOT_PERMITTED_EXT"/>
+ <enum extends="VkStructureType" alias="VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_KHR" name="VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT"/>
+ <enum extends="VkResult" alias="VK_ERROR_NOT_PERMITTED_KHR" name="VK_ERROR_NOT_PERMITTED_EXT"/>
<type name="VkDeviceQueueGlobalPriorityCreateInfoEXT"/>
<type name="VkQueueGlobalPriorityEXT"/>
</require>
@@ -14285,8 +17385,8 @@ typedef void <name>CAMetalLayer</name>;
</extension>
<extension name="VK_EXT_extension_177" number="177" author="EXT" contact="Neil Henning @sheredom" supported="disabled">
<require>
- <enum value="0" name="VK_KHR_EXTENSION_177_SPEC_VERSION"/>
- <enum value="&quot;VK_KHR_extension_177&quot;" name="VK_KHR_EXTENSION_177_EXTENSION_NAME"/>
+ <enum value="0" name="VK_EXT_EXTENSION_177_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_177&quot;" name="VK_EXT_EXTENSION_177_EXTENSION_NAME"/>
</require>
</extension>
<extension name="VK_KHR_8bit_storage" number="178" type="device" requires="VK_KHR_get_physical_device_properties2,VK_KHR_storage_buffer_storage_class" author="KHR" contact="Alexander Galazin @alegal-arm" supported="vulkan" promotedto="VK_VERSION_1_2">
@@ -14337,8 +17437,8 @@ typedef void <name>CAMetalLayer</name>;
</extension>
<extension name="VK_AMD_extension_183" number="183" author="AMD" contact="Daniel Rakos @drakos-amd" supported="disabled">
<require>
- <enum value="0" name="VK_KHR_EXTENSION_183_SPEC_VERSION"/>
- <enum value="&quot;VK_AMD_extension_183&quot;" name="VK_KHR_EXTENSION_183_EXTENSION_NAME"/>
+ <enum value="0" name="VK_AMD_EXTENSION_183_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_183&quot;" name="VK_AMD_EXTENSION_183_EXTENSION_NAME"/>
</require>
</extension>
<extension name="VK_AMD_pipeline_compiler_control" number="184" type="device" author="AMD" contact="Matthaeus G. Chajdas @anteru" supported="vulkan">
@@ -14372,38 +17472,44 @@ typedef void <name>CAMetalLayer</name>;
</extension>
<extension name="VK_AMD_extension_187" number="187" author="AMD" contact="Daniel Rakos @drakos-amd" supported="disabled">
<require>
- <enum value="0" name="VK_KHR_EXTENSION_187_SPEC_VERSION"/>
- <enum value="&quot;VK_AMD_extension_187&quot;" name="VK_KHR_EXTENSION_187_EXTENSION_NAME"/>
+ <enum value="0" name="VK_AMD_EXTENSION_187_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_187&quot;" name="VK_AMD_EXTENSION_187_EXTENSION_NAME"/>
</require>
</extension>
- <extension name="VK_EXT_video_decode_h265" number="188" type="device" requires="VK_KHR_video_decode_queue" author="KHR" contact="peter.fang@amd.com" provisional="true" platform="provisional" supported="vulkan">
+ <extension name="VK_KHR_video_decode_h265" number="188" type="device" requires="VK_KHR_video_decode_queue" author="KHR" contact="peter.fang@amd.com" supported="vulkan">
<require>
- <enum value="1" name="VK_EXT_VIDEO_DECODE_H265_SPEC_VERSION"/>
- <enum value="&quot;VK_EXT_video_decode_h265&quot;" name="VK_EXT_VIDEO_DECODE_H265_EXTENSION_NAME"/>
- <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_CAPABILITIES_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_CREATE_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_CREATE_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_ADD_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PROFILE_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="5" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PICTURE_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum offset="6" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_DPB_SLOT_INFO_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <enum bitpos="1" extends="VkVideoCodecOperationFlagBitsKHR" name="VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_EXT" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum value="7" name="VK_KHR_VIDEO_DECODE_H265_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_video_decode_h265&quot;" name="VK_KHR_VIDEO_DECODE_H265_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_CAPABILITIES_KHR"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_CREATE_INFO_KHR"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_SESSION_PARAMETERS_ADD_INFO_KHR"/>
+ <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PROFILE_INFO_KHR"/>
+ <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PICTURE_INFO_KHR"/>
+ <enum offset="5" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_DPB_SLOT_INFO_KHR"/>
+ <enum bitpos="1" extends="VkVideoCodecOperationFlagBitsKHR" name="VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR"/>
- <type name="VkVideoDecodeH265CreateFlagsEXT"/>
- <type name="VkVideoDecodeH265ProfileEXT"/>
- <type name="VkVideoDecodeH265CapabilitiesEXT"/>
- <type name="VkVideoDecodeH265SessionCreateInfoEXT"/>
+ <type name="VkVideoDecodeH265ProfileInfoKHR"/>
+ <type name="VkVideoDecodeH265CapabilitiesKHR"/>
- <type name="VkVideoDecodeH265SessionParametersCreateInfoEXT"/>
- <type name="VkVideoDecodeH265SessionParametersAddInfoEXT"/>
- <type name="VkVideoDecodeH265PictureInfoEXT"/>
- <type name="VkVideoDecodeH265DpbSlotInfoEXT"/>
+ <type name="VkVideoDecodeH265SessionParametersCreateInfoKHR"/>
+ <type name="VkVideoDecodeH265SessionParametersAddInfoKHR"/>
+ <type name="VkVideoDecodeH265PictureInfoKHR"/>
+ <type name="VkVideoDecodeH265DpbSlotInfoKHR"/>
</require>
</extension>
- <extension name="VK_AMD_extension_189" number="189" author="AMD" contact="Daniel Rakos @drakos-amd" supported="disabled">
+ <extension name="VK_KHR_global_priority" number="189" type="device" author="KHR" contact="Tobias Hector @tobski" supported="vulkan">
<require>
- <enum value="0" name="VK_KHR_EXTENSION_189_SPEC_VERSION"/>
- <enum value="&quot;VK_AMD_extension_189&quot;" name="VK_KHR_EXTENSION_189_EXTENSION_NAME"/>
+ <enum value="1" name="VK_KHR_GLOBAL_PRIORITY_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_global_priority&quot;" name="VK_KHR_GLOBAL_PRIORITY_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" extnumber="175" name="VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_KHR"/>
+ <enum offset="0" extends="VkStructureType" extnumber="389" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_KHR"/>
+ <enum offset="1" extends="VkStructureType" extnumber="389" name="VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_KHR"/>
+ <enum extends="VkResult" extnumber="175" offset="1" dir="-" name="VK_ERROR_NOT_PERMITTED_KHR"/>
+ <enum name="VK_MAX_GLOBAL_PRIORITY_SIZE_KHR"/>
+ <type name="VkDeviceQueueGlobalPriorityCreateInfoKHR"/>
+ <type name="VkQueueGlobalPriorityKHR"/>
+ <type name="VkPhysicalDeviceGlobalPriorityQueryFeaturesKHR"/>
+ <type name="VkQueueFamilyGlobalPriorityPropertiesKHR"/>
</require>
</extension>
<extension name="VK_AMD_memory_overallocation_behavior" number="190" type="device" author="AMD" contact="Martin Dinkov @mdinkov" supported="vulkan">
@@ -14436,11 +17542,11 @@ typedef void <name>CAMetalLayer</name>;
<type name="VkPresentFrameTokenGGP"/>
</require>
</extension>
- <extension name="VK_EXT_pipeline_creation_feedback" number="193" type="device" author="GOOGLE" contact="Jean-Francois Roy @jfroy" specialuse="devtools" supported="vulkan">
+ <extension name="VK_EXT_pipeline_creation_feedback" number="193" type="device" author="GOOGLE" contact="Jean-Francois Roy @jfroy" specialuse="devtools" supported="vulkan" promotedto="VK_VERSION_1_3">
<require>
- <enum value="1" name="VK_EXT_PIPELINE_CREATION_FEEDBACK_SPEC_VERSION"/>
+ <enum value="1" name="VK_EXT_PIPELINE_CREATION_FEEDBACK_SPEC_VERSION"/>
<enum value="&quot;VK_EXT_pipeline_creation_feedback&quot;" name="VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME"/>
- <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO_EXT"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO_EXT" alias="VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO"/>
<type name="VkPipelineCreationFeedbackFlagBitsEXT"/>
<type name="VkPipelineCreationFeedbackFlagsEXT"/>
<type name="VkPipelineCreationFeedbackCreateInfoEXT"/>
@@ -14548,10 +17654,10 @@ typedef void <name>CAMetalLayer</name>;
<enum value="&quot;VK_NV_mesh_shader&quot;" name="VK_NV_MESH_SHADER_EXTENSION_NAME"/>
<enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_NV"/>
<enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV"/>
- <enum bitpos="6" extends="VkShaderStageFlagBits" name="VK_SHADER_STAGE_TASK_BIT_NV"/>
- <enum bitpos="7" extends="VkShaderStageFlagBits" name="VK_SHADER_STAGE_MESH_BIT_NV"/>
- <enum bitpos="19" extends="VkPipelineStageFlagBits" name="VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV"/>
- <enum bitpos="20" extends="VkPipelineStageFlagBits" name="VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV"/>
+ <enum extends="VkShaderStageFlagBits" name="VK_SHADER_STAGE_TASK_BIT_NV" alias="VK_SHADER_STAGE_TASK_BIT_EXT"/>
+ <enum extends="VkShaderStageFlagBits" name="VK_SHADER_STAGE_MESH_BIT_NV" alias="VK_SHADER_STAGE_MESH_BIT_EXT"/>
+ <enum extends="VkPipelineStageFlagBits" name="VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV" alias="VK_PIPELINE_STAGE_TASK_SHADER_BIT_EXT"/>
+ <enum extends="VkPipelineStageFlagBits" name="VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV" alias="VK_PIPELINE_STAGE_MESH_SHADER_BIT_EXT"/>
<command name="vkCmdDrawMeshTasksNV"/>
<command name="vkCmdDrawMeshTasksIndirectNV"/>
<command name="vkCmdDrawMeshTasksIndirectCountNV"/>
@@ -14560,11 +17666,11 @@ typedef void <name>CAMetalLayer</name>;
<type name="VkDrawMeshTasksIndirectCommandNV"/>
</require>
</extension>
- <extension name="VK_NV_fragment_shader_barycentric" number="204" type="device" requires="VK_KHR_get_physical_device_properties2" author="NV" contact="Pat Brown @nvpbrown" supported="vulkan">
+ <extension name="VK_NV_fragment_shader_barycentric" number="204" type="device" requires="VK_KHR_get_physical_device_properties2" author="NV" contact="Pat Brown @nvpbrown" supported="vulkan" promotedto="VK_KHR_fragment_shader_barycentric">
<require>
<enum value="1" name="VK_NV_FRAGMENT_SHADER_BARYCENTRIC_SPEC_VERSION"/>
<enum value="&quot;VK_NV_fragment_shader_barycentric&quot;" name="VK_NV_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME"/>
- <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_NV"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_NV" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR"/>
<type name="VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV"/>
</require>
</extension>
@@ -14646,7 +17752,7 @@ typedef void <name>CAMetalLayer</name>;
<enum value="2" name="VK_INTEL_PERFORMANCE_QUERY_SPEC_VERSION"/>
<enum value="&quot;VK_INTEL_performance_query&quot;" name="VK_INTEL_PERFORMANCE_QUERY_EXTENSION_NAME"/>
<enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_QUERY_POOL_PERFORMANCE_QUERY_CREATE_INFO_INTEL"/>
- <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO_INTEL" alias="VK_STRUCTURE_TYPE_QUERY_POOL_PERFORMANCE_QUERY_CREATE_INFO_INTEL" comment="Backwards-compatible alias"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO_INTEL" alias="VK_STRUCTURE_TYPE_QUERY_POOL_PERFORMANCE_QUERY_CREATE_INFO_INTEL" comment="Backwards-compatible alias containing a typo"/>
<enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_INITIALIZE_PERFORMANCE_API_INFO_INTEL"/>
<enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PERFORMANCE_MARKER_INFO_INTEL"/>
<enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PERFORMANCE_STREAM_MARKER_INFO_INTEL"/>
@@ -14718,18 +17824,18 @@ typedef void <name>CAMetalLayer</name>;
<command name="vkCreateImagePipeSurfaceFUCHSIA"/>
</require>
</extension>
- <extension name="VK_KHR_shader_terminate_invocation" number="216" type="device" author="KHR" requires="VK_KHR_get_physical_device_properties2" contact="Jesse Hall @critsec" supported="vulkan">
+ <extension name="VK_KHR_shader_terminate_invocation" number="216" type="device" author="KHR" requires="VK_KHR_get_physical_device_properties2" contact="Jesse Hall @critsec" supported="vulkan" promotedto="VK_VERSION_1_3">
<require>
<enum value="1" name="VK_KHR_SHADER_TERMINATE_INVOCATION_SPEC_VERSION"/>
<enum value="&quot;VK_KHR_shader_terminate_invocation&quot;" name="VK_KHR_SHADER_TERMINATE_INVOCATION_EXTENSION_NAME"/>
- <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES_KHR"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TERMINATE_INVOCATION_FEATURES"/>
<type name="VkPhysicalDeviceShaderTerminateInvocationFeaturesKHR"/>
</require>
</extension>
<extension name="VK_GOOGLE_extension_217" number="217" author="GOOGLE" contact="Jesse Hall @critsec" supported="disabled">
<require>
- <enum value="0" name="VK_KHR_EXTENSION_217_SPEC_VERSION"/>
- <enum value="&quot;VK_KHR_extension_217&quot;" name="VK_KHR_EXTENSION_217_EXTENSION_NAME"/>
+ <enum value="0" name="VK_GOOGLE_EXTENSION_217_SPEC_VERSION"/>
+ <enum value="&quot;VK_GOOGLE_extension_217&quot;" name="VK_GOOGLE_EXTENSION_217_EXTENSION_NAME"/>
</require>
</extension>
<extension name="VK_EXT_metal_surface" number="218" type="instance" requires="VK_KHR_surface" platform="metal" supported="vulkan" author="EXT" contact="Dzmitry Malyshau @kvark">
@@ -14745,7 +17851,7 @@ typedef void <name>CAMetalLayer</name>;
</extension>
<extension name="VK_EXT_fragment_density_map" number="219" type="device" requires="VK_KHR_get_physical_device_properties2" author="EXT" contact="Matthew Netsch @mnetsch" supported="vulkan">
<require>
- <enum value="1" name="VK_EXT_FRAGMENT_DENSITY_MAP_SPEC_VERSION"/>
+ <enum value="2" name="VK_EXT_FRAGMENT_DENSITY_MAP_SPEC_VERSION"/>
<enum value="&quot;VK_EXT_fragment_density_map&quot;" name="VK_EXT_FRAGMENT_DENSITY_MAP_EXTENSION_NAME"/>
<enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT"/>
<enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT"/>
@@ -14763,6 +17869,9 @@ typedef void <name>CAMetalLayer</name>;
<type name="VkPhysicalDeviceFragmentDensityMapPropertiesEXT"/>
<type name="VkRenderPassFragmentDensityMapCreateInfoEXT"/>
</require>
+ <require extension="VK_KHR_format_feature_flags2">
+ <enum bitpos="24" extends="VkFormatFeatureFlagBits2" name="VK_FORMAT_FEATURE_2_FRAGMENT_DENSITY_MAP_BIT_EXT"/>
+ </require>
</extension>
<extension name="VK_EXT_extension_220" number="220" author="EXT" contact="Dzmitry Malyshau @kvark" supported="disabled">
<require>
@@ -14793,8 +17902,10 @@ typedef void <name>CAMetalLayer</name>;
</extension>
<extension name="VK_GOOGLE_hlsl_functionality1" number="224" type="device" author="GOOGLE" contact="Hai Nguyen @chaoticbob" supported="vulkan">
<require>
- <enum value="1" name="VK_GOOGLE_HLSL_FUNCTIONALITY1_SPEC_VERSION"/>
- <enum value="&quot;VK_GOOGLE_hlsl_functionality1&quot;" name="VK_GOOGLE_HLSL_FUNCTIONALITY1_EXTENSION_NAME"/>
+ <enum value="1" name="VK_GOOGLE_HLSL_FUNCTIONALITY_1_SPEC_VERSION"/>
+ <enum value="&quot;VK_GOOGLE_hlsl_functionality1&quot;" name="VK_GOOGLE_HLSL_FUNCTIONALITY_1_EXTENSION_NAME"/>
+ <enum alias="VK_GOOGLE_HLSL_FUNCTIONALITY_1_SPEC_VERSION" name="VK_GOOGLE_HLSL_FUNCTIONALITY1_SPEC_VERSION" comment="Backwards-compatible alias containing a typo"/>
+ <enum alias="VK_GOOGLE_HLSL_FUNCTIONALITY_1_EXTENSION_NAME" name="VK_GOOGLE_HLSL_FUNCTIONALITY1_EXTENSION_NAME" comment="Backwards-compatible alias containing a typo"/>
</require>
</extension>
<extension name="VK_GOOGLE_decorate_string" number="225" type="device" author="GOOGLE" contact="Hai Nguyen @chaoticbob" supported="vulkan">
@@ -14803,23 +17914,23 @@ typedef void <name>CAMetalLayer</name>;
<enum value="&quot;VK_GOOGLE_decorate_string&quot;" name="VK_GOOGLE_DECORATE_STRING_EXTENSION_NAME"/>
</require>
</extension>
- <extension name="VK_EXT_subgroup_size_control" number="226" type="device" requiresCore="1.1" author="EXT" contact="Neil Henning @sheredom" supported="vulkan">
+ <extension name="VK_EXT_subgroup_size_control" number="226" type="device" requiresCore="1.1" author="EXT" contact="Neil Henning @sheredom" supported="vulkan" promotedto="VK_VERSION_1_3">
<require>
- <enum value="2" name="VK_EXT_SUBGROUP_SIZE_CONTROL_SPEC_VERSION"/>
- <enum value="&quot;VK_EXT_subgroup_size_control&quot;" name="VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME"/>
- <type name="VkPhysicalDeviceSubgroupSizeControlFeaturesEXT"/>
- <type name="VkPhysicalDeviceSubgroupSizeControlPropertiesEXT"/>
- <type name="VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT"/>
- <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES_EXT"/>
- <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT"/>
- <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT"/>
- <enum bitpos="0" extends="VkPipelineShaderStageCreateFlagBits" name="VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT"/>
- <enum bitpos="1" extends="VkPipelineShaderStageCreateFlagBits" name="VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT"/>
+ <enum value="2" name="VK_EXT_SUBGROUP_SIZE_CONTROL_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_subgroup_size_control&quot;" name="VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME"/>
+ <type name="VkPhysicalDeviceSubgroupSizeControlFeaturesEXT"/>
+ <type name="VkPhysicalDeviceSubgroupSizeControlPropertiesEXT"/>
+ <type name="VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES_EXT" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT" alias="VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES_EXT" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_FEATURES"/>
+ <enum extends="VkPipelineShaderStageCreateFlagBits" name="VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT" alias="VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT"/>
+ <enum extends="VkPipelineShaderStageCreateFlagBits" name="VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT_EXT" alias="VK_PIPELINE_SHADER_STAGE_CREATE_REQUIRE_FULL_SUBGROUPS_BIT"/>
</require>
</extension>
<extension name="VK_KHR_fragment_shading_rate" number="227" type="device" requires="VK_KHR_create_renderpass2,VK_KHR_get_physical_device_properties2" author="KHR" contact="Tobias Hector @tobski" supported="vulkan">
<require>
- <enum value="1" name="VK_KHR_FRAGMENT_SHADING_RATE_SPEC_VERSION"/>
+ <enum value="2" name="VK_KHR_FRAGMENT_SHADING_RATE_SPEC_VERSION"/>
<enum value="&quot;VK_KHR_fragment_shading_rate&quot;" name="VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME"/>
<type name="VkFragmentShadingRateCombinerOpKHR"/>
<type name="VkFragmentShadingRateAttachmentInfoKHR"/>
@@ -14841,6 +17952,9 @@ typedef void <name>CAMetalLayer</name>;
<enum bitpos="22" extends="VkPipelineStageFlagBits" name="VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR"/>
<enum bitpos="30" extends="VkFormatFeatureFlagBits" name="VK_FORMAT_FEATURE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR"/>
</require>
+ <require extension="VK_KHR_format_feature_flags2">
+ <enum bitpos="30" extends="VkFormatFeatureFlagBits2" name="VK_FORMAT_FEATURE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR"/>
+ </require>
</extension>
<extension name="VK_AMD_shader_core_properties2" number="228" type="device" author="AMD" contact="Matthaeus G. Chajdas @anteru" supported="vulkan" requires="VK_AMD_shader_core_properties">
<require>
@@ -14966,6 +18080,7 @@ typedef void <name>CAMetalLayer</name>;
<require>
<enum value="0" name="VK_INTEL_EXTENSION_243_SPEC_VERSION"/>
<enum value="&quot;VK_INTEL_extension_243&quot;" name="VK_INTEL_EXTENSION_243_EXTENSION_NAME"/>
+ <enum bitpos="46" extends="VkAccessFlagBits2" name="VK_ACCESS_2_RESERVED_46_BIT_EXT"/>
</require>
</extension>
<extension name="VK_MESA_extension_244" number="244" author="MESA" contact="Andres Rodriguez @lostgoat" supported="disabled">
@@ -14992,25 +18107,25 @@ typedef void <name>CAMetalLayer</name>;
<command name="vkGetBufferDeviceAddressEXT"/>
</require>
</extension>
- <extension name="VK_EXT_tooling_info" number="246" type="device" author="EXT" contact="Tobias Hector @tobski" supported="vulkan">
+ <extension name="VK_EXT_tooling_info" number="246" type="device" author="EXT" contact="Tobias Hector @tobski" supported="vulkan" promotedto="VK_VERSION_1_3">
<require>
<enum value="1" name="VK_EXT_TOOLING_INFO_SPEC_VERSION"/>
<enum value="&quot;VK_EXT_tooling_info&quot;" name="VK_EXT_TOOLING_INFO_EXTENSION_NAME"/>
- <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES_EXT"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES_EXT" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TOOL_PROPERTIES"/>
<type name="VkToolPurposeFlagBitsEXT"/>
<type name="VkToolPurposeFlagsEXT"/>
<type name="VkPhysicalDeviceToolPropertiesEXT"/>
<command name="vkGetPhysicalDeviceToolPropertiesEXT"/>
</require>
<require extension="VK_EXT_debug_report">
- <enum bitpos="5" extends="VkToolPurposeFlagBitsEXT" name="VK_TOOL_PURPOSE_DEBUG_REPORTING_BIT_EXT"/>
+ <enum bitpos="5" extends="VkToolPurposeFlagBits" name="VK_TOOL_PURPOSE_DEBUG_REPORTING_BIT_EXT"/>
</require>
<require extension="VK_EXT_debug_marker">
- <enum bitpos="6" extends="VkToolPurposeFlagBitsEXT" name="VK_TOOL_PURPOSE_DEBUG_MARKERS_BIT_EXT"/>
+ <enum bitpos="6" extends="VkToolPurposeFlagBits" name="VK_TOOL_PURPOSE_DEBUG_MARKERS_BIT_EXT"/>
</require>
<require extension="VK_EXT_debug_utils">
- <enum bitpos="5" extends="VkToolPurposeFlagBitsEXT" name="VK_TOOL_PURPOSE_DEBUG_REPORTING_BIT_EXT"/>
- <enum bitpos="6" extends="VkToolPurposeFlagBitsEXT" name="VK_TOOL_PURPOSE_DEBUG_MARKERS_BIT_EXT"/>
+ <enum bitpos="5" extends="VkToolPurposeFlagBits" name="VK_TOOL_PURPOSE_DEBUG_REPORTING_BIT_EXT"/>
+ <enum bitpos="6" extends="VkToolPurposeFlagBits" name="VK_TOOL_PURPOSE_DEBUG_MARKERS_BIT_EXT"/>
</require>
</extension>
<extension name="VK_EXT_separate_stencil_usage" number="247" type="device" author="EXT" contact="Daniel Rakos @drakos-amd" supported="vulkan" promotedto="VK_VERSION_1_2">
@@ -15035,9 +18150,9 @@ typedef void <name>CAMetalLayer</name>;
<require>
<enum value="1" name="VK_KHR_PRESENT_WAIT_SPEC_VERSION"/>
<enum value="&quot;VK_KHR_present_wait&quot;" name="VK_KHR_PRESENT_WAIT_EXTENSION_NAME"/>
- <command name="vkWaitForPresentKHR"/>
- <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR"/>
- <type name="VkPhysicalDevicePresentWaitFeaturesKHR"/>
+ <command name="vkWaitForPresentKHR"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR"/>
+ <type name="VkPhysicalDevicePresentWaitFeaturesKHR"/>
</require>
</extension>
<extension name="VK_NV_cooperative_matrix" number="250" type="device" requires="VK_KHR_get_physical_device_properties2" author="NV" contact="Jeff Bolz @jeffbolznv" supported="vulkan">
@@ -15170,6 +18285,10 @@ typedef void <name>CAMetalLayer</name>;
<require>
<enum value="0" name="VK_EXT_EXTENSION_259_SPEC_VERSION"/>
<enum value="&quot;VK_EXT_extension_259&quot;" name="VK_EXT_EXTENSION_259_EXTENSION_NAME"/>
+ <enum bitpos="9" extends="VkQueueFlagBits" name="VK_QUEUE_RESERVED_9_BIT_EXT"/>
+ <enum bitpos="44" extends="VkFormatFeatureFlagBits2" name="VK_FORMAT_FEATURE_2_RESERVED_44_BIT_EXT"/>
+ <enum bitpos="45" extends="VkFormatFeatureFlagBits2" name="VK_FORMAT_FEATURE_2_RESERVED_45_BIT_EXT"/>
+ <enum bitpos="19" extends="VkImageCreateFlagBits" name="VK_IMAGE_CREATE_RESERVED_19_BIT_EXT"/>
</require>
</extension>
<extension name="VK_EXT_line_rasterization" number="260" type="device" requires="VK_KHR_get_physical_device_properties2" author="EXT" contact="Jeff Bolz @jeffbolznv" specialuse="cadsupport" supported="vulkan">
@@ -15206,8 +18325,8 @@ typedef void <name>CAMetalLayer</name>;
</extension>
<extension name="VK_GGP_extension_263" number="263" author="GGP" contact="Jean-Francois Roy @jfroy" supported="disabled">
<require>
- <enum value="0" name="VK_GOOGLE_EXTENSION_263_SPEC_VERSION"/>
- <enum value="&quot;VK_GGP_extension_263&quot;" name="VK_GOOGLE_EXTENSION_263_EXTENSION_NAME"/>
+ <enum value="0" name="VK_GGP_EXTENSION_263_SPEC_VERSION"/>
+ <enum value="&quot;VK_GGP_extension_263&quot;" name="VK_GGP_EXTENSION_263_EXTENSION_NAME"/>
</require>
</extension>
<extension name="VK_BRCM_extension_264" number="264" author="BRCM" contact="Graeme Leese @gnl21" supported="disabled">
@@ -15234,27 +18353,27 @@ typedef void <name>CAMetalLayer</name>;
<extension name="VK_EXT_extension_267" number="267" type="device" author="EXT" contact="Piers Daniell @pdaniell-nv" supported="disabled">
<require>
<enum value="0" name="VK_EXT_EXTENSION_267_SPEC_VERSION"/>
- <enum value="&quot;VK_EXT_extension_267&quot;" name="VK_EXT_extension_267"/>
+ <enum value="&quot;VK_EXT_extension_267&quot;" name="VK_EXT_EXTENSION_267_EXTENSION_NAME"/>
</require>
</extension>
- <extension name="VK_EXT_extended_dynamic_state" number="268" type="device" requires="VK_KHR_get_physical_device_properties2" author="EXT" contact="Piers Daniell @pdaniell-nv" supported="vulkan">
+ <extension name="VK_EXT_extended_dynamic_state" number="268" type="device" requires="VK_KHR_get_physical_device_properties2" author="EXT" contact="Piers Daniell @pdaniell-nv" supported="vulkan" promotedto="VK_VERSION_1_3">
<require>
<enum value="1" name="VK_EXT_EXTENDED_DYNAMIC_STATE_SPEC_VERSION"/>
<enum value="&quot;VK_EXT_extended_dynamic_state&quot;" name="VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME"/>
- <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT"/>
- <enum offset="0" extends="VkDynamicState" name="VK_DYNAMIC_STATE_CULL_MODE_EXT"/>
- <enum offset="1" extends="VkDynamicState" name="VK_DYNAMIC_STATE_FRONT_FACE_EXT"/>
- <enum offset="2" extends="VkDynamicState" name="VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT"/>
- <enum offset="3" extends="VkDynamicState" name="VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT"/>
- <enum offset="4" extends="VkDynamicState" name="VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT"/>
- <enum offset="5" extends="VkDynamicState" name="VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT"/>
- <enum offset="6" extends="VkDynamicState" name="VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT"/>
- <enum offset="7" extends="VkDynamicState" name="VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT"/>
- <enum offset="8" extends="VkDynamicState" name="VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT"/>
- <enum offset="9" extends="VkDynamicState" name="VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT"/>
- <enum offset="10" extends="VkDynamicState" name="VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT"/>
- <enum offset="11" extends="VkDynamicState" name="VK_DYNAMIC_STATE_STENCIL_OP_EXT"/>
- <type name="VkPhysicalDeviceExtendedDynamicStateFeaturesEXT"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT" comment="Not promoted to 1.3"/>
+ <enum extends="VkDynamicState" name="VK_DYNAMIC_STATE_CULL_MODE_EXT" alias="VK_DYNAMIC_STATE_CULL_MODE"/>
+ <enum extends="VkDynamicState" name="VK_DYNAMIC_STATE_FRONT_FACE_EXT" alias="VK_DYNAMIC_STATE_FRONT_FACE"/>
+ <enum extends="VkDynamicState" name="VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT" alias="VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY"/>
+ <enum extends="VkDynamicState" name="VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT" alias="VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT"/>
+ <enum extends="VkDynamicState" name="VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT" alias="VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT"/>
+ <enum extends="VkDynamicState" name="VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT" alias="VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE"/>
+ <enum extends="VkDynamicState" name="VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT" alias="VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE"/>
+ <enum extends="VkDynamicState" name="VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT" alias="VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE"/>
+ <enum extends="VkDynamicState" name="VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT" alias="VK_DYNAMIC_STATE_DEPTH_COMPARE_OP"/>
+ <enum extends="VkDynamicState" name="VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT" alias="VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE"/>
+ <enum extends="VkDynamicState" name="VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT" alias="VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE"/>
+ <enum extends="VkDynamicState" name="VK_DYNAMIC_STATE_STENCIL_OP_EXT" alias="VK_DYNAMIC_STATE_STENCIL_OP"/>
+ <type name="VkPhysicalDeviceExtendedDynamicStateFeaturesEXT" comment="Not promoted to 1.3"/>
<command name="vkCmdSetCullModeEXT"/>
<command name="vkCmdSetFrontFaceEXT"/>
<command name="vkCmdSetPrimitiveTopologyEXT"/>
@@ -15314,19 +18433,20 @@ typedef void <name>CAMetalLayer</name>;
<extension name="VK_INTEL_extension_271" number="271" type="device" author="INTEL" contact="Jason Ekstrand @jekstrand" supported="disabled">
<require>
<enum value="0" name="VK_INTEL_EXTENSION_271_SPEC_VERSION"/>
- <enum value="&quot;VK_KHR_extension_271&quot;" name="VK_INTEL_extension_271"/>
+ <enum value="&quot;VK_INTEL_extension_271&quot;" name="VK_INTEL_EXTENSION_271_EXTENSION_NAME"/>
+ <enum bitpos="22" extends="VkImageUsageFlagBits" name="VK_IMAGE_USAGE_RESERVED_22_BIT_EXT"/>
</require>
</extension>
<extension name="VK_INTEL_extension_272" number="272" type="device" author="INTEL" contact="Jason Ekstrand @jekstrand" supported="disabled">
<require>
<enum value="0" name="VK_INTEL_EXTENSION_272_SPEC_VERSION"/>
- <enum value="&quot;VK_KHR_extension_272&quot;" name="VK_INTEL_extension_272"/>
+ <enum value="&quot;VK_INTEL_extension_272&quot;" name="VK_INTEL_EXTENSION_272_EXTENSION_NAME"/>
</require>
</extension>
<extension name="VK_INTEL_extension_273" number="273" type="device" author="INTEL" contact="Jason Ekstrand @jekstrand" supported="disabled">
<require>
<enum value="0" name="VK_INTEL_EXTENSION_273_SPEC_VERSION"/>
- <enum value="&quot;VK_KHR_extension_273&quot;" name="VK_INTEL_extension_273"/>
+ <enum value="&quot;VK_INTEL_extension_273&quot;" name="VK_INTEL_EXTENSION_273_EXTENSION_NAME"/>
</require>
</extension>
<extension name="VK_EXT_shader_atomic_float2" number="274" type="device" requires="VK_EXT_shader_atomic_float" author="EXT" contact="Jason Ekstrand @jekstrand" supported="vulkan">
@@ -15337,28 +18457,56 @@ typedef void <name>CAMetalLayer</name>;
<type name="VkPhysicalDeviceShaderAtomicFloat2FeaturesEXT"/>
</require>
</extension>
- <extension name="VK_KHR_extension_275" number="275" type="instance" author="KHR" contact="Lionel Landwerlin @llandwerlin" supported="disabled">
- <require>
- <enum value="0" name="VK_KHR_EXTENSION_275_SPEC_VERSION"/>
- <enum value="&quot;VK_KHR_extension_275&quot;" name="VK_KHR_extension_275"/>
- </require>
- </extension>
- <extension name="VK_KHR_extension_276" number="276" type="device" author="KHR" contact="James Jones @cubanismo" supported="disabled">
- <require>
- <enum value="0" name="VK_KHR_EXTENSION_276_SPEC_VERSION"/>
- <enum value="&quot;VK_KHR_extension_276&quot;" name="VK_KHR_extension_276"/>
- </require>
- </extension>
- <extension name="VK_EXT_shader_demote_to_helper_invocation" number="277" type="device" requires="VK_KHR_get_physical_device_properties2" author="EXT" contact="Jeff Bolz @jeffbolznv" supported="vulkan">
+ <extension name="VK_EXT_surface_maintenance1" number="275" type="instance" requires="VK_KHR_surface,VK_KHR_get_surface_capabilities2" author="EXT" contact="Shahbaz Youssefi @syoussefi" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_SURFACE_MAINTENANCE_1_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_surface_maintenance1&quot;" name="VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT"/>
+ <type name="VkSurfacePresentModeEXT"/>
+ <type name="VkPresentScalingFlagBitsEXT"/>
+ <type name="VkPresentScalingFlagsEXT"/>
+ <type name="VkPresentGravityFlagBitsEXT"/>
+ <type name="VkPresentGravityFlagsEXT"/>
+ <type name="VkSurfacePresentScalingCapabilitiesEXT"/>
+ <type name="VkSurfacePresentModeCompatibilityEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_swapchain_maintenance1" number="276" type="device" requires="VK_KHR_swapchain,VK_EXT_surface_maintenance1,VK_KHR_get_physical_device_properties2" author="EXT" contact="Shahbaz Youssefi @syoussefi" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_SWAPCHAIN_MAINTENANCE_1_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_swapchain_maintenance1&quot;" name="VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_FENCE_INFO_EXT"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODES_CREATE_INFO_EXT"/>
+ <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODE_INFO_EXT"/>
+ <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_SCALING_CREATE_INFO_EXT"/>
+ <enum offset="5" extends="VkStructureType" name="VK_STRUCTURE_TYPE_RELEASE_SWAPCHAIN_IMAGES_INFO_EXT"/>
+ <enum bitpos="3" extends="VkSwapchainCreateFlagBitsKHR" name="VK_SWAPCHAIN_CREATE_DEFERRED_MEMORY_ALLOCATION_BIT_EXT"/>
+ <type name="VkPhysicalDeviceSwapchainMaintenance1FeaturesEXT"/>
+ <type name="VkSwapchainPresentFenceInfoEXT"/>
+ <type name="VkSwapchainPresentModesCreateInfoEXT"/>
+ <type name="VkSwapchainPresentModeInfoEXT"/>
+ <type name="VkSwapchainPresentScalingCreateInfoEXT"/>
+ <type name="VkReleaseSwapchainImagesInfoEXT"/>
+ <command name="vkReleaseSwapchainImagesEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_shader_demote_to_helper_invocation" number="277" type="device" requires="VK_KHR_get_physical_device_properties2" author="EXT" contact="Jeff Bolz @jeffbolznv" supported="vulkan" promotedto="VK_VERSION_1_3">
<require>
<enum value="1" name="VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_SPEC_VERSION"/>
<enum value="&quot;VK_EXT_shader_demote_to_helper_invocation&quot;" name="VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME"/>
- <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES"/>
<type name="VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT"/>
</require>
</extension>
- <extension name="VK_NV_device_generated_commands" number="278" type="device" requiresCore="1.1" author="NV" contact="Christoph Kubisch @pixeljetstream" supported="vulkan">
+ <extension name="VK_NV_device_generated_commands" number="278" type="device" requiresCore="1.1" requires="VK_KHR_buffer_device_address" author="NV" contact="Christoph Kubisch @pixeljetstream" supported="vulkan">
<require>
+ <comment>
+ This extension requires buffer_device_address functionality.
+ VK_EXT_buffer_device_address is also acceptable, but since it is deprecated the KHR version is preferred.
+ </comment>
<enum value="3" name="VK_NV_DEVICE_GENERATED_COMMANDS_SPEC_VERSION"/>
<enum value="&quot;VK_NV_device_generated_commands&quot;" name="VK_NV_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME"/>
<enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_NV"/>
@@ -15414,28 +18562,32 @@ typedef void <name>CAMetalLayer</name>;
<extension name="VK_KHR_extension_280" number="280" type="device" author="KHR" contact="Kevin Petit @kevinpetit" supported="disabled">
<require>
<enum value="0" name="VK_KHR_EXTENSION_280_SPEC_VERSION"/>
- <enum value="&quot;VK_KHR_extension_280&quot;" name="VK_KHR_extension_280"/>
+ <enum value="&quot;VK_KHR_extension_280&quot;" name="VK_KHR_EXTENSION_280_EXTENSION_NAME"/>
</require>
</extension>
- <extension name="VK_ARM_extension_281" number="281" type="device" author="ARM" contact="Kevin Petit @kevinpetit" supported="disabled">
+ <extension name="VK_KHR_shader_integer_dot_product" number="281" type="device" author="KHR" requires="VK_KHR_get_physical_device_properties2" contact="Kevin Petit @kevinpetit" supported="vulkan" promotedto="VK_VERSION_1_3">
<require>
- <enum value="0" name="VK_ARM_EXTENSION_281_SPEC_VERSION"/>
- <enum value="&quot;VK_ARM_extension_281&quot;" name="VK_ARM_extension_281"/>
+ <enum value="1" name="VK_KHR_SHADER_INTEGER_DOT_PRODUCT_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_shader_integer_dot_product&quot;" name="VK_KHR_SHADER_INTEGER_DOT_PRODUCT_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_FEATURES"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES"/>
+ <type name="VkPhysicalDeviceShaderIntegerDotProductFeaturesKHR"/>
+ <type name="VkPhysicalDeviceShaderIntegerDotProductPropertiesKHR"/>
</require>
</extension>
- <extension name="VK_EXT_texel_buffer_alignment" number="282" type="device" requires="VK_KHR_get_physical_device_properties2" author="EXT" contact="Jeff Bolz @jeffbolznv" supported="vulkan">
+ <extension name="VK_EXT_texel_buffer_alignment" number="282" type="device" requires="VK_KHR_get_physical_device_properties2" author="EXT" contact="Jeff Bolz @jeffbolznv" supported="vulkan" promotedto="VK_VERSION_1_3">
<require>
<enum value="1" name="VK_EXT_TEXEL_BUFFER_ALIGNMENT_SPEC_VERSION"/>
<enum value="&quot;VK_EXT_texel_buffer_alignment&quot;" name="VK_EXT_TEXEL_BUFFER_ALIGNMENT_EXTENSION_NAME"/>
- <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT"/>
- <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT"/>
- <type name="VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_FEATURES_EXT" comment="Not promoted to 1.3"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES"/>
+ <type name="VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT" comment="Not promoted to 1.3"/>
<type name="VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT"/>
</require>
</extension>
<extension name="VK_QCOM_render_pass_transform" number="283" type="device" requires="VK_KHR_swapchain,VK_KHR_surface" author="QCOM" contact="Jeff Leger @jackohound" supported="vulkan">
<require>
- <enum value="2" name="VK_QCOM_RENDER_PASS_TRANSFORM_SPEC_VERSION"/>
+ <enum value="3" name="VK_QCOM_RENDER_PASS_TRANSFORM_SPEC_VERSION"/>
<enum value="&quot;VK_QCOM_render_pass_transform&quot;" name="VK_QCOM_RENDER_PASS_TRANSFORM_EXTENSION_NAME"/>
<enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDER_PASS_TRANSFORM_INFO_QCOM"/>
<enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_RENDER_PASS_TRANSFORM_BEGIN_INFO_QCOM"/>
@@ -15447,7 +18599,7 @@ typedef void <name>CAMetalLayer</name>;
<extension name="VK_EXT_extension_284" number="284" type="device" author="EXT" contact="Samuel Pitoiset @hakzsam" supported="disabled">
<require>
<enum value="0" name="VK_EXT_EXTENSION_284_SPEC_VERSION"/>
- <enum value="&quot;VK_EXT_extension_284&quot;" name="VK_EXT_extension_284"/>
+ <enum value="&quot;VK_EXT_extension_284&quot;" name="VK_EXT_EXTENSION_284_EXTENSION_NAME"/>
</require>
</extension>
<extension name="VK_EXT_device_memory_report" number="285" type="device" requires="VK_KHR_get_physical_device_properties2" author="EXT" contact="Yiwei Zhang @zhangyiwei" specialuse="devtools" supported="vulkan">
@@ -15559,13 +18711,19 @@ typedef void <name>CAMetalLayer</name>;
<enum value="&quot;VK_NV_extension_292&quot;" name="VK_NV_EXTENSION_292_EXTENSION_NAME"/>
</require>
</extension>
- <extension name="VK_NV_extension_293" number="293" author="NV" contact="Daniel Koch @dgkoch" supported="disabled">
+ <extension name="VK_NV_present_barrier" number="293" type="device" author="NV" requires="VK_KHR_get_physical_device_properties2,VK_KHR_surface,VK_KHR_get_surface_capabilities2,VK_KHR_swapchain" contact="Liya Li @liyli" supported="vulkan">
<require>
- <enum value="0" name="VK_NV_EXTENSION_293_SPEC_VERSION"/>
- <enum value="&quot;VK_NV_extension_293&quot;" name="VK_NV_EXTENSION_293_EXTENSION_NAME"/>
+ <enum value="1" name="VK_NV_PRESENT_BARRIER_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_present_barrier&quot;" name="VK_NV_PRESENT_BARRIER_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_BARRIER_FEATURES_NV"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_PRESENT_BARRIER_NV"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_BARRIER_CREATE_INFO_NV"/>
+ <type name="VkPhysicalDevicePresentBarrierFeaturesNV"/>
+ <type name="VkSurfaceCapabilitiesPresentBarrierNV"/>
+ <type name="VkSwapchainPresentBarrierCreateInfoNV"/>
</require>
</extension>
- <extension name="VK_KHR_shader_non_semantic_info" number="294" type="device" author="KHR" contact="Baldur Karlsson @baldurk" supported="vulkan">
+ <extension name="VK_KHR_shader_non_semantic_info" number="294" type="device" author="KHR" contact="Baldur Karlsson @baldurk" supported="vulkan" promotedto="VK_VERSION_1_3">
<require>
<enum value="1" name="VK_KHR_SHADER_NON_SEMANTIC_INFO_SPEC_VERSION"/>
<enum value="&quot;VK_KHR_shader_non_semantic_info&quot;" name="VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME"/>
@@ -15577,24 +18735,23 @@ typedef void <name>CAMetalLayer</name>;
<enum value="&quot;VK_KHR_present_id&quot;" name="VK_KHR_PRESENT_ID_EXTENSION_NAME"/>
<enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PRESENT_ID_KHR"/>
<type name="VkPresentIdKHR"/>
- <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR"/>
- <type name="VkPhysicalDevicePresentIdFeaturesKHR"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR"/>
+ <type name="VkPhysicalDevicePresentIdFeaturesKHR"/>
</require>
</extension>
- <extension name="VK_EXT_private_data" number="296" type="device" author="NV" contact="Matthew Rusch @mattruschnv" supported="vulkan">
+ <extension name="VK_EXT_private_data" number="296" type="device" author="NV" contact="Matthew Rusch @mattruschnv" supported="vulkan" promotedto="VK_VERSION_1_3">
<require>
<enum value="1" name="VK_EXT_PRIVATE_DATA_SPEC_VERSION"/>
<enum value="&quot;VK_EXT_private_data&quot;" name="VK_EXT_PRIVATE_DATA_EXTENSION_NAME"/>
- <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES_EXT"/>
- <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO_EXT"/>
- <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO_EXT"/>
- <enum offset="0" extends="VkObjectType" name="VK_OBJECT_TYPE_PRIVATE_DATA_SLOT_EXT"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES_EXT" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO_EXT" alias="VK_STRUCTURE_TYPE_DEVICE_PRIVATE_DATA_CREATE_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO_EXT" alias="VK_STRUCTURE_TYPE_PRIVATE_DATA_SLOT_CREATE_INFO"/>
+ <enum extends="VkObjectType" name="VK_OBJECT_TYPE_PRIVATE_DATA_SLOT_EXT" alias="VK_OBJECT_TYPE_PRIVATE_DATA_SLOT"/>
<type name="VkPhysicalDevicePrivateDataFeaturesEXT"/>
<type name="VkDevicePrivateDataCreateInfoEXT"/>
<type name="VkPrivateDataSlotCreateInfoEXT"/>
<type name="VkPrivateDataSlotEXT"/>
- <type name="VkPrivateDataSlotCreateFlagsEXT"/>
- <type name="VkPrivateDataSlotCreateFlagBitsEXT"/>
+ <type name="VkPrivateDataSlotCreateFlagsEXT" comment="Will add VkPrivateDataSlotCreateFlagBits when bits are defined in the future"/>
<command name="vkCreatePrivateDataSlotEXT"/>
<command name="vkDestroyPrivateDataSlotEXT"/>
<command name="vkSetPrivateDataEXT"/>
@@ -15608,22 +18765,18 @@ typedef void <name>CAMetalLayer</name>;
<enum bitpos="3" extends="VkPipelineShaderStageCreateFlagBits" name="VK_PIPELINE_SHADER_STAGE_CREATE_RESERVED_3_BIT_KHR"/>
</require>
</extension>
- <extension name="VK_EXT_pipeline_creation_cache_control" number="298" type="device" author="AMD" contact="Gregory Grebe @grgrebe_amd" supported="vulkan">
+ <extension name="VK_EXT_pipeline_creation_cache_control" number="298" type="device" author="AMD" contact="Gregory Grebe @grgrebe_amd" supported="vulkan" promotedto="VK_VERSION_1_3">
<require>
- <enum value="3" name="VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_SPEC_VERSION"/>
- <enum value="&quot;VK_EXT_pipeline_creation_cache_control&quot;"
- name="VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_EXTENSION_NAME"/>
- <enum offset="0" extends="VkStructureType"
- name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES_EXT"/>
+ <enum value="3" name="VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_pipeline_creation_cache_control&quot;" name="VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES_EXT" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES"/>
<type name="VkPhysicalDevicePipelineCreationCacheControlFeaturesEXT"/>
- <enum bitpos="8" extends="VkPipelineCreateFlagBits"
- name="VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT"/>
- <enum bitpos="9" extends="VkPipelineCreateFlagBits"
- name="VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT_EXT"/>
- <enum extends="VkResult" offset="0" name="VK_PIPELINE_COMPILE_REQUIRED_EXT"/>
- <enum extends="VkResult" name="VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT" alias="VK_PIPELINE_COMPILE_REQUIRED_EXT"/>
- <enum bitpos="0" extends="VkPipelineCacheCreateFlagBits"
- name="VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT_EXT"/>
+ <enum extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT_EXT" alias="VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT"/>
+ <enum extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT_EXT" alias="VK_PIPELINE_CREATE_EARLY_RETURN_ON_FAILURE_BIT"/>
+ <enum extends="VkResult" name="VK_PIPELINE_COMPILE_REQUIRED_EXT" alias="VK_PIPELINE_COMPILE_REQUIRED"/>
+ <enum extends="VkResult" name="VK_ERROR_PIPELINE_COMPILE_REQUIRED_EXT" alias="VK_PIPELINE_COMPILE_REQUIRED"/>
+ <enum extends="VkPipelineCacheCreateFlagBits" name="VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT_EXT" alias="VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT"/>
+ <type name="VkPipelineCacheCreateFlagBits" comment="This is a temporary workaround for processors not recognizing that VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT_EXT above also requires this type"/>
</require>
</extension>
<extension name="VK_KHR_extension_299" number="299" author="KHR" contact="Mark Bellamy @mark.bellamy_arm" supported="disabled">
@@ -15635,16 +18788,22 @@ typedef void <name>CAMetalLayer</name>;
<enum bitpos="2" extends="VkPipelineCacheCreateFlagBits" name="VK_PIPELINE_CACHE_CREATE_RESERVED_2_BIT_KHR"/>
</require>
</extension>
- <extension name="VK_KHR_video_encode_queue" number="300" type="device" requires="VK_KHR_video_queue,VK_KHR_synchronization2" author="KHR" contact="ahmed.abdelkalek@amd.com" provisional="true" platform="provisional" supported="vulkan">
+ <extension name="VK_KHR_video_encode_queue" number="300" type="device" requires="VK_KHR_video_queue,VK_KHR_synchronization2" author="KHR" contact="Ahmed Abdelkhalek @aabdelkh" provisional="true" platform="provisional" supported="vulkan">
<require>
- <enum value="2" name="VK_KHR_VIDEO_ENCODE_QUEUE_SPEC_VERSION"/>
+ <enum value="7" name="VK_KHR_VIDEO_ENCODE_QUEUE_SPEC_VERSION"/>
<enum value="&quot;VK_KHR_video_encode_queue&quot;" name="VK_KHR_VIDEO_ENCODE_QUEUE_EXTENSION_NAME"/>
- <enum bitpos="27" extends="VkPipelineStageFlagBits2KHR" name="VK_PIPELINE_STAGE_2_VIDEO_ENCODE_BIT_KHR" protect="VK_ENABLE_BETA_EXTENSIONS" />
- <enum bitpos="37" extends="VkAccessFlagBits2KHR" name="VK_ACCESS_2_VIDEO_ENCODE_READ_BIT_KHR" protect="VK_ENABLE_BETA_EXTENSIONS" />
- <enum bitpos="38" extends="VkAccessFlagBits2KHR" name="VK_ACCESS_2_VIDEO_ENCODE_WRITE_BIT_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <!-- VkPipelineStageFlagBits bitpos="27" is reserved by this extension, but not used -->
+ <enum bitpos="27" extends="VkPipelineStageFlagBits2" name="VK_PIPELINE_STAGE_2_VIDEO_ENCODE_BIT_KHR" protect="VK_ENABLE_BETA_EXTENSIONS" />
+ <enum bitpos="37" extends="VkAccessFlagBits2" name="VK_ACCESS_2_VIDEO_ENCODE_READ_BIT_KHR" protect="VK_ENABLE_BETA_EXTENSIONS" />
+ <enum bitpos="38" extends="VkAccessFlagBits2" name="VK_ACCESS_2_VIDEO_ENCODE_WRITE_BIT_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
<enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_INFO_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
<enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_RATE_CONTROL_INFO_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_RATE_CONTROL_LAYER_INFO_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_CAPABILITIES_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_VIDEO_ENCODE_USAGE_INFO_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
<enum bitpos="6" extends="VkQueueFlagBits" name="VK_QUEUE_VIDEO_ENCODE_BIT_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum bitpos="1" extends="VkVideoCodingControlFlagBitsKHR" name="VK_VIDEO_CODING_CONTROL_ENCODE_RATE_CONTROL_BIT_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum bitpos="2" extends="VkVideoCodingControlFlagBitsKHR" name="VK_VIDEO_CODING_CONTROL_ENCODE_RATE_CONTROL_LAYER_BIT_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
<enum bitpos="15" extends="VkBufferUsageFlagBits" name="VK_BUFFER_USAGE_VIDEO_ENCODE_DST_BIT_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
<enum bitpos="16" extends="VkBufferUsageFlagBits" name="VK_BUFFER_USAGE_VIDEO_ENCODE_SRC_BIT_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
<enum bitpos="13" extends="VkImageUsageFlagBits" name="VK_IMAGE_USAGE_VIDEO_ENCODE_DST_BIT_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
@@ -15657,22 +18816,36 @@ typedef void <name>CAMetalLayer</name>;
<enum offset="2" extends="VkImageLayout" name="VK_IMAGE_LAYOUT_VIDEO_ENCODE_DPB_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
<enum offset="0" extends="VkQueryType" name="VK_QUERY_TYPE_VIDEO_ENCODE_BITSTREAM_BUFFER_RANGE_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
- <type name="VkVideoEncodeFlagBitsKHR"/>
<type name="VkVideoEncodeFlagsKHR"/>
<type name="VkVideoEncodeInfoKHR"/>
- <type name="VkVideoEncodeRateControlFlagBitsKHR"/>
+ <type name="VkVideoEncodeCapabilityFlagBitsKHR"/>
+ <type name="VkVideoEncodeCapabilityFlagsKHR"/>
+ <type name="VkVideoEncodeCapabilitiesKHR"/>
+
+ <type name="VkVideoEncodeUsageFlagBitsKHR"/>
+ <type name="VkVideoEncodeUsageFlagsKHR"/>
+ <type name="VkVideoEncodeContentFlagBitsKHR"/>
+ <type name="VkVideoEncodeContentFlagsKHR"/>
+ <type name="VkVideoEncodeTuningModeKHR"/>
+ <type name="VkVideoEncodeUsageInfoKHR"/>
+
<type name="VkVideoEncodeRateControlFlagsKHR"/>
<type name="VkVideoEncodeRateControlModeFlagBitsKHR"/>
<type name="VkVideoEncodeRateControlModeFlagsKHR"/>
-
<type name="VkVideoEncodeRateControlInfoKHR"/>
+ <type name="VkVideoEncodeRateControlLayerInfoKHR"/>
+
<command name="vkCmdEncodeVideoKHR"/>
</require>
+ <require extension="VK_KHR_format_feature_flags2">
+ <enum bitpos="27" extends="VkFormatFeatureFlagBits2" name="VK_FORMAT_FEATURE_2_VIDEO_ENCODE_INPUT_BIT_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ <enum bitpos="28" extends="VkFormatFeatureFlagBits2" name="VK_FORMAT_FEATURE_2_VIDEO_ENCODE_DPB_BIT_KHR" protect="VK_ENABLE_BETA_EXTENSIONS"/>
+ </require>
</extension>
<extension name="VK_NV_device_diagnostics_config" number="301" type="device" requires="VK_KHR_get_physical_device_properties2" author="NV" contact="Kedarnath Thangudu @kthangudu" supported="vulkan">
<require>
- <enum value="1" name="VK_NV_DEVICE_DIAGNOSTICS_CONFIG_SPEC_VERSION"/>
+ <enum value="2" name="VK_NV_DEVICE_DIAGNOSTICS_CONFIG_SPEC_VERSION"/>
<enum value="&quot;VK_NV_device_diagnostics_config&quot;" name="VK_NV_DEVICE_DIAGNOSTICS_CONFIG_EXTENSION_NAME"/>
<enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV"/>
<enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEVICE_DIAGNOSTICS_CONFIG_CREATE_INFO_NV"/>
@@ -15686,37 +18859,37 @@ typedef void <name>CAMetalLayer</name>;
<require>
<enum value="2" name="VK_QCOM_RENDER_PASS_STORE_OPS_SPEC_VERSION"/>
<enum value="&quot;VK_QCOM_render_pass_store_ops&quot;" name="VK_QCOM_RENDER_PASS_STORE_OPS_EXTENSION_NAME"/>
- <enum offset="0" extends="VkAttachmentStoreOp" name="VK_ATTACHMENT_STORE_OP_NONE_QCOM"/>
+ <enum extends="VkAttachmentStoreOp" name="VK_ATTACHMENT_STORE_OP_NONE_QCOM" alias="VK_ATTACHMENT_STORE_OP_NONE"/>
</require>
</extension>
<extension name="VK_QCOM_extension_303" number="303" author="QCOM" contact="Bill Licea-Kane @wwlk" supported="disabled">
<require>
- <enum value="0" name="VK_QCOM_extension_303_SPEC_VERSION"/>
- <enum value="&quot;VK_QCOM_extension_303&quot;" name="VK_QCOM_extension_303_EXTENSION_NAME"/>
+ <enum value="0" name="VK_QCOM_EXTENSION_303_SPEC_VERSION"/>
+ <enum value="&quot;VK_QCOM_extension_303&quot;" name="VK_QCOM_EXTENSION_303_EXTENSION_NAME"/>
</require>
</extension>
<extension name="VK_QCOM_extension_304" number="304" author="QCOM" contact="Bill Licea-Kane @wwlk" supported="disabled">
<require>
- <enum value="0" name="VK_QCOM_extension_304_SPEC_VERSION"/>
- <enum value="&quot;VK_QCOM_extension_304&quot;" name="VK_QCOM_extension_304_EXTENSION_NAME"/>
+ <enum value="0" name="VK_QCOM_EXTENSION_304_SPEC_VERSION"/>
+ <enum value="&quot;VK_QCOM_extension_304&quot;" name="VK_QCOM_EXTENSION_304_EXTENSION_NAME"/>
</require>
</extension>
<extension name="VK_QCOM_extension_305" number="305" author="QCOM" contact="Bill Licea-Kane @wwlk" supported="disabled">
<require>
- <enum value="0" name="VK_QCOM_extension_305_SPEC_VERSION"/>
- <enum value="&quot;VK_QCOM_extension_305&quot;" name="VK_QCOM_extension_305_EXTENSION_NAME"/>
+ <enum value="0" name="VK_QCOM_EXTENSION_305_SPEC_VERSION"/>
+ <enum value="&quot;VK_QCOM_extension_305&quot;" name="VK_QCOM_EXTENSION_305_EXTENSION_NAME"/>
</require>
</extension>
<extension name="VK_QCOM_extension_306" number="306" author="QCOM" contact="Bill Licea-Kane @wwlk" supported="disabled">
<require>
- <enum value="0" name="VK_QCOM_extension_306_SPEC_VERSION"/>
- <enum value="&quot;VK_QCOM_extension_306&quot;" name="VK_QCOM_extension_306_EXTENSION_NAME"/>
+ <enum value="0" name="VK_QCOM_EXTENSION_306_SPEC_VERSION"/>
+ <enum value="&quot;VK_QCOM_extension_306&quot;" name="VK_QCOM_EXTENSION_306_EXTENSION_NAME"/>
</require>
</extension>
<extension name="VK_QCOM_extension_307" number="307" author="QCOM" contact="Bill Licea-Kane @wwlk" supported="disabled">
<require>
- <enum value="0" name="VK_QCOM_extension_307_SPEC_VERSION"/>
- <enum value="&quot;VK_QCOM_extension_307&quot;" name="VK_QCOM_extension_307_EXTENSION_NAME"/>
+ <enum value="0" name="VK_QCOM_EXTENSION_307_SPEC_VERSION"/>
+ <enum value="&quot;VK_QCOM_extension_307&quot;" name="VK_QCOM_EXTENSION_307_EXTENSION_NAME"/>
</require>
</extension>
<extension name="VK_NV_extension_308" number="308" type="device" author="NV" contact="Tristan Lorach @tlorach" supported="disabled">
@@ -15733,8 +18906,8 @@ typedef void <name>CAMetalLayer</name>;
</extension>
<extension name="VK_QCOM_extension_310" number="310" author="QCOM" contact="Jeff Leger @jackohound" supported="disabled">
<require>
- <enum value="0" name="VK_QCOM_extension_310_SPEC_VERSION"/>
- <enum value="&quot;VK_QCOM_extension_310&quot;" name="VK_QCOM_extension_310_EXTENSION_NAME"/>
+ <enum value="0" name="VK_QCOM_EXTENSION_310_SPEC_VERSION"/>
+ <enum value="&quot;VK_QCOM_extension_310&quot;" name="VK_QCOM_EXTENSION_310_EXTENSION_NAME"/>
<enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_RESERVED_QCOM"/>
</require>
</extension>
@@ -15744,10 +18917,43 @@ typedef void <name>CAMetalLayer</name>;
<enum value="&quot;VK_NV_extension_311&quot;" name="VK_NV_EXTENSION_311_EXTENSION_NAME"/>
</require>
</extension>
- <extension name="VK_EXT_extension_312" number="312" author="MVK" contact="Bill Hollings @billhollings" supported="disabled">
- <require>
- <enum value="0" name="VK_EXT_EXTENSION_312_SPEC_VERSION"/>
- <enum value="&quot;VK_EXT_extension_312&quot;" name="VK_EXT_EXTENSION_312_EXTENSION_NAME"/>
+ <extension name="VK_EXT_metal_objects" number="312" type="device" platform="metal" supported="vulkan" author="EXT" contact="Bill Hollings @billhollings">
+ <require>
+ <enum value="1" name="VK_EXT_METAL_OBJECTS_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_metal_objects&quot;" name="VK_EXT_METAL_OBJECTS_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_EXPORT_METAL_OBJECT_CREATE_INFO_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_EXPORT_METAL_OBJECTS_INFO_EXT"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_EXPORT_METAL_DEVICE_INFO_EXT"/>
+ <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_EXPORT_METAL_COMMAND_QUEUE_INFO_EXT"/>
+ <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_EXPORT_METAL_BUFFER_INFO_EXT"/>
+ <enum offset="5" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMPORT_METAL_BUFFER_INFO_EXT"/>
+ <enum offset="6" extends="VkStructureType" name="VK_STRUCTURE_TYPE_EXPORT_METAL_TEXTURE_INFO_EXT"/>
+ <enum offset="7" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMPORT_METAL_TEXTURE_INFO_EXT"/>
+ <enum offset="8" extends="VkStructureType" name="VK_STRUCTURE_TYPE_EXPORT_METAL_IO_SURFACE_INFO_EXT"/>
+ <enum offset="9" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMPORT_METAL_IO_SURFACE_INFO_EXT"/>
+ <enum offset="10" extends="VkStructureType" name="VK_STRUCTURE_TYPE_EXPORT_METAL_SHARED_EVENT_INFO_EXT"/>
+ <enum offset="11" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMPORT_METAL_SHARED_EVENT_INFO_EXT"/>
+ <type name="VkExportMetalObjectTypeFlagBitsEXT"/>
+ <type name="VkExportMetalObjectTypeFlagsEXT"/>
+ <type name="VkExportMetalObjectCreateInfoEXT"/>
+ <type name="VkExportMetalObjectsInfoEXT"/>
+ <type name="VkExportMetalDeviceInfoEXT"/>
+ <type name="VkExportMetalCommandQueueInfoEXT"/>
+ <type name="VkExportMetalBufferInfoEXT"/>
+ <type name="VkImportMetalBufferInfoEXT"/>
+ <type name="VkExportMetalTextureInfoEXT"/>
+ <type name="VkImportMetalTextureInfoEXT"/>
+ <type name="VkExportMetalIOSurfaceInfoEXT"/>
+ <type name="VkImportMetalIOSurfaceInfoEXT"/>
+ <type name="VkExportMetalSharedEventInfoEXT"/>
+ <type name="VkImportMetalSharedEventInfoEXT"/>
+ <type name="MTLDevice_id"/>
+ <type name="MTLCommandQueue_id"/>
+ <type name="MTLBuffer_id"/>
+ <type name="MTLTexture_id"/>
+ <type name="MTLSharedEvent_id"/>
+ <type name="IOSurfaceRef"/>
+ <command name="vkExportMetalObjectsEXT"/>
</require>
</extension>
<extension name="VK_EXT_extension_313" number="313" author="MVK" contact="Bill Hollings @billhollings" supported="disabled">
@@ -15762,23 +18968,24 @@ typedef void <name>CAMetalLayer</name>;
<enum value="&quot;VK_AMD_extension_314&quot;" name="VK_AMD_EXTENSION_314_EXTENSION_NAME"/>
</require>
</extension>
- <extension name="VK_KHR_synchronization2" number="315" type="device" author="KHR" requires="VK_KHR_get_physical_device_properties2" contact="Tobias Hector @tobski" supported="vulkan">
+ <extension name="VK_KHR_synchronization2" number="315" type="device" author="KHR" requires="VK_KHR_get_physical_device_properties2" contact="Tobias Hector @tobski" supported="vulkan" promotedto="VK_VERSION_1_3">
<require>
<enum value="1" name="VK_KHR_SYNCHRONIZATION_2_SPEC_VERSION"/>
<enum value="&quot;VK_KHR_synchronization2&quot;" name="VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME"/>
- <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_MEMORY_BARRIER_2_KHR"/>
- <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2_KHR"/>
- <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2_KHR"/>
- <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEPENDENCY_INFO_KHR"/>
- <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SUBMIT_INFO_2_KHR"/>
- <enum offset="5" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR"/>
- <enum offset="6" extends="VkStructureType" name="VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO_KHR"/>
- <enum offset="7" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR"/>
- <enum bitpos="0" extends="VkEventCreateFlagBits" name="VK_EVENT_CREATE_DEVICE_ONLY_BIT_KHR"/>
- <enum offset="0" extends="VkImageLayout" name="VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL_KHR"/>
- <enum offset="1" extends="VkImageLayout" name="VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR"/>
- <enum value="0" extends="VkPipelineStageFlagBits" name="VK_PIPELINE_STAGE_NONE_KHR"/>
- <enum value="0" extends="VkAccessFlagBits" name="VK_ACCESS_NONE_KHR"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_MEMORY_BARRIER_2_KHR" alias="VK_STRUCTURE_TYPE_MEMORY_BARRIER_2"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2_KHR" alias="VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2_KHR" alias="VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEPENDENCY_INFO_KHR" alias="VK_STRUCTURE_TYPE_DEPENDENCY_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_SUBMIT_INFO_2_KHR" alias="VK_STRUCTURE_TYPE_SUBMIT_INFO_2"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO_KHR" alias="VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO_KHR" alias="VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES"/>
+ <enum extends="VkEventCreateFlagBits" name="VK_EVENT_CREATE_DEVICE_ONLY_BIT_KHR" alias="VK_EVENT_CREATE_DEVICE_ONLY_BIT"/>
+ <enum extends="VkImageLayout" name="VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL_KHR" alias="VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL"/>
+ <enum extends="VkImageLayout" name="VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL_KHR" alias="VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL"/>
+ <enum extends="VkPipelineStageFlagBits" name="VK_PIPELINE_STAGE_NONE_KHR" alias="VK_PIPELINE_STAGE_NONE"/>
+ <enum extends="VkAccessFlagBits" name="VK_ACCESS_NONE_KHR" alias="VK_ACCESS_NONE"/>
+ <type name="VkFlags64"/>
<type name="VkPipelineStageFlags2KHR"/>
<type name="VkPipelineStageFlagBits2KHR"/>
<type name="VkAccessFlags2KHR"/>
@@ -15801,52 +19008,52 @@ typedef void <name>CAMetalLayer</name>;
<command name="vkQueueSubmit2KHR"/>
</require>
<require extension="VK_EXT_transform_feedback">
- <enum bitpos="24" extends="VkPipelineStageFlagBits2KHR" name="VK_PIPELINE_STAGE_2_TRANSFORM_FEEDBACK_BIT_EXT"/>
- <enum bitpos="25" extends="VkAccessFlagBits2KHR" name="VK_ACCESS_2_TRANSFORM_FEEDBACK_WRITE_BIT_EXT"/>
- <enum bitpos="26" extends="VkAccessFlagBits2KHR" name="VK_ACCESS_2_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT"/>
- <enum bitpos="27" extends="VkAccessFlagBits2KHR" name="VK_ACCESS_2_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT"/>
+ <enum bitpos="24" extends="VkPipelineStageFlagBits2" name="VK_PIPELINE_STAGE_2_TRANSFORM_FEEDBACK_BIT_EXT"/>
+ <enum bitpos="25" extends="VkAccessFlagBits2" name="VK_ACCESS_2_TRANSFORM_FEEDBACK_WRITE_BIT_EXT"/>
+ <enum bitpos="26" extends="VkAccessFlagBits2" name="VK_ACCESS_2_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT"/>
+ <enum bitpos="27" extends="VkAccessFlagBits2" name="VK_ACCESS_2_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT"/>
</require>
<require extension="VK_EXT_conditional_rendering">
- <enum bitpos="18" extends="VkPipelineStageFlagBits2KHR" name="VK_PIPELINE_STAGE_2_CONDITIONAL_RENDERING_BIT_EXT" comment="A pipeline stage for conditional rendering predicate fetch"/>
- <enum bitpos="20" extends="VkAccessFlagBits2KHR" name="VK_ACCESS_2_CONDITIONAL_RENDERING_READ_BIT_EXT" comment="read access flag for reading conditional rendering predicate"/>
+ <enum bitpos="18" extends="VkPipelineStageFlagBits2" name="VK_PIPELINE_STAGE_2_CONDITIONAL_RENDERING_BIT_EXT" comment="A pipeline stage for conditional rendering predicate fetch"/>
+ <enum bitpos="20" extends="VkAccessFlagBits2" name="VK_ACCESS_2_CONDITIONAL_RENDERING_READ_BIT_EXT" comment="read access flag for reading conditional rendering predicate"/>
</require>
<require extension="VK_NV_device_generated_commands">
- <enum bitpos="17" extends="VkPipelineStageFlagBits2KHR" name="VK_PIPELINE_STAGE_2_COMMAND_PREPROCESS_BIT_NV"/>
- <enum bitpos="17" extends="VkAccessFlagBits2KHR" name="VK_ACCESS_2_COMMAND_PREPROCESS_READ_BIT_NV"/>
- <enum bitpos="18" extends="VkAccessFlagBits2KHR" name="VK_ACCESS_2_COMMAND_PREPROCESS_WRITE_BIT_NV"/>
+ <enum bitpos="17" extends="VkPipelineStageFlagBits2" name="VK_PIPELINE_STAGE_2_COMMAND_PREPROCESS_BIT_NV"/>
+ <enum bitpos="17" extends="VkAccessFlagBits2" name="VK_ACCESS_2_COMMAND_PREPROCESS_READ_BIT_NV"/>
+ <enum bitpos="18" extends="VkAccessFlagBits2" name="VK_ACCESS_2_COMMAND_PREPROCESS_WRITE_BIT_NV"/>
</require>
<require extension="VK_KHR_fragment_shading_rate">
- <enum bitpos="22" extends="VkPipelineStageFlagBits2KHR" name="VK_PIPELINE_STAGE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR"/>
- <enum bitpos="23" extends="VkAccessFlagBits2KHR" name="VK_ACCESS_2_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR"/>
+ <enum bitpos="22" extends="VkPipelineStageFlagBits2" name="VK_PIPELINE_STAGE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR"/>
+ <enum bitpos="23" extends="VkAccessFlagBits2" name="VK_ACCESS_2_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR"/>
</require>
<require extension="VK_NV_shading_rate_image">
- <enum extends="VkPipelineStageFlagBits2KHR" name="VK_PIPELINE_STAGE_2_SHADING_RATE_IMAGE_BIT_NV" alias="VK_PIPELINE_STAGE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR"/>
- <enum extends="VkAccessFlagBits2KHR" name="VK_ACCESS_2_SHADING_RATE_IMAGE_READ_BIT_NV" alias="VK_ACCESS_2_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR"/>
+ <enum extends="VkPipelineStageFlagBits2" name="VK_PIPELINE_STAGE_2_SHADING_RATE_IMAGE_BIT_NV" alias="VK_PIPELINE_STAGE_2_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR"/>
+ <enum extends="VkAccessFlagBits2" name="VK_ACCESS_2_SHADING_RATE_IMAGE_READ_BIT_NV" alias="VK_ACCESS_2_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR"/>
</require>
<require extension="VK_KHR_acceleration_structure">
- <enum bitpos="25" extends="VkPipelineStageFlagBits2KHR" name="VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR"/>
- <enum bitpos="21" extends="VkAccessFlagBits2KHR" name="VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR"/>
- <enum bitpos="22" extends="VkAccessFlagBits2KHR" name="VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_KHR"/>
+ <enum bitpos="25" extends="VkPipelineStageFlagBits2" name="VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR"/>
+ <enum bitpos="21" extends="VkAccessFlagBits2" name="VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR"/>
+ <enum bitpos="22" extends="VkAccessFlagBits2" name="VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_KHR"/>
</require>
<require extension="VK_KHR_ray_tracing_pipeline">
- <enum bitpos="21" extends="VkPipelineStageFlagBits2KHR" name="VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR"/>
+ <enum bitpos="21" extends="VkPipelineStageFlagBits2" name="VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR"/>
</require>
<require extension="VK_NV_ray_tracing">
- <enum extends="VkPipelineStageFlagBits2KHR" name="VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_NV" alias="VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR"/>
- <enum extends="VkPipelineStageFlagBits2KHR" name="VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_NV" alias="VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR"/>
- <enum extends="VkAccessFlagBits2KHR" name="VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_NV" alias="VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR"/>
- <enum extends="VkAccessFlagBits2KHR" name="VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_NV" alias="VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_KHR"/>
+ <enum extends="VkPipelineStageFlagBits2" name="VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_NV" alias="VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR"/>
+ <enum extends="VkPipelineStageFlagBits2" name="VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_NV" alias="VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR"/>
+ <enum extends="VkAccessFlagBits2" name="VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_NV" alias="VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR"/>
+ <enum extends="VkAccessFlagBits2" name="VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_NV" alias="VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_KHR"/>
</require>
<require extension="VK_EXT_fragment_density_map">
- <enum bitpos="23" extends="VkPipelineStageFlagBits2KHR" name="VK_PIPELINE_STAGE_2_FRAGMENT_DENSITY_PROCESS_BIT_EXT"/>
- <enum bitpos="24" extends="VkAccessFlagBits2KHR" name="VK_ACCESS_2_FRAGMENT_DENSITY_MAP_READ_BIT_EXT"/>
+ <enum bitpos="23" extends="VkPipelineStageFlagBits2" name="VK_PIPELINE_STAGE_2_FRAGMENT_DENSITY_PROCESS_BIT_EXT"/>
+ <enum bitpos="24" extends="VkAccessFlagBits2" name="VK_ACCESS_2_FRAGMENT_DENSITY_MAP_READ_BIT_EXT"/>
</require>
<require extension="VK_EXT_blend_operation_advanced">
- <enum bitpos="19" extends="VkAccessFlagBits2KHR" name="VK_ACCESS_2_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT"/>
+ <enum bitpos="19" extends="VkAccessFlagBits2" name="VK_ACCESS_2_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT"/>
</require>
<require extension="VK_NV_mesh_shader">
- <enum bitpos="19" extends="VkPipelineStageFlagBits2KHR" name="VK_PIPELINE_STAGE_2_TASK_SHADER_BIT_NV"/>
- <enum bitpos="20" extends="VkPipelineStageFlagBits2KHR" name="VK_PIPELINE_STAGE_2_MESH_SHADER_BIT_NV"/>
+ <enum extends="VkPipelineStageFlagBits2" name="VK_PIPELINE_STAGE_2_TASK_SHADER_BIT_NV" alias="VK_PIPELINE_STAGE_2_TASK_SHADER_BIT_EXT"/>
+ <enum extends="VkPipelineStageFlagBits2" name="VK_PIPELINE_STAGE_2_MESH_SHADER_BIT_NV" alias="VK_PIPELINE_STAGE_2_MESH_SHADER_BIT_EXT"/>
</require>
<require extension="VK_AMD_buffer_marker">
<command name="vkCmdWriteBufferMarker2AMD"/>
@@ -15858,6 +19065,10 @@ typedef void <name>CAMetalLayer</name>;
<enum offset="8" extends="VkStructureType" name="VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_2_NV"/>
<enum offset="9" extends="VkStructureType" name="VK_STRUCTURE_TYPE_CHECKPOINT_DATA_2_NV"/>
</require>
+ <require extension="VK_EXT_mesh_shader">
+ <enum bitpos="19" extends="VkPipelineStageFlagBits2" name="VK_PIPELINE_STAGE_2_TASK_SHADER_BIT_EXT"/>
+ <enum bitpos="20" extends="VkPipelineStageFlagBits2" name="VK_PIPELINE_STAGE_2_MESH_SHADER_BIT_EXT"/>
+ </require>
</extension>
<extension name="VK_AMD_extension_316" number="316" author="AMD" contact="Martin Dinkov @mdinkov" supported="disabled">
<require>
@@ -15865,10 +19076,62 @@ typedef void <name>CAMetalLayer</name>;
<enum value="&quot;VK_AMD_extension_316&quot;" name="VK_AMD_EXTENSION_316_EXTENSION_NAME"/>
</require>
</extension>
- <extension name="VK_AMD_extension_317" number="317" author="AMD" contact="Martin Dinkov @mdinkov" supported="disabled">
- <require>
- <enum value="0" name="VK_AMD_EXTENSION_317_SPEC_VERSION"/>
- <enum value="&quot;VK_AMD_extension_317&quot;" name="VK_AMD_EXTENSION_317_EXTENSION_NAME"/>
+ <extension name="VK_EXT_descriptor_buffer" number="317" type="device" author="EXT" requires="VK_KHR_get_physical_device_properties2,VK_KHR_buffer_device_address,VK_KHR_synchronization2,VK_EXT_descriptor_indexing" contact="Tobias Hector @tobski" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_DESCRIPTOR_BUFFER_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_descriptor_buffer&quot;" name="VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_DENSITY_MAP_PROPERTIES_EXT"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT"/>
+ <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DESCRIPTOR_ADDRESS_INFO_EXT"/>
+ <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DESCRIPTOR_GET_INFO_EXT"/>
+ <enum offset="5" extends="VkStructureType" name="VK_STRUCTURE_TYPE_BUFFER_CAPTURE_DESCRIPTOR_DATA_INFO_EXT"/>
+ <enum offset="6" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_CAPTURE_DESCRIPTOR_DATA_INFO_EXT"/>
+ <enum offset="7" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_VIEW_CAPTURE_DESCRIPTOR_DATA_INFO_EXT"/>
+ <enum offset="8" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SAMPLER_CAPTURE_DESCRIPTOR_DATA_INFO_EXT"/>
+ <enum offset="10" extends="VkStructureType" name="VK_STRUCTURE_TYPE_OPAQUE_CAPTURE_DESCRIPTOR_DATA_CREATE_INFO_EXT"/>
+ <enum offset="11" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DESCRIPTOR_BUFFER_BINDING_INFO_EXT"/>
+ <enum offset="12" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DESCRIPTOR_BUFFER_BINDING_PUSH_DESCRIPTOR_BUFFER_HANDLE_EXT"/>
+ <enum bitpos="4" extends="VkDescriptorSetLayoutCreateFlagBits" name="VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT"/>
+ <enum bitpos="5" extends="VkDescriptorSetLayoutCreateFlagBits" name="VK_DESCRIPTOR_SET_LAYOUT_CREATE_EMBEDDED_IMMUTABLE_SAMPLERS_BIT_EXT"/>
+ <enum bitpos="21" extends="VkBufferUsageFlagBits" name="VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT"/>
+ <enum bitpos="22" extends="VkBufferUsageFlagBits" name="VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT"/>
+ <enum bitpos="26" extends="VkBufferUsageFlagBits" name="VK_BUFFER_USAGE_PUSH_DESCRIPTORS_DESCRIPTOR_BUFFER_BIT_EXT"/>
+ <enum bitpos="5" extends="VkBufferCreateFlagBits" name="VK_BUFFER_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT"/>
+ <enum bitpos="16" extends="VkImageCreateFlagBits" name="VK_IMAGE_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT"/>
+ <enum bitpos="2" extends="VkImageViewCreateFlagBits" name="VK_IMAGE_VIEW_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT"/>
+ <enum bitpos="3" extends="VkSamplerCreateFlagBits" name="VK_SAMPLER_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT"/>
+ <enum bitpos="3" extends="VkAccelerationStructureCreateFlagBitsKHR" name="VK_ACCELERATION_STRUCTURE_CREATE_DESCRIPTOR_BUFFER_CAPTURE_REPLAY_BIT_EXT"/>
+ <enum bitpos="41" extends="VkAccessFlagBits2" name="VK_ACCESS_2_DESCRIPTOR_BUFFER_READ_BIT_EXT"/>
+ <enum bitpos="29" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_DESCRIPTOR_BUFFER_BIT_EXT"/>
+ <type name="VkPhysicalDeviceDescriptorBufferPropertiesEXT"/>
+ <type name="VkPhysicalDeviceDescriptorBufferDensityMapPropertiesEXT"/>
+ <type name="VkPhysicalDeviceDescriptorBufferFeaturesEXT"/>
+ <type name="VkDescriptorAddressInfoEXT"/>
+ <type name="VkDescriptorBufferBindingInfoEXT"/>
+ <type name="VkDescriptorBufferBindingPushDescriptorBufferHandleEXT"/>
+ <type name="VkDescriptorDataEXT"/>
+ <type name="VkDescriptorGetInfoEXT"/>
+ <type name="VkBufferCaptureDescriptorDataInfoEXT"/>
+ <type name="VkImageCaptureDescriptorDataInfoEXT"/>
+ <type name="VkImageViewCaptureDescriptorDataInfoEXT"/>
+ <type name="VkSamplerCaptureDescriptorDataInfoEXT"/>
+ <type name="VkOpaqueCaptureDescriptorDataCreateInfoEXT"/>
+ <command name="vkGetDescriptorSetLayoutSizeEXT"/>
+ <command name="vkGetDescriptorSetLayoutBindingOffsetEXT"/>
+ <command name="vkGetDescriptorEXT"/>
+ <command name="vkCmdBindDescriptorBuffersEXT"/>
+ <command name="vkCmdSetDescriptorBufferOffsetsEXT"/>
+ <command name="vkCmdBindDescriptorBufferEmbeddedSamplersEXT"/>
+ <command name="vkGetBufferOpaqueCaptureDescriptorDataEXT"/>
+ <command name="vkGetImageOpaqueCaptureDescriptorDataEXT"/>
+ <command name="vkGetImageViewOpaqueCaptureDescriptorDataEXT"/>
+ <command name="vkGetSamplerOpaqueCaptureDescriptorDataEXT"/>
+ </require>
+ <require extension="VK_KHR_acceleration_structure,VK_NV_ray_tracing">
+ <enum offset="9" extends="VkStructureType" name="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CAPTURE_DESCRIPTOR_DATA_INFO_EXT"/>
+ <type name="VkAccelerationStructureCaptureDescriptorDataInfoEXT"/>
+ <command name="vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT"/>
</require>
</extension>
<extension name="VK_AMD_extension_318" number="318" author="AMD" contact="Martin Dinkov @mdinkov" supported="disabled">
@@ -15891,24 +19154,40 @@ typedef void <name>CAMetalLayer</name>;
<enum value="&quot;VK_AMD_extension_320&quot;" name="VK_AMD_EXTENSION_320_EXTENSION_NAME"/>
</require>
</extension>
- <extension name="VK_AMD_extension_321" number="321" author="AMD" contact="Martin Dinkov @mdinkov" supported="disabled">
+ <extension name="VK_EXT_graphics_pipeline_library" number="321" type="device" requires="VK_KHR_get_physical_device_properties2,VK_KHR_pipeline_library" author="AMD" contact="Tobias Hector @tobski" supported="vulkan">
<require>
- <enum value="0" name="VK_AMD_EXTENSION_321_SPEC_VERSION"/>
- <enum value="&quot;VK_AMD_extension_321&quot;" name="VK_AMD_EXTENSION_321_EXTENSION_NAME"/>
- <enum bitpos="23" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_RESERVED_23_BIT_AMD"/>
- <enum bitpos="10" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_RESERVED_10_BIT_AMD"/>
+ <enum value="1" name="VK_EXT_GRAPHICS_PIPELINE_LIBRARY_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_graphics_pipeline_library&quot;" name="VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME"/>
+ <type name="VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT"/>
+ <type name="VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT"/>
+ <type name="VkGraphicsPipelineLibraryCreateInfoEXT"/>
+ <type name="VkGraphicsPipelineLibraryFlagBitsEXT"/>
+ <type name="VkGraphicsPipelineLibraryFlagsEXT"/>
+ <type name="VkPipelineLayoutCreateFlagBits"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_PROPERTIES_EXT"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_LIBRARY_CREATE_INFO_EXT"/>
+ <enum bitpos="23" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_RETAIN_LINK_TIME_OPTIMIZATION_INFO_BIT_EXT"/>
+ <enum bitpos="10" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_LINK_TIME_OPTIMIZATION_BIT_EXT"/>
+ <enum bitpos="1" extends="VkPipelineLayoutCreateFlagBits" name="VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT"/>
</require>
</extension>
- <extension name="VK_AMD_extension_322" number="322" author="AMD" contact="Martin Dinkov @mdinkov" supported="disabled">
+ <extension name="VK_AMD_shader_early_and_late_fragment_tests" number="322" author="EXT" contact="Tobias Hector @tobski" type="device" supported="vulkan">
<require>
- <enum value="0" name="VK_AMD_EXTENSION_322_SPEC_VERSION"/>
- <enum value="&quot;VK_AMD_extension_322&quot;" name="VK_AMD_EXTENSION_322_EXTENSION_NAME"/>
+ <enum value="1" name="VK_AMD_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_shader_early_and_late_fragment_tests&quot;" name="VK_AMD_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_EXTENSION_NAME"/>
+ <type name="VkPhysicalDeviceShaderEarlyAndLateFragmentTestsFeaturesAMD"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_EARLY_AND_LATE_FRAGMENT_TESTS_FEATURES_AMD"/>
</require>
</extension>
- <extension name="VK_AMD_extension_323" number="323" author="AMD" contact="Martin Dinkov @mdinkov" supported="disabled">
+ <extension name="VK_KHR_fragment_shader_barycentric" number="323" type="device" requires="VK_KHR_get_physical_device_properties2" author="KHR" contact="Stu Smith" supported="vulkan">
<require>
- <enum value="0" name="VK_AMD_EXTENSION_323_SPEC_VERSION"/>
- <enum value="&quot;VK_AMD_extension_323&quot;" name="VK_AMD_EXTENSION_323_EXTENSION_NAME"/>
+ <enum value="1" name="VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_fragment_shader_barycentric&quot;" name="VK_KHR_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" extnumber="204" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_FEATURES_KHR"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_PROPERTIES_KHR"/>
+ <type name="VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR"/>
+ <type name="VkPhysicalDeviceFragmentShaderBarycentricPropertiesKHR"/>
</require>
</extension>
<extension name="VK_KHR_shader_subgroup_uniform_control_flow" number="324" type="device" requiresCore="1.1" author="KHR" contact="Alan Baker @alan-baker" supported="vulkan">
@@ -15925,11 +19204,11 @@ typedef void <name>CAMetalLayer</name>;
<enum value="&quot;VK_KHR_extension_325&quot;" name="VK_KHR_EXTENSION_325_EXTENSION_NAME"/>
</require>
</extension>
- <extension name="VK_KHR_zero_initialize_workgroup_memory" number="326" type="device" requires="VK_KHR_get_physical_device_properties2" author="KHR" contact="Alan Baker @alan-baker" supported="vulkan">
+ <extension name="VK_KHR_zero_initialize_workgroup_memory" number="326" type="device" requires="VK_KHR_get_physical_device_properties2" author="KHR" contact="Alan Baker @alan-baker" supported="vulkan" promotedto="VK_VERSION_1_3">
<require>
- <enum value="1" name="VK_KHR_ZERO_INITIALIZE_WORKGROUP_MEMORY_SPEC_VERSION"/>
+ <enum value="1" name="VK_KHR_ZERO_INITIALIZE_WORKGROUP_MEMORY_SPEC_VERSION"/>
<enum value="&quot;VK_KHR_zero_initialize_workgroup_memory&quot;" name="VK_KHR_ZERO_INITIALIZE_WORKGROUP_MEMORY_EXTENSION_NAME"/>
- <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES_KHR"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES"/>
<type name="VkPhysicalDeviceZeroInitializeWorkgroupMemoryFeaturesKHR"/>
</require>
</extension>
@@ -15948,8 +19227,7 @@ typedef void <name>CAMetalLayer</name>;
<command name="vkCmdSetFragmentShadingRateEnumNV"/>
</require>
</extension>
- <extension name="VK_NV_ray_tracing_motion_blur" number="328" type="device"
- requires="VK_KHR_ray_tracing_pipeline" author="NV" contact="Eric Werness" supported="vulkan">
+ <extension name="VK_NV_ray_tracing_motion_blur" number="328" type="device" requires="VK_KHR_ray_tracing_pipeline" author="NV" contact="Eric Werness" supported="vulkan">
<require>
<enum value="1" name="VK_NV_RAY_TRACING_MOTION_BLUR_SPEC_VERSION"/>
<enum value="&quot;VK_NV_ray_tracing_motion_blur&quot;" name="VK_NV_RAY_TRACING_MOTION_BLUR_EXTENSION_NAME"/>
@@ -15972,10 +19250,28 @@ typedef void <name>CAMetalLayer</name>;
<type name="VkAccelerationStructureMotionInstanceFlagsNV"/>
</require>
</extension>
- <extension name="VK_NV_extension_329" number="329" author="NV" contact="Pat Brown @nvpbrown" supported="disabled">
- <require>
- <enum value="0" name="VK_NV_EXTENSION_329_SPEC_VERSION"/>
- <enum value="&quot;VK_NV_extension_329&quot;" name="VK_NV_EXTENSION_329_EXTENSION_NAME"/>
+ <extension name="VK_EXT_mesh_shader" number="329" type="device" requiresCore="1.1" requires="VK_KHR_get_physical_device_properties2,VK_KHR_spirv_1_4" author="EXT" sortorder="1" contact="Christoph Kubisch @pixeljetstream" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_MESH_SHADER_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_mesh_shader&quot;" name="VK_EXT_MESH_SHADER_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_EXT"/>
+ <enum bitpos="6" extends="VkShaderStageFlagBits" name="VK_SHADER_STAGE_TASK_BIT_EXT"/>
+ <enum bitpos="7" extends="VkShaderStageFlagBits" name="VK_SHADER_STAGE_MESH_BIT_EXT"/>
+ <enum bitpos="19" extends="VkPipelineStageFlagBits" name="VK_PIPELINE_STAGE_TASK_SHADER_BIT_EXT"/>
+ <enum bitpos="20" extends="VkPipelineStageFlagBits" name="VK_PIPELINE_STAGE_MESH_SHADER_BIT_EXT"/>
+ <enum offset="0" extends="VkQueryType" name="VK_QUERY_TYPE_MESH_PRIMITIVES_GENERATED_EXT"/>
+ <enum bitpos="11" extends="VkQueryPipelineStatisticFlagBits" name="VK_QUERY_PIPELINE_STATISTIC_TASK_SHADER_INVOCATIONS_BIT_EXT"/>
+ <enum bitpos="12" extends="VkQueryPipelineStatisticFlagBits" name="VK_QUERY_PIPELINE_STATISTIC_MESH_SHADER_INVOCATIONS_BIT_EXT"/>
+ <command name="vkCmdDrawMeshTasksEXT"/>
+ <command name="vkCmdDrawMeshTasksIndirectEXT"/>
+ <command name="vkCmdDrawMeshTasksIndirectCountEXT"/>
+ <type name="VkPhysicalDeviceMeshShaderFeaturesEXT"/>
+ <type name="VkPhysicalDeviceMeshShaderPropertiesEXT"/>
+ <type name="VkDrawMeshTasksIndirectCommandEXT"/>
+ </require>
+ <require extension="VK_NV_device_generated_commands">
+ <enum offset="0" extends="VkIndirectCommandsTokenTypeNV" name="VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_NV"/>
</require>
</extension>
<extension name="VK_NV_extension_330" number="330" author="NV" contact="Liam Middlebrook @liam-middlebrook" supported="disabled">
@@ -15984,15 +19280,20 @@ typedef void <name>CAMetalLayer</name>;
<enum value="&quot;VK_NV_extension_330&quot;" name="VK_NV_EXTENSION_330_EXTENSION_NAME"/>
</require>
</extension>
- <extension name="VK_EXT_ycbcr_2plane_444_formats" number="331" type="device" requires="VK_KHR_sampler_ycbcr_conversion" author="EXT" contact="Tony Zlatinski @tzlatinski" supported="vulkan">
+ <extension name="VK_EXT_ycbcr_2plane_444_formats" number="331" type="device" requires="VK_KHR_sampler_ycbcr_conversion" author="EXT" contact="Tony Zlatinski @tzlatinski" supported="vulkan" promotedto="VK_VERSION_1_3">
<require>
+ <comment>
+ VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT and
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT
+ were not promoted to Vulkan 1.3.
+ </comment>
<enum value="1" name="VK_EXT_YCBCR_2PLANE_444_FORMATS_SPEC_VERSION"/>
<enum value="&quot;VK_EXT_ycbcr_2plane_444_formats&quot;" name="VK_EXT_YCBCR_2PLANE_444_FORMATS_EXTENSION_NAME"/>
<enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_YCBCR_2_PLANE_444_FORMATS_FEATURES_EXT"/>
- <enum offset="0" extends="VkFormat" name="VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT"/>
- <enum offset="1" extends="VkFormat" name="VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16_EXT"/>
- <enum offset="2" extends="VkFormat" name="VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16_EXT"/>
- <enum offset="3" extends="VkFormat" name="VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT"/>
+ <enum extends="VkFormat" name="VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT" alias="VK_FORMAT_G8_B8R8_2PLANE_444_UNORM"/>
+ <enum extends="VkFormat" name="VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16_EXT" alias="VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16"/>
+ <enum extends="VkFormat" name="VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16_EXT" alias="VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16"/>
+ <enum extends="VkFormat" name="VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT" alias="VK_FORMAT_G16_B16R16_2PLANE_444_UNORM"/>
<type name="VkPhysicalDeviceYcbcr2Plane444FormatsFeaturesEXT"/>
</require>
</extension>
@@ -16027,11 +19328,11 @@ typedef void <name>CAMetalLayer</name>;
<enum value="&quot;VK_KHR_extension_335&quot;" name="VK_KHR_EXTENSION_335_EXTENSION_NAME"/>
</require>
</extension>
- <extension name="VK_EXT_image_robustness" number="336" type="device" author="EXT" contact="Graeme Leese @gnl21" supported="vulkan" requires="VK_KHR_get_physical_device_properties2">
+ <extension name="VK_EXT_image_robustness" number="336" type="device" author="EXT" contact="Graeme Leese @gnl21" supported="vulkan" requires="VK_KHR_get_physical_device_properties2" promotedto="VK_VERSION_1_3">
<require>
<enum value="1" name="VK_EXT_IMAGE_ROBUSTNESS_SPEC_VERSION"/>
<enum value="&quot;VK_EXT_image_robustness&quot;" name="VK_EXT_IMAGE_ROBUSTNESS_EXTENSION_NAME"/>
- <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES_EXT"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES_EXT" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ROBUSTNESS_FEATURES"/>
<type name="VkPhysicalDeviceImageRobustnessFeaturesEXT"/>
</require>
</extension>
@@ -16043,21 +19344,21 @@ typedef void <name>CAMetalLayer</name>;
<type name="VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR"/>
</require>
</extension>
- <extension name="VK_KHR_copy_commands2" number="338" author="KHR" type="device" contact="Jeff Leger @jackohound" supported="vulkan">
+ <extension name="VK_KHR_copy_commands2" number="338" author="KHR" type="device" contact="Jeff Leger @jackohound" supported="vulkan" promotedto="VK_VERSION_1_3">
<require>
<enum value="1" name="VK_KHR_COPY_COMMANDS_2_SPEC_VERSION"/>
<enum value="&quot;VK_KHR_copy_commands2&quot;" name="VK_KHR_COPY_COMMANDS_2_EXTENSION_NAME"/>
- <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2_KHR"/>
- <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2_KHR"/>
- <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2_KHR"/>
- <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2_KHR"/>
- <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2_KHR"/>
- <enum offset="5" extends="VkStructureType" name="VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2_KHR"/>
- <enum offset="6" extends="VkStructureType" name="VK_STRUCTURE_TYPE_BUFFER_COPY_2_KHR"/>
- <enum offset="7" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_COPY_2_KHR"/>
- <enum offset="8" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_BLIT_2_KHR"/>
- <enum offset="9" extends="VkStructureType" name="VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2_KHR"/>
- <enum offset="10" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2_KHR"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2_KHR" alias="VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2_KHR" alias="VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2_KHR" alias="VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2_KHR" alias="VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2_KHR" alias="VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2_KHR" alias="VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_BUFFER_COPY_2_KHR" alias="VK_STRUCTURE_TYPE_BUFFER_COPY_2"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_COPY_2_KHR" alias="VK_STRUCTURE_TYPE_IMAGE_COPY_2"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_BLIT_2_KHR" alias="VK_STRUCTURE_TYPE_IMAGE_BLIT_2"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2_KHR" alias="VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2_KHR" alias="VK_STRUCTURE_TYPE_IMAGE_RESOLVE_2"/>
<type name="VkCopyBufferInfo2KHR"/>
<type name="VkCopyImageInfo2KHR"/>
<type name="VkCopyBufferToImageInfo2KHR"/>
@@ -16077,39 +19378,86 @@ typedef void <name>CAMetalLayer</name>;
<command name="vkCmdResolveImage2KHR"/>
</require>
</extension>
- <extension name="VK_ARM_extension_339" number="339" author="ARM" contact="Jan-Harald Fredriksen @janharaldfredriksen-arm" supported="disabled">
+ <extension name="VK_EXT_image_compression_control" number="339" type="device" author="EXT" contact="Jan-Harald Fredriksen @janharaldfredriksen-arm" supported="vulkan">
<require>
- <enum value="0" name="VK_ARM_EXTENSION_339_SPEC_VERSION"/>
- <enum value="&quot;VK_ARM_extension_339&quot;" name="VK_ARM_EXTENSION_339_EXTENSION_NAME"/>
+ <enum value="1" name="VK_EXT_IMAGE_COMPRESSION_CONTROL_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_image_compression_control&quot;" name="VK_EXT_IMAGE_COMPRESSION_CONTROL_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_FEATURES_EXT"/>
+ <type name="VkPhysicalDeviceImageCompressionControlFeaturesEXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT"/>
+ <type name="VkImageCompressionControlEXT"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SUBRESOURCE_LAYOUT_2_EXT"/>
+ <type name="VkSubresourceLayout2EXT"/>
+ <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_SUBRESOURCE_2_EXT"/>
+ <type name="VkImageSubresource2EXT"/>
+ <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT"/>
+ <type name="VkImageCompressionPropertiesEXT"/>
+ <type name="VkImageCompressionFlagBitsEXT"/>
+ <type name="VkImageCompressionFlagsEXT"/>
+ <type name="VkImageCompressionFixedRateFlagBitsEXT"/>
+ <type name="VkImageCompressionFixedRateFlagsEXT"/>
+ <enum offset="0" dir="-" extends="VkResult" name="VK_ERROR_COMPRESSION_EXHAUSTED_EXT"/>
+ <command name="vkGetImageSubresourceLayout2EXT"/>
</require>
</extension>
- <extension name="VK_EXT_extension_340" number="340" author="EXT" contact="Joshua Ashton @Joshua-Ashton" supported="disabled">
+ <extension name="VK_EXT_attachment_feedback_loop_layout" number="340" type="device" requires="VK_KHR_get_physical_device_properties2" author="EXT" contact="Joshua Ashton @Joshua-Ashton" supported="vulkan">
<require>
- <enum value="0" name="VK_EXT_EXTENSION_340_SPEC_VERSION"/>
- <enum value="&quot;VK_EXT_extension_340&quot;" name="VK_EXT_EXTENSION_340_EXTENSION_NAME"/>
- <enum bitpos="19" extends="VkImageUsageFlagBits" name="VK_IMAGE_USAGE_RESERVED_19_BIT_EXT"/>
+ <enum value="2" name="VK_EXT_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_attachment_feedback_loop_layout&quot;" name="VK_EXT_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ATTACHMENT_FEEDBACK_LOOP_LAYOUT_FEATURES_EXT"/>
+ <enum offset="0" extends="VkImageLayout" name="VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT"/>
+ <enum bitpos="19" extends="VkImageUsageFlagBits" name="VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT"/>
+ <enum bitpos="25" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_COLOR_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT"/>
+ <enum bitpos="26" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_DEPTH_STENCIL_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT"/>
+ <enum bitpos="3" extends="VkDependencyFlagBits" name="VK_DEPENDENCY_FEEDBACK_LOOP_BIT_EXT" comment="Dependency may be a feedback loop"/>
+ <type name="VkPhysicalDeviceAttachmentFeedbackLoopLayoutFeaturesEXT"/>
</require>
</extension>
- <extension name="VK_EXT_4444_formats" number="341" type="device" requires="VK_KHR_get_physical_device_properties2" author="EXT" contact="Joshua Ashton @Joshua-Ashton" supported="vulkan">
+ <extension name="VK_EXT_4444_formats" number="341" type="device" requires="VK_KHR_get_physical_device_properties2" author="EXT" contact="Joshua Ashton @Joshua-Ashton" supported="vulkan" promotedto="VK_VERSION_1_3">
<require>
+ <comment>
+ VkPhysicalDevice4444FormatsFeaturesEXT and
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT
+ were not promoted to Vulkan 1.3.
+ </comment>
<enum value="1" name="VK_EXT_4444_FORMATS_SPEC_VERSION"/>
<enum value="&quot;VK_EXT_4444_formats&quot;" name="VK_EXT_4444_FORMATS_EXTENSION_NAME"/>
<enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT"/>
- <enum offset="0" extends="VkFormat" name="VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT"/>
- <enum offset="1" extends="VkFormat" name="VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT"/>
+ <enum extends="VkFormat" name="VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT" alias="VK_FORMAT_A4R4G4B4_UNORM_PACK16"/>
+ <enum extends="VkFormat" name="VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT" alias="VK_FORMAT_A4B4G4R4_UNORM_PACK16"/>
<type name="VkPhysicalDevice4444FormatsFeaturesEXT"/>
</require>
</extension>
- <extension name="VK_EXT_extension_342" number="342" author="EXT" contact="Ralph Potter gitlab:@r_potter" supported="disabled">
+ <extension name="VK_EXT_device_fault" number="342" type="device" requires="VK_KHR_get_physical_device_properties2" author="EXT" contact="Ralph Potter gitlab:@r_potter" supported="vulkan">
<require>
- <enum value="0" name="VK_EXT_EXTENSION_342_SPEC_VERSION"/>
- <enum value="&quot;VK_EXT_extension_342&quot;" name="VK_EXT_EXTENSION_342_EXTENSION_NAME"/>
+ <enum value="1" name="VK_EXT_DEVICE_FAULT_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_device_fault&quot;" name="VK_EXT_DEVICE_FAULT_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEVICE_FAULT_COUNTS_EXT"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEVICE_FAULT_INFO_EXT"/>
+ <type name="VkPhysicalDeviceFaultFeaturesEXT"/>
+ <type name="VkDeviceFaultCountsEXT"/>
+ <type name="VkDeviceFaultInfoEXT"/>
+ <type name="VkDeviceFaultAddressInfoEXT"/>
+ <type name="VkDeviceFaultAddressTypeEXT"/>
+ <type name="VkDeviceFaultVendorInfoEXT"/>
+ <type name="VkDeviceFaultVendorBinaryHeaderVersionEXT"/>
+ <type name="VkDeviceFaultVendorBinaryHeaderVersionOneEXT"/>
+ <command name="vkGetDeviceFaultInfoEXT"/>
</require>
</extension>
- <extension name="VK_ARM_extension_343" number="343" author="ARM" contact="Jan-Harald Fredriksen @janharaldfredriksen-arm" supported="disabled">
+ <extension name="VK_ARM_rasterization_order_attachment_access" number="343" type="device" requires="VK_KHR_get_physical_device_properties2" author="ARM" contact="Jan-Harald Fredriksen @janharaldfredriksen-arm" supported="vulkan" promotedto="VK_EXT_rasterization_order_attachment_access">
<require>
- <enum value="0" name="VK_ARM_EXTENSION_343_SPEC_VERSION"/>
- <enum value="&quot;VK_ARM_extension_343&quot;" name="VK_ARM_EXTENSION_343_EXTENSION_NAME"/>
+ <enum value="1" name="VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_SPEC_VERSION"/>
+ <enum value="&quot;VK_ARM_rasterization_order_attachment_access&quot;" name="VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_ARM" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT"/>
+ <type name="VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesARM"/>
+ <enum extends="VkPipelineColorBlendStateCreateFlagBits" name="VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_ARM" alias="VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_EXT"/>
+ <enum extends="VkPipelineDepthStencilStateCreateFlagBits" name="VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_ARM" alias="VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_EXT"/>
+ <enum extends="VkPipelineDepthStencilStateCreateFlagBits" name="VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_ARM" alias="VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_EXT"/>
+ <enum extends="VkSubpassDescriptionFlagBits" name="VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_ARM" alias="VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_EXT"/>
+ <enum extends="VkSubpassDescriptionFlagBits" name="VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_ARM" alias="VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_EXT"/>
+ <enum extends="VkSubpassDescriptionFlagBits" name="VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_ARM" alias="VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_EXT"/>
</require>
</extension>
<extension name="VK_ARM_extension_344" number="344" author="ARM" contact="Jan-Harald Fredriksen @janharaldfredriksen-arm" supported="disabled">
@@ -16118,10 +19466,12 @@ typedef void <name>CAMetalLayer</name>;
<enum value="&quot;VK_ARM_extension_344&quot;" name="VK_ARM_EXTENSION_344_EXTENSION_NAME"/>
</require>
</extension>
- <extension name="VK_ARM_extension_345" number="345" author="ARM" contact="Jan-Harald Fredriksen @janharaldfredriksen-arm" supported="disabled">
- <require>
- <enum value="0" name="VK_ARM_EXTENSION_345_SPEC_VERSION"/>
- <enum value="&quot;VK_ARM_extension_345&quot;" name="VK_ARM_EXTENSION_345_EXTENSION_NAME"/>
+ <extension name="VK_EXT_rgba10x6_formats" number="345" type="device" requires="VK_KHR_sampler_ycbcr_conversion" author="EXT" contact="Jan-Harald Fredriksen @janharaldfredriksen-arm" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_RGBA10X6_FORMATS_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_rgba10x6_formats&quot;" name="VK_EXT_RGBA10X6_FORMATS_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RGBA10X6_FORMATS_FEATURES_EXT"/>
+ <type name="VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT"/>
</require>
</extension>
<extension name="VK_NV_acquire_winrt_display" number="346" type="device" requires="VK_EXT_direct_mode_display" author="NV" contact="Jeff Juliano @jjuliano" platform="win32" supported="vulkan">
@@ -16155,15 +19505,15 @@ typedef void <name>CAMetalLayer</name>;
<enum value="&quot;VK_NV_extension_351&quot;" name="VK_NV_EXTENSION_351_EXTENSION_NAME"/>
</require>
</extension>
- <extension name="VK_VALVE_mutable_descriptor_type" number="352" type="device" supported="vulkan" author="VALVE" contact="Joshua Ashton @Joshua-Ashton,Hans-Kristian Arntzen @HansKristian-Work" specialuse="d3demulation" requires="VK_KHR_maintenance3">
+ <extension name="VK_VALVE_mutable_descriptor_type" number="352" type="device" supported="vulkan" author="VALVE" contact="Joshua Ashton @Joshua-Ashton,Hans-Kristian Arntzen @HansKristian-Work" specialuse="d3demulation" requires="VK_KHR_maintenance3" promotedto="VK_EXT_mutable_descriptor_type">
<require>
<enum value="1" name="VK_VALVE_MUTABLE_DESCRIPTOR_TYPE_SPEC_VERSION"/>
<enum value="&quot;VK_VALVE_mutable_descriptor_type&quot;" name="VK_VALVE_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME"/>
- <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_VALVE"/>
- <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_VALVE"/>
- <enum offset="0" extends="VkDescriptorType" name="VK_DESCRIPTOR_TYPE_MUTABLE_VALVE"/>
- <enum bitpos="2" extends="VkDescriptorPoolCreateFlagBits" name="VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_VALVE"/>
- <enum bitpos="2" extends="VkDescriptorSetLayoutCreateFlagBits" name="VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_VALVE"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_VALVE" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_VALVE" alias="VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT"/>
+ <enum extends="VkDescriptorType" name="VK_DESCRIPTOR_TYPE_MUTABLE_VALVE" alias="VK_DESCRIPTOR_TYPE_MUTABLE_EXT"/>
+ <enum extends="VkDescriptorPoolCreateFlagBits" name="VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_VALVE" alias="VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_EXT"/>
+ <enum extends="VkDescriptorSetLayoutCreateFlagBits" name="VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_VALVE" alias="VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_EXT"/>
<type name="VkPhysicalDeviceMutableDescriptorTypeFeaturesVALVE"/>
<type name="VkMutableDescriptorTypeListVALVE"/>
<type name="VkMutableDescriptorTypeCreateInfoVALVE"/>
@@ -16193,22 +19543,36 @@ typedef void <name>CAMetalLayer</name>;
<type name="VkPhysicalDeviceDrmPropertiesEXT"/>
</require>
</extension>
- <extension name="VK_EXT_extension_355" number="355" author="EXT" contact="Ralph Potter gitlab:@r_potter" supported="disabled">
+ <extension name="VK_EXT_device_address_binding_report" number="355" type="device" requires="VK_KHR_get_physical_device_properties2,VK_EXT_debug_utils" author="EXT" contact="Ralph Potter gitlab:@r_potter" specialuse="debugging,devtools" supported="vulkan">
<require>
- <enum value="0" name="VK_EXT_EXTENSION_355_SPEC_VERSION"/>
- <enum value="&quot;VK_EXT_extension_355&quot;" name="VK_EXT_EXTENSION_355_EXTENSION_NAME"/>
+ <enum value="1" name="VK_EXT_DEVICE_ADDRESS_BINDING_REPORT_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_device_address_binding_report&quot;" name="VK_EXT_DEVICE_ADDRESS_BINDING_REPORT_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ADDRESS_BINDING_REPORT_FEATURES_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEVICE_ADDRESS_BINDING_CALLBACK_DATA_EXT"/>
+ <enum bitpos="3" extends="VkDebugUtilsMessageTypeFlagBitsEXT" name="VK_DEBUG_UTILS_MESSAGE_TYPE_DEVICE_ADDRESS_BINDING_BIT_EXT"/>
+ <type name="VkPhysicalDeviceAddressBindingReportFeaturesEXT" />
+ <type name="VkDeviceAddressBindingCallbackDataEXT" />
+ <type name="VkDeviceAddressBindingFlagsEXT" />
+ <type name="VkDeviceAddressBindingFlagBitsEXT" />
+ <type name="VkDeviceAddressBindingTypeEXT" />
</require>
</extension>
- <extension name="VK_EXT_vertex_attribute_aliasing" number="356" type="device" author="EXT" contact="Shahbaz Youssefi @syoussefi" supported="disabled" specialuse="glemulation">
+ <extension name="VK_EXT_depth_clip_control" number="356" type="device" requires="VK_KHR_get_physical_device_properties2" author="EXT" contact="Shahbaz Youssefi @syoussefi" supported="vulkan" specialuse="glemulation">
<require>
- <enum value="0" name="VK_EXT_VERTEX_ATTRIBUTE_ALIASING_SPEC_VERSION"/>
- <enum value="&quot;VK_EXT_vertex_attribute_aliasing&quot;" name="VK_EXT_VERTEX_ATTRIBUTE_ALIASING_EXTENSION_NAME"/>
+ <enum value="1" name="VK_EXT_DEPTH_CLIP_CONTROL_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_depth_clip_control&quot;" name="VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_DEPTH_CLIP_CONTROL_CREATE_INFO_EXT"/>
+ <type name="VkPhysicalDeviceDepthClipControlFeaturesEXT"/>
+ <type name="VkPipelineViewportDepthClipControlCreateInfoEXT"/>
</require>
</extension>
- <extension name="VK_EXT_extension_357" number="357" author="EXT" contact="Courtney Goeltzenleuchter @courtney-g" supported="disabled" specialuse="glemulation">
+ <extension name="VK_EXT_primitive_topology_list_restart" number="357" type="device" author="EXT" contact="Shahbaz Youssefi @syoussefi" supported="vulkan" specialuse="glemulation">
<require>
- <enum value="0" name="VK_EXT_EXTENSION_357"/>
- <enum value="&quot;VK_EXT_extension_357&quot;" name="VK_EXT_EXTENSION_357"/>
+ <enum value="1" name="VK_EXT_PRIMITIVE_TOPOLOGY_LIST_RESTART_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_primitive_topology_list_restart&quot;" name="VK_EXT_PRIMITIVE_TOPOLOGY_LIST_RESTART_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT"/>
+ <type name="VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT"/>
</require>
</extension>
<extension name="VK_KHR_extension_358" number="358" author="KHR" contact="Jeff Bolz @jeffbolznv" supported="disabled">
@@ -16219,20 +19583,24 @@ typedef void <name>CAMetalLayer</name>;
</extension>
<extension name="VK_EXT_extension_359" number="359" author="EXT" contact="Bill Hollings @billhollings" supported="disabled" specialuse="glemulation">
<require>
- <enum value="0" name="VK_EXT_EXTENSION_359"/>
- <enum value="&quot;VK_EXT_extension_359&quot;" name="VK_EXT_EXTENSION_359"/>
+ <enum value="0" name="VK_EXT_EXTENSION_359_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_359&quot;" name="VK_EXT_EXTENSION_359_EXTENSION_NAME"/>
</require>
</extension>
<extension name="VK_EXT_extension_360" number="360" author="EXT" contact="Bill Hollings @billhollings" supported="disabled" specialuse="glemulation">
<require>
- <enum value="0" name="VK_EXT_EXTENSION_360"/>
- <enum value="&quot;VK_EXT_extension_360&quot;" name="VK_EXT_EXTENSION_360"/>
+ <enum value="0" name="VK_EXT_EXTENSION_360_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_360&quot;" name="VK_EXT_EXTENSION_360_EXTENSION_NAME"/>
</require>
</extension>
- <extension name="VK_KHR_extension_361" number="361" author="KHR" contact="Lionel Landwerlin @llandwerlin" supported="disabled">
+ <extension name="VK_KHR_format_feature_flags2" number="361" author="KHR" type="device" requires="VK_KHR_get_physical_device_properties2" contact="Lionel Landwerlin @llandwerlin" supported="vulkan" promotedto="VK_VERSION_1_3">
<require>
- <enum value="0" name="VK_EXT_EXTENSION_361"/>
- <enum value="&quot;VK_EXT_extension_361&quot;" name="VK_EXT_EXTENSION_361"/>
+ <enum value="2" name="VK_KHR_FORMAT_FEATURE_FLAGS_2_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_format_feature_flags2&quot;" name="VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3_KHR" alias="VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_3"/>
+ <type name="VkFormatFeatureFlags2KHR"/>
+ <type name="VkFormatFeatureFlagBits2KHR"/>
+ <type name="VkFormatProperties3KHR"/>
</require>
</extension>
<extension name="VK_EXT_extension_362" number="362" author="EXT" contact="Lionel Duc @nvlduc" supported="disabled">
@@ -16249,8 +19617,8 @@ typedef void <name>CAMetalLayer</name>;
</extension>
<extension name="VK_FUCHSIA_extension_364" number="364" author="FUCHSIA" contact="Craig Stout @cdotstout" supported="disabled">
<require>
- <enum value="0" name="VK_EXT_EXTENSION_364_SPEC_VERSION"/>
- <enum value="&quot;VK_EXT_extension_364&quot;" name="VK_EXT_EXTENSION_364_EXTENSION_NAME"/>
+ <enum value="0" name="VK_FUCHSIA_EXTENSION_364_SPEC_VERSION"/>
+ <enum value="&quot;VK_FUCHSIA_extension_364&quot;" name="VK_FUCHSIA_EXTENSION_364_EXTENSION_NAME"/>
</require>
</extension>
<extension name="VK_FUCHSIA_external_memory" number="365" type="device" requires="VK_KHR_external_memory_capabilities,VK_KHR_external_memory" author="FUCHSIA" contact="John Rosasco @rosasco" platform="fuchsia" supported="vulkan">
@@ -16281,16 +19649,47 @@ typedef void <name>CAMetalLayer</name>;
<command name="vkGetSemaphoreZirconHandleFUCHSIA"/>
</require>
</extension>
- <extension name="VK_FUCHSIA_extension_367" number="367" author="FUCHSIA" contact="Craig Stout @cdotstout" supported="disabled">
- <require>
- <enum value="0" name="VK_EXT_EXTENSION_367_SPEC_VERSION"/>
- <enum value="&quot;VK_EXT_extension_367&quot;" name="VK_EXT_EXTENSION_367_EXTENSION_NAME"/>
+ <extension name="VK_FUCHSIA_buffer_collection" number="367" type="device" requires="VK_FUCHSIA_external_memory,VK_KHR_sampler_ycbcr_conversion" author="FUCHSIA" contact="John Rosasco @rosasco" supported="vulkan" platform="fuchsia">
+ <require>
+ <enum value="2" name="VK_FUCHSIA_BUFFER_COLLECTION_SPEC_VERSION"/>
+ <enum value="&quot;VK_FUCHSIA_buffer_collection&quot;" name="VK_FUCHSIA_BUFFER_COLLECTION_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_BUFFER_COLLECTION_CREATE_INFO_FUCHSIA"/>
+ <enum offset="0" extends="VkObjectType" name="VK_OBJECT_TYPE_BUFFER_COLLECTION_FUCHSIA" comment="VkBufferCollectionFUCHSIA"/>
+ <enum offset="0" extends="VkDebugReportObjectTypeEXT" name="VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_COLLECTION_FUCHSIA_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMPORT_MEMORY_BUFFER_COLLECTION_FUCHSIA"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_BUFFER_COLLECTION_IMAGE_CREATE_INFO_FUCHSIA"/>
+ <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_BUFFER_COLLECTION_PROPERTIES_FUCHSIA"/>
+ <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_BUFFER_CONSTRAINTS_INFO_FUCHSIA"/>
+ <enum offset="5" extends="VkStructureType" name="VK_STRUCTURE_TYPE_BUFFER_COLLECTION_BUFFER_CREATE_INFO_FUCHSIA"/>
+ <enum offset="6" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_CONSTRAINTS_INFO_FUCHSIA"/>
+ <enum offset="7" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_FORMAT_CONSTRAINTS_INFO_FUCHSIA"/>
+ <enum offset="8" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SYSMEM_COLOR_SPACE_FUCHSIA"/>
+ <enum offset="9" extends="VkStructureType" name="VK_STRUCTURE_TYPE_BUFFER_COLLECTION_CONSTRAINTS_INFO_FUCHSIA"/>
+ <type name="VkBufferCollectionFUCHSIA"/>
+ <type name="VkBufferCollectionCreateInfoFUCHSIA"/>
+ <type name="VkImportMemoryBufferCollectionFUCHSIA"/>
+ <type name="VkBufferCollectionImageCreateInfoFUCHSIA"/>
+ <type name="VkBufferConstraintsInfoFUCHSIA"/>
+ <type name="VkBufferCollectionBufferCreateInfoFUCHSIA"/>
+ <type name="VkBufferCollectionPropertiesFUCHSIA"/>
+ <type name="VkImageFormatConstraintsFlagsFUCHSIA" comment="Will add VkImageFormatConstraintsFlagBitsFUCHSIA when bits are defined in the future"/>
+ <type name="VkSysmemColorSpaceFUCHSIA"/>
+ <type name="VkImageConstraintsInfoFlagBitsFUCHSIA"/>
+ <type name="VkImageConstraintsInfoFlagsFUCHSIA"/>
+ <type name="VkImageConstraintsInfoFUCHSIA"/>
+ <type name="VkImageFormatConstraintsInfoFUCHSIA"/>
+ <type name="VkBufferCollectionConstraintsInfoFUCHSIA"/>
+ <command name="vkCreateBufferCollectionFUCHSIA"/>
+ <command name="vkSetBufferCollectionImageConstraintsFUCHSIA"/>
+ <command name="vkSetBufferCollectionBufferConstraintsFUCHSIA"/>
+ <command name="vkDestroyBufferCollectionFUCHSIA"/>
+ <command name="vkGetBufferCollectionPropertiesFUCHSIA"/>
</require>
</extension>
<extension name="VK_FUCHSIA_extension_368" number="368" author="FUCHSIA" contact="Craig Stout @cdotstout" supported="disabled">
<require>
- <enum value="0" name="VK_EXT_EXTENSION_368_SPEC_VERSION"/>
- <enum value="&quot;VK_EXT_extension_368&quot;" name="VK_EXT_EXTENSION_368_EXTENSION_NAME"/>
+ <enum value="0" name="VK_FUCHSIA_EXTENSION_368_SPEC_VERSION"/>
+ <enum value="&quot;VK_FUCHSIA_extension_368&quot;" name="VK_FUCHSIA_EXTENSION_368_EXTENSION_NAME"/>
</require>
</extension>
<extension name="VK_QCOM_extension_369" number="369" author="QCOM" contact="Matthew Netsch @mnetsch" supported="disabled">
@@ -16300,7 +19699,7 @@ typedef void <name>CAMetalLayer</name>;
<enum bitpos="4" extends="VkDescriptorBindingFlagBits" name="VK_DESCRIPTOR_BINDING_RESERVED_4_BIT_QCOM"/>
</require>
</extension>
- <extension name="VK_HUAWEI_subpass_shading" number="370" type="device" author="HUAWEI" contact="Hueilong Wang @wyvernathuawei" requires="VK_KHR_create_renderpass2,VK_KHR_synchronization2" supported="vulkan">
+ <extension name="VK_HUAWEI_subpass_shading" number="370" type="device" author="HUAWEI" contact="Pan Gao @PanGao-h" requires="VK_KHR_create_renderpass2,VK_KHR_synchronization2" supported="vulkan">
<require>
<enum value="2" name="VK_HUAWEI_SUBPASS_SHADING_SPEC_VERSION"/>
<enum value="&quot;VK_HUAWEI_subpass_shading&quot;" name="VK_HUAWEI_SUBPASS_SHADING_EXTENSION_NAME"/>
@@ -16308,7 +19707,7 @@ typedef void <name>CAMetalLayer</name>;
<enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_FEATURES_HUAWEI"/>
<enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_PROPERTIES_HUAWEI"/>
<enum offset="3" extends="VkPipelineBindPoint" extnumber="370" name="VK_PIPELINE_BIND_POINT_SUBPASS_SHADING_HUAWEI"/>
- <enum bitpos="39" extends="VkPipelineStageFlagBits2KHR" name="VK_PIPELINE_STAGE_2_SUBPASS_SHADING_BIT_HUAWEI"/>
+ <enum bitpos="39" extends="VkPipelineStageFlagBits2" name="VK_PIPELINE_STAGE_2_SUBPASS_SHADING_BIT_HUAWEI"/>
<enum bitpos="14" extends="VkShaderStageFlagBits" name="VK_SHADER_STAGE_SUBPASS_SHADING_BIT_HUAWEI"/>
<type name="VkSubpassShadingPipelineCreateInfoHUAWEI"/>
<type name="VkPhysicalDeviceSubpassShadingFeaturesHUAWEI"/>
@@ -16317,14 +19716,14 @@ typedef void <name>CAMetalLayer</name>;
<command name="vkCmdSubpassShadingHUAWEI"/>
</require>
</extension>
- <extension name="VK_HUAWEI_invocation_mask" number="371" type="device" requires="VK_KHR_ray_tracing_pipeline,VK_KHR_synchronization2" author="Huawei" contact="Yunpeng Zhu @yunxingzhu" supported="vulkan">
+ <extension name="VK_HUAWEI_invocation_mask" number="371" type="device" requires="VK_KHR_ray_tracing_pipeline,VK_KHR_synchronization2" author="Huawei" contact="Pan Gao @PanGao-h" supported="vulkan">
<require>
<enum value="1" name="VK_HUAWEI_INVOCATION_MASK_SPEC_VERSION"/>
<enum value="&quot;VK_HUAWEI_invocation_mask&quot;" name="VK_HUAWEI_INVOCATION_MASK_EXTENSION_NAME"/>
<enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INVOCATION_MASK_FEATURES_HUAWEI"/>
- <enum bitpos="39" extends="VkAccessFlagBits2KHR" name="VK_ACCESS_2_INVOCATION_MASK_READ_BIT_HUAWEI"/>
+ <enum bitpos="39" extends="VkAccessFlagBits2" name="VK_ACCESS_2_INVOCATION_MASK_READ_BIT_HUAWEI"/>
<enum bitpos="18" extends="VkImageUsageFlagBits" name="VK_IMAGE_USAGE_INVOCATION_MASK_BIT_HUAWEI"/>
- <enum bitpos="40" extends="VkPipelineStageFlagBits2KHR" name="VK_PIPELINE_STAGE_2_INVOCATION_MASK_BIT_HUAWEI"/>
+ <enum bitpos="40" extends="VkPipelineStageFlagBits2" name="VK_PIPELINE_STAGE_2_INVOCATION_MASK_BIT_HUAWEI"/>
<type name="VkPhysicalDeviceInvocationMaskFeaturesHUAWEI"/>
<command name="vkCmdBindInvocationMaskHUAWEI"/>
</require>
@@ -16343,10 +19742,17 @@ typedef void <name>CAMetalLayer</name>;
<command name="vkGetMemoryRemoteAddressNV"/>
</require>
</extension>
- <extension name="VK_NV_extension_373" number="373" author="NV" contact="Daniel Koch @dgkoch" supported="disabled">
+ <extension name="VK_EXT_pipeline_properties" number="373" type="device" requires="VK_KHR_get_physical_device_properties2" author="EXT" contact="Mukund Keshava @mkeshavanv" supported="vulkan">
<require>
- <enum value="0" name="VK_NV_EXTENSION_373_SPEC_VERSION"/>
- <enum value="&quot;VK_NV_extension_373&quot;" name="VK_NV_EXTENSION_373_EXTENSION_NAME"/>
+ <enum value="1" name="VK_EXT_PIPELINE_PROPERTIES_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_pipeline_properties&quot;" name="VK_EXT_PIPELINE_PROPERTIES_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_PROPERTIES_IDENTIFIER_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROPERTIES_FEATURES_EXT"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_INFO_EXT" alias="VK_STRUCTURE_TYPE_PIPELINE_INFO_KHR"/>
+ <type name="VkPipelineInfoEXT"/>
+ <type name="VkPipelinePropertiesIdentifierEXT"/>
+ <type name="VkPhysicalDevicePipelinePropertiesFeaturesEXT"/>
+ <command name="vkGetPipelinePropertiesEXT"/>
</require>
</extension>
<extension name="VK_NV_extension_374" number="374" author="NV" contact="Daniel Koch @dgkoch" supported="disabled">
@@ -16356,7 +19762,6 @@ typedef void <name>CAMetalLayer</name>;
<enum bitpos="4" extends="VkExternalFenceHandleTypeFlagBits" name="VK_EXTERNAL_FENCE_HANDLE_TYPE_RESERVED_4_BIT_NV"/>
<enum bitpos="5" extends="VkExternalFenceHandleTypeFlagBits" name="VK_EXTERNAL_FENCE_HANDLE_TYPE_RESERVED_5_BIT_NV"/>
<enum bitpos="5" extends="VkExternalSemaphoreHandleTypeFlagBits" name="VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_RESERVED_5_BIT_NV"/>
- <enum bitpos="6" extends="VkExternalSemaphoreHandleTypeFlagBits" name="VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_RESERVED_6_BIT_NV"/>
</require>
</extension>
<extension name="VK_NV_extension_375" number="375" author="NV" contact="Daniel Koch @dgkoch" supported="disabled">
@@ -16366,33 +19771,40 @@ typedef void <name>CAMetalLayer</name>;
<enum bitpos="13" extends="VkExternalMemoryHandleTypeFlagBits" name="VK_EXTERNAL_MEMORY_HANDLE_TYPE_RESERVED_13_BIT_NV"/>
</require>
</extension>
- <extension name="VK_EXT_extension_376" number="376" author="EXT" contact="Shahbaz Youssefi @syoussefi" supported="disabled">
+ <extension name="VK_EXT_extension_376" number="376" author="EXT" contact="Melih Yasin Yalcin @yalcinmelihyasin" supported="disabled">
<require>
<enum value="0" name="VK_EXT_EXTENSION_376_SPEC_VERSION"/>
<enum value="&quot;VK_EXT_extension_376&quot;" name="VK_EXT_EXTENSION_376_EXTENSION_NAME"/>
</require>
</extension>
- <extension name="VK_EXT_extension_377" number="377" author="EXT" contact="Hugues Evrard @hevrard" supported="disabled">
+ <extension name="VK_EXT_multisampled_render_to_single_sampled" number="377" type="device" requires="VK_KHR_create_renderpass2,VK_KHR_depth_stencil_resolve" author="EXT" contact="Shahbaz Youssefi @syoussefi" supported="vulkan">
<require>
- <enum value="0" name="VK_EXT_EXTENSION_377_SPEC_VERSION"/>
- <enum value="&quot;VK_EXT_extension_377&quot;" name="VK_EXT_EXTENSION_377_EXTENSION_NAME"/>
+ <enum value="1" name="VK_EXT_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_multisampled_render_to_single_sampled&quot;" name="VK_EXT_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_FEATURES_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SUBPASS_RESOLVE_PERFORMANCE_QUERY_EXT"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_INFO_EXT"/>
+ <enum bitpos="18" extends="VkImageCreateFlagBits" name="VK_IMAGE_CREATE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_BIT_EXT"/>
+ <type name="VkPhysicalDeviceMultisampledRenderToSingleSampledFeaturesEXT"/>
+ <type name="VkSubpassResolvePerformanceQueryEXT"/>
+ <type name="VkMultisampledRenderToSingleSampledInfoEXT"/>
</require>
</extension>
- <extension name="VK_EXT_extended_dynamic_state2" number="378" type="device" requires="VK_KHR_get_physical_device_properties2" author="EXT" contact="Vikram Kushwaha @vkushwaha-nv" supported="vulkan">
+ <extension name="VK_EXT_extended_dynamic_state2" number="378" type="device" requires="VK_KHR_get_physical_device_properties2" author="EXT" contact="Vikram Kushwaha @vkushwaha-nv" supported="vulkan" promotedto="VK_VERSION_1_3">
<require>
<enum value="1" name="VK_EXT_EXTENDED_DYNAMIC_STATE_2_SPEC_VERSION"/>
- <enum value="&quot;VK_EXT_extended_dynamic_state2&quot;" name="VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME"/>
- <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT"/>
- <enum offset="0" extends="VkDynamicState" name="VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT"/>
- <enum offset="1" extends="VkDynamicState" name="VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT"/>
- <enum offset="2" extends="VkDynamicState" name="VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE_EXT"/>
- <enum offset="3" extends="VkDynamicState" name="VK_DYNAMIC_STATE_LOGIC_OP_EXT"/>
- <enum offset="4" extends="VkDynamicState" name="VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT"/>
- <type name="VkPhysicalDeviceExtendedDynamicState2FeaturesEXT"/>
- <command name="vkCmdSetPatchControlPointsEXT"/>
+ <enum value="&quot;VK_EXT_extended_dynamic_state2&quot;" name="VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT" comment="Not promoted to 1.3"/>
+ <enum offset="0" extends="VkDynamicState" name="VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT" comment="Not promoted to 1.3"/>
+ <enum extends="VkDynamicState" name="VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT" alias="VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE"/>
+ <enum extends="VkDynamicState" name="VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE_EXT" alias="VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE"/>
+ <enum offset="3" extends="VkDynamicState" name="VK_DYNAMIC_STATE_LOGIC_OP_EXT" comment="Not promoted to 1.3"/>
+ <enum extends="VkDynamicState" name="VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT" alias="VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE"/>
+ <type name="VkPhysicalDeviceExtendedDynamicState2FeaturesEXT" comment="Not promoted to 1.3"/>
+ <command name="vkCmdSetPatchControlPointsEXT" comment="Not promoted to 1.3"/>
<command name="vkCmdSetRasterizerDiscardEnableEXT"/>
<command name="vkCmdSetDepthBiasEnableEXT"/>
- <command name="vkCmdSetLogicOpEXT"/>
+ <command name="vkCmdSetLogicOpEXT" comment="Not promoted to 1.3"/>
<command name="vkCmdSetPrimitiveRestartEnableEXT"/>
</require>
</extension>
@@ -16431,10 +19843,13 @@ typedef void <name>CAMetalLayer</name>;
<command name="vkCmdSetColorWriteEnableEXT"/>
</require>
</extension>
- <extension name="VK_EXT_extension_383" number="383" author="EXT" contact="Shahbaz Youssefi @syoussefi" supported="disabled">
+ <extension name="VK_EXT_primitives_generated_query" number="383" type="device" requires="VK_EXT_transform_feedback" author="EXT" contact="Shahbaz Youssefi @syoussefi" supported="vulkan" specialuse="glemulation">
<require>
- <enum value="0" name="VK_EXT_EXTENSION_383_SPEC_VERSION"/>
- <enum value="&quot;VK_EXT_extension_383&quot;" name="VK_EXT_EXTENSION_383_EXTENSION_NAME"/>
+ <enum value="1" name="VK_EXT_PRIMITIVES_GENERATED_QUERY_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_primitives_generated_query&quot;" name="VK_EXT_PRIMITIVES_GENERATED_QUERY_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT"/>
+ <enum offset="0" extends="VkQueryType" name="VK_QUERY_TYPE_PRIMITIVES_GENERATED_EXT"/>
+ <type name="VkPhysicalDevicePrimitivesGeneratedQueryFeaturesEXT"/>
</require>
</extension>
<extension name="VK_EXT_extension_384" number="384" type="instance" author="EXT" contact="Chia-I Wu @olvaffe1" supported="disabled">
@@ -16455,10 +19870,25 @@ typedef void <name>CAMetalLayer</name>;
<enum value="&quot;VK_GOOGLE_extension_386&quot;" name="VK_GOOGLE_EXTENSION_386_EXTENSION_NAME"/>
</require>
</extension>
- <extension name="VK_KHR_extension_387" number="387" author="KHR" contact="Daniel Koch @dgkoch" supported="disabled">
+ <extension name="VK_KHR_ray_tracing_maintenance1" number="387" type="device" requiresCore="1.1" requires="VK_KHR_acceleration_structure" author="KHR" contact="Daniel Koch @dgkoch" supported="vulkan">
<require>
- <enum value="0" name="VK_KHR_EXTENSION_387_SPEC_VERSION"/>
- <enum value="&quot;VK_KHR_extension_387&quot;" name="VK_KHR_EXTENSION_387_EXTENSION_NAME"/>
+ <enum value="1" name="VK_KHR_RAY_TRACING_MAINTENANCE_1_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_ray_tracing_maintenance1&quot;" name="VK_KHR_RAY_TRACING_MAINTENANCE_1_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_MAINTENANCE_1_FEATURES_KHR"/>
+ <enum offset="0" extends="VkQueryType" name="VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SERIALIZATION_BOTTOM_LEVEL_POINTERS_KHR"/>
+ <enum offset="1" extends="VkQueryType" name="VK_QUERY_TYPE_ACCELERATION_STRUCTURE_SIZE_KHR"/>
+ <type name="VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR"/>
+ </require>
+ <require extension="VK_KHR_synchronization2">
+ <!-- VkPipelineStageFlagBits bitpos="28" is reserved by this extension, but not used -->
+ <enum bitpos="28" extends="VkPipelineStageFlagBits2" name="VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_COPY_BIT_KHR"/>
+ </require>
+ <require extension="VK_KHR_synchronization2+VK_KHR_ray_tracing_pipeline">
+ <enum bitpos="40" extends="VkAccessFlagBits2" name="VK_ACCESS_2_SHADER_BINDING_TABLE_READ_BIT_KHR"/>
+ </require>
+ <require extension="VK_KHR_ray_tracing_pipeline">
+ <type name="VkTraceRaysIndirectCommand2KHR"/>
+ <command name="vkCmdTraceRaysIndirect2KHR"/>
</require>
</extension>
<extension name="VK_EXT_extension_388" number="388" author="EXT" contact="Alan Baker @alan-baker" supported="disabled">
@@ -16467,12 +19897,12 @@ typedef void <name>CAMetalLayer</name>;
<enum value="&quot;VK_EXT_extension_388&quot;" name="VK_EXT_EXTENSION_388_EXTENSION_NAME"/>
</require>
</extension>
- <extension name="VK_EXT_global_priority_query" number="389" type="device" requires="VK_EXT_global_priority,VK_KHR_get_physical_device_properties2" author="EXT" contact="Yiwei Zhang @zhangyiwei" supported="vulkan">
+ <extension name="VK_EXT_global_priority_query" number="389" type="device" requires="VK_EXT_global_priority,VK_KHR_get_physical_device_properties2" author="EXT" contact="Yiwei Zhang @zhangyiwei" supported="vulkan" promotedto="VK_KHR_global_priority">
<require>
<enum value="1" name="VK_EXT_GLOBAL_PRIORITY_QUERY_SPEC_VERSION"/>
<enum value="&quot;VK_EXT_global_priority_query&quot;" name="VK_EXT_GLOBAL_PRIORITY_QUERY_EXTENSION_NAME"/>
- <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_EXT"/>
- <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_EXT"/>
+ <enum extends="VkStructureType" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_KHR" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GLOBAL_PRIORITY_QUERY_FEATURES_EXT"/>
+ <enum extends="VkStructureType" alias="VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_KHR" name="VK_STRUCTURE_TYPE_QUEUE_FAMILY_GLOBAL_PRIORITY_PROPERTIES_EXT"/>
<enum name="VK_MAX_GLOBAL_PRIORITY_SIZE_EXT"/>
<type name="VkPhysicalDeviceGlobalPriorityQueryFeaturesEXT"/>
<type name="VkQueueFamilyGlobalPriorityPropertiesEXT"/>
@@ -16490,10 +19920,14 @@ typedef void <name>CAMetalLayer</name>;
<enum value="&quot;VK_EXT_extension_391&quot;" name="VK_EXT_EXTENSION_391_EXTENSION_NAME"/>
</require>
</extension>
- <extension name="VK_EXT_extension_392" number="392" author="EXT" contact="Joshua Ashton @Joshua-Ashton" supported="disabled">
+ <extension name="VK_EXT_image_view_min_lod" number="392" type="device" requires="VK_KHR_get_physical_device_properties2" author="EXT" contact="Joshua Ashton @Joshua-Ashton" supported="vulkan">
<require>
- <enum value="0" name="VK_EXT_EXTENSION_392_SPEC_VERSION"/>
- <enum value="&quot;VK_EXT_extension_392&quot;" name="VK_EXT_EXTENSION_392_EXTENSION_NAME"/>
+ <enum value="1" name="VK_EXT_IMAGE_VIEW_MIN_LOD_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_image_view_min_lod&quot;" name="VK_EXT_IMAGE_VIEW_MIN_LOD_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_MIN_LOD_FEATURES_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_VIEW_MIN_LOD_CREATE_INFO_EXT"/>
+ <type name="VkPhysicalDeviceImageViewMinLodFeaturesEXT"/>
+ <type name="VkImageViewMinLodCreateInfoEXT"/>
</require>
</extension>
<extension name="VK_EXT_multi_draw" number="393" author="EXT" contact="Mike Blumenkrantz @zmike" type="device" supported="vulkan">
@@ -16510,16 +19944,20 @@ typedef void <name>CAMetalLayer</name>;
<type name="VkMultiDrawIndexedInfoEXT"/>
</require>
</extension>
- <extension name="VK_EXT_extension_394" number="394" author="EXT" contact="Mike Blumenkrantz @zmike" type="device" supported="disabled">
+ <extension name="VK_EXT_image_2d_view_of_3d" number="394" requires="VK_KHR_maintenance1,VK_KHR_get_physical_device_properties2" author="EXT" contact="Mike Blumenkrantz @zmike" specialuse="glemulation" type="device" supported="vulkan">
<require>
- <enum value="0" name="VK_EXT_EXTENSION_394_SPEC_VERSION"/>
- <enum value="&quot;VK_EXT_extension_394&quot;" name="VK_EXT_EXTENSION_394_EXTENSION_NAME"/>
+ <enum value="1" name="VK_EXT_IMAGE_2D_VIEW_OF_3D_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_image_2d_view_of_3d&quot;" name="VK_EXT_IMAGE_2D_VIEW_OF_3D_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_2D_VIEW_OF_3D_FEATURES_EXT"/>
+ <type name="VkPhysicalDeviceImage2DViewOf3DFeaturesEXT"/>
+ <enum extends="VkImageCreateFlagBits" bitpos="17" name="VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT" comment="Image is created with a layout where individual slices are capable of being used as 2D images"/>
</require>
</extension>
- <extension name="VK_KHR_extension_395" number="395" author="KHR" contact="Lenny Komow @lkomow" supported="disabled">
+ <extension name="VK_KHR_portability_enumeration" number="395" author="KHR" contact="Charles Giessen @charles-lunarg" type="instance" supported="vulkan">
<require>
- <enum value="0" name="VK_KHR_EXTENSION_395_SPEC_VERSION"/>
- <enum value="&quot;VK_KHR_extension_395&quot;" name="VK_KHR_EXTENSION_395_EXTENSION_NAME"/>
+ <enum value="1" name="VK_KHR_PORTABILITY_ENUMERATION_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_portability_enumeration&quot;" name="VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME"/>
+ <enum bitpos="0" extends="VkInstanceCreateFlagBits" name="VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR"/>
</require>
</extension>
<extension name="VK_KHR_extension_396" number="396" author="EXT" contact="Jan-Harald Fredriksen @janharaldfredriksen-arm" supported="disabled">
@@ -16528,16 +19966,79 @@ typedef void <name>CAMetalLayer</name>;
<enum value="&quot;VK_KHR_extension_396&quot;" name="VK_KHR_EXTENSION_396_EXTENSION_NAME"/>
</require>
</extension>
- <extension name="VK_NV_extension_397" number="397" author="NV" contact="Christoph Kubisch @pixeljetstream" supported="disabled">
- <require>
- <enum value="0" name="VK_NV_EXTENSION_397_SPEC_VERSION"/>
- <enum value="&quot;VK_NV_extension_397&quot;" name="VK_NV_EXTENSION_397_EXTENSION_NAME"/>
- </require>
- </extension>
- <extension name="VK_NV_extension_398" number="398" author="NV" contact="Christoph Kubisch @pixeljetstream" supported="disabled">
+ <extension name="VK_EXT_opacity_micromap" number="397" type="device" requires="VK_KHR_acceleration_structure,VK_KHR_synchronization2" author="EXT" contact="Christoph Kubisch @pixeljetstream, Eric Werness" supported="vulkan">
+ <require>
+ <enum value="2" name="VK_EXT_OPACITY_MICROMAP_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_opacity_micromap&quot;" name="VK_EXT_OPACITY_MICROMAP_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_MICROMAP_BUILD_INFO_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_MICROMAP_VERSION_INFO_EXT"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_COPY_MICROMAP_INFO_EXT"/>
+ <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_COPY_MICROMAP_TO_MEMORY_INFO_EXT"/>
+ <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_COPY_MEMORY_TO_MICROMAP_INFO_EXT"/>
+ <enum offset="5" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_FEATURES_EXT"/>
+ <enum offset="6" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_PROPERTIES_EXT"/>
+ <enum offset="7" extends="VkStructureType" name="VK_STRUCTURE_TYPE_MICROMAP_CREATE_INFO_EXT"/>
+ <enum offset="8" extends="VkStructureType" name="VK_STRUCTURE_TYPE_MICROMAP_BUILD_SIZES_INFO_EXT"/>
+ <enum offset="9" extends="VkStructureType" name="VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_TRIANGLES_OPACITY_MICROMAP_EXT"/>
+ <enum bitpos="30" extends="VkPipelineStageFlagBits2" name="VK_PIPELINE_STAGE_2_MICROMAP_BUILD_BIT_EXT"/>
+ <enum bitpos="44" extends="VkAccessFlagBits2" name="VK_ACCESS_2_MICROMAP_READ_BIT_EXT"/>
+ <enum bitpos="45" extends="VkAccessFlagBits2" name="VK_ACCESS_2_MICROMAP_WRITE_BIT_EXT"/>
+ <enum offset="0" extends="VkQueryType" name="VK_QUERY_TYPE_MICROMAP_SERIALIZATION_SIZE_EXT"/>
+ <enum offset="1" extends="VkQueryType" name="VK_QUERY_TYPE_MICROMAP_COMPACTED_SIZE_EXT"/>
+ <enum offset="0" extends="VkObjectType" name="VK_OBJECT_TYPE_MICROMAP_EXT"/>
+ <enum bitpos="23" extends="VkBufferUsageFlagBits" name="VK_BUFFER_USAGE_MICROMAP_BUILD_INPUT_READ_ONLY_BIT_EXT"/>
+ <enum bitpos="24" extends="VkBufferUsageFlagBits" name="VK_BUFFER_USAGE_MICROMAP_STORAGE_BIT_EXT"/>
+ <enum bitpos="24" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_RAY_TRACING_OPACITY_MICROMAP_BIT_EXT"/>
+ <enum bitpos="4" extends="VkGeometryInstanceFlagBitsKHR" name="VK_GEOMETRY_INSTANCE_FORCE_OPACITY_MICROMAP_2_STATE_EXT"/>
+ <enum bitpos="5" extends="VkGeometryInstanceFlagBitsKHR" name="VK_GEOMETRY_INSTANCE_DISABLE_OPACITY_MICROMAPS_EXT"/>
+ <enum bitpos="6" extends="VkBuildAccelerationStructureFlagBitsKHR" name="VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_OPACITY_MICROMAP_UPDATE_EXT"/>
+ <enum bitpos="7" extends="VkBuildAccelerationStructureFlagBitsKHR" name="VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_DISABLE_OPACITY_MICROMAPS_EXT"/>
+ <enum bitpos="8" extends="VkBuildAccelerationStructureFlagBitsKHR" name="VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_OPACITY_MICROMAP_DATA_UPDATE_EXT"/>
+ <type name="VkMicromapTypeEXT"/>
+ <type name="VkMicromapBuildInfoEXT"/>
+ <type name="VkMicromapUsageEXT"/>
+ <type name="VkMicromapCreateInfoEXT"/>
+ <type name="VkMicromapEXT"/>
+ <type name="VkBuildMicromapFlagBitsEXT"/>
+ <type name="VkBuildMicromapFlagsEXT"/>
+ <type name="VkCopyMicromapModeEXT"/>
+ <type name="VkPhysicalDeviceOpacityMicromapFeaturesEXT"/>
+ <type name="VkPhysicalDeviceOpacityMicromapPropertiesEXT"/>
+ <type name="VkMicromapVersionInfoEXT"/>
+ <type name="VkCopyMicromapToMemoryInfoEXT"/>
+ <type name="VkCopyMemoryToMicromapInfoEXT"/>
+ <type name="VkCopyMicromapInfoEXT"/>
+ <type name="VkMicromapCreateFlagBitsEXT"/>
+ <type name="VkMicromapCreateFlagsEXT"/>
+ <type name="VkBuildMicromapModeEXT"/>
+ <type name="VkMicromapBuildSizesInfoEXT"/>
+ <type name="VkOpacityMicromapFormatEXT"/>
+ <type name="VkAccelerationStructureTrianglesOpacityMicromapEXT"/>
+ <type name="VkMicromapTriangleEXT"/>
+ <type name="VkOpacityMicromapSpecialIndexEXT"/>
+ <command name="vkCreateMicromapEXT"/>
+ <command name="vkDestroyMicromapEXT"/>
+ <command name="vkCmdBuildMicromapsEXT"/>
+ <command name="vkBuildMicromapsEXT"/>
+ <command name="vkCopyMicromapEXT"/>
+ <command name="vkCopyMicromapToMemoryEXT"/>
+ <command name="vkCopyMemoryToMicromapEXT"/>
+ <command name="vkWriteMicromapsPropertiesEXT"/>
+ <command name="vkCmdCopyMicromapEXT"/>
+ <command name="vkCmdCopyMicromapToMemoryEXT"/>
+ <command name="vkCmdCopyMemoryToMicromapEXT"/>
+ <command name="vkCmdWriteMicromapsPropertiesEXT"/>
+ <command name="vkGetDeviceMicromapCompatibilityEXT"/>
+ <command name="vkGetMicromapBuildSizesEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_extension_398" number="398" author="NV" contact="Christoph Kubisch @pixeljetstream, Eric Werness @ewerness-nv" supported="disabled">
<require>
<enum value="0" name="VK_NV_EXTENSION_398_SPEC_VERSION"/>
<enum value="&quot;VK_NV_extension_398&quot;" name="VK_NV_EXTENSION_398_EXTENSION_NAME"/>
+ <enum bitpos="28" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_RESERVED_BIT_28_NV"/>
+ <enum bitpos="9" extends="VkBuildAccelerationStructureFlagBitsKHR" name="VK_BUILD_ACCELERATION_STRUCTURE_RESERVED_BIT_9_NV"/>
+ <enum bitpos="10" extends="VkBuildAccelerationStructureFlagBitsKHR" name="VK_BUILD_ACCELERATION_STRUCTURE_RESERVED_BIT_10_NV"/>
</require>
</extension>
<extension name="VK_JUICE_extension_399" number="399" author="JUICE" contact="Dean Beeler @canadacow" supported="disabled">
@@ -16552,10 +20053,12 @@ typedef void <name>CAMetalLayer</name>;
<enum value="&quot;VK_JUICE_extension_400&quot;" name="VK_JUICE_EXTENSION_400_EXTENSION_NAME"/>
</require>
</extension>
- <extension name="VK_KHR_extension_401" number="401" author="KHR" contact="Shahbaz Youssefi @syoussefi" supported="disabled">
+ <extension name="VK_EXT_load_store_op_none" number="401" author="EXT" type="device" contact="Shahbaz Youssefi @syoussefi" supported="vulkan">
<require>
- <enum value="0" name="VK_KHR_EXTENSION_401_SPEC_VERSION"/>
- <enum value="&quot;VK_KHR_extension_401&quot;" name="VK_KHR_EXTENSION_401_EXTENSION_NAME"/>
+ <enum value="1" name="VK_EXT_LOAD_STORE_OP_NONE_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_load_store_op_none&quot;" name="VK_EXT_LOAD_STORE_OP_NONE_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkAttachmentLoadOp" name="VK_ATTACHMENT_LOAD_OP_NONE_EXT"/>
+ <enum extends="VkAttachmentStoreOp" name="VK_ATTACHMENT_STORE_OP_NONE_EXT" alias="VK_ATTACHMENT_STORE_OP_NONE"/>
</require>
</extension>
<extension name="VK_FB_extension_402" number="402" author="FB" contact="Artem Bolgar @artyom17" supported="disabled">
@@ -16579,7 +20082,9 @@ typedef void <name>CAMetalLayer</name>;
<extension name="VK_HUAWEI_extension_405" number="405" author="HUAWEI" contact="Hueilong Wang @wyvernathuawei" supported="disabled">
<require>
<enum value="0" name="VK_HUAWEI_EXTENSION_405_SPEC_VERSION"/>
- <enum value="&quot;VK_HUAWEI_extension_405&quot;" name="VK_HUAWEI_EXTENSION_405_EXTENSION_NAME"/>
+ <enum value="&quot;VK_HUAWEI_extension_405&quot;" name="VK_HUAWEI_EXTENSION_405_EXTENSION_NAME"/>
+ <enum bitpos="41" extends="VkPipelineStageFlagBits2" name="VK_PIPELINE_STAGE_2_RESEVED_41_BIT_HUAWEI"/>
+ <enum bitpos="19" extends="VkShaderStageFlagBits" name="VK_SHADER_STAGE_RESERVED_19_BIT_HUAWEI"/>
</require>
</extension>
<extension name="VK_HUAWEI_extension_406" number="406" author="HUAWEI" contact="Hueilong Wang @wyvernathuawei" supported="disabled">
@@ -16618,22 +20123,41 @@ typedef void <name>CAMetalLayer</name>;
<enum value="&quot;VK_GGP_extension_411&quot;" name="VK_GGP_EXTENSION_411_EXTENSION_NAME"/>
</require>
</extension>
- <extension name="VK_NV_extension_412" number="412" author="NV" contact="Piers Daniell @pdaniell-nv" supported="disabled">
+ <extension name="VK_EXT_border_color_swizzle" number="412" type="device" author="EXT" contact="Piers Daniell @pdaniell-nv" supported="vulkan" requires="VK_EXT_custom_border_color" specialuse="glemulation,d3demulation">
<require>
- <enum value="0" name="VK_NV_EXTENSION_412_SPEC_VERSION"/>
- <enum value="&quot;VK_NV_extension_412&quot;" name="VK_NV_EXTENSION_412_EXTENSION_NAME"/>
+ <enum value="1" name="VK_EXT_BORDER_COLOR_SWIZZLE_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_border_color_swizzle&quot;" name="VK_EXT_BORDER_COLOR_SWIZZLE_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BORDER_COLOR_SWIZZLE_FEATURES_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SAMPLER_BORDER_COLOR_COMPONENT_MAPPING_CREATE_INFO_EXT"/>
+ <type name="VkPhysicalDeviceBorderColorSwizzleFeaturesEXT"/>
+ <type name="VkSamplerBorderColorComponentMappingCreateInfoEXT"/>
</require>
</extension>
- <extension name="VK_NV_extension_413" number="413" author="NV" contact="Piers Daniell @pdaniell-nv" supported="disabled">
+ <extension name="VK_EXT_pageable_device_local_memory" number="413" author="EXT" contact="Piers Daniell @pdaniell-nv" type="device" requires="VK_EXT_memory_priority" supported="vulkan">
<require>
- <enum value="0" name="VK_NV_EXTENSION_413_SPEC_VERSION"/>
- <enum value="&quot;VK_NV_extension_413&quot;" name="VK_NV_EXTENSION_413_EXTENSION_NAME"/>
+ <enum value="1" name="VK_EXT_PAGEABLE_DEVICE_LOCAL_MEMORY_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_pageable_device_local_memory&quot;" name="VK_EXT_PAGEABLE_DEVICE_LOCAL_MEMORY_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PAGEABLE_DEVICE_LOCAL_MEMORY_FEATURES_EXT"/>
+ <type name="VkPhysicalDevicePageableDeviceLocalMemoryFeaturesEXT"/>
+ <command name="vkSetDeviceMemoryPriorityEXT"/>
</require>
</extension>
- <extension name="VK_NV_extension_414" number="414" author="NV" contact="Piers Daniell @pdaniell-nv" supported="disabled">
+ <extension name="VK_KHR_maintenance4" number="414" type="device" requiresCore="1.1" author="KHR" contact="Piers Daniell @pdaniell-nv" supported="vulkan" promotedto="VK_VERSION_1_3">
<require>
- <enum value="0" name="VK_NV_EXTENSION_414_SPEC_VERSION"/>
- <enum value="&quot;VK_NV_extension_414&quot;" name="VK_NV_EXTENSION_414_EXTENSION_NAME"/>
+ <enum value="2" name="VK_KHR_MAINTENANCE_4_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_maintenance4&quot;" name="VK_KHR_MAINTENANCE_4_EXTENSION_NAME"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_FEATURES"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES_KHR" alias="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS_KHR" alias="VK_STRUCTURE_TYPE_DEVICE_BUFFER_MEMORY_REQUIREMENTS"/>
+ <enum extends="VkStructureType" name="VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS_KHR" alias="VK_STRUCTURE_TYPE_DEVICE_IMAGE_MEMORY_REQUIREMENTS"/>
+ <enum extends="VkImageAspectFlagBits" name="VK_IMAGE_ASPECT_NONE_KHR" alias="VK_IMAGE_ASPECT_NONE"/>
+ <type name="VkPhysicalDeviceMaintenance4FeaturesKHR"/>
+ <type name="VkPhysicalDeviceMaintenance4PropertiesKHR"/>
+ <type name="VkDeviceBufferMemoryRequirementsKHR"/>
+ <type name="VkDeviceImageMemoryRequirementsKHR"/>
+ <command name="vkGetDeviceBufferMemoryRequirementsKHR"/>
+ <command name="vkGetDeviceImageMemoryRequirementsKHR"/>
+ <command name="vkGetDeviceImageSparseMemoryRequirementsKHR"/>
</require>
</extension>
<extension name="VK_HUAWEI_extension_415" number="415" author="HUAWEI" contact="Hueilong Wang @wyvernathuawei" supported="disabled">
@@ -16650,8 +20174,8 @@ typedef void <name>CAMetalLayer</name>;
</extension>
<extension name="VK_KHR_extension_417" number="417" author="KHR" contact="Kevin Petit @kevinpetit" supported="disabled">
<require>
- <enum value="0" name="VK_ARM_EXTENSION_417_SPEC_VERSION"/>
- <enum value="&quot;VK_ARM_extension_417&quot;" name="VK_ARM_EXTENSION_417_EXTENSION_NAME"/>
+ <enum value="0" name="VK_KHR_EXTENSION_417_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_extension_417&quot;" name="VK_KHR_EXTENSION_417_EXTENSION_NAME"/>
</require>
</extension>
<extension name="VK_ARM_extension_418" number="418" author="ARM" contact="Kevin Petit @kevinpetit" supported="disabled">
@@ -16664,25 +20188,2165 @@ typedef void <name>CAMetalLayer</name>;
<require>
<enum value="0" name="VK_EXT_EXTENSION_419_SPEC_VERSION"/>
<enum value="&quot;VK_EXT_extension_419&quot;" name="VK_EXT_EXTENSION_419_EXTENSION_NAME"/>
+ <enum bitpos="3" extends="VkImageViewCreateFlagBits" name="VK_IMAGE_VIEW_CREATE_RESERVED_3_BIT_EXT"/>
</require>
</extension>
<extension name="VK_EXT_extension_420" number="420" author="EXT" contact="Mike Blumenkrantz @zmike" type="device" supported="disabled">
<require>
<enum value="0" name="VK_EXT_EXTENSION_420_SPEC_VERSION"/>
<enum value="&quot;VK_EXT_extension_420&quot;" name="VK_EXT_EXTENSION_420_EXTENSION_NAME"/>
+ <enum bitpos="4" extends="VkSwapchainCreateFlagBitsKHR" name="VK_SWAPCHAIN_CREATE_RESERVED_4_BIT_EXT"/>
</require>
</extension>
- <extension name="VK_KHR_extension_421" number="421" author="KHR" contact="Hans-Kristian Arntzen @HansKristian-Work" supported="disabled">
+ <extension name="VK_VALVE_descriptor_set_host_mapping" number="421" type="device" author="VALVE" contact="Hans-Kristian Arntzen @HansKristian-Work" specialuse="d3demulation" supported="vulkan">
<require>
- <enum value="0" name="VK_KHR_EXTENSION_421_SPEC_VERSION"/>
- <enum value="&quot;VK_KHR_extension_421&quot;" name="VK_KHR_EXTENSION_421_EXTENSION_NAME"/>
+ <enum value="1" name="VK_VALVE_DESCRIPTOR_SET_HOST_MAPPING_SPEC_VERSION"/>
+ <enum value="&quot;VK_VALVE_descriptor_set_host_mapping&quot;" name="VK_VALVE_DESCRIPTOR_SET_HOST_MAPPING_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_SET_HOST_MAPPING_FEATURES_VALVE"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DESCRIPTOR_SET_BINDING_REFERENCE_VALVE"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_HOST_MAPPING_INFO_VALVE"/>
+ <type name="VkPhysicalDeviceDescriptorSetHostMappingFeaturesVALVE"/>
+ <type name="VkDescriptorSetBindingReferenceVALVE"/>
+ <type name="VkDescriptorSetLayoutHostMappingInfoVALVE"/>
+ <command name="vkGetDescriptorSetLayoutHostMappingInfoVALVE"/>
+ <command name="vkGetDescriptorSetHostMappingVALVE"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_depth_clamp_zero_one" number="422" author="EXT" type="device" contact="Graeme Leese @gnl21" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_DEPTH_CLAMP_ZERO_ONE_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_depth_clamp_zero_one&quot;" name="VK_EXT_DEPTH_CLAMP_ZERO_ONE_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLAMP_ZERO_ONE_FEATURES_EXT"/>
+ <type name="VkPhysicalDeviceDepthClampZeroOneFeaturesEXT" />
+ </require>
+ </extension>
+ <extension name="VK_EXT_non_seamless_cube_map" number="423" author="EXT" type="device" contact="Georg Lehmann @DadSchoorse" specialuse="d3demulation,glemulation" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_NON_SEAMLESS_CUBE_MAP_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_non_seamless_cube_map&quot;" name="VK_EXT_NON_SEAMLESS_CUBE_MAP_EXTENSION_NAME"/>
+ <enum bitpos="2" extends="VkSamplerCreateFlagBits" name="VK_SAMPLER_CREATE_NON_SEAMLESS_CUBE_MAP_BIT_EXT"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NON_SEAMLESS_CUBE_MAP_FEATURES_EXT"/>
+ <type name="VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_ARM_extension_424" number="424" author="ARM" contact="Jan-Harald Fredriksen @janharaldfredriksen-arm" supported="disabled">
+ <require>
+ <enum value="0" name="VK_ARM_EXTENSION_424_SPEC_VERSION"/>
+ <enum value="&quot;VK_ARM_extension_424&quot;" name="VK_ARM_EXTENSION_424_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_ARM_extension_425" number="425" author="ARM" contact="Jan-Harald Fredriksen @janharaldfredriksen-arm" supported="disabled">
+ <require>
+ <enum value="0" name="VK_ARM_EXTENSION_425_SPEC_VERSION"/>
+ <enum value="&quot;VK_ARM_extension_425&quot;" name="VK_ARM_EXTENSION_425_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_QCOM_fragment_density_map_offset" number="426" type="device" requires="VK_KHR_get_physical_device_properties2,VK_EXT_fragment_density_map" author="QCOM" contact="Matthew Netsch @mnetsch" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_QCOM_FRAGMENT_DENSITY_MAP_OFFSET_SPEC_VERSION"/>
+ <enum value="&quot;VK_QCOM_fragment_density_map_offset&quot;" name="VK_QCOM_FRAGMENT_DENSITY_MAP_OFFSET_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_FEATURES_QCOM"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_PROPERTIES_QCOM"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SUBPASS_FRAGMENT_DENSITY_MAP_OFFSET_END_INFO_QCOM"/>
+ <enum bitpos="15" extends="VkImageCreateFlagBits" name="VK_IMAGE_CREATE_FRAGMENT_DENSITY_MAP_OFFSET_BIT_QCOM"/>
+ <type name="VkPhysicalDeviceFragmentDensityMapOffsetFeaturesQCOM"/>
+ <type name="VkPhysicalDeviceFragmentDensityMapOffsetPropertiesQCOM"/>
+ <type name="VkSubpassFragmentDensityMapOffsetEndInfoQCOM"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_copy_memory_indirect" number="427" type="device" requires="VK_KHR_get_physical_device_properties2,VK_KHR_buffer_device_address" author="NV" contact="Vikram Kushwaha @vkushwaha-nv" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_NV_COPY_MEMORY_INDIRECT_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_copy_memory_indirect&quot;" name="VK_NV_COPY_MEMORY_INDIRECT_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_FEATURES_NV"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_PROPERTIES_NV"/>
+ <type name="VkCopyMemoryIndirectCommandNV"/>
+ <type name="VkCopyMemoryToImageIndirectCommandNV"/>
+ <type name="VkPhysicalDeviceCopyMemoryIndirectFeaturesNV"/>
+ <type name="VkPhysicalDeviceCopyMemoryIndirectPropertiesNV"/>
+ <command name="vkCmdCopyMemoryIndirectNV"/>
+ <command name="vkCmdCopyMemoryToImageIndirectNV"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_memory_decompression" number="428" type="device" requires="VK_KHR_get_physical_device_properties2,VK_KHR_buffer_device_address" author="NV" contact="Vikram Kushwaha @vkushwaha-nv" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_NV_MEMORY_DECOMPRESSION_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_memory_decompression&quot;" name="VK_NV_MEMORY_DECOMPRESSION_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_FEATURES_NV"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_PROPERTIES_NV"/>
+ <type name="VkMemoryDecompressionMethodFlagBitsNV"/>
+ <type name="VkMemoryDecompressionMethodFlagsNV"/>
+ <type name="VkDecompressMemoryRegionNV"/>
+ <type name="VkPhysicalDeviceMemoryDecompressionFeaturesNV"/>
+ <type name="VkPhysicalDeviceMemoryDecompressionPropertiesNV"/>
+ <command name="vkCmdDecompressMemoryNV"/>
+ <command name="vkCmdDecompressMemoryIndirectCountNV"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_extension_429" number="429" author="NV" contact="Vikram Kushwaha @vkushwaha-nv" supported="disabled">
+ <require>
+ <enum value="0" name="VK_NV_EXTENSION_429_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_extension_429&quot;" name="VK_NV_EXTENSION_429_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_extension_430" number="430" author="NV" contact="Vikram Kushwaha @vkushwaha-nv" supported="disabled">
+ <require>
+ <enum value="0" name="VK_NV_EXTENSION_430_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_extension_430&quot;" name="VK_NV_EXTENSION_430_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_linear_color_attachment" number="431" type="device" author="NVIDIA" contact="sourav parmar @souravpNV" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_NV_LINEAR_COLOR_ATTACHMENT_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_linear_color_attachment&quot;" name="VK_NV_LINEAR_COLOR_ATTACHMENT_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINEAR_COLOR_ATTACHMENT_FEATURES_NV"/>
+ <type name="VkPhysicalDeviceLinearColorAttachmentFeaturesNV"/>
+ </require>
+ <require extension="VK_KHR_format_feature_flags2">
+ <enum bitpos="38" extends="VkFormatFeatureFlagBits2" name="VK_FORMAT_FEATURE_2_LINEAR_COLOR_ATTACHMENT_BIT_NV" comment="Format support linear image as render target, it cannot be mixed with non linear attachment"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_extension_432" number="432" author="NV" contact="Sourav Parmar @souravpNV" supported="disabled">
+ <require>
+ <enum value="0" name="VK_NV_EXTENSION_432_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_extension_432&quot;" name="VK_NV_EXTENSION_432_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_extension_433" number="433" author="NV" contact="Sourav Parmar @souravpNV" supported="disabled">
+ <require>
+ <enum value="0" name="VK_NV_EXTENSION_433_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_extension_433&quot;" name="VK_NV_EXTENSION_433_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_GOOGLE_surfaceless_query" number="434" type="instance" requires="VK_KHR_surface" author="GOOGLE" contact="Shahbaz Youssefi @syoussefi" specialuse="glemulation" supported="vulkan">
+ <require>
+ <enum value="2" name="VK_GOOGLE_SURFACELESS_QUERY_SPEC_VERSION"/>
+ <enum value="&quot;VK_GOOGLE_surfaceless_query&quot;" name="VK_GOOGLE_SURFACELESS_QUERY_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_KHR_extension_435" number="435" author="KHR" contact="Alan Baker @alan-baker" supported="disabled">
+ <require>
+ <enum value="0" name="VK_KHR_EXTENSION_435_SPEC_VERSION"/>
+ <enum value="&quot;VK_KHR_extension_435&quot;" name="VK_KHR_EXTENSION_435_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_extension_436" number="436" author="NV" contact="Daniel Koch @dgkoch" supported="disabled">
+ <require>
+ <enum value="0" name="VK_NV_EXTENSION_436_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_extension_436&quot;" name="VK_NV_EXTENSION_436_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_437" number="437" author="EXT" contact="Jonathan Weinstein @Jonathan-Weinstein" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_437_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_437&quot;" name="VK_EXT_EXTENSION_437_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_image_compression_control_swapchain" number="438" type="device" requires="VK_EXT_image_compression_control" author="EXT" contact="Jan-Harald Fredriksen @janharaldfredriksen-arm" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_image_compression_control_swapchain&quot;" name="VK_EXT_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_COMPRESSION_CONTROL_SWAPCHAIN_FEATURES_EXT"/>
+ <type name="VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_SEC_extension_439" number="439" author="SEC" contact="Ralph Potter gitlab:@r_potter" supported="disabled">
+ <require>
+ <enum value="0" name="VK_SEC_EXTENSION_439_SPEC_VERSION"/>
+ <enum value="&quot;VK_SEC_extension_439&quot;" name="VK_SEC_EXTENSION_439_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_QCOM_extension_440" number="440" author="QCOM" contact="Jeff Leger @jackohound" supported="disabled">
+ <require>
+ <enum value="0" name="VK_QCOM_EXTENSION_440_SPEC_VERSION"/>
+ <enum value="&quot;VK_QCOM_extension_440&quot;" name="VK_QCOM_EXTENSION_440_EXTENSION_NAME"/>
+ <enum bitpos="7" extends="VkQueueFlagBits" name="VK_QUEUE_RESERVED_7_BIT_QCOM"/>
+ <enum bitpos="1" extends="VkDeviceQueueCreateFlagBits" name="VK_DEVICE_QUEUE_CREATE_RESERVED_1_BIT_QCOM"/>
+ </require>
+ </extension>
+ <extension name="VK_QCOM_image_processing" number="441" type="device" requires="VK_KHR_format_feature_flags2" author="QCOM" contact="Jeff Leger @jackohound" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_QCOM_IMAGE_PROCESSING_SPEC_VERSION"/>
+ <enum value="&quot;VK_QCOM_image_processing&quot;" name="VK_QCOM_IMAGE_PROCESSING_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_FEATURES_QCOM"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_PROPERTIES_QCOM"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_IMAGE_VIEW_SAMPLE_WEIGHT_CREATE_INFO_QCOM"/>
+ <enum bitpos="4" extends="VkSamplerCreateFlagBits" name="VK_SAMPLER_CREATE_IMAGE_PROCESSING_BIT_QCOM"/>
+ <enum bitpos="20" extends="VkImageUsageFlagBits" name="VK_IMAGE_USAGE_SAMPLE_WEIGHT_BIT_QCOM"/>
+ <enum bitpos="21" extends="VkImageUsageFlagBits" name="VK_IMAGE_USAGE_SAMPLE_BLOCK_MATCH_BIT_QCOM"/>
+ <enum offset="0" extends="VkDescriptorType" name="VK_DESCRIPTOR_TYPE_SAMPLE_WEIGHT_IMAGE_QCOM"/>
+ <enum offset="1" extends="VkDescriptorType" name="VK_DESCRIPTOR_TYPE_BLOCK_MATCH_IMAGE_QCOM"/>
+ <type name="VkImageViewSampleWeightCreateInfoQCOM"/>
+ <type name="VkPhysicalDeviceImageProcessingFeaturesQCOM"/>
+ <type name="VkPhysicalDeviceImageProcessingPropertiesQCOM"/>
+ </require>
+ <require extension="VK_KHR_format_feature_flags2">
+ <enum bitpos="34" extends="VkFormatFeatureFlagBits2" name="VK_FORMAT_FEATURE_2_WEIGHT_IMAGE_BIT_QCOM"/>
+ <enum bitpos="35" extends="VkFormatFeatureFlagBits2" name="VK_FORMAT_FEATURE_2_WEIGHT_SAMPLED_IMAGE_BIT_QCOM"/>
+ <enum bitpos="36" extends="VkFormatFeatureFlagBits2" name="VK_FORMAT_FEATURE_2_BLOCK_MATCHING_BIT_QCOM"/>
+ <enum bitpos="37" extends="VkFormatFeatureFlagBits2" name="VK_FORMAT_FEATURE_2_BOX_FILTER_SAMPLED_BIT_QCOM"/>
+ </require>
+ </extension>
+ <extension name="VK_COREAVI_extension_442" number="442" author="COREAVI" contact="Aidan Fabius @afabius" supported="disabled">
+ <require>
+ <enum value="0" name="VK_COREAVI_EXTENSION_442_SPEC_VERSION"/>
+ <enum value="&quot;VK_COREAVI_extension_442&quot;" name="VK_COREAVI_EXTENSION_442_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_COREAVI_extension_443" number="443" author="COREAVI" contact="Aidan Fabius @afabius" supported="disabled">
+ <require>
+ <enum value="0" name="VK_COREAVI_EXTENSION_443_SPEC_VERSION"/>
+ <enum value="&quot;VK_COREAVI_extension_443&quot;" name="VK_COREAVI_EXTENSION_443_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_COREAVI_extension_444" number="444" author="COREAVI" contact="Aidan Fabius @afabius" supported="disabled">
+ <require>
+ <enum value="0" name="VK_COREAVI_EXTENSION_444_SPEC_VERSION"/>
+ <enum value="&quot;VK_COREAVI_extension_444&quot;" name="VK_COREAVI_EXTENSION_444_EXTENSION_NAME"/>
+ <enum extends="VkCommandPoolResetFlagBits" bitpos="1" name="VK_COMMAND_POOL_RESET_RESERVED_1_BIT_COREAVI"/>
+ </require>
+ </extension>
+ <extension name="VK_COREAVI_extension_445" number="445" author="COREAVI" contact="Aidan Fabius @afabius" supported="disabled">
+ <require>
+ <enum value="0" name="VK_COREAVI_EXTENSION_445_SPEC_VERSION"/>
+ <enum value="&quot;VK_COREAVI_extension_445&quot;" name="VK_COREAVI_EXTENSION_445_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_COREAVI_extension_446" number="446" author="COREAVI" contact="Aidan Fabius @afabius" supported="disabled">
+ <require>
+ <enum value="0" name="VK_COREAVI_EXTENSION_446_SPEC_VERSION"/>
+ <enum value="&quot;VK_COREAVI_extension_446&quot;" name="VK_COREAVI_EXTENSION_446_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_COREAVI_extension_447" number="447" author="COREAVI" contact="Aidan Fabius @afabius" supported="disabled">
+ <require>
+ <enum value="0" name="VK_COREAVI_EXTENSION_447_SPEC_VERSION"/>
+ <enum value="&quot;VK_COREAVI_extension_447&quot;" name="VK_COREAVI_EXTENSION_447_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_SEC_extension_448" number="448" author="SEC" contact="Ralph Potter gitlab:@r_potter" supported="disabled">
+ <require>
+ <enum value="0" name="VK_SEC_EXTENSION_448_SPEC_VERSION"/>
+ <enum value="&quot;VK_SEC_extension_448&quot;" name="VK_SEC_EXTENSION_448_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_SEC_extension_449" number="449" author="SEC" contact="Ralph Potter gitlab:@r_potter" supported="disabled">
+ <require>
+ <enum value="0" name="VK_SEC_EXTENSION_449_SPEC_VERSION"/>
+ <enum value="&quot;VK_SEC_extension_449&quot;" name="VK_SEC_EXTENSION_449_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_SEC_extension_450" number="450" author="SEC" contact="Ralph Potter gitlab:@r_potter" supported="disabled">
+ <require>
+ <enum value="0" name="VK_SEC_EXTENSION_450_SPEC_VERSION"/>
+ <enum value="&quot;VK_SEC_extension_450&quot;" name="VK_SEC_EXTENSION_450_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_SEC_extension_451" number="451" author="SEC" contact="Ralph Potter gitlab:@r_potter" supported="disabled">
+ <require>
+ <enum value="0" name="VK_SEC_EXTENSION_451_SPEC_VERSION"/>
+ <enum value="&quot;VK_SEC_extension_451&quot;" name="VK_SEC_EXTENSION_451_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_extension_452" number="452" author="NV" contact="Piers Daniell @pdaniell-nv" supported="disabled">
+ <require>
+ <enum value="0" name="VK_NV_EXTENSION_452_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_extension_452&quot;" name="VK_NV_EXTENSION_452_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_ARM_extension_453" number="453" author="Arm" contact="Kevin Petit @kevinpetit" supported="disabled">
+ <require>
+ <enum value="0" name="VK_ARM_EXTENSION_453_SPEC_VERSION"/>
+ <enum value="&quot;VK_ARM_extension_453&quot;" name="VK_ARM_EXTENSION_453_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_GOOGLE_extension_454" number="454" author="GOOGLE" contact="Chad Versace @chadversary" supported="disabled">
+ <require>
+ <enum value="0" name="VK_GOOGLE_EXTENSION_454_SPEC_VERSION"/>
+ <enum value="&quot;VK_GOOGLE_extension_454&quot;" name="VK_GOOGLE_EXTENSION_454_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_GOOGLE_extension_455" number="455" author="GOOGLE" contact="Chad Versace @chadversary" supported="disabled">
+ <require>
+ <enum value="0" name="VK_GOOGLE_EXTENSION_455_SPEC_VERSION"/>
+ <enum value="&quot;VK_GOOGLE_extension_455&quot;" name="VK_GOOGLE_EXTENSION_455_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extended_dynamic_state3" number="456" type="device" requires="VK_KHR_get_physical_device_properties2" author="NV" contact="Piers Daniell @pdaniell-nv" supported="vulkan">
+ <require>
+ <enum value="2" name="VK_EXT_EXTENDED_DYNAMIC_STATE_3_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extended_dynamic_state3&quot;" name="VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_FEATURES_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_PROPERTIES_EXT"/>
+ <enum offset="2" extends="VkDynamicState" name="VK_DYNAMIC_STATE_TESSELLATION_DOMAIN_ORIGIN_EXT"/>
+ <enum offset="3" extends="VkDynamicState" name="VK_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT"/>
+ <enum offset="4" extends="VkDynamicState" name="VK_DYNAMIC_STATE_POLYGON_MODE_EXT"/>
+ <enum offset="5" extends="VkDynamicState" name="VK_DYNAMIC_STATE_RASTERIZATION_SAMPLES_EXT"/>
+ <enum offset="6" extends="VkDynamicState" name="VK_DYNAMIC_STATE_SAMPLE_MASK_EXT"/>
+ <enum offset="7" extends="VkDynamicState" name="VK_DYNAMIC_STATE_ALPHA_TO_COVERAGE_ENABLE_EXT"/>
+ <enum offset="8" extends="VkDynamicState" name="VK_DYNAMIC_STATE_ALPHA_TO_ONE_ENABLE_EXT"/>
+ <enum offset="9" extends="VkDynamicState" name="VK_DYNAMIC_STATE_LOGIC_OP_ENABLE_EXT"/>
+ <enum offset="10" extends="VkDynamicState" name="VK_DYNAMIC_STATE_COLOR_BLEND_ENABLE_EXT"/>
+ <enum offset="11" extends="VkDynamicState" name="VK_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT"/>
+ <enum offset="12" extends="VkDynamicState" name="VK_DYNAMIC_STATE_COLOR_WRITE_MASK_EXT"/>
+ <enum offset="13" extends="VkDynamicState" name="VK_DYNAMIC_STATE_RASTERIZATION_STREAM_EXT"/>
+ <enum offset="14" extends="VkDynamicState" name="VK_DYNAMIC_STATE_CONSERVATIVE_RASTERIZATION_MODE_EXT"/>
+ <enum offset="15" extends="VkDynamicState" name="VK_DYNAMIC_STATE_EXTRA_PRIMITIVE_OVERESTIMATION_SIZE_EXT"/>
+ <enum offset="16" extends="VkDynamicState" name="VK_DYNAMIC_STATE_DEPTH_CLIP_ENABLE_EXT"/>
+ <enum offset="17" extends="VkDynamicState" name="VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_ENABLE_EXT"/>
+ <enum offset="18" extends="VkDynamicState" name="VK_DYNAMIC_STATE_COLOR_BLEND_ADVANCED_EXT"/>
+ <enum offset="19" extends="VkDynamicState" name="VK_DYNAMIC_STATE_PROVOKING_VERTEX_MODE_EXT"/>
+ <enum offset="20" extends="VkDynamicState" name="VK_DYNAMIC_STATE_LINE_RASTERIZATION_MODE_EXT"/>
+ <enum offset="21" extends="VkDynamicState" name="VK_DYNAMIC_STATE_LINE_STIPPLE_ENABLE_EXT"/>
+ <enum offset="22" extends="VkDynamicState" name="VK_DYNAMIC_STATE_DEPTH_CLIP_NEGATIVE_ONE_TO_ONE_EXT"/>
+ <enum offset="23" extends="VkDynamicState" name="VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_ENABLE_NV"/>
+ <enum offset="24" extends="VkDynamicState" name="VK_DYNAMIC_STATE_VIEWPORT_SWIZZLE_NV"/>
+ <enum offset="25" extends="VkDynamicState" name="VK_DYNAMIC_STATE_COVERAGE_TO_COLOR_ENABLE_NV"/>
+ <enum offset="26" extends="VkDynamicState" name="VK_DYNAMIC_STATE_COVERAGE_TO_COLOR_LOCATION_NV"/>
+ <enum offset="27" extends="VkDynamicState" name="VK_DYNAMIC_STATE_COVERAGE_MODULATION_MODE_NV"/>
+ <enum offset="28" extends="VkDynamicState" name="VK_DYNAMIC_STATE_COVERAGE_MODULATION_TABLE_ENABLE_NV"/>
+ <enum offset="29" extends="VkDynamicState" name="VK_DYNAMIC_STATE_COVERAGE_MODULATION_TABLE_NV"/>
+ <enum offset="30" extends="VkDynamicState" name="VK_DYNAMIC_STATE_SHADING_RATE_IMAGE_ENABLE_NV"/>
+ <enum offset="31" extends="VkDynamicState" name="VK_DYNAMIC_STATE_REPRESENTATIVE_FRAGMENT_TEST_ENABLE_NV"/>
+ <enum offset="32" extends="VkDynamicState" name="VK_DYNAMIC_STATE_COVERAGE_REDUCTION_MODE_NV"/>
+ <type name="VkPhysicalDeviceExtendedDynamicState3FeaturesEXT"/>
+ <type name="VkPhysicalDeviceExtendedDynamicState3PropertiesEXT"/>
+ <type name="VkColorBlendEquationEXT"/>
+ <type name="VkColorBlendAdvancedEXT"/>
+ <command name="vkCmdSetTessellationDomainOriginEXT"/>
+ <command name="vkCmdSetDepthClampEnableEXT"/>
+ <command name="vkCmdSetPolygonModeEXT"/>
+ <command name="vkCmdSetRasterizationSamplesEXT"/>
+ <command name="vkCmdSetSampleMaskEXT"/>
+ <command name="vkCmdSetAlphaToCoverageEnableEXT"/>
+ <command name="vkCmdSetAlphaToOneEnableEXT"/>
+ <command name="vkCmdSetLogicOpEnableEXT"/>
+ <command name="vkCmdSetColorBlendEnableEXT"/>
+ <command name="vkCmdSetColorBlendEquationEXT"/>
+ <command name="vkCmdSetColorWriteMaskEXT"/>
+ <command name="vkCmdSetRasterizationStreamEXT"/>
+ <command name="vkCmdSetConservativeRasterizationModeEXT"/>
+ <command name="vkCmdSetExtraPrimitiveOverestimationSizeEXT"/>
+ <command name="vkCmdSetDepthClipEnableEXT"/>
+ <command name="vkCmdSetSampleLocationsEnableEXT"/>
+ <command name="vkCmdSetColorBlendAdvancedEXT"/>
+ <command name="vkCmdSetProvokingVertexModeEXT"/>
+ <command name="vkCmdSetLineRasterizationModeEXT"/>
+ <command name="vkCmdSetLineStippleEnableEXT"/>
+ <command name="vkCmdSetDepthClipNegativeOneToOneEXT"/>
+ <command name="vkCmdSetViewportWScalingEnableNV"/>
+ <command name="vkCmdSetViewportSwizzleNV"/>
+ <command name="vkCmdSetCoverageToColorEnableNV"/>
+ <command name="vkCmdSetCoverageToColorLocationNV"/>
+ <command name="vkCmdSetCoverageModulationModeNV"/>
+ <command name="vkCmdSetCoverageModulationTableEnableNV"/>
+ <command name="vkCmdSetCoverageModulationTableNV"/>
+ <command name="vkCmdSetShadingRateImageEnableNV"/>
+ <command name="vkCmdSetRepresentativeFragmentTestEnableNV"/>
+ <command name="vkCmdSetCoverageReductionModeNV"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_457" number="457" author="RASTERGRID" contact="Daniel Rakos @aqnuep1" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_457_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_457&quot;" name="VK_EXT_EXTENSION_457_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_458" number="458" author="RASTERGRID" contact="Daniel Rakos @aqnuep1" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_458_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_458&quot;" name="VK_EXT_EXTENSION_458_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_subpass_merge_feedback" number="459" type="device" author="EXT" contact="Ting Wei @catweiting" supported="vulkan">
+ <require>
+ <enum value="2" name="VK_EXT_SUBPASS_MERGE_FEEDBACK_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_subpass_merge_feedback&quot;" name="VK_EXT_SUBPASS_MERGE_FEEDBACK_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_MERGE_FEEDBACK_FEATURES_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_RENDER_PASS_CREATION_CONTROL_EXT"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_RENDER_PASS_CREATION_FEEDBACK_CREATE_INFO_EXT"/>
+ <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_RENDER_PASS_SUBPASS_FEEDBACK_CREATE_INFO_EXT"/>
+ <type name="VkPhysicalDeviceSubpassMergeFeedbackFeaturesEXT"/>
+ <type name="VkRenderPassCreationControlEXT"/>
+ <type name="VkRenderPassCreationFeedbackInfoEXT"/>
+ <type name="VkRenderPassCreationFeedbackCreateInfoEXT"/>
+ <type name="VkRenderPassSubpassFeedbackInfoEXT"/>
+ <type name="VkRenderPassSubpassFeedbackCreateInfoEXT"/>
+ <type name="VkSubpassMergeStatusEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_LUNARG_direct_driver_loading" number="460" type="instance" author="LUNARG" contact="Charles Giessen @charles-lunarg" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_LUNARG_DIRECT_DRIVER_LOADING_SPEC_VERSION"/>
+ <enum value="&quot;VK_LUNARG_direct_driver_loading&quot;" name="VK_LUNARG_DIRECT_DRIVER_LOADING_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DIRECT_DRIVER_LOADING_INFO_LUNARG"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_DIRECT_DRIVER_LOADING_LIST_LUNARG"/>
+ <type name="VkDirectDriverLoadingFlagsLUNARG" comment="Will add VkDirectDriverLoadingFlagBitsLUNARG when bits are defined in the future"/>
+ <type name="VkDirectDriverLoadingModeLUNARG"/>
+ <type name="VkDirectDriverLoadingInfoLUNARG"/>
+ <type name="VkDirectDriverLoadingListLUNARG"/>
+ <type name="PFN_vkGetInstanceProcAddrLUNARG"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_461" number="461" author="EXT" contact="Kevin Petit @kevinpetit" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_461_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_461&quot;" name="VK_EXT_EXTENSION_461_EXTENSION_NAME"/>
+ <enum bitpos="39" extends="VkFormatFeatureFlagBits2" name="VK_FORMAT_FEATURE_2_RESERVED_39_BIT_EXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_462" number="462" author="EXT" contact="Joshua Ashton @Joshua-Ashton,Liam Middlebrook @liam-middlebrook" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_462_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_462&quot;" name="VK_EXT_EXTENSION_462_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_shader_module_identifier" number="463" type="device" requires="VK_KHR_get_physical_device_properties2,VK_EXT_pipeline_creation_cache_control" author="EXT" contact="Hans-Kristian Arntzen @HansKristian-Work" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_SHADER_MODULE_IDENTIFIER_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_shader_module_identifier&quot;" name="VK_EXT_SHADER_MODULE_IDENTIFIER_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_FEATURES_EXT"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_PROPERTIES_EXT"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_MODULE_IDENTIFIER_CREATE_INFO_EXT"/>
+ <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_SHADER_MODULE_IDENTIFIER_EXT"/>
+ <enum name="VK_MAX_SHADER_MODULE_IDENTIFIER_SIZE_EXT"/>
+ <type name="VkPhysicalDeviceShaderModuleIdentifierFeaturesEXT"/>
+ <type name="VkPhysicalDeviceShaderModuleIdentifierPropertiesEXT"/>
+ <type name="VkPipelineShaderStageModuleIdentifierCreateInfoEXT"/>
+ <type name="VkShaderModuleIdentifierEXT"/>
+ <command name="vkGetShaderModuleIdentifierEXT"/>
+ <command name="vkGetShaderModuleCreateInfoIdentifierEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_rasterization_order_attachment_access" number="464" type="device" requires="VK_KHR_get_physical_device_properties2" author="ARM" contact="Jan-Harald Fredriksen @janharaldfredriksen-arm" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_rasterization_order_attachment_access&quot;" name="VK_EXT_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" extnumber="343" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT"/>
+ <type name="VkPhysicalDeviceRasterizationOrderAttachmentAccessFeaturesEXT"/>
+ <type name="VkPipelineColorBlendStateCreateFlagBits"/>
+ <type name="VkPipelineDepthStencilStateCreateFlagBits"/>
+ <enum bitpos="0" extends="VkPipelineColorBlendStateCreateFlagBits" name="VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_EXT"/>
+ <enum bitpos="0" extends="VkPipelineDepthStencilStateCreateFlagBits" name="VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_EXT"/>
+ <enum bitpos="1" extends="VkPipelineDepthStencilStateCreateFlagBits" name="VK_PIPELINE_DEPTH_STENCIL_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_EXT"/>
+ <enum bitpos="4" extends="VkSubpassDescriptionFlagBits" name="VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_EXT"/>
+ <enum bitpos="5" extends="VkSubpassDescriptionFlagBits" name="VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_DEPTH_ACCESS_BIT_EXT"/>
+ <enum bitpos="6" extends="VkSubpassDescriptionFlagBits" name="VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_STENCIL_ACCESS_BIT_EXT"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_optical_flow" number="465" requires="VK_KHR_get_physical_device_properties2,VK_KHR_format_feature_flags2,VK_KHR_synchronization2" type="device" author="NV" contact="Carsten Rohde @crohde" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_NV_OPTICAL_FLOW_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_optical_flow&quot;" name="VK_NV_OPTICAL_FLOW_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_FEATURES_NV"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_PROPERTIES_NV"/>
+ <enum offset="2" extends="VkStructureType" name="VK_STRUCTURE_TYPE_OPTICAL_FLOW_IMAGE_FORMAT_INFO_NV"/>
+ <enum offset="3" extends="VkStructureType" name="VK_STRUCTURE_TYPE_OPTICAL_FLOW_IMAGE_FORMAT_PROPERTIES_NV"/>
+ <enum offset="4" extends="VkStructureType" name="VK_STRUCTURE_TYPE_OPTICAL_FLOW_SESSION_CREATE_INFO_NV"/>
+ <enum offset="5" extends="VkStructureType" name="VK_STRUCTURE_TYPE_OPTICAL_FLOW_EXECUTE_INFO_NV"/>
+ <enum offset="10" extends="VkStructureType" name="VK_STRUCTURE_TYPE_OPTICAL_FLOW_SESSION_CREATE_PRIVATE_DATA_INFO_NV"/><comment>NV internal use only</comment>
+ <enum offset="0" extends="VkFormat" name="VK_FORMAT_R16G16_S10_5_NV"/>
+ <enum offset="0" extends="VkObjectType" name="VK_OBJECT_TYPE_OPTICAL_FLOW_SESSION_NV"/>
+ <enum bitpos="8" extends="VkQueueFlagBits" name="VK_QUEUE_OPTICAL_FLOW_BIT_NV"/>
+ <enum bitpos="29" extends="VkPipelineStageFlagBits2" name="VK_PIPELINE_STAGE_2_OPTICAL_FLOW_BIT_NV"/>
+ <enum bitpos="42" extends="VkAccessFlagBits2" name="VK_ACCESS_2_OPTICAL_FLOW_READ_BIT_NV"/>
+ <enum bitpos="43" extends="VkAccessFlagBits2" name="VK_ACCESS_2_OPTICAL_FLOW_WRITE_BIT_NV"/>
+ <enum bitpos="40" extends="VkFormatFeatureFlagBits2" name="VK_FORMAT_FEATURE_2_OPTICAL_FLOW_IMAGE_BIT_NV"/>
+ <enum bitpos="41" extends="VkFormatFeatureFlagBits2" name="VK_FORMAT_FEATURE_2_OPTICAL_FLOW_VECTOR_BIT_NV"/>
+ <enum bitpos="42" extends="VkFormatFeatureFlagBits2" name="VK_FORMAT_FEATURE_2_OPTICAL_FLOW_COST_BIT_NV"/>
+ <type name="VkPhysicalDeviceOpticalFlowFeaturesNV"/>
+ <type name="VkPhysicalDeviceOpticalFlowPropertiesNV"/>
+ <type name="VkOpticalFlowUsageFlagBitsNV"/>
+ <type name="VkOpticalFlowUsageFlagsNV"/>
+ <type name="VkOpticalFlowImageFormatInfoNV"/>
+ <type name="VkOpticalFlowImageFormatPropertiesNV"/>
+ <type name="VkOpticalFlowGridSizeFlagBitsNV"/>
+ <type name="VkOpticalFlowGridSizeFlagsNV"/>
+ <type name="VkOpticalFlowPerformanceLevelNV"/>
+ <type name="VkOpticalFlowSessionBindingPointNV"/>
+ <type name="VkOpticalFlowSessionCreateFlagBitsNV"/>
+ <type name="VkOpticalFlowSessionCreateFlagsNV"/>
+ <type name="VkOpticalFlowExecuteFlagBitsNV"/>
+ <type name="VkOpticalFlowExecuteFlagsNV"/>
+ <type name="VkOpticalFlowSessionNV"/>
+ <type name="VkOpticalFlowSessionCreateInfoNV"/>
+ <type name="VkOpticalFlowSessionCreatePrivateDataInfoNV"/><comment>NV internal use only</comment>
+ <type name="VkOpticalFlowExecuteInfoNV"/>
+ <command name="vkGetPhysicalDeviceOpticalFlowImageFormatsNV"/>
+ <command name="vkCreateOpticalFlowSessionNV"/>
+ <command name="vkDestroyOpticalFlowSessionNV"/>
+ <command name="vkBindOpticalFlowSessionImageNV"/>
+ <command name="vkCmdOpticalFlowExecuteNV"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_legacy_dithering" number="466" type="device" requires="VK_KHR_get_physical_device_properties2" author="EXT" contact="Shahbaz Youssefi @syoussefi" supported="vulkan" specialuse="glemulation">
+ <require>
+ <enum value="1" name="VK_EXT_LEGACY_DITHERING_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_legacy_dithering&quot;" name="VK_EXT_LEGACY_DITHERING_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_DITHERING_FEATURES_EXT"/>
+ <enum bitpos="7" extends="VkSubpassDescriptionFlagBits" name="VK_SUBPASS_DESCRIPTION_ENABLE_LEGACY_DITHERING_BIT_EXT"/>
+ <type name="VkPhysicalDeviceLegacyDitheringFeaturesEXT"/>
+ </require>
+ <require feature="VK_VERSION_1_3">
+ <enum bitpos="3" extends="VkRenderingFlagBits" name="VK_RENDERING_ENABLE_LEGACY_DITHERING_BIT_EXT"/>
+ </require>
+ <require extension="VK_KHR_dynamic_rendering">
+ <enum bitpos="3" extends="VkRenderingFlagBits" name="VK_RENDERING_ENABLE_LEGACY_DITHERING_BIT_EXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_pipeline_protected_access" number="467" type="device" requires="VK_KHR_get_physical_device_properties2" author="EXT" contact="Shahbaz Youssefi @syoussefi" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_EXT_PIPELINE_PROTECTED_ACCESS_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_pipeline_protected_access&quot;" name="VK_EXT_PIPELINE_PROTECTED_ACCESS_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROTECTED_ACCESS_FEATURES_EXT"/>
+ <enum bitpos="27" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_NO_PROTECTED_ACCESS_BIT_EXT"/>
+ <enum bitpos="30" extends="VkPipelineCreateFlagBits" name="VK_PIPELINE_CREATE_PROTECTED_ACCESS_ONLY_BIT_EXT"/>
+ <type name="VkPhysicalDevicePipelineProtectedAccessFeaturesEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_468" number="468" author="EXT" contact="Shahbaz Youssefi @syoussefi" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_468_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_468&quot;" name="VK_EXT_EXTENSION_468_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_ANDROID_extension_469" number="469" type="device" platform="android" author="ANDROID" contact="Chris Forbes @chrisforbes" supported="disabled">
+ <require>
+ <enum value="0" name="VK_ANDROID_EXTENSION_469_SPEC_VERSION"/>
+ <enum value="&quot;VK_ANDROID_extension_469&quot;" name="VK_ANDROID_EXTENSION_469_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_470" number="470" author="AMD" contact="Stu Smith" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_470_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_470&quot;" name="VK_AMD_EXTENSION_470_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_471" number="471" author="AMD" contact="Stu Smith" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_471_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_471&quot;" name="VK_AMD_EXTENSION_471_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_472" number="472" author="AMD" contact="Stu Smith" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_472_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_472&quot;" name="VK_AMD_EXTENSION_472_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_473" number="473" author="AMD" contact="Stu Smith" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_473_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_473&quot;" name="VK_AMD_EXTENSION_473_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_474" number="474" author="AMD" contact="Stu Smith" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_474_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_474&quot;" name="VK_AMD_EXTENSION_474_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_475" number="475" author="AMD" contact="Stu Smith" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_475_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_475&quot;" name="VK_AMD_EXTENSION_475_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_476" number="476" author="AMD" contact="Stu Smith" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_476_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_476&quot;" name="VK_AMD_EXTENSION_476_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_477" number="477" author="AMD" contact="Stu Smith" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_477_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_477&quot;" name="VK_AMD_EXTENSION_477_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_478" number="478" author="AMD" contact="Stu Smith" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_478_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_478&quot;" name="VK_AMD_EXTENSION_478_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_AMD_extension_479" number="479" author="AMD" contact="Stu Smith" supported="disabled">
+ <require>
+ <enum value="0" name="VK_AMD_EXTENSION_479_SPEC_VERSION"/>
+ <enum value="&quot;VK_AMD_extension_479&quot;" name="VK_AMD_EXTENSION_479_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_480" number="480" author="EXT" contact="Daniel Stone" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_480_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_480&quot;" name="VK_EXT_EXTENSION_480_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_481" number="481" author="EXT" contact="Daniel Stone" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_481_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_481&quot;" name="VK_EXT_EXTENSION_481_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_482" number="482" author="KHR" contact="Eric Werness" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_482_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_482&quot;" name="VK_EXT_EXTENSION_482_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_483" number="483" author="EXT" contact="Piers Daniell" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_483_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_483&quot;" name="VK_EXT_EXTENSION_483_EXTENSION_NAME"/>
+ <enum bitpos="15" extends="VkShaderStageFlagBits" name="VK_SHADER_STAGE_EXT_483_RESERVE_15"/>
+ <enum bitpos="16" extends="VkShaderStageFlagBits" name="VK_SHADER_STAGE_EXT_483_RESERVE_16"/>
+ <enum bitpos="17" extends="VkShaderStageFlagBits" name="VK_SHADER_STAGE_EXT_483_RESERVE_17"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_484" number="484" author="KHR" contact="Chris Glover @cdglove" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_484_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_484&quot;" name="VK_EXT_EXTENSION_484_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_QCOM_tile_properties" number="485" type="device" requires="VK_KHR_get_physical_device_properties2" author="QCOM" contact="Jeff Leger @jackohound" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_QCOM_TILE_PROPERTIES_SPEC_VERSION"/>
+ <enum value="&quot;VK_QCOM_tile_properties&quot;" name="VK_QCOM_TILE_PROPERTIES_EXTENSION_NAME"/>
+ <command name="vkGetFramebufferTilePropertiesQCOM"/>
+ <command name="vkGetDynamicRenderingTilePropertiesQCOM"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_PROPERTIES_FEATURES_QCOM"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_TILE_PROPERTIES_QCOM"/>
+ <type name="VkPhysicalDeviceTilePropertiesFeaturesQCOM"/>
+ <type name="VkTilePropertiesQCOM"/>
+ <type name="VkRenderingInfoKHR"/>
+ </require>
+ </extension>
+ <extension name="VK_SEC_amigo_profiling" number="486" type="device" requires="VK_KHR_get_physical_device_properties2" author="SEC" contact="Ralph Potter gitlab:@r_potter" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_SEC_AMIGO_PROFILING_SPEC_VERSION"/>
+ <enum value="&quot;VK_SEC_amigo_profiling&quot;" name="VK_SEC_AMIGO_PROFILING_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_AMIGO_PROFILING_FEATURES_SEC"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_AMIGO_PROFILING_SUBMIT_INFO_SEC"/>
+ <type name="VkPhysicalDeviceAmigoProfilingFeaturesSEC"/>
+ <type name="VkAmigoProfilingSubmitInfoSEC"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_487" number="487" author="EXT" contact="Shahbaz Youssefi @syoussefi" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_487_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_487&quot;" name="VK_EXT_EXTENSION_487_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_488" number="488" author="EXT" contact="Shahbaz Youssefi @syoussefi" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_488_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_488&quot;" name="VK_EXT_EXTENSION_488_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_QCOM_multiview_per_view_viewports" number="489" type="device" author="QCOM" contact="Jeff Leger @jackohound" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_QCOM_MULTIVIEW_PER_VIEW_VIEWPORTS_SPEC_VERSION"/>
+ <enum value="&quot;VK_QCOM_multiview_per_view_viewports&quot;" name="VK_QCOM_MULTIVIEW_PER_VIEW_VIEWPORTS_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_VIEWPORTS_FEATURES_QCOM"/>
+ <type name="VkPhysicalDeviceMultiviewPerViewViewportsFeaturesQCOM"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_extension_490" number="490" author="NV" contact="Daniel Koch @dgkoch" supported="disabled">
+ <require>
+ <enum value="0" name="VK_NV_EXTENSION_490_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_extension_490&quot;" name="VK_NV_EXTENSION_490_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_ray_tracing_invocation_reorder" number="491" type="device" requires="VK_KHR_ray_tracing_pipeline" author="NV" contact="Eric Werness @ewerness-nv" supported="vulkan">
+ <require>
+ <enum value="1" name="VK_NV_RAY_TRACING_INVOCATION_REORDER_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_ray_tracing_invocation_reorder&quot;" name="VK_NV_RAY_TRACING_INVOCATION_REORDER_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_FEATURES_NV"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_PROPERTIES_NV"/>
+ <type name="VkRayTracingInvocationReorderModeNV"/>
+ <type name="VkPhysicalDeviceRayTracingInvocationReorderPropertiesNV"/>
+ <type name="VkPhysicalDeviceRayTracingInvocationReorderFeaturesNV"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_extension_492" number="492" author="NV" contact="Daniel Koch @dgkoch" supported="disabled">
+ <require>
+ <enum value="0" name="VK_NV_EXTENSION_492_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_extension_492&quot;" name="VK_NV_EXTENSION_492_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_extension_493" number="493" author="NV" contact="Daniel Koch @dgkoch" supported="disabled">
+ <require>
+ <enum value="0" name="VK_NV_EXTENSION_493_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_extension_493&quot;" name="VK_NV_EXTENSION_493_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_extension_494" number="494" author="NV" contact="Daniel Koch @dgkoch" supported="disabled">
+ <require>
+ <enum value="0" name="VK_NV_EXTENSION_494_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_extension_494&quot;" name="VK_NV_EXTENSION_494_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_mutable_descriptor_type" number="495" type="device" supported="vulkan" author="EXT" contact="Joshua Ashton @Joshua-Ashton,Hans-Kristian Arntzen @HansKristian-Work" specialuse="d3demulation" requires="VK_KHR_maintenance3">
+ <require>
+ <enum value="1" name="VK_EXT_MUTABLE_DESCRIPTOR_TYPE_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_mutable_descriptor_type&quot;" name="VK_EXT_MUTABLE_DESCRIPTOR_TYPE_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" extnumber="352" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MUTABLE_DESCRIPTOR_TYPE_FEATURES_EXT"/>
+ <enum offset="2" extends="VkStructureType" extnumber="352" name="VK_STRUCTURE_TYPE_MUTABLE_DESCRIPTOR_TYPE_CREATE_INFO_EXT"/>
+ <enum offset="0" extends="VkDescriptorType" extnumber="352" name="VK_DESCRIPTOR_TYPE_MUTABLE_EXT"/>
+ <enum bitpos="2" extends="VkDescriptorPoolCreateFlagBits" name="VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_EXT"/>
+ <enum bitpos="2" extends="VkDescriptorSetLayoutCreateFlagBits" name="VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_EXT"/>
+ <type name="VkPhysicalDeviceMutableDescriptorTypeFeaturesEXT"/>
+ <type name="VkMutableDescriptorTypeListEXT"/>
+ <type name="VkMutableDescriptorTypeCreateInfoEXT"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_496" number="496" author="EXT" contact="Mike Blumenkrantz @zmike" type="device" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_496_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_496&quot;" name="VK_EXT_EXTENSION_496_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_497" number="497" author="EXT" contact="Christophe Riccio @christophe" type="device" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_497_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_497&quot;" name="VK_EXT_EXTENSION_497_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_ARM_shader_core_builtins" number="498" author="ARM" contact="Kevin Petit @kevinpetit" type="device" supported="vulkan">
+ <require>
+ <enum value="2" name="VK_ARM_SHADER_CORE_BUILTINS_SPEC_VERSION"/>
+ <enum value="&quot;VK_ARM_shader_core_builtins&quot;" name="VK_ARM_SHADER_CORE_BUILTINS_EXTENSION_NAME"/>
+ <enum offset="0" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_FEATURES_ARM"/>
+ <enum offset="1" extends="VkStructureType" name="VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_PROPERTIES_ARM"/>
+ <type name="VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM"/>
+ <type name="VkPhysicalDeviceShaderCoreBuiltinsPropertiesARM"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_499" number="499" author="EXT" contact="Hans-Kristian Arntzen @HansKristian-Work" type="device" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_499_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_499&quot;" name="VK_EXT_EXTENSION_499_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_500" number="500" author="EXT" contact="Piers Daniell @pdaniell-nv" type="device" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_500_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_500&quot;" name="VK_EXT_EXTENSION_500_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_501" number="501" author="SEC" contact="Chris Hambacher @chambacher" type="device" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_501_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_501&quot;" name="VK_EXT_EXTENSION_501_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_502" number="502" author="HUAWEI" contact="Pan Gao @PanGao-h" type="device" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_502_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_502&quot;" name="VK_EXT_EXTENSION_502_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_503" number="503" author="HUAWEI" contact="Pan Gao @PanGao-h" type="device" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_503_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_503&quot;" name="VK_EXT_EXTENSION_503_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_extension_504" number="504" author="NV" contact="Piers Daniell @pdaniell-nv" type="instance" supported="disabled">
+ <require>
+ <enum value="0" name="VK_NV_EXTENSION_504_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_extension_504&quot;" name="VK_NV_EXTENSION_504_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_EXT_extension_505" number="505" author="EXT" contact="Jamie Madill @jmadill" type="device" supported="disabled">
+ <require>
+ <enum value="0" name="VK_EXT_EXTENSION_505_SPEC_VERSION"/>
+ <enum value="&quot;VK_EXT_extension_505&quot;" name="VK_EXT_EXTENSION_505_EXTENSION_NAME"/>
+ </require>
+ </extension>
+ <extension name="VK_NV_extension_506" number="506" author="NV" contact="Charles Hansen @cshansen" type="device" supported="disabled">
+ <require>
+ <enum value="0" name="VK_NV_EXTENSION_506_SPEC_VERSION"/>
+ <enum value="&quot;VK_NV_extension_506&quot;" name="VK_NV_EXTENSION_506_EXTENSION_NAME"/>
</require>
</extension>
-
</extensions>
+ <formats>
+ <format name="VK_FORMAT_R4G4_UNORM_PACK8" class="8-bit" blockSize="1" texelsPerBlock="1" packed="8">
+ <component name="R" bits="4" numericFormat="UNORM"/>
+ <component name="G" bits="4" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_R4G4B4A4_UNORM_PACK16" class="16-bit" blockSize="2" texelsPerBlock="1" packed="16">
+ <component name="R" bits="4" numericFormat="UNORM"/>
+ <component name="G" bits="4" numericFormat="UNORM"/>
+ <component name="B" bits="4" numericFormat="UNORM"/>
+ <component name="A" bits="4" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_B4G4R4A4_UNORM_PACK16" class="16-bit" blockSize="2" texelsPerBlock="1" packed="16">
+ <component name="B" bits="4" numericFormat="UNORM"/>
+ <component name="G" bits="4" numericFormat="UNORM"/>
+ <component name="R" bits="4" numericFormat="UNORM"/>
+ <component name="A" bits="4" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_R5G6B5_UNORM_PACK16" class="16-bit" blockSize="2" texelsPerBlock="1" packed="16">
+ <component name="R" bits="5" numericFormat="UNORM"/>
+ <component name="G" bits="6" numericFormat="UNORM"/>
+ <component name="B" bits="5" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_B5G6R5_UNORM_PACK16" class="16-bit" blockSize="2" texelsPerBlock="1" packed="16">
+ <component name="B" bits="5" numericFormat="UNORM"/>
+ <component name="G" bits="6" numericFormat="UNORM"/>
+ <component name="R" bits="5" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_R5G5B5A1_UNORM_PACK16" class="16-bit" blockSize="2" texelsPerBlock="1" packed="16">
+ <component name="R" bits="5" numericFormat="UNORM"/>
+ <component name="G" bits="5" numericFormat="UNORM"/>
+ <component name="B" bits="5" numericFormat="UNORM"/>
+ <component name="A" bits="1" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_B5G5R5A1_UNORM_PACK16" class="16-bit" blockSize="2" texelsPerBlock="1" packed="16">
+ <component name="B" bits="5" numericFormat="UNORM"/>
+ <component name="R" bits="5" numericFormat="UNORM"/>
+ <component name="G" bits="5" numericFormat="UNORM"/>
+ <component name="A" bits="1" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_A1R5G5B5_UNORM_PACK16" class="16-bit" blockSize="2" texelsPerBlock="1" packed="16">
+ <component name="A" bits="1" numericFormat="UNORM"/>
+ <component name="R" bits="5" numericFormat="UNORM"/>
+ <component name="G" bits="5" numericFormat="UNORM"/>
+ <component name="B" bits="5" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_R8_UNORM" class="8-bit" blockSize="1" texelsPerBlock="1">
+ <component name="R" bits="8" numericFormat="UNORM"/>
+ <spirvimageformat name="R8"/>
+ </format>
+ <format name="VK_FORMAT_R8_SNORM" class="8-bit" blockSize="1" texelsPerBlock="1">
+ <component name="R" bits="8" numericFormat="SNORM"/>
+ <spirvimageformat name="R8Snorm"/>
+ </format>
+ <format name="VK_FORMAT_R8_USCALED" class="8-bit" blockSize="1" texelsPerBlock="1">
+ <component name="R" bits="8" numericFormat="USCALED"/>
+ </format>
+ <format name="VK_FORMAT_R8_SSCALED" class="8-bit" blockSize="1" texelsPerBlock="1">
+ <component name="R" bits="8" numericFormat="SSCALED"/>
+ </format>
+ <format name="VK_FORMAT_R8_UINT" class="8-bit" blockSize="1" texelsPerBlock="1">
+ <component name="R" bits="8" numericFormat="UINT"/>
+ <spirvimageformat name="R8ui"/>
+ </format>
+ <format name="VK_FORMAT_R8_SINT" class="8-bit" blockSize="1" texelsPerBlock="1">
+ <component name="R" bits="8" numericFormat="SINT"/>
+ <spirvimageformat name="R8i"/>
+ </format>
+ <format name="VK_FORMAT_R8_SRGB" class="8-bit" blockSize="1" texelsPerBlock="1">
+ <component name="R" bits="8" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_R8G8_UNORM" class="16-bit" blockSize="2" texelsPerBlock="1">
+ <component name="R" bits="8" numericFormat="UNORM"/>
+ <component name="G" bits="8" numericFormat="UNORM"/>
+ <spirvimageformat name="Rg8"/>
+ </format>
+ <format name="VK_FORMAT_R8G8_SNORM" class="16-bit" blockSize="2" texelsPerBlock="1">
+ <component name="R" bits="8" numericFormat="SNORM"/>
+ <component name="G" bits="8" numericFormat="SNORM"/>
+ <spirvimageformat name="Rg8Snorm"/>
+ </format>
+ <format name="VK_FORMAT_R8G8_USCALED" class="16-bit" blockSize="2" texelsPerBlock="1">
+ <component name="R" bits="8" numericFormat="USCALED"/>
+ <component name="G" bits="8" numericFormat="USCALED"/>
+ </format>
+ <format name="VK_FORMAT_R8G8_SSCALED" class="16-bit" blockSize="2" texelsPerBlock="1">
+ <component name="R" bits="8" numericFormat="SSCALED"/>
+ <component name="G" bits="8" numericFormat="SSCALED"/>
+ </format>
+ <format name="VK_FORMAT_R8G8_UINT" class="16-bit" blockSize="2" texelsPerBlock="1">
+ <component name="R" bits="8" numericFormat="UINT"/>
+ <component name="G" bits="8" numericFormat="UINT"/>
+ <spirvimageformat name="Rg8ui"/>
+ </format>
+ <format name="VK_FORMAT_R8G8_SINT" class="16-bit" blockSize="2" texelsPerBlock="1">
+ <component name="R" bits="8" numericFormat="SINT"/>
+ <component name="G" bits="8" numericFormat="SINT"/>
+ <spirvimageformat name="Rg8i"/>
+ </format>
+ <format name="VK_FORMAT_R8G8_SRGB" class="16-bit" blockSize="2" texelsPerBlock="1">
+ <component name="R" bits="8" numericFormat="SRGB"/>
+ <component name="G" bits="8" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_R8G8B8_UNORM" class="24-bit" blockSize="3" texelsPerBlock="1">
+ <component name="R" bits="8" numericFormat="UNORM"/>
+ <component name="G" bits="8" numericFormat="UNORM"/>
+ <component name="B" bits="8" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_R8G8B8_SNORM" class="24-bit" blockSize="3" texelsPerBlock="1">
+ <component name="R" bits="8" numericFormat="SNORM"/>
+ <component name="G" bits="8" numericFormat="SNORM"/>
+ <component name="B" bits="8" numericFormat="SNORM"/>
+ </format>
+ <format name="VK_FORMAT_R8G8B8_USCALED" class="24-bit" blockSize="3" texelsPerBlock="1">
+ <component name="R" bits="8" numericFormat="USCALED"/>
+ <component name="G" bits="8" numericFormat="USCALED"/>
+ <component name="B" bits="8" numericFormat="USCALED"/>
+ </format>
+ <format name="VK_FORMAT_R8G8B8_SSCALED" class="24-bit" blockSize="3" texelsPerBlock="1">
+ <component name="R" bits="8" numericFormat="SSCALED"/>
+ <component name="G" bits="8" numericFormat="SSCALED"/>
+ <component name="B" bits="8" numericFormat="SSCALED"/>
+ </format>
+ <format name="VK_FORMAT_R8G8B8_UINT" class="24-bit" blockSize="3" texelsPerBlock="1">
+ <component name="R" bits="8" numericFormat="UINT"/>
+ <component name="G" bits="8" numericFormat="UINT"/>
+ <component name="B" bits="8" numericFormat="UINT"/>
+ </format>
+ <format name="VK_FORMAT_R8G8B8_SINT" class="24-bit" blockSize="3" texelsPerBlock="1">
+ <component name="R" bits="8" numericFormat="SINT"/>
+ <component name="G" bits="8" numericFormat="SINT"/>
+ <component name="B" bits="8" numericFormat="SINT"/>
+ </format>
+ <format name="VK_FORMAT_R8G8B8_SRGB" class="24-bit" blockSize="3" texelsPerBlock="1">
+ <component name="R" bits="8" numericFormat="SRGB"/>
+ <component name="G" bits="8" numericFormat="SRGB"/>
+ <component name="B" bits="8" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_B8G8R8_UNORM" class="24-bit" blockSize="3" texelsPerBlock="1">
+ <component name="B" bits="8" numericFormat="UNORM"/>
+ <component name="G" bits="8" numericFormat="UNORM"/>
+ <component name="R" bits="8" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_B8G8R8_SNORM" class="24-bit" blockSize="3" texelsPerBlock="1">
+ <component name="B" bits="8" numericFormat="SNORM"/>
+ <component name="G" bits="8" numericFormat="SNORM"/>
+ <component name="R" bits="8" numericFormat="SNORM"/>
+ </format>
+ <format name="VK_FORMAT_B8G8R8_USCALED" class="24-bit" blockSize="3" texelsPerBlock="1">
+ <component name="B" bits="8" numericFormat="USCALED"/>
+ <component name="G" bits="8" numericFormat="USCALED"/>
+ <component name="R" bits="8" numericFormat="USCALED"/>
+ </format>
+ <format name="VK_FORMAT_B8G8R8_SSCALED" class="24-bit" blockSize="3" texelsPerBlock="1">
+ <component name="B" bits="8" numericFormat="SSCALED"/>
+ <component name="G" bits="8" numericFormat="SSCALED"/>
+ <component name="R" bits="8" numericFormat="SSCALED"/>
+ </format>
+ <format name="VK_FORMAT_B8G8R8_UINT" class="24-bit" blockSize="3" texelsPerBlock="1">
+ <component name="B" bits="8" numericFormat="UINT"/>
+ <component name="G" bits="8" numericFormat="UINT"/>
+ <component name="R" bits="8" numericFormat="UINT"/>
+ </format>
+ <format name="VK_FORMAT_B8G8R8_SINT" class="24-bit" blockSize="3" texelsPerBlock="1">
+ <component name="B" bits="8" numericFormat="SINT"/>
+ <component name="G" bits="8" numericFormat="SINT"/>
+ <component name="R" bits="8" numericFormat="SINT"/>
+ </format>
+ <format name="VK_FORMAT_B8G8R8_SRGB" class="24-bit" blockSize="3" texelsPerBlock="1">
+ <component name="B" bits="8" numericFormat="SRGB"/>
+ <component name="G" bits="8" numericFormat="SRGB"/>
+ <component name="R" bits="8" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_R8G8B8A8_UNORM" class="32-bit" blockSize="4" texelsPerBlock="1">
+ <component name="R" bits="8" numericFormat="UNORM"/>
+ <component name="G" bits="8" numericFormat="UNORM"/>
+ <component name="B" bits="8" numericFormat="UNORM"/>
+ <component name="A" bits="8" numericFormat="UNORM"/>
+ <spirvimageformat name="Rgba8"/>
+ </format>
+ <format name="VK_FORMAT_R8G8B8A8_SNORM" class="32-bit" blockSize="4" texelsPerBlock="1">
+ <component name="R" bits="8" numericFormat="SNORM"/>
+ <component name="G" bits="8" numericFormat="SNORM"/>
+ <component name="B" bits="8" numericFormat="SNORM"/>
+ <component name="A" bits="8" numericFormat="SNORM"/>
+ <spirvimageformat name="Rgba8Snorm"/>
+ </format>
+ <format name="VK_FORMAT_R8G8B8A8_USCALED" class="32-bit" blockSize="4" texelsPerBlock="1">
+ <component name="R" bits="8" numericFormat="USCALED"/>
+ <component name="G" bits="8" numericFormat="USCALED"/>
+ <component name="B" bits="8" numericFormat="USCALED"/>
+ <component name="A" bits="8" numericFormat="USCALED"/>
+ </format>
+ <format name="VK_FORMAT_R8G8B8A8_SSCALED" class="32-bit" blockSize="4" texelsPerBlock="1">
+ <component name="R" bits="8" numericFormat="SSCALED"/>
+ <component name="G" bits="8" numericFormat="SSCALED"/>
+ <component name="B" bits="8" numericFormat="SSCALED"/>
+ <component name="A" bits="8" numericFormat="SSCALED"/>
+ </format>
+ <format name="VK_FORMAT_R8G8B8A8_UINT" class="32-bit" blockSize="4" texelsPerBlock="1">
+ <component name="R" bits="8" numericFormat="UINT"/>
+ <component name="G" bits="8" numericFormat="UINT"/>
+ <component name="B" bits="8" numericFormat="UINT"/>
+ <component name="A" bits="8" numericFormat="UINT"/>
+ <spirvimageformat name="Rgba8ui"/>
+ </format>
+ <format name="VK_FORMAT_R8G8B8A8_SINT" class="32-bit" blockSize="4" texelsPerBlock="1">
+ <component name="R" bits="8" numericFormat="SINT"/>
+ <component name="G" bits="8" numericFormat="SINT"/>
+ <component name="B" bits="8" numericFormat="SINT"/>
+ <component name="A" bits="8" numericFormat="SINT"/>
+ <spirvimageformat name="Rgba8i"/>
+ </format>
+ <format name="VK_FORMAT_R8G8B8A8_SRGB" class="32-bit" blockSize="4" texelsPerBlock="1">
+ <component name="R" bits="8" numericFormat="SRGB"/>
+ <component name="G" bits="8" numericFormat="SRGB"/>
+ <component name="B" bits="8" numericFormat="SRGB"/>
+ <component name="A" bits="8" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_B8G8R8A8_UNORM" class="32-bit" blockSize="4" texelsPerBlock="1">
+ <component name="B" bits="8" numericFormat="UNORM"/>
+ <component name="G" bits="8" numericFormat="UNORM"/>
+ <component name="R" bits="8" numericFormat="UNORM"/>
+ <component name="A" bits="8" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_B8G8R8A8_SNORM" class="32-bit" blockSize="4" texelsPerBlock="1">
+ <component name="B" bits="8" numericFormat="SNORM"/>
+ <component name="G" bits="8" numericFormat="SNORM"/>
+ <component name="R" bits="8" numericFormat="SNORM"/>
+ <component name="A" bits="8" numericFormat="SNORM"/>
+ </format>
+ <format name="VK_FORMAT_B8G8R8A8_USCALED" class="32-bit" blockSize="4" texelsPerBlock="1">
+ <component name="B" bits="8" numericFormat="USCALED"/>
+ <component name="G" bits="8" numericFormat="USCALED"/>
+ <component name="R" bits="8" numericFormat="USCALED"/>
+ <component name="A" bits="8" numericFormat="USCALED"/>
+ </format>
+ <format name="VK_FORMAT_B8G8R8A8_SSCALED" class="32-bit" blockSize="4" texelsPerBlock="1">
+ <component name="B" bits="8" numericFormat="SSCALED"/>
+ <component name="G" bits="8" numericFormat="SSCALED"/>
+ <component name="R" bits="8" numericFormat="SSCALED"/>
+ <component name="A" bits="8" numericFormat="SSCALED"/>
+ </format>
+ <format name="VK_FORMAT_B8G8R8A8_UINT" class="32-bit" blockSize="4" texelsPerBlock="1">
+ <component name="B" bits="8" numericFormat="UINT"/>
+ <component name="G" bits="8" numericFormat="UINT"/>
+ <component name="R" bits="8" numericFormat="UINT"/>
+ <component name="A" bits="8" numericFormat="UINT"/>
+ </format>
+ <format name="VK_FORMAT_B8G8R8A8_SINT" class="32-bit" blockSize="4" texelsPerBlock="1">
+ <component name="B" bits="8" numericFormat="SINT"/>
+ <component name="G" bits="8" numericFormat="SINT"/>
+ <component name="R" bits="8" numericFormat="SINT"/>
+ <component name="A" bits="8" numericFormat="SINT"/>
+ </format>
+ <format name="VK_FORMAT_B8G8R8A8_SRGB" class="32-bit" blockSize="4" texelsPerBlock="1">
+ <component name="B" bits="8" numericFormat="SRGB"/>
+ <component name="G" bits="8" numericFormat="SRGB"/>
+ <component name="R" bits="8" numericFormat="SRGB"/>
+ <component name="A" bits="8" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_A8B8G8R8_UNORM_PACK32" class="32-bit" blockSize="4" texelsPerBlock="1" packed="32">
+ <component name="A" bits="8" numericFormat="UNORM"/>
+ <component name="B" bits="8" numericFormat="UNORM"/>
+ <component name="G" bits="8" numericFormat="UNORM"/>
+ <component name="R" bits="8" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_A8B8G8R8_SNORM_PACK32" class="32-bit" blockSize="4" texelsPerBlock="1" packed="32">
+ <component name="A" bits="8" numericFormat="SNORM"/>
+ <component name="B" bits="8" numericFormat="SNORM"/>
+ <component name="G" bits="8" numericFormat="SNORM"/>
+ <component name="R" bits="8" numericFormat="SNORM"/>
+ </format>
+ <format name="VK_FORMAT_A8B8G8R8_USCALED_PACK32" class="32-bit" blockSize="4" texelsPerBlock="1" packed="32">
+ <component name="A" bits="8" numericFormat="USCALED"/>
+ <component name="B" bits="8" numericFormat="USCALED"/>
+ <component name="G" bits="8" numericFormat="USCALED"/>
+ <component name="R" bits="8" numericFormat="USCALED"/>
+ </format>
+ <format name="VK_FORMAT_A8B8G8R8_SSCALED_PACK32" class="32-bit" blockSize="4" texelsPerBlock="1" packed="32">
+ <component name="A" bits="8" numericFormat="SSCALED"/>
+ <component name="B" bits="8" numericFormat="SSCALED"/>
+ <component name="G" bits="8" numericFormat="SSCALED"/>
+ <component name="R" bits="8" numericFormat="SSCALED"/>
+ </format>
+ <format name="VK_FORMAT_A8B8G8R8_UINT_PACK32" class="32-bit" blockSize="4" texelsPerBlock="1" packed="32">
+ <component name="A" bits="8" numericFormat="UINT"/>
+ <component name="B" bits="8" numericFormat="UINT"/>
+ <component name="G" bits="8" numericFormat="UINT"/>
+ <component name="R" bits="8" numericFormat="UINT"/>
+ </format>
+ <format name="VK_FORMAT_A8B8G8R8_SINT_PACK32" class="32-bit" blockSize="4" texelsPerBlock="1" packed="32">
+ <component name="A" bits="8" numericFormat="SINT"/>
+ <component name="B" bits="8" numericFormat="SINT"/>
+ <component name="G" bits="8" numericFormat="SINT"/>
+ <component name="R" bits="8" numericFormat="SINT"/>
+ </format>
+ <format name="VK_FORMAT_A8B8G8R8_SRGB_PACK32" class="32-bit" blockSize="4" texelsPerBlock="1" packed="32">
+ <component name="A" bits="8" numericFormat="SRGB"/>
+ <component name="B" bits="8" numericFormat="SRGB"/>
+ <component name="G" bits="8" numericFormat="SRGB"/>
+ <component name="R" bits="8" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_A2R10G10B10_UNORM_PACK32" class="32-bit" blockSize="4" texelsPerBlock="1" packed="32">
+ <component name="A" bits="2" numericFormat="UNORM"/>
+ <component name="R" bits="10" numericFormat="UNORM"/>
+ <component name="G" bits="10" numericFormat="UNORM"/>
+ <component name="B" bits="10" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_A2R10G10B10_SNORM_PACK32" class="32-bit" blockSize="4" texelsPerBlock="1" packed="32">
+ <component name="A" bits="2" numericFormat="SNORM"/>
+ <component name="R" bits="10" numericFormat="SNORM"/>
+ <component name="G" bits="10" numericFormat="SNORM"/>
+ <component name="B" bits="10" numericFormat="SNORM"/>
+ </format>
+ <format name="VK_FORMAT_A2R10G10B10_USCALED_PACK32" class="32-bit" blockSize="4" texelsPerBlock="1" packed="32">
+ <component name="A" bits="2" numericFormat="USCALED"/>
+ <component name="R" bits="10" numericFormat="USCALED"/>
+ <component name="G" bits="10" numericFormat="USCALED"/>
+ <component name="B" bits="10" numericFormat="USCALED"/>
+ </format>
+ <format name="VK_FORMAT_A2R10G10B10_SSCALED_PACK32" class="32-bit" blockSize="4" texelsPerBlock="1" packed="32">
+ <component name="A" bits="2" numericFormat="SSCALED"/>
+ <component name="R" bits="10" numericFormat="SSCALED"/>
+ <component name="G" bits="10" numericFormat="SSCALED"/>
+ <component name="B" bits="10" numericFormat="SSCALED"/>
+ </format>
+ <format name="VK_FORMAT_A2R10G10B10_UINT_PACK32" class="32-bit" blockSize="4" texelsPerBlock="1" packed="32">
+ <component name="A" bits="2" numericFormat="UINT"/>
+ <component name="R" bits="10" numericFormat="UINT"/>
+ <component name="G" bits="10" numericFormat="UINT"/>
+ <component name="B" bits="10" numericFormat="UINT"/>
+ </format>
+ <format name="VK_FORMAT_A2R10G10B10_SINT_PACK32" class="32-bit" blockSize="4" texelsPerBlock="1" packed="32">
+ <component name="A" bits="2" numericFormat="SINT"/>
+ <component name="R" bits="10" numericFormat="SINT"/>
+ <component name="G" bits="10" numericFormat="SINT"/>
+ <component name="B" bits="10" numericFormat="SINT"/>
+ </format>
+ <format name="VK_FORMAT_A2B10G10R10_UNORM_PACK32" class="32-bit" blockSize="4" texelsPerBlock="1" packed="32">
+ <component name="A" bits="2" numericFormat="UNORM"/>
+ <component name="B" bits="10" numericFormat="UNORM"/>
+ <component name="G" bits="10" numericFormat="UNORM"/>
+ <component name="R" bits="10" numericFormat="UNORM"/>
+ <spirvimageformat name="Rgb10A2"/>
+ </format>
+ <format name="VK_FORMAT_A2B10G10R10_SNORM_PACK32" class="32-bit" blockSize="4" texelsPerBlock="1" packed="32">
+ <component name="A" bits="2" numericFormat="SNORM"/>
+ <component name="B" bits="10" numericFormat="SNORM"/>
+ <component name="G" bits="10" numericFormat="SNORM"/>
+ <component name="R" bits="10" numericFormat="SNORM"/>
+ </format>
+ <format name="VK_FORMAT_A2B10G10R10_USCALED_PACK32" class="32-bit" blockSize="4" texelsPerBlock="1" packed="32">
+ <component name="A" bits="2" numericFormat="USCALED"/>
+ <component name="B" bits="10" numericFormat="USCALED"/>
+ <component name="G" bits="10" numericFormat="USCALED"/>
+ <component name="R" bits="10" numericFormat="USCALED"/>
+ </format>
+ <format name="VK_FORMAT_A2B10G10R10_SSCALED_PACK32" class="32-bit" blockSize="4" texelsPerBlock="1" packed="32">
+ <component name="A" bits="2" numericFormat="SSCALED"/>
+ <component name="B" bits="10" numericFormat="SSCALED"/>
+ <component name="G" bits="10" numericFormat="SSCALED"/>
+ <component name="R" bits="10" numericFormat="SSCALED"/>
+ </format>
+ <format name="VK_FORMAT_A2B10G10R10_UINT_PACK32" class="32-bit" blockSize="4" texelsPerBlock="1" packed="32">
+ <component name="A" bits="2" numericFormat="UINT"/>
+ <component name="B" bits="10" numericFormat="UINT"/>
+ <component name="G" bits="10" numericFormat="UINT"/>
+ <component name="R" bits="10" numericFormat="UINT"/>
+ <spirvimageformat name="Rgb10a2ui"/>
+ </format>
+ <format name="VK_FORMAT_A2B10G10R10_SINT_PACK32" class="32-bit" blockSize="4" texelsPerBlock="1" packed="32">
+ <component name="A" bits="2" numericFormat="SINT"/>
+ <component name="B" bits="10" numericFormat="SINT"/>
+ <component name="G" bits="10" numericFormat="SINT"/>
+ <component name="R" bits="10" numericFormat="SINT"/>
+ </format>
+ <format name="VK_FORMAT_R16_UNORM" class="16-bit" blockSize="2" texelsPerBlock="1">
+ <component name="R" bits="16" numericFormat="UNORM"/>
+ <spirvimageformat name="R16"/>
+ </format>
+ <format name="VK_FORMAT_R16_SNORM" class="16-bit" blockSize="2" texelsPerBlock="1">
+ <component name="R" bits="16" numericFormat="SNORM"/>
+ <spirvimageformat name="R16Snorm"/>
+ </format>
+ <format name="VK_FORMAT_R16_USCALED" class="16-bit" blockSize="2" texelsPerBlock="1">
+ <component name="R" bits="16" numericFormat="USCALED"/>
+ </format>
+ <format name="VK_FORMAT_R16_SSCALED" class="16-bit" blockSize="2" texelsPerBlock="1">
+ <component name="R" bits="16" numericFormat="SSCALED"/>
+ </format>
+ <format name="VK_FORMAT_R16_UINT" class="16-bit" blockSize="2" texelsPerBlock="1">
+ <component name="R" bits="16" numericFormat="UINT"/>
+ <spirvimageformat name="R16ui"/>
+ </format>
+ <format name="VK_FORMAT_R16_SINT" class="16-bit" blockSize="2" texelsPerBlock="1">
+ <component name="R" bits="16" numericFormat="SINT"/>
+ <spirvimageformat name="R16i"/>
+ </format>
+ <format name="VK_FORMAT_R16_SFLOAT" class="16-bit" blockSize="2" texelsPerBlock="1">
+ <component name="R" bits="16" numericFormat="SFLOAT"/>
+ <spirvimageformat name="R16f"/>
+ </format>
+ <format name="VK_FORMAT_R16G16_UNORM" class="32-bit" blockSize="4" texelsPerBlock="1">
+ <component name="R" bits="16" numericFormat="UNORM"/>
+ <component name="G" bits="16" numericFormat="UNORM"/>
+ <spirvimageformat name="Rg16"/>
+ </format>
+ <format name="VK_FORMAT_R16G16_SNORM" class="32-bit" blockSize="4" texelsPerBlock="1">
+ <component name="R" bits="16" numericFormat="SNORM"/>
+ <component name="G" bits="16" numericFormat="SNORM"/>
+ <spirvimageformat name="Rg16Snorm"/>
+ </format>
+ <format name="VK_FORMAT_R16G16_USCALED" class="32-bit" blockSize="4" texelsPerBlock="1">
+ <component name="R" bits="16" numericFormat="USCALED"/>
+ <component name="G" bits="16" numericFormat="USCALED"/>
+ </format>
+ <format name="VK_FORMAT_R16G16_SSCALED" class="32-bit" blockSize="4" texelsPerBlock="1">
+ <component name="R" bits="16" numericFormat="SSCALED"/>
+ <component name="G" bits="16" numericFormat="SSCALED"/>
+ </format>
+ <format name="VK_FORMAT_R16G16_UINT" class="32-bit" blockSize="4" texelsPerBlock="1">
+ <component name="R" bits="16" numericFormat="UINT"/>
+ <component name="G" bits="16" numericFormat="UINT"/>
+ <spirvimageformat name="Rg16ui"/>
+ </format>
+ <format name="VK_FORMAT_R16G16_SINT" class="32-bit" blockSize="4" texelsPerBlock="1">
+ <component name="R" bits="16" numericFormat="SINT"/>
+ <component name="G" bits="16" numericFormat="SINT"/>
+ <spirvimageformat name="Rg16i"/>
+ </format>
+ <format name="VK_FORMAT_R16G16_SFLOAT" class="32-bit" blockSize="4" texelsPerBlock="1">
+ <component name="R" bits="16" numericFormat="SFLOAT"/>
+ <component name="G" bits="16" numericFormat="SFLOAT"/>
+ <spirvimageformat name="Rg16f"/>
+ </format>
+ <format name="VK_FORMAT_R16G16B16_UNORM" class="48-bit" blockSize="6" texelsPerBlock="1">
+ <component name="R" bits="16" numericFormat="UNORM"/>
+ <component name="G" bits="16" numericFormat="UNORM"/>
+ <component name="B" bits="16" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_R16G16B16_SNORM" class="48-bit" blockSize="6" texelsPerBlock="1">
+ <component name="R" bits="16" numericFormat="SNORM"/>
+ <component name="G" bits="16" numericFormat="SNORM"/>
+ <component name="B" bits="16" numericFormat="SNORM"/>
+ </format>
+ <format name="VK_FORMAT_R16G16B16_USCALED" class="48-bit" blockSize="6" texelsPerBlock="1">
+ <component name="R" bits="16" numericFormat="USCALED"/>
+ <component name="G" bits="16" numericFormat="USCALED"/>
+ <component name="B" bits="16" numericFormat="USCALED"/>
+ </format>
+ <format name="VK_FORMAT_R16G16B16_SSCALED" class="48-bit" blockSize="6" texelsPerBlock="1">
+ <component name="R" bits="16" numericFormat="SSCALED"/>
+ <component name="G" bits="16" numericFormat="SSCALED"/>
+ <component name="B" bits="16" numericFormat="SSCALED"/>
+ </format>
+ <format name="VK_FORMAT_R16G16B16_UINT" class="48-bit" blockSize="6" texelsPerBlock="1">
+ <component name="R" bits="16" numericFormat="UINT"/>
+ <component name="G" bits="16" numericFormat="UINT"/>
+ <component name="B" bits="16" numericFormat="UINT"/>
+ </format>
+ <format name="VK_FORMAT_R16G16B16_SINT" class="48-bit" blockSize="6" texelsPerBlock="1">
+ <component name="R" bits="16" numericFormat="SINT"/>
+ <component name="G" bits="16" numericFormat="SINT"/>
+ <component name="B" bits="16" numericFormat="SINT"/>
+ </format>
+ <format name="VK_FORMAT_R16G16B16_SFLOAT" class="48-bit" blockSize="6" texelsPerBlock="1">
+ <component name="R" bits="16" numericFormat="SFLOAT"/>
+ <component name="G" bits="16" numericFormat="SFLOAT"/>
+ <component name="B" bits="16" numericFormat="SFLOAT"/>
+ </format>
+ <format name="VK_FORMAT_R16G16B16A16_UNORM" class="64-bit" blockSize="8" texelsPerBlock="1">
+ <component name="R" bits="16" numericFormat="UNORM"/>
+ <component name="G" bits="16" numericFormat="UNORM"/>
+ <component name="B" bits="16" numericFormat="UNORM"/>
+ <component name="A" bits="16" numericFormat="UNORM"/>
+ <spirvimageformat name="Rgba16"/>
+ </format>
+ <format name="VK_FORMAT_R16G16B16A16_SNORM" class="64-bit" blockSize="8" texelsPerBlock="1">
+ <component name="R" bits="16" numericFormat="SNORM"/>
+ <component name="G" bits="16" numericFormat="SNORM"/>
+ <component name="B" bits="16" numericFormat="SNORM"/>
+ <component name="A" bits="16" numericFormat="SNORM"/>
+ <spirvimageformat name="Rgba16Snorm"/>
+ </format>
+ <format name="VK_FORMAT_R16G16B16A16_USCALED" class="64-bit" blockSize="8" texelsPerBlock="1">
+ <component name="R" bits="16" numericFormat="USCALED"/>
+ <component name="G" bits="16" numericFormat="USCALED"/>
+ <component name="B" bits="16" numericFormat="USCALED"/>
+ <component name="A" bits="16" numericFormat="USCALED"/>
+ </format>
+ <format name="VK_FORMAT_R16G16B16A16_SSCALED" class="64-bit" blockSize="8" texelsPerBlock="1">
+ <component name="R" bits="16" numericFormat="SSCALED"/>
+ <component name="G" bits="16" numericFormat="SSCALED"/>
+ <component name="B" bits="16" numericFormat="SSCALED"/>
+ <component name="A" bits="16" numericFormat="SSCALED"/>
+ </format>
+ <format name="VK_FORMAT_R16G16B16A16_UINT" class="64-bit" blockSize="8" texelsPerBlock="1">
+ <component name="R" bits="16" numericFormat="UINT"/>
+ <component name="G" bits="16" numericFormat="UINT"/>
+ <component name="B" bits="16" numericFormat="UINT"/>
+ <component name="A" bits="16" numericFormat="UINT"/>
+ <spirvimageformat name="Rgba16ui"/>
+ </format>
+ <format name="VK_FORMAT_R16G16B16A16_SINT" class="64-bit" blockSize="8" texelsPerBlock="1">
+ <component name="R" bits="16" numericFormat="SINT"/>
+ <component name="G" bits="16" numericFormat="SINT"/>
+ <component name="B" bits="16" numericFormat="SINT"/>
+ <component name="A" bits="16" numericFormat="SINT"/>
+ <spirvimageformat name="Rgba16i"/>
+ </format>
+ <format name="VK_FORMAT_R16G16B16A16_SFLOAT" class="64-bit" blockSize="8" texelsPerBlock="1">
+ <component name="R" bits="16" numericFormat="SFLOAT"/>
+ <component name="G" bits="16" numericFormat="SFLOAT"/>
+ <component name="B" bits="16" numericFormat="SFLOAT"/>
+ <component name="A" bits="16" numericFormat="SFLOAT"/>
+ <spirvimageformat name="Rgba16f"/>
+ </format>
+ <format name="VK_FORMAT_R32_UINT" class="32-bit" blockSize="4" texelsPerBlock="1">
+ <component name="R" bits="32" numericFormat="UINT"/>
+ <spirvimageformat name="R32ui"/>
+ </format>
+ <format name="VK_FORMAT_R32_SINT" class="32-bit" blockSize="4" texelsPerBlock="1">
+ <component name="R" bits="32" numericFormat="SINT"/>
+ <spirvimageformat name="R32i"/>
+ </format>
+ <format name="VK_FORMAT_R32_SFLOAT" class="32-bit" blockSize="4" texelsPerBlock="1">
+ <component name="R" bits="32" numericFormat="SFLOAT"/>
+ <spirvimageformat name="R32f"/>
+ </format>
+ <format name="VK_FORMAT_R32G32_UINT" class="64-bit" blockSize="8" texelsPerBlock="1">
+ <component name="R" bits="32" numericFormat="UINT"/>
+ <component name="G" bits="32" numericFormat="UINT"/>
+ <spirvimageformat name="Rg32ui"/>
+ </format>
+ <format name="VK_FORMAT_R32G32_SINT" class="64-bit" blockSize="8" texelsPerBlock="1">
+ <component name="R" bits="32" numericFormat="SINT"/>
+ <component name="G" bits="32" numericFormat="SINT"/>
+ <spirvimageformat name="Rg32i"/>
+ </format>
+ <format name="VK_FORMAT_R32G32_SFLOAT" class="64-bit" blockSize="8" texelsPerBlock="1">
+ <component name="R" bits="32" numericFormat="SFLOAT"/>
+ <component name="G" bits="32" numericFormat="SFLOAT"/>
+ <spirvimageformat name="Rg32f"/>
+ </format>
+ <format name="VK_FORMAT_R32G32B32_UINT" class="96-bit" blockSize="12" texelsPerBlock="1">
+ <component name="R" bits="32" numericFormat="UINT"/>
+ <component name="G" bits="32" numericFormat="UINT"/>
+ <component name="B" bits="32" numericFormat="UINT"/>
+ </format>
+ <format name="VK_FORMAT_R32G32B32_SINT" class="96-bit" blockSize="12" texelsPerBlock="1">
+ <component name="R" bits="32" numericFormat="SINT"/>
+ <component name="G" bits="32" numericFormat="SINT"/>
+ <component name="B" bits="32" numericFormat="SINT"/>
+ </format>
+ <format name="VK_FORMAT_R32G32B32_SFLOAT" class="96-bit" blockSize="12" texelsPerBlock="1">
+ <component name="R" bits="32" numericFormat="SFLOAT"/>
+ <component name="G" bits="32" numericFormat="SFLOAT"/>
+ <component name="B" bits="32" numericFormat="SFLOAT"/>
+ </format>
+ <format name="VK_FORMAT_R32G32B32A32_UINT" class="128-bit" blockSize="16" texelsPerBlock="1">
+ <component name="R" bits="32" numericFormat="UINT"/>
+ <component name="G" bits="32" numericFormat="UINT"/>
+ <component name="B" bits="32" numericFormat="UINT"/>
+ <component name="A" bits="32" numericFormat="UINT"/>
+ <spirvimageformat name="Rgba32ui"/>
+ </format>
+ <format name="VK_FORMAT_R32G32B32A32_SINT" class="128-bit" blockSize="16" texelsPerBlock="1">
+ <component name="R" bits="32" numericFormat="SINT"/>
+ <component name="G" bits="32" numericFormat="SINT"/>
+ <component name="B" bits="32" numericFormat="SINT"/>
+ <component name="A" bits="32" numericFormat="SINT"/>
+ <spirvimageformat name="Rgba32i"/>
+ </format>
+ <format name="VK_FORMAT_R32G32B32A32_SFLOAT" class="128-bit" blockSize="16" texelsPerBlock="1">
+ <component name="R" bits="32" numericFormat="SFLOAT"/>
+ <component name="G" bits="32" numericFormat="SFLOAT"/>
+ <component name="B" bits="32" numericFormat="SFLOAT"/>
+ <component name="A" bits="32" numericFormat="SFLOAT"/>
+ <spirvimageformat name="Rgba32f"/>
+ </format>
+ <format name="VK_FORMAT_R64_UINT" class="64-bit" blockSize="8" texelsPerBlock="1">
+ <component name="R" bits="64" numericFormat="UINT"/>
+ <spirvimageformat name="R64ui"/>
+ </format>
+ <format name="VK_FORMAT_R64_SINT" class="64-bit" blockSize="8" texelsPerBlock="1">
+ <component name="R" bits="64" numericFormat="SINT"/>
+ <spirvimageformat name="R64i"/>
+ </format>
+ <format name="VK_FORMAT_R64_SFLOAT" class="64-bit" blockSize="8" texelsPerBlock="1">
+ <component name="R" bits="64" numericFormat="SFLOAT"/>
+ </format>
+ <format name="VK_FORMAT_R64G64_UINT" class="128-bit" blockSize="16" texelsPerBlock="1">
+ <component name="R" bits="64" numericFormat="UINT"/>
+ <component name="B" bits="64" numericFormat="UINT"/>
+ </format>
+ <format name="VK_FORMAT_R64G64_SINT" class="128-bit" blockSize="16" texelsPerBlock="1">
+ <component name="R" bits="64" numericFormat="SINT"/>
+ <component name="B" bits="64" numericFormat="SINT"/>
+ </format>
+ <format name="VK_FORMAT_R64G64_SFLOAT" class="128-bit" blockSize="16" texelsPerBlock="1">
+ <component name="R" bits="64" numericFormat="SFLOAT"/>
+ <component name="B" bits="64" numericFormat="SFLOAT"/>
+ </format>
+ <format name="VK_FORMAT_R64G64B64_UINT" class="192-bit" blockSize="24" texelsPerBlock="1">
+ <component name="R" bits="64" numericFormat="UINT"/>
+ <component name="G" bits="64" numericFormat="UINT"/>
+ <component name="B" bits="64" numericFormat="UINT"/>
+ </format>
+ <format name="VK_FORMAT_R64G64B64_SINT" class="192-bit" blockSize="24" texelsPerBlock="1">
+ <component name="R" bits="64" numericFormat="SINT"/>
+ <component name="G" bits="64" numericFormat="SINT"/>
+ <component name="B" bits="64" numericFormat="SINT"/>
+ </format>
+ <format name="VK_FORMAT_R64G64B64_SFLOAT" class="192-bit" blockSize="24" texelsPerBlock="1">
+ <component name="R" bits="64" numericFormat="SFLOAT"/>
+ <component name="G" bits="64" numericFormat="SFLOAT"/>
+ <component name="B" bits="64" numericFormat="SFLOAT"/>
+ </format>
+ <format name="VK_FORMAT_R64G64B64A64_UINT" class="256-bit" blockSize="32" texelsPerBlock="1">
+ <component name="R" bits="64" numericFormat="UINT"/>
+ <component name="G" bits="64" numericFormat="UINT"/>
+ <component name="B" bits="64" numericFormat="UINT"/>
+ <component name="A" bits="64" numericFormat="UINT"/>
+ </format>
+ <format name="VK_FORMAT_R64G64B64A64_SINT" class="256-bit" blockSize="32" texelsPerBlock="1">
+ <component name="R" bits="64" numericFormat="SINT"/>
+ <component name="G" bits="64" numericFormat="SINT"/>
+ <component name="B" bits="64" numericFormat="SINT"/>
+ <component name="A" bits="64" numericFormat="SINT"/>
+ </format>
+ <format name="VK_FORMAT_R64G64B64A64_SFLOAT" class="256-bit" blockSize="32" texelsPerBlock="1">
+ <component name="R" bits="64" numericFormat="SFLOAT"/>
+ <component name="G" bits="64" numericFormat="SFLOAT"/>
+ <component name="B" bits="64" numericFormat="SFLOAT"/>
+ <component name="A" bits="64" numericFormat="SFLOAT"/>
+ </format>
+ <format name="VK_FORMAT_B10G11R11_UFLOAT_PACK32" class="32-bit" blockSize="4" texelsPerBlock="1" packed="32">
+ <component name="B" bits="10" numericFormat="UFLOAT"/>
+ <component name="G" bits="11" numericFormat="UFLOAT"/>
+ <component name="R" bits="10" numericFormat="UFLOAT"/>
+ <spirvimageformat name="R11fG11fB10f"/>
+ </format>
+ <format name="VK_FORMAT_E5B9G9R9_UFLOAT_PACK32" class="32-bit" blockSize="4" texelsPerBlock="1" packed="32">
+ <component name="B" bits="9" numericFormat="UFLOAT"/>
+ <component name="G" bits="9" numericFormat="UFLOAT"/>
+ <component name="R" bits="9" numericFormat="UFLOAT"/>
+ </format>
+ <format name="VK_FORMAT_D16_UNORM" class="D16" blockSize="2" texelsPerBlock="1">
+ <component name="D" bits="16" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_X8_D24_UNORM_PACK32" class="D24" blockSize="4" texelsPerBlock="1" packed="32">
+ <component name="D" bits="24" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_D32_SFLOAT" class="D32" blockSize="4" texelsPerBlock="1">
+ <component name="D" bits="32" numericFormat="SFLOAT"/>
+ </format>
+ <format name="VK_FORMAT_S8_UINT" class="S8" blockSize="1" texelsPerBlock="1">
+ <component name="S" bits="8" numericFormat="UINT"/>
+ </format>
+ <format name="VK_FORMAT_D16_UNORM_S8_UINT" class="D16S8" blockSize="3" texelsPerBlock="1">
+ <component name="D" bits="16" numericFormat="UNORM"/>
+ <component name="S" bits="8" numericFormat="UINT"/>
+ </format>
+ <format name="VK_FORMAT_D24_UNORM_S8_UINT" class="D24S8" blockSize="4" texelsPerBlock="1">
+ <component name="D" bits="24" numericFormat="UNORM"/>
+ <component name="S" bits="8" numericFormat="UINT"/>
+ </format>
+ <format name="VK_FORMAT_D32_SFLOAT_S8_UINT" class="D32S8" blockSize="5" texelsPerBlock="1">
+ <component name="D" bits="32" numericFormat="SFLOAT"/>
+ <component name="S" bits="8" numericFormat="UINT"/>
+ </format>
+ <format name="VK_FORMAT_BC1_RGB_UNORM_BLOCK" class="BC1_RGB" blockSize="8" texelsPerBlock="16" blockExtent="4,4,1" compressed="BC">
+ <component name="R" bits="compressed" numericFormat="UNORM"/>
+ <component name="G" bits="compressed" numericFormat="UNORM"/>
+ <component name="B" bits="compressed" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_BC1_RGB_SRGB_BLOCK" class="BC1_RGB" blockSize="8" texelsPerBlock="16" blockExtent="4,4,1" compressed="BC">
+ <component name="R" bits="compressed" numericFormat="SRGB"/>
+ <component name="G" bits="compressed" numericFormat="SRGB"/>
+ <component name="B" bits="compressed" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_BC1_RGBA_UNORM_BLOCK" class="BC1_RGBA" blockSize="8" texelsPerBlock="16" blockExtent="4,4,1" compressed="BC">
+ <component name="R" bits="compressed" numericFormat="UNORM"/>
+ <component name="G" bits="compressed" numericFormat="UNORM"/>
+ <component name="B" bits="compressed" numericFormat="UNORM"/>
+ <component name="A" bits="compressed" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_BC1_RGBA_SRGB_BLOCK" class="BC1_RGBA" blockSize="8" texelsPerBlock="16" blockExtent="4,4,1" compressed="BC">
+ <component name="R" bits="compressed" numericFormat="SRGB"/>
+ <component name="G" bits="compressed" numericFormat="SRGB"/>
+ <component name="B" bits="compressed" numericFormat="SRGB"/>
+ <component name="A" bits="compressed" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_BC2_UNORM_BLOCK" class="BC2" blockSize="16" texelsPerBlock="16" blockExtent="4,4,1" compressed="BC">
+ <component name="R" bits="compressed" numericFormat="UNORM"/>
+ <component name="G" bits="compressed" numericFormat="UNORM"/>
+ <component name="B" bits="compressed" numericFormat="UNORM"/>
+ <component name="A" bits="compressed" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_BC2_SRGB_BLOCK" class="BC2" blockSize="16" texelsPerBlock="16" blockExtent="4,4,1" compressed="BC">
+ <component name="R" bits="compressed" numericFormat="SRGB"/>
+ <component name="G" bits="compressed" numericFormat="SRGB"/>
+ <component name="B" bits="compressed" numericFormat="SRGB"/>
+ <component name="A" bits="compressed" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_BC3_UNORM_BLOCK" class="BC3" blockSize="16" texelsPerBlock="16" blockExtent="4,4,1" compressed="BC">
+ <component name="R" bits="compressed" numericFormat="UNORM"/>
+ <component name="G" bits="compressed" numericFormat="UNORM"/>
+ <component name="B" bits="compressed" numericFormat="UNORM"/>
+ <component name="A" bits="compressed" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_BC3_SRGB_BLOCK" class="BC3" blockSize="16" texelsPerBlock="16" blockExtent="4,4,1" compressed="BC">
+ <component name="R" bits="compressed" numericFormat="SRGB"/>
+ <component name="G" bits="compressed" numericFormat="SRGB"/>
+ <component name="B" bits="compressed" numericFormat="SRGB"/>
+ <component name="A" bits="compressed" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_BC4_UNORM_BLOCK" class="BC4" blockSize="8" texelsPerBlock="16" blockExtent="4,4,1" compressed="BC">
+ <component name="R" bits="compressed" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_BC4_SNORM_BLOCK" class="BC4" blockSize="8" texelsPerBlock="16" blockExtent="4,4,1" compressed="BC">
+ <component name="R" bits="compressed" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_BC5_UNORM_BLOCK" class="BC5" blockSize="16" texelsPerBlock="16" blockExtent="4,4,1" compressed="BC">
+ <component name="R" bits="compressed" numericFormat="UNORM"/>
+ <component name="G" bits="compressed" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_BC5_SNORM_BLOCK" class="BC5" blockSize="16" texelsPerBlock="16" blockExtent="4,4,1" compressed="BC">
+ <component name="R" bits="compressed" numericFormat="SRGB"/>
+ <component name="G" bits="compressed" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_BC6H_UFLOAT_BLOCK" class="BC6H" blockSize="16" texelsPerBlock="16" blockExtent="4,4,1" compressed="BC">
+ <component name="R" bits="compressed" numericFormat="UFLOAT"/>
+ <component name="G" bits="compressed" numericFormat="UFLOAT"/>
+ <component name="B" bits="compressed" numericFormat="UFLOAT"/>
+ </format>
+ <format name="VK_FORMAT_BC6H_SFLOAT_BLOCK" class="BC6H" blockSize="16" texelsPerBlock="16" blockExtent="4,4,1" compressed="BC">
+ <component name="R" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="G" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="B" bits="compressed" numericFormat="SFLOAT"/>
+ </format>
+ <format name="VK_FORMAT_BC7_UNORM_BLOCK" class="BC7" blockSize="16" texelsPerBlock="16" blockExtent="4,4,1" compressed="BC">
+ <component name="R" bits="compressed" numericFormat="UNORM"/>
+ <component name="G" bits="compressed" numericFormat="UNORM"/>
+ <component name="B" bits="compressed" numericFormat="UNORM"/>
+ <component name="A" bits="compressed" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_BC7_SRGB_BLOCK" class="BC7" blockSize="16" texelsPerBlock="16" blockExtent="4,4,1" compressed="BC">
+ <component name="R" bits="compressed" numericFormat="SRGB"/>
+ <component name="G" bits="compressed" numericFormat="SRGB"/>
+ <component name="B" bits="compressed" numericFormat="SRGB"/>
+ <component name="A" bits="compressed" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK" class="ETC2_RGB" blockSize="8" texelsPerBlock="16" blockExtent="4,4,1" compressed="ETC2">
+ <component name="R" bits="compressed" numericFormat="UNORM"/>
+ <component name="G" bits="compressed" numericFormat="UNORM"/>
+ <component name="B" bits="compressed" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK" class="ETC2_RGB" blockSize="8" texelsPerBlock="16" blockExtent="4,4,1" compressed="ETC2">
+ <component name="R" bits="compressed" numericFormat="SRGB"/>
+ <component name="G" bits="compressed" numericFormat="SRGB"/>
+ <component name="B" bits="compressed" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK" class="ETC2_RGBA" blockSize="8" texelsPerBlock="16" blockExtent="4,4,1" compressed="ETC2">
+ <component name="R" bits="compressed" numericFormat="UNORM"/>
+ <component name="G" bits="compressed" numericFormat="UNORM"/>
+ <component name="B" bits="compressed" numericFormat="UNORM"/>
+ <component name="A" bits="compressed" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK" class="ETC2_RGBA" blockSize="8" texelsPerBlock="16" blockExtent="4,4,1" compressed="ETC2">
+ <component name="R" bits="compressed" numericFormat="SRGB"/>
+ <component name="G" bits="compressed" numericFormat="SRGB"/>
+ <component name="B" bits="compressed" numericFormat="SRGB"/>
+ <component name="A" bits="compressed" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK" class="ETC2_EAC_RGBA" blockSize="16" texelsPerBlock="16" blockExtent="4,4,1" compressed="ETC2">
+ <component name="R" bits="compressed" numericFormat="UNORM"/>
+ <component name="G" bits="compressed" numericFormat="UNORM"/>
+ <component name="B" bits="compressed" numericFormat="UNORM"/>
+ <component name="A" bits="compressed" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK" class="ETC2_EAC_RGBA" blockSize="16" texelsPerBlock="16" blockExtent="4,4,1" compressed="ETC2">
+ <component name="R" bits="compressed" numericFormat="SRGB"/>
+ <component name="G" bits="compressed" numericFormat="SRGB"/>
+ <component name="B" bits="compressed" numericFormat="SRGB"/>
+ <component name="A" bits="compressed" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_EAC_R11_UNORM_BLOCK" class="EAC_R" blockSize="8" texelsPerBlock="16" blockExtent="4,4,1" compressed="EAC">
+ <component name="R" bits="11" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_EAC_R11_SNORM_BLOCK" class="EAC_R" blockSize="8" texelsPerBlock="16" blockExtent="4,4,1" compressed="EAC">
+ <component name="R" bits="11" numericFormat="SNORM"/>
+ </format>
+ <format name="VK_FORMAT_EAC_R11G11_UNORM_BLOCK" class="EAC_RG" blockSize="16" texelsPerBlock="16" blockExtent="4,4,1" compressed="EAC">
+ <component name="R" bits="11" numericFormat="UNORM"/>
+ <component name="G" bits="11" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_EAC_R11G11_SNORM_BLOCK" class="EAC_RG" blockSize="16" texelsPerBlock="16" blockExtent="4,4,1" compressed="EAC">
+ <component name="R" bits="11" numericFormat="SNORM"/>
+ <component name="G" bits="11" numericFormat="SNORM"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_4x4_UNORM_BLOCK" class="ASTC_4x4" blockSize="16" texelsPerBlock="16" blockExtent="4,4,1" compressed="ASTC LDR">
+ <component name="R" bits="compressed" numericFormat="UNORM"/>
+ <component name="G" bits="compressed" numericFormat="UNORM"/>
+ <component name="B" bits="compressed" numericFormat="UNORM"/>
+ <component name="A" bits="compressed" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_4x4_SRGB_BLOCK" class="ASTC_4x4" blockSize="16" texelsPerBlock="16" blockExtent="4,4,1" compressed="ASTC LDR">
+ <component name="R" bits="compressed" numericFormat="SRGB"/>
+ <component name="G" bits="compressed" numericFormat="SRGB"/>
+ <component name="B" bits="compressed" numericFormat="SRGB"/>
+ <component name="A" bits="compressed" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_5x4_UNORM_BLOCK" class="ASTC_5x4" blockSize="16" texelsPerBlock="20" blockExtent="5,4,1" compressed="ASTC LDR">
+ <component name="R" bits="compressed" numericFormat="UNORM"/>
+ <component name="G" bits="compressed" numericFormat="UNORM"/>
+ <component name="B" bits="compressed" numericFormat="UNORM"/>
+ <component name="A" bits="compressed" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_5x4_SRGB_BLOCK" class="ASTC_5x4" blockSize="16" texelsPerBlock="20" blockExtent="5,4,1" compressed="ASTC LDR">
+ <component name="R" bits="compressed" numericFormat="SRGB"/>
+ <component name="G" bits="compressed" numericFormat="SRGB"/>
+ <component name="B" bits="compressed" numericFormat="SRGB"/>
+ <component name="A" bits="compressed" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_5x5_UNORM_BLOCK" class="ASTC_5x5" blockSize="16" texelsPerBlock="25" blockExtent="5,5,1" compressed="ASTC LDR">
+ <component name="R" bits="compressed" numericFormat="UNORM"/>
+ <component name="G" bits="compressed" numericFormat="UNORM"/>
+ <component name="B" bits="compressed" numericFormat="UNORM"/>
+ <component name="A" bits="compressed" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_5x5_SRGB_BLOCK" class="ASTC_5x5" blockSize="16" texelsPerBlock="25" blockExtent="5,5,1" compressed="ASTC LDR">
+ <component name="R" bits="compressed" numericFormat="SRGB"/>
+ <component name="G" bits="compressed" numericFormat="SRGB"/>
+ <component name="B" bits="compressed" numericFormat="SRGB"/>
+ <component name="A" bits="compressed" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_6x5_UNORM_BLOCK" class="ASTC_6x5" blockSize="16" texelsPerBlock="30" blockExtent="6,5,1" compressed="ASTC LDR">
+ <component name="R" bits="compressed" numericFormat="UNORM"/>
+ <component name="G" bits="compressed" numericFormat="UNORM"/>
+ <component name="B" bits="compressed" numericFormat="UNORM"/>
+ <component name="A" bits="compressed" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_6x5_SRGB_BLOCK" class="ASTC_6x5" blockSize="16" texelsPerBlock="30" blockExtent="6,5,1" compressed="ASTC LDR">
+ <component name="R" bits="compressed" numericFormat="SRGB"/>
+ <component name="G" bits="compressed" numericFormat="SRGB"/>
+ <component name="B" bits="compressed" numericFormat="SRGB"/>
+ <component name="A" bits="compressed" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_6x6_UNORM_BLOCK" class="ASTC_6x6" blockSize="16" texelsPerBlock="36" blockExtent="6,6,1" compressed="ASTC LDR">
+ <component name="R" bits="compressed" numericFormat="UNORM"/>
+ <component name="G" bits="compressed" numericFormat="UNORM"/>
+ <component name="B" bits="compressed" numericFormat="UNORM"/>
+ <component name="A" bits="compressed" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_6x6_SRGB_BLOCK" class="ASTC_6x6" blockSize="16" texelsPerBlock="36" blockExtent="6,6,1" compressed="ASTC LDR">
+ <component name="R" bits="compressed" numericFormat="SRGB"/>
+ <component name="G" bits="compressed" numericFormat="SRGB"/>
+ <component name="B" bits="compressed" numericFormat="SRGB"/>
+ <component name="A" bits="compressed" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_8x5_UNORM_BLOCK" class="ASTC_8x5" blockSize="16" texelsPerBlock="40" blockExtent="8,5,1" compressed="ASTC LDR">
+ <component name="R" bits="compressed" numericFormat="UNORM"/>
+ <component name="G" bits="compressed" numericFormat="UNORM"/>
+ <component name="B" bits="compressed" numericFormat="UNORM"/>
+ <component name="A" bits="compressed" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_8x5_SRGB_BLOCK" class="ASTC_8x5" blockSize="16" texelsPerBlock="40" blockExtent="8,5,1" compressed="ASTC LDR">
+ <component name="R" bits="compressed" numericFormat="SRGB"/>
+ <component name="G" bits="compressed" numericFormat="SRGB"/>
+ <component name="B" bits="compressed" numericFormat="SRGB"/>
+ <component name="A" bits="compressed" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_8x6_UNORM_BLOCK" class="ASTC_8x6" blockSize="16" texelsPerBlock="48" blockExtent="8,6,1" compressed="ASTC LDR">
+ <component name="R" bits="compressed" numericFormat="UNORM"/>
+ <component name="G" bits="compressed" numericFormat="UNORM"/>
+ <component name="B" bits="compressed" numericFormat="UNORM"/>
+ <component name="A" bits="compressed" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_8x6_SRGB_BLOCK" class="ASTC_8x6" blockSize="16" texelsPerBlock="48" blockExtent="8,6,1" compressed="ASTC LDR">
+ <component name="R" bits="compressed" numericFormat="SRGB"/>
+ <component name="G" bits="compressed" numericFormat="SRGB"/>
+ <component name="B" bits="compressed" numericFormat="SRGB"/>
+ <component name="A" bits="compressed" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_8x8_UNORM_BLOCK" class="ASTC_8x8" blockSize="16" texelsPerBlock="64" blockExtent="8,8,1" compressed="ASTC LDR">
+ <component name="R" bits="compressed" numericFormat="UNORM"/>
+ <component name="G" bits="compressed" numericFormat="UNORM"/>
+ <component name="B" bits="compressed" numericFormat="UNORM"/>
+ <component name="A" bits="compressed" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_8x8_SRGB_BLOCK" class="ASTC_8x8" blockSize="16" texelsPerBlock="64" blockExtent="8,8,1" compressed="ASTC LDR">
+ <component name="R" bits="compressed" numericFormat="SRGB"/>
+ <component name="G" bits="compressed" numericFormat="SRGB"/>
+ <component name="B" bits="compressed" numericFormat="SRGB"/>
+ <component name="A" bits="compressed" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_10x5_UNORM_BLOCK" class="ASTC_10x5" blockSize="16" texelsPerBlock="50" blockExtent="10,5,1" compressed="ASTC LDR">
+ <component name="R" bits="compressed" numericFormat="UNORM"/>
+ <component name="G" bits="compressed" numericFormat="UNORM"/>
+ <component name="B" bits="compressed" numericFormat="UNORM"/>
+ <component name="A" bits="compressed" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_10x5_SRGB_BLOCK" class="ASTC_10x5" blockSize="16" texelsPerBlock="50" blockExtent="10,5,1" compressed="ASTC LDR">
+ <component name="R" bits="compressed" numericFormat="SRGB"/>
+ <component name="G" bits="compressed" numericFormat="SRGB"/>
+ <component name="B" bits="compressed" numericFormat="SRGB"/>
+ <component name="A" bits="compressed" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_10x6_UNORM_BLOCK" class="ASTC_10x6" blockSize="16" texelsPerBlock="60" blockExtent="10,6,1" compressed="ASTC LDR">
+ <component name="R" bits="compressed" numericFormat="UNORM"/>
+ <component name="G" bits="compressed" numericFormat="UNORM"/>
+ <component name="B" bits="compressed" numericFormat="UNORM"/>
+ <component name="A" bits="compressed" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_10x6_SRGB_BLOCK" class="ASTC_10x6" blockSize="16" texelsPerBlock="60" blockExtent="10,6,1" compressed="ASTC LDR">
+ <component name="R" bits="compressed" numericFormat="SRGB"/>
+ <component name="G" bits="compressed" numericFormat="SRGB"/>
+ <component name="B" bits="compressed" numericFormat="SRGB"/>
+ <component name="A" bits="compressed" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_10x8_UNORM_BLOCK" class="ASTC_10x8" blockSize="16" texelsPerBlock="80" blockExtent="10,8,1" compressed="ASTC LDR">
+ <component name="R" bits="compressed" numericFormat="UNORM"/>
+ <component name="G" bits="compressed" numericFormat="UNORM"/>
+ <component name="B" bits="compressed" numericFormat="UNORM"/>
+ <component name="A" bits="compressed" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_10x8_SRGB_BLOCK" class="ASTC_10x8" blockSize="16" texelsPerBlock="80" blockExtent="10,8,1" compressed="ASTC LDR">
+ <component name="R" bits="compressed" numericFormat="SRGB"/>
+ <component name="G" bits="compressed" numericFormat="SRGB"/>
+ <component name="B" bits="compressed" numericFormat="SRGB"/>
+ <component name="A" bits="compressed" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_10x10_UNORM_BLOCK" class="ASTC_10x10" blockSize="16" texelsPerBlock="100" blockExtent="10,10,1" compressed="ASTC LDR">
+ <component name="R" bits="compressed" numericFormat="UNORM"/>
+ <component name="G" bits="compressed" numericFormat="UNORM"/>
+ <component name="B" bits="compressed" numericFormat="UNORM"/>
+ <component name="A" bits="compressed" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_10x10_SRGB_BLOCK" class="ASTC_10x10" blockSize="16" texelsPerBlock="100" blockExtent="10,10,1" compressed="ASTC LDR">
+ <component name="R" bits="compressed" numericFormat="SRGB"/>
+ <component name="G" bits="compressed" numericFormat="SRGB"/>
+ <component name="B" bits="compressed" numericFormat="SRGB"/>
+ <component name="A" bits="compressed" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_12x10_UNORM_BLOCK" class="ASTC_12x10" blockSize="16" texelsPerBlock="120" blockExtent="12,10,1" compressed="ASTC LDR">
+ <component name="R" bits="compressed" numericFormat="UNORM"/>
+ <component name="G" bits="compressed" numericFormat="UNORM"/>
+ <component name="B" bits="compressed" numericFormat="UNORM"/>
+ <component name="A" bits="compressed" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_12x10_SRGB_BLOCK" class="ASTC_12x10" blockSize="16" texelsPerBlock="120" blockExtent="12,10,1" compressed="ASTC LDR">
+ <component name="R" bits="compressed" numericFormat="SRGB"/>
+ <component name="G" bits="compressed" numericFormat="SRGB"/>
+ <component name="B" bits="compressed" numericFormat="SRGB"/>
+ <component name="A" bits="compressed" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_12x12_UNORM_BLOCK" class="ASTC_12x12" blockSize="16" texelsPerBlock="144" blockExtent="12,12,1" compressed="ASTC LDR">
+ <component name="R" bits="compressed" numericFormat="UNORM"/>
+ <component name="G" bits="compressed" numericFormat="UNORM"/>
+ <component name="B" bits="compressed" numericFormat="UNORM"/>
+ <component name="A" bits="compressed" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_12x12_SRGB_BLOCK" class="ASTC_12x12" blockSize="16" texelsPerBlock="144" blockExtent="12,12,1" compressed="ASTC LDR">
+ <component name="R" bits="compressed" numericFormat="SRGB"/>
+ <component name="G" bits="compressed" numericFormat="SRGB"/>
+ <component name="B" bits="compressed" numericFormat="SRGB"/>
+ <component name="A" bits="compressed" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_G8B8G8R8_422_UNORM" class="32-bit G8B8G8R8" blockSize="4" texelsPerBlock="1" blockExtent="2,1,1" chroma="422">
+ <component name="G" bits="8" numericFormat="UNORM"/>
+ <component name="B" bits="8" numericFormat="UNORM"/>
+ <component name="G" bits="8" numericFormat="UNORM"/>
+ <component name="R" bits="8" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_B8G8R8G8_422_UNORM" class="32-bit B8G8R8G8" blockSize="4" texelsPerBlock="1" blockExtent="2,1,1" chroma="422">
+ <component name="B" bits="8" numericFormat="UNORM"/>
+ <component name="G" bits="8" numericFormat="UNORM"/>
+ <component name="R" bits="8" numericFormat="UNORM"/>
+ <component name="G" bits="8" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM" class="8-bit 3-plane 420" blockSize="3" texelsPerBlock="1" chroma="420">
+ <component name="G" bits="8" numericFormat="UNORM" planeIndex="0"/>
+ <component name="B" bits="8" numericFormat="UNORM" planeIndex="1"/>
+ <component name="R" bits="8" numericFormat="UNORM" planeIndex="2"/>
+ <plane index="0" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R8_UNORM"/>
+ <plane index="1" widthDivisor="2" heightDivisor="2" compatible="VK_FORMAT_R8_UNORM"/>
+ <plane index="2" widthDivisor="2" heightDivisor="2" compatible="VK_FORMAT_R8_UNORM"/>
+ </format>
+ <format name="VK_FORMAT_G8_B8R8_2PLANE_420_UNORM" class="8-bit 2-plane 420" blockSize="3" texelsPerBlock="1" chroma="420">
+ <component name="G" bits="8" numericFormat="UNORM" planeIndex="0"/>
+ <component name="B" bits="8" numericFormat="UNORM" planeIndex="1"/>
+ <component name="R" bits="8" numericFormat="UNORM" planeIndex="1"/>
+ <plane index="0" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R8_UNORM"/>
+ <plane index="1" widthDivisor="2" heightDivisor="2" compatible="VK_FORMAT_R8G8_UNORM"/>
+ </format>
+ <format name="VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM" class="8-bit 3-plane 422" blockSize="3" texelsPerBlock="1" chroma="422">
+ <component name="G" bits="8" numericFormat="UNORM" planeIndex="0"/>
+ <component name="B" bits="8" numericFormat="UNORM" planeIndex="1"/>
+ <component name="R" bits="8" numericFormat="UNORM" planeIndex="2"/>
+ <plane index="0" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R8_UNORM"/>
+ <plane index="1" widthDivisor="2" heightDivisor="1" compatible="VK_FORMAT_R8_UNORM"/>
+ <plane index="2" widthDivisor="2" heightDivisor="1" compatible="VK_FORMAT_R8_UNORM"/>
+ </format>
+ <format name="VK_FORMAT_G8_B8R8_2PLANE_422_UNORM" class="8-bit 2-plane 422" blockSize="3" texelsPerBlock="1" chroma="422">
+ <component name="G" bits="8" numericFormat="UNORM" planeIndex="0"/>
+ <component name="B" bits="8" numericFormat="UNORM" planeIndex="1"/>
+ <component name="R" bits="8" numericFormat="UNORM" planeIndex="1"/>
+ <plane index="0" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R8_UNORM"/>
+ <plane index="1" widthDivisor="2" heightDivisor="1" compatible="VK_FORMAT_R8G8_UNORM"/>
+ </format>
+ <format name="VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM" class="8-bit 3-plane 444" blockSize="3" texelsPerBlock="1" chroma="444">
+ <component name="G" bits="8" numericFormat="UNORM" planeIndex="0"/>
+ <component name="B" bits="8" numericFormat="UNORM" planeIndex="1"/>
+ <component name="R" bits="8" numericFormat="UNORM" planeIndex="2"/>
+ <plane index="0" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R8_UNORM"/>
+ <plane index="1" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R8_UNORM"/>
+ <plane index="2" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R8_UNORM"/>
+ </format>
+ <format name="VK_FORMAT_R10X6_UNORM_PACK16" class="16-bit" blockSize="2" texelsPerBlock="1" packed="16">
+ <component name="R" bits="10" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_R10X6G10X6_UNORM_2PACK16" class="32-bit" blockSize="4" texelsPerBlock="1" packed="16">
+ <component name="R" bits="10" numericFormat="UNORM"/>
+ <component name="G" bits="10" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16" class="64-bit R10G10B10A10" blockSize="8" texelsPerBlock="1" packed="16" chroma="444">
+ <component name="R" bits="10" numericFormat="UNORM"/>
+ <component name="G" bits="10" numericFormat="UNORM"/>
+ <component name="B" bits="10" numericFormat="UNORM"/>
+ <component name="A" bits="10" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16" class="64-bit G10B10G10R10" blockSize="8" texelsPerBlock="1" blockExtent="2,1,1" packed="16" chroma="422">
+ <component name="G" bits="10" numericFormat="UNORM"/>
+ <component name="B" bits="10" numericFormat="UNORM"/>
+ <component name="G" bits="10" numericFormat="UNORM"/>
+ <component name="R" bits="10" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16" class="64-bit B10G10R10G10" blockSize="8" texelsPerBlock="1" blockExtent="2,1,1" packed="16" chroma="422">
+ <component name="B" bits="10" numericFormat="UNORM"/>
+ <component name="G" bits="10" numericFormat="UNORM"/>
+ <component name="R" bits="10" numericFormat="UNORM"/>
+ <component name="G" bits="10" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16" class="10-bit 3-plane 420" blockSize="6" texelsPerBlock="1" packed="16" chroma="420">
+ <component name="G" bits="10" numericFormat="UNORM" planeIndex="0"/>
+ <component name="B" bits="10" numericFormat="UNORM" planeIndex="1"/>
+ <component name="R" bits="10" numericFormat="UNORM" planeIndex="2"/>
+ <plane index="0" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R10X6_UNORM_PACK16"/>
+ <plane index="1" widthDivisor="2" heightDivisor="2" compatible="VK_FORMAT_R10X6_UNORM_PACK16"/>
+ <plane index="2" widthDivisor="2" heightDivisor="2" compatible="VK_FORMAT_R10X6_UNORM_PACK16"/>
+ </format>
+ <format name="VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16" class="10-bit 2-plane 420" blockSize="6" texelsPerBlock="1" packed="16" chroma="420">
+ <component name="G" bits="10" numericFormat="UNORM" planeIndex="0"/>
+ <component name="B" bits="10" numericFormat="UNORM" planeIndex="1"/>
+ <component name="R" bits="10" numericFormat="UNORM" planeIndex="1"/>
+ <plane index="0" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R10X6_UNORM_PACK16"/>
+ <plane index="1" widthDivisor="2" heightDivisor="2" compatible="VK_FORMAT_R10X6G10X6_UNORM_2PACK16"/>
+ </format>
+ <format name="VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16" class="10-bit 3-plane 422" blockSize="6" texelsPerBlock="1" packed="16" chroma="422">
+ <component name="G" bits="10" numericFormat="UNORM" planeIndex="0"/>
+ <component name="B" bits="10" numericFormat="UNORM" planeIndex="1"/>
+ <component name="R" bits="10" numericFormat="UNORM" planeIndex="2"/>
+ <plane index="0" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R10X6_UNORM_PACK16"/>
+ <plane index="1" widthDivisor="2" heightDivisor="1" compatible="VK_FORMAT_R10X6_UNORM_PACK16"/>
+ <plane index="2" widthDivisor="2" heightDivisor="1" compatible="VK_FORMAT_R10X6_UNORM_PACK16"/>
+ </format>
+ <format name="VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16" class="10-bit 2-plane 422" blockSize="6" texelsPerBlock="1" packed="16" chroma="422">
+ <component name="G" bits="10" numericFormat="UNORM" planeIndex="0"/>
+ <component name="B" bits="10" numericFormat="UNORM" planeIndex="1"/>
+ <component name="R" bits="10" numericFormat="UNORM" planeIndex="1"/>
+ <plane index="0" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R10X6_UNORM_PACK16"/>
+ <plane index="1" widthDivisor="2" heightDivisor="1" compatible="VK_FORMAT_R10X6G10X6_UNORM_2PACK16"/>
+ </format>
+ <format name="VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16" class="10-bit 3-plane 444" blockSize="6" texelsPerBlock="1" packed="16" chroma="444">
+ <component name="G" bits="10" numericFormat="UNORM" planeIndex="0"/>
+ <component name="B" bits="10" numericFormat="UNORM" planeIndex="1"/>
+ <component name="R" bits="10" numericFormat="UNORM" planeIndex="2"/>
+ <plane index="0" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R10X6_UNORM_PACK16"/>
+ <plane index="1" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R10X6_UNORM_PACK16"/>
+ <plane index="2" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R10X6_UNORM_PACK16"/>
+ </format>
+ <format name="VK_FORMAT_R12X4_UNORM_PACK16" class="16-bit" blockSize="2" texelsPerBlock="1" packed="16">
+ <component name="R" bits="12" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_R12X4G12X4_UNORM_2PACK16" class="32-bit" blockSize="4" texelsPerBlock="1" packed="16">
+ <component name="R" bits="12" numericFormat="UNORM"/>
+ <component name="G" bits="12" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16" class="64-bit R12G12B12A12" blockSize="8" texelsPerBlock="1" packed="16" chroma="444">
+ <component name="R" bits="12" numericFormat="UNORM"/>
+ <component name="G" bits="12" numericFormat="UNORM"/>
+ <component name="B" bits="12" numericFormat="UNORM"/>
+ <component name="A" bits="12" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16" class="64-bit G12B12G12R12" blockSize="8" texelsPerBlock="1" blockExtent="2,1,1" packed="16" chroma="422">
+ <component name="G" bits="12" numericFormat="UNORM"/>
+ <component name="B" bits="12" numericFormat="UNORM"/>
+ <component name="G" bits="12" numericFormat="UNORM"/>
+ <component name="R" bits="12" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16" class="64-bit B12G12R12G12" blockSize="8" texelsPerBlock="1" blockExtent="2,1,1" packed="16" chroma="422">
+ <component name="B" bits="12" numericFormat="UNORM"/>
+ <component name="G" bits="12" numericFormat="UNORM"/>
+ <component name="R" bits="12" numericFormat="UNORM"/>
+ <component name="G" bits="12" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16" class="12-bit 3-plane 420" blockSize="6" texelsPerBlock="1" packed="16" chroma="420">
+ <component name="G" bits="12" numericFormat="UNORM" planeIndex="0"/>
+ <component name="B" bits="12" numericFormat="UNORM" planeIndex="1"/>
+ <component name="R" bits="12" numericFormat="UNORM" planeIndex="2"/>
+ <plane index="0" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R12X4_UNORM_PACK16"/>
+ <plane index="1" widthDivisor="2" heightDivisor="2" compatible="VK_FORMAT_R12X4_UNORM_PACK16"/>
+ <plane index="2" widthDivisor="2" heightDivisor="2" compatible="VK_FORMAT_R12X4_UNORM_PACK16"/>
+ </format>
+ <format name="VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16" class="12-bit 2-plane 420" blockSize="6" texelsPerBlock="1" packed="16" chroma="420">
+ <component name="G" bits="12" numericFormat="UNORM" planeIndex="0"/>
+ <component name="B" bits="12" numericFormat="UNORM" planeIndex="1"/>
+ <component name="R" bits="12" numericFormat="UNORM" planeIndex="1"/>
+ <plane index="0" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R12X4_UNORM_PACK16"/>
+ <plane index="1" widthDivisor="2" heightDivisor="2" compatible="VK_FORMAT_R12X4G12X4_UNORM_2PACK16"/>
+ </format>
+ <format name="VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16" class="12-bit 3-plane 422" blockSize="6" texelsPerBlock="1" packed="16" chroma="422">
+ <component name="G" bits="12" numericFormat="UNORM" planeIndex="0"/>
+ <component name="B" bits="12" numericFormat="UNORM" planeIndex="1"/>
+ <component name="R" bits="12" numericFormat="UNORM" planeIndex="2"/>
+ <plane index="0" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R12X4_UNORM_PACK16"/>
+ <plane index="1" widthDivisor="2" heightDivisor="1" compatible="VK_FORMAT_R12X4_UNORM_PACK16"/>
+ <plane index="2" widthDivisor="2" heightDivisor="1" compatible="VK_FORMAT_R12X4_UNORM_PACK16"/>
+ </format>
+ <format name="VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16" class="12-bit 2-plane 422" blockSize="6" texelsPerBlock="1" packed="16" chroma="422">
+ <component name="G" bits="12" numericFormat="UNORM" planeIndex="0"/>
+ <component name="B" bits="12" numericFormat="UNORM" planeIndex="1"/>
+ <component name="R" bits="12" numericFormat="UNORM" planeIndex="1"/>
+ <plane index="0" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R12X4_UNORM_PACK16"/>
+ <plane index="1" widthDivisor="2" heightDivisor="1" compatible="VK_FORMAT_R12X4G12X4_UNORM_2PACK16"/>
+ </format>
+ <format name="VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16" class="12-bit 3-plane 444" blockSize="6" texelsPerBlock="1" packed="16" chroma="444">
+ <component name="G" bits="12" numericFormat="UNORM" planeIndex="0"/>
+ <component name="B" bits="12" numericFormat="UNORM" planeIndex="1"/>
+ <component name="R" bits="12" numericFormat="UNORM" planeIndex="2"/>
+ <plane index="0" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R12X4_UNORM_PACK16"/>
+ <plane index="1" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R12X4_UNORM_PACK16"/>
+ <plane index="2" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R12X4_UNORM_PACK16"/>
+ </format>
+ <format name="VK_FORMAT_G16B16G16R16_422_UNORM" class="64-bit G16B16G16R16" blockSize="8" texelsPerBlock="1" blockExtent="2,1,1" chroma="422">
+ <component name="G" bits="16" numericFormat="UNORM"/>
+ <component name="B" bits="16" numericFormat="UNORM"/>
+ <component name="G" bits="16" numericFormat="UNORM"/>
+ <component name="R" bits="16" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_B16G16R16G16_422_UNORM" class="64-bit B16G16R16G16" blockSize="8" texelsPerBlock="1" blockExtent="2,1,1" chroma="422">
+ <component name="B" bits="16" numericFormat="UNORM"/>
+ <component name="G" bits="16" numericFormat="UNORM"/>
+ <component name="R" bits="16" numericFormat="UNORM"/>
+ <component name="G" bits="16" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM" class="16-bit 3-plane 420" blockSize="6" texelsPerBlock="1" chroma="420">
+ <component name="G" bits="16" numericFormat="UNORM" planeIndex="0"/>
+ <component name="B" bits="16" numericFormat="UNORM" planeIndex="1"/>
+ <component name="R" bits="16" numericFormat="UNORM" planeIndex="2"/>
+ <plane index="0" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R16_UNORM"/>
+ <plane index="1" widthDivisor="2" heightDivisor="2" compatible="VK_FORMAT_R16_UNORM"/>
+ <plane index="2" widthDivisor="2" heightDivisor="2" compatible="VK_FORMAT_R16_UNORM"/>
+ </format>
+ <format name="VK_FORMAT_G16_B16R16_2PLANE_420_UNORM" class="16-bit 2-plane 420" blockSize="6" texelsPerBlock="1" chroma="420">
+ <component name="G" bits="16" numericFormat="UNORM" planeIndex="0"/>
+ <component name="B" bits="16" numericFormat="UNORM" planeIndex="1"/>
+ <component name="R" bits="16" numericFormat="UNORM" planeIndex="1"/>
+ <plane index="0" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R16_UNORM"/>
+ <plane index="1" widthDivisor="2" heightDivisor="2" compatible="VK_FORMAT_R16G16_UNORM"/>
+ </format>
+ <format name="VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM" class="16-bit 3-plane 422" blockSize="6" texelsPerBlock="1" chroma="422">
+ <component name="G" bits="16" numericFormat="UNORM" planeIndex="0"/>
+ <component name="B" bits="16" numericFormat="UNORM" planeIndex="1"/>
+ <component name="R" bits="16" numericFormat="UNORM" planeIndex="2"/>
+ <plane index="0" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R16_UNORM"/>
+ <plane index="1" widthDivisor="2" heightDivisor="1" compatible="VK_FORMAT_R16_UNORM"/>
+ <plane index="2" widthDivisor="2" heightDivisor="1" compatible="VK_FORMAT_R16_UNORM"/>
+ </format>
+ <format name="VK_FORMAT_G16_B16R16_2PLANE_422_UNORM" class="16-bit 2-plane 422" blockSize="6" texelsPerBlock="1" chroma="422">
+ <component name="G" bits="16" numericFormat="UNORM" planeIndex="0"/>
+ <component name="B" bits="16" numericFormat="UNORM" planeIndex="1"/>
+ <component name="R" bits="16" numericFormat="UNORM" planeIndex="1"/>
+ <plane index="0" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R16_UNORM"/>
+ <plane index="1" widthDivisor="2" heightDivisor="1" compatible="VK_FORMAT_R16G16_UNORM"/>
+ </format>
+ <format name="VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM" class="16-bit 3-plane 444" blockSize="6" texelsPerBlock="1" chroma="444">
+ <component name="G" bits="16" numericFormat="UNORM" planeIndex="0"/>
+ <component name="B" bits="16" numericFormat="UNORM" planeIndex="1"/>
+ <component name="R" bits="16" numericFormat="UNORM" planeIndex="2"/>
+ <plane index="0" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R16_UNORM"/>
+ <plane index="1" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R16_UNORM"/>
+ <plane index="2" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R16_UNORM"/>
+ </format>
+ <format name="VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG" class="PVRTC1_2BPP" blockSize="8" texelsPerBlock="1" blockExtent="8,4,1" compressed="PVRTC">
+ <component name="R" bits="compressed" numericFormat="UNORM"/>
+ <component name="G" bits="compressed" numericFormat="UNORM"/>
+ <component name="B" bits="compressed" numericFormat="UNORM"/>
+ <component name="A" bits="compressed" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG" class="PVRTC1_4BPP" blockSize="8" texelsPerBlock="1" blockExtent="4,4,1" compressed="PVRTC">
+ <component name="R" bits="compressed" numericFormat="UNORM"/>
+ <component name="G" bits="compressed" numericFormat="UNORM"/>
+ <component name="B" bits="compressed" numericFormat="UNORM"/>
+ <component name="A" bits="compressed" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG" class="PVRTC2_2BPP" blockSize="8" texelsPerBlock="1" blockExtent="8,4,1" compressed="PVRTC">
+ <component name="R" bits="compressed" numericFormat="UNORM"/>
+ <component name="G" bits="compressed" numericFormat="UNORM"/>
+ <component name="B" bits="compressed" numericFormat="UNORM"/>
+ <component name="A" bits="compressed" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG" class="PVRTC2_4BPP" blockSize="8" texelsPerBlock="1" blockExtent="4,4,1" compressed="PVRTC">
+ <component name="R" bits="compressed" numericFormat="UNORM"/>
+ <component name="G" bits="compressed" numericFormat="UNORM"/>
+ <component name="B" bits="compressed" numericFormat="UNORM"/>
+ <component name="A" bits="compressed" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG" class="PVRTC1_2BPP" blockSize="8" texelsPerBlock="1" blockExtent="8,4,1" compressed="PVRTC">
+ <component name="R" bits="compressed" numericFormat="SRGB"/>
+ <component name="G" bits="compressed" numericFormat="SRGB"/>
+ <component name="B" bits="compressed" numericFormat="SRGB"/>
+ <component name="A" bits="compressed" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG" class="PVRTC1_4BPP" blockSize="8" texelsPerBlock="1" blockExtent="4,4,1" compressed="PVRTC">
+ <component name="R" bits="compressed" numericFormat="SRGB"/>
+ <component name="G" bits="compressed" numericFormat="SRGB"/>
+ <component name="B" bits="compressed" numericFormat="SRGB"/>
+ <component name="A" bits="compressed" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG" class="PVRTC2_2BPP" blockSize="8" texelsPerBlock="1" blockExtent="8,4,1" compressed="PVRTC">
+ <component name="R" bits="compressed" numericFormat="SRGB"/>
+ <component name="G" bits="compressed" numericFormat="SRGB"/>
+ <component name="B" bits="compressed" numericFormat="SRGB"/>
+ <component name="A" bits="compressed" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG" class="PVRTC2_4BPP" blockSize="8" texelsPerBlock="1" blockExtent="4,4,1" compressed="PVRTC">
+ <component name="R" bits="compressed" numericFormat="SRGB"/>
+ <component name="G" bits="compressed" numericFormat="SRGB"/>
+ <component name="B" bits="compressed" numericFormat="SRGB"/>
+ <component name="A" bits="compressed" numericFormat="SRGB"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK" class="ASTC_4x4" blockSize="16" texelsPerBlock="16" blockExtent="4,4,1" compressed="ASTC HDR">
+ <component name="R" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="G" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="B" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="A" bits="compressed" numericFormat="SFLOAT"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK" class="ASTC_5x4" blockSize="16" texelsPerBlock="20" blockExtent="5,4,1" compressed="ASTC HDR">
+ <component name="R" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="G" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="B" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="A" bits="compressed" numericFormat="SFLOAT"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK" class="ASTC_5x5" blockSize="16" texelsPerBlock="25" blockExtent="5,5,1" compressed="ASTC HDR">
+ <component name="R" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="G" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="B" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="A" bits="compressed" numericFormat="SFLOAT"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK" class="ASTC_6x5" blockSize="16" texelsPerBlock="30" blockExtent="6,5,1" compressed="ASTC HDR">
+ <component name="R" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="G" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="B" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="A" bits="compressed" numericFormat="SFLOAT"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK" class="ASTC_6x6" blockSize="16" texelsPerBlock="36" blockExtent="6,6,1" compressed="ASTC HDR">
+ <component name="R" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="G" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="B" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="A" bits="compressed" numericFormat="SFLOAT"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK" class="ASTC_8x5" blockSize="16" texelsPerBlock="40" blockExtent="8,5,1" compressed="ASTC HDR">
+ <component name="R" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="G" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="B" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="A" bits="compressed" numericFormat="SFLOAT"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK" class="ASTC_8x6" blockSize="16" texelsPerBlock="48" blockExtent="8,6,1" compressed="ASTC HDR">
+ <component name="R" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="G" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="B" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="A" bits="compressed" numericFormat="SFLOAT"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK" class="ASTC_8x8" blockSize="16" texelsPerBlock="64" blockExtent="8,8,1" compressed="ASTC HDR">
+ <component name="R" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="G" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="B" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="A" bits="compressed" numericFormat="SFLOAT"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK" class="ASTC_10x5" blockSize="16" texelsPerBlock="50" blockExtent="10,5,1" compressed="ASTC HDR">
+ <component name="R" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="G" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="B" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="A" bits="compressed" numericFormat="SFLOAT"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK" class="ASTC_10x6" blockSize="16" texelsPerBlock="60" blockExtent="10,6,1" compressed="ASTC HDR">
+ <component name="R" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="G" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="B" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="A" bits="compressed" numericFormat="SFLOAT"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK" class="ASTC_10x8" blockSize="16" texelsPerBlock="80" blockExtent="10,8,1" compressed="ASTC HDR">
+ <component name="R" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="G" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="B" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="A" bits="compressed" numericFormat="SFLOAT"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK" class="ASTC_10x10" blockSize="16" texelsPerBlock="100" blockExtent="10,10,1" compressed="ASTC HDR">
+ <component name="R" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="G" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="B" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="A" bits="compressed" numericFormat="SFLOAT"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK" class="ASTC_12x10" blockSize="16" texelsPerBlock="120" blockExtent="12,10,1" compressed="ASTC HDR">
+ <component name="R" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="G" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="B" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="A" bits="compressed" numericFormat="SFLOAT"/>
+ </format>
+ <format name="VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK" class="ASTC_12x12" blockSize="16" texelsPerBlock="144" blockExtent="12,12,1" compressed="ASTC HDR">
+ <component name="R" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="G" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="B" bits="compressed" numericFormat="SFLOAT"/>
+ <component name="A" bits="compressed" numericFormat="SFLOAT"/>
+ </format>
+ <format name="VK_FORMAT_G8_B8R8_2PLANE_444_UNORM" class="8-bit 2-plane 444" blockSize="3" texelsPerBlock="1" chroma="444">
+ <component name="G" bits="8" numericFormat="UNORM" planeIndex="0"/>
+ <component name="B" bits="8" numericFormat="UNORM" planeIndex="1"/>
+ <component name="R" bits="8" numericFormat="UNORM" planeIndex="1"/>
+ <plane index="0" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R8_UNORM"/>
+ <plane index="1" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R8G8_UNORM"/>
+ </format>
+ <format name="VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16" class="10-bit 2-plane 444" blockSize="6" texelsPerBlock="1" packed="16" chroma="444">
+ <component name="G" bits="10" numericFormat="UNORM" planeIndex="0"/>
+ <component name="B" bits="10" numericFormat="UNORM" planeIndex="1"/>
+ <component name="R" bits="10" numericFormat="UNORM" planeIndex="1"/>
+ <plane index="0" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R10X6_UNORM_PACK16"/>
+ <plane index="1" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R10X6G10X6_UNORM_2PACK16"/>
+ </format>
+ <format name="VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16" class="12-bit 2-plane 444" blockSize="6" texelsPerBlock="1" packed="16" chroma="444">
+ <component name="G" bits="12" numericFormat="UNORM" planeIndex="0"/>
+ <component name="B" bits="12" numericFormat="UNORM" planeIndex="1"/>
+ <component name="R" bits="12" numericFormat="UNORM" planeIndex="1"/>
+ <plane index="0" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R12X4_UNORM_PACK16"/>
+ <plane index="1" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R12X4G12X4_UNORM_2PACK16"/>
+ </format>
+ <format name="VK_FORMAT_G16_B16R16_2PLANE_444_UNORM" class="16-bit 2-plane 444" blockSize="6" texelsPerBlock="1" chroma="444">
+ <component name="G" bits="16" numericFormat="UNORM" planeIndex="0"/>
+ <component name="B" bits="16" numericFormat="UNORM" planeIndex="1"/>
+ <component name="R" bits="16" numericFormat="UNORM" planeIndex="1"/>
+ <plane index="0" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R16_UNORM"/>
+ <plane index="1" widthDivisor="1" heightDivisor="1" compatible="VK_FORMAT_R16G16_UNORM"/>
+ </format>
+ <format name="VK_FORMAT_A4R4G4B4_UNORM_PACK16" class="16-bit" blockSize="2" texelsPerBlock="1" packed="16">
+ <component name="A" bits="4" numericFormat="UNORM"/>
+ <component name="R" bits="4" numericFormat="UNORM"/>
+ <component name="G" bits="4" numericFormat="UNORM"/>
+ <component name="B" bits="4" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_A4B4G4R4_UNORM_PACK16" class="16-bit" blockSize="2" texelsPerBlock="1" packed="16">
+ <component name="A" bits="4" numericFormat="UNORM"/>
+ <component name="B" bits="4" numericFormat="UNORM"/>
+ <component name="G" bits="4" numericFormat="UNORM"/>
+ <component name="R" bits="4" numericFormat="UNORM"/>
+ </format>
+ <format name="VK_FORMAT_R16G16_S10_5_NV" class="32-bit" blockSize="4" texelsPerBlock="1">
+ <component name="R" bits="16" numericFormat="SINT"/>
+ <component name="G" bits="16" numericFormat="SINT"/>
+ </format>
+ </formats>
<spirvextensions comment="SPIR-V Extensions allowed in Vulkan and what is required to use it">
<spirvextension name="SPV_KHR_variable_pointers">
- <enable version="VK_API_VERSION_1_1"/>
+ <enable version="VK_VERSION_1_1"/>
<enable extension="VK_KHR_variable_pointers"/>
</spirvextension>
<spirvextension name="SPV_AMD_shader_explicit_vertex_parameter">
@@ -16712,27 +22376,30 @@ typedef void <name>CAMetalLayer</name>;
<spirvextension name="SPV_AMD_texture_gather_bias_lod">
<enable extension="VK_AMD_texture_gather_bias_lod"/>
</spirvextension>
+ <spirvextension name="SPV_AMD_shader_early_and_late_fragment_tests">
+ <enable extension="VK_AMD_shader_early_and_late_fragment_tests"/>
+ </spirvextension>
<spirvextension name="SPV_KHR_shader_draw_parameters">
- <enable version="VK_API_VERSION_1_1"/>
+ <enable version="VK_VERSION_1_1"/>
<enable extension="VK_KHR_shader_draw_parameters"/>
</spirvextension>
<spirvextension name="SPV_KHR_8bit_storage">
- <enable version="VK_API_VERSION_1_2"/>
+ <enable version="VK_VERSION_1_2"/>
<enable extension="VK_KHR_8bit_storage"/>
</spirvextension>
<spirvextension name="SPV_KHR_16bit_storage">
- <enable version="VK_API_VERSION_1_1"/>
+ <enable version="VK_VERSION_1_1"/>
<enable extension="VK_KHR_16bit_storage"/>
</spirvextension>
<spirvextension name="SPV_KHR_shader_clock">
<enable extension="VK_KHR_shader_clock"/>
</spirvextension>
<spirvextension name="SPV_KHR_float_controls">
- <enable version="VK_API_VERSION_1_2"/>
+ <enable version="VK_VERSION_1_2"/>
<enable extension="VK_KHR_shader_float_controls"/>
</spirvextension>
<spirvextension name="SPV_KHR_storage_buffer_storage_class">
- <enable version="VK_API_VERSION_1_1"/>
+ <enable version="VK_VERSION_1_1"/>
<enable extension="VK_KHR_storage_buffer_storage_class"/>
</spirvextension>
<spirvextension name="SPV_KHR_post_depth_coverage">
@@ -16762,19 +22429,22 @@ typedef void <name>CAMetalLayer</name>;
<spirvextension name="SPV_NV_shader_subgroup_partitioned">
<enable extension="VK_NV_shader_subgroup_partitioned"/>
</spirvextension>
+ <spirvextension name="SPV_NV_shader_invocation_reorder">
+ <enable extension="VK_NV_ray_tracing_invocation_reorder"/>
+ </spirvextension>
<spirvextension name="SPV_EXT_shader_viewport_index_layer">
- <enable version="VK_API_VERSION_1_2"/>
+ <enable version="VK_VERSION_1_2"/>
<enable extension="VK_EXT_shader_viewport_index_layer"/>
</spirvextension>
<spirvextension name="SPV_NVX_multiview_per_view_attributes">
<enable extension="VK_NVX_multiview_per_view_attributes"/>
</spirvextension>
<spirvextension name="SPV_EXT_descriptor_indexing">
- <enable version="VK_API_VERSION_1_2"/>
+ <enable version="VK_VERSION_1_2"/>
<enable extension="VK_EXT_descriptor_indexing"/>
</spirvextension>
<spirvextension name="SPV_KHR_vulkan_memory_model">
- <enable version="VK_API_VERSION_1_2"/>
+ <enable version="VK_VERSION_1_2"/>
<enable extension="VK_KHR_vulkan_memory_model"/>
</spirvextension>
<spirvextension name="SPV_NV_compute_shader_derivatives">
@@ -16798,6 +22468,9 @@ typedef void <name>CAMetalLayer</name>;
<spirvextension name="SPV_KHR_ray_query">
<enable extension="VK_KHR_ray_query"/>
</spirvextension>
+ <spirvextension name="SPV_KHR_ray_cull_mask">
+ <enable extension="VK_KHR_ray_tracing_maintenance1"/>
+ </spirvextension>
<spirvextension name="SPV_GOOGLE_hlsl_functionality1">
<enable extension="VK_GOOGLE_hlsl_functionality1"/>
</spirvextension>
@@ -16811,7 +22484,7 @@ typedef void <name>CAMetalLayer</name>;
<enable extension="VK_EXT_fragment_density_map"/>
</spirvextension>
<spirvextension name="SPV_KHR_physical_storage_buffer">
- <enable version="VK_API_VERSION_1_2"/>
+ <enable version="VK_VERSION_1_2"/>
<enable extension="VK_KHR_buffer_device_address"/>
</spirvextension>
<spirvextension name="SPV_EXT_physical_storage_buffer">
@@ -16827,22 +22500,25 @@ typedef void <name>CAMetalLayer</name>;
<enable extension="VK_EXT_fragment_shader_interlock"/>
</spirvextension>
<spirvextension name="SPV_EXT_demote_to_helper_invocation">
+ <enable version="VK_API_VERSION_1_3"/>
<enable extension="VK_EXT_shader_demote_to_helper_invocation"/>
</spirvextension>
<spirvextension name="SPV_KHR_fragment_shading_rate">
<enable extension="VK_KHR_fragment_shading_rate"/>
</spirvextension>
<spirvextension name="SPV_KHR_non_semantic_info">
+ <enable version="VK_API_VERSION_1_3"/>
<enable extension="VK_KHR_shader_non_semantic_info"/>
</spirvextension>
<spirvextension name="SPV_EXT_shader_image_int64">
<enable extension="VK_EXT_shader_image_atomic_int64"/>
</spirvextension>
<spirvextension name="SPV_KHR_terminate_invocation">
+ <enable version="VK_API_VERSION_1_3"/>
<enable extension="VK_KHR_shader_terminate_invocation"/>
</spirvextension>
<spirvextension name="SPV_KHR_multiview">
- <enable version="VK_API_VERSION_1_1"/>
+ <enable version="VK_VERSION_1_1"/>
<enable extension="VK_KHR_multiview"/>
</spirvextension>
<spirvextension name="SPV_KHR_workgroup_memory_explicit_layout">
@@ -16851,7 +22527,11 @@ typedef void <name>CAMetalLayer</name>;
<spirvextension name="SPV_EXT_shader_atomic_float_add">
<enable extension="VK_EXT_shader_atomic_float"/>
</spirvextension>
+ <spirvextension name="SPV_KHR_fragment_shader_barycentric">
+ <enable extension="VK_KHR_fragment_shader_barycentric"/>
+ </spirvextension>
<spirvextension name="SPV_KHR_subgroup_uniform_control_flow">
+ <enable version="VK_API_VERSION_1_3"/>
<enable extension="VK_KHR_shader_subgroup_uniform_control_flow"/>
</spirvextension>
<spirvextension name="SPV_EXT_shader_atomic_float_min_max">
@@ -16860,34 +22540,51 @@ typedef void <name>CAMetalLayer</name>;
<spirvextension name="SPV_EXT_shader_atomic_float16_add">
<enable extension="VK_EXT_shader_atomic_float2"/>
</spirvextension>
+ <spirvextension name="SPV_KHR_integer_dot_product">
+ <enable version="VK_API_VERSION_1_3"/>
+ <enable extension="VK_KHR_shader_integer_dot_product"/>
+ </spirvextension>
+ <spirvextension name="SPV_INTEL_shader_integer_functions">
+ <enable extension="VK_INTEL_shader_integer_functions2"/>
+ </spirvextension>
+ <spirvextension name="SPV_KHR_device_group">
+ <enable version="VK_API_VERSION_1_1"/>
+ <enable extension="VK_KHR_device_group"/>
+ </spirvextension>
+ <spirvextension name="SPV_QCOM_image_processing">
+ <enable extension="VK_QCOM_image_processing"/>
+ </spirvextension>
+ <spirvextension name="SPV_EXT_mesh_shader">
+ <enable extension="VK_EXT_mesh_shader"/>
+ </spirvextension>
</spirvextensions>
<spirvcapabilities comment="SPIR-V Capabilities allowed in Vulkan and what is required to use it">
<spirvcapability name="Matrix">
- <enable version="VK_API_VERSION_1_0"/>
+ <enable version="VK_VERSION_1_0"/>
</spirvcapability>
<spirvcapability name="Shader">
- <enable version="VK_API_VERSION_1_0"/>
+ <enable version="VK_VERSION_1_0"/>
</spirvcapability>
<spirvcapability name="InputAttachment">
- <enable version="VK_API_VERSION_1_0"/>
+ <enable version="VK_VERSION_1_0"/>
</spirvcapability>
<spirvcapability name="Sampled1D">
- <enable version="VK_API_VERSION_1_0"/>
+ <enable version="VK_VERSION_1_0"/>
</spirvcapability>
<spirvcapability name="Image1D">
- <enable version="VK_API_VERSION_1_0"/>
+ <enable version="VK_VERSION_1_0"/>
</spirvcapability>
<spirvcapability name="SampledBuffer">
- <enable version="VK_API_VERSION_1_0"/>
+ <enable version="VK_VERSION_1_0"/>
</spirvcapability>
<spirvcapability name="ImageBuffer">
- <enable version="VK_API_VERSION_1_0"/>
+ <enable version="VK_VERSION_1_0"/>
</spirvcapability>
<spirvcapability name="ImageQuery">
- <enable version="VK_API_VERSION_1_0"/>
+ <enable version="VK_VERSION_1_0"/>
</spirvcapability>
<spirvcapability name="DerivativeControl">
- <enable version="VK_API_VERSION_1_0"/>
+ <enable version="VK_VERSION_1_0"/>
</spirvcapability>
<spirvcapability name="Geometry">
<enable struct="VkPhysicalDeviceFeatures" feature="geometryShader" requires="VK_VERSION_1_0"/>
@@ -16987,16 +22684,20 @@ typedef void <name>CAMetalLayer</name>;
<enable struct="VkPhysicalDeviceFeatures" feature="shaderStorageImageMultisample" requires="VK_VERSION_1_0"/>
</spirvcapability>
<spirvcapability name="StorageImageExtendedFormats">
- <enable version="VK_API_VERSION_1_0"/>
+ <enable version="VK_VERSION_1_0"/>
</spirvcapability>
<spirvcapability name="InterpolationFunction">
<enable struct="VkPhysicalDeviceFeatures" feature="sampleRateShading" requires="VK_VERSION_1_0"/>
</spirvcapability>
<spirvcapability name="StorageImageReadWithoutFormat">
<enable struct="VkPhysicalDeviceFeatures" feature="shaderStorageImageReadWithoutFormat" requires="VK_VERSION_1_0"/>
+ <enable version="VK_API_VERSION_1_3"/>
+ <enable extension="VK_KHR_format_feature_flags2"/>
</spirvcapability>
<spirvcapability name="StorageImageWriteWithoutFormat">
<enable struct="VkPhysicalDeviceFeatures" feature="shaderStorageImageWriteWithoutFormat" requires="VK_VERSION_1_0"/>
+ <enable version="VK_API_VERSION_1_3"/>
+ <enable extension="VK_KHR_format_feature_flags2"/>
</spirvcapability>
<spirvcapability name="MultiViewport">
<enable struct="VkPhysicalDeviceFeatures" feature="multiViewport" requires="VK_VERSION_1_0"/>
@@ -17011,7 +22712,7 @@ typedef void <name>CAMetalLayer</name>;
<enable struct="VkPhysicalDeviceMultiviewFeatures" feature="multiview" requires="VK_KHR_multiview"/>
</spirvcapability>
<spirvcapability name="DeviceGroup">
- <enable version="VK_API_VERSION_1_1"/>
+ <enable version="VK_VERSION_1_1"/>
<enable extension="VK_KHR_device_group"/>
</spirvcapability>
<spirvcapability name="VariablePointersStorageBuffer">
@@ -17114,7 +22815,7 @@ typedef void <name>CAMetalLayer</name>;
<enable extension="VK_EXT_post_depth_coverage"/>
</spirvcapability>
<spirvcapability name="ShaderNonUniform">
- <enable version="VK_API_VERSION_1_2"/>
+ <enable version="VK_VERSION_1_2"/>
<enable extension="VK_EXT_descriptor_indexing"/>
</spirvcapability>
<spirvcapability name="RuntimeDescriptorArray">
@@ -17150,6 +22851,9 @@ typedef void <name>CAMetalLayer</name>;
<spirvcapability name="StorageTexelBufferArrayNonUniformIndexing">
<enable struct="VkPhysicalDeviceVulkan12Features" feature="shaderStorageTexelBufferArrayNonUniformIndexing" requires="VK_VERSION_1_2,VK_EXT_descriptor_indexing"/>
</spirvcapability>
+ <spirvcapability name="FragmentFullyCoveredEXT">
+ <enable extension="VK_EXT_conservative_rasterization"/>
+ </spirvcapability>
<spirvcapability name="Float16">
<enable struct="VkPhysicalDeviceVulkan12Features" feature="shaderFloat16" requires="VK_VERSION_1_2,VK_KHR_shader_float16_int8"/>
<enable extension="VK_AMD_gpu_shader_half_float"/>
@@ -17223,6 +22927,10 @@ typedef void <name>CAMetalLayer</name>;
</spirvcapability>
<spirvcapability name="RayTraversalPrimitiveCullingKHR">
<enable struct="VkPhysicalDeviceRayTracingPipelineFeaturesKHR" feature="rayTraversalPrimitiveCulling" requires="VK_KHR_ray_tracing_pipeline"/>
+ <enable struct="VkPhysicalDeviceRayQueryFeaturesKHR" feature="rayQuery" requires="VK_KHR_ray_query"/>
+ </spirvcapability>
+ <spirvcapability name="RayCullMaskKHR">
+ <enable struct="VkPhysicalDeviceRayTracingMaintenance1FeaturesKHR" feature="rayTracingMaintenance1" requires="VK_KHR_ray_tracing_maintenance1"/>
</spirvcapability>
<spirvcapability name="RayTracingNV">
<enable extension="VK_NV_ray_tracing"/>
@@ -17263,6 +22971,7 @@ typedef void <name>CAMetalLayer</name>;
<enable struct="VkPhysicalDeviceShadingRateImageFeaturesNV" feature="shadingRateImage" requires="VK_NV_shading_rate_image"/>
</spirvcapability>
<spirvcapability name="DemoteToHelperInvocationEXT">
+ <enable struct="VkPhysicalDeviceVulkan13Features" feature="shaderDemoteToHelperInvocation" requires="VK_VERSION_1_3,VK_EXT_shader_demote_to_helper_invocation"/>
<enable struct="VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT" feature="shaderDemoteToHelperInvocation" requires="VK_EXT_shader_demote_to_helper_invocation"/>
</spirvcapability>
<spirvcapability name="FragmentShadingRateKHR">
@@ -17279,5 +22988,45 @@ typedef void <name>CAMetalLayer</name>;
<spirvcapability name="WorkgroupMemoryExplicitLayout16BitAccessKHR">
<enable struct="VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR" feature="workgroupMemoryExplicitLayout16BitAccess" requires="VK_KHR_workgroup_memory_explicit_layout"/>
</spirvcapability>
+ <spirvcapability name="DotProductInputAllKHR">
+ <enable struct="VkPhysicalDeviceVulkan13Features" feature="shaderIntegerDotProduct" requires="VK_VERSION_1_3,VK_KHR_shader_integer_dot_product"/>
+ <enable struct="VkPhysicalDeviceShaderIntegerDotProductFeaturesKHR" feature="shaderIntegerDotProduct" requires="VK_KHR_shader_integer_dot_product"/>
+ </spirvcapability>
+ <spirvcapability name="DotProductInput4x8BitKHR">
+ <enable struct="VkPhysicalDeviceVulkan13Features" feature="shaderIntegerDotProduct" requires="VK_VERSION_1_3,VK_KHR_shader_integer_dot_product"/>
+ <enable struct="VkPhysicalDeviceShaderIntegerDotProductFeaturesKHR" feature="shaderIntegerDotProduct" requires="VK_KHR_shader_integer_dot_product"/>
+ </spirvcapability>
+ <spirvcapability name="DotProductInput4x8BitPackedKHR">
+ <enable struct="VkPhysicalDeviceVulkan13Features" feature="shaderIntegerDotProduct" requires="VK_VERSION_1_3,VK_KHR_shader_integer_dot_product"/>
+ <enable struct="VkPhysicalDeviceShaderIntegerDotProductFeaturesKHR" feature="shaderIntegerDotProduct" requires="VK_KHR_shader_integer_dot_product"/>
+ </spirvcapability>
+ <spirvcapability name="DotProductKHR">
+ <enable struct="VkPhysicalDeviceVulkan13Features" feature="shaderIntegerDotProduct" requires="VK_VERSION_1_3,VK_KHR_shader_integer_dot_product"/>
+ <enable struct="VkPhysicalDeviceShaderIntegerDotProductFeaturesKHR" feature="shaderIntegerDotProduct" requires="VK_KHR_shader_integer_dot_product"/>
+ </spirvcapability>
+ <spirvcapability name="FragmentBarycentricKHR">
+ <enable struct="VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR" feature="fragmentShaderBarycentric" requires="VK_KHR_fragment_shader_barycentric"/>
+ </spirvcapability>
+ <spirvcapability name="TextureSampleWeightedQCOM">
+ <enable struct="VkPhysicalDeviceImageProcessingFeaturesQCOM" feature="textureSampleWeighted" requires="VK_QCOM_image_processing"/>
+ </spirvcapability>
+ <spirvcapability name="TextureBoxFilterQCOM">
+ <enable struct="VkPhysicalDeviceImageProcessingFeaturesQCOM" feature="textureBoxFilter" requires="VK_QCOM_image_processing"/>
+ </spirvcapability>
+ <spirvcapability name="TextureBlockMatchQCOM">
+ <enable struct="VkPhysicalDeviceImageProcessingFeaturesQCOM" feature="textureBlockMatch" requires="VK_QCOM_image_processing"/>
+ </spirvcapability>
+ <spirvcapability name="MeshShadingEXT">
+ <enable extension="VK_EXT_mesh_shader"/>
+ </spirvcapability>
+ <spirvcapability name="RayTracingOpacityMicromapEXT">
+ <enable extension="VK_EXT_opacity_micromap"/>
+ </spirvcapability>
+ <spirvcapability name="CoreBuiltinsARM">
+ <enable struct="VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM" feature="shaderCoreBuiltins" requires="VK_ARM_shader_core_builtins"/>
+ </spirvcapability>
+ <spirvcapability name="ShaderInvocationReorderNV">
+ <enable extension="VK_NV_ray_tracing_invocation_reorder"/>
+ </spirvcapability>
</spirvcapabilities>
</registry>